diff --git a/DSL/Filter/NestedFilter.php b/DSL/Filter/NestedFilter.php new file mode 100644 index 00000000..bba9a974 --- /dev/null +++ b/DSL/Filter/NestedFilter.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace ONGR\ElasticsearchBundle\DSL\Filter; + +use ONGR\ElasticsearchBundle\DSL\BuilderInterface; +use ONGR\ElasticsearchBundle\DSL\ParametersTrait; + +/** + * Nested filter implementation. + */ +class NestedFilter implements BuilderInterface +{ + use ParametersTrait; + + /** + * @var string + */ + private $path; + + /** + * @var BuilderInterface + */ + private $query; + + /** + * @var array + */ + private $parameters; + + /** + * @param string $path + * @param BuilderInterface $query + * @param array $parameters + */ + public function __construct($path, BuilderInterface $query, array $parameters = []) + { + $this->path = $path; + $this->query = $query; + $this->parameters = $parameters; + } + + /** + * {@inheritdoc} + */ + public function getType() + { + return 'nested'; + } + + /** + * {@inheritdoc} + */ + public function toArray() + { + $query = [ + 'path' => $this->path, + 'filter' => [ + $this->query->getType() => $this->query->toArray(), + ], + ]; + + $output = $this->processArray($query); + + return $output; + } +} diff --git a/Tests/Functional/DSL/Filter/NestedFilterTest.php b/Tests/Functional/DSL/Filter/NestedFilterTest.php new file mode 100644 index 00000000..58922329 --- /dev/null +++ b/Tests/Functional/DSL/Filter/NestedFilterTest.php @@ -0,0 +1,156 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace ONGR\ElasticsearchBundle\Tests\Functional\DSL\Filter; + +use ONGR\ElasticsearchBundle\DSL\BuilderInterface; +use ONGR\ElasticsearchBundle\DSL\Filter\MatchAllFilter; +use ONGR\ElasticsearchBundle\DSL\Filter\NestedFilter; +use ONGR\ElasticsearchBundle\DSL\Filter\RangeFilter; +use ONGR\ElasticsearchBundle\DSL\Filter\TermsFilter; +use ONGR\ElasticsearchBundle\ORM\Repository; +use ONGR\ElasticsearchBundle\Test\AbstractElasticsearchTestCase; + +/** + * Nested Filter functional test. + */ +class NestedFilterTest extends AbstractElasticsearchTestCase +{ + /** + * {@inheritdoc} + */ + protected function getDataArray() + { + return [ + 'default' => [ + 'product' => [ + [ + 'sub_product' => [ + '_id' => 1, + 'title' => 'foo', + 'price' => 10, + ], + ], + [ + 'sub_product' => [ + '_id' => 2, + 'title' => 'bar', + 'price' => 100, + ], + ], + [ + 'sub_product' => [ + '_id' => 3, + 'title' => 'baz', + 'price' => 1000, + ], + ], + ], + ], + ]; + } + + /** + * Data provider for testNestedFilter. + * + * @return array + */ + public function getTestNestedFilterData() + { + $out = []; + $testData = $this->getDataArray(); + + $mapping = [ + 'product' => [ + 'properties' => [ + 'sub_product' => [ + 'type' => 'nested', + 'properties' => [ + 'id' => [ + 'type' => 'string', + 'index' => 'not_analyzed', + ], + 'title' => [ + 'type' => 'string', + ], + 'price' => [ + 'type' => 'float', + ], + ], + ], + ], + ], + ]; + + // Case #0: Test range. + $query = new NestedFilter('sub_product', new RangeFilter('sub_product.price', ['from' => 100])); + + $out[] = [ + $query, + [ + $testData['default']['product'][2], + $testData['default']['product'][1], + ], + $mapping, + ]; + + // Case #1: Test MatchAll with no data. + $query = new NestedFilter('sub_product', new MatchAllFilter()); + + $out[] = [ + $query, + [ + $testData['default']['product'][1], + $testData['default']['product'][2], + $testData['default']['product'][0], + ], + $mapping, + ]; + + // Case #2: Test terms filter. + $query = new NestedFilter( + 'sub_product', + new TermsFilter('sub_product.title', ['foo']), + ['_cache' => true, '_name' => 'named'] + ); + + $out[] = [$query, [$testData['default']['product'][0]], $mapping]; + + return $out; + } + + /** + * Test NestedFilter for expected search results. + * + * @param BuilderInterface $query + * @param array $expected + * @param array $mapping + * + * @dataProvider getTestNestedFilterData + */ + public function testNestedFilter($query, $expected, $mapping) + { + /** @var Repository $repo */ + $repo = $this->getManager('default', true, $mapping)->getRepository('AcmeTestBundle:Product'); + $search = $repo->createSearch()->addFilter($query, 'must'); + $results = $repo->execute($search, Repository::RESULTS_ARRAY); + + sort($results); + sort($expected); + $this->assertEquals($expected, $results); + + $search = $repo->createSearch()->addFilter($query); + $results = $repo->execute($search, Repository::RESULTS_ARRAY); + + sort($results); + $this->assertEquals($expected, $results); + } +} diff --git a/Tests/Unit/DSL/Filter/NestedFilterTest.php b/Tests/Unit/DSL/Filter/NestedFilterTest.php new file mode 100644 index 00000000..1e27ad8d --- /dev/null +++ b/Tests/Unit/DSL/Filter/NestedFilterTest.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace ONGR\ElasticsearchBundle\Tests\Unit\DSL\Filter; + +use ONGR\ElasticsearchBundle\DSL\Filter\NestedFilter; +use ONGR\ElasticsearchBundle\DSL\Filter\TermFilter; +use ONGR\ElasticsearchBundle\DSL\Filter\TermsFilter; + +class NestedFilterTest extends \PHPUnit_Framework_TestCase +{ + /** + * Tests GetType method. + */ + public function testGetType() + { + $filter = new NestedFilter('', new TermFilter('foo', 'bar')); + $this->assertEquals('nested', $filter->getType()); + } + + /** + * Data provider to testGetToArray. + * + * @return array + */ + public function getArrayDataProvider() + { + $filter = [ + 'terms' => [ + 'foo' => 'bar', + ], + ]; + + return [ + // Case #0 Basic filter. + [ + 'product.sub_item', + [], + ['path' => 'product.sub_item', 'filter' => $filter], + ], + // Case #1 with parameters. + [ + 'product.sub_item', + ['_cache' => true, '_name' => 'named_result'], + [ + 'path' => 'product.sub_item', + 'filter' => $filter, + '_cache' => true, + '_name' => 'named_result', + ], + ], + ]; + } + + /** + * Test for filter toArray() method. + * + * @param string $path + * @param array $parameters + * @param array $expected + * + * @dataProvider getArrayDataProvider + */ + public function testToArray($path, $parameters, $expected) + { + $query = new TermsFilter('foo', 'bar'); + $filter = new NestedFilter($path, $query, $parameters); + $result = $filter->toArray(); + $this->assertEquals($expected, $result); + } +}