From a7b852fcc3eed9e0b3a5f0d0247d287471f11c4d Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Sat, 4 Jan 2014 04:26:50 +0100 Subject: [PATCH 1/6] Changed elasticsearch AR primary key handling now supports mapped primary key when _id is part of source with an alias. --- extensions/yii/elasticsearch/ActiveQuery.php | 34 ++++++++-- extensions/yii/elasticsearch/ActiveRecord.php | 77 +++++++++++++++------- extensions/yii/elasticsearch/CHANGELOG.md | 1 + extensions/yii/elasticsearch/QueryBuilder.php | 12 ++-- extensions/yii/elasticsearch/README.md | 13 ++-- extensions/yii/gii/generators/crud/Generator.php | 8 +-- .../gii/generators/crud/templates/controller.php | 2 +- framework/yii/data/ActiveDataProvider.php | 2 +- framework/yii/db/BaseActiveRecord.php | 4 +- framework/yii/validators/UniqueValidator.php | 2 +- tests/unit/data/ar/elasticsearch/Customer.php | 31 ++++++++- tests/unit/data/ar/elasticsearch/Item.php | 27 +++++++- tests/unit/data/ar/elasticsearch/Order.php | 38 +++++++++-- tests/unit/data/ar/elasticsearch/OrderItem.php | 25 ++++++- .../extensions/elasticsearch/ActiveRecordTest.php | 70 +++++++++++--------- tests/unit/framework/ar/ActiveRecordTestTrait.php | 3 + 16 files changed, 256 insertions(+), 93 deletions(-) diff --git a/extensions/yii/elasticsearch/ActiveQuery.php b/extensions/yii/elasticsearch/ActiveQuery.php index 96d6681..2a282d3 100644 --- a/extensions/yii/elasticsearch/ActiveQuery.php +++ b/extensions/yii/elasticsearch/ActiveQuery.php @@ -90,16 +90,26 @@ class ActiveQuery extends Query implements ActiveQueryInterface } unset($row); } + /** @var ActiveRecord $modelClass */ + $modelClass = $this->modelClass; + $pk = $modelClass::primaryKey(); if ($this->asArray && $this->indexBy) { foreach ($result['hits']['hits'] as &$row) { - $row['_source'][ActiveRecord::PRIMARY_KEY_NAME] = $row['_id']; + 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) { - $model['_source'][ActiveRecord::PRIMARY_KEY_NAME] = $model['_id']; + if ($pk === '_id') { + $model['_source']['_id'] = $model['_id']; + } + $model['_source']['_score'] = $model['_score']; $models[$key] = $model['_source']; } } @@ -123,8 +133,14 @@ class ActiveQuery extends Query implements ActiveQueryInterface return null; } if ($this->asArray) { + /** @var ActiveRecord $modelClass */ + $modelClass = $this->modelClass; $model = $result['_source']; - $model[ActiveRecord::PRIMARY_KEY_NAME] = $result['_id']; + $pk = $modelClass::primaryKey(); + if ($pk === '_id') { + $model['_id'] = $result['_id']; + } + $model['_score'] = $result['_score']; } else { /** @var ActiveRecord $class */ $class = $this->modelClass; @@ -147,8 +163,14 @@ class ActiveQuery extends Query implements ActiveQueryInterface if (!empty($result['hits']['hits'])) { $models = $this->createModels($result['hits']['hits']); if ($this->asArray) { + /** @var ActiveRecord $modelClass */ + $modelClass = $this->modelClass; + $pk = $modelClass::primaryKey(); foreach($models as $key => $model) { - $model['_source'][ActiveRecord::PRIMARY_KEY_NAME] = $model['_id']; + if ($pk === '_id') { + $model['_source']['_id'] = $model['_id']; + } + $model['_source']['_score'] = $model['_score']; $models[$key] = $model['_source']; } } @@ -167,7 +189,7 @@ class ActiveQuery extends Query implements ActiveQueryInterface { $record = parent::one($db); if ($record !== false) { - if ($field == ActiveRecord::PRIMARY_KEY_NAME) { + if ($field == '_id') { return $record['_id']; } elseif (isset($record['_source'][$field])) { return $record['_source'][$field]; @@ -181,7 +203,7 @@ class ActiveQuery extends Query implements ActiveQueryInterface */ public function column($field, $db = null) { - if ($field == ActiveRecord::PRIMARY_KEY_NAME) { + if ($field == '_id') { $command = $this->createCommand($db); $command->queryParts['fields'] = []; $result = $command->search(); diff --git a/extensions/yii/elasticsearch/ActiveRecord.php b/extensions/yii/elasticsearch/ActiveRecord.php index 9cc6549..29d62f3 100644 --- a/extensions/yii/elasticsearch/ActiveRecord.php +++ b/extensions/yii/elasticsearch/ActiveRecord.php @@ -47,6 +47,7 @@ class ActiveRecord extends BaseActiveRecord const PRIMARY_KEY_NAME = 'id'; private $_id; + private $_score; private $_version; /** @@ -155,9 +156,12 @@ class ActiveRecord extends BaseActiveRecord // TODO implement copy and move as pk change is not possible - public function getId() + /** + * @return float returns the score of this record when it was retrieved via a [[find()]] query. + */ + public function getScore() { - return $this->_id; + return $this->_score; } /** @@ -165,10 +169,11 @@ class ActiveRecord extends BaseActiveRecord * @param mixed $value * @throws \yii\base\InvalidCallException when record is not new */ - public function setId($value) + public function setPrimaryKey($value) { - if ($this->isNewRecord) { - $this->_id = $value; + $pk = static::primaryKey(); + if ($this->getIsNewRecord() || $pk != '_id') { + $this->$pk = $value; } else { throw new InvalidCallException('Changing the primaryKey of an already saved record is not allowed.'); } @@ -179,10 +184,11 @@ class ActiveRecord extends BaseActiveRecord */ public function getPrimaryKey($asArray = false) { + $pk = static::primaryKey(); if ($asArray) { - return [ActiveRecord::PRIMARY_KEY_NAME => $this->_id]; + return [$pk => $this->$pk]; } else { - return $this->_id; + return $this->$pk; } } @@ -191,11 +197,18 @@ class ActiveRecord extends BaseActiveRecord */ public function getOldPrimaryKey($asArray = false) { - $id = $this->isNewRecord ? null : $this->_id; + $pk = static::primaryKey(); + if ($this->getIsNewRecord()) { + $id = null; + } elseif ($pk == '_id') { + $id = $this->_id; + } else { + $id = $this->getOldAttribute($pk); + } if ($asArray) { - return [ActiveRecord::PRIMARY_KEY_NAME => $id]; + return [$pk => $id]; } else { - return $this->_id; + return $id; } } @@ -204,11 +217,11 @@ class ActiveRecord extends BaseActiveRecord * * The primaryKey for elasticsearch documents is always `primaryKey`. It can not be changed. * - * @return string[] the primary keys of this record. + * @return string the primary key of this record. */ public static function primaryKey() { - return [ActiveRecord::PRIMARY_KEY_NAME]; + return '_id'; } /** @@ -246,8 +259,11 @@ class ActiveRecord extends BaseActiveRecord */ public static function create($row) { - $row['_source'][ActiveRecord::PRIMARY_KEY_NAME] = $row['_id']; $record = parent::create($row['_source']); + $pk = static::primaryKey(); + $record->$pk = $row['_id']; + $record->_score = isset($row['_score']) ? $row['_score'] : null; + $record->_version = isset($row['_version']) ? $row['_version'] : null; // TODO version should always be available... return $record; } @@ -317,11 +333,13 @@ class ActiveRecord extends BaseActiveRecord $options ); - if (!$response['ok']) { + if (!isset($response['ok'])) { return false; } - $this->_id = $response['_id']; + $pk = static::primaryKey(); + $values[$pk] = $this->$pk = $response['_id']; $this->_version = $response['_version']; + $this->_score = null; $this->setOldAttributes($values); $this->afterSave(true); return true; @@ -344,10 +362,11 @@ class ActiveRecord extends BaseActiveRecord */ public static function updateAll($attributes, $condition = []) { - if (count($condition) == 1 && isset($condition[ActiveRecord::PRIMARY_KEY_NAME])) { - $primaryKeys = (array) $condition[ActiveRecord::PRIMARY_KEY_NAME]; + $pkName = static::primaryKey(); + if (count($condition) == 1 && isset($condition[$pkName])) { + $primaryKeys = (array) $condition[$pkName]; } else { - $primaryKeys = static::find()->where($condition)->column(ActiveRecord::PRIMARY_KEY_NAME); + $primaryKeys = static::find()->where($condition)->column($pkName); // TODO check whether this works with default pk _id } if (empty($primaryKeys)) { return 0; @@ -371,11 +390,17 @@ class ActiveRecord extends BaseActiveRecord $url = [static::index(), static::type(), '_bulk']; $response = static::getDb()->post($url, [], $bulk); $n=0; + $errors = []; foreach($response['items'] as $item) { - if ($item['update']['ok']) { + if (isset($item['update']['error'])) { + $errors[] = $item['update']; + } elseif ($item['update']['ok']) { $n++; } } + if (!empty($errors)) { + throw new Exception(__METHOD__ . ' failed updating records.', $errors); + } return $n; } @@ -395,10 +420,11 @@ class ActiveRecord extends BaseActiveRecord */ public static function updateAllCounters($counters, $condition = []) { - if (count($condition) == 1 && isset($condition[ActiveRecord::PRIMARY_KEY_NAME])) { - $primaryKeys = (array) $condition[ActiveRecord::PRIMARY_KEY_NAME]; + $pkName = static::primaryKey(); + if (count($condition) == 1 && isset($condition[$pkName])) { + $primaryKeys = (array) $condition[$pkName]; } else { - $primaryKeys = static::find()->where($condition)->column(ActiveRecord::PRIMARY_KEY_NAME); + $primaryKeys = static::find()->where($condition)->column($pkName); // TODO check whether this works with default pk _id } if (empty($primaryKeys) || empty($counters)) { return 0; @@ -452,10 +478,11 @@ class ActiveRecord extends BaseActiveRecord */ public static function deleteAll($condition = []) { - if (count($condition) == 1 && isset($condition[ActiveRecord::PRIMARY_KEY_NAME])) { - $primaryKeys = (array) $condition[ActiveRecord::PRIMARY_KEY_NAME]; + $pkName = static::primaryKey(); + if (count($condition) == 1 && isset($condition[$pkName])) { + $primaryKeys = (array) $condition[$pkName]; } else { - $primaryKeys = static::find()->where($condition)->column(ActiveRecord::PRIMARY_KEY_NAME); + $primaryKeys = static::find()->where($condition)->column($pkName); // TODO check whether this works with default pk _id } if (empty($primaryKeys)) { return 0; diff --git a/extensions/yii/elasticsearch/CHANGELOG.md b/extensions/yii/elasticsearch/CHANGELOG.md index 1a84ed3..04db504 100644 --- a/extensions/yii/elasticsearch/CHANGELOG.md +++ b/extensions/yii/elasticsearch/CHANGELOG.md @@ -5,6 +5,7 @@ Yii Framework 2 elasticsearch extension Change Log ---------------------------- - Enh #1382: Added a debug toolbar panel for elasticsearch (cebe) +- Chg: Changed handling of ActiveRecord primary keys (cebe) 2.0.0 alpha, December 1, 2013 ----------------------------- diff --git a/extensions/yii/elasticsearch/QueryBuilder.php b/extensions/yii/elasticsearch/QueryBuilder.php index eae9451..aa37471 100644 --- a/extensions/yii/elasticsearch/QueryBuilder.php +++ b/extensions/yii/elasticsearch/QueryBuilder.php @@ -114,7 +114,7 @@ class QueryBuilder extends \yii\base\Object } else { $column = $name; } - if ($column == ActiveRecord::PRIMARY_KEY_NAME) { + if ($column == '_id') { $column = '_uid'; } @@ -176,7 +176,7 @@ class QueryBuilder extends \yii\base\Object { $parts = []; foreach($condition as $attribute => $value) { - if ($attribute == ActiveRecord::PRIMARY_KEY_NAME) { + if ($attribute == '_id') { if ($value == null) { // there is no null pk $parts[] = ['script' => ['script' => '0==1']]; } else { @@ -235,8 +235,8 @@ class QueryBuilder extends \yii\base\Object } list($column, $value1, $value2) = $operands; - if ($column == ActiveRecord::PRIMARY_KEY_NAME) { - throw new NotSupportedException('Between condition is not supported for primaryKey.'); + if ($column == '_id') { + throw new NotSupportedException('Between condition is not supported for the _id field.'); } $filter = ['range' => [$column => ['gte' => $value1, 'lte' => $value2]]]; if ($operator == 'not between') { @@ -274,7 +274,7 @@ class QueryBuilder extends \yii\base\Object unset($values[$i]); } } - if ($column == ActiveRecord::PRIMARY_KEY_NAME) { + if ($column == '_id') { if (empty($values) && $canBeNull) { // there is no null pk $filter = ['script' => ['script' => '0==1']]; } else { @@ -306,6 +306,6 @@ class QueryBuilder extends \yii\base\Object private function buildLikeCondition($operator, $operands) { - throw new NotSupportedException('like conditions is not supported by elasticsearch.'); + throw new NotSupportedException('like conditions are not supported by elasticsearch.'); } } diff --git a/extensions/yii/elasticsearch/README.md b/extensions/yii/elasticsearch/README.md index ecbf633..d299736 100644 --- a/extensions/yii/elasticsearch/README.md +++ b/extensions/yii/elasticsearch/README.md @@ -55,8 +55,10 @@ For general information on how to use yii's ActiveRecord please refer to the [gu For defining an elasticsearch ActiveRecord class your record class needs to extend from `yii\elasticsearch\ActiveRecord` and implement at least the `attributes()` method to define the attributes of the record. -The primary key (the `_id` field in elasticsearch terms) is represented by `getId()` and `setId()` and can not be changed. -The primary key is not part of the attributes. +The handling of primary keys is different in elasticsearch as the primary key (the `_id` field in elasticsearch terms) +is not part of the attributes by default. However it is possible to define a [mapping](TODO link to ES docs) +for the `_id` field to be part of the attributes. See [...TODO...] on how to do this. +The `_id` field of a document/record can be accessed using [[ActiveRecord::getPrimaryKey()]] and [[ActiveRecord::setPrimaryKey()]]. primary key can be defined via [[primaryKey()]] which defaults to `id` if not specified. The primaryKey needs to be part of the attributes so make sure you have an `id` attribute defined if you do @@ -152,10 +154,11 @@ Using the elasticsearch DebugPanel ---------------------------------- The yii2 elasticsearch extensions provides a `DebugPanel` that can be integrated with the yii debug module -an shows the executed elasticsearch queries. It also allows to run these queries on different cluster nodes -an view the results. +and shows the executed elasticsearch queries. It also allows to run these queries +and view the results. -Add the following to you application config to enable it: +Add the following to you application config to enable it (if you already have the debug module +enabled, it is sufficient to just add the panels configuration): ```php // ... diff --git a/extensions/yii/gii/generators/crud/Generator.php b/extensions/yii/gii/generators/crud/Generator.php index bbd2ab5..7e0e671 100644 --- a/extensions/yii/gii/generators/crud/Generator.php +++ b/extensions/yii/gii/generators/crud/Generator.php @@ -176,7 +176,7 @@ class Generator extends \yii\gii\Generator /** @var \yii\db\ActiveRecord $class */ $class = $this->modelClass; $pk = $class::primaryKey(); - return $pk[0]; + return is_array($pk) ? $pk[0] : $pk; } /** @@ -363,7 +363,7 @@ class Generator extends \yii\gii\Generator { /** @var ActiveRecord $class */ $class = $this->modelClass; - $pks = $class::primaryKey(); + $pks = (array) $class::primaryKey(); if (count($pks) === 1) { return "'id' => \$model->{$pks[0]}"; } else { @@ -379,7 +379,7 @@ class Generator extends \yii\gii\Generator { /** @var ActiveRecord $class */ $class = $this->modelClass; - $pks = $class::primaryKey(); + $pks = (array) $class::primaryKey(); if (count($pks) === 1) { return '$id'; } else { @@ -391,7 +391,7 @@ class Generator extends \yii\gii\Generator { /** @var ActiveRecord $class */ $class = $this->modelClass; - $pks = $class::primaryKey(); + $pks = (array) $class::primaryKey(); if (($table = $this->getTableSchema()) === false) { $params = []; foreach ($pks as $pk) { diff --git a/extensions/yii/gii/generators/crud/templates/controller.php b/extensions/yii/gii/generators/crud/templates/controller.php index bb5d3f4..7430b78 100644 --- a/extensions/yii/gii/generators/crud/templates/controller.php +++ b/extensions/yii/gii/generators/crud/templates/controller.php @@ -19,7 +19,7 @@ if ($modelClass === $searchModelClass) { /** @var ActiveRecordInterface $class */ $class = $generator->modelClass; -$pks = $class::primaryKey(); +$pks = (array) $class::primaryKey(); $urlParams = $generator->generateUrlParams(); $actionParams = $generator->generateActionParams(); $actionParamComments = $generator->generateActionParamComments(); diff --git a/framework/yii/data/ActiveDataProvider.php b/framework/yii/data/ActiveDataProvider.php index 2292286..e1175a8 100644 --- a/framework/yii/data/ActiveDataProvider.php +++ b/framework/yii/data/ActiveDataProvider.php @@ -128,7 +128,7 @@ class ActiveDataProvider extends BaseDataProvider } elseif ($this->query instanceof ActiveQueryInterface) { /** @var \yii\db\ActiveRecord $class */ $class = $this->query->modelClass; - $pks = $class::primaryKey(); + $pks = (array) $class::primaryKey(); if (count($pks) === 1) { $pk = $pks[0]; foreach ($models as $model) { diff --git a/framework/yii/db/BaseActiveRecord.php b/framework/yii/db/BaseActiveRecord.php index cefcfe6..133c9b6 100644 --- a/framework/yii/db/BaseActiveRecord.php +++ b/framework/yii/db/BaseActiveRecord.php @@ -924,7 +924,7 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface */ public function equals($record) { - if ($this->isNewRecord || $record->isNewRecord) { + if ($this->getIsNewRecord() || $record->getIsNewRecord()) { return false; } return get_class($this) === get_class($record) && $this->getPrimaryKey() === $record->getPrimaryKey(); @@ -1273,7 +1273,7 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface */ public static function isPrimaryKey($keys) { - $pks = static::primaryKey(); + $pks = (array) static::primaryKey(); if (count($keys) === count($pks)) { return count(array_intersect($keys, $pks)) === count($pks); } else { diff --git a/framework/yii/validators/UniqueValidator.php b/framework/yii/validators/UniqueValidator.php index 51474b0..55c96cf 100644 --- a/framework/yii/validators/UniqueValidator.php +++ b/framework/yii/validators/UniqueValidator.php @@ -101,7 +101,7 @@ class UniqueValidator extends Validator $n = count($objects); if ($n === 1) { $keys = array_keys($params); - $pks = $targetClass::primaryKey(); + $pks = (array) $targetClass::primaryKey(); sort($keys); sort($pks); if ($keys === $pks) { diff --git a/tests/unit/data/ar/elasticsearch/Customer.php b/tests/unit/data/ar/elasticsearch/Customer.php index 0c07d08..1ff1cef 100644 --- a/tests/unit/data/ar/elasticsearch/Customer.php +++ b/tests/unit/data/ar/elasticsearch/Customer.php @@ -1,6 +1,7 @@ hasMany(Order::className(), array('customer_id' => ActiveRecord::PRIMARY_KEY_NAME))->orderBy('create_time'); + return $this->hasMany(Order::className(), array('customer_id' => 'id'))->orderBy('create_time'); } public static function active($query) @@ -40,4 +46,25 @@ class Customer extends ActiveRecord ActiveRecordTest::$afterSaveNewRecord = $this->isNewRecord; parent::afterSave($insert); } + + /** + * sets up the index for this record + * @param Command $command + */ + public static function setUpMapping($command, $statusIsBoolean = false) + { + $command->deleteMapping(static::index(), static::type()); + $command->setMapping(static::index(), static::type(), [ + static::type() => [ + "_id" => ["path" => "id", "index" => "not_analyzed", "store" => "yes"], + "properties" => [ + "name" => ["type" => "string", "index" => "not_analyzed"], + "email" => ["type" => "string", "index" => "not_analyzed"], + "address" => ["type" => "string", "index" => "analyzed"], + "status" => $statusIsBoolean ? ["type" => "boolean"] : ["type" => "integer"], + ] + ] + ]); + + } } diff --git a/tests/unit/data/ar/elasticsearch/Item.php b/tests/unit/data/ar/elasticsearch/Item.php index 7e09b0c..2474f60 100644 --- a/tests/unit/data/ar/elasticsearch/Item.php +++ b/tests/unit/data/ar/elasticsearch/Item.php @@ -1,6 +1,7 @@ deleteMapping(static::index(), static::type()); + $command->setMapping(static::index(), static::type(), [ + static::type() => [ + "_id" => ["path" => "id", "index" => "not_analyzed", "store" => "yes"], + "properties" => [ + "name" => ["type" => "string", "index" => "not_analyzed"], + "category_id" => ["type" => "integer"], + ] + ] + ]); + } } diff --git a/tests/unit/data/ar/elasticsearch/Order.php b/tests/unit/data/ar/elasticsearch/Order.php index 088011c..41d05f7 100644 --- a/tests/unit/data/ar/elasticsearch/Order.php +++ b/tests/unit/data/ar/elasticsearch/Order.php @@ -1,6 +1,7 @@ hasOne(Customer::className(), [ActiveRecord::PRIMARY_KEY_NAME => 'customer_id']); + return $this->hasOne(Customer::className(), ['id' => 'customer_id']); } public function getOrderItems() { - return $this->hasMany(OrderItem::className(), ['order_id' => ActiveRecord::PRIMARY_KEY_NAME]); + return $this->hasMany(OrderItem::className(), ['order_id' => 'id']); } public function getItems() { - return $this->hasMany(Item::className(), [ActiveRecord::PRIMARY_KEY_NAME => 'item_id']) + return $this->hasMany(Item::className(), ['id' => 'item_id']) ->via('orderItems')->orderBy('id'); } @@ -51,8 +57,8 @@ class Order extends ActiveRecord // public function getBooks() // { -// return $this->hasMany('Item', [ActiveRecord::PRIMARY_KEY_NAME => 'item_id']) -// ->viaTable('tbl_order_item', ['order_id' => ActiveRecord::PRIMARY_KEY_NAME]) +// return $this->hasMany('Item', ['id' => 'item_id']) +// ->viaTable('tbl_order_item', ['order_id' => 'id']) // ->where(['category_id' => 1]); // } @@ -65,4 +71,24 @@ class Order extends ActiveRecord return false; } } + + /** + * sets up the index for this record + * @param Command $command + */ + public static function setUpMapping($command) + { + $command->deleteMapping(static::index(), static::type()); + $command->setMapping(static::index(), static::type(), [ + static::type() => [ + "_id" => ["path" => "id", "index" => "not_analyzed", "store" => "yes"], + "properties" => [ + "customer_id" => ["type" => "integer"], +// "create_time" => ["type" => "string", "index" => "not_analyzed"], + "total" => ["type" => "integer"], + ] + ] + ]); + + } } diff --git a/tests/unit/data/ar/elasticsearch/OrderItem.php b/tests/unit/data/ar/elasticsearch/OrderItem.php index a43d8b2..36961d9 100644 --- a/tests/unit/data/ar/elasticsearch/OrderItem.php +++ b/tests/unit/data/ar/elasticsearch/OrderItem.php @@ -1,6 +1,7 @@ hasOne(Order::className(), [ActiveRecord::PRIMARY_KEY_NAME => 'order_id']); + return $this->hasOne(Order::className(), ['id' => 'order_id']); } public function getItem() { - return $this->hasOne(Item::className(), [ActiveRecord::PRIMARY_KEY_NAME => 'item_id']); + return $this->hasOne(Item::className(), ['id' => 'item_id']); + } + + /** + * sets up the index for this record + * @param Command $command + */ + public static function setUpMapping($command) + { + $command->deleteMapping(static::index(), static::type()); + $command->setMapping(static::index(), static::type(), [ + static::type() => [ + "properties" => [ + "order_id" => ["type" => "integer"], + "item_id" => ["type" => "integer"], + "quantity" => ["type" => "integer"], + "subtotal" => ["type" => "integer"], + ] + ] + ]); + } } diff --git a/tests/unit/extensions/elasticsearch/ActiveRecordTest.php b/tests/unit/extensions/elasticsearch/ActiveRecordTest.php index b1d103e..89431aa 100644 --- a/tests/unit/extensions/elasticsearch/ActiveRecordTest.php +++ b/tests/unit/extensions/elasticsearch/ActiveRecordTest.php @@ -48,17 +48,11 @@ class ActiveRecordTest extends ElasticSearchTestCase $db->createCommand()->deleteIndex('yiitest'); } - $db->post(['yiitest'], [], Json::encode([ - 'mappings' => [ - "item" => [ - "_source" => [ "enabled" => true ], - "properties" => [ - // allow proper sorting by name - "name" => ["type" => "string", "index" => "not_analyzed"], - ] - ] - ], - ])); + $command = $db->createCommand(); + Customer::setUpMapping($command); + Item::setUpMapping($command); + Order::setUpMapping($command); + OrderItem::setUpMapping($command); $customer = new Customer(); $customer->id = 1; @@ -132,6 +126,20 @@ class ActiveRecordTest extends ElasticSearchTestCase $db->createCommand()->flushIndex('yiitest'); } + public function testFindAsArray() + { + // asArray + $customer = $this->callCustomerFind()->where(['id' => 2])->asArray()->one(); + $this->assertEquals([ + 'id' => 2, + 'email' => 'user2@example.com', + 'name' => 'user2', + 'address' => 'address2', + 'status' => 1, + '_score' => 1.0 + ], $customer); + } + public function testSearch() { $customers = $this->callCustomerFind()->search()['hits']; @@ -243,8 +251,8 @@ class ActiveRecordTest extends ElasticSearchTestCase public function testInsertNoPk() { - $this->assertEquals([ActiveRecord::PRIMARY_KEY_NAME], Customer::primaryKey()); - $pkName = ActiveRecord::PRIMARY_KEY_NAME; + $this->assertEquals('id', Customer::primaryKey()); + $pkName = 'id'; $customer = new Customer; $customer->email = 'user4@example.com'; @@ -257,6 +265,7 @@ class ActiveRecordTest extends ElasticSearchTestCase $this->assertTrue($customer->isNewRecord); $customer->save(); + $this->afterSave(); $this->assertNotNull($customer->primaryKey); $this->assertNotNull($customer->oldPrimaryKey); @@ -268,7 +277,7 @@ class ActiveRecordTest extends ElasticSearchTestCase public function testInsertPk() { - $pkName = ActiveRecord::PRIMARY_KEY_NAME; + $pkName = 'id'; $customer = new Customer; $customer->$pkName = 5; @@ -288,17 +297,26 @@ class ActiveRecordTest extends ElasticSearchTestCase public function testUpdatePk() { - $pkName = ActiveRecord::PRIMARY_KEY_NAME; + $pkName = 'id'; - $pk = [$pkName => 2]; - $orderItem = Order::find($pk); + $orderItem = Order::find([$pkName => 2]); $this->assertEquals(2, $orderItem->primaryKey); $this->assertEquals(2, $orderItem->oldPrimaryKey); $this->assertEquals(2, $orderItem->$pkName); - $this->setExpectedException('yii\base\InvalidCallException'); +// $this->setExpectedException('yii\base\InvalidCallException'); $orderItem->$pkName = 13; + $this->assertEquals(13, $orderItem->primaryKey); + $this->assertEquals(2, $orderItem->oldPrimaryKey); + $this->assertEquals(13, $orderItem->$pkName); $orderItem->save(); + $this->afterSave(); + $this->assertEquals(13, $orderItem->primaryKey); + $this->assertEquals(13, $orderItem->oldPrimaryKey); + $this->assertEquals(13, $orderItem->$pkName); + + $this->assertNull(Order::find([$pkName => 2])); + $this->assertNotNull(Order::find([$pkName => 13])); } public function testFindLazyVia2() @@ -306,7 +324,7 @@ class ActiveRecordTest extends ElasticSearchTestCase /** @var TestCase|ActiveRecordTestTrait $this */ /** @var Order $order */ $orderClass = $this->getOrderClass(); - $pkName = ActiveRecord::PRIMARY_KEY_NAME; + $pkName = 'id'; $order = new $orderClass(); $order->$pkName = 100; @@ -320,18 +338,8 @@ class ActiveRecordTest extends ElasticSearchTestCase public function testBooleanAttribute() { $db = $this->getConnection(); - $db->createCommand()->deleteIndex('yiitest'); - $db->post(['yiitest'], [], Json::encode([ - 'mappings' => [ - "customer" => [ - "_source" => [ "enabled" => true ], - "properties" => [ - // this is for the boolean test - "status" => ["type" => "boolean"], - ] - ] - ], - ])); + Customer::setUpMapping($db->createCommand(), true); + Customer::deleteAll(); $customerClass = $this->getCustomerClass(); $customer = new $customerClass(); diff --git a/tests/unit/framework/ar/ActiveRecordTestTrait.php b/tests/unit/framework/ar/ActiveRecordTestTrait.php index 43cb52a..e54df3f 100644 --- a/tests/unit/framework/ar/ActiveRecordTestTrait.php +++ b/tests/unit/framework/ar/ActiveRecordTestTrait.php @@ -145,7 +145,10 @@ trait ActiveRecordTestTrait // scope $this->assertEquals(2, count($this->callCustomerFind()->active()->all())); $this->assertEquals(2, $this->callCustomerFind()->active()->count()); + } + public function testFindAsArray() + { // asArray $customer = $this->callCustomerFind()->where(['id' => 2])->asArray()->one(); $this->assertEquals([ From 5dca1257b2d4a00ed5503a72cfd8d421cb343e54 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Thu, 9 Jan 2014 13:44:12 +0100 Subject: [PATCH 2/6] reverted primaryKey of elasticsearch to be array again meet the AR interface requirements. --- extensions/yii/elasticsearch/ActiveQuery.php | 6 +-- extensions/yii/elasticsearch/ActiveRecord.php | 59 ++++++++++++++-------- extensions/yii/gii/generators/crud/Generator.php | 8 +-- .../gii/generators/crud/templates/controller.php | 2 +- framework/yii/data/ActiveDataProvider.php | 2 +- framework/yii/db/BaseActiveRecord.php | 2 +- framework/yii/validators/UniqueValidator.php | 2 +- tests/unit/data/ar/elasticsearch/Customer.php | 2 +- tests/unit/data/ar/elasticsearch/Item.php | 2 +- tests/unit/data/ar/elasticsearch/Order.php | 2 +- .../extensions/elasticsearch/ActiveRecordTest.php | 2 +- 11 files changed, 54 insertions(+), 35 deletions(-) diff --git a/extensions/yii/elasticsearch/ActiveQuery.php b/extensions/yii/elasticsearch/ActiveQuery.php index 2a282d3..d67327c 100644 --- a/extensions/yii/elasticsearch/ActiveQuery.php +++ b/extensions/yii/elasticsearch/ActiveQuery.php @@ -92,7 +92,7 @@ class ActiveQuery extends Query implements ActiveQueryInterface } /** @var ActiveRecord $modelClass */ $modelClass = $this->modelClass; - $pk = $modelClass::primaryKey(); + $pk = $modelClass::primaryKey()[0]; if ($this->asArray && $this->indexBy) { foreach ($result['hits']['hits'] as &$row) { if ($pk === '_id') { @@ -136,7 +136,7 @@ class ActiveQuery extends Query implements ActiveQueryInterface /** @var ActiveRecord $modelClass */ $modelClass = $this->modelClass; $model = $result['_source']; - $pk = $modelClass::primaryKey(); + $pk = $modelClass::primaryKey()[0]; if ($pk === '_id') { $model['_id'] = $result['_id']; } @@ -165,7 +165,7 @@ class ActiveQuery extends Query implements ActiveQueryInterface if ($this->asArray) { /** @var ActiveRecord $modelClass */ $modelClass = $this->modelClass; - $pk = $modelClass::primaryKey(); + $pk = $modelClass::primaryKey()[0]; foreach($models as $key => $model) { if ($pk === '_id') { $model['_source']['_id'] = $model['_id']; diff --git a/extensions/yii/elasticsearch/ActiveRecord.php b/extensions/yii/elasticsearch/ActiveRecord.php index 29d62f3..df50039 100644 --- a/extensions/yii/elasticsearch/ActiveRecord.php +++ b/extensions/yii/elasticsearch/ActiveRecord.php @@ -171,7 +171,7 @@ class ActiveRecord extends BaseActiveRecord */ public function setPrimaryKey($value) { - $pk = static::primaryKey(); + $pk = static::primaryKey()[0]; if ($this->getIsNewRecord() || $pk != '_id') { $this->$pk = $value; } else { @@ -184,7 +184,7 @@ class ActiveRecord extends BaseActiveRecord */ public function getPrimaryKey($asArray = false) { - $pk = static::primaryKey(); + $pk = static::primaryKey()[0]; if ($asArray) { return [$pk => $this->$pk]; } else { @@ -197,7 +197,7 @@ class ActiveRecord extends BaseActiveRecord */ public function getOldPrimaryKey($asArray = false) { - $pk = static::primaryKey(); + $pk = static::primaryKey()[0]; if ($this->getIsNewRecord()) { $id = null; } elseif ($pk == '_id') { @@ -213,21 +213,37 @@ class ActiveRecord extends BaseActiveRecord } /** - * This method defines the primary. + * This method defines the attribute that uniquely identifies a record. * - * The primaryKey for elasticsearch documents is always `primaryKey`. It can not be changed. + * The primaryKey for elasticsearch documents is the `_id` field by default. This field is not part of the + * ActiveRecord attributes so you should never add `_id` to the list of [[attributes()|attributes]]. * - * @return string the primary key of this record. + * You may overide this method to define the primary key name when you have defined + * [path mapping](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-id-field.html) + * for the `_id` field so that it is part of the `_source` and thus part of the [[attributes()|attributes]]. + * + * Note that elasticsearch only supports _one_ attribute to be the primary key. However to match the signature + * of the [[\yii\db\ActiveRecordInterface|ActiveRecordInterface]] this methods returns an array instead of a + * single string. + * + * @return string[] array of primary key attributes. Only the first element of the array will be used. */ public static function primaryKey() { - return '_id'; + return ['_id']; } /** * Returns the list of all attribute names of the model. + * * This method must be overridden by child classes to define available attributes. - * @return array list of attribute names. + * + * Attributes are names of fields of the corresponding elasticsearch document. + * The primaryKey for elasticsearch documents is the `_id` field by default which is not part of the attributes. + * You may define [path mapping](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-id-field.html) + * for the `_id` field so that it is part of the `_source` fields and thus becomes part of the attributes. + * + * @return string[] list of attribute names. */ public function attributes() { @@ -260,7 +276,7 @@ class ActiveRecord extends BaseActiveRecord public static function create($row) { $record = parent::create($row['_source']); - $pk = static::primaryKey(); + $pk = static::primaryKey()[0]; $record->$pk = $row['_id']; $record->_score = isset($row['_score']) ? $row['_score'] : null; $record->_version = isset($row['_version']) ? $row['_version'] : null; // TODO version should always be available... @@ -336,8 +352,11 @@ class ActiveRecord extends BaseActiveRecord if (!isset($response['ok'])) { return false; } - $pk = static::primaryKey(); - $values[$pk] = $this->$pk = $response['_id']; + $pk = static::primaryKey()[0]; + $this->$pk = $response['_id']; + if ($pk != '_id') { + $values[$pk] = $response['_id']; + } $this->_version = $response['_version']; $this->_score = null; $this->setOldAttributes($values); @@ -362,9 +381,9 @@ class ActiveRecord extends BaseActiveRecord */ public static function updateAll($attributes, $condition = []) { - $pkName = static::primaryKey(); + $pkName = static::primaryKey()[0]; if (count($condition) == 1 && isset($condition[$pkName])) { - $primaryKeys = (array) $condition[$pkName]; + $primaryKeys = is_array($condition[$pkName]) ? $condition[$pkName] : [$condition[$pkName]]; } else { $primaryKeys = static::find()->where($condition)->column($pkName); // TODO check whether this works with default pk _id } @@ -372,7 +391,7 @@ class ActiveRecord extends BaseActiveRecord return 0; } $bulk = ''; - foreach((array) $primaryKeys as $pk) { + foreach($primaryKeys as $pk) { $action = Json::encode([ "update" => [ "_id" => $pk, @@ -420,9 +439,9 @@ class ActiveRecord extends BaseActiveRecord */ public static function updateAllCounters($counters, $condition = []) { - $pkName = static::primaryKey(); + $pkName = static::primaryKey()[0]; if (count($condition) == 1 && isset($condition[$pkName])) { - $primaryKeys = (array) $condition[$pkName]; + $primaryKeys = is_array($condition[$pkName]) ? $condition[$pkName] : [$condition[$pkName]]; } else { $primaryKeys = static::find()->where($condition)->column($pkName); // TODO check whether this works with default pk _id } @@ -430,7 +449,7 @@ class ActiveRecord extends BaseActiveRecord return 0; } $bulk = ''; - foreach((array) $primaryKeys as $pk) { + foreach($primaryKeys as $pk) { $action = Json::encode([ "update" => [ "_id" => $pk, @@ -478,9 +497,9 @@ class ActiveRecord extends BaseActiveRecord */ public static function deleteAll($condition = []) { - $pkName = static::primaryKey(); + $pkName = static::primaryKey()[0]; if (count($condition) == 1 && isset($condition[$pkName])) { - $primaryKeys = (array) $condition[$pkName]; + $primaryKeys = is_array($condition[$pkName]) ? $condition[$pkName] : [$condition[$pkName]]; } else { $primaryKeys = static::find()->where($condition)->column($pkName); // TODO check whether this works with default pk _id } @@ -488,7 +507,7 @@ class ActiveRecord extends BaseActiveRecord return 0; } $bulk = ''; - foreach((array) $primaryKeys as $pk) { + foreach($primaryKeys as $pk) { $bulk .= Json::encode([ "delete" => [ "_id" => $pk, diff --git a/extensions/yii/gii/generators/crud/Generator.php b/extensions/yii/gii/generators/crud/Generator.php index 7e0e671..bbd2ab5 100644 --- a/extensions/yii/gii/generators/crud/Generator.php +++ b/extensions/yii/gii/generators/crud/Generator.php @@ -176,7 +176,7 @@ class Generator extends \yii\gii\Generator /** @var \yii\db\ActiveRecord $class */ $class = $this->modelClass; $pk = $class::primaryKey(); - return is_array($pk) ? $pk[0] : $pk; + return $pk[0]; } /** @@ -363,7 +363,7 @@ class Generator extends \yii\gii\Generator { /** @var ActiveRecord $class */ $class = $this->modelClass; - $pks = (array) $class::primaryKey(); + $pks = $class::primaryKey(); if (count($pks) === 1) { return "'id' => \$model->{$pks[0]}"; } else { @@ -379,7 +379,7 @@ class Generator extends \yii\gii\Generator { /** @var ActiveRecord $class */ $class = $this->modelClass; - $pks = (array) $class::primaryKey(); + $pks = $class::primaryKey(); if (count($pks) === 1) { return '$id'; } else { @@ -391,7 +391,7 @@ class Generator extends \yii\gii\Generator { /** @var ActiveRecord $class */ $class = $this->modelClass; - $pks = (array) $class::primaryKey(); + $pks = $class::primaryKey(); if (($table = $this->getTableSchema()) === false) { $params = []; foreach ($pks as $pk) { diff --git a/extensions/yii/gii/generators/crud/templates/controller.php b/extensions/yii/gii/generators/crud/templates/controller.php index 7430b78..bb5d3f4 100644 --- a/extensions/yii/gii/generators/crud/templates/controller.php +++ b/extensions/yii/gii/generators/crud/templates/controller.php @@ -19,7 +19,7 @@ if ($modelClass === $searchModelClass) { /** @var ActiveRecordInterface $class */ $class = $generator->modelClass; -$pks = (array) $class::primaryKey(); +$pks = $class::primaryKey(); $urlParams = $generator->generateUrlParams(); $actionParams = $generator->generateActionParams(); $actionParamComments = $generator->generateActionParamComments(); diff --git a/framework/yii/data/ActiveDataProvider.php b/framework/yii/data/ActiveDataProvider.php index e1175a8..2292286 100644 --- a/framework/yii/data/ActiveDataProvider.php +++ b/framework/yii/data/ActiveDataProvider.php @@ -128,7 +128,7 @@ class ActiveDataProvider extends BaseDataProvider } elseif ($this->query instanceof ActiveQueryInterface) { /** @var \yii\db\ActiveRecord $class */ $class = $this->query->modelClass; - $pks = (array) $class::primaryKey(); + $pks = $class::primaryKey(); if (count($pks) === 1) { $pk = $pks[0]; foreach ($models as $model) { diff --git a/framework/yii/db/BaseActiveRecord.php b/framework/yii/db/BaseActiveRecord.php index 133c9b6..4219507 100644 --- a/framework/yii/db/BaseActiveRecord.php +++ b/framework/yii/db/BaseActiveRecord.php @@ -1273,7 +1273,7 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface */ public static function isPrimaryKey($keys) { - $pks = (array) static::primaryKey(); + $pks = static::primaryKey(); if (count($keys) === count($pks)) { return count(array_intersect($keys, $pks)) === count($pks); } else { diff --git a/framework/yii/validators/UniqueValidator.php b/framework/yii/validators/UniqueValidator.php index 55c96cf..51474b0 100644 --- a/framework/yii/validators/UniqueValidator.php +++ b/framework/yii/validators/UniqueValidator.php @@ -101,7 +101,7 @@ class UniqueValidator extends Validator $n = count($objects); if ($n === 1) { $keys = array_keys($params); - $pks = (array) $targetClass::primaryKey(); + $pks = $targetClass::primaryKey(); sort($keys); sort($pks); if ($keys === $pks) { diff --git a/tests/unit/data/ar/elasticsearch/Customer.php b/tests/unit/data/ar/elasticsearch/Customer.php index 1ff1cef..22d2c09 100644 --- a/tests/unit/data/ar/elasticsearch/Customer.php +++ b/tests/unit/data/ar/elasticsearch/Customer.php @@ -22,7 +22,7 @@ class Customer extends ActiveRecord public static function primaryKey() { - return 'id'; + return ['id']; } public function attributes() diff --git a/tests/unit/data/ar/elasticsearch/Item.php b/tests/unit/data/ar/elasticsearch/Item.php index 2474f60..033c38d 100644 --- a/tests/unit/data/ar/elasticsearch/Item.php +++ b/tests/unit/data/ar/elasticsearch/Item.php @@ -14,7 +14,7 @@ class Item extends ActiveRecord { public static function primaryKey() { - return 'id'; + return ['id']; } public function attributes() diff --git a/tests/unit/data/ar/elasticsearch/Order.php b/tests/unit/data/ar/elasticsearch/Order.php index 41d05f7..e7607cd 100644 --- a/tests/unit/data/ar/elasticsearch/Order.php +++ b/tests/unit/data/ar/elasticsearch/Order.php @@ -15,7 +15,7 @@ class Order extends ActiveRecord { public static function primaryKey() { - return 'id'; + return ['id']; } public function attributes() diff --git a/tests/unit/extensions/elasticsearch/ActiveRecordTest.php b/tests/unit/extensions/elasticsearch/ActiveRecordTest.php index 89431aa..2d31792 100644 --- a/tests/unit/extensions/elasticsearch/ActiveRecordTest.php +++ b/tests/unit/extensions/elasticsearch/ActiveRecordTest.php @@ -251,7 +251,7 @@ class ActiveRecordTest extends ElasticSearchTestCase public function testInsertNoPk() { - $this->assertEquals('id', Customer::primaryKey()); + $this->assertEquals(['id'], Customer::primaryKey()); $pkName = 'id'; $customer = new Customer; From 6d0f1e4c231d905affb972b073c81d9f3ab976c8 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Thu, 9 Jan 2014 14:24:49 +0100 Subject: [PATCH 3/6] improved error reporting --- extensions/yii/elasticsearch/ActiveRecord.php | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/extensions/yii/elasticsearch/ActiveRecord.php b/extensions/yii/elasticsearch/ActiveRecord.php index df50039..67410a6 100644 --- a/extensions/yii/elasticsearch/ActiveRecord.php +++ b/extensions/yii/elasticsearch/ActiveRecord.php @@ -44,8 +44,6 @@ use yii\helpers\StringHelper; */ class ActiveRecord extends BaseActiveRecord { - const PRIMARY_KEY_NAME = 'id'; - private $_id; private $_score; private $_version; @@ -471,13 +469,18 @@ class ActiveRecord extends BaseActiveRecord // TODO do this via command $url = [static::index(), static::type(), '_bulk']; $response = static::getDb()->post($url, [], $bulk); - $n=0; + $errors = []; foreach($response['items'] as $item) { - if ($item['update']['ok']) { + if (isset($item['update']['error'])) { + $errors[] = $item['update']; + } elseif ($item['update']['ok']) { $n++; } } + if (!empty($errors)) { + throw new Exception(__METHOD__ . ' failed updating records counters.', $errors); + } return $n; } @@ -521,11 +524,17 @@ class ActiveRecord extends BaseActiveRecord $url = [static::index(), static::type(), '_bulk']; $response = static::getDb()->post($url, [], $bulk); $n=0; + $errors = []; foreach($response['items'] as $item) { - if ($item['delete']['found'] && $item['delete']['ok']) { + if (isset($item['delete']['error'])) { + $errors[] = $item['delete']; + } elseif ($item['delete']['found'] && $item['delete']['ok']) { $n++; } } + if (!empty($errors)) { + throw new Exception(__METHOD__ . ' failed deleting records.', $errors); + } return $n; } } From 31fece562e2e1e1e0cd731e377a6faa30fcb4e1e Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Fri, 10 Jan 2014 15:39:06 +0100 Subject: [PATCH 4/6] fixed test break --- .../extensions/elasticsearch/ActiveRecordTest.php | 3 +++ tests/unit/framework/ar/ActiveRecordTestTrait.php | 31 ++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/tests/unit/extensions/elasticsearch/ActiveRecordTest.php b/tests/unit/extensions/elasticsearch/ActiveRecordTest.php index 2d31792..8d3db69 100644 --- a/tests/unit/extensions/elasticsearch/ActiveRecordTest.php +++ b/tests/unit/extensions/elasticsearch/ActiveRecordTest.php @@ -47,6 +47,7 @@ class ActiveRecordTest extends ElasticSearchTestCase if ($db->createCommand()->indexExists('yiitest')) { $db->createCommand()->deleteIndex('yiitest'); } + $db->createCommand()->createIndex('yiitest'); $command = $db->createCommand(); Customer::setUpMapping($command); @@ -54,6 +55,8 @@ class ActiveRecordTest extends ElasticSearchTestCase Order::setUpMapping($command); OrderItem::setUpMapping($command); + $db->createCommand()->flushIndex('yiitest'); + $customer = new Customer(); $customer->id = 1; $customer->setAttributes(['email' => 'user1@example.com', 'name' => 'user1', 'address' => 'address1', 'status' => 1], false); diff --git a/tests/unit/framework/ar/ActiveRecordTestTrait.php b/tests/unit/framework/ar/ActiveRecordTestTrait.php index e54df3f..338217b 100644 --- a/tests/unit/framework/ar/ActiveRecordTestTrait.php +++ b/tests/unit/framework/ar/ActiveRecordTestTrait.php @@ -487,6 +487,37 @@ trait ActiveRecordTestTrait public function testFindEagerViaRelationPreserveOrder() { /** @var TestCase|ActiveRecordTestTrait $this */ + + /* + Item (name, category_id) + Order (customer_id, create_time, total) + OrderItem (order_id, item_id, quantity, subtotal) + + Result should be the following: + + Order 1: 1, 1325282384, 110.0 + - orderItems: + OrderItem: 1, 1, 1, 30.0 + OrderItem: 1, 2, 2, 40.0 + - itemsInOrder: + Item 1: 'Agile Web Application Development with Yii1.1 and PHP5', 1 + Item 2: 'Yii 1.1 Application Development Cookbook', 1 + + Order 2: 2, 1325334482, 33.0 + - orderItems: + OrderItem: 2, 3, 1, 8.0 + OrderItem: 2, 4, 1, 10.0 + OrderItem: 2, 5, 1, 15.0 + - itemsInOrder: + Item 5: 'Cars', 2 + Item 3: 'Ice Age', 2 + Item 4: 'Toy Story', 2 + Order 3: 2, 1325502201, 40.0 + - orderItems: + OrderItem: 3, 2, 1, 40.0 + - itemsInOrder: + Item 3: 'Ice Age', 2 + */ $orders = $this->callOrderFind()->with('itemsInOrder1')->orderBy('create_time')->all(); $this->assertEquals(3, count($orders)); From 3a86270de90b51a94bc86cde0ae1ce0b1d2ace2d Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Fri, 10 Jan 2014 15:51:25 +0100 Subject: [PATCH 5/6] updated docs --- extensions/yii/elasticsearch/CHANGELOG.md | 3 ++- extensions/yii/elasticsearch/README.md | 37 ++++++++++++++++++++----------- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/extensions/yii/elasticsearch/CHANGELOG.md b/extensions/yii/elasticsearch/CHANGELOG.md index 04db504..55d52af 100644 --- a/extensions/yii/elasticsearch/CHANGELOG.md +++ b/extensions/yii/elasticsearch/CHANGELOG.md @@ -5,7 +5,8 @@ Yii Framework 2 elasticsearch extension Change Log ---------------------------- - Enh #1382: Added a debug toolbar panel for elasticsearch (cebe) -- Chg: Changed handling of ActiveRecord primary keys (cebe) +- Enh #1765: Added support for primary key path mapping, pk can now be part of the attributes when mapping is defined (cebe) +- Chg #1765: Changed handling of ActiveRecord primary keys, removed getId(), use getPrimaryKey() instead (cebe) 2.0.0 alpha, December 1, 2013 ----------------------------- diff --git a/extensions/yii/elasticsearch/README.md b/extensions/yii/elasticsearch/README.md index d299736..f2ba8d9 100644 --- a/extensions/yii/elasticsearch/README.md +++ b/extensions/yii/elasticsearch/README.md @@ -56,13 +56,11 @@ For general information on how to use yii's ActiveRecord please refer to the [gu For defining an elasticsearch ActiveRecord class your record class needs to extend from `yii\elasticsearch\ActiveRecord` and implement at least the `attributes()` method to define the attributes of the record. The handling of primary keys is different in elasticsearch as the primary key (the `_id` field in elasticsearch terms) -is not part of the attributes by default. However it is possible to define a [mapping](TODO link to ES docs) -for the `_id` field to be part of the attributes. See [...TODO...] on how to do this. +is not part of the attributes by default. However it is possible to define a [path mapping](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-id-field.html) +for the `_id` field to be part of the attributes. +See [elasticsearch docs](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-id-field.html) on how to define it. The `_id` field of a document/record can be accessed using [[ActiveRecord::getPrimaryKey()]] and [[ActiveRecord::setPrimaryKey()]]. - - primary key can be defined via [[primaryKey()]] which defaults to `id` if not specified. -The primaryKey needs to be part of the attributes so make sure you have an `id` attribute defined if you do -not specify your own primary key. +When path mapping is defined, the attribute name can be defined using the [[primaryKey()]] method. The following is an example model called `Customer`: @@ -74,6 +72,7 @@ class Customer extends \yii\elasticsearch\ActiveRecord */ public function attributes() { + // path mapping for '_id' is setup to field 'id' return ['id', 'name', 'address', 'registration_date']; } @@ -107,25 +106,23 @@ It supports the same interface and features except the following limitations and and [type](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/glossary.html#glossary-type) to query against. - `select()` has been replaced with `fields()` which basically does the same but `fields` is more elasticsearch terminology. It defines the fields to retrieve from a document. -- `via`-relations can not be defined via a table as there are not tables in elasticsearch. You can only define relations via other records. -- As elasticsearch is a data storage and search engine there is of course support added for search your records. +- `via`-relations can not be defined via a table as there are no tables in elasticsearch. You can only define relations via other records. +- As elasticsearch is not only a data storage but also a search engine there is of course support added for search your records. There are `query()`, `filter()` and `addFacets()` methods that allows to compose an elasticsearch query. See the usage example below on how they work and check out the [Query DSL](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl.html) on how to compose `query` and `filter` parts. - It is also possible to define relations from elasticsearch ActiveRecords to normal ActiveRecord classes and vice versa. -Elasticsearch separates primary key from attributes. You need to set the `id` property of the record to set its primary key. - Usage example: ```php $customer = new Customer(); -$customer->id = 1; +$customer->primaryKey = 1; // in this case equivalent to $customer->id = 1; $customer->attributes = ['name' => 'test']; $customer->save(); $customer = Customer::get(1); // get a record by pk -$customers = Customer::get([1,2,3]); // get a records multiple by pk +$customers = Customer::mget([1,2,3]); // get multiple records by pk $customer = Customer::find()->where(['name' => 'test'])->one(); // find by query $customers = Customer::find()->active()->all(); // find all by query (using the `active` scope) @@ -176,4 +173,18 @@ enabled, it is sufficient to just add the panels configuration): // ... ``` -![elasticsearch DebugPanel](README-debug.png) \ No newline at end of file +![elasticsearch DebugPanel](README-debug.png) + + +Relation definitions with records whose primary keys are not part of attributes +------------------------------------------------------------------------------- + +TODO + + +Patterns +-------- + +### Fetching records from different indexes/types + +TODO From 35b5bd8ef41040929661d381928fa3d9deb44c4a Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Fri, 10 Jan 2014 15:56:42 +0100 Subject: [PATCH 6/6] removed get() shortcut from find() --- extensions/yii/elasticsearch/ActiveRecord.php | 8 -------- 1 file changed, 8 deletions(-) diff --git a/extensions/yii/elasticsearch/ActiveRecord.php b/extensions/yii/elasticsearch/ActiveRecord.php index 67410a6..f91df2c 100644 --- a/extensions/yii/elasticsearch/ActiveRecord.php +++ b/extensions/yii/elasticsearch/ActiveRecord.php @@ -66,14 +66,6 @@ class ActiveRecord extends BaseActiveRecord { $query = static::createQuery(); if (is_array($q)) { - if (count($q) == 1 && (array_key_exists(ActiveRecord::PRIMARY_KEY_NAME, $q)) && $query->where === null) { - $pk = $q[ActiveRecord::PRIMARY_KEY_NAME]; - if (is_array($pk)) { - return static::mget($pk); - } else { - return static::get($pk); - } - } return $query->andWhere($q)->one(); } elseif ($q !== null) { return static::get($q);