ActiveFixture.php 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  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\elasticsearch;
  8. use Yii;
  9. use yii\base\InvalidConfigException;
  10. use yii\test\BaseActiveFixture;
  11. /**
  12. * ActiveFixture represents a fixture for testing backed up by an [[modelClass|ActiveRecord class]] or an elastic search index.
  13. *
  14. * Either [[modelClass]] or [[index]] and [[type]] must be set. You should also provide fixture data in the file
  15. * specified by [[dataFile]] or overriding [[getData()]] if you want to use code to generate the fixture data.
  16. *
  17. * When the fixture is being loaded, it will first call [[resetIndex()]] to remove any existing data in the index for the [[type]].
  18. * It will then populate the index with the data returned by [[getData()]].
  19. *
  20. * After the fixture is loaded, you can access the loaded data via the [[data]] property. If you set [[modelClass]],
  21. * you will also be able to retrieve an instance of [[modelClass]] with the populated data via [[getModel()]].
  22. *
  23. * @author Carsten Brandt <mail@cebe.cc>
  24. * @author Qiang Xue <qiang.xue@gmail.com>
  25. * @since 2.0.2
  26. */
  27. class ActiveFixture extends BaseActiveFixture
  28. {
  29. /**
  30. * @var Connection|string the DB connection object or the application component ID of the DB connection.
  31. * After the DbFixture object is created, if you want to change this property, you should only assign it
  32. * with a DB connection object.
  33. */
  34. public $db = 'elasticsearch';
  35. /**
  36. * @var string the name of the index that this fixture is about. If this property is not set,
  37. * the name will be determined via [[modelClass]].
  38. * @see modelClass
  39. */
  40. public $index;
  41. /**
  42. * @var string the name of the type that this fixture is about. If this property is not set,
  43. * the name will be determined via [[modelClass]].
  44. * @see modelClass
  45. */
  46. public $type;
  47. /**
  48. * @var string|boolean the file path or path alias of the data file that contains the fixture data
  49. * to be returned by [[getData()]]. If this is not set, it will default to `FixturePath/data/Index/Type.php`,
  50. * where `FixturePath` stands for the directory containing this fixture class, `Index` stands for the elasticsearch [[index]] name
  51. * and `Type` stands for the [[type]] associated with this fixture.
  52. * You can set this property to be false to prevent loading any data.
  53. */
  54. public $dataFile;
  55. /**
  56. * @inheritdoc
  57. */
  58. public function init()
  59. {
  60. parent::init();
  61. if (!isset($this->modelClass) && (!isset($this->index) || !isset($this->type))) {
  62. throw new InvalidConfigException('Either "modelClass" or "index" and "type" must be set.');
  63. }
  64. /* @var $modelClass ActiveRecord */
  65. $modelClass = $this->modelClass;
  66. if ($this->index === null) {
  67. $this->index = $modelClass::index();
  68. }
  69. if ($this->type === null) {
  70. $this->type = $modelClass::type();
  71. }
  72. }
  73. /**
  74. * Loads the fixture.
  75. *
  76. * The default implementation will first clean up the index by calling [[resetIndex()]].
  77. * It will then populate the index with the data returned by [[getData()]].
  78. *
  79. * If you override this method, you should consider calling the parent implementation
  80. * so that the data returned by [[getData()]] can be populated into the index.
  81. */
  82. public function load()
  83. {
  84. $this->resetIndex();
  85. $this->data = [];
  86. $idField = '_id';
  87. foreach ($this->getData() as $alias => $row) {
  88. $options = [];
  89. $id = isset($row[$idField]) ? $row[$idField] : null;
  90. unset($row[$idField]);
  91. if (isset($row['_parent'])) {
  92. $options['parent'] = $row['_parent'];
  93. unset($row['_parent']);
  94. }
  95. try {
  96. $response = $this->db->createCommand()->insert($this->index, $this->type, $row, $id, $options);
  97. } catch(\yii\db\Exception $e) {
  98. throw new \yii\base\Exception("Failed to insert fixture data \"$alias\": " . $e->getMessage() . "\n" . print_r($e->errorInfo, true), $e->getCode(), $e);
  99. }
  100. if ($id === null) {
  101. $row[$idField] = $response['_id'];
  102. }
  103. $this->data[$alias] = $row;
  104. }
  105. // ensure all data is flushed and immediately available in the test
  106. $this->db->createCommand()->refreshIndex($this->index);
  107. }
  108. /**
  109. * Returns the fixture data.
  110. *
  111. * The default implementation will try to return the fixture data by including the external file specified by [[dataFile]].
  112. * The file should return an array of data rows (column name => column value), each corresponding to a row in the index.
  113. *
  114. * If the data file does not exist, an empty array will be returned.
  115. *
  116. * @return array the data rows to be inserted into the database index.
  117. */
  118. protected function getData()
  119. {
  120. if ($this->dataFile === null) {
  121. $class = new \ReflectionClass($this);
  122. $dataFile = dirname($class->getFileName()) . "/data/{$this->index}/{$this->type}.php";
  123. return is_file($dataFile) ? require($dataFile) : [];
  124. } else {
  125. return parent::getData();
  126. }
  127. }
  128. /**
  129. * Removes all existing data from the specified index and type.
  130. * This method is called before populating fixture data into the index associated with this fixture.
  131. */
  132. protected function resetIndex()
  133. {
  134. $this->db->createCommand([
  135. 'index' => $this->index,
  136. 'type' => $this->type,
  137. 'queryParts' => ['query' => ['match_all' => new \stdClass()]],
  138. ])->deleteByQuery();
  139. }
  140. }