├── Console ├── Command │ ├── FakeSeederShell.php │ ├── Task │ │ └── DynamicModelSeederTask.php │ └── SeederShell.php └── SeederTaskBase.php ├── .scrutinizer.yml ├── .editorconfig ├── Test ├── Case │ ├── AllFakeSeederTest.php │ ├── Lib │ │ ├── ShellModelTruncatorTest.php │ │ ├── ColumnTypeGuesserTest.php │ │ └── ShellSeedProcessorTest.php │ └── Console │ │ ├── Command │ │ ├── Task │ │ │ └── DynamicModelSeederTaskTest.php │ │ └── SeederShellTest.php │ │ └── SeederTaskBaseTest.php └── Fixture │ ├── AppleFixture.php │ ├── BananaFixture.php │ └── PearFixture.php ├── CHANGELOG.md ├── .gitignore ├── Docs └── Examples │ ├── ExampleSeederShell.php │ └── ExampleSeederTask.php ├── .gitattributes ├── .travis.yml ├── Lib ├── ShellModelTruncator.php ├── ColumnTypeGuesser.php └── ShellSeedProcessor.php ├── LICENSE ├── composer.json ├── CONTRIBUTING.md ├── README.md └── composer.lock /Console/Command/FakeSeederShell.php: -------------------------------------------------------------------------------- 1 | addTestDirectoryRecursive($path); 17 | 18 | return $suite; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project are documented in this file. 3 | This project adheres to [Semantic Versioning](http://semver.org/). 4 | 5 | ## [Unreleased](https://github.com/ravage84/cakephp-fake-seeder/compare/0.1.0...master) 6 | ### Added 7 | 8 | ### Changed 9 | 10 | ### Fixed 11 | - Update minimum PHP Version to PHP 5.4 12 | - Added vendor/ folder to .gitignore 13 | 14 | ## [0.1.0](https://github.com/ravage84/cakephp-fake-seeder/tag/0.1.0) - 2015-08-31 15 | ### Added 16 | - Initial commit 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # User specific & automatically generated files # 2 | ################################################# 3 | *.mo 4 | 5 | # IDE and editor specific files # 6 | ################################# 7 | /nbproject 8 | .idea 9 | 10 | # Eclipse / PHP Development Tools / Aptana Studio 11 | .project 12 | .buildpath 13 | .settings 14 | 15 | # PHP Tools # 16 | ############# 17 | *.phar 18 | 19 | # OS generated files # 20 | ###################### 21 | .DS_Store 22 | .DS_Store? 23 | ._* 24 | .Spotlight-V100 25 | .Trashes 26 | Icon? 27 | ehthumbs.db 28 | Thumbs.db 29 | 30 | vendor/ 31 | -------------------------------------------------------------------------------- /Docs/Examples/ExampleSeederShell.php: -------------------------------------------------------------------------------- 1 | array('type' => 'integer', 'key' => 'primary'), 7 | 'title' => array('type' => 'string', 'length' => 255, 'null' => false), 8 | 'body' => 'text', 9 | 'published' => array('type' => 'integer', 'default' => '0', 'null' => false), 10 | 'created' => 'datetime', 11 | 'updated' => 'datetime' 12 | ); 13 | 14 | public function init() { 15 | $this->records = array( 16 | array( 17 | 'id' => 1, 18 | 'title' => 'First Article', 19 | 'body' => 'First Article Body', 20 | 'published' => '1', 21 | 'created' => date('Y-m-d H:i:s'), 22 | 'updated' => date('Y-m-d H:i:s'), 23 | ), 24 | ); 25 | parent::init(); 26 | } 27 | } -------------------------------------------------------------------------------- /Test/Fixture/BananaFixture.php: -------------------------------------------------------------------------------- 1 | array('type' => 'integer', 'key' => 'primary'), 7 | 'title' => array('type' => 'string', 'length' => 255, 'null' => false), 8 | 'body' => 'text', 9 | 'published' => array('type' => 'integer', 'default' => '0', 'null' => false), 10 | 'created' => 'datetime', 11 | 'updated' => 'datetime' 12 | ); 13 | 14 | public function init() { 15 | $this->records = array( 16 | array( 17 | 'id' => 1, 18 | 'title' => 'First Article', 19 | 'body' => 'First Article Body', 20 | 'published' => '1', 21 | 'created' => date('Y-m-d H:i:s'), 22 | 'updated' => date('Y-m-d H:i:s'), 23 | ), 24 | ); 25 | parent::init(); 26 | } 27 | } -------------------------------------------------------------------------------- /Test/Fixture/PearFixture.php: -------------------------------------------------------------------------------- 1 | array('type' => 'integer', 'key' => 'primary'), 7 | 'title' => array('type' => 'string', 'length' => 255, 'null' => false), 8 | 'body' => 'text', 9 | 'published' => array('type' => 'integer', 'default' => '0', 'null' => false), 10 | 'created' => 'datetime', 11 | 'updated' => 'datetime' 12 | ); 13 | 14 | public function init() { 15 | $this->records = array( 16 | array( 17 | 'id' => 1, 18 | 'title' => 'First Article', 19 | 'body' => 'First Article Body', 20 | 'published' => '1', 21 | 'created' => date('Y-m-d H:i:s'), 22 | 'updated' => date('Y-m-d H:i:s'), 23 | ), 24 | ); 25 | parent::init(); 26 | } 27 | } -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Define the line ending behavior of the different file extensions 2 | # Set default behaviour, in case users don't have core.autocrlf set. 3 | * text=auto 4 | 5 | # Explicitly declare text files we want to always be normalized and converted 6 | # to native line endings on checkout. 7 | *.php text 8 | *.default text 9 | *.ctp text 10 | *.sql text 11 | *.md text 12 | *.po text 13 | *.js text 14 | *.css text 15 | *.ini text 16 | *.properties text 17 | *.txt text 18 | *.xml text 19 | *.yml text 20 | .htaccess text 21 | 22 | # Declare files that will always have CRLF line endings on checkout. 23 | *.bat eol=crlf 24 | 25 | # Declare files that will always have LF line endings on checkout. 26 | *.pem eol=lf 27 | 28 | # Denote all files that are truly binary and should not be modified. 29 | *.png binary 30 | *.jpg binary 31 | *.gif binary 32 | *.ico binary 33 | *.mo binary 34 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.4 5 | - 5.5 6 | - 5.6 7 | - 7.0 8 | - hhvm 9 | 10 | env: 11 | global: 12 | - PLUGIN_NAME=FakeSeeder 13 | - REQUIRE="" 14 | 15 | matrix: 16 | - DB=mysql CAKE_VERSION=2.7 17 | 18 | matrix: 19 | fast_finish: true 20 | allow_failures: 21 | - php: 7.0 22 | - php: hhvm 23 | include: 24 | - php: 5.4 25 | env: 26 | - COVERALLS=1 DB=mysql CAKE_VERSION=2.7 27 | #- php: 5.4 28 | #env: 29 | #- PHPCS=1 DB=mysql CAKE_VERSION=2.7 30 | 31 | before_script: 32 | - git clone -b master https://github.com/FriendsOfCake/travis.git --depth 1 ../travis 33 | - ../travis/before_script.sh 34 | - cd ../cakephp/app 35 | - echo "require './vendor/autoload.php';spl_autoload_unregister(array('App', 'load'));spl_autoload_register(array('App', 'load'), true, true);" >> Config/core.php 36 | - cat Config/core.php 37 | - cd .. 38 | 39 | script: 40 | - ../travis/script.sh 41 | 42 | after_success: 43 | - ../travis/after_success.sh 44 | 45 | notifications: 46 | email: false 47 | -------------------------------------------------------------------------------- /Lib/ShellModelTruncator.php: -------------------------------------------------------------------------------- 1 | _shell = $shell; 22 | } 23 | 24 | /** 25 | * Truncate the given models 26 | * 27 | * @param array $modelsToTruncate An array of models (names) to truncate 28 | * @return void 29 | * @todo Improve testability by extracting the model object retrieval part. 30 | */ 31 | public function truncateModels($modelsToTruncate) { 32 | foreach ($modelsToTruncate as $modelName) { 33 | $this->_shell->out(__('Truncate model %s...', $modelName), 1, Shell::VERBOSE); 34 | $model = ClassRegistry::init($modelName); 35 | $datasource = $model->getDataSource(); 36 | $datasource->truncate($model->tablePrefix . $model->useTable); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Marc Würth 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Console/Command/Task/DynamicModelSeederTask.php: -------------------------------------------------------------------------------- 1 | args[0]; 31 | 32 | return $modelName; 33 | } 34 | 35 | /** 36 | * Set/get the field formatters 37 | * 38 | * Just return the field formatters. 39 | * 40 | * {@inheritDoc} 41 | */ 42 | public function fieldFormatters() { 43 | return $this->_fieldFormatters; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ravage84/cakephp-fake-seeder", 3 | "description": "A shell to seed your database with fake and/or fixed data.", 4 | "type": "cakephp-plugin", 5 | "keywords":[ 6 | "cakephp", 7 | "plugin", 8 | "seeder", 9 | "faker", 10 | "data", 11 | "fixtures" 12 | ], 13 | "homepage": "https://github.com/ravage84/cakephp-fake-seeder", 14 | "license": "MIT", 15 | "authors": [ 16 | { 17 | "name": "Marc Würth", 18 | "homepage": "https://github.com/ravage84/", 19 | "email": "ravage@bluewin.ch", 20 | "role": "Lead developer" 21 | }, 22 | { 23 | "name": "Other contributors", 24 | "homepage": "https://github.com/ravage84/cakephp-fake-seeder/graphs/contributors", 25 | "role": "Contributors" 26 | } 27 | ], 28 | "support": { 29 | "source": "https://github.com/ravage84/cakephp-fake-seeder", 30 | "issues": "https://github.com/ravage84/cakephp-fake-seeder/issues", 31 | "wiki":"https://github.com/ravage84/cakephp-fake-seeder/wiki" 32 | }, 33 | "require": { 34 | "php": ">=5.4.0", 35 | "composer/installers": "^1.0.0", 36 | "fzaninotto/faker": "^1.5.0" 37 | }, 38 | "require-dev": { 39 | "phpunit/phpunit": "^3.7.0" 40 | }, 41 | "extra": { 42 | "installer-name": "FakeSeeder" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute 2 | 3 | We welcome your contribution. There are several ways to help out: 4 | 5 | * Create an issue on GitHub, 6 | if you have found a bug or have an idea for a feature 7 | * Write test cases for open bug issues 8 | * Write patches for open bug/feature issues 9 | 10 | There are a few guidelines that we need contributors to follow, so that we have a 11 | chance of keeping on top of things. 12 | 13 | * The code must follow the [CakePHP coding standard](http://book.cakephp.org/2.0/en/contributing/cakephp-coding-conventions.html). 14 | * All code changes should be covered by unit tests 15 | 16 | ## Issues 17 | 18 | * Submit an issue, but: 19 | * Make sure it does not already exist. 20 | * Clearly describe the issue including steps to reproduce, when it is a bug. 21 | * Make sure you mention the version and configuration of all software that could be relevant. 22 | 23 | ## Coding Standard 24 | 25 | Make sure your code changes comply with the CakePHP Coding standard, 26 | using [PHP Codesniffer](https://github.com/squizlabs/PHP_CodeSniffer). 27 | Execute the following command from the plugin folder: 28 | 29 | vendor/bin/phpcs -p --extensions=php --standard=CakePHP 30 | 31 | ## Additional Resources 32 | 33 | * [General GitHub documentation](https://help.github.com/) 34 | * [GitHub pull request documentation](https://help.github.com/send-pull-requests/) 35 | -------------------------------------------------------------------------------- /Lib/ColumnTypeGuesser.php: -------------------------------------------------------------------------------- 1 | _generator = $generator; 29 | } 30 | 31 | /** 32 | * Guess the formatter 33 | * 34 | * @param array $column The column info. 35 | * @return callable|null 36 | */ 37 | public function guessFormat($column) { 38 | $generator = $this->_generator; 39 | 40 | switch ($column['type']) { 41 | case 'boolean': 42 | return function () use ($generator) { 43 | return $generator->boolean; 44 | }; 45 | case 'integer': 46 | return function () use ($generator) { 47 | return $generator->randomNumber(9); 48 | }; 49 | case 'biginteger': 50 | return function () use ($generator) { 51 | return $generator->randomNumber(18); 52 | }; 53 | case 'decimal': 54 | case 'float': 55 | return function () use ($generator) { 56 | return $generator->randomFloat(); 57 | }; 58 | case 'uuid': 59 | return function () use ($generator) { 60 | return $generator->uuid(); 61 | }; 62 | case 'string': 63 | $length = $column['length']; 64 | $string = str_repeat("?", $length); 65 | if ($length <= '5') { 66 | return function () use ($generator, $string) { 67 | return $generator->lexify($string); 68 | }; 69 | } 70 | return function () use ($generator, $length) { 71 | return $generator->text($length); 72 | }; 73 | case 'text': 74 | return function () use ($generator) { 75 | return $generator->text(); 76 | }; 77 | case 'date': 78 | case 'datetime': 79 | case 'timestamp': 80 | case 'time': 81 | return function () use ($generator) { 82 | return $generator->iso8601(); 83 | }; 84 | 85 | case 'binary': 86 | default: 87 | return null; 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Test/Case/Lib/ShellModelTruncatorTest.php: -------------------------------------------------------------------------------- 1 | getMock('ConsoleOutput', array(), array(), '', false); 50 | $in = $this->getMock('ConsoleInput', array(), array(), '', false); 51 | $this->_shell = $this->getMock('Shell', 52 | array('in', 'out', 'hr', 'createFile', 'error', 'err', '_stop'), 53 | array($out, $out, $in) 54 | ); 55 | 56 | $this->_truncator = new ShellModelTruncator($this->_shell); 57 | } 58 | 59 | /** 60 | * Test the constructor 61 | * 62 | * @return void 63 | * @covers ::__construct 64 | */ 65 | public function testConstruct() { 66 | $truncator = new ShellModelTruncator($this->_shell); 67 | $this->assertAttributeInstanceOf('Shell', '_shell', $truncator); 68 | } 69 | 70 | /** 71 | * Tests the truncateModels function 72 | * 73 | * @return void 74 | * @covers ::truncateModels 75 | */ 76 | public function testTruncateModels() { 77 | $this->_shell->expects($this->at(0))->method('out')->with($this->equalTo('Truncate model Apple...')); 78 | $this->_shell->expects($this->at(1))->method('out')->with($this->equalTo('Truncate model Banana...')); 79 | $this->_shell->expects($this->at(2))->method('out')->with($this->equalTo('Truncate model Pear...')); 80 | 81 | $models = array('Apple', 'Banana', 'Pear'); 82 | $this->_truncator->truncateModels($models); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /Test/Case/Console/Command/Task/DynamicModelSeederTaskTest.php: -------------------------------------------------------------------------------- 1 | 'ModelName'); 18 | 19 | /** 20 | * Set some test dummy formatters 21 | * 22 | * @var array 23 | */ 24 | protected $_fieldFormatters = array('foo' => 'bar'); 25 | 26 | } 27 | 28 | /** 29 | * DynamicModelSeederTask Test 30 | * 31 | * @coversDefaultClass DynamicModelSeederTask 32 | */ 33 | class DynamicModelSeederTaskTest extends CakeTestCase { 34 | 35 | /** 36 | * The task under test 37 | * 38 | * @var null|TestDynamicModelSeederTask 39 | */ 40 | protected $_task = null; 41 | 42 | /** 43 | * Setup the shell under test 44 | * 45 | * @return void 46 | */ 47 | public function setUp() { 48 | parent::setUp(); 49 | 50 | $this->_createShellMock( 51 | array('in', 'out', 'hr', 'createFile', 'error', 'err', '_stop', '_showInfo', 'dispatchShell', '_getSeederTasks') 52 | ); 53 | } 54 | 55 | /** 56 | * Creates a shell mock 57 | * 58 | * @param array $methods A list of methods to mock. 59 | * @param string $className Optional name of the seeder shell class to mock. 60 | * @return void 61 | */ 62 | protected function _createShellMock($methods, $className = 'TestDynamicModelSeederTask') { 63 | $out = $this->getMock('ConsoleOutput', array(), array(), '', false); 64 | $in = $this->getMock('ConsoleInput', array(), array(), '', false); 65 | $this->_task = $this->getMock( 66 | $className, 67 | $methods, 68 | array($out, $out, $in) 69 | ); 70 | } 71 | 72 | /** 73 | * Tests the _getModelName method 74 | * 75 | * @return void 76 | * @covers ::getModelName 77 | */ 78 | public function testGetModelName() { 79 | $result = $this->_task->getModelName(); 80 | $expected = 'ModelName'; 81 | $this->assertEquals($expected, $result); 82 | } 83 | 84 | /** 85 | * Tests the _fieldFormatters method 86 | * 87 | * @return void 88 | * @covers ::fieldFormatters 89 | */ 90 | public function testFieldFormatters() { 91 | $result = $this->_task->fieldFormatters(); 92 | $expected = array('foo' => 'bar'); 93 | $this->assertEquals($expected, $result); 94 | } 95 | 96 | /** 97 | * Tests the _getSeedingMode method 98 | * 99 | * @return void 100 | * @covers ::getSeedingMode 101 | */ 102 | public function testGetSeedingMode() { 103 | $result = $this->_task->getSeedingMode(); 104 | $this->assertEquals('auto', $result); 105 | } 106 | } -------------------------------------------------------------------------------- /Docs/Examples/ExampleSeederTask.php: -------------------------------------------------------------------------------- 1 | 1, 45 | 'name' => 'abc', 46 | ), 47 | array( 48 | 'id' => 2, 49 | 'name' => 'def', 50 | ), 51 | ); 52 | 53 | /** 54 | * The seeding mode, optional. 55 | * 56 | * @var null|string 57 | */ 58 | protected $_mode = 'mixed'; 59 | 60 | /** 61 | * The locale to use for Faker, optional 62 | * 63 | * @var null|int 64 | */ 65 | protected $_locale = 'de_DE'; 66 | 67 | /** 68 | * Set the minimum record count for a seeder task, null means no minimum. 69 | * 70 | * @var null|int 71 | */ 72 | protected $_minRecords = 100; 73 | 74 | /** 75 | * Set the maximum record count for a seeder task, null means no maximum. 76 | * 77 | * @var null|int 78 | */ 79 | protected $_maxRecords = 20000; 80 | 81 | /** 82 | * The records to seed, optional 83 | * 84 | * @var null|int 85 | */ 86 | protected $_records = 12345; 87 | 88 | /** 89 | * Whether or not to validate the seeding data when saving, optional 90 | * 91 | * @var null|bool|string 92 | * @see Model::saveAll() See for possible values for `validate`. 93 | */ 94 | protected $_validateSeeding = true; 95 | 96 | /** 97 | * The seeding number for Faker to use 98 | * 99 | * @var null|bool|int 100 | * @see Generator::seed Faker's seed method. 101 | */ 102 | protected $_seedingNumber = 123456; 103 | 104 | /** 105 | * Whether or not to truncate the model , optional. 106 | * 107 | * @var null|bool 108 | */ 109 | protected $_noTruncate = false; 110 | 111 | /** 112 | * Set/get the field formatters 113 | * 114 | * {@inheritDoc} 115 | */ 116 | public function fieldFormatters() { 117 | parent::fieldFormatters(); 118 | $faker = $this->faker; 119 | 120 | return $this->_mergeFieldFormatters( 121 | array( 122 | 'name' => function ($state) use ($faker) { 123 | return $faker->unique()->name; 124 | }, 125 | ) 126 | ); 127 | } 128 | 129 | /** 130 | * Set/get state per record 131 | * 132 | * Can be overridden to return some state with data per record. 133 | * 134 | * @return array The state per record. 135 | */ 136 | public function recordState() { 137 | return array( 138 | 'foo' => 'bar', 139 | ); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /Test/Case/Lib/ColumnTypeGuesserTest.php: -------------------------------------------------------------------------------- 1 | _faker = $this->getMock('\\Faker\\Generator', array('__get', '__call')); 37 | $this->_guesser = new ColumnTypeGuesser($this->_faker); 38 | } 39 | 40 | /** 41 | * Test the constructor 42 | * 43 | * @return void 44 | * @covers ::__construct 45 | */ 46 | public function testConstruct() { 47 | $guesser = new ColumnTypeGuesser($this->_faker); 48 | $this->assertAttributeInstanceOf('\\Faker\\Generator', '_generator', $guesser); 49 | } 50 | 51 | /** 52 | * Tests the guessFormat method with various types 53 | * 54 | * @param string $magicMethod The name of the magic method (__call or __get). 55 | * @param string $method The name of the method (e.g. randomNumber). 56 | * @param array $column The column schema with type etc. 57 | * @return void 58 | * @covers ::guessFormat 59 | * @dataProvider formatProvider 60 | */ 61 | public function testGuessFormats($magicMethod, $method, $column) { 62 | $this->_faker->expects($this->at(0))->method($magicMethod)->with( 63 | $this->equalTo($method) 64 | ); 65 | $result = $this->_guesser->guessFormat($column); 66 | $result(); 67 | } 68 | 69 | /** 70 | * Tests the guessFormat method with various types resulting to null 71 | * 72 | * @param null|array $column The column schema with type etc. 73 | * @return void 74 | * @covers ::guessFormat 75 | * @dataProvider specialFormatProvider 76 | */ 77 | public function testGuessSpecialFormat($column) { 78 | $result = $this->_guesser->guessFormat($column); 79 | $this->assertEquals($result, null); 80 | } 81 | 82 | /** 83 | * A format data provider 84 | * 85 | * @return array Formats 86 | */ 87 | public function formatProvider() { 88 | return array( 89 | 'boolean' => array('__get', 'boolean', array('type' => 'boolean')), 90 | 'integer' => array('__call', 'randomNumber', array('type' => 'integer')), 91 | 'bigInteger' => array('__call', 'randomNumber', array('type' => 'biginteger')), 92 | 'decimal' => array('__call', 'randomFloat', array('type' => 'decimal')), 93 | 'float' => array('__call', 'randomFloat', array('type' => 'float')), 94 | 'uuid' => array('__call', 'uuid', array('type' => 'uuid')), 95 | 'lexify' => array('__call', 'lexify', array('type' => 'string', 'length' => 4)), 96 | 'string' => array('__call', 'text', array('type' => 'string', 'length' => 20)), 97 | 'text' => array('__call', 'text', array('type' => 'text')), 98 | 'date' => array('__call', 'iso8601', array('type' => 'date')), 99 | 'datetime' => array('__call', 'iso8601', array('type' => 'datetime')), 100 | 'timestamp' => array('__call', 'iso8601', array('type' => 'timestamp')), 101 | 'time' => array('__call', 'iso8601', array('type' => 'time')), 102 | ); 103 | } 104 | 105 | /** 106 | * A format data provider for resulting to null cases 107 | * 108 | * @return array Formats 109 | */ 110 | public function specialFormatProvider() { 111 | return array( 112 | 'null' => array(null), 113 | 'binary' => array( 114 | array( 115 | 'type' => 'binary' 116 | ) 117 | ), 118 | ); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /Lib/ShellSeedProcessor.php: -------------------------------------------------------------------------------- 1 | _seeder = $seeder; 24 | } 25 | 26 | /** 27 | * Process the fixtures 28 | * 29 | * @return void 30 | */ 31 | public function processFixtures() { 32 | $fixtures = $this->_seeder->fixtureRecords(); 33 | if (empty($fixtures)) { 34 | return; 35 | } 36 | $this->saveSeeds($fixtures); 37 | } 38 | 39 | /** 40 | * Sow the seeds 41 | * 42 | * @return void 43 | */ 44 | public function sowSeeds() { 45 | $modelName = $this->_seeder->getModelName(); 46 | $recordsTotal = $this->_seeder->getRecordsCount(); 47 | $this->_seeder->out(__('Sowing %s seeds for model %s', $recordsTotal, $modelName)); 48 | 49 | $fieldFormatters = $this->getFieldFormatters(); 50 | if (empty($fieldFormatters)) { 51 | $this->_seeder->out(__('No field formatters configured, aborting.')); 52 | return; 53 | } 54 | 55 | // Improve seed access 56 | $this->_seeder->seeds = array(); 57 | for ($record = 1; $record <= $recordsTotal; $record++) { 58 | $newSeed = $this->createSeed($fieldFormatters); 59 | if (empty($newSeed)) { 60 | $this->_seeder->out(__('Created seed is empty! Check the field formatters.')); 61 | break; 62 | } 63 | $this->_seeder->seeds[] = $newSeed; 64 | 65 | $this->_seeder->out('.', 0); 66 | $modulo = $record % 50; 67 | if ($modulo == 0 || $record == $recordsTotal) { 68 | $alignSpaces = 0; 69 | if ($modulo !== 0 && $record >= 50) { 70 | $alignSpaces = 50 - $modulo; 71 | } 72 | $alignSpaces = $alignSpaces + strlen($recordsTotal) - strlen($record) + 1; 73 | $alignSpaces = str_repeat(' ', $alignSpaces); 74 | $this->_seeder->out(sprintf('%s%s / %s', $alignSpaces, $record, $recordsTotal)); 75 | } 76 | } 77 | $this->saveSeeds($this->_seeder->seeds); 78 | 79 | $this->_seeder->out(__('Finished sowing %s seeds for model %s', $recordsTotal, $modelName)); 80 | } 81 | 82 | /** 83 | * Get the field formatters depending on the seeding mode 84 | * 85 | * 'manual' = No Field formatters are guessed. 86 | * 'auto' = All field formatters are guessed. 87 | * 'mixed' = Only missing field formatters are guessed. 88 | * 89 | * @return array The field formatters 90 | */ 91 | public function getFieldFormatters() { 92 | $mode = $this->_seeder->getSeedingMode(); 93 | switch ($mode) { 94 | case 'manual': 95 | return $this->_seeder->fieldFormatters(); 96 | case 'auto': 97 | return $this->_guessFieldFormatters(); 98 | case 'mixed': 99 | // TODO Improve by only guessing those needed 100 | $guesedFormatters = $this->_guessFieldFormatters(); 101 | $setFormatters = $this->_seeder->fieldFormatters(); 102 | return array_merge( 103 | $guesedFormatters, 104 | $setFormatters 105 | ); 106 | } 107 | // TODO Handle invalid mode 108 | return array(); 109 | } 110 | 111 | /** 112 | * Guess the field formatters based on the column type 113 | * 114 | * @return array The guessed field formatters. 115 | */ 116 | protected function _guessFieldFormatters() { 117 | $columns = $this->_getColumns(); 118 | 119 | $columnTypeGuesser = $this->_getColumnTypeGuesser(); 120 | $fieldFormatters = array(); 121 | foreach ($columns as $columnName => $column) { 122 | $fieldFormatters[$columnName] = $columnTypeGuesser->guessFormat($column); 123 | } 124 | return $fieldFormatters; 125 | } 126 | 127 | /** 128 | * Get a ColumnTypeGuesser instance 129 | * 130 | * @return ColumnTypeGuesser A ColumnTypeGuesser instance. 131 | */ 132 | protected function _getColumnTypeGuesser() { 133 | return new ColumnTypeGuesser($this->_seeder->faker); 134 | } 135 | 136 | /** 137 | * Get the columns (schema) 138 | * 139 | * Removes the primary key, though. 140 | * 141 | * @return array The columns (schema). 142 | */ 143 | protected function _getColumns() { 144 | $model = $this->_getModel(); 145 | $columns = $model->schema(); 146 | unset($columns[$model->primaryKey]); 147 | return $columns; 148 | } 149 | 150 | /** 151 | * Create seed to sow 152 | * 153 | * Gets some (optional) record state data, 154 | * which can be shared by all field formatters of one record. 155 | * 156 | * @param array $fieldFormatters The fields and their formatter 157 | * @return array A seed to sow. 158 | */ 159 | public function createSeed($fieldFormatters) { 160 | $seed = array(); 161 | $modelName = $this->_seeder->getModelName(); 162 | $state = $this->_seeder->recordState(); 163 | 164 | foreach ($fieldFormatters as $fieldName => $formatter) { 165 | $seed[$modelName][$fieldName] = $formatter($state); 166 | } 167 | return $seed; 168 | } 169 | 170 | /** 171 | * Save the seeds 172 | * 173 | * @param array $seeds The seeds to save. 174 | * @return void 175 | * @todo Make data saving/validation handling configurable (atomic true/false) 176 | */ 177 | public function saveSeeds($seeds) { 178 | $model = $this->_getModel(); 179 | $validate = $this->_seeder->getValidateSeeding(); 180 | 181 | if ($validate === 'false') { 182 | $validate = false; 183 | } elseif ($validate !== 'first' && $validate !== 'only') { 184 | $validate = (bool)$validate; 185 | } 186 | 187 | $saved = $model->saveAll( 188 | $seeds, 189 | array( 190 | 'validate' => $validate 191 | ) 192 | ); 193 | if (!$saved) { 194 | $this->_seeder->out(__('Seeds could not be saved successfully!')); 195 | $this->_seeder->out(__('Data validation errors: %s', var_export($model->validationErrors, true)), 1, Shell::VERBOSE); 196 | } 197 | } 198 | 199 | /** 200 | * Get the model instance 201 | * 202 | * @return Model The model instance. 203 | */ 204 | protected function _getModel() { 205 | $modelName = $this->_seeder->getModelName(); 206 | $model = ClassRegistry::init($modelName); 207 | return $model; 208 | } 209 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CakePHP Fake Seeder 2 | 3 | [![Travis-CI Build Status](https://travis-ci.org/ravage84/cakephp-fake-seeder.png)](https://travis-ci.org/ravage84/cakephp-fake-seeder) 4 | [![Coverage Status](https://img.shields.io/coveralls/ravage84/cakephp-fake-seeder.svg)](https://coveralls.io/r/ravage84/cakephp-fake-seeder?branch=master) 5 | [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/ravage84/cakephp-fake-seeder/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/ravage84/cakephp-fake-seeder/?branch=master) 6 | [![Total Downloads](https://poser.pugx.org/ravage84/cakephp-fake-seeder/d/total.png)](https://packagist.org/packages/ravage84/cakephp-fake-seeder) 7 | [![Latest Stable Version](https://poser.pugx.org/ravage84/cakephp-fake-seeder/v/stable.png)](https://packagist.org/packages/ravage84/cakephp-fake-seeder) 8 | 9 | A CakePHP shell to seed your database with fake and/or fixed data. 10 | 11 | Uses Faker to generate the fake data. 12 | Uses shell tasks for implementing specific seeders. 13 | Organizes logical groups of seeders in custom seeder shells/suites. 14 | 15 | ## Why should I use it? 16 | 17 | You are wondering why you should use this plugin instead of using 18 | [Faker](https://github.com/fzaninotto/Faker) directly or 19 | creating fake data on your own? 20 | 21 | This plugin... 22 | 23 | - keeps you from doing the repetitive work (DRY) 24 | - provides you three working modes (manual faking to fully automatic guessing) 25 | - helps you to stick to conventions, by following 26 | CakePHP's "Convention over Configuration" principle 27 | - still provides you flexible configuration 28 | - reduces documentation needs 29 | - is properly covered by unit tests 30 | - is easy to learn 31 | - is extensible 32 | 33 | ## Installation 34 | 35 | ### Requirements 36 | 37 | - PHP >= 5.4 38 | - CakePHP 2.x (tested with 2.6.2, 2.7.3) 39 | 40 | ### Installation via composer 41 | 42 | ```` 43 | composer require ravage84/cakephp-fake-seeder 44 | ```` 45 | 46 | ### Installation alternatives 47 | 48 | Refer to the CakePHP CookBook section 49 | [How To Install Plugins](http://book.cakephp.org/2.0/en/plugins/how-to-install-plugins.html). 50 | 51 | ## CakePHP Version Support 52 | 53 | This plugin only supports CakePHP 2.x. 54 | 55 | ## Versioning 56 | 57 | The releases of this plugin are versioned using [SemVer](http://semver.org/). 58 | 59 | ## Configuration 60 | 61 | Set the configuration key ``FakeSeeder.seedable`` to true, by adding 62 | ``Configure::write('FakeSeeder.seedable', true);`` to your boostrap code. 63 | 64 | ## How to use 65 | 66 | After installing and configuring the plugin, you can invoke the shell 67 | by executing ``php Console/cake.php FakeSeeder.seeder -h``. 68 | 69 | ```` 70 | Welcome to CakePHP v2.6.2 Console 71 | --------------------------------------------------------------- 72 | App : app 73 | Path: D:\dev\xampp\htdocs\cate\app\ 74 | --------------------------------------------------------------- 75 | A shell to seed your database with fake and/or fixed data. 76 | 77 | Uses Faker to generate the fake data. 78 | Uses shell tasks for implementing specific seeders. 79 | Organizes logical groups of seeders in custom seeder shells/suites. 80 | 81 | Usage: 82 | cake fake_seeder.seeder [options] [] 83 | 84 | Options: 85 | 86 | --help, -h Display this help. 87 | --verbose, -v Enable verbose output. 88 | --quiet, -q Enable quiet output. 89 | --mode, -m The seeding mode. 90 | 'manual' = No Field formatters are guessed. 91 | 'auto' = All field formatters are guessed. 92 | 'mixed' = Only missing field formatters are guessed. 93 | (choices: manual|auto|mixed) 94 | --locale, -l The locale to use for Faker. 95 | --records, -r The amount of records to seed. 96 | --validate Whether or not to validate when saving the seeding 97 | data. (choices: first|1|) 98 | --seed, -s Set the seed number for Faker to use. 99 | --no-truncate Prevents that the model gets truncated before 100 | seeding. 101 | 102 | Arguments: 103 | 104 | model The name of a seeder shell task without 'SeederTask' suffix. 105 | For example 'Article' for 'ArticleSeederTask'. 106 | Alternatively the name of a model. 107 | It will try to guess the field formatters then. 108 | (optional) 109 | 110 | All shell options can be set through: 111 | 1. CLI parameter, e.g. "--records" 112 | 2. The seeder specific configuration, e.g. "FakeSeeder.Article.records" 113 | 3. The general seeder configuration, e.g "FakeSeeder.records" 114 | 4. The seeder shell task class properties, e.g. "$_records" 115 | The values are checked in that order. The first value found is taken. 116 | If no value is set, it will fall back to an optional default value. 117 | 118 | When no seeders are set (e.g. in a custom seeder suite) and if called 119 | without arguments, it will prompt to execute one of the seeder shell 120 | tasks available. 121 | 122 | ```` 123 | 124 | - See [ExampleSeederShell.php](Docs/Examples/ExampleSeederShell.php) for an example how to create 125 | a **custom seeder shell**. 126 | - See [ExampleSeederTask.php](Docs/Examples/ExampleSeederTask.php) for an example how to create 127 | a **custom seeder task**. 128 | 129 | ## Contributing 130 | 131 | See [CONTRIBUTING.md](CONTRIBUTING.md) 132 | 133 | ## Changelog 134 | 135 | See [CHANGELOG.md](CHANGELOG.md) 136 | 137 | ## TODOs 138 | 139 | - Improve Documentation 140 | - Simplify integration of 3rd party data provider 141 | - Implement seeder shell task baking 142 | - Check possibility to use code for TestFixtures, like [gourmet/faker](https://github.com/gourmet/faker) 143 | 144 | ## License 145 | 146 | This plugin is licensed under the [MIT License](LICENSE). 147 | 148 | ## Attribution 149 | 150 | This project was inspired by the works of others, such as: 151 | 152 | - The book ["Build APIs You Won't Hate"](https://leanpub.com/build-apis-you-wont-hate) by [Phil Sturgeon](https://github.com/philsturgeon) 153 | - The [Faker plugin for CakePHP 3.x](https://github.com/gourmet/faker) by [Jad Bitar](https://github.com/jadb) 154 | - [Faker](https://github.com/fzaninotto/Faker) by [Francois Zaninotto](https://github.com/fzaninotto) 155 | - [CakePHP Faker Fixtures Plugin](https://github.com/burriko/cakephp-faker-fixtures/) 156 | - [CakePHP Seed Shell Plugin](https://github.com/jlis/Cake-Seed-Shell) 157 | -------------------------------------------------------------------------------- /Console/Command/SeederShell.php: -------------------------------------------------------------------------------- 1 | _checkSeedable(); 40 | } 41 | 42 | /** 43 | * Check if seeding the database is allowed 44 | * 45 | * @return void 46 | * ¦todo Consider making this over writable by a CLI parameter, e.g. --force or --ignore-check 47 | */ 48 | protected function _checkSeedable() { 49 | if (Configure::read('FakeSeeder.seedable') !== true) { 50 | $this->_stop(__('Seeding is not activated in configuration in "FakeSeeder.seedable"!')); 51 | } 52 | if (Configure::read('debug') < 1) { 53 | $this->_stop(__('Seeding is allowed only in debug mode!')); 54 | } 55 | } 56 | 57 | /** 58 | * Get the Console Option Parser 59 | * 60 | * @return ConsoleOptionParser The Console Option Parser. 61 | */ 62 | public function getOptionParser() { 63 | $parser = parent::getOptionParser(); 64 | 65 | $parser->description(array( 66 | __('A shell to seed your database with fake and/or fixed data.'), 67 | __(''), 68 | __('Uses Faker to generate the fake data.'), 69 | __('Uses shell tasks for implementing specific seeders.'), 70 | __('Organizes logical groups of seeders in custom seeder shells/suites.'), 71 | )); 72 | $parser->addArguments(array( 73 | 'model' => array( 74 | 'help' => "The name of a seeder shell task without 'SeederTask' suffix.\n" . 75 | "For example 'Article' for 'ArticleSeederTask'.\n" . 76 | "Alternatively the name of a model.\n" . 77 | "It will try to guess the field formatters then.", 78 | 'required' => false, 79 | ) 80 | )); 81 | $parser->addOptions(array( 82 | 'mode' => array( 83 | 'help' => "The seeding mode.\n" . 84 | "'manual' = No Field formatters are guessed.\n" . 85 | "'auto' = All field formatters are guessed.\n" . 86 | "'mixed' = Only missing field formatters are guessed.\n", 87 | 'short' => 'm', 88 | 'choices' => array('manual', 'auto', 'mixed'), 89 | 'default' => '', 90 | ), 91 | 'locale' => array( 92 | 'help' => 'The locale to use for Faker.', 93 | 'short' => 'l', 94 | 'default' => '', 95 | ), 96 | 'records' => array( 97 | 'help' => 'The amount of records to seed.', 98 | 'short' => 'r', 99 | 'default' => '', 100 | ), 101 | 'validate' => array( 102 | 'help' => 'Whether or not to validate when saving the seeding data.', 103 | 'choices' => array('first', true, false), 104 | 'default' => '', 105 | ), 106 | 'seed' => array( 107 | 'help' => 'Set the seed number for Faker to use.', 108 | 'short' => 's', 109 | 'default' => '', 110 | ), 111 | 'no-truncate' => array( 112 | 'help' => 'Prevents that the model gets truncated before seeding.', 113 | 'boolean' => true, 114 | ), 115 | )); 116 | $parser->epilog(array( 117 | __('All shell options can be set through:'), 118 | __('1. CLI parameter, e.g. "--records"'), 119 | __('2. The seeder specific configuration, e.g. "FakeSeeder.Article.records"'), 120 | __('3. The general seeder configuration, e.g "FakeSeeder.records"'), 121 | __('4. The seeder shell task class properties, e.g. "$_records"'), 122 | __('The values are checked in that order. The first value found is taken.'), 123 | __('If no value is set, it will fall back to an optional default value.'), 124 | __(''), 125 | __('When no seeders are set (e.g. in a custom seeder suite) and if called without arguments, ' . 126 | 'it will prompt to execute one of the seeder shell tasks available.'), 127 | )); 128 | 129 | return $parser; 130 | } 131 | 132 | /** 133 | * Main Seeder method 134 | * 135 | * If invoked with a seeder name an argument, it executes this single seeder shell task. 136 | * If invoked without seeder name as argument, it prompts for a seeder shell to execute. 137 | * 138 | * @return void 139 | * @todo Consider using DB transaction(s) 140 | */ 141 | public function main() { 142 | // TODO Disable FK constraints 143 | 144 | if (!empty($this->args[0])) { 145 | // Either execute the given seeder task 146 | $seederName = $this->args[0]; 147 | $this->out(__('Execute %s seeder...', $seederName)); 148 | $this->_executeSeederTask($seederName, $this->params['no-truncate']); 149 | } elseif (!empty($this->_seeders)) { 150 | // Execute all seeders set in $_seeders (only applies for subclasses) 151 | if ($this->params['no-truncate'] === false) { 152 | $this->_truncateModels(); 153 | } 154 | $this->_callSeeders(); 155 | } else { 156 | // Prompt for a seeder shell task to execute 157 | $this->_promptForSeeder(); 158 | } 159 | 160 | // TODO Enable FK constraints, if necessary 161 | } 162 | 163 | /** 164 | * Truncate the models 165 | * 166 | * Merges all the models from all seeders with the additionally configured models. 167 | * 168 | * @return void 169 | * @see ShellModelTruncator::truncateModels 170 | */ 171 | protected function _truncateModels() { 172 | $this->out(__('Truncating models...')); 173 | 174 | // Get all models from all seeders 175 | $modelsToTruncate = array(); 176 | foreach ($this->_seeders as $seederName) { 177 | $modelsToTruncate = array_merge( 178 | $modelsToTruncate, 179 | $this->_getModelsToTruncateFromSeederTask($seederName) 180 | ); 181 | } 182 | 183 | $modelsToTruncate = array_merge($modelsToTruncate, $this->_modelsToTruncate); 184 | $modelsToTruncate = array_unique($modelsToTruncate); 185 | 186 | $modelTruncator = $this->_getModelTruncator(); 187 | $modelTruncator->truncateModels($modelsToTruncate); 188 | 189 | $this->out(__('Finished truncating models.')); 190 | } 191 | 192 | /** 193 | * Get an instance of the ShellModelTruncator, for delegating the model truncation 194 | * 195 | * @return ShellModelTruncator The shell model truncator instance. 196 | */ 197 | protected function _getModelTruncator() { 198 | return new ShellModelTruncator($this); 199 | } 200 | 201 | /** 202 | * Get the models to truncate from the seeder task 203 | * 204 | * @param string $seederName The name of the seeder task. 205 | * @return array The models to truncate. 206 | */ 207 | protected function _getModelsToTruncateFromSeederTask($seederName) { 208 | $seederName = $seederName . 'Seeder'; 209 | $seederTask = $this->Tasks->load($seederName); 210 | 211 | $models = $seederTask->getModelsToTruncate(); 212 | return $models; 213 | } 214 | 215 | /** 216 | * Call the seeders of the suite 217 | * 218 | * Does not execute the data truncation in the seeders as we've done that already. 219 | * 220 | * @return void 221 | */ 222 | protected function _callSeeders() { 223 | $this->out(__('Execute seeders...')); 224 | 225 | foreach ($this->_seeders as $seederName) { 226 | $this->out(__('Execute %s seeder...', $seederName)); 227 | $this->_executeSeederTask($seederName, true); 228 | 229 | } 230 | $this->out(__('Finished executing seeders.')); 231 | } 232 | 233 | /** 234 | * Prompts the user with a list of available seeder shell tasks 235 | * 236 | * Only supports app based seeder shell tasks, at the moment. 237 | * 238 | * @return void 239 | */ 240 | protected function _promptForSeeder() { 241 | $seederTasks = $this->_getSeederTasks(); 242 | 243 | $this->out(__('Choose one seeder shell task to execute:')); 244 | $taskCount = count($seederTasks); 245 | for ($i = 0; $i < $taskCount; $i++) { 246 | $this->out(sprintf("%d. %s", $i + 1, $seederTasks[$i])); 247 | } 248 | 249 | $chosenSeeder = $this->in(__("Enter a number from the list above,\n" . 250 | "type in the name of another seeder shell task,\n" . 251 | "type in the name of a model,\n" . 252 | "or 'q' to exit"), null, 'q'); 253 | 254 | if ($chosenSeeder === 'q') { 255 | $this->_stop(); 256 | return; 257 | } 258 | 259 | if (!$chosenSeeder || (int)$chosenSeeder > $taskCount) { 260 | $this->err(__d('cake_console', "The seeder shell task name you supplied was empty,\n" . 261 | "or the number you selected was not a valid option. Please try again.")); 262 | $this->_stop(); 263 | return; 264 | } 265 | if ((int)$chosenSeeder > 0 && (int)$chosenSeeder <= $taskCount) { 266 | $chosenSeeder = $seederTasks[(int)$chosenSeeder - 1]; 267 | } 268 | 269 | $this->out(__('Execute %s seeder...', $chosenSeeder)); 270 | // Add seeder to argument list, in case it is a model 271 | $this->args[0] = $chosenSeeder; 272 | $this->_executeSeederTask($chosenSeeder, $this->params['no-truncate']); 273 | } 274 | 275 | /** 276 | * Get the available seeder shell tasks 277 | * 278 | * Checks for *SeederTask.php files in 279 | * app/Console/Command/Task/. 280 | * 281 | * @return array The available seeder shell tasks. 282 | * @todo Also support plugin shell tasks. 283 | * @todo Improve testability by getting the Folder object from externally. 284 | */ 285 | protected function _getSeederTasks() { 286 | $taskDir = ROOT . DS . APP_DIR . DS . 'Console' . DS . 'Command' . DS . 'Task' . DS; 287 | $dir = new Folder($taskDir); 288 | $files = $dir->find('(.*)SeederTask\.php'); 289 | $seedTasks = array(); 290 | foreach ($files as $file) { 291 | $seedTasks[] = substr(basename($file), 0, -14); 292 | } 293 | sort($seedTasks); 294 | return $seedTasks; 295 | } 296 | 297 | /** 298 | * Execute a seeder Task 299 | * 300 | * Loads a task and make sure it is initialized properly 301 | * 302 | * @param string $seederName The name of the seeder task, without SeederTask. 303 | * @param bool $noTruncate Prevents that the model gets truncated before seeding, defaults to true. 304 | * @return void 305 | */ 306 | protected function _executeSeederTask($seederName, $noTruncate = true) { 307 | $seederNameSuffixed = $seederName . 'Seeder'; 308 | try { 309 | $seederTask = $this->Tasks->load($seederNameSuffixed); 310 | } catch (MissingTaskException $e) { 311 | $this->out(__( 312 | "No seeder shell tasks named '%s' found. Trying to find a '%s' model.", 313 | $seederNameSuffixed, 314 | $seederName 315 | )); 316 | 317 | // Make sure the table/model exists 318 | $model = $this->_loadSeederModel($seederName); 319 | if ($model === false) { 320 | $this->out(__("No model '%s' found , aborting.", $seederName)); 321 | return; 322 | } 323 | 324 | // Execute the DynamicModelSeeder if the model exists 325 | $seederTask = $this->Tasks->load('FakeSeeder.DynamicModelSeeder'); 326 | } 327 | // Copy given arguments & parameters 328 | $seederTask->args =& $this->args; 329 | $seederTask->params =& $this->params; 330 | // Overwrite no-truncate to make ake sure a task does not truncates again 331 | // when executed as a site 332 | $seederTask->params['no-truncate'] = $noTruncate; 333 | 334 | $seederTask->initialize(); 335 | 336 | $seederTask->execute(); 337 | } 338 | 339 | /** 340 | * Load a model to seed 341 | * 342 | * @param string $seederName The model to load 343 | * @return 344 | */ 345 | protected function _loadSeederModel($seederName) { 346 | return ClassRegistry::init($seederName); 347 | } 348 | } 349 | -------------------------------------------------------------------------------- /Console/SeederTaskBase.php: -------------------------------------------------------------------------------- 1 | _getFaker(); 140 | 141 | // Disable FK constraints 142 | 143 | if ($this->getNoTruncate() === false) { 144 | $this->_truncateModels(); 145 | } 146 | 147 | // Process the fixtures before the fake seeds 148 | $seedProcessor = $this->_getSeedProcessor(); 149 | $seedProcessor->processFixtures(); 150 | $seedProcessor->sowSeeds(); 151 | 152 | // Enable FK constraints, if necessary 153 | } 154 | 155 | /** 156 | * Get a ShellSeedProcessor instance 157 | * 158 | * @return ShellSeedProcessor An instance of ShellSeedProcessor. 159 | */ 160 | protected function _getSeedProcessor() { 161 | return new ShellSeedProcessor($this); 162 | } 163 | 164 | /** 165 | * Get the Faker generator with the (optionally) configured locale 166 | * 167 | * @return Generator 168 | */ 169 | protected function _getFaker() { 170 | $locale = $this->getLocale(); 171 | $seed = $this->getSeedingNumber(); 172 | 173 | $this->out(__('Create Faker instance with "%s" locale...', $locale), 1, Shell::VERBOSE); 174 | 175 | $this->faker = Factory::create($locale); 176 | if (!empty($seed)) { 177 | $this->out(__("Use seed '%s' for Faker.", $seed), 1, Shell::VERBOSE); 178 | $this->faker->seed($seed); 179 | } 180 | return $this->faker; 181 | } 182 | 183 | /** 184 | * Truncate the models 185 | * 186 | * @return void 187 | * @see ShellModelTruncator::truncateModels 188 | */ 189 | protected function _truncateModels() { 190 | $modelsToTruncate = $this->getModelsToTruncate(); 191 | 192 | $modelTruncator = $this->_getModelTruncator(); 193 | $modelTruncator->truncateModels($modelsToTruncate); 194 | } 195 | 196 | /** 197 | * Get an instance of the ShellModelTruncator, for delegating the model truncation 198 | * 199 | * @return ShellModelTruncator The shell model truncator instance. 200 | */ 201 | protected function _getModelTruncator() { 202 | return new ShellModelTruncator($this); 203 | } 204 | 205 | /** 206 | * Get models to truncate 207 | * 208 | * Returns the ones set in $_modelsToTruncate oo 209 | * gets the model name based on the current 210 | * seeder shell task name. 211 | * 212 | * @return array The models to truncate. 213 | */ 214 | public function getModelsToTruncate() { 215 | if (!empty($this->_modelsToTruncate)) { 216 | return $this->_modelsToTruncate; 217 | } 218 | 219 | $modelName = $this->getModelName(); 220 | return array($modelName); 221 | } 222 | 223 | /** 224 | * Set/get the fixture records 225 | * 226 | * @return array The fixture records. 227 | */ 228 | public function fixtureRecords() { 229 | return $this->_fixtureRecords; 230 | } 231 | 232 | /** 233 | * Set/get the field formatters 234 | * 235 | * @return array The formatters per field. 236 | * @link https://github.com/fzaninotto/Faker#formatters 237 | */ 238 | abstract public function fieldFormatters(); 239 | 240 | /** 241 | * Merges the given field formatters with the exiting ones 242 | * 243 | * @param array $fieldFormatters The field formatters to merge. 244 | * @return array The merged field formatters. 245 | */ 246 | protected function _mergeFieldFormatters($fieldFormatters) { 247 | $this->_fieldFormatters = array_merge( 248 | $this->_fieldFormatters, 249 | $fieldFormatters 250 | ); 251 | return $this->_fieldFormatters; 252 | } 253 | 254 | /** 255 | * Set/get state per record 256 | * 257 | * Can be overridden to return some state with data per record. 258 | * 259 | * @return array The state per record. 260 | */ 261 | public function recordState() { 262 | return array(); 263 | } 264 | 265 | /** 266 | * Get the model name 267 | * 268 | * @return string The model name. 269 | */ 270 | public function getModelName() { 271 | $modelName = $this->_getSeederNamePrefix(); 272 | if (!empty($this->_modelName)) { 273 | $modelName = $this->_modelName; 274 | } 275 | 276 | return $modelName; 277 | } 278 | 279 | /** 280 | * Get the seeding mode 281 | * 282 | * @return mixed The the seeding mode. 283 | */ 284 | public function getSeedingMode() { 285 | $configKey = 'mode'; 286 | $propertyName = '_mode'; 287 | $defaultValue = 'manual'; 288 | return $this->_getParameter($configKey, $propertyName, $defaultValue); 289 | } 290 | 291 | /** 292 | * Get the locale to use for Faker 293 | * 294 | * @return string The locale for Faker. 295 | */ 296 | public function getLocale() { 297 | $configKey = 'locale'; 298 | $propertyName = '_locale'; 299 | $defaultValue = 'en_US'; 300 | return $this->_getParameter($configKey, $propertyName, $defaultValue); 301 | } 302 | 303 | /** 304 | * Get record count to create 305 | * 306 | * @return mixed The amount of records to create. 307 | */ 308 | public function getRecordsCount() { 309 | $configKey = 'records'; 310 | $propertyName = '_records'; 311 | $defaultValue = 10; 312 | 313 | $records = $this->_getParameter($configKey, $propertyName, $defaultValue); 314 | 315 | $records = $this->_enforceRecordMaximum($records); 316 | $records = $this->_enforceRecordMinimum($records); 317 | return $records; 318 | } 319 | 320 | /** 321 | * Enforce the maximum amount of records to be seeded 322 | * 323 | * @param int $records The amount of records to check/reduce. 324 | * @return int The enforced maximum amount of records. 325 | */ 326 | protected function _enforceRecordMaximum($records) { 327 | if (isset($this->_maxRecords) && $records > $this->_maxRecords) { 328 | $this->out(__('%s records exceed the allowed maximum amount. Reducing it to %s records.', 329 | $records, $this->_maxRecords), 1, Shell::VERBOSE); 330 | 331 | return $this->_maxRecords; 332 | } 333 | 334 | return $records; 335 | } 336 | 337 | /** 338 | * Enforce the minimum amount of records to be seeded 339 | * 340 | * @param int $records The amount of records to check/increase. 341 | * @return int The enforced minimum amount of records. 342 | */ 343 | protected function _enforceRecordMinimum($records) { 344 | if (isset($this->_minRecords) && $records < $this->_minRecords) { 345 | $this->out(__('%s records fall below the allowed minimum amount. Increasing it to %s records.', 346 | $records, $this->_minRecords), 1, Shell::VERBOSE); 347 | 348 | return $this->_minRecords; 349 | } 350 | 351 | return $records; 352 | } 353 | 354 | /** 355 | * Get whether or not to validate seeding 356 | * 357 | * @return bool|string Whether or not to validate seeding. 358 | * @see Model::saveAll() See for possible values for `validate`. 359 | */ 360 | public function getValidateSeeding() { 361 | $configKey = 'validate'; 362 | $propertyName = '_validateSeeding'; 363 | $defaultValue = 'first'; 364 | return $this->_getParameter($configKey, $propertyName, $defaultValue); 365 | } 366 | 367 | /** 368 | * Get the seed number for Faker to use 369 | * 370 | * @return bool|string The seed number for Faker to use 371 | * @see Generator::seed Faker's seed method. 372 | */ 373 | public function getSeedingNumber() { 374 | $configKey = 'seed'; 375 | $propertyName = '_seedingNumber'; 376 | $defaultValue = null; 377 | return $this->_getParameter($configKey, $propertyName, $defaultValue); 378 | } 379 | 380 | /** 381 | * Get whether or not to truncate the model 382 | * 383 | * @return bool Whether or not to truncate the model 384 | */ 385 | public function getNoTruncate() { 386 | $configKey = 'no-truncate'; 387 | $propertyName = '_noTruncate'; 388 | $defaultValue = false; 389 | return $this->_getParameter($configKey, $propertyName, $defaultValue); 390 | } 391 | 392 | /** 393 | * Get the value of a parameter 394 | * 395 | * Inspects 396 | * 1. The CLI parameters, e.g. "--records" 397 | * 2. The seeder specific configuration, e.g. "FakeSeeder.Article.records" 398 | * 3. The general seeder configuration, e.g "FakeSeeder.records" 399 | * 4. The seeder shell task class properties, e.g. "$_records" 400 | * 4. Falls back to an optional default value 401 | * 402 | * @param string $configKey The name of the config key to check. 403 | * @param string $propertyName The name of the class property to check. 404 | * @param string $defaultValue The default value to use as fallback, optional. 405 | * @return mixed The value of the parameter. 406 | */ 407 | protected function _getParameter($configKey, $propertyName, $defaultValue = null) { 408 | // If given as CLI parameter, use that value 409 | if ($this->params[$configKey]) { 410 | $this->out(__('Parameter "%s" given through CLI parameter: "%s"', $configKey, $this->params[$configKey]), 1, Shell::VERBOSE); 411 | return $this->params[$configKey]; 412 | } 413 | 414 | // If set in the seeder specific configuration, use that value 415 | $localeConfigKey = sprintf('%s.%s', $this->_getSeederConfigKey(), $configKey); 416 | if (Configure::check($localeConfigKey)) { 417 | $this->out(__('Parameter "%s" configured in seeder specific configuration: "%s"', $configKey, Configure::read($localeConfigKey)), 1, Shell::VERBOSE); 418 | return Configure::read($localeConfigKey); 419 | } 420 | 421 | // If set in the general FakeSeeder configuration, use that value 422 | $localeConfigKey = sprintf('%s.%s', $this->_getSeederShellName(), $configKey); 423 | if (Configure::check($localeConfigKey)) { 424 | $this->out(__('Parameter "%s" configured in general seeder configuration: "%s"', $configKey, Configure::read($localeConfigKey)), 1, Shell::VERBOSE); 425 | return Configure::read($localeConfigKey); 426 | } 427 | 428 | // If set in the seeder class, use that value 429 | if ($this->{$propertyName}) { 430 | $this->out(__('Parameter "%s" set in class: "%s"', $configKey, $this->{$propertyName}), 1, Shell::VERBOSE); 431 | return $this->{$propertyName}; 432 | } 433 | 434 | $this->out(__('Parameter "%s" not given/configured, falling back to default "%s".', $configKey, $defaultValue), 1, Shell::VERBOSE); 435 | // Otherwise use the default value as fallback 436 | return $defaultValue; 437 | } 438 | 439 | /** 440 | * Get the seeder specific config key 441 | * 442 | * Can be overridden by setting $_configKey 443 | * 444 | * @return string The seeder specific config key. 445 | * @see ::$_configKey 446 | */ 447 | protected function _getSeederConfigKey() { 448 | $configKey = $this->_getSeederNamePrefix(); 449 | if (!empty($this->_configKey)) { 450 | $configKey = $this->_configKey; 451 | } 452 | 453 | return sprintf('%s.%s', $this->_getSeederShellName(), $configKey); 454 | } 455 | 456 | /** 457 | * Get the prefix of the seeder (class) shell task name 458 | * 459 | * "Article" for "ArticleSeederTask". 460 | * 461 | * @return string The prefix of the seeder (class) shell task name. 462 | */ 463 | protected function _getSeederNamePrefix() { 464 | $className = get_class($this); 465 | $seederName = substr($className, 0, -10); 466 | return $seederName; 467 | } 468 | 469 | /** 470 | * Get the name of the seeder shell 471 | * 472 | * @return string The name of the seeder shell. 473 | * @todo Return actual name of the seeder shell (not task!). 474 | */ 475 | protected function _getSeederShellName() { 476 | return 'FakeSeeder'; 477 | } 478 | } 479 | -------------------------------------------------------------------------------- /Test/Case/Lib/ShellSeedProcessorTest.php: -------------------------------------------------------------------------------- 1 | getMock('ConsoleOutput', array(), array(), '', false); 56 | $in = $this->getMock('ConsoleInput', array(), array(), '', false); 57 | $this->_seeder = $this->getMock('SeederTaskBase', 58 | array(), 59 | array($out, $out, $in) 60 | ); 61 | } 62 | 63 | /** 64 | * Create a ShellSeedProcessor mock 65 | * 66 | * @param array $methods The methods to mock. 67 | * @return void 68 | */ 69 | protected function _createProcessorMock($methods) { 70 | $this->_processor = $this->getMock( 71 | 'ShellSeedProcessor', 72 | $methods, 73 | array($this->_seeder) 74 | ); 75 | } 76 | 77 | /** 78 | * Test the constructor 79 | * 80 | * @return void 81 | * @covers ::__construct 82 | */ 83 | public function testConstruct() { 84 | $processor = new ShellSeedProcessor($this->_seeder); 85 | $this->assertAttributeInstanceOf('SeederTaskBase', '_seeder', $processor); 86 | } 87 | 88 | /** 89 | * Tests the processFixtures method 90 | * 91 | * @return void 92 | * @covers ::processFixtures 93 | */ 94 | public function testProcessFixtures() { 95 | $this->_createProcessorMock(array('saveSeeds')); 96 | $fixtures = array(array('Model' => array('foo' => 'bar'))); 97 | 98 | $this->_seeder->expects($this->at(0))->method('fixtureRecords')->will($this->returnValue($fixtures)); 99 | $this->_processor->expects($this->at(0))->method('saveSeeds'); 100 | 101 | $this->_processor->processFixtures(); 102 | } 103 | 104 | /** 105 | * Tests the processFixtures method with no fixtures set 106 | * 107 | * @return void 108 | * @covers ::processFixtures 109 | */ 110 | public function testProcessFixturesNoFixturesSet() { 111 | $this->_createProcessorMock(array('saveSeeds')); 112 | 113 | $fixtures = array(); 114 | 115 | $this->_seeder->expects($this->at(0))->method('fixtureRecords')->will($this->returnValue($fixtures)); 116 | $this->_processor->expects($this->never())->method('saveSeeds'); 117 | 118 | $this->_processor->processFixtures(); 119 | } 120 | 121 | /** 122 | * Tests the sowSeeds method when there are no field formatters 123 | * 124 | * @return void 125 | * @covers ::sowSeeds 126 | */ 127 | public function testSowSeedsNoFieldFormatters() { 128 | $this->_createProcessorMock(array('getFieldFormatters', 'createSeed', 'saveSeeds')); 129 | 130 | $this->_seeder->expects($this->at(0))->method('getModelName')->will($this->returnValue('Apple')); 131 | $this->_seeder->expects($this->at(1))->method('getRecordsCount')->will($this->returnValue(5)); 132 | $this->_seeder->expects($this->at(2))->method('out')->with($this->equalTo('Sowing 5 seeds for model Apple')); 133 | $this->_seeder->expects($this->at(3))->method('out')->with($this->equalTo('No field formatters configured, aborting.')); 134 | 135 | $this->_processor->expects($this->at(0))->method('getFieldFormatters')->will($this->returnValue(array())); 136 | $this->_processor->expects($this->never())->method('createSeed'); 137 | $this->_processor->expects($this->never())->method('saveSeeds'); 138 | 139 | $this->_processor->sowSeeds(); 140 | } 141 | 142 | /** 143 | * Tests the sowSeeds method when empty seeds get created 144 | * 145 | * @return void 146 | * @covers ::sowSeeds 147 | */ 148 | public function testSowSeedsCreatedSeedEmpty() { 149 | $this->_createProcessorMock(array('getFieldFormatters', 'createSeed', 'saveSeeds')); 150 | 151 | $this->_seeder->expects($this->at(0))->method('getModelName')->will($this->returnValue('Apple')); 152 | $this->_seeder->expects($this->at(1))->method('getRecordsCount')->will($this->returnValue(5)); 153 | $this->_seeder->expects($this->at(2))->method('out')->with($this->equalTo('Sowing 5 seeds for model Apple')); 154 | $this->_seeder->expects($this->at(3))->method('out')->with($this->equalTo('Created seed is empty! Check the field formatters.')); 155 | $this->_seeder->expects($this->at(4))->method('out')->with($this->equalTo('Finished sowing 5 seeds for model Apple')); 156 | 157 | $this->_processor->expects($this->at(0))->method('getFieldFormatters')->will($this->returnValue(array('NotEmpty'))); 158 | $this->_processor->expects($this->at(1))->method('createSeed')->will($this->returnValue(array())); 159 | $this->_processor->expects($this->at(2))->method('saveSeeds'); 160 | 161 | $this->_processor->sowSeeds(); 162 | } 163 | 164 | /** 165 | * Tests the sowSeeds method 166 | * 167 | * @return void 168 | * @covers ::sowSeeds 169 | */ 170 | public function testSowSeeds() { 171 | $this->_createProcessorMock(array('getFieldFormatters', 'createSeed', 'saveSeeds')); 172 | 173 | $this->_seeder->expects($this->at(0))->method('getModelName')->will($this->returnValue('Apple')); 174 | $this->_seeder->expects($this->at(1))->method('getRecordsCount')->will($this->returnValue(5)); 175 | $this->_seeder->expects($this->at(2))->method('out')->with($this->equalTo('Sowing 5 seeds for model Apple')); 176 | $this->_seeder->expects($this->at(4))->method('out')->with($this->equalTo('.'), $this->equalTo(0)); 177 | $this->_seeder->expects($this->at(5))->method('out')->with($this->equalTo('.'), $this->equalTo(0)); 178 | $this->_seeder->expects($this->at(6))->method('out')->with($this->equalTo('.'), $this->equalTo(0)); 179 | $this->_seeder->expects($this->at(7))->method('out')->with($this->equalTo('.'), $this->equalTo(0)); 180 | $this->_seeder->expects($this->at(8))->method('out')->with($this->equalTo(' 5 / 5'), $this->equalTo(1)); 181 | $this->_seeder->expects($this->at(9))->method('out')->with($this->equalTo('Finished sowing 5 seeds for model Apple')); 182 | 183 | $this->_processor->expects($this->at(0))->method('getFieldFormatters')->will($this->returnValue(array('NotEmpty'))); 184 | $this->_processor->expects($this->exactly(5))->method('createSeed')->will($this->returnValue(array('NotEmpty'))); 185 | $this->_processor->expects($this->at(2))->method('saveSeeds'); 186 | 187 | $this->_processor->sowSeeds(); 188 | } 189 | 190 | /** 191 | * Tests the sowSeeds method when sowing more than 50 seeds 192 | * 193 | * @return void 194 | * @covers ::sowSeeds 195 | */ 196 | public function testSowSeedsFithyPlus() { 197 | $this->_createProcessorMock(array('getFieldFormatters', 'createSeed', 'saveSeeds')); 198 | 199 | $this->_seeder->expects($this->at(0))->method('getModelName')->will($this->returnValue('Apple')); 200 | $this->_seeder->expects($this->at(1))->method('getRecordsCount')->will($this->returnValue(55)); 201 | $this->_seeder->expects($this->at(3))->method('out')->with($this->equalTo('.'), $this->equalTo(0)); 202 | $this->_seeder->expects($this->at(53))->method('out')->with($this->equalTo(' 50 / 55'), $this->equalTo(1)); 203 | $this->_seeder->expects($this->at(58))->method('out')->with($this->equalTo('.'), $this->equalTo(0)); 204 | $this->_seeder->expects($this->at(59))->method('out')->with( 205 | $this->equalTo(str_repeat(' ', 46) . '55 / 55', 1) 206 | ); 207 | 208 | $this->_processor->expects($this->at(0))->method('getFieldFormatters')->will($this->returnValue(array('NotEmpty'))); 209 | $this->_processor->expects($this->any())->method('createSeed')->will($this->returnValue(array('NotEmpty'))); 210 | $this->_processor->expects($this->at(2))->method('saveSeeds'); 211 | 212 | $this->_processor->sowSeeds(); 213 | } 214 | 215 | /** 216 | * Tests the getFieldFormatters method for 'manual' mode 217 | * 218 | * @return void 219 | * @covers ::getFieldFormatters 220 | */ 221 | public function testGetFieldFormattersManualMode() { 222 | $this->_createProcessorMock(array('_guessFieldFormatters')); 223 | 224 | $expected = array('field formatters from manual mode'); 225 | 226 | $this->_seeder->expects($this->at(0))->method('getSeedingMode')->will($this->returnValue('manual')); 227 | $this->_seeder->expects($this->at(1))->method('fieldFormatters')->will($this->returnValue($expected)); 228 | $this->_processor->expects($this->never())->method('_guessFieldFormatters'); 229 | 230 | $result = $this->_processor->getFieldFormatters(); 231 | $this->assertEquals($expected, $result); 232 | } 233 | 234 | /** 235 | * Tests the getFieldFormatters method for 'auto' mode 236 | * 237 | * @return void 238 | * @covers ::getFieldFormatters 239 | */ 240 | public function testGetFieldFormattersAutolMode() { 241 | $this->_createProcessorMock(array('_guessFieldFormatters')); 242 | 243 | $expected = array('field formatters from auto mode'); 244 | 245 | $this->_seeder->expects($this->at(0))->method('getSeedingMode')->will($this->returnValue('auto')); 246 | $this->_seeder->expects($this->never())->method('fieldFormatters'); 247 | $this->_processor->expects($this->at(0))->method('_guessFieldFormatters')->will($this->returnValue($expected)); 248 | 249 | $result = $this->_processor->getFieldFormatters(); 250 | $this->assertEquals($expected, $result); 251 | } 252 | 253 | /** 254 | * Tests the getFieldFormatters method for 'mixed' mode 255 | * 256 | * @return void 257 | * @covers ::getFieldFormatters 258 | */ 259 | public function testGetFieldFormattersMixedMode() { 260 | $this->_createProcessorMock(array('_guessFieldFormatters')); 261 | 262 | $manualMode = array('field formatters from manual mode'); 263 | $autoMode = array('field formatters from auto mode'); 264 | $expected = array_merge( 265 | $autoMode, 266 | $manualMode 267 | ); 268 | 269 | $this->_seeder->expects($this->at(0))->method('getSeedingMode')->will($this->returnValue('mixed')); 270 | $this->_seeder->expects($this->once())->method('fieldFormatters')->will($this->returnValue($manualMode)); 271 | $this->_processor->expects($this->once())->method('_guessFieldFormatters')->will($this->returnValue($autoMode)); 272 | 273 | $result = $this->_processor->getFieldFormatters(); 274 | $this->assertEquals($expected, $result); 275 | } 276 | 277 | /** 278 | * Tests the getFieldFormatters method for an invalid mode 279 | * 280 | * @return void 281 | * @covers ::getFieldFormatters 282 | */ 283 | public function testGetFieldFormattersInvalidMode() { 284 | $this->_createProcessorMock(array('_guessFieldFormatters')); 285 | 286 | $this->_seeder->expects($this->at(0))->method('getSeedingMode')->will($this->returnValue('foo')); 287 | $this->_seeder->expects($this->never())->method('fieldFormatters'); 288 | $this->_processor->expects($this->never())->method('_guessFieldFormatters'); 289 | 290 | $result = $this->_processor->getFieldFormatters(); 291 | $this->assertEmpty($result); 292 | } 293 | 294 | /** 295 | * Tests the _guessFieldFormatters method 296 | * 297 | * @return void 298 | * @covers ::_guessFieldFormatters 299 | * @covers ::_getColumns 300 | */ 301 | public function testGuessFieldFormatters() { 302 | $this->_createProcessorMock(array('_getModel', '_getColumnTypeGuesser')); 303 | 304 | $model = $this->getMock('Apple', array('schema')); 305 | $model->primaryKey = 'id'; 306 | 307 | $schema = array( 308 | 'id' => array( 309 | 'type' => 'integer', 310 | 'null' => false, 311 | 'default' => NULL, 312 | 'length' => 11, 313 | 'unsigned' => false, 314 | 'key' => 'primary', 315 | ), 316 | 'field1' => array( 317 | 'type' => 'string', 318 | 'null' => false, 319 | 'default' => NULL, 320 | 'length' => 255, 321 | 'collate' => 'latin1_swedish_ci', 322 | 'charset' => 'latin1', 323 | ), 324 | 'field2' => array( 325 | 'type' => 'datetime', 326 | 'null' => true, 327 | 'default' => NULL, 328 | 'length' => NULL, 329 | ), 330 | ); 331 | 332 | $guesser = $this->getMock( 333 | 'ColumnTypeGuesser', 334 | array(), 335 | array(), 336 | '', 337 | false 338 | ); 339 | 340 | $guessedFormats = 'guessed formatter'; 341 | 342 | $this->_seeder->expects($this->at(0))->method('getSeedingMode')->will($this->returnValue('auto')); 343 | $this->_processor->expects($this->at(0))->method('_getModel')->will($this->returnValue($model)); 344 | $model->expects($this->at(0))->method('schema')->will($this->returnValue($schema)); 345 | $this->_processor->expects($this->at(1))->method('_getColumnTypeGuesser')->will($this->returnValue($guesser)); 346 | $guesser->expects($this->at(0))->method('guessFormat') 347 | ->with($this->equalTo($schema['field1'])) 348 | ->will($this->returnValue($guessedFormats)); 349 | $guesser->expects($this->at(1))->method('guessFormat') 350 | ->with($this->equalTo($schema['field2'])) 351 | ->will($this->returnValue($guessedFormats)); 352 | 353 | $result = $this->_processor->getFieldFormatters(); 354 | $expected = array( 355 | 'field1' => $guessedFormats, 356 | 'field2' => $guessedFormats, 357 | ); 358 | $this->assertEquals($expected, $result); 359 | } 360 | 361 | /** 362 | * Tests the createSeed method 363 | * 364 | * @return void 365 | * @covers ::createSeed 366 | */ 367 | public function testCreateSeed() { 368 | $this->_createProcessorMock(array('_getModel')); 369 | 370 | $this->_seeder->expects($this->at(0))->method('getModelName')->will($this->returnValue('ModelName')); 371 | $this->_seeder->expects($this->at(1))->method('recordState')->will($this->returnValue('state1')); 372 | 373 | $callable = function ($state) { 374 | return $state; 375 | }; 376 | 377 | $fieldFormatters = array( 378 | 'field1' => $callable, 379 | 'field2' => $callable, 380 | ); 381 | $result = $this->_processor->createSeed($fieldFormatters); 382 | $expected = array( 383 | 'ModelName' => array( 384 | 'field1' => 'state1', 385 | 'field2' => 'state1', 386 | ), 387 | ); 388 | $this->assertEquals($expected, $result); 389 | } 390 | 391 | /** 392 | * Tests the saveSeeds method when validate is 'false' 393 | * 394 | * @return void 395 | * @covers ::saveSeeds 396 | */ 397 | public function testSaveSeedsValidateFalse() { 398 | $this->_createProcessorMock(array('_getModel')); 399 | $seeds = array('seeds'); 400 | $model = $this->getMock('Apple', array('saveAll')); 401 | $options = array( 402 | 'validate' => false 403 | ); 404 | 405 | $this->_seeder->expects($this->at(0))->method('getValidateSeeding')->will($this->returnValue('false')); 406 | $this->_processor->expects($this->at(0))->method('_getModel')->will($this->returnValue($model)); 407 | $model->expects($this->at(0))->method('saveAll')->with( 408 | $this->equalTo($seeds), 409 | $this->equalTo($options) 410 | )->will($this->returnValue(true)); 411 | 412 | $this->_seeder->expects($this->never())->method('out'); 413 | 414 | $this->_processor->saveSeeds($seeds); 415 | } 416 | 417 | /** 418 | * Tests the saveSeeds method when validate casts to true 419 | * 420 | * @return void 421 | * @covers ::saveSeeds 422 | */ 423 | public function testSaveSeedsValidateTrue() { 424 | $this->_createProcessorMock(array('_getModel')); 425 | $seeds = array('seeds'); 426 | $model = $this->getMock('Apple', array('saveAll')); 427 | $options = array( 428 | 'validate' => true 429 | ); 430 | 431 | $this->_seeder->expects($this->at(0))->method('getValidateSeeding')->will($this->returnValue('true')); 432 | $this->_processor->expects($this->at(0))->method('_getModel')->will($this->returnValue($model)); 433 | $model->expects($this->at(0))->method('saveAll')->with( 434 | $this->equalTo($seeds), 435 | $this->equalTo($options) 436 | )->will($this->returnValue(true)); 437 | 438 | $this->_seeder->expects($this->never())->method('out'); 439 | 440 | $this->_processor->saveSeeds($seeds); 441 | } 442 | 443 | /** 444 | * Tests the saveSeeds method when saving fails 445 | * 446 | * @return void 447 | * @covers ::saveSeeds 448 | */ 449 | public function testSaveSeedsNotSaved() { 450 | $this->_createProcessorMock(array('_getModel')); 451 | $seeds = array('seeds'); 452 | $model = $this->getMock('Apple', array('saveAll')); 453 | $options = array( 454 | 'validate' => 'first' 455 | ); 456 | 457 | $model->validationErrors = 'test123'; 458 | 459 | $this->_seeder->expects($this->at(0))->method('getValidateSeeding')->will($this->returnValue('first')); 460 | $this->_processor->expects($this->at(0))->method('_getModel')->will($this->returnValue($model)); 461 | 462 | $model->expects($this->at(0))->method('saveAll')->with( 463 | $this->equalTo($seeds), 464 | $this->equalTo($options) 465 | )->will($this->returnValue(false)); 466 | 467 | $this->_seeder->expects($this->at(1))->method('out')->with($this->equalTo('Seeds could not be saved successfully!')); 468 | $this->_seeder->expects($this->at(2))->method('out')->with($this->equalTo("Data validation errors: 'test123'")); 469 | 470 | $this->_processor->saveSeeds($seeds); 471 | } 472 | } 473 | -------------------------------------------------------------------------------- /Test/Case/Console/Command/SeederShellTest.php: -------------------------------------------------------------------------------- 1 | _createShellMock( 70 | array('in', 'out', 'hr', 'createFile', 'error', 'err', '_stop', '_showInfo', 'dispatchShell', '_getSeederTasks') 71 | ); 72 | } 73 | 74 | /** 75 | * Creates a shell mock 76 | * 77 | * @param array $methods A list of methods to mock. 78 | * @param string $className Optional name of the seeder shell class to mock. 79 | * @return void 80 | */ 81 | protected function _createShellMock($methods, $className = 'SeederShell') { 82 | $out = $this->getMock('ConsoleOutput', array(), array(), '', false); 83 | $in = $this->getMock('ConsoleInput', array(), array(), '', false); 84 | $this->_shell = $this->getMock( 85 | $className, 86 | $methods, 87 | array($out, $out, $in) 88 | ); 89 | } 90 | 91 | /** 92 | * Test the seedability check on init 93 | * 94 | * @return void 95 | * @covers ::initialize 96 | * @covers ::_checkSeedable 97 | */ 98 | public function testNotSeedable() { 99 | Configure::delete('FakeSeeder.seedable'); 100 | $this->_shell->expects($this->at(0))->method('_stop')->with( 101 | $this->equalTo('Seeding is not activated in configuration in "FakeSeeder.seedable"!') 102 | ); 103 | $this->_shell->initialize(); 104 | 105 | 106 | $debug = Configure::read('debug'); 107 | Configure::write('debug', 0); 108 | $this->_shell->expects($this->at(1))->method('_stop')->with( 109 | $this->equalTo('Seeding is allowed only in debug mode!') 110 | ); 111 | $this->_shell->initialize(); 112 | Configure::write('debug', $debug); 113 | } 114 | 115 | /** 116 | * Tests the getOptionParser method 117 | * 118 | * @return void 119 | * @covers ::getOptionParser 120 | */ 121 | public function testGetOptionParser() { 122 | $perser = $this->_shell->getOptionParser(); 123 | 124 | $this->assertNotEmpty($perser->description()); 125 | 126 | $arguments = $perser->arguments(); 127 | $this->assertArrayHasKey(0, $arguments); 128 | $arg = $arguments[0]; 129 | $this->assertEquals('model', $arg->name()); 130 | $this->assertFalse($arg->isRequired()); 131 | $this->assertNotEmpty($arg->help()); 132 | 133 | $options = $perser->options(); 134 | 135 | $this->assertArrayHasKey('mode', $options); 136 | $this->assertArrayHasKey('locale', $options); 137 | $this->assertArrayHasKey('records', $options); 138 | $this->assertArrayHasKey('validate', $options); 139 | $this->assertArrayHasKey('seed', $options); 140 | $this->assertArrayHasKey('no-truncate', $options); 141 | 142 | $option = $options['mode']; 143 | $this->assertEquals('mode', $option->name()); 144 | $this->assertAttributeNotEmpty('_help', $option); 145 | $this->assertEquals('m', $option->short()); 146 | $this->assertFalse($option->isBoolean()); 147 | $this->assertEquals('', $option->defaultValue()); 148 | $this->assertAttributeEquals(array('manual', 'auto', 'mixed'), '_choices', $option); 149 | 150 | $option = $options['locale']; 151 | $this->assertEquals('locale', $option->name()); 152 | $this->assertAttributeNotEmpty('_help', $option); 153 | $this->assertEquals('l', $option->short()); 154 | $this->assertFalse($option->isBoolean()); 155 | $this->assertEquals('', $option->defaultValue()); 156 | $this->assertAttributeEmpty('_choices', $option); 157 | 158 | $option = $options['records']; 159 | $this->assertEquals('records', $option->name()); 160 | $this->assertAttributeNotEmpty('_help', $option); 161 | $this->assertEquals('r', $option->short()); 162 | $this->assertFalse($option->isBoolean()); 163 | $this->assertEquals('', $option->defaultValue()); 164 | $this->assertAttributeEmpty('_choices', $option); 165 | 166 | $option = $options['validate']; 167 | $this->assertEquals('validate', $option->name()); 168 | $this->assertAttributeNotEmpty('_help', $option); 169 | $this->assertEmpty($option->short()); 170 | $this->assertFalse($option->isBoolean()); 171 | $this->assertEquals('', $option->defaultValue()); 172 | $this->assertAttributeEquals(array('first', true, false), '_choices', $option); 173 | 174 | $option = $options['seed']; 175 | $this->assertEquals('seed', $option->name()); 176 | $this->assertAttributeNotEmpty('_help', $option); 177 | $this->assertEquals('s', $option->short()); 178 | $this->assertFalse($option->isBoolean()); 179 | $this->assertEquals('', $option->defaultValue()); 180 | $this->assertAttributeEmpty('_choices', $option); 181 | 182 | $option = $options['no-truncate']; 183 | $this->assertEquals('no-truncate', $option->name()); 184 | $this->assertAttributeNotEmpty('_help', $option); 185 | $this->assertEmpty($option->short()); 186 | $this->assertTrue($option->isBoolean()); 187 | $this->assertEquals('', $option->defaultValue()); 188 | $this->assertAttributeEmpty('_choices', $option); 189 | 190 | $this->assertNotEmpty($perser->epilog()); 191 | } 192 | 193 | /** 194 | * Test the main method when quitting the tasks prompt 195 | * 196 | * @return void 197 | * @covers ::main 198 | * @covers ::_promptForSeeder 199 | */ 200 | public function testMainQuitPrompt() { 201 | $tasks = array('Apple', 'Banana'); 202 | $this->_shell->expects($this->at(0))->method('_getSeederTasks')->will($this->returnValue($tasks)); 203 | $this->_shell->expects($this->at(1))->method('out')->with( 204 | $this->equalTo('Choose one seeder shell task to execute:') 205 | ); 206 | $this->_shell->expects($this->at(2))->method('out')->with( 207 | $this->equalTo('1. Apple') 208 | ); 209 | $this->_shell->expects($this->at(3))->method('out')->with( 210 | $this->equalTo('2. Banana') 211 | ); 212 | $this->_shell->expects($this->at(4))->method('in')->with( 213 | $this->equalTo("Enter a number from the list above,\n" . 214 | "type in the name of another seeder shell task,\n" . 215 | "type in the name of a model,\n" . 216 | "or 'q' to exit"))->will($this->returnValue('q')); 217 | 218 | $this->_shell->main(); 219 | 220 | $this->assertArrayNotHasKey(0, $this->_shell->args); 221 | } 222 | 223 | /** 224 | * Test the main method when providing an invalid seeder name 225 | * 226 | * @return void 227 | * @covers ::main 228 | * @covers ::_promptForSeeder 229 | */ 230 | public function testMainInvalidSeederPrompt() { 231 | $tasks = array('Apple', 'Banana'); 232 | $this->_shell->expects($this->at(0))->method('_getSeederTasks')->will($this->returnValue($tasks)); 233 | $this->_shell->expects($this->at(4))->method('in')->will($this->returnValue('999999999')); 234 | $this->_shell->expects($this->at(5))->method('err')->with( 235 | $this->equalTo("The seeder shell task name you supplied was empty,\n" . 236 | "or the number you selected was not a valid option. Please try again.") 237 | ); 238 | 239 | $this->_shell->main(); 240 | 241 | $this->assertArrayNotHasKey(0, $this->_shell->args); 242 | } 243 | 244 | /** 245 | * Test the main method when executing one of the prompted (non-existing) seeders by name 246 | * 247 | * @return void 248 | * @covers ::main 249 | * @covers ::_promptForSeeder 250 | * @covers ::_executeSeederTask 251 | */ 252 | public function testMainExecuteByNameSeederPrompt() { 253 | $this->_createShellMock( 254 | array('out', 'in', '_getSeederTasks', '_executeSeederTask') 255 | ); 256 | 257 | $tasks = array('Apple', 'Banana'); 258 | $this->_shell->params['no-truncate'] = 'foo'; 259 | $this->_shell->expects($this->at(0))->method('_getSeederTasks')->will($this->returnValue($tasks)); 260 | $this->_shell->expects($this->at(4))->method('in')->will($this->returnValue('Apple')); 261 | $this->_shell->expects($this->at(5))->method('out')->with( 262 | $this->equalTo('Execute Apple seeder...') 263 | ); 264 | $this->_shell->expects($this->at(6))->method('_executeSeederTask')->with( 265 | $this->equalTo('Apple'), $this->equalTo('foo') 266 | ); 267 | 268 | $this->_shell->main(); 269 | 270 | $this->assertEquals('Apple', $this->_shell->args[0]); 271 | } 272 | 273 | /** 274 | * Test the main method when executing one of the prompted (non-existing) seeders by number 275 | * 276 | * @return void 277 | * @covers ::main 278 | * @covers ::_promptForSeeder 279 | * @covers ::_executeSeederTask 280 | */ 281 | public function testMainExecuteByNumberSeederPrompt() { 282 | $this->_createShellMock( 283 | array('out', 'in', '_getSeederTasks', '_executeSeederTask') 284 | ); 285 | 286 | $tasks = array('Apple', 'Banana'); 287 | $this->_shell->params['no-truncate'] = 'foo'; 288 | $this->_shell->expects($this->at(0))->method('_getSeederTasks')->will($this->returnValue($tasks)); 289 | $this->_shell->expects($this->at(4))->method('in')->will($this->returnValue('1')); 290 | $this->_shell->expects($this->at(5))->method('out')->with( 291 | $this->equalTo('Execute Apple seeder...') 292 | ); 293 | $this->_shell->expects($this->at(6))->method('_executeSeederTask')->with( 294 | $this->equalTo('Apple'), $this->equalTo('foo') 295 | ); 296 | 297 | $this->_shell->main(); 298 | 299 | $this->assertEquals('Apple', $this->_shell->args[0]); 300 | } 301 | 302 | /** 303 | * Test the main method when executing a seeder given by parameter 304 | * 305 | * @return void 306 | * @covers ::main 307 | */ 308 | public function testMainExecuteSeederGivenByParameter() { 309 | $this->_createShellMock( 310 | array('out', '_executeSeederTask') 311 | ); 312 | 313 | $this->_shell->args[0] = 'Apple'; 314 | $this->_shell->params['no-truncate'] = 'foo'; 315 | 316 | $this->_shell->expects($this->at(0))->method('out')->with( 317 | $this->equalTo('Execute Apple seeder...') 318 | ); 319 | $this->_shell->expects($this->at(1))->method('_executeSeederTask')->with( 320 | $this->equalTo("Apple"), 321 | $this->_shell->params['no-truncate'] 322 | ); 323 | 324 | $this->_shell->main(); 325 | } 326 | 327 | /** 328 | * Test the main method when executing a seeder given by parameter when there are seeders defined 329 | * 330 | * Should execute the given seeder nonetheless. 331 | * 332 | * @return void 333 | * @covers ::main 334 | */ 335 | public function testMainExecuteSeederGivenByParameterWithDefinedSeeders() { 336 | $this->_createShellMock( 337 | array('out', '_executeSeederTask'), 338 | 'SeederShellWithTasks' 339 | ); 340 | 341 | $this->_shell->args[0] = 'Apple'; 342 | $this->_shell->params['no-truncate'] = 'foo'; 343 | 344 | $this->_shell->expects($this->at(0))->method('out')->with( 345 | $this->equalTo('Execute Apple seeder...') 346 | ); 347 | $this->_shell->expects($this->at(1))->method('_executeSeederTask')->with( 348 | $this->equalTo("Apple"), 349 | $this->_shell->params['no-truncate'] 350 | ); 351 | 352 | $this->_shell->main(); 353 | } 354 | 355 | /** 356 | * Test the _executeSeederTask method when trying to execute an existing seeder 357 | * 358 | * @return void 359 | * @covers ::main 360 | * @covers ::_executeSeederTask 361 | */ 362 | public function testMainExecuteSeederTaskByName() { 363 | $this->loadFixtures('Apple'); 364 | 365 | $this->_createShellMock( 366 | array('out'), 367 | 'SeederShellWithTasks' 368 | ); 369 | $this->_shell->Tasks = $this->getMock( 370 | 'TaskCollection', 371 | array('load'), 372 | array(), 373 | '', 374 | false 375 | ); 376 | $seederTask = $this->getMock( 377 | 'SeederTaskBase', 378 | array('initialize', 'execute', 'fieldFormatters') 379 | ); 380 | 381 | $this->_shell->Tasks->expects($this->once())->method('load')->with($this->equalTo('AppleSeeder'))->will($this->returnValue($seederTask)); 382 | 383 | $seederTask->expects($this->at(0))->method('initialize'); 384 | $seederTask->expects($this->at(1))->method('execute'); 385 | 386 | $this->_shell->args[0] = 'Apple'; 387 | $this->_shell->params['no-truncate'] = 'foo'; 388 | // Add an additional option parameter 389 | $this->_shell->params['records'] = 50; 390 | 391 | $this->_shell->main(); 392 | 393 | $this->assertAttributeEquals($this->_shell->args, 'args', $seederTask); 394 | $this->assertAttributeEquals($this->_shell->params, 'params', $seederTask); 395 | } 396 | 397 | /** 398 | * Test the _executeSeederTask method when trying to execute a non existing seeder 399 | * 400 | * Should execute the built-in DynamicModelSeeder instead. 401 | * 402 | * @return void 403 | * @covers ::main 404 | * @covers ::_executeSeederTask 405 | */ 406 | public function testMainExecuteSeederTaskDynamicModelSeeder() { 407 | $this->loadFixtures('Apple'); 408 | 409 | $this->_createShellMock( 410 | array('out'), 411 | 'SeederShellWithTasks' 412 | ); 413 | $this->_shell->Tasks = $this->getMock( 414 | 'TaskCollection', 415 | array('load'), 416 | array(), 417 | '', 418 | false 419 | ); 420 | $seederTask = $this->getMock( 421 | 'SeederTaskBase', 422 | array('initialize', 'execute', 'fieldFormatters') 423 | ); 424 | 425 | $this->_shell->Tasks->expects($this->at(0))->method('load')->with($this->equalTo('AppleSeeder'))->will($this->throwException(new MissingTaskException(''))); 426 | $this->_shell->Tasks->expects($this->at(1))->method('load')->with($this->equalTo('FakeSeeder.DynamicModelSeeder'))->will($this->returnValue($seederTask)); 427 | 428 | $seederTask->expects($this->at(0))->method('initialize'); 429 | $seederTask->expects($this->at(1))->method('execute'); 430 | 431 | $this->_shell->args[0] = 'Apple'; 432 | $this->_shell->params['no-truncate'] = 'foo'; 433 | // Add an additional option parameter 434 | $this->_shell->params['records'] = 50; 435 | 436 | $this->_shell->main(); 437 | 438 | $this->assertAttributeEquals($this->_shell->args, 'args', $seederTask); 439 | $this->assertAttributeEquals($this->_shell->params, 'params', $seederTask); 440 | } 441 | 442 | /** 443 | * Test the _executeSeederTask method when trying to execute a non existing seeder for which no model/table exists 444 | * 445 | * @return void 446 | * @covers ::main 447 | * @covers ::_executeSeederTask 448 | */ 449 | public function testMainExecuteSeederTaskNoTable() { 450 | $this->_createShellMock( 451 | array('out', '_loadSeederModel'), 452 | 'SeederShellWithTasks' 453 | ); 454 | $this->_shell->Tasks = $this->getMock( 455 | 'TaskCollection', 456 | array('load'), 457 | array(), 458 | '', 459 | false 460 | ); 461 | $seederTask = $this->getMock( 462 | 'SeederTaskBase', 463 | array('initialize', 'execute', 'fieldFormatters') 464 | ); 465 | 466 | $this->_shell->Tasks->expects($this->once())->method('load')->with($this->equalTo('NonExistingModelSeeder')) 467 | ->will($this->throwException(new MissingTaskException(''))); 468 | $this->_shell->expects($this->once())->method('_loadSeederModel')->with($this->equalTo('NonExistingModel')) 469 | ->will($this->returnValue(false)); 470 | 471 | $seederTask->expects($this->never())->method('initialize'); 472 | $seederTask->expects($this->never())->method('execute'); 473 | 474 | $this->_shell->args[0] = 'NonExistingModel'; 475 | $this->_shell->params['no-truncate'] = 'foo'; 476 | 477 | $this->_shell->main(); 478 | } 479 | 480 | /** 481 | * Test the main method with seeders defined and no truncate 482 | * 483 | * @return void 484 | * @covers ::main 485 | */ 486 | public function testMainExecuteDefinedSeedersNoTruncate() { 487 | $this->_createShellMock( 488 | array('out', '_truncateModels', '_callSeeders'), 489 | 'SeederShellWithTasks' 490 | ); 491 | 492 | // Disable truncate 493 | $this->_shell->params['no-truncate'] = true; 494 | 495 | $this->_shell->expects($this->never())->method('_truncateModels'); 496 | $this->_shell->expects($this->at(0))->method('_callSeeders'); 497 | 498 | $this->_shell->main(); 499 | } 500 | 501 | /** 502 | * Test the main method with seeders defined with truncate 503 | * 504 | * @return void 505 | * @covers ::main 506 | */ 507 | public function testMainExecuteDefinedSeedersWithTruncate() { 508 | $this->_createShellMock( 509 | array('out', '_truncateModels', '_callSeeders'), 510 | 'SeederShellWithTasks' 511 | ); 512 | 513 | // Enable truncate 514 | $this->_shell->params['no-truncate'] = false; 515 | 516 | $this->_shell->expects($this->at(0))->method('_truncateModels'); 517 | $this->_shell->expects($this->at(1))->method('_callSeeders'); 518 | 519 | $this->_shell->main(); 520 | } 521 | 522 | /** 523 | * Test the _truncateModels method 524 | * 525 | * @return void 526 | * @covers ::_truncateModels 527 | * @covers ::_getModelsToTruncateFromSeederTask 528 | */ 529 | public function testTruncateModels() { 530 | $this->loadFixtures('Apple', 'Banana', 'Pear'); 531 | 532 | $this->_createShellMock( 533 | array('out', '_callSeeders', '_getModelTruncator'), 534 | 'SeederShellWithTasks' 535 | ); 536 | $this->_shell->Tasks = $this->getMock( 537 | 'TaskCollection', 538 | array('load'), 539 | array(), 540 | '', 541 | false 542 | ); 543 | $seederTask = $this->getMock( 544 | 'SeederTaskBase', 545 | array('getModelsToTruncate', 'fieldFormatters') 546 | ); 547 | $modelTruncator = $this->getMock( 548 | 'ShellModelTruncator', 549 | array('truncateModels'), 550 | array(), 551 | '', 552 | false 553 | ); 554 | 555 | $this->_shell->expects($this->at(0))->method('out')->with($this->equalTo('Truncating models...')); 556 | $this->_shell->expects($this->at(1))->method('_getModelTruncator')->will($this->returnValue($modelTruncator)); 557 | $this->_shell->expects($this->at(2))->method('out')->with($this->equalTo('Finished truncating models.')); 558 | 559 | $this->_shell->Tasks->expects($this->at(0))->method('load')->with($this->equalTo('AppleSeeder'))->will($this->returnValue($seederTask)); 560 | $this->_shell->Tasks->expects($this->at(1))->method('load')->with($this->equalTo('BananaSeeder'))->will($this->returnValue($seederTask)); 561 | 562 | $seederTask->expects($this->at(0))->method('getModelsToTruncate')->will($this->returnValue(array('Apple'))); 563 | $seederTask->expects($this->at(1))->method('getModelsToTruncate')->will($this->returnValue(array('Banana'))); 564 | 565 | $modelsToTruncate = array('Apple', 'Banana', 'Pear'); 566 | $modelTruncator->expects($this->at(0))->method('truncateModels')->with($this->equalTo($modelsToTruncate)); 567 | 568 | // Enable truncate 569 | $this->_shell->params['no-truncate'] = false; 570 | 571 | $this->_shell->main(); 572 | } 573 | 574 | /** 575 | * Test the _callSeeders method 576 | * 577 | * @return void 578 | * @covers ::_callSeeders 579 | */ 580 | public function testCallSeeders() { 581 | $this->_createShellMock( 582 | array('out', '_executeSeederTask'), 583 | 'SeederShellWithTasks' 584 | ); 585 | 586 | $this->_shell->expects($this->at(0))->method('out')->with($this->equalTo('Execute seeders...')); 587 | $this->_shell->expects($this->at(1))->method('out')->with($this->equalTo('Execute Apple seeder...')); 588 | $this->_shell->expects($this->at(2))->method('_executeSeederTask')->with( 589 | $this->equalTo("Apple"), 590 | true 591 | ); 592 | $this->_shell->expects($this->at(3))->method('out')->with($this->equalTo('Execute Banana seeder...')); 593 | $this->_shell->expects($this->at(4))->method('_executeSeederTask')->with( 594 | $this->equalTo("Banana"), 595 | true 596 | ); 597 | $this->_shell->expects($this->at(0))->method('out')->with($this->equalTo('Execute seeders...')); 598 | 599 | // Set no-truncate to something else than boolean true, 600 | // so we can verify _executeSeederTask gets called with literal true 601 | $this->_shell->params['no-truncate'] = 'foo'; 602 | 603 | $this->_shell->main(); 604 | } 605 | 606 | } -------------------------------------------------------------------------------- /Test/Case/Console/SeederTaskBaseTest.php: -------------------------------------------------------------------------------- 1 | _mergeFieldFormatters($fieldFormatters); 18 | } 19 | 20 | /** 21 | * A test proxy method for _getParameter 22 | */ 23 | public function getParameter($configKey, $propertyName, $defaultValue = null) { 24 | return parent::_getParameter($configKey, $propertyName, $defaultValue); 25 | } 26 | 27 | /** 28 | * Needs to be implemented 29 | */ 30 | public function fieldFormatters() { 31 | $this->_fieldFormatters; 32 | } 33 | 34 | /** 35 | * A test proxy method for _getSeederConfigKey 36 | */ 37 | public function getSeederConfigKey() { 38 | return $this->_getSeederConfigKey(); 39 | } 40 | 41 | /** 42 | * A test proxy method for _getSeederNamePrefix 43 | */ 44 | public function getSeederNamePrefix() { 45 | return $this->_getSeederNamePrefix(); 46 | } 47 | 48 | /** 49 | * A test proxy method for _getSeederShellName 50 | */ 51 | public function getSeederShellName() { 52 | return $this->_getSeederShellName(); 53 | } 54 | 55 | } 56 | 57 | /** 58 | * A testable implementation of SeederTaskBase with all proprties set 59 | */ 60 | class PropertiesSetSeederTaskBase extends TestSeederTaskBase { 61 | 62 | /** 63 | * The config key to read, 'FakeSeeder.$_configKey.valueKey' 64 | * 65 | * Does not need to be set, uses the name of the seeder class by default, e.g. "Article" for "ArticleSeederShell". 66 | * 67 | * @var string 68 | */ 69 | protected $_configKey = 'CustomConfigKey'; 70 | 71 | /** 72 | * The name of the model to seed 73 | * 74 | * Does not need to be set, uses the name of the seeder class by default, e.g. "Article" for "ArticleSeederTask". 75 | * 76 | * @var string 77 | */ 78 | protected $_modelName = 'CustomModelName'; 79 | 80 | /** 81 | * Models to truncate 82 | * 83 | * Does not need to be set, uses the name of the seeder class by default, e.g. "Article" for "ArticleSeederTask". 84 | * 85 | * @var array 86 | */ 87 | protected $_modelsToTruncate = array('AnotherModel'); 88 | 89 | /** 90 | * Fixture records which are processed additionally and before the faked ones 91 | * 92 | * @var array 93 | */ 94 | protected $_fixtureRecords = array(array('foo' => 'bar')); 95 | 96 | /** 97 | * The fields and their formatter 98 | * 99 | * @var array 100 | */ 101 | protected $_fieldFormatters = array(); 102 | 103 | /** 104 | * The seeding mode, optional. 105 | * 106 | * @var null|string 107 | */ 108 | protected $_mode = 'mixed'; 109 | 110 | /** 111 | * The locale to use for Faker, optional 112 | * 113 | * @var null|int 114 | */ 115 | protected $_locale = 'de_DE'; 116 | 117 | /** 118 | * Set the minimum record count for a seeder task, null means no minimum. 119 | * 120 | * @var null|int 121 | */ 122 | protected $_minRecords = 5; 123 | 124 | /** 125 | * Set the maximum record count for a seeder task, null means no maximum. 126 | * 127 | * @var null|int 128 | */ 129 | protected $_maxRecords = 100; 130 | 131 | /** 132 | * The records to seed, optional 133 | * 134 | * @var null|int 135 | */ 136 | protected $_records = 50; 137 | 138 | /** 139 | * Whether or not to validate the seeding data when saving, optional 140 | * 141 | * @var null|bool|string 142 | * @see Model::saveAll() See for possible values for `validate`. 143 | */ 144 | protected $_validateSeeding = false; 145 | 146 | /** 147 | * The seeding number for Faker to use 148 | * 149 | * @var null|bool|int 150 | * @see Generator::seed Faker's seed method. 151 | */ 152 | protected $_seedingNumber = 123456789; 153 | 154 | /** 155 | * Whether or not to truncate the model , optional. 156 | * 157 | * @var null|bool 158 | */ 159 | protected $_noTruncate = true; 160 | } 161 | 162 | /** 163 | * SeederTaskBase Test 164 | * 165 | * @coversDefaultClass SeederTaskBase 166 | */ 167 | class SeederTaskBaseTest extends CakeTestCase { 168 | 169 | /** 170 | * The task under test 171 | * 172 | * @var null|TestSeederTaskBase 173 | */ 174 | protected $_task = null; 175 | 176 | /** 177 | * Setup the shell under test 178 | * 179 | * @return void 180 | */ 181 | public function setUp() { 182 | parent::setUp(); 183 | 184 | $this->_createShellMock( 185 | array('in', 'out', 'hr', 'createFile', 'error', 'err', '_stop', '_showInfo', 'dispatchShell', '_getParameter') 186 | ); 187 | } 188 | 189 | /** 190 | * Creates a shell mock 191 | * 192 | * @param array $methods A list of methods to mock. 193 | * @param string $className Optional name of the seeder shell class to mock. 194 | * @return void 195 | */ 196 | protected function _createShellMock($methods, $className = 'TestSeederTaskBase') { 197 | $out = $this->getMock('ConsoleOutput', array(), array(), '', false); 198 | $in = $this->getMock('ConsoleInput', array(), array(), '', false); 199 | $this->_task = $this->getMock( 200 | $className, 201 | $methods, 202 | array($out, $out, $in) 203 | ); 204 | } 205 | 206 | /** 207 | * Tests the execute method 208 | * 209 | * @return void 210 | * @covers ::execute 211 | * @covers ::_getFaker 212 | * @covers ::_truncateModels 213 | */ 214 | public function testExecute() { 215 | $this->_createShellMock( 216 | array('in', 'out', 'hr', 'createFile', 'error', 'err', '_stop', '_showInfo', 'dispatchShell', 'getLocale', 'getSeedingNumber', 'getNoTruncate', 'getModelsToTruncate', '_getModelTruncator', '_getSeedProcessor') 217 | ); 218 | $seedProcessor = $this->getMock( 219 | 'ShellSeedProcessor', 220 | array('processFixtures', 'sowSeeds'), 221 | array(), 222 | '', 223 | false 224 | ); 225 | $modelTruncator = $this->getMock( 226 | 'ShellModelTruncator', 227 | array('truncateModels'), 228 | array(), 229 | '', 230 | false 231 | ); 232 | $modelsToTruncate = array('Apple', 'Banana'); 233 | 234 | $this->_task->expects($this->at(0))->method('getLocale')->will($this->returnValue('de_DE')); 235 | $this->_task->expects($this->at(1))->method('getSeedingNumber')->will($this->returnValue(123456)); 236 | $this->_task->expects($this->at(2))->method('out')->with($this->equalTo('Create Faker instance with "de_DE" locale...')); 237 | $this->_task->expects($this->at(3))->method('out')->with($this->equalTo("Use seed '123456' for Faker.")); 238 | $this->_task->expects($this->at(4))->method('getNoTruncate')->will($this->returnValue(false)); 239 | $this->_task->expects($this->at(5))->method('getModelsToTruncate')->will($this->returnValue($modelsToTruncate)); 240 | $this->_task->expects($this->at(6))->method('_getModelTruncator')->will($this->returnValue($modelTruncator)); 241 | $this->_task->expects($this->at(7))->method('_getSeedProcessor')->will($this->returnValue($seedProcessor)); 242 | 243 | $modelTruncator->expects($this->at(0))->method('truncateModels')->with($this->equalTo($modelsToTruncate)); 244 | 245 | $seedProcessor->expects($this->at(0))->method('processFixtures'); 246 | $seedProcessor->expects($this->at(1))->method('sowSeeds'); 247 | 248 | $this->_task->execute(); 249 | } 250 | 251 | /** 252 | * Tests the getModelsToTruncate method 253 | * 254 | * @return void 255 | * @covers ::getModelsToTruncate 256 | */ 257 | public function testGetModelsToTruncate() { 258 | $this->_createShellMock( 259 | array('in', 'out', 'hr', 'createFile', 'error', 'err', '_stop', '_showInfo', 'dispatchShell', 'getModelName') 260 | ); 261 | $expected = array('YetAnotherModel'); 262 | $this->_task->expects($this->at(0))->method('getModelName')->will($this->returnValue('YetAnotherModel')); 263 | 264 | $result = $this->_task->getModelsToTruncate(); 265 | 266 | $this->assertEquals($expected, $result); 267 | } 268 | 269 | /** 270 | * Tests the fixtureRecords method 271 | * 272 | * @return void 273 | * @covers ::getModelsToTruncate 274 | */ 275 | public function testGetModelsToTruncatePropertySet() { 276 | $this->_createShellMock( 277 | array('in', 'out', 'hr', 'createFile', 'error', 'err', '_stop', '_showInfo', 'dispatchShell', '_getParameter'), 278 | 'PropertiesSetSeederTaskBase' 279 | ); 280 | 281 | $result = $this->_task->getModelsToTruncate(); 282 | $expected = array('AnotherModel'); 283 | 284 | $this->assertEquals($expected, $result); 285 | } 286 | 287 | /** 288 | * Tests the getModelsToTruncate method 289 | * 290 | * @return void 291 | * @covers ::fixtureRecords 292 | */ 293 | public function testFixtureRecords() { 294 | $this->_createShellMock( 295 | array('in', 'out', 'hr', 'createFile', 'error', 'err', '_stop', '_showInfo', 'dispatchShell', '_getParameter'), 296 | 'PropertiesSetSeederTaskBase' 297 | ); 298 | 299 | $result = $this->_task->fixtureRecords(); 300 | $expected = array(array('foo' => 'bar')); 301 | 302 | $this->assertEquals($expected, $result); 303 | } 304 | 305 | /** 306 | * Tests the _mergeFieldFormatters method 307 | * 308 | * @return void 309 | * @covers ::_mergeFieldFormatters 310 | */ 311 | public function testMergeFieldFormatters() { 312 | $result = $this->_task->mergeFieldFormatters(array()); 313 | $this->assertEmpty($result); 314 | 315 | $fieldFormatters = array('foo'); 316 | $result = $this->_task->mergeFieldFormatters($fieldFormatters); 317 | $this->assertEquals($fieldFormatters, $result); 318 | 319 | $fieldFormatters = array('bar'); 320 | $result = $this->_task->mergeFieldFormatters($fieldFormatters); 321 | $expected = array('foo', 'bar'); 322 | $this->assertEquals($expected, $result); 323 | } 324 | 325 | /** 326 | * Tests the recordState method 327 | * 328 | * @return void 329 | * @covers ::recordState 330 | */ 331 | public function testRecordsState() { 332 | $result = $this->_task->recordState(); 333 | $expected = array(); 334 | 335 | $this->assertEquals($expected, $result); 336 | } 337 | 338 | /** 339 | * Tests the getModelName method 340 | * 341 | * @return void 342 | * @covers ::getModelName 343 | */ 344 | public function testGetModelName() { 345 | $this->_createShellMock( 346 | array('in', 'out', 'hr', 'createFile', 'error', 'err', '_stop', '_showInfo', 'dispatchShell', '_getSeederNamePrefix') 347 | ); 348 | $expected = 'AModelName'; 349 | $this->_task->expects($this->at(0))->method('_getSeederNamePrefix')->will($this->returnValue($expected)); 350 | $result = $this->_task->getModelName(); 351 | $this->assertEquals($expected, $result); 352 | } 353 | 354 | /** 355 | * Tests the getModelName method 356 | * 357 | * @return void 358 | * @covers ::getModelName 359 | */ 360 | public function testGetModelNamePropertySet() { 361 | $this->_createShellMock( 362 | array('in', 'out', 'hr', 'createFile', 'error', 'err', '_stop', '_showInfo', 'dispatchShell'), 363 | 'PropertiesSetSeederTaskBase' 364 | ); 365 | $expected = 'CustomModelName'; 366 | $result = $this->_task->getModelName(); 367 | $this->assertEquals($expected, $result); 368 | } 369 | 370 | /** 371 | * Tests the getSeedingMode method 372 | * 373 | * @return void 374 | * @covers ::getSeedingMode 375 | */ 376 | public function testGetSeedingMode() { 377 | $value = 'auto'; 378 | $this->_task->expects($this->at(0))->method('_getParameter')->will($this->returnValue($value)); 379 | $result = $this->_task->getSeedingMode(); 380 | $this->assertEquals($value, $result); 381 | } 382 | 383 | /** 384 | * Tests the getSeedingMode method 385 | * 386 | * @return void 387 | * @covers ::getLocale 388 | */ 389 | public function testGetLocale() { 390 | $value = 'de_DE'; 391 | $this->_task->expects($this->at(0))->method('_getParameter')->will($this->returnValue($value)); 392 | $result = $this->_task->getLocale(); 393 | $this->assertEquals($value, $result); 394 | } 395 | 396 | /** 397 | * Tests the getRecordsCount method 398 | * 399 | * @return void 400 | * @covers ::getRecordsCount 401 | * @covers ::_enforceRecordMaximum 402 | * @covers ::_enforceRecordMinimum 403 | */ 404 | public function testGetRecordsCount() { 405 | $value = '50'; 406 | $this->_task->expects($this->at(0))->method('_getParameter')->will($this->returnValue($value)); 407 | $this->_task->expects($this->never())->method('out'); 408 | $result = $this->_task->getRecordsCount(); 409 | $this->assertEquals($value, $result); 410 | } 411 | 412 | /** 413 | * Tests the getRecordsCount method when records is set too high 414 | * 415 | * @return void 416 | * @covers ::getRecordsCount 417 | * @covers ::_enforceRecordMaximum 418 | */ 419 | public function testGetRecordsCountTooHigh() { 420 | $this->_createShellMock( 421 | array('in', 'out', 'hr', 'createFile', 'error', 'err', '_stop', '_showInfo', 'dispatchShell', '_getParameter'), 422 | 'PropertiesSetSeederTaskBase' 423 | ); 424 | 425 | $value = '500'; 426 | $this->_task->expects($this->at(0))->method('_getParameter')->will($this->returnValue($value)); 427 | $this->_task->expects($this->at(1))->method('out')->with($this->equalTo('500 records exceed the allowed maximum amount. Reducing it to 100 records.')); 428 | $result = $this->_task->getRecordsCount(); 429 | 430 | $this->assertEquals(100, $result); 431 | } 432 | 433 | /** 434 | * Tests the getRecordsCount method when records is set too low 435 | * 436 | * @return void 437 | * @covers ::getRecordsCount 438 | * @covers ::_enforceRecordMinimum 439 | */ 440 | public function testGetRecordsCountTooLow() { 441 | $this->_createShellMock( 442 | array('in', 'out', 'hr', 'createFile', 'error', 'err', '_stop', '_showInfo', 'dispatchShell', '_getParameter'), 443 | 'PropertiesSetSeederTaskBase' 444 | ); 445 | 446 | $value = '1'; 447 | $this->_task->expects($this->at(0))->method('_getParameter')->will($this->returnValue($value)); 448 | $this->_task->expects($this->at(1))->method('out')->with($this->equalTo('1 records fall below the allowed minimum amount. Increasing it to 5 records.')); 449 | $result = $this->_task->getRecordsCount(); 450 | 451 | $this->assertEquals(5, $result); 452 | } 453 | 454 | /** 455 | * Tests the getValidateSeeding method 456 | * 457 | * @return void 458 | * @covers ::getValidateSeeding 459 | */ 460 | public function testGetValidateSeeding() { 461 | $value = 'first'; 462 | $this->_task->expects($this->at(0))->method('_getParameter')->will($this->returnValue($value)); 463 | $result = $this->_task->getValidateSeeding(); 464 | $this->assertEquals($value, $result); 465 | } 466 | 467 | /** 468 | * Tests the getSeedingNumber method 469 | * 470 | * @return void 471 | * @covers ::getSeedingNumber 472 | */ 473 | public function testGetSeedingNumber() { 474 | $value = '123456'; 475 | $this->_task->expects($this->at(0))->method('_getParameter')->will($this->returnValue($value)); 476 | $result = $this->_task->getSeedingNumber(); 477 | $this->assertEquals($value, $result); 478 | } 479 | 480 | /** 481 | * Tests the getNoTruncate method 482 | * 483 | * @return void 484 | * @covers ::getNoTruncate 485 | */ 486 | public function testGetNoTruncate() { 487 | $value = true; 488 | $this->_task->expects($this->at(0))->method('_getParameter')->will($this->returnValue($value)); 489 | $result = $this->_task->getNoTruncate(); 490 | $this->assertEquals($value, $result); 491 | } 492 | 493 | /** 494 | * Tests the _getParameter method for the default value 495 | * 496 | * @return void 497 | * @covers ::_getParameter 498 | */ 499 | public function testGetParameterDefaultValue() { 500 | $this->_createShellMock( 501 | array('in', 'out', 'hr', 'createFile', 'error', 'err', '_stop', '_showInfo', 'dispatchShell', '_getSeederTasks') 502 | ); 503 | 504 | $this->_task->expects($this->at(0))->method('out')->with($this->equalTo('Parameter "records" not given/configured, falling back to default "500".')); 505 | 506 | $configKey = 'records'; 507 | $propertyName = '_records'; 508 | $defaultValue = '500'; 509 | 510 | $this->_task->params[$configKey] = null; 511 | Configure::write('FakeSeeder.TestSeederTaskBase.' . $configKey, null); 512 | Configure::write('FakeSeeder.' . $configKey, null); 513 | 514 | $result = $this->_task->getParameter($configKey, $propertyName, $defaultValue); 515 | $this->assertEquals($defaultValue, $result); 516 | } 517 | 518 | /** 519 | * Tests the _getParameter method when the property is set 520 | * 521 | * @return void 522 | * @covers ::_getParameter 523 | */ 524 | public function testGetParameterPropertySet() { 525 | $this->_createShellMock( 526 | array('in', 'out', 'hr', 'createFile', 'error', 'err', '_stop', '_showInfo', 'dispatchShell', '_getSeederTasks') 527 | ); 528 | 529 | $this->_createShellMock(array('out'), 'PropertiesSetSeederTaskBase'); 530 | 531 | $this->_task->expects($this->at(0))->method('out')->with($this->equalTo('Parameter "records" set in class: "50"')); 532 | 533 | $configKey = 'records'; 534 | $propertyName = '_records'; 535 | 536 | $this->_task->params[$configKey] = null; 537 | Configure::write('FakeSeeder.TestSeederTaskBase.' . $configKey, null); 538 | Configure::write('FakeSeeder.' . $configKey, null); 539 | 540 | $result = $this->_task->getParameter($configKey, $propertyName); 541 | $this->assertEquals(50, $result); 542 | } 543 | 544 | /** 545 | * Tests the _getParameter method when the general config is set 546 | * 547 | * @return void 548 | * @covers ::_getParameter 549 | */ 550 | public function testGetParameterGeneralConfgigSet() { 551 | $this->_createShellMock( 552 | array('in', 'out', 'hr', 'createFile', 'error', 'err', '_stop', '_showInfo', 'dispatchShell', '_getSeederTasks') 553 | ); 554 | 555 | $this->_task->expects($this->at(0))->method('out')->with($this->equalTo('Parameter "records" configured in general seeder configuration: "75"')); 556 | 557 | $configKey = 'records'; 558 | $propertyName = '_records'; 559 | 560 | $this->_task->params[$configKey] = null; 561 | Configure::write('FakeSeeder.TestSeederTaskBase.' . $configKey, null); 562 | Configure::write('FakeSeeder.' . $configKey, 75); 563 | 564 | $result = $this->_task->getParameter($configKey, $propertyName); 565 | $this->assertEquals(75, $result); 566 | } 567 | 568 | /** 569 | * Tests the _getParameter method when the seeder specific config is set 570 | * 571 | * @return void 572 | * @covers ::_getParameter 573 | */ 574 | public function testGetParameterSeederConfgigSet() { 575 | $this->_createShellMock( 576 | array('in', 'out', 'hr', 'createFile', 'error', 'err', '_stop', '_showInfo', 'dispatchShell', '_getSeederTasks') 577 | ); 578 | 579 | $this->_createShellMock(array('out', '_getSeederConfigKey')); 580 | 581 | $this->_task->expects($this->at(0))->method('_getSeederConfigKey')->will($this->returnValue('FakeSeeder.TestSeederTaskBase')); 582 | $this->_task->expects($this->at(1))->method('out')->with($this->equalTo('Parameter "records" configured in seeder specific configuration: "62"')); 583 | 584 | $configKey = 'records'; 585 | $propertyName = '_records'; 586 | 587 | $this->_task->params[$configKey] = null; 588 | Configure::write('FakeSeeder.TestSeederTaskBase.' . $configKey, 62); 589 | Configure::write('FakeSeeder.' . $configKey, null); 590 | 591 | $result = $this->_task->getParameter($configKey, $propertyName); 592 | $this->assertEquals(62, $result); 593 | } 594 | 595 | /** 596 | * Tests the _getParameter method when the parameter is set 597 | * 598 | * @return void 599 | * @covers ::_getParameter 600 | */ 601 | public function testGetParameterParameterSet() { 602 | $this->_createShellMock( 603 | array('in', 'out', 'hr', 'createFile', 'error', 'err', '_stop', '_showInfo', 'dispatchShell', '_getSeederTasks') 604 | ); 605 | 606 | $this->_task->expects($this->at(0))->method('out')->with($this->equalTo('Parameter "records" given through CLI parameter: "24"')); 607 | 608 | $configKey = 'records'; 609 | $propertyName = '_records'; 610 | 611 | $this->_task->params[$configKey] = 24; 612 | Configure::write('FakeSeeder.TestSeederTaskBase.' . $configKey, null); 613 | Configure::write('FakeSeeder.' . $configKey, null); 614 | 615 | $result = $this->_task->getParameter($configKey, $propertyName); 616 | $this->assertEquals(24, $result); 617 | } 618 | 619 | /** 620 | * Tests the _getSeederConfigKey method 621 | * 622 | * @return void 623 | * @covers ::_getSeederConfigKey 624 | */ 625 | public function testGetSeederConfigKey() { 626 | $this->_createShellMock( 627 | array('in', 'out', 'hr', 'createFile', 'error', 'err', '_stop', '_showInfo', 'dispatchShell', '_getSeederShellName', '_getSeederNamePrefix') 628 | ); 629 | $this->_task->expects($this->at(0))->method('_getSeederNamePrefix')->will($this->returnValue('TaskName')); 630 | $this->_task->expects($this->at(1))->method('_getSeederShellName')->will($this->returnValue('FakeSeeder')); 631 | $expected = 'FakeSeeder.TaskName'; 632 | $result = $this->_task->getSeederConfigKey(); 633 | $this->assertEquals($expected, $result); 634 | } 635 | 636 | /** 637 | * Tests the _getSeederConfigKey method 638 | * 639 | * @return void 640 | * @covers ::_getSeederConfigKey 641 | */ 642 | public function testGetSeederConfigKeyPropertySet() { 643 | $this->_createShellMock( 644 | array('in', 'out', 'hr', 'createFile', 'error', 'err', '_stop', '_showInfo', 'dispatchShell', '_getSeederShellName'), 645 | 'PropertiesSetSeederTaskBase' 646 | ); 647 | $this->_task->expects($this->at(0))->method('_getSeederShellName')->will($this->returnValue('FakeSeeder')); 648 | $expected = 'FakeSeeder.CustomConfigKey'; 649 | $result = $this->_task->getSeederConfigKey(); 650 | $this->assertEquals($expected, $result); 651 | } 652 | 653 | /** 654 | * Tests the _getSeederNamePrefix method 655 | * 656 | * @return void 657 | * @covers ::_getSeederNamePrefix 658 | */ 659 | public function testGetSeederNamePrefix() { 660 | $out = $this->getMock('ConsoleOutput', array(), array(), '', false); 661 | $in = $this->getMock('ConsoleInput', array(), array(), '', false); 662 | $this->_task = $this->getMock( 663 | 'TestSeederTaskBase', 664 | null, 665 | array($out, $out, $in), 666 | 'TestNameSeederTask', 667 | false 668 | ); 669 | 670 | $expected = 'TestName'; 671 | $result = $this->_task->getSeederNamePrefix(); 672 | $this->assertEquals($expected, $result); 673 | } 674 | 675 | /** 676 | * Tests the _getSeederShellName method 677 | * 678 | * @return void 679 | * @covers ::_getSeederShellName 680 | */ 681 | public function testGetSeederShellName() { 682 | $this->assertEquals('FakeSeeder', $this->_task->getSeederShellName()); 683 | } 684 | } 685 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "e7e62056dee231b24940b757569a9b9c", 8 | "packages": [ 9 | { 10 | "name": "composer/installers", 11 | "version": "v1.4.0", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/composer/installers.git", 15 | "reference": "9ce17fb70e9a38dd8acff0636a29f5cf4d575c1b" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/composer/installers/zipball/9ce17fb70e9a38dd8acff0636a29f5cf4d575c1b", 20 | "reference": "9ce17fb70e9a38dd8acff0636a29f5cf4d575c1b", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "composer-plugin-api": "^1.0" 25 | }, 26 | "replace": { 27 | "roundcube/plugin-installer": "*", 28 | "shama/baton": "*" 29 | }, 30 | "require-dev": { 31 | "composer/composer": "1.0.*@dev", 32 | "phpunit/phpunit": "4.1.*" 33 | }, 34 | "type": "composer-plugin", 35 | "extra": { 36 | "class": "Composer\\Installers\\Plugin", 37 | "branch-alias": { 38 | "dev-master": "1.0-dev" 39 | } 40 | }, 41 | "autoload": { 42 | "psr-4": { 43 | "Composer\\Installers\\": "src/Composer/Installers" 44 | } 45 | }, 46 | "notification-url": "https://packagist.org/downloads/", 47 | "license": [ 48 | "MIT" 49 | ], 50 | "authors": [ 51 | { 52 | "name": "Kyle Robinson Young", 53 | "email": "kyle@dontkry.com", 54 | "homepage": "https://github.com/shama" 55 | } 56 | ], 57 | "description": "A multi-framework Composer library installer", 58 | "homepage": "https://composer.github.io/installers/", 59 | "keywords": [ 60 | "Craft", 61 | "Dolibarr", 62 | "Eliasis", 63 | "Hurad", 64 | "ImageCMS", 65 | "Kanboard", 66 | "Lan Management System", 67 | "MODX Evo", 68 | "Mautic", 69 | "Maya", 70 | "OXID", 71 | "Plentymarkets", 72 | "Porto", 73 | "RadPHP", 74 | "SMF", 75 | "Thelia", 76 | "WolfCMS", 77 | "agl", 78 | "aimeos", 79 | "annotatecms", 80 | "attogram", 81 | "bitrix", 82 | "cakephp", 83 | "chef", 84 | "cockpit", 85 | "codeigniter", 86 | "concrete5", 87 | "croogo", 88 | "dokuwiki", 89 | "drupal", 90 | "eZ Platform", 91 | "elgg", 92 | "expressionengine", 93 | "fuelphp", 94 | "grav", 95 | "installer", 96 | "itop", 97 | "joomla", 98 | "kohana", 99 | "laravel", 100 | "lavalite", 101 | "lithium", 102 | "magento", 103 | "mako", 104 | "mediawiki", 105 | "modulework", 106 | "moodle", 107 | "osclass", 108 | "phpbb", 109 | "piwik", 110 | "ppi", 111 | "puppet", 112 | "reindex", 113 | "roundcube", 114 | "shopware", 115 | "silverstripe", 116 | "sydes", 117 | "symfony", 118 | "typo3", 119 | "wordpress", 120 | "yawik", 121 | "zend", 122 | "zikula" 123 | ], 124 | "time": "2017-08-09T07:53:48+00:00" 125 | }, 126 | { 127 | "name": "fzaninotto/faker", 128 | "version": "v1.7.1", 129 | "source": { 130 | "type": "git", 131 | "url": "https://github.com/fzaninotto/Faker.git", 132 | "reference": "d3ed4cc37051c1ca52d22d76b437d14809fc7e0d" 133 | }, 134 | "dist": { 135 | "type": "zip", 136 | "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/d3ed4cc37051c1ca52d22d76b437d14809fc7e0d", 137 | "reference": "d3ed4cc37051c1ca52d22d76b437d14809fc7e0d", 138 | "shasum": "" 139 | }, 140 | "require": { 141 | "php": "^5.3.3 || ^7.0" 142 | }, 143 | "require-dev": { 144 | "ext-intl": "*", 145 | "phpunit/phpunit": "^4.0 || ^5.0", 146 | "squizlabs/php_codesniffer": "^1.5" 147 | }, 148 | "type": "library", 149 | "extra": { 150 | "branch-alias": { 151 | "dev-master": "1.8-dev" 152 | } 153 | }, 154 | "autoload": { 155 | "psr-4": { 156 | "Faker\\": "src/Faker/" 157 | } 158 | }, 159 | "notification-url": "https://packagist.org/downloads/", 160 | "license": [ 161 | "MIT" 162 | ], 163 | "authors": [ 164 | { 165 | "name": "François Zaninotto" 166 | } 167 | ], 168 | "description": "Faker is a PHP library that generates fake data for you.", 169 | "keywords": [ 170 | "data", 171 | "faker", 172 | "fixtures" 173 | ], 174 | "time": "2017-08-15T16:48:10+00:00" 175 | } 176 | ], 177 | "packages-dev": [ 178 | { 179 | "name": "phpunit/php-code-coverage", 180 | "version": "1.2.18", 181 | "source": { 182 | "type": "git", 183 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git", 184 | "reference": "fe2466802556d3fe4e4d1d58ffd3ccfd0a19be0b" 185 | }, 186 | "dist": { 187 | "type": "zip", 188 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/fe2466802556d3fe4e4d1d58ffd3ccfd0a19be0b", 189 | "reference": "fe2466802556d3fe4e4d1d58ffd3ccfd0a19be0b", 190 | "shasum": "" 191 | }, 192 | "require": { 193 | "php": ">=5.3.3", 194 | "phpunit/php-file-iterator": ">=1.3.0@stable", 195 | "phpunit/php-text-template": ">=1.2.0@stable", 196 | "phpunit/php-token-stream": ">=1.1.3,<1.3.0" 197 | }, 198 | "require-dev": { 199 | "phpunit/phpunit": "3.7.*@dev" 200 | }, 201 | "suggest": { 202 | "ext-dom": "*", 203 | "ext-xdebug": ">=2.0.5" 204 | }, 205 | "type": "library", 206 | "extra": { 207 | "branch-alias": { 208 | "dev-master": "1.2.x-dev" 209 | } 210 | }, 211 | "autoload": { 212 | "classmap": [ 213 | "PHP/" 214 | ] 215 | }, 216 | "notification-url": "https://packagist.org/downloads/", 217 | "include-path": [ 218 | "" 219 | ], 220 | "license": [ 221 | "BSD-3-Clause" 222 | ], 223 | "authors": [ 224 | { 225 | "name": "Sebastian Bergmann", 226 | "email": "sb@sebastian-bergmann.de", 227 | "role": "lead" 228 | } 229 | ], 230 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", 231 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage", 232 | "keywords": [ 233 | "coverage", 234 | "testing", 235 | "xunit" 236 | ], 237 | "time": "2014-09-02T10:13:14+00:00" 238 | }, 239 | { 240 | "name": "phpunit/php-file-iterator", 241 | "version": "1.4.2", 242 | "source": { 243 | "type": "git", 244 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git", 245 | "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5" 246 | }, 247 | "dist": { 248 | "type": "zip", 249 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5", 250 | "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5", 251 | "shasum": "" 252 | }, 253 | "require": { 254 | "php": ">=5.3.3" 255 | }, 256 | "type": "library", 257 | "extra": { 258 | "branch-alias": { 259 | "dev-master": "1.4.x-dev" 260 | } 261 | }, 262 | "autoload": { 263 | "classmap": [ 264 | "src/" 265 | ] 266 | }, 267 | "notification-url": "https://packagist.org/downloads/", 268 | "license": [ 269 | "BSD-3-Clause" 270 | ], 271 | "authors": [ 272 | { 273 | "name": "Sebastian Bergmann", 274 | "email": "sb@sebastian-bergmann.de", 275 | "role": "lead" 276 | } 277 | ], 278 | "description": "FilterIterator implementation that filters files based on a list of suffixes.", 279 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", 280 | "keywords": [ 281 | "filesystem", 282 | "iterator" 283 | ], 284 | "time": "2016-10-03T07:40:28+00:00" 285 | }, 286 | { 287 | "name": "phpunit/php-text-template", 288 | "version": "1.2.1", 289 | "source": { 290 | "type": "git", 291 | "url": "https://github.com/sebastianbergmann/php-text-template.git", 292 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" 293 | }, 294 | "dist": { 295 | "type": "zip", 296 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 297 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 298 | "shasum": "" 299 | }, 300 | "require": { 301 | "php": ">=5.3.3" 302 | }, 303 | "type": "library", 304 | "autoload": { 305 | "classmap": [ 306 | "src/" 307 | ] 308 | }, 309 | "notification-url": "https://packagist.org/downloads/", 310 | "license": [ 311 | "BSD-3-Clause" 312 | ], 313 | "authors": [ 314 | { 315 | "name": "Sebastian Bergmann", 316 | "email": "sebastian@phpunit.de", 317 | "role": "lead" 318 | } 319 | ], 320 | "description": "Simple template engine.", 321 | "homepage": "https://github.com/sebastianbergmann/php-text-template/", 322 | "keywords": [ 323 | "template" 324 | ], 325 | "time": "2015-06-21T13:50:34+00:00" 326 | }, 327 | { 328 | "name": "phpunit/php-timer", 329 | "version": "1.0.9", 330 | "source": { 331 | "type": "git", 332 | "url": "https://github.com/sebastianbergmann/php-timer.git", 333 | "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" 334 | }, 335 | "dist": { 336 | "type": "zip", 337 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", 338 | "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", 339 | "shasum": "" 340 | }, 341 | "require": { 342 | "php": "^5.3.3 || ^7.0" 343 | }, 344 | "require-dev": { 345 | "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" 346 | }, 347 | "type": "library", 348 | "extra": { 349 | "branch-alias": { 350 | "dev-master": "1.0-dev" 351 | } 352 | }, 353 | "autoload": { 354 | "classmap": [ 355 | "src/" 356 | ] 357 | }, 358 | "notification-url": "https://packagist.org/downloads/", 359 | "license": [ 360 | "BSD-3-Clause" 361 | ], 362 | "authors": [ 363 | { 364 | "name": "Sebastian Bergmann", 365 | "email": "sb@sebastian-bergmann.de", 366 | "role": "lead" 367 | } 368 | ], 369 | "description": "Utility class for timing", 370 | "homepage": "https://github.com/sebastianbergmann/php-timer/", 371 | "keywords": [ 372 | "timer" 373 | ], 374 | "time": "2017-02-26T11:10:40+00:00" 375 | }, 376 | { 377 | "name": "phpunit/php-token-stream", 378 | "version": "1.2.2", 379 | "source": { 380 | "type": "git", 381 | "url": "https://github.com/sebastianbergmann/php-token-stream.git", 382 | "reference": "ad4e1e23ae01b483c16f600ff1bebec184588e32" 383 | }, 384 | "dist": { 385 | "type": "zip", 386 | "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/ad4e1e23ae01b483c16f600ff1bebec184588e32", 387 | "reference": "ad4e1e23ae01b483c16f600ff1bebec184588e32", 388 | "shasum": "" 389 | }, 390 | "require": { 391 | "ext-tokenizer": "*", 392 | "php": ">=5.3.3" 393 | }, 394 | "type": "library", 395 | "extra": { 396 | "branch-alias": { 397 | "dev-master": "1.2-dev" 398 | } 399 | }, 400 | "autoload": { 401 | "classmap": [ 402 | "PHP/" 403 | ] 404 | }, 405 | "notification-url": "https://packagist.org/downloads/", 406 | "include-path": [ 407 | "" 408 | ], 409 | "license": [ 410 | "BSD-3-Clause" 411 | ], 412 | "authors": [ 413 | { 414 | "name": "Sebastian Bergmann", 415 | "email": "sb@sebastian-bergmann.de", 416 | "role": "lead" 417 | } 418 | ], 419 | "description": "Wrapper around PHP's tokenizer extension.", 420 | "homepage": "https://github.com/sebastianbergmann/php-token-stream/", 421 | "keywords": [ 422 | "tokenizer" 423 | ], 424 | "time": "2014-03-03T05:10:30+00:00" 425 | }, 426 | { 427 | "name": "phpunit/phpunit", 428 | "version": "3.7.38", 429 | "source": { 430 | "type": "git", 431 | "url": "https://github.com/sebastianbergmann/phpunit.git", 432 | "reference": "38709dc22d519a3d1be46849868aa2ddf822bcf6" 433 | }, 434 | "dist": { 435 | "type": "zip", 436 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/38709dc22d519a3d1be46849868aa2ddf822bcf6", 437 | "reference": "38709dc22d519a3d1be46849868aa2ddf822bcf6", 438 | "shasum": "" 439 | }, 440 | "require": { 441 | "ext-ctype": "*", 442 | "ext-dom": "*", 443 | "ext-json": "*", 444 | "ext-pcre": "*", 445 | "ext-reflection": "*", 446 | "ext-spl": "*", 447 | "php": ">=5.3.3", 448 | "phpunit/php-code-coverage": "~1.2", 449 | "phpunit/php-file-iterator": "~1.3", 450 | "phpunit/php-text-template": "~1.1", 451 | "phpunit/php-timer": "~1.0", 452 | "phpunit/phpunit-mock-objects": "~1.2", 453 | "symfony/yaml": "~2.0" 454 | }, 455 | "require-dev": { 456 | "pear-pear.php.net/pear": "1.9.4" 457 | }, 458 | "suggest": { 459 | "phpunit/php-invoker": "~1.1" 460 | }, 461 | "bin": [ 462 | "composer/bin/phpunit" 463 | ], 464 | "type": "library", 465 | "extra": { 466 | "branch-alias": { 467 | "dev-master": "3.7.x-dev" 468 | } 469 | }, 470 | "autoload": { 471 | "classmap": [ 472 | "PHPUnit/" 473 | ] 474 | }, 475 | "notification-url": "https://packagist.org/downloads/", 476 | "include-path": [ 477 | "", 478 | "../../symfony/yaml/" 479 | ], 480 | "license": [ 481 | "BSD-3-Clause" 482 | ], 483 | "authors": [ 484 | { 485 | "name": "Sebastian Bergmann", 486 | "email": "sebastian@phpunit.de", 487 | "role": "lead" 488 | } 489 | ], 490 | "description": "The PHP Unit Testing framework.", 491 | "homepage": "http://www.phpunit.de/", 492 | "keywords": [ 493 | "phpunit", 494 | "testing", 495 | "xunit" 496 | ], 497 | "time": "2014-10-17T09:04:17+00:00" 498 | }, 499 | { 500 | "name": "phpunit/phpunit-mock-objects", 501 | "version": "1.2.3", 502 | "source": { 503 | "type": "git", 504 | "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", 505 | "reference": "5794e3c5c5ba0fb037b11d8151add2a07fa82875" 506 | }, 507 | "dist": { 508 | "type": "zip", 509 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/5794e3c5c5ba0fb037b11d8151add2a07fa82875", 510 | "reference": "5794e3c5c5ba0fb037b11d8151add2a07fa82875", 511 | "shasum": "" 512 | }, 513 | "require": { 514 | "php": ">=5.3.3", 515 | "phpunit/php-text-template": ">=1.1.1@stable" 516 | }, 517 | "suggest": { 518 | "ext-soap": "*" 519 | }, 520 | "type": "library", 521 | "autoload": { 522 | "classmap": [ 523 | "PHPUnit/" 524 | ] 525 | }, 526 | "notification-url": "https://packagist.org/downloads/", 527 | "include-path": [ 528 | "" 529 | ], 530 | "license": [ 531 | "BSD-3-Clause" 532 | ], 533 | "authors": [ 534 | { 535 | "name": "Sebastian Bergmann", 536 | "email": "sb@sebastian-bergmann.de", 537 | "role": "lead" 538 | } 539 | ], 540 | "description": "Mock Object library for PHPUnit", 541 | "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", 542 | "keywords": [ 543 | "mock", 544 | "xunit" 545 | ], 546 | "time": "2013-01-13T10:24:48+00:00" 547 | }, 548 | { 549 | "name": "symfony/yaml", 550 | "version": "v2.8.28", 551 | "source": { 552 | "type": "git", 553 | "url": "https://github.com/symfony/yaml.git", 554 | "reference": "842fb6df22180244b4c65935ce1a88d324e5ff9e" 555 | }, 556 | "dist": { 557 | "type": "zip", 558 | "url": "https://api.github.com/repos/symfony/yaml/zipball/842fb6df22180244b4c65935ce1a88d324e5ff9e", 559 | "reference": "842fb6df22180244b4c65935ce1a88d324e5ff9e", 560 | "shasum": "" 561 | }, 562 | "require": { 563 | "php": ">=5.3.9" 564 | }, 565 | "type": "library", 566 | "extra": { 567 | "branch-alias": { 568 | "dev-master": "2.8-dev" 569 | } 570 | }, 571 | "autoload": { 572 | "psr-4": { 573 | "Symfony\\Component\\Yaml\\": "" 574 | }, 575 | "exclude-from-classmap": [ 576 | "/Tests/" 577 | ] 578 | }, 579 | "notification-url": "https://packagist.org/downloads/", 580 | "license": [ 581 | "MIT" 582 | ], 583 | "authors": [ 584 | { 585 | "name": "Fabien Potencier", 586 | "email": "fabien@symfony.com" 587 | }, 588 | { 589 | "name": "Symfony Community", 590 | "homepage": "https://symfony.com/contributors" 591 | } 592 | ], 593 | "description": "Symfony Yaml Component", 594 | "homepage": "https://symfony.com", 595 | "time": "2017-10-05T14:38:30+00:00" 596 | } 597 | ], 598 | "aliases": [], 599 | "minimum-stability": "stable", 600 | "stability-flags": [], 601 | "prefer-stable": false, 602 | "prefer-lowest": false, 603 | "platform": { 604 | "php": ">=5.4.0" 605 | }, 606 | "platform-dev": [] 607 | } 608 | --------------------------------------------------------------------------------