diff --git a/extensions/elasticsearch/Command.php b/extensions/elasticsearch/Command.php index 6555113d85a..18e93ab1c57 100644 --- a/extensions/elasticsearch/Command.php +++ b/extensions/elasticsearch/Command.php @@ -237,15 +237,14 @@ public function update($index, $type, $id, $data, $options = []) /** * creates an index - * @param $index - * @param array $configuration - * @return mixed + * @param string $index index name. + * @param array $configuration index configuration. + * @return mixed the request result. * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-create-index.html */ public function createIndex($index, $configuration = null) { $body = $configuration !== null ? Json::encode($configuration) : null; - return $this->db->put([$index], [], $body); } diff --git a/extensions/elasticsearch/MigrateController.php b/extensions/elasticsearch/MigrateController.php new file mode 100644 index 00000000000..abc8ca3f525 --- /dev/null +++ b/extensions/elasticsearch/MigrateController.php @@ -0,0 +1,198 @@ + [ + * 'es-migrate' => 'yii\elasticsearch\MigrateController', + * 'index' => 'myindex', // set this to the index you want to use to store migration state + * 'type' => 'migrations', + * ], + * ]; + * ~~~ + * + * Below are some common usages of this command: + * + * ~~~ + * # creates a new migration named 'create_user_index' + * yii es-migrate/create create_user_index + * + * # applies ALL new migrations + * yii es-migrate + * + * # reverts the last applied migration + * yii es-migrate/down + * ~~~ + * + * @author Carsten Brandt + * @since 2.0.3 + */ +class MigrateController extends BaseMigrateController +{ + /** + * @var Connection|array|string the DB connection object or the application component ID of the DB connection. + * Starting from version 2.0.2, this can also be a configuration array for creating the object. + */ + public $db = 'elasticsearch'; + /** + * @var string the name of the index that is used to store migration state. + * Defaults to `yii2`. + * @see type + */ + public $index = 'yii2'; + /** + * @var string the name of the type that is used to store migration state. + * Defaults to `migrations`. + * @see index + */ + public $type = 'migrations'; + /** + * @inheritdoc + */ + public $templateFile = '@yii/mongodb/views/migration.php'; //TODO + + + /** + * @inheritdoc + */ + public function options($actionID) + { + return array_merge( + parent::options($actionID), + ['index', 'type', 'db'] // global for all actions + ); + } + + /** + * @inheritdoc + */ + public function beforeAction($action) + { + if (parent::beforeAction($action)) { + if ($action->id !== 'create') { + $this->db = Instance::ensure($this->db, Connection::className()); + } + return true; + } else { + return false; + } + } + + /** + * Creates a new migration instance. + * @param string $class the migration class name + * @return \yii\elasticsearch\Migration the migration instance + */ + protected function createMigration($class) + { + $file = $this->migrationPath . DIRECTORY_SEPARATOR . $class . '.php'; + require_once($file); + + return new $class(['db' => $this->db]); + } + + /** + * @inheritdoc + */ + protected function getMigrationHistory($limit) + { + $this->ensureBaseMigrationHistory(); + + $query = new Query; + $rows = $query->source(['version', 'apply_time']) + ->from($this->index, $this->type) + ->orderBy(['version' => SORT_DESC]) + ->limit($limit === null ? 10000 : $limit) + ->all($this->db); + $history = ArrayHelper::map( + $rows, + function($row) { return $row['_source']['version']; }, + function($row) { return $row['_source']['apply_time']; } + ); + unset($history[self::BASE_MIGRATION]); + return $history; + } + + /** + * Ensures migration history contains at least base migration entry. + */ + protected function ensureBaseMigrationHistory() + { + $command = $this->db->createCommand(); + if (!$command->typeExists($this->index, $this->type)) { + $this->stdout("Creating migration history index and type \"{$this->index}/{$this->type}\"..."); + + if (!$command->indexExists($this->index)) { + $command->createIndex($this->index); + } + $command->setMapping($this->index, $this->type, [ + $this->migrationTable => [ + "_id" => [ + "index" => "not_analyzed", + "store" => "yes", + "path" => "version" + ], + "properties" => [ + "version" => ["type" => "string", "index" => "not_analyzed"], + "apply_time" => ["type" => "integer"], + ], + ] + ]); + $this->stdout("done.\n", Console::FG_GREEN); + } + + $baseMigration = $command->get($this->index, $this->type, self::BASE_MIGRATION); + if ($baseMigration['found'] === false) { + $this->addMigrationHistory(self::BASE_MIGRATION); + } + } + + /** + * @inheritdoc + */ + protected function addMigrationHistory($version) + { + $this->db->createCommand()->insert($this->index, $this->type, [ + 'version' => $version, + 'apply_time' => time(), + ], $version, [ + 'op_type' => 'create', + 'refresh' => 'true' + ]); + } + + /** + * @inheritdoc + */ + protected function removeMigrationHistory($version) + { + $this->db->createCommand()->delete($this->index, $this->type, $version); + } +} diff --git a/extensions/elasticsearch/Migration.php b/extensions/elasticsearch/Migration.php new file mode 100644 index 00000000000..554f30787fd --- /dev/null +++ b/extensions/elasticsearch/Migration.php @@ -0,0 +1,82 @@ + + * @since 2.0.3 + */ +abstract class Migration extends Component implements MigrationInterface +{ + /** + * @var Connection|array|string the DB connection object or the application component ID of the DB connection. + * This can also be a configuration array for creating the object. + */ + public $db = 'elasticsearch'; + + + // TODO pass index and type of the command here + // TODO use reference to the command for output + + /** + * Initializes the migration. + * This method will set [[db]] to be the 'db' application component, if it is null. + */ + public function init() + { + parent::init(); + $this->db = Instance::ensure($this->db, Connection::className()); + } + + /** + * Creates a command for execution. + * @param array $config the configuration for the Command class + * @return Command the DB command + */ + protected function createCommand($config = []) + { + return $this->db->createCommand($config); + } + + /** + * creates an index + * @param string $index index name. + * @param array $configuration index configuration. + * @return mixed the request result. + * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-create-index.html + */ + public function createIndex($index, $configuration = null) + { + echo " > create index \"{$index}\" ..."; + $time = microtime(true); + $this->createCommand()->createIndex($index, $configuration); + echo " done (time: " . sprintf('%.3f', microtime(true) - $time) . "s)\n"; + } + + // TODO add more shortcut functions +} diff --git a/extensions/mongodb/console/controllers/MigrateController.php b/extensions/mongodb/console/controllers/MigrateController.php index c42ddc78b54..7391952e408 100644 --- a/extensions/mongodb/console/controllers/MigrateController.php +++ b/extensions/mongodb/console/controllers/MigrateController.php @@ -10,6 +10,7 @@ use Yii; use yii\console\controllers\BaseMigrateController; use yii\console\Exception; +use yii\di\Instance; use yii\mongodb\Connection; use yii\mongodb\Query; use yii\helpers\ArrayHelper; @@ -64,8 +65,9 @@ class MigrateController extends BaseMigrateController */ public $templateFile = '@yii/mongodb/views/migration.php'; /** - * @var Connection|string the DB connection object or the application - * component ID of the DB connection. + * @var Connection|array|string the MongoDB connection object or the application component ID of the MongoDB connection + * that this migration should work with. + * Starting from version 2.0.3, this can also be a configuration array for creating the object. */ public $db = 'mongodb'; @@ -92,12 +94,7 @@ public function beforeAction($action) { if (parent::beforeAction($action)) { if ($action->id !== 'create') { - if (is_string($this->db)) { - $this->db = Yii::$app->get($this->db); - } - if (!$this->db instanceof Connection) { - throw new Exception("The 'db' option must refer to the application component ID of a MongoDB connection."); - } + $this->db = Instance::ensure($this->db, Connection::className()); } return true; } else { diff --git a/framework/console/controllers/MigrateController.php b/framework/console/controllers/MigrateController.php index ab444273845..30c866b44f2 100644 --- a/framework/console/controllers/MigrateController.php +++ b/framework/console/controllers/MigrateController.php @@ -11,6 +11,7 @@ use yii\console\Exception; use yii\db\Connection; use yii\db\Query; +use yii\di\Instance; use yii\helpers\ArrayHelper; use yii\helpers\Console; @@ -64,8 +65,9 @@ class MigrateController extends BaseMigrateController */ public $templateFile = '@yii/views/migration.php'; /** - * @var Connection|string the DB connection object or the application - * component ID of the DB connection. + * @var Connection|array|string the DB connection object or the application component ID of the DB connection + * that this migration should work with. + * Starting from version 2.0.3, this can also be a configuration array for creating the object. */ public $db = 'db'; @@ -92,12 +94,7 @@ public function beforeAction($action) { if (parent::beforeAction($action)) { if ($action->id !== 'create') { - if (is_string($this->db)) { - $this->db = Yii::$app->get($this->db); - } - if (!$this->db instanceof Connection) { - throw new Exception("The 'db' option must refer to the application component ID of a DB connection."); - } + $this->db = Instance::ensure($this->db, Connection::className()); } return true; } else {