New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Yii2 faker integration #1743
Yii2 faker integration #1743
Changes from 8 commits
a3071fd
60c305f
9666bc6
34b0342
1bf1a34
319d0ae
2ae2d57
aa90497
467254a
4204f89
8dc5c5c
02bfea4
c5bd270
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
Yii Framework 2 faker extension Change Log | ||
============================================== | ||
|
||
2.0.0 beta under development | ||
---------------------------- | ||
|
||
- no changes in this release. | ||
|
||
2.0.0 alpha, December 1, 2013 | ||
----------------------------- | ||
|
||
- Initial release. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,335 @@ | ||
<?php | ||
/** | ||
* @link http://www.yiiframework.com/ | ||
* @copyright Copyright (c) 2008 Yii Software LLC | ||
* @license http://www.yiiframework.com/license/ | ||
*/ | ||
|
||
namespace yii\faker; | ||
|
||
use Yii; | ||
use yii\console\Exception; | ||
use yii\helpers\FileHelper; | ||
use yii\helpers\Console; | ||
|
||
/** | ||
* This command manage fixtures creations based on given template. | ||
* | ||
* Fixtures are one of the important paths in unit testing. To speed up developers | ||
* work this fixtures can be generated automatically, based on prepared template. | ||
* This command is a simple wrapper for the fixtures library [Faker](https://github.com/fzaninotto/Faker). | ||
* | ||
* You should configure this command as follows (you can use any alias, not only "faker:fixture"): | ||
* | ||
* ~~~ | ||
* 'controllerMap' => [ | ||
* 'faker' => [ | ||
* 'class' => 'yii\faker\FixtureController', | ||
* ], | ||
* ], | ||
* ~~~ | ||
* | ||
* To start using this command you need to be familiar (read guide) for the Faker library and | ||
* generate fixtures template files, according to the given format: | ||
* | ||
* ~~~ | ||
* #users.php file under $templatePath | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please use |
||
* | ||
* return [ | ||
* [ | ||
* 'table_column0' => 'faker_formatter', | ||
* ... | ||
* 'table_columnN' => 'other_faker_formatter | ||
* 'table_columnN+1' => function ($fixture, $faker, $index) { | ||
* //set needed fixture fields based on different conditions | ||
* return $fixture; | ||
* } | ||
* ], | ||
* ]; | ||
* ~~~ | ||
* | ||
* If you use callback as a attribute value, then it will be called as shown with three parameters: | ||
* * $fixture - current fixture array. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Better to use |
||
* * $faker - faker generator instance | ||
* * $index - current fixture index. For example if user need to generate 3 fixtures for tbl_user, it will be 0..2 | ||
* After you set all needed fields in callback, you need to return $fixture array back from the callback. | ||
* | ||
* After you prepared needed templates for tables you can simply generate your fixtures via command | ||
* | ||
* ~~~ | ||
* php yii faker/generate users | ||
* | ||
* #also a short version of this command (generate action is default) | ||
* php yii faker users | ||
* ~~~ | ||
* | ||
* In the code above "users" is template name, after this command run, new file named same as template | ||
* will be created under the $fixturesPath folder. | ||
* You can generate fixtures for all templates by specifying keyword "all_fixtures" | ||
* | ||
* ~~~ | ||
* php yii faker/generate all_fixtures | ||
* ~~~ | ||
* | ||
* This command will generate fixtures for all template files that are stored under $templatePath and | ||
* store fixtures under $fixturesPath with file names same as templates names. | ||
* | ||
* You can specify how many fixtures per file you need by the second parameter. In the code below we generate | ||
* all fixtures and in each file there will be 3 rows (fixtures). | ||
* | ||
* ~~~ | ||
* php yii faker/generate all_fixtures 3 | ||
* ~~~ | ||
* | ||
* You can specify different options of this command: | ||
* | ||
* ~~~ | ||
* #generate fixtures in russian languge | ||
* php yii faker/generate users 5 --language='ru_RU' | ||
* | ||
* #read templates from the other path | ||
* php yii faker/generate all_fixtures --templatePath='@app/path/to/my/custom/templates' | ||
* | ||
* #generate fixtures into other folders, but be sure that this folders exists or you will get notice about that. | ||
* php yii faker/generate all_fixtures --fixturesPath='@tests/unit/fixtures/subfolder1/subfolder2/subfolder3' | ||
* ~~~ | ||
* | ||
* You also can create your own data providers for custom tables fields, see Faker library guide for more info (https://github.com/fzaninotto/Faker); | ||
* After you created custom provider, for example: | ||
* | ||
* ~~~ | ||
* | ||
* class Book extends \Faker\Provider\Base | ||
* { | ||
* public function title($nbWords = 5) | ||
* { | ||
* $sentence = $this->generator->sentence($nbWords); | ||
* return mb_substr($sentence, 0, mb_strlen($sentence) - 1); | ||
* } | ||
* | ||
* public function ISBN() | ||
* { | ||
* return $this->generator->randomNumber(13); | ||
* } | ||
* } | ||
* ~~~ | ||
* | ||
* you can use it by adding it to the $providers property of the current command. In your console.php config: | ||
* | ||
* ~~~ | ||
* 'controllerMap' => [ | ||
* 'faker' => [ | ||
* 'class' => 'yii\faker\FixtureController', | ||
* 'providers' => [ | ||
* 'app\tests\unit\faker\providers\Book', | ||
* ], | ||
* ], | ||
* ], | ||
* ~~~ | ||
* | ||
* @property \Faker\Generator $generator | ||
* | ||
* @since 2.0.0 | ||
*/ | ||
class FixtureController extends \yii\console\controllers\FixtureController | ||
{ | ||
|
||
/** | ||
* type of fixture generating | ||
*/ | ||
const GENERATE_ALL = 'all_fixtures'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I still don't quite like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. was thinking about the same There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the command can be configured using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok, will do changes. change docs also about There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. There's no need to have both There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, we can do it. If you configure it via Also, I suggest we rename There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. but if we do so, user will no be able to load his fixtures to db? what are you thinking about There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
its already so, or what do you mean? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yes, faker controller has all the features of fixture controller. I don't see problem replacing the default fixture controller with faker. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Forget about it. I didn't read carefully. |
||
|
||
/** | ||
* @var string controller default action ID. | ||
*/ | ||
public $defaultAction = 'generate'; | ||
|
||
/** | ||
* Alias to the template path, where all tables templates are stored. | ||
* @var string | ||
*/ | ||
public $templatePath = '@tests/unit/templates/fixtures'; | ||
|
||
/** | ||
* Language to use when generating fixtures data. | ||
* @var string | ||
*/ | ||
public $language; | ||
|
||
/** | ||
* Additional data providers that can be created by user and will be added to the Faker generator. | ||
* More info in [Faker](https://github.com/fzaninotto/Faker.) library docs. | ||
* @var array | ||
*/ | ||
public $providers = array(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Short array syntax should be used. |
||
|
||
/** | ||
* Faker generator instance | ||
* @var \Faker\Generator | ||
*/ | ||
private $_generator; | ||
|
||
/** | ||
* Returns the names of the global options for this command. | ||
* @return array the names of the global options for this command. | ||
*/ | ||
public function globalOptions() | ||
{ | ||
return array_merge(parent::globalOptions(), [ | ||
'templatePath','language' | ||
]); | ||
} | ||
|
||
public function beforeAction($action) | ||
{ | ||
if (parent::beforeAction($action)) { | ||
$this->checkPaths(); | ||
$this->addProviders(); | ||
return true; | ||
} else { | ||
return false; | ||
} | ||
} | ||
|
||
/** | ||
* Generates fixtures and fill them with Faker data. | ||
* @param string $file filename for the table template. You can generate all fixtures for all tables | ||
* by specifiyng keyword "all_fixtures" as filename. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about using |
||
* @param integer $times how much fixtures do you want per table | ||
*/ | ||
public function actionGenerate($file, $times = 2) | ||
{ | ||
$templatePath = Yii::getAlias($this->templatePath); | ||
$fixturesPath = Yii::getAlias($this->fixturesPath); | ||
|
||
if ($this->needToGenerateAll($file)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should use |
||
$files = FileHelper::findFiles($templatePath, ['only' => ['.php']]); | ||
else | ||
$files = FileHelper::findFiles($templatePath, ['only' => [$file.'.php']]); | ||
|
||
foreach ($files as $templateFile) | ||
{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should be on the same line as |
||
$fixtureFileName = basename($templateFile); | ||
$template = $this->getTemplate($templateFile); | ||
$fixtures = []; | ||
|
||
for ($i = 0; $i < $times; $i++) { | ||
$fixtures[$i] = $this->generateFixture($template, $i); | ||
} | ||
|
||
$content = $this->getExportedFormat($fixtures); | ||
file_put_contents($fixturesPath.'/'.$fixtureFileName, $content); | ||
$this->stdout("Fixture file was generated under: " . realpath($fixturesPath . "/" . $fixtureFileName) . "\n", Console::FG_GREEN); | ||
} | ||
} | ||
|
||
/** | ||
* Returns Faker generator instance. Getter for private property. | ||
* @return \Faker\Generator | ||
*/ | ||
public function getGenerator() | ||
{ | ||
if (is_null($this->_generator)) | ||
{ | ||
#replacing - on _ because Faker support only en_US format and not intl | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Better to use |
||
|
||
$language = is_null($this->language) ? str_replace('-','_', Yii::$app->language) : $this->language; | ||
$this->_generator = \Faker\Factory::create($language); | ||
} | ||
|
||
return $this->_generator; | ||
} | ||
|
||
/** | ||
* Check if the template path and migrations path exists and writable. | ||
*/ | ||
public function checkPaths() | ||
{ | ||
$path = Yii::getAlias($this->templatePath); | ||
|
||
if (!is_dir($path)) | ||
throw new Exception("The template path \"{$this->templatePath}\" not exist"); | ||
} | ||
|
||
/** | ||
* Adds users providers to the faker generator. | ||
*/ | ||
public function addProviders() | ||
{ | ||
foreach($this->providers as $provider) | ||
$this->generator->addProvider(new $provider($this->generator)); | ||
} | ||
|
||
/** | ||
* Checks if needed to generate all fixtures. | ||
* @param string $file | ||
* @return bool | ||
*/ | ||
public function needToGenerateAll($file) | ||
{ | ||
return $file == self::GENERATE_ALL; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should it be a separate method? If yes, should it be public? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, i think it should, public is enough here, because it could be overridden and almost all Yii2/Yii1 code use private/public. |
||
} | ||
|
||
/** | ||
* Returns generator template for the given fixture name | ||
* @param string $file template file | ||
* @return array generator template | ||
* @throws \yii\console\Exception if wrong file format | ||
*/ | ||
public function getTemplate($file) | ||
{ | ||
$template = require($file); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Currently it can't be called twice because of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. require calling each time, what exactly you are referring to? Tested it with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK. |
||
|
||
if (!is_array($template)) { | ||
throw new Exception("The template file \"$file\" has wrong format. It should return valid template array"); | ||
} | ||
|
||
return $template; | ||
} | ||
|
||
/** | ||
* Returns exported to the string representation of given fixtures array. | ||
* @param type $fixtures | ||
* @return string exported fixtures format | ||
*/ | ||
public function getExportedFormat($fixtures) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about simply There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm talking about renaming the method. It could be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok. |
||
{ | ||
$content = "<?php\n\nreturn ["; | ||
|
||
foreach($fixtures as $fixture) { | ||
|
||
$content .= "\n\t["; | ||
|
||
foreach($fixture as $name=>$value) { | ||
$content .= "\n\t\t'{$name}' => '{$value}',"; | ||
} | ||
|
||
$content .= "\n\t],"; | ||
|
||
} | ||
$content .= "\n];\n"; | ||
return $content; | ||
} | ||
|
||
/** | ||
* Generates fixture from given template | ||
* @param array $template fixture template | ||
* @param integer $index current fixture index | ||
* @return array fixture | ||
*/ | ||
public function generateFixture($template, $index) | ||
{ | ||
$fixture = []; | ||
|
||
foreach($template as $attribute => $fakerProperty) { | ||
if (!is_string($fakerProperty)) { | ||
$fixture = call_user_func_array($fakerProperty,[$fixture,$this->generator, $index]); | ||
} else { | ||
$fixture[$attribute] = $this->generator->$fakerProperty; | ||
} | ||
} | ||
|
||
return $fixture; | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
The Yii framework is free software. It is released under the terms of | ||
the following BSD License. | ||
|
||
Copyright © 2008-2013 by Yii Software LLC (http://www.yiisoft.com) | ||
All rights reserved. | ||
|
||
Redistribution and use in source and binary forms, with or without | ||
modification, are permitted provided that the following conditions | ||
are met: | ||
|
||
* Redistributions of source code must retain the above copyright | ||
notice, this list of conditions and the following disclaimer. | ||
* Redistributions in binary form must reproduce the above copyright | ||
notice, this list of conditions and the following disclaimer in | ||
the documentation and/or other materials provided with the | ||
distribution. | ||
* Neither the name of Yii Software LLC nor the names of its | ||
contributors may be used to endorse or promote products derived | ||
from this software without specific prior written permission. | ||
|
||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | ||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
POSSIBILITY OF SUCH DAMAGE. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this -> these