Migration.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. <?php
  2. /**
  3. * @link http://www.yiiframework.com/
  4. * @copyright Copyright (c) 2008 Yii Software LLC
  5. * @license http://www.yiiframework.com/license/
  6. */
  7. namespace yii\mongodb;
  8. use yii\base\Component;
  9. use yii\db\MigrationInterface;
  10. use yii\di\Instance;
  11. use yii\helpers\Json;
  12. /**
  13. * Migration is the base class for representing a MongoDB migration.
  14. *
  15. * Each child class of Migration represents an individual MongoDB migration which
  16. * is identified by the child class name.
  17. *
  18. * Within each migration, the [[up()]] method should be overridden to contain the logic
  19. * for "upgrading" the database; while the [[down()]] method for the "downgrading"
  20. * logic.
  21. *
  22. * Migration provides a set of convenient methods for manipulating MongoDB data and schema.
  23. * For example, the [[createIndex()]] method can be used to create a collection index.
  24. * Compared with the same methods in [[Collection]], these methods will display extra
  25. * information showing the method parameters and execution time, which may be useful when
  26. * applying migrations.
  27. *
  28. * @author Klimov Paul <klimov@zfort.com>
  29. * @since 2.0
  30. */
  31. abstract class Migration extends Component implements MigrationInterface
  32. {
  33. /**
  34. * @var Connection|array|string the MongoDB connection object or the application component ID of the MongoDB connection
  35. * that this migration should work with.
  36. * Starting from version 2.0.2, this can also be a configuration array for creating the object.
  37. */
  38. public $db = 'mongodb';
  39. /**
  40. * @var bool indicates whether the log output should be compacted.
  41. * If this is set to true, the individual commands ran within the migration will not be output to the console log.
  42. * Default is `false`, in other words the output is fully verbose by default.
  43. * @since 2.1.5
  44. */
  45. public $compact = false;
  46. /**
  47. * Initializes the migration.
  48. * This method will set [[db]] to be the 'db' application component, if it is null.
  49. */
  50. public function init()
  51. {
  52. parent::init();
  53. $this->db = Instance::ensure($this->db, Connection::className());
  54. }
  55. /**
  56. * Creates new collection with the specified options.
  57. * @param string|array $collection name of the collection
  58. * @param array $options collection options in format: "name" => "value"
  59. */
  60. public function createCollection($collection, $options = [])
  61. {
  62. if (is_array($collection)) {
  63. list($database, $collectionName) = $collection;
  64. } else {
  65. $database = null;
  66. $collectionName = $collection;
  67. }
  68. $this->beginProfile($token = " > create collection " . $this->composeCollectionLogName($collection) . " ...");
  69. $this->db->getDatabase($database)->createCollection($collectionName, $options);
  70. $this->endProfile($token);
  71. }
  72. /**
  73. * Drops existing collection.
  74. * @param string|array $collection name of the collection
  75. */
  76. public function dropCollection($collection)
  77. {
  78. $this->beginProfile($token = " > drop collection " . $this->composeCollectionLogName($collection) . " ...");
  79. $this->db->getCollection($collection)->drop();
  80. $this->endProfile($token);
  81. }
  82. /**
  83. * Creates indexes in the collection.
  84. * @param string|array $collection name of the collection
  85. * @param array $indexes indexes specifications.
  86. * @since 2.1
  87. */
  88. public function createIndexes($collection, $indexes)
  89. {
  90. $this->beginProfile($token = " > create indexes on " . $this->composeCollectionLogName($collection) . " (" . Json::encode($indexes) . ") ...");
  91. $this->db->getCollection($collection)->createIndexes($indexes);
  92. $this->endProfile($token);
  93. }
  94. /**
  95. * Drops collection indexes by name.
  96. * @param string|array $collection name of the collection
  97. * @param string $indexes wildcard for name of the indexes to be dropped.
  98. * @since 2.1
  99. */
  100. public function dropIndexes($collection, $indexes)
  101. {
  102. $this->beginProfile($token = " > drop indexes '{$indexes}' on " . $this->composeCollectionLogName($collection) . ") ...");
  103. $this->db->getCollection($collection)->dropIndexes($indexes);
  104. $this->endProfile($token);
  105. }
  106. /**
  107. * Creates an index on the collection and the specified fields.
  108. * @param string|array $collection name of the collection
  109. * @param array|string $columns column name or list of column names.
  110. * @param array $options list of options in format: optionName => optionValue.
  111. */
  112. public function createIndex($collection, $columns, $options = [])
  113. {
  114. $this->beginProfile($token = " > create index on " . $this->composeCollectionLogName($collection) . " (" . Json::encode((array) $columns) . empty($options) ? "" : ", " . Json::encode($options) . ") ...");
  115. $this->db->getCollection($collection)->createIndex($columns, $options);
  116. $this->endProfile($token);
  117. }
  118. /**
  119. * Drop indexes for specified column(s).
  120. * @param string|array $collection name of the collection
  121. * @param string|array $columns column name or list of column names.
  122. */
  123. public function dropIndex($collection, $columns)
  124. {
  125. $this->beginProfile($token = " > drop index on " . $this->composeCollectionLogName($collection) . " (" . Json::encode((array) $columns) . ") ...");
  126. $this->db->getCollection($collection)->dropIndex($columns);
  127. $this->endProfile($token);
  128. }
  129. /**
  130. * Drops all indexes for specified collection.
  131. * @param string|array $collection name of the collection.
  132. */
  133. public function dropAllIndexes($collection)
  134. {
  135. $this->beginProfile($token = " > drop all indexes on " . $this->composeCollectionLogName($collection) . ") ...");
  136. $this->db->getCollection($collection)->dropAllIndexes();
  137. $this->endProfile($token);
  138. }
  139. /**
  140. * Inserts new data into collection.
  141. * @param array|string $collection collection name.
  142. * @param array|object $data data to be inserted.
  143. * @param array $options list of options in format: optionName => optionValue.
  144. * @return \MongoDB\BSON\ObjectID new record id instance.
  145. */
  146. public function insert($collection, $data, $options = [])
  147. {
  148. $this->beginProfile($token = " > insert into " . $this->composeCollectionLogName($collection) . ") ...");
  149. $id = $this->db->getCollection($collection)->insert($data, $options);
  150. $this->endProfile($token);
  151. return $id;
  152. }
  153. /**
  154. * Inserts several new rows into collection.
  155. * @param array|string $collection collection name.
  156. * @param array $rows array of arrays or objects to be inserted.
  157. * @param array $options list of options in format: optionName => optionValue.
  158. * @return array inserted data, each row will have "_id" key assigned to it.
  159. */
  160. public function batchInsert($collection, $rows, $options = [])
  161. {
  162. $this->beginProfile($token = " > insert into " . $this->composeCollectionLogName($collection) . ") ...");
  163. $rows = $this->db->getCollection($collection)->batchInsert($rows, $options);
  164. $this->endProfile($token);
  165. return $rows;
  166. }
  167. /**
  168. * Updates the rows, which matches given criteria by given data.
  169. * Note: for "multiple" mode Mongo requires explicit strategy "$set" or "$inc"
  170. * to be specified for the "newData". If no strategy is passed "$set" will be used.
  171. * @param array|string $collection collection name.
  172. * @param array $condition description of the objects to update.
  173. * @param array $newData the object with which to update the matching records.
  174. * @param array $options list of options in format: optionName => optionValue.
  175. * @return int|bool number of updated documents or whether operation was successful.
  176. */
  177. public function update($collection, $condition, $newData, $options = [])
  178. {
  179. $this->beginProfile($token = " > update " . $this->composeCollectionLogName($collection) . ") ...");
  180. $result = $this->db->getCollection($collection)->update($condition, $newData, $options);
  181. $this->endProfile($token);
  182. return $result;
  183. }
  184. /**
  185. * Update the existing database data, otherwise insert this data
  186. * @param array|string $collection collection name.
  187. * @param array|object $data data to be updated/inserted.
  188. * @param array $options list of options in format: optionName => optionValue.
  189. * @return \MongoDB\BSON\ObjectID updated/new record id instance.
  190. */
  191. public function save($collection, $data, $options = [])
  192. {
  193. $this->beginProfile($token = " > save " . $this->composeCollectionLogName($collection) . ") ...");
  194. $id = $this->db->getCollection($collection)->save($data, $options);
  195. $this->endProfile($token);
  196. return $id;
  197. }
  198. /**
  199. * Removes data from the collection.
  200. * @param array|string $collection collection name.
  201. * @param array $condition description of records to remove.
  202. * @param array $options list of options in format: optionName => optionValue.
  203. * @return int|bool number of updated documents or whether operation was successful.
  204. */
  205. public function remove($collection, $condition = [], $options = [])
  206. {
  207. $this->beginProfile($token = " > remove " . $this->composeCollectionLogName($collection) . ") ...");
  208. $result = $this->db->getCollection($collection)->remove($condition, $options);
  209. $this->endProfile($token);
  210. return $result;
  211. }
  212. /**
  213. * Composes string representing collection name.
  214. * @param array|string $collection collection name.
  215. * @return string collection name.
  216. */
  217. protected function composeCollectionLogName($collection)
  218. {
  219. if (is_array($collection)) {
  220. list($database, $collection) = $collection;
  221. return $database . '.' . $collection;
  222. }
  223. return $collection;
  224. }
  225. /**
  226. * @var array opened profile tokens.
  227. * @since 2.1.1
  228. */
  229. private $profileTokens = [];
  230. /**
  231. * Logs the incoming message.
  232. * By default this method sends message to 'stdout'.
  233. * @param string $string message to be logged.
  234. * @since 2.1.1
  235. */
  236. protected function log($string)
  237. {
  238. echo $string;
  239. }
  240. /**
  241. * Marks the beginning of a code block for profiling.
  242. * @param string $token token for the code block.
  243. * @since 2.1.1
  244. */
  245. protected function beginProfile($token)
  246. {
  247. $this->profileTokens[$token] = microtime(true);
  248. if (!$this->compact) {
  249. $this->log($token);
  250. }
  251. }
  252. /**
  253. * Marks the end of a code block for profiling.
  254. * @param string $token token for the code block.
  255. * @since 2.1.1
  256. */
  257. protected function endProfile($token)
  258. {
  259. if (isset($this->profileTokens[$token])) {
  260. $time = microtime(true) - $this->profileTokens[$token];
  261. unset($this->profileTokens[$token]);
  262. } else {
  263. $time = 0;
  264. }
  265. if (!$this->compact) {
  266. $this->log(" done (time: " . sprintf('%.3f', $time) . "s)\n");
  267. }
  268. }
  269. }