Browse Source

Changed elasticsearch AR primary key handling

now supports mapped primary key when _id is part of source with an
alias.
tags/2.0.0-beta
Carsten Brandt 11 years ago
parent
commit
a7b852fcc3
  1. 34
      extensions/yii/elasticsearch/ActiveQuery.php
  2. 77
      extensions/yii/elasticsearch/ActiveRecord.php
  3. 1
      extensions/yii/elasticsearch/CHANGELOG.md
  4. 12
      extensions/yii/elasticsearch/QueryBuilder.php
  5. 13
      extensions/yii/elasticsearch/README.md
  6. 8
      extensions/yii/gii/generators/crud/Generator.php
  7. 2
      extensions/yii/gii/generators/crud/templates/controller.php
  8. 2
      framework/yii/data/ActiveDataProvider.php
  9. 4
      framework/yii/db/BaseActiveRecord.php
  10. 2
      framework/yii/validators/UniqueValidator.php
  11. 31
      tests/unit/data/ar/elasticsearch/Customer.php
  12. 27
      tests/unit/data/ar/elasticsearch/Item.php
  13. 38
      tests/unit/data/ar/elasticsearch/Order.php
  14. 25
      tests/unit/data/ar/elasticsearch/OrderItem.php
  15. 70
      tests/unit/extensions/elasticsearch/ActiveRecordTest.php
  16. 3
      tests/unit/framework/ar/ActiveRecordTestTrait.php

34
extensions/yii/elasticsearch/ActiveQuery.php

@ -90,16 +90,26 @@ class ActiveQuery extends Query implements ActiveQueryInterface
} }
unset($row); unset($row);
} }
/** @var ActiveRecord $modelClass */
$modelClass = $this->modelClass;
$pk = $modelClass::primaryKey();
if ($this->asArray && $this->indexBy) { if ($this->asArray && $this->indexBy) {
foreach ($result['hits']['hits'] as &$row) { 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']; $row = $row['_source'];
} }
unset($row);
} }
$models = $this->createModels($result['hits']['hits']); $models = $this->createModels($result['hits']['hits']);
if ($this->asArray && !$this->indexBy) { if ($this->asArray && !$this->indexBy) {
foreach($models as $key => $model) { 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']; $models[$key] = $model['_source'];
} }
} }
@ -123,8 +133,14 @@ class ActiveQuery extends Query implements ActiveQueryInterface
return null; return null;
} }
if ($this->asArray) { if ($this->asArray) {
/** @var ActiveRecord $modelClass */
$modelClass = $this->modelClass;
$model = $result['_source']; $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 { } else {
/** @var ActiveRecord $class */ /** @var ActiveRecord $class */
$class = $this->modelClass; $class = $this->modelClass;
@ -147,8 +163,14 @@ class ActiveQuery extends Query implements ActiveQueryInterface
if (!empty($result['hits']['hits'])) { if (!empty($result['hits']['hits'])) {
$models = $this->createModels($result['hits']['hits']); $models = $this->createModels($result['hits']['hits']);
if ($this->asArray) { if ($this->asArray) {
/** @var ActiveRecord $modelClass */
$modelClass = $this->modelClass;
$pk = $modelClass::primaryKey();
foreach($models as $key => $model) { 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']; $models[$key] = $model['_source'];
} }
} }
@ -167,7 +189,7 @@ class ActiveQuery extends Query implements ActiveQueryInterface
{ {
$record = parent::one($db); $record = parent::one($db);
if ($record !== false) { if ($record !== false) {
if ($field == ActiveRecord::PRIMARY_KEY_NAME) { if ($field == '_id') {
return $record['_id']; return $record['_id'];
} elseif (isset($record['_source'][$field])) { } elseif (isset($record['_source'][$field])) {
return $record['_source'][$field]; return $record['_source'][$field];
@ -181,7 +203,7 @@ class ActiveQuery extends Query implements ActiveQueryInterface
*/ */
public function column($field, $db = null) public function column($field, $db = null)
{ {
if ($field == ActiveRecord::PRIMARY_KEY_NAME) { if ($field == '_id') {
$command = $this->createCommand($db); $command = $this->createCommand($db);
$command->queryParts['fields'] = []; $command->queryParts['fields'] = [];
$result = $command->search(); $result = $command->search();

77
extensions/yii/elasticsearch/ActiveRecord.php

@ -47,6 +47,7 @@ class ActiveRecord extends BaseActiveRecord
const PRIMARY_KEY_NAME = 'id'; const PRIMARY_KEY_NAME = 'id';
private $_id; private $_id;
private $_score;
private $_version; private $_version;
/** /**
@ -155,9 +156,12 @@ class ActiveRecord extends BaseActiveRecord
// TODO implement copy and move as pk change is not possible // 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 * @param mixed $value
* @throws \yii\base\InvalidCallException when record is not new * @throws \yii\base\InvalidCallException when record is not new
*/ */
public function setId($value) public function setPrimaryKey($value)
{ {
if ($this->isNewRecord) { $pk = static::primaryKey();
$this->_id = $value; if ($this->getIsNewRecord() || $pk != '_id') {
$this->$pk = $value;
} else { } else {
throw new InvalidCallException('Changing the primaryKey of an already saved record is not allowed.'); 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) public function getPrimaryKey($asArray = false)
{ {
$pk = static::primaryKey();
if ($asArray) { if ($asArray) {
return [ActiveRecord::PRIMARY_KEY_NAME => $this->_id]; return [$pk => $this->$pk];
} else { } else {
return $this->_id; return $this->$pk;
} }
} }
@ -191,11 +197,18 @@ class ActiveRecord extends BaseActiveRecord
*/ */
public function getOldPrimaryKey($asArray = false) 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) { if ($asArray) {
return [ActiveRecord::PRIMARY_KEY_NAME => $id]; return [$pk => $id];
} else { } 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. * 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() public static function primaryKey()
{ {
return [ActiveRecord::PRIMARY_KEY_NAME]; return '_id';
} }
/** /**
@ -246,8 +259,11 @@ class ActiveRecord extends BaseActiveRecord
*/ */
public static function create($row) public static function create($row)
{ {
$row['_source'][ActiveRecord::PRIMARY_KEY_NAME] = $row['_id'];
$record = parent::create($row['_source']); $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; return $record;
} }
@ -317,11 +333,13 @@ class ActiveRecord extends BaseActiveRecord
$options $options
); );
if (!$response['ok']) { if (!isset($response['ok'])) {
return false; return false;
} }
$this->_id = $response['_id']; $pk = static::primaryKey();
$values[$pk] = $this->$pk = $response['_id'];
$this->_version = $response['_version']; $this->_version = $response['_version'];
$this->_score = null;
$this->setOldAttributes($values); $this->setOldAttributes($values);
$this->afterSave(true); $this->afterSave(true);
return true; return true;
@ -344,10 +362,11 @@ class ActiveRecord extends BaseActiveRecord
*/ */
public static function updateAll($attributes, $condition = []) public static function updateAll($attributes, $condition = [])
{ {
if (count($condition) == 1 && isset($condition[ActiveRecord::PRIMARY_KEY_NAME])) { $pkName = static::primaryKey();
$primaryKeys = (array) $condition[ActiveRecord::PRIMARY_KEY_NAME]; if (count($condition) == 1 && isset($condition[$pkName])) {
$primaryKeys = (array) $condition[$pkName];
} else { } 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)) { if (empty($primaryKeys)) {
return 0; return 0;
@ -371,11 +390,17 @@ class ActiveRecord extends BaseActiveRecord
$url = [static::index(), static::type(), '_bulk']; $url = [static::index(), static::type(), '_bulk'];
$response = static::getDb()->post($url, [], $bulk); $response = static::getDb()->post($url, [], $bulk);
$n=0; $n=0;
$errors = [];
foreach($response['items'] as $item) { foreach($response['items'] as $item) {
if ($item['update']['ok']) { if (isset($item['update']['error'])) {
$errors[] = $item['update'];
} elseif ($item['update']['ok']) {
$n++; $n++;
} }
} }
if (!empty($errors)) {
throw new Exception(__METHOD__ . ' failed updating records.', $errors);
}
return $n; return $n;
} }
@ -395,10 +420,11 @@ class ActiveRecord extends BaseActiveRecord
*/ */
public static function updateAllCounters($counters, $condition = []) public static function updateAllCounters($counters, $condition = [])
{ {
if (count($condition) == 1 && isset($condition[ActiveRecord::PRIMARY_KEY_NAME])) { $pkName = static::primaryKey();
$primaryKeys = (array) $condition[ActiveRecord::PRIMARY_KEY_NAME]; if (count($condition) == 1 && isset($condition[$pkName])) {
$primaryKeys = (array) $condition[$pkName];
} else { } 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)) { if (empty($primaryKeys) || empty($counters)) {
return 0; return 0;
@ -452,10 +478,11 @@ class ActiveRecord extends BaseActiveRecord
*/ */
public static function deleteAll($condition = []) public static function deleteAll($condition = [])
{ {
if (count($condition) == 1 && isset($condition[ActiveRecord::PRIMARY_KEY_NAME])) { $pkName = static::primaryKey();
$primaryKeys = (array) $condition[ActiveRecord::PRIMARY_KEY_NAME]; if (count($condition) == 1 && isset($condition[$pkName])) {
$primaryKeys = (array) $condition[$pkName];
} else { } 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)) { if (empty($primaryKeys)) {
return 0; return 0;

1
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) - 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 2.0.0 alpha, December 1, 2013
----------------------------- -----------------------------

12
extensions/yii/elasticsearch/QueryBuilder.php

@ -114,7 +114,7 @@ class QueryBuilder extends \yii\base\Object
} else { } else {
$column = $name; $column = $name;
} }
if ($column == ActiveRecord::PRIMARY_KEY_NAME) { if ($column == '_id') {
$column = '_uid'; $column = '_uid';
} }
@ -176,7 +176,7 @@ class QueryBuilder extends \yii\base\Object
{ {
$parts = []; $parts = [];
foreach($condition as $attribute => $value) { foreach($condition as $attribute => $value) {
if ($attribute == ActiveRecord::PRIMARY_KEY_NAME) { if ($attribute == '_id') {
if ($value == null) { // there is no null pk if ($value == null) { // there is no null pk
$parts[] = ['script' => ['script' => '0==1']]; $parts[] = ['script' => ['script' => '0==1']];
} else { } else {
@ -235,8 +235,8 @@ class QueryBuilder extends \yii\base\Object
} }
list($column, $value1, $value2) = $operands; list($column, $value1, $value2) = $operands;
if ($column == ActiveRecord::PRIMARY_KEY_NAME) { if ($column == '_id') {
throw new NotSupportedException('Between condition is not supported for primaryKey.'); throw new NotSupportedException('Between condition is not supported for the _id field.');
} }
$filter = ['range' => [$column => ['gte' => $value1, 'lte' => $value2]]]; $filter = ['range' => [$column => ['gte' => $value1, 'lte' => $value2]]];
if ($operator == 'not between') { if ($operator == 'not between') {
@ -274,7 +274,7 @@ class QueryBuilder extends \yii\base\Object
unset($values[$i]); unset($values[$i]);
} }
} }
if ($column == ActiveRecord::PRIMARY_KEY_NAME) { if ($column == '_id') {
if (empty($values) && $canBeNull) { // there is no null pk if (empty($values) && $canBeNull) { // there is no null pk
$filter = ['script' => ['script' => '0==1']]; $filter = ['script' => ['script' => '0==1']];
} else { } else {
@ -306,6 +306,6 @@ class QueryBuilder extends \yii\base\Object
private function buildLikeCondition($operator, $operands) 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.');
} }
} }

13
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 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. 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 handling of primary keys is different in elasticsearch as the primary key (the `_id` field in elasticsearch terms)
The primary key is not part of the attributes. 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. 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 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 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 and shows the executed elasticsearch queries. It also allows to run these queries
an view the results. 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 ```php
// ... // ...

8
extensions/yii/gii/generators/crud/Generator.php

@ -176,7 +176,7 @@ class Generator extends \yii\gii\Generator
/** @var \yii\db\ActiveRecord $class */ /** @var \yii\db\ActiveRecord $class */
$class = $this->modelClass; $class = $this->modelClass;
$pk = $class::primaryKey(); $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 */ /** @var ActiveRecord $class */
$class = $this->modelClass; $class = $this->modelClass;
$pks = $class::primaryKey(); $pks = (array) $class::primaryKey();
if (count($pks) === 1) { if (count($pks) === 1) {
return "'id' => \$model->{$pks[0]}"; return "'id' => \$model->{$pks[0]}";
} else { } else {
@ -379,7 +379,7 @@ class Generator extends \yii\gii\Generator
{ {
/** @var ActiveRecord $class */ /** @var ActiveRecord $class */
$class = $this->modelClass; $class = $this->modelClass;
$pks = $class::primaryKey(); $pks = (array) $class::primaryKey();
if (count($pks) === 1) { if (count($pks) === 1) {
return '$id'; return '$id';
} else { } else {
@ -391,7 +391,7 @@ class Generator extends \yii\gii\Generator
{ {
/** @var ActiveRecord $class */ /** @var ActiveRecord $class */
$class = $this->modelClass; $class = $this->modelClass;
$pks = $class::primaryKey(); $pks = (array) $class::primaryKey();
if (($table = $this->getTableSchema()) === false) { if (($table = $this->getTableSchema()) === false) {
$params = []; $params = [];
foreach ($pks as $pk) { foreach ($pks as $pk) {

2
extensions/yii/gii/generators/crud/templates/controller.php

@ -19,7 +19,7 @@ if ($modelClass === $searchModelClass) {
/** @var ActiveRecordInterface $class */ /** @var ActiveRecordInterface $class */
$class = $generator->modelClass; $class = $generator->modelClass;
$pks = $class::primaryKey(); $pks = (array) $class::primaryKey();
$urlParams = $generator->generateUrlParams(); $urlParams = $generator->generateUrlParams();
$actionParams = $generator->generateActionParams(); $actionParams = $generator->generateActionParams();
$actionParamComments = $generator->generateActionParamComments(); $actionParamComments = $generator->generateActionParamComments();

2
framework/yii/data/ActiveDataProvider.php

@ -128,7 +128,7 @@ class ActiveDataProvider extends BaseDataProvider
} elseif ($this->query instanceof ActiveQueryInterface) { } elseif ($this->query instanceof ActiveQueryInterface) {
/** @var \yii\db\ActiveRecord $class */ /** @var \yii\db\ActiveRecord $class */
$class = $this->query->modelClass; $class = $this->query->modelClass;
$pks = $class::primaryKey(); $pks = (array) $class::primaryKey();
if (count($pks) === 1) { if (count($pks) === 1) {
$pk = $pks[0]; $pk = $pks[0];
foreach ($models as $model) { foreach ($models as $model) {

4
framework/yii/db/BaseActiveRecord.php

@ -924,7 +924,7 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface
*/ */
public function equals($record) public function equals($record)
{ {
if ($this->isNewRecord || $record->isNewRecord) { if ($this->getIsNewRecord() || $record->getIsNewRecord()) {
return false; return false;
} }
return get_class($this) === get_class($record) && $this->getPrimaryKey() === $record->getPrimaryKey(); 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) public static function isPrimaryKey($keys)
{ {
$pks = static::primaryKey(); $pks = (array) static::primaryKey();
if (count($keys) === count($pks)) { if (count($keys) === count($pks)) {
return count(array_intersect($keys, $pks)) === count($pks); return count(array_intersect($keys, $pks)) === count($pks);
} else { } else {

2
framework/yii/validators/UniqueValidator.php

@ -101,7 +101,7 @@ class UniqueValidator extends Validator
$n = count($objects); $n = count($objects);
if ($n === 1) { if ($n === 1) {
$keys = array_keys($params); $keys = array_keys($params);
$pks = $targetClass::primaryKey(); $pks = (array) $targetClass::primaryKey();
sort($keys); sort($keys);
sort($pks); sort($pks);
if ($keys === $pks) { if ($keys === $pks) {

31
tests/unit/data/ar/elasticsearch/Customer.php

@ -1,6 +1,7 @@
<?php <?php
namespace yiiunit\data\ar\elasticsearch; namespace yiiunit\data\ar\elasticsearch;
use yii\elasticsearch\Command;
use yiiunit\extensions\elasticsearch\ActiveRecordTest; use yiiunit\extensions\elasticsearch\ActiveRecordTest;
/** /**
@ -19,14 +20,19 @@ class Customer extends ActiveRecord
public $status2; public $status2;
public static function primaryKey()
{
return 'id';
}
public function attributes() public function attributes()
{ {
return ['name', 'email', 'address', 'status']; return ['id', 'name', 'email', 'address', 'status'];
} }
public function getOrders() public function getOrders()
{ {
return $this->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) public static function active($query)
@ -40,4 +46,25 @@ class Customer extends ActiveRecord
ActiveRecordTest::$afterSaveNewRecord = $this->isNewRecord; ActiveRecordTest::$afterSaveNewRecord = $this->isNewRecord;
parent::afterSave($insert); 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"],
]
]
]);
}
} }

27
tests/unit/data/ar/elasticsearch/Item.php

@ -1,6 +1,7 @@
<?php <?php
namespace yiiunit\data\ar\elasticsearch; namespace yiiunit\data\ar\elasticsearch;
use yii\elasticsearch\Command;
/** /**
* Class Item * Class Item
@ -11,8 +12,32 @@ namespace yiiunit\data\ar\elasticsearch;
*/ */
class Item extends ActiveRecord class Item extends ActiveRecord
{ {
public static function primaryKey()
{
return 'id';
}
public function attributes() public function attributes()
{ {
return ['name', 'category_id']; return ['id', 'name', 'category_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() => [
"_id" => ["path" => "id", "index" => "not_analyzed", "store" => "yes"],
"properties" => [
"name" => ["type" => "string", "index" => "not_analyzed"],
"category_id" => ["type" => "integer"],
]
]
]);
} }
} }

38
tests/unit/data/ar/elasticsearch/Order.php

@ -1,6 +1,7 @@
<?php <?php
namespace yiiunit\data\ar\elasticsearch; namespace yiiunit\data\ar\elasticsearch;
use yii\elasticsearch\Command;
/** /**
* Class Order * Class Order
@ -12,24 +13,29 @@ namespace yiiunit\data\ar\elasticsearch;
*/ */
class Order extends ActiveRecord class Order extends ActiveRecord
{ {
public static function primaryKey()
{
return 'id';
}
public function attributes() public function attributes()
{ {
return ['customer_id', 'create_time', 'total']; return ['id', 'customer_id', 'create_time', 'total'];
} }
public function getCustomer() public function getCustomer()
{ {
return $this->hasOne(Customer::className(), [ActiveRecord::PRIMARY_KEY_NAME => 'customer_id']); return $this->hasOne(Customer::className(), ['id' => 'customer_id']);
} }
public function getOrderItems() 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() 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'); ->via('orderItems')->orderBy('id');
} }
@ -51,8 +57,8 @@ class Order extends ActiveRecord
// public function getBooks() // public function getBooks()
// { // {
// return $this->hasMany('Item', [ActiveRecord::PRIMARY_KEY_NAME => 'item_id']) // return $this->hasMany('Item', ['id' => 'item_id'])
// ->viaTable('tbl_order_item', ['order_id' => ActiveRecord::PRIMARY_KEY_NAME]) // ->viaTable('tbl_order_item', ['order_id' => 'id'])
// ->where(['category_id' => 1]); // ->where(['category_id' => 1]);
// } // }
@ -65,4 +71,24 @@ class Order extends ActiveRecord
return false; 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"],
]
]
]);
}
} }

25
tests/unit/data/ar/elasticsearch/OrderItem.php

@ -1,6 +1,7 @@
<?php <?php
namespace yiiunit\data\ar\elasticsearch; namespace yiiunit\data\ar\elasticsearch;
use yii\elasticsearch\Command;
/** /**
* Class OrderItem * Class OrderItem
@ -19,11 +20,31 @@ class OrderItem extends ActiveRecord
public function getOrder() public function getOrder()
{ {
return $this->hasOne(Order::className(), [ActiveRecord::PRIMARY_KEY_NAME => 'order_id']); return $this->hasOne(Order::className(), ['id' => 'order_id']);
} }
public function getItem() 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"],
]
]
]);
} }
} }

70
tests/unit/extensions/elasticsearch/ActiveRecordTest.php

@ -48,17 +48,11 @@ class ActiveRecordTest extends ElasticSearchTestCase
$db->createCommand()->deleteIndex('yiitest'); $db->createCommand()->deleteIndex('yiitest');
} }
$db->post(['yiitest'], [], Json::encode([ $command = $db->createCommand();
'mappings' => [ Customer::setUpMapping($command);
"item" => [ Item::setUpMapping($command);
"_source" => [ "enabled" => true ], Order::setUpMapping($command);
"properties" => [ OrderItem::setUpMapping($command);
// allow proper sorting by name
"name" => ["type" => "string", "index" => "not_analyzed"],
]
]
],
]));
$customer = new Customer(); $customer = new Customer();
$customer->id = 1; $customer->id = 1;
@ -132,6 +126,20 @@ class ActiveRecordTest extends ElasticSearchTestCase
$db->createCommand()->flushIndex('yiitest'); $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() public function testSearch()
{ {
$customers = $this->callCustomerFind()->search()['hits']; $customers = $this->callCustomerFind()->search()['hits'];
@ -243,8 +251,8 @@ class ActiveRecordTest extends ElasticSearchTestCase
public function testInsertNoPk() public function testInsertNoPk()
{ {
$this->assertEquals([ActiveRecord::PRIMARY_KEY_NAME], Customer::primaryKey()); $this->assertEquals('id', Customer::primaryKey());
$pkName = ActiveRecord::PRIMARY_KEY_NAME; $pkName = 'id';
$customer = new Customer; $customer = new Customer;
$customer->email = 'user4@example.com'; $customer->email = 'user4@example.com';
@ -257,6 +265,7 @@ class ActiveRecordTest extends ElasticSearchTestCase
$this->assertTrue($customer->isNewRecord); $this->assertTrue($customer->isNewRecord);
$customer->save(); $customer->save();
$this->afterSave();
$this->assertNotNull($customer->primaryKey); $this->assertNotNull($customer->primaryKey);
$this->assertNotNull($customer->oldPrimaryKey); $this->assertNotNull($customer->oldPrimaryKey);
@ -268,7 +277,7 @@ class ActiveRecordTest extends ElasticSearchTestCase
public function testInsertPk() public function testInsertPk()
{ {
$pkName = ActiveRecord::PRIMARY_KEY_NAME; $pkName = 'id';
$customer = new Customer; $customer = new Customer;
$customer->$pkName = 5; $customer->$pkName = 5;
@ -288,17 +297,26 @@ class ActiveRecordTest extends ElasticSearchTestCase
public function testUpdatePk() public function testUpdatePk()
{ {
$pkName = ActiveRecord::PRIMARY_KEY_NAME; $pkName = 'id';
$pk = [$pkName => 2]; $orderItem = Order::find([$pkName => 2]);
$orderItem = Order::find($pk);
$this->assertEquals(2, $orderItem->primaryKey); $this->assertEquals(2, $orderItem->primaryKey);
$this->assertEquals(2, $orderItem->oldPrimaryKey); $this->assertEquals(2, $orderItem->oldPrimaryKey);
$this->assertEquals(2, $orderItem->$pkName); $this->assertEquals(2, $orderItem->$pkName);
$this->setExpectedException('yii\base\InvalidCallException'); // $this->setExpectedException('yii\base\InvalidCallException');
$orderItem->$pkName = 13; $orderItem->$pkName = 13;
$this->assertEquals(13, $orderItem->primaryKey);
$this->assertEquals(2, $orderItem->oldPrimaryKey);
$this->assertEquals(13, $orderItem->$pkName);
$orderItem->save(); $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() public function testFindLazyVia2()
@ -306,7 +324,7 @@ class ActiveRecordTest extends ElasticSearchTestCase
/** @var TestCase|ActiveRecordTestTrait $this */ /** @var TestCase|ActiveRecordTestTrait $this */
/** @var Order $order */ /** @var Order $order */
$orderClass = $this->getOrderClass(); $orderClass = $this->getOrderClass();
$pkName = ActiveRecord::PRIMARY_KEY_NAME; $pkName = 'id';
$order = new $orderClass(); $order = new $orderClass();
$order->$pkName = 100; $order->$pkName = 100;
@ -320,18 +338,8 @@ class ActiveRecordTest extends ElasticSearchTestCase
public function testBooleanAttribute() public function testBooleanAttribute()
{ {
$db = $this->getConnection(); $db = $this->getConnection();
$db->createCommand()->deleteIndex('yiitest'); Customer::setUpMapping($db->createCommand(), true);
$db->post(['yiitest'], [], Json::encode([ Customer::deleteAll();
'mappings' => [
"customer" => [
"_source" => [ "enabled" => true ],
"properties" => [
// this is for the boolean test
"status" => ["type" => "boolean"],
]
]
],
]));
$customerClass = $this->getCustomerClass(); $customerClass = $this->getCustomerClass();
$customer = new $customerClass(); $customer = new $customerClass();

3
tests/unit/framework/ar/ActiveRecordTestTrait.php

@ -145,7 +145,10 @@ trait ActiveRecordTestTrait
// scope // scope
$this->assertEquals(2, count($this->callCustomerFind()->active()->all())); $this->assertEquals(2, count($this->callCustomerFind()->active()->all()));
$this->assertEquals(2, $this->callCustomerFind()->active()->count()); $this->assertEquals(2, $this->callCustomerFind()->active()->count());
}
public function testFindAsArray()
{
// asArray // asArray
$customer = $this->callCustomerFind()->where(['id' => 2])->asArray()->one(); $customer = $this->callCustomerFind()->where(['id' => 2])->asArray()->one();
$this->assertEquals([ $this->assertEquals([

Loading…
Cancel
Save