From fdd80e2a5a7fb02bdb00f896f325454b82bb3426 Mon Sep 17 00:00:00 2001 From: dieterve Date: Fri, 21 Aug 2015 15:53:13 +0200 Subject: [PATCH 1/4] Fragments: allow setting of the body via dotted notation. --- src/Abstracts/AbstractFragment.php | 17 +++++++++++++++++ tests/Abstracts/AbstractFragmentTest.php | 15 +++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 tests/Abstracts/AbstractFragmentTest.php diff --git a/src/Abstracts/AbstractFragment.php b/src/Abstracts/AbstractFragment.php index ef8cdc7..b7f4416 100644 --- a/src/Abstracts/AbstractFragment.php +++ b/src/Abstracts/AbstractFragment.php @@ -2,6 +2,8 @@ namespace ElasticSearcher\Abstracts; +use Illuminate\Support\Arr; + /** * Base class for fragments that can be used in the body of requests to Elasticsearch. */ @@ -39,4 +41,19 @@ public function getBody() { return $this->body; } + + /** + * Set a value in the body using the dotted notation. + * + * @param string $key + * @param mixed $value + * + * @return $this + */ + public function set($key, $value) + { + Arr::set($this->body, $key, $value); + + return $this; + } } diff --git a/tests/Abstracts/AbstractFragmentTest.php b/tests/Abstracts/AbstractFragmentTest.php new file mode 100644 index 0000000..ceedb33 --- /dev/null +++ b/tests/Abstracts/AbstractFragmentTest.php @@ -0,0 +1,15 @@ +getMockForAbstractClass(ElasticSearcher\Abstracts\AbstractFragment::class); + + $stub->set('key', 'value'); + $this->assertEquals(['key' => 'value'], $stub->getBody()); + + $stub->set('key.nested', 'value'); + $this->assertEquals(['key' => ['nested' => 'value']], $stub->getBody()); + } +} From f7325cd55ed0addb72a3b1302b34079a8e52d465 Mon Sep 17 00:00:00 2001 From: dieterve Date: Fri, 11 Sep 2015 14:30:44 +0200 Subject: [PATCH 2/4] Extract body related actions to a trait. --- src/Abstracts/AbstractFragment.php | 41 +----------------- src/Abstracts/AbstractQuery.php | 18 ++------ src/Traits/BodyTrait.php | 53 ++++++++++++++++++++++++ tests/Abstracts/AbstractFragmentTest.php | 15 ------- tests/Traits/BodyTraitTest.php | 17 ++++++++ 5 files changed, 75 insertions(+), 69 deletions(-) create mode 100644 src/Traits/BodyTrait.php delete mode 100644 tests/Abstracts/AbstractFragmentTest.php create mode 100644 tests/Traits/BodyTraitTest.php diff --git a/src/Abstracts/AbstractFragment.php b/src/Abstracts/AbstractFragment.php index b7f4416..9661839 100644 --- a/src/Abstracts/AbstractFragment.php +++ b/src/Abstracts/AbstractFragment.php @@ -2,20 +2,14 @@ namespace ElasticSearcher\Abstracts; -use Illuminate\Support\Arr; +use ElasticSearcher\Traits\BodyTrait; /** * Base class for fragments that can be used in the body of requests to Elasticsearch. */ abstract class AbstractFragment { - /** - * Body of the fragment to be executed. Should be the array as if you would pass it - * directly to the ElasticSearcher SDK. - * - * @var array - */ - protected $body; + use BodyTrait; /** * Should this fragment be merged with its parent, or simply be replaced. @@ -25,35 +19,4 @@ abstract class AbstractFragment * @var bool */ public $mergeWithParent = false; - - /** - * @param array $body - */ - public function setBody(array $body) - { - $this->body = $body; - } - - /** - * @return array - */ - public function getBody() - { - return $this->body; - } - - /** - * Set a value in the body using the dotted notation. - * - * @param string $key - * @param mixed $value - * - * @return $this - */ - public function set($key, $value) - { - Arr::set($this->body, $key, $value); - - return $this; - } } diff --git a/src/Abstracts/AbstractQuery.php b/src/Abstracts/AbstractQuery.php index 41772c5..c681acc 100644 --- a/src/Abstracts/AbstractQuery.php +++ b/src/Abstracts/AbstractQuery.php @@ -5,12 +5,15 @@ use ElasticSearcher\ElasticSearcher; use ElasticSearcher\Parsers\ArrayResultParser; use ElasticSearcher\Parsers\FragmentParser; +use ElasticSearcher\Traits\BodyTrait; /** * Base class for queries. */ abstract class AbstractQuery { + use BodyTrait; + /** * @var ElasticSearcher */ @@ -30,13 +33,6 @@ abstract class AbstractQuery */ protected $types = []; - /** - * Body of the query to execute. - * - * @var array - */ - protected $body = []; - /** * Data that can be used when building a query. * @@ -142,14 +138,6 @@ protected function searchInTypes(array $types) $this->types = array_unique($this->types); } - /** - * @param array $body - */ - protected function setBody(array $body) - { - $this->body = $body; - } - /** * Build the query by adding all chunks together. * diff --git a/src/Traits/BodyTrait.php b/src/Traits/BodyTrait.php new file mode 100644 index 0000000..efd4e52 --- /dev/null +++ b/src/Traits/BodyTrait.php @@ -0,0 +1,53 @@ +body = $body; + } + + /** + * Set a value in the body using the dotted notation. + * + * @param string $key + * @param mixed $value + * + * @return $this + */ + public function set($key, $value) + { + Arr::set($this->body, $key, $value); + + return $this; + } + + /** + * @return array + */ + public function getBody() + { + return $this->body; + } +} diff --git a/tests/Abstracts/AbstractFragmentTest.php b/tests/Abstracts/AbstractFragmentTest.php deleted file mode 100644 index ceedb33..0000000 --- a/tests/Abstracts/AbstractFragmentTest.php +++ /dev/null @@ -1,15 +0,0 @@ -getMockForAbstractClass(ElasticSearcher\Abstracts\AbstractFragment::class); - - $stub->set('key', 'value'); - $this->assertEquals(['key' => 'value'], $stub->getBody()); - - $stub->set('key.nested', 'value'); - $this->assertEquals(['key' => ['nested' => 'value']], $stub->getBody()); - } -} diff --git a/tests/Traits/BodyTraitTest.php b/tests/Traits/BodyTraitTest.php new file mode 100644 index 0000000..ebe17c9 --- /dev/null +++ b/tests/Traits/BodyTraitTest.php @@ -0,0 +1,17 @@ +getMockForTrait(BodyTrait::class); + + $mock->set('key', 'value'); + $this->assertEquals(['key' => 'value'], $mock->getBody()); + + $mock->set('key.nested', 'value'); + $this->assertEquals(['key' => ['nested' => 'value']], $mock->getBody()); + } +} From aff13fde1d4a36989ad01d7bbb2edacae3a11871 Mon Sep 17 00:00:00 2001 From: dieterve Date: Fri, 11 Sep 2015 15:33:36 +0200 Subject: [PATCH 3/4] Indices: simplify and allign index building. Refactored so it uses the same methology of query building or fragment building. This should simplify it and make it clearer. I also believe its more flexibel. --- docs/index-management.md | 41 ++++++++----------- src/Abstracts/AbstractIndex.php | 50 +++++++++++++++++------ src/Traits/BodyTrait.php | 19 +++++++-- tests/dummy/Indexes/AuthorsIndex.php | 42 ++++++++----------- tests/dummy/Indexes/MoviesIndex.php | 26 +++++------- tests/dummy/Queries/MovieWithIDXQuery.php | 12 +----- 6 files changed, 98 insertions(+), 92 deletions(-) diff --git a/docs/index-management.md b/docs/index-management.md index 63809b9..b73b9ee 100644 --- a/docs/index-management.md +++ b/docs/index-management.md @@ -1,7 +1,7 @@ # Index Management The package includes an indices manager. You are required to register indices that you'll using, whether its for -CRUD on the indices or for quering. The index manager is accessed via: +CRUD on the indices or for querying. The index manager is accessed via: ```php $manager = $searcher->indicesManager(); @@ -20,33 +20,28 @@ class SuggestionsIndex extends \ElasticSearcher\Abstracts\AbstractIndex return 'suggestions'; } - public function getTypes() + public function setup() { - return array( - 'books' => array( - 'properties' => array( - 'id' => array( - 'type' => 'integer' - ), - 'name' => array( - 'type' => 'string' - ) - ) - ), - 'movies' => array( - 'properties' => array( - 'name' => array( - 'type' => 'string' - ) - ) - ) - ); + $this->setTypes([ + 'books' => [ + 'properties' => [ + 'id' => ['type' => 'integer'], + 'name' => ['type' => 'string'], + ] + ], + 'movies' => [ + 'properties' => [ + 'name' => ['type' => 'string'], + ] + ] + ]); } } ``` -This the minimum required for defining an index. If you require more extensive configuration, override the `getBody` -method. +This the minimum required for defining an index. Inside the `setup()` method you can setup your index further, +for example adding settings, aggregations, .... An index is [body aware](https://github.com/madewithlove/elasticsearcher/tree/master/src/Traits/BodyTrait.php) +for easy manipulation. ### Using re-useable fragments diff --git a/src/Abstracts/AbstractIndex.php b/src/Abstracts/AbstractIndex.php index d35ac1c..6d10c72 100644 --- a/src/Abstracts/AbstractIndex.php +++ b/src/Abstracts/AbstractIndex.php @@ -3,12 +3,15 @@ namespace ElasticSearcher\Abstracts; use ElasticSearcher\Parsers\FragmentParser; +use ElasticSearcher\Traits\BodyTrait; /** * Base class for indexes. */ abstract class AbstractIndex { + use BodyTrait; + /** * @var FragmentParser */ @@ -22,13 +25,15 @@ abstract public function getName(); /** * @return array */ - abstract public function getTypes(); + abstract public function setup(); /** */ public function __construct() { $this->fragmentParser = new FragmentParser(); + + $this->setup(); } /** @@ -36,15 +41,36 @@ public function __construct() */ public function getBody() { - $body = [ - 'settings' => $this->getSettings(), - 'mappings' => $this->getTypes(), - ]; - // Replace fragments with their raw body. - $body = $this->fragmentParser->parse($body); + return $this->fragmentParser->parse($this->body); + } + + /** + * @param array $types + * + * @return array + */ + public function setTypes(array $types) + { + return $this->set('mappings', $types); + } + + /** + * @return array + */ + public function getTypes() + { + return $this->get('mappings'); + } - return $body; + /** + * @param array $settings + * + * @return array + */ + public function setSettings(array $settings) + { + return $this->set('settings', $settings); } /** @@ -52,18 +78,16 @@ public function getBody() */ public function getSettings() { - return null; + return $this->get('settings'); } /** * @param string $type * - * @return mixed + * @return array */ public function getType($type) { - $types = $this->getTypes(); - - return $types[$type]; + return $this->get('mappings.'.$type); } } diff --git a/src/Traits/BodyTrait.php b/src/Traits/BodyTrait.php index efd4e52..ceabc58 100644 --- a/src/Traits/BodyTrait.php +++ b/src/Traits/BodyTrait.php @@ -28,6 +28,14 @@ public function setBody(array $body) $this->body = $body; } + /** + * @return array + */ + public function getBody() + { + return $this->body; + } + /** * Set a value in the body using the dotted notation. * @@ -44,10 +52,15 @@ public function set($key, $value) } /** - * @return array + * Get a value in the body using the dotted notation. + * + * @param string $key + * @param mixed $default + * + * @return $this */ - public function getBody() + public function get($key, $default = null) { - return $this->body; + return Arr::get($this->body, $key, $default); } } diff --git a/tests/dummy/Indexes/AuthorsIndex.php b/tests/dummy/Indexes/AuthorsIndex.php index 5859e03..ac2dc2f 100644 --- a/tests/dummy/Indexes/AuthorsIndex.php +++ b/tests/dummy/Indexes/AuthorsIndex.php @@ -9,32 +9,22 @@ public function getName() return 'authors'; } - public function getTypes() + public function setup() { - return array( - 'directors' => array( - 'properties' => array( - 'id' => array( - 'type' => 'integer' - ), - 'first_name' => array( - 'type' => 'string' - ), - 'last_name' => array( - 'type' => 'string' - ) - ) - ), - 'producers' => array( - 'properties' => array( - 'id' => array( - 'type' => 'integer' - ), - 'name' => array( - 'type' => 'string' - ) - ) - ) - ); + $this->setTypes([ + 'directors' => [ + 'properties' => [ + 'id' => ['type' => 'integer'], + 'first_name' => ['type' => 'string'], + 'last_name' => ['type' => 'string'] + ] + ], + 'producers' => [ + 'properties' => [ + 'id' => ['type' => 'integer'], + 'name' => ['type' => 'string'] + ] + ] + ]); } } diff --git a/tests/dummy/Indexes/MoviesIndex.php b/tests/dummy/Indexes/MoviesIndex.php index bc26ceb..a59573a 100644 --- a/tests/dummy/Indexes/MoviesIndex.php +++ b/tests/dummy/Indexes/MoviesIndex.php @@ -9,22 +9,16 @@ public function getName() return 'movies'; } - public function getTypes() + public function setup() { - return array( - 'movies' => array( - 'properties' => array( - 'id' => array( - 'type' => 'integer' - ), - 'name' => array( - 'type' => 'string' - ), - 'year' => array( - 'type' => 'integer', - ) - ) - ) - ); + $this->setTypes([ + 'movies' => [ + 'properties' => [ + 'id' => ['type' => 'integer'], + 'name' => ['type' => 'string'], + 'year' => ['type' => 'integer'], + ] + ] + ]); } } diff --git a/tests/dummy/Queries/MovieWithIDXQuery.php b/tests/dummy/Queries/MovieWithIDXQuery.php index c6e0aa4..453c644 100644 --- a/tests/dummy/Queries/MovieWithIDXQuery.php +++ b/tests/dummy/Queries/MovieWithIDXQuery.php @@ -8,16 +8,6 @@ public function setup() { $this->searchIn('movies', 'movies'); - $body = array( - 'query' => array( - 'filtered' => array( - 'filter' => array( - new IDFilter($this->getData('id')) - ) - ) - ) - ); - - $this->setBody($body); + $this->set('query.filtered.filter', [new IDFilter($this->getData('id'))]); } } From 82992a2b935622a07e8e0ee1e65315be76628853 Mon Sep 17 00:00:00 2001 From: dieterve Date: Fri, 11 Sep 2015 15:42:22 +0200 Subject: [PATCH 4/4] Update docs to include dotted notation. This makes them much more readable as well. --- README.md | 37 +++++++---------- docs/index-management.md | 4 +- docs/query-building.md | 46 ++++++++------------- docs/re-useable-fragments.md | 3 ++ tests/dummy/Queries/MoviesFrom2014Query.php | 12 +----- 5 files changed, 38 insertions(+), 64 deletions(-) diff --git a/README.md b/README.md index 6f14ff9..14b8f7b 100644 --- a/README.md +++ b/README.md @@ -26,19 +26,20 @@ class MoviesFrom2014Query extends AbstractQuery { $this->searchIn('movies', 'movies'); - $body = array( - 'query' => array( - 'filtered' => array( - 'filter' => array( - 'term' => array( - 'year' => 2014 - ) - ) - ) - ) - ); - + // Full notation + $body = [ + 'query' => [ + 'filtered' => [ + 'filter' => [ + 'term' => ['year' => 2014] + ] + ] + ] + ]; $this->setBody($body); + + // Short (dotted) notation + $this->set('query.filtered.filter.term.year', 2014); } } @@ -58,17 +59,7 @@ class MoviesFrom2014Query extends AbstractQuery { $this->searchIn('movies', 'movies'); - $body = array( - 'query' => array( - 'filtered' => array( - 'filter' => array( - new YearFilter(2014) - ) - ) - ) - ); - - $this->setBody($body); + $this->set('query.filtered.filter', [new YearFilter(2014)]); } } ``` diff --git a/docs/index-management.md b/docs/index-management.md index b73b9ee..606e567 100644 --- a/docs/index-management.md +++ b/docs/index-management.md @@ -60,9 +60,9 @@ $suggestionsIndex = new SuggestionsIndex(); $searcher->indicesManager()->register($suggestionsIndex); // Grouped registration -$indices = array( +$indices = [ $suggestionsIndex -); +]; $searcher->indicesManager()->registerIndices($indices); // Other diff --git a/docs/query-building.md b/docs/query-building.md index bcb007c..1765cab 100644 --- a/docs/query-building.md +++ b/docs/query-building.md @@ -31,8 +31,9 @@ var_dump($result->getResults()); ## Body building -Inside your Query class you can build the body of the query however you like. We only require you to call `setBody` with -the body array. Here are some examples. +Inside your Query class you can build the body of the query however you like. A query is +[body aware](https://github.com/madewithlove/elasticsearcher/tree/master/src/Traits/BodyTrait.php) +for easy manipulation. Here are some examples. Basic example: @@ -45,19 +46,20 @@ class MoviesYouMightLikeQuery extends QueryAbstract { $this->searchIn('suggestions', 'movies'); - $body = array( - 'query' => array( - 'filtered' => array( - 'filter' => array( - 'term' => array( - 'status' => 'active' - ) - ) - ) - ) - ); - - $this->setBody($body); + // Long notation + $body = [ + 'query' => [ + 'filtered' => [ + 'filter' => [ + 'term' => ['status' => 'active'] + ] + ] + ] + ]; + $this->setBody($body); + + // Short dotted notation + $this->set('query.filtered.filter.term.status', 'active'); } } ``` @@ -73,19 +75,7 @@ class MoviesYouMightLikeQuery extends AbstractQuery { $this->searchIn('suggestions', 'movies'); - $body = array( - 'query' => array( - 'filtered' => array( - 'filter' => array( - 'term' => array( - 'status' => $this->getData('status') - ) - ) - ) - ) - ); - - $this->setBody($body); + $this->set('query.filtered.filter.term.status', $this->getData('status')); } } ``` diff --git a/docs/re-useable-fragments.md b/docs/re-useable-fragments.md index 2d2b7c2..5fc136f 100644 --- a/docs/re-useable-fragments.md +++ b/docs/re-useable-fragments.md @@ -5,6 +5,9 @@ comes with a build-in set of fragments but you are encouraged to build your own. For example: `BookingRangeFilter(date, date)`, `MovieIDFilter(int)`, .... As long as they extend `ElasticSearcher\Abstracts\AbstractFragment` they can be used in queries or indices. +A fragment is [body aware](https://github.com/madewithlove/elasticsearcher/tree/master/src/Traits/BodyTrait.php) +for easy manipulation. + ## Examples ```php diff --git a/tests/dummy/Queries/MoviesFrom2014Query.php b/tests/dummy/Queries/MoviesFrom2014Query.php index 1f1a034..aa4cacd 100644 --- a/tests/dummy/Queries/MoviesFrom2014Query.php +++ b/tests/dummy/Queries/MoviesFrom2014Query.php @@ -9,16 +9,6 @@ public function setup() { $this->searchIn('movies', 'movies'); - $body = array( - 'query' => array( - 'filtered' => array( - 'filter' => array( - new TermFilter('year', 2014) - ) - ) - ) - ); - - $this->setBody($body); + $this->set('query.filtered.filter', [new TermFilter('year', 2014)]); } }