diff --git a/extensions/elasticsearch/ActiveQuery.php b/extensions/elasticsearch/ActiveQuery.php index 4fb02ffaef..499ecccb63 100644 --- a/extensions/elasticsearch/ActiveQuery.php +++ b/extensions/elasticsearch/ActiveQuery.php @@ -7,6 +7,7 @@ namespace yii\elasticsearch; +use yii\base\NotSupportedException; use yii\db\ActiveQueryInterface; use yii\db\ActiveQueryTrait; use yii\db\ActiveRelationTrait; @@ -143,47 +144,21 @@ class ActiveQuery extends Query implements ActiveQueryInterface */ public function all($db = null) { + if ($this->asArray) { + // TODO implement with + return parent::all($db); + } + $result = $this->createCommand($db)->search(); if (empty($result['hits']['hits'])) { return []; } - if ($this->fields !== null) { - foreach ($result['hits']['hits'] as &$row) { - $row['_source'] = isset($row['fields']) ? $row['fields'] : []; - unset($row['fields']); - } - unset($row); - } - /** @var ActiveRecord $modelClass */ - $modelClass = $this->modelClass; - $pk = $modelClass::primaryKey()[0]; - if ($this->asArray && $this->indexBy) { - foreach ($result['hits']['hits'] as &$row) { - if ($pk === '_id') { - $row['_source']['_id'] = $row['_id']; - } - $row['_source']['_score'] = $row['_score']; - $row = $row['_source']; - } - unset($row); - } $models = $this->createModels($result['hits']['hits']); - if ($this->asArray && !$this->indexBy) { - foreach ($models as $key => $model) { - if ($pk === '_id') { - $model['_source']['_id'] = $model['_id']; - } - $model['_source']['_score'] = $model['_score']; - $models[$key] = $model['_source']; - } - } if (!empty($this->with)) { $this->findWith($this->with, $models); } - if (!$this->asArray) { - foreach ($models as $model) { - $model->afterFind(); - } + foreach ($models as $model) { + $model->afterFind(); } return $models; @@ -203,30 +178,34 @@ class ActiveQuery extends Query implements ActiveQueryInterface return null; } if ($this->asArray) { - /** @var ActiveRecord $modelClass */ - $modelClass = $this->modelClass; - $model = $result['_source']; - $pk = $modelClass::primaryKey()[0]; - if ($pk === '_id') { - $model['_id'] = $result['_id']; - } - $model['_score'] = $result['_score']; + // TODO implement with +// /** @var ActiveRecord $modelClass */ +// $modelClass = $this->modelClass; +// $model = $result['_source']; +// $pk = $modelClass::primaryKey()[0]; +// if ($pk === '_id') { +// $model['_id'] = $result['_id']; +// } +// $model['_score'] = $result['_score']; +// if (!empty($this->with)) { +// $models = [$model]; +// $this->findWith($this->with, $models); +// $model = $models[0]; +// } + return $result; } else { /** @var ActiveRecord $class */ $class = $this->modelClass; $model = $class::instantiate($result); $class::populateRecord($model, $result); - } - if (!empty($this->with)) { - $models = [$model]; - $this->findWith($this->with, $models); - $model = $models[0]; - } - if (!$this->asArray) { + if (!empty($this->with)) { + $models = [$model]; + $this->findWith($this->with, $models); + $model = $models[0]; + } $model->afterFind(); + return $model; } - - return $model; } /** @@ -235,27 +214,14 @@ class ActiveQuery extends Query implements ActiveQueryInterface public function search($db = null, $options = []) { $result = $this->createCommand($db)->search($options); - if (!empty($result['hits']['hits'])) { + // TODO implement with for asArray + if (!empty($result['hits']['hits']) && !$this->asArray) { $models = $this->createModels($result['hits']['hits']); - if ($this->asArray) { - /** @var ActiveRecord $modelClass */ - $modelClass = $this->modelClass; - $pk = $modelClass::primaryKey()[0]; - foreach ($models as $key => $model) { - if ($pk === '_id') { - $model['_source']['_id'] = $model['_id']; - } - $model['_source']['_score'] = $model['_score']; - $models[$key] = $model['_source']; - } - } if (!empty($this->with)) { $this->findWith($this->with, $models); } - if (!$this->asArray) { - foreach ($models as $model) { - $model->afterFind(); - } + foreach ($models as $model) { + $model->afterFind(); } $result['hits']['hits'] = $models; } @@ -263,23 +229,6 @@ class ActiveQuery extends Query implements ActiveQueryInterface return $result; } - /** - * @inheritdoc - */ - public function scalar($field, $db = null) - { - $record = parent::one($db); - if ($record !== false) { - if ($field == '_id') { - return $record['_id']; - } elseif (isset($record['_source'][$field])) { - return $record['_source'][$field]; - } - } - - return null; - } - /** * @inheritdoc */ @@ -288,6 +237,7 @@ class ActiveQuery extends Query implements ActiveQueryInterface if ($field == '_id') { $command = $this->createCommand($db); $command->queryParts['fields'] = []; + $command->queryParts['_source'] = false; $result = $command->search(); if (empty($result['hits']['hits'])) { return []; diff --git a/extensions/elasticsearch/ActiveRecord.php b/extensions/elasticsearch/ActiveRecord.php index b5c14542d8..6ff1095d4f 100644 --- a/extensions/elasticsearch/ActiveRecord.php +++ b/extensions/elasticsearch/ActiveRecord.php @@ -114,7 +114,7 @@ class ActiveRecord extends BaseActiveRecord } $command = static::getDb()->createCommand(); $result = $command->get(static::index(), static::type(), $primaryKey, $options); - if ($result['exists']) { + if ($result['found']) { $model = static::instantiate($result); static::populateRecord($model, $result); $model->afterFind(); @@ -150,7 +150,7 @@ class ActiveRecord extends BaseActiveRecord $result = $command->mget(static::index(), static::type(), $primaryKeys, $options); $models = []; foreach ($result['docs'] as $doc) { - if ($doc['exists']) { + if ($doc['found']) { $model = static::instantiate($doc); static::populateRecord($model, $doc); $model->afterFind(); @@ -282,8 +282,23 @@ class ActiveRecord extends BaseActiveRecord */ public static function populateRecord($record, $row) { - parent::populateRecord($record, $row['_source']); - $pk = static::primaryKey()[0]; + $attributes = []; + if (isset($row['_source'])) { + $attributes = $row['_source']; + } + if (isset($row['fields'])) { + // reset fields in case it is scalar value TODO use field metadata for this + foreach($row['fields'] as $key => $value) { + if (count($value) == 1) { + $row['fields'][$key] = reset($value); + } + } + $attributes = array_merge($attributes, $row['fields']); + } + + parent::populateRecord($record, $attributes); + + $pk = static::primaryKey()[0];//TODO should always set ID in case of fields are not returned if ($pk === '_id') { $record->_id = $row['_id']; } @@ -379,9 +394,9 @@ class ActiveRecord extends BaseActiveRecord $options ); - if (!isset($response['ok'])) { - return false; - } +// if (!isset($response['ok'])) { +// return false; +// } $pk = static::primaryKey()[0]; $this->$pk = $response['_id']; if ($pk != '_id') { @@ -444,13 +459,13 @@ class ActiveRecord extends BaseActiveRecord $n = 0; $errors = []; foreach ($response['items'] as $item) { - if (isset($item['update']['error'])) { - $errors[] = $item['update']; - } elseif ($item['update']['ok']) { + if (isset($item['update']['status']) && $item['update']['status'] == 200) { $n++; + } else { + $errors[] = $item['update']; } } - if (!empty($errors)) { + if (!empty($errors) || isset($response['errors']) && $response['errors']) { throw new Exception(__METHOD__ . ' failed updating records.', $errors); } @@ -508,13 +523,13 @@ class ActiveRecord extends BaseActiveRecord $n = 0; $errors = []; foreach ($response['items'] as $item) { - if (isset($item['update']['error'])) { - $errors[] = $item['update']; - } elseif ($item['update']['ok']) { + if (isset($item['update']['status']) && $item['update']['status'] == 200) { $n++; + } else { + $errors[] = $item['update']; } } - if (!empty($errors)) { + if (!empty($errors) || isset($response['errors']) && $response['errors']) { throw new Exception(__METHOD__ . ' failed updating records counters.', $errors); } @@ -563,13 +578,15 @@ class ActiveRecord extends BaseActiveRecord $n = 0; $errors = []; foreach ($response['items'] as $item) { - if (isset($item['delete']['error'])) { + if (isset($item['delete']['status']) && $item['delete']['status'] == 200) { + if (isset($item['delete']['found']) && $item['delete']['found']) { + $n++; + } + } else { $errors[] = $item['delete']; - } elseif ($item['delete']['found'] && $item['delete']['ok']) { - $n++; } } - if (!empty($errors)) { + if (!empty($errors) || isset($response['errors']) && $response['errors']) { throw new Exception(__METHOD__ . ' failed deleting records.', $errors); } diff --git a/extensions/elasticsearch/CHANGELOG.md b/extensions/elasticsearch/CHANGELOG.md index 6b69719783..3710c9708c 100644 --- a/extensions/elasticsearch/CHANGELOG.md +++ b/extensions/elasticsearch/CHANGELOG.md @@ -4,7 +4,9 @@ Yii Framework 2 elasticsearch extension Change Log 2.0.0-rc under development -------------------------- -- no changes in this release. +- Chg: asArray in ActiveQuery is now equal to using the normal Query. This means, that the output structure has changed and `with` is supported anymore. (cebe) +- Chg: Deletion of a record is now also considered successfull if the record did not exist. (cebe) +- Chg: Requirement changes: Yii now requires elasticsearch version 1.0 or higher (cebe) 2.0.0-beta April 13, 2014 diff --git a/extensions/elasticsearch/Command.php b/extensions/elasticsearch/Command.php index 560992b813..f1313ad15b 100644 --- a/extensions/elasticsearch/Command.php +++ b/extensions/elasticsearch/Command.php @@ -315,7 +315,7 @@ class Command extends Component { $body = $mapping !== null ? (is_string($mapping) ? $mapping : Json::encode($mapping)) : null; - return $this->db->put([$index, $type, '_mapping'], $options, $body); + return $this->db->put([$index, '_mapping', $type], $options, $body); } /** @@ -326,7 +326,7 @@ class Command extends Component */ public function getMapping($index = '_all', $type = '_all') { - return $this->db->get([$index, $type, '_mapping']); + return $this->db->get([$index, '_mapping', $type]); } /** @@ -337,7 +337,7 @@ class Command extends Component */ public function deleteMapping($index, $type) { - return $this->db->delete([$index, $type]); + return $this->db->delete([$index, '_mapping', $type]); } /** @@ -346,10 +346,11 @@ class Command extends Component * @return mixed * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-get-field-mapping.html */ - public function getFieldMapping($index, $type = '_all') - { - return $this->db->put([$index, $type, '_mapping']); - } +// public function getFieldMapping($index, $type = '_all') +// { +// // TODO implement +// return $this->db->put([$index, $type, '_mapping']); +// } /** * @param $options diff --git a/extensions/elasticsearch/Connection.php b/extensions/elasticsearch/Connection.php index 5d0737b130..8a8124dbad 100644 --- a/extensions/elasticsearch/Connection.php +++ b/extensions/elasticsearch/Connection.php @@ -109,7 +109,7 @@ class Connection extends Component if (strncmp($host, 'inet[/', 6) == 0) { $host = substr($host, 6, -1); } - $response = $this->httpRequest('GET', 'http://' . $host . '/_cluster/nodes'); + $response = $this->httpRequest('GET', 'http://' . $host . '/_nodes'); $this->nodes = $response['nodes']; if (empty($this->nodes)) { throw new Exception('cluster autodetection did not find any active node.'); diff --git a/extensions/elasticsearch/Query.php b/extensions/elasticsearch/Query.php index dc9996bdb3..535e1c83eb 100644 --- a/extensions/elasticsearch/Query.php +++ b/extensions/elasticsearch/Query.php @@ -58,12 +58,51 @@ class Query extends Component implements QueryInterface /** * @var array the fields being retrieved from the documents. For example, `['id', 'name']`. - * If not set, it means retrieving all fields. An empty array will result in no fields being - * retrieved. This means that only the primaryKey of a record will be available in the result. + * If not set, this option will not be applied to the query and no fields will be returned. + * In this case the `_source` field will be returned by default which can be configured using [[source]]. + * Setting this to an empty array will result in no fields being retrieved, which means that only the primaryKey + * of a record will be available in the result. + * + * For each field you may also add an array representing a [script field]. Example: + * + * ```php + * $query->fields = [ + * 'id', + * 'name', + * 'value_times_two' => [ + * 'script' => "doc['my_field_name'].value * 2", + * ], + * 'value_times_factor' => [ + * 'script' => "doc['my_field_name'].value * factor", + * 'params' => [ + * 'factor' => 2.0 + * ], + * ], + * ] + * ``` + * + * > Note: Field values are [always returned as arrays] even if they only have one value. + * + * [always returned as arrays]: http://www.elasticsearch.org/guide/en/elasticsearch/reference/1.x/_return_values.html#_return_values + * [script field]: http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-script-fields.html + * * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-fields.html#search-request-fields + * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-script-fields.html * @see fields() + * @see source */ public $fields; + /** + * @var array this option controls how the `_source` field is returned from the documents. For example, `['id', 'name']` + * means that only the `id` and `name` field should be returned from `_source`. + * If not set, it means retrieving the full `_source` field unless [[fields]] are specified. + * Setting this option to `false` will disable return of the `_source` field, this means that only the primaryKey + * of a record will be available in the result. + * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-source-filtering.html + * @see source() + * @see fields + */ + public $source; /** * @var string|array The index to retrieve data from. This can be a string representing a single index * or a an array of multiple indexes. If this is not set, indexes are being queried. @@ -137,25 +176,20 @@ class Query extends Component implements QueryInterface return []; } $rows = $result['hits']['hits']; - if ($this->indexBy === null && $this->fields === null) { + if ($this->indexBy === null) { return $rows; } $models = []; foreach ($rows as $key => $row) { - if ($this->fields !== null) { - $row['_source'] = isset($row['fields']) ? $row['fields'] : []; - unset($row['fields']); - } if ($this->indexBy !== null) { if (is_string($this->indexBy)) { - $key = $row['_source'][$this->indexBy]; + $key = isset($row['fields'][$this->indexBy]) ? reset($row['fields'][$this->indexBy]) : $row['_source'][$this->indexBy]; } else { $key = call_user_func($this->indexBy, $row); } } $models[$key] = $row; } - return $models; } @@ -173,10 +207,6 @@ class Query extends Component implements QueryInterface return false; } $record = reset($result['hits']['hits']); - if ($this->fields !== null) { - $record['_source'] = isset($record['fields']) ? $record['fields'] : []; - unset($record['fields']); - } return $record; } @@ -195,25 +225,18 @@ class Query extends Component implements QueryInterface public function search($db = null, $options = []) { $result = $this->createCommand($db)->search($options); - if (!empty($result['hits']['hits']) && ($this->indexBy === null || $this->fields === null)) { + if (!empty($result['hits']['hits']) && $this->indexBy !== null) { $rows = []; foreach ($result['hits']['hits'] as $key => $row) { - if ($this->fields !== null) { - $row['_source'] = isset($row['fields']) ? $row['fields'] : []; - unset($row['fields']); - } - if ($this->indexBy !== null) { - if (is_string($this->indexBy)) { - $key = $row['_source'][$this->indexBy]; - } else { - $key = call_user_func($this->indexBy, $row); - } + if (is_string($this->indexBy)) { + $key = isset($row['fields'][$this->indexBy]) ? $row['fields'][$this->indexBy] : $row['_source'][$this->indexBy]; + } else { + $key = call_user_func($this->indexBy, $row); } $rows[$key] = $row; } $result['hits']['hits'] = $rows; } - return $result; } @@ -247,12 +270,17 @@ class Query extends Component implements QueryInterface */ public function scalar($field, $db = null) { - $record = self::one($db); // TODO limit fields to the one required - if ($record !== false && isset($record['_source'][$field])) { - return $record['_source'][$field]; - } else { - return null; + $record = self::one($db); + if ($record !== false) { + if ($field === '_id') { + return $record['_id']; + } elseif (isset($record['_source'][$field])) { + return $record['_source'][$field]; + } elseif (isset($record['fields'][$field])) { + return count($record['fields'][$field]) == 1 ? reset($record['fields'][$field]) : $record['fields'][$field]; + } } + return null; } /** @@ -265,14 +293,14 @@ class Query extends Component implements QueryInterface public function column($field, $db = null) { $command = $this->createCommand($db); - $command->queryParts['fields'] = [$field]; + $command->queryParts['_source'] = [$field]; $result = $command->search(); if (empty($result['hits']['hits'])) { return []; } $column = []; foreach ($result['hits']['hits'] as $row) { - $column[] = isset($row['fields'][$field]) ? $row['fields'][$field] : null; + $column[] = isset($row['_source'][$field]) ? $row['_source'][$field] : null; } return $column; } @@ -497,6 +525,22 @@ class Query extends Component implements QueryInterface return $this; } + /** + * Sets the source filtering, specifying how the `_source` field of the document should be returned. + * @param array $source the source patterns to be selected. + * @return static the query object itself + * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-source-filtering.html + */ + public function source($source) + { + if (is_array($source) || $source === null) { + $this->source = $source; + } else { + $this->source = func_get_args(); + } + return $this; + } + /** * Sets the search timeout. * @param integer $timeout A search timeout, bounding the search request to be executed within the specified time value diff --git a/extensions/elasticsearch/QueryBuilder.php b/extensions/elasticsearch/QueryBuilder.php index 7d0e770311..951e6f6d17 100644 --- a/extensions/elasticsearch/QueryBuilder.php +++ b/extensions/elasticsearch/QueryBuilder.php @@ -45,8 +45,27 @@ class QueryBuilder extends \yii\base\Object { $parts = []; - if ($query->fields !== null) { - $parts['fields'] = (array) $query->fields; + if ($query->fields === []) { + $parts['fields'] = []; + } elseif ($query->fields !== null) { + $fields = []; + $scriptFields = []; + foreach($query->fields as $key => $field) { + if (is_int($key)) { + $fields[] = $field; + } else { + $scriptFields[$key] = $field; + } + } + if (!empty($fields)) { + $parts['fields'] = $fields; + } + if (!empty($scriptFields)) { + $parts['script_fields'] = $scriptFields; + } + } + if ($query->source !== null) { + $parts['_source'] = $query->source; } if ($query->limit !== null && $query->limit >= 0) { $parts['size'] = $query->limit; diff --git a/extensions/elasticsearch/README.md b/extensions/elasticsearch/README.md index e952f0aba7..0875e8e6cd 100644 --- a/extensions/elasticsearch/README.md +++ b/extensions/elasticsearch/README.md @@ -22,6 +22,10 @@ return [ ]; ``` +Requirements +------------ + +elasticsearch version 1.0 or higher is required. Installation ------------ diff --git a/tests/unit/data/ar/elasticsearch/OrderItem.php b/tests/unit/data/ar/elasticsearch/OrderItem.php index 1e1b6e6859..4541559f5d 100644 --- a/tests/unit/data/ar/elasticsearch/OrderItem.php +++ b/tests/unit/data/ar/elasticsearch/OrderItem.php @@ -14,6 +14,8 @@ use yii\elasticsearch\Command; */ class OrderItem extends ActiveRecord { + public $total; + public function attributes() { return ['order_id', 'item_id', 'quantity', 'subtotal']; diff --git a/tests/unit/extensions/elasticsearch/ActiveRecordTest.php b/tests/unit/extensions/elasticsearch/ActiveRecordTest.php index bb9521934c..125df4244c 100644 --- a/tests/unit/extensions/elasticsearch/ActiveRecordTest.php +++ b/tests/unit/extensions/elasticsearch/ActiveRecordTest.php @@ -151,8 +151,8 @@ class ActiveRecordTest extends ElasticSearchTestCase 'name' => 'user2', 'address' => 'address2', 'status' => 1, - '_score' => 1.0 - ], $customer); +// '_score' => 1.0 + ], $customer['_source']); } public function testSearch() @@ -174,21 +174,21 @@ class ActiveRecordTest extends ElasticSearchTestCase $this->assertEquals(3, $result['total']); $customers = $result['hits']; $this->assertEquals(3, count($customers)); - $this->assertArrayHasKey('id', $customers[0]); - $this->assertArrayHasKey('name', $customers[0]); - $this->assertArrayHasKey('email', $customers[0]); - $this->assertArrayHasKey('address', $customers[0]); - $this->assertArrayHasKey('status', $customers[0]); - $this->assertArrayHasKey('id', $customers[1]); - $this->assertArrayHasKey('name', $customers[1]); - $this->assertArrayHasKey('email', $customers[1]); - $this->assertArrayHasKey('address', $customers[1]); - $this->assertArrayHasKey('status', $customers[1]); - $this->assertArrayHasKey('id', $customers[2]); - $this->assertArrayHasKey('name', $customers[2]); - $this->assertArrayHasKey('email', $customers[2]); - $this->assertArrayHasKey('address', $customers[2]); - $this->assertArrayHasKey('status', $customers[2]); + $this->assertArrayHasKey('id', $customers[0]['_source']); + $this->assertArrayHasKey('name', $customers[0]['_source']); + $this->assertArrayHasKey('email', $customers[0]['_source']); + $this->assertArrayHasKey('address', $customers[0]['_source']); + $this->assertArrayHasKey('status', $customers[0]['_source']); + $this->assertArrayHasKey('id', $customers[1]['_source']); + $this->assertArrayHasKey('name', $customers[1]['_source']); + $this->assertArrayHasKey('email', $customers[1]['_source']); + $this->assertArrayHasKey('address', $customers[1]['_source']); + $this->assertArrayHasKey('status', $customers[1]['_source']); + $this->assertArrayHasKey('id', $customers[2]['_source']); + $this->assertArrayHasKey('name', $customers[2]['_source']); + $this->assertArrayHasKey('email', $customers[2]['_source']); + $this->assertArrayHasKey('address', $customers[2]['_source']); + $this->assertArrayHasKey('status', $customers[2]['_source']); // TODO test asArray() + fields() + indexBy() @@ -387,35 +387,67 @@ class ActiveRecordTest extends ElasticSearchTestCase $this->assertEquals(2, count($customers)); } + public function testScriptFields() + { + $orderItems = OrderItem::find()->fields(['quantity', 'subtotal', 'total' => ['script' => "doc['quantity'].value * doc['subtotal'].value"]])->all(); + foreach($orderItems as $item) { + $this->assertEquals($item->subtotal * $item->quantity, $item->total); + } + } + public function testFindAsArrayFields() { /** @var TestCase|ActiveRecordTestTrait $this */ // indexBy + asArray $customers = Customer::find()->asArray()->fields(['id', 'name'])->all(); $this->assertEquals(3, count($customers)); - $this->assertArrayHasKey('id', $customers[0]); - $this->assertArrayHasKey('name', $customers[0]); - $this->assertArrayNotHasKey('email', $customers[0]); - $this->assertArrayNotHasKey('address', $customers[0]); - $this->assertArrayNotHasKey('status', $customers[0]); - $this->assertArrayHasKey('id', $customers[1]); - $this->assertArrayHasKey('name', $customers[1]); - $this->assertArrayNotHasKey('email', $customers[1]); - $this->assertArrayNotHasKey('address', $customers[1]); - $this->assertArrayNotHasKey('status', $customers[1]); - $this->assertArrayHasKey('id', $customers[2]); - $this->assertArrayHasKey('name', $customers[2]); - $this->assertArrayNotHasKey('email', $customers[2]); - $this->assertArrayNotHasKey('address', $customers[2]); - $this->assertArrayNotHasKey('status', $customers[2]); + $this->assertArrayHasKey('id', $customers[0]['fields']); + $this->assertArrayHasKey('name', $customers[0]['fields']); + $this->assertArrayNotHasKey('email', $customers[0]['fields']); + $this->assertArrayNotHasKey('address', $customers[0]['fields']); + $this->assertArrayNotHasKey('status', $customers[0]['fields']); + $this->assertArrayHasKey('id', $customers[1]['fields']); + $this->assertArrayHasKey('name', $customers[1]['fields']); + $this->assertArrayNotHasKey('email', $customers[1]['fields']); + $this->assertArrayNotHasKey('address', $customers[1]['fields']); + $this->assertArrayNotHasKey('status', $customers[1]['fields']); + $this->assertArrayHasKey('id', $customers[2]['fields']); + $this->assertArrayHasKey('name', $customers[2]['fields']); + $this->assertArrayNotHasKey('email', $customers[2]['fields']); + $this->assertArrayNotHasKey('address', $customers[2]['fields']); + $this->assertArrayNotHasKey('status', $customers[2]['fields']); } - public function testFindIndexByFields() + public function testFindAsArraySourceFilter() + { + /** @var TestCase|ActiveRecordTestTrait $this */ + // indexBy + asArray + $customers = Customer::find()->asArray()->source(['id', 'name'])->all(); + $this->assertEquals(3, count($customers)); + $this->assertArrayHasKey('id', $customers[0]['_source']); + $this->assertArrayHasKey('name', $customers[0]['_source']); + $this->assertArrayNotHasKey('email', $customers[0]['_source']); + $this->assertArrayNotHasKey('address', $customers[0]['_source']); + $this->assertArrayNotHasKey('status', $customers[0]['_source']); + $this->assertArrayHasKey('id', $customers[1]['_source']); + $this->assertArrayHasKey('name', $customers[1]['_source']); + $this->assertArrayNotHasKey('email', $customers[1]['_source']); + $this->assertArrayNotHasKey('address', $customers[1]['_source']); + $this->assertArrayNotHasKey('status', $customers[1]['_source']); + $this->assertArrayHasKey('id', $customers[2]['_source']); + $this->assertArrayHasKey('name', $customers[2]['_source']); + $this->assertArrayNotHasKey('email', $customers[2]['_source']); + $this->assertArrayNotHasKey('address', $customers[2]['_source']); + $this->assertArrayNotHasKey('status', $customers[2]['_source']); + } + + + public function testFindIndexBySource() { $customerClass = $this->getCustomerClass(); /** @var TestCase|ActiveRecordTestTrait $this */ // indexBy + asArray - $customers = Customer::find()->indexBy('name')->fields('id', 'name')->all(); + $customers = Customer::find()->indexBy('name')->source('id', 'name')->all(); $this->assertEquals(3, count($customers)); $this->assertTrue($customers['user1'] instanceof $customerClass); $this->assertTrue($customers['user2'] instanceof $customerClass); @@ -467,42 +499,89 @@ class ActiveRecordTest extends ElasticSearchTestCase // indexBy + asArray $customers = Customer::find()->indexBy('name')->asArray()->fields('id', 'name')->all(); $this->assertEquals(3, count($customers)); - $this->assertArrayHasKey('id', $customers['user1']); - $this->assertArrayHasKey('name', $customers['user1']); - $this->assertArrayNotHasKey('email', $customers['user1']); - $this->assertArrayNotHasKey('address', $customers['user1']); - $this->assertArrayNotHasKey('status', $customers['user1']); - $this->assertArrayHasKey('id', $customers['user2']); - $this->assertArrayHasKey('name', $customers['user2']); - $this->assertArrayNotHasKey('email', $customers['user2']); - $this->assertArrayNotHasKey('address', $customers['user2']); - $this->assertArrayNotHasKey('status', $customers['user2']); - $this->assertArrayHasKey('id', $customers['user3']); - $this->assertArrayHasKey('name', $customers['user3']); - $this->assertArrayNotHasKey('email', $customers['user3']); - $this->assertArrayNotHasKey('address', $customers['user3']); - $this->assertArrayNotHasKey('status', $customers['user3']); + $this->assertArrayHasKey('id', $customers['user1']['fields']); + $this->assertArrayHasKey('name', $customers['user1']['fields']); + $this->assertArrayNotHasKey('email', $customers['user1']['fields']); + $this->assertArrayNotHasKey('address', $customers['user1']['fields']); + $this->assertArrayNotHasKey('status', $customers['user1']['fields']); + $this->assertArrayHasKey('id', $customers['user2']['fields']); + $this->assertArrayHasKey('name', $customers['user2']['fields']); + $this->assertArrayNotHasKey('email', $customers['user2']['fields']); + $this->assertArrayNotHasKey('address', $customers['user2']['fields']); + $this->assertArrayNotHasKey('status', $customers['user2']['fields']); + $this->assertArrayHasKey('id', $customers['user3']['fields']); + $this->assertArrayHasKey('name', $customers['user3']['fields']); + $this->assertArrayNotHasKey('email', $customers['user3']['fields']); + $this->assertArrayNotHasKey('address', $customers['user3']['fields']); + $this->assertArrayNotHasKey('status', $customers['user3']['fields']); // indexBy callable + asArray $customers = Customer::find()->indexBy(function ($customer) { - return $customer['id'] . '-' . $customer['name']; + return reset($customer['fields']['id']) . '-' . reset($customer['fields']['name']); })->asArray()->fields('id', 'name')->all(); $this->assertEquals(3, count($customers)); - $this->assertArrayHasKey('id', $customers['1-user1']); - $this->assertArrayHasKey('name', $customers['1-user1']); - $this->assertArrayNotHasKey('email', $customers['1-user1']); - $this->assertArrayNotHasKey('address', $customers['1-user1']); - $this->assertArrayNotHasKey('status', $customers['1-user1']); - $this->assertArrayHasKey('id', $customers['2-user2']); - $this->assertArrayHasKey('name', $customers['2-user2']); - $this->assertArrayNotHasKey('email', $customers['2-user2']); - $this->assertArrayNotHasKey('address', $customers['2-user2']); - $this->assertArrayNotHasKey('status', $customers['2-user2']); - $this->assertArrayHasKey('id', $customers['3-user3']); - $this->assertArrayHasKey('name', $customers['3-user3']); - $this->assertArrayNotHasKey('email', $customers['3-user3']); - $this->assertArrayNotHasKey('address', $customers['3-user3']); - $this->assertArrayNotHasKey('status', $customers['3-user3']); + $this->assertArrayHasKey('id', $customers['1-user1']['fields']); + $this->assertArrayHasKey('name', $customers['1-user1']['fields']); + $this->assertArrayNotHasKey('email', $customers['1-user1']['fields']); + $this->assertArrayNotHasKey('address', $customers['1-user1']['fields']); + $this->assertArrayNotHasKey('status', $customers['1-user1']['fields']); + $this->assertArrayHasKey('id', $customers['2-user2']['fields']); + $this->assertArrayHasKey('name', $customers['2-user2']['fields']); + $this->assertArrayNotHasKey('email', $customers['2-user2']['fields']); + $this->assertArrayNotHasKey('address', $customers['2-user2']['fields']); + $this->assertArrayNotHasKey('status', $customers['2-user2']['fields']); + $this->assertArrayHasKey('id', $customers['3-user3']['fields']); + $this->assertArrayHasKey('name', $customers['3-user3']['fields']); + $this->assertArrayNotHasKey('email', $customers['3-user3']['fields']); + $this->assertArrayNotHasKey('address', $customers['3-user3']['fields']); + $this->assertArrayNotHasKey('status', $customers['3-user3']['fields']); + } + + public function testFindIndexByAsArray() + { + /** @var \yii\db\ActiveRecordInterface $customerClass */ + $customerClass = $this->getCustomerClass(); + + /** @var TestCase|ActiveRecordTestTrait $this */ + // indexBy + asArray + $customers = $customerClass::find()->asArray()->indexBy('name')->all(); + $this->assertEquals(3, count($customers)); + $this->assertArrayHasKey('id', $customers['user1']['_source']); + $this->assertArrayHasKey('name', $customers['user1']['_source']); + $this->assertArrayHasKey('email', $customers['user1']['_source']); + $this->assertArrayHasKey('address', $customers['user1']['_source']); + $this->assertArrayHasKey('status', $customers['user1']['_source']); + $this->assertArrayHasKey('id', $customers['user2']['_source']); + $this->assertArrayHasKey('name', $customers['user2']['_source']); + $this->assertArrayHasKey('email', $customers['user2']['_source']); + $this->assertArrayHasKey('address', $customers['user2']['_source']); + $this->assertArrayHasKey('status', $customers['user2']['_source']); + $this->assertArrayHasKey('id', $customers['user3']['_source']); + $this->assertArrayHasKey('name', $customers['user3']['_source']); + $this->assertArrayHasKey('email', $customers['user3']['_source']); + $this->assertArrayHasKey('address', $customers['user3']['_source']); + $this->assertArrayHasKey('status', $customers['user3']['_source']); + + // indexBy callable + asArray + $customers = $customerClass::find()->indexBy(function ($customer) { + return $customer['_source']['id'] . '-' . $customer['_source']['name']; + })->asArray()->all(); + $this->assertEquals(3, count($customers)); + $this->assertArrayHasKey('id', $customers['1-user1']['_source']); + $this->assertArrayHasKey('name', $customers['1-user1']['_source']); + $this->assertArrayHasKey('email', $customers['1-user1']['_source']); + $this->assertArrayHasKey('address', $customers['1-user1']['_source']); + $this->assertArrayHasKey('status', $customers['1-user1']['_source']); + $this->assertArrayHasKey('id', $customers['2-user2']['_source']); + $this->assertArrayHasKey('name', $customers['2-user2']['_source']); + $this->assertArrayHasKey('email', $customers['2-user2']['_source']); + $this->assertArrayHasKey('address', $customers['2-user2']['_source']); + $this->assertArrayHasKey('status', $customers['2-user2']['_source']); + $this->assertArrayHasKey('id', $customers['3-user3']['_source']); + $this->assertArrayHasKey('name', $customers['3-user3']['_source']); + $this->assertArrayHasKey('email', $customers['3-user3']['_source']); + $this->assertArrayHasKey('address', $customers['3-user3']['_source']); + $this->assertArrayHasKey('status', $customers['3-user3']['_source']); } public function testAfterFindGet() diff --git a/tests/unit/extensions/elasticsearch/ElasticSearchConnectionTest.php b/tests/unit/extensions/elasticsearch/ElasticSearchConnectionTest.php index b072585724..ee44ac9853 100644 --- a/tests/unit/extensions/elasticsearch/ElasticSearchConnectionTest.php +++ b/tests/unit/extensions/elasticsearch/ElasticSearchConnectionTest.php @@ -20,7 +20,7 @@ class ElasticSearchConnectionTest extends ElasticSearchTestCase $connection->open(); $this->assertNotNull($connection->activeNode); $this->assertArrayHasKey('name', reset($connection->nodes)); - $this->assertArrayHasKey('hostname', reset($connection->nodes)); +// $this->assertArrayHasKey('hostname', reset($connection->nodes)); $this->assertArrayHasKey('version', reset($connection->nodes)); $this->assertArrayHasKey('http_address', reset($connection->nodes)); } diff --git a/tests/unit/extensions/elasticsearch/QueryBuilderTest.php b/tests/unit/extensions/elasticsearch/QueryBuilderTest.php index 82387617b6..bad2387076 100644 --- a/tests/unit/extensions/elasticsearch/QueryBuilderTest.php +++ b/tests/unit/extensions/elasticsearch/QueryBuilderTest.php @@ -49,7 +49,7 @@ class QueryBuilderTest extends ElasticSearchTestCase public function testYiiCanBeFoundByQuery() { $this->prepareDbData(); - $queryParts = ['field' => ['title' => 'yii']]; + $queryParts = ['term' => ['title' => 'yii']]; $query = new Query(); $query->from('yiitest', 'article'); $query->query = $queryParts; diff --git a/tests/unit/extensions/elasticsearch/QueryTest.php b/tests/unit/extensions/elasticsearch/QueryTest.php index d631f1514b..1e853da85c 100644 --- a/tests/unit/extensions/elasticsearch/QueryTest.php +++ b/tests/unit/extensions/elasticsearch/QueryTest.php @@ -40,16 +40,16 @@ class QueryTest extends ElasticSearchTestCase $this->assertEquals(['name', 'status'], $query->fields); $result = $query->one($this->getConnection()); - $this->assertEquals(2, count($result['_source'])); - $this->assertArrayHasKey('status', $result['_source']); - $this->assertArrayHasKey('name', $result['_source']); + $this->assertEquals(2, count($result['fields'])); + $this->assertArrayHasKey('status', $result['fields']); + $this->assertArrayHasKey('name', $result['fields']); $this->assertArrayHasKey('_id', $result); $query->fields([]); $this->assertEquals([], $query->fields); $result = $query->one($this->getConnection()); - $this->assertEquals([], $result['_source']); + $this->assertArrayNotHasKey('fields', $result); $this->assertArrayHasKey('_id', $result); $query->fields(null); diff --git a/tests/unit/framework/ar/ActiveRecordTestTrait.php b/tests/unit/framework/ar/ActiveRecordTestTrait.php index e52bb70715..5ae9d9041e 100644 --- a/tests/unit/framework/ar/ActiveRecordTestTrait.php +++ b/tests/unit/framework/ar/ActiveRecordTestTrait.php @@ -70,25 +70,6 @@ trait ActiveRecordTestTrait $this->assertTrue($customers[1] instanceof $customerClass); $this->assertTrue($customers[2] instanceof $customerClass); - // find all asArray - $customers = $customerClass::find()->asArray()->all(); - $this->assertEquals(3, count($customers)); - $this->assertArrayHasKey('id', $customers[0]); - $this->assertArrayHasKey('name', $customers[0]); - $this->assertArrayHasKey('email', $customers[0]); - $this->assertArrayHasKey('address', $customers[0]); - $this->assertArrayHasKey('status', $customers[0]); - $this->assertArrayHasKey('id', $customers[1]); - $this->assertArrayHasKey('name', $customers[1]); - $this->assertArrayHasKey('email', $customers[1]); - $this->assertArrayHasKey('address', $customers[1]); - $this->assertArrayHasKey('status', $customers[1]); - $this->assertArrayHasKey('id', $customers[2]); - $this->assertArrayHasKey('name', $customers[2]); - $this->assertArrayHasKey('email', $customers[2]); - $this->assertArrayHasKey('address', $customers[2]); - $this->assertArrayHasKey('status', $customers[2]); - // find by a single primary key $customer = $customerClass::findOne(2); $this->assertTrue($customer instanceof $customerClass); @@ -136,6 +117,25 @@ trait ActiveRecordTestTrait 'status' => 1, 'profile_id' => null, ], $customer); + + // find all asArray + $customers = $customerClass::find()->asArray()->all(); + $this->assertEquals(3, count($customers)); + $this->assertArrayHasKey('id', $customers[0]); + $this->assertArrayHasKey('name', $customers[0]); + $this->assertArrayHasKey('email', $customers[0]); + $this->assertArrayHasKey('address', $customers[0]); + $this->assertArrayHasKey('status', $customers[0]); + $this->assertArrayHasKey('id', $customers[1]); + $this->assertArrayHasKey('name', $customers[1]); + $this->assertArrayHasKey('email', $customers[1]); + $this->assertArrayHasKey('address', $customers[1]); + $this->assertArrayHasKey('status', $customers[1]); + $this->assertArrayHasKey('id', $customers[2]); + $this->assertArrayHasKey('name', $customers[2]); + $this->assertArrayHasKey('email', $customers[2]); + $this->assertArrayHasKey('address', $customers[2]); + $this->assertArrayHasKey('status', $customers[2]); } public function testFindScalar()