eftec/chaosmachineone

1.13 2022-09-17 22:58 UTC

This package is auto-updated.

Last update: 2024-09-18 03:15:39 UTC


README

PHP 的受控随机生成器数据。该库的目的是帮助生成和填充随机值到内存、Mysql、Sql Server 和 Oracle,同时我们可以添加一些倾向/偏差,使得这些值不是完全随机的。

Build Status Packagist Total Downloads Maintenance composer php CocoaPods

目录

目标是什么?

有时我们希望为数据库生成受控且一致的数据。因此,这个库试图创建一个有序的混沌。

尽管有生成随机值的库(如 fzaninotto/Faker),但这个库的目标是填充表格,使得数据随机但可信/有趋势。

Medium 文章

让我们做一个练习。我们想为一个新的系统(销售)生成随机值

如果我们生成随机值,图表会看起来像

->gen('when _index<200 then idtable.value=random(-10,10,0.2)')

random

为什么这么随机?因为它们是随机值(sic)。

所以,它们是对的,但它们看起来不真实,因为没有趋势或信息的自然流动,它只是静态噪音。

那么,让我们用正弦(例如,让我们说销售有一个周期)生成相同的值

->gen('when _index<200 then idtable.add=sin(0,0,10,30)')

random

图表有趋势,但太可预测了。所以,让我们添加所有因素。

->gen('when _index<200 then idtable.value=random(-10,10,0.2) and idtable.add=sin(0,0,10,30)')

random

虽然这个图表远非真实,但它不是太随机,并且有一个趋势。

字段

field($name,$type,$special='database',$initValue=0,$min=PHP_INT_MIN,$max=PHP_INT_MAX)

字段是我们的值。它们可以是数字、日期和字符串。

  • 字段可以有速度和加速度。然而,如果您手动更改值,则忽略速度和加速度。

  • "field.value=X" 设置字段的值。

  • "field.speed=X" 设置字段的速度。

  • "field.accel=X" 用于设置场加速。如果手动设置速度,则忽略加速。

  • "field.stop=X" 将速度和加速设置为0,并将值设置为X。

  • 速度和加速在执行时(run() 方法)进行评估。

示例

"set field.value=20" // it sets the value of the field to 20   
"set field.speed=3" // it sets the speed of the field by 3. The field increases the value every cycle by 3    
"set field.accel=1" // it sets the acceleration of the field by 1. The field increases the speed every cycle by 1    
"set field.value=30 and field.speed=1" // the value is always 30, no matter the speed
$this->gen('when _index<40 then idtable.accel=1'); // the acceleration is 1 until index=40
$this->gen('when _index<60 then idtable.accel=-1'); // the acceleration is -1 until index=60
$this->gen('when _index<100 then idtable.accel=-1'); // the acceleration is -1 until index=100

accel

gen

它使用Minilang语法生成一个值。

语法如下

when logic and/or logic2 and/or logic3 then setvalue1 , setvalue2 , setvalue3

minilang

保留变量

示例

myvar = 是一个变量

当始终设置 myvar.value=null
当 _index<20 设置 myvar.value=false

限制。

  • 不允许使用括号(除非它定义了一个函数)。
    • a1=(20+30) 不允许,然而 a1=20,a1+30 是允许的

  • 语法分为两部分,一部分是逻辑(when),另一部分是设置(then)。
  • 条件按顺序评估。如果一个条件满足,则停止其他评估。
    • $this->gen('when a1=1 then b1=1');
      $this->gen('when a1<10 then b1=10'); // if a1=1 then this expression is not evaluated.

逻辑

使用“与”或“或”分隔条件。

不允许在逻辑中使用多个运算符。a1=20+30 不允许。

范围函数(数字)

生成一系列值的函数

ramp($fromX, $toX, $fromY, $toY)

它生成斜坡值(线性值)

->gen('when _index<200 then idtable.value=ramp(0,100,10,1000)')

ramp

->gen('when _index<200 then idtable.value=ramp(0,100,1000,10)')

ramp inverse

log($startX,$startY,$scale=1)

它生成对数值

->gen('when _index<200 then idtable.value=log(0,0,100)')

log

exp($startX,$startY,$scale=1)

它生成指数值。尺度是Y的除法

->gen('when _index<200 then idtable.value=exp(0,0,10)')

exp

sin($startX,$startY,$speed=1,$scale=1,$angle=null)

它生成正弦值。角度

  • startX 是X的位置
  • startY 是Y的位置(你可以上下移动值)
  • 速度是角度的速度。
    • 例如 sin(0,0,1,1),每个 _index 值相当于一个度。
    • 例如 sin(0,0,2,1),每个 _index 值相当于 x2 度。
  • scale 是图表的Y轴尺度。
  • angle,如果未设置,则使用当前索引x速度(以度为单位)计算。如果不设置,则用于确定正弦值的角
$this->gen('when _index<200 then idtable.value=sin(0,0,1,1)'); // speed (horizontal) is 1.

sin1

$this->gen('when _index<200 then idtable.value=sin(0,0,10,1)'); // speed (horizontal) is 10

sin10

atan($centerX,$startY,$speed=1,$scale=1)

它生成反正切值

$this->gen('when _index<200 then idtable.value=atan(50,0,20,10)');

atan

parabola($centerX,$startY,$scaleA=1,$scaleB=1,$scale=1)

它生成抛物线。可以通过将scaleA设置为负值来反转抛物线

$this->gen('when _index<200 then idtable.value=parabola(50,0,1,1,1)');

parabola1

$this->gen('when _index<200 then idtable.value=parabola(50,0,-1,1,1)');

parabola2

$this->gen('when _index<200 then idtable.value=parabola(50,2500,-1,1,1)');

parabola3

bell($centerX, $startY, $sigma=1, $scaleY=1)

它生成钟形值,sigma是钟的“宽度”。

$this->gen('when _index<=360 then idtable.value=bell(50,0,30,100)');

bell30

$this->gen('when _index<=360 then idtable.value=bell(50,0,1,100)');

bell1

固定函数(数字)

生成单个值的函数

randomprop(...$args)

它通过使用不同的比例或概率生成随机值。

randomprop(1,2,3,30,50,20)

  • 有30%的概率是1
  • 有50%的概率是2
  • 有20%的概率是3

示例

$this->gen('when _index<200 then idtable.value=randomprop(1,2,3,30,50,20)'); // 30% chance of 1, 50% chance of 2, 20% change of 3
$this->gen('when always then idtable.value=randomprop(idtable,null,1,1)); // there is a 50% chance the value is keep and 50% chance the value is null

randomprop

random($from,$to,$jump=1,...$probs)

它从$from生成一个随机值到$to。

random(1,10) // 1,2,3,4,5,6,7,8,9,10
random(1,10,2) // 1,3,5,7,9
$this->gen('when _index<200 then idtable.value=random(-10,10,0.2)');

random

可选地,你可以为每个段添加一个概率。

random(0,100,1,10,20,70)

  • 有10%的概率随机值在0到33之间
  • 有20%的概率随机值在34到66之间
  • 有70%的概率随机值在67到100之间

idtable.value=random(0,200,1,80,10,10) // 值趋势保持在底部

random trend lower

idtable.value=random(0,200,1,10,80,10) // 值趋势保持在中心

random trend middle

idtable.value=random(0,200,1,10,10,80) // 值趋势保持在顶部

random trend higher

你还可以使用值名称的下一个名称

示例

$this->gen('when _index<200 then idtable.value=random(1,100,1,"fakebell")');

field.speed=xxxx

它设置场的速度。如果场有速度,则每次交互时值会增加。

示例

$this->gen('when date.weekday<6 set counter.speed=1'); // the speed during the working days is 1
$this->gen('when date.weekday>=6 set counter.speed=2'); // the speed during the weekends is 2
// counter=1 if counter initially is 1, and the variable date changes 1 day per iteraction the:
// monday: counter 2
// thuesday: counter 3
// wednesday: counter 4
// thursday: counter 5
// friday: counter 6
// saturday: counter 8
// sunday: counter 10
// monday: counter 11

field.accel=xxxx

它设置场的加速。如果场有加速度,则每次迭代时速度会增加。

示例

$this->gen('when always set counter.acceleration=1'); 
// counter.value: 1 counter.velocity: 0
// counter.value: 2 counter.velocity: 1
// counter.value: 4 counter.velocity: 2
// counter.value: 7 counter.velocity: 3

field.value=xxxx

它设置场的值

示例

$this->gen('when always set var1=1 and var2="hello world" and var3=2+3'); 

field.getvalue

它返回场的值

示例

$this->gen('when always set var1=var2.getvalue'); 

field.valueabs

它将场的值转换为绝对值(总是正值)

示例

$this->gen('when always set var1=var2.getvalueabs'); 

field.day , field.month , field.year, field.hour, field.minute, field.weekday

它返回当前日期部分(日、月、年、小时、分钟和星期)。

它用于日期时间类型的字段。它不是用于设置值,而是仅用于获取值,无论值如何。星期:1=星期一,7=星期日

月份:1 = 一月,12=十二月

示例

$this->gen('when field.day=1 set var1="first day of the month"'); 

field.stop=xxxx

设置或返回字段的值,同时将速度和加速度标记为零。

field.add=xxxx

向字段添加一个值。如果字段是datetime类型,则可以添加"hour"、"minute"和"day"。

$this->gen('when always set field.add=20'); // add 20 to the field
$this->gen('when always set field.add="5h"'); // adds 5 hours to the field. 5m = 5 minutes, 5d = 5 days

field.concat=xxxx

将一个值连接到字段。

this->gen('when always set field1.value="hello" and field2.value="world"');
this->gen('when always set field1.concat=field2'); // field1: "helloworld"

field.skip=xxx

跳过值到下一个值。用于日期。

field.skip='day'  // it skips to the next day (it start at 00:00)
field.skip='month'  // it skips to the next month (it start at the first day of the month 00:00)
field.skip='monday' // (or the name of the day), it skips to the next monday (00:00 hours)
field.skip='hour' // it skips to the next hour (minute 00)
$this->gen('when field.month=3 set field.skip="month"'); // we skip march.

数组与文本

->setArray('arrayname',[])

设置一个数组。如果数组是关联的,则值是选择概率。

$this->setArray('arrayname',['a','b','c']) // it sets an array with 3 values with the same chances.
$this->setArray('arrayname',['a'=>80,'b'=>10,'c'=>10]) // it sets an array with 3 values with the changes 
                                                       // of a(80%),b(10%) and c(10%)

注意:数组和变量共享相同的内存空间,因此如果我们有一个变量和数组具有相同的值,那么其中一个将被覆盖。

randomarray("arrayname",'field'=null)

返回由setArray()声明的数组内的随机行。如果数组是关联的,则根据其概率返回值。

如果数组是对象的列表,则返回字段的值。

$this->gen('when always set name.value=randomarray("arrayname")');

示例

$this->setArray('namearr',['john','bob','peter']);
$this->gen('when always set name.value=randomarray("namearr")'); // example: "john"

->setFormat('formatName',[])

设置一个格式(模板)以合并不同的数组。

此函数与randomformat()同时使用。

数组标记为{{数组名称}}。如果数组未定义,则返回字段的值。

如果数组是关联的,则根据其概率返回值。

$this->setFormat('maleNameFormats',['{{namearr}} {{lastnamearr}}','Dr.{{namearr}} {{lastnamearr}}'])
$this->setFormat('maleNameFormats',['{{namearr}} {{lastnamearr}}'=>80,'Dr.{{namearr}} {{lastnamearr}}'=>20]) //probability of 80% and 20%

示例

$this->setArray('namearr',['john','bob','peter']);
$this->setArray('lastnamearr',['doe','smith','johnsons']);
$this->setFormat('maleNameFormats',['{{namearr}} {{lastnamearr}}','Dr.{{namearr}} {{lastnamearr}}']);  // "john doe" or "dr. john doe"

randomformat($nameFormat)

使用格式和不同数组混合生成随机文本。

$this->gen('when always set fullname.value=randomformat("nameFormat")');

示例

$this->setArray('namearr',['john','bob','peter']);
$this->setArray('lastnamearr',['doe','smith','johnsons']);
$this->setFormat('maleNameFormats',['{{namearr}} {{lastnamearr}}','Dr.{{namearr}} {{lastnamearr}}']);  // "john doe" or "dr. john doe"
$this->gen('when always set fullname.value=randomformat("nameFormat")'); // fullname could be  "john doe", "dr. john doe", "bob doe" or others.

randomtext($starting,$arrayName,$paragraph,$wordMinimum,$wordMaximum)

使用名为$arrayName的数组生成随机文本。文本可以以默认文本开头。

如果$paragraph不是0,则可以生成段落(换行符)

如果arrayName为空,则使用包含"lorem ipsum"单词的数组。

$this->gen('when always then text.value=randomtext("Lorem ipsum dolor","loremIpsumArray",1,4,30)')

randommask($mask,$arrayName='')

根据掩码生成文本。

  • # = 一个(可选)随机数字
  • 0 = 一个随机数字。
  • u = 一个大写字母
  • l = 一个小写字母
  • v = 一个大写或小写字母。
  • w = 一个随机字母(大写或小写)或数字。
  • X = 一个可选的大写字母
  • x = 一个可选的小写字母
  • ? = 来自数组或格式的随机单词。
  • \ = 转义字符,(下一个字符将返回而不进行处理)

randommask("##-00 uu ll \0 - oo (a)","lastName") // 其中lastName是一个数组

示例

$this->gen('when always then text.value=randommask("ulllll####000")');

其他特性

end

结束当前运行。当您想停止插入值时很有用。

示例

$this->gen('when counter>100 then end()');

omit

跳过当前循环。当您想跳过一些值时很有用。

示例

$this->gen('when counter>20 and counter<30 then omit()'); // values where counter are in between 20 and 30, are omited.

见跳过以省略日期

文件特性

arrayFromFolder()

读取一个文件夹并返回一个文件数组。读取不是递归的,并且可以通过扩展名进行过滤。

$filesWithoutExtension=$chaos->arrayFromFolder($localfolder,'jpg',false);

Script function destionationArray.copyfilefrom()=originArray.getvalue

从一个位置复制文件到另一个位置。

$this->gen('when always set ImageDestination.copyfilefrom=ImageSource.getvalue')

数据库

此库允许直接与数据库交互,读取和插入信息。

例如,让我们看看下面的练习

$db=new PdoOne("mysql","localhost","root","abc.123","chaosdb"); // connect to mysql
$db->open(); // it opens the connection

$chaos = new ChaosMachineOne();
$chaos->debugMode=true;
$chaos->table('SOMETABLE', 1000) // we will work with the table SOMETABLE
    ->setDb($db) // we indicates to our library to use the connection to the database
    ->field('fixedid','int','local',5) // we created a field (local), it will not be stored in the database
    ->field('idcustomer', 'int','identity', 0, 0, 1000) // we created a field (database), however it is identity so it will not be stored in the database
    ->field('name', 'string', 'database', '', 0, 45) // this field will be stored in the database
    //...
    ->setInsert()
    ->run(); // finally we insert the new values (1000 values) : insert into SOMETABLE (name) values(...);

table($table, $conditions,$prefix='origin_')

设置工作表和要处理值的数量。

如果您正在使用数据库,则表用于确定值将插入的位置。

如果您没有使用数据库,则表仅作参考。

  • $table = 表名
  • $conditions (int) = 它可以指示要生成的行数。
  • $conditions (array) = 它指示要迭代的值。
  • $conditions (string) = 它指示用作值“来源”的表(或查询)。您可以使用查询的内连接,但查询必须返回唯一的列。
  • $prefix (string) = 它设置一个前缀值。
$chaos->table('SOMETABLE', 1000) // insert 1000 rows into SOMETABLE
$chaos->table('SOMETABLE', ['a','b','c'],'letter') // it will iterate between a,b,c, each letter could be obtained in the fields called letter
$chaos->table('SOMETABLE', 'ORIGINTABLE') // insert "n" rows into SOMETABLE. "n" depends in the number of rows of ORIGINTABLE.
$chaos->table('SOMETABLE', 'select * from ORIGINTABLE') // insert "n" rows into SOMETABLE. "n" depends in the number of rows of ORIGINTABLE.

查询值存储在称为:origin_列名的字段中

$chaos->table('SOMETABLE', 'select col1,col2 from ORIGINTABLE','i_'); 
// it will generate the fields i_col1 and i_col2 with the values of the origin table, that you can read and process.

update($table,$indexcolumn,$indexvalue,$updatecolumn1,$updatevalue1...)

更新表的简单行。您可以更新最多3个值。

示例

$this->update('table1','id',20,'col','hello world')
// update table1 set col='hello world' where id=20
$this->update('table1','id',20,'col','hello','col2','world','col3','hi')
// update table1 set col='hello',col2='world',col3='hi' where id=20    
    
$this->gen('when field.value>10 then update("table1","id",field.value,"col","hello world")'); 
// if field>10 then update table1 set col='hello world' where id=field

insert($storeCache=false,$echoProgress=null,$continueOnError=false,$maxRetry=3)

向数据库中插入随机值。

注意:此方法已弃用。请改用setInsert()

  • $storecache : 如果为true,则插入值并将其值存储到内存中。
  • $echoProgress : (printf格式)如果不为空,则显示进度(echo)
  • $continueOnError = 如果为真,则插入失败时继续。
  • $maxRetry = 重试次数(如果插入失败)

setInsert($continueOnError=false,$maxRetry=3)

它将值插入数据库。此操作在执行run()命令时执行。

  • $continueOnError = 如果为真,则插入失败时继续。
  • $maxRetry = 重试次数(如果插入失败)
$this->table('SOMETABLE', 1000);
$this->field('name', 'string', 'database', '', 0, 45) // this field will be stored in the database
// here we assign the value to name
$this->setInsert(); // insert into sometable(name) values(... ); we repeat it 1000 times.
$this->run();

setArrayFromDBQuery($name,$query,$probability=[1],$queryParam=null)

它使用查询设置一个数组

  • $name = 数组名称
  • $query = 原始值的源查询。它必须返回单列。
  • $probability = 概率数组。如果[1],则表示每个值100%,[80,20]表示数组前半部分的值为80%,后半部分为20%。
  • $queryParam = (可选)查询参数。
->setArrayFromDBQuery('namemale','select first_name from sakila.actor')
->setArrayFromDBQuery('lastname','select last_name from sakila.actor where actor_id={{fixedid}}',[1])

注意:数组和变量共享相同的内存空间。

setArrayFromDBTable($name,$table,$column,$probability=[1])

它使用表设置一个数组

  • $name = 数组名称
  • $query = 原始值的源查询。它必须返回单列。
  • $probability = 概率数组。如果[1],则表示每个值100%,[80,20]表示数组前半部分的值为80%,后半部分为20%。
  • $queryParam = (可选)查询参数。
$this->setArrayFromDBTable('namemale','sakila.actor','first_name');
$this->setArrayFromDBTable('lastname','sakila.actor','first_name',[1]);

注意:数组和变量共享相同的内存空间,所以如果您使用相同的名称,则可以覆盖其中一个。

示例

连接到 Sql Server

$chaos=new ChaosMachineOne();
$chaos->setDb(new PdoOne('sqlsrv','localhost\sqlexpress','sa','password','testdb'));
$chaos->getDb()->logLevel=3; // for debug purpose
$chaos->getDb()->connect();

连接到 Mysql

$chaos=new ChaosMachineOne();
$chaos->setDb(new PdoOne('mysql','localhost','root','password','testdb'));
$chaos->getDb()->logLevel=3; // for debug purpose
$chaos->getDb()->connect();

基于表的生成代码

假设我们在数据库中有一个名为table1的表。

// $chaos is an instance of ChaosMachineOne and it must be connected to the database.
echo "<pre>";
echo $chaos->generateCode('table1'); // the table to generate the code.
// echo $chaos->generateCode('*'); // you also could generate code of all tables at once.
echo "</pre>";

后面的代码将显示以下值

$chaos->table('table1', 1000)
		->setDb($db)
		->field('id', 'int','identity', 0)
		->field('number', 'int','database')
			->isnullable(true)
		->field('text', 'string','database','',0,50)
			->isnullable(true)
		->gen('when always set number.value=random(1,100,1,10,10)') 
		->gen('when always set text.value=random(0,50)')
		->setInsert(true)
		->showTable(['id','number','text'],true)
		->run(true);

因此,您不需要从头开始。

此代码生成器也理解外键。

插入 1000 个随机值

$chaos->table('table1', 1000)
    ->field('id', 'int','identity', 0)
    ->field('number', 'int','database')
    ->isnullable(true)
    ->field('text', 'string','database','',0,50)
    ->isnullable(true)
    ->gen('when always set number.value=random(1,100,1,10,10)') // later you can change the values.
    ->gen('when always set text.value=random(0,50)')
    ->setInsert(true) // if you don't want to insert, then you could remove this line
    ->showTable(['id','number','text'],true) // if you don't want to show the values, then you could remove this line.
    ->run(true);

注意:此代码的部分可以自动生成。

更新表的所有行

$chaos->table('table1', 'table1') // the first table is used for insert, since we are not inserting, then this value is not used. The second table is the table where the values will be read.
    ->field('text', 'string','database','',0,50)->isnullable(true)
    ->gen('when always set text.value="hello world"')
    ->gen('when always set update("table1","id",origin_id,"text",text.value)') // here whe update the same table. the prefix "origin_" is added automatically
    //->setInsert(true) we don't want to insert.
    ->showTable(['text'],true)
    ->run(true);

版本

  • 1.13 2022-09-17
    • 为代码添加了类型提示。
    • 清理了代码。
    • 更新了要求。现在,此库需要PHP 7.2及以上版本。
    • 更新了库依赖。
  • 1.12 2022-01-03
    • 在构造函数中添加了随机种子。默认情况下,随机种子使用处理器的微秒数生成。
    • 修复了一些操作的精度问题
    • 随机现在允许任何值数组。
  • 1.11 2021-12-01
    • 添加了end()、omit()和update()方法
    • 更新了sin()方法。现在可以指定当前角度。
    • 修复了日期处理过程中的某些错误。
  • 1.10 2021-11-22
    • 一些清理。
  • 1.9 2020-08-12
    • 更新了数据库问题(无限循环)。
    • 更新了代码。
    • 更新了依赖。
  • 1.8 2020-04-09
    • 方法insert()已弃用。请改用setInsert()。
    • 新方法setInsert()。
  • 1.7 2020-04-09 更新依赖项 eftec/pdoone (1.19 => 1.28.1)
  • 1.6 添加了showTable()和show()函数
  • 1.5 更新MiniLang 2.12 -> 2.14
  • 1.4 我们可以同时运行 ->insert(true)->show()。Insert(true)将保留值(因此我们可以显示它而不重新计算)
  • 1.3 现在它可以复制文件。新方法arrayFromFolder()读取文件夹中的所有文件。
    脚本方法field.copyfilefrom=origin从源(文件数组)复制。
    现在,randommask (?) 通配符与数组和格式一起工作。
  • 1.2 一些清理。
  • 1.1 现在Minilib是一个外部库
  • 1.0 第一个开源版本

许可证

双许可协议

LGPL-V3和商业许可。

版权所有:Jorge Patricio Castro Castillo (2018)