Commit fbd7ea73 by Qiang Xue

Merge pull request #2313 from Ragazzo/fixture_controller_global_fixtures_option

Fixture controller global fixtures option
parents 87b49414 1caa22d7
...@@ -49,36 +49,41 @@ Loading fixtures ...@@ -49,36 +49,41 @@ Loading fixtures
Fixture classes should be suffixed by `Fixture` class. By default fixtures will be searched under `tests\unit\fixtures` namespace, you can Fixture classes should be suffixed by `Fixture` class. By default fixtures will be searched under `tests\unit\fixtures` namespace, you can
change this behavior with config or command options. change this behavior with config or command options.
To apply fixture, run the following command: To load fixture, run the following command:
``` ```
yii fixture/apply <fixture_name> yii fixture/load <fixture_name>
``` ```
The required `fixture_name` parameter specifies a fixture name which data will be loaded. You can load several fixtures at once. The required `fixture_name` parameter specifies a fixture name which data will be loaded. You can load several fixtures at once.
Below are correct formats of this command: Below are correct formats of this command:
``` ```
// apply `users` fixture // load `users` fixture
yii fixture/apply User yii fixture/load User
// same as above, because default action of "fixture" command is "apply" // same as above, because default action of "fixture" command is "load"
yii fixture User yii fixture User
// apply several fixtures. Note that there should not be any whitespace between ",", it should be one string. // load several fixtures. Note that there should not be any whitespace between ",", it should be one string.
yii fixture User,UserProfile yii fixture User,UserProfile
// apply all fixtures // load all fixtures
yii fixture/apply all yii fixture/load all
// same as above // same as above
yii fixture all yii fixture all
// apply fixtures, but for other database connection. // load fixtures, but for other database connection.
yii fixtures User --db='customDbConnectionId' yii fixture User --db='customDbConnectionId'
// apply fixtures, but search them in different namespace. By default namespace is: tests\unit\fixtures. // load fixtures, but search them in different namespace. By default namespace is: tests\unit\fixtures.
yii fixtures User --namespace='alias\my\custom\namespace' yii fixture User --namespace='alias\my\custom\namespace'
// load global fixture `some\name\space\CustomFixture` before other fixtures will be loaded.
// By default this option is set to `InitDbFixture` to disable/enable integrity checks. You can specify several
// global fixtures separated by comma.
yii fixture User --globalFixtures='some\name\space\Custom'
``` ```
Unloading fixtures Unloading fixtures
...@@ -88,16 +93,16 @@ To unload fixture, run the following command: ...@@ -88,16 +93,16 @@ To unload fixture, run the following command:
``` ```
// unload Users fixture, by default it will clear fixture storage (for example "users" table, or "users" collection if this is mongodb fixture). // unload Users fixture, by default it will clear fixture storage (for example "users" table, or "users" collection if this is mongodb fixture).
yii fixture/clear User yii fixture/unload User
// Unload several fixtures. Note that there should not be any whitespace between ",", it should be one string. // Unload several fixtures. Note that there should not be any whitespace between ",", it should be one string.
yii fixture/clear User,UserProfile yii fixture/unload User,UserProfile
// unload all fixtures // unload all fixtures
yii fixture/clear all yii fixture/unload all
``` ```
Same command options like: `db`, `namespace` also can be applied to this command. Same command options like: `db`, `namespace`, `globalFixtures` also can be applied to this command.
Configure Command Globally Configure Command Globally
-------------------------- --------------------------
...@@ -111,6 +116,10 @@ different migration path as follows: ...@@ -111,6 +116,10 @@ different migration path as follows:
'class' => 'yii\console\controllers\FixtureController', 'class' => 'yii\console\controllers\FixtureController',
'db' => 'customDbConnectionId', 'db' => 'customDbConnectionId',
'namespace' => 'myalias\some\custom\namespace', 'namespace' => 'myalias\some\custom\namespace',
'globalFixtures' => [
'some\name\space\Foo',
'other\name\space\Bar'
],
], ],
] ]
``` ```
......
...@@ -12,8 +12,6 @@ use yii\console\Controller; ...@@ -12,8 +12,6 @@ use yii\console\Controller;
use yii\console\Exception; use yii\console\Exception;
use yii\helpers\Console; use yii\helpers\Console;
use yii\helpers\FileHelper; use yii\helpers\FileHelper;
use yii\helpers\ArrayHelper;
use yii\helpers\Inflector;
use yii\test\FixtureTrait; use yii\test\FixtureTrait;
/** /**
...@@ -35,16 +33,16 @@ use yii\test\FixtureTrait; ...@@ -35,16 +33,16 @@ use yii\test\FixtureTrait;
* *
* ~~~ * ~~~
* #load fixtures under $fixturePath from UsersFixture class with default namespace "tests\unit\fixtures" * #load fixtures under $fixturePath from UsersFixture class with default namespace "tests\unit\fixtures"
* yii fixture/apply User * yii fixture/load User
* *
* #also a short version of this command (generate action is default) * #also a short version of this command (generate action is default)
* yii fixture User * yii fixture User
* *
* #load fixtures under $fixturePath with the different database connection * #load fixtures under $fixturePath with the different database connection
* yii fixture/apply User --db=someOtherDbConnection * yii fixture/load User --db=someOtherDbConnection
* *
* #load fixtures under different $fixturePath. * #load fixtures under different $fixturePath.
* yii fixture/apply User --namespace=alias\my\custom\namespace\goes\here * yii fixture/load User --namespace=alias\my\custom\namespace\goes\here
* ~~~ * ~~~
* *
* @author Mark Jebri <mark.github@yandex.ru> * @author Mark Jebri <mark.github@yandex.ru>
...@@ -68,11 +66,17 @@ class FixtureController extends Controller ...@@ -68,11 +66,17 @@ class FixtureController extends Controller
* @var string id of the database connection component of the application. * @var string id of the database connection component of the application.
*/ */
public $db = 'db'; public $db = 'db';
/** /**
* @var string default namespace to search fixtures in * @var string default namespace to search fixtures in
*/ */
public $namespace = 'tests\unit\fixtures'; public $namespace = 'tests\unit\fixtures';
/**
* @var array global fixtures that should be applied when loading and unloading. By default it is set to `InitDbFixture`
* that disables and enables integrity check, so your data can be safely loaded.
*/
public $globalFixtures = [
'yii\test\InitDb',
];
/** /**
* Returns the names of the global options for this command. * Returns the names of the global options for this command.
...@@ -81,18 +85,19 @@ class FixtureController extends Controller ...@@ -81,18 +85,19 @@ class FixtureController extends Controller
public function globalOptions() public function globalOptions()
{ {
return array_merge(parent::globalOptions(), [ return array_merge(parent::globalOptions(), [
'db', 'namespace' 'db', 'namespace','globalFixtures'
]); ]);
} }
/** /**
* Apply given fixture to the table. You can load several fixtures specifying * Loads given fixture. You can load several fixtures specifying
* their names separated with commas, like: tbl_user,tbl_profile. Be sure there is no * their names separated with commas, like: User,UserProfile,MyCustom. Be sure there is no
* whitespace between tables names. * whitespace between names. Note that if you are loading fixtures to storage, for example: database or nosql,
* storage will not be cleared, data will be appended to already existed.
* @param array $fixtures * @param array $fixtures
* @throws \yii\console\Exception * @throws \yii\console\Exception
*/ */
public function actionApply(array $fixtures, array $except = []) public function actionLoad(array $fixtures, array $except = [])
{ {
$foundFixtures = $this->findFixtures($fixtures); $foundFixtures = $this->findFixtures($fixtures);
...@@ -110,39 +115,38 @@ class FixtureController extends Controller ...@@ -110,39 +115,38 @@ class FixtureController extends Controller
); );
} }
if (!$this->confirmApply($foundFixtures, $except)) { if (!$this->confirmLoad($foundFixtures, $except)) {
return; return;
} }
$fixtures = $this->getFixturesConfig(array_diff($foundFixtures, $except)); $filtered = array_diff($foundFixtures, $except);
$fixtures = $this->getFixturesConfig(array_merge($this->globalFixtures ,$filtered));
if (!$fixtures) { if (!$fixtures) {
throw new Exception('No fixtures were found in namespace: "' . $this->namespace . '"' . ''); throw new Exception('No fixtures were found in namespace: "' . $this->namespace . '"' . '');
} }
$transaction = Yii::$app->db->beginTransaction(); $transaction = $this->getDbConnection()->beginTransaction();
try { try {
$this->getDbConnection()->createCommand()->checkIntegrity(false)->execute();
$this->loadFixtures($this->createFixtures($fixtures)); $this->loadFixtures($this->createFixtures($fixtures));
$this->getDbConnection()->createCommand()->checkIntegrity(true)->execute();
$transaction->commit(); $transaction->commit();
} catch (\Exception $e) { } catch (\Exception $e) {
$transaction->rollback(); $transaction->rollback();
$this->stdout("Exception occurred, transaction rollback. Tables will be in same state.\n", Console::BG_RED); $this->stdout("Exception occurred, transaction rollback. Tables will be in same state.\n", Console::BG_RED);
throw $e; throw $e;
} }
$this->notifyLoaded(ArrayHelper::getColumn($fixtures, 'class', false)); $this->notifyLoaded($fixtures);
} }
/** /**
* Unloads given fixtures. You can clear environment and unload multiple fixtures by specifying * Unloads given fixtures. You can clear environment and unload multiple fixtures by specifying
* their names separated with commas, like: tbl_user,tbl_profile. Be sure there is no * their names separated with commas, like: User,UserProfile,MyCustom. Be sure there is no
* whitespace between tables names. * whitespace between tables names.
* @param array|string $fixtures * @param array|string $fixtures
* @param array|string $except * @param array|string $except
*/ */
public function actionClear(array $fixtures, array $except = []) public function actionUnload(array $fixtures, array $except = [])
{ {
$foundFixtures = $this->findFixtures($fixtures); $foundFixtures = $this->findFixtures($fixtures);
...@@ -160,22 +164,21 @@ class FixtureController extends Controller ...@@ -160,22 +164,21 @@ class FixtureController extends Controller
); );
} }
if (!$this->confirmClear($foundFixtures, $except)) { if (!$this->confirmUnload($foundFixtures, $except)) {
return; return;
} }
$fixtures = $this->getFixturesConfig(array_diff($foundFixtures, $except)); $filtered = array_diff($foundFixtures, $except);
$fixtures = $this->getFixturesConfig(array_merge($this->globalFixtures ,$filtered));
if (!$fixtures) { if (!$fixtures) {
throw new Exception('No fixtures were found in namespace: ' . $this->namespace . '".'); throw new Exception('No fixtures were found in namespace: ' . $this->namespace . '".');
} }
$transaction = Yii::$app->db->beginTransaction(); $transaction = $this->getDbConnection()->beginTransaction();
try { try {
$this->getDbConnection()->createCommand()->checkIntegrity(false)->execute();
$this->unloadFixtures($this->createFixtures($fixtures)); $this->unloadFixtures($this->createFixtures($fixtures));
$this->getDbConnection()->createCommand()->checkIntegrity(true)->execute();
$transaction->commit(); $transaction->commit();
} catch (\Exception $e) { } catch (\Exception $e) {
...@@ -183,7 +186,7 @@ class FixtureController extends Controller ...@@ -183,7 +186,7 @@ class FixtureController extends Controller
$this->stdout("Exception occurred, transaction rollback. Tables will be in same state.\n", Console::BG_RED); $this->stdout("Exception occurred, transaction rollback. Tables will be in same state.\n", Console::BG_RED);
throw $e; throw $e;
} }
$this->notifyUnloaded(ArrayHelper::getColumn($fixtures, 'class', false)); $this->notifyUnloaded($fixtures);
} }
/** /**
...@@ -243,12 +246,17 @@ class FixtureController extends Controller ...@@ -243,12 +246,17 @@ class FixtureController extends Controller
* @param array $except * @param array $except
* @return boolean * @return boolean
*/ */
private function confirmApply($fixtures, $except) private function confirmLoad($fixtures, $except)
{ {
$this->stdout("Fixtures namespace is: \n", Console::FG_YELLOW); $this->stdout("Fixtures namespace is: \n", Console::FG_YELLOW);
$this->stdout("\t" . $this->namespace . "\n\n", Console::FG_GREEN); $this->stdout("\t" . $this->namespace . "\n\n", Console::FG_GREEN);
$this->stdout("Fixtures below will be loaded:\n\n", Console::FG_YELLOW); if (count($this->globalFixtures)) {
$this->stdout("Global fixtures will be loaded:\n\n", Console::FG_YELLOW);
$this->outputList($this->globalFixtures);
}
$this->stdout("\nFixtures below will be loaded:\n\n", Console::FG_YELLOW);
$this->outputList($fixtures); $this->outputList($fixtures);
if (count($except)) { if (count($except)) {
...@@ -265,12 +273,17 @@ class FixtureController extends Controller ...@@ -265,12 +273,17 @@ class FixtureController extends Controller
* @param array $except * @param array $except
* @return boolean * @return boolean
*/ */
private function confirmClear($fixtures, $except) private function confirmUnload($fixtures, $except)
{ {
$this->stdout("Fixtures namespace is: \n", Console::FG_YELLOW); $this->stdout("Fixtures namespace is: \n", Console::FG_YELLOW);
$this->stdout("\t" . $this->namespace . "\n\n", Console::FG_GREEN); $this->stdout("\t" . $this->namespace . "\n\n", Console::FG_GREEN);
$this->stdout("Fixtures below will be unloaded:\n\n", Console::FG_YELLOW); if (count($this->globalFixtures)) {
$this->stdout("Global fixtures will be unloaded:\n\n", Console::FG_YELLOW);
$this->outputList($this->globalFixtures);
}
$this->stdout("\nFixtures below will be unloaded:\n\n", Console::FG_YELLOW);
$this->outputList($fixtures); $this->outputList($fixtures);
if (count($except)) { if (count($except)) {
...@@ -339,12 +352,11 @@ class FixtureController extends Controller ...@@ -339,12 +352,11 @@ class FixtureController extends Controller
foreach ($fixtures as $fixture) { foreach ($fixtures as $fixture) {
$fullClassName = $this->namespace . '\\' . $fixture . 'Fixture'; $isNamespaced = (strpos($fixture, '\\') !== false);
$fullClassName = $isNamespaced ? $fixture . 'Fixture' : $this->namespace . '\\' . $fixture . 'Fixture';
if (class_exists($fullClassName)) { if (class_exists($fullClassName)) {
$config[Inflector::camel2id($fixture, '_')] = [ $config[] = $fullClassName;
'class' => $fullClassName,
];
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment