diff --git a/.gitignore b/.gitignore index 6482763..5586ab2 100644 --- a/.gitignore +++ b/.gitignore @@ -13,13 +13,15 @@ nbproject Thumbs.db # composer vendor dir -/yii/vendor +/vendor # composer itself is not needed composer.phar +# composer.lock should not be committed as we always want the latest versions +/composer.lock # Mac DS_Store Files .DS_Store # local phpunit config -/phpunit.xml \ No newline at end of file +/phpunit.xml diff --git a/.travis.yml b/.travis.yml index 8c9b258..346bd81 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,7 @@ php: services: - redis-server - memcached + - elasticsearch before_script: - composer self-update && composer --version diff --git a/extensions/elasticsearch/ActiveQuery.php b/extensions/elasticsearch/ActiveQuery.php index 2a99643..79c83c8 100644 --- a/extensions/elasticsearch/ActiveQuery.php +++ b/extensions/elasticsearch/ActiveQuery.php @@ -84,7 +84,7 @@ class ActiveQuery extends Query implements ActiveQueryInterface public function all($db = null) { $command = $this->createCommand($db); - $result = $command->queryAll(); + $result = $command->search(); if (empty($result['hits'])) { return []; } @@ -154,7 +154,7 @@ class ActiveQuery extends Query implements ActiveQueryInterface if ($field == ActiveRecord::PRIMARY_KEY_NAME) { $command = $this->createCommand($db); $command->queryParts['fields'] = []; - $rows = $command->queryAll()['hits']; + $rows = $command->search()['hits']; $result = []; foreach ($rows as $row) { $result[] = $row['_id']; diff --git a/extensions/elasticsearch/ActiveRecord.php b/extensions/elasticsearch/ActiveRecord.php index 33b01dd..f113cf3 100644 --- a/extensions/elasticsearch/ActiveRecord.php +++ b/extensions/elasticsearch/ActiveRecord.php @@ -370,11 +370,10 @@ class ActiveRecord extends \yii\db\ActiveRecord } // TODO do this via command - $url = '/' . static::index() . '/' . static::type() . '/_bulk'; - $response = static::getDb()->http()->post($url, null, $bulk)->send(); - $body = Json::decode($response->getBody(true)); + $url = [static::index(), static::type(), '_bulk']; + $response = static::getDb()->post($url, [], $bulk); $n=0; - foreach($body['items'] as $item) { + foreach($response['items'] as $item) { if ($item['update']['ok']) { $n++; } @@ -421,11 +420,10 @@ class ActiveRecord extends \yii\db\ActiveRecord } // TODO do this via command - $url = '/' . static::index() . '/' . static::type() . '/_bulk'; - $response = static::getDb()->http()->post($url, null, $bulk)->send(); - $body = Json::decode($response->getBody(true)); + $url = [static::index(), static::type(), '_bulk']; + $response = static::getDb()->post($url, [], $bulk); $n=0; - foreach($body['items'] as $item) { + foreach($response['items'] as $item) { if ($item['delete']['found'] && $item['delete']['ok']) { $n++; } diff --git a/extensions/elasticsearch/Command.php b/extensions/elasticsearch/Command.php index 35334f4..7d5aa8e 100644 --- a/extensions/elasticsearch/Command.php +++ b/extensions/elasticsearch/Command.php @@ -43,7 +43,11 @@ class Command extends Component public $options = []; - public function queryAll($options = []) + /** + * @param array $options + * @return mixed + */ + public function search($options = []) { $query = $this->queryParts; if (empty($query)) { @@ -57,23 +61,9 @@ class Command extends Component $this->type !== null ? $this->type : '_all', '_search' ]; - try { - $response = $this->db->http()->post($this->createUrl($url, $options), null, $query)->send(); - } catch(ClientErrorResponseException $e) { - throw new Exception("elasticsearch error:\n\n" - . $query . "\n\n" . $e->getMessage() - . print_r(Json::decode($e->getResponse()->getBody(true)), true), [], 0, $e); - } - return Json::decode($response->getBody(true))['hits']; - } - - public function queryCount($options = []) - { - $options['search_type'] = 'count'; - return $this->queryAll($options); + return $this->db->get($url, array_merge($this->options, $options), $query)['hits']; } - /** * Inserts a document into an index * @param string $index @@ -88,18 +78,11 @@ class Command extends Component { $body = is_array($data) ? Json::encode($data) : $data; - try { - if ($id !== null) { - $response = $this->db->http()->put($this->createUrl([$index, $type, $id], $options), null, $body)->send(); - } else { - $response = $this->db->http()->post($this->createUrl([$index, $type], $options), null, $body)->send(); - } - } catch(ClientErrorResponseException $e) { - throw new Exception("elasticsearch error:\n\n" - . $body . "\n\n" . $e->getMessage() - . print_r(Json::decode($e->getResponse()->getBody(true)), true), [], 0, $e); + if ($id !== null) { + return $this->db->put([$index, $type, $id], $options, $body); + } else { + return $this->db->post([$index, $type], $options, $body); } - return Json::decode($response->getBody(true)); } /** @@ -113,15 +96,7 @@ class Command extends Component */ public function get($index, $type, $id, $options = []) { - $httpOptions = [ - 'exceptions' => false, - ]; - $response = $this->db->http()->get($this->createUrl([$index, $type, $id], $options), null, $httpOptions)->send(); - if ($response->getStatusCode() == 200 || $response->getStatusCode() == 404) { - return Json::decode($response->getBody(true)); - } else { - throw new Exception('Elasticsearch request failed.'); - } + return $this->db->get([$index, $type, $id], $options, null, [200, 404]); } /** @@ -133,25 +108,12 @@ class Command extends Component * @param $id * @param array $options * @return mixed - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-get.html + * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-multi-get.html */ public function mget($index, $type, $ids, $options = []) { - $httpOptions = [ - 'exceptions' => false, - ]; $body = Json::encode(['ids' => array_values($ids)]); - $response = $this->db->http()->post( // TODO guzzle does not manage to send get request with content - $this->createUrl([$index, $type, '_mget'], $options), - null, - $body, - $httpOptions - )->send(); - if ($response->getStatusCode() == 200) { - return Json::decode($response->getBody(true)); - } else { - throw new Exception('Elasticsearch request failed.'); - } + return $this->db->get([$index, $type, '_mget'], $options, $body); } /** @@ -164,12 +126,9 @@ class Command extends Component */ public function getSource($index, $type, $id) { - $response = $this->db->http()->head($this->createUrl([$index, $type, $id]))->send(); - return Json::decode($response->getBody(true)); + return $this->db->get([$index, $type, $id]); } - // TODO mget http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-multi-get.html - /** * gets a document from the index * @param $index @@ -180,8 +139,7 @@ class Command extends Component */ public function exists($index, $type, $id) { - $response = $this->db->http()->head($this->createUrl([$index, $type, $id]))->send(); - return $response->getStatusCode() == 200; + return $this->db->head([$index, $type, $id]); } /** @@ -195,8 +153,7 @@ class Command extends Component */ public function delete($index, $type, $id, $options = []) { - $response = $this->db->http()->delete($this->createUrl([$index, $type, $id], $options))->send(); - return Json::decode($response->getBody(true)); + return $this->db->delete([$index, $type, $id], $options); } /** @@ -211,21 +168,18 @@ class Command extends Component public function update($index, $type, $id, $data, $options = []) { // TODO - $response = $this->db->http()->delete($this->createUrl([$index, $type, $id], $options))->send(); - return Json::decode($response->getBody(true)); +// return $this->db->delete([$index, $type, $id], $options); } // TODO bulk http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-bulk.html - /** * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-create-index.html */ public function createIndex($index, $configuration = null) { $body = $configuration !== null ? Json::encode($configuration) : null; - $response = $this->db->http()->put($this->createUrl([$index]), null, $body)->send(); - return Json::decode($response->getBody(true)); + return $this->db->put([$index], $body); } /** @@ -233,8 +187,7 @@ class Command extends Component */ public function deleteIndex($index) { - $response = $this->db->http()->delete($this->createUrl([$index]))->send(); - return Json::decode($response->getBody(true)); + return $this->db->delete([$index]); } /** @@ -242,8 +195,7 @@ class Command extends Component */ public function deleteAllIndexes() { - $response = $this->db->http()->delete($this->createUrl(['_all']))->send(); - return Json::decode($response->getBody(true)); + return $this->db->delete(['_all']); } /** @@ -251,8 +203,7 @@ class Command extends Component */ public function indexExists($index) { - $response = $this->db->http()->head($this->createUrl([$index]))->send(); - return $response->getStatusCode() == 200; + return $this->db->head([$index]); } /** @@ -260,8 +211,7 @@ class Command extends Component */ public function typeExists($index, $type) { - $response = $this->db->http()->head($this->createUrl([$index, $type]))->send(); - return $response->getStatusCode() == 200; + return $this->db->head([$index, $type]); } // TODO http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-aliases.html @@ -276,8 +226,7 @@ class Command extends Component */ public function openIndex($index) { - $response = $this->db->http()->post($this->createUrl([$index, '_open']))->send(); - return $response->getStatusCode() == 200; + return $this->db->post([$index, '_open']); } /** @@ -285,8 +234,7 @@ class Command extends Component */ public function closeIndex($index) { - $response = $this->db->http()->post($this->createUrl([$index, '_close']))->send(); - return $response->getStatusCode() == 200; + return $this->db->post([$index, '_close']); } /** @@ -294,8 +242,7 @@ class Command extends Component */ public function getIndexStatus($index = '_all') { - $response = $this->db->http()->get($this->createUrl([$index, '_status']))->send(); - return Json::decode($response->getBody(true)); + return $this->db->get([$index, '_status']); } // TODO http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-stats.html @@ -306,8 +253,7 @@ class Command extends Component */ public function clearIndexCache($index) { - $response = $this->db->http()->post($this->createUrl([$index, '_cache', 'clear']))->send(); - return $response->getStatusCode() == 200; + return $this->db->post([$index, '_cache', 'clear']); } /** @@ -315,8 +261,7 @@ class Command extends Component */ public function flushIndex($index = '_all') { - $response = $this->db->http()->post($this->createUrl([$index, '_flush']))->send(); - return $response->getStatusCode() == 200; + return $this->db->post([$index, '_flush']); } /** @@ -324,8 +269,7 @@ class Command extends Component */ public function refreshIndex($index) { - $response = $this->db->http()->post($this->createUrl([$index, '_refresh']))->send(); - return $response->getStatusCode() == 200; + return $this->db->post([$index, '_refresh']); } // TODO http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-optimize.html @@ -338,8 +282,7 @@ class Command extends Component public function setMapping($index, $type, $mapping) { $body = $mapping !== null ? Json::encode($mapping) : null; - $response = $this->db->http()->put($this->createUrl([$index, $type, '_mapping']), null, $body)->send(); - return $response->getStatusCode() == 200; + return $this->db->put([$index, $type, '_mapping'], $body); } /** @@ -347,8 +290,7 @@ class Command extends Component */ public function getMapping($index = '_all', $type = '_all') { - $response = $this->db->http()->get($this->createUrl([$index, $type, '_mapping']))->send(); - return Json::decode($response->getBody(true)); + return $this->db->get([$index, $type, '_mapping']); } /** @@ -356,8 +298,7 @@ class Command extends Component */ public function deleteMapping($index, $type) { - $response = $this->db->http()->delete($this->createUrl([$index, $type]))->send(); - return $response->getStatusCode() == 200; + return $this->db->delete([$index, $type]); } /** @@ -365,9 +306,7 @@ class Command extends Component */ public function getFieldMapping($index, $type = '_all') { - // TODO - $response = $this->db->http()->put($this->createUrl([$index, $type, '_mapping']))->send(); - return Json::decode($response->getBody(true)); + return $this->db->put([$index, $type, '_mapping']); } /** @@ -375,10 +314,8 @@ class Command extends Component */ public function analyze($options, $index = null) { - // TODO - $response = $this->db->http()->put($this->createUrl([$index, $type, '_mapping']))->send(); - return Json::decode($response->getBody(true)); - + // TODO implement +// return $this->db->put([$index]); } /** @@ -390,10 +327,10 @@ class Command extends Component 'template' => $pattern, 'order' => $order, 'settings' => (object) $settings, - 'mappings' => (object) $settings, + 'mappings' => (object) $mappings, ]); - $response = $this->db->http()->put($this->createUrl(['_template', $name]), null, $body)->send(); - return $response->getStatusCode() == 200; + return $this->db->put(['_template', $name], $body); + } /** @@ -401,8 +338,8 @@ class Command extends Component */ public function deleteTemplate($name) { - $response = $this->db->http()->delete($this->createUrl(['_template', $name]))->send(); - return $response->getStatusCode() == 200; + return $this->db->delete(['_template', $name]); + } /** @@ -410,21 +347,6 @@ class Command extends Component */ public function getTemplate($name) { - $response = $this->db->http()->get($this->createUrl(['_template', $name]))->send(); - return Json::decode($response->getBody(true)); - } - - private function createUrl($path, $options = []) - { - $url = implode('/', array_map(function($a) { - return urlencode(is_array($a) ? implode(',', $a) : $a); - }, $path)); - - if (!empty($options) || !empty($this->options)) { - $options = array_merge($this->options, $options); - $url .= '?' . http_build_query($options); - } - - return $url; + return $this->db->get(['_template', $name]); } } \ No newline at end of file diff --git a/extensions/elasticsearch/Connection.php b/extensions/elasticsearch/Connection.php index 46c1efb..1adc42b 100644 --- a/extensions/elasticsearch/Connection.php +++ b/extensions/elasticsearch/Connection.php @@ -8,68 +8,56 @@ namespace yii\elasticsearch; +use Guzzle\Http\Exception\ClientErrorResponseException; +use Yii; use yii\base\Component; +use yii\base\Exception; use yii\base\InvalidConfigException; +use yii\helpers\Json; /** * elasticsearch Connection is used to connect to an elasticsearch cluster version 0.20 or higher * - * * @author Carsten Brandt * @since 2.0 */ -class Connection extends Component +abstract class Connection extends Component { /** * @event Event an event that is triggered after a DB connection is established */ const EVENT_AFTER_OPEN = 'afterOpen'; - // TODO add autodetection of cluster nodes - // http://localhost:9200/_cluster/nodes - public $nodes = array( - array( - 'host' => 'localhost', - 'port' => 9200, - ) - ); - - // http://www.elasticsearch.org/guide/en/elasticsearch/client/php-api/current/_configuration.html#_example_configuring_http_basic_auth - public $auth = []; - - // TODO use timeouts /** - * @var float timeout to use for connection to redis. If not set the timeout set in php.ini will be used: ini_get("default_socket_timeout") + * @var bool whether to autodetect available cluster nodes on [[open()]] */ - public $connectionTimeout = null; + public $autodetectCluster = true; /** - * @var float timeout to use for redis socket when reading and writing data. If not set the php default value will be used. + * @var array cluster nodes + * This is populated with the result of a cluster nodes request when [[autodetectCluster]] is true. + * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/cluster-nodes-info.html#cluster-nodes-info */ - public $dataTimeout = null; - + public $nodes = [ + ['http_address' => 'inet[/127.0.0.1:9200]'], + ]; + /** + * @var array the active node. key of [[nodes]]. Will be randomly selected on [[open()]]. + */ + public $activeNode; + // TODO http://www.elasticsearch.org/guide/en/elasticsearch/client/php-api/current/_configuration.html#_example_configuring_http_basic_auth + public $auth = []; public function init() { - if ($this->nodes === array()) { - throw new InvalidConfigException('elasticsearch needs at least one node.'); + foreach($this->nodes as $node) { + if (!isset($node['http_address'])) { + throw new InvalidConfigException('Elasticsearch node needs at least a http_address configured.'); + } } } /** - * Creates a command for execution. - * @param string $query the SQL statement to be executed - * @return Command the DB command - */ - public function createCommand($config = []) - { - $this->open(); - $config['db'] = $this; - $command = new Command($config); - return $command; - } - - /** * Closes the connection when this component is being serialized. * @return array */ @@ -85,7 +73,7 @@ class Connection extends Component */ public function getIsActive() { - return false; // TODO implement + return $this->activeNode !== null; } /** @@ -95,48 +83,37 @@ class Connection extends Component */ public function open() { - // TODO select one node to be the active one. - - - foreach($this->nodes as $key => $node) { - if (is_array($node)) { - $this->nodes[$key] = new Node($node); - } + if ($this->activeNode !== null) { + return; } -/* if ($this->_socket === null) { - if (empty($this->dsn)) { - throw new InvalidConfigException('Connection.dsn cannot be empty.'); - } - $dsn = explode('/', $this->dsn); - $host = $dsn[2]; - if (strpos($host, ':')===false) { - $host .= ':6379'; + if (empty($this->nodes)) { + throw new InvalidConfigException('elasticsearch needs at least one node to operate.'); + } + if ($this->autodetectCluster) { + $node = reset($this->nodes); + $host = $node['http_address']; + if (strncmp($host, 'inet[/', 6) == 0) { + $host = substr($host, 6, -1); } - $db = isset($dsn[3]) ? $dsn[3] : 0; - - \Yii::trace('Opening DB connection: ' . $this->dsn, __CLASS__); - $this->_socket = @stream_socket_client( - $host, - $errorNumber, - $errorDescription, - $this->connectionTimeout ? $this->connectionTimeout : ini_get("default_socket_timeout") - ); - if ($this->_socket) { - if ($this->dataTimeout !== null) { - stream_set_timeout($this->_socket, $timeout=(int)$this->dataTimeout, (int) (($this->dataTimeout - $timeout) * 1000000)); - } - if ($this->password !== null) { - $this->executeCommand('AUTH', array($this->password)); - } - $this->executeCommand('SELECT', array($db)); - $this->initConnection(); - } else { - \Yii::error("Failed to open DB connection ({$this->dsn}): " . $errorNumber . ' - ' . $errorDescription, __CLASS__); - $message = YII_DEBUG ? 'Failed to open DB connection: ' . $errorNumber . ' - ' . $errorDescription : 'Failed to open DB connection.'; - throw new Exception($message, $errorDescription, (int)$errorNumber); + $response = $this->httpRequest('get', 'http://' . $host . '/_cluster/nodes'); + $this->nodes = $response['nodes']; + if (empty($this->nodes)) { + throw new Exception('cluster autodetection did not find any active node.'); } - }*/ - // TODO implement + } + $this->selectActiveNode(); + Yii::trace('Opening connection to elasticsearch. Nodes in cluster: ' . count($this->nodes) + . ', active node: ' . $this->nodes[$this->activeNode]['http_address'], __CLASS__); + $this->initConnection(); + } + + /** + * select active node randomly + */ + public function selectActiveNode() + { + $keys = array_keys($this->nodes); + $this->activeNode = $keys[rand(0, count($keys) - 1)]; } /** @@ -145,14 +122,9 @@ class Connection extends Component */ public function close() { - // TODO implement -/* if ($this->_socket !== null) { - \Yii::trace('Closing DB connection: ' . $this->dsn, __CLASS__); - $this->executeCommand('QUIT'); - stream_socket_shutdown($this->_socket, STREAM_SHUT_RDWR); - $this->_socket = null; - $this->_transaction = null; - }*/ + Yii::trace('Closing connection to elasticsearch. Active node was: ' + . $this->nodes[$this->activeNode]['http_address'], __CLASS__); + $this->activeNode = null; } /** @@ -174,9 +146,17 @@ class Connection extends Component return 'elasticsearch'; } - public function getNodeInfo() + /** + * Creates a command for execution. + * @param array $config the configuration for the Command class + * @return Command the DB command + */ + public function createCommand($config = []) { - // TODO HTTP request to localhost:9200/ + $this->open(); + $config['db'] = $this; + $command = new Command($config); + return $command; } public function getQueryBuilder() @@ -184,13 +164,58 @@ class Connection extends Component return new QueryBuilder($this); } - /** - * @return \Guzzle\Http\Client - */ - public function http() + public function get($url, $options = [], $body = null, $validCodes = []) + { + $this->open(); + return $this->httpRequest('get', $this->createUrl($url, $options), $body); + } + + public function head($url, $options = [], $body = null) + { + $this->open(); + return $this->httpRequest('head', $this->createUrl($url, $options), $body); + } + + public function post($url, $options = [], $body = null) + { + $this->open(); + return $this->httpRequest('post', $this->createUrl($url, $options), $body); + } + + public function put($url, $options = [], $body = null) + { + $this->open(); + return $this->httpRequest('put', $this->createUrl($url, $options), $body); + } + + public function delete($url, $options = [], $body = null) + { + $this->open(); + return $this->httpRequest('delete', $this->createUrl($url, $options), $body); + } + + private function createUrl($path, $options = []) + { + $url = implode('/', array_map(function($a) { + return urlencode(is_array($a) ? implode(',', $a) : $a); + }, $path)); + + if (!empty($options)) { + $url .= '?' . http_build_query($options); + } + + return $url; + } + + protected abstract function httpRequest($type, $url, $body = null); + + public function getNodeInfo() + { + return $this->get([]); + } + + public function getClusterState() { - $guzzle = new \Guzzle\Http\Client('http://localhost:9200/'); - //$guzzle->setDefaultOption() - return $guzzle; + return $this->get(['_cluster', 'state']); } } \ No newline at end of file diff --git a/extensions/elasticsearch/GuzzleConnection.php b/extensions/elasticsearch/GuzzleConnection.php new file mode 100644 index 0000000..82f2fd1 --- /dev/null +++ b/extensions/elasticsearch/GuzzleConnection.php @@ -0,0 +1,57 @@ + + */ + +namespace yii\elasticsearch; + + +use Guzzle\Http\Exception\ClientErrorResponseException; +use yii\base\Exception; +use yii\helpers\Json; + +class GuzzleConnection extends Connection +{ + /** + * @var \Guzzle\Http\Client + */ + private $_http; + + protected function httpRequest($type, $url, $body = null) + { + if ($this->_http === null) { + $this->_http = new \Guzzle\Http\Client('http://localhost:9200/');// TODO use active node + //$guzzle->setDefaultOption() + } + $requestOptions = []; + if ($type == 'head') { + $requestOptions['exceptions'] = false; + } + if ($type == 'get' && $body !== null) { + $type = 'post'; + } + try{ + $response = $this->_http->createRequest( + strtoupper($type) + , $url, + null, + $body, + $requestOptions + )->send(); + } catch(ClientErrorResponseException $e) { + if ($e->getResponse()->getStatusCode() == 404) { + return false; + } + throw new Exception("elasticsearch error:\n\n" + . $body . "\n\n" . $e->getMessage() + . print_r(Json::decode($e->getResponse()->getBody(true)), true), 0, $e); + } + if ($type == 'head') { + return $response->getStatusCode() == 200; + } + return Json::decode($response->getBody(true)); + } + +} \ No newline at end of file diff --git a/extensions/elasticsearch/Query.php b/extensions/elasticsearch/Query.php index 23d9de1..db6e137 100644 --- a/extensions/elasticsearch/Query.php +++ b/extensions/elasticsearch/Query.php @@ -84,7 +84,7 @@ class Query extends Component implements QueryInterface */ public function all($db = null) { - $result = $this->createCommand($db)->queryAll(); + $result = $this->createCommand($db)->search(); // TODO publish facet results $rows = $result['hits']; if ($this->indexBy === null && $this->fields === null) { @@ -118,7 +118,7 @@ class Query extends Component implements QueryInterface public function one($db = null) { $options['size'] = 1; - $result = $this->createCommand($db)->queryAll($options); + $result = $this->createCommand($db)->search($options); // TODO publish facet results if (empty($result['hits'])) { return false; @@ -175,7 +175,7 @@ class Query extends Component implements QueryInterface { $command = $this->createCommand($db); $command->queryParts['fields'] = [$field]; - $rows = $command->queryAll()['hits']; + $rows = $command->search()['hits']; $result = []; foreach ($rows as $row) { $result[] = isset($row['fields'][$field]) ? $row['fields'][$field] : null; @@ -196,7 +196,9 @@ class Query extends Component implements QueryInterface // only when no facety are registerted. // http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-count.html - $count = $this->createCommand($db)->queryCount()['total']; + $options = []; + $options['search_type'] = 'count'; + $count = $this->createCommand($db)->search($options)['total']; if ($this->limit === null && $this->offset === null) { return $count; } elseif ($this->offset !== null) { diff --git a/extensions/elasticsearch/README.md b/extensions/elasticsearch/README.md index bc272d1..4894c85 100644 --- a/extensions/elasticsearch/README.md +++ b/extensions/elasticsearch/README.md @@ -14,7 +14,7 @@ return [ 'elasticsearch' => [ 'class' => 'yii\elasticsearch\Connection', 'hosts' => [ - ['hostname' => 'localhost', 'port' => 9200], + ['http_address' => '127.0.0.1:9200'], // configure more hosts if you have a cluster ], ], diff --git a/tests/unit/data/ar/elasticsearch/ActiveRecord.php b/tests/unit/data/ar/elasticsearch/ActiveRecord.php index 6c4dff6..aa1f304 100644 --- a/tests/unit/data/ar/elasticsearch/ActiveRecord.php +++ b/tests/unit/data/ar/elasticsearch/ActiveRecord.php @@ -24,4 +24,9 @@ class ActiveRecord extends \yii\elasticsearch\ActiveRecord { return self::$db; } + + public static function index() + { + return 'yiitest'; + } } diff --git a/tests/unit/extensions/elasticsearch/ActiveRecordTest.php b/tests/unit/extensions/elasticsearch/ActiveRecordTest.php index 65825e9..69f9edb 100644 --- a/tests/unit/extensions/elasticsearch/ActiveRecordTest.php +++ b/tests/unit/extensions/elasticsearch/ActiveRecordTest.php @@ -43,10 +43,12 @@ class ActiveRecordTest extends ElasticSearchTestCase /** @var Connection $db */ $db = ActiveRecord::$db = $this->getConnection(); - // delete all indexes - $db->http()->delete('_all')->send(); + // delete index + if ($db->createCommand()->indexExists('yiitest')) { + $db->createCommand()->deleteIndex('yiitest'); + } - $db->http()->post('items', null, Json::encode([ + $db->post(['yiitest'], [], Json::encode([ 'mappings' => [ "item" => [ "_source" => [ "enabled" => true ], @@ -56,19 +58,7 @@ class ActiveRecordTest extends ElasticSearchTestCase ] ] ], - ]))->send(); - - $db->http()->post('customers', null, Json::encode([ - 'mappings' => [ - "item" => [ - "_source" => [ "enabled" => true ], - "properties" => [ - // this is for the boolean test - "status" => ["type" => "boolean"], - ] - ] - ], - ]))->send(); + ])); $customer = new Customer(); $customer->id = 1; @@ -281,10 +271,10 @@ class ActiveRecordTest extends ElasticSearchTestCase public function testBooleanAttribute() { $db = $this->getConnection(); - $db->createCommand()->deleteIndex('customers'); - $db->http()->post('customers', null, Json::encode([ + $db->createCommand()->deleteIndex('yiitest'); + $db->post(['yiitest'], [], Json::encode([ 'mappings' => [ - "item" => [ + "customer" => [ "_source" => [ "enabled" => true ], "properties" => [ // this is for the boolean test @@ -292,7 +282,7 @@ class ActiveRecordTest extends ElasticSearchTestCase ] ] ], - ]))->send(); + ])); $customerClass = $this->getCustomerClass(); $customer = new $customerClass(); diff --git a/tests/unit/extensions/elasticsearch/ElasticSearchConnectionTest.php b/tests/unit/extensions/elasticsearch/ElasticSearchConnectionTest.php index 7e04d90..9e37466 100644 --- a/tests/unit/extensions/elasticsearch/ElasticSearchConnectionTest.php +++ b/tests/unit/extensions/elasticsearch/ElasticSearchConnectionTest.php @@ -2,13 +2,28 @@ namespace yiiunit\extensions\elasticsearch; -use yii\redis\Connection; +use yii\elasticsearch\Connection; +use yii\elasticsearch\GuzzleConnection; /** * @group elasticsearch */ class ElasticSearchConnectionTest extends ElasticSearchTestCase { - // TODO + public function testOpen() + { + $connection = new GuzzleConnection(); + $connection->autodetectCluster; + $connection->nodes = [ + ['http_address' => 'inet[/127.0.0.1:9200]'], + ]; + $this->assertNull($connection->activeNode); + $connection->open(); + $this->assertNotNull($connection->activeNode); + $this->assertArrayHasKey('name', reset($connection->nodes)); + $this->assertArrayHasKey('hostname', reset($connection->nodes)); + $this->assertArrayHasKey('version', reset($connection->nodes)); + $this->assertArrayHasKey('http_address', reset($connection->nodes)); + } } \ No newline at end of file diff --git a/tests/unit/extensions/elasticsearch/ElasticSearchTestCase.php b/tests/unit/extensions/elasticsearch/ElasticSearchTestCase.php index 532d1d5..dc639d7 100644 --- a/tests/unit/extensions/elasticsearch/ElasticSearchTestCase.php +++ b/tests/unit/extensions/elasticsearch/ElasticSearchTestCase.php @@ -4,6 +4,7 @@ namespace yiiunit\extensions\elasticsearch; use Yii; use yii\elasticsearch\Connection; +use yii\elasticsearch\GuzzleConnection; use yiiunit\TestCase; Yii::setAlias('@yii/elasticsearch', __DIR__ . '/../../../../extensions/elasticsearch'); @@ -42,7 +43,7 @@ class ElasticSearchTestCase extends TestCase { $databases = $this->getParam('databases'); $params = isset($databases['elasticsearch']) ? $databases['elasticsearch'] : array(); - $db = new Connection; + $db = new GuzzleConnection(); if ($reset) { $db->open(); }