diff --git a/ActiveDataProvider.php b/ActiveDataProvider.php index 281869f0e..0e864c716 100644 --- a/ActiveDataProvider.php +++ b/ActiveDataProvider.php @@ -95,7 +95,11 @@ protected function prepareModels() $query->addOrderBy($sort->getOrders()); } - if (is_array(($results = $query->search($this->db)))) { + $options = []; + if ($pagination !== false) { + $options = ['track_total_hits' => 'true']; + } + if (is_array(($results = $query->search($this->db, $options)))) { $this->setQueryResults($results); if ($pagination !== false) { $pagination->totalCount = $this->getTotalCount(); @@ -116,7 +120,15 @@ protected function prepareTotalCount() } $results = $this->getQueryResults(); - return isset($results['hits']['total']) ? (int)$results['hits']['total'] : 0; + $totalValue = 0; + if(isset($results['hits']['total'])){ + if(is_array($results['hits']['total']) && isset($results['hits']['total']['value'])) { + $totalValue = (int)$results['hits']['total']['value']; + } else { + $totalValue = (int)$results['hits']['total']; + } + } + return $totalValue; } /** diff --git a/ActiveFixture.php b/ActiveFixture.php index e72c26862..e633a82ff 100644 --- a/ActiveFixture.php +++ b/ActiveFixture.php @@ -90,7 +90,7 @@ public function load() $this->resetIndex(); $this->data = []; - $mapping = $this->db->createCommand()->getMapping($this->index, $this->type); + $mapping = $this->db->createCommand()->getMapping($this->index); if (isset($mapping[$this->index]['mappings'][$this->type]['_id']['path'])) { $idField = $mapping[$this->index]['mappings'][$this->type]['_id']['path']; } else { diff --git a/ActiveRecord.php b/ActiveRecord.php index 121714c35..06759662e 100644 --- a/ActiveRecord.php +++ b/ActiveRecord.php @@ -593,6 +593,72 @@ protected function updateInternal($attributes = null, $options = []) } } + public function replace($runValidation = true, $attributeNames = null, $options = []) + { + if ($runValidation && !$this->validate($attributeNames)) { + return false; + } + return $this->replaceInternal($attributeNames, $options); + } + + /** + * Rewrite full document on save + * @param array $attributes attributes to update + * @param array $options options given in this parameter are passed to elasticsearch + * as request URI parameters. See [[update()]] for details. + * @return integer|false the number of rows affected, or false if [[beforeSave()]] stops the updating process. + * @throws StaleObjectException if optimistic locking is enabled and the data being updated is outdated. + * @throws InvalidParamException if no [[version]] is available and optimistic locking is enabled. + * @throws Exception in case update failed. + */ + protected function replaceInternal($attributes = null, $options = []) + { + if (!$this->beforeSave(false)) { + return false; + } + $values = $this->getAttributes($attributes); + if (empty($values)) { + $this->afterSave(false, $values); + return 0; + } + if (isset($options['optimistic_locking']) && $options['optimistic_locking']) { + if ($this->_version === null) { + throw new InvalidParamException('Unable to use optimistic locking on a record that has no version set. Refer to the docs of ActiveRecord::update() for details.'); + } + $options['version'] = $this->_version; + unset($options['optimistic_locking']); + } + try { + $result = static::getDb()->createCommand()->insert( + static::index(), + static::type(), + $values, + $this->getOldPrimaryKey(false), + $options + ); + } catch(Exception $e) { + // HTTP 409 is the response in case of failed optimistic locking + // http://www.elastic.co/guide/en/elasticsearch/guide/current/optimistic-concurrency-control.html + if (isset($e->errorInfo['responseCode']) && $e->errorInfo['responseCode'] == 409) { + throw new StaleObjectException('The object being updated is outdated.', $e->errorInfo, $e->getCode(), $e); + } + throw $e; + } + + if (is_array($result) && isset($result['_version'])) { + $this->_version = $result['_version']; + } + + $changedAttributes = []; + foreach ($values as $name => $value) { + $changedAttributes[$name] = $this->getOldAttribute($name); + $this->setOldAttribute($name, $value); + } + $this->afterSave(false, $changedAttributes); + + return $result === false ? false : true; + } + /** * Performs a quick and highly efficient scroll/scan query to get the list of primary keys that * satisfy the given condition. If condition is a list of primary keys diff --git a/Command.php b/Command.php index 9e2f7ca70..7f5d3f456 100644 --- a/Command.php +++ b/Command.php @@ -568,31 +568,26 @@ public function refreshIndex($index) /** * @param string $index - * @param string $type * @param string|array $mapping * @param array $options * @return mixed * @see http://www.elastic.co/guide/en/elasticsearch/reference/current/indices-put-mapping.html */ - public function setMapping($index, $type, $mapping, $options = []) + public function setMapping($index, $mapping, $options = []) { $body = $mapping !== null ? (is_string($mapping) ? $mapping : Json::encode($mapping)) : null; - return $this->db->put([$index, '_mapping', $type], $options, $body); + return $this->db->put([$index, '_mapping'], $options, $body); } /** * @param string $index - * @param string $type * @return mixed * @see http://www.elastic.co/guide/en/elasticsearch/reference/current/indices-get-mapping.html */ - public function getMapping($index = '_all', $type = null) + public function getMapping($index = '_all') { $url = [$index, '_mapping']; - if ($type !== null) { - $url[] = $type; - } return $this->db->get($url); } @@ -662,4 +657,19 @@ public function getTemplate($name) { return $this->db->get(['_template', $name]); } + + /** + * @param $index + * @param $mapping + * @param array $options + * @return mixed + * @throws Exception + * @throws \yii\base\InvalidConfigException + */ + public function updateMapping($index, $mapping, $options = []) + { + $body = $mapping !== null ? (is_string($mapping) ? $mapping : Json::encode($mapping)) : null; + return $this->db->put([$index, '_mapping'], $options, $body); + } + } diff --git a/DebugAction.php b/DebugAction.php index 50db9499c..39fbbbc0a 100644 --- a/DebugAction.php +++ b/DebugAction.php @@ -56,7 +56,7 @@ public function run($logId, $tag) $method = mb_substr($url, 0, $pos = mb_strpos($url, ' ')); $url = mb_substr($url, $pos + 1); - $options = ['pretty' => true]; + $options = ['pretty' => 'true']; /* @var $db Connection */ $db = \Yii::$app->get($this->db); diff --git a/Query.php b/Query.php index 75f93a63e..8c968635e 100644 --- a/Query.php +++ b/Query.php @@ -226,7 +226,7 @@ public function createCommand($db = null) */ public function all($db = null) { - $result = $this->createCommand($db)->search(); + $result = $this->createCommand($db)->search(['track_total_hits' => 'true']); if ($result === false) { throw new Exception('Elasticsearch search query failed.'); } @@ -398,7 +398,7 @@ public function count($q = '*', $db = null) { // performing a query with return size of 0, is equal to getting result stats such as count // https://www.elastic.co/guide/en/elasticsearch/reference/5.6/breaking_50_search_changes.html#_literal_search_type_literal - $count = $this->createCommand($db)->search(['size' => 0])['hits']['total']; + $count = $this->createCommand($db)->search(['size' => 0, 'track_total_hits' => 'true'])['hits']['total']['value']; if ($count === false) { throw new Exception('Elasticsearch count query failed.'); } diff --git a/QueryBuilder.php b/QueryBuilder.php index c50f87fd1..34e69682c 100644 --- a/QueryBuilder.php +++ b/QueryBuilder.php @@ -127,9 +127,6 @@ public function buildOrderBy($columns) } else { $column = $name; } - if ($column == '_id') { - $column = '_uid'; - } // allow elasticsearch extended syntax as described in http://www.elastic.co/guide/en/elasticsearch/guide/master/_sorting.html if (is_array($direction)) { @@ -216,7 +213,7 @@ private function buildHashCondition($condition) foreach ($condition as $attribute => $value) { if ($attribute == '_id') { if ($value === null) { // there is no null pk - $parts[] = ['terms' => ['_uid' => []]]; // this condition is equal to WHERE false + $parts[] = ['terms' => ['_id' => []]]; // this condition is equal to WHERE false } else { $parts[] = ['ids' => ['values' => is_array($value) ? $value : [$value]]]; } @@ -317,10 +314,10 @@ private function buildInCondition($operator, $operands) $values = (array)$values; if (empty($values) || $column === []) { - return $operator === 'in' ? ['terms' => ['_uid' => []]] : []; // this condition is equal to WHERE false + return $operator === 'in' ? ['terms' => ['_id' => []]] : []; // this condition is equal to WHERE false } - if (count($column) > 1) { + if (is_array($column) && count($column) > 1) { return $this->buildCompositeInCondition($operator, $column, $values); } elseif (is_array($column)) { $column = reset($column); @@ -337,7 +334,7 @@ private function buildInCondition($operator, $operands) } if ($column === '_id') { if (empty($values) && $canBeNull) { // there is no null pk - $filter = ['terms' => ['_uid' => []]]; // this condition is equal to WHERE false + $filter = ['terms' => ['_id' => []]]; // this condition is equal to WHERE false } else { $filter = ['ids' => ['values' => array_values($values)]]; if ($canBeNull) { @@ -400,9 +397,6 @@ private function buildHalfBoundedRangeCondition($operator, $operands) } list($column, $value) = $operands; - if ($column === '_id') { - $column = '_uid'; - } $range_operator = null; diff --git a/composer.json b/composer.json index da2532c0d..449de6840 100644 --- a/composer.json +++ b/composer.json @@ -21,9 +21,18 @@ "yiisoft/yii2": "~2.0.14", "ext-curl": "*" }, + "require-dev": { + "phpunit/phpunit": "4.8.27|~5.7.21|^6.2" + }, "autoload": { "psr-4": { "micetm\\elasticsearch\\": "" } }, + "repositories": [ + { + "type": "composer", + "url": "https://asset-packagist.org" + } + ], "extra": { "branch-alias": { "dev-master": "2.0.x-dev"