kfilin / randdata
支持复杂数据和依赖实现的生成器
Requires
- php: >=5.6.0
Requires (Dev)
- phpunit/phpunit: ^5.7
README
支持复杂数据和依赖实现的生成器。您可以在项目的 演示站点 检查。
安装
composer require kfilin/randdata
基本使用
更多示例在 src/examples 文件夹中
原始随机值示例
$fabric = new RandData\Fabric(); $dataSetInteger = $fabric->createObjectFromString("integer"); for ($i = 1; $i <= 5; $i++) { echo $dataSetInteger->get() . PHP_EOL; } $dataSetInteger2 = $fabric->createObjectFromString("integer:min=-5;max=7"); $dataSetInteger3 = $fabric->createObjectFromString("integer:min=111;max=222");
使用模板填充字符串
假设我们有一个包含一对变量单词的字符串。我们将用随机值填充这些字段
class BlankTuple extends \RandData\Tuple { public function getDataSets() { return [ "name" => "string_list:values=John,Paul,George,Ringo", "dt" => "date:min=1962-10-05;max=1970-05-08" ]; } } $generator = new RandData\BlankGenerator(new BlankTuple); $tpl = "Hello, I'm {name} and today is {dt}"; $generator->init($tpl); echo $tpl . " => ". $generator->run() . PHP_EOL; // Hello, I'm {name} and today is {dt} // => // Hello, I'm George and today is 1965-12-12
让我们使它更复杂一点
class BlankTuple extends \RandData\Tuple { public function getDataSets() { return [ "name" => "string_list:values=John,Paul,George,Ringo", "dt" => "date:min=1962-10-05;max=1970-05-08", "age" => "integer:min=19;max=30" ]; } // Age field is dependant from dt field. See [Data dependency] protected function getValue(\RandData\Set $set, $fldName) { $birthDtList = [ "John" => "1940-10-09", "Paul" => "1942-06-18", "George" => "1943-02-25", "Ringo" => "1940-07-07" ]; if ($fldName == "age") { $name = $this->result["name"]; $dt = new \DateTime($this->result["dt"]); $birth = !empty($birthDtList[$name]) ? new \Datetime($birthDtList[$name]) : null; if ($dt && $birth) { $interval = $birth->diff($dt); return $interval->format("%y"); } return 0; } return $set->get(); } } $generator = new RandData\BlankGenerator(new BlankTuple); $tpl = "Hello, I'm {name}, my age {age} and today is {dt}. {name} at {dt}"; $generator->init($tpl); echo $generator->run() . PHP_EOL; // Hello, I'm John, my age 27 and today is 1968-07-08. John at 1968-07-08 // Hello, I'm Paul, my age 21 and today is 1963-11-14. Paul at 1963-11-14 // Hello, I'm George, my age 24 and today is 1967-08-14. George at 1967-08-14 // Hello, I'm Ringo, my age 28 and today is 1969-07-05. Ringo at 1969-07-05 // ...
生成器。创建csv文件
class PersonTuple extends \RandData\Tuple { public function getDataSets() { return [ "Id" => "counter", "Login" => "counter:template=user_#;start=100", "Name" => "en_person", "Birth" => "date:min=1900-01-01;max=2005-12-31", "Phone" => "phone:country_list=7;region_list=495,499,915,919,905,903", "Sum" => "integer:min=100;max=10000", "Class" => "string_list:values=aaa,bbb,ccc;possibility=50,20,30" ]; } protected function getNullProbability() { return [ "Phone" => 20, // null approximately 20% (every fifth) "Sum" => 50, // null approximately 50% (every second) ]; } } $formatter = new RandData\Formatter\Csv(new \RandData\Generator(new PersonTuple(), 20)); $formatter->setShowHeaders(false); $formatter->setShowCounter(false); echo $formatter->build(); echo PHP_EOL; /* #;Name;Birth;Phone;Sum 1;user_100;Jeremy Tyson Newman;1975-05-02;+7 (905) 513-68-76;NA;aaa 2;user_101;Valerie Camden Murray;1908-05-07;+7 (915) 573-60-43;2101;aaa 3;user_102;Theodore Kelton Graves;1939-06-26;+7 (903) 647-33-24;NA;bbb ... */
生成器。填充数据库等
首先,您可以手动定义您的数据
class PersonTuple extends \RandData\Tuple { public function getDataSets() { return [ "Id" => "counter", "Login" => "counter:template=user_#;start=100", "Name" => "en_person", "Birth" => "date:min=1900-01-01;max=2005-12-31", "Phone" => "phone:country_list=7;region_list=495,499,915,919,905,903", "Sum" => "integer:min=100;max=10000", "Class" => "string_list:values=aaa,bbb,ccc;possibility=50,20,30" ]; } protected function getNullProbability() { return [ "Phone" => 20, // null approximately 20% (every fifth) "Sum" => 50, // null approximately 50% (every second) ]; } } /* INSERT INTO `clients` (`Id`,`Login`,`Name`,`Birth`,`Phone`,`Sum`,`Class`) VALUES ('1','user_100','Thomas Brendon Simmons','1941-09-13','+7 (499) 877-05-17','8005','ccc'); INSERT INTO `clients` (`Id`,`Login`,`Name`,`Birth`,`Phone`,`Sum`,`Class`) VALUES ('2','user_101','Audrey Lee Howell','2005-10-16','+7 (499) 888-14-81','9693','aaa'); INSERT INTO `clients` (`Id`,`Login`,`Name`,`Birth`,`Phone`,`Sum`,`Class`) VALUES ('3','user_102','Penelope Ellen Arnold','1975-04-30','+7 (903) 991-48-86','1986','aaa');... */
如果您的数据库太大,您希望快速获取它,您可以从 sql SHOW CREATE TABLE 命令中获取它
$sql = "CREATE TABLE `user` ( `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT, `login` varchar(100) NOT NULL, `role` enum('admin','student') NOT NULL, `name` varchar(255) DEFAULT NULL, `passhash` varchar(50) NOT NULL, `blocked` tinyint(1) unsigned NOT NULL DEFAULT '0', `activate_code` varchar(100) DEFAULT NULL, `activate_dt` date DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `login` (`login`) ) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8"; $tableName = "user"; $tuple = new \RandData\Fabric\Tuple\SqlCreateTuple($sql); $generator = new \RandData\Generator($tuple, 20); $formatter = new \RandData\Formatter\Sql($generator, $tableName); echo $formatter->build() . PHP_EOL . PHP_EOL; foreach ($tuple->getDataSets() as $fldName => $fldDef) { echo "'" . $fldName . "' => '" . $fldDef . "'" . PHP_EOL; } echo PHP_EOL; /* In output sql insert command: */ INSERT INTO `user` (`id`,`login`,`role`,`name`,`passhash`,`blocked`,`activate_code`,`activate_dt`) VALUES ('1','Xi9ERI','student',NULL,'ZsT1ECLs3BrmgUnWBdjpHpLbHgLExH7sxLFzX5','N','hljwMnafH2pn8tPfwflWSl7MyXtnaMUbehdWvocM5avrFk3e',NULL); INSERT INTO `user` (`id`,`login`,`role`,`name`,`passhash`,`blocked`,`activate_code`,`activate_dt`) VALUES ('2','hHroxmPFgpDGOMl9yvFDykcAFoZ755P5CGHfZXgA9YNIo','student','Yl3UVeEKxvUysapnddBI9hEr9DeaulWUutMVE0WEdifEoytUdIp2APHPdo6XeWXx3hbfl5ps34sDg4pOto470yzuEXT7fn3VwOZ','BnesLyU43ly6T2bg6KWdii2piBLDhVtcSyie','1','j','2014-07-06'); // ... /* And rules for inserting into php class, where you can set more strict rules: */ 'id' => 'counter', 'login' => 'string:length_min=1;length_max=100', 'role' => 'string_list:values=admin,student', 'name' => 'string:length_min=1;length_max=255', 'passhash' => 'string:length_min=1;length_max=50', 'blocked' => 'boolean:valTrue=1;valFalse=0', 'activate_code' => 'string:length_min=1;length_max=100', 'activate_dt' => 'date:min=1900-01-01;max=2099-12-31',
如果您非常需要快速获取它,并且不太关心合理性,您可以填充所有数据库表(如果任何字段可能为 NULL,则其值将以大约 50% 的概率为 NULL)
$dbhost = "localhost"; $dbname = "test"; $dbuser = "root"; $dbpass = "123"; $dsn = sprintf("mysql:dbname=%s;host=%s", $dbname, $dbhost); try { $dbh = new PDO($dsn, $dbuser, $dbpass); $rows = $dbh->query("show TABLES", PDO::FETCH_COLUMN, 0); foreach ($rows as $tblName) { $rowCountSql = "SELECT count(*) FROM `" . $tblName . "`"; $rowCountRes = $dbh->query($rowCountSql, PDO::FETCH_COLUMN, 0); $rowCount = $rowCountRes->fetch(); // Just as a precaution if ($rowCount > 0) { echo "Non empty table: [" . $tblName . "]. Rows count: " . $rowCount . PHP_EOL; die; } $createSqlRow = "SHOW CREATE TABLE `" . $tblName . "`"; $createSqlRes = $dbh->query($createSqlRow, PDO::FETCH_COLUMN, 1); $sql = $createSqlRes->fetch(); $tuple = new \RandData\Fabric\Tuple\SqlCreateTuple($sql); $generator = new \RandData\Generator($tuple, 20); $formatter = new \RandData\Formatter\Sql($generator, $tblName); $sqlIns = $formatter->build(); $dbh->exec($sqlIns); } } catch (PDOException $e) { echo 'Connection failed: ' . $e->getMessage(); } echo PHP_EOL;
目前仅支持以下数据类型(请随意要求扩展列表或为项目做出自己的贡献)
- (tiny|small|medium|big)int
- decimal
- varchar
- (tiny|medium|long)text
- enum
- set(仅生成行中可用的值之一,例如,一个 OR 两个 OR 三个,而不是一个,两个或一个,三个)
- datetime/date/time/year/year(4)/year(2)
数据依赖
在现实生活中,数据是相互依赖的。出生必须在死亡之前,日出时间必须在日落时间之前,工资是根据工作时间、时薪、罚款等计算的。
此库可以生成依赖于其他对象属性的依赖数据(例如,雇佣日期依赖于出生日期)。
class EmployeeTuple extends \RandData\Tuple { const LEVEL_1 = 40*365*24*3600; const LEVEL_2 = 30*365*24*3600; const HIRED_AGE_MIN = 20*365*24*3600; const HIRED_AGE_MAX = 50*365*24*3600; public function getDataSets() { return [ "sex" => "string_list:values=" . RandData\Set\en_GB\Person::SEX_MALE . "," . RandData\Set\en_GB\Person::SEX_FEMALE, "name" => "en_person", "birth" => "date:min=now -50 year;max=now -20 year", "hired" => "date:min=now -3 year;max=now", "fired" => "date:min=now -3 year;max=now", "score" => "int:min=1;max=3" ]; } protected function getNullProbability() { return [ "fired" => 30 ]; } protected function getSetValueOrNull(RandData\Set $set, $fldName) { $value = parent::getSetValueOrNull($set, $fldName); // Override dependent datasets if ($fldName == "sex") { $this->getValueSex($value); } elseif ($fldName == "birth") { $this->getValueBirth($value); } elseif ($fldName == "hired") { $this->getValueHired($value); } return $value; } private function getValueSex(&$value) { $this->datasets["name"] = "en_person:sex=" . $value; $value = $value == RandData\Set\en_GB\Person::SEX_MALE ? "Male" : "Female"; } private function getValueHired($value) { // Fired date must be later than hired date, // but earlier than today $hiredTs = date("U", strtotime($value)); $firedDtMin = date("Y-m-d", $hiredTs + 1*24*3600); $firedDtMax = date("Y-m-d", date("U") - 3*24*3600); $this->datasets["fired"] = "date:min=" . $firedDtMin . ";max=" .$firedDtMax ; } private function getValueBirth($value) { $birthTs = date("U", strtotime($value)); $nowTs = date("U"); // Hired date must be later than birth date // Let's we can hire somebody in the ages from 20 to 50 $hiredTsMin = date("Y-m-d", date("U", min([ $birthTs + self::HIRED_AGE_MIN, date("U") ]))); $hiredTsMax = date("Y-m-d", date("U", min([ $birthTs + self::HIRED_AGE_MAX, date("U") ]))); $this->datasets["hired"] = "date:min=" . $hiredTsMin . ";max=" . $hiredTsMax; // Let's some dummy score will be dependant on age if (self::LEVEL_1 < $nowTs - $birthTs) { $this->datasets["score"] = "int:min=20;max=25"; } elseif (self::LEVEL_2 < $nowTs - $birthTs) { $this->datasets["score"] = "int:min=10;max=13"; } } } $employeeTuple = new EmployeeTuple(); $generator = new \RandData\Generator($employeeTuple, 50); $formatter = new \RandData\Formatter\Csv($generator); echo $formatter->build() . PHP_EOL;
如果您在不同的对象之间存在依赖关系(例如,作者和书籍),这可能会有些棘手,但有一些关于这个问题的东西
$bookTuple->setAuthorIds($authorsIds) // ... and then choose from this list
或者更简单,如果您测试 100 位作者
class PersonTuple extends \RandData\Tuple { public function getDataSets() { return [ // ... "author_id" => "integer:min=1;max=100", // ... ]; } }
数据依赖。嵌套数据集
另一种声明依赖的方法是嵌套数据集
class CarTuple extends \RandData\Tuple { public function getDataSets() { return [ "mark" => "string_list:values=ford,bmw,audi,vw,skoda,toyota,volvo,mercedez,bently,saab", "color" => "string_list:values=white,black,grey,blue,yellow,green,orange,red", "year" => "integer:min=1950;max=2017" ]; } } class PersonTuple extends \RandData\Tuple { public function getDataSets() { return [ "name" => "en_person", "birth" => "date:min=1920-01-01;max=1999-12-31", "login" => "string:char_list=abcdefghjklmnopqrstuvwxyz0123456789;length_min=2;length_max=8", "car" => new CarTuple() ]; } protected function getNullProbability() { return [ "car" => 30 ]; } } class OrderTuple extends \RandData\Tuple { protected $personList; function __construct($personList) { parent::__construct(); $this->personList = $personList; } public function getDataSets() { return [ "num" => "complex:template=id{string:char_list=abcdef;length_min=2;length_max=2}/" . date("Ymd") . "/{integer:min=1000;max=9999}", "delivery_address" => "en_address", "price" => "integer:min=50;max=1000", "person" => "value:value=person" ]; } protected function getSetValueOrNull(RandData\Set $set, $fldName) { if ($fldName == "person") { return $this->personList[array_rand($this->personList)]; } return $set->get(); } } $generator = new \RandData\Generator(new PersonTuple(), 3); $personList = $generator->run(); $ot = new OrderTuple($personList); $generator2 = new \RandData\Generator($ot, 5); $orderList = $generator2->run(); var_dump($generator2->run()); echo PHP_EOL;
填写表格
请参阅 演示站点
主要对象
RandData Fabric
创建 RandDataSet 对象
RandData Set
生成一个随机值。原子数据片段,可能是简单的(布尔值、数字或字符),也可能是复杂的,例如 PersonName 对象(FirstName + MiddleName + LastName)或 AviaTicket Order 对象(出发信息、路线、乘客名单、状态信息等)
Tuple
管理数据集列表。可以从 PHP 对象或从字符串中添加数据集。生成随机值数组
RandData Generator
管理生成过程。产生一定数量的随机数据集(随机值数组数组)
RandData 格式化器
构建数据流为有用的东西。现在可以是 csv 文件、sql INSERT 命令或 JSON 数组
数据集选项
所有数据集都可以从字符串标识符("boolean"、"string"、"integer" 等)创建
还可以有可选的参数
ID:params
参数由分号分隔,键值对由等号分隔
ID:key1=value1;key2=value2;key3=value3
值可能是一个数组项,其项由逗号分隔
ID:letters:a,b,c;persons:John,Mary,Jane
计数器
简单计数器。在字符串内部生成数字序列或作为数字。当通过生成器对象调用时,会自动递增。当直接调用或通过元组对象调用时,需要手动设置计数器值
ID
计数器,cnt
参数
- tpl,模板:当设置时,它会生成带有计数器的字符串(例如,模板 "user_#" 会变成 { user_1, user_2, user_3, ... }。当缺失时,则返回常规的无符号整数 { 1, 2, 3, ... }
- start:默认起始值。例如,您将生成器的数量属性设置为20,并将计数器起始属性设置为100,则您将获得值 { 100, 101, 102, ..., 119 }
初始化字符串示例
counter:template=user_#;start=100
布尔型
ID
布尔值
参数
- valTrue:当为真时显示的字符串(例如:1,Y,Yes,+,...)
- valFalse:当为假时显示的字符串(例如:0,N,No,-,...)
初始化字符串示例
boolean:valTrue=1;valFalse=0
boolean:valTrue=true;valFalse=false
整数
ID
int,整数
参数
- min:最小值(默认为0)
- max:最大值(默认为getrandmax() PHP函数的返回值)
初始化字符串示例
integer
integer:min=-5;max=7
小数
ID
decimal
参数
- min:最小值(默认为0)
- max:最大值(默认为getrandmax() PHP函数的返回值)
- minFractionDigits:小数点后的最小位数。默认为0
- maxFractionDigits:小数点后的最大位数。默认为8
初始化字符串示例
decimal:min=8;max=13
decimal:min=4;max=6;minFractionDigits=2;maxFractionDigits=4
字符串
所选字符的字符串
ID
string
参数
- length_min:字符串长度。默认为1。必须是至少1
- length_max:字符串长度。默认为10。必须是最大100
- char_list:随机字符串组成的字符列表。默认为 [A-Za-z0-9]
初始化字符串示例
string:length_min=3;length_max=5;char_list=ABCDEF0123456789
段落
由空格分隔的单词(随机字符字符串)的段落
ID
paragraph
参数
- words_min:段落中的最小单词数。默认为3。必须是至少1
- words_max:段落中的最大单词数。默认为100。必须是最大500
- length_min:字符串长度。默认为1。必须是至少1
- length_max:字符串长度。默认为10。必须是最大100
- char_list:随机字符串组成的字符列表。默认为 [A-Za-z0-9]
初始化字符串示例
paragraph:words_min=15;words_max=30
paragraph:words_min=15;words_max=30;length_min=4;length_max=6;char_list=ABCDEF0123456789
字符串列表
列表中的字符串
ID
string_list
参数
- values:可用值的逗号分隔列表
- possibility:值的可能性(以百分比表示)。必须等于值的数量,并且其总和必须是100。如果缺失,则所有值具有相同的机会。
初始化字符串示例
string_list:values=Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday
string_list:values=aaa,bbb,ccc;possibility=50,20,30
// aaa will be choosen approximately 50 times from 100
// bbb will be choosen approximately 20 times from 100
// ccc will be choosen approximately 30 times from 100
时间
ID
时间
参数
- min:最小时间。默认为 "00:00"
- max:最大时间。默认为 "23:59"
- seconds:是否显示秒。1 - 显示,0 - 隐藏。默认为0
初始化字符串示例
time:seconds=1
time:min=12:30;max=13:15
日期
ID
日期
参数
- min:最小日期。默认为今天减去一个月。输入格式 YYYY-MM-DD。
- max:最大日期。默认为今天。输入格式 YYYY-MM-DD。
- format:输出格式。理解date() PHP函数的任何格式。默认为 YYYY-MM-DD
初始化字符串示例
date:format=d.m.Y
date:min=2017-12-25;max=2017-12-28
日期时间
ID
日期时间
参数
- date_min:最小日期。默认为今天减去一个月。输入格式 YYYY-MM-DD。
- date_max:最大日期。默认为今天。输入格式 YYYY-MM-DD。
- date_format:输出格式。理解date() PHP函数的任何格式。默认为 YYYY-MM-DD
- time_min:最小时间。默认为 "00:00"
- time_max:最大时间。默认为 "23:59"
- seconds:是否显示秒。1 - 显示,0 - 隐藏。默认为1
初始化字符串示例
datetime:date_format=d.m.Y;seconds=0
datetime:date_min=2017-05-17;date_max=2017-05-21;time_min=11:00;time_max=14:30
电话
ID
电话
参数
- country_list:可用国家代码列表(1-9)
- region_list:可用地区代码列表(3或4位数字)
- format:是否显示格式为 +# (###) ###-##-## 或 +# (####) ###-### 的号码或11位号码。1 - 格式化(默认),0 - 未格式化。
初始化字符串示例
phone:format=0
phone:country_list=3,7;region_list=123,456,7890
域名
ID
二级www域名
domain
参数
- tld_list:可用顶级域列表。默认:com,edu,org,net
- char_list_edge:首尾字符。默认:abcdefghijklmnopqrstuvwxyz0123456789
- char_list:可用字符(除首尾字符外)。默认是 char_list_edge 字符和破折号字符 ("-")。
- skip_www:跳过域名的 www 部分。可以是 0 或 1。默认 0
初始化字符串示例
domain:skip_www=1
domain:tld_list=org,net;char_list_edge=01;char_list=abcdef0123456789
电子邮件
ID
电子邮件
参数
- domain_list:仅在此域中生成邮件
初始化字符串示例
email:domain_list=gmail.com,yahoo.com,hotmail.com,fbi.gov
值
生成单个值
ID
value
参数
- value:要生成的值
初始化字符串示例
email:domain_list=gmail.com,yahoo.com,hotmail.com,fbi.gov
复杂
数据集由其他数据集组成
ID
complex
参数
- 模板:初始化字符串 - 包含在{}内的任何字符串,用于数据集定义。请参阅示例以获取详细信息
初始化字符串示例
complex:template=Hello, I'm {string_list:values=Peter,James,John}, my age is {integer:min=5;max=30}, I live @ {en_address} and today is {date}
示例
$tpl = "Hello, I'm {string_list:values=Peter,James,John}, my age is {integer:min=5;max=30}, I live @ {en_address} and today is {date}"; $generator = new \RandData\Set\Complex($tpl); echo $generator->run() . PHP_EOL;
DataSet (en_GB)
地址
ID
en_address
参数
无参数
城市
ID
en_city
参数
- postcode:从该邮编区域获取城市的参数
初始化字符串示例
en_city:postcode=IP29 8FX
人员
ID
en_person
参数
- sex:人员性别的列表。m - 男,f - 女。默认为两者都包含
- format:名(%f)、中名(%m)和姓(%l)的顺序。默认为 "%f %m %l"。%f1 - 名字的第一个字母,%m1 - 中名的第一个字母,%l1 - 名字的最后一个字母
初始化字符串示例
en_person:format=%f %m %l en_person:format=%f %m1. %l en_person:sex=m
邮政编码
ID
en_postcode
参数
无参数
街道
ID
en_street
参数
无参数
DataSet (ru_RU)
地址 (ru)
ID
ru_address
参数
- show_flat:是否显示公寓号码。1 - 显示,0 - 隐藏
初始化字符串示例
ru_address:show_flat=0
城市 (ru)
ID
ru_city
参数
无参数
人员 (ru)
ID
ru_person
参数
- sex:人员性别的列表。m - 男,f - 女。默认为两者都包含
- format:名(%f)、中名(%m)和姓(%l)的顺序。默认为 "%l %f %m"。%f1 - 名字的第一个字母,%m1 - 中名的第一个字母,%l1 - 名字的最后一个字母
初始化字符串示例
ru_person:format=%f %m %l
ru_person:format=%l %f1. %m1.
ru_person:sex=m
邮政编码 (ru)
ID
ru_postcode
参数
无参数
街道 (ru)
ID
ru_street
参数
无参数
待办事项
- (-)代码风格,混乱检测器,代码度量
- (-)持续集成(CI)
- (-)v1.0