From d4b163219cabf6e8fecaf43109ada9cae987d77f Mon Sep 17 00:00:00 2001 From: sizuhiko Date: Sat, 31 May 2014 16:53:07 +0900 Subject: [PATCH 01/13] fix indent --- Lib/Fabricate.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/Fabricate.php b/Lib/Fabricate.php index 76908d8..6c21650 100755 --- a/Lib/Fabricate.php +++ b/Lib/Fabricate.php @@ -25,7 +25,7 @@ private static function getInstance() { */ public function __construct() { $this->config = new FabricateConfig(); - } + } /** * To override these settings From 97af915170b0653f72bcc3a2374442fc4c796462 Mon Sep 17 00:00:00 2001 From: sizuhiko Date: Sat, 31 May 2014 21:23:40 +0900 Subject: [PATCH 02/13] WIP separate fabricate to factories for create from model or definition --- Lib/Definition/FabricateDefinition.php | 25 +++++ Lib/Fabricate.php | 101 +++--------------- Lib/FabricateRegistry.php | 59 ++++++++++ Lib/Factory/FabricateAbstractFactory.php | 60 +++++++++++ Lib/Factory/FabricateDefinitionFactory.php | 5 + Lib/Factory/FabricateFactory.php | 25 +++++ Lib/Factory/FabricateModelFactory.php | 81 ++++++++++++++ Lib/empty | 0 Test/Case/AllFabricateTest.php | 2 +- .../Definition/FabricateDefinitionTest.php | 21 ++++ Test/Case/Lib/FabricateRegistryTest.php | 48 +++++++++ .../Case/Lib/Factory/FabricateFactoryTest.php | 30 ++++++ 12 files changed, 370 insertions(+), 87 deletions(-) create mode 100644 Lib/Definition/FabricateDefinition.php create mode 100644 Lib/FabricateRegistry.php create mode 100644 Lib/Factory/FabricateAbstractFactory.php create mode 100644 Lib/Factory/FabricateDefinitionFactory.php create mode 100644 Lib/Factory/FabricateFactory.php create mode 100644 Lib/Factory/FabricateModelFactory.php delete mode 100755 Lib/empty create mode 100644 Test/Case/Lib/Definition/FabricateDefinitionTest.php create mode 100644 Test/Case/Lib/FabricateRegistryTest.php create mode 100644 Test/Case/Lib/Factory/FabricateFactoryTest.php diff --git a/Lib/Definition/FabricateDefinition.php b/Lib/Definition/FabricateDefinition.php new file mode 100644 index 0000000..29e3627 --- /dev/null +++ b/Lib/Definition/FabricateDefinition.php @@ -0,0 +1,25 @@ +define = $define; + } + + public function run($data, $world) { + if(is_callable($this->define)) { + $callback = $this->define; + $result = $callback($data, $world); + } else if(is_array($this->define)) { + $result = $this->define; + } + return $result; + } +} \ No newline at end of file diff --git a/Lib/Fabricate.php b/Lib/Fabricate.php index 6c21650..6d7c3a9 100755 --- a/Lib/Fabricate.php +++ b/Lib/Fabricate.php @@ -1,6 +1,8 @@ config = new FabricateConfig(); + self::$_instance->registry = new FabricateRegistry('Fabricate'); } return self::$_instance; } @@ -24,7 +29,6 @@ private static function getInstance() { * Override constructor. */ public function __construct() { - $this->config = new FabricateConfig(); } /** @@ -43,11 +47,8 @@ public static function config($callback) { */ public static function create($modelName, $recordCount=1, $callback = null) { $attributes = self::attributes_for($modelName, $recordCount, $callback); - $model = ClassRegistry::init($modelName); - foreach ($attributes as $data) { - $model->create($data); - $model->save(null, self::getInstance()->config->auto_validate); - } + $factory = self::factory($modelName); + return $factory->create($attributes, $recordCount, $callback); } /** * Only create a model instance. @@ -57,9 +58,8 @@ public static function create($modelName, $recordCount=1, $callback = null) { */ public static function build($modelName, $callback = null) { $data = self::attributes_for($modelName, 1, $callback); - $model = ClassRegistry::init($modelName); - $model->create($data[0]); - return $model; + $factory = self::factory($modelName); + return $factory->build($data, $callback); } /** * Only create model attributes array. @@ -70,84 +70,13 @@ public static function attributes_for($modelName, $recordCount=1, $callback = nu $callback = $recordCount; $recordCount = 1; } - $model = ClassRegistry::init($modelName); - $results = self::getInstance()->_generateRecords($model->schema(), $recordCount, $callback); - return $results; + $factory = self::factory($modelName); + return $factory->attributes_for($recordCount, $callback); } - /** - * Generate String representation of Records - * - * @param array $tableInfo Table schema array - * @param integer $recordCount - * @return array Array of records. - */ - private function _generateRecords($tableInfo, $recordCount = 1, $callback) { - $world = new FabricateContext($this->config); - $records = array(); - for ($i = 0; $i < $recordCount; $i++) { - $record = array(); - foreach ($tableInfo as $field => $fieldInfo) { - if (empty($fieldInfo['type'])) { - continue; - } - $insert = ''; - switch ($fieldInfo['type']) { - case 'integer': - case 'float': - $insert = $this->config->sequence_start + $i; - break; - case 'string': - case 'binary': - $isPrimaryUuid = ( - isset($fieldInfo['key']) && strtolower($fieldInfo['key']) === 'primary' && - isset($fieldInfo['length']) && $fieldInfo['length'] == 36 - ); - if ($isPrimaryUuid) { - $insert = String::uuid(); - } else { - $insert = "Lorem ipsum dolor sit amet"; - if (!empty($fieldInfo['length'])) { - $insert = substr($insert, 0, (int)$fieldInfo['length'] - 2); - } - } - break; - case 'timestamp': - $insert = time(); - break; - case 'datetime': - $insert = date('Y-m-d H:i:s'); - break; - case 'date': - $insert = date('Y-m-d'); - break; - case 'time': - $insert = date('H:i:s'); - break; - case 'boolean': - $insert = 1; - break; - case 'text': - $insert = "Lorem ipsum dolor sit amet, aliquet feugiat."; - $insert .= " Convallis morbi fringilla gravida,"; - $insert .= " phasellus feugiat dapibus velit nunc, pulvinar eget sollicitudin"; - $insert .= " venenatis cum nullam, vivamus ut a sed, mollitia lectus. Nulla"; - $insert .= " vestibulum massa neque ut et, id hendrerit sit,"; - $insert .= " feugiat in taciti enim proin nibh, tempor dignissim, rhoncus"; - $insert .= " duis vestibulum nunc mattis convallis."; - break; - } - $record[$field] = $insert; - } - if(is_callable($callback)) { - $record = array_merge($record, $callback($record, $world)); - } else if(is_array($callback)) { - $record = array_merge($record, $callback); - } - $records[] = $record; - } - return $records; + private static function factory($name) { + $factory = FabricateFactory::create(self::getInstance()->registry->find($name)); + $factory->setConfig(self::getInstance()->config); + return $factory; } - - } \ No newline at end of file diff --git a/Lib/FabricateRegistry.php b/Lib/FabricateRegistry.php new file mode 100644 index 0000000..846934d --- /dev/null +++ b/Lib/FabricateRegistry.php @@ -0,0 +1,59 @@ +name = $name; + $this->items = []; + } + + /** + * Clear registerd entries + */ + public function clear() { + $this->items = []; + } + + /** + * Find from registred or model by name + * @param string $name + * @return mixed registerd object + */ + public function find($name) { + if($this->is_registered($name)) { + return $this->items[$name]; + } + $model = ClassRegistry::init($name, true); + if($model) { + return $model; + } + throw new InvalidArgumentException("{$name} not registered"); + } + + /** + * Regist to registries + * @param string $name + * @param FabricateDefinition $item + */ + public function register($name, $item) { + $this->items[$name] = $item; + } + + /** + * Is registered? + * @param string $name + * @return boolean + */ + private function is_registered($name) { + return array_key_exists($name, $this->items); + } +} diff --git a/Lib/Factory/FabricateAbstractFactory.php b/Lib/Factory/FabricateAbstractFactory.php new file mode 100644 index 0000000..26f9268 --- /dev/null +++ b/Lib/Factory/FabricateAbstractFactory.php @@ -0,0 +1,60 @@ +config = $config; + } + + /** + * Generate Records + * + * @param array $params fakeRecord parameter + * @param integer $recordCount + * @return array Array of records. + */ + protected function _generateRecords($params, $recordCount = 1, $callback) { + $world = new FabricateContext($this->config); + $records = array(); + for ($i = 0; $i < $recordCount; $i++) { + $record = $this->fakeRecord($params, $i); + + if(is_callable($callback)) { + $record = array_merge($record, $callback($record, $world)); + } else if(is_array($callback)) { + $record = array_merge($record, $callback); + } + $records[] = $record; + } + return $records; + } +} \ No newline at end of file diff --git a/Lib/Factory/FabricateDefinitionFactory.php b/Lib/Factory/FabricateDefinitionFactory.php new file mode 100644 index 0000000..52a8f82 --- /dev/null +++ b/Lib/Factory/FabricateDefinitionFactory.php @@ -0,0 +1,5 @@ +model = $model; + } + + public function create($attributes, $recordCount=1, $callback = null) { + foreach ($attributes as $data) { + $this->model->create($data); + $this->model->save(null, $this->config->auto_validate); + } + return $this->model; + } + public function build($data, $callback = null) { + $this->model->create($data[0]); + return $this->model; + } + public function attributes_for($recordCount=1, $callback = null) { + return $this->_generateRecords($this->model->schema(), $recordCount, $callback); + } + + protected function fakeRecord($tableInfo, $index) { + foreach ($tableInfo as $field => $fieldInfo) { + if (empty($fieldInfo['type'])) { + continue; + } + $insert = ''; + switch ($fieldInfo['type']) { + case 'integer': + case 'float': + $insert = $this->config->sequence_start + $index; + break; + case 'string': + case 'binary': + $isPrimaryUuid = ( + isset($fieldInfo['key']) && strtolower($fieldInfo['key']) === 'primary' && + isset($fieldInfo['length']) && $fieldInfo['length'] == 36 + ); + if ($isPrimaryUuid) { + $insert = String::uuid(); + } else { + $insert = "Lorem ipsum dolor sit amet"; + if (!empty($fieldInfo['length'])) { + $insert = substr($insert, 0, (int)$fieldInfo['length'] - 2); + } + } + break; + case 'timestamp': + $insert = time(); + break; + case 'datetime': + $insert = date('Y-m-d H:i:s'); + break; + case 'date': + $insert = date('Y-m-d'); + break; + case 'time': + $insert = date('H:i:s'); + break; + case 'boolean': + $insert = 1; + break; + case 'text': + $insert = "Lorem ipsum dolor sit amet, aliquet feugiat."; + $insert .= " Convallis morbi fringilla gravida,"; + $insert .= " phasellus feugiat dapibus velit nunc, pulvinar eget sollicitudin"; + $insert .= " venenatis cum nullam, vivamus ut a sed, mollitia lectus. Nulla"; + $insert .= " vestibulum massa neque ut et, id hendrerit sit,"; + $insert .= " feugiat in taciti enim proin nibh, tempor dignissim, rhoncus"; + $insert .= " duis vestibulum nunc mattis convallis."; + break; + } + $record[$field] = $insert; + } + return $record; + } +} \ No newline at end of file diff --git a/Lib/empty b/Lib/empty deleted file mode 100755 index e69de29..0000000 diff --git a/Test/Case/AllFabricateTest.php b/Test/Case/AllFabricateTest.php index 4334199..e3ec0b4 100644 --- a/Test/Case/AllFabricateTest.php +++ b/Test/Case/AllFabricateTest.php @@ -12,7 +12,7 @@ class AllFabricateTest extends PHPUnit_Framework_TestSuite { */ public static function suite() { $suite = new CakeTestSuite('All Fabricate Plugin related class tests'); - $suite->addTestDirectory(dirname(__FILE__).DS.'Lib'); + $suite->addTestDirectoryRecursive(dirname(__FILE__).DS.'Lib'); return $suite; } } diff --git a/Test/Case/Lib/Definition/FabricateDefinitionTest.php b/Test/Case/Lib/Definition/FabricateDefinitionTest.php new file mode 100644 index 0000000..350b104 --- /dev/null +++ b/Test/Case/Lib/Definition/FabricateDefinitionTest.php @@ -0,0 +1,21 @@ +assertEquals(['name'=>'taro'], $data); + $this->assertEquals('world', $world); + return ['name'=>'jiro']; + }); + $this->assertEquals(['name'=>'jiro'], $target->run(['name'=>'taro'], 'world')); + } + + public function testRunArrayDefinition() { + $target = new FabricateDefinition(['name'=>'jiro']); + $this->assertEquals(['name'=>'jiro'], $target->run(['name'=>'taro'], 'world')); + } +} \ No newline at end of file diff --git a/Test/Case/Lib/FabricateRegistryTest.php b/Test/Case/Lib/FabricateRegistryTest.php new file mode 100644 index 0000000..6c19a92 --- /dev/null +++ b/Test/Case/Lib/FabricateRegistryTest.php @@ -0,0 +1,48 @@ +Registry = new FabricateRegistry('FabricateRegistry'); + } + + public function testFindIfNotRegisterdAndExistsModel() { + $this->assertInstanceOf('FabricateRegistryTestPost', $this->Registry->find('FabricateRegistryTestPost')); + } + + public function testFindIfRegisteredObject() { + $this->Registry->register('FabricateRegistryTestComment', 'dummy'); + $this->assertEquals('dummy', $this->Registry->find('FabricateRegistryTestComment')); + } + + public function testFindIfRegisteredObjectOverwriteExistsModel() { + $this->Registry->register('FabricateRegistryTestPost', 'dummy'); + $this->assertEquals('dummy', $this->Registry->find('FabricateRegistryTestPost')); + } + + /** + * @expectedException InvalidArgumentException + */ + public function testFindThrowExceptionIfNotRegistered() { + $this->Registry->find('NotRegistered'); + } + + /** + * @expectedException InvalidArgumentException + */ + public function testFindThrowExceptionIfRegisteredObjectCleared() { + $this->Registry->register('FabricateRegistryTestComment', 'dummy'); + $this->Registry->clear(); + $this->Registry->find('FabricateRegistryTestComment'); + } +} \ No newline at end of file diff --git a/Test/Case/Lib/Factory/FabricateFactoryTest.php b/Test/Case/Lib/Factory/FabricateFactoryTest.php new file mode 100644 index 0000000..c777ed1 --- /dev/null +++ b/Test/Case/Lib/Factory/FabricateFactoryTest.php @@ -0,0 +1,30 @@ +assertInstanceOf('FabricateModelFactory', FabricateFactory::create(ClassRegistry::init('FabricateFactoryTestPost'))); + } + + public function testCreateDefinitionFactory() { + $this->assertInstanceOf('FabricateDefinitionFactory', FabricateFactory::create(new FabricateDefinition([]))); + } + + /** + * @expectedException InvalidArgumentException + */ + public function testCreateThrowExceptionIfNotSupportInstance() { + FabricateFactory::create('Not Supported'); + } +} \ No newline at end of file From 8d45b837fda1668382c8e3596d88ac715ffe0c02 Mon Sep 17 00:00:00 2001 From: sizuhiko Date: Sat, 31 May 2014 21:53:43 +0900 Subject: [PATCH 03/13] WIP Fix test failure --- Lib/Definition/FabricateDefinition.php | 1 + Lib/Fabricate.php | 30 ++++++++++++++----- Lib/Factory/FabricateAbstractFactory.php | 24 +++++++-------- Lib/Factory/FabricateModelFactory.php | 8 ++--- .../Definition/FabricateDefinitionTest.php | 5 ++++ 5 files changed, 44 insertions(+), 24 deletions(-) diff --git a/Lib/Definition/FabricateDefinition.php b/Lib/Definition/FabricateDefinition.php index 29e3627..08b6952 100644 --- a/Lib/Definition/FabricateDefinition.php +++ b/Lib/Definition/FabricateDefinition.php @@ -14,6 +14,7 @@ public function __construct($define) { } public function run($data, $world) { + $result = []; if(is_callable($this->define)) { $callback = $this->define; $result = $callback($data, $world); diff --git a/Lib/Fabricate.php b/Lib/Fabricate.php index 6d7c3a9..ebe8a28 100755 --- a/Lib/Fabricate.php +++ b/Lib/Fabricate.php @@ -3,6 +3,7 @@ App::uses('FabricateContext', 'Fabricate.Lib'); App::uses('FabricateRegistry', 'Fabricate.Lib'); App::uses('FabricateFactory', 'Fabricate.Lib/Factory'); +App::uses('FabricateDefinition', 'Fabricate.Lib/Definition'); /** * Fabricator for CakePHP model. @@ -48,7 +49,9 @@ public static function config($callback) { public static function create($modelName, $recordCount=1, $callback = null) { $attributes = self::attributes_for($modelName, $recordCount, $callback); $factory = self::factory($modelName); - return $factory->create($attributes, $recordCount, $callback); + $definition = self::definition($recordCount, $callback); + $recordCount = self::recordCount($recordCount); + return $factory->create($attributes, $recordCount, $definition); } /** * Only create a model instance. @@ -59,19 +62,18 @@ public static function create($modelName, $recordCount=1, $callback = null) { public static function build($modelName, $callback = null) { $data = self::attributes_for($modelName, 1, $callback); $factory = self::factory($modelName); - return $factory->build($data, $callback); + $definition = self::definition(1, $callback); + return $factory->build($data, $definition); } /** * Only create model attributes array. * @return array model attributes array. */ public static function attributes_for($modelName, $recordCount=1, $callback = null) { - if(is_callable($recordCount) || is_array($recordCount)) { - $callback = $recordCount; - $recordCount = 1; - } $factory = self::factory($modelName); - return $factory->attributes_for($recordCount, $callback); + $definition = self::definition($recordCount, $callback); + $recordCount = self::recordCount($recordCount); + return $factory->attributes_for($recordCount, $definition); } private static function factory($name) { @@ -79,4 +81,18 @@ private static function factory($name) { $factory->setConfig(self::getInstance()->config); return $factory; } + + private static function recordCount($recordCount) { + if(is_callable($recordCount) || is_array($recordCount)) { + $recordCount = 1; + } + return $recordCount; + } + + private static function definition($recordCount, $callback) { + if(is_callable($recordCount) || is_array($recordCount)) { + $callback = $recordCount; + } + return new FabricateDefinition($callback); + } } \ No newline at end of file diff --git a/Lib/Factory/FabricateAbstractFactory.php b/Lib/Factory/FabricateAbstractFactory.php index 26f9268..2040a5e 100644 --- a/Lib/Factory/FabricateAbstractFactory.php +++ b/Lib/Factory/FabricateAbstractFactory.php @@ -6,21 +6,23 @@ abstract class FabricateAbstractFactory { * Create and Save fablicated model data to database. * @param array $attributes * @param integer $recordCount count for creating. - * @param mixed $callback callback or array can change fablicated data if you want to overwrite + * @param FabricateDefinition $definition */ - abstract public function create($attributes, $recordCount=1, $callback = null); + abstract public function create($attributes, $recordCount, $definition); /** * Only create a model instance. * @param mixed $data - * @param $callback function callback can chenge fablicated data if you want to overwrite - * @return Model Initializes the model for writing a new record + * @param FabricateDefinition $definition + * @return mided */ - abstract public function build($data, $callback = null); + abstract public function build($data, $definition); /** * Only create model attributes array. + * @param integer $recordCount count for creating. + * @param FabricateDefinition $definition * @return array model attributes array. */ - abstract public function attributes_for($recordCount=1, $callback = null); + abstract public function attributes_for($recordCount, $definition); /** * Fake a record * @param mixed $params _generateRecords params attribute @@ -40,19 +42,15 @@ public function setConfig($config) { * * @param array $params fakeRecord parameter * @param integer $recordCount + * @param FabricateDefinition $definition * @return array Array of records. */ - protected function _generateRecords($params, $recordCount = 1, $callback) { + protected function _generateRecords($params, $recordCount, $definition) { $world = new FabricateContext($this->config); $records = array(); for ($i = 0; $i < $recordCount; $i++) { $record = $this->fakeRecord($params, $i); - - if(is_callable($callback)) { - $record = array_merge($record, $callback($record, $world)); - } else if(is_array($callback)) { - $record = array_merge($record, $callback); - } + $record = array_merge($record, $definition->run($record, $world)); $records[] = $record; } return $records; diff --git a/Lib/Factory/FabricateModelFactory.php b/Lib/Factory/FabricateModelFactory.php index dcba135..daa7c1d 100644 --- a/Lib/Factory/FabricateModelFactory.php +++ b/Lib/Factory/FabricateModelFactory.php @@ -8,19 +8,19 @@ public function __construct($model) { $this->model = $model; } - public function create($attributes, $recordCount=1, $callback = null) { + public function create($attributes, $recordCount, $definition) { foreach ($attributes as $data) { $this->model->create($data); $this->model->save(null, $this->config->auto_validate); } return $this->model; } - public function build($data, $callback = null) { + public function build($data, $definition) { $this->model->create($data[0]); return $this->model; } - public function attributes_for($recordCount=1, $callback = null) { - return $this->_generateRecords($this->model->schema(), $recordCount, $callback); + public function attributes_for($recordCount, $definition) { + return $this->_generateRecords($this->model->schema(), $recordCount, $definition); } protected function fakeRecord($tableInfo, $index) { diff --git a/Test/Case/Lib/Definition/FabricateDefinitionTest.php b/Test/Case/Lib/Definition/FabricateDefinitionTest.php index 350b104..e3e1506 100644 --- a/Test/Case/Lib/Definition/FabricateDefinitionTest.php +++ b/Test/Case/Lib/Definition/FabricateDefinitionTest.php @@ -18,4 +18,9 @@ public function testRunArrayDefinition() { $target = new FabricateDefinition(['name'=>'jiro']); $this->assertEquals(['name'=>'jiro'], $target->run(['name'=>'taro'], 'world')); } + + public function testRunNullDefinition() { + $target = new FabricateDefinition(null); + $this->assertEquals([], $target->run(['name'=>'taro'], 'world')); + } } \ No newline at end of file From 0bd28b2fc59fc35faf4448815c1e25ff720bf87d Mon Sep 17 00:00:00 2001 From: sizuhiko Date: Sun, 1 Jun 2014 13:09:21 +0900 Subject: [PATCH 04/13] change function from static to instance --- Lib/Fabricate.php | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/Lib/Fabricate.php b/Lib/Fabricate.php index ebe8a28..87c0b17 100755 --- a/Lib/Fabricate.php +++ b/Lib/Fabricate.php @@ -13,6 +13,7 @@ class Fabricate { private static $_instance = null; private $config; private $registry; + private $factory; /** * Return Fabricator instance @@ -48,10 +49,10 @@ public static function config($callback) { */ public static function create($modelName, $recordCount=1, $callback = null) { $attributes = self::attributes_for($modelName, $recordCount, $callback); - $factory = self::factory($modelName); - $definition = self::definition($recordCount, $callback); - $recordCount = self::recordCount($recordCount); - return $factory->create($attributes, $recordCount, $definition); + $instance = self::getInstance(); + $definition = $instance->definition($recordCount, $callback); + $recordCount = $instance->recordCount($recordCount); + return $instance->factory->create($attributes, $recordCount, $definition); } /** * Only create a model instance. @@ -61,35 +62,36 @@ public static function create($modelName, $recordCount=1, $callback = null) { */ public static function build($modelName, $callback = null) { $data = self::attributes_for($modelName, 1, $callback); - $factory = self::factory($modelName); - $definition = self::definition(1, $callback); - return $factory->build($data, $definition); + $instance = self::getInstance(); + $definition = $instance->definition(1, $callback); + return $instance->factory->build($data, $definition); } /** * Only create model attributes array. * @return array model attributes array. */ public static function attributes_for($modelName, $recordCount=1, $callback = null) { - $factory = self::factory($modelName); - $definition = self::definition($recordCount, $callback); - $recordCount = self::recordCount($recordCount); - return $factory->attributes_for($recordCount, $definition); + $instance = self::getInstance(); + $instance->factory = $instance->factory($modelName); + $definition = $instance->definition($recordCount, $callback); + $recordCount = $instance->recordCount($recordCount); + return $instance->factory->attributes_for($recordCount, $definition); } - private static function factory($name) { + private function factory($name) { $factory = FabricateFactory::create(self::getInstance()->registry->find($name)); $factory->setConfig(self::getInstance()->config); return $factory; } - private static function recordCount($recordCount) { + private function recordCount($recordCount) { if(is_callable($recordCount) || is_array($recordCount)) { $recordCount = 1; } return $recordCount; } - private static function definition($recordCount, $callback) { + private function definition($recordCount, $callback) { if(is_callable($recordCount) || is_array($recordCount)) { $callback = $recordCount; } From 4bdf3c2feecbc67bff6d7af882c10eee789319a9 Mon Sep 17 00:00:00 2001 From: sizuhiko Date: Sun, 1 Jun 2014 16:44:07 +0900 Subject: [PATCH 05/13] Implement define feature --- Lib/Definition/FabricateDefinition.php | 1 + Lib/Fabricate.php | 33 +++++++++++++++++++ Lib/FabricateRegistry.php | 2 +- Lib/Factory/FabricateAbstractFactory.php | 11 +++++-- Lib/Factory/FabricateDefinitionFactory.php | 37 ++++++++++++++++++++-- Test/Case/Lib/FabricateTest.php | 28 ++++++++++++++++ 6 files changed, 106 insertions(+), 6 deletions(-) diff --git a/Lib/Definition/FabricateDefinition.php b/Lib/Definition/FabricateDefinition.php index 08b6952..56f5a66 100644 --- a/Lib/Definition/FabricateDefinition.php +++ b/Lib/Definition/FabricateDefinition.php @@ -5,6 +5,7 @@ */ class FabricateDefinition { private $define = false; + public $parent = false; /** * @param mixed $define callback or attributes diff --git a/Lib/Fabricate.php b/Lib/Fabricate.php index 87c0b17..92b118e 100755 --- a/Lib/Fabricate.php +++ b/Lib/Fabricate.php @@ -78,6 +78,39 @@ public static function attributes_for($modelName, $recordCount=1, $callback = nu return $instance->factory->attributes_for($recordCount, $definition); } + /** + * @param mixed $name + * @param mixed $define + */ + public static function define($name, $define) { + $instance = self::getInstance(); + $parent = false; + $base = false; + if(is_array($name)) { + $parent = array_key_exists('parent', $name)?$name['parent']:false; + $base = array_key_exists('class', $name)?$name['class']:false; + $name = $name[0]; + } + if(empty($name)) { + throw new InvalidArgumentException("name is empty"); + } + if($parent && !$instance->registry->is_registered($parent)) { + throw new InvalidArgumentException("parent `{$parent}` is not registered"); + } + if($base && in_array(ClassRegistry::init($base, true),[false, null])) { + throw new InvalidArgumentException("class `{$base}` is not found"); + } + if(!$parent && !$base) { + $base = $name; + } + $definition = new FabricateDefinition($define); + $definition->parent = $parent?FabricateFactory::create($instance->registry->find($parent)):false; + $definition->parent = $base?FabricateFactory::create(ClassRegistry::init($base)):$definition->parent; + $definition->parent->setConfig(self::getInstance()->config); + + $instance->registry->register($name, $definition); + } + private function factory($name) { $factory = FabricateFactory::create(self::getInstance()->registry->find($name)); $factory->setConfig(self::getInstance()->config); diff --git a/Lib/FabricateRegistry.php b/Lib/FabricateRegistry.php index 846934d..7a89c87 100644 --- a/Lib/FabricateRegistry.php +++ b/Lib/FabricateRegistry.php @@ -53,7 +53,7 @@ public function register($name, $item) { * @param string $name * @return boolean */ - private function is_registered($name) { + public function is_registered($name) { return array_key_exists($name, $this->items); } } diff --git a/Lib/Factory/FabricateAbstractFactory.php b/Lib/Factory/FabricateAbstractFactory.php index 2040a5e..8fdce00 100644 --- a/Lib/Factory/FabricateAbstractFactory.php +++ b/Lib/Factory/FabricateAbstractFactory.php @@ -42,15 +42,20 @@ public function setConfig($config) { * * @param array $params fakeRecord parameter * @param integer $recordCount - * @param FabricateDefinition $definition + * @param mixed $definition FabricateDefinition(s) * @return array Array of records. */ - protected function _generateRecords($params, $recordCount, $definition) { + protected function _generateRecords($params, $recordCount, $definitions) { $world = new FabricateContext($this->config); + if(!is_array($definitions)) { + $definitions = [$definitions]; + } $records = array(); for ($i = 0; $i < $recordCount; $i++) { $record = $this->fakeRecord($params, $i); - $record = array_merge($record, $definition->run($record, $world)); + foreach ($definitions as $definition) { + $record = array_merge($record, $definition->run($record, $world)); + } $records[] = $record; } return $records; diff --git a/Lib/Factory/FabricateDefinitionFactory.php b/Lib/Factory/FabricateDefinitionFactory.php index 52a8f82..3002a17 100644 --- a/Lib/Factory/FabricateDefinitionFactory.php +++ b/Lib/Factory/FabricateDefinitionFactory.php @@ -1,5 +1,38 @@ definition = $definition; + } + + public function create($attributes, $recordCount, $definition) { + if($this->definition->parent) { + return $this->definition->parent->create($attributes, $recordCount, $definition); + } + return; + } + public function build($data, $definition) { + if($this->definition->parent) { + return $this->definition->parent->build($attributes, $definition); + } + return; + } + public function attributes_for($recordCount, $definition) { + if($this->definition->parent) { + if(is_array($definition)) { + $definitions = $definition; + } else { + $definitions = [$definition]; + } + array_unshift($definitions, $this->definition); + return $this->definition->parent->attributes_for($recordCount, $definitions); + } + return $this->_generateRecords([], $recordCount, $definition); + } + + protected function fakeRecord($params, $index) { + return []; + } } \ No newline at end of file diff --git a/Test/Case/Lib/FabricateTest.php b/Test/Case/Lib/FabricateTest.php index c992722..0534d46 100755 --- a/Test/Case/Lib/FabricateTest.php +++ b/Test/Case/Lib/FabricateTest.php @@ -143,6 +143,34 @@ public function testCreateUsingSequence() { $this->assertEquals('Title 10', $results[9]['title']); } + /** + * @dataProvider exampleInvalidDefineParameter + * @expectedException InvalidArgumentException + */ + public function testDefineThrowExceptionIfInvalidParameter($name, $case) { + Fabricate::define($name, ['title'=>'title'], $case); + } + public function exampleInvalidDefineParameter() { + return [ + ['', 'Empty name'], + [['', 'class'=>'Post'], 'Empty name'], + [['Test', 'parent'=>'NotDefine'], 'No defined parent'], + [['Author', 'class'=>'User'], 'Not found class'], + ]; + } + public function testDefineUseClassOption() { + Fabricate::define(['PublishedPost', 'class'=>'Post'], ['published'=>'1']); + $results = Fabricate::attributes_for('PublishedPost'); + $this->assertEquals('1', $results[0]['published']); + } + + public function testDefineUseNestedOption() { + Fabricate::define(['PublishedPost', 'class'=>'Post'], ['published'=>'1']); + Fabricate::define(['Author5PublishedPost', 'parent'=>'PublishedPost'], ['author_id'=>'5']); + $results = Fabricate::attributes_for('Author5PublishedPost'); + $this->assertEquals('1', $results[0]['published']); + $this->assertEquals('5', $results[0]['author_id']); + } } From 72e5441712046d0d776737d2d68bbb9a0672e9b0 Mon Sep 17 00:00:00 2001 From: sizuhiko Date: Sun, 1 Jun 2014 17:05:22 +0900 Subject: [PATCH 06/13] Add filter key config --- Lib/Fabricate.php | 4 ++++ Lib/FabricateConfig.php | 1 + Lib/Factory/FabricateModelFactory.php | 4 ++-- Test/Case/Lib/FabricateTest.php | 15 +++++++++++++++ 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/Lib/Fabricate.php b/Lib/Fabricate.php index 92b118e..5f1f925 100755 --- a/Lib/Fabricate.php +++ b/Lib/Fabricate.php @@ -33,6 +33,10 @@ private static function getInstance() { public function __construct() { } + public static function clear() { + self::$_instance = null; + } + /** * To override these settings * @param $callback($config) can override $config(class of FabricateConfig) attributes diff --git a/Lib/FabricateConfig.php b/Lib/FabricateConfig.php index 953e929..a45482a 100644 --- a/Lib/FabricateConfig.php +++ b/Lib/FabricateConfig.php @@ -6,4 +6,5 @@ class FabricateConfig { public $sequence_start = 1; public $auto_validate = false; + public $filter_key = false; } \ No newline at end of file diff --git a/Lib/Factory/FabricateModelFactory.php b/Lib/Factory/FabricateModelFactory.php index daa7c1d..4743f62 100644 --- a/Lib/Factory/FabricateModelFactory.php +++ b/Lib/Factory/FabricateModelFactory.php @@ -10,13 +10,13 @@ public function __construct($model) { public function create($attributes, $recordCount, $definition) { foreach ($attributes as $data) { - $this->model->create($data); + $this->model->create($data, $this->config->filter_key); $this->model->save(null, $this->config->auto_validate); } return $this->model; } public function build($data, $definition) { - $this->model->create($data[0]); + $this->model->create($data[0], $this->config->filter_key); return $this->model; } public function attributes_for($recordCount, $definition) { diff --git a/Test/Case/Lib/FabricateTest.php b/Test/Case/Lib/FabricateTest.php index 0534d46..f807a2c 100755 --- a/Test/Case/Lib/FabricateTest.php +++ b/Test/Case/Lib/FabricateTest.php @@ -16,6 +16,11 @@ class Post extends CakeTestModel { class FabricateTest extends CakeTestCase { public $fixtures = ['plugin.fabricate.post']; + public function setUp() { + parent::setUp(); + Fabricate::clear(); + } + public function testAttributesFor() { $results = Fabricate::attributes_for('Post', 10, function($data){ return ["created" => "2013-10-09 12:40:28", "updated" => "2013-10-09 12:40:28"]; @@ -173,4 +178,14 @@ public function testDefineUseNestedOption() { $this->assertEquals('5', $results[0]['author_id']); } + public function testCreateOverwritesAnyPrimaryKeyInputWithAnEmptyIfFilterKeyIsTrue() { + Fabricate::config(function($config) { + $config->filter_key = true; + }); + Fabricate::create('Post', ["id"=>5,"created" => "2013-10-09 12:40:28", "updated" => "2013-10-09 12:40:28"]); + $model = ClassRegistry::init('Post'); + $results = $model->find('all'); + $this->assertEquals(1, $results[0]['Post']['id']); + } + } From 290efc4d9906e914987821cb4f6e427431ceac9f Mon Sep 17 00:00:00 2001 From: sizuhiko Date: Sun, 1 Jun 2014 17:12:27 +0900 Subject: [PATCH 07/13] add define name only test case --- Test/Case/Lib/FabricateTest.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Test/Case/Lib/FabricateTest.php b/Test/Case/Lib/FabricateTest.php index f807a2c..459378d 100755 --- a/Test/Case/Lib/FabricateTest.php +++ b/Test/Case/Lib/FabricateTest.php @@ -188,4 +188,10 @@ public function testCreateOverwritesAnyPrimaryKeyInputWithAnEmptyIfFilterKeyIsTr $this->assertEquals(1, $results[0]['Post']['id']); } + public function testDefineNameOnlyOption() { + Fabricate::define('Post', ['published'=>'1']); + $results = Fabricate::attributes_for('Post'); + $this->assertEquals('1', $results[0]['published']); + } + } From 3f8a21cefb2e8632c9ed22cc4efed816b4928b04 Mon Sep 17 00:00:00 2001 From: sizuhiko Date: Wed, 4 Jun 2014 01:33:11 +0900 Subject: [PATCH 08/13] Support deep association save --- Lib/Fabricate.php | 12 ++++++++ Lib/Factory/FabricateModelFactory.php | 5 +++- Test/Case/Lib/FabricateTest.php | 35 +++++++++++++++++++++-- Test/Fixture/UserFixture.php | 40 +++++++++++++++++++++++++++ 4 files changed, 89 insertions(+), 3 deletions(-) create mode 100644 Test/Fixture/UserFixture.php diff --git a/Lib/Fabricate.php b/Lib/Fabricate.php index 5f1f925..9e9a8fb 100755 --- a/Lib/Fabricate.php +++ b/Lib/Fabricate.php @@ -82,6 +82,18 @@ public static function attributes_for($modelName, $recordCount=1, $callback = nu return $instance->factory->attributes_for($recordCount, $definition); } + /** + * Only create model attributes array for association. + * @return array model attributes array. + */ + public static function association($modelName, $recordCount=1, $callback = null) { + $instance = self::getInstance(); + $factory = $instance->factory($modelName); + $definition = $instance->definition($recordCount, $callback); + $recordCount = $instance->recordCount($recordCount); + return $factory->attributes_for($recordCount, $definition); + } + /** * @param mixed $name * @param mixed $define diff --git a/Lib/Factory/FabricateModelFactory.php b/Lib/Factory/FabricateModelFactory.php index 4743f62..fad650b 100644 --- a/Lib/Factory/FabricateModelFactory.php +++ b/Lib/Factory/FabricateModelFactory.php @@ -11,7 +11,10 @@ public function __construct($model) { public function create($attributes, $recordCount, $definition) { foreach ($attributes as $data) { $this->model->create($data, $this->config->filter_key); - $this->model->save(null, $this->config->auto_validate); + $this->model->saveAssociated(null, [ + 'validate' => $this->config->auto_validate, + 'deep' => true, + ]); } return $this->model; } diff --git a/Test/Case/Lib/FabricateTest.php b/Test/Case/Lib/FabricateTest.php index 459378d..23b79c3 100755 --- a/Test/Case/Lib/FabricateTest.php +++ b/Test/Case/Lib/FabricateTest.php @@ -2,19 +2,33 @@ App::uses('Fabricate', 'Fabricate.Lib'); +/** + * User class + * + * @package Cake.Test.Case.Model + */ +class User extends CakeTestModel { + public $hasMany = [ + 'Post' => ['foreignKey' => 'author_id'] + ]; +} + /** * Post class * * @package Cake.Test.Case.Model */ class Post extends CakeTestModel { + public $belongsTo = [ + 'Author' => ['className' => 'User', 'foreignKey' => 'author_id'], + ]; } /** * Fabricate class test case */ class FabricateTest extends CakeTestCase { - public $fixtures = ['plugin.fabricate.post']; + public $fixtures = ['plugin.fabricate.post', 'plugin.fabricate.user']; public function setUp() { parent::setUp(); @@ -160,7 +174,7 @@ public function exampleInvalidDefineParameter() { ['', 'Empty name'], [['', 'class'=>'Post'], 'Empty name'], [['Test', 'parent'=>'NotDefine'], 'No defined parent'], - [['Author', 'class'=>'User'], 'Not found class'], + [['Manager', 'class'=>'Person'], 'Not found class'], ]; } @@ -194,4 +208,21 @@ public function testDefineNameOnlyOption() { $this->assertEquals('1', $results[0]['published']); } + public function testSaveWithAssociation() { + Fabricate::define(['PublishedPost', 'class'=>'Post'], ['published'=>'1']); + Fabricate::create('User', function($data, $world) { + $ret = [ + 'user' => 'taro', + 'Post' => Fabricate::association('PublishedPost', 3, ['id'=>false,'author_id'=>false]), + ]; + return $ret; + }); + + $model = ClassRegistry::init('User'); + $results = $model->find('first', ['contain'=>['Post']]); + $this->assertEquals('taro', $results['User']['user']); + $this->assertCount(3, $results['Post']); + } + + } diff --git a/Test/Fixture/UserFixture.php b/Test/Fixture/UserFixture.php new file mode 100644 index 0000000..3b06657 --- /dev/null +++ b/Test/Fixture/UserFixture.php @@ -0,0 +1,40 @@ + + * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * For full copyright and license information, please see the LICENSE.txt + * Redistributions of files must retain the above copyright notice + * + * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://book.cakephp.org/2.0/en/development/testing.html CakePHP(tm) Tests + * @package Cake.Test.Fixture + * @since CakePHP(tm) v 1.2.0.4667 + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +/** + * Class UserFixture + * + * @package Cake.Test.Fixture + */ +class UserFixture extends CakeTestFixture { + +/** + * fields property + * + * @var array + */ + public $fields = array( + 'id' => array('type' => 'integer', 'key' => 'primary'), + 'user' => array('type' => 'string', 'null' => true), + 'password' => array('type' => 'string', 'null' => true), + 'created' => 'datetime', + 'updated' => 'datetime' + ); +} From cd4da3206342317fbf3e6c438c072779eafdc3d1 Mon Sep 17 00:00:00 2001 From: sizuhiko Date: Wed, 4 Jun 2014 23:36:50 +0900 Subject: [PATCH 09/13] fix return to one liner --- Test/Case/Lib/FabricateTest.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Test/Case/Lib/FabricateTest.php b/Test/Case/Lib/FabricateTest.php index 23b79c3..f45116c 100755 --- a/Test/Case/Lib/FabricateTest.php +++ b/Test/Case/Lib/FabricateTest.php @@ -211,11 +211,10 @@ public function testDefineNameOnlyOption() { public function testSaveWithAssociation() { Fabricate::define(['PublishedPost', 'class'=>'Post'], ['published'=>'1']); Fabricate::create('User', function($data, $world) { - $ret = [ + return [ 'user' => 'taro', 'Post' => Fabricate::association('PublishedPost', 3, ['id'=>false,'author_id'=>false]), ]; - return $ret; }); $model = ClassRegistry::init('User'); From 5f3d5a8cd9e07225e1b1cf390b44d1156391b091 Mon Sep 17 00:00:00 2001 From: sizuhiko Date: Thu, 5 Jun 2014 01:20:58 +0900 Subject: [PATCH 10/13] Add trait feature --- Lib/Fabricate.php | 25 +++++++++++++++-- Lib/FabricateContext.php | 27 ++++++++++++++++++ Lib/Factory/FabricateAbstractFactory.php | 25 ++++++++++++++--- Test/Case/Lib/FabricateTest.php | 35 ++++++++++++++++++++++++ 4 files changed, 106 insertions(+), 6 deletions(-) diff --git a/Lib/Fabricate.php b/Lib/Fabricate.php index 9e9a8fb..551a08e 100755 --- a/Lib/Fabricate.php +++ b/Lib/Fabricate.php @@ -14,6 +14,7 @@ class Fabricate { private $config; private $registry; private $factory; + private $traits; /** * Return Fabricator instance @@ -23,6 +24,7 @@ private static function getInstance() { self::$_instance = new Fabricate(); self::$_instance->config = new FabricateConfig(); self::$_instance->registry = new FabricateRegistry('Fabricate'); + self::$_instance->traits = []; } return self::$_instance; } @@ -94,6 +96,14 @@ public static function association($modelName, $recordCount=1, $callback = null) return $factory->attributes_for($recordCount, $definition); } + /** + * Return defined traits. + * @return array registed trait definition + */ + public static function traits() { + return self::getInstance()->traits; + } + /** * @param mixed $name * @param mixed $define @@ -102,10 +112,17 @@ public static function define($name, $define) { $instance = self::getInstance(); $parent = false; $base = false; + $trait = false; if(is_array($name)) { $parent = array_key_exists('parent', $name)?$name['parent']:false; $base = array_key_exists('class', $name)?$name['class']:false; - $name = $name[0]; + if(array_key_exists('trait', $name)) { + $name = $name['trait']; + $parent = $base = false; + $trait = true; + } else { + $name = $name[0]; + } } if(empty($name)) { throw new InvalidArgumentException("name is empty"); @@ -116,10 +133,14 @@ public static function define($name, $define) { if($base && in_array(ClassRegistry::init($base, true),[false, null])) { throw new InvalidArgumentException("class `{$base}` is not found"); } + $definition = new FabricateDefinition($define); + if($trait) { + $instance->traits[$name] = $definition; + return; + } if(!$parent && !$base) { $base = $name; } - $definition = new FabricateDefinition($define); $definition->parent = $parent?FabricateFactory::create($instance->registry->find($parent)):false; $definition->parent = $base?FabricateFactory::create(ClassRegistry::init($base)):$definition->parent; $definition->parent->setConfig(self::getInstance()->config); diff --git a/Lib/FabricateContext.php b/Lib/FabricateContext.php index a9126de..12eda79 100644 --- a/Lib/FabricateContext.php +++ b/Lib/FabricateContext.php @@ -11,6 +11,10 @@ class FabricateContext { * Sequence Hash map */ private $sequences = []; + /** + * Trait use array + */ + private $traits = []; /** * Fabricate config */ @@ -50,4 +54,27 @@ public function sequence($name, $start=null, $callback=null) { $this->sequences[$name]->next(); return $ret; } + + /** + * Add apply trait in the scope. + * @param string|array $name use trait name(s) + */ + public function traits($name) { + if(is_array($name)) { + $this->traits = array_merge($this->traits, $name); + } else { + $this->traits[] = $name; + } + } + + /** + * Flush trait stack in the scope + * @return array flushed trait stack + */ + public function flashTraits() { + $traits = $this->traits; + $this->traits = []; + return $traits; + } + } \ No newline at end of file diff --git a/Lib/Factory/FabricateAbstractFactory.php b/Lib/Factory/FabricateAbstractFactory.php index 8fdce00..a191a96 100644 --- a/Lib/Factory/FabricateAbstractFactory.php +++ b/Lib/Factory/FabricateAbstractFactory.php @@ -53,11 +53,28 @@ protected function _generateRecords($params, $recordCount, $definitions) { $records = array(); for ($i = 0; $i < $recordCount; $i++) { $record = $this->fakeRecord($params, $i); - foreach ($definitions as $definition) { - $record = array_merge($record, $definition->run($record, $world)); - } - $records[] = $record; + $records[] = $this->applyNestedDefinitions($definitions, $record, $world); } return $records; } + + private function applyNestedDefinitions($definitions, $record, $world) { + foreach ($definitions as $definition) { + $result = $definition->run($record, $world); + $record = $this->applyTraits($record, $world); + $record = array_merge($record, $result); + } + return $record; + } + + private function applyTraits($record, $world) { + foreach ($world->flashTraits() as $use) { + $traits = Fabricate::traits(); + if(array_key_exists($use, $traits)) { + $record = array_merge($record, $traits[$use]->run($record, $world)); + } + } + return $record; + } + } \ No newline at end of file diff --git a/Test/Case/Lib/FabricateTest.php b/Test/Case/Lib/FabricateTest.php index f45116c..b56758f 100755 --- a/Test/Case/Lib/FabricateTest.php +++ b/Test/Case/Lib/FabricateTest.php @@ -223,5 +223,40 @@ public function testSaveWithAssociation() { $this->assertCount(3, $results['Post']); } + public function testDefineAndUseTrait() { + Fabricate::define(['trait'=>'published'], ['published'=>'1']); + $results = Fabricate::attributes_for('Post', function($data, $world) { + $world->traits('published'); + return ['id'=>false]; + }); + $this->assertEquals('1', $results[0]['published']); + } + + public function testDefineAndUseMultiTrait() { + Fabricate::define(['trait'=>'published'], ['published'=>'1']); + Fabricate::define(['trait'=>'author5'], function($data, $world) { return ['author_id'=>5]; }); + $results = Fabricate::attributes_for('Post', function($data, $world) { + $world->traits(['published','author5']); + return ['id'=>false]; + }); + $this->assertEquals('1', $results[0]['published']); + $this->assertEquals(5, $results[0]['author_id']); + } + + public function testDefineAndAssociationAndTraits() { + Fabricate::define(['trait'=>'published'], ['published'=>'1']); + Fabricate::define(['PublishedPost', 'class'=>'Post'], function($data, $world) { return ['published'=>'1']; }); + Fabricate::create('User', function($data, $world) { + return [ + 'user' => 'taro', + 'Post' => Fabricate::association('PublishedPost', 3, ['id'=>false,'author_id'=>false]), + ]; + }); + + $model = ClassRegistry::init('User'); + $results = $model->find('first', ['contain'=>['Post']]); + $this->assertEquals('taro', $results['User']['user']); + $this->assertEquals(['1','1','1'], Hash::extract($results, 'Post.{n}.published')); + } } From 528cdac3494338050b6d78be757ce6d18cd25e6a Mon Sep 17 00:00:00 2001 From: sizuhiko Date: Thu, 5 Jun 2014 01:26:28 +0900 Subject: [PATCH 11/13] fix combine test case --- Test/Case/Lib/FabricateTest.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Test/Case/Lib/FabricateTest.php b/Test/Case/Lib/FabricateTest.php index b56758f..e147a9b 100755 --- a/Test/Case/Lib/FabricateTest.php +++ b/Test/Case/Lib/FabricateTest.php @@ -245,7 +245,10 @@ public function testDefineAndUseMultiTrait() { public function testDefineAndAssociationAndTraits() { Fabricate::define(['trait'=>'published'], ['published'=>'1']); - Fabricate::define(['PublishedPost', 'class'=>'Post'], function($data, $world) { return ['published'=>'1']; }); + Fabricate::define(['PublishedPost', 'class'=>'Post'], function($data, $world) { + $world->traits('published'); + return ['title'=>$world->sequence('title',function($i) { return "Title{$i}"; })]; + }); Fabricate::create('User', function($data, $world) { return [ 'user' => 'taro', @@ -257,6 +260,7 @@ public function testDefineAndAssociationAndTraits() { $results = $model->find('first', ['contain'=>['Post']]); $this->assertEquals('taro', $results['User']['user']); $this->assertEquals(['1','1','1'], Hash::extract($results, 'Post.{n}.published')); + $this->assertEquals(['Title1','Title2','Title3'], Hash::extract($results, 'Post.{n}.title')); } } From 2447b6b82721a70611b88ff43ceab4ecccb50e54 Mon Sep 17 00:00:00 2001 From: sizuhiko Date: Thu, 5 Jun 2014 21:31:58 +0900 Subject: [PATCH 12/13] add App::uses, and fix code highlight --- README.md | 174 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 101 insertions(+), 73 deletions(-) diff --git a/README.md b/README.md index a478b48..e02199e 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Fabricate CakePHP data generator for Testing -It's inspired on [Fabrication](https://github.com/paulelliott/fabrication) from the Ruby world. +It's inspired on [Fabrication](https://github.com/paulelliott/fabrication) and [factory-girl](https://github.com/thoughtbot/factory_girl) from the Ruby world. Fabricate is a simple fake object generation plugin for CakePHP. Quickly Fabricate objects as needed anywhere in your app or test case. @@ -18,29 +18,43 @@ Add require-dev in your composer.json Add bootstrap -`CakePlugin::load('Fabricate');` +```php +CakePlugin::load('Fabricate'); +``` ## Usage ### The Basics +Include Fabricate class using App::uses on your test file + +```php +App::uses('Fabricate', 'Fabricate.Lib'); +``` + The simplest way to generate objects - Fabricate::create('Post') +```php +Fabricate::create('Post') +``` That will generate and save to database an instance of Post using the schema information. To set additional attributes or override what is in the Fabricator, you can pass a array to Fabricate with the fields you want to set. - Fabricate::create('Post', ["created" => "2013-10-09 12:40:28", "updated" => "2013-10-09 12:40:28"]) +```php +Fabricate::create('Post', ["created" => "2013-10-09 12:40:28", "updated" => "2013-10-09 12:40:28"]) +``` ### Fabricating With Blocks In addition to the array, you can pass a callback function to Fabricate and all the features of a Fabricator definition are available to you at object generation time. - Fabricate::create('Post', 10, function($data){ - return ["created" => "2013-10-09 12:40:28", "updated" => "2013-10-09 12:40:28"]; - }); +```php +Fabricate::create('Post', 10, function($data){ + return ["created" => "2013-10-09 12:40:28", "updated" => "2013-10-09 12:40:28"]; +}); +``` The hash will overwrite any fields defined in the callback function. @@ -56,23 +70,25 @@ The hash will overwrite any fields defined in the callback function. #### Example - $results = Fabricate::attributes_for('Post', 10, function($data){ - return ["created" => "2013-10-09 12:40:28", "updated" => "2013-10-09 12:40:28"]; - }); - - // $results is followings : - array ( - 0 => - array ( - 'id' => 1, - 'title' => 'Lorem ipsum dolor sit amet', - 'body' => 'Lorem ipsum dolor sit amet, aliquet feugiat. Convallis morbi fringilla gravida, phasellus feugiat dapibus velit nunc, pulvinar eget sollicitudin venenatis cum nullam, vivamus ut a sed, mollitia lectus. Nulla vestibulum massa neque ut et, id hendrerit sit, feugiat in taciti enim proin nibh, tempor dignissim, rhoncus duis vestibulum nunc mattis convallis.', - 'created' => '2013-10-09 12:40:28', - 'updated' => '2013-10-09 12:40:28', - ), - 1 => - array ( - .... +```php +$results = Fabricate::attributes_for('Post', 10, function($data){ + return ["created" => "2013-10-09 12:40:28", "updated" => "2013-10-09 12:40:28"]; +}); + +// $results is followings : +array ( + 0 => + array ( + 'id' => 1, + 'title' => 'Lorem ipsum dolor sit amet', + 'body' => 'Lorem ipsum dolor sit amet, aliquet feugiat. Convallis morbi fringilla gravida, phasellus feugiat dapibus velit nunc, pulvinar eget sollicitudin venenatis cum nullam, vivamus ut a sed, mollitia lectus. Nulla vestibulum massa neque ut et, id hendrerit sit, feugiat in taciti enim proin nibh, tempor dignissim, rhoncus duis vestibulum nunc mattis convallis.', + 'created' => '2013-10-09 12:40:28', + 'updated' => '2013-10-09 12:40:28', + ), + 1 => + array ( + .... +``` ### Generate a model instance (not saved) @@ -83,19 +99,21 @@ The hash will overwrite any fields defined in the callback function. #### Example - $result = Fabricate::build('Post', function($data){ - return ["created" => "2013-10-09 12:40:28", "updated" => "2013-10-09 12:40:28"]; - }); - - // $results is followings : - AppModel::__set_state(array( - 'useDbConfig' => 'default', - 'useTable' => 'posts', - 'id' => 1, - 'data' => - array ( - 'Post' => - ...... +```php +$result = Fabricate::build('Post', function($data){ + return ["created" => "2013-10-09 12:40:28", "updated" => "2013-10-09 12:40:28"]; +}); + +// $results is followings : +AppModel::__set_state(array( + 'useDbConfig' => 'default', + 'useTable' => 'posts', + 'id' => 1, + 'data' => + array ( + 'Post' => + ...... +``` ### Generate records to database @@ -107,9 +125,11 @@ The hash will overwrite any fields defined in the callback function. #### Example - Fabricate::create('Post', 10, function($data){ - return ["created" => "2013-10-09 12:40:28", "updated" => "2013-10-09 12:40:28"]; - }); +```php +Fabricate::create('Post', 10, function($data){ + return ["created" => "2013-10-09 12:40:28", "updated" => "2013-10-09 12:40:28"]; +}); +``` ## Sequences @@ -120,36 +140,39 @@ A sequence allows you to get a series of numbers unique within the each generati Allows you to specify the default starting number for all sequences. This can still be overridden for specific sequences. - Fabricate::config(function($config) { - $config->sequence_start = 100; - }); +```php +Fabricate::config(function($config) { + $config->sequence_start = 100; +}); +``` ### Usage - Fabricate::config(function($config) { - $config->sequence_start = 100; - }); - $results = Fabricate::attributes_for('Post', 10, function($data, $world){ - return [ - 'id'=> $world->sequence('id'), - 'title'=> $world->sequence('title', 1, function($i){ return "Title {$i}"; }) - ]; - }); - - // $results is followings : - array ( - 0 => - array ( - 'id' => 100, // starting configure sequence - 'title' => 'Title 1', // closure function returned - ... - ), - 1 => - array ( - 'id' => 101, // starting configure sequence - 'title' => 'Title 2', // closure function returned - ... - +```php +Fabricate::config(function($config) { + $config->sequence_start = 100; +}); +$results = Fabricate::attributes_for('Post', 10, function($data, $world){ + return [ + 'id'=> $world->sequence('id'), + 'title'=> $world->sequence('title', 1, function($i){ return "Title {$i}"; }) + ]; +}); + +// $results is followings : +array ( + 0 => + array ( + 'id' => 100, // starting configure sequence + 'title' => 'Title 1', // closure function returned + ... + ), + 1 => + array ( + 'id' => 101, // starting configure sequence + 'title' => 'Title 2', // closure function returned + ... +``` If you want use sequence within generation function, callback has second attribute. `$world` is FabricateContext instance. It have sequence method. @@ -158,19 +181,24 @@ If you want use sequence within generation function, callback has second attribu You should set name argument to sequence. - $world->sequence('id') +```php +$world->sequence('id') +``` If you want to specify the starting number, you can do it with a second parameter. It will always return the seed number on the first call and it will be ignored with subsequent calls. - $world->sequence('id', 10) +```php +$world->sequence('id', 10) +``` If you are generating something like an unique string, you can pass it a callback function and the callback function response will be returned. - $world->sequence('title', function($i){ return "Title {$i}"; } - // or with start number - $world->sequence('title', 1, function($i){ return "Title {$i}"; } - +```php +$world->sequence('title', function($i){ return "Title {$i}"; } +// or with start number +$world->sequence('title', 1, function($i){ return "Title {$i}"; } +``` ## Contributing to this Plugin From 61215b666bebec39e13d3e0db746843d6fc44fee Mon Sep 17 00:00:00 2001 From: sizuhiko Date: Thu, 5 Jun 2014 22:31:58 +0900 Subject: [PATCH 13/13] Add Feature 1.2 Documentation --- README.md | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/README.md b/README.md index e02199e..20afc2c 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,41 @@ The hash will overwrite any fields defined in the callback function. ## APIs +### Configuration + +To override these settings, put a bootstrap.php in your app folder and append the path to phpunit.xml + +``` +Fabricate::config(function($config) { + $config->sequence_start = 1; + $config->auto_validate = false; + $config->filter_key = false; +}); +``` + +#### Supported Options + +##### sequence_start + +Allows you to specify the default starting number for all sequences. +This can still be overridden for specific sequences. + +`Default: 1` + +##### auto_validate + +Indicates whether or not to validate before creating. +see: CakePHP's Model::save() + +`Default: false` + +##### filter_key + +filter_key If true, overwrites any primary key input with an empty value. +see: CakePHP's Model::create() + +`Default: false` + ### Generate model attributes as array (not saved) `Fabricate::attributes_for(:model_name, :number_of_generation, :array_or_callback)` generate only attributes. @@ -131,6 +166,61 @@ Fabricate::create('Post', 10, function($data){ }); ``` +## Defining + +Fabricate has a name and a set of attributes when fabricating objects. +The name is used to guess the class of the object by default, + +```php +Fabricate::define('Post', ['published'=>'1']); +// or using callback block +Fabricate::define('Post', function($data, $world) { + return ['published'=>'1'] +}); +``` + +To use a different name from the class, you must specify 'class'=>:class_name into first argument as array. + +```php +Fabricate::define(['PublishedPost', 'class'=>'Post'], ['published'=>'1']); + +Fabricate::create('PublishedPost'); +``` + +You can inherit attributes from other defined set of attributes by using the 'parent' key. + +```php +Fabricate::define(['PublishedPost', 'class'=>'Post'], ['published'=>'1']); +Fabricate::define(['Author5PublishedPost', 'parent'=>'PublishedPost'], ['author_id'=>'5']); + +Fabricate::create('Author5PublishedPost'); +``` +## Associations + +It's possible to set up associations(hasOne/hasMany) within Fabricate::create(). +You can also specify a Fabricate::association(). +It will generate the attributes, and set(merge) it in the current array. + +### Usage + +```php +Fabricate::create('User', function($data, $world) { + return [ + 'user' => 'taro', + 'Post' => Fabricate::association('Post', 3), + ]; +}); +// or can overwritten by array or callback block. +Fabricate::create('User', function($data, $world) { + return [ + 'user' => 'taro', + 'Post' => Fabricate::association('Post', 3, function($data, $world) { + return ['title'=>$world->sequence('Post.title',function($i){ return "Title-${i}"; })]; + }), + ]; +}); +``` + ## Sequences A sequence allows you to get a series of numbers unique within the each generation function. Fabrication provides you with an easy and flexible means for keeping track of sequences. @@ -200,6 +290,37 @@ $world->sequence('title', function($i){ return "Title {$i}"; } $world->sequence('title', 1, function($i){ return "Title {$i}"; } ``` +## Traits + +Traits allow you to group attributes together and then apply them to any fabricating objects. + +```php +Fabricate::define(['trait'=>'published'], ['published'=>'1']); +Fabricate::create('Post', function($data, $world) { + $world->traits('published'); + return ['author_id'=>5]; +}); +``` + +`traits` can specify defined names as array + +```php +Fabricate::define(['trait'=>'published'], ['published'=>'1']); +Fabricate::define(['trait'=>'author5'], function($data, $world) { return ['author_id'=>5]; }); +Fabricate::create('Post', function($data, $world) { + $world->traits(['published','author5']); + return []; +}); +``` + +## Reloading + +If you need to reset fabricate back to its original state after it has been loaded. + +```php +Fabricate::clear(); +``` + ## Contributing to this Plugin Please feel free to contribute to the plugin with new issues, requests, unit tests and code fixes or new features.