You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					336 lines
				
				8.9 KiB
			
		
		
			
		
	
	
					336 lines
				
				8.9 KiB
			| 
											12 years ago
										 | <?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
 | ||
|  |  * 
 | ||
|  |  * 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. 
 | ||
|  |  * * $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';
 | ||
|  | 
 | ||
|  | 	/**
 | ||
|  | 	 * @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();
 | ||
|  | 
 | ||
|  | 	/**
 | ||
|  | 	 * 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.
 | ||
|  | 	 * @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))
 | ||
|  | 			$files = FileHelper::findFiles($templatePath, ['only' => ['.php']]);
 | ||
|  | 		else
 | ||
|  | 			$files = FileHelper::findFiles($templatePath, ['only' => [$file.'.php']]);
 | ||
|  | 
 | ||
|  | 		foreach ($files as $templateFile)
 | ||
|  | 		{
 | ||
|  | 			$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
 | ||
|  | 
 | ||
|  | 			$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;
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	/**
 | ||
|  | 	 * 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);
 | ||
|  | 
 | ||
|  | 		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)
 | ||
|  | 	{
 | ||
|  | 		$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;
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | }
 |