diff --git a/README.markdown b/README.markdown index 64e2063..39d87eb 100644 --- a/README.markdown +++ b/README.markdown @@ -36,17 +36,6 @@ $es->get($id); $es->search('title:cool'); ``` -### Creating mapping - -```php -$es->map(array( - 'title' => array( - 'type' => 'string', - 'index' => 'analyzed' - ) -)); -``` - ### Search multiple indexes or types ```php @@ -157,6 +146,3 @@ class FooController extends Controller } } ``` - - - diff --git a/composer.json b/composer.json index 8f94608..59a2ddc 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name" : "nervetattoo/elasticsearch", "type" : "library", - "description" : "ElasticSearch client for PHP 5.3", + "description" : "ElasticSearch client for PHP 7.1+", "keywords" : ["elasticsearch", "client"], "homepage" : "http://github.com/nervetattoo/elasticsearch", "license" : "MIT", @@ -13,7 +13,9 @@ } ], "require" : { - "php" : ">=5.3.0" + "php" : ">=7.1", + "ext-curl": "*", + "ext-json": "*" }, "require-dev" : { "atoum/atoum" : "^2.9" diff --git a/src/ElasticSearch/Bulk.php b/src/ElasticSearch/Bulk.php index 23fc42a..80aa3d6 100644 --- a/src/ElasticSearch/Bulk.php +++ b/src/ElasticSearch/Bulk.php @@ -2,10 +2,11 @@ namespace ElasticSearch; -class Bulk { +class Bulk +{ - private $client; - private $operations = array(); + private $client; + private $operations = []; /** * Construct a bulk operation @@ -13,51 +14,59 @@ class Bulk { * @param \ElasticSearch\Client */ - public function __construct(Client $client) { - $this->client = $client; - } + public function __construct(Client $client) + { + $this->client = $client; + } /** * commit this operation */ - public function commit() { - return $this->client->request('/_bulk', 'POST', $this->createPayload()); - } - + public function commit(): array + { + return $this->client->request('/_bulk', 'POST', $this->createPayload()); + } + /** * reset this operation */ - public function reset() { - $this->operations = array(); - } - + public function reset() + { + $this->operations = []; + } + /** * Index a new document or update it if existing * - * @param array $document - * @param mixed $id Optional - * @param string $index Index - * @param string $type Type - * @param array $options Allow sending query parameters to control indexing further - * _refresh_ *bool* If set to true, immediately refresh the shard after indexing + * @param array $document + * @param string|null $id Optional + * @param string $index Index + * @param string $type Type + * @param array $options Allow sending query parameters to control indexing further + * _refresh_ *bool* If set to true, immediately refresh the shard after indexing + * * @return \Elasticsearch\Bulk */ - public function index($document, $id=null, $index, $type, array $options = array()) { - $params = array( '_id' => $id, - '_index' => $index, - '_type' => $type); - - foreach ($options as $key => $value) { - $params['_' . $key] = $value; - } - - $operation = array( - array('index' => $params), - $document - ); - $this->operations[] = $operation; - return $this; - } + public function index(array $document, ?string $id, string $index, string $type, array $options = []): self + { + $params = [ + '_id' => $id, + '_index' => $index, + '_type' => $type + ]; + + foreach ($options as $key => $value) { + $params['_' . $key] = $value; + } + + $operation = [ + [ 'index' => $params ], + $document, + ]; + $this->operations[] = $operation; + + return $this; + } /** * Update a part of a document @@ -71,80 +80,88 @@ public function index($document, $id=null, $index, $type, array $options = array * * @return \Elasticsearch\Bulk */ - public function update($partialDocument, $id, $index, $type, array $options = array()) { - $params = array( - '_id' => $id, + public function update(array $partialDocument, string $id, string $index, string $type, array $options = []): self + { + $params = [ + '_id' => $id, '_index' => $index, - '_type' => $type, - ); + '_type' => $type, + ]; foreach ($options as $key => $value) { - $params['_'.$key] = $value; + $params['_' . $key] = $value; } - $operation = array( - array('update' => $params), - array('doc' => $partialDocument), - ); + $operation = [ + [ 'update' => $params ], + [ 'doc' => $partialDocument ], + ]; $this->operations[] = $operation; return $this; } - /** + /** * delete a document * - * @param mixed $id - * @param string $index Index - * @param string $type Type - * @param array $options Parameters to pass to delete action + * @param string $id + * @param string $index Index + * @param string $type Type + * @param array $options Parameters to pass to delete action + * * @return \Elasticsearch\Bulk */ - public function delete($id=false, $index, $type, array $options = array()) { - $params = array( '_id' => $id, - '_index' => $index, - '_type' => $type); - - foreach ($options as $key => $value) { - $params['_' . $key] = $value; - } - - $operation = array( - array('delete' => $params) - ); - $this->operations[] = $operation; - return $this; - - } - - /** - * get all pending operations - * @return array + public function delete(string $id, string $index, string $type, array $options = []): Bulk + { + $params = [ + '_id' => $id, + '_index' => $index, + '_type' => $type + ]; + + foreach ($options as $key => $value) { + $params['_' . $key] = $value; + } + + $operation = [ + [ 'delete' => $params ], + ]; + $this->operations[] = $operation; + + return $this; + } + + /** + * get all pending operations + * @return array */ - public function getOperations() { - return $this->operations; - } + public function getOperations(): array + { + return $this->operations; + } - /** - * count all pending operations - * @return int + /** + * count all pending operations + * @return int */ - public function count() { - return count($this->operations); - } + public function count(): int + { + return count($this->operations); + } - /** - * create a request payload with all pending operations - * @return string + /** + * create a request payload with all pending operations + * @return string */ - public function createPayload() - { - $payloads = array(); - foreach ($this->operations as $operation) { - foreach ($operation as $partial) { - $payloads[] = json_encode($partial); - } - } - return join("\n", $payloads)."\n"; - } + public function createPayload(): string + { + $payloads = []; + foreach ($this->operations as $operation) { + foreach ($operation as $partial) { + $payloads[] = json_encode($partial); + } + } + + return implode("\n", $payloads) . "\n"; + } } diff --git a/src/ElasticSearch/Client.php b/src/ElasticSearch/Client.php index 3a4954c..3c37cee 100755 --- a/src/ElasticSearch/Client.php +++ b/src/ElasticSearch/Client.php @@ -2,6 +2,9 @@ namespace ElasticSearch; +use ElasticSearch\Transport\Base; +use ElasticSearch\Transport\HTTP; + /** * This file is part of the ElasticSearch PHP client * @@ -10,39 +13,48 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - -class Client { +class Client +{ const DEFAULT_PROTOCOL = 'http'; - const DEFAULT_SERVER = '127.0.0.1:9200'; - const DEFAULT_INDEX = 'default-index'; - const DEFAULT_TYPE = 'default-type'; + const DEFAULT_SERVER = '127.0.0.1:9200'; + const DEFAULT_INDEX = 'default-index'; + const DEFAULT_TYPE = 'default-type'; - protected $_config = array(); + protected $_config = []; - protected static $_defaults = array( + protected static $_defaults = [ 'protocol' => Client::DEFAULT_PROTOCOL, 'servers' => Client::DEFAULT_SERVER, 'index' => Client::DEFAULT_INDEX, 'type' => Client::DEFAULT_TYPE, 'timeout' => null, - ); + ]; + + protected static $_protocols = [ + 'http' => HTTP::class, + ]; + + /** @var Base */ + private $transport; - protected static $_protocols = array( - 'http' => 'ElasticSearch\\Transport\\HTTP', - 'memcached' => 'ElasticSearch\\Transport\\Memcached', - ); + /** @var string|null */ + private $index; - private $transport, $index, $type, $bulk; + /** @var string|null */ + private $type; + + /** @var Bulk|null */ + private $bulk; /** * Construct search client * - * @return \ElasticSearch\Client - * @param \ElasticSearch\Transport\Base $transport - * @param string $index - * @param string $type + * @param Base $transport + * @param string|null $index + * @param string|null $type */ - public function __construct($transport, $index = null, $type = null) { + public function __construct(Base $transport, string $index = null, string $type = null) + { $this->transport = $transport; $this->setIndex($index)->setType($type); } @@ -52,15 +64,17 @@ public function __construct($transport, $index = null, $type = null) { * Defaults to opening a http transport connection to 127.0.0.1:9200 * * @param string|array $config Allow overriding only the configuration bits you desire - * - _transport_ - * - _host_ - * - _port_ - * - _index_ - * - _type_ + * - _transport_ + * - _host_ + * - _port_ + * - _index_ + * - _type_ + * + * @return Client * @throws \Exception - * @return \ElasticSearch\Client */ - public static function connection($config = array()) { + public static function connection(array $config = []): Client + { if (!$config && ($url = getenv('ELASTICSEARCH_URL'))) { $config = $url; } @@ -68,198 +82,282 @@ public static function connection($config = array()) { $config = self::parseDsn($config); } - $config += self::$_defaults; + $config = array_merge(self::$_defaults, $config); $protocol = $config['protocol']; if (!isset(self::$_protocols[$protocol])) { - throw new \Exception("Tried to use unknown protocol: $protocol"); + throw new \Exception("Tried to use unknown protocol: {$protocol}"); } $class = self::$_protocols[$protocol]; if (null !== $config['timeout'] && !is_numeric($config['timeout'])) { - throw new \Exception("HTTP timeout should have a numeric value when specified."); + throw new \Exception('HTTP timeout should have a numeric value when specified.'); } $server = is_array($config['servers']) ? $config['servers'][0] : $config['servers']; - list($host, $port) = explode(':', $server); - + [ $host, $port ] = explode(':', $server); + $transport = new $class($host, $port, $config['timeout']); - + $client = new self($transport, $config['index'], $config['type']); $client->config($config); + return $client; } + /** + * @param int $timeout + */ + public function setTimeout(int $timeout): void + { + $this->transport->setTimeout($timeout); + } + + /** + * @return int + */ + public function getTimeout(): int + { + return $this->transport->getTimeout(); + } + + /** + * @return Base + */ + public function getTransport(): Base + { + return $this->transport; + } + + /** + * Set fix unicode option in transport + */ + public function setFixUnicode(bool $fixUnicode): void + { + $this->transport->setFixUnicode($fixUnicode); + } + /** * @param array|null $config + * * @return array|void */ - public function config($config = null) { - if (!$config) - return $this->_config; - if (is_array($config)) - $this->_config = $config + $this->_config; + public function config(array $config = null): array + { + if (is_array($config)) { + $this->_config = array_merge($this->_config, $config); + } + + return $this->_config; } /** * Change what index to go against - * @return \ElasticSearch\Client + * * @param mixed $index + * + * @return Client */ - public function setIndex($index) { - if (is_array($index)) - $index = implode(",", array_filter($index)); + public function setIndex($index): self + { + if (is_array($index)) { + $index = implode(',', array_filter($index)); + } + $this->index = $index; $this->transport->setIndex($index); + return $this; } /** * Change what types to act against - * @return \ElasticSearch\Client + * * @param mixed $type + * + * @return Client */ - public function setType($type) { - if (is_array($type)) - $type = implode(",", array_filter($type)); + public function setType($type): self + { + if (is_array($type)) { + $type = implode(',', array_filter($type)); + } $this->type = $type; $this->transport->setType($type); + return $this; } /** * Fetch a document by its id * - * @return array * @param mixed $id Optional - * @param bool $verbose - */ - public function get($id, $verbose=false) { - return $this->request($id, "GET"); - } - - /** - * Puts a mapping on index + * @param bool $verbose * - * @param array|object $mapping - * @param array $config - * @throws Exception * @return array */ - public function map($mapping, array $config = array()) { - if (is_array($mapping)) $mapping = new Mapping($mapping); - $mapping->config($config); - - try { - $type = $mapping->config('type'); - } - catch (\Exception $e) {} // No type is cool - if (isset($type) && !$this->passesTypeConstraint($type)) { - throw new Exception("Cant create mapping due to type constraint mismatch"); - } - - return $this->request('_mapping', 'PUT', $mapping->export(), true); + public function get($id, bool $verbose = false): array + { + return $this->request($id, 'GET'); } - protected function passesTypeConstraint($constraint) { - if (is_string($constraint)) $constraint = array($constraint); + protected function passesTypeConstraint($constraint): bool + { + if (is_string($constraint)) { + $constraint = [ $constraint ]; + } $currentType = explode(',', $this->type); $includeTypes = array_intersect($constraint, $currentType); + return ($constraint && count($includeTypes) === count($constraint)); } /** - * Perform a raw request + * Perform a request * * Usage example * * $response = $client->request('_status', 'GET'); * + * @param mixed $path Request path to use. + * `type` is prepended to this path inside request + * @param string $method HTTP verb to use + * @param mixed $payload Array of data to be json-encoded + * @param bool $verbose Controls response data, if `false` + * only `_source` of response is returned + * * @return array - * @param mixed $path Request path to use. - * `type` is prepended to this path inside request - * @param string $method HTTP verb to use - * @param mixed $payload Array of data to be json-encoded - * @param bool $verbose Controls response data, if `false` - * only `_source` of response is returned */ - public function request($path, $method = 'GET', $payload = false, $verbose=false) { + public function request($path, string $method = 'GET', $payload = false, bool $verbose = false): array + { $response = $this->transport->request($this->expandPath($path), $method, $payload); + return ($verbose || !isset($response['_source'])) ? $response : $response['_source']; } /** - * Index a new document or update it if existing + * Perform a raw request + * + * Usage example + * + * $response = $client->rawRequest('_cluster/health/indexName', 'GET', false, ['level' => 'indices]); + * + * @param mixed $path Request path to use. + * `type` is prepended to this path inside request + * @param string $method HTTP verb to use + * @param mixed $payload Array of data to be json-encoded + * @param array $options * * @return array + */ + public function rawRequest($path, string $method = 'GET', $payload = false, array $options = []): array + { + return $this->transport->request($this->expandPath($path), $method, $payload, $options); + } + + /** + * Index a new document or update it if existing + * * @param array $document - * @param mixed $id Optional + * @param mixed $id Optional * @param array $options Allow sending query parameters to control indexing further - * _refresh_ *bool* If set to true, immediately refresh the shard after indexing + * _refresh_ *bool* If set to true, immediately refresh the shard after indexing + * + * @return array|Bulk */ - public function index($document, $id=false, array $options = array()) { + public function index(array $document, $id = false, array $options = []) + { if ($this->bulk) { return $this->bulk->index($document, $id, $this->index, $this->type, $options); } + return $this->transport->index($document, $id, $options); } /** * Update a part of a document * - * @return array - * * @param array $partialDocument * @param mixed $id * @param array $options Allow sending query parameters to control indexing further * _refresh_ *bool* If set to true, immediately refresh the shard after indexing + * + * @return array|Bulk + * */ - public function update($partialDocument, $id, array $options = array()) { + public function update(array $partialDocument, $id, array $options = []) + { if ($this->bulk) { return $this->bulk->update($partialDocument, $id, $this->index, $this->type, $options); } + return $this->transport->update($partialDocument, $id, $options); } /** * Perform search, this is the sweet spot * - * @return array - * @param $query + * @param $query * @param array $options + * + * @return array */ - public function search($query, array $options = array()) { + public function search($query, array $options = []): array + { $start = microtime(true); $result = $this->transport->search($query, $options); $result['time'] = microtime(true) - $start; + return $result; } - + /** - * Flush this index/type combination + * Continue scroll + * + * @param string $scrollId + * @param string $scroll * * @return array - * @param mixed $id If id is supplied, delete that id for this index - * if not wipe the entire index + */ + public function scroll(string $scrollId, string $scroll): array + { + return $this->transport->request('/_search/scroll', 'POST', [ + 'scroll_id' => $scrollId, + 'scroll' => $scroll + ]); + } + + /** + * Flush this index/type combination + * + * @param mixed $id If id is supplied, delete that id for this index + * if not wipe the entire index * @param array $options Parameters to pass to delete action + * + * @return array|Bulk */ - public function delete($id=false, array $options = array()) { + public function delete($id = false, array $options = []) + { if ($this->bulk) { return $this->bulk->delete($id, $this->index, $this->type, $options); } + return $this->transport->delete($id, $options); } /** * Flush this index/type combination * - * @return array - * @param mixed $query Text or array based query to delete everything that matches + * @param mixed $query Text or array based query to delete everything that matches * @param array $options Parameters to pass to delete action + * + * @return bool + * @throws \Elasticsearch\Exception */ - public function deleteByQuery($query, array $options = array()) { + public function deleteByQuery($query, array $options = []): bool + { return $this->transport->deleteByQuery($query, $options); } @@ -268,8 +366,9 @@ public function deleteByQuery($query, array $options = array()) { * * @return array */ - public function refresh() { - return $this->transport->request(array('_refresh'), 'GET'); + public function refresh(): array + { + return $this->transport->request([ '_refresh' ], 'GET'); } /** @@ -278,13 +377,14 @@ public function refresh() { * If it is an absolute path it will be used as is * * @param mixed $path + * * @return array */ - protected function expandPath($path) { - $path = (array) $path; - $isAbsolute = $path[0][0] === '/'; + protected function expandPath($path): array + { + $path = (array)$path; - return $isAbsolute + return $path[0][0] === '/' ? $path : array_merge((array) $this->type, $path); } @@ -293,16 +393,19 @@ protected function expandPath($path) { * Parse a DSN string into an associative array * * @param string $dsn + * * @return array */ - protected static function parseDsn($dsn) { + protected static function parseDsn(string $dsn): array + { $parts = parse_url($dsn); $protocol = $parts['scheme']; $servers = $parts['host'] . ':' . $parts['port']; if (isset($parts['path'])) { $path = explode('/', $parts['path']); - list($index, $type) = array_values(array_filter($path)); + [ $index, $type ] = array_values(array_filter($path)); } + return compact('protocol', 'servers', 'index', 'type'); } @@ -312,49 +415,71 @@ protected static function parseDsn($dsn) { * @return \Elasticsearch\Bulk */ - public function createBulk() { + public function createBulk(): Bulk + { return new Bulk($this); } - /** * Begin a transparent bulk-transaction * if one is already running, return its handle + * @note Maybe deprecated in next version prior to createBulk method + * * @return \Elasticsearch\Bulk */ - - public function beginBulk() { + public function beginBulk(): Bulk + { if (!$this->bulk) { - $this->bulk = $this->createBulk($this); + $this->bulk = $this->createBulk(); } - return $this->bulk; - } - /** - * @see beginBulk - */ - public function begin() { - return $this->beginBulk(); + return $this->bulk; } /** * commit a bulk-transaction - * @return array + * @return array|null */ - - public function commitBulk() { + public function commitBulk(): ?array + { if ($this->bulk && $this->bulk->count()) { $result = $this->bulk->commit(); $this->bulk = null; + return $result; } + + return null; } /** - * @see commitBulk - */ - public function commit() { + * Stop bulk without commit + */ + public function stopBulk(): void + { + if ($this->bulk) { + $this->bulk = null; + } + } + + /** + * @see beginBulk + */ + public function begin(): Bulk + { + return $this->beginBulk(); + } + + /** + * @see commitBulk + */ + public function commit(): array + { return $this->commitBulk(); } - + + public static function addProtocol(string $protocolClassName, string $protocolName): void + { + self::$_protocols[$protocolName] = $protocolClassName; + } } diff --git a/src/ElasticSearch/DSL/Builder.php b/src/ElasticSearch/DSL/Builder.php index 73e1192..b0ba47e 100755 --- a/src/ElasticSearch/DSL/Builder.php +++ b/src/ElasticSearch/DSL/Builder.php @@ -16,14 +16,15 @@ * $dsl = new ElasticSearchDSL; * $bool = $dsl->bool(); // Return a new bool structure * - * @author Raymond Julin + * @author Raymond Julin * @package ElasticSearchClient - * @since 0.1 + * @since 0.1 * Created: 2010-07-23 */ -class Builder { +class Builder +{ - protected $dsl = array(); + protected $dsl = []; private $explain = null; private $from = null; @@ -36,44 +37,55 @@ class Builder { /** * Construct DSL object * - * @return \ElasticSearch\DSL\Builder * @param array $options */ - public function __construct(array $options=array()) { - foreach ($options as $key => $value) + public function __construct(array $options = []) + { + foreach ($options as $key => $value) { $this->$key = $value; + } } /** * Add array clause, can only be one * - * @return \ElasticSearch\DSL\Query * @param array $options + * + * @return \ElasticSearch\DSL\Query */ - public function query(array $options=array()) { - if (!($this->query instanceof Query)) + public function query(array $options = []): Query + { + if (!($this->query instanceof Query)) { $this->query = new Query($options); + } + return $this->query; } /** * Build the DSL as array * - * @throws \ElasticSearch\Exception * @return array + * @throws \ElasticSearch\Exception */ - public function build() { - $built = array(); - if ($this->from != null) + public function build(): array + { + $built = []; + if ($this->from != null) { $built['from'] = $this->from; - if ($this->size != null) + } + if ($this->size != null) { $built['size'] = $this->size; - if ($this->sort && is_array($this->sort)) + } + if ($this->sort && is_array($this->sort)) { $built['sort'] = $this->sort; - if (!$this->query) + } + if (!$this->query) { throw new \ElasticSearch\Exception("Query must be specified"); - else + } else { $built['query'] = $this->query->build(); + } + return $built; } } diff --git a/src/ElasticSearch/DSL/Query.php b/src/ElasticSearch/DSL/Query.php index 33ab5ff..bb0880a 100755 --- a/src/ElasticSearch/DSL/Query.php +++ b/src/ElasticSearch/DSL/Query.php @@ -12,14 +12,15 @@ */ /** - * Handle the query sub dsl + * Handle the query sub dsl * - * @author Raymond Julin + * @author Raymond Julin * @package ElasticSearchClient - * @since 0.1 + * @since 0.1 * Created: 2010-07-24 */ -class Query { +class Query +{ protected $term = null; /** * @var RangeQuery @@ -34,45 +35,55 @@ class Query { protected $constantScore = null; protected $filteredQuery = null; - public function __construct(array $options=array()) { + public function __construct(array $options = []) + { } /** * Add a term to this query * - * @return \ElasticSearch\DSL\Query - * @param string $term + * @param string $term * @param bool|string $field + * + * @return \ElasticSearch\DSL\Query */ - public function term($term, $field=false) { + public function term(string $term, $field = false): self + { $this->term = ($field) - ? array($field => $term) + ? [ $field => $term ] : $term; + return $this; } /** * Add a wildcard to this query * - * @return \ElasticSearch\DSL\Query - * @param $val + * @param $val * @param bool|string $field + * + * @return \ElasticSearch\DSL\Query */ - public function wildcard($val, $field=false) { + public function wildcard($val, $field = false): self + { $this->wildcard = ($field) - ? array($field => $val) + ? [ $field => $val ] : $val; + return $this; } - + /** * Add a range query * - * @return \ElasticSearch\DSL\RangeQuery * @param array $options + * + * @return \ElasticSearch\DSL\RangeQuery */ - public function range(array $options=array()) { + public function range(array $options = []): RangeQuery + { $this->range = new RangeQuery($options); + return $this->range; } @@ -80,15 +91,20 @@ public function range(array $options=array()) { * Build the DSL as array * * @return array + * + * @throws \ElasticSearch\Exception */ - public function build() { - $built = array(); - if ($this->term) + public function build(): array + { + $built = []; + if ($this->term) { $built['term'] = $this->term; - elseif ($this->range) + } elseif ($this->range) { $built['range'] = $this->range->build(); - elseif ($this->wildcard) + } elseif ($this->wildcard) { $built['wildcard'] = $this->wildcard; + } + return $built; } } diff --git a/src/ElasticSearch/DSL/RangeQuery.php b/src/ElasticSearch/DSL/RangeQuery.php index 18f4380..52f873e 100755 --- a/src/ElasticSearch/DSL/RangeQuery.php +++ b/src/ElasticSearch/DSL/RangeQuery.php @@ -14,104 +14,134 @@ /** * Range queries * - * @author Raymond Julin + * @author Raymond Julin * @package ElasticSearchClient - * @since 0.1 + * @since 0.1 * Created: 2010-07-24 */ -class RangeQuery { - protected $fieldname = null; +class RangeQuery +{ + protected $fieldName = null; protected $from = null; protected $to = null; protected $includeLower = null; protected $includeUpper = null; protected $boost = null; - + /** * Construct new RangeQuery component * - * @return \ElasticSearch\DSL\RangeQuery * @param array $options + * + * @return \ElasticSearch\DSL\RangeQuery */ - public function __construct(array $options=array()) { - $this->fieldname = key($options); + public function __construct(array $options = []) + { + $this->fieldName = key($options); $values = current($options); if (is_array($values)) { - foreach ($values as $key => $val) + foreach ($values as $key => $val) { $this->$key = $val; + } } } - + /** * Setters * - * @return \ElasticSearch\DSL\RangeQuery * @param mixed $value + * + * @return \ElasticSearch\DSL\RangeQuery */ - public function fieldname($value) { - $this->fieldname = $value; + public function fieldName($value): self + { + $this->fieldName = $value; + return $this; } /** * @param $value + * * @return \ElasticSearch\DSL\RangeQuery $this */ - public function from($value) { + public function from($value): self + { $this->from = $value; + return $this; } + /** * @param $value + * * @return \ElasticSearch\DSL\RangeQuery $this */ - public function to($value) { + public function to($value): self + { $this->to = $value; + return $this; } + /** * @param $value + * * @return \ElasticSearch\DSL\RangeQuery $this */ - public function includeLower($value) { + public function includeLower($value): self + { $this->includeLower = $value; + return $this; } + /** * @param $value + * * @return \ElasticSearch\DSL\RangeQuery $this */ - public function includeUpper($value) { + public function includeUpper($value): self + { $this->includeUpper = $value; + return $this; } + /** * @param $value + * * @return \ElasticSearch\DSL\RangeQuery $this */ - public function boost($value) { + public function boost($value): self + { $this->boost = $value; + return $this; } /** * Build to array * - * @throws \ElasticSearch\Exception * @return array + * @throws \ElasticSearch\Exception */ - public function build() { - $built = array(); - if ($this->fieldname) { - $built[$this->fieldname] = array(); - foreach (array("from","to","includeLower","includeUpper", "boost") as $opt) { - if ($this->$opt !== null) - $built[$this->fieldname][$opt] = $this->$opt; + public function build(): self + { + $built = []; + if ($this->fieldName) { + $built[$this->fieldName] = []; + foreach ([ "from", "to", "includeLower", "includeUpper", "boost" ] as $opt) { + if ($this->$opt !== null) { + $built[$this->fieldName][$opt] = $this->$opt; + } } - if (count($built[$this->fieldname]) == 0) + if (count($built[$this->fieldName]) == 0) { throw new \ElasticSearch\Exception("Empty RangeQuery cant be created"); + } } + return $built; } } diff --git a/src/ElasticSearch/DSL/Stringify.php b/src/ElasticSearch/DSL/Stringify.php index d2885d6..b8e98a5 100644 --- a/src/ElasticSearch/DSL/Stringify.php +++ b/src/ElasticSearch/DSL/Stringify.php @@ -17,32 +17,40 @@ * This will remove certain fields that are not supported * in a string representation * - * @author Raymond Julin + * @author Raymond Julin * @package ElasticSearch - * @since 0.1 + * @since 0.1 * Created: 2010-07-24 */ -class Stringify { +class Stringify +{ - protected $dsl = array(); - - public function __construct(array $dsl) { + protected $dsl = []; + + public function __construct(array $dsl) + { $this->dsl = $dsl; } - public function __toString() { + public function __toString() + { $dsl = $this->dsl; $query = $dsl['query']; - $string = ""; - if (array_key_exists("term", $query)) + $string = ''; + if (array_key_exists('term', $query)) { $string .= $this->transformDSLTermToString($query['term']); - if (array_key_exists("wildcard", $query)) + } + if (array_key_exists('wildcard', $query)) { $string .= $this->transformDSLTermToString($query['wildcard']); - if (array_key_exists("sort", $dsl)) + } + if (array_key_exists('sort', $dsl)) { $string .= $this->transformDSLSortToString($dsl['sort']); - if (array_key_exists("fields", $dsl)) + } + if (array_key_exists('fields', $dsl)) { $string .= $this->transformDSLFieldsToString($dsl['fields']); + } + return $string; } @@ -50,68 +58,83 @@ public function __toString() { * A naive transformation of possible term and wildcard arrays in a DSL * query * - * @return string * @param mixed $dslTerm + * + * @return string */ - protected function transformDSLTermToString($dslTerm) { - $string = ""; + protected function transformDSLTermToString($dslTerm): string + { + $string = ''; if (is_array($dslTerm)) { $key = key($dslTerm); $value = $dslTerm[$key]; - if (is_string($key)) + if (is_string($key)) { $string .= "$key:"; - } - else + } + } else { $value = $dslTerm; + } /** * If a specific key is used as key in the array * this should translate to searching in a specific field (field:term) */ - if (strpos($value, " ") !== false) + if (strpos($value, ' ') !== false) { $string .= '"' . $value . '"'; - else + } else { $string .= $value; + } + return $string; } /** * Transform search parameters to string * - * @return string * @param mixed $dslSort + * + * @return string */ - protected function transformDSLSortToString($dslSort) { - $string = ""; - if (is_array($dslSort)) { - foreach ($dslSort as $sort) { - if (is_array($sort)) { - $field = key($sort); - $info = current($sort); - } - else - $field = $sort; - $string .= "&sort=" . $field; - if (isset($info)) { - if (is_string($info) && $info == "desc") - $string .= ":reverse"; - elseif (is_array($info) && array_key_exists("reverse", $info) && $info['reverse']) - $string .= ":reverse"; + protected function transformDSLSortToString($dslSort): string + { + if (!is_array($dslSort)) { + return ''; + } + $string = ''; + + foreach ($dslSort as $sort) { + if (is_array($sort)) { + $field = key($sort); + $info = current($sort); + } else { + $field = $sort; + } + $string .= '&sort=' . $field; + if (isset($info)) { + if (is_string($info) && $info == 'desc') { + $string .= ':reverse'; + } elseif (is_array($info) && array_key_exists('reverse', $info) && $info['reverse']) { + $string .= ':reverse'; } } } + return $string; } /** * Transform a selection of fields to return to string form * - * @return string * @param mixed $dslFields + * + * @return string */ - protected function transformDSLFieldsToString($dslFields) { - $string = ""; - if (is_array($dslFields)) - $string .= "&fields=" . join(",", $dslFields); + protected function transformDSLFieldsToString($dslFields): string + { + $string = ''; + if (is_array($dslFields)) { + $string .= '&fields=' . join(',', $dslFields); + } + return $string; } } diff --git a/src/ElasticSearch/Mapping.php b/src/ElasticSearch/Mapping.php deleted file mode 100755 index 2f7f487..0000000 --- a/src/ElasticSearch/Mapping.php +++ /dev/null @@ -1,73 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -class Mapping { - - protected $properties = array(); - protected $config = array(); - - /** - * Build mapping data - * - * @param array $properties - * @param array $config - * @return \ElasticSearch\Mapping - */ - public function __construct(array $properties = array(), array $config = array()) { - $this->properties = $properties; - $this->config = $config; - } - - /** - * Export mapping data as a json-ready array - * - * @return string - */ - public function export() { - return array( - 'properties' => $this->properties - ); - } - - /** - * Add or overwrite existing field by name - * - * @param string $field - * @param string|array $config - * @return $this - */ - public function field($field, $config = array()) { - if (is_string($config)) $config = array('type' => $config); - $this->properties[$field] = $config; - return $this; - } - - /** - * Get or set a config - * - * @param string $key - * @param mixed $value - * @throws \Exception - * @return array|void - */ - public function config($key, $value = null) { - if (is_array($key)) - $this->config = $key + $this->config; - else { - if ($value !== null) $this->config[$key] = $value; - if (!isset($this->config[$key])) - throw new \Exception("Configuration key `type` is not set"); - return $this->config[$key]; - } - } -} diff --git a/src/ElasticSearch/Transport/Base.php b/src/ElasticSearch/Transport/Base.php index 5c117ea..bfbe524 100755 --- a/src/ElasticSearch/Transport/Base.php +++ b/src/ElasticSearch/Transport/Base.php @@ -10,15 +10,15 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - -abstract class Base { +abstract class Base +{ /** * What host to connect to for server * @var string */ protected $host = ""; - + /** * Port to connect on * @var int @@ -30,19 +30,24 @@ abstract class Base { * @var string */ protected $index; - + /** * ElasticSearch document type * @var string */ protected $type; + /** @var bool */ + protected $fixUnicode = true; + /** * Default constructor, just set host and port + * * @param string $host - * @param int $port + * @param int $port */ - public function __construct($host, $port) { + public function __construct(string $host, int $port) + { $this->host = $host; $this->port = $port; } @@ -50,20 +55,24 @@ public function __construct($host, $port) { /** * Method for indexing a new document * - * @param array|object $document - * @param mixed $id - * @param array $options + * @param array $document + * @param string|null $id + * @param array $options + * + * @return array */ - abstract public function index($document, $id=false, array $options = array()); + abstract public function index(array $document, string $id = null, array $options = []): array; /** * Method for updating a document * - * @param array|object $partialDocument - * @param mixed $id - * @param array $options + * @param array $partialDocument + * @param string $id + * @param array $options + * + * @return array */ - abstract public function update($partialDocument, $id, array $options = array()); + abstract public function update(array $partialDocument, string $id, array $options = []): array; /** * Perform a request against the given path/method/payload combination @@ -71,72 +80,112 @@ abstract public function update($partialDocument, $id, array $options = array()) * $es->request('/_status'); * * @param string|array $path - * @param string $method - * @param array|bool $payload - * @return + * @param string $method + * @param mixed $payload + * @param array $options + * + * @return array */ - abstract public function request($path, $method="GET", $payload=false); + abstract public function request($path, string $method = 'GET', $payload = false, array $options = []): array; /** * Delete a document by its id + * * @param mixed $id */ - abstract public function delete($id=false); + abstract public function delete($id = false): array; /** * Perform a search based on query + * * @param array|string $query */ abstract public function search($query); + /** + * Set timeout + * + * @param int $timeout + */ + abstract public function setTimeout(int $timeout); + + /** + * Get timeout + * @return int + */ + abstract public function getTimeout(): int; + + /** + * @param bool $fixUnicode + */ + public function setFixUnicode(bool $fixUnicode): void + { + $this->fixUnicode = $fixUnicode; + } + /** * Search * - * @return array - * @param mixed $query String or array to use as criteria for delete + * @param mixed $query String or array to use as criteria for delete * @param array $options Parameters to pass to delete action + * + * @return bool * @throws \Elasticsearch\Exception */ - public function deleteByQuery($query, array $options = array()) { + public function deleteByQuery($query, array $options = []): bool + { throw new \Elasticsearch\Exception(__FUNCTION__ . ' not implemented for ' . __CLASS__); } /** * Set what index to act against - * @param string $index + * + * @param string|null $index */ - public function setIndex($index) { + public function setIndex(?string $index): void + { $this->index = $index; } /** * Set what document types to act against - * @param string $type + * + * @param string|null $type */ - public function setType($type) { + public function setType(?string $type): void + { $this->type = $type; } /** * Build a callable url * + * @param array|string $path + * @param array $options Query parameter options to pass + * * @return string - * @param array|bool $path - * @param array $options Query parameter options to pass */ - protected function buildUrl($path = false, array $options = array()) { - $isAbsolute = (is_array($path) ? $path[0][0] : $path[0]) === '/'; - $url = $isAbsolute || null === $this->index ? '' : "/" . $this->index; + protected function buildUrl($path, array $options = []): string + { + if (is_array($path)) { + $first = (string) ($path[0] ?? ''); + $firstChar = $first !== '' ? $first[0] : ''; + } else { + $firstChar = $path[0]; + } + + $isAbsolute = $firstChar === '/'; + + $url = $isAbsolute || $this->index === null ? '' : "/{$this->index}"; if ($path && is_array($path) && count($path) > 0) { - $path = implode("/", array_filter($path)); - $url .= "/" . ltrim($path, '/'); - } - if (substr($url, -1) === "/") { - $url = substr($url, 0, -1); + $path = implode('/', array_filter($path)); + $url .= '/' . ltrim($path, '/'); } + $url = rtrim($url, '/'); + if (count($options) > 0) { - $url .= "?" . http_build_query($options, '', '&'); + $url .= (strpos($url, '?') !== false ? '&' : '?') . http_build_query($options, '', '&'); } return $url; diff --git a/src/ElasticSearch/Transport/HTTP.php b/src/ElasticSearch/Transport/HTTP.php index 95bb2e6..908109f 100755 --- a/src/ElasticSearch/Transport/HTTP.php +++ b/src/ElasticSearch/Transport/HTTP.php @@ -11,70 +11,82 @@ * file that was distributed with this source code. */ -if (!defined('CURLE_OPERATION_TIMEDOUT')) +if (!defined('CURLE_OPERATION_TIMEDOUT')) { define('CURLE_OPERATION_TIMEDOUT', 28); +} + +class HTTP + extends Base +{ -class HTTP extends Base { - /** * How long before timing out CURL call + * @var int */ private $timeout = 5; - + /** * curl handler which is needed for reusing existing http connection to the server + * * @var resource */ protected $ch; - - - public function __construct($host='localhost', $port=9200, $timeout=null) { + + public function __construct(string $host = 'localhost', int $port = 9200, int $timeout = null) + { parent::__construct($host, $port); - if(null !== $timeout) { + if (null !== $timeout) { $this->setTimeout($timeout); - } - $this->ch = curl_init(); + } } /** * Index a new document or update it if existing * + * @param array $document + * @param string|null $id Optional + * @param array $options + * * @return array - * @param array $document - * @param mixed $id Optional - * @param array $options + * @throws HTTPException */ - public function index($document, $id=false, array $options = array()) { - $url = $this->buildUrl(array($this->type, $id), $options); - $method = ($id == false) ? "POST" : "PUT"; + public function index(array $document, string $id = null, array $options = []): array + { + $url = $this->buildUrl([ $this->type, $id ], $options); + $method = ($id == false) ? 'POST' : 'PUT'; + return $this->call($url, $method, $document); } /** * Update a part of a document * - * @return array + * @param array $partialDocument + * @param string $id + * @param array $options * - * @param array $partialDocument - * @param mixed $id - * @param array $options + * @return array + * @throws HTTPException */ - public function update($partialDocument, $id, array $options = array()) { - $url = $this->buildUrl(array($this->type, $id, '_update'), $options); + public function update(array $partialDocument, string $id, array $options = []): array + { + $url = $this->buildUrl([ $this->type, $id, '_update' ], $options); - return $this->call($url, "POST", array('doc' => $partialDocument)); + return $this->call($url, "POST", [ 'doc' => $partialDocument ]); } /** * Search * - * @return array * @param array|string $query - * @param array $options + * @param array $options + * + * @return array + * @throws HTTPException */ - public function search($query, array $options = array()) { - $result = false; + public function search($query, array $options = []): array + { if (is_array($query)) { /** * Array implies using the JSON query DSL @@ -86,59 +98,63 @@ public function search($query, array $options = array()) { * or * $options['preference'] = 'xyzabc123' */ - $url = $this->buildUrl(array($this->type, $arg), $options); + $url = $this->buildUrl([ $this->type, $arg ], $options); - $result = $this->call($url, "GET", $query); - } - elseif (is_string($query)) { + $result = $this->call($url, 'GET', $query); + } elseif (is_string($query)) { /** * String based search means http query string search */ - $url = $this->buildUrl(array( - $this->type, "_search?q=" . $query - )); - $result = $this->call($url, "POST", $options); - } - else { + $url = $this->buildUrl([ + $this->type, "_search?q=" . $query, + ]); + $result = $this->call($url, 'POST', $options); + } else { /** * no http query string search */ - $url = $this->buildUrl(array( - $this->type, "_search?" - )); - $result = $this->call($url, "POST", $options); + $url = $this->buildUrl([ + $this->type, '_search?', + ]); + $result = $this->call($url, 'POST', $options); } + return $result; } /** * Search * - * @return array * @param mixed $query * @param array $options Parameters to pass to delete action + * + * @return bool + * @throws HTTPException */ - public function deleteByQuery($query, array $options = array()) { - $options += array( - 'refresh' => true - ); + public function deleteByQuery($query, array $options = []): bool + { + $options = array_merge($options, [ + 'refresh' => true, + ]); + if (is_array($query)) { /** * Array implies using the JSON query DSL */ - $url = $this->buildUrl(array($this->type, "_query")); - $result = $this->call($url, "DELETE", $query); - } - elseif (is_string($query)) { + $url = $this->buildUrl([ $this->type, '_query' ]); + $result = $this->call($url, 'DELETE', $query); + } elseif (is_string($query)) { /** * String based search means http query string search */ - $url = $this->buildUrl(array($this->type, "_query"), array('q' => $query)); - $result = $this->call($url, "DELETE"); + $url = $this->buildUrl([ $this->type, '_query' ], [ 'q' => $query ]); + $result = $this->call($url, 'DELETE'); } + if ($options['refresh']) { - $this->request('_refresh', "POST"); + $this->request('_refresh', 'POST'); } + return !isset($result['error']); } @@ -148,126 +164,151 @@ public function deleteByQuery($query, array $options = array()) { * $es->request('/_status'); * * @param string|array $path - * @param string $method - * @param array|bool $payload + * @param string $method + * @param mixed $payload + * @param array $options + * * @return array + * @throws HTTPException */ - public function request($path, $method="GET", $payload=false) { - return $this->call($this->buildUrl($path), $method, $payload); + public function request($path, string $method = 'GET', $payload = false, array $options = []): array + { + return $this->call($this->buildUrl($path, $options), $method, $payload); } - + /** * Flush this index/type combination * - * @return array - * @param mixed $id Id of document to delete + * @param mixed $id Id of document to delete * @param array $options Parameters to pass to delete action + * + * @return array + * @throws HTTPException */ - public function delete($id=false, array $options = array()) { - if ($id) - return $this->call($this->buildUrl(array($this->type, $id), $options), "DELETE"); - else - return $this->request(false, "DELETE"); + public function delete($id = false, array $options = []): array + { + if ($id) { + return $this->call($this->buildUrl([ $this->type, $id ], $options), 'DELETE'); + } + + return $this->request(false, 'DELETE'); } /** * Perform a http call against an url with an optional payload * + * @param string $url + * @param string $method (GET/POST/PUT/DELETE) + * @param array|string $payload The document/instructions to pass along + * * @return array - * @param string $url - * @param string $method (GET/POST/PUT/DELETE) - * @param array|bool $payload The document/instructions to pass along * @throws HTTPException */ - protected function call($url, $method="GET", $payload=null) { - $conn = $this->ch; - $protocol = "http"; + protected function call(string $url, string $method = 'GET', $payload = null): array + { + $conn = $this->getConnection(); + + $protocol = 'http'; $requestURL = $protocol . "://" . $this->host . $url; curl_setopt($conn, CURLOPT_URL, $requestURL); curl_setopt($conn, CURLOPT_TIMEOUT, $this->timeout); curl_setopt($conn, CURLOPT_PORT, $this->port); curl_setopt($conn, CURLOPT_CUSTOMREQUEST, strtoupper($method)); - curl_setopt($conn, CURLOPT_FORBID_REUSE , 0) ; - - $headers = array(); - $headers[] = 'Accept: application/json'; - $headers[] = 'Content-Type: application/json'; - - curl_setopt($conn, CURLOPT_HTTPHEADER, $headers); - - if (is_array($payload) && count($payload) > 0) - curl_setopt($conn, CURLOPT_POSTFIELDS, json_encode($payload)) ; - else - curl_setopt($conn, CURLOPT_POSTFIELDS, $payload); - - // cURL opt returntransfer leaks memory, therefore OB instead. - ob_start(); - curl_exec($conn); - $response = ob_get_clean(); - if ($response !== false) { + curl_setopt($conn, CURLOPT_FORBID_REUSE, 0); + curl_setopt($conn, CURLOPT_RETURNTRANSFER, true); + + curl_setopt($conn, CURLOPT_HTTPHEADER, [ + 'Accept: application/json', + 'Content-Type: application/json' + ]); + + if (is_array($payload) && count($payload) > 0) { + curl_setopt($conn, CURLOPT_POSTFIELDS, json_encode($payload)); + } else { + curl_setopt($conn, CURLOPT_POSTFIELDS, $payload); + } + + $response = curl_exec($conn); + + if (!empty($response)) { $data = json_decode($response, true); + if (!$data && $this->fixUnicode && json_last_error() === JSON_ERROR_UTF16) { + $data = json_decode(preg_replace('/\\\\uD[89A-F][0-9A-F]{2}/i', '', $response), true); + } if (!$data) { - $data = array('error' => $response, "code" => curl_getinfo($conn, CURLINFO_HTTP_CODE)); + $data = [ 'error' => $response, 'code' => curl_getinfo($conn, CURLINFO_HTTP_CODE) ]; } - } - else { + } else { /** * cUrl error code reference can be found here: * http://curl.haxx.se/libcurl/c/libcurl-errors.html */ $errno = curl_errno($conn); - switch ($errno) - { + switch ($errno) { case CURLE_UNSUPPORTED_PROTOCOL: - $error = "Unsupported protocol [$protocol]"; + $error = "Unsupported protocol [{$protocol}]"; break; case CURLE_FAILED_INIT: $error = "Internal cUrl error?"; break; case CURLE_URL_MALFORMAT: - $error = "Malformed URL [$requestURL] -d " . json_encode($payload); + $error = "Malformed URL [{$requestURL}] -d " . json_encode($payload); break; case CURLE_COULDNT_RESOLVE_PROXY: - $error = "Couldnt resolve proxy"; + $error = "Couldn't resolve proxy"; break; case CURLE_COULDNT_RESOLVE_HOST: - $error = "Couldnt resolve host"; + $error = "Couldn't resolve host"; break; case CURLE_COULDNT_CONNECT: - $error = "Couldnt connect to host [{$this->host}], ElasticSearch down?"; + $error = "Couldn't connect to host [{$this->host}], ElasticSearch down?"; break; case CURLE_OPERATION_TIMEDOUT: - $error = "Operation timed out on [$requestURL]"; + $error = "Operation timed out on [{$requestURL}]"; break; default: $error = "Unknown error"; if ($errno == 0) { $error .= ". Non-cUrl error"; } else { - $errstr = curl_error($conn); - $error .= " ($errstr)"; + $errStr = curl_error($conn); + $error .= " ({$errStr})"; } break; } + $exception = new HTTPException($error); $exception->payload = $payload; $exception->port = $this->port; $exception->protocol = $protocol; $exception->host = $this->host; $exception->method = $method; + $exception->url = $url; + throw $exception; } return $data; } - public function setTimeout($timeout) + public function setTimeout(int $timeout) { $this->timeout = $timeout; } - public function getTimeout() + public function getTimeout(): int { return $this->timeout; } + + /** + * Get connection + * + * @return resource + */ + private function getConnection() + { + // TODO: Now always return new handler. Rewrite to forkManager in future + return curl_init(); + } } diff --git a/src/ElasticSearch/Transport/HTTPException.php b/src/ElasticSearch/Transport/HTTPException.php index f0556de..57573bd 100644 --- a/src/ElasticSearch/Transport/HTTPException.php +++ b/src/ElasticSearch/Transport/HTTPException.php @@ -9,6 +9,12 @@ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. + * @property mixed $payload + * @property mixed $port + * @property mixed $protocol + * @property mixed $host + * @property mixed $method + * @property mixed $url */ class HTTPException extends \Exception { @@ -27,33 +33,41 @@ class HTTPException extends \Exception { /** * Setter + * * @param mixed $key * @param mixed $value */ - public function __set($key, $value) { - if (array_key_exists($key, $this->data)) + public function __set($key, $value): void + { + if (array_key_exists($key, $this->data)) { $this->data[$key] = $value; + } } /** * Getter + * * @param mixed $key + * * @return mixed */ - public function __get($key) { - if (array_key_exists($key, $this->data)) + public function __get($key) + { + if (array_key_exists($key, $this->data)) { return $this->data[$key]; - else - return false; + } + + return false; } /** * Rebuild CLI command using curl to further investigate the failure * @return string */ - public function getCLICommand() { + public function getCLICommand(): string + { $postData = json_encode($this->payload); - $curlCall = "curl -X{$method} 'http://{$this->host}:{$this->port}$this->url' -d '$postData'"; - return $curlCall; + + return "curl -X{$this->method} '{$this->protocol}://{$this->host}:{$this->port}{$this->url}' -d '{$postData}'"; } } diff --git a/src/ElasticSearch/Transport/Memcached.php b/src/ElasticSearch/Transport/Memcached.php deleted file mode 100755 index 8e4b2a0..0000000 --- a/src/ElasticSearch/Transport/Memcached.php +++ /dev/null @@ -1,131 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -class Memcached extends Base { - public function __construct($host="127.0.0.1", $port=11311, $timeout=null) { - parent::__construct($host, $port); - $this->conn = new Memcache; - $this->conn->connect($host, $port, $timeout); - } - - /** - * Index a new document or update it if existing - * - * @return array - * @param array $document - * @param mixed $id Optional - * @param array $options - * @throws \ElasticSearch\Exception - */ - public function index($document, $id=false, array $options = array()) { - if ($id === false) - throw new \ElasticSearch\Exception("Memcached transport requires id when indexing"); - - $document = json_encode($document); - $url = $this->buildUrl(array($this->type, $id)); - $response = $this->conn->set($url, $document); - return array( - 'ok' => $response - ); - } - - /** - * Update a part of a document - * - * @return array - * @param array $partialDocument - * @param mixed $id - * @param array $options - */ - public function update($partialDocument, $id, array $options = array()) { - $document = json_encode(array('doc' => $partialDocument)); - $url = $this->buildUrl(array($this->type, $id)); - $response = $this->conn->set($url, $document); - - return array( - 'ok' => $response, - ); - } - - /** - * Search - * - * @return array - * @param array|string $query - * @throws \ElasticSearch\Exception - */ - public function search($query) { - if (is_array($query)) { - if (array_key_exists("query", $query)) { - $dsl = new Stringify($query); - $q = (string) $dsl; - $url = $this->buildUrl(array( - $this->type, "_search?q=" . $q - )); - $result = json_decode($this->conn->get($url), true); - return $result; - } - throw new \ElasticSearch\Exception("Memcached protocol doesnt support the full DSL, only query"); - } - elseif (is_string($query)) { - /** - * String based search means http query string search - */ - $url = $this->buildUrl(array( - $this->type, "_search?q=" . $query - )); - $result = json_decode($this->conn->get($url), true); - return $result; - } - } - - /** - * Perform a request against the given path/method/payload combination - * Example: - * $es->request('/_status'); - * - * @param string|array $path - * @param string $method - * @param array|bool $payload - * @return array - */ - public function request($path, $method="GET", $payload=false) { - $url = $this->buildUrl($path); - switch ($method) { - case 'GET': - $result = $this->conn->get($url); - break; - case 'DELETE': - $result = $this->conn->delete($url); - break; - } - return json_decode($result); - } - - /** - * Flush this index/type combination - * - * @return array - * @param mixed $id - * @param array $options Parameters to pass to delete action - */ - public function delete($id=false, array $options = array()) { - if ($id) - return $this->request(array($this->type, $id), "DELETE"); - else - return $this->request(false, "DELETE"); - } -} diff --git a/tests/install-php-memcache.sh b/tests/install-php-memcache.sh deleted file mode 100644 index 208e161..0000000 --- a/tests/install-php-memcache.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -wget http://pecl.php.net/get/memcache-2.2.6.tgz -tar -xzf memcache-2.2.6.tgz -sh -c "cd memcache-2.2.6 && phpize && ./configure --enable-memcache && make && sudo make install" -echo "extension=memcache.so" >> `php --ini | grep "Loaded Configuration" | sed -e "s|.*:\s*||"` -exit diff --git a/tests/units/Mapping.php b/tests/units/Mapping.php deleted file mode 100644 index b702c2d..0000000 --- a/tests/units/Mapping.php +++ /dev/null @@ -1,104 +0,0 @@ -setIndex('test-index')->delete(); - \ElasticSearch\Client::connection()->delete(); - } - - public function testMapCreate() { - $mapping = new \ElasticSearch\Mapping(array( - 'tweet' => array( - 'type' => 'string' - ), - 'user.name' => array( - 'index' => 'not_analyzed' - ) - )); - - $jsonBody = $mapping->export(); - - $this->assert->array($jsonBody) - ->isNotEmpty() - ->hasSize(1) - ->array($jsonBody['properties']) - ->hasSize(2); - - $properties = $jsonBody['properties']; - - $this->assert->array($properties['tweet']) - ->isNotEmpty() - ->isEqualTo(array( - 'type' => 'string' - )); - - $this->assert->array($properties['user.name']) - ->isNotEmpty() - ->isEqualTo(array( - 'index' => 'not_analyzed' - )); - } - - public function testAddMoreFieldsToMapping() { - $mapping = new \ElasticSearch\Mapping; - - $exported = $mapping->field('tweet', array( - 'type' => 'string' - ))->export(); - - // TODO Does atoum have a prettier interface for this drill down? - $this->assert->array($exported)->isNotEmpty() - ->isEqualTo(array( - 'properties' => array( - 'tweet' => array('type' => 'string') - ) - )); - } - - public function testAddFieldWithTypeLazy() { - $mapping = new \ElasticSearch\Mapping; - // Basic mappings: - $exported = $mapping->field('tweet', 'string')->export(); - $this->assert->array($exported)->isNotEmpty() - ->isEqualTo(array( - 'properties' => array( - 'tweet' => array('type' => 'string') - ) - )); - } - - public function testAddTypeConstrainedMapping() { - $mapping = new \ElasticSearch\Mapping(array( - 'tweet' => array( - 'type' => 'string' - ) - ), array('type' => 'tweet')); - - $exported = $mapping->export(); - $this->assert->array($exported)->isNotEmpty() - ->hasKey('properties')->notHasKey('type'); - } - - // Integrate and perform query - public function testMapFields() { - $client = \ElasticSearch\Client::connection(array( - 'index' => 'test-index', - 'type' => 'test-type' - )); - $client->index(array( - 'tweet' => 'ElasticSearch is awesome' - )); - $response = $client->map(array( - 'tweet' => array('type' => 'string') - )); - - $this->assert->array($response)->isNotEmpty(); - } -}