123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335 |
- <?php
- /**
- * @link http://www.yiiframework.com/
- * @copyright Copyright (c) 2008 Yii Software LLC
- * @license http://www.yiiframework.com/license/
- */
- namespace yii\console\controllers;
- use Yii;
- use yii\console\Controller;
- use yii\console\Exception;
- use yii\helpers\FileHelper;
- use yii\helpers\Console;
- /**
- * This command manages fixtures load to the database tables.
- * You can specify different options of this command to point fixture manager
- * to the specific tables of the different database connections.
- *
- * To use this command simply configure your console.php config like this:
- *
- * ~~~
- * 'db' => [
- * 'class' => 'yii\db\Connection',
- * 'dsn' => 'mysql:host=localhost;dbname={your_database}',
- * 'username' => '{your_db_user}',
- * 'password' => '',
- * 'charset' => 'utf8',
- * ],
- * 'fixture' => [
- * 'class' => 'yii\test\DbFixtureManager',
- * ],
- * ~~~
- *
- * ~~~
- * #load fixtures under $fixturePath to the "users" table
- * yii fixture/apply users
- *
- * #also a short version of this command (generate action is default)
- * yii fixture users
- *
- * #load fixtures under $fixturePath to the "users" table to the different connection
- * yii fixture/apply users --db=someOtherDbConneciton
- *
- * #load fixtures under different $fixturePath to the "users" table.
- * yii fixture/apply users --fixturePath=@app/some/other/path/to/fixtures
- * ~~~
- *
- * @author Mark Jebri <[email protected]>
- * @since 2.0
- */
- class FixtureController extends Controller
- {
- use DbTestTrait;
-
- /**
- * type of fixture apply to database
- */
- const APPLY_ALL = 'all';
- /**
- * @var string controller default action ID.
- */
- public $defaultAction = 'apply';
- /**
- * Alias to the path, where all fixtures are stored.
- * @var string
- */
- public $fixturePath = '@tests/unit/fixtures';
- /**
- * Id of the database connection component of the application.
- * @var string
- */
- public $db = 'db';
- /**
- * 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(), [
- 'db', 'fixturePath'
- ]);
- }
- /**
- * This method is invoked right before an action is to be executed (after all possible filters.)
- * It checks that fixtures path and database connection are available.
- * @param \yii\base\Action $action
- * @return boolean
- */
- public function beforeAction($action)
- {
- if (parent::beforeAction($action)) {
- $this->checkRequirements();
- return true;
- } else {
- return false;
- }
- }
- /**
- * Apply given fixture to the table. You can load several fixtures specifying
- * their names separated with commas, like: tbl_user,tbl_profile. Be sure there is no
- * whitespace between tables names.
- * @param array $fixtures
- * @throws \yii\console\Exception
- */
- public function actionApply(array $fixtures, array $except = [])
- {
- if ($this->getFixtureManager() === null) {
- throw new Exception('Fixture manager is not configured properly. Please refer to official documentation for this purposes.');
- }
- $foundFixtures = $this->findFixtures($fixtures);
- if (!$this->needToApplyAll($fixtures[0])) {
- $notFoundFixtures = array_diff($fixtures, $foundFixtures);
- if ($notFoundFixtures) {
- $this->notifyNotFound($notFoundFixtures);
- }
- }
- if (!$foundFixtures) {
- throw new Exception("No files were found by name: \"" . implode(', ', $fixtures) . "\".\n"
- . "Check that fixtures with these name exists, under fixtures path: \n\"" . Yii::getAlias($this->fixturePath) . "\"."
- );
- }
- if (!$this->confirmApply($foundFixtures, $except)) {
- return;
- }
- $fixtures = array_diff($foundFixtures, $except);
- $this->getFixtureManager()->basePath = $this->fixturePath;
- $this->getFixtureManager()->db = $this->db;
- $transaction = Yii::$app->db->beginTransaction();
- try {
- $this->loadFixtures($foundFixtures);
- $transaction->commit();
- } catch (\Exception $e) {
- $transaction->rollback();
- $this->stdout("Exception occured, transaction rollback. Tables will be in same state.\n", Console::BG_RED);
- throw $e;
- }
- $this->notifySuccess($foundFixtures);
- }
- /**
- * Truncate given table and clear all fixtures from it. You can clear several tables specifying
- * their names separated with commas, like: tbl_user,tbl_profile. Be sure there is no
- * whitespace between tables names.
- * @param array|string $tables
- */
- public function actionClear(array $tables, array $except = ['tbl_migration'])
- {
- if ($this->needToApplyAll($tables[0])) {
- $tables = $this->getDbConnection()->schema->getTableNames();
- }
- if (!$this->confirmClear($tables, $except)) {
- return;
- }
- $tables = array_diff($tables, $except);
- $transaction = Yii::$app->db->beginTransaction();
- try {
- $this->getDbConnection()->createCommand()->checkIntegrity(false)->execute();
- foreach($tables as $table) {
- $this->getDbConnection()->createCommand()->delete($table)->execute();
- $this->getDbConnection()->createCommand()->resetSequence($table)->execute();
- $this->stdout(" Table \"{$table}\" was successfully cleared. \n", Console::FG_GREEN);
- }
- $this->getDbConnection()->createCommand()->checkIntegrity(true)->execute();
- $transaction->commit();
- } catch (\Exception $e) {
- $transaction->rollback();
- $this->stdout("Exception occured, transaction rollback. Tables will be in same state.\n", Console::BG_RED);
- throw $e;
- }
- }
- /**
- * Checks if the database and fixtures path are available.
- * @throws Exception
- */
- public function checkRequirements()
- {
- $path = Yii::getAlias($this->fixturePath, false);
- if (!is_dir($path) || !is_writable($path)) {
- throw new Exception("The fixtures path \"{$this->fixturePath}\" not exist or is not writable.");
- }
- }
- /**
- * Returns database connection component
- * @return \yii\db\Connection
- * @throws Exception if [[db]] is invalid.
- */
- public function getDbConnection()
- {
- $db = Yii::$app->getComponent($this->db);
- if ($db === null) {
- throw new Exception("There is no database connection component with id \"{$this->db}\".");
- }
- return $db;
- }
- /**
- * Notifies user that fixtures were successfully loaded.
- * @param array $fixtures
- */
- private function notifySuccess($fixtures)
- {
- $this->stdout("Fixtures were successfully loaded from path:\n", Console::FG_YELLOW);
- $this->stdout(Yii::getAlias($this->fixturePath) . "\n\n", Console::FG_GREEN);
- $this->outputList($fixtures);
- }
- /**
- * Notifies user that fixtures were not found under fixtures path.
- * @param array $fixtures
- */
- private function notifyNotFound($fixtures)
- {
- $this->stdout("Some fixtures were not found under path:\n", Console::BG_RED);
- $this->stdout(Yii::getAlias($this->fixturePath) . "\n\n", Console::FG_GREEN);
- $this->outputList($fixtures);
- $this->stdout("\n");
- }
- /**
- * Prompts user with confirmation if fixtures should be loaded.
- * @param array $fixtures
- * @param array $except
- * @return boolean
- */
- private function confirmApply($fixtures, $except)
- {
- $this->stdout("Fixtures will be loaded from path: \n", Console::FG_YELLOW);
- $this->stdout(Yii::getAlias($this->fixturePath) . "\n\n", Console::FG_GREEN);
- $this->outputList($fixtures);
- if (count($except)) {
- $this->stdout("\nFixtures that will NOT be loaded: \n\n", Console::FG_YELLOW);
- $this->outputList($except);
- }
- return $this->confirm("\nLoad to database above fixtures?");
- }
- /**
- * Prompts user with confirmation for tables that should be cleared.
- * @param array $tables
- * @param array $except
- * @return boolean
- */
- private function confirmClear($tables, $except)
- {
- $this->stdout("Tables below will be cleared:\n\n", Console::FG_YELLOW);
- $this->outputList($tables);
- if (count($except)) {
- $this->stdout("\nTables that will NOT be cleared:\n\n", Console::FG_YELLOW);
- $this->outputList($except);
- }
- return $this->confirm("\nClear tables?");
- }
- /**
- * Outputs data to the console as a list.
- * @param array $data
- */
- private function outputList($data)
- {
- foreach($data as $index => $item) {
- $this->stdout(" " . ($index + 1) . ". {$item}\n", Console::FG_GREEN);
- }
- }
- /**
- * Checks if needed to apply all fixtures.
- * @param string $fixture
- * @return bool
- */
- public function needToApplyAll($fixture)
- {
- return $fixture == self::APPLY_ALL;
- }
- /**
- * @param array $fixtures
- * @return array Array of found fixtures. These may differ from input parameter as not all fixtures may exists.
- */
- private function findFixtures(array $fixtures)
- {
- $fixturesPath = Yii::getAlias($this->fixturePath);
- $filesToSearch = ['.php'];
- if (!$this->needToApplyAll($fixtures[0])) {
- $filesToSearch = [];
- foreach ($fixtures as $fileName) {
- $filesToSearch[] = $fileName . '.php';
- }
- }
- $files = FileHelper::findFiles($fixturesPath, ['only' => $filesToSearch]);
- $foundFixtures = [];
- foreach ($files as $fixture) {
- $foundFixtures[] = basename($fixture , '.php');
- }
- return $foundFixtures;
- }
- }
|