From 83e27ede93ab9f48a4c5d455cfa32392f4729d34 Mon Sep 17 00:00:00 2001 From: Karel Souffriau Date: Thu, 4 Apr 2013 15:44:42 +0200 Subject: [PATCH 001/447] Require PropertyAccess component --- .../AbstractElasticaToModelTransformer.php | 29 ++++++++++++---- Propel/ElasticaToModelTransformer.php | 31 +++++++++++++---- Resources/config/config.xml | 6 +++- Resources/config/mongodb.xml | 3 ++ Resources/config/orm.xml | 3 ++ Resources/config/propel.xml | 3 ++ Tests/Persister/ObjectPersisterTest.php | 5 +-- .../ModelToElasticaAutoTransformerTest.php | 12 ++----- .../ModelToElasticaAutoTransformer.php | 33 ++++--------------- composer.json | 2 +- 10 files changed, 71 insertions(+), 56 deletions(-) diff --git a/Doctrine/AbstractElasticaToModelTransformer.php b/Doctrine/AbstractElasticaToModelTransformer.php index 0b339fb..f796eec 100755 --- a/Doctrine/AbstractElasticaToModelTransformer.php +++ b/Doctrine/AbstractElasticaToModelTransformer.php @@ -5,7 +5,7 @@ namespace FOS\ElasticaBundle\Doctrine; use FOS\ElasticaBundle\HybridResult; use FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface; use FOS\ElasticaBundle\Transformer\HighlightableModelInterface; -use Symfony\Component\Form\Util\PropertyPath; +use Symfony\Component\PropertyAccess\PropertyAccessorInterface; /** * Maps Elastica documents with Doctrine objects @@ -33,9 +33,16 @@ abstract class AbstractElasticaToModelTransformer implements ElasticaToModelTran */ protected $options = array( 'hydrate' => true, - 'identifier' => 'id' + 'identifier' => 'id' ); + /** + * PropertyAccessor instance + * + * @var PropertyAccessorInterface + */ + protected $propertyAccessor; + /** * Instantiates a new Mapper * @@ -60,6 +67,16 @@ abstract class AbstractElasticaToModelTransformer implements ElasticaToModelTran return $this->objectClass; } + /** + * Set the PropertyAccessor + * + * @param PropertyAccessorInterface $propertyAccessor + */ + public function setPropertyAccessor(PropertyAccessorInterface $propertyAccessor) + { + $this->propertyAccessor = $propertyAccessor; + } + /** * Transforms an array of elastica objects into an array of * model objects fetched from the doctrine repository @@ -87,13 +104,13 @@ abstract class AbstractElasticaToModelTransformer implements ElasticaToModelTran } } - $identifierProperty = new PropertyPath($this->options['identifier']); - // sort objects in the order of ids $idPos = array_flip($ids); - usort($objects, function($a, $b) use ($idPos, $identifierProperty) + $identifier = $this->options['identifier']; + $propertyAccessor = $this->propertyAccessor; + usort($objects, function($a, $b) use ($idPos, $identifier, $propertyAccessor) { - return $idPos[$identifierProperty->getValue($a)] > $idPos[$identifierProperty->getValue($b)]; + return $idPos[$propertyAccessor->getValue($a, $identifier)] > $idPos[$propertyAccessor->getValue($b, $identifier)]; }); return $objects; diff --git a/Propel/ElasticaToModelTransformer.php b/Propel/ElasticaToModelTransformer.php index 76e4233..2678cd6 100644 --- a/Propel/ElasticaToModelTransformer.php +++ b/Propel/ElasticaToModelTransformer.php @@ -4,7 +4,7 @@ namespace FOS\ElasticaBundle\Propel; use FOS\ElasticaBundle\HybridResult; use FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface; -use Symfony\Component\Form\Util\PropertyPath; +use Symfony\Component\PropertyAccess\PropertyAccessorInterface; /** * Maps Elastica documents with Propel objects @@ -32,6 +32,13 @@ class ElasticaToModelTransformer implements ElasticaToModelTransformerInterface 'identifier' => 'id' ); + /** + * PropertyAccessor instance + * + * @var PropertyAccessorInterface + */ + protected $propertyAccessor; + /** * Instantiates a new Mapper * @@ -44,6 +51,16 @@ class ElasticaToModelTransformer implements ElasticaToModelTransformerInterface $this->options = array_merge($this->options, $options); } + /** + * Set the PropertyAccessor + * + * @param PropertyAccessorInterface $propertyAccessor + */ + public function setPropertyAccessor(PropertyAccessorInterface $propertyAccessor) + { + $this->propertyAccessor = $propertyAccessor; + } + /** * Transforms an array of elastica objects into an array of * model objects fetched from the propel repository @@ -59,17 +76,17 @@ class ElasticaToModelTransformer implements ElasticaToModelTransformerInterface $objects = $this->findByIdentifiers($ids, $this->options['hydrate']); - $identifierProperty = new PropertyPath($this->options['identifier']); - // sort objects in the order of ids $idPos = array_flip($ids); + $identifier = $this->options['identifier']; + $propertyAccessor = $this->propertyAccessor; if (is_object($objects)) { - $objects->uasort(function($a, $b) use ($idPos, $identifierProperty) { - return $idPos[$identifierProperty->getValue($a)] > $idPos[$identifierProperty->getValue($b)]; + $objects->uasort(function($a, $b) use ($idPos, $identifier, $propertyAccessor) { + return $idPos[$propertyAccessor->getValue($a, $identifier)] > $idPos[$propertyAccessor->getValue($b, $identifier)]; }); } else { - usort($objects, function($a, $b) use ($idPos, $identifierProperty) { - return $idPos[$identifierProperty->getValue($a)] > $idPos[$identifierProperty->getValue($b)]; + usort($objects, function($a, $b) use ($idPos, $identifier, $propertyAccessor) { + return $idPos[$propertyAccessor->getValue($a, $identifier)] > $idPos[$propertyAccessor->getValue($b, $identifier)]; }); } diff --git a/Resources/config/config.xml b/Resources/config/config.xml index a0819fb..bf9d40d 100644 --- a/Resources/config/config.xml +++ b/Resources/config/config.xml @@ -13,6 +13,7 @@ FOS\ElasticaBundle\Manager\RepositoryManager FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerCollection FOS\ElasticaBundle\Provider\ProviderRegistry + Symfony\Component\PropertyAccess\PropertyAccessor @@ -58,7 +59,7 @@ - + @@ -75,6 +76,9 @@ + + + diff --git a/Resources/config/mongodb.xml b/Resources/config/mongodb.xml index 53c82f9..e60e3dc 100644 --- a/Resources/config/mongodb.xml +++ b/Resources/config/mongodb.xml @@ -24,6 +24,9 @@ + + + diff --git a/Resources/config/orm.xml b/Resources/config/orm.xml index b47cfc1..4fd6ae7 100644 --- a/Resources/config/orm.xml +++ b/Resources/config/orm.xml @@ -25,6 +25,9 @@ + + + diff --git a/Resources/config/propel.xml b/Resources/config/propel.xml index a6fc32f..7a7d93e 100644 --- a/Resources/config/propel.xml +++ b/Resources/config/propel.xml @@ -14,6 +14,9 @@ + + + diff --git a/Tests/Persister/ObjectPersisterTest.php b/Tests/Persister/ObjectPersisterTest.php index 0a46553..e672e12 100644 --- a/Tests/Persister/ObjectPersisterTest.php +++ b/Tests/Persister/ObjectPersisterTest.php @@ -213,10 +213,7 @@ class ObjectPersisterTest extends \PHPUnit_Framework_TestCase private function getTransformer() { $transformer = new ModelToElasticaAutoTransformer(); - - if (class_exists('Symfony\Component\PropertyAccess\PropertyAccess')) { - $transformer->setPropertyAccessor(PropertyAccess::getPropertyAccessor()); - } + $transformer->setPropertyAccessor(PropertyAccess::getPropertyAccessor()); return $transformer; } diff --git a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php index 798ea38..5ac13e6 100644 --- a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php +++ b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php @@ -203,12 +203,7 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase public function testThatCannotTransformObjectWhenGetterDoesNotExistForPrivateMethod() { - // Support both Symfony 2.1 (Form component) and 2.2 (PropertyAccess component) - $expectedException = class_exists('Symfony\Component\PropertyAccess\PropertyAccess') - ? 'Symfony\Component\PropertyAccess\Exception\PropertyAccessDeniedException' - : 'Symfony\Component\Form\Exception\PropertyAccessDeniedException'; - - $this->setExpectedException($expectedException); + $this->setExpectedException('Symfony\Component\PropertyAccess\Exception\PropertyAccessDeniedException'); $transformer = $this->getTransformer(); $transformer->transform(new POPO(), array('desc' => array())); @@ -302,10 +297,7 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase private function getTransformer() { $transformer = new ModelToElasticaAutoTransformer(); - - if (class_exists('Symfony\Component\PropertyAccess\PropertyAccess')) { - $transformer->setPropertyAccessor(PropertyAccess::getPropertyAccessor()); - } + $transformer->setPropertyAccessor(PropertyAccess::getPropertyAccessor()); return $transformer; } diff --git a/Transformer/ModelToElasticaAutoTransformer.php b/Transformer/ModelToElasticaAutoTransformer.php index 4565199..ad20529 100644 --- a/Transformer/ModelToElasticaAutoTransformer.php +++ b/Transformer/ModelToElasticaAutoTransformer.php @@ -2,7 +2,6 @@ namespace FOS\ElasticaBundle\Transformer; -use Symfony\Component\Form\Util\PropertyPath; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; /** @@ -22,11 +21,11 @@ class ModelToElasticaAutoTransformer implements ModelToElasticaTransformerInterf ); /** - * PropertyAccessor instance (will be used if available) + * PropertyAccessor instance * * @var PropertyAccessorInterface */ - private $propertyAccessor; + protected $propertyAccessor; /** * Instanciates a new Mapper @@ -43,7 +42,7 @@ class ModelToElasticaAutoTransformer implements ModelToElasticaTransformerInterf * * @param PropertyAccessorInterface $propertyAccessor */ - public function setPropertyAccessor(PropertyAccessorInterface $propertyAccessor = null) + public function setPropertyAccessor(PropertyAccessorInterface $propertyAccessor) { $this->propertyAccessor = $propertyAccessor; } @@ -58,17 +57,17 @@ class ModelToElasticaAutoTransformer implements ModelToElasticaTransformerInterf **/ public function transform($object, array $fields) { - $identifier = $this->getPropertyValue($object, $this->options['identifier']); + $identifier = $this->propertyAccessor->getValue($object, $this->options['identifier']); $document = new \Elastica_Document($identifier); foreach ($fields as $key => $mapping) { - $value = $this->getPropertyValue($object, $key); + $value = $this->propertyAccessor->getValue($object, $key); if (isset($mapping['_parent']['identifier'])) { /* $value is the parent. Read its identifier and set that as the * document's parent. */ - $document->setParent($this->getPropertyValue($value, $mapping['_parent']['identifier'])); + $document->setParent($this->propertyAccessor->getValue($value, $mapping['_parent']['identifier'])); continue; } @@ -96,26 +95,6 @@ class ModelToElasticaAutoTransformer implements ModelToElasticaTransformerInterf return $document; } - /** - * Get the value of an object property. - * - * This method will use Symfony 2.2's PropertyAccessor if it is available. - * - * @param object $object - * @param string $property - * @return mixed - */ - protected function getPropertyValue($object, $property) - { - if (isset($this->propertyAccessor)) { - return $this->propertyAccessor->getValue($object, $property); - } - - $propertyPath = new PropertyPath($property); - - return $propertyPath->getValue($object); - } - /** * transform a nested document or an object property into an array of ElasticaDocument * diff --git a/composer.json b/composer.json index a4969a0..3629fda 100644 --- a/composer.json +++ b/composer.json @@ -15,6 +15,7 @@ "symfony/framework-bundle": ">=2.1.0,<2.3.0-dev", "symfony/console": ">=2.1.0,<2.3.0-dev", "symfony/form": ">=2.1.0,<2.3.0-dev", + "symfony/property-access": "2.2.*", "ruflin/elastica": "0.19.8" }, "require-dev":{ @@ -25,7 +26,6 @@ "knplabs/knp-components": "1.2.*" }, "suggest": { - "symfony/property-access": "2.2.*", "doctrine/orm": ">=2.2,<2.5-dev", "doctrine/mongodb-odm": "1.0.*@dev", "propel/propel1": "1.6.*", From 4f5be038ef8892c7efde9fb7a68c30d929a5081f Mon Sep 17 00:00:00 2001 From: Karel Souffriau Date: Fri, 5 Apr 2013 13:17:00 +0200 Subject: [PATCH 002/447] Collector: print query data as json instead of yaml --- Resources/views/Collector/elastica.html.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/views/Collector/elastica.html.twig b/Resources/views/Collector/elastica.html.twig index 137dcdb..a665e2d 100644 --- a/Resources/views/Collector/elastica.html.twig +++ b/Resources/views/Collector/elastica.html.twig @@ -46,7 +46,7 @@ Path: {{ query.path }}
Method: {{ query.method }}
- {{ query.data|yaml_encode }} + {{ query.data|json_encode }}
Time: {{ '%0.2f'|format(query.executionMS * 1000) }} ms From ae4f676c2504de6583a0458fb105889e88e2a53d Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Fri, 5 Apr 2013 13:31:19 -0400 Subject: [PATCH 003/447] Create 2.1.x-dev branch alias for master --- composer.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 3629fda..b1be5fa 100644 --- a/composer.json +++ b/composer.json @@ -35,5 +35,10 @@ "autoload": { "psr-0": { "FOS\\ElasticaBundle": "" } }, - "target-dir": "FOS/ElasticaBundle" + "target-dir": "FOS/ElasticaBundle", + "extra": { + "branch-alias": { + "dev-master": "2.1.x-dev" + } + } } From 58e983fb068df8b28c171fb87fcc68ad175fedef Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 16 Apr 2013 13:16:53 -0400 Subject: [PATCH 004/447] Document installation via composer in README (closes #271) --- README.md | 107 +++++++++++++++--------------------------------------- 1 file changed, 29 insertions(+), 78 deletions(-) diff --git a/README.md b/README.md index eefb1b7..a375ca1 100644 --- a/README.md +++ b/README.md @@ -1,95 +1,46 @@ -[Elastica](https://github.com/ruflin/Elastica) integration in Symfony2 +[Elastica](https://github.com/ruflin/Elastica) integration in Symfony2 -## Installation +### Installation -### Install elasticsearch +#### Bundle and Dependencies -http://www.elasticsearch.org/guide/reference/setup/installation.html +For Symfony 2.0.x projects, you must use a 1.x release of this bundle. -### Install Elastica +Add FOSElasticaBundle to your application's `composer.json` file: -#### Download +```json +{ + "require": { + "friendsofsymfony/elastica-bundle": "~1.0" + } +} +``` -**With submodule** - - `git submodule add git://github.com/ruflin/Elastica vendor/elastica` - -**With clone** - - `git clone git://github.com/ruflin/Elastica vendor/elastica` - -**Using the vendors script** - -Add the following lines to your deps file: - - [Elastica] - git=git://github.com/ruflin/Elastica.git - target=elastica - -#### Register autoloading - - // app/autoload.php - - $loader->registerPrefixes(array( - ... - 'Elastica' => __DIR__.'/../vendor/elastica/lib', - )); - -### Install ElasticaBundle - -Use the master branch with Symfony2 master only, use the 2.0 branch with Symfony2.0.x releases. - -#### Download - -**With submodule** - - `git submodule add git://github.com/Exercise/FOSElasticaBundle vendor/bundles/FOS/ElasticaBundle` - -**With clone** - - `git clone git://github.com/Exercise/FOSElasticaBundle vendor/bundles/FOS/ElasticaBundle` - -**With the vendors script** - -Add the following lines to your deps file: - - [FOSElasticaBundle] - git=git://github.com/Exercise/FOSElasticaBundle.git - target=bundles/FOS/ElasticaBundle - -For the 2.0 branch for use with Symfony2.0.x releases add the following: - - [FOSElasticaBundle] - git=git://github.com/Exercise/FOSElasticaBundle.git - target=bundles/FOS/ElasticaBundle - version=origin/2.0 - -Run the vendors script: +Install the bundle and its dependencies with the following command: ```bash -$ php bin/vendors install +$ php composer.phar update friendsofsymfony/elastica-bundle ``` -#### Register autoloading - // app/autoload.php +You may rely on Composer to fetch the appropriate version of Elastica. Lastly, +enable the bundle in your application kernel: - $loader->registerNamespaces(array( - ... - 'FOS' => __DIR__.'/../vendor/bundles', - )); +```php +// app/AppKernel.php -#### Register the bundle +public function registerBundles() +{ + $bundles = array( + // ... + new FOS\ElasticaBundle\FOSElasticaBundle(), + ); +} +``` - // app/AppKernel.php +#### Elasticsearch - public function registerBundles() - { - return array( - // ... - new FOS\ElasticaBundle\FOSElasticaBundle(), - // ... - ); - } +Instructions for installing and deploying Elasticsearch may be found +[here](http://www.elasticsearch.org/guide/reference/setup/installation/). ### Basic configuration From 8ffd1a7c3de611eabcf61040dcb48ab605c768b9 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 16 Apr 2013 13:26:14 -0400 Subject: [PATCH 005/447] Update install version and add links to compatibility info --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9c80bdf..0bcae02 100644 --- a/README.md +++ b/README.md @@ -4,14 +4,18 @@ #### Bundle and Dependencies -For Symfony 2.0.x projects, you must use a 1.x release of this bundle. +For Symfony 2.0.x projects, you must use a 1.x release of this bundle. Please +check the bundle +[tags](https://github.com/FriendsOfSymfony/FOSElasticaBundle/tags) or the +[Packagist](https://packagist.org/packages/friendsofsymfony/elastica-bundle) +page for information on Symfony and Elastica compatibility. Add FOSElasticaBundle to your application's `composer.json` file: ```json { "require": { - "friendsofsymfony/elastica-bundle": "~1.0" + "friendsofsymfony/elastica-bundle": "~2.0" } } ``` From 4b4a56db1e42fd3bc30aca3cb553e7e1f636caee Mon Sep 17 00:00:00 2001 From: Thomas Tourlourat Date: Wed, 17 Apr 2013 11:33:32 +0300 Subject: [PATCH 006/447] Check for "indexes" key in Configuration::getNestings() --- DependencyInjection/Configuration.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 7872e90..4482a4c 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -363,6 +363,10 @@ class Configuration implements ConfigurationInterface */ protected function getNestings() { + if (!isset($this->configArray[0]['indexes'])) { + return array(); + } + $nestings = array(); foreach ($this->configArray[0]['indexes'] as $index) { if (empty($index['types'])) { From c5ee26099bbfe846a558f0357704ddbd8b62750c Mon Sep 17 00:00:00 2001 From: Lea Haensenberger Date: Thu, 10 Jan 2013 14:05:50 +0100 Subject: [PATCH 007/447] Adding support to pass a serializer to elastica --- DependencyInjection/Configuration.php | 10 ++++++++++ DependencyInjection/FOSElasticaExtension.php | 12 ++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 4482a4c..6f5c35c 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -34,6 +34,7 @@ class Configuration implements ConfigurationInterface ->scalarNode('default_client')->end() ->scalarNode('default_index')->end() ->scalarNode('default_manager')->defaultValue('orm')->end() + ->scalarNode('serializer_id')->end() ->end() ; @@ -205,6 +206,15 @@ class Configuration implements ConfigurationInterface ->prototype('array') ->treatNullLike(array()) ->children() + ->arrayNode('serializer') + ->addDefaultsIfNotSet() + ->children() + ->arrayNode('groups') + ->treatNullLike(array()) + ->prototype('scalar')->end() + ->end() + ->end() + ->end() ->scalarNode('index_analyzer')->end() ->scalarNode('search_analyzer')->end() ->arrayNode('persistence') diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 0cb5c27..4cad42c 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -40,7 +40,7 @@ class FOSElasticaExtension extends Extension } $clientIdsByName = $this->loadClients($config['clients'], $container); - $indexIdsByName = $this->loadIndexes($config['indexes'], $container, $clientIdsByName, $config['default_client']); + $indexIdsByName = $this->loadIndexes($config['indexes'], $container, $clientIdsByName, $config['default_client'], $config['serializer_id']); $indexRefsByName = array_map(function($id) { return new Reference($id); }, $indexIdsByName); @@ -93,7 +93,7 @@ class FOSElasticaExtension extends Extension * @throws \InvalidArgumentException * @return array */ - protected function loadIndexes(array $indexes, ContainerBuilder $container, array $clientIdsByName, $defaultClientName) + protected function loadIndexes(array $indexes, ContainerBuilder $container, array $clientIdsByName, $defaultClientName, $serializerId) { $indexIds = array(); foreach ($indexes as $name => $index) { @@ -128,7 +128,7 @@ class FOSElasticaExtension extends Extension if (!empty($index['settings'])) { $this->indexConfigs[$name]['config']['settings'] = $index['settings']; } - $this->loadTypes(isset($index['types']) ? $index['types'] : array(), $container, $name, $indexId, $typePrototypeConfig); + $this->loadTypes(isset($index['types']) ? $index['types'] : array(), $container, $name, $indexId, $typePrototypeConfig, $serializerId); } return $indexIds; @@ -169,8 +169,9 @@ class FOSElasticaExtension extends Extension * @param $indexId * @param array $typePrototypeConfig */ - protected function loadTypes(array $types, ContainerBuilder $container, $indexName, $indexId, array $typePrototypeConfig) + protected function loadTypes(array $types, ContainerBuilder $container, $indexName, $indexId, array $typePrototypeConfig, $serializerId) { + $serializer = $serializerId ? new Reference($serializerId) : null; foreach ($types as $name => $type) { $type = self::deepArrayUnion($typePrototypeConfig, $type); $typeId = sprintf('%s.%s', $indexId, $name); @@ -178,6 +179,9 @@ class FOSElasticaExtension extends Extension $typeDef = new Definition('%fos_elastica.type.class%', $typeDefArgs); $typeDef->setFactoryService($indexId); $typeDef->setFactoryMethod('getType'); + if ($serializer) { + $typeDef->addMethodCall('setSerializer', array($serializer, $type['serializer']['groups'])); + } $container->setDefinition($typeId, $typeDef); if (isset($type['_source'])) { $this->indexConfigs[$indexName]['config']['mappings'][$name]['_source'] = $type['_source']; From 73fd4fe6b00e22dfa582fd8e13261d341edb3ddb Mon Sep 17 00:00:00 2001 From: Lea Haensenberger Date: Thu, 24 Jan 2013 15:07:38 +0100 Subject: [PATCH 008/447] Creating a serializer callable for every type in an index and passing it to elastica --- DependencyInjection/Configuration.php | 10 ++++++++- DependencyInjection/FOSElasticaExtension.php | 23 ++++++++++++++------ 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 6f5c35c..7e0af16 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -34,7 +34,15 @@ class Configuration implements ConfigurationInterface ->scalarNode('default_client')->end() ->scalarNode('default_index')->end() ->scalarNode('default_manager')->defaultValue('orm')->end() - ->scalarNode('serializer_id')->end() + ->arrayNode('serializer') + ->prototype('array') + ->treatNullLike(array()) + ->children() + ->scalarNode('callable_class')->end() + ->scalarNode('id')->end() + ->end() + ->end() + ->end() ->end() ; diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 4cad42c..1469510 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -40,7 +40,7 @@ class FOSElasticaExtension extends Extension } $clientIdsByName = $this->loadClients($config['clients'], $container); - $indexIdsByName = $this->loadIndexes($config['indexes'], $container, $clientIdsByName, $config['default_client'], $config['serializer_id']); + $indexIdsByName = $this->loadIndexes($config['indexes'], $container, $clientIdsByName, $config['default_client'], $config['serializer']); $indexRefsByName = array_map(function($id) { return new Reference($id); }, $indexIdsByName); @@ -93,7 +93,7 @@ class FOSElasticaExtension extends Extension * @throws \InvalidArgumentException * @return array */ - protected function loadIndexes(array $indexes, ContainerBuilder $container, array $clientIdsByName, $defaultClientName, $serializerId) + protected function loadIndexes(array $indexes, ContainerBuilder $container, array $clientIdsByName, $defaultClientName, $serializerConfig) { $indexIds = array(); foreach ($indexes as $name => $index) { @@ -128,7 +128,7 @@ class FOSElasticaExtension extends Extension if (!empty($index['settings'])) { $this->indexConfigs[$name]['config']['settings'] = $index['settings']; } - $this->loadTypes(isset($index['types']) ? $index['types'] : array(), $container, $name, $indexId, $typePrototypeConfig, $serializerId); + $this->loadTypes(isset($index['types']) ? $index['types'] : array(), $container, $name, $indexId, $typePrototypeConfig, $serializerConfig); } return $indexIds; @@ -169,9 +169,8 @@ class FOSElasticaExtension extends Extension * @param $indexId * @param array $typePrototypeConfig */ - protected function loadTypes(array $types, ContainerBuilder $container, $indexName, $indexId, array $typePrototypeConfig, $serializerId) + protected function loadTypes(array $types, ContainerBuilder $container, $indexName, $indexId, array $typePrototypeConfig, $serializerConfig) { - $serializer = $serializerId ? new Reference($serializerId) : null; foreach ($types as $name => $type) { $type = self::deepArrayUnion($typePrototypeConfig, $type); $typeId = sprintf('%s.%s', $indexId, $name); @@ -179,8 +178,18 @@ class FOSElasticaExtension extends Extension $typeDef = new Definition('%fos_elastica.type.class%', $typeDefArgs); $typeDef->setFactoryService($indexId); $typeDef->setFactoryMethod('getType'); - if ($serializer) { - $typeDef->addMethodCall('setSerializer', array($serializer, $type['serializer']['groups'])); + if ($serializerConfig) { + + $serializerDefArgs = array(new Reference($serializerConfig['id'])); + if (isset($type['serializer']['groups'])) { + $serializerDefArgs[] = $type['serializer']['groups']; + } + + $serializerDef = new Definition("%{$serializerConfig['callable_class']}%", $serializerDefArgs); + $serializerId = sprintf('%s.%s.serializer', $indexId, $name); + $container->setDefinition($serializerId, $serializerDef); + + $typeDef->addMethodCall('setSerializer', array(array(new Reference($serializerId), 'serialize'))); } $container->setDefinition($typeId, $typeDef); if (isset($type['_source'])) { From c99eee9c4b0b8f1239e1d6256bd7f53a35cfd631 Mon Sep 17 00:00:00 2001 From: Lea Haensenberger Date: Thu, 24 Jan 2013 15:57:02 +0100 Subject: [PATCH 009/447] Adding some documentation --- README.md | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/README.md b/README.md index 0bcae02..cc39175 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,23 @@ Most of the time, you will need only one. clients: default: { host: localhost, port: 9200 } + +#### Declare a serializer + +Elastica can handle objects instead of data arrays if a serializer callable is configured + + #app/config/config.yml + foq_elastica: + clients: + default: { host: localhost, port: 9200 } + serializer: + callable_class: %classname% + id: serializer + +"callable_class" is the class name of a class having a public method serialize($object). "id" is the service id for the +actual serializer, e.g. 'serializer' if you're using the JMSSerializerBundle. If this is configured you can use +Elastica_Type::addObject instead of Elastica_Type::addDocument to add data to the index. + #### Declare an index Elasticsearch index is comparable to Doctrine entity manager. @@ -66,6 +83,9 @@ Most of the time, you will need only one. fos_elastica: clients: default: { host: localhost, port: 9200 } + serializer: + callable_class: %classname% + id: serializer indexes: website: client: default @@ -96,6 +116,9 @@ Elasticsearch type is comparable to Doctrine entity repository. fos_elastica: clients: default: { host: localhost, port: 9200 } + serializer: + callable_class: %classname% + id: serializer indexes: website: client: default @@ -109,11 +132,38 @@ Elasticsearch type is comparable to Doctrine entity repository. Our type is now available as a service: `fos_elastica.index.website.user`. It is an instance of `Elastica_Type`. +### Declaring serializer groups + +If you are using the JMSSerializerBundle for serializing objects passed to elastica you can define serializer groups +per type. + + foq_elastica: + clients: + default: { host: localhost, port: 9200 } + serializer: + callable_class: %classname% + id: serializer + indexes: + website: + client: default + types: + user: + mappings: + username: { boost: 5 } + firstName: { boost: 3 } + lastName: { boost: 3 } + aboutMe: + serializer: + groups: [elastica, Default] + ### Declaring parent field fos_elastica: clients: default: { host: localhost, port: 9200 } + serializer: + callable_class: %classname% + id: serializer indexes: website: client: default @@ -129,6 +179,9 @@ Our type is now available as a service: `fos_elastica.index.website.user`. It is fos_elastica: clients: default: { host: localhost, port: 9200 } + serializer: + callable_class: %classname% + id: serializer indexes: website: client: default @@ -164,6 +217,9 @@ some configuration will let ElasticaBundle do it for us. fos_elastica: clients: default: { host: localhost, port: 9200 } + serializer: + callable_class: %classname% + id: serializer indexes: website: client: default @@ -281,6 +337,9 @@ Declare that you want a Doctrine/Propel finder in your configuration: fos_elastica: clients: default: { host: localhost, port: 9200 } + serializer: + callable_class: %classname% + id: serializer indexes: website: client: default From a139d18b220b60334192669e6eb87c2dd143cdab Mon Sep 17 00:00:00 2001 From: Lea Haensenberger Date: Fri, 25 Jan 2013 16:48:29 +0100 Subject: [PATCH 010/447] Adding default callback for serialization if serialization is turned on --- DependencyInjection/Configuration.php | 10 ++++---- DependencyInjection/FOSElasticaExtension.php | 13 +++++----- Resources/config/config.xml | 6 +++-- Serializer/Callback.php | 25 ++++++++++++++++++++ 4 files changed, 39 insertions(+), 15 deletions(-) create mode 100644 Serializer/Callback.php diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 7e0af16..f23f3a8 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -35,12 +35,10 @@ class Configuration implements ConfigurationInterface ->scalarNode('default_index')->end() ->scalarNode('default_manager')->defaultValue('orm')->end() ->arrayNode('serializer') - ->prototype('array') - ->treatNullLike(array()) - ->children() - ->scalarNode('callable_class')->end() - ->scalarNode('id')->end() - ->end() + ->treatNullLike(array()) + ->children() + ->scalarNode('callback')->defaultValue('foq_elastica.serializer.callback')->end() + ->scalarNode('serializer')->defaultValue('serializer')->end() ->end() ->end() ->end() diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 1469510..1c2cbe0 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -40,7 +40,8 @@ class FOSElasticaExtension extends Extension } $clientIdsByName = $this->loadClients($config['clients'], $container); - $indexIdsByName = $this->loadIndexes($config['indexes'], $container, $clientIdsByName, $config['default_client'], $config['serializer']); + $serializerConfig = isset($config['serializer']) ? $config['serializer'] : null; + $indexIdsByName = $this->loadIndexes($config['indexes'], $container, $clientIdsByName, $config['default_client'], $serializerConfig); $indexRefsByName = array_map(function($id) { return new Reference($id); }, $indexIdsByName); @@ -179,14 +180,12 @@ class FOSElasticaExtension extends Extension $typeDef->setFactoryService($indexId); $typeDef->setFactoryMethod('getType'); if ($serializerConfig) { - - $serializerDefArgs = array(new Reference($serializerConfig['id'])); + $serializerDef = clone $container->getDefinition($serializerConfig['callback']); + $serializerDef->addMethodCall('setSerializer', array(new Reference($serializerConfig['serializer']))); if (isset($type['serializer']['groups'])) { - $serializerDefArgs[] = $type['serializer']['groups']; + $serializerDef->addMethodCall('setGroups', array($type['serializer']['groups'])); } - - $serializerDef = new Definition("%{$serializerConfig['callable_class']}%", $serializerDefArgs); - $serializerId = sprintf('%s.%s.serializer', $indexId, $name); + $serializerId = sprintf('%s.%s.serializer.callback', $indexId, $name); $container->setDefinition($serializerId, $serializerDef); $typeDef->addMethodCall('setSerializer', array(array(new Reference($serializerId), 'serialize'))); diff --git a/Resources/config/config.xml b/Resources/config/config.xml index bf9d40d..f073aeb 100644 --- a/Resources/config/config.xml +++ b/Resources/config/config.xml @@ -14,6 +14,7 @@ FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerCollection FOS\ElasticaBundle\Provider\ProviderRegistry Symfony\Component\PropertyAccess\PropertyAccessor + FOQ\ElasticaBundle\Serializer\Callback @@ -77,8 +78,9 @@
- - + + + diff --git a/Serializer/Callback.php b/Serializer/Callback.php new file mode 100644 index 0000000..576004a --- /dev/null +++ b/Serializer/Callback.php @@ -0,0 +1,25 @@ +serializer = $serializer; + } + + public function setGroups($groups){ + $this->groups = $groups; + } + + public function serialize($object) + { + $this->serializer->setGroups(null); + $this->serializer->setGroups($this->groups); + return $this->serializer->serialize($object, 'json'); + } +} From bcf564d09c2116b2f9ed1df28503e54b9bc5f40d Mon Sep 17 00:00:00 2001 From: Lea Haensenberger Date: Mon, 28 Jan 2013 08:22:01 +0100 Subject: [PATCH 011/447] Adapting readme --- README.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index cc39175..e8ba475 100644 --- a/README.md +++ b/README.md @@ -68,12 +68,18 @@ Elastica can handle objects instead of data arrays if a serializer callable is c clients: default: { host: localhost, port: 9200 } serializer: - callable_class: %classname% - id: serializer + callback: callback + serializer: serializer -"callable_class" is the class name of a class having a public method serialize($object). "id" is the service id for the +"callback" is the service having a public method serialize($object). "serializer" is the service id for the actual serializer, e.g. 'serializer' if you're using the JMSSerializerBundle. If this is configured you can use Elastica_Type::addObject instead of Elastica_Type::addDocument to add data to the index. +The bundle provides a default implementation with a serializer service id 'serializer' that can be turned on by adding +the following line to your config. + + #app/config/config.yml + foq_elastica: + serializer: ~ #### Declare an index From 1abe1f48ddd92253f106c72f9bb77dd3601c5e41 Mon Sep 17 00:00:00 2001 From: Lea Haensenberger Date: Mon, 28 Jan 2013 08:54:53 +0100 Subject: [PATCH 012/447] Having a parameter name defining a class for the serializer callback, because directly putting service id or parameter doesn't work because these values are not available at bundle configuration time --- DependencyInjection/Configuration.php | 2 +- DependencyInjection/FOSElasticaExtension.php | 8 ++++++-- README.md | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index f23f3a8..c68aba5 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -37,7 +37,7 @@ class Configuration implements ConfigurationInterface ->arrayNode('serializer') ->treatNullLike(array()) ->children() - ->scalarNode('callback')->defaultValue('foq_elastica.serializer.callback')->end() + ->scalarNode('callback')->defaultValue('foq_elastica.serializer.callback.class')->end() ->scalarNode('serializer')->defaultValue('serializer')->end() ->end() ->end() diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 1c2cbe0..c1d8aa2 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -180,12 +180,16 @@ class FOSElasticaExtension extends Extension $typeDef->setFactoryService($indexId); $typeDef->setFactoryMethod('getType'); if ($serializerConfig) { - $serializerDef = clone $container->getDefinition($serializerConfig['callback']); + + $serializerDef = new Definition("%{$serializerConfig['callback']}%"); + $serializerId = sprintf('%s.%s.serializer.callback', $indexId, $name); + + $typeDef->addMethodCall('setSerializer', array(array(new Reference($serializerId), 'serialize'))); $serializerDef->addMethodCall('setSerializer', array(new Reference($serializerConfig['serializer']))); if (isset($type['serializer']['groups'])) { $serializerDef->addMethodCall('setGroups', array($type['serializer']['groups'])); } - $serializerId = sprintf('%s.%s.serializer.callback', $indexId, $name); + $container->setDefinition($serializerId, $serializerDef); $typeDef->addMethodCall('setSerializer', array(array(new Reference($serializerId), 'serialize'))); diff --git a/README.md b/README.md index e8ba475..8580481 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ Elastica can handle objects instead of data arrays if a serializer callable is c callback: callback serializer: serializer -"callback" is the service having a public method serialize($object). "serializer" is the service id for the +"callback" is the name of a parameter defining a class having a public method serialize($object). "serializer" is the service id for the actual serializer, e.g. 'serializer' if you're using the JMSSerializerBundle. If this is configured you can use Elastica_Type::addObject instead of Elastica_Type::addDocument to add data to the index. The bundle provides a default implementation with a serializer service id 'serializer' that can be turned on by adding From d8f836d17929b0e15342a6bbe6dc849ba4ca70a1 Mon Sep 17 00:00:00 2001 From: Lukas Kahwe Smith Date: Tue, 29 Jan 2013 23:17:40 +0100 Subject: [PATCH 013/447] CS fixes and minor tweaks in the Callback class --- Serializer/Callback.php | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/Serializer/Callback.php b/Serializer/Callback.php index 576004a..fff190d 100644 --- a/Serializer/Callback.php +++ b/Serializer/Callback.php @@ -2,24 +2,32 @@ namespace FOQ\ElasticaBundle\Serializer; +use JMS\Serializer\Serializer; + class Callback { protected $serializer; protected $groups; - public function setSerializer($serializer){ + public function setSerializer($serializer) + { $this->serializer = $serializer; } - public function setGroups($groups){ + public function setGroups(array $groups) + { $this->groups = $groups; } public function serialize($object) { - $this->serializer->setGroups(null); - $this->serializer->setGroups($this->groups); + if ($this->serializer instanceof Serializer) { + $this->serializer->setGroups($this->groups); + } elseif ($this->groups) { + throw new \RuntimeException('Setting serialization groups requires using "JMS\Serializer\Serializer"'); + } + return $this->serializer->serialize($object, 'json'); } } From aafb6e53fb8f99e37f4113027189cbb7abd4b949 Mon Sep 17 00:00:00 2001 From: Lukas Kahwe Smith Date: Mon, 22 Apr 2013 13:20:10 +0200 Subject: [PATCH 014/447] made the bundle compatible with Elastica 0.20.x --- Client.php | 6 +-- Command/SearchCommand.php | 12 ++--- DependencyInjection/Configuration.php | 3 +- DependencyInjection/FOSElasticaExtension.php | 3 ++ Finder/FinderInterface.php | 2 +- Finder/PaginatedFinderInterface.php | 4 +- Finder/TransformedFinder.php | 14 +++--- HybridResult.php | 4 +- IndexManager.php | 10 +++-- Paginator/RawPaginatorAdapter.php | 20 ++++----- Paginator/RawPartialResults.php | 10 ++--- Paginator/TransformedPaginatorAdapter.php | 12 ++--- Paginator/TransformedPartialResults.php | 6 +-- Persister/ObjectPersister.php | 8 ++-- Propel/ElasticaToModelTransformer.php | 5 ++- README.md | 44 ++++++++++--------- Resetter.php | 6 ++- Resources/config/config.xml | 6 +-- Serializer/Callback.php | 32 +++++++++++--- Tests/IndexManagerTest.php | 4 +- Tests/Persister/ObjectPersisterTest.php | 34 +++++++------- Tests/ResetterTest.php | 13 +++--- ...asticaToModelTransformerCollectionTest.php | 9 ++-- .../ModelToElasticaAutoTransformerTest.php | 6 +-- .../ElasticaToModelTransformerCollection.php | 4 +- .../ModelToElasticaAutoTransformer.php | 5 ++- .../ModelToElasticaTransformerInterface.php | 2 +- composer.json | 2 +- 28 files changed, 161 insertions(+), 125 deletions(-) diff --git a/Client.php b/Client.php index cd30cb2..31384e5 100644 --- a/Client.php +++ b/Client.php @@ -2,13 +2,13 @@ namespace FOS\ElasticaBundle; -use Elastica_Client; +use Elastica\Client as ElasticaClient; use FOS\ElasticaBundle\Logger\ElasticaLogger; /** * @author Gordon Franke */ -class Client extends Elastica_Client +class Client extends ElasticaClient { /** * @var ElasticaLogger @@ -20,7 +20,7 @@ class Client extends Elastica_Client $this->logger = $logger; } - public function request($path, $method, $data = array(), array $query = array()) + public function request($path, $method = Request::GET, $data = array(), array $query = array()) { $start = microtime(true); $response = parent::request($path, $method, $data, $query); diff --git a/Command/SearchCommand.php b/Command/SearchCommand.php index acf9449..62e3340 100644 --- a/Command/SearchCommand.php +++ b/Command/SearchCommand.php @@ -8,8 +8,8 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\Output; -use Elastica_Query; -use Elastica_Result; +use Elastica\Query; +use Elastica\Result; /** * Searches a type @@ -41,11 +41,11 @@ class SearchCommand extends ContainerAwareCommand protected function execute(InputInterface $input, OutputInterface $output) { $indexName = $input->getOption('index'); - /** @var $index \Elastica_Index */ + /** @var $index \Elastica\Index */ $index = $this->getContainer()->get('fos_elastica.index_manager')->getIndex($indexName ? $indexName : null); $type = $index->getType($input->getArgument('type')); - $query = Elastica_Query::create($input->getArgument('query')); - $query->setLimit($input->getOption('limit')); + $query = Query::create($input->getArgument('query')); + $query->setSize($input->getOption('limit')); if ($input->getOption('explain')) { $query->setExplain(true); } @@ -58,7 +58,7 @@ class SearchCommand extends ContainerAwareCommand } } - protected function formatResult(Elastica_Result $result, $showField, $showSource, $showId, $explain) + protected function formatResult(Result $result, $showField, $showSource, $showId, $explain) { $source = $result->getSource(); if ($showField) { diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index c68aba5..ba8e9f5 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -37,7 +37,7 @@ class Configuration implements ConfigurationInterface ->arrayNode('serializer') ->treatNullLike(array()) ->children() - ->scalarNode('callback')->defaultValue('foq_elastica.serializer.callback.class')->end() + ->scalarNode('callback')->defaultValue('fos_elastica.serializer.callback.class')->end() ->scalarNode('serializer')->defaultValue('serializer')->end() ->end() ->end() @@ -219,6 +219,7 @@ class Configuration implements ConfigurationInterface ->treatNullLike(array()) ->prototype('scalar')->end() ->end() + ->scalarNode('version')->end() ->end() ->end() ->scalarNode('index_analyzer')->end() diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index c1d8aa2..8628199 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -189,6 +189,9 @@ class FOSElasticaExtension extends Extension if (isset($type['serializer']['groups'])) { $serializerDef->addMethodCall('setGroups', array($type['serializer']['groups'])); } + if (isset($type['serializer']['version'])) { + $serializerDef->addMethodCall('version', array($type['serializer']['version'])); + } $container->setDefinition($serializerId, $serializerDef); diff --git a/Finder/FinderInterface.php b/Finder/FinderInterface.php index 2cc0838..4805d58 100644 --- a/Finder/FinderInterface.php +++ b/Finder/FinderInterface.php @@ -7,7 +7,7 @@ interface FinderInterface /** * Searches for query results within a given limit * - * @param mixed $query Can be a string, an array or an Elastica_Query object + * @param mixed $query Can be a string, an array or an \Elastica\Query object * @param int $limit How many results to get * @return array results */ diff --git a/Finder/PaginatedFinderInterface.php b/Finder/PaginatedFinderInterface.php index e26a048..3581cda 100644 --- a/Finder/PaginatedFinderInterface.php +++ b/Finder/PaginatedFinderInterface.php @@ -4,14 +4,14 @@ namespace FOS\ElasticaBundle\Finder; use FOS\ElasticaBundle\Paginator\PaginatorAdapterInterface; use Pagerfanta\Pagerfanta; -use Elastica_Query; +use Elastica\Query; interface PaginatedFinderInterface extends FinderInterface { /** * Searches for query results and returns them wrapped in a paginator * - * @param mixed $query Can be a string, an array or an Elastica_Query object + * @param mixed $query Can be a string, an array or an \Elastica\Query object * @return Pagerfanta paginated results */ function findPaginated($query); diff --git a/Finder/TransformedFinder.php b/Finder/TransformedFinder.php index e1eade8..e0b9cd0 100644 --- a/Finder/TransformedFinder.php +++ b/Finder/TransformedFinder.php @@ -7,8 +7,8 @@ use FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface; use FOS\ElasticaBundle\Paginator\TransformedPaginatorAdapter; use FOS\ElasticaBundle\Paginator\FantaPaginatorAdapter; use Pagerfanta\Pagerfanta; -use Elastica_Searchable; -use Elastica_Query; +use Elastica\SearchableInterface; +use Elastica\Query; /** * Finds elastica documents and map them to persisted objects @@ -18,7 +18,7 @@ class TransformedFinder implements PaginatedFinderInterface protected $searchable; protected $transformer; - public function __construct(Elastica_Searchable $searchable, ElasticaToModelTransformerInterface $transformer) + public function __construct(SearchableInterface $searchable, ElasticaToModelTransformerInterface $transformer) { $this->searchable = $searchable; $this->transformer = $transformer; @@ -52,9 +52,9 @@ class TransformedFinder implements PaginatedFinderInterface */ protected function search($query, $limit = null) { - $queryObject = Elastica_Query::create($query); + $queryObject = Query::create($query); if (null !== $limit) { - $queryObject->setLimit($limit); + $queryObject->setSize($limit); } $results = $this->searchable->search($queryObject)->getResults(); @@ -70,7 +70,7 @@ class TransformedFinder implements PaginatedFinderInterface */ public function findPaginated($query) { - $queryObject = Elastica_Query::create($query); + $queryObject = Query::create($query); $paginatorAdapter = $this->createPaginatorAdapter($queryObject); return new Pagerfanta(new FantaPaginatorAdapter($paginatorAdapter)); @@ -81,7 +81,7 @@ class TransformedFinder implements PaginatedFinderInterface */ public function createPaginatorAdapter($query) { - $query = Elastica_Query::create($query); + $query = Query::create($query); return new TransformedPaginatorAdapter($this->searchable, $query, $this->transformer); } } diff --git a/HybridResult.php b/HybridResult.php index e2b8245..ebd0e99 100644 --- a/HybridResult.php +++ b/HybridResult.php @@ -2,14 +2,14 @@ namespace FOS\ElasticaBundle; -use Elastica_Result; +use Elastica\Result; class HybridResult { protected $result; protected $transformed; - public function __construct(Elastica_Result $result, $transformed = null) + public function __construct(Result $result, $transformed = null) { $this->result = $result; $this->transformed = $transformed; diff --git a/IndexManager.php b/IndexManager.php index ae844d0..e20a791 100644 --- a/IndexManager.php +++ b/IndexManager.php @@ -2,6 +2,8 @@ namespace FOS\ElasticaBundle; +use Elastica\Index; + class IndexManager { protected $indexesByName; @@ -11,9 +13,9 @@ class IndexManager * Constructor. * * @param array $indexesByName - * @param \Elastica_Index $defaultIndex + * @param Index $defaultIndex */ - public function __construct(array $indexesByName, \Elastica_Index $defaultIndex) + public function __construct(array $indexesByName, Index $defaultIndex) { $this->indexesByName = $indexesByName; $this->defaultIndexName = $defaultIndex->getName(); @@ -33,7 +35,7 @@ class IndexManager * Gets an index by its name * * @param string $name Index to return, or the default index if null - * @return \Elastica_Index + * @return Index * @throws \InvalidArgumentException if no index exists for the given name */ public function getIndex($name = null) @@ -52,7 +54,7 @@ class IndexManager /** * Gets the default index * - * @return \Elastica_Index + * @return Index */ public function getDefaultIndex() { diff --git a/Paginator/RawPaginatorAdapter.php b/Paginator/RawPaginatorAdapter.php index 9a80d39..3ed8638 100644 --- a/Paginator/RawPaginatorAdapter.php +++ b/Paginator/RawPaginatorAdapter.php @@ -2,35 +2,35 @@ namespace FOS\ElasticaBundle\Paginator; -use Elastica_Searchable; -use Elastica_Query; -use Elastica_ResultSet; +use Elastica\SearchableInterface; +use Elastica\Query; +use Elastica\ResultSet; use FOS\ElasticaBundle\Paginator\PaginatorAdapterInterface; use FOS\ElasticaBundle\Paginator\RawPartialResults; use FOS\ElasticaBundle\Paginator\PartialResultsInterface; /** - * Allows pagination of Elastica_Query. Does not map results + * Allows pagination of Elastica\Query. Does not map results */ class RawPaginatorAdapter implements PaginatorAdapterInterface { /** - * @var Elastica_Searchable the object to search in + * @var SearchableInterface the object to search in */ private $searchable = null; /** - * @var Elastica_Query the query to search + * @var Query the query to search */ private $query = null; /** * @see PaginatorAdapterInterface::__construct * - * @param Elastica_Searchable $searchable the object to search in - * @param Elastica_Query $query the query to search + * @param SearchableInterface $searchable the object to search in + * @param Query $query the query to search */ - public function __construct(Elastica_Searchable $searchable, Elastica_Query $query) + public function __construct(SearchableInterface $searchable, Query $query) { $this->searchable = $searchable; $this->query = $query; @@ -41,7 +41,7 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface * * @param $offset * @param $itemCountPerPage - * @return Elastica_ResultSet + * @return ResultSet */ protected function getElasticaResults($offset, $itemCountPerPage) { diff --git a/Paginator/RawPartialResults.php b/Paginator/RawPartialResults.php index ef1ed6b..270e4cd 100644 --- a/Paginator/RawPartialResults.php +++ b/Paginator/RawPartialResults.php @@ -3,8 +3,8 @@ namespace FOS\ElasticaBundle\Paginator; use FOS\ElasticaBundle\Paginator\PartialResultsInterface; -use Elastica_ResultSet; -use Elastica_Result; +use Elastica\ResultSet; +use Elastica\Result; /** * Raw partial results transforms to a simple array @@ -14,9 +14,9 @@ class RawPartialResults implements PartialResultsInterface protected $resultSet; /** - * @param \Elastica_ResultSet $resultSet + * @param ResultSet $resultSet */ - public function __construct(Elastica_ResultSet $resultSet) + public function __construct(ResultSet $resultSet) { $this->resultSet = $resultSet; } @@ -26,7 +26,7 @@ class RawPartialResults implements PartialResultsInterface */ public function toArray() { - return array_map(function(Elastica_Result $result) { + return array_map(function(Result $result) { return $result->getSource(); }, $this->resultSet->getResults()); } diff --git a/Paginator/TransformedPaginatorAdapter.php b/Paginator/TransformedPaginatorAdapter.php index 59a94d0..a668636 100644 --- a/Paginator/TransformedPaginatorAdapter.php +++ b/Paginator/TransformedPaginatorAdapter.php @@ -4,22 +4,22 @@ namespace FOS\ElasticaBundle\Paginator; use FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface; use FOS\ElasticaBundle\Paginator\TransformedPartialResults; -use Elastica_Searchable; -use Elastica_Query; +use Elastica\SearchableInterface; +use Elastica\Query; /** - * Allows pagination of Elastica_Query + * Allows pagination of \Elastica\Query */ class TransformedPaginatorAdapter extends RawPaginatorAdapter { private $transformer; /** - * @param Elastica_Searchable $searchable the object to search in - * @param Elastica_Query $query the query to search + * @param SearchableInterface $searchable the object to search in + * @param Query $query the query to search * @param ElasticaToModelTransformerInterface $transformer the transformer for fetching the results */ - public function __construct(Elastica_Searchable $searchable, Elastica_Query $query, ElasticaToModelTransformerInterface $transformer) + public function __construct(SearchableInterface $searchable, Query $query, ElasticaToModelTransformerInterface $transformer) { parent::__construct($searchable, $query); diff --git a/Paginator/TransformedPartialResults.php b/Paginator/TransformedPartialResults.php index 7afd6d4..f7f125a 100644 --- a/Paginator/TransformedPartialResults.php +++ b/Paginator/TransformedPartialResults.php @@ -4,7 +4,7 @@ namespace FOS\ElasticaBundle\Paginator; use FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface; use FOS\ElasticaBundle\Paginator\RawPartialResults; -use Elastica_ResultSet; +use Elastica\ResultSet; /** * Partial transformed result set @@ -14,10 +14,10 @@ class TransformedPartialResults extends RawPartialResults protected $transformer; /** - * @param \Elastica_ResultSet $resultSet + * @param ResultSet $resultSet * @param \FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface $transformer */ - public function __construct(Elastica_ResultSet $resultSet, ElasticaToModelTransformerInterface $transformer) + public function __construct(ResultSet $resultSet, ElasticaToModelTransformerInterface $transformer) { parent::__construct($resultSet); diff --git a/Persister/ObjectPersister.php b/Persister/ObjectPersister.php index db94880..643b817 100644 --- a/Persister/ObjectPersister.php +++ b/Persister/ObjectPersister.php @@ -3,8 +3,8 @@ namespace FOS\ElasticaBundle\Persister; use FOS\ElasticaBundle\Transformer\ModelToElasticaTransformerInterface; -use Elastica_Type; -use Elastica_Document; +use Elastica\Type; +use Elastica\Document; /** * Inserts, replaces and deletes single documents in an elastica type @@ -19,7 +19,7 @@ class ObjectPersister implements ObjectPersisterInterface protected $objectClass; protected $fields; - public function __construct(Elastica_Type $type, ModelToElasticaTransformerInterface $transformer, $objectClass, array $fields) + public function __construct(Type $type, ModelToElasticaTransformerInterface $transformer, $objectClass, array $fields) { $this->type = $type; $this->transformer = $transformer; @@ -95,7 +95,7 @@ class ObjectPersister implements ObjectPersisterInterface * Transforms an object to an elastica document * * @param object $object - * @return Elastica_Document the elastica document + * @return Document the elastica document */ public function transformToElasticaDocument($object) { diff --git a/Propel/ElasticaToModelTransformer.php b/Propel/ElasticaToModelTransformer.php index 2678cd6..4f006a7 100644 --- a/Propel/ElasticaToModelTransformer.php +++ b/Propel/ElasticaToModelTransformer.php @@ -2,6 +2,7 @@ namespace FOS\ElasticaBundle\Propel; +use Elastica\Document; use FOS\ElasticaBundle\HybridResult; use FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; @@ -65,12 +66,12 @@ class ElasticaToModelTransformer implements ElasticaToModelTransformerInterface * Transforms an array of elastica objects into an array of * model objects fetched from the propel repository * - * @param \Elastica_Document[] $elasticaObjects array of elastica objects + * @param Document[] $elasticaObjects array of elastica objects * @return array */ public function transform(array $elasticaObjects) { - $ids = array_map(function(\Elastica_Document $elasticaObject) { + $ids = array_map(function(Document $elasticaObject) { return $elasticaObject->getId(); }, $elasticaObjects); diff --git a/README.md b/README.md index 8580481..e3f43ce 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ Most of the time, you will need only one. Elastica can handle objects instead of data arrays if a serializer callable is configured #app/config/config.yml - foq_elastica: + fos_elastica: clients: default: { host: localhost, port: 9200 } serializer: @@ -73,12 +73,12 @@ Elastica can handle objects instead of data arrays if a serializer callable is c "callback" is the name of a parameter defining a class having a public method serialize($object). "serializer" is the service id for the actual serializer, e.g. 'serializer' if you're using the JMSSerializerBundle. If this is configured you can use -Elastica_Type::addObject instead of Elastica_Type::addDocument to add data to the index. +\Elastica\Type::addObject instead of \Elastica\Type::addDocument to add data to the index. The bundle provides a default implementation with a serializer service id 'serializer' that can be turned on by adding the following line to your config. #app/config/config.yml - foq_elastica: + fos_elastica: serializer: ~ #### Declare an index @@ -98,7 +98,7 @@ Most of the time, you will need only one. Here we created a "website" index, that uses our "default" client. -Our index is now available as a service: `fos_elastica.index.website`. It is an instance of `Elastica_Index`. +Our index is now available as a service: `fos_elastica.index.website`. It is an instance of `\Elastica\Index`. If you need to have different index name from the service name, for example, in order to have different indexes for different environments then you can @@ -136,14 +136,14 @@ Elasticsearch type is comparable to Doctrine entity repository. lastName: { boost: 3 } aboutMe: ~ -Our type is now available as a service: `fos_elastica.index.website.user`. It is an instance of `Elastica_Type`. +Our type is now available as a service: `fos_elastica.index.website.user`. It is an instance of `\Elastica\Type`. ### Declaring serializer groups If you are using the JMSSerializerBundle for serializing objects passed to elastica you can define serializer groups per type. - foq_elastica: + fos_elastica: clients: default: { host: localhost, port: 9200 } serializer: @@ -294,13 +294,14 @@ Its class must implement `FOS\ElasticaBundle\Provider\ProviderInterface`. namespace Acme\UserBundle\Provider; use FOS\ElasticaBundle\Provider\ProviderInterface; - use Elastica_Type; + use Elastica\Type; + use Elastica\Document; class UserProvider implements ProviderInterface { protected $userType; - public function __construct(Elastica_Type $userType) + public function __construct(Type $userType) { $this->userType = $userType; } @@ -316,7 +317,7 @@ Its class must implement `FOS\ElasticaBundle\Provider\ProviderInterface`. $loggerClosure('Indexing users'); } - $document = new \Elastica_Document(); + $document = new Document(); $document->setData(array('username' => 'Bob')); $this->userType->addDocuments(array($document)); } @@ -328,10 +329,10 @@ You will find a more complete implementation example in `src/FOS/ElasticaBundle/ You can just use the index and type Elastica objects, provided as services, to perform searches. - /** var Elastica_Type */ + /** var Elastica\Type */ $userType = $this->container->get('fos_elastica.index.website.user'); - /** var Elastica_ResultSet */ + /** var Elastica\ResultSet */ $resultSet = $userType->search('bob'); #### Doctrine/Propel finder @@ -383,7 +384,7 @@ Knp paginator: $userPaginator = $paginator->paginate($finder->createPaginatorAdapter('bob')); You can also get both the Elastica results and the entities together from the finder. -You can then access the score, highlights etc. from the Elastica_Result whilst +You can then access the score, highlights etc. from the Elastica\Result whilst still also getting the entity. /** var array of FOS\ElasticaBundle\HybridResult */ @@ -393,7 +394,7 @@ still also getting the entity. /** var Acme\UserBundle\Entity\User */ $user = $hybridResult->getTransformed(); - /** var Elastica_Result */ + /** var Elastica\Result */ $result = $hybridResult->getResult(); } @@ -628,7 +629,7 @@ Any setting can be specified when declaring a type. For example, to enable a cus By default, exceptions from the Elastica client library will propagate through the bundle's Client class. For instance, if the elasticsearch server is offline, -issuing a request will result in an `Elastica_Exception_Client` being thrown. +issuing a request will result in an `Elastica\Exception\Connection` being thrown. Depending on your needs, it may be desirable to suppress these exceptions and allow searches to fail silently. @@ -644,14 +645,17 @@ namespace Acme\ElasticaBundle; use FOS\ElasticaBundle\Client as BaseClient; +use Elastica\Exception\AbstractException; +use Elastica\Response; + class Client extends BaseClient { public function request($path, $method, $data = array()) { try { return parent::request($path, $method, $data); - } catch (\Elastica_Exception_Abstract $e) { - return new \Elastica_Response('{"took":0,"timed_out":false,"hits":{"total":0,"max_score":0,"hits":[]}}'); + } catch (AbstractException $e) { + return new Response('{"took":0,"timed_out":false,"hits":{"total":0,"max_score":0,"hits":[]}}'); } } } @@ -669,18 +673,18 @@ apply to queries against the `title` field. ```php $finder = $this->container->get('fos_elastica.finder.website.article'); -$boolQuery = new \Elastica_Query_Bool(); +$boolQuery = new \Elastica\Query\Bool(); -$fieldQuery = new \Elastica_Query_Text(); +$fieldQuery = new \Elastica\Query\Text(); $fieldQuery->setFieldQuery('title', 'I am a title string'); $fieldQuery->setFieldParam('title', 'analyzer', 'my_analyzer'); $boolQuery->addShould($fieldQuery); -$tagsQuery = new \Elastica_Query_Terms(); +$tagsQuery = new \Elastica\Query\Terms(); $tagsQuery->setTerms('tags', array('tag1', 'tag2')); $boolQuery->addShould($tagsQuery); -$categoryQuery = new \Elastica_Query_Terms(); +$categoryQuery = new \Elastica\Query\Terms(); $categoryQuery->setTerms('categoryIds', array('1', '2', '3')); $boolQuery->addMust($categoryQuery); diff --git a/Resetter.php b/Resetter.php index 7614675..7ef2895 100644 --- a/Resetter.php +++ b/Resetter.php @@ -2,6 +2,8 @@ namespace FOS\ElasticaBundle; +use Elastica\Type\Mapping; + /** * Deletes and recreates indexes */ @@ -66,11 +68,11 @@ class Resetter * create type mapping object * * @param array $indexConfig - * @return \Elastica_Type_Mapping + * @return Mapping */ protected function createMapping($indexConfig) { - $mapping = \Elastica_Type_Mapping::create($indexConfig['properties']); + $mapping = Mapping::create($indexConfig['properties']); foreach($indexConfig['properties'] as $type) { if (!empty($type['_parent']) && $type['_parent'] !== '~') { diff --git a/Resources/config/config.xml b/Resources/config/config.xml index f073aeb..7f6351d 100644 --- a/Resources/config/config.xml +++ b/Resources/config/config.xml @@ -6,15 +6,15 @@ FOS\ElasticaBundle\Client - Elastica_Index - Elastica_Type + Elastica\Index + Elastica\Type FOS\ElasticaBundle\Logger\ElasticaLogger FOS\ElasticaBundle\DataCollector\ElasticaDataCollector FOS\ElasticaBundle\Manager\RepositoryManager FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerCollection FOS\ElasticaBundle\Provider\ProviderRegistry Symfony\Component\PropertyAccess\PropertyAccessor - FOQ\ElasticaBundle\Serializer\Callback + FOS\ElasticaBundle\Serializer\Callback diff --git a/Serializer/Callback.php b/Serializer/Callback.php index fff190d..a563da9 100644 --- a/Serializer/Callback.php +++ b/Serializer/Callback.php @@ -1,7 +1,8 @@ serializer = $serializer; @@ -20,14 +23,31 @@ class Callback $this->groups = $groups; } + public function setVersion($version) + { + $this->version = $version; + } + public function serialize($object) { - if ($this->serializer instanceof Serializer) { - $this->serializer->setGroups($this->groups); - } elseif ($this->groups) { - throw new \RuntimeException('Setting serialization groups requires using "JMS\Serializer\Serializer"'); + $context = $this->serializer instanceof Serializer ? new SerializationContext() : null; + + if ($this->groups) { + if (!$context) { + throw new \RuntimeException('Setting serialization groups requires using "JMS\Serializer\Serializer"'); + } + + $context->setGroups($this->groups); } - return $this->serializer->serialize($object, 'json'); + if ($this->version) { + if (!$context) { + throw new \RuntimeException('Setting serialization version requires using "JMS\Serializer\Serializer"'); + } + + $context->setVersion($this->version); + } + + return $this->serializer->serialize($object, 'json', $context); } } diff --git a/Tests/IndexManagerTest.php b/Tests/IndexManagerTest.php index 9a03986..0a8ea37 100644 --- a/Tests/IndexManagerTest.php +++ b/Tests/IndexManagerTest.php @@ -19,8 +19,8 @@ class IndexManagerTest extends \PHPUnit_Framework_TestCase 'index2' => 'test2', ); - /** @var $defaultIndex \PHPUnit_Framework_MockObject_MockObject|\Elastica_Index */ - $defaultIndex = $this->getMockBuilder('Elastica_Index') + /** @var $defaultIndex \PHPUnit_Framework_MockObject_MockObject|\Elastica\Index */ + $defaultIndex = $this->getMockBuilder('Elastica\Index') ->disableOriginalConstructor() ->getMock(); diff --git a/Tests/Persister/ObjectPersisterTest.php b/Tests/Persister/ObjectPersisterTest.php index e672e12..497c286 100644 --- a/Tests/Persister/ObjectPersisterTest.php +++ b/Tests/Persister/ObjectPersisterTest.php @@ -33,7 +33,7 @@ class ObjectPersisterTest extends \PHPUnit_Framework_TestCase { public function setUp() { - if (!class_exists('Elastica_Type')) { + if (!class_exists('Elastica\Type')) { $this->markTestSkipped('The Elastica library classes are not available'); } } @@ -42,8 +42,8 @@ class ObjectPersisterTest extends \PHPUnit_Framework_TestCase { $transformer = $this->getTransformer(); - /** @var $typeMock \PHPUnit_Framework_MockObject_MockObject|\Elastica_Type */ - $typeMock = $this->getMockBuilder('Elastica_Type') + /** @var $typeMock \PHPUnit_Framework_MockObject_MockObject|\Elastica\Type */ + $typeMock = $this->getMockBuilder('Elastica\Type') ->disableOriginalConstructor() ->getMock(); $typeMock->expects($this->once()) @@ -65,8 +65,8 @@ class ObjectPersisterTest extends \PHPUnit_Framework_TestCase { $transformer = $this->getTransformer(); - /** @var $typeMock \PHPUnit_Framework_MockObject_MockObject|\Elastica_Type */ - $typeMock = $this->getMockBuilder('Elastica_Type') + /** @var $typeMock \PHPUnit_Framework_MockObject_MockObject|\Elastica\Type */ + $typeMock = $this->getMockBuilder('Elastica\Type') ->disableOriginalConstructor() ->getMock(); $typeMock->expects($this->never()) @@ -84,8 +84,8 @@ class ObjectPersisterTest extends \PHPUnit_Framework_TestCase { $transformer = $this->getTransformer(); - /** @var $typeMock \PHPUnit_Framework_MockObject_MockObject|\Elastica_Type */ - $typeMock = $this->getMockBuilder('Elastica_Type') + /** @var $typeMock \PHPUnit_Framework_MockObject_MockObject|\Elastica\Type */ + $typeMock = $this->getMockBuilder('Elastica\Type') ->disableOriginalConstructor() ->getMock(); $typeMock->expects($this->never()) @@ -106,8 +106,8 @@ class ObjectPersisterTest extends \PHPUnit_Framework_TestCase { $transformer = $this->getTransformer(); - /** @var $typeMock \PHPUnit_Framework_MockObject_MockObject|\Elastica_Type */ - $typeMock = $this->getMockBuilder('Elastica_Type') + /** @var $typeMock \PHPUnit_Framework_MockObject_MockObject|\Elastica\Type */ + $typeMock = $this->getMockBuilder('Elastica\Type') ->disableOriginalConstructor() ->getMock(); $typeMock->expects($this->never()) @@ -125,8 +125,8 @@ class ObjectPersisterTest extends \PHPUnit_Framework_TestCase { $transformer = $this->getTransformer(); - /** @var $typeMock \PHPUnit_Framework_MockObject_MockObject|\Elastica_Type */ - $typeMock = $this->getMockBuilder('Elastica_Type') + /** @var $typeMock \PHPUnit_Framework_MockObject_MockObject|\Elastica\Type */ + $typeMock = $this->getMockBuilder('Elastica\Type') ->disableOriginalConstructor() ->getMock(); $typeMock->expects($this->once()) @@ -147,8 +147,8 @@ class ObjectPersisterTest extends \PHPUnit_Framework_TestCase { $transformer = $this->getTransformer(); - /** @var $typeMock \PHPUnit_Framework_MockObject_MockObject|\Elastica_Type */ - $typeMock = $this->getMockBuilder('Elastica_Type') + /** @var $typeMock \PHPUnit_Framework_MockObject_MockObject|\Elastica\Type */ + $typeMock = $this->getMockBuilder('Elastica\Type') ->disableOriginalConstructor() ->getMock(); $typeMock->expects($this->never()) @@ -166,8 +166,8 @@ class ObjectPersisterTest extends \PHPUnit_Framework_TestCase { $transformer = $this->getTransformer(); - /** @var $typeMock \PHPUnit_Framework_MockObject_MockObject|\Elastica_Type */ - $typeMock = $this->getMockBuilder('Elastica_Type') + /** @var $typeMock \PHPUnit_Framework_MockObject_MockObject|\Elastica\Type */ + $typeMock = $this->getMockBuilder('Elastica\Type') ->disableOriginalConstructor() ->getMock(); $typeMock->expects($this->never()) @@ -190,8 +190,8 @@ class ObjectPersisterTest extends \PHPUnit_Framework_TestCase { $transformer = $this->getTransformer(); - /** @var $typeMock \PHPUnit_Framework_MockObject_MockObject|\Elastica_Type */ - $typeMock = $this->getMockBuilder('Elastica_Type') + /** @var $typeMock \PHPUnit_Framework_MockObject_MockObject|\Elastica\Type */ + $typeMock = $this->getMockBuilder('Elastica\Type') ->disableOriginalConstructor() ->getMock(); $typeMock->expects($this->never()) diff --git a/Tests/ResetterTest.php b/Tests/ResetterTest.php index 61a18a9..1a7190e 100644 --- a/Tests/ResetterTest.php +++ b/Tests/ResetterTest.php @@ -3,6 +3,7 @@ namespace FOS\ElasticaBundle\Tests\Resetter; use FOS\ElasticaBundle\Resetter; +use Elastica\Type\Mapping; class ResetterTest extends \PHPUnit_Framework_TestCase { @@ -91,7 +92,7 @@ class ResetterTest extends \PHPUnit_Framework_TestCase $type->expects($this->once()) ->method('delete'); - $mapping = \Elastica_Type_Mapping::create($this->indexConfigsByName['foo']['config']['mappings']['a']['properties']); + $mapping = Mapping::create($this->indexConfigsByName['foo']['config']['mappings']['a']['properties']); $type->expects($this->once()) ->method('setMapping') ->with($mapping); @@ -130,7 +131,7 @@ class ResetterTest extends \PHPUnit_Framework_TestCase $type->expects($this->once()) ->method('delete'); - $mapping = \Elastica_Type_Mapping::create($this->indexConfigsByName['parent']['config']['mappings']['a']['properties']); + $mapping = Mapping::create($this->indexConfigsByName['parent']['config']['mappings']['a']['properties']); $mapping->setParam('_parent', array('type' => 'b')); $type->expects($this->once()) ->method('setMapping') @@ -141,21 +142,21 @@ class ResetterTest extends \PHPUnit_Framework_TestCase } /** - * @return \Elastica_Index + * @return \Elastica\Index */ private function getMockElasticaIndex() { - return $this->getMockBuilder('Elastica_Index') + return $this->getMockBuilder('Elastica\Index') ->disableOriginalConstructor() ->getMock(); } /** - * @return \Elastica_Type + * @return \Elastica\Type */ private function getMockElasticaType() { - return $this->getMockBuilder('Elastica_Type') + return $this->getMockBuilder('Elastica\Type') ->disableOriginalConstructor() ->getMock(); } diff --git a/Tests/Transformer/ElasticaToModelTransformerCollectionTest.php b/Tests/Transformer/ElasticaToModelTransformerCollectionTest.php index 2660f07..9b1d782 100644 --- a/Tests/Transformer/ElasticaToModelTransformerCollectionTest.php +++ b/Tests/Transformer/ElasticaToModelTransformerCollectionTest.php @@ -2,6 +2,7 @@ namespace FOS\ElasticaBundle\Tests\Transformer; +use Elastica\Document; use FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerCollection; class ElasticaToModelTransformerCollectionTest extends \PHPUnit_Framework_TestCase @@ -53,8 +54,8 @@ class ElasticaToModelTransformerCollectionTest extends \PHPUnit_Framework_TestCa { $this->collectionSetup(); - $document1 = new \Elastica_Document(123, array('data' => 'lots of data'), 'type1'); - $document2 = new \Elastica_Document(124, array('data' => 'not so much data'), 'type2'); + $document1 = new Document(123, array('data' => 'lots of data'), 'type1'); + $document2 = new Document(124, array('data' => 'not so much data'), 'type2'); $result1 = new POPO(123, 'lots of data'); $result2 = new POPO2(124, 'not so much data'); @@ -80,8 +81,8 @@ class ElasticaToModelTransformerCollectionTest extends \PHPUnit_Framework_TestCa { $this->collectionSetup(); - $document1 = new \Elastica_Document(123, array('data' => 'lots of data'), 'type1'); - $document2 = new \Elastica_Document(124, array('data' => 'not so much data'), 'type1'); + $document1 = new Document(123, array('data' => 'lots of data'), 'type1'); + $document2 = new Document(124, array('data' => 'not so much data'), 'type1'); $result1 = new POPO(123, 'lots of data'); $result2 = new POPO2(124, 'not so much data'); diff --git a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php index 5ac13e6..8bfbbae 100644 --- a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php +++ b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php @@ -112,7 +112,7 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase { public function setUp() { - if (!class_exists('Elastica_Document')) { + if (!class_exists('Elastica\Document')) { ; $this->markTestSkipped('The Elastica library classes are not available'); } @@ -124,7 +124,7 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase $document = $transformer->transform(new POPO(), array('name' => array())); $data = $document->getData(); - $this->assertInstanceOf('Elastica_Document', $document); + $this->assertInstanceOf('Elastica\Document', $document); $this->assertEquals(123, $document->getId()); $this->assertEquals('someName', $data['name']); } @@ -143,7 +143,7 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase ); $data = $document->getData(); - $this->assertInstanceOf('Elastica_Document', $document); + $this->assertInstanceOf('Elastica\Document', $document); $this->assertEquals(123, $document->getId()); $this->assertEquals('someName', $data['name']); $this->assertEquals(7.2, $data['float']); diff --git a/Transformer/ElasticaToModelTransformerCollection.php b/Transformer/ElasticaToModelTransformerCollection.php index 8f750c5..6264959 100644 --- a/Transformer/ElasticaToModelTransformerCollection.php +++ b/Transformer/ElasticaToModelTransformerCollection.php @@ -3,7 +3,7 @@ namespace FOS\ElasticaBundle\Transformer; use FOS\ElasticaBundle\HybridResult; -use Elastica_Document; +use Elastica\Document; /** * Holds a collection of transformers for an index wide transformation. @@ -40,7 +40,7 @@ class ElasticaToModelTransformerCollection implements ElasticaToModelTransformer } /** - * @param Elastica_Document[] $elasticaObjects + * @param Document[] $elasticaObjects * @return array */ public function transform(array $elasticaObjects) diff --git a/Transformer/ModelToElasticaAutoTransformer.php b/Transformer/ModelToElasticaAutoTransformer.php index ad20529..38bd065 100644 --- a/Transformer/ModelToElasticaAutoTransformer.php +++ b/Transformer/ModelToElasticaAutoTransformer.php @@ -3,6 +3,7 @@ namespace FOS\ElasticaBundle\Transformer; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; +use Elastica\Document; /** * Maps Elastica documents with Doctrine objects @@ -53,12 +54,12 @@ class ModelToElasticaAutoTransformer implements ModelToElasticaTransformerInterf * @param object $object the object to convert * @param array $fields the keys we want to have in the returned array * - * @return \Elastica_Document + * @return Document **/ public function transform($object, array $fields) { $identifier = $this->propertyAccessor->getValue($object, $this->options['identifier']); - $document = new \Elastica_Document($identifier); + $document = new Document($identifier); foreach ($fields as $key => $mapping) { $value = $this->propertyAccessor->getValue($object, $key); diff --git a/Transformer/ModelToElasticaTransformerInterface.php b/Transformer/ModelToElasticaTransformerInterface.php index 924bc7c..ec9ada3 100644 --- a/Transformer/ModelToElasticaTransformerInterface.php +++ b/Transformer/ModelToElasticaTransformerInterface.php @@ -12,7 +12,7 @@ interface ModelToElasticaTransformerInterface * * @param object $object the object to convert * @param array $fields the keys we want to have in the returned array - * @return \Elastica_Document + * @return \Elastica\Document **/ function transform($object, array $fields); } diff --git a/composer.json b/composer.json index b1be5fa..bbd502f 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ "symfony/console": ">=2.1.0,<2.3.0-dev", "symfony/form": ">=2.1.0,<2.3.0-dev", "symfony/property-access": "2.2.*", - "ruflin/elastica": "0.19.8" + "ruflin/elastica": "dev-master" }, "require-dev":{ "doctrine/orm": ">=2.2,<2.5-dev", From 965ee39c5a67497bea59513eda5fc89dff4f3166 Mon Sep 17 00:00:00 2001 From: Lukas Kahwe Smith Date: Mon, 22 Apr 2013 16:08:21 +0200 Subject: [PATCH 015/447] typo fix --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index e3f43ce..02c600f 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ Most of the time, you will need only one. clients: default: { host: localhost, port: 9200 } serializer: - callable_class: %classname% + callback: %classname% id: serializer indexes: website: @@ -123,7 +123,7 @@ Elasticsearch type is comparable to Doctrine entity repository. clients: default: { host: localhost, port: 9200 } serializer: - callable_class: %classname% + callback: %classname% id: serializer indexes: website: @@ -147,7 +147,7 @@ per type. clients: default: { host: localhost, port: 9200 } serializer: - callable_class: %classname% + callback: %classname% id: serializer indexes: website: @@ -168,7 +168,7 @@ per type. clients: default: { host: localhost, port: 9200 } serializer: - callable_class: %classname% + callback: %classname% id: serializer indexes: website: @@ -186,7 +186,7 @@ per type. clients: default: { host: localhost, port: 9200 } serializer: - callable_class: %classname% + callback: %classname% id: serializer indexes: website: @@ -224,7 +224,7 @@ some configuration will let ElasticaBundle do it for us. clients: default: { host: localhost, port: 9200 } serializer: - callable_class: %classname% + callback: %classname% id: serializer indexes: website: @@ -345,7 +345,7 @@ Declare that you want a Doctrine/Propel finder in your configuration: clients: default: { host: localhost, port: 9200 } serializer: - callable_class: %classname% + callback: %classname% id: serializer indexes: website: From 8a9a9686babbff82320fd8e249d5d6f2719e6de5 Mon Sep 17 00:00:00 2001 From: Lukas Kahwe Smith Date: Mon, 22 Apr 2013 17:00:26 +0200 Subject: [PATCH 016/447] various tweaks --- DependencyInjection/FOSElasticaExtension.php | 2 +- README.md | 10 +++++----- Serializer/Callback.php | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 8628199..e67ba53 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -190,7 +190,7 @@ class FOSElasticaExtension extends Extension $serializerDef->addMethodCall('setGroups', array($type['serializer']['groups'])); } if (isset($type['serializer']['version'])) { - $serializerDef->addMethodCall('version', array($type['serializer']['version'])); + $serializerDef->addMethodCall('setVersion', array($type['serializer']['version'])); } $container->setDefinition($serializerId, $serializerDef); diff --git a/README.md b/README.md index 02c600f..87b01aa 100644 --- a/README.md +++ b/README.md @@ -71,11 +71,11 @@ Elastica can handle objects instead of data arrays if a serializer callable is c callback: callback serializer: serializer -"callback" is the name of a parameter defining a class having a public method serialize($object). "serializer" is the service id for the -actual serializer, e.g. 'serializer' if you're using the JMSSerializerBundle. If this is configured you can use -\Elastica\Type::addObject instead of \Elastica\Type::addDocument to add data to the index. -The bundle provides a default implementation with a serializer service id 'serializer' that can be turned on by adding -the following line to your config. +``callback`` is the name of a parameter defining a class having a public method serialize($object). +``serializer`` is the service id for the actual serializer, e.g. ``serializer`` if you're using +JMSSerializerBundle. If this is configured you can use ``\Elastica\Type::addObject`` instead of +``\Elastica\Type::addDocument`` to add data to the index. The bundle provides a default implementation +with a serializer service id 'serializer' that can be turned on by adding the following line to your config. #app/config/config.yml fos_elastica: diff --git a/Serializer/Callback.php b/Serializer/Callback.php index a563da9..fbf391e 100644 --- a/Serializer/Callback.php +++ b/Serializer/Callback.php @@ -3,7 +3,7 @@ namespace FOS\ElasticaBundle\Serializer; use JMS\Serializer\SerializationContext; -use JMS\Serializer\Serializer; +use JMS\Serializer\SerializerInterface; class Callback { @@ -30,7 +30,7 @@ class Callback public function serialize($object) { - $context = $this->serializer instanceof Serializer ? new SerializationContext() : null; + $context = $this->serializer instanceof SerializerInterface ? new SerializationContext() : array(); if ($this->groups) { if (!$context) { From 800e38f8aa9666860440f9eab1d622d04b0c3725 Mon Sep 17 00:00:00 2001 From: Lukas Kahwe Smith Date: Mon, 22 Apr 2013 20:02:12 +0200 Subject: [PATCH 017/447] tweaked the callback handling --- DependencyInjection/Configuration.php | 2 +- DependencyInjection/FOSElasticaExtension.php | 17 +++++---- README.md | 36 +++++++++++--------- Serializer/Callback.php | 23 ++++++++----- 4 files changed, 43 insertions(+), 35 deletions(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index ba8e9f5..966f04f 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -37,7 +37,7 @@ class Configuration implements ConfigurationInterface ->arrayNode('serializer') ->treatNullLike(array()) ->children() - ->scalarNode('callback')->defaultValue('fos_elastica.serializer.callback.class')->end() + ->scalarNode('callback_class')->defaultValue('FOS\ElasticaBundle\Serializer\Callback')->end() ->scalarNode('serializer')->defaultValue('serializer')->end() ->end() ->end() diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index e67ba53..3f757df 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -180,22 +180,21 @@ class FOSElasticaExtension extends Extension $typeDef->setFactoryService($indexId); $typeDef->setFactoryMethod('getType'); if ($serializerConfig) { + $callbackDef = new Definition($serializerConfig['callback_class']); + $callbackId = sprintf('%s.%s.serializer.callback', $indexId, $name); - $serializerDef = new Definition("%{$serializerConfig['callback']}%"); - $serializerId = sprintf('%s.%s.serializer.callback', $indexId, $name); - - $typeDef->addMethodCall('setSerializer', array(array(new Reference($serializerId), 'serialize'))); - $serializerDef->addMethodCall('setSerializer', array(new Reference($serializerConfig['serializer']))); + $typeDef->addMethodCall('setSerializer', array(array(new Reference($callbackId), 'serialize'))); + $callbackDef->addMethodCall('setSerializer', array(new Reference($serializerConfig['serializer']))); if (isset($type['serializer']['groups'])) { - $serializerDef->addMethodCall('setGroups', array($type['serializer']['groups'])); + $callbackDef->addMethodCall('setGroups', array($type['serializer']['groups'])); } if (isset($type['serializer']['version'])) { - $serializerDef->addMethodCall('setVersion', array($type['serializer']['version'])); + $callbackDef->addMethodCall('setVersion', array($type['serializer']['version'])); } - $container->setDefinition($serializerId, $serializerDef); + $container->setDefinition($callbackId, $callbackDef); - $typeDef->addMethodCall('setSerializer', array(array(new Reference($serializerId), 'serialize'))); + $typeDef->addMethodCall('setSerializer', array(array(new Reference($callbackId), 'serialize'))); } $container->setDefinition($typeId, $typeDef); if (isset($type['_source'])) { diff --git a/README.md b/README.md index 87b01aa..a0acec2 100644 --- a/README.md +++ b/README.md @@ -68,10 +68,12 @@ Elastica can handle objects instead of data arrays if a serializer callable is c clients: default: { host: localhost, port: 9200 } serializer: - callback: callback + callback_class: callback_class serializer: serializer -``callback`` is the name of a parameter defining a class having a public method serialize($object). +``callback_class`` is the name of a class having a public method serialize($object) and should +extends from ``FOS\ElasticaBundle\Serializer\Callback``. + ``serializer`` is the service id for the actual serializer, e.g. ``serializer`` if you're using JMSSerializerBundle. If this is configured you can use ``\Elastica\Type::addObject`` instead of ``\Elastica\Type::addDocument`` to add data to the index. The bundle provides a default implementation @@ -90,7 +92,7 @@ Most of the time, you will need only one. clients: default: { host: localhost, port: 9200 } serializer: - callback: %classname% + callback_class: FOS\ElasticaBundle\Serializer\Callback id: serializer indexes: website: @@ -123,7 +125,7 @@ Elasticsearch type is comparable to Doctrine entity repository. clients: default: { host: localhost, port: 9200 } serializer: - callback: %classname% + callback_class: FOS\ElasticaBundle\Serializer\Callback id: serializer indexes: website: @@ -147,7 +149,7 @@ per type. clients: default: { host: localhost, port: 9200 } serializer: - callback: %classname% + callback_class: %classname% id: serializer indexes: website: @@ -168,7 +170,7 @@ per type. clients: default: { host: localhost, port: 9200 } serializer: - callback: %classname% + callback_class_class: FOS\ElasticaBundle\Serializer\Callback id: serializer indexes: website: @@ -186,7 +188,7 @@ per type. clients: default: { host: localhost, port: 9200 } serializer: - callback: %classname% + callback_class: FOS\ElasticaBundle\Serializer\Callback id: serializer indexes: website: @@ -224,7 +226,7 @@ some configuration will let ElasticaBundle do it for us. clients: default: { host: localhost, port: 9200 } serializer: - callback: %classname% + callback_class: FOS\ElasticaBundle\Serializer\Callback id: serializer indexes: website: @@ -345,7 +347,7 @@ Declare that you want a Doctrine/Propel finder in your configuration: clients: default: { host: localhost, port: 9200 } serializer: - callback: %classname% + callback_class: FOS\ElasticaBundle\Serializer\Callback id: serializer indexes: website: @@ -575,28 +577,28 @@ You can also choose to only listen for some of the events: If you use listeners to update your index, you may need to validate your entities before you index them (e.g. only index "public" entities). Typically, you'll want the listener to be consistent with the provider's query criteria. -This may be achieved by using the `is_indexable_callback` config parameter: +This may be achieved by using the `is_indexable_callback_class` config parameter: persistence: listener: - is_indexable_callback: "isPublic" + is_indexable_callback_class: "isPublic" -If `is_indexable_callback` is a string and the entity has a method with the +If `is_indexable_callback_class` is a string and the entity has a method with the specified name, the listener will only index entities for which the method returns `true`. Additionally, you may provide a service and method name pair: persistence: listener: - is_indexable_callback: [ "%custom_service_id%", "isIndexable" ] + is_indexable_callback_class: [ "%custom_service_id%", "isIndexable" ] -In this case, the callback will be the `isIndexable()` method on the specified +In this case, the callback_class will be the `isIndexable()` method on the specified service and the object being considered for indexing will be passed as the only argument. This allows you to do more complex validation (e.g. ACL checks). -As you might expect, new entities will only be indexed if the callback returns +As you might expect, new entities will only be indexed if the callback_class returns `true`. Additionally, modified entities will be updated or removed from the -index depending on whether the callback returns `true` or `false`, respectively. -The delete listener disregards the callback. +index depending on whether the callback_class returns `true` or `false`, respectively. +The delete listener disregards the callback_class. > **Propel** doesn't support this feature yet. diff --git a/Serializer/Callback.php b/Serializer/Callback.php index fbf391e..50307e0 100644 --- a/Serializer/Callback.php +++ b/Serializer/Callback.php @@ -16,16 +16,31 @@ class Callback public function setSerializer($serializer) { $this->serializer = $serializer; + if (!method_exists($this->serializer, 'serialize')) { + throw new \RuntimeException('The serializer must have a "serialize" method.'); + } } public function setGroups(array $groups) { $this->groups = $groups; + + if ($this->groups) { + if (!$this->serializer instanceof SerializerInterface) { + throw new \RuntimeException('Setting serialization groups requires using "JMS\Serializer\Serializer".'); + } + } } public function setVersion($version) { $this->version = $version; + + if ($this->version) { + if (!$this->serializer instanceof SerializerInterface) { + throw new \RuntimeException('Setting serialization version requires using "JMS\Serializer\Serializer".'); + } + } } public function serialize($object) @@ -33,18 +48,10 @@ class Callback $context = $this->serializer instanceof SerializerInterface ? new SerializationContext() : array(); if ($this->groups) { - if (!$context) { - throw new \RuntimeException('Setting serialization groups requires using "JMS\Serializer\Serializer"'); - } - $context->setGroups($this->groups); } if ($this->version) { - if (!$context) { - throw new \RuntimeException('Setting serialization version requires using "JMS\Serializer\Serializer"'); - } - $context->setVersion($this->version); } From 0af8f6ce199c89e9e4de852c0d2208f9a1eaa12d Mon Sep 17 00:00:00 2001 From: Lukas Kahwe Smith Date: Wed, 24 Apr 2013 09:02:33 +0200 Subject: [PATCH 018/447] updated for Elastica master changes --- README.md | 4 ++-- composer.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a0acec2..822cf3f 100644 --- a/README.md +++ b/README.md @@ -647,7 +647,7 @@ namespace Acme\ElasticaBundle; use FOS\ElasticaBundle\Client as BaseClient; -use Elastica\Exception\AbstractException; +use Elastica\Exception\ExceptionInterface; use Elastica\Response; class Client extends BaseClient @@ -656,7 +656,7 @@ class Client extends BaseClient { try { return parent::request($path, $method, $data); - } catch (AbstractException $e) { + } catch (ExceptionInterface $e) { return new Response('{"took":0,"timed_out":false,"hits":{"total":0,"max_score":0,"hits":[]}}'); } } diff --git a/composer.json b/composer.json index bbd502f..701cfde 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ "symfony/console": ">=2.1.0,<2.3.0-dev", "symfony/form": ">=2.1.0,<2.3.0-dev", "symfony/property-access": "2.2.*", - "ruflin/elastica": "dev-master" + "ruflin/elastica": "0.20.5.0.*@dev" }, "require-dev":{ "doctrine/orm": ">=2.2,<2.5-dev", @@ -38,7 +38,7 @@ "target-dir": "FOS/ElasticaBundle", "extra": { "branch-alias": { - "dev-master": "2.1.x-dev" + "dev-master": "3.0.x-dev" } } } From c35cb1b25f333de990ec0e3d2d454eea55b762f9 Mon Sep 17 00:00:00 2001 From: Lukas Kahwe Smith Date: Wed, 24 Apr 2013 10:02:41 +0200 Subject: [PATCH 019/447] fixed Elastica dependency --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 701cfde..69edc36 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ "symfony/console": ">=2.1.0,<2.3.0-dev", "symfony/form": ">=2.1.0,<2.3.0-dev", "symfony/property-access": "2.2.*", - "ruflin/elastica": "0.20.5.0.*@dev" + "ruflin/elastica": "0.20.5.*@dev" }, "require-dev":{ "doctrine/orm": ">=2.2,<2.5-dev", From e898deb6df0accc4a9f994f480fb90ea5fa99780 Mon Sep 17 00:00:00 2001 From: Lukas Kahwe Smith Date: Fri, 26 Apr 2013 14:12:28 +0200 Subject: [PATCH 020/447] cleanups --- Resources/config/config.xml | 3 --- 1 file changed, 3 deletions(-) diff --git a/Resources/config/config.xml b/Resources/config/config.xml index 7f6351d..cd91961 100644 --- a/Resources/config/config.xml +++ b/Resources/config/config.xml @@ -14,7 +14,6 @@ FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerCollection FOS\ElasticaBundle\Provider\ProviderRegistry Symfony\Component\PropertyAccess\PropertyAccessor - FOS\ElasticaBundle\Serializer\Callback @@ -79,8 +78,6 @@ - - From 813f57e3d06a58abea9605bb297f199682f86b3e Mon Sep 17 00:00:00 2001 From: Lukas Kahwe Smith Date: Fri, 26 Apr 2013 14:15:57 +0200 Subject: [PATCH 021/447] added purge command --- Command/PurgeCommand.php | 78 ++++++++++++++++++++++++++++++++++ Doctrine/RepositoryManager.php | 2 +- Manager/RepositoryManager.php | 2 +- Repository.php | 2 +- 4 files changed, 81 insertions(+), 3 deletions(-) create mode 100755 Command/PurgeCommand.php diff --git a/Command/PurgeCommand.php b/Command/PurgeCommand.php new file mode 100755 index 0000000..3f5fa00 --- /dev/null +++ b/Command/PurgeCommand.php @@ -0,0 +1,78 @@ +setName('fos:elastica:purge') + ->addOption('index', null, InputOption::VALUE_OPTIONAL, 'The index to purge') + ->addOption('type', null, InputOption::VALUE_OPTIONAL, 'The type to purge') + ->setDescription('Purge search indexes') + ; + } + + /** + * @see Symfony\Component\Console\Command\Command::initialize() + */ + protected function initialize(InputInterface $input, OutputInterface $output) + { + $this->indexManager = $this->getContainer()->get('fos_elastica.index_manager'); + $this->resetter = $this->getContainer()->get('fos_elastica.resetter'); + } + + /** + * @see Symfony\Component\Console\Command\Command::execute() + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $index = $input->getOption('index'); + $type = $input->getOption('type'); + + if (null === $index && null !== $type) { + throw new \InvalidArgumentException('Cannot specify type option without an index.'); + } + + if (null !== $type) { + $output->writeln(sprintf('Resetting: %s/%s', $index, $type)); + $this->resetter->resetIndex($index, $type); + } else { + $indexes = null === $index + ? array_keys($this->indexManager->getAllIndexes()) + : array($index) + ; + + foreach ($indexes as $index) { + $output->writeln(sprintf('Resetting %s', $index)); + $this->resetter->resetIndex($index); + } + } + } +} diff --git a/Doctrine/RepositoryManager.php b/Doctrine/RepositoryManager.php index 8224ffb..6ba6bf5 100644 --- a/Doctrine/RepositoryManager.php +++ b/Doctrine/RepositoryManager.php @@ -28,7 +28,7 @@ class RepositoryManager extends BaseManager * Return repository for entity * * Returns custom repository if one specified otherwise - * returns a basic respository. + * returns a basic repository. */ public function getRepository($entityName) { diff --git a/Manager/RepositoryManager.php b/Manager/RepositoryManager.php index 7701ec9..6459c19 100644 --- a/Manager/RepositoryManager.php +++ b/Manager/RepositoryManager.php @@ -33,7 +33,7 @@ class RepositoryManager implements RepositoryManagerInterface * Return repository for entity * * Returns custom repository if one specified otherwise - * returns a basic respository. + * returns a basic repository. */ public function getRepository($entityName) { diff --git a/Repository.php b/Repository.php index dde07c6..413f1e4 100644 --- a/Repository.php +++ b/Repository.php @@ -7,7 +7,7 @@ use FOS\ElasticaBundle\Finder\PaginatedFinderInterface; /** * @author Richard Miller * - * Basic respoitory to be extended to hold custom queries to be run + * Basic repository to be extended to hold custom queries to be run * in the finder. */ class Repository From b204f5bf5f416f5dc2d45c7bf44bd5923c0142ad Mon Sep 17 00:00:00 2001 From: Tom Corrigan Date: Fri, 3 May 2013 01:01:29 +1000 Subject: [PATCH 022/447] Allow symfony >= 2.3 This required a small tweak to the tests as Symfony\Component\PropertyAccess\Exception\PropertyAccessDeniedException has been removed in 2.3 --- Tests/Transformer/ModelToElasticaAutoTransformerTest.php | 2 +- composer.json | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php index 8bfbbae..1c8905b 100644 --- a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php +++ b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php @@ -203,7 +203,7 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase public function testThatCannotTransformObjectWhenGetterDoesNotExistForPrivateMethod() { - $this->setExpectedException('Symfony\Component\PropertyAccess\Exception\PropertyAccessDeniedException'); + $this->setExpectedException('Symfony\Component\PropertyAccess\Exception\ExceptionInterface'); $transformer = $this->getTransformer(); $transformer->transform(new POPO(), array('desc' => array())); diff --git a/composer.json b/composer.json index 69edc36..1f7098b 100644 --- a/composer.json +++ b/composer.json @@ -12,10 +12,10 @@ ], "require": { "php": ">=5.3.2", - "symfony/framework-bundle": ">=2.1.0,<2.3.0-dev", - "symfony/console": ">=2.1.0,<2.3.0-dev", - "symfony/form": ">=2.1.0,<2.3.0-dev", - "symfony/property-access": "2.2.*", + "symfony/framework-bundle": "~2.1", + "symfony/console": "~2.1", + "symfony/form": "~2.1", + "symfony/property-access": "~2.2", "ruflin/elastica": "0.20.5.*@dev" }, "require-dev":{ From ee6f3cb04d8f3678596ed9557d7dd1e1b2265072 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Thu, 2 May 2013 11:24:27 -0400 Subject: [PATCH 023/447] Expect a more specific PropertyAccess exception RuntimeException is the nearest common ancestor of the PropertyAccessDeniedException (removed in 2.3) and NoSuchPropertyException. See: symfony/symfony@2a666cb7c3ecbaa6226e5a9da0476b10b6e997db --- Tests/Transformer/ModelToElasticaAutoTransformerTest.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php index 1c8905b..cbcb6bd 100644 --- a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php +++ b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php @@ -201,10 +201,11 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase $this->assertTrue(array_key_exists('nullValue', $data)); } + /** + * @expectedException Symfony\Component\PropertyAccess\Exception\RuntimeException + */ public function testThatCannotTransformObjectWhenGetterDoesNotExistForPrivateMethod() { - $this->setExpectedException('Symfony\Component\PropertyAccess\Exception\ExceptionInterface'); - $transformer = $this->getTransformer(); $transformer->transform(new POPO(), array('desc' => array())); } From 4ffc499c66e5ba721abfe40ee5530b7517a458d0 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Fri, 3 May 2013 11:20:44 +1000 Subject: [PATCH 024/447] Saner version constraints --- composer.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 1f7098b..7b54d57 100644 --- a/composer.json +++ b/composer.json @@ -12,10 +12,10 @@ ], "require": { "php": ">=5.3.2", - "symfony/framework-bundle": "~2.1", - "symfony/console": "~2.1", - "symfony/form": "~2.1", - "symfony/property-access": "~2.2", + "symfony/framework-bundle": ">=2.1,<2.4-dev", + "symfony/console": ">=2.1,<2.4-dev", + "symfony/form": ">=2.1,<2.4-dev", + "symfony/property-access": ">=2.2,<2.4-dev", "ruflin/elastica": "0.20.5.*@dev" }, "require-dev":{ From f48ae85cc88e58c3e649b8d12caf34612dc56a28 Mon Sep 17 00:00:00 2001 From: Lukas Kahwe Smith Date: Mon, 6 May 2013 10:32:50 +0200 Subject: [PATCH 025/447] added missing use statement --- Client.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Client.php b/Client.php index 31384e5..27cff7f 100644 --- a/Client.php +++ b/Client.php @@ -3,6 +3,8 @@ namespace FOS\ElasticaBundle; use Elastica\Client as ElasticaClient; +use Elastica\Request; + use FOS\ElasticaBundle\Logger\ElasticaLogger; /** From b8a4a47b38ae840970329ede869f7fe5ab32e210 Mon Sep 17 00:00:00 2001 From: Lukas Kahwe Smith Date: Wed, 8 May 2013 09:10:40 +0200 Subject: [PATCH 026/447] renamed PurgeCommand to ResetCommand --- Command/{PurgeCommand.php => ResetCommand.php} | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) rename Command/{PurgeCommand.php => ResetCommand.php} (90%) diff --git a/Command/PurgeCommand.php b/Command/ResetCommand.php similarity index 90% rename from Command/PurgeCommand.php rename to Command/ResetCommand.php index 3f5fa00..f223d63 100755 --- a/Command/PurgeCommand.php +++ b/Command/ResetCommand.php @@ -12,9 +12,9 @@ use FOS\ElasticaBundle\IndexManager; use FOS\ElasticaBundle\Resetter; /** - * Purge search indexes + * Reset search indexes */ -class PurgeCommand extends ContainerAwareCommand +class ResetCommand extends ContainerAwareCommand { /** * @var IndexManager @@ -32,10 +32,10 @@ class PurgeCommand extends ContainerAwareCommand protected function configure() { $this - ->setName('fos:elastica:purge') - ->addOption('index', null, InputOption::VALUE_OPTIONAL, 'The index to purge') - ->addOption('type', null, InputOption::VALUE_OPTIONAL, 'The type to purge') - ->setDescription('Purge search indexes') + ->setName('fos:elastica:reset') + ->addOption('index', null, InputOption::VALUE_OPTIONAL, 'The index to reset') + ->addOption('type', null, InputOption::VALUE_OPTIONAL, 'The type to reset') + ->setDescription('Reset search indexes') ; } From 23dfd3f595a9d9d6e93e2dff9fac1bc3a5541aaa Mon Sep 17 00:00:00 2001 From: Arne Stockmans Date: Wed, 8 May 2013 14:29:22 +0200 Subject: [PATCH 027/447] Renamed is_indexable_callback_class back to is_indexable_callback --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 822cf3f..5fec319 100644 --- a/README.md +++ b/README.md @@ -577,19 +577,19 @@ You can also choose to only listen for some of the events: If you use listeners to update your index, you may need to validate your entities before you index them (e.g. only index "public" entities). Typically, you'll want the listener to be consistent with the provider's query criteria. -This may be achieved by using the `is_indexable_callback_class` config parameter: +This may be achieved by using the `is_indexable_callback` config parameter: persistence: listener: - is_indexable_callback_class: "isPublic" + is_indexable_callback: "isPublic" -If `is_indexable_callback_class` is a string and the entity has a method with the +If `is_indexable_callback` is a string and the entity has a method with the specified name, the listener will only index entities for which the method returns `true`. Additionally, you may provide a service and method name pair: persistence: listener: - is_indexable_callback_class: [ "%custom_service_id%", "isIndexable" ] + is_indexable_callback: [ "%custom_service_id%", "isIndexable" ] In this case, the callback_class will be the `isIndexable()` method on the specified service and the object being considered for indexing will be passed as the only From d6e8134189971e03cba66442ccd703f977b65b36 Mon Sep 17 00:00:00 2001 From: Philipp Wahala Date: Wed, 15 May 2013 15:56:21 +0200 Subject: [PATCH 028/447] Correct serializer configuration in README --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 822cf3f..43cf4b1 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,7 @@ Most of the time, you will need only one. default: { host: localhost, port: 9200 } serializer: callback_class: FOS\ElasticaBundle\Serializer\Callback - id: serializer + serializer: serializer indexes: website: client: default @@ -126,7 +126,7 @@ Elasticsearch type is comparable to Doctrine entity repository. default: { host: localhost, port: 9200 } serializer: callback_class: FOS\ElasticaBundle\Serializer\Callback - id: serializer + serializer: serializer indexes: website: client: default @@ -150,7 +150,7 @@ per type. default: { host: localhost, port: 9200 } serializer: callback_class: %classname% - id: serializer + serializer: serializer indexes: website: client: default @@ -170,8 +170,8 @@ per type. clients: default: { host: localhost, port: 9200 } serializer: - callback_class_class: FOS\ElasticaBundle\Serializer\Callback - id: serializer + callback_class: FOS\ElasticaBundle\Serializer\Callback + serializer: serializer indexes: website: client: default @@ -189,7 +189,7 @@ per type. default: { host: localhost, port: 9200 } serializer: callback_class: FOS\ElasticaBundle\Serializer\Callback - id: serializer + serializer: serializer indexes: website: client: default @@ -227,7 +227,7 @@ some configuration will let ElasticaBundle do it for us. default: { host: localhost, port: 9200 } serializer: callback_class: FOS\ElasticaBundle\Serializer\Callback - id: serializer + serializer: serializer indexes: website: client: default @@ -348,7 +348,7 @@ Declare that you want a Doctrine/Propel finder in your configuration: default: { host: localhost, port: 9200 } serializer: callback_class: FOS\ElasticaBundle\Serializer\Callback - id: serializer + serializer: serializer indexes: website: client: default From 00b67fd8a4e10c132bb3ed7a82d40169bd420ab4 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 18 Apr 2013 10:01:34 +1000 Subject: [PATCH 029/447] Ignore missing index hits --- DependencyInjection/Configuration.php | 2 ++ DependencyInjection/FOSElasticaExtension.php | 5 +++-- Doctrine/AbstractElasticaToModelTransformer.php | 7 ++++--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 4482a4c..df0fe19 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -170,6 +170,7 @@ class Configuration implements ConfigurationInterface ->addDefaultsIfNotSet() ->children() ->scalarNode('hydrate')->defaultTrue()->end() + ->scalarNode('ignore_missing')->defaultFalse()->end() ->scalarNode('service')->end() ->end() ->end() @@ -250,6 +251,7 @@ class Configuration implements ConfigurationInterface ->addDefaultsIfNotSet() ->children() ->scalarNode('hydrate')->defaultTrue()->end() + ->scalarNode('ignore_missing')->defaultFalse()->end() ->scalarNode('service')->end() ->end() ->end() diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 0cb5c27..6d38714 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -272,8 +272,9 @@ class FOSElasticaExtension extends Extension $serviceDef->replaceArgument($argPos, $typeConfig['model']); $serviceDef->replaceArgument($argPos + 1, array( - 'identifier' => $typeConfig['identifier'], - 'hydrate' => $typeConfig['elastica_to_model_transformer']['hydrate'] + 'hydrate' => $typeConfig['elastica_to_model_transformer']['hydrate'], + 'identifier' => $typeConfig['identifier'], + 'ignore_missing' => $typeConfig['elastica_to_model_transformer']['ignore_missing'] )); $container->setDefinition($serviceId, $serviceDef); diff --git a/Doctrine/AbstractElasticaToModelTransformer.php b/Doctrine/AbstractElasticaToModelTransformer.php index f796eec..e8f9472 100755 --- a/Doctrine/AbstractElasticaToModelTransformer.php +++ b/Doctrine/AbstractElasticaToModelTransformer.php @@ -32,8 +32,9 @@ abstract class AbstractElasticaToModelTransformer implements ElasticaToModelTran * @var array */ protected $options = array( - 'hydrate' => true, - 'identifier' => 'id' + 'hydrate' => true, + 'identifier' => 'id', + 'ignore_missing' => false, ); /** @@ -94,7 +95,7 @@ abstract class AbstractElasticaToModelTransformer implements ElasticaToModelTran } $objects = $this->findByIdentifiers($ids, $this->options['hydrate']); - if (count($objects) < count($elasticaObjects)) { + if (!$this->options['ignore_missing'] && count($objects) < count($elasticaObjects)) { throw new \RuntimeException('Cannot find corresponding Doctrine objects for all Elastica results.'); }; From c05e0caa9cdc5c599780dd740be843c92bfdbbce Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 2 May 2013 10:18:05 +1000 Subject: [PATCH 030/447] Added documentation for ignoring missing hits --- README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/README.md b/README.md index 0bcae02..c289cd6 100644 --- a/README.md +++ b/README.md @@ -534,6 +534,23 @@ The delete listener disregards the callback. > **Propel** doesn't support this feature yet. +### Ignoring missing index results + +By default, FOSElasticaBundle will throw an exception if the results returned from +Elasticsearch are different from the results it finds from the chosen persistence +provider. This may pose problems for a large index where updates do not occur instantly +or another process has removed the results from your persistence provider without +updating Elasticsearch. + +The error you're likely to see is something like: +'Cannot find corresponding Doctrine objects for all Elastica results.' + +To solve this issue, each mapped object can be configured to ignore the missing results: + + persistence: + elastica_to_model_transformer: + ignore_missing: true + ### Advanced elasticsearch configuration Any setting can be specified when declaring a type. For example, to enable a custom analyzer, you could write: From 41c747907c483043c47d6160daf7a048030d7a9d Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 15 May 2013 10:55:30 -0500 Subject: [PATCH 031/447] Create 2.1.x changelog --- CHANGELOG-2.1.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 CHANGELOG-2.1.md diff --git a/CHANGELOG-2.1.md b/CHANGELOG-2.1.md new file mode 100644 index 0000000..f4373e7 --- /dev/null +++ b/CHANGELOG-2.1.md @@ -0,0 +1,18 @@ +CHANGELOG for 2.1.x +=================== + +This changelog references the relevant changes (bug and security fixes) done +in 2.1 minor versions. + +To get the diff for a specific change, go to +https://github.com/FriendsOfSymfony/FOSElasticaBundle/commit/XXX where XXX is +the commit hash. To get the diff between two versions, go to +https://github.com/FriendsOfSymfony/FOSElasticaBundle/compare/v2.1.0...v2.1.1 + +To generate a changelog summary since the last version, run +`git log --no-merges --oneline v2.1.0...2.1.x` + +* 2.1.0 (2013-5-15) + + * c05e0ca: Added documentation for ignoring missing hits + * 00b67fd: Ignore missing index hits From 50730cca3d59f3429bfc0908424c4e998ab780df Mon Sep 17 00:00:00 2001 From: Lukas Kahwe Smith Date: Fri, 17 May 2013 00:22:46 +0200 Subject: [PATCH 032/447] added path support, see http://www.elasticsearch.org/guide/reference/mapping/id-field/ --- DependencyInjection/Configuration.php | 18 ++++++++++++++++++ DependencyInjection/FOSElasticaExtension.php | 3 +++ 2 files changed, 21 insertions(+) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index f79eece..d901bfb 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -281,6 +281,7 @@ class Configuration implements ConfigurationInterface ->end() ->end() ->end() + ->append($this->getIdNode()) ->append($this->getMappingsNode()) ->append($this->getSourceNode()) ->append($this->getBoostNode()) @@ -435,6 +436,23 @@ class Configuration implements ConfigurationInterface $nestings[$property] = array_merge_recursive($nestings[$property], $this->getNestingsForType($field[$property])); } + /** + * Returns the array node used for "_id". + */ + protected function getIdNode() + { + $builder = new TreeBuilder(); + $node = $builder->root('_id'); + + $node + ->children() + ->scalarNode('path')->end() + ->end() + ; + + return $node; + } + /** * Returns the array node used for "_source". */ diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 473cec3..c28fb99 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -197,6 +197,9 @@ class FOSElasticaExtension extends Extension $typeDef->addMethodCall('setSerializer', array(array(new Reference($callbackId), 'serialize'))); } $container->setDefinition($typeId, $typeDef); + if (isset($type['_id'])) { + $this->indexConfigs[$indexName]['config']['mappings'][$name]['_id'] = $type['_id']; + } if (isset($type['_source'])) { $this->indexConfigs[$indexName]['config']['mappings'][$name]['_source'] = $type['_source']; } From be065735c13c2934200fcb59b29c604908c1d950 Mon Sep 17 00:00:00 2001 From: Lukas Kahwe Smith Date: Wed, 22 May 2013 21:52:48 +0200 Subject: [PATCH 033/447] master is 3.0.x --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 555f5b1..e0915b8 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Add FOSElasticaBundle to your application's `composer.json` file: ```json { "require": { - "friendsofsymfony/elastica-bundle": "~2.0" + "friendsofsymfony/elastica-bundle": "3.0.*@dev" } } ``` From 43d1531cd412f3ac9613702898a14a2dbfca628f Mon Sep 17 00:00:00 2001 From: Lukas Kahwe Smith Date: Thu, 23 May 2013 00:25:38 +0300 Subject: [PATCH 034/447] cs fix --- DependencyInjection/Configuration.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index d901bfb..79cadf2 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -12,7 +12,8 @@ class Configuration implements ConfigurationInterface private $configArray = array(); - public function __construct($configArray){ + public function __construct($configArray) + { $this->configArray = $configArray; } From fab42fa0ceef2c5c5966f8cbf06480aac13cbfbe Mon Sep 17 00:00:00 2001 From: Patrick McAndrew Date: Fri, 24 May 2013 12:27:37 +0100 Subject: [PATCH 035/447] Properities should not be required for object as elastica can automap --- README.md | 8 +++++++ .../ModelToElasticaAutoTransformerTest.php | 24 +++++++++++++++++++ .../ModelToElasticaAutoTransformer.php | 2 +- 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 555f5b1..fac11d1 100644 --- a/README.md +++ b/README.md @@ -184,6 +184,8 @@ per type. ### Declaring `nested` or `object` +Note that object can autodetect properties + fos_elastica: clients: default: { host: localhost, port: 9200 } @@ -204,6 +206,12 @@ per type. properties: date: { boost: 5 } content: ~ + user: + type: "object" + approver: + type: "object" + properties: + date: { boost: 5 } ### Populate the types diff --git a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php index cbcb6bd..080cbfe 100644 --- a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php +++ b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php @@ -102,6 +102,11 @@ class POPO ); } + public function getObj() + { + return array('foo' => 'foo', 'bar' => 'foo', 'id' => 1); + } + public function getUpper() { return (object) array('id' => 'parent', 'name' => 'a random name'); @@ -268,6 +273,25 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase ), $data['sub']); } + public function testObjectDoesNotRequireProperties() + { + $transformer = $this->getTransformer(); + $document = $transformer->transform(new POPO(), array( + 'obj' => array( + 'type' => 'object' + ) + )); + $data = $document->getData(); + + $this->assertTrue(array_key_exists('obj', $data)); + $this->assertInternalType('array', $data['obj']); + $this->assertEquals(array( + 'foo' => 'foo', + 'bar' => 'foo', + 'id' => 1 + ), $data['obj']); + } + public function testParentMapping() { $transformer = $this->getTransformer(); diff --git a/Transformer/ModelToElasticaAutoTransformer.php b/Transformer/ModelToElasticaAutoTransformer.php index 38bd065..ebeacfb 100644 --- a/Transformer/ModelToElasticaAutoTransformer.php +++ b/Transformer/ModelToElasticaAutoTransformer.php @@ -72,7 +72,7 @@ class ModelToElasticaAutoTransformer implements ModelToElasticaTransformerInterf continue; } - if (isset($mapping['type']) && in_array($mapping['type'], array('nested', 'object'))) { + if (isset($mapping['type']) && in_array($mapping['type'], array('nested', 'object')) && isset($mapping['properties'])) { /* $value is a nested document or object. Transform $value into * an array of documents, respective the mapped properties. */ From f374dbbaa2d3db3797907e3caed4db99432aaec9 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Thu, 30 May 2013 16:26:16 +0000 Subject: [PATCH 036/447] update to PSR3 LoggerInterface per change in ruflin/elastica --- Client.php | 4 ++- Logger/ElasticaLogger.php | 76 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 77 insertions(+), 3 deletions(-) diff --git a/Client.php b/Client.php index 27cff7f..517fa8b 100644 --- a/Client.php +++ b/Client.php @@ -7,6 +7,8 @@ use Elastica\Request; use FOS\ElasticaBundle\Logger\ElasticaLogger; +use PSR\Log\LoggerInterface; + /** * @author Gordon Franke */ @@ -17,7 +19,7 @@ class Client extends ElasticaClient */ protected $logger; - public function setLogger(ElasticaLogger $logger) + public function setLogger(LoggerInterface $logger) { $this->logger = $logger; } diff --git a/Logger/ElasticaLogger.php b/Logger/ElasticaLogger.php index e8840da..1705d06 100644 --- a/Logger/ElasticaLogger.php +++ b/Logger/ElasticaLogger.php @@ -2,7 +2,7 @@ namespace FOS\ElasticaBundle\Logger; -use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\LoggerInterface; /** * Logger for the Elastica. @@ -12,7 +12,7 @@ use Symfony\Component\HttpKernel\Log\LoggerInterface; * * @author Gordon Franke */ -class ElasticaLogger +class ElasticaLogger implements LoggerInterface { protected $logger; protected $queries; @@ -75,4 +75,76 @@ class ElasticaLogger { return $this->queries; } + + /** + * {@inheritdoc} + */ + public function emergency($message, array $context = array()) + { + return $this->logger->emergency($message, $context); + } + + /** + * {@inheritdoc} + */ + public function alert($message, array $context = array()) + { + return $this->logger->alert($message, $context); + } + + /** + * {@inheritdoc} + */ + public function critical($message, array $context = array()) + { + return $this->logger->critical($message, $context); + } + + /** + * {@inheritdoc} + */ + public function error($message, array $context = array()) + { + return $this->logger->error($message, $context); + } + + /** + * {@inheritdoc} + */ + public function warning($message, array $context = array()) + { + return $this->logger->warning($message, $context); + } + + /** + * {@inheritdoc} + */ + public function notice($message, array $context = array()) + { + return $this->logger->notice($message, $context); + } + + /** + * {@inheritdoc} + */ + public function info($message, array $context = array()) + { + return $this->logger->info($message, $context); + } + + /** + * {@inheritdoc} + */ + public function debug($message, array $context = array()) + { + return $this->logger->debug($message, $context); + } + + /** + * {@inheritdoc} + */ + public function log($level, $message, array $context = array()) + { + return $this->logger->log($message, $context); + } } From 55edceadcb4a7152f6aefe1ccba047e769edb05e Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Thu, 30 May 2013 16:43:10 +0000 Subject: [PATCH 037/447] remove redundant property/method --- Client.php | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/Client.php b/Client.php index 517fa8b..ef9a8bd 100644 --- a/Client.php +++ b/Client.php @@ -5,25 +5,11 @@ namespace FOS\ElasticaBundle; use Elastica\Client as ElasticaClient; use Elastica\Request; -use FOS\ElasticaBundle\Logger\ElasticaLogger; - -use PSR\Log\LoggerInterface; - /** * @author Gordon Franke */ class Client extends ElasticaClient { - /** - * @var ElasticaLogger - */ - protected $logger; - - public function setLogger(LoggerInterface $logger) - { - $this->logger = $logger; - } - public function request($path, $method = Request::GET, $data = array(), array $query = array()) { $start = microtime(true); From 929c1bfc0d61f11c18fb265ede9c6e26db673ce2 Mon Sep 17 00:00:00 2001 From: ceednee Date: Thu, 30 May 2013 21:27:31 +0200 Subject: [PATCH 038/447] Fixes Undefined property: FOS\ElasticaBundle\Client:: --- Client.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Client.php b/Client.php index ef9a8bd..8430b36 100644 --- a/Client.php +++ b/Client.php @@ -15,9 +15,9 @@ class Client extends ElasticaClient $start = microtime(true); $response = parent::request($path, $method, $data, $query); - if (null !== $this->logger) { + if (null !== $this->_logger) { $time = microtime(true) - $start; - $this->logger->logQuery($path, $method, $data, $time); + $this->_logger->logQuery($path, $method, $data, $time); } return $response; From 94ab3b1d3ccdd45fe0aa780c9b52a5e0fd386df7 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Fri, 31 May 2013 13:16:49 -0400 Subject: [PATCH 039/447] Add PSR Log dependency (see: #304) --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 7b54d57..a2951f0 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,8 @@ "symfony/console": ">=2.1,<2.4-dev", "symfony/form": ">=2.1,<2.4-dev", "symfony/property-access": ">=2.2,<2.4-dev", - "ruflin/elastica": "0.20.5.*@dev" + "ruflin/elastica": "0.20.5.*@dev", + "psr/log": "~1.0" }, "require-dev":{ "doctrine/orm": ">=2.2,<2.5-dev", From 1fc94b22133e5803123c6b5a8523756b585e6d99 Mon Sep 17 00:00:00 2001 From: Richard Fullmer Date: Tue, 4 Jun 2013 11:45:45 -0700 Subject: [PATCH 040/447] Ignore failed deletions in ObjectPersister This probably isn't the best way to solve my problem, but the issue is this. Step 1: Create a new doctrine entity for which it's `is_indexable_callback` returns false. When doctrine flushes this entity to the database, elastia will not index it with elastic search. (Correct) Step 2: Update your doctrine entity and change some fields so that `is_indexable_callback` _still_ returns false. Persist and flush to the database. At this point, the postUpdate listener on ElastiaBundle is called and since the `is_indexable_callback` returns false, it believes it needs to remove it from the elastic search index and queues it for deletion. The deletion of course fails because it was never there in the first place. This solution simply ignores failures from deletions in the index. Perhaps a better solution would be to have a smarter listener that could determine if the entity was previously present in the elastic search index or not, but that would require significant refactoring. Addresses issues discuseed in #284 Credit to @bbeaulant for simple solution. Opening a PR to discuss more generally. --- Persister/ObjectPersister.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Persister/ObjectPersister.php b/Persister/ObjectPersister.php index 643b817..450e43b 100644 --- a/Persister/ObjectPersister.php +++ b/Persister/ObjectPersister.php @@ -2,6 +2,7 @@ namespace FOS\ElasticaBundle\Persister; +use Elastica\Exception\NotFoundException; use FOS\ElasticaBundle\Transformer\ModelToElasticaTransformerInterface; use Elastica\Type; use Elastica\Document; @@ -48,7 +49,9 @@ class ObjectPersister implements ObjectPersisterInterface public function replaceOne($object) { $document = $this->transformToElasticaDocument($object); - $this->type->deleteById($document->getId()); + try { + $this->type->deleteById($document->getId()); + } catch (NotFoundException $e) {} $this->type->addDocument($document); } @@ -61,7 +64,9 @@ class ObjectPersister implements ObjectPersisterInterface public function deleteOne($object) { $document = $this->transformToElasticaDocument($object); - $this->type->deleteById($document->getId()); + try { + $this->type->deleteById($document->getId()); + } catch (NotFoundException $e) {} } /** @@ -73,7 +78,9 @@ class ObjectPersister implements ObjectPersisterInterface **/ public function deleteById($id) { - $this->type->deleteById($id); + try { + $this->type->deleteById($id); + } catch (NotFoundException $e) {} } From 00e9a49460142aeb099a314e00ef151ae2728d53 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Thu, 6 Jun 2013 11:02:55 -0400 Subject: [PATCH 041/447] Allow Symfony dependencies until 3.0 --- composer.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index a4969a0..def510b 100644 --- a/composer.json +++ b/composer.json @@ -12,9 +12,9 @@ ], "require": { "php": ">=5.3.2", - "symfony/framework-bundle": ">=2.1.0,<2.3.0-dev", - "symfony/console": ">=2.1.0,<2.3.0-dev", - "symfony/form": ">=2.1.0,<2.3.0-dev", + "symfony/framework-bundle": "~2.1", + "symfony/console": "~2.1", + "symfony/form": "~2.1", "ruflin/elastica": "0.19.8" }, "require-dev":{ @@ -25,7 +25,7 @@ "knplabs/knp-components": "1.2.*" }, "suggest": { - "symfony/property-access": "2.2.*", + "symfony/property-access": "~2.2", "doctrine/orm": ">=2.2,<2.5-dev", "doctrine/mongodb-odm": "1.0.*@dev", "propel/propel1": "1.6.*", From cd48a3668794fbc548192da10e0c60033eac1a78 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Thu, 6 Jun 2013 11:05:31 -0400 Subject: [PATCH 042/447] Update 2.0.x changelog --- CHANGELOG-2.0.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG-2.0.md b/CHANGELOG-2.0.md index b384948..26c779c 100644 --- a/CHANGELOG-2.0.md +++ b/CHANGELOG-2.0.md @@ -12,6 +12,13 @@ https://github.com/FriendsOfSymfony/FOSElasticaBundle/compare/v2.0.0...v2.0.1 To generate a changelog summary since the last version, run `git log --no-merges --oneline v2.0.0...2.0.x` +* 2.0.2 (2013-06-06) + + * 00e9a49: Allow Symfony dependencies until 3.0 + * 4b4a56d: Check for "indexes" key in Configuration::getNestings() + * 8ffd1a7: Update install version and add links to compatibility info + * 58e983f: Document installation via composer in README (closes #271) + * 2.0.1 (2013-04-04) * f0d3a4d: Ensure mongo extension is available in Travis CI From 2dfbfffbd0dce5071e29c525f48aa760c5417b9f Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Thu, 6 Jun 2013 11:19:59 -0400 Subject: [PATCH 043/447] Update 2.1.x changelog --- CHANGELOG-2.1.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-2.1.md b/CHANGELOG-2.1.md index f4373e7..4069cdd 100644 --- a/CHANGELOG-2.1.md +++ b/CHANGELOG-2.1.md @@ -12,7 +12,11 @@ https://github.com/FriendsOfSymfony/FOSElasticaBundle/compare/v2.1.0...v2.1.1 To generate a changelog summary since the last version, run `git log --no-merges --oneline v2.1.0...2.1.x` -* 2.1.0 (2013-5-15) +* 2.1.2 (2013-06-06) + + * 00e9a49: Allow Symfony dependencies until 3.0 + +* 2.1.1 (2013-05-15) * c05e0ca: Added documentation for ignoring missing hits * 00b67fd: Ignore missing index hits From 16ecd7cca306063a0fff9ac27d38af3f416e98f5 Mon Sep 17 00:00:00 2001 From: Patrick McAndrew Date: Thu, 16 May 2013 15:56:44 +0100 Subject: [PATCH 044/447] Tag client with fos_elastica.client --- Resources/config/config.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/Resources/config/config.xml b/Resources/config/config.xml index cd91961..4097289 100644 --- a/Resources/config/config.xml +++ b/Resources/config/config.xml @@ -33,6 +33,7 @@ + From b9da709f22dc36c2e7934a6af933a3282bb932b2 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Mon, 10 Jun 2013 10:36:28 -0400 Subject: [PATCH 045/447] Add documentation for client tagging --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index c31bc29..475de02 100644 --- a/README.md +++ b/README.md @@ -680,6 +680,14 @@ class Client extends BaseClient } ``` +### Clients as Tagged Services + +Clients will be tagged as `fos_elastica.client`, which makes it possible to +retrieve all clients from the service container and interact with them via a +compiler pass. See +[Working with Tagged Services](http://symfony.com/doc/current/components/dependency_injection/tags.html) +for more information. + ### Example of Advanced Query If you would like to perform more advanced queries, here is one example using From c4cc199fbeaafbdfc21511778594d3e2c94c7a70 Mon Sep 17 00:00:00 2001 From: RobertPlant Date: Wed, 12 Jun 2013 10:34:42 +0200 Subject: [PATCH 046/447] Document object mapping implications for Doctrine ORM --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 475de02..7cc86c2 100644 --- a/README.md +++ b/README.md @@ -205,6 +205,12 @@ per type. date: { boost: 5 } content: ~ +#### Doctrine ORM and `object` mappings + +Objects operate in the same way as the nested results but they need to have associations set up in Doctrine ORM so that they can be referenced correctly when indexing. + +If an "Entity was not found" error occurs while indexing, a null association has been discovered in the database. A custom Doctrine query must be used to utilize left joins instead of the default inner join. + ### Populate the types php app/console fos:elastica:populate From fd5ef8005e68a27e9568c46a02780652a3c947a5 Mon Sep 17 00:00:00 2001 From: RobertPlant Date: Thu, 13 Jun 2013 11:28:49 +0200 Subject: [PATCH 047/447] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 7cc86c2..e575f88 100644 --- a/README.md +++ b/README.md @@ -386,6 +386,9 @@ Pagerfanta: /** var Pagerfanta\Pagerfanta */ $userPaginator = $finder->findPaginated('bob'); + /** Number of results to be used for paging the results */ + $countOfResults = $userPaginator->getNbResults(); + Knp paginator: $paginator = $this->get('knp_paginator'); From a386ffefe332d23e7ac9bcfcb71e667302a49d47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20J=2E=20Garc=C3=ADa=20Lagar?= Date: Mon, 17 Jun 2013 21:19:11 +0200 Subject: [PATCH 048/447] Fix parent mapping --- DependencyInjection/Configuration.php | 28 ++++++++++++++----- DependencyInjection/FOSElasticaExtension.php | 6 +++- README.md | 2 +- Resetter.php | 6 ++-- Tests/ResetterTest.php | 13 +++++++-- .../ModelToElasticaAutoTransformerTest.php | 12 +++----- .../ModelToElasticaAutoTransformer.php | 12 ++++---- 7 files changed, 48 insertions(+), 31 deletions(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 79cadf2..da63a2d 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -287,6 +287,7 @@ class Configuration implements ConfigurationInterface ->append($this->getSourceNode()) ->append($this->getBoostNode()) ->append($this->getRoutingNode()) + ->append($this->getParentNode()) ->end() ; @@ -338,13 +339,7 @@ class Configuration implements ConfigurationInterface ->scalarNode('index_options')->end() ->scalarNode('ignore_above')->end() ->scalarNode('position_offset_gap')->end() - ->arrayNode('_parent') - ->treatNullLike(array()) - ->children() - ->scalarNode('type')->end() - ->scalarNode('identifier')->defaultValue('id')->end() - ->end() - ->end(); + ; if (isset($nestings['fields'])) { $this->addNestedFieldConfig($node, $nestings, 'fields'); @@ -516,4 +511,23 @@ class Configuration implements ConfigurationInterface return $node; } + + /** + * Returns the array node used for "_parent". + */ + protected function getParentNode() + { + $builder = new TreeBuilder(); + $node = $builder->root('_parent'); + + $node + ->children() + ->scalarNode('type')->end() + ->scalarNode('property')->end() + ->scalarNode('identifier')->defaultValue('id')->end() + ->end() + ; + + return $node; + } } diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index c28fb99..d83b604 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -214,6 +214,11 @@ class FOSElasticaExtension extends Extension $typeName = sprintf('%s/%s', $indexName, $name); $this->typeFields[$typeName] = $type['mappings']; } + if (isset($type['_parent'])) { + $this->indexConfigs[$indexName]['config']['mappings'][$name]['_parent'] = array('type' => $type['_parent']['type']); + $typeName = sprintf('%s/%s', $indexName, $name); + $this->typeFields[$typeName]['_parent'] = $type['_parent']; + } if (isset($type['persistence'])) { $this->loadTypePersistenceIntegration($type['persistence'], $container, $typeDef, $indexName, $name); } @@ -476,5 +481,4 @@ class FOSElasticaExtension extends Extension $container->setAlias('fos_elastica.manager', sprintf('fos_elastica.manager.%s', $defaultManagerService)); } - } diff --git a/README.md b/README.md index e575f88..47789b7 100644 --- a/README.md +++ b/README.md @@ -178,9 +178,9 @@ per type. types: comment: mappings: - post: {_parent: { type: "post", identifier: "id" } } date: { boost: 5 } content: ~ + _parent: { type: "post", property: "post", identifier: "id" } ### Declaring `nested` or `object` diff --git a/Resetter.php b/Resetter.php index 7ef2895..9a9da0b 100644 --- a/Resetter.php +++ b/Resetter.php @@ -74,10 +74,8 @@ class Resetter { $mapping = Mapping::create($indexConfig['properties']); - foreach($indexConfig['properties'] as $type) { - if (!empty($type['_parent']) && $type['_parent'] !== '~') { - $mapping->setParam('_parent', array('type' => $type['_parent']['type'])); - } + if (isset($indexConfig['_parent'])) { + $mapping->setParam('_parent', array('type' => $indexConfig['_parent']['type'])); } return $mapping; diff --git a/Tests/ResetterTest.php b/Tests/ResetterTest.php index 1a7190e..18cbe06 100644 --- a/Tests/ResetterTest.php +++ b/Tests/ResetterTest.php @@ -34,9 +34,16 @@ class ResetterTest extends \PHPUnit_Framework_TestCase 'index' => $this->getMockElasticaIndex(), 'config' => array( 'mappings' => array( - 'a' => array('properties' => array( - 'field_1' => array('_parent' => array('type' => 'b', 'identifier' => 'id')), - 'field_2' => array())), + 'a' => array( + 'properties' => array( + 'field_2' => array() + ), + '_parent' => array( + 'type' => 'b', + 'property' => 'b', + 'identifier' => 'id' + ), + ), 'b' => array('properties' => array()), ), ), diff --git a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php index cbcb6bd..8b6b3ae 100644 --- a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php +++ b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php @@ -272,10 +272,8 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase { $transformer = $this->getTransformer(); $document = $transformer->transform(new POPO(), array( - 'upper' => array( - '_parent' => array('type' => 'upper', 'identifier' => 'id'), - ) - )); + '_parent' => array('type' => 'upper', 'property'=>'upper', 'identifier' => 'id'), + )); $this->assertEquals("parent", $document->getParent()); } @@ -284,10 +282,8 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase { $transformer = $this->getTransformer(); $document = $transformer->transform(new POPO(), array( - 'upper' => array( - '_parent' => array('type' => 'upper', 'identifier' => 'name'), - ) - )); + '_parent' => array('type' => 'upper', 'property'=>'upper', 'identifier' => 'name'), + )); $this->assertEquals("a random name", $document->getParent()); } diff --git a/Transformer/ModelToElasticaAutoTransformer.php b/Transformer/ModelToElasticaAutoTransformer.php index 38bd065..5d8701a 100644 --- a/Transformer/ModelToElasticaAutoTransformer.php +++ b/Transformer/ModelToElasticaAutoTransformer.php @@ -62,15 +62,13 @@ class ModelToElasticaAutoTransformer implements ModelToElasticaTransformerInterf $document = new Document($identifier); foreach ($fields as $key => $mapping) { - $value = $this->propertyAccessor->getValue($object, $key); - - if (isset($mapping['_parent']['identifier'])) { - /* $value is the parent. Read its identifier and set that as the - * document's parent. - */ - $document->setParent($this->propertyAccessor->getValue($value, $mapping['_parent']['identifier'])); + if ($key == '_parent') { + $value = $this->propertyAccessor->getValue($object, $mapping['property']); + $document->setParent($this->propertyAccessor->getValue($value, $mapping['identifier'])); continue; } + + $value = $this->propertyAccessor->getValue($object, $key); if (isset($mapping['type']) && in_array($mapping['type'], array('nested', 'object'))) { /* $value is a nested document or object. Transform $value into From 0bf6e0b09a0a10de34203598c7b1aa64974cfce6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20J=2E=20Garc=C3=ADa=20Lagar?= Date: Tue, 18 Jun 2013 09:52:44 +0200 Subject: [PATCH 049/447] Fix output colors --- Command/PopulateCommand.php | 6 +++--- Command/ResetCommand.php | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Command/PopulateCommand.php b/Command/PopulateCommand.php index 4f88b75..3fa7cd2 100755 --- a/Command/PopulateCommand.php +++ b/Command/PopulateCommand.php @@ -125,18 +125,18 @@ class PopulateCommand extends ContainerAwareCommand private function populateIndexType(OutputInterface $output, $index, $type, $reset) { if ($reset) { - $output->writeln(sprintf('Resetting: %s/%s', $index, $type)); + $output->writeln(sprintf('Resetting %s/%s', $index, $type)); $this->resetter->resetIndexType($index, $type); } $loggerClosure = function($message) use ($output, $index, $type) { - $output->writeln(sprintf('Populating: %s/%s, %s', $index, $type, $message)); + $output->writeln(sprintf('Populating %s/%s, %s', $index, $type, $message)); }; $provider = $this->providerRegistry->getProvider($index, $type); $provider->populate($loggerClosure); - $output->writeln(sprintf('Refreshing: %s', $index)); + $output->writeln(sprintf('Refreshing %s', $index)); $this->indexManager->getIndex($index)->refresh(); } } diff --git a/Command/ResetCommand.php b/Command/ResetCommand.php index f223d63..b318827 100755 --- a/Command/ResetCommand.php +++ b/Command/ResetCommand.php @@ -61,7 +61,7 @@ class ResetCommand extends ContainerAwareCommand } if (null !== $type) { - $output->writeln(sprintf('Resetting: %s/%s', $index, $type)); + $output->writeln(sprintf('Resetting %s/%s', $index, $type)); $this->resetter->resetIndex($index, $type); } else { $indexes = null === $index From b11b4299ef58d3c964a227f889527f2c484cc2c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20J=2E=20Garc=C3=ADa=20Lagar?= Date: Wed, 19 Jun 2013 12:36:59 +0200 Subject: [PATCH 050/447] An orderBy DQL part is required to avoid feching the same row twice --- Doctrine/ORM/Provider.php | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/Doctrine/ORM/Provider.php b/Doctrine/ORM/Provider.php index 0f130fc..cbd69f0 100644 --- a/Doctrine/ORM/Provider.php +++ b/Doctrine/ORM/Provider.php @@ -8,6 +8,8 @@ use FOS\ElasticaBundle\Exception\InvalidArgumentTypeException; class Provider extends AbstractProvider { + const ENTITY_ALIAS = 'a'; + /** * @see FOS\ElasticaBundle\Doctrine\AbstractProvider::countObjects() */ @@ -40,6 +42,24 @@ class Provider extends AbstractProvider throw new InvalidArgumentTypeException($queryBuilder, 'Doctrine\ORM\QueryBuilder'); } + /** + * An orderBy DQL part is required to avoid feching the same row twice. + * @see http://stackoverflow.com/questions/6314879/does-limit-offset-length-require-order-by-for-pagination + * @see http://www.postgresql.org/docs/current/static/queries-limit.html + * @see http://www.sqlite.org/lang_select.html#orderby + */ + $orderBy = $queryBuilder->getDQLPart('orderBy'); + if (empty($orderBy)) { + $identifierFieldNames = $this->managerRegistry + ->getManagerForClass($this->objectClass) + ->getClassMetadata($this->objectClass) + ->getIdentifierFieldNames(); + sort($identifierFieldNames); + foreach ($identifierFieldNames as $fieldName) { + $queryBuilder->addOrderBy(static::ENTITY_ALIAS.'.'.$fieldName); + } + } + return $queryBuilder ->setFirstResult($offset) ->setMaxResults($limit) @@ -56,6 +76,6 @@ class Provider extends AbstractProvider ->getManagerForClass($this->objectClass) ->getRepository($this->objectClass) // ORM query builders require an alias argument - ->{$this->options['query_builder_method']}('a'); + ->{$this->options['query_builder_method']}(static::ENTITY_ALIAS); } } From 7f3cfa49fb3f569d6a2d733221317992b54e17a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20J=2E=20Garc=C3=ADa=20Lagar?= Date: Wed, 19 Jun 2013 13:57:15 +0200 Subject: [PATCH 051/447] Make the property param optional --- DependencyInjection/Configuration.php | 4 +-- README.md | 6 +++++ .../ModelToElasticaAutoTransformerTest.php | 25 +++++++++++++++++++ .../ModelToElasticaAutoTransformer.php | 5 ++-- 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index da63a2d..f9f633f 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -511,7 +511,7 @@ class Configuration implements ConfigurationInterface return $node; } - + /** * Returns the array node used for "_parent". */ @@ -523,7 +523,7 @@ class Configuration implements ConfigurationInterface $node ->children() ->scalarNode('type')->end() - ->scalarNode('property')->end() + ->scalarNode('property')->defaultValue(null)->end() ->scalarNode('identifier')->defaultValue('id')->end() ->end() ; diff --git a/README.md b/README.md index 47789b7..0b6c3af 100644 --- a/README.md +++ b/README.md @@ -182,6 +182,12 @@ per type. content: ~ _parent: { type: "post", property: "post", identifier: "id" } +The parent filed declaration has the following values: + + * `type`: The parent type. + * `property`: The property in the child entity where to look for the parent entity. It may be ignored if is equal to the parent type. + * `identifier`: The property in the parent entity which have the parent identifier. Defaults to `id`. + ### Declaring `nested` or `object` fos_elastica: diff --git a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php index 8b6b3ae..9990fa2 100644 --- a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php +++ b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php @@ -106,6 +106,11 @@ class POPO { return (object) array('id' => 'parent', 'name' => 'a random name'); } + + public function getUpperAlias() + { + return $this->getUpper(); + } } class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase @@ -288,6 +293,26 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase $this->assertEquals("a random name", $document->getParent()); } + public function testParentMappingWithNullProperty() + { + $transformer = $this->getTransformer(); + $document = $transformer->transform(new POPO(), array( + '_parent' => array('type' => 'upper', 'property'=>null, 'identifier' => 'id'), + )); + + $this->assertEquals("parent", $document->getParent()); + } + + public function testParentMappingWithCustomProperty() + { + $transformer = $this->getTransformer(); + $document = $transformer->transform(new POPO(), array( + '_parent' => array('type' => 'upper', 'property'=>'upperAlias', 'identifier' => 'id'), + )); + + $this->assertEquals("parent", $document->getParent()); + } + /** * @return ModelToElasticaAutoTransformer */ diff --git a/Transformer/ModelToElasticaAutoTransformer.php b/Transformer/ModelToElasticaAutoTransformer.php index 5d8701a..d99f301 100644 --- a/Transformer/ModelToElasticaAutoTransformer.php +++ b/Transformer/ModelToElasticaAutoTransformer.php @@ -63,11 +63,12 @@ class ModelToElasticaAutoTransformer implements ModelToElasticaTransformerInterf foreach ($fields as $key => $mapping) { if ($key == '_parent') { - $value = $this->propertyAccessor->getValue($object, $mapping['property']); + $property = (null !== $mapping['property'])?$mapping['property']:$mapping['type']; + $value = $this->propertyAccessor->getValue($object, $property); $document->setParent($this->propertyAccessor->getValue($value, $mapping['identifier'])); continue; } - + $value = $this->propertyAccessor->getValue($object, $key); if (isset($mapping['type']) && in_array($mapping['type'], array('nested', 'object'))) { From 8b785c57c3d33be4e00e87bd2c77bcac35c03aac Mon Sep 17 00:00:00 2001 From: Tobias Schultze Date: Mon, 24 Jun 2013 18:44:46 +0300 Subject: [PATCH 052/447] Allow elastica 0.90. Elasticsearch made the jump from 0.20 to 0.90 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 22e492e..099868b 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ "symfony/console": "~2.1", "symfony/form": "~2.1", "symfony/property-access": "~2.2", - "ruflin/elastica": "0.20.5.*@dev", + "ruflin/elastica": "~0.20", "psr/log": "~1.0" }, "require-dev":{ From 170864a30d2f2bc451dbb794c78d51bd735e31d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20J=2E=20Garc=C3=ADa=20Lagar?= Date: Thu, 4 Jul 2013 08:07:00 +0200 Subject: [PATCH 053/447] Removes sort call --- Doctrine/ORM/Provider.php | 1 - 1 file changed, 1 deletion(-) diff --git a/Doctrine/ORM/Provider.php b/Doctrine/ORM/Provider.php index cbd69f0..3549550 100644 --- a/Doctrine/ORM/Provider.php +++ b/Doctrine/ORM/Provider.php @@ -54,7 +54,6 @@ class Provider extends AbstractProvider ->getManagerForClass($this->objectClass) ->getClassMetadata($this->objectClass) ->getIdentifierFieldNames(); - sort($identifierFieldNames); foreach ($identifierFieldNames as $fieldName) { $queryBuilder->addOrderBy(static::ENTITY_ALIAS.'.'.$fieldName); } From 9beb2777458771763cadb969646d83cbdbf5f8fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3th?= Date: Thu, 4 Jul 2013 18:47:58 +0200 Subject: [PATCH 054/447] Remove unused parameter from ModelToElasticaAutoTransformer.php --- Transformer/ModelToElasticaAutoTransformer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Transformer/ModelToElasticaAutoTransformer.php b/Transformer/ModelToElasticaAutoTransformer.php index 38bd065..559bb59 100644 --- a/Transformer/ModelToElasticaAutoTransformer.php +++ b/Transformer/ModelToElasticaAutoTransformer.php @@ -76,7 +76,7 @@ class ModelToElasticaAutoTransformer implements ModelToElasticaTransformerInterf /* $value is a nested document or object. Transform $value into * an array of documents, respective the mapped properties. */ - $document->add($key, $this->transformNested($value, $mapping['properties'], $document)); + $document->add($key, $this->transformNested($value, $mapping['properties'])); continue; } From 9e2e8ab1c94e937f35378bdb5e291817941157fb Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Fri, 12 Jul 2013 17:32:33 -0400 Subject: [PATCH 055/447] Fix missing getter for private field test for PropertyAccess 2.3+ See: https://github.com/symfony/PropertyAccess/commit/df67239b02a9cef12cf84579f6cf569680298238 --- .../ModelToElasticaAutoTransformerTest.php | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php index 798ea38..daa6512 100644 --- a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php +++ b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php @@ -203,10 +203,17 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase public function testThatCannotTransformObjectWhenGetterDoesNotExistForPrivateMethod() { - // Support both Symfony 2.1 (Form component) and 2.2 (PropertyAccess component) - $expectedException = class_exists('Symfony\Component\PropertyAccess\PropertyAccess') - ? 'Symfony\Component\PropertyAccess\Exception\PropertyAccessDeniedException' - : 'Symfony\Component\Form\Exception\PropertyAccessDeniedException'; + // Support both Symfony 2.1 (Form component) and 2.2+ (PropertyAccess component) + if (class_exists('Symfony\Component\PropertyAccess\PropertyAccess')) { + /* ProperyAccess 2.3+ removed PropertyAccessDeniedException, so we + * must expect NoSuchPropertyException in its absence. + */ + $expectedException = class_exists('Symfony\Component\Form\Exception\PropertyAccessDeniedException') + ? 'Symfony\Component\Form\Exception\PropertyAccessDeniedException' + : 'Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException'; + } else { + $expectedException = 'Symfony\Component\Form\Exception\PropertyAccessDeniedException'; + } $this->setExpectedException($expectedException); From cce1ffb06c519d59c00322687d507aea2dc7dd54 Mon Sep 17 00:00:00 2001 From: RobertPlant Date: Fri, 14 Jun 2013 11:28:19 +0200 Subject: [PATCH 056/447] Add filtered query example to README.md --- README.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/README.md b/README.md index e575f88..2c1aef2 100644 --- a/README.md +++ b/README.md @@ -754,3 +754,32 @@ fos_elastica: provider: finder: ``` + +### Filtering Results and executing a default query + +You may want to remove a certain section of results from a query, filtering is ideal because it is slightly faster in performance compared to a standard query because the only the filtered subset of results are cached. This improves query speed because the query is ran against the predetermined subset from previous queries rather than recalculating the whole query again. Filtering can effectively when trying to look for only active records which are indicated by a field in the database. `FilteredQuery` should be used to combine the `QueryString` operator with the `Filter`, an example of `FilteredQuery` is shown Below. + +```php +$term = new \Elastica\Filter\Term(); +$term->setParams(array( + 'active' => 'active', + 'address.postCode' => $postCode //Accessing elements nested within an object. address is the object and postCode is the property within it. + 'companyGroup' => $department + )); + +$query = new \Elastica\Query\QueryString(); +$query->setQuery($queryString); + +$filteredQuery = new \Elastica\Query\Filtered($query, $term); + +$results = $this->container->get('fos_elastica.finder.company.company')->findPaginated($filteredQuery); + +// Filter results for paging +$results->setMaxPerPage($limit); +$results->setCurrentPage($page); + +// Number of total results for paging +$total = $results->getNbResults(); + +``` + From 00f37835fc554e976710482be5d811e9c791ccc1 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 16 Jul 2013 13:33:21 -0400 Subject: [PATCH 057/447] Rewrite filtered query example in README Cleaning up the description paragraph and removing extra fields and pagination from the example, since we already have pagination examples elsewhere in the README. --- README.md | 32 ++++++++++---------------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 2c1aef2..ccae8db 100644 --- a/README.md +++ b/README.md @@ -755,31 +755,19 @@ fos_elastica: finder: ``` -### Filtering Results and executing a default query +### Filtering Results and Executing a Default Query -You may want to remove a certain section of results from a query, filtering is ideal because it is slightly faster in performance compared to a standard query because the only the filtered subset of results are cached. This improves query speed because the query is ran against the predetermined subset from previous queries rather than recalculating the whole query again. Filtering can effectively when trying to look for only active records which are indicated by a field in the database. `FilteredQuery` should be used to combine the `QueryString` operator with the `Filter`, an example of `FilteredQuery` is shown Below. +If may want to omit certain results from a query, filtering can be more +performant than a basic query because the filter results can be cached. In turn, +the query is run against only a subset of the results. A common use case for +filtering would be if your data has fields that indicate whether records are +"active" or "inactive". The following example illustrates how to issue such a +query with Elastica: ```php -$term = new \Elastica\Filter\Term(); -$term->setParams(array( - 'active' => 'active', - 'address.postCode' => $postCode //Accessing elements nested within an object. address is the object and postCode is the property within it. - 'companyGroup' => $department - )); - -$query = new \Elastica\Query\QueryString(); -$query->setQuery($queryString); +$query = new \Elastica\Query\QueryString($queryString); +$term = new \Elastica\Filter\Term(array('active' => true)); $filteredQuery = new \Elastica\Query\Filtered($query, $term); - -$results = $this->container->get('fos_elastica.finder.company.company')->findPaginated($filteredQuery); - -// Filter results for paging -$results->setMaxPerPage($limit); -$results->setCurrentPage($page); - -// Number of total results for paging -$total = $results->getNbResults(); - +$results = $this->container->get('fos_elastica.finder.index.type')->find($filteredQuery); ``` - From 5b6a1f7bd656f6c8490035aa309334cdce415457 Mon Sep 17 00:00:00 2001 From: Lea Haensenberger Date: Wed, 17 Jul 2013 08:58:15 +0200 Subject: [PATCH 058/447] Adding new persister and new transformer to make use of the serializer support of elastica when persisting doctrine objects --- DependencyInjection/FOSElasticaExtension.php | 47 ++++++--- Persister/ObjectSerializerPersister.php | 97 +++++++++++++++++++ Resources/config/config.xml | 13 +++ .../ModelToElasticaIdentifierTransformer.php | 26 +++++ 4 files changed, 169 insertions(+), 14 deletions(-) create mode 100644 Persister/ObjectSerializerPersister.php create mode 100644 Transformer/ModelToElasticaIdentifierTransformer.php diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index c28fb99..9a15a83 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -16,6 +16,7 @@ class FOSElasticaExtension extends Extension protected $indexConfigs = array(); protected $typeFields = array(); protected $loadedDrivers = array(); + protected $serializerConfig = array(); public function load(array $configs, ContainerBuilder $container) { @@ -40,8 +41,8 @@ class FOSElasticaExtension extends Extension } $clientIdsByName = $this->loadClients($config['clients'], $container); - $serializerConfig = isset($config['serializer']) ? $config['serializer'] : null; - $indexIdsByName = $this->loadIndexes($config['indexes'], $container, $clientIdsByName, $config['default_client'], $serializerConfig); + $this->serializerConfig = isset($config['serializer']) ? $config['serializer'] : null; + $indexIdsByName = $this->loadIndexes($config['indexes'], $container, $clientIdsByName, $config['default_client']); $indexRefsByName = array_map(function($id) { return new Reference($id); }, $indexIdsByName); @@ -94,7 +95,7 @@ class FOSElasticaExtension extends Extension * @throws \InvalidArgumentException * @return array */ - protected function loadIndexes(array $indexes, ContainerBuilder $container, array $clientIdsByName, $defaultClientName, $serializerConfig) + protected function loadIndexes(array $indexes, ContainerBuilder $container, array $clientIdsByName, $defaultClientName) { $indexIds = array(); foreach ($indexes as $name => $index) { @@ -129,7 +130,7 @@ class FOSElasticaExtension extends Extension if (!empty($index['settings'])) { $this->indexConfigs[$name]['config']['settings'] = $index['settings']; } - $this->loadTypes(isset($index['types']) ? $index['types'] : array(), $container, $name, $indexId, $typePrototypeConfig, $serializerConfig); + $this->loadTypes(isset($index['types']) ? $index['types'] : array(), $container, $name, $indexId, $typePrototypeConfig); } return $indexIds; @@ -170,7 +171,7 @@ class FOSElasticaExtension extends Extension * @param $indexId * @param array $typePrototypeConfig */ - protected function loadTypes(array $types, ContainerBuilder $container, $indexName, $indexId, array $typePrototypeConfig, $serializerConfig) + protected function loadTypes(array $types, ContainerBuilder $container, $indexName, $indexId, array $typePrototypeConfig) { foreach ($types as $name => $type) { $type = self::deepArrayUnion($typePrototypeConfig, $type); @@ -179,12 +180,12 @@ class FOSElasticaExtension extends Extension $typeDef = new Definition('%fos_elastica.type.class%', $typeDefArgs); $typeDef->setFactoryService($indexId); $typeDef->setFactoryMethod('getType'); - if ($serializerConfig) { - $callbackDef = new Definition($serializerConfig['callback_class']); + if ($this->serializerConfig) { + $callbackDef = new Definition($this->serializerConfig['callback_class']); $callbackId = sprintf('%s.%s.serializer.callback', $indexId, $name); $typeDef->addMethodCall('setSerializer', array(array(new Reference($callbackId), 'serialize'))); - $callbackDef->addMethodCall('setSerializer', array(new Reference($serializerConfig['serializer']))); + $callbackDef->addMethodCall('setSerializer', array(new Reference($this->serializerConfig['serializer']))); if (isset($type['serializer']['groups'])) { $callbackDef->addMethodCall('setGroups', array($type['serializer']['groups'])); } @@ -307,7 +308,11 @@ class FOSElasticaExtension extends Extension if (isset($typeConfig['model_to_elastica_transformer']['service'])) { return $typeConfig['model_to_elastica_transformer']['service']; } - $abstractId = sprintf('fos_elastica.model_to_elastica_transformer.prototype.auto'); + if ($this->serializerConfig) { + $abstractId = sprintf('fos_elastica.model_to_elastica_transformer.prototype.identifier'); + } else { + $abstractId = sprintf('fos_elastica.model_to_elastica_transformer.prototype.auto'); + } $serviceId = sprintf('fos_elastica.model_to_elastica_transformer.%s.%s', $indexName, $typeName); $serviceDef = new DefinitionDecorator($abstractId); $serviceDef->replaceArgument(0, array( @@ -320,13 +325,27 @@ class FOSElasticaExtension extends Extension protected function loadObjectPersister(array $typeConfig, Definition $typeDef, ContainerBuilder $container, $indexName, $typeName, $transformerId) { - $abstractId = sprintf('fos_elastica.object_persister.prototype'); + if ($this->serializerConfig) { + $abstractId = sprintf('fos_elastica.object_serializer_persister.prototype'); + $arguments = array( + $typeDef, + new Reference($transformerId), + $typeConfig['model'], + ); + } else { + $abstractId = sprintf('fos_elastica.object_persister.prototype'); + $arguments = array( + $typeDef, + new Reference($transformerId), + $typeConfig['model'], + $this->typeFields[sprintf('%s/%s', $indexName, $typeName)], + ); + } $serviceId = sprintf('fos_elastica.object_persister.%s.%s', $indexName, $typeName); $serviceDef = new DefinitionDecorator($abstractId); - $serviceDef->replaceArgument(0, $typeDef); - $serviceDef->replaceArgument(1, new Reference($transformerId)); - $serviceDef->replaceArgument(2, $typeConfig['model']); - $serviceDef->replaceArgument(3, $this->typeFields[sprintf('%s/%s', $indexName, $typeName)]); + foreach ($arguments as $i => $argument) { + $serviceDef->replaceArgument($i, $argument); + } $container->setDefinition($serviceId, $serviceDef); return $serviceId; diff --git a/Persister/ObjectSerializerPersister.php b/Persister/ObjectSerializerPersister.php new file mode 100644 index 0000000..db8122a --- /dev/null +++ b/Persister/ObjectSerializerPersister.php @@ -0,0 +1,97 @@ + + */ +class ObjectSerializerPersister extends ObjectPersister +{ + public function __construct(Type $type, ModelToElasticaTransformerInterface $transformer, $objectClass) + { + $this->type = $type; + $this->transformer = $transformer; + $this->objectClass = $objectClass; + } + + /** + * Insert one object into the type + * The object will be transformed to an elastica document + * + * @param object $object + */ + public function insertOne($object) + { + $document = $this->transformToElasticaDocument($object); + $this->type->addObject($object, $document); + } + + /** + * Replaces one object in the type + * + * @param object $object + * @return null + **/ + public function replaceOne($object) + { + $document = $this->transformToElasticaDocument($object); + $this->type->deleteById($document->getId()); + $this->type->addObject($object, $document); + } + + /** + * Deletes one object in the type + * + * @param object $object + * @return null + **/ + public function deleteOne($object) + { + $document = $this->transformToElasticaDocument($object); + $this->type->deleteById($document->getId()); + } + + /** + * Deletes one object in the type by id + * + * @param mixed $id + * + * @return null + **/ + public function deleteById($id) + { + $this->type->deleteById($id); + } + + + /** + * Inserts an array of objects in the type + * + * @param array $objects array of domain model objects + **/ + public function insertMany(array $objects) + { + foreach ($objects as $object) { + $this->insertOne($object); + } + } + + /** + * Transforms an object to an elastica document + * with just the identifier set + * + * @param object $object + * @return Document the elastica document + */ + public function transformToElasticaDocument($object) + { + return $this->transformer->transform($object, array()); + } +} diff --git a/Resources/config/config.xml b/Resources/config/config.xml index 4097289..3f5f7cf 100644 --- a/Resources/config/config.xml +++ b/Resources/config/config.xml @@ -52,6 +52,12 @@ + + + + + + @@ -64,6 +70,13 @@ + + + + + + + diff --git a/Transformer/ModelToElasticaIdentifierTransformer.php b/Transformer/ModelToElasticaIdentifierTransformer.php new file mode 100644 index 0000000..416eaf7 --- /dev/null +++ b/Transformer/ModelToElasticaIdentifierTransformer.php @@ -0,0 +1,26 @@ +propertyAccessor->getValue($object, $this->options['identifier']); + return new Document($identifier); + } +} From d10e8f56c8b7e1374dae924e1a0efd2067986208 Mon Sep 17 00:00:00 2001 From: Lea Haensenberger Date: Wed, 17 Jul 2013 10:10:07 +0200 Subject: [PATCH 059/447] Tests for new provider and new transformer --- .../ObjectSerializerPersisterTest.php | 117 ++++++++++++++++++ ...delToElasticaIdentifierTransformerTest.php | 66 ++++++++++ 2 files changed, 183 insertions(+) create mode 100644 Tests/Persister/ObjectSerializerPersisterTest.php create mode 100644 Tests/Transformer/ModelToElasticaIdentifierTransformerTest.php diff --git a/Tests/Persister/ObjectSerializerPersisterTest.php b/Tests/Persister/ObjectSerializerPersisterTest.php new file mode 100644 index 0000000..10c63ab --- /dev/null +++ b/Tests/Persister/ObjectSerializerPersisterTest.php @@ -0,0 +1,117 @@ +id; + } + + public function getName() + { + return $this->name; + } +} + +class ObjectSerializerPersisterTest extends \PHPUnit_Framework_TestCase +{ + public function setUp() + { + if (!class_exists('Elastica\Type')) { + $this->markTestSkipped('The Elastica library classes are not available'); + } + } + + public function testThatCanReplaceObject() + { + $transformer = $this->getTransformer(); + + /** @var $typeMock \PHPUnit_Framework_MockObject_MockObject|\Elastica\Type */ + $typeMock = $this->getMockBuilder('Elastica\Type') + ->disableOriginalConstructor() + ->getMock(); + $typeMock->expects($this->once()) + ->method('deleteById') + ->with($this->equalTo(123)); + $typeMock->expects($this->once()) + ->method('addObject'); + + $objectPersister = new ObjectSerializerPersister($typeMock, $transformer, 'SomeClass'); + $objectPersister->replaceOne(new POPO()); + } + + public function testThatCanInsertObject() + { + $transformer = $this->getTransformer(); + + /** @var $typeMock \PHPUnit_Framework_MockObject_MockObject|\Elastica\Type */ + $typeMock = $this->getMockBuilder('Elastica\Type') + ->disableOriginalConstructor() + ->getMock(); + $typeMock->expects($this->never()) + ->method('deleteById'); + $typeMock->expects($this->once()) + ->method('addObject'); + + $objectPersister = new ObjectSerializerPersister($typeMock, $transformer, 'SomeClass'); + $objectPersister->insertOne(new POPO()); + } + + public function testThatCanDeleteObject() + { + $transformer = $this->getTransformer(); + + /** @var $typeMock \PHPUnit_Framework_MockObject_MockObject|\Elastica\Type */ + $typeMock = $this->getMockBuilder('Elastica\Type') + ->disableOriginalConstructor() + ->getMock(); + $typeMock->expects($this->once()) + ->method('deleteById'); + $typeMock->expects($this->never()) + ->method('addObject'); + + $objectPersister = new ObjectSerializerPersister($typeMock, $transformer, 'SomeClass'); + $objectPersister->deleteOne(new POPO()); + } + + public function testThatCanInsertManyObjects() + { + $transformer = $this->getTransformer(); + + /** @var $typeMock \PHPUnit_Framework_MockObject_MockObject|\Elastica\Type */ + $typeMock = $this->getMockBuilder('Elastica\Type') + ->disableOriginalConstructor() + ->getMock(); + $typeMock->expects($this->never()) + ->method('deleteById'); + $typeMock->expects($this->exactly(2)) + ->method('addObject'); + $typeMock->expects($this->never()) + ->method('addObjects'); + + $objectPersister = new ObjectSerializerPersister($typeMock, $transformer, 'SomeClass'); + $objectPersister->insertMany(array(new POPO(), new POPO())); + } + + /** + * @return ModelToElasticaIdentifierTransformer + */ + private function getTransformer() + { + $transformer = new ModelToElasticaIdentifierTransformer(); + $transformer->setPropertyAccessor(PropertyAccess::getPropertyAccessor()); + + return $transformer; + } +} diff --git a/Tests/Transformer/ModelToElasticaIdentifierTransformerTest.php b/Tests/Transformer/ModelToElasticaIdentifierTransformerTest.php new file mode 100644 index 0000000..59a747a --- /dev/null +++ b/Tests/Transformer/ModelToElasticaIdentifierTransformerTest.php @@ -0,0 +1,66 @@ +id; + } + + public function getName() + { + return $this->name; + } +} + +class ModelToElasticaIdentifierTransformerTest extends \PHPUnit_Framework_TestCase +{ + public function setUp() + { + if (!class_exists('Elastica\Document')) { + ; + $this->markTestSkipped('The Elastica library classes are not available'); + } + } + + public function testGetDocumentWithIdentifierOnly() + { + $transformer = $this->getTransformer(); + $document = $transformer->transform(new POPO(), array()); + $data = $document->getData(); + + $this->assertInstanceOf('Elastica\Document', $document); + $this->assertEquals(123, $document->getId()); + $this->assertCount(0, $data); + } + + public function testGetDocumentWithIdentifierOnlyWithFields() + { + $transformer = $this->getTransformer(); + $document = $transformer->transform(new POPO(), array('name' => array())); + $data = $document->getData(); + + $this->assertInstanceOf('Elastica\Document', $document); + $this->assertEquals(123, $document->getId()); + $this->assertCount(0, $data); + } + + /** + * @return ModelToElasticaIdentifierTransformer + */ + private function getTransformer() + { + $transformer = new ModelToElasticaIdentifierTransformer(); + $transformer->setPropertyAccessor(PropertyAccess::getPropertyAccessor()); + + return $transformer; + } +} From ab0c27c4819bba166511bde3705861ca68001717 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 17 Jul 2013 15:53:32 -0400 Subject: [PATCH 060/447] Fix expected exception class (related to #338) This corrects a typo in a66a37aebd7424e9a82e81bd1a3760abb735ea7e. --- Tests/Transformer/ModelToElasticaAutoTransformerTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php index daa6512..cb980da 100644 --- a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php +++ b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php @@ -208,8 +208,8 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase /* ProperyAccess 2.3+ removed PropertyAccessDeniedException, so we * must expect NoSuchPropertyException in its absence. */ - $expectedException = class_exists('Symfony\Component\Form\Exception\PropertyAccessDeniedException') - ? 'Symfony\Component\Form\Exception\PropertyAccessDeniedException' + $expectedException = class_exists('Symfony\Component\PropertyAccess\Exception\PropertyAccessDeniedException') + ? 'Symfony\Component\PropertyAccess\Exception\PropertyAccessDeniedException' : 'Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException'; } else { $expectedException = 'Symfony\Component\Form\Exception\PropertyAccessDeniedException'; From 300d189a9d62559c2fc7c65d1cef03f060cc7d9f Mon Sep 17 00:00:00 2001 From: Lea Haensenberger Date: Thu, 18 Jul 2013 10:51:51 +0200 Subject: [PATCH 061/447] renaming services to avoid potential conflicts --- DependencyInjection/FOSElasticaExtension.php | 4 ++-- Resources/config/config.xml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 9a15a83..e0f7a2d 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -309,7 +309,7 @@ class FOSElasticaExtension extends Extension return $typeConfig['model_to_elastica_transformer']['service']; } if ($this->serializerConfig) { - $abstractId = sprintf('fos_elastica.model_to_elastica_transformer.prototype.identifier'); + $abstractId = sprintf('fos_elastica.model_to_elastica_identifier_transformer'); } else { $abstractId = sprintf('fos_elastica.model_to_elastica_transformer.prototype.auto'); } @@ -326,7 +326,7 @@ class FOSElasticaExtension extends Extension protected function loadObjectPersister(array $typeConfig, Definition $typeDef, ContainerBuilder $container, $indexName, $typeName, $transformerId) { if ($this->serializerConfig) { - $abstractId = sprintf('fos_elastica.object_serializer_persister.prototype'); + $abstractId = sprintf('fos_elastica.object_serializer_persister'); $arguments = array( $typeDef, new Reference($transformerId), diff --git a/Resources/config/config.xml b/Resources/config/config.xml index 3f5f7cf..4d85d9f 100644 --- a/Resources/config/config.xml +++ b/Resources/config/config.xml @@ -52,7 +52,7 @@ - + @@ -70,7 +70,7 @@ - + From 77156b35aa0f70420b555151d9700591de1f6fc8 Mon Sep 17 00:00:00 2001 From: Lea Haensenberger Date: Thu, 18 Jul 2013 10:54:11 +0200 Subject: [PATCH 062/447] some formatting and cleaning up --- Persister/ObjectSerializerPersister.php | 8 ++++---- Tests/Transformer/ModelToElasticaAutoTransformerTest.php | 1 - .../ModelToElasticaIdentifierTransformerTest.php | 1 - Transformer/ModelToElasticaIdentifierTransformer.php | 4 ++-- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/Persister/ObjectSerializerPersister.php b/Persister/ObjectSerializerPersister.php index db8122a..269515b 100644 --- a/Persister/ObjectSerializerPersister.php +++ b/Persister/ObjectSerializerPersister.php @@ -16,9 +16,9 @@ class ObjectSerializerPersister extends ObjectPersister { public function __construct(Type $type, ModelToElasticaTransformerInterface $transformer, $objectClass) { - $this->type = $type; - $this->transformer = $transformer; - $this->objectClass = $objectClass; + $this->type = $type; + $this->transformer = $transformer; + $this->objectClass = $objectClass; } /** @@ -38,7 +38,7 @@ class ObjectSerializerPersister extends ObjectPersister * * @param object $object * @return null - **/ + */ public function replaceOne($object) { $document = $this->transformToElasticaDocument($object); diff --git a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php index cbcb6bd..16bb5cd 100644 --- a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php +++ b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php @@ -113,7 +113,6 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase public function setUp() { if (!class_exists('Elastica\Document')) { - ; $this->markTestSkipped('The Elastica library classes are not available'); } } diff --git a/Tests/Transformer/ModelToElasticaIdentifierTransformerTest.php b/Tests/Transformer/ModelToElasticaIdentifierTransformerTest.php index 59a747a..f1a77d4 100644 --- a/Tests/Transformer/ModelToElasticaIdentifierTransformerTest.php +++ b/Tests/Transformer/ModelToElasticaIdentifierTransformerTest.php @@ -26,7 +26,6 @@ class ModelToElasticaIdentifierTransformerTest extends \PHPUnit_Framework_TestCa public function setUp() { if (!class_exists('Elastica\Document')) { - ; $this->markTestSkipped('The Elastica library classes are not available'); } } diff --git a/Transformer/ModelToElasticaIdentifierTransformer.php b/Transformer/ModelToElasticaIdentifierTransformer.php index 416eaf7..654850f 100644 --- a/Transformer/ModelToElasticaIdentifierTransformer.php +++ b/Transformer/ModelToElasticaIdentifierTransformer.php @@ -5,8 +5,8 @@ namespace FOS\ElasticaBundle\Transformer; use Elastica\Document; /** - * Creates an elastica document with the id of - * the doctrine object as elastica document id + * Creates an Elastica document with the ID of + * the Doctrine object as Elastica document ID */ class ModelToElasticaIdentifierTransformer extends ModelToElasticaAutoTransformer { From 37cfdb0df79298ece68280984a8313e71a58fde0 Mon Sep 17 00:00:00 2001 From: Lea Haensenberger Date: Thu, 18 Jul 2013 10:56:25 +0200 Subject: [PATCH 063/447] refactoring some code --- DependencyInjection/FOSElasticaExtension.php | 21 ++++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index e0f7a2d..68e21dd 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -325,21 +325,16 @@ class FOSElasticaExtension extends Extension protected function loadObjectPersister(array $typeConfig, Definition $typeDef, ContainerBuilder $container, $indexName, $typeName, $transformerId) { + $arguments = array( + $typeDef, + new Reference($transformerId), + $typeConfig['model'], + ); if ($this->serializerConfig) { - $abstractId = sprintf('fos_elastica.object_serializer_persister'); - $arguments = array( - $typeDef, - new Reference($transformerId), - $typeConfig['model'], - ); + $abstractId = 'fos_elastica.object_serializer_persister'; } else { - $abstractId = sprintf('fos_elastica.object_persister.prototype'); - $arguments = array( - $typeDef, - new Reference($transformerId), - $typeConfig['model'], - $this->typeFields[sprintf('%s/%s', $indexName, $typeName)], - ); + $abstractId = 'fos_elastica.object_persister.prototype'; + $arguments[] = $this->typeFields[sprintf('%s/%s', $indexName, $typeName)]; } $serviceId = sprintf('fos_elastica.object_persister.%s.%s', $indexName, $typeName); $serviceDef = new DefinitionDecorator($abstractId); From 617b9d3f4b025ba38f33bfa3989f8fa451982dff Mon Sep 17 00:00:00 2001 From: NicolasBadey Date: Wed, 17 Jul 2013 13:35:55 +0200 Subject: [PATCH 064/447] Recalculate pagination Query size if a limit is already set --- Paginator/RawPaginatorAdapter.php | 39 +++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/Paginator/RawPaginatorAdapter.php b/Paginator/RawPaginatorAdapter.php index 3ed8638..ab92dd4 100644 --- a/Paginator/RawPaginatorAdapter.php +++ b/Paginator/RawPaginatorAdapter.php @@ -8,6 +8,7 @@ use Elastica\ResultSet; use FOS\ElasticaBundle\Paginator\PaginatorAdapterInterface; use FOS\ElasticaBundle\Paginator\RawPartialResults; use FOS\ElasticaBundle\Paginator\PartialResultsInterface; +use InvalidArgumentException; /** * Allows pagination of Elastica\Query. Does not map results @@ -17,12 +18,17 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface /** * @var SearchableInterface the object to search in */ - private $searchable = null; + private $searchable; /** * @var Query the query to search */ - private $query = null; + private $query; + + /** + * @var integer the number of hits + */ + private $totalHits; /** * @see PaginatorAdapterInterface::__construct @@ -45,11 +51,28 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface */ protected function getElasticaResults($offset, $itemCountPerPage) { + $offset = (integer) $offset; + $itemCountPerPage = (integer) $itemCountPerPage; + $size = $this->query->hasParam('size') + ? (integer) $this->query->getParam('size') + : null; + + if ($size && $size < $offset + $itemCountPerPage) { + $itemCountPerPage = $size - $offset; + } + + if ($itemCountPerPage < 1) { + throw new InvalidArgumentException('$itemCountPerPage must be greater than zero'); + } + $query = clone $this->query; $query->setFrom($offset); - $query->setLimit($itemCountPerPage); + $query->setSize($itemCountPerPage); - return $this->searchable->search($query); + $resultSet = $this->searchable->search($query); + $this->totalHits = $resultSet->getTotalHits(); + + return $resultSet; } /** @@ -71,6 +94,12 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface */ public function getTotalHits() { - return $this->searchable->search($this->query)->getTotalHits(); + if ( ! isset($this->totalHits)) { + $this->totalHits = $this->searchable->search($this->query)->getTotalHits(); + } + + return $this->query->hasParam('size') + ? min($this->totalHits, (integer) $this->query->getParam('size')) + : $this->totalHits; } } From e2b6177a33050a7dcfcb424e0c9697d81f840221 Mon Sep 17 00:00:00 2001 From: cedric lombardot Date: Tue, 6 Aug 2013 20:48:38 +0200 Subject: [PATCH 065/447] Fix ElasticaToModelTransformer the transform closure use Result instead of Document --- Propel/ElasticaToModelTransformer.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Propel/ElasticaToModelTransformer.php b/Propel/ElasticaToModelTransformer.php index 4f006a7..952673b 100644 --- a/Propel/ElasticaToModelTransformer.php +++ b/Propel/ElasticaToModelTransformer.php @@ -2,7 +2,6 @@ namespace FOS\ElasticaBundle\Propel; -use Elastica\Document; use FOS\ElasticaBundle\HybridResult; use FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; @@ -71,9 +70,10 @@ class ElasticaToModelTransformer implements ElasticaToModelTransformerInterface */ public function transform(array $elasticaObjects) { - $ids = array_map(function(Document $elasticaObject) { - return $elasticaObject->getId(); - }, $elasticaObjects); + $ids = array(); + foreach ($elasticaObjects as $elasticaObject) { + $ids[] = $elasticaObject->getId(); + } $objects = $this->findByIdentifiers($ids, $this->options['hydrate']); From c15caf309632c95b840e797a7ae54f501b1abe3b Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Fri, 9 Aug 2013 13:56:51 -0400 Subject: [PATCH 066/447] Code and documentation formatting in Propel transformer class --- Propel/ElasticaToModelTransformer.php | 67 ++++++++++++++------------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/Propel/ElasticaToModelTransformer.php b/Propel/ElasticaToModelTransformer.php index 952673b..af5f8ab 100644 --- a/Propel/ElasticaToModelTransformer.php +++ b/Propel/ElasticaToModelTransformer.php @@ -7,40 +7,41 @@ use FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; /** - * Maps Elastica documents with Propel objects - * This mapper assumes an exact match between - * elastica documents ids and propel object ids + * Maps Elastica documents with Propel objects. + * + * This mapper assumes an exact match between Elastica document IDs and Propel + * entity IDs. * * @author William Durand */ class ElasticaToModelTransformer implements ElasticaToModelTransformerInterface { /** - * Class of the model to map to the elastica documents + * Propel model class to map to Elastica documents. * * @var string */ protected $objectClass = null; /** - * Optional parameters + * Transformer options. * * @var array */ protected $options = array( 'hydrate' => true, - 'identifier' => 'id' + 'identifier' => 'id', ); /** - * PropertyAccessor instance + * PropertyAccessor instance. * * @var PropertyAccessorInterface */ protected $propertyAccessor; /** - * Instantiates a new Mapper + * Constructor. * * @param string $objectClass * @param array $options @@ -48,11 +49,11 @@ class ElasticaToModelTransformer implements ElasticaToModelTransformerInterface public function __construct($objectClass, array $options = array()) { $this->objectClass = $objectClass; - $this->options = array_merge($this->options, $options); + $this->options = array_merge($this->options, $options); } /** - * Set the PropertyAccessor + * Set the PropertyAccessor instance. * * @param PropertyAccessorInterface $propertyAccessor */ @@ -62,11 +63,11 @@ class ElasticaToModelTransformer implements ElasticaToModelTransformerInterface } /** - * Transforms an array of elastica objects into an array of - * model objects fetched from the propel repository + * Transforms an array of Elastica document into an array of Propel entities + * fetched from the database. * - * @param Document[] $elasticaObjects array of elastica objects - * @return array + * @param array $elasticaObjects + * @return array|\ArrayObject */ public function transform(array $elasticaObjects) { @@ -77,18 +78,19 @@ class ElasticaToModelTransformer implements ElasticaToModelTransformerInterface $objects = $this->findByIdentifiers($ids, $this->options['hydrate']); - // sort objects in the order of ids + // Sort objects in the order of their IDs $idPos = array_flip($ids); $identifier = $this->options['identifier']; $propertyAccessor = $this->propertyAccessor; + + $sortCallback = function($a, $b) use ($idPos, $identifier, $propertyAccessor) { + return $idPos[$propertyAccessor->getValue($a, $identifier)] > $idPos[$propertyAccessor->getValue($b, $identifier)]; + }; + if (is_object($objects)) { - $objects->uasort(function($a, $b) use ($idPos, $identifier, $propertyAccessor) { - return $idPos[$propertyAccessor->getValue($a, $identifier)] > $idPos[$propertyAccessor->getValue($b, $identifier)]; - }); + $objects->uasort($sortCallback); } else { - usort($objects, function($a, $b) use ($idPos, $identifier, $propertyAccessor) { - return $idPos[$propertyAccessor->getValue($a, $identifier)] > $idPos[$propertyAccessor->getValue($b, $identifier)]; - }); + usort($objects, $sortCallback); } return $objects; @@ -126,11 +128,14 @@ class ElasticaToModelTransformer implements ElasticaToModelTransformerInterface } /** - * Fetch objects for theses identifier values + * Fetch Propel entities for the given identifier values. * - * @param array $identifierValues ids values - * @param boolean $hydrate whether or not to hydrate the objects, false returns arrays - * @return array of objects or arrays + * If $hydrate is false, the returned array elements will be arrays. + * Otherwise, the results will be hydrated to instances of the model class. + * + * @param array $identifierValues Identifier values + * @param boolean $hydrate Whether or not to hydrate the results + * @return array */ protected function findByIdentifiers(array $identifierValues, $hydrate) { @@ -140,7 +145,7 @@ class ElasticaToModelTransformer implements ElasticaToModelTransformerInterface $query = $this->createQuery($this->objectClass, $this->options['identifier'], $identifierValues); - if (!$hydrate) { + if ( ! $hydrate) { return $query->toArray(); } @@ -150,9 +155,9 @@ class ElasticaToModelTransformer implements ElasticaToModelTransformerInterface /** * Create a query to use in the findByIdentifiers() method. * - * @param string $class the model class - * @param string $identifierField like 'id' - * @param array $identifierValues ids values + * @param string $class Propel model class + * @param string $identifierField Identifier field name (e.g. "id") + * @param array $identifierValues Identifier values * @return \ModelCriteria */ protected function createQuery($class, $identifierField, array $identifierValues) @@ -160,9 +165,7 @@ class ElasticaToModelTransformer implements ElasticaToModelTransformerInterface $queryClass = $class.'Query'; $filterMethod = 'filterBy'.$this->camelize($identifierField); - return $queryClass::create() - ->$filterMethod($identifierValues) - ; + return $queryClass::create()->$filterMethod($identifierValues); } /** From 79501dc319606971b2fa35b088ae23336e42f423 Mon Sep 17 00:00:00 2001 From: Richard Miller Date: Mon, 12 Aug 2013 11:04:54 +0100 Subject: [PATCH 067/447] Add moreLikeThis query to finder --- Finder/TransformedFinder.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Finder/TransformedFinder.php b/Finder/TransformedFinder.php index e1eade8..c520f08 100644 --- a/Finder/TransformedFinder.php +++ b/Finder/TransformedFinder.php @@ -45,6 +45,22 @@ class TransformedFinder implements PaginatedFinderInterface return $this->transformer->hybridTransform($results); } + /** + * Find documents similar to one with passed id. + * + * @param integer $id + * @param array $params + * @param array $query + * @return array of model objects + **/ + public function moreLikeThis($id, $params = array(), $query = array()) + { + $doc = new Document($id); + $results = $this->searchable->moreLikeThis($doc, $params, $query)->getResults(); + + return $this->transformer->transform($results); + } + /** * @param $query * @param null|int $limit From e97b60fc7e4315a7ae62174f000f620bb1ae0203 Mon Sep 17 00:00:00 2001 From: Richard Fullmer Date: Tue, 4 Jun 2013 11:45:45 -0700 Subject: [PATCH 068/447] Ignore failed deletions in ObjectPersister This probably isn't the best way to solve my problem, but the issue is this. Step 1: Create a new doctrine entity for which it's `is_indexable_callback` returns false. When doctrine flushes this entity to the database, elastia will not index it with elastic search. (Correct) Step 2: Update your doctrine entity and change some fields so that `is_indexable_callback` _still_ returns false. Persist and flush to the database. At this point, the postUpdate listener on ElastiaBundle is called and since the `is_indexable_callback` returns false, it believes it needs to remove it from the elastic search index and queues it for deletion. The deletion of course fails because it was never there in the first place. This solution simply ignores failures from deletions in the index. Perhaps a better solution would be to have a smarter listener that could determine if the entity was previously present in the elastic search index or not, but that would require significant refactoring. Addresses issues discuseed in #284 Credit to @bbeaulant for simple solution. Opening a PR to discuss more generally. --- Persister/ObjectPersister.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Persister/ObjectPersister.php b/Persister/ObjectPersister.php index 643b817..450e43b 100644 --- a/Persister/ObjectPersister.php +++ b/Persister/ObjectPersister.php @@ -2,6 +2,7 @@ namespace FOS\ElasticaBundle\Persister; +use Elastica\Exception\NotFoundException; use FOS\ElasticaBundle\Transformer\ModelToElasticaTransformerInterface; use Elastica\Type; use Elastica\Document; @@ -48,7 +49,9 @@ class ObjectPersister implements ObjectPersisterInterface public function replaceOne($object) { $document = $this->transformToElasticaDocument($object); - $this->type->deleteById($document->getId()); + try { + $this->type->deleteById($document->getId()); + } catch (NotFoundException $e) {} $this->type->addDocument($document); } @@ -61,7 +64,9 @@ class ObjectPersister implements ObjectPersisterInterface public function deleteOne($object) { $document = $this->transformToElasticaDocument($object); - $this->type->deleteById($document->getId()); + try { + $this->type->deleteById($document->getId()); + } catch (NotFoundException $e) {} } /** @@ -73,7 +78,9 @@ class ObjectPersister implements ObjectPersisterInterface **/ public function deleteById($id) { - $this->type->deleteById($id); + try { + $this->type->deleteById($id); + } catch (NotFoundException $e) {} } From 3c01ebb7756a487e2809afeecdc3af87d7bbe20a Mon Sep 17 00:00:00 2001 From: cedric lombardot Date: Tue, 6 Aug 2013 20:48:38 +0200 Subject: [PATCH 069/447] Fix ElasticaToModelTransformer the transform closure use Result instead of Document --- Propel/ElasticaToModelTransformer.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Propel/ElasticaToModelTransformer.php b/Propel/ElasticaToModelTransformer.php index 4f006a7..952673b 100644 --- a/Propel/ElasticaToModelTransformer.php +++ b/Propel/ElasticaToModelTransformer.php @@ -2,7 +2,6 @@ namespace FOS\ElasticaBundle\Propel; -use Elastica\Document; use FOS\ElasticaBundle\HybridResult; use FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; @@ -71,9 +70,10 @@ class ElasticaToModelTransformer implements ElasticaToModelTransformerInterface */ public function transform(array $elasticaObjects) { - $ids = array_map(function(Document $elasticaObject) { - return $elasticaObject->getId(); - }, $elasticaObjects); + $ids = array(); + foreach ($elasticaObjects as $elasticaObject) { + $ids[] = $elasticaObject->getId(); + } $objects = $this->findByIdentifiers($ids, $this->options['hydrate']); From b40149cbdc74d916b6035bdbd36a9ad85d9de043 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Fri, 9 Aug 2013 13:56:51 -0400 Subject: [PATCH 070/447] Code and documentation formatting in Propel transformer class --- Propel/ElasticaToModelTransformer.php | 67 ++++++++++++++------------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/Propel/ElasticaToModelTransformer.php b/Propel/ElasticaToModelTransformer.php index 952673b..af5f8ab 100644 --- a/Propel/ElasticaToModelTransformer.php +++ b/Propel/ElasticaToModelTransformer.php @@ -7,40 +7,41 @@ use FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; /** - * Maps Elastica documents with Propel objects - * This mapper assumes an exact match between - * elastica documents ids and propel object ids + * Maps Elastica documents with Propel objects. + * + * This mapper assumes an exact match between Elastica document IDs and Propel + * entity IDs. * * @author William Durand */ class ElasticaToModelTransformer implements ElasticaToModelTransformerInterface { /** - * Class of the model to map to the elastica documents + * Propel model class to map to Elastica documents. * * @var string */ protected $objectClass = null; /** - * Optional parameters + * Transformer options. * * @var array */ protected $options = array( 'hydrate' => true, - 'identifier' => 'id' + 'identifier' => 'id', ); /** - * PropertyAccessor instance + * PropertyAccessor instance. * * @var PropertyAccessorInterface */ protected $propertyAccessor; /** - * Instantiates a new Mapper + * Constructor. * * @param string $objectClass * @param array $options @@ -48,11 +49,11 @@ class ElasticaToModelTransformer implements ElasticaToModelTransformerInterface public function __construct($objectClass, array $options = array()) { $this->objectClass = $objectClass; - $this->options = array_merge($this->options, $options); + $this->options = array_merge($this->options, $options); } /** - * Set the PropertyAccessor + * Set the PropertyAccessor instance. * * @param PropertyAccessorInterface $propertyAccessor */ @@ -62,11 +63,11 @@ class ElasticaToModelTransformer implements ElasticaToModelTransformerInterface } /** - * Transforms an array of elastica objects into an array of - * model objects fetched from the propel repository + * Transforms an array of Elastica document into an array of Propel entities + * fetched from the database. * - * @param Document[] $elasticaObjects array of elastica objects - * @return array + * @param array $elasticaObjects + * @return array|\ArrayObject */ public function transform(array $elasticaObjects) { @@ -77,18 +78,19 @@ class ElasticaToModelTransformer implements ElasticaToModelTransformerInterface $objects = $this->findByIdentifiers($ids, $this->options['hydrate']); - // sort objects in the order of ids + // Sort objects in the order of their IDs $idPos = array_flip($ids); $identifier = $this->options['identifier']; $propertyAccessor = $this->propertyAccessor; + + $sortCallback = function($a, $b) use ($idPos, $identifier, $propertyAccessor) { + return $idPos[$propertyAccessor->getValue($a, $identifier)] > $idPos[$propertyAccessor->getValue($b, $identifier)]; + }; + if (is_object($objects)) { - $objects->uasort(function($a, $b) use ($idPos, $identifier, $propertyAccessor) { - return $idPos[$propertyAccessor->getValue($a, $identifier)] > $idPos[$propertyAccessor->getValue($b, $identifier)]; - }); + $objects->uasort($sortCallback); } else { - usort($objects, function($a, $b) use ($idPos, $identifier, $propertyAccessor) { - return $idPos[$propertyAccessor->getValue($a, $identifier)] > $idPos[$propertyAccessor->getValue($b, $identifier)]; - }); + usort($objects, $sortCallback); } return $objects; @@ -126,11 +128,14 @@ class ElasticaToModelTransformer implements ElasticaToModelTransformerInterface } /** - * Fetch objects for theses identifier values + * Fetch Propel entities for the given identifier values. * - * @param array $identifierValues ids values - * @param boolean $hydrate whether or not to hydrate the objects, false returns arrays - * @return array of objects or arrays + * If $hydrate is false, the returned array elements will be arrays. + * Otherwise, the results will be hydrated to instances of the model class. + * + * @param array $identifierValues Identifier values + * @param boolean $hydrate Whether or not to hydrate the results + * @return array */ protected function findByIdentifiers(array $identifierValues, $hydrate) { @@ -140,7 +145,7 @@ class ElasticaToModelTransformer implements ElasticaToModelTransformerInterface $query = $this->createQuery($this->objectClass, $this->options['identifier'], $identifierValues); - if (!$hydrate) { + if ( ! $hydrate) { return $query->toArray(); } @@ -150,9 +155,9 @@ class ElasticaToModelTransformer implements ElasticaToModelTransformerInterface /** * Create a query to use in the findByIdentifiers() method. * - * @param string $class the model class - * @param string $identifierField like 'id' - * @param array $identifierValues ids values + * @param string $class Propel model class + * @param string $identifierField Identifier field name (e.g. "id") + * @param array $identifierValues Identifier values * @return \ModelCriteria */ protected function createQuery($class, $identifierField, array $identifierValues) @@ -160,9 +165,7 @@ class ElasticaToModelTransformer implements ElasticaToModelTransformerInterface $queryClass = $class.'Query'; $filterMethod = 'filterBy'.$this->camelize($identifierField); - return $queryClass::create() - ->$filterMethod($identifierValues) - ; + return $queryClass::create()->$filterMethod($identifierValues); } /** From 41e132140e2c9164c8b831579793612fd2b743d5 Mon Sep 17 00:00:00 2001 From: Robert Plant Date: Wed, 14 Aug 2013 10:20:45 +0100 Subject: [PATCH 071/447] Added ability to access facets with paginated results --- Paginator/FantaPaginatorAdapter.php | 12 ++++++++++++ Paginator/PaginatorAdapterInterface.php | 7 +++++++ Paginator/RawPaginatorAdapter.php | 21 ++++++++++++++++++++- README.md | 16 ++++++++++++++++ 4 files changed, 55 insertions(+), 1 deletion(-) diff --git a/Paginator/FantaPaginatorAdapter.php b/Paginator/FantaPaginatorAdapter.php index 4307abc..a2f8c0e 100644 --- a/Paginator/FantaPaginatorAdapter.php +++ b/Paginator/FantaPaginatorAdapter.php @@ -29,6 +29,18 @@ class FantaPaginatorAdapter implements AdapterInterface return $this->adapter->getTotalHits(); } + /** + * Returns Facets + * + * @return mixed + * + * @api + */ + public function getFacets() + { + return $this->adapter->getFacets(); + } + /** * Returns an slice of the results. * diff --git a/Paginator/PaginatorAdapterInterface.php b/Paginator/PaginatorAdapterInterface.php index 29eb66c..9182973 100644 --- a/Paginator/PaginatorAdapterInterface.php +++ b/Paginator/PaginatorAdapterInterface.php @@ -26,4 +26,11 @@ interface PaginatorAdapterInterface * @api */ function getResults($offset, $length); + + /** + * Returns Facets + * + * @return mixed + */ + function getFacets(); } diff --git a/Paginator/RawPaginatorAdapter.php b/Paginator/RawPaginatorAdapter.php index ab92dd4..125cd35 100644 --- a/Paginator/RawPaginatorAdapter.php +++ b/Paginator/RawPaginatorAdapter.php @@ -30,6 +30,11 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface */ private $totalHits; + /** + * @array for the facets + */ + private $facets; + /** * @see PaginatorAdapterInterface::__construct * @@ -71,7 +76,7 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface $resultSet = $this->searchable->search($query); $this->totalHits = $resultSet->getTotalHits(); - + $this->facets = $resultSet->getFacets(); return $resultSet; } @@ -102,4 +107,18 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface ? min($this->totalHits, (integer) $this->query->getParam('size')) : $this->totalHits; } + + /** + * Returns Facets + * + * @return mixed + */ + public function getFacets() + { + if ( ! isset($this->facets)) { + $this->facets = $this->searchable->search($this->query)->getFacets(); + } + + return $this->facets; + } } diff --git a/README.md b/README.md index ccae8db..6b92ce3 100644 --- a/README.md +++ b/README.md @@ -409,6 +409,22 @@ still also getting the entity. $result = $hybridResult->getResult(); } +If you would like to access facets while using Pagerfanta they can be accessed through +the Adapter seen in the example below. + +```php +$query = new \Elastica\Query(); +$facet = new \Elastica\Facet\Terms('tags'); +$facet->setField('companyGroup'); +$query->addFacet($facet); + +$companies = $finder->findPaginated($query); +$companies->setMaxPerPage($params['limit']); +$companies->setCurrentPage($params['page']); + +$facets = $companies->getAdapter()->getFacets()); +``` + ##### Index wide finder You can also define a finder that will work on the entire index. Adjust your index From 655102875340d7a6e80aa406f7a9855daa388b8a Mon Sep 17 00:00:00 2001 From: Peter Kokot Date: Sun, 15 Sep 2013 09:17:13 +0200 Subject: [PATCH 072/447] Update LICENSE Updated license year range --- Resources/meta/LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/meta/LICENSE b/Resources/meta/LICENSE index 39afd28..314bd5b 100644 --- a/Resources/meta/LICENSE +++ b/Resources/meta/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2011 Exercise.com, Inc +Copyright (c) 2011-2013 Exercise.com, Inc Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 2b942a6edf49c22d02b38610817f7852b37c2a56 Mon Sep 17 00:00:00 2001 From: Peter Kokot Date: Mon, 16 Sep 2013 19:47:05 +0200 Subject: [PATCH 073/447] LICENSE file removed in favor of Resources/meta/LICENSE file --- LICENSE | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 LICENSE diff --git a/LICENSE b/LICENSE deleted file mode 100644 index d0ba561..0000000 --- a/LICENSE +++ /dev/null @@ -1,18 +0,0 @@ -Copyright (c) 2012 Exercise.com - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. From ac56775791ced221946ad07f2b1042fc47ea70dd Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Thu, 26 Sep 2013 10:02:48 +0200 Subject: [PATCH 074/447] add a note how to use the parent mapping --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index bad644e..30c6e18 100644 --- a/README.md +++ b/README.md @@ -188,6 +188,9 @@ The parent filed declaration has the following values: * `property`: The property in the child entity where to look for the parent entity. It may be ignored if is equal to the parent type. * `identifier`: The property in the parent entity which have the parent identifier. Defaults to `id`. +Note that to create a document with a parent, you need to call `setParent` on the document rather than setting a _parent field. +If you do this wrong, you will see a `RoutingMissingException` as elasticsearch does not know where to store a document that should have a parent but does not specify it. + ### Declaring `nested` or `object` fos_elastica: From 85a10613bad047b4612a362e9ff1ae366d9b506e Mon Sep 17 00:00:00 2001 From: Thierry Marianne Date: Thu, 17 Oct 2013 22:32:11 +0200 Subject: [PATCH 075/447] Fix type hinting in "Manual provider" example --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 30c6e18..22d4100 100644 --- a/README.md +++ b/README.md @@ -326,9 +326,9 @@ Its class must implement `FOS\ElasticaBundle\Provider\ProviderInterface`. /** * Insert the repository objects in the type index * - * @param Closure $loggerClosure + * @param \Closure $loggerClosure */ - public function populate(Closure $loggerClosure = null) + public function populate(\Closure $loggerClosure = null) { if ($loggerClosure) { $loggerClosure('Indexing users'); From 9d1201099d591915d6d8f511f108570f6b296549 Mon Sep 17 00:00:00 2001 From: Karel Souffriau Date: Mon, 28 Oct 2013 17:07:49 +0100 Subject: [PATCH 076/447] Add date format field --- DependencyInjection/Configuration.php | 3 +- README.md | 18 ++++++++++ .../DependencyInjection/ConfigurationTest.php | 34 +++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 Tests/DependencyInjection/ConfigurationTest.php diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index df0fe19..d44e714 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -325,7 +325,8 @@ class Configuration implements ConfigurationInterface ->scalarNode('type')->end() ->scalarNode('identifier')->defaultValue('id')->end() ->end() - ->end(); + ->end() + ->scalarNode('format')->end(); if (isset($nestings['fields'])) { $this->addNestedFieldConfig($node, $nestings, 'fields'); diff --git a/README.md b/README.md index c289cd6..1c5c5f3 100644 --- a/README.md +++ b/README.md @@ -666,3 +666,21 @@ fos_elastica: provider: finder: ``` + +#### Date format example + +If you want to specify a [date format](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-date-format.html): + +```yaml +fos_elastica: + clients: + default: { host: localhost, port: 9200 } + indexes: + site: + types: + user: + mappings: + username: { type: string } + lastlogin: { type: date, format: basic_date_time } + birthday: { type: date, format: "yyyy-MM-dd" } +``` diff --git a/Tests/DependencyInjection/ConfigurationTest.php b/Tests/DependencyInjection/ConfigurationTest.php new file mode 100644 index 0000000..f410621 --- /dev/null +++ b/Tests/DependencyInjection/ConfigurationTest.php @@ -0,0 +1,34 @@ +configuration = new Configuration(array()); + } + + public function testEmptyConfigContainsFormatMappingOptionNode() + { + $tree = $this->configuration->getConfigTree(); + $children = $tree->getChildren(); + $children = $children['indexes']->getPrototype()->getChildren(); + $typeNodes = $children['types']->getPrototype()->getChildren(); + $mappings = $typeNodes['mappings']->getPrototype()->getChildren(); + + $this->assertArrayHasKey('format', $mappings); + $this->assertInstanceOf('Symfony\Component\Config\Definition\ScalarNode', $mappings['format']); + $this->assertNull($mappings['format']->getDefaultValue()); + } +} From 43e026500cde3db4abaf2f0b145a5dc7b4787197 Mon Sep 17 00:00:00 2001 From: Matyas Somfai Date: Tue, 8 Oct 2013 12:00:04 +0200 Subject: [PATCH 077/447] added new options to fos:elastica:populate command and options array parameter to ProviderInterface removed assume-yes option as the no-interaction option has the same purpose --- Command/PopulateCommand.php | 36 ++++++++++++++++++++++++---------- Doctrine/AbstractProvider.php | 11 ++++++++--- Propel/Provider.php | 11 ++++++++--- Provider/ProviderInterface.php | 3 ++- README.md | 3 ++- 5 files changed, 46 insertions(+), 18 deletions(-) diff --git a/Command/PopulateCommand.php b/Command/PopulateCommand.php index 3fa7cd2..58e5e9f 100755 --- a/Command/PopulateCommand.php +++ b/Command/PopulateCommand.php @@ -3,6 +3,7 @@ namespace FOS\ElasticaBundle\Command; use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; +use Symfony\Component\Console\Helper\DialogHelper; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputInterface; @@ -43,6 +44,9 @@ class PopulateCommand extends ContainerAwareCommand ->addOption('index', null, InputOption::VALUE_OPTIONAL, 'The index to repopulate') ->addOption('type', null, InputOption::VALUE_OPTIONAL, 'The type to repopulate') ->addOption('no-reset', null, InputOption::VALUE_NONE, 'Do not reset index before populating') + ->addOption('offset', null, InputOption::VALUE_REQUIRED, 'Start indexing at offset', 0) + ->addOption('sleep', null, InputOption::VALUE_REQUIRED, 'Sleep time between persisting iterations (microseconds)', 0) + ->addOption('batch-size', null, InputOption::VALUE_REQUIRED, 'Index packet size (overrides provider config option)') ->setDescription('Populates search indexes from providers') ; } @@ -62,9 +66,19 @@ class PopulateCommand extends ContainerAwareCommand */ protected function execute(InputInterface $input, OutputInterface $output) { - $index = $input->getOption('index'); - $type = $input->getOption('type'); - $reset = $input->getOption('no-reset') ? false : true; + $index = $input->getOption('index'); + $type = $input->getOption('type'); + $reset = $input->getOption('no-reset') ? false : true; + $noInteraction = $input->getOption('no-interaction'); + $options = $input->getOptions(); + + if (!$noInteraction && $reset && $input->getOption('offset')) { + /** @var DialogHelper $dialog */ + $dialog = $this->getHelperSet()->get('dialog'); + if (!$dialog->askConfirmation($output, 'You chose to reset the index and start indexing with an offset. Do you really want to do that?', true)) { + return; + } + } if (null === $index && null !== $type) { throw new \InvalidArgumentException('Cannot specify type option without an index.'); @@ -72,15 +86,15 @@ class PopulateCommand extends ContainerAwareCommand if (null !== $index) { if (null !== $type) { - $this->populateIndexType($output, $index, $type, $reset); + $this->populateIndexType($output, $index, $type, $reset, $options); } else { - $this->populateIndex($output, $index, $reset); + $this->populateIndex($output, $index, $reset, $options); } } else { $indexes = array_keys($this->indexManager->getAllIndexes()); foreach ($indexes as $index) { - $this->populateIndex($output, $index, $reset); + $this->populateIndex($output, $index, $reset, $options); } } } @@ -91,8 +105,9 @@ class PopulateCommand extends ContainerAwareCommand * @param OutputInterface $output * @param string $index * @param boolean $reset + * @param array $options */ - private function populateIndex(OutputInterface $output, $index, $reset) + private function populateIndex(OutputInterface $output, $index, $reset, $options) { if ($reset) { $output->writeln(sprintf('Resetting %s', $index)); @@ -107,7 +122,7 @@ class PopulateCommand extends ContainerAwareCommand $output->writeln(sprintf('Populating %s/%s, %s', $index, $type, $message)); }; - $provider->populate($loggerClosure); + $provider->populate($loggerClosure, $options); } $output->writeln(sprintf('Refreshing %s', $index)); @@ -121,8 +136,9 @@ class PopulateCommand extends ContainerAwareCommand * @param string $index * @param string $type * @param boolean $reset + * @param array $options */ - private function populateIndexType(OutputInterface $output, $index, $type, $reset) + private function populateIndexType(OutputInterface $output, $index, $type, $reset, $options) { if ($reset) { $output->writeln(sprintf('Resetting %s/%s', $index, $type)); @@ -134,7 +150,7 @@ class PopulateCommand extends ContainerAwareCommand }; $provider = $this->providerRegistry->getProvider($index, $type); - $provider->populate($loggerClosure); + $provider->populate($loggerClosure, $options); $output->writeln(sprintf('Refreshing %s', $index)); $this->indexManager->getIndex($index)->refresh(); diff --git a/Doctrine/AbstractProvider.php b/Doctrine/AbstractProvider.php index 43e8c20..1fb41f5 100644 --- a/Doctrine/AbstractProvider.php +++ b/Doctrine/AbstractProvider.php @@ -31,16 +31,19 @@ abstract class AbstractProvider extends BaseAbstractProvider /** * @see FOS\ElasticaBundle\Provider\ProviderInterface::populate() */ - public function populate(\Closure $loggerClosure = null) + public function populate(\Closure $loggerClosure = null, array $options = array()) { $queryBuilder = $this->createQueryBuilder(); $nbObjects = $this->countObjects($queryBuilder); + $offset = isset($options['offset']) ? intval($options['offset']) : 0; + $sleep = isset($options['sleep']) ? intval($options['sleep']) : 0; + $batchSize = isset($options['batch-size']) ? intval($options['batch-size']) : $this->options['batch_size']; - for ($offset = 0; $offset < $nbObjects; $offset += $this->options['batch_size']) { + for (; $offset < $nbObjects; $offset += $batchSize) { if ($loggerClosure) { $stepStartTime = microtime(true); } - $objects = $this->fetchSlice($queryBuilder, $this->options['batch_size'], $offset); + $objects = $this->fetchSlice($queryBuilder, $batchSize, $offset); $this->objectPersister->insertMany($objects); @@ -48,6 +51,8 @@ abstract class AbstractProvider extends BaseAbstractProvider $this->managerRegistry->getManagerForClass($this->objectClass)->clear(); } + usleep($sleep); + if ($loggerClosure) { $stepNbObjects = count($objects); $stepCount = $stepNbObjects + $offset; diff --git a/Propel/Provider.php b/Propel/Provider.php index f173e72..c319691 100644 --- a/Propel/Provider.php +++ b/Propel/Provider.php @@ -14,23 +14,28 @@ class Provider extends AbstractProvider /** * @see FOS\ElasticaBundle\Provider\ProviderInterface::populate() */ - public function populate(\Closure $loggerClosure = null) + public function populate(\Closure $loggerClosure = null, array $options = array()) { $queryClass = $this->objectClass . 'Query'; $nbObjects = $queryClass::create()->count(); + $offset = isset($options['offset']) ? intval($options['offset']) : 0; + $sleep = isset($options['sleep']) ? intval($options['sleep']) : 0; + $batchSize = isset($options['batch-size']) ? intval($options['batch-size']) : $this->options['batch_size']; - for ($offset = 0; $offset < $nbObjects; $offset += $this->options['batch_size']) { + for (; $offset < $nbObjects; $offset += $batchSize) { if ($loggerClosure) { $stepStartTime = microtime(true); } $objects = $queryClass::create() - ->limit($this->options['batch_size']) + ->limit($batchSize) ->offset($offset) ->find(); $this->objectPersister->insertMany($objects->getArrayCopy()); + usleep($sleep); + if ($loggerClosure) { $stepNbObjects = count($objects); $stepCount = $stepNbObjects + $offset; diff --git a/Provider/ProviderInterface.php b/Provider/ProviderInterface.php index 710fd4b..e8d7ea4 100644 --- a/Provider/ProviderInterface.php +++ b/Provider/ProviderInterface.php @@ -13,7 +13,8 @@ interface ProviderInterface * Persists all domain objects to ElasticSearch for this provider. * * @param \Closure $loggerClosure + * @param array $options * @return */ - function populate(\Closure $loggerClosure = null); + function populate(\Closure $loggerClosure = null, array $options = array()); } diff --git a/README.md b/README.md index e132a15..1f6cf06 100644 --- a/README.md +++ b/README.md @@ -327,8 +327,9 @@ Its class must implement `FOS\ElasticaBundle\Provider\ProviderInterface`. * Insert the repository objects in the type index * * @param \Closure $loggerClosure + * @param array $options */ - public function populate(\Closure $loggerClosure = null) + public function populate(\Closure $loggerClosure = null, array $options = array()) { if ($loggerClosure) { $loggerClosure('Indexing users'); From c68bb411aca4ab58edd9f1ba4cadd4007a3509fd Mon Sep 17 00:00:00 2001 From: Karel Souffriau Date: Mon, 28 Oct 2013 16:15:30 +0100 Subject: [PATCH 078/447] Add support for dynamic templates --- DependencyInjection/Configuration.php | 32 +++++++++++++++ DependencyInjection/FOSElasticaExtension.php | 6 +++ README.md | 30 ++++++++++++++ Resetter.php | 4 ++ .../DependencyInjection/ConfigurationTest.php | 41 +++++++++++++++++++ Tests/ResetterTest.php | 6 ++- 6 files changed, 118 insertions(+), 1 deletion(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index d44e714..eb6abd2 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -265,6 +265,7 @@ class Configuration implements ConfigurationInterface ->end() ->end() ->append($this->getMappingsNode()) + ->append($this->getDynamicTemplateNode()) ->append($this->getSourceNode()) ->append($this->getBoostNode()) ->append($this->getRoutingNode()) @@ -296,6 +297,37 @@ class Configuration implements ConfigurationInterface return $node; } + /** + * Returns the array node used for "dynamic_templates". + */ + public function getDynamicTemplateNode() + { + $builder = new TreeBuilder(); + $node = $builder->root('dynamic_templates'); + + $node + ->useAttributeAsKey('name') + ->prototype('array') + ->children() + ->scalarNode('match')->isRequired()->end() + ->scalarNode('match_mapping_type')->end() + ->arrayNode('mapping') + ->isRequired() + ->children() + ->scalarNode('type')->end() + ->scalarNode('index')->end() + ->arrayNode('fields') + ->children() + ->end() + ->end() + ->end() + ->end() + ->end() + ; + + return $node; + } + /** * @param \Symfony\Component\Config\Definition\Builder\NodeBuilder $node The node to which to attach the field config to * @param array $nestings the nested mappings for the current field level diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 6d38714..26cb209 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -205,6 +205,12 @@ class FOSElasticaExtension extends Extension if (isset($type['index'])) { $this->indexConfigs[$indexName]['config']['mappings'][$name]['index'] = $type['index']; } + if (!empty($type['dynamic_templates'])) { + $this->indexConfigs[$indexName]['config']['mappings'][$name]['dynamic_templates'] = array(); + foreach ($type['dynamic_templates'] as $templateName => $templateData) { + $this->indexConfigs[$indexName]['config']['mappings'][$name]['dynamic_templates'][] = array($templateName => $templateData); + } + } } } diff --git a/README.md b/README.md index 1c5c5f3..28359f6 100644 --- a/README.md +++ b/README.md @@ -684,3 +684,33 @@ fos_elastica: lastlogin: { type: date, format: basic_date_time } birthday: { type: date, format: "yyyy-MM-dd" } ``` + +#### Dynamic templates + +Dynamic templates allow to define mapping templates that will be +applied when dynamic introduction of fields / objects happens. + +[Documentation](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-root-object-type.html#_dynamic_templates) + +```yaml +fos_elastica: + clients: + default: { host: localhost, port: 9200 } + indexes: + site: + types: + user: + dynamic_templates: + my_template_1: + match: apples_* + mapping: + type: float + my_template_2: + match: * + match_mapping_type: string + mapping: + type: string + index: not_analyzed + mappings: + username: { type: string } +``` diff --git a/Resetter.php b/Resetter.php index 7614675..5929cc8 100644 --- a/Resetter.php +++ b/Resetter.php @@ -78,6 +78,10 @@ class Resetter } } + if (isset($indexConfig['dynamic_templates'])) { + $mapping->setParam('dynamic_templates', $indexConfig['dynamic_templates']); + } + return $mapping; } diff --git a/Tests/DependencyInjection/ConfigurationTest.php b/Tests/DependencyInjection/ConfigurationTest.php index f410621..ead9977 100644 --- a/Tests/DependencyInjection/ConfigurationTest.php +++ b/Tests/DependencyInjection/ConfigurationTest.php @@ -31,4 +31,45 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('Symfony\Component\Config\Definition\ScalarNode', $mappings['format']); $this->assertNull($mappings['format']->getDefaultValue()); } + + public function testDynamicTemplateNodes() + { + $tree = $this->configuration->getConfigTree(); + $children = $tree->getChildren(); + $children = $children['indexes']->getPrototype()->getChildren(); + $typeNodes = $children['types']->getPrototype()->getChildren(); + $dynamicTemplates = $typeNodes['dynamic_templates']->getPrototype()->getChildren(); + + $this->assertArrayHasKey('match', $dynamicTemplates); + $this->assertInstanceOf('Symfony\Component\Config\Definition\ScalarNode', $dynamicTemplates['match']); + $this->assertNull($dynamicTemplates['match']->getDefaultValue()); + + $this->assertArrayHasKey('match_mapping_type', $dynamicTemplates); + $this->assertInstanceOf('Symfony\Component\Config\Definition\ScalarNode', $dynamicTemplates['match_mapping_type']); + $this->assertNull($dynamicTemplates['match_mapping_type']->getDefaultValue()); + + $this->assertArrayHasKey('mapping', $dynamicTemplates); + $this->assertInstanceOf('Symfony\Component\Config\Definition\ArrayNode', $dynamicTemplates['mapping']); + } + + public function testDynamicTemplateMappingNodes() + { + $tree = $this->configuration->getConfigTree(); + $children = $tree->getChildren(); + $children = $children['indexes']->getPrototype()->getChildren(); + $typeNodes = $children['types']->getPrototype()->getChildren(); + $dynamicTemplates = $typeNodes['dynamic_templates']->getPrototype()->getChildren(); + $mapping = $dynamicTemplates['mapping']->getChildren(); + + $this->assertArrayHasKey('type', $mapping); + $this->assertInstanceOf('Symfony\Component\Config\Definition\ScalarNode', $mapping['type']); + $this->assertNull($mapping['type']->getDefaultValue()); + + $this->assertArrayHasKey('index', $mapping); + $this->assertInstanceOf('Symfony\Component\Config\Definition\ScalarNode', $mapping['index']); + $this->assertNull($mapping['index']->getDefaultValue()); + + $this->assertArrayHasKey('fields', $mapping); + $this->assertInstanceOf('Symfony\Component\Config\Definition\ArrayNode', $mapping['fields']); + } } diff --git a/Tests/ResetterTest.php b/Tests/ResetterTest.php index 61a18a9..cc9154b 100644 --- a/Tests/ResetterTest.php +++ b/Tests/ResetterTest.php @@ -15,7 +15,10 @@ class ResetterTest extends \PHPUnit_Framework_TestCase 'index' => $this->getMockElasticaIndex(), 'config' => array( 'mappings' => array( - 'a' => array('properties' => array()), + 'a' => array( + 'dynamic_templates' => array(), + 'properties' => array(), + ), 'b' => array('properties' => array()), ), ), @@ -92,6 +95,7 @@ class ResetterTest extends \PHPUnit_Framework_TestCase ->method('delete'); $mapping = \Elastica_Type_Mapping::create($this->indexConfigsByName['foo']['config']['mappings']['a']['properties']); + $mapping->setParam('dynamic_templates', $this->indexConfigsByName['foo']['config']['mappings']['a']['dynamic_templates']); $type->expects($this->once()) ->method('setMapping') ->with($mapping); From 604193396f332d9a96024b58c119cf0bd18bf7b7 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Fri, 12 Jul 2013 17:56:14 -0400 Subject: [PATCH 079/447] Remove "prototype" from abstract definition IDs; note possible conflicts Due to the naming of transformer, listener, and finder services, it's possible for index/type services to clobber the ID of another concrete or abstract service. This cannot be helped without breaking BC, but we should note it within the extension class. --- DependencyInjection/FOSElasticaExtension.php | 29 ++++++++++++-------- Resources/config/config.xml | 8 +++--- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 0cb5c27..4b90e91 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -144,14 +144,15 @@ class FOSElasticaExtension extends Extension */ protected function loadIndexFinder(ContainerBuilder $container, $name, $indexId) { - $abstractTransformerId = 'fos_elastica.elastica_to_model_transformer.collection.prototype'; + /* Note: transformer services may conflict with "collection.index", if + * an index and type names were "collection" and an index, respectively. + */ $transformerId = sprintf('fos_elastica.elastica_to_model_transformer.collection.%s', $name); - $transformerDef = new DefinitionDecorator($abstractTransformerId); + $transformerDef = new DefinitionDecorator('fos_elastica.elastica_to_model_transformer.collection'); $container->setDefinition($transformerId, $transformerDef); - $abstractFinderId = 'fos_elastica.finder.prototype'; $finderId = sprintf('fos_elastica.finder.%s', $name); - $finderDef = new DefinitionDecorator($abstractFinderId); + $finderDef = new DefinitionDecorator('fos_elastica.finder'); $finderDef->replaceArgument(0, new Reference($indexId)); $finderDef->replaceArgument(1, new Reference($transformerId)); @@ -262,6 +263,9 @@ class FOSElasticaExtension extends Extension if (isset($typeConfig['elastica_to_model_transformer']['service'])) { return $typeConfig['elastica_to_model_transformer']['service']; } + /* Note: transformer services may conflict with "prototype.driver", if + * the index and type names were "prototype" and a driver, respectively. + */ $abstractId = sprintf('fos_elastica.elastica_to_model_transformer.prototype.%s', $typeConfig['driver']); $serviceId = sprintf('fos_elastica.elastica_to_model_transformer.%s.%s', $indexName, $typeName); $serviceDef = new DefinitionDecorator($abstractId); @@ -285,9 +289,9 @@ class FOSElasticaExtension extends Extension if (isset($typeConfig['model_to_elastica_transformer']['service'])) { return $typeConfig['model_to_elastica_transformer']['service']; } - $abstractId = sprintf('fos_elastica.model_to_elastica_transformer.prototype.auto'); + $serviceId = sprintf('fos_elastica.model_to_elastica_transformer.%s.%s', $indexName, $typeName); - $serviceDef = new DefinitionDecorator($abstractId); + $serviceDef = new DefinitionDecorator('fos_elastica.model_to_elastica_transformer'); $serviceDef->replaceArgument(0, array( 'identifier' => $typeConfig['identifier'] )); @@ -298,9 +302,8 @@ class FOSElasticaExtension extends Extension protected function loadObjectPersister(array $typeConfig, Definition $typeDef, ContainerBuilder $container, $indexName, $typeName, $transformerId) { - $abstractId = sprintf('fos_elastica.object_persister.prototype'); $serviceId = sprintf('fos_elastica.object_persister.%s.%s', $indexName, $typeName); - $serviceDef = new DefinitionDecorator($abstractId); + $serviceDef = new DefinitionDecorator('fos_elastica.object_persister'); $serviceDef->replaceArgument(0, $typeDef); $serviceDef->replaceArgument(1, new Reference($transformerId)); $serviceDef->replaceArgument(2, $typeConfig['model']); @@ -315,7 +318,9 @@ class FOSElasticaExtension extends Extension if (isset($typeConfig['provider']['service'])) { return $typeConfig['provider']['service']; } - + /* Note: provider services may conflict with "prototype.driver", if the + * index and type names were "prototype" and a driver, respectively. + */ $providerId = sprintf('fos_elastica.provider.%s.%s', $indexName, $typeName); $providerDef = new DefinitionDecorator('fos_elastica.provider.prototype.' . $typeConfig['driver']); $providerDef->addTag('fos_elastica.provider', array('index' => $indexName, 'type' => $typeName)); @@ -333,6 +338,9 @@ class FOSElasticaExtension extends Extension if (isset($typeConfig['listener']['service'])) { return $typeConfig['listener']['service']; } + /* Note: listener services may conflict with "prototype.driver", if the + * index and type names were "prototype" and a driver, respectively. + */ $abstractListenerId = sprintf('fos_elastica.listener.prototype.%s', $typeConfig['driver']); $listenerId = sprintf('fos_elastica.listener.%s.%s', $indexName, $typeName); $listenerDef = new DefinitionDecorator($abstractListenerId); @@ -384,9 +392,8 @@ class FOSElasticaExtension extends Extension if (isset($typeConfig['finder']['service'])) { $finderId = $typeConfig['finder']['service']; } else { - $abstractFinderId = 'fos_elastica.finder.prototype'; $finderId = sprintf('fos_elastica.finder.%s.%s', $indexName, $typeName); - $finderDef = new DefinitionDecorator($abstractFinderId); + $finderDef = new DefinitionDecorator('fos_elastica.finder'); $finderDef->replaceArgument(0, $typeDef); $finderDef->replaceArgument(1, new Reference($elasticaToModelId)); $container->setDefinition($finderId, $finderDef); diff --git a/Resources/config/config.xml b/Resources/config/config.xml index a0819fb..1540269 100644 --- a/Resources/config/config.xml +++ b/Resources/config/config.xml @@ -43,26 +43,26 @@ - + - + - + - + From 74d993b64206e0e230d576928616c43fb7a3a94d Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Fri, 12 Jul 2013 17:58:13 -0400 Subject: [PATCH 080/447] Do not clobber existing client definitions (closes #336 and #324) While we could have used an abstract definition, its ID would likely conflict with the alias we set for the default client. Remove the abstract definition altogether and simply construct new definitions for each client. This resolves the previous issue where multiple clients would overwrite the constructor arguments of the previous definition. --- DependencyInjection/FOSElasticaExtension.php | 5 ++--- Resources/config/config.xml | 7 ------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 4b90e91..f264d7c 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -70,10 +70,9 @@ class FOSElasticaExtension extends Extension { $clientIds = array(); foreach ($clients as $name => $clientConfig) { - $clientDef = $container->getDefinition('fos_elastica.client'); - $clientDef->replaceArgument(0, $clientConfig); - $clientId = sprintf('fos_elastica.client.%s', $name); + $clientDef = new Definition('%fos_elastica.client.class%', array($clientConfig)); + $clientDef->addMethodCall('setLogger', array(new Reference('fos_elastica.logger'))); $container->setDefinition($clientId, $clientDef); diff --git a/Resources/config/config.xml b/Resources/config/config.xml index 1540269..dfb417d 100644 --- a/Resources/config/config.xml +++ b/Resources/config/config.xml @@ -27,13 +27,6 @@ - - - - - - - From 467ccbf753188e27bd5809a18f03e2399002ea6d Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 30 Oct 2013 17:15:09 -0400 Subject: [PATCH 081/447] Tag client services in DI extension class These tags were originally introduced in 16ecd7cca306063a0fff9ac27d38af3f416e98f5. #339 removed the fos_elastica.client definition from config.xml, so this tag needs to be added via the DI extension class now. --- DependencyInjection/FOSElasticaExtension.php | 1 + 1 file changed, 1 insertion(+) diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 632031f..eb6dd4d 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -74,6 +74,7 @@ class FOSElasticaExtension extends Extension $clientId = sprintf('fos_elastica.client.%s', $name); $clientDef = new Definition('%fos_elastica.client.class%', array($clientConfig)); $clientDef->addMethodCall('setLogger', array(new Reference('fos_elastica.logger'))); + $clientDef->addTag('fos_elastica.client'); $container->setDefinition($clientId, $clientDef); From 21ce3cf6ff543a0ee6255d14d8e07d3e8c2cf81f Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Fri, 1 Nov 2013 09:15:14 +1100 Subject: [PATCH 082/447] Fix definition decorators (closes #393) --- DependencyInjection/Compiler/TransformerPass.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DependencyInjection/Compiler/TransformerPass.php b/DependencyInjection/Compiler/TransformerPass.php index f94b95f..4281d0b 100644 --- a/DependencyInjection/Compiler/TransformerPass.php +++ b/DependencyInjection/Compiler/TransformerPass.php @@ -19,7 +19,7 @@ class TransformerPass implements CompilerPassInterface */ public function process(ContainerBuilder $container) { - if (!$container->hasDefinition('fos_elastica.elastica_to_model_transformer.collection.prototype')) { + if (!$container->hasDefinition('fos_elastica.elastica_to_model_transformer.collection')) { return; } @@ -44,4 +44,4 @@ class TransformerPass implements CompilerPassInterface $index->replaceArgument(0, $indexTransformers); } } -} \ No newline at end of file +} From 97c98a02432fef3bd7f650a69de9eefd9bc1a1ec Mon Sep 17 00:00:00 2001 From: Pierre du Plessis Date: Mon, 4 Nov 2013 00:09:21 +0200 Subject: [PATCH 083/447] Add Symfony ExpressionLanguage support for indexable callback --- Doctrine/AbstractListener.php | 59 ++++++++++++++++++++++++- README.md | 7 +++ Tests/Doctrine/AbstractListenerTest.php | 2 + composer.json | 6 ++- 4 files changed, 71 insertions(+), 3 deletions(-) diff --git a/Doctrine/AbstractListener.php b/Doctrine/AbstractListener.php index a7e8867..7a88e4b 100644 --- a/Doctrine/AbstractListener.php +++ b/Doctrine/AbstractListener.php @@ -6,6 +6,9 @@ use Doctrine\Common\EventSubscriber; use Doctrine\Common\Persistence\ObjectManager; use FOS\ElasticaBundle\Persister\ObjectPersisterInterface; use FOS\ElasticaBundle\Persister\ObjectPersister; +use Symfony\Component\ExpressionLanguage\Expression; +use Symfony\Component\ExpressionLanguage\ExpressionLanguage; +use Symfony\Component\ExpressionLanguage\SyntaxError; abstract class AbstractListener implements EventSubscriber { @@ -51,6 +54,13 @@ abstract class AbstractListener implements EventSubscriber */ private $scheduledForRemoval = array(); + /** + * An instance of ExpressionLanguage + * + * @var ExpressionLanguage + */ + protected $expressionLanguage; + /** * Constructor. * @@ -89,8 +99,21 @@ abstract class AbstractListener implements EventSubscriber public function setIsIndexableCallback($callback) { if (is_string($callback)) { + if (!is_callable(array($this->objectClass, $callback))) { - throw new \RuntimeException(sprintf('Indexable callback %s::%s() is not callable.', $this->objectClass, $callback)); + + if(false !== ($expression = $this->getExpressionLanguage())) { + + $callback = new Expression($callback); + + try { + $expression->compile($callback, array($this->getExpressionVar())); + } catch(SyntaxError $e) { + throw new \RuntimeException(sprintf('Indexable callback %s::%s() is not callable or a valid expression.', $this->objectClass, $callback), 0, $e); + } + } else { + throw new \RuntimeException(sprintf('Indexable callback %s::%s() is not callable.', $this->objectClass, $callback)); + } } } elseif (!is_callable($callback)) { if (is_array($callback)) { @@ -98,6 +121,7 @@ abstract class AbstractListener implements EventSubscriber if (is_object($class)) { $class = get_class($class); } + if ($class && $method) { throw new \RuntimeException(sprintf('Indexable callback %s::%s() is not callable.', $class, $method)); } @@ -120,6 +144,10 @@ abstract class AbstractListener implements EventSubscriber return true; } + if($this->isIndexableCallback instanceof Expression) { + return $this->getExpressionLanguage()->evaluate($this->isIndexableCallback, array($this->getExpressionVar($object) => $object)); + } + return is_string($this->isIndexableCallback) ? call_user_func(array($object, $this->isIndexableCallback)) : call_user_func($this->isIndexableCallback, $object); @@ -155,4 +183,33 @@ abstract class AbstractListener implements EventSubscriber unset($this->scheduledForRemoval[$objectHash]); } } + + /** + * @param mixed $object + * @return string + */ + private function getExpressionVar($object = null) + { + $class = $object ?: $this->objectClass; + + $ref = new \ReflectionClass($class); + + return strtolower($ref->getShortName()); + } + + /** + * @return bool|ExpressionLanguage + */ + private function getExpressionLanguage() + { + if(null === $this->expressionLanguage) { + if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) { + return false; + } + + $this->expressionLanguage = new ExpressionLanguage(); + } + + return $this->expressionLanguage; + } } diff --git a/README.md b/README.md index 1f6cf06..6a9b899 100644 --- a/README.md +++ b/README.md @@ -630,6 +630,13 @@ In this case, the callback_class will be the `isIndexable()` method on the speci service and the object being considered for indexing will be passed as the only argument. This allows you to do more complex validation (e.g. ACL checks). +If you have the [Symfony ExpressionLanguage](https://github.com/symfony/expression-language) component installed, you can use expressions +to evaluate the callback: + + persistence: + listener: + is_indexable_callback: "user.isActive() && user.hasRole('ROLE_USER')" + As you might expect, new entities will only be indexed if the callback_class returns `true`. Additionally, modified entities will be updated or removed from the index depending on whether the callback_class returns `true` or `false`, respectively. diff --git a/Tests/Doctrine/AbstractListenerTest.php b/Tests/Doctrine/AbstractListenerTest.php index e3af609..e99e26d 100644 --- a/Tests/Doctrine/AbstractListenerTest.php +++ b/Tests/Doctrine/AbstractListenerTest.php @@ -164,6 +164,7 @@ abstract class AbstractListenerTest extends \PHPUnit_Framework_TestCase array('nonexistentEntityMethod'), array(array(new Listener\IndexableDecider(), 'internalMethod')), array(42), + array('entity.getIsIndexable() && nonexistentEntityFunction()'), ); } @@ -173,6 +174,7 @@ abstract class AbstractListenerTest extends \PHPUnit_Framework_TestCase array('getIsIndexable'), array(array(new Listener\IndexableDecider(), 'isIndexable')), array(function(Listener\Entity $entity) { return $entity->getIsIndexable(); }), + array('entity.getIsIndexable()') ); } diff --git a/composer.json b/composer.json index 099868b..094eba5 100644 --- a/composer.json +++ b/composer.json @@ -24,14 +24,16 @@ "doctrine/mongodb-odm": "1.0.*@dev", "propel/propel1": "1.6.*", "pagerfanta/pagerfanta": "1.0.*@dev", - "knplabs/knp-components": "1.2.*" + "knplabs/knp-components": "1.2.*", + "symfony/expression-language" : "2.4.*@dev" }, "suggest": { "doctrine/orm": ">=2.2,<2.5-dev", "doctrine/mongodb-odm": "1.0.*@dev", "propel/propel1": "1.6.*", "pagerfanta/pagerfanta": "1.0.*@dev", - "knplabs/knp-components": "1.2.*" + "knplabs/knp-components": "1.2.*", + "symfony/expression-language" : "2.4.*@dev" }, "autoload": { "psr-0": { "FOS\\ElasticaBundle": "" } From f972b4af5946cb370bc3b64eb7a3e1382dce9113 Mon Sep 17 00:00:00 2001 From: Pierre du Plessis Date: Mon, 4 Nov 2013 08:50:41 +0200 Subject: [PATCH 084/447] Fixed CS --- Doctrine/AbstractListener.php | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/Doctrine/AbstractListener.php b/Doctrine/AbstractListener.php index 7a88e4b..3b62444 100644 --- a/Doctrine/AbstractListener.php +++ b/Doctrine/AbstractListener.php @@ -93,22 +93,18 @@ abstract class AbstractListener implements EventSubscriber * should expect the object for consideration as its only argument and * return a boolean. * - * @param callback $callback + * @param callback $callback * @throws \RuntimeException if the callback is not callable */ public function setIsIndexableCallback($callback) { if (is_string($callback)) { - if (!is_callable(array($this->objectClass, $callback))) { - - if(false !== ($expression = $this->getExpressionLanguage())) { - + if (false !== ($expression = $this->getExpressionLanguage())) { $callback = new Expression($callback); - try { $expression->compile($callback, array($this->getExpressionVar())); - } catch(SyntaxError $e) { + } catch (SyntaxError $e) { throw new \RuntimeException(sprintf('Indexable callback %s::%s() is not callable or a valid expression.', $this->objectClass, $callback), 0, $e); } } else { @@ -135,7 +131,7 @@ abstract class AbstractListener implements EventSubscriber /** * Return whether the object is indexable with respect to the callback. * - * @param object $object + * @param object $object * @return boolean */ protected function isObjectIndexable($object) @@ -144,7 +140,7 @@ abstract class AbstractListener implements EventSubscriber return true; } - if($this->isIndexableCallback instanceof Expression) { + if ($this->isIndexableCallback instanceof Expression) { return $this->getExpressionLanguage()->evaluate($this->isIndexableCallback, array($this->getExpressionVar($object) => $object)); } @@ -185,13 +181,12 @@ abstract class AbstractListener implements EventSubscriber } /** - * @param mixed $object + * @param mixed $object * @return string */ private function getExpressionVar($object = null) { $class = $object ?: $this->objectClass; - $ref = new \ReflectionClass($class); return strtolower($ref->getShortName()); @@ -202,7 +197,7 @@ abstract class AbstractListener implements EventSubscriber */ private function getExpressionLanguage() { - if(null === $this->expressionLanguage) { + if (null === $this->expressionLanguage) { if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) { return false; } From be4c99a0d3f9f8967983773dbe785ddc802ae404 Mon Sep 17 00:00:00 2001 From: igorRovenki Date: Wed, 6 Nov 2013 11:01:53 +0200 Subject: [PATCH 085/447] Update README.md Should be "listener: ~" on the line 595, otherwise listener does not working --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6a9b899..13d2024 100644 --- a/README.md +++ b/README.md @@ -592,7 +592,7 @@ Declare that you want to update the index in real time: persistence: driver: orm model: Application\UserBundle\Entity\User - listener: # by default, listens to "insert", "update" and "delete" + listener: ~ # by default, listens to "insert", "update" and "delete" Now the index is automatically updated each time the state of the bound Doctrine repository changes. No need to repopulate the whole "user" index when a new `User` is created. From 9b6b0b01482325eeea80c098b37852f60ce25127 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Mon, 23 Sep 2013 09:57:58 +1000 Subject: [PATCH 086/447] Add query_builder_method option to the transformers --- DependencyInjection/Configuration.php | 2 + DependencyInjection/FOSElasticaExtension.php | 3 +- .../AbstractElasticaToModelTransformer.php | 1 + .../MongoDB/ElasticaToModelTransformer.php | 2 +- Doctrine/ORM/ElasticaToModelTransformer.php | 25 +++- .../ORM/ElasticaToModelTransformerTest.php | 130 ++++++++++++++++++ 6 files changed, 155 insertions(+), 8 deletions(-) create mode 100644 Tests/Doctrine/ORM/ElasticaToModelTransformerTest.php diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index eb6abd2..0fea69a 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -171,6 +171,7 @@ class Configuration implements ConfigurationInterface ->children() ->scalarNode('hydrate')->defaultTrue()->end() ->scalarNode('ignore_missing')->defaultFalse()->end() + ->scalarNode('query_builder_method')->defaultValue('createQueryBuilder')->end() ->scalarNode('service')->end() ->end() ->end() @@ -252,6 +253,7 @@ class Configuration implements ConfigurationInterface ->children() ->scalarNode('hydrate')->defaultTrue()->end() ->scalarNode('ignore_missing')->defaultFalse()->end() + ->scalarNode('query_builder_method')->defaultValue('createQueryBuilder')->end() ->scalarNode('service')->end() ->end() ->end() diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 7005779..7fbbe7f 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -283,7 +283,8 @@ class FOSElasticaExtension extends Extension $serviceDef->replaceArgument($argPos + 1, array( 'hydrate' => $typeConfig['elastica_to_model_transformer']['hydrate'], 'identifier' => $typeConfig['identifier'], - 'ignore_missing' => $typeConfig['elastica_to_model_transformer']['ignore_missing'] + 'ignore_missing' => $typeConfig['elastica_to_model_transformer']['ignore_missing'], + 'query_builder_method' => $typeConfig['elastica_to_model_transformer']['query_builder_method'] )); $container->setDefinition($serviceId, $serviceDef); diff --git a/Doctrine/AbstractElasticaToModelTransformer.php b/Doctrine/AbstractElasticaToModelTransformer.php index e8f9472..147067d 100755 --- a/Doctrine/AbstractElasticaToModelTransformer.php +++ b/Doctrine/AbstractElasticaToModelTransformer.php @@ -35,6 +35,7 @@ abstract class AbstractElasticaToModelTransformer implements ElasticaToModelTran 'hydrate' => true, 'identifier' => 'id', 'ignore_missing' => false, + 'query_builder_method' => 'createQueryBuilder', ); /** diff --git a/Doctrine/MongoDB/ElasticaToModelTransformer.php b/Doctrine/MongoDB/ElasticaToModelTransformer.php index 4c35a0c..855a093 100644 --- a/Doctrine/MongoDB/ElasticaToModelTransformer.php +++ b/Doctrine/MongoDB/ElasticaToModelTransformer.php @@ -22,7 +22,7 @@ class ElasticaToModelTransformer extends AbstractElasticaToModelTransformer { return $this->registry ->getManagerForClass($this->objectClass) - ->createQueryBuilder($this->objectClass) + ->{$this->options['query_builder_method']}($this->objectClass) ->field($this->options['identifier'])->in($identifierValues) ->hydrate($hydrate) ->getQuery() diff --git a/Doctrine/ORM/ElasticaToModelTransformer.php b/Doctrine/ORM/ElasticaToModelTransformer.php index 0a889a3..20ec6e8 100644 --- a/Doctrine/ORM/ElasticaToModelTransformer.php +++ b/Doctrine/ORM/ElasticaToModelTransformer.php @@ -12,6 +12,8 @@ use Doctrine\ORM\Query; */ class ElasticaToModelTransformer extends AbstractElasticaToModelTransformer { + const ENTITY_ALIAS = 'o'; + /** * Fetch objects for theses identifier values * @@ -25,14 +27,25 @@ class ElasticaToModelTransformer extends AbstractElasticaToModelTransformer return array(); } $hydrationMode = $hydrate ? Query::HYDRATE_OBJECT : Query::HYDRATE_ARRAY; - $qb = $this->registry - ->getManagerForClass($this->objectClass) - ->getRepository($this->objectClass) - ->createQueryBuilder('o'); - /* @var $qb \Doctrine\ORM\QueryBuilder */ - $qb->where($qb->expr()->in('o.'.$this->options['identifier'], ':values')) + + $qb = $this->getEntityQueryBuilder(); + $qb->where($qb->expr()->in(static::ENTITY_ALIAS.'.'.$this->options['identifier'], ':values')) ->setParameter('values', $identifierValues); return $qb->getQuery()->setHydrationMode($hydrationMode)->execute(); } + + /** + * Retrieves a query builder to be used for querying by identifiers + * + * @return \Doctrine\ORM\QueryBuilder + */ + protected function getEntityQueryBuilder() + { + $repository = $this->registry + ->getManagerForClass($this->objectClass) + ->getRepository($this->objectClass); + + return $repository->{$this->options['query_builder_method']}(static::ENTITY_ALIAS); + } } diff --git a/Tests/Doctrine/ORM/ElasticaToModelTransformerTest.php b/Tests/Doctrine/ORM/ElasticaToModelTransformerTest.php new file mode 100644 index 0000000..c35b9fc --- /dev/null +++ b/Tests/Doctrine/ORM/ElasticaToModelTransformerTest.php @@ -0,0 +1,130 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FOS\ElasticaBundle\Tests\Doctrine\ORM; + +use Doctrine\ORM\QueryBuilder; +use FOS\ElasticaBundle\Doctrine\ORM\ElasticaToModelTransformer; + +class ElasticaToModelTransformerTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Doctrine\Common\Persistence\ManagerRegistry|\PHPUnit_Framework_MockObject_MockObject + */ + protected $registry; + + /** + * @var \Doctrine\ORM\EntityManager|\PHPUnit_Framework_MockObject_MockObject + */ + protected $manager; + + /** + * @var \Doctrine\Common\Persistence\ObjectRepository|\PHPUnit_Framework_MockObject_MockObject + */ + protected $repository; + + /** + * @var string + */ + protected $objectClass = 'stdClass'; + + /** + * Tests that the Transformer uses the query_builder_method configuration option + * allowing configuration of createQueryBuilder call. + */ + public function testTransformUsesQueryBuilderMethodConfiguration() + { + $qb = $this->getMockBuilder('Doctrine\ORM\QueryBuilder') + ->disableOriginalConstructor() + ->getMock(); + + $this->repository->expects($this->once()) + ->method('customQueryBuilderCreator') + ->with($this->equalTo(ElasticaToModelTransformer::ENTITY_ALIAS)) + ->will($this->returnValue($qb)); + $this->repository->expects($this->never()) + ->method('createQueryBuilder'); + + $transformer = new ElasticaToModelTransformer($this->registry, $this->objectClass, array( + 'query_builder_method' => 'customQueryBuilderCreator', + )); + + $class = new \ReflectionClass('FOS\ElasticaBundle\Doctrine\ORM\ElasticaToModelTransformer'); + $method = $class->getMethod('getEntityQueryBuilder'); + $method->setAccessible(true); + + $method->invokeArgs($transformer, array()); + } + + /** + * Tests that the Transformer uses the query_builder_method configuration option + * allowing configuration of createQueryBuilder call. + */ + public function testTransformUsesDefaultQueryBuilderMethodConfiguration() + { + $qb = $this->getMockBuilder('Doctrine\ORM\QueryBuilder') + ->disableOriginalConstructor() + ->getMock(); + + $this->repository->expects($this->never()) + ->method('customQueryBuilderCreator'); + $this->repository->expects($this->once()) + ->method('createQueryBuilder') + ->with($this->equalTo(ElasticaToModelTransformer::ENTITY_ALIAS)) + ->will($this->returnValue($qb)); + + $transformer = new ElasticaToModelTransformer($this->registry, $this->objectClass); + + $class = new \ReflectionClass('FOS\ElasticaBundle\Doctrine\ORM\ElasticaToModelTransformer'); + $method = $class->getMethod('getEntityQueryBuilder'); + $method->setAccessible(true); + + $method->invokeArgs($transformer, array()); + } + + protected function setUp() + { + if (!interface_exists('Doctrine\Common\Persistence\ManagerRegistry')) { + $this->markTestSkipped('Doctrine Common is not present'); + } + if (!class_exists('Doctrine\ORM\EntityManager')) { + $this->markTestSkipped('Doctrine Common is not present'); + } + + $this->registry = $this->getMockBuilder('Doctrine\Common\Persistence\ManagerRegistry') + ->disableOriginalConstructor() + ->getMock(); + + $this->manager = $this->getMockBuilder('Doctrine\ORM\EntityManager') + ->disableOriginalConstructor() + ->getMock(); + + $this->registry->expects($this->any()) + ->method('getManagerForClass') + ->with($this->objectClass) + ->will($this->returnValue($this->manager)); + + $this->repository = $this->getMock('Doctrine\Common\Persistence\ObjectRepository', array( + 'customQueryBuilderCreator', + 'createQueryBuilder', + 'find', + 'findAll', + 'findBy', + 'findOneBy', + 'getClassName' + )); + + $this->manager->expects($this->any()) + ->method('getRepository') + ->with($this->objectClass) + ->will($this->returnValue($this->repository)); + } +} From 52d5d0d55f6f979e66f1df045b825e8ae263aca4 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Mon, 11 Nov 2013 13:21:36 +1100 Subject: [PATCH 087/447] Remove incorrect copyright header --- Tests/Doctrine/ORM/ElasticaToModelTransformerTest.php | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/Tests/Doctrine/ORM/ElasticaToModelTransformerTest.php b/Tests/Doctrine/ORM/ElasticaToModelTransformerTest.php index c35b9fc..14f3ffb 100644 --- a/Tests/Doctrine/ORM/ElasticaToModelTransformerTest.php +++ b/Tests/Doctrine/ORM/ElasticaToModelTransformerTest.php @@ -1,17 +1,7 @@ - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - namespace FOS\ElasticaBundle\Tests\Doctrine\ORM; -use Doctrine\ORM\QueryBuilder; use FOS\ElasticaBundle\Doctrine\ORM\ElasticaToModelTransformer; class ElasticaToModelTransformerTest extends \PHPUnit_Framework_TestCase From 3f784b0a5b889f160b2c884bac4e29e1edebef94 Mon Sep 17 00:00:00 2001 From: Matyas Somfai Date: Tue, 8 Oct 2013 12:00:04 +0200 Subject: [PATCH 088/447] added new options to fos:elastica:populate command and options array parameter to ProviderInterface removed assume-yes option as the no-interaction option has the same purpose --- Command/PopulateCommand.php | 36 ++++++++++++++++++++++++---------- Doctrine/AbstractProvider.php | 11 ++++++++--- Propel/Provider.php | 11 ++++++++--- Provider/ProviderInterface.php | 3 ++- README.md | 15 +++++++------- 5 files changed, 52 insertions(+), 24 deletions(-) diff --git a/Command/PopulateCommand.php b/Command/PopulateCommand.php index 4f88b75..237b223 100755 --- a/Command/PopulateCommand.php +++ b/Command/PopulateCommand.php @@ -3,6 +3,7 @@ namespace FOS\ElasticaBundle\Command; use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; +use Symfony\Component\Console\Helper\DialogHelper; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputInterface; @@ -43,6 +44,9 @@ class PopulateCommand extends ContainerAwareCommand ->addOption('index', null, InputOption::VALUE_OPTIONAL, 'The index to repopulate') ->addOption('type', null, InputOption::VALUE_OPTIONAL, 'The type to repopulate') ->addOption('no-reset', null, InputOption::VALUE_NONE, 'Do not reset index before populating') + ->addOption('offset', null, InputOption::VALUE_REQUIRED, 'Start indexing at offset', 0) + ->addOption('sleep', null, InputOption::VALUE_REQUIRED, 'Sleep time between persisting iterations (microseconds)', 0) + ->addOption('batch-size', null, InputOption::VALUE_REQUIRED, 'Index packet size (overrides provider config option)') ->setDescription('Populates search indexes from providers') ; } @@ -62,9 +66,19 @@ class PopulateCommand extends ContainerAwareCommand */ protected function execute(InputInterface $input, OutputInterface $output) { - $index = $input->getOption('index'); - $type = $input->getOption('type'); - $reset = $input->getOption('no-reset') ? false : true; + $index = $input->getOption('index'); + $type = $input->getOption('type'); + $reset = $input->getOption('no-reset') ? false : true; + $noInteraction = $input->getOption('no-interaction'); + $options = $input->getOptions(); + + if (!$noInteraction && $reset && $input->getOption('offset')) { + /** @var DialogHelper $dialog */ + $dialog = $this->getHelperSet()->get('dialog'); + if (!$dialog->askConfirmation($output, 'You chose to reset the index and start indexing with an offset. Do you really want to do that?', true)) { + return; + } + } if (null === $index && null !== $type) { throw new \InvalidArgumentException('Cannot specify type option without an index.'); @@ -72,15 +86,15 @@ class PopulateCommand extends ContainerAwareCommand if (null !== $index) { if (null !== $type) { - $this->populateIndexType($output, $index, $type, $reset); + $this->populateIndexType($output, $index, $type, $reset, $options); } else { - $this->populateIndex($output, $index, $reset); + $this->populateIndex($output, $index, $reset, $options); } } else { $indexes = array_keys($this->indexManager->getAllIndexes()); foreach ($indexes as $index) { - $this->populateIndex($output, $index, $reset); + $this->populateIndex($output, $index, $reset, $options); } } } @@ -91,8 +105,9 @@ class PopulateCommand extends ContainerAwareCommand * @param OutputInterface $output * @param string $index * @param boolean $reset + * @param array $options */ - private function populateIndex(OutputInterface $output, $index, $reset) + private function populateIndex(OutputInterface $output, $index, $reset, $options) { if ($reset) { $output->writeln(sprintf('Resetting %s', $index)); @@ -107,7 +122,7 @@ class PopulateCommand extends ContainerAwareCommand $output->writeln(sprintf('Populating %s/%s, %s', $index, $type, $message)); }; - $provider->populate($loggerClosure); + $provider->populate($loggerClosure, $options); } $output->writeln(sprintf('Refreshing %s', $index)); @@ -121,8 +136,9 @@ class PopulateCommand extends ContainerAwareCommand * @param string $index * @param string $type * @param boolean $reset + * @param array $options */ - private function populateIndexType(OutputInterface $output, $index, $type, $reset) + private function populateIndexType(OutputInterface $output, $index, $type, $reset, $options) { if ($reset) { $output->writeln(sprintf('Resetting: %s/%s', $index, $type)); @@ -134,7 +150,7 @@ class PopulateCommand extends ContainerAwareCommand }; $provider = $this->providerRegistry->getProvider($index, $type); - $provider->populate($loggerClosure); + $provider->populate($loggerClosure, $options); $output->writeln(sprintf('Refreshing: %s', $index)); $this->indexManager->getIndex($index)->refresh(); diff --git a/Doctrine/AbstractProvider.php b/Doctrine/AbstractProvider.php index 43e8c20..1fb41f5 100644 --- a/Doctrine/AbstractProvider.php +++ b/Doctrine/AbstractProvider.php @@ -31,16 +31,19 @@ abstract class AbstractProvider extends BaseAbstractProvider /** * @see FOS\ElasticaBundle\Provider\ProviderInterface::populate() */ - public function populate(\Closure $loggerClosure = null) + public function populate(\Closure $loggerClosure = null, array $options = array()) { $queryBuilder = $this->createQueryBuilder(); $nbObjects = $this->countObjects($queryBuilder); + $offset = isset($options['offset']) ? intval($options['offset']) : 0; + $sleep = isset($options['sleep']) ? intval($options['sleep']) : 0; + $batchSize = isset($options['batch-size']) ? intval($options['batch-size']) : $this->options['batch_size']; - for ($offset = 0; $offset < $nbObjects; $offset += $this->options['batch_size']) { + for (; $offset < $nbObjects; $offset += $batchSize) { if ($loggerClosure) { $stepStartTime = microtime(true); } - $objects = $this->fetchSlice($queryBuilder, $this->options['batch_size'], $offset); + $objects = $this->fetchSlice($queryBuilder, $batchSize, $offset); $this->objectPersister->insertMany($objects); @@ -48,6 +51,8 @@ abstract class AbstractProvider extends BaseAbstractProvider $this->managerRegistry->getManagerForClass($this->objectClass)->clear(); } + usleep($sleep); + if ($loggerClosure) { $stepNbObjects = count($objects); $stepCount = $stepNbObjects + $offset; diff --git a/Propel/Provider.php b/Propel/Provider.php index f173e72..c319691 100644 --- a/Propel/Provider.php +++ b/Propel/Provider.php @@ -14,23 +14,28 @@ class Provider extends AbstractProvider /** * @see FOS\ElasticaBundle\Provider\ProviderInterface::populate() */ - public function populate(\Closure $loggerClosure = null) + public function populate(\Closure $loggerClosure = null, array $options = array()) { $queryClass = $this->objectClass . 'Query'; $nbObjects = $queryClass::create()->count(); + $offset = isset($options['offset']) ? intval($options['offset']) : 0; + $sleep = isset($options['sleep']) ? intval($options['sleep']) : 0; + $batchSize = isset($options['batch-size']) ? intval($options['batch-size']) : $this->options['batch_size']; - for ($offset = 0; $offset < $nbObjects; $offset += $this->options['batch_size']) { + for (; $offset < $nbObjects; $offset += $batchSize) { if ($loggerClosure) { $stepStartTime = microtime(true); } $objects = $queryClass::create() - ->limit($this->options['batch_size']) + ->limit($batchSize) ->offset($offset) ->find(); $this->objectPersister->insertMany($objects->getArrayCopy()); + usleep($sleep); + if ($loggerClosure) { $stepNbObjects = count($objects); $stepCount = $stepNbObjects + $offset; diff --git a/Provider/ProviderInterface.php b/Provider/ProviderInterface.php index 710fd4b..e8d7ea4 100644 --- a/Provider/ProviderInterface.php +++ b/Provider/ProviderInterface.php @@ -13,7 +13,8 @@ interface ProviderInterface * Persists all domain objects to ElasticSearch for this provider. * * @param \Closure $loggerClosure + * @param array $options * @return */ - function populate(\Closure $loggerClosure = null); + function populate(\Closure $loggerClosure = null, array $options = array()); } diff --git a/README.md b/README.md index 28359f6..914150a 100644 --- a/README.md +++ b/README.md @@ -74,9 +74,9 @@ Here we created a "website" index, that uses our "default" client. Our index is now available as a service: `fos_elastica.index.website`. It is an instance of `Elastica_Index`. -If you need to have different index name from the service name, for example, -in order to have different indexes for different environments then you can -use the ```index_name``` key to change the index name. The service name will +If you need to have different index name from the service name, for example, +in order to have different indexes for different environments then you can +use the ```index_name``` key to change the index name. The service name will remain the same across the environments: fos_elastica: @@ -86,8 +86,8 @@ remain the same across the environments: website: client: default index_name: website_qa - -The service id will be `fos_elastica.index.website` but the underlying index name is website_qa. + +The service id will be `fos_elastica.index.website` but the underlying index name is website_qa. #### Declare a type @@ -246,9 +246,10 @@ Its class must implement `FOS\ElasticaBundle\Provider\ProviderInterface`. /** * Insert the repository objects in the type index * - * @param Closure $loggerClosure + * @param \Closure $loggerClosure + * @param array $options */ - public function populate(Closure $loggerClosure = null) + public function populate(\Closure $loggerClosure = null, array $options = array()) { if ($loggerClosure) { $loggerClosure('Indexing users'); From 97aadf48971895b5944edb6a4348220d1ff3106f Mon Sep 17 00:00:00 2001 From: Karel Souffriau Date: Fri, 15 Nov 2013 17:39:02 +0100 Subject: [PATCH 089/447] TransformedFinder::moreLikeThis: use \Elastica_Document instead of \Document --- Finder/TransformedFinder.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Finder/TransformedFinder.php b/Finder/TransformedFinder.php index c520f08..9e624fd 100644 --- a/Finder/TransformedFinder.php +++ b/Finder/TransformedFinder.php @@ -7,6 +7,7 @@ use FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface; use FOS\ElasticaBundle\Paginator\TransformedPaginatorAdapter; use FOS\ElasticaBundle\Paginator\FantaPaginatorAdapter; use Pagerfanta\Pagerfanta; +use Elastica_Document; use Elastica_Searchable; use Elastica_Query; @@ -55,7 +56,7 @@ class TransformedFinder implements PaginatedFinderInterface **/ public function moreLikeThis($id, $params = array(), $query = array()) { - $doc = new Document($id); + $doc = new Elastica_Document($id); $results = $this->searchable->moreLikeThis($doc, $params, $query)->getResults(); return $this->transformer->transform($results); @@ -77,7 +78,6 @@ class TransformedFinder implements PaginatedFinderInterface return $results; } - /** * Gets a paginator wrapping the result of a search * From c82006e8aceaf030bef9afa16629fbacca7964b6 Mon Sep 17 00:00:00 2001 From: Luis Cordova Date: Fri, 15 Nov 2013 15:41:10 -0500 Subject: [PATCH 090/447] fix typos --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9792139..c777a91 100644 --- a/README.md +++ b/README.md @@ -182,11 +182,11 @@ per type. content: ~ _parent: { type: "post", property: "post", identifier: "id" } -The parent filed declaration has the following values: +The parent field declaration has the following values: * `type`: The parent type. * `property`: The property in the child entity where to look for the parent entity. It may be ignored if is equal to the parent type. - * `identifier`: The property in the parent entity which have the parent identifier. Defaults to `id`. + * `identifier`: The property in the parent entity which has the parent identifier. Defaults to `id`. Note that to create a document with a parent, you need to call `setParent` on the document rather than setting a _parent field. If you do this wrong, you will see a `RoutingMissingException` as elasticsearch does not know where to store a document that should have a parent but does not specify it. @@ -230,7 +230,7 @@ It applies the configured mappings to the types. This command needs providers to insert new documents in the elasticsearch types. There are 2 ways to create providers. If your elasticsearch type matches a Doctrine repository or a Propel query, go for the persistence automatic provider. -Or, for complete flexibility, go for manual provider. +Or, for complete flexibility, go for a manual provider. #### Persistence automatic provider @@ -495,7 +495,7 @@ If you use multiple drivers then you can choose which one is aliased to `fos_ela using the `default_manager` parameter: fos_elastica: - default_manager: mongodb #defauults to orm + default_manager: mongodb #defaults to orm clients: default: { host: localhost, port: 9200 } #-- From cacb40286c6dd1da6d53d141f453ade237344fa5 Mon Sep 17 00:00:00 2001 From: Luis Cordova Date: Thu, 14 Nov 2013 10:04:08 -0500 Subject: [PATCH 091/447] clean ups --- Command/PopulateCommand.php | 2 -- Command/ResetCommand.php | 2 -- Command/SearchCommand.php | 1 - Configuration/Search.php | 2 -- DependencyInjection/FOSElasticaExtension.php | 2 ++ Doctrine/RepositoryManager.php | 1 - Finder/TransformedFinder.php | 1 + Manager/RepositoryManager.php | 6 +++--- Manager/RepositoryManagerInterface.php | 1 - Paginator/FantaPaginatorAdapter.php | 5 ++--- Paginator/PaginatorAdapterInterface.php | 2 -- Paginator/RawPaginatorAdapter.php | 4 +--- Paginator/RawPartialResults.php | 1 - Paginator/TransformedPaginatorAdapter.php | 1 - Paginator/TransformedPartialResults.php | 1 - Provider/AbstractProvider.php | 1 - Provider/ProviderRegistry.php | 2 -- Resources/views/Collector/elastica.html.twig | 12 ++++++------ Serializer/Callback.php | 2 -- Tests/DataCollector/ElasticaDataCollectorTest.php | 2 -- Tests/Doctrine/RepositoryManagerTest.php | 1 - Tests/Logger/ElasticaLoggerTest.php | 1 - Tests/Manager/RepositoryManagerTest.php | 1 - Tests/RepositoryTest.php | 2 -- .../ElasticaToModelTransformerCollectionTest.php | 1 - Transformer/ModelToElasticaAutoTransformer.php | 1 - 26 files changed, 15 insertions(+), 43 deletions(-) diff --git a/Command/PopulateCommand.php b/Command/PopulateCommand.php index 58e5e9f..7297523 100755 --- a/Command/PopulateCommand.php +++ b/Command/PopulateCommand.php @@ -4,11 +4,9 @@ namespace FOS\ElasticaBundle\Command; use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; use Symfony\Component\Console\Helper\DialogHelper; -use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Console\Output\Output; use FOS\ElasticaBundle\IndexManager; use FOS\ElasticaBundle\Provider\ProviderRegistry; use FOS\ElasticaBundle\Resetter; diff --git a/Command/ResetCommand.php b/Command/ResetCommand.php index b318827..280f9aa 100755 --- a/Command/ResetCommand.php +++ b/Command/ResetCommand.php @@ -3,11 +3,9 @@ namespace FOS\ElasticaBundle\Command; use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; -use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Console\Output\Output; use FOS\ElasticaBundle\IndexManager; use FOS\ElasticaBundle\Resetter; diff --git a/Command/SearchCommand.php b/Command/SearchCommand.php index 62e3340..ec7cfb7 100644 --- a/Command/SearchCommand.php +++ b/Command/SearchCommand.php @@ -7,7 +7,6 @@ use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Console\Output\Output; use Elastica\Query; use Elastica\Result; diff --git a/Configuration/Search.php b/Configuration/Search.php index ded65a5..cee10ab 100644 --- a/Configuration/Search.php +++ b/Configuration/Search.php @@ -11,8 +11,6 @@ namespace FOS\ElasticaBundle\Configuration; */ class Search { - /** @var string */ public $repositoryClass; - } diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 9bf732e..50621a5 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -91,6 +91,7 @@ class FOSElasticaExtension extends Extension * @param ContainerBuilder $container A ContainerBuilder instance * @param array $clientIdsByName * @param $defaultClientName + * @param $serializerConfig * @throws \InvalidArgumentException * @return array */ @@ -170,6 +171,7 @@ class FOSElasticaExtension extends Extension * @param $indexName * @param $indexId * @param array $typePrototypeConfig + * @param $serializerConfig */ protected function loadTypes(array $types, ContainerBuilder $container, $indexName, $indexId, array $typePrototypeConfig, $serializerConfig) { diff --git a/Doctrine/RepositoryManager.php b/Doctrine/RepositoryManager.php index 6ba6bf5..f8867eb 100644 --- a/Doctrine/RepositoryManager.php +++ b/Doctrine/RepositoryManager.php @@ -40,5 +40,4 @@ class RepositoryManager extends BaseManager return parent::getRepository($realEntityName); } - } diff --git a/Finder/TransformedFinder.php b/Finder/TransformedFinder.php index 24f680f..4c8aa98 100644 --- a/Finder/TransformedFinder.php +++ b/Finder/TransformedFinder.php @@ -97,6 +97,7 @@ class TransformedFinder implements PaginatedFinderInterface public function createPaginatorAdapter($query) { $query = Query::create($query); + return new TransformedPaginatorAdapter($this->searchable, $query, $this->transformer); } } diff --git a/Manager/RepositoryManager.php b/Manager/RepositoryManager.php index 6459c19..3cf8e96 100644 --- a/Manager/RepositoryManager.php +++ b/Manager/RepositoryManager.php @@ -5,6 +5,7 @@ namespace FOS\ElasticaBundle\Manager; use Doctrine\Common\Annotations\Reader; use FOS\ElasticaBundle\Finder\FinderInterface; use RuntimeException; + /** * @author Richard Miller * @@ -70,11 +71,10 @@ class RepositoryManager implements RepositoryManagerInterface private function createRepository($entityName) { - $repositoryName = $this->getRepositoryName($entityName); - if (!class_exists($repositoryName)) { + if (!class_exists($repositoryName = $this->getRepositoryName($entityName))) { throw new RuntimeException(sprintf('%s repository for %s does not exist', $repositoryName, $entityName)); } + return new $repositoryName($this->entities[$entityName]['finder']); } - } diff --git a/Manager/RepositoryManagerInterface.php b/Manager/RepositoryManagerInterface.php index c831d35..1008371 100644 --- a/Manager/RepositoryManagerInterface.php +++ b/Manager/RepositoryManagerInterface.php @@ -32,5 +32,4 @@ interface RepositoryManagerInterface * @param string $entityName */ public function getRepository($entityName); - } diff --git a/Paginator/FantaPaginatorAdapter.php b/Paginator/FantaPaginatorAdapter.php index a2f8c0e..2ad6983 100644 --- a/Paginator/FantaPaginatorAdapter.php +++ b/Paginator/FantaPaginatorAdapter.php @@ -3,14 +3,13 @@ namespace FOS\ElasticaBundle\Paginator; use Pagerfanta\Adapter\AdapterInterface; -use FOS\ElasticaBundle\Paginator\PaginatorAdapterInterface; class FantaPaginatorAdapter implements AdapterInterface { private $adapter; /** - * @param PaginatorAdapterInterface $adapter + * @param \FOS\ElasticaBundle\Paginator\PaginatorAdapterInterface $adapter */ public function __construct(PaginatorAdapterInterface $adapter) { @@ -42,7 +41,7 @@ class FantaPaginatorAdapter implements AdapterInterface } /** - * Returns an slice of the results. + * Returns a slice of the results. * * @param integer $offset The offset. * @param integer $length The length. diff --git a/Paginator/PaginatorAdapterInterface.php b/Paginator/PaginatorAdapterInterface.php index 9182973..25786a0 100644 --- a/Paginator/PaginatorAdapterInterface.php +++ b/Paginator/PaginatorAdapterInterface.php @@ -2,8 +2,6 @@ namespace FOS\ElasticaBundle\Paginator; -use FOS\ElasticaBundle\Paginator\PartialResultsInterface; - interface PaginatorAdapterInterface { /** diff --git a/Paginator/RawPaginatorAdapter.php b/Paginator/RawPaginatorAdapter.php index 125cd35..d4b5357 100644 --- a/Paginator/RawPaginatorAdapter.php +++ b/Paginator/RawPaginatorAdapter.php @@ -5,9 +5,6 @@ namespace FOS\ElasticaBundle\Paginator; use Elastica\SearchableInterface; use Elastica\Query; use Elastica\ResultSet; -use FOS\ElasticaBundle\Paginator\PaginatorAdapterInterface; -use FOS\ElasticaBundle\Paginator\RawPartialResults; -use FOS\ElasticaBundle\Paginator\PartialResultsInterface; use InvalidArgumentException; /** @@ -52,6 +49,7 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface * * @param $offset * @param $itemCountPerPage + * @throws \InvalidArgumentException * @return ResultSet */ protected function getElasticaResults($offset, $itemCountPerPage) diff --git a/Paginator/RawPartialResults.php b/Paginator/RawPartialResults.php index 270e4cd..a4afb00 100644 --- a/Paginator/RawPartialResults.php +++ b/Paginator/RawPartialResults.php @@ -2,7 +2,6 @@ namespace FOS\ElasticaBundle\Paginator; -use FOS\ElasticaBundle\Paginator\PartialResultsInterface; use Elastica\ResultSet; use Elastica\Result; diff --git a/Paginator/TransformedPaginatorAdapter.php b/Paginator/TransformedPaginatorAdapter.php index a668636..7bc038a 100644 --- a/Paginator/TransformedPaginatorAdapter.php +++ b/Paginator/TransformedPaginatorAdapter.php @@ -3,7 +3,6 @@ namespace FOS\ElasticaBundle\Paginator; use FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface; -use FOS\ElasticaBundle\Paginator\TransformedPartialResults; use Elastica\SearchableInterface; use Elastica\Query; diff --git a/Paginator/TransformedPartialResults.php b/Paginator/TransformedPartialResults.php index f7f125a..13d716c 100644 --- a/Paginator/TransformedPartialResults.php +++ b/Paginator/TransformedPartialResults.php @@ -3,7 +3,6 @@ namespace FOS\ElasticaBundle\Paginator; use FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface; -use FOS\ElasticaBundle\Paginator\RawPartialResults; use Elastica\ResultSet; /** diff --git a/Provider/AbstractProvider.php b/Provider/AbstractProvider.php index daa57ae..06883a3 100644 --- a/Provider/AbstractProvider.php +++ b/Provider/AbstractProvider.php @@ -3,7 +3,6 @@ namespace FOS\ElasticaBundle\Provider; use FOS\ElasticaBundle\Persister\ObjectPersisterInterface; -use FOS\ElasticaBundle\Provider\ProviderInterface; abstract class AbstractProvider implements ProviderInterface { diff --git a/Provider/ProviderRegistry.php b/Provider/ProviderRegistry.php index ed5b499..2142223 100644 --- a/Provider/ProviderRegistry.php +++ b/Provider/ProviderRegistry.php @@ -2,8 +2,6 @@ namespace FOS\ElasticaBundle\Provider; -use Symfony\Component\DependencyInjection\ContainerBuilder; - use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\DependencyInjection\ContainerInterface; diff --git a/Resources/views/Collector/elastica.html.twig b/Resources/views/Collector/elastica.html.twig index a665e2d..4a4c3e8 100644 --- a/Resources/views/Collector/elastica.html.twig +++ b/Resources/views/Collector/elastica.html.twig @@ -19,13 +19,13 @@ {% endblock %} {% block menu %} - - - Elastica - - {{ collector.querycount }} + + + Elastica + + {{ collector.querycount }} + - {% endblock %} {% block panel %} diff --git a/Serializer/Callback.php b/Serializer/Callback.php index 50307e0..9fe7064 100644 --- a/Serializer/Callback.php +++ b/Serializer/Callback.php @@ -8,9 +8,7 @@ use JMS\Serializer\SerializerInterface; class Callback { protected $serializer; - protected $groups; - protected $version; public function setSerializer($serializer) diff --git a/Tests/DataCollector/ElasticaDataCollectorTest.php b/Tests/DataCollector/ElasticaDataCollectorTest.php index 758e1c2..aac1fb4 100644 --- a/Tests/DataCollector/ElasticaDataCollectorTest.php +++ b/Tests/DataCollector/ElasticaDataCollectorTest.php @@ -9,7 +9,6 @@ use FOS\ElasticaBundle\DataCollector\ElasticaDataCollector; */ class ElasticaDataCollectorTest extends \PHPUnit_Framework_TestCase { - public function testCorrectAmountOfQueries() { /** @var $requestMock \PHPUnit_Framework_MockObject_MockObject|\Symfony\Component\HttpFoundation\Request */ @@ -93,5 +92,4 @@ class ElasticaDataCollectorTest extends \PHPUnit_Framework_TestCase $elasticaDataCollector->collect($requestMock, $responseMock); $this->assertEquals(30, $elasticaDataCollector->getTime()); } - } diff --git a/Tests/Doctrine/RepositoryManagerTest.php b/Tests/Doctrine/RepositoryManagerTest.php index 2863127..ce7b14b 100644 --- a/Tests/Doctrine/RepositoryManagerTest.php +++ b/Tests/Doctrine/RepositoryManagerTest.php @@ -156,5 +156,4 @@ class RepositoryManagerTest extends \PHPUnit_Framework_TestCase $repository = $manager->getRepository($shortEntityName); $this->assertInstanceOf('FOS\ElasticaBundle\Repository', $repository); } - } diff --git a/Tests/Logger/ElasticaLoggerTest.php b/Tests/Logger/ElasticaLoggerTest.php index 3cf6d2d..9f68baf 100644 --- a/Tests/Logger/ElasticaLoggerTest.php +++ b/Tests/Logger/ElasticaLoggerTest.php @@ -86,5 +86,4 @@ class ElasticaLoggerTest extends \PHPUnit_Framework_TestCase $elasticaLogger->logQuery($path, $method, $data, $time); } - } diff --git a/Tests/Manager/RepositoryManagerTest.php b/Tests/Manager/RepositoryManagerTest.php index 8cdf1b4..8849035 100644 --- a/Tests/Manager/RepositoryManagerTest.php +++ b/Tests/Manager/RepositoryManagerTest.php @@ -97,5 +97,4 @@ class RepositoryManagerTest extends \PHPUnit_Framework_TestCase $manager->addEntity($entityName, $finderMock, 'FOS\ElasticaBundle\Tests\MissingRepository'); $manager->getRepository('Missing Entity'); } - } diff --git a/Tests/RepositoryTest.php b/Tests/RepositoryTest.php index ded8009..6eabe7b 100644 --- a/Tests/RepositoryTest.php +++ b/Tests/RepositoryTest.php @@ -9,7 +9,6 @@ use FOS\ElasticaBundle\Repository; */ class RepositoryTest extends \PHPUnit_Framework_TestCase { - public function testThatFindCallsFindOnFinder() { $testQuery = 'Test Query'; @@ -75,5 +74,4 @@ class RepositoryTest extends \PHPUnit_Framework_TestCase $repository = new Repository($finderMock); $repository->findHybrid($testQuery, $testLimit); } - } diff --git a/Tests/Transformer/ElasticaToModelTransformerCollectionTest.php b/Tests/Transformer/ElasticaToModelTransformerCollectionTest.php index 9b1d782..d33708e 100644 --- a/Tests/Transformer/ElasticaToModelTransformerCollectionTest.php +++ b/Tests/Transformer/ElasticaToModelTransformerCollectionTest.php @@ -119,5 +119,4 @@ class POPO class POPO2 extends POPO { - } diff --git a/Transformer/ModelToElasticaAutoTransformer.php b/Transformer/ModelToElasticaAutoTransformer.php index 6e01907..0ebcc47 100644 --- a/Transformer/ModelToElasticaAutoTransformer.php +++ b/Transformer/ModelToElasticaAutoTransformer.php @@ -149,5 +149,4 @@ class ModelToElasticaAutoTransformer implements ModelToElasticaTransformerInterf return $value; } - } From b149ac235b6bd8b61aa2c7db9e3e0a8585107067 Mon Sep 17 00:00:00 2001 From: Damien Alexandre Date: Fri, 29 Nov 2013 13:53:25 +0100 Subject: [PATCH 092/447] Replace deprecated calls `Document::add` to `Document::set` --- Transformer/ModelToElasticaAutoTransformer.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Transformer/ModelToElasticaAutoTransformer.php b/Transformer/ModelToElasticaAutoTransformer.php index e960dc5..ecddacf 100644 --- a/Transformer/ModelToElasticaAutoTransformer.php +++ b/Transformer/ModelToElasticaAutoTransformer.php @@ -75,7 +75,7 @@ class ModelToElasticaAutoTransformer implements ModelToElasticaTransformerInterf /* $value is a nested document or object. Transform $value into * an array of documents, respective the mapped properties. */ - $document->add($key, $this->transformNested($value, $mapping['properties'])); + $document->set($key, $this->transformNested($value, $mapping['properties'])); continue; } @@ -89,7 +89,7 @@ class ModelToElasticaAutoTransformer implements ModelToElasticaTransformerInterf continue; } - $document->add($key, $this->normalizeValue($value)); + $document->set($key, $this->normalizeValue($value)); } return $document; From 2862259d8e810e852e4872f6e1d57835ab2708c3 Mon Sep 17 00:00:00 2001 From: Damien Alexandre Date: Fri, 29 Nov 2013 14:59:56 +0100 Subject: [PATCH 093/447] Allow empty or null or no `mappings:` key under type configuration refs #300. This commit allow to define types without having to set any mapping as Elasticsearch build his own. The minimal config become: indexes: toto: client: default types: Article: mappings: ~ ... --- DependencyInjection/Configuration.php | 4 ++++ DependencyInjection/FOSElasticaExtension.php | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index fe7e9a4..e9e2dbb 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -432,6 +432,10 @@ class Configuration implements ConfigurationInterface } foreach ($index['types'] as $type) { + if (empty($type['mappings'])) { + continue; + } + $nestings = array_merge_recursive($nestings, $this->getNestingsForType($type['mappings'], $nestings)); } } diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 7a72d96..12d81ee 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -199,6 +199,11 @@ class FOSElasticaExtension extends Extension $typeDef->addMethodCall('setSerializer', array(array(new Reference($callbackId), 'serialize'))); } $container->setDefinition($typeId, $typeDef); + + $this->indexConfigs[$indexName]['config']['mappings'][$name] = array( + "_source" => array("enabled" => true), // Add a default setting for empty mapping settings + ); + if (isset($type['_id'])) { $this->indexConfigs[$indexName]['config']['mappings'][$name]['_id'] = $type['_id']; } @@ -211,7 +216,7 @@ class FOSElasticaExtension extends Extension if (isset($type['_routing'])) { $this->indexConfigs[$indexName]['config']['mappings'][$name]['_routing'] = $type['_routing']; } - if (isset($type['mappings'])) { + if (isset($type['mappings']) && !empty($type['mappings'])) { $this->indexConfigs[$indexName]['config']['mappings'][$name]['properties'] = $type['mappings']; $typeName = sprintf('%s/%s', $indexName, $name); $this->typeFields[$typeName] = $type['mappings']; From 3027c687e227e6c1d7bacf6793adf03839fc7355 Mon Sep 17 00:00:00 2001 From: Damien Alexandre Date: Fri, 29 Nov 2013 15:35:59 +0100 Subject: [PATCH 094/447] Ref #341, fix the insertMany method to use Bulk indexing To make it works, I inject the serializer defined for the Type into the fos_elastica.object_serializer_persister service. This is the SAME service injected in the setSerializer of Type. We deport the handling of serialization outside Elastica, this is not so good but we need to build our own Documents to get the ID's correctly. --- DependencyInjection/FOSElasticaExtension.php | 2 ++ Persister/ObjectSerializerPersister.php | 19 ++++++++---- Resources/config/config.xml | 1 + .../ObjectSerializerPersisterTest.php | 30 ++++++++++++++----- 4 files changed, 39 insertions(+), 13 deletions(-) diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 12d81ee..5b533aa 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -356,6 +356,8 @@ class FOSElasticaExtension extends Extension if ($this->serializerConfig) { $abstractId = 'fos_elastica.object_serializer_persister'; + $callbackId = sprintf('%s.%s.serializer.callback', $this->indexConfigs[$indexName]['index'], $typeName); + $arguments[] = array(new Reference($callbackId), 'serialize'); } else { $abstractId = 'fos_elastica.object_persister'; $arguments[] = $this->typeFields[sprintf('%s/%s', $indexName, $typeName)]; diff --git a/Persister/ObjectSerializerPersister.php b/Persister/ObjectSerializerPersister.php index 269515b..40305c4 100644 --- a/Persister/ObjectSerializerPersister.php +++ b/Persister/ObjectSerializerPersister.php @@ -2,6 +2,7 @@ namespace FOS\ElasticaBundle\Persister; +use Elastica\Document; use Elastica\Type; use FOS\ElasticaBundle\Transformer\ModelToElasticaTransformerInterface; @@ -14,11 +15,12 @@ use FOS\ElasticaBundle\Transformer\ModelToElasticaTransformerInterface; */ class ObjectSerializerPersister extends ObjectPersister { - public function __construct(Type $type, ModelToElasticaTransformerInterface $transformer, $objectClass) + public function __construct(Type $type, ModelToElasticaTransformerInterface $transformer, $objectClass, $serializer) { $this->type = $type; $this->transformer = $transformer; $this->objectClass = $objectClass; + $this->serializer = $serializer; } /** @@ -30,7 +32,7 @@ class ObjectSerializerPersister extends ObjectPersister public function insertOne($object) { $document = $this->transformToElasticaDocument($object); - $this->type->addObject($object, $document); + $this->type->addDocument($document); } /** @@ -43,7 +45,7 @@ class ObjectSerializerPersister extends ObjectPersister { $document = $this->transformToElasticaDocument($object); $this->type->deleteById($document->getId()); - $this->type->addObject($object, $document); + $this->type->addDocument($document); } /** @@ -78,9 +80,11 @@ class ObjectSerializerPersister extends ObjectPersister **/ public function insertMany(array $objects) { + $docs = array(); foreach ($objects as $object) { - $this->insertOne($object); + $docs[] = $this->transformToElasticaDocument($object); } + $this->type->addDocuments($docs); } /** @@ -92,6 +96,11 @@ class ObjectSerializerPersister extends ObjectPersister */ public function transformToElasticaDocument($object) { - return $this->transformer->transform($object, array()); + $document = $this->transformer->transform($object, array()); + + $data = call_user_func($this->serializer, $object); + $document->setData($data); + + return $document; } } diff --git a/Resources/config/config.xml b/Resources/config/config.xml index 77c280d..1fb2c1d 100644 --- a/Resources/config/config.xml +++ b/Resources/config/config.xml @@ -53,6 +53,7 @@ + diff --git a/Tests/Persister/ObjectSerializerPersisterTest.php b/Tests/Persister/ObjectSerializerPersisterTest.php index 10c63ab..aae3a64 100644 --- a/Tests/Persister/ObjectSerializerPersisterTest.php +++ b/Tests/Persister/ObjectSerializerPersisterTest.php @@ -45,9 +45,12 @@ class ObjectSerializerPersisterTest extends \PHPUnit_Framework_TestCase ->method('deleteById') ->with($this->equalTo(123)); $typeMock->expects($this->once()) - ->method('addObject'); + ->method('addDocument'); - $objectPersister = new ObjectSerializerPersister($typeMock, $transformer, 'SomeClass'); + $serializerMock = $this->getMockBuilder('FOS\ElasticaBundle\Serializer\Callback')->getMock(); + $serializerMock->expects($this->once())->method('serialize'); + + $objectPersister = new ObjectSerializerPersister($typeMock, $transformer, 'SomeClass', array($serializerMock, 'serialize')); $objectPersister->replaceOne(new POPO()); } @@ -62,9 +65,12 @@ class ObjectSerializerPersisterTest extends \PHPUnit_Framework_TestCase $typeMock->expects($this->never()) ->method('deleteById'); $typeMock->expects($this->once()) - ->method('addObject'); + ->method('addDocument'); - $objectPersister = new ObjectSerializerPersister($typeMock, $transformer, 'SomeClass'); + $serializerMock = $this->getMockBuilder('FOS\ElasticaBundle\Serializer\Callback')->getMock(); + $serializerMock->expects($this->once())->method('serialize'); + + $objectPersister = new ObjectSerializerPersister($typeMock, $transformer, 'SomeClass', array($serializerMock, 'serialize')); $objectPersister->insertOne(new POPO()); } @@ -79,9 +85,12 @@ class ObjectSerializerPersisterTest extends \PHPUnit_Framework_TestCase $typeMock->expects($this->once()) ->method('deleteById'); $typeMock->expects($this->never()) - ->method('addObject'); + ->method('addDocument'); - $objectPersister = new ObjectSerializerPersister($typeMock, $transformer, 'SomeClass'); + $serializerMock = $this->getMockBuilder('FOS\ElasticaBundle\Serializer\Callback')->getMock(); + $serializerMock->expects($this->once())->method('serialize'); + + $objectPersister = new ObjectSerializerPersister($typeMock, $transformer, 'SomeClass', array($serializerMock, 'serialize')); $objectPersister->deleteOne(new POPO()); } @@ -95,12 +104,17 @@ class ObjectSerializerPersisterTest extends \PHPUnit_Framework_TestCase ->getMock(); $typeMock->expects($this->never()) ->method('deleteById'); - $typeMock->expects($this->exactly(2)) + $typeMock->expects($this->never()) ->method('addObject'); $typeMock->expects($this->never()) ->method('addObjects'); + $typeMock->expects($this->once()) + ->method('addDocuments'); - $objectPersister = new ObjectSerializerPersister($typeMock, $transformer, 'SomeClass'); + $serializerMock = $this->getMockBuilder('FOS\ElasticaBundle\Serializer\Callback')->getMock(); + $serializerMock->expects($this->exactly(2))->method('serialize'); + + $objectPersister = new ObjectSerializerPersister($typeMock, $transformer, 'SomeClass', array($serializerMock, 'serialize')); $objectPersister->insertMany(array(new POPO(), new POPO())); } From f258c9ddc0f1adf3a61fb2e5b3b2a267794a4f6f Mon Sep 17 00:00:00 2001 From: nurikabe Date: Sun, 1 Dec 2013 21:17:55 +0000 Subject: [PATCH 095/447] Exploratory development for https://github.com/FriendsOfSymfony/FOSElasticaBundle/issues/410 --- DependencyInjection/FOSElasticaExtension.php | 4 + Doctrine/AbstractListener.php | 94 ++++++++++++-------- Doctrine/MongoDB/Listener.php | 40 ++------- Doctrine/ORM/Listener.php | 39 ++------ 4 files changed, 78 insertions(+), 99 deletions(-) diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 9bf732e..3caaf57 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -405,11 +405,15 @@ class FOSElasticaExtension extends Extension private function getDoctrineEvents(array $typeConfig) { + // Flush event always fires; not configurable + $typeConfig['listener']['flush'] = true; + $events = array(); $eventMapping = array( 'insert' => array('postPersist'), 'update' => array('postUpdate'), 'delete' => array('postRemove', 'preRemove') + 'flush' => array('postFlush') ); foreach ($eventMapping as $event => $doctrineEvents) { diff --git a/Doctrine/AbstractListener.php b/Doctrine/AbstractListener.php index 3b62444..9a4385a 100644 --- a/Doctrine/AbstractListener.php +++ b/Doctrine/AbstractListener.php @@ -2,8 +2,8 @@ namespace FOS\ElasticaBundle\Doctrine; +use Doctrine\Common\EventArgs; use Doctrine\Common\EventSubscriber; -use Doctrine\Common\Persistence\ObjectManager; use FOS\ElasticaBundle\Persister\ObjectPersisterInterface; use FOS\ElasticaBundle\Persister\ObjectPersister; use Symfony\Component\ExpressionLanguage\Expression; @@ -48,11 +48,11 @@ abstract class AbstractListener implements EventSubscriber protected $isIndexableCallback; /** - * Objects scheduled for removal - * - * @var array + * Objects scheduled for insertion, replacement, or removal */ - private $scheduledForRemoval = array(); + protected $scheduledForInsertion = array(); + protected $scheduledForUpdate = array(); + protected $scheduledForDeletion = array(); /** * An instance of ExpressionLanguage @@ -149,37 +149,6 @@ abstract class AbstractListener implements EventSubscriber : call_user_func($this->isIndexableCallback, $object); } - /** - * Schedules the object for removal. - * - * This is usually called during the pre-remove event. - * - * @param object $object - * @param ObjectManager $objectManager - */ - protected function scheduleForRemoval($object, ObjectManager $objectManager) - { - $metadata = $objectManager->getClassMetadata($this->objectClass); - $esId = $metadata->getFieldValue($object, $this->esIdentifierField); - $this->scheduledForRemoval[spl_object_hash($object)] = $esId; - } - - /** - * Removes the object if it was scheduled for removal. - * - * This is usually called during the post-remove event. - * - * @param object $object - */ - protected function removeIfScheduled($object) - { - $objectHash = spl_object_hash($object); - if (isset($this->scheduledForRemoval[$objectHash])) { - $this->objectPersister->deleteById($this->scheduledForRemoval[$objectHash]); - unset($this->scheduledForRemoval[$objectHash]); - } - } - /** * @param mixed $object * @return string @@ -207,4 +176,57 @@ abstract class AbstractListener implements EventSubscriber return $this->expressionLanguage; } + + public function postPersist(EventArgs $eventArgs) + { + $entity = $eventArgs->getEntity(); + + if ($entity instanceof $this->objectClass && $this->isObjectIndexable($entity)) { + $this->scheduledForInsertion[] = $entity; + } + } + + public function postUpdate(EventArgs $eventArgs) + { + $entity = $eventArgs->getEntity(); + + if ($entity instanceof $this->objectClass) { + if ($this->isObjectIndexable($entity)) { + $this->scheduledForUpdate[] = $entity; + } else { + // Delete if no longer indexable + $this->scheduledForDeletion[] = $entity; + } + } + } + + public function preRemove(EventArgs $eventArgs) + { + $entity = $eventArgs->getEntity(); + + if ($entity instanceof $this->objectClass) { + $this->scheduledForDeletion[] = $entity; + } + } + + public function postRemove(EventArgs $eventArgs) + { + } + + /** + * Iterate through scheduled actions *after* flushing to ensure that the ElasticSearch index will only be affected + * only if the query is successful + */ + public function postFlush(EventArgs $eventArgs) + { + foreach ($this->scheduledForInsertion as $entity) { + $this->objectPersister->insertOne($entity); + } + foreach ($this->scheduledForUpdate as $entity) { + $this->objectPersister->replaceOne($entity); + } + foreach ($this->scheduledForDeletion as $entity) { + $this->objectPersister->deleteOne($entity); + } + } } diff --git a/Doctrine/MongoDB/Listener.php b/Doctrine/MongoDB/Listener.php index 9fa3536..13e1d25 100644 --- a/Doctrine/MongoDB/Listener.php +++ b/Doctrine/MongoDB/Listener.php @@ -2,49 +2,23 @@ namespace FOS\ElasticaBundle\Doctrine\MongoDB; -use Doctrine\ODM\MongoDB\Event\LifecycleEventArgs; +use Doctrine\Common\EventArgs; use FOS\ElasticaBundle\Doctrine\AbstractListener; class Listener extends AbstractListener { - public function postPersist(LifecycleEventArgs $eventArgs) + public function postPersist(EventArgs $eventArgs) { - $document = $eventArgs->getDocument(); - - if ($document instanceof $this->objectClass && $this->isObjectIndexable($document)) { - $this->objectPersister->insertOne($document); - } + parent::postPersist($eventArgs); } - public function postUpdate(LifecycleEventArgs $eventArgs) + public function postUpdate(EventArgs $eventArgs) { - $document = $eventArgs->getDocument(); - - if ($document instanceof $this->objectClass) { - if ($this->isObjectIndexable($document)) { - $this->objectPersister->replaceOne($document); - } else { - $this->scheduleForRemoval($document, $eventArgs->getDocumentManager()); - $this->removeIfScheduled($document); - } - } + parent::postUpdate($eventArgs); } - public function preRemove(LifecycleEventArgs $eventArgs) + public function postRemove(EventArgs $eventArgs) { - $document = $eventArgs->getDocument(); - - if ($document instanceof $this->objectClass) { - $this->scheduleForRemoval($document, $eventArgs->getDocumentManager()); - } - } - - public function postRemove(LifecycleEventArgs $eventArgs) - { - $document = $eventArgs->getDocument(); - - if ($document instanceof $this->objectClass) { - $this->removeIfScheduled($document); - } + parent::postRemove($eventArgs); } } diff --git a/Doctrine/ORM/Listener.php b/Doctrine/ORM/Listener.php index 790ddb8..97f8792 100644 --- a/Doctrine/ORM/Listener.php +++ b/Doctrine/ORM/Listener.php @@ -2,49 +2,28 @@ namespace FOS\ElasticaBundle\Doctrine\ORM; -use Doctrine\ORM\Event\LifecycleEventArgs; +use Doctrine\Common\EventArgs; use FOS\ElasticaBundle\Doctrine\AbstractListener; class Listener extends AbstractListener { - public function postPersist(LifecycleEventArgs $eventArgs) + public function postPersist(EventArgs $eventArgs) { - $entity = $eventArgs->getEntity(); - - if ($entity instanceof $this->objectClass && $this->isObjectIndexable($entity)) { - $this->objectPersister->insertOne($entity); - } + parent::postPersist($eventArgs); } - public function postUpdate(LifecycleEventArgs $eventArgs) + public function postUpdate(EventArgs $eventArgs) { - $entity = $eventArgs->getEntity(); - - if ($entity instanceof $this->objectClass) { - if ($this->isObjectIndexable($entity)) { - $this->objectPersister->replaceOne($entity); - } else { - $this->scheduleForRemoval($entity, $eventArgs->getEntityManager()); - $this->removeIfScheduled($entity); - } - } + parent::postUpdate($eventArgs); } - public function preRemove(LifecycleEventArgs $eventArgs) + public function preRemove(EventArgs $eventArgs) { - $entity = $eventArgs->getEntity(); - - if ($entity instanceof $this->objectClass) { - $this->scheduleForRemoval($entity, $eventArgs->getEntityManager()); - } + parent::preRemove($eventArgs); } - public function postRemove(LifecycleEventArgs $eventArgs) + public function postRemove(EventArgs $eventArgs) { - $entity = $eventArgs->getEntity(); - - if ($entity instanceof $this->objectClass) { - $this->removeIfScheduled($entity); - } + parent::postRemove($eventArgs); } } From 5ec652063de1c381400488f5607870ba490b21ba Mon Sep 17 00:00:00 2001 From: nurikabe Date: Sun, 1 Dec 2013 21:48:41 +0000 Subject: [PATCH 096/447] Don't need postRemove. --- DependencyInjection/FOSElasticaExtension.php | 2 +- Doctrine/AbstractListener.php | 4 ---- Doctrine/ORM/Listener.php | 5 ----- 3 files changed, 1 insertion(+), 10 deletions(-) diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 3caaf57..30ad07a 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -412,7 +412,7 @@ class FOSElasticaExtension extends Extension $eventMapping = array( 'insert' => array('postPersist'), 'update' => array('postUpdate'), - 'delete' => array('postRemove', 'preRemove') + 'delete' => array('preRemove'), 'flush' => array('postFlush') ); diff --git a/Doctrine/AbstractListener.php b/Doctrine/AbstractListener.php index 9a4385a..0fa15df 100644 --- a/Doctrine/AbstractListener.php +++ b/Doctrine/AbstractListener.php @@ -209,10 +209,6 @@ abstract class AbstractListener implements EventSubscriber } } - public function postRemove(EventArgs $eventArgs) - { - } - /** * Iterate through scheduled actions *after* flushing to ensure that the ElasticSearch index will only be affected * only if the query is successful diff --git a/Doctrine/ORM/Listener.php b/Doctrine/ORM/Listener.php index 97f8792..722b89d 100644 --- a/Doctrine/ORM/Listener.php +++ b/Doctrine/ORM/Listener.php @@ -21,9 +21,4 @@ class Listener extends AbstractListener { parent::preRemove($eventArgs); } - - public function postRemove(EventArgs $eventArgs) - { - parent::postRemove($eventArgs); - } } From 1d700261abb7b7f39c56550cac0732e807240b35 Mon Sep 17 00:00:00 2001 From: nurikabe Date: Mon, 2 Dec 2013 12:42:04 +0000 Subject: [PATCH 097/447] Refactor to a single Listener class. Update tests. --- Doctrine/AbstractListener.php | 228 ------------------------ Doctrine/MongoDB/Listener.php | 24 --- Doctrine/ORM/Listener.php | 24 --- Resources/config/mongodb.xml | 2 +- Resources/config/orm.xml | 2 +- Tests/Doctrine/AbstractListenerTest.php | 75 +++++--- Tests/Doctrine/MongoDB/ListenerTest.php | 6 +- Tests/Doctrine/ORM/ListenerTest.php | 6 +- 8 files changed, 57 insertions(+), 310 deletions(-) delete mode 100644 Doctrine/AbstractListener.php delete mode 100644 Doctrine/MongoDB/Listener.php delete mode 100644 Doctrine/ORM/Listener.php diff --git a/Doctrine/AbstractListener.php b/Doctrine/AbstractListener.php deleted file mode 100644 index 0fa15df..0000000 --- a/Doctrine/AbstractListener.php +++ /dev/null @@ -1,228 +0,0 @@ -objectPersister = $objectPersister; - $this->objectClass = $objectClass; - $this->events = $events; - $this->esIdentifierField = $esIdentifierField; - } - - /** - * @see Doctrine\Common\EventSubscriber::getSubscribedEvents() - */ - public function getSubscribedEvents() - { - return $this->events; - } - - /** - * Set the callback for determining object index eligibility. - * - * If callback is a string, it must be public method on the object class - * that expects no arguments and returns a boolean. Otherwise, the callback - * should expect the object for consideration as its only argument and - * return a boolean. - * - * @param callback $callback - * @throws \RuntimeException if the callback is not callable - */ - public function setIsIndexableCallback($callback) - { - if (is_string($callback)) { - if (!is_callable(array($this->objectClass, $callback))) { - if (false !== ($expression = $this->getExpressionLanguage())) { - $callback = new Expression($callback); - try { - $expression->compile($callback, array($this->getExpressionVar())); - } catch (SyntaxError $e) { - throw new \RuntimeException(sprintf('Indexable callback %s::%s() is not callable or a valid expression.', $this->objectClass, $callback), 0, $e); - } - } else { - throw new \RuntimeException(sprintf('Indexable callback %s::%s() is not callable.', $this->objectClass, $callback)); - } - } - } elseif (!is_callable($callback)) { - if (is_array($callback)) { - list($class, $method) = $callback + array(null, null); - if (is_object($class)) { - $class = get_class($class); - } - - if ($class && $method) { - throw new \RuntimeException(sprintf('Indexable callback %s::%s() is not callable.', $class, $method)); - } - } - throw new \RuntimeException('Indexable callback is not callable.'); - } - - $this->isIndexableCallback = $callback; - } - - /** - * Return whether the object is indexable with respect to the callback. - * - * @param object $object - * @return boolean - */ - protected function isObjectIndexable($object) - { - if (!$this->isIndexableCallback) { - return true; - } - - if ($this->isIndexableCallback instanceof Expression) { - return $this->getExpressionLanguage()->evaluate($this->isIndexableCallback, array($this->getExpressionVar($object) => $object)); - } - - return is_string($this->isIndexableCallback) - ? call_user_func(array($object, $this->isIndexableCallback)) - : call_user_func($this->isIndexableCallback, $object); - } - - /** - * @param mixed $object - * @return string - */ - private function getExpressionVar($object = null) - { - $class = $object ?: $this->objectClass; - $ref = new \ReflectionClass($class); - - return strtolower($ref->getShortName()); - } - - /** - * @return bool|ExpressionLanguage - */ - private function getExpressionLanguage() - { - if (null === $this->expressionLanguage) { - if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) { - return false; - } - - $this->expressionLanguage = new ExpressionLanguage(); - } - - return $this->expressionLanguage; - } - - public function postPersist(EventArgs $eventArgs) - { - $entity = $eventArgs->getEntity(); - - if ($entity instanceof $this->objectClass && $this->isObjectIndexable($entity)) { - $this->scheduledForInsertion[] = $entity; - } - } - - public function postUpdate(EventArgs $eventArgs) - { - $entity = $eventArgs->getEntity(); - - if ($entity instanceof $this->objectClass) { - if ($this->isObjectIndexable($entity)) { - $this->scheduledForUpdate[] = $entity; - } else { - // Delete if no longer indexable - $this->scheduledForDeletion[] = $entity; - } - } - } - - public function preRemove(EventArgs $eventArgs) - { - $entity = $eventArgs->getEntity(); - - if ($entity instanceof $this->objectClass) { - $this->scheduledForDeletion[] = $entity; - } - } - - /** - * Iterate through scheduled actions *after* flushing to ensure that the ElasticSearch index will only be affected - * only if the query is successful - */ - public function postFlush(EventArgs $eventArgs) - { - foreach ($this->scheduledForInsertion as $entity) { - $this->objectPersister->insertOne($entity); - } - foreach ($this->scheduledForUpdate as $entity) { - $this->objectPersister->replaceOne($entity); - } - foreach ($this->scheduledForDeletion as $entity) { - $this->objectPersister->deleteOne($entity); - } - } -} diff --git a/Doctrine/MongoDB/Listener.php b/Doctrine/MongoDB/Listener.php deleted file mode 100644 index 13e1d25..0000000 --- a/Doctrine/MongoDB/Listener.php +++ /dev/null @@ -1,24 +0,0 @@ - - + diff --git a/Resources/config/orm.xml b/Resources/config/orm.xml index 4fd6ae7..5bd16e5 100644 --- a/Resources/config/orm.xml +++ b/Resources/config/orm.xml @@ -13,7 +13,7 @@ - + diff --git a/Tests/Doctrine/AbstractListenerTest.php b/Tests/Doctrine/AbstractListenerTest.php index e99e26d..a6ad2aa 100644 --- a/Tests/Doctrine/AbstractListenerTest.php +++ b/Tests/Doctrine/AbstractListenerTest.php @@ -3,9 +3,11 @@ namespace FOS\ElasticaBundle\Tests\Doctrine; /** + * See concrete MongoDB/ORM instances of this abstract test + * * @author Richard Miller */ -abstract class AbstractListenerTest extends \PHPUnit_Framework_TestCase +abstract class ListenerTest extends \PHPUnit_Framework_TestCase { public function testObjectInsertedOnPersist() { @@ -14,12 +16,16 @@ abstract class AbstractListenerTest extends \PHPUnit_Framework_TestCase $entity = new Listener\Entity(1); $eventArgs = $this->createLifecycleEventArgs($entity, $this->getMockObjectManager()); + $listener = $this->createListener($persister, get_class($entity), array()); + $listener->postPersist($eventArgs); + + $this->assertEquals($entity, current($listener->scheduledForInsertion)); + $persister->expects($this->once()) ->method('insertOne') ->with($entity); - $listener = $this->createListener($persister, get_class($entity), array()); - $listener->postPersist($eventArgs); + $listener->postFlush($eventArgs); } /** @@ -32,12 +38,16 @@ abstract class AbstractListenerTest extends \PHPUnit_Framework_TestCase $entity = new Listener\Entity(1, false); $eventArgs = $this->createLifecycleEventArgs($entity, $this->getMockObjectManager()); - $persister->expects($this->never()) - ->method('insertOne'); - $listener = $this->createListener($persister, get_class($entity), array()); $listener->setIsIndexableCallback($isIndexableCallback); $listener->postPersist($eventArgs); + + $this->assertEmpty($listener->scheduledForInsertion); + + $persister->expects($this->never()) + ->method('insertOne'); + + $listener->postFlush($eventArgs); } public function testObjectReplacedOnUpdate() @@ -47,15 +57,18 @@ abstract class AbstractListenerTest extends \PHPUnit_Framework_TestCase $entity = new Listener\Entity(1); $eventArgs = $this->createLifecycleEventArgs($entity, $this->getMockObjectManager()); + $listener = $this->createListener($persister, get_class($entity), array()); + $listener->postUpdate($eventArgs); + + $this->assertEquals($entity, current($listener->scheduledForUpdate)); + $persister->expects($this->once()) ->method('replaceOne') ->with($entity); - $persister->expects($this->never()) ->method('deleteById'); - $listener = $this->createListener($persister, get_class($entity), array()); - $listener->postUpdate($eventArgs); + $listener->postFlush($eventArgs); } /** @@ -80,16 +93,20 @@ abstract class AbstractListenerTest extends \PHPUnit_Framework_TestCase ->with($entity, 'id') ->will($this->returnValue($entity->getId())); - $persister->expects($this->never()) - ->method('replaceOne'); - - $persister->expects($this->once()) - ->method('deleteById') - ->with($entity->getId()); - $listener = $this->createListener($persister, get_class($entity), array()); $listener->setIsIndexableCallback($isIndexableCallback); $listener->postUpdate($eventArgs); + + $this->assertEmpty($listener->scheduledForUpdate); + $this->assertEquals($entity, current($listener->scheduledForDeletion)); + + $persister->expects($this->never()) + ->method('replaceOne'); + $persister->expects($this->once()) + ->method('deleteOne') + ->with($entity); + + $listener->postFlush($eventArgs); } public function testObjectDeletedOnRemove() @@ -111,13 +128,16 @@ abstract class AbstractListenerTest extends \PHPUnit_Framework_TestCase ->with($entity, 'id') ->will($this->returnValue($entity->getId())); - $persister->expects($this->once()) - ->method('deleteById') - ->with($entity->getId()); - $listener = $this->createListener($persister, get_class($entity), array()); $listener->preRemove($eventArgs); - $listener->postRemove($eventArgs); + + $this->assertEquals($entity, current($listener->scheduledForDeletion)); + + $persister->expects($this->once()) + ->method('deleteOne') + ->with($entity); + + $listener->postFlush($eventArgs); } public function testObjectWithNonStandardIdentifierDeletedOnRemove() @@ -139,13 +159,16 @@ abstract class AbstractListenerTest extends \PHPUnit_Framework_TestCase ->with($entity, 'identifier') ->will($this->returnValue($entity->getId())); - $persister->expects($this->once()) - ->method('deleteById') - ->with($entity->getId()); - $listener = $this->createListener($persister, get_class($entity), array(), 'identifier'); $listener->preRemove($eventArgs); - $listener->postRemove($eventArgs); + + $this->assertEquals($entity, current($listener->scheduledForDeletion)); + + $persister->expects($this->once()) + ->method('deleteOne') + ->with($entity); + + $listener->postFlush($eventArgs); } /** diff --git a/Tests/Doctrine/MongoDB/ListenerTest.php b/Tests/Doctrine/MongoDB/ListenerTest.php index 7f1a9ab..37a0203 100644 --- a/Tests/Doctrine/MongoDB/ListenerTest.php +++ b/Tests/Doctrine/MongoDB/ListenerTest.php @@ -2,9 +2,9 @@ namespace FOS\ElasticaBundle\Tests\Doctrine\MongoDB; -use FOS\ElasticaBundle\Tests\Doctrine\AbstractListenerTest; +use FOS\ElasticaBundle\Tests\Doctrine\ListenerTest as BaseListenerTest; -class ListenerTest extends AbstractListenerTest +class ListenerTest extends BaseListenerTest { public function setUp() { @@ -25,7 +25,7 @@ class ListenerTest extends AbstractListenerTest protected function getListenerClass() { - return 'FOS\ElasticaBundle\Doctrine\MongoDB\Listener'; + return 'FOS\ElasticaBundle\Doctrine\Listener'; } protected function getObjectManagerClass() diff --git a/Tests/Doctrine/ORM/ListenerTest.php b/Tests/Doctrine/ORM/ListenerTest.php index 48702c0..12a89b2 100644 --- a/Tests/Doctrine/ORM/ListenerTest.php +++ b/Tests/Doctrine/ORM/ListenerTest.php @@ -2,9 +2,9 @@ namespace FOS\ElasticaBundle\Tests\Doctrine\ORM; -use FOS\ElasticaBundle\Tests\Doctrine\AbstractListenerTest; +use FOS\ElasticaBundle\Tests\Doctrine\ListenerTest as BaseListenerTest; -class ListenerTest extends AbstractListenerTest +class ListenerTest extends BaseListenerTest { public function setUp() { @@ -25,7 +25,7 @@ class ListenerTest extends AbstractListenerTest protected function getListenerClass() { - return 'FOS\ElasticaBundle\Doctrine\ORM\Listener'; + return 'FOS\ElasticaBundle\Doctrine\Listener'; } protected function getObjectManagerClass() From cf3e35e892f8dcc40727b8d048819f00119ee87b Mon Sep 17 00:00:00 2001 From: Damien Alexandre Date: Mon, 2 Dec 2013 22:15:11 +0100 Subject: [PATCH 098/447] Remove extra line-break --- Persister/ObjectSerializerPersister.php | 1 - 1 file changed, 1 deletion(-) diff --git a/Persister/ObjectSerializerPersister.php b/Persister/ObjectSerializerPersister.php index 40305c4..c0d2d28 100644 --- a/Persister/ObjectSerializerPersister.php +++ b/Persister/ObjectSerializerPersister.php @@ -72,7 +72,6 @@ class ObjectSerializerPersister extends ObjectPersister $this->type->deleteById($id); } - /** * Inserts an array of objects in the type * From 25e59a311badec60ceccbabbe4b53e40d18acb38 Mon Sep 17 00:00:00 2001 From: Damien Alexandre Date: Mon, 2 Dec 2013 22:26:30 +0100 Subject: [PATCH 099/447] Fix Persister constructor and undefined property --- Persister/ObjectSerializerPersister.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Persister/ObjectSerializerPersister.php b/Persister/ObjectSerializerPersister.php index c0d2d28..8938a2f 100644 --- a/Persister/ObjectSerializerPersister.php +++ b/Persister/ObjectSerializerPersister.php @@ -15,11 +15,11 @@ use FOS\ElasticaBundle\Transformer\ModelToElasticaTransformerInterface; */ class ObjectSerializerPersister extends ObjectPersister { + protected $serializer; + public function __construct(Type $type, ModelToElasticaTransformerInterface $transformer, $objectClass, $serializer) { - $this->type = $type; - $this->transformer = $transformer; - $this->objectClass = $objectClass; + parent::__construct($type, $transformer, $objectClass, array()); $this->serializer = $serializer; } From 8a4848a16dc916afda6ebd3632e4d3894a571755 Mon Sep 17 00:00:00 2001 From: Damien Alexandre Date: Mon, 2 Dec 2013 22:35:50 +0100 Subject: [PATCH 100/447] Add UPGRADE-3.0.md file with descriptions of new features / changes --- UPGRADE-3.0.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 UPGRADE-3.0.md diff --git a/UPGRADE-3.0.md b/UPGRADE-3.0.md new file mode 100644 index 0000000..a9a99a4 --- /dev/null +++ b/UPGRADE-3.0.md @@ -0,0 +1,32 @@ +UPGRADE FROM 2.1 to 3.0 +======================= + +### Serialization + + * you can now define a Serializer service and callback for indexing. All providers and listeners will use it. + + ```yml + serializer: + callback_class: FOS\ElasticaBundle\Serializer\Callback + serializer: serializer + ``` + +### Mapping + + * you do not have to setup any mapping anymore if you use a Serializer, properties are no more indexed only if + they are mapped. So this kind of configuration became valid: + + ```yml + serializer: + callback_class: FOS\ElasticaBundle\Serializer\Callback + serializer: serializer + indexes: + acme: + client: default + types: + Article: + persistence: + driver: orm + model: Acme\Bundle\CoreBundle\Entity\Article + provider: ~ + ``` From af2827df016feea3463ba911454f12ab3b1e6b00 Mon Sep 17 00:00:00 2001 From: nurikabe Date: Tue, 3 Dec 2013 14:01:21 +0000 Subject: [PATCH 101/447] Re-add renamed Listener. --- Doctrine/Listener.php | 228 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100644 Doctrine/Listener.php diff --git a/Doctrine/Listener.php b/Doctrine/Listener.php new file mode 100644 index 0000000..6584207 --- /dev/null +++ b/Doctrine/Listener.php @@ -0,0 +1,228 @@ +objectPersister = $objectPersister; + $this->objectClass = $objectClass; + $this->events = $events; + $this->esIdentifierField = $esIdentifierField; + } + + /** + * @see Doctrine\Common\EventSubscriber::getSubscribedEvents() + */ + public function getSubscribedEvents() + { + return $this->events; + } + + /** + * Set the callback for determining object index eligibility. + * + * If callback is a string, it must be public method on the object class + * that expects no arguments and returns a boolean. Otherwise, the callback + * should expect the object for consideration as its only argument and + * return a boolean. + * + * @param callback $callback + * @throws \RuntimeException if the callback is not callable + */ + public function setIsIndexableCallback($callback) + { + if (is_string($callback)) { + if (!is_callable(array($this->objectClass, $callback))) { + if (false !== ($expression = $this->getExpressionLanguage())) { + $callback = new Expression($callback); + try { + $expression->compile($callback, array($this->getExpressionVar())); + } catch (SyntaxError $e) { + throw new \RuntimeException(sprintf('Indexable callback %s::%s() is not callable or a valid expression.', $this->objectClass, $callback), 0, $e); + } + } else { + throw new \RuntimeException(sprintf('Indexable callback %s::%s() is not callable.', $this->objectClass, $callback)); + } + } + } elseif (!is_callable($callback)) { + if (is_array($callback)) { + list($class, $method) = $callback + array(null, null); + if (is_object($class)) { + $class = get_class($class); + } + + if ($class && $method) { + throw new \RuntimeException(sprintf('Indexable callback %s::%s() is not callable.', $class, $method)); + } + } + throw new \RuntimeException('Indexable callback is not callable.'); + } + + $this->isIndexableCallback = $callback; + } + + /** + * Return whether the object is indexable with respect to the callback. + * + * @param object $object + * @return boolean + */ + protected function isObjectIndexable($object) + { + if (!$this->isIndexableCallback) { + return true; + } + + if ($this->isIndexableCallback instanceof Expression) { + return $this->getExpressionLanguage()->evaluate($this->isIndexableCallback, array($this->getExpressionVar($object) => $object)); + } + + return is_string($this->isIndexableCallback) + ? call_user_func(array($object, $this->isIndexableCallback)) + : call_user_func($this->isIndexableCallback, $object); + } + + /** + * @param mixed $object + * @return string + */ + private function getExpressionVar($object = null) + { + $class = $object ?: $this->objectClass; + $ref = new \ReflectionClass($class); + + return strtolower($ref->getShortName()); + } + + /** + * @return bool|ExpressionLanguage + */ + private function getExpressionLanguage() + { + if (null === $this->expressionLanguage) { + if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) { + return false; + } + + $this->expressionLanguage = new ExpressionLanguage(); + } + + return $this->expressionLanguage; + } + + public function postPersist(EventArgs $eventArgs) + { + $entity = $eventArgs->getEntity(); + + if ($entity instanceof $this->objectClass && $this->isObjectIndexable($entity)) { + $this->scheduledForInsertion[] = $entity; + } + } + + public function postUpdate(EventArgs $eventArgs) + { + $entity = $eventArgs->getEntity(); + + if ($entity instanceof $this->objectClass) { + if ($this->isObjectIndexable($entity)) { + $this->scheduledForUpdate[] = $entity; + } else { + // Delete if no longer indexable + $this->scheduledForDeletion[] = $entity; + } + } + } + + public function preRemove(EventArgs $eventArgs) + { + $entity = $eventArgs->getEntity(); + + if ($entity instanceof $this->objectClass) { + $this->scheduledForDeletion[] = $entity; + } + } + + /** + * Iterate through scheduled actions *after* flushing to ensure that the ElasticSearch index will only be affected + * only if the query is successful + */ + public function postFlush(EventArgs $eventArgs) + { + foreach ($this->scheduledForInsertion as $entity) { + $this->objectPersister->insertOne($entity); + } + foreach ($this->scheduledForUpdate as $entity) { + $this->objectPersister->replaceOne($entity); + } + foreach ($this->scheduledForDeletion as $entity) { + $this->objectPersister->deleteOne($entity); + } + } +} From 22a5d67d05d2df4fe46ca6e80f4b21198f2d3b19 Mon Sep 17 00:00:00 2001 From: nurikabe Date: Tue, 3 Dec 2013 20:41:26 +0000 Subject: [PATCH 102/447] pre/postFlush configuration. Update documentation. --- DependencyInjection/Configuration.php | 2 ++ DependencyInjection/FOSElasticaExtension.php | 6 +++-- Doctrine/Listener.php | 23 +++++++++++++++++--- README.md | 22 ++++++++++++++++--- UPGRADE-3.0.md | 11 ++++++++++ 5 files changed, 56 insertions(+), 8 deletions(-) create mode 100644 UPGRADE-3.0.md diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index fe7e9a4..50d4b89 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -165,6 +165,7 @@ class Configuration implements ConfigurationInterface ->scalarNode('insert')->defaultTrue()->end() ->scalarNode('update')->defaultTrue()->end() ->scalarNode('delete')->defaultTrue()->end() + ->scalarNode('persist')->defaultValue('postFlush')->end() ->scalarNode('service')->end() ->variableNode('is_indexable_callback')->defaultNull()->end() ->end() @@ -257,6 +258,7 @@ class Configuration implements ConfigurationInterface ->scalarNode('insert')->defaultTrue()->end() ->scalarNode('update')->defaultTrue()->end() ->scalarNode('delete')->defaultTrue()->end() + ->booleanNode('immediate')->defaultFalse()->end() ->scalarNode('service')->end() ->variableNode('is_indexable_callback')->defaultNull()->end() ->end() diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 30ad07a..4a7ebbc 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -405,7 +405,7 @@ class FOSElasticaExtension extends Extension private function getDoctrineEvents(array $typeConfig) { - // Flush event always fires; not configurable + // Flush always calls depending on actions scheduled in lifecycle listeners $typeConfig['listener']['flush'] = true; $events = array(); @@ -413,9 +413,11 @@ class FOSElasticaExtension extends Extension 'insert' => array('postPersist'), 'update' => array('postUpdate'), 'delete' => array('preRemove'), - 'flush' => array('postFlush') + 'flush' => array($typeConfig['listener']['immediate'] ? 'preFlush' : 'postFlush') ); + var_dump($eventMapping); + foreach ($eventMapping as $event => $doctrineEvents) { if (isset($typeConfig['listener'][$event]) && $typeConfig['listener'][$event]) { $events = array_merge($events, $doctrineEvents); diff --git a/Doctrine/Listener.php b/Doctrine/Listener.php index 6584207..683070e 100644 --- a/Doctrine/Listener.php +++ b/Doctrine/Listener.php @@ -210,10 +210,9 @@ class Listener implements EventSubscriber } /** - * Iterate through scheduled actions *after* flushing to ensure that the ElasticSearch index will only be affected - * only if the query is successful + * Persist scheduled action to ElasticSearch */ - public function postFlush(EventArgs $eventArgs) + private function persistScheduled() { foreach ($this->scheduledForInsertion as $entity) { $this->objectPersister->insertOne($entity); @@ -225,4 +224,22 @@ class Listener implements EventSubscriber $this->objectPersister->deleteOne($entity); } } + + /** + * Iterate through scheduled actions before flushing to emulate 2.x behavior. Note that the ElasticSearch index + * will fall out of sync with the data source in event of a crash on flush. + */ + public function preFlush(EventArgs $eventArgs) + { + $this->persistScheduled(); + } + + /** + * Iterating through scheduled actions *after* flushing ensures that the ElasticSearch index will be affected + * only if the query is successful + */ + public function postFlush(EventArgs $eventArgs) + { + $this->persistScheduled(); + } } diff --git a/README.md b/README.md index 9792139..9f77a1b 100644 --- a/README.md +++ b/README.md @@ -576,7 +576,11 @@ class User ### Realtime, selective index update If you use the Doctrine integration, you can let ElasticaBundle update the indexes automatically -when an object is added, updated or removed. It uses Doctrine lifecycle events. +when an object is added, updated or removed. It uses Doctrine lifecycle events to schedule updates +and then synchronizes changes either before or after flush. + +> **Propel** doesn't support this feature yet. + Declare that you want to update the index in real time: fos_elastica: @@ -592,7 +596,7 @@ Declare that you want to update the index in real time: persistence: driver: orm model: Application\UserBundle\Entity\User - listener: ~ # by default, listens to "insert", "update" and "delete" + listener: ~ # by default, listens to "insert", "update" and "delete" and updates `postFlush` Now the index is automatically updated each time the state of the bound Doctrine repository changes. No need to repopulate the whole "user" index when a new `User` is created. @@ -605,7 +609,19 @@ You can also choose to only listen for some of the events: update: false delete: true -> **Propel** doesn't support this feature yet. +By default, the ElasticSearch index will be updated after flush. To update before flushing, set `immediate` +to `true`: + + persistence: + listener: + insert: true + update: false + delete: true + immediate: true + +> Updating ElasticSearch before flushing may cause the ElasticSearch index to fall out of sync with the +> original data in the event of a crash. + ### Checking an entity method for listener diff --git a/UPGRADE-3.0.md b/UPGRADE-3.0.md new file mode 100644 index 0000000..0b0d370 --- /dev/null +++ b/UPGRADE-3.0.md @@ -0,0 +1,11 @@ +UPGRADE FROM 2.x to 3.0 +======================= + +### ElasticSearch Synchronization Event + + * Prior to 3.0, the ElasticSearch index was synchronized in the `postInsert`, + `postUpdate`, and `pre/postRemove` events which fire before flush. Because + of this, exceptions thrown when flushing would cause the data source and + ElasticSearch index to fall out of sync. + + As of 3.0, ElasticSearch is updated `postFlush` by default. From ed21e60869e86a5372f3d1a69ee97c4f61c65829 Mon Sep 17 00:00:00 2001 From: nurikabe Date: Tue, 3 Dec 2013 23:40:00 +0000 Subject: [PATCH 103/447] Remove upgrade doc. Merk will add manually. --- UPGRADE-3.0.md | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 UPGRADE-3.0.md diff --git a/UPGRADE-3.0.md b/UPGRADE-3.0.md deleted file mode 100644 index 0b0d370..0000000 --- a/UPGRADE-3.0.md +++ /dev/null @@ -1,11 +0,0 @@ -UPGRADE FROM 2.x to 3.0 -======================= - -### ElasticSearch Synchronization Event - - * Prior to 3.0, the ElasticSearch index was synchronized in the `postInsert`, - `postUpdate`, and `pre/postRemove` events which fire before flush. Because - of this, exceptions thrown when flushing would cause the data source and - ElasticSearch index to fall out of sync. - - As of 3.0, ElasticSearch is updated `postFlush` by default. From 8b6dffbc141d07bdbd446680e1f854a20617686f Mon Sep 17 00:00:00 2001 From: Ben Longden Date: Tue, 3 Dec 2013 15:45:43 +0000 Subject: [PATCH 104/447] Adds enabled mapping option (default true) --- DependencyInjection/Configuration.php | 1 + 1 file changed, 1 insertion(+) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 4482a4c..af27f09 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -311,6 +311,7 @@ class Configuration implements ConfigurationInterface ->scalarNode('term_vector')->end() ->scalarNode('null_value')->end() ->booleanNode('include_in_all')->defaultValue(true)->end() + ->booleanNode('enabled')->defaultValue(true)->end() ->scalarNode('lat_lon')->end() ->scalarNode('index_name')->end() ->booleanNode('omit_norms')->end() From 3a279f8edbff1eed66c224516904917725ccfc6b Mon Sep 17 00:00:00 2001 From: nurikabe Date: Wed, 4 Dec 2013 10:46:05 +0000 Subject: [PATCH 105/447] Remove debug. --- DependencyInjection/FOSElasticaExtension.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 4a7ebbc..6380873 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -416,8 +416,6 @@ class FOSElasticaExtension extends Extension 'flush' => array($typeConfig['listener']['immediate'] ? 'preFlush' : 'postFlush') ); - var_dump($eventMapping); - foreach ($eventMapping as $event => $doctrineEvents) { if (isset($typeConfig['listener'][$event]) && $typeConfig['listener'][$event]) { $events = array_merge($events, $doctrineEvents); From 759950aff66092489a5d40f79d2c5c2aea1a9194 Mon Sep 17 00:00:00 2001 From: Pierre du Plessis Date: Mon, 4 Nov 2013 17:24:35 +0200 Subject: [PATCH 106/447] Add option to disable logger or specify different logger service --- DependencyInjection/Configuration.php | 13 ++++++++++--- DependencyInjection/FOSElasticaExtension.php | 5 ++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 8a067b5..e05dd2e 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -76,8 +76,9 @@ class Configuration implements ConfigurationInterface return array( 'servers' => array( array( - 'host' => $v['host'], - 'port' => $v['port'], + 'host' => $v['host'], + 'port' => $v['port'], + 'logger' => $v['logger'] ) ) ); @@ -89,7 +90,8 @@ class Configuration implements ConfigurationInterface return array( 'servers' => array( array( - 'url' => $v['url'], + 'url' => $v['url'], + 'logger' => $v['logger'] ) ) ); @@ -102,6 +104,11 @@ class Configuration implements ConfigurationInterface ->scalarNode('url')->end() ->scalarNode('host')->end() ->scalarNode('port')->end() + ->scalarNode('logger') + ->defaultValue('fos_elastica.logger') + ->treatNullLike('fos_elastica.logger') + ->treatTrueLike('fos_elastica.logger') + ->end() ->end() ->end() ->end() diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index eb6dd4d..bcf8e84 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -73,7 +73,10 @@ class FOSElasticaExtension extends Extension foreach ($clients as $name => $clientConfig) { $clientId = sprintf('fos_elastica.client.%s', $name); $clientDef = new Definition('%fos_elastica.client.class%', array($clientConfig)); - $clientDef->addMethodCall('setLogger', array(new Reference('fos_elastica.logger'))); + $logger = $clientConfig['servers'][0]['logger']; + if (false !== $logger) { + $clientDef->addMethodCall('setLogger', array(new Reference($logger))); + } $clientDef->addTag('fos_elastica.client'); $container->setDefinition($clientId, $clientDef); From 08193ec2fd9b0e47961cbe9c64289bff91500729 Mon Sep 17 00:00:00 2001 From: Lea Haensenberger Date: Thu, 5 Dec 2013 16:35:30 +0100 Subject: [PATCH 107/447] Add support to disable the _all field for a type --- DependencyInjection/Configuration.php | 18 ++++++++++++++++++ DependencyInjection/FOSElasticaExtension.php | 3 +++ 2 files changed, 21 insertions(+) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index f9f633f..3c3ea9e 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -288,6 +288,7 @@ class Configuration implements ConfigurationInterface ->append($this->getBoostNode()) ->append($this->getRoutingNode()) ->append($this->getParentNode()) + ->append($this->getAllNode()) ->end() ; @@ -530,4 +531,21 @@ class Configuration implements ConfigurationInterface return $node; } + + /** + * Returns the array node used for "_all" + */ + protected function getAllNode() + { + $builder = new TreeBuilder(); + $node = $builder->root('_all'); + + $node + ->children() + ->scalarNode('enabled')->defaultValue(true)->end() + ->end() + ; + + return $node; + } } diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index d83b604..cba715c 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -231,6 +231,9 @@ class FOSElasticaExtension extends Extension if (isset($type['index'])) { $this->indexConfigs[$indexName]['config']['mappings'][$name]['index'] = $type['index']; } + if (isset($type['_all'])) { + $this->indexConfigs[$indexName]['config']['mappings'][$name]['_all'] = $type['_all']; + } } } From c97a4abceb3fe0b42c660b30c63e721ee888c6d7 Mon Sep 17 00:00:00 2001 From: Damien Alexandre Date: Mon, 9 Dec 2013 10:09:36 +0100 Subject: [PATCH 108/447] Add display cURL on the web debug queries shower --- Resources/views/Collector/elastica.html.twig | 35 +++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/Resources/views/Collector/elastica.html.twig b/Resources/views/Collector/elastica.html.twig index a665e2d..bfbd31a 100644 --- a/Resources/views/Collector/elastica.html.twig +++ b/Resources/views/Collector/elastica.html.twig @@ -41,7 +41,7 @@

{% else %}
    - {% for query in collector.queries %} + {% for key, query in collector.queries %}
  • Path: {{ query.path }}
    Method: {{ query.method }} @@ -51,8 +51,41 @@ Time: {{ '%0.2f'|format(query.executionMS * 1000) }} ms + + + + + - + Display cURL query + + +
  • {% endfor %}
+ + {% endif %} {% endblock %} From ca507a5e347d376729f6496030c40ff1eac35b7f Mon Sep 17 00:00:00 2001 From: Damien Alexandre Date: Mon, 9 Dec 2013 10:40:47 +0100 Subject: [PATCH 109/447] Add full_host in logger for HTTP(s) queries --- Client.php | 13 ++++++++++++- Logger/ElasticaLogger.php | 6 ++++-- Resources/views/Collector/elastica.html.twig | 19 ++++++++++--------- Tests/Logger/ElasticaLoggerTest.php | 7 ++++--- 4 files changed, 30 insertions(+), 15 deletions(-) diff --git a/Client.php b/Client.php index 8430b36..8c9be1a 100644 --- a/Client.php +++ b/Client.php @@ -4,6 +4,8 @@ namespace FOS\ElasticaBundle; use Elastica\Client as ElasticaClient; use Elastica\Request; +use Elastica\Transport\Http; +use Elastica\Transport\Https; /** * @author Gordon Franke @@ -17,7 +19,16 @@ class Client extends ElasticaClient if (null !== $this->_logger) { $time = microtime(true) - $start; - $this->_logger->logQuery($path, $method, $data, $time); + + $connection = $this->getLastRequest()->getConnection(); + $transport = $connection->getTransportObject(); + $full_host = null; + + if ($transport instanceof Http || $transport instanceof Https) { + $full_host = $connection->getTransport().'://'.$connection->getHost().':'.$connection->getPort(); + } + + $this->_logger->logQuery($path, $method, $data, $time, $full_host); } return $response; diff --git a/Logger/ElasticaLogger.php b/Logger/ElasticaLogger.php index 1705d06..2d8d0ae 100644 --- a/Logger/ElasticaLogger.php +++ b/Logger/ElasticaLogger.php @@ -38,15 +38,17 @@ class ElasticaLogger implements LoggerInterface * @param string $method Rest method to use (GET, POST, DELETE, PUT) * @param array $data arguments * @param float $time execution time + * @param string $full_host host and port of the query */ - public function logQuery($path, $method, $data, $time) + public function logQuery($path, $method, $data, $time, $full_host = null) { if ($this->debug) { $this->queries[] = array( 'path' => $path, 'method' => $method, 'data' => $data, - 'executionMS' => $time + 'executionMS' => $time, + 'full_host' => $full_host ); } diff --git a/Resources/views/Collector/elastica.html.twig b/Resources/views/Collector/elastica.html.twig index bfbd31a..8b27376 100644 --- a/Resources/views/Collector/elastica.html.twig +++ b/Resources/views/Collector/elastica.html.twig @@ -52,15 +52,17 @@ Time: {{ '%0.2f'|format(query.executionMS * 1000) }} ms
- - + - - - Display cURL query - + {% if query.full_host %} + + + + - + Display cURL query + - + + {% endif %} {% endfor %} @@ -79,7 +81,6 @@ } else { sections[0].style.display = 'inline'; sections[1].style.display = 'none'; - //sections[3].style.display = 'none'; document.getElementById(link.hash.replace("#", "")).style.display = 'none'; } diff --git a/Tests/Logger/ElasticaLoggerTest.php b/Tests/Logger/ElasticaLoggerTest.php index 3cf6d2d..73ba4ac 100644 --- a/Tests/Logger/ElasticaLoggerTest.php +++ b/Tests/Logger/ElasticaLoggerTest.php @@ -9,7 +9,6 @@ use FOS\ElasticaBundle\Logger\ElasticaLogger; */ class ElasticaLoggerTest extends \PHPUnit_Framework_TestCase { - public function testGetZeroIfNoQueriesAdded() { $elasticaLogger = new ElasticaLogger; @@ -36,15 +35,17 @@ class ElasticaLoggerTest extends \PHPUnit_Framework_TestCase $method = 'testMethod'; $data = array('data'); $time = 12; + $full_host = 'http://example.com:9200'; $expected = array( 'path' => $path, 'method' => $method, 'data' => $data, - 'executionMS' => $time + 'executionMS' => $time, + 'full_host' => $full_host, ); - $elasticaLogger->logQuery($path, $method, $data, $time); + $elasticaLogger->logQuery($path, $method, $data, $time, $full_host); $returnedQueries = $elasticaLogger->getQueries(); $this->assertEquals($expected, $returnedQueries[0]); } From 1ddd7c0e0cb054e7438a3c07fbd6e633267dc503 Mon Sep 17 00:00:00 2001 From: Damien Alexandre Date: Mon, 9 Dec 2013 14:46:06 +0100 Subject: [PATCH 110/447] Store connection infos for all transports, display infos in debug --- Client.php | 14 ++++++-------- Logger/ElasticaLogger.php | 6 +++--- Resources/views/Collector/elastica.html.twig | 6 +++--- Tests/Logger/ElasticaLoggerTest.php | 6 +++--- 4 files changed, 15 insertions(+), 17 deletions(-) diff --git a/Client.php b/Client.php index 8c9be1a..119f420 100644 --- a/Client.php +++ b/Client.php @@ -4,8 +4,6 @@ namespace FOS\ElasticaBundle; use Elastica\Client as ElasticaClient; use Elastica\Request; -use Elastica\Transport\Http; -use Elastica\Transport\Https; /** * @author Gordon Franke @@ -21,14 +19,14 @@ class Client extends ElasticaClient $time = microtime(true) - $start; $connection = $this->getLastRequest()->getConnection(); - $transport = $connection->getTransportObject(); - $full_host = null; - if ($transport instanceof Http || $transport instanceof Https) { - $full_host = $connection->getTransport().'://'.$connection->getHost().':'.$connection->getPort(); - } + $connection_array = array( + 'host' => $connection->getHost(), + 'port' => $connection->getPort(), + 'transport' => $connection->getTransport(), + ); - $this->_logger->logQuery($path, $method, $data, $time, $full_host); + $this->_logger->logQuery($path, $method, $data, $time, $connection_array); } return $response; diff --git a/Logger/ElasticaLogger.php b/Logger/ElasticaLogger.php index 2d8d0ae..bf7694e 100644 --- a/Logger/ElasticaLogger.php +++ b/Logger/ElasticaLogger.php @@ -38,9 +38,9 @@ class ElasticaLogger implements LoggerInterface * @param string $method Rest method to use (GET, POST, DELETE, PUT) * @param array $data arguments * @param float $time execution time - * @param string $full_host host and port of the query + * @param array $connection host, port and transport of the query */ - public function logQuery($path, $method, $data, $time, $full_host = null) + public function logQuery($path, $method, $data, $time, $connection = array()) { if ($this->debug) { $this->queries[] = array( @@ -48,7 +48,7 @@ class ElasticaLogger implements LoggerInterface 'method' => $method, 'data' => $data, 'executionMS' => $time, - 'full_host' => $full_host + 'connection' => $connection ); } diff --git a/Resources/views/Collector/elastica.html.twig b/Resources/views/Collector/elastica.html.twig index 8b27376..5da6048 100644 --- a/Resources/views/Collector/elastica.html.twig +++ b/Resources/views/Collector/elastica.html.twig @@ -44,7 +44,7 @@ {% for key, query in collector.queries %}
  • Path: {{ query.path }}
    - Method: {{ query.method }} + Method: {{ query.method }} ({{ query.connection.transport }} on {{ query.connection.host }}:{{ query.connection.port }})
    {{ query.data|json_encode }}
    @@ -52,7 +52,7 @@ Time: {{ '%0.2f'|format(query.executionMS * 1000) }} ms - {% if query.full_host %} + {% if query.connection.transport in ['Http', 'Https'] %}{# cURL support only HTTP #} + - @@ -60,7 +60,7 @@ {% endif %}
  • diff --git a/Tests/Logger/ElasticaLoggerTest.php b/Tests/Logger/ElasticaLoggerTest.php index 73ba4ac..18eb44b 100644 --- a/Tests/Logger/ElasticaLoggerTest.php +++ b/Tests/Logger/ElasticaLoggerTest.php @@ -35,17 +35,17 @@ class ElasticaLoggerTest extends \PHPUnit_Framework_TestCase $method = 'testMethod'; $data = array('data'); $time = 12; - $full_host = 'http://example.com:9200'; + $connection = array('host' => 'localhost', 'port' => '8999', 'transport' => 'https'); $expected = array( 'path' => $path, 'method' => $method, 'data' => $data, 'executionMS' => $time, - 'full_host' => $full_host, + 'connection' => $connection, ); - $elasticaLogger->logQuery($path, $method, $data, $time, $full_host); + $elasticaLogger->logQuery($path, $method, $data, $time, $connection); $returnedQueries = $elasticaLogger->getQueries(); $this->assertEquals($expected, $returnedQueries[0]); } From 70e6cb2e7ea3459ab2f8040f87d1a41e17fa13b3 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Tue, 10 Dec 2013 21:25:38 +1100 Subject: [PATCH 111/447] Fix issue with logger not having logQuery method --- Client.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Client.php b/Client.php index 119f420..ea0c572 100644 --- a/Client.php +++ b/Client.php @@ -4,6 +4,7 @@ namespace FOS\ElasticaBundle; use Elastica\Client as ElasticaClient; use Elastica\Request; +use FOS\ElasticaBundle\Logger\ElasticaLogger; /** * @author Gordon Franke @@ -15,7 +16,7 @@ class Client extends ElasticaClient $start = microtime(true); $response = parent::request($path, $method, $data, $query); - if (null !== $this->_logger) { + if (null !== $this->_logger and $this->_logger instanceof ElasticaLogger) { $time = microtime(true) - $start; $connection = $this->getLastRequest()->getConnection(); From e16ece821d662429ceaf3cf7724874bbfe54335a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cs=C3=A1sz=C3=A1r=20D=C3=A1niel?= Date: Tue, 10 Dec 2013 13:54:50 +0100 Subject: [PATCH 112/447] Fix client configuration missing logger --- DependencyInjection/Configuration.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index a9c9898..8d913f0 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -78,7 +78,7 @@ class Configuration implements ConfigurationInterface array( 'host' => $v['host'], 'port' => $v['port'], - 'logger' => $v['logger'] + 'logger' => isset($v['logger']) ? $v['logger'] : null ) ) ); @@ -91,7 +91,7 @@ class Configuration implements ConfigurationInterface 'servers' => array( array( 'url' => $v['url'], - 'logger' => $v['logger'] + 'logger' => isset($v['logger']) ? $v['logger'] : null ) ) ); From eaf52fa9072c5905b035e69d9c2585218b53838e Mon Sep 17 00:00:00 2001 From: Lea Haensenberger Date: Tue, 10 Dec 2013 08:42:56 +0100 Subject: [PATCH 113/447] Allow a more dynamic mapping for dynamic templates --- DependencyInjection/Configuration.php | 61 ++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 10 deletions(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 8d913f0..70718ef 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -341,16 +341,7 @@ class Configuration implements ConfigurationInterface ->children() ->scalarNode('match')->isRequired()->end() ->scalarNode('match_mapping_type')->end() - ->arrayNode('mapping') - ->isRequired() - ->children() - ->scalarNode('type')->end() - ->scalarNode('index')->end() - ->arrayNode('fields') - ->children() - ->end() - ->end() - ->end() + ->append($this->getDynamicTemplateMapping()) ->end() ->end() ; @@ -358,6 +349,21 @@ class Configuration implements ConfigurationInterface return $node; } + /** + * @return the array node used for mapping in dynamic templates + */ + protected function getDynamicTemplateMapping() + { + $builder = new TreeBuilder(); + $node = $builder->root('mapping'); + + $nestings = $this->getNestingsForDynamicTemplates(); + + $this->addFieldConfig($node->children(), $nestings); + + return $node; + } + /** * @param \Symfony\Component\Config\Definition\Builder\NodeBuilder $node The node to which to attach the field config to * @param array $nestings the nested mappings for the current field level @@ -451,6 +457,41 @@ class Configuration implements ConfigurationInterface return $nestings; } + /** + * @return array The unique nested mappings for all dynamic templates + */ + protected function getNestingsForDynamicTemplates() + { + if (!isset($this->configArray[0]['indexes'])) { + return array(); + } + + $nestings = array(); + foreach ($this->configArray[0]['indexes'] as $index) { + if (empty($index['types'])) { + continue; + } + + foreach ($index['types'] as $type) { + if (empty($type['dynamic_templates'])) { + continue; + } + + foreach ($type['dynamic_templates'] as $definition) { + $field = $definition['mapping']; + + if (isset($field['fields'])) { + $this->addPropertyNesting($field, $nestings, 'fields'); + } else if (isset($field['properties'])) { + $this->addPropertyNesting($field, $nestings, 'properties'); + } + } + + } + } + return $nestings; + } + /** * @param array $mappings The mappings for the current type * @return array The nested mappings defined for this type From bad1769c844207f9d64247eb30811f1fcdca1eaf Mon Sep 17 00:00:00 2001 From: Lea Haensenberger Date: Tue, 10 Dec 2013 08:49:20 +0100 Subject: [PATCH 114/447] Fixing tests --- Tests/DependencyInjection/ConfigurationTest.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Tests/DependencyInjection/ConfigurationTest.php b/Tests/DependencyInjection/ConfigurationTest.php index ead9977..84285fb 100644 --- a/Tests/DependencyInjection/ConfigurationTest.php +++ b/Tests/DependencyInjection/ConfigurationTest.php @@ -63,13 +63,10 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase $this->assertArrayHasKey('type', $mapping); $this->assertInstanceOf('Symfony\Component\Config\Definition\ScalarNode', $mapping['type']); - $this->assertNull($mapping['type']->getDefaultValue()); + $this->assertSame('string', $mapping['type']->getDefaultValue()); $this->assertArrayHasKey('index', $mapping); $this->assertInstanceOf('Symfony\Component\Config\Definition\ScalarNode', $mapping['index']); $this->assertNull($mapping['index']->getDefaultValue()); - - $this->assertArrayHasKey('fields', $mapping); - $this->assertInstanceOf('Symfony\Component\Config\Definition\ArrayNode', $mapping['fields']); } } From 09031457cd5159044127e4f5c2a404062ab5912d Mon Sep 17 00:00:00 2001 From: Lea Haensenberger Date: Tue, 10 Dec 2013 09:02:17 +0100 Subject: [PATCH 115/447] Allow more matching methods --- DependencyInjection/Configuration.php | 6 +++++- Tests/DependencyInjection/ConfigurationTest.php | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 70718ef..e9088e8 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -339,8 +339,12 @@ class Configuration implements ConfigurationInterface ->useAttributeAsKey('name') ->prototype('array') ->children() - ->scalarNode('match')->isRequired()->end() + ->scalarNode('match')->end() + ->scalarNode('unmatch')->end() ->scalarNode('match_mapping_type')->end() + ->scalarNode('path_match')->end() + ->scalarNode('path_unmatch')->end() + ->scalarNode('match_pattern')->end() ->append($this->getDynamicTemplateMapping()) ->end() ->end() diff --git a/Tests/DependencyInjection/ConfigurationTest.php b/Tests/DependencyInjection/ConfigurationTest.php index 84285fb..53d060d 100644 --- a/Tests/DependencyInjection/ConfigurationTest.php +++ b/Tests/DependencyInjection/ConfigurationTest.php @@ -48,6 +48,22 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('Symfony\Component\Config\Definition\ScalarNode', $dynamicTemplates['match_mapping_type']); $this->assertNull($dynamicTemplates['match_mapping_type']->getDefaultValue()); + $this->assertArrayHasKey('unmatch', $dynamicTemplates); + $this->assertInstanceOf('Symfony\Component\Config\Definition\ScalarNode', $dynamicTemplates['unmatch']); + $this->assertNull($dynamicTemplates['unmatch']->getDefaultValue()); + + $this->assertArrayHasKey('path_match', $dynamicTemplates); + $this->assertInstanceOf('Symfony\Component\Config\Definition\ScalarNode', $dynamicTemplates['path_match']); + $this->assertNull($dynamicTemplates['path_match']->getDefaultValue()); + + $this->assertArrayHasKey('path_unmatch', $dynamicTemplates); + $this->assertInstanceOf('Symfony\Component\Config\Definition\ScalarNode', $dynamicTemplates['v']); + $this->assertNull($dynamicTemplates['path_unmatch']->getDefaultValue()); + + $this->assertArrayHasKey('match_pattern', $dynamicTemplates); + $this->assertInstanceOf('Symfony\Component\Config\Definition\ScalarNode', $dynamicTemplates['match_pattern']); + $this->assertNull($dynamicTemplates['match_pattern']->getDefaultValue()); + $this->assertArrayHasKey('mapping', $dynamicTemplates); $this->assertInstanceOf('Symfony\Component\Config\Definition\ArrayNode', $dynamicTemplates['mapping']); } From e55c7e8632556bce7d58fbf9cfa3f0936a32b1d2 Mon Sep 17 00:00:00 2001 From: Lea Haensenberger Date: Tue, 10 Dec 2013 09:03:27 +0100 Subject: [PATCH 116/447] Set match to '*' by default --- DependencyInjection/Configuration.php | 2 +- Tests/DependencyInjection/ConfigurationTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index e9088e8..c790f66 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -339,7 +339,7 @@ class Configuration implements ConfigurationInterface ->useAttributeAsKey('name') ->prototype('array') ->children() - ->scalarNode('match')->end() + ->scalarNode('match')->defaultValue('*')->end() ->scalarNode('unmatch')->end() ->scalarNode('match_mapping_type')->end() ->scalarNode('path_match')->end() diff --git a/Tests/DependencyInjection/ConfigurationTest.php b/Tests/DependencyInjection/ConfigurationTest.php index 53d060d..f3ff4a6 100644 --- a/Tests/DependencyInjection/ConfigurationTest.php +++ b/Tests/DependencyInjection/ConfigurationTest.php @@ -42,7 +42,7 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase $this->assertArrayHasKey('match', $dynamicTemplates); $this->assertInstanceOf('Symfony\Component\Config\Definition\ScalarNode', $dynamicTemplates['match']); - $this->assertNull($dynamicTemplates['match']->getDefaultValue()); + $this->assertSame('*', $dynamicTemplates['match']->getDefaultValue()); $this->assertArrayHasKey('match_mapping_type', $dynamicTemplates); $this->assertInstanceOf('Symfony\Component\Config\Definition\ScalarNode', $dynamicTemplates['match_mapping_type']); From 0aa98d2295d536a4b4f0373e1efee33e0f1ca201 Mon Sep 17 00:00:00 2001 From: Lea Haensenberger Date: Tue, 10 Dec 2013 12:58:34 +0100 Subject: [PATCH 117/447] Fixing copy&paste error --- Tests/DependencyInjection/ConfigurationTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/DependencyInjection/ConfigurationTest.php b/Tests/DependencyInjection/ConfigurationTest.php index f3ff4a6..4ea5657 100644 --- a/Tests/DependencyInjection/ConfigurationTest.php +++ b/Tests/DependencyInjection/ConfigurationTest.php @@ -57,7 +57,7 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase $this->assertNull($dynamicTemplates['path_match']->getDefaultValue()); $this->assertArrayHasKey('path_unmatch', $dynamicTemplates); - $this->assertInstanceOf('Symfony\Component\Config\Definition\ScalarNode', $dynamicTemplates['v']); + $this->assertInstanceOf('Symfony\Component\Config\Definition\ScalarNode', $dynamicTemplates['path_unmatch']); $this->assertNull($dynamicTemplates['path_unmatch']->getDefaultValue()); $this->assertArrayHasKey('match_pattern', $dynamicTemplates); From a59385af7b08439c02271904ea3b96c6000f36fd Mon Sep 17 00:00:00 2001 From: Lea Haensenberger Date: Tue, 10 Dec 2013 15:37:41 +0100 Subject: [PATCH 118/447] Do not set default value to *, might conflict when using e.g. path_match and match_pattern regex together --- DependencyInjection/Configuration.php | 2 +- Tests/DependencyInjection/ConfigurationTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index c790f66..e9088e8 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -339,7 +339,7 @@ class Configuration implements ConfigurationInterface ->useAttributeAsKey('name') ->prototype('array') ->children() - ->scalarNode('match')->defaultValue('*')->end() + ->scalarNode('match')->end() ->scalarNode('unmatch')->end() ->scalarNode('match_mapping_type')->end() ->scalarNode('path_match')->end() diff --git a/Tests/DependencyInjection/ConfigurationTest.php b/Tests/DependencyInjection/ConfigurationTest.php index 4ea5657..35b2af3 100644 --- a/Tests/DependencyInjection/ConfigurationTest.php +++ b/Tests/DependencyInjection/ConfigurationTest.php @@ -42,7 +42,7 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase $this->assertArrayHasKey('match', $dynamicTemplates); $this->assertInstanceOf('Symfony\Component\Config\Definition\ScalarNode', $dynamicTemplates['match']); - $this->assertSame('*', $dynamicTemplates['match']->getDefaultValue()); + $this->assertNull($dynamicTemplates['match']->getDefaultValue()); $this->assertArrayHasKey('match_mapping_type', $dynamicTemplates); $this->assertInstanceOf('Symfony\Component\Config\Definition\ScalarNode', $dynamicTemplates['match_mapping_type']); From 090f02b05d827b0f242d70434f17b46138564f6b Mon Sep 17 00:00:00 2001 From: Craig Marvelley Date: Wed, 11 Dec 2013 22:52:25 +0000 Subject: [PATCH 119/447] Improve test coverage --- Logger/ElasticaLogger.php | 2 +- Tests/ClientTest.php | 42 ++++++++++++++ Tests/FOSElasticaBundleTest.php | 39 +++++++++++++ Tests/HybridResultTest.php | 19 ++++++ Tests/Logger/ElasticaLoggerTest.php | 90 +++++++++++++++++++++++++++-- Tests/RepositoryTest.php | 16 +++++ 6 files changed, 203 insertions(+), 5 deletions(-) create mode 100644 Tests/ClientTest.php create mode 100644 Tests/FOSElasticaBundleTest.php create mode 100644 Tests/HybridResultTest.php diff --git a/Logger/ElasticaLogger.php b/Logger/ElasticaLogger.php index bf7694e..7aacac5 100644 --- a/Logger/ElasticaLogger.php +++ b/Logger/ElasticaLogger.php @@ -147,6 +147,6 @@ class ElasticaLogger implements LoggerInterface */ public function log($level, $message, array $context = array()) { - return $this->logger->log($message, $context); + return $this->logger->log($level, $message, $context); } } diff --git a/Tests/ClientTest.php b/Tests/ClientTest.php new file mode 100644 index 0000000..c8509cf --- /dev/null +++ b/Tests/ClientTest.php @@ -0,0 +1,42 @@ +getMock('Elastica\Connection'); + $connection->expects($this->any())->method('getTransportObject')->will($this->returnValue($transport)); + $connection->expects($this->any())->method('toArray')->will($this->returnValue(array())); + + $logger = $this->getMock('FOS\ElasticaBundle\Logger\ElasticaLogger'); + $logger + ->expects($this->once()) + ->method('logQuery') + ->with( + 'foo', + Request::GET, + $this->isType('array'), + $this->isType('float'), + $this->isType('array') + ); + + $client = $this->getMockBuilder('FOS\ElasticaBundle\Client') + ->setMethods(array('getConnection')) + ->getMock(); + + $client->expects($this->any())->method('getConnection')->will($this->returnValue($connection)); + + $client->setLogger($logger); + + $response = $client->request('foo'); + + $this->assertInstanceOf('Elastica\Response', $response); + } +} diff --git a/Tests/FOSElasticaBundleTest.php b/Tests/FOSElasticaBundleTest.php new file mode 100644 index 0000000..2bfc7f9 --- /dev/null +++ b/Tests/FOSElasticaBundleTest.php @@ -0,0 +1,39 @@ +getMock('Symfony\Component\DependencyInjection\ContainerBuilder'); + + $container + ->expects($this->at(0)) + ->method('addCompilerPass') + ->with($this->isInstanceOf($passes[0][0]), $passes[0][1]); + + $container + ->expects($this->at(1)) + ->method('addCompilerPass') + ->with($this->isInstanceOf($passes[1][0])); + + $bundle = new FOSElasticaBundle(); + + $bundle->build($container); + } +} diff --git a/Tests/HybridResultTest.php b/Tests/HybridResultTest.php new file mode 100644 index 0000000..cb382d1 --- /dev/null +++ b/Tests/HybridResultTest.php @@ -0,0 +1,19 @@ +assertSame($result, $hybridResult->getResult()); + $this->assertNull($hybridResult->getTransformed()); + } +} diff --git a/Tests/Logger/ElasticaLoggerTest.php b/Tests/Logger/ElasticaLoggerTest.php index 05624cc..30ce30c 100644 --- a/Tests/Logger/ElasticaLoggerTest.php +++ b/Tests/Logger/ElasticaLoggerTest.php @@ -9,6 +9,40 @@ use FOS\ElasticaBundle\Logger\ElasticaLogger; */ class ElasticaLoggerTest extends \PHPUnit_Framework_TestCase { + /** + * @return \PHPUnit_Framework_MockObject_MockObject|\Symfony\Component\HttpKernel\Log\LoggerInterface + */ + private function getMockLogger() + { + return $this->getMockBuilder('Symfony\Component\HttpKernel\Log\LoggerInterface') + ->disableOriginalConstructor() + ->getMock(); + } + + /** + * @param string $level + * @param string $message + * @param array $context + * @return ElasticaLogger + */ + private function getMockLoggerForLevelMessageAndContext($level, $message, $context) + { + $loggerMock = $this->getMockBuilder('Symfony\Component\HttpKernel\Log\LoggerInterface') + ->disableOriginalConstructor() + ->getMock(); + + $loggerMock->expects($this->once()) + ->method($level) + ->with( + $this->equalTo($message), + $this->equalTo($context) + ); + + $elasticaLogger = new ElasticaLogger($loggerMock); + + return $elasticaLogger; + } + public function testGetZeroIfNoQueriesAdded() { $elasticaLogger = new ElasticaLogger; @@ -64,10 +98,7 @@ class ElasticaLoggerTest extends \PHPUnit_Framework_TestCase public function testQueryIsLogged() { - /** @var $loggerMock \PHPUnit_Framework_MockObject_MockObject|\Symfony\Component\HttpKernel\Log\LoggerInterface */ - $loggerMock = $this->getMockBuilder('Symfony\Component\HttpKernel\Log\LoggerInterface') - ->disableOriginalConstructor() - ->getMock(); + $loggerMock = $this->getMockLogger(); $elasticaLogger = new ElasticaLogger($loggerMock); @@ -87,4 +118,55 @@ class ElasticaLoggerTest extends \PHPUnit_Framework_TestCase $elasticaLogger->logQuery($path, $method, $data, $time); } + + /** + * @return array + */ + public function logLevels() + { + return array( + array('emergency'), + array('alert'), + array('critical'), + array('error'), + array('warning'), + array('notice'), + array('info'), + array('debug'), + ); + } + + /** + * @dataProvider logLevels + */ + public function testMessagesCanBeLoggedAtSpecificLogLevels($level) + { + $message = 'foo'; + $context = array('data'); + + $loggerMock = $this->getMockLoggerForLevelMessageAndContext($level, $message, $context); + + call_user_func(array($loggerMock, $level), $message, $context); + } + + public function testMessagesCanBeLoggedToArbitraryLevels() + { + $loggerMock = $this->getMockLogger(); + + $level = 'info'; + $message = 'foo'; + $context = array('data'); + + $loggerMock->expects($this->once()) + ->method('log') + ->with( + $level, + $message, + $context + ); + + $elasticaLogger = new ElasticaLogger($loggerMock); + + $elasticaLogger->log($level, $message, $context); + } } diff --git a/Tests/RepositoryTest.php b/Tests/RepositoryTest.php index 6eabe7b..c4d4efc 100644 --- a/Tests/RepositoryTest.php +++ b/Tests/RepositoryTest.php @@ -58,6 +58,22 @@ class RepositoryTest extends \PHPUnit_Framework_TestCase $repository->findPaginated($testQuery); } + public function testThatCreatePaginatorCreatesAPaginatorViaFinder() + { + $testQuery = 'Test Query'; + + /** @var $typeMock \PHPUnit_Framework_MockObject_MockObject|\FOS\ElasticaBundle\Finder\TransformedFinder */ + $finderMock = $this->getMockBuilder('FOS\ElasticaBundle\Finder\TransformedFinder') + ->disableOriginalConstructor() + ->getMock(); + $finderMock->expects($this->once()) + ->method('createPaginatorAdapter') + ->with($this->equalTo($testQuery)); + + $repository = new Repository($finderMock); + $repository->createPaginatorAdapter($testQuery); + } + public function testThatFindHybridCallsFindHybridOnFinder() { $testQuery = 'Test Query'; From 11a87c5ce3fbe1b7a4e240b494d2be12f4973000 Mon Sep 17 00:00:00 2001 From: Craig Marvelley Date: Thu, 12 Dec 2013 20:48:15 +0000 Subject: [PATCH 120/447] Add test for ElasticaToModelTransformerCollection::hybridTransform --- ...asticaToModelTransformerCollectionTest.php | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/Tests/Transformer/ElasticaToModelTransformerCollectionTest.php b/Tests/Transformer/ElasticaToModelTransformerCollectionTest.php index d33708e..bb5f6a3 100644 --- a/Tests/Transformer/ElasticaToModelTransformerCollectionTest.php +++ b/Tests/Transformer/ElasticaToModelTransformerCollectionTest.php @@ -3,6 +3,7 @@ namespace FOS\ElasticaBundle\Tests\Transformer; use Elastica\Document; +use Elastica\Result; use FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerCollection; class ElasticaToModelTransformerCollectionTest extends \PHPUnit_Framework_TestCase @@ -98,6 +99,57 @@ class ElasticaToModelTransformerCollectionTest extends \PHPUnit_Framework_TestCa $result2, ), $results); } + + public function testGetIdentifierFieldReturnsAMapOfIdentifiers() + { + $collection = new ElasticaToModelTransformerCollection(array()); + $identifiers = $collection->getIdentifierField(); + $this->assertInternalType('array', $identifiers); + $this->assertEmpty($identifiers); + + $this->collectionSetup(); + $identifiers = $this->collection->getIdentifierField(); + $this->assertInternalType('array', $identifiers); + $this->assertEquals(array('type1' => 'id', 'type2' => 'id'), $identifiers); + } + + public function elasticaResults() + { + $document = new Result(array('_id' => 123, '_type' => 'type1')); + $result = new POPO(123, array()); + + return array( + array( + $document, $result + ) + ); + } + + /** + * @dataProvider elasticaResults + */ + public function testHybridTransformDecoratesResultsWithHybridResultObjects($document, $result) + { + $transformer = $this->getMock('FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface'); + $transformer->expects($this->any())->method('getIdentifierField')->will($this->returnValue('id')); + + $transformer + ->expects($this->any()) + ->method('transform') + ->will($this->returnValue(array($result))); + + $collection = new ElasticaToModelTransformerCollection(array('type1' => $transformer)); + + $hybridResults = $collection->hybridTransform(array($document)); + + $this->assertInternalType('array', $hybridResults); + $this->assertNotEmpty($hybridResults); + $this->assertContainsOnlyInstancesOf('FOS\ElasticaBundle\HybridResult', $hybridResults); + + $hybridResult = array_pop($hybridResults); + $this->assertEquals($document, $hybridResult->getResult()); + $this->assertEquals($result, $hybridResult->getTransformed()); + } } class POPO From 5d16ffb1bf31c01d0748e2f6b6950af3989d2b2c Mon Sep 17 00:00:00 2001 From: Craig Marvelley Date: Thu, 12 Dec 2013 20:50:15 +0000 Subject: [PATCH 121/447] Remove unused method --- Transformer/ElasticaToModelTransformerCollection.php | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Transformer/ElasticaToModelTransformerCollection.php b/Transformer/ElasticaToModelTransformerCollection.php index 6264959..a261e81 100644 --- a/Transformer/ElasticaToModelTransformerCollection.php +++ b/Transformer/ElasticaToModelTransformerCollection.php @@ -84,11 +84,4 @@ class ElasticaToModelTransformerCollection implements ElasticaToModelTransformer return $result; } - - protected function getTypeToClassMap() - { - return array_map(function (ElasticaToModelTransformerInterface $transformer) { - return $transformer->getObjectClass(); - }, $this->transformers); - } } From e0ef8dff23dd7d100905bb8a8a28ee07ef89a660 Mon Sep 17 00:00:00 2001 From: Burkhard Reffeling Date: Thu, 12 Dec 2013 22:41:20 +0000 Subject: [PATCH 122/447] removed duplicate methods --- Persister/ObjectSerializerPersister.php | 63 ------------------------- 1 file changed, 63 deletions(-) diff --git a/Persister/ObjectSerializerPersister.php b/Persister/ObjectSerializerPersister.php index 8938a2f..1a15656 100644 --- a/Persister/ObjectSerializerPersister.php +++ b/Persister/ObjectSerializerPersister.php @@ -23,69 +23,6 @@ class ObjectSerializerPersister extends ObjectPersister $this->serializer = $serializer; } - /** - * Insert one object into the type - * The object will be transformed to an elastica document - * - * @param object $object - */ - public function insertOne($object) - { - $document = $this->transformToElasticaDocument($object); - $this->type->addDocument($document); - } - - /** - * Replaces one object in the type - * - * @param object $object - * @return null - */ - public function replaceOne($object) - { - $document = $this->transformToElasticaDocument($object); - $this->type->deleteById($document->getId()); - $this->type->addDocument($document); - } - - /** - * Deletes one object in the type - * - * @param object $object - * @return null - **/ - public function deleteOne($object) - { - $document = $this->transformToElasticaDocument($object); - $this->type->deleteById($document->getId()); - } - - /** - * Deletes one object in the type by id - * - * @param mixed $id - * - * @return null - **/ - public function deleteById($id) - { - $this->type->deleteById($id); - } - - /** - * Inserts an array of objects in the type - * - * @param array $objects array of domain model objects - **/ - public function insertMany(array $objects) - { - $docs = array(); - foreach ($objects as $object) { - $docs[] = $this->transformToElasticaDocument($object); - } - $this->type->addDocuments($docs); - } - /** * Transforms an object to an elastica document * with just the identifier set From 292af9f039e2c52b4d02fb9c0f2f916b068f67f9 Mon Sep 17 00:00:00 2001 From: Craig Marvelley Date: Thu, 12 Dec 2013 22:55:37 +0000 Subject: [PATCH 123/447] Better variable names --- .../ElasticaToModelTransformerCollectionTest.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Tests/Transformer/ElasticaToModelTransformerCollectionTest.php b/Tests/Transformer/ElasticaToModelTransformerCollectionTest.php index bb5f6a3..eb4d8e4 100644 --- a/Tests/Transformer/ElasticaToModelTransformerCollectionTest.php +++ b/Tests/Transformer/ElasticaToModelTransformerCollectionTest.php @@ -115,12 +115,12 @@ class ElasticaToModelTransformerCollectionTest extends \PHPUnit_Framework_TestCa public function elasticaResults() { - $document = new Result(array('_id' => 123, '_type' => 'type1')); - $result = new POPO(123, array()); + $result = new Result(array('_id' => 123, '_type' => 'type1')); + $transformedObject = new POPO(123, array()); return array( array( - $document, $result + $result, $transformedObject ) ); } @@ -128,7 +128,7 @@ class ElasticaToModelTransformerCollectionTest extends \PHPUnit_Framework_TestCa /** * @dataProvider elasticaResults */ - public function testHybridTransformDecoratesResultsWithHybridResultObjects($document, $result) + public function testHybridTransformDecoratesResultsWithHybridResultObjects($result, $transformedObject) { $transformer = $this->getMock('FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface'); $transformer->expects($this->any())->method('getIdentifierField')->will($this->returnValue('id')); @@ -136,19 +136,19 @@ class ElasticaToModelTransformerCollectionTest extends \PHPUnit_Framework_TestCa $transformer ->expects($this->any()) ->method('transform') - ->will($this->returnValue(array($result))); + ->will($this->returnValue(array($transformedObject))); $collection = new ElasticaToModelTransformerCollection(array('type1' => $transformer)); - $hybridResults = $collection->hybridTransform(array($document)); + $hybridResults = $collection->hybridTransform(array($result)); $this->assertInternalType('array', $hybridResults); $this->assertNotEmpty($hybridResults); $this->assertContainsOnlyInstancesOf('FOS\ElasticaBundle\HybridResult', $hybridResults); $hybridResult = array_pop($hybridResults); - $this->assertEquals($document, $hybridResult->getResult()); - $this->assertEquals($result, $hybridResult->getTransformed()); + $this->assertEquals($result, $hybridResult->getResult()); + $this->assertEquals($transformedObject, $hybridResult->getTransformed()); } } From 3bd9155f467b6d46896d88d29050ddc593c53324 Mon Sep 17 00:00:00 2001 From: nurikabe Date: Fri, 13 Dec 2013 17:51:15 +0000 Subject: [PATCH 124/447] Use constants of corresponding events classes rather than making assumption about string values. --- DependencyInjection/FOSElasticaExtension.php | 23 ++++++++++++++++---- Doctrine/Listener.php | 2 +- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 6380873..733a039 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -403,17 +403,32 @@ class FOSElasticaExtension extends Extension return $listenerId; } + /** + * Map Elastica to Doctrine events for the current driver + */ private function getDoctrineEvents(array $typeConfig) { // Flush always calls depending on actions scheduled in lifecycle listeners $typeConfig['listener']['flush'] = true; + switch ($typeConfig['driver']) { + case 'orm': + $eventsClass = '\Doctrine\ORM\Events'; + break; + case 'mongodb': + $eventsClass = '\Doctrine\ODM\MongoDB\Events'; + break; + default: + throw new InvalidArgumentException(sprintf('Cannot determine events for driver "%s"', $typeConfig['driver'])); + break; + } + $events = array(); $eventMapping = array( - 'insert' => array('postPersist'), - 'update' => array('postUpdate'), - 'delete' => array('preRemove'), - 'flush' => array($typeConfig['listener']['immediate'] ? 'preFlush' : 'postFlush') + 'insert' => array(constant($eventsClass.'::postPersist')), + 'update' => array(constant($eventsClass.'::postUpdate')), + 'delete' => array(constant($eventsClass.'::preRemove')), + 'flush' => array($typeConfig['listener']['immediate'] ? constant($eventsClass.'::preFlush') : constant($eventsClass.'::postFlush')) ); foreach ($eventMapping as $event => $doctrineEvents) { diff --git a/Doctrine/Listener.php b/Doctrine/Listener.php index 683070e..383e02f 100644 --- a/Doctrine/Listener.php +++ b/Doctrine/Listener.php @@ -27,7 +27,7 @@ class Listener implements EventSubscriber protected $objectClass; /** - * List of su]bscribed events + * List of subscribed events * * @var array */ From e2e21b1e0ceb9745404f459b8a1b9a393233b100 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Sun, 15 Dec 2013 18:33:31 +1100 Subject: [PATCH 125/447] Allow bundle to be used without clients or indexes defined. --- DependencyInjection/FOSElasticaExtension.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 8b85629..cb2f706 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -24,12 +24,14 @@ class FOSElasticaExtension extends Extension $config = $this->processConfiguration($configuration, $configs); $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); - $loader->load('config.xml'); if (empty($config['clients']) || empty($config['indexes'])) { - throw new InvalidArgumentException('You must define at least one client and one index'); + // No Clients or indexes are defined + return; } + $loader->load('config.xml'); + if (empty($config['default_client'])) { $keys = array_keys($config['clients']); $config['default_client'] = reset($keys); From 90022b0d0a540e8bf5fc44cde6c8b996c072aefd Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Sun, 15 Dec 2013 18:33:45 +1100 Subject: [PATCH 126/447] Move type configuration into independent method --- DependencyInjection/Configuration.php | 228 +++++++++++--------------- 1 file changed, 95 insertions(+), 133 deletions(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index e9088e8..11c1cf4 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -138,68 +138,9 @@ class Configuration implements ConfigurationInterface ->scalarNode('client')->end() ->scalarNode('finder') ->treatNullLike(true) - ->defaultFalse() - ->end() - ->arrayNode('type_prototype') - ->children() - ->scalarNode('index_analyzer')->end() - ->scalarNode('search_analyzer')->end() - ->arrayNode('persistence') - ->validate() - ->ifTrue(function($v) { return isset($v['driver']) && 'propel' === $v['driver'] && isset($v['listener']); }) - ->thenInvalid('Propel doesn\'t support listeners') - ->ifTrue(function($v) { return isset($v['driver']) && 'propel' === $v['driver'] && isset($v['repository']); }) - ->thenInvalid('Propel doesn\'t support the "repository" parameter') - ->end() - ->children() - ->scalarNode('driver') - ->validate() - ->ifNotInArray($this->supportedDrivers) - ->thenInvalid('The driver %s is not supported. Please choose one of '.json_encode($this->supportedDrivers)) - ->end() - ->end() - ->scalarNode('identifier')->defaultValue('id')->end() - ->arrayNode('provider') - ->children() - ->scalarNode('query_builder_method')->defaultValue('createQueryBuilder')->end() - ->scalarNode('batch_size')->defaultValue(100)->end() - ->scalarNode('clear_object_manager')->defaultTrue()->end() - ->scalarNode('service')->end() - ->end() - ->end() - ->arrayNode('listener') - ->children() - ->scalarNode('insert')->defaultTrue()->end() - ->scalarNode('update')->defaultTrue()->end() - ->scalarNode('delete')->defaultTrue()->end() - ->scalarNode('service')->end() - ->variableNode('is_indexable_callback')->defaultNull()->end() - ->end() - ->end() - ->arrayNode('finder') - ->children() - ->scalarNode('service')->end() - ->end() - ->end() - ->arrayNode('elastica_to_model_transformer') - ->addDefaultsIfNotSet() - ->children() - ->scalarNode('hydrate')->defaultTrue()->end() - ->scalarNode('ignore_missing')->defaultFalse()->end() - ->scalarNode('query_builder_method')->defaultValue('createQueryBuilder')->end() - ->scalarNode('service')->end() - ->end() - ->end() - ->arrayNode('model_to_elastica_transformer') - ->addDefaultsIfNotSet() - ->children() - ->scalarNode('service')->end() - ->end() - ->end() - ->end() - ->end() - ->end() + ->defaultTrue() ->end() + ->append($this->getTypePrototypeNode()) ->variableNode('settings')->defaultValue(array())->end() ->end() ->append($this->getTypesNode()) @@ -209,6 +150,19 @@ class Configuration implements ConfigurationInterface ; } + /** + * Builds a type prototype node for the index configuration. + */ + protected function getTypePrototypeNode() + { + $builder = new TreeBuilder(); + $node = $builder->root('type_prototype'); + + $this->applyTypeConfiguration($node); + + return $node; + } + /** * Returns the array node used for "types". */ @@ -217,92 +171,100 @@ class Configuration implements ConfigurationInterface $builder = new TreeBuilder(); $node = $builder->root('types'); - $node + $childrenNode = $node ->useAttributeAsKey('name') ->prototype('array') - ->treatNullLike(array()) - ->children() - ->arrayNode('serializer') - ->addDefaultsIfNotSet() - ->children() - ->arrayNode('groups') - ->treatNullLike(array()) - ->prototype('scalar')->end() - ->end() - ->scalarNode('version')->end() + ->treatNullLike(array()); + + $this->applyTypeConfiguration($childrenNode); + + return $node; + } + + /** + * Applies all type configuration fields to a node. + */ + protected function applyTypeConfiguration($node) + { + $node + ->children() + ->arrayNode('serializer') + ->addDefaultsIfNotSet() + ->children() + ->arrayNode('groups') + ->treatNullLike(array()) + ->prototype('scalar')->end() ->end() + ->scalarNode('version')->end() ->end() - ->scalarNode('index_analyzer')->end() - ->scalarNode('search_analyzer')->end() - ->arrayNode('persistence') - ->validate() - ->ifTrue(function($v) { return isset($v['driver']) && 'propel' === $v['driver'] && isset($v['listener']); }) - ->thenInvalid('Propel doesn\'t support listeners') - ->ifTrue(function($v) { return isset($v['driver']) && 'propel' === $v['driver'] && isset($v['repository']); }) - ->thenInvalid('Propel doesn\'t support the "repository" parameter') + ->end() + ->scalarNode('index_analyzer')->end() + ->scalarNode('search_analyzer')->end() + ->arrayNode('persistence') + ->validate() + ->ifTrue(function($v) { return isset($v['driver']) && 'propel' === $v['driver'] && isset($v['listener']); }) + ->thenInvalid('Propel doesn\'t support listeners') + ->ifTrue(function($v) { return isset($v['driver']) && 'propel' === $v['driver'] && isset($v['repository']); }) + ->thenInvalid('Propel doesn\'t support the "repository" parameter') + ->end() + ->children() + ->scalarNode('driver') + ->validate() + ->ifNotInArray($this->supportedDrivers) + ->thenInvalid('The driver %s is not supported. Please choose one of '.json_encode($this->supportedDrivers)) + ->end() ->end() - ->children() - ->scalarNode('driver') - ->validate() - ->ifNotInArray($this->supportedDrivers) - ->thenInvalid('The driver %s is not supported. Please choose one of '.json_encode($this->supportedDrivers)) - ->end() + ->scalarNode('model')->end() + ->scalarNode('repository')->end() + ->scalarNode('identifier')->defaultValue('id')->end() + ->arrayNode('provider') + ->children() + ->scalarNode('query_builder_method')->defaultValue('createQueryBuilder')->end() + ->scalarNode('batch_size')->defaultValue(100)->end() + ->scalarNode('clear_object_manager')->defaultTrue()->end() + ->scalarNode('service')->end() ->end() - ->scalarNode('model')->end() - ->scalarNode('repository')->end() - ->scalarNode('identifier')->defaultValue('id')->end() - ->arrayNode('provider') - ->children() - ->scalarNode('query_builder_method')->defaultValue('createQueryBuilder')->end() - ->scalarNode('batch_size')->defaultValue(100)->end() - ->scalarNode('clear_object_manager')->defaultTrue()->end() - ->scalarNode('service')->end() - ->end() + ->end() + ->arrayNode('listener') + ->children() + ->scalarNode('insert')->defaultTrue()->end() + ->scalarNode('update')->defaultTrue()->end() + ->scalarNode('delete')->defaultTrue()->end() + ->scalarNode('service')->end() + ->variableNode('is_indexable_callback')->defaultNull()->end() ->end() - ->arrayNode('listener') - ->children() - ->scalarNode('insert')->defaultTrue()->end() - ->scalarNode('update')->defaultTrue()->end() - ->scalarNode('delete')->defaultTrue()->end() - ->scalarNode('service')->end() - ->variableNode('is_indexable_callback')->defaultNull()->end() - ->end() + ->end() + ->arrayNode('finder') + ->children() + ->scalarNode('service')->end() ->end() - ->arrayNode('finder') - ->children() - ->scalarNode('service')->end() - ->end() + ->end() + ->arrayNode('elastica_to_model_transformer') + ->addDefaultsIfNotSet() + ->children() + ->scalarNode('hydrate')->defaultTrue()->end() + ->scalarNode('ignore_missing')->defaultFalse()->end() + ->scalarNode('query_builder_method')->defaultValue('createQueryBuilder')->end() + ->scalarNode('service')->end() ->end() - ->arrayNode('elastica_to_model_transformer') - ->addDefaultsIfNotSet() - ->children() - ->scalarNode('hydrate')->defaultTrue()->end() - ->scalarNode('ignore_missing')->defaultFalse()->end() - ->scalarNode('query_builder_method')->defaultValue('createQueryBuilder')->end() - ->scalarNode('service')->end() - ->end() - ->end() - ->arrayNode('model_to_elastica_transformer') - ->addDefaultsIfNotSet() - ->children() - ->scalarNode('service')->end() - ->end() + ->end() + ->arrayNode('model_to_elastica_transformer') + ->addDefaultsIfNotSet() + ->children() + ->scalarNode('service')->end() ->end() ->end() ->end() ->end() - ->append($this->getIdNode()) - ->append($this->getMappingsNode()) - ->append($this->getDynamicTemplateNode()) - ->append($this->getSourceNode()) - ->append($this->getBoostNode()) - ->append($this->getRoutingNode()) - ->append($this->getParentNode()) - ->append($this->getAllNode()) ->end() - ; - - return $node; + ->append($this->getIdNode()) + ->append($this->getMappingsNode()) + ->append($this->getDynamicTemplateNode()) + ->append($this->getSourceNode()) + ->append($this->getBoostNode()) + ->append($this->getRoutingNode()) + ->append($this->getParentNode()) + ->append($this->getAllNode()); } /** From 05ee300ddb2c1d13ec44c8f65b79808e06fbfe2a Mon Sep 17 00:00:00 2001 From: Lea Haensenberger Date: Mon, 16 Dec 2013 11:58:58 +0100 Subject: [PATCH 127/447] Fixing reset command to allow resetting of just one type, starting to write test --- Command/ResetCommand.php | 2 +- Tests/Command/ResetCommandTest.php | 53 ++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 Tests/Command/ResetCommandTest.php diff --git a/Command/ResetCommand.php b/Command/ResetCommand.php index 280f9aa..06cfe48 100755 --- a/Command/ResetCommand.php +++ b/Command/ResetCommand.php @@ -60,7 +60,7 @@ class ResetCommand extends ContainerAwareCommand if (null !== $type) { $output->writeln(sprintf('Resetting %s/%s', $index, $type)); - $this->resetter->resetIndex($index, $type); + $this->resetter->resetIndexType($index, $type); } else { $indexes = null === $index ? array_keys($this->indexManager->getAllIndexes()) diff --git a/Tests/Command/ResetCommandTest.php b/Tests/Command/ResetCommandTest.php new file mode 100644 index 0000000..44d493e --- /dev/null +++ b/Tests/Command/ResetCommandTest.php @@ -0,0 +1,53 @@ +resetter = $this->getMockBuilder('\FOS\ElasticaBundle\Resetter') + ->disableOriginalConstructor() + ->setMethods(array('resetIndex', 'resetIndexType')) + ->getMock(); + + $container->set('fos_elastica.resetter', $this->resetter); + + $this->indexManager = $this->getMockBuilder('\FOS\ElasticaBundle\IndexManager') + ->disableOriginalConstructor() + ->setMethods(array('getAllIndexes')) + ->getMock(); + + $this->command = new ResetCommand(); + $this->command->setContainer($container); + } + + public function testResetAllIndexes() + { + $this->indexManager->expects($this->any()) + ->method('getAllIndexes') + ->will($this->returnValue(array('index1', 'index2'))); + + $this->resetter->expects($this->at(1)) + ->method('resetIndex') + ->with($this->equalTo('index1')); + + $this->resetter->expects($this->at(2)) + ->method('resetIndex') + ->with($this->equalTo('index2')); + + $this->command->run( + new ArrayInput(array()), + new NullOutput() + ); + } +} \ No newline at end of file From e906d780ad019d4196b4e0817337f5a5a31eba17 Mon Sep 17 00:00:00 2001 From: Lea Haensenberger Date: Mon, 16 Dec 2013 12:06:53 +0100 Subject: [PATCH 128/447] Adding tests --- Tests/Command/ResetCommandTest.php | 44 ++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/Tests/Command/ResetCommandTest.php b/Tests/Command/ResetCommandTest.php index 44d493e..b6548aa 100644 --- a/Tests/Command/ResetCommandTest.php +++ b/Tests/Command/ResetCommandTest.php @@ -4,6 +4,9 @@ namespace FOS\ElasticaBundle\Tests\Command; use FOS\ElasticaBundle\Command\ResetCommand; +use Symfony\Component\Console\Input\ArrayInput; +use Symfony\Component\Console\Output\NullOutput; +use Symfony\Component\DependencyInjection\Container; class ResetCommandTest extends \PHPUnit_Framework_TestCase { @@ -27,6 +30,8 @@ class ResetCommandTest extends \PHPUnit_Framework_TestCase ->setMethods(array('getAllIndexes')) ->getMock(); + $container->set('fos_elastica.index_manager', $this->indexManager); + $this->command = new ResetCommand(); $this->command->setContainer($container); } @@ -35,13 +40,13 @@ class ResetCommandTest extends \PHPUnit_Framework_TestCase { $this->indexManager->expects($this->any()) ->method('getAllIndexes') - ->will($this->returnValue(array('index1', 'index2'))); + ->will($this->returnValue(array('index1' => true, 'index2' => true))); - $this->resetter->expects($this->at(1)) + $this->resetter->expects($this->at(0)) ->method('resetIndex') ->with($this->equalTo('index1')); - $this->resetter->expects($this->at(2)) + $this->resetter->expects($this->at(1)) ->method('resetIndex') ->with($this->equalTo('index2')); @@ -50,4 +55,37 @@ class ResetCommandTest extends \PHPUnit_Framework_TestCase new NullOutput() ); } + + public function testResetIndex() + { + $this->indexManager->expects($this->never()) + ->method('getAllIndexes'); + + $this->resetter->expects($this->at(0)) + ->method('resetIndex') + ->with($this->equalTo('index1')); + + $this->command->run( + new ArrayInput(array('--index' => 'index1')), + new NullOutput() + ); + } + + public function testResetIndexType() + { + $this->indexManager->expects($this->never()) + ->method('getAllIndexes'); + + $this->resetter->expects($this->never()) + ->method('resetIndex'); + + $this->resetter->expects($this->at(0)) + ->method('resetIndexType') + ->with($this->equalTo('index1'), $this->equalTo('type1')); + + $this->command->run( + new ArrayInput(array('--index' => 'index1', '--type' => 'type1')), + new NullOutput() + ); + } } \ No newline at end of file From 5f8b8003d1f10173094c8dec58db8fb486432a66 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Tue, 17 Dec 2013 21:09:58 +1100 Subject: [PATCH 129/447] Refactor documentation --- DependencyInjection/Configuration.php | 22 +- README.md | 868 +----------------- Resources/doc/cookbook/custom-repositories.md | 72 ++ Resources/doc/cookbook/manual-provider.md | 56 ++ .../doc/cookbook/suppress-server-errors.md | 36 + Resources/doc/index.md | 14 + Resources/doc/serializer.md | 39 + Resources/doc/setup.md | 144 +++ Resources/doc/types.md | 264 ++++++ Resources/doc/usage.md | 177 ++++ 10 files changed, 838 insertions(+), 854 deletions(-) create mode 100644 Resources/doc/cookbook/custom-repositories.md create mode 100644 Resources/doc/cookbook/manual-provider.md create mode 100644 Resources/doc/cookbook/suppress-server-errors.md create mode 100644 Resources/doc/index.md create mode 100644 Resources/doc/serializer.md create mode 100644 Resources/doc/setup.md create mode 100644 Resources/doc/types.md create mode 100644 Resources/doc/usage.md diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 11c1cf4..b05bd54 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -8,6 +8,11 @@ use Symfony\Component\Config\Definition\ConfigurationInterface; class Configuration implements ConfigurationInterface { + /** + * Stores supported database drivers. + * + * @var array + */ private $supportedDrivers = array('orm', 'mongodb', 'propel'); private $configArray = array(); @@ -32,8 +37,12 @@ class Configuration implements ConfigurationInterface $rootNode ->children() - ->scalarNode('default_client')->end() - ->scalarNode('default_index')->end() + ->scalarNode('default_client') + ->info('Defaults to the first client defined') + ->end() + ->scalarNode('default_index') + ->info('Defaults to the first index defined') + ->end() ->scalarNode('default_manager')->defaultValue('orm')->end() ->arrayNode('serializer') ->treatNullLike(array()) @@ -105,6 +114,7 @@ class Configuration implements ConfigurationInterface ->scalarNode('host')->end() ->scalarNode('port')->end() ->scalarNode('logger') + ->info('Set your own logger service for this client or disable the logger with false.') ->defaultValue('fos_elastica.logger') ->treatNullLike('fos_elastica.logger') ->treatTrueLike('fos_elastica.logger') @@ -134,11 +144,14 @@ class Configuration implements ConfigurationInterface ->prototype('array') ->performNoDeepMerging() ->children() - ->scalarNode('index_name')->end() + ->scalarNode('index_name') + ->info('Defaults to the name of the index, but can be modified if the index name is different in ElasticSearch') + ->end() ->scalarNode('client')->end() ->scalarNode('finder') + ->info('Defines an index wide finder that will search all types.') ->treatNullLike(true) - ->defaultTrue() + ->defaultFalse() ->end() ->append($this->getTypePrototypeNode()) ->variableNode('settings')->defaultValue(array())->end() @@ -157,6 +170,7 @@ class Configuration implements ConfigurationInterface { $builder = new TreeBuilder(); $node = $builder->root('type_prototype'); + $node->info('Allows a prototype type definition that can be applied to all types.'); $this->applyTypeConfiguration($node); diff --git a/README.md b/README.md index 3006bd1..ce5afab 100644 --- a/README.md +++ b/README.md @@ -1,862 +1,30 @@ -[Elastica](https://github.com/ruflin/Elastica) integration in Symfony2 +FOSElasticaBundle +================= -### Installation +This bundle provides integration with [ElasticSearch](http://www.elasticsearch.org) and [Elastica](https://github.com/ruflin/Elastica) with +Symfony2. Features include: -#### Bundle and Dependencies +- Features... -For Symfony 2.0.x projects, you must use a 1.x release of this bundle. Please -check the bundle -[tags](https://github.com/FriendsOfSymfony/FOSElasticaBundle/tags) or the -[Packagist](https://packagist.org/packages/friendsofsymfony/elastica-bundle) -page for information on Symfony and Elastica compatibility. +[![Build Status](https://secure.travis-ci.org/FriendsOfSymfony/FOSElasticaBundle.png?branch=master)](http://travis-ci.org/FriendsOfSymfony/FOSElasticaBundle) [![Total Downloads](https://poser.pugx.org/FriendsOfSymfony/elastica-bundle/downloads.png)](https://packagist.org/packages/FriendsOfSymfony/elastica-bundle) [![Latest Stable Version](https://poser.pugx.org/FriendsOfSymfony/elastica-bundle/v/stable.png)](https://packagist.org/packages/FriendsOfSymfony/elastica-bundle) -Add FOSElasticaBundle to your application's `composer.json` file: +Documentation +------------- -```json -{ - "require": { - "friendsofsymfony/elastica-bundle": "3.0.*@dev" - } -} -``` +Documentation for FOSElasticaBundle is in `Resources/doc/index.md` -Install the bundle and its dependencies with the following command: +[Read the documentation for 3.0.x (master))](https://github.com/FriendsOfSymfony/FOSElasticaBundle/blob/master/Resources/doc/index.md) -```bash -$ php composer.phar update friendsofsymfony/elastica-bundle -``` +[Read the documentation for 2.1.x](https://github.com/FriendsOfSymfony/FOSElasticaBundle/blob/2.1.x/README.md) -You may rely on Composer to fetch the appropriate version of Elastica. Lastly, -enable the bundle in your application kernel: +Installation +------------ -```php -// app/AppKernel.php +Installation instructions can be found in the [documentation](https://github.com/FriendsOfSymfony/FOSElasticaBundle/blob/master/Resources/doc/setup.md) -public function registerBundles() -{ - $bundles = array( - // ... - new FOS\ElasticaBundle\FOSElasticaBundle(), - ); -} -``` +License +------- -#### Elasticsearch +This bundle is under the MIT license. See the complete license in the bundle: -Instructions for installing and deploying Elasticsearch may be found -[here](http://www.elasticsearch.org/guide/reference/setup/installation/). - -### Basic configuration - -#### Declare a client - -Elasticsearch client is comparable to a database connection. -Most of the time, you will need only one. - - #app/config/config.yml - fos_elastica: - clients: - default: { host: localhost, port: 9200 } - - -#### Declare a serializer - -Elastica can handle objects instead of data arrays if a serializer callable is configured - - #app/config/config.yml - fos_elastica: - clients: - default: { host: localhost, port: 9200 } - serializer: - callback_class: callback_class - serializer: serializer - -``callback_class`` is the name of a class having a public method serialize($object) and should -extends from ``FOS\ElasticaBundle\Serializer\Callback``. - -``serializer`` is the service id for the actual serializer, e.g. ``serializer`` if you're using -JMSSerializerBundle. If this is configured you can use ``\Elastica\Type::addObject`` instead of -``\Elastica\Type::addDocument`` to add data to the index. The bundle provides a default implementation -with a serializer service id 'serializer' that can be turned on by adding the following line to your config. - - #app/config/config.yml - fos_elastica: - serializer: ~ - -#### Declare an index - -Elasticsearch index is comparable to Doctrine entity manager. -Most of the time, you will need only one. - - fos_elastica: - clients: - default: { host: localhost, port: 9200 } - serializer: - callback_class: FOS\ElasticaBundle\Serializer\Callback - serializer: serializer - indexes: - website: - client: default - -Here we created a "website" index, that uses our "default" client. - -Our index is now available as a service: `fos_elastica.index.website`. It is an instance of `\Elastica\Index`. - -If you need to have different index name from the service name, for example, -in order to have different indexes for different environments then you can -use the ```index_name``` key to change the index name. The service name will -remain the same across the environments: - - fos_elastica: - clients: - default: { host: localhost, port: 9200 } - indexes: - website: - client: default - index_name: website_qa - -The service id will be `fos_elastica.index.website` but the underlying index name is website_qa. - -#### Declare a type - -Elasticsearch type is comparable to Doctrine entity repository. - - fos_elastica: - clients: - default: { host: localhost, port: 9200 } - serializer: - callback_class: FOS\ElasticaBundle\Serializer\Callback - serializer: serializer - indexes: - website: - client: default - types: - user: - mappings: - username: { boost: 5 } - firstName: { boost: 3 } - lastName: { boost: 3 } - aboutMe: ~ - -Our type is now available as a service: `fos_elastica.index.website.user`. It is an instance of `\Elastica\Type`. - -### Declaring serializer groups - -If you are using the JMSSerializerBundle for serializing objects passed to elastica you can define serializer groups -per type. - - fos_elastica: - clients: - default: { host: localhost, port: 9200 } - serializer: - callback_class: %classname% - serializer: serializer - indexes: - website: - client: default - types: - user: - mappings: - username: { boost: 5 } - firstName: { boost: 3 } - lastName: { boost: 3 } - aboutMe: - serializer: - groups: [elastica, Default] - -### Declaring parent field - - fos_elastica: - clients: - default: { host: localhost, port: 9200 } - serializer: - callback_class: FOS\ElasticaBundle\Serializer\Callback - serializer: serializer - indexes: - website: - client: default - types: - comment: - mappings: - date: { boost: 5 } - content: ~ - _parent: { type: "post", property: "post", identifier: "id" } - -The parent field declaration has the following values: - - * `type`: The parent type. - * `property`: The property in the child entity where to look for the parent entity. It may be ignored if is equal to the parent type. - * `identifier`: The property in the parent entity which has the parent identifier. Defaults to `id`. - -Note that to create a document with a parent, you need to call `setParent` on the document rather than setting a _parent field. -If you do this wrong, you will see a `RoutingMissingException` as elasticsearch does not know where to store a document that should have a parent but does not specify it. - -### Declaring `nested` or `object` - -Note that object can autodetect properties - - fos_elastica: - clients: - default: { host: localhost, port: 9200 } - serializer: - callback_class: FOS\ElasticaBundle\Serializer\Callback - serializer: serializer - indexes: - website: - client: default - types: - post: - mappings: - date: { boost: 5 } - title: { boost: 3 } - content: ~ - comments: - type: "nested" - properties: - date: { boost: 5 } - content: ~ - user: - type: "object" - approver: - type: "object" - properties: - date: { boost: 5 } - -#### Doctrine ORM and `object` mappings - -Objects operate in the same way as the nested results but they need to have associations set up in Doctrine ORM so that they can be referenced correctly when indexing. - -If an "Entity was not found" error occurs while indexing, a null association has been discovered in the database. A custom Doctrine query must be used to utilize left joins instead of the default inner join. - -### Populate the types - - php app/console fos:elastica:populate - -This command deletes and creates the declared indexes and types. -It applies the configured mappings to the types. - -This command needs providers to insert new documents in the elasticsearch types. -There are 2 ways to create providers. -If your elasticsearch type matches a Doctrine repository or a Propel query, go for the persistence automatic provider. -Or, for complete flexibility, go for a manual provider. - -#### Persistence automatic provider - -If we want to index the entities from a Doctrine repository or a Propel query, -some configuration will let ElasticaBundle do it for us. - - fos_elastica: - clients: - default: { host: localhost, port: 9200 } - serializer: - callback_class: FOS\ElasticaBundle\Serializer\Callback - serializer: serializer - indexes: - website: - client: default - types: - user: - mappings: - username: { boost: 5 } - firstName: { boost: 3 } - # more mappings... - persistence: - driver: orm # orm, mongodb, propel are available - model: Application\UserBundle\Entity\User - provider: ~ - -Three drivers are actually supported: orm, mongodb, and propel. - -##### Use a custom Doctrine query builder - -You can control which entities will be indexed by specifying a custom query builder method. - - persistence: - driver: orm - model: Application\UserBundle\Entity\User - provider: - query_builder_method: createIsActiveQueryBuilder - -Your repository must implement this method and return a Doctrine query builder. - -> **Propel** doesn't support this feature yet. - -##### Change the batch size - -By default, ElasticaBundle will index documents by packets of 100. -You can change this value in the provider configuration. - - persistence: - driver: orm - model: Application\UserBundle\Entity\User - provider: - batch_size: 100 - -##### Change the document identifier field - -By default, ElasticaBundle will use the `id` field of your entities as the elasticsearch document identifier. -You can change this value in the persistence configuration. - - persistence: - driver: orm - model: Application\UserBundle\Entity\User - identifier: id - -#### Manual provider - -Create a service with the tag "fos_elastica.provider" and attributes for the -index and type for which the service will provide. - - - - - - -Its class must implement `FOS\ElasticaBundle\Provider\ProviderInterface`. - - userType = $userType; - } - - /** - * Insert the repository objects in the type index - * - * @param \Closure $loggerClosure - * @param array $options - */ - public function populate(\Closure $loggerClosure = null, array $options = array()) - { - if ($loggerClosure) { - $loggerClosure('Indexing users'); - } - - $document = new Document(); - $document->setData(array('username' => 'Bob')); - $this->userType->addDocuments(array($document)); - } - } - -You will find a more complete implementation example in `src/FOS/ElasticaBundle/Doctrine/AbstractProvider.php`. - -### Search - -You can just use the index and type Elastica objects, provided as services, to perform searches. - - /** var Elastica\Type */ - $userType = $this->container->get('fos_elastica.index.website.user'); - - /** var Elastica\ResultSet */ - $resultSet = $userType->search('bob'); - -#### Doctrine/Propel finder - -If your elasticsearch type is bound to a Doctrine entity repository or a Propel query, -you can get your entities instead of Elastica results when you perform a search. -Declare that you want a Doctrine/Propel finder in your configuration: - - fos_elastica: - clients: - default: { host: localhost, port: 9200 } - serializer: - callback_class: FOS\ElasticaBundle\Serializer\Callback - serializer: serializer - indexes: - website: - client: default - types: - user: - mappings: - # your mappings - persistence: - driver: orm - model: Application\UserBundle\Entity\User - provider: ~ - finder: ~ - -You can now use the `fos_elastica.finder.website.user` service: - - /** var FOS\ElasticaBundle\Finder\TransformedFinder */ - $finder = $container->get('fos_elastica.finder.website.user'); - - /** var array of Acme\UserBundle\Entity\User */ - $users = $finder->find('bob'); - - /** var array of Acme\UserBundle\Entity\User limited to 10 results */ - $users = $finder->find('bob', 10); - -You can even get paginated results! - -Pagerfanta: - - /** var Pagerfanta\Pagerfanta */ - $userPaginator = $finder->findPaginated('bob'); - - /** Number of results to be used for paging the results */ - $countOfResults = $userPaginator->getNbResults(); - -Knp paginator: - - $paginator = $this->get('knp_paginator'); - $userPaginator = $paginator->paginate($finder->createPaginatorAdapter('bob')); - -You can also get both the Elastica results and the entities together from the finder. -You can then access the score, highlights etc. from the Elastica\Result whilst -still also getting the entity. - - /** var array of FOS\ElasticaBundle\HybridResult */ - $hybridResults = $finder->findHybrid('bob'); - foreach ($hybridResults as $hybridResult) { - - /** var Acme\UserBundle\Entity\User */ - $user = $hybridResult->getTransformed(); - - /** var Elastica\Result */ - $result = $hybridResult->getResult(); - } - -If you would like to access facets while using Pagerfanta they can be accessed through -the Adapter seen in the example below. - -```php -$query = new \Elastica\Query(); -$facet = new \Elastica\Facet\Terms('tags'); -$facet->setField('companyGroup'); -$query->addFacet($facet); - -$companies = $finder->findPaginated($query); -$companies->setMaxPerPage($params['limit']); -$companies->setCurrentPage($params['page']); - -$facets = $companies->getAdapter()->getFacets()); -``` - -##### Index wide finder - -You can also define a finder that will work on the entire index. Adjust your index -configuration as per below: - - fos_elastica: - indexes: - website: - client: default - finder: ~ - -You can now use the index wide finder service `fos_elastica.finder.website`: - - /** var FOS\ElasticaBundle\Finder\MappedFinder */ - $finder = $container->get('fos_elastica.finder.website'); - - // Returns a mixed array of any objects mapped - $results = $finder->find('bob'); - -#### Repositories - -As well as using the finder service for a particular Doctrine/Propel entity you -can use a manager service for each driver and get a repository for an entity to search -against. This allows you to use the same service rather than the particular finder. For -example: - - /** var FOS\ElasticaBundle\Manager\RepositoryManager */ - $repositoryManager = $container->get('fos_elastica.manager.orm'); - - /** var FOS\ElasticaBundle\Repository */ - $repository = $repositoryManager->getRepository('UserBundle:User'); - - /** var array of Acme\UserBundle\Entity\User */ - $users = $repository->find('bob'); - -You can also specify the full name of the entity instead of the shortcut syntax: - - /** var FOS\ElasticaBundle\Repository */ - $repository = $repositoryManager->getRepository('Application\UserBundle\Entity\User'); - -> The **2.0** branch doesn't support using `UserBundle:User` style syntax and you must use the full name of the entity. . - -##### Default Manager - -If you are only using one driver then its manager service is automatically aliased -to `fos_elastica.manager`. So the above example could be simplified to: - - /** var FOS\ElasticaBundle\Manager\RepositoryManager */ - $repositoryManager = $container->get('fos_elastica.manager'); - - /** var FOS\ElasticaBundle\Repository */ - $repository = $repositoryManager->getRepository('UserBundle:User'); - - /** var array of Acme\UserBundle\Entity\User */ - $users = $repository->find('bob'); - -If you use multiple drivers then you can choose which one is aliased to `fos_elastica.manager` -using the `default_manager` parameter: - - fos_elastica: - default_manager: mongodb #defaults to orm - clients: - default: { host: localhost, port: 9200 } - #-- - -##### Custom Repositories - -As well as the default repository you can create a custom repository for an entity and add -methods for particular searches. These need to extend `FOS\ElasticaBundle\Repository` to have -access to the finder: - -``` -find($query); - } -} -``` - -To use the custom repository specify it in the mapping for the entity: - - fos_elastica: - clients: - default: { host: localhost, port: 9200 } - indexes: - website: - client: default - types: - user: - mappings: - # your mappings - persistence: - driver: orm - model: Application\UserBundle\Entity\User - provider: ~ - finder: ~ - repository: Acme\ElasticaBundle\SearchRepository\UserRepository - -Then the custom queries will be available when using the repository returned from the manager: - - /** var FOS\ElasticaBundle\Manager\RepositoryManager */ - $repositoryManager = $container->get('fos_elastica.manager'); - - /** var FOS\ElasticaBundle\Repository */ - $repository = $repositoryManager->getRepository('UserBundle:User'); - - /** var array of Acme\UserBundle\Entity\User */ - $users = $repository->findWithCustomQuery('bob'); - -Alternatively you can specify the custom repository using an annotation in the entity: - -``` - **Propel** doesn't support this feature yet. - -### Checking an entity method for listener - -If you use listeners to update your index, you may need to validate your -entities before you index them (e.g. only index "public" entities). Typically, -you'll want the listener to be consistent with the provider's query criteria. -This may be achieved by using the `is_indexable_callback` config parameter: - - persistence: - listener: - is_indexable_callback: "isPublic" - -If `is_indexable_callback` is a string and the entity has a method with the -specified name, the listener will only index entities for which the method -returns `true`. Additionally, you may provide a service and method name pair: - - persistence: - listener: - is_indexable_callback: [ "%custom_service_id%", "isIndexable" ] - -In this case, the callback_class will be the `isIndexable()` method on the specified -service and the object being considered for indexing will be passed as the only -argument. This allows you to do more complex validation (e.g. ACL checks). - -If you have the [Symfony ExpressionLanguage](https://github.com/symfony/expression-language) component installed, you can use expressions -to evaluate the callback: - - persistence: - listener: - is_indexable_callback: "user.isActive() && user.hasRole('ROLE_USER')" - -As you might expect, new entities will only be indexed if the callback_class returns -`true`. Additionally, modified entities will be updated or removed from the -index depending on whether the callback_class returns `true` or `false`, respectively. -The delete listener disregards the callback_class. - -> **Propel** doesn't support this feature yet. - -### Ignoring missing index results - -By default, FOSElasticaBundle will throw an exception if the results returned from -Elasticsearch are different from the results it finds from the chosen persistence -provider. This may pose problems for a large index where updates do not occur instantly -or another process has removed the results from your persistence provider without -updating Elasticsearch. - -The error you're likely to see is something like: -'Cannot find corresponding Doctrine objects for all Elastica results.' - -To solve this issue, each mapped object can be configured to ignore the missing results: - - persistence: - elastica_to_model_transformer: - ignore_missing: true - -### Advanced elasticsearch configuration - -Any setting can be specified when declaring a type. For example, to enable a custom analyzer, you could write: - - fos_elastica: - indexes: - doc: - settings: - index: - analysis: - analyzer: - my_analyzer: - type: custom - tokenizer: lowercase - filter : [my_ngram] - filter: - my_ngram: - type: "nGram" - min_gram: 3 - max_gram: 5 - types: - blog: - mappings: - title: { boost: 8, analyzer: my_analyzer } - -### Overriding the Client class to suppress exceptions - -By default, exceptions from the Elastica client library will propagate through -the bundle's Client class. For instance, if the elasticsearch server is offline, -issuing a request will result in an `Elastica\Exception\Connection` being thrown. -Depending on your needs, it may be desirable to suppress these exceptions and -allow searches to fail silently. - -One way to achieve this is to override the `fos_elastica.client.class` service -container parameter with a custom class. In the following example, we override -the `Client::request()` method and return the equivalent of an empty search -response if an exception occurred. - -``` -container->get('fos_elastica.finder.website.article'); -$boolQuery = new \Elastica\Query\Bool(); - -$fieldQuery = new \Elastica\Query\Text(); -$fieldQuery->setFieldQuery('title', 'I am a title string'); -$fieldQuery->setFieldParam('title', 'analyzer', 'my_analyzer'); -$boolQuery->addShould($fieldQuery); - -$tagsQuery = new \Elastica\Query\Terms(); -$tagsQuery->setTerms('tags', array('tag1', 'tag2')); -$boolQuery->addShould($tagsQuery); - -$categoryQuery = new \Elastica\Query\Terms(); -$categoryQuery->setTerms('categoryIds', array('1', '2', '3')); -$boolQuery->addMust($categoryQuery); - -$data = $finder->find($boolQuery); -``` - -Configuration: - -```yaml -fos_elastica: - clients: - default: { host: localhost, port: 9200 } - indexes: - site: - settings: - index: - analysis: - analyzer: - my_analyzer: - type: snowball - language: English - types: - article: - mappings: - title: { boost: 10, analyzer: my_analyzer } - tags: - categoryIds: - persistence: - driver: orm - model: Acme\DemoBundle\Entity\Article - provider: - finder: -``` - -### Filtering Results and Executing a Default Query - -If may want to omit certain results from a query, filtering can be more -performant than a basic query because the filter results can be cached. In turn, -the query is run against only a subset of the results. A common use case for -filtering would be if your data has fields that indicate whether records are -"active" or "inactive". The following example illustrates how to issue such a -query with Elastica: - -```php -$query = new \Elastica\Query\QueryString($queryString); -$term = new \Elastica\Filter\Term(array('active' => true)); - -$filteredQuery = new \Elastica\Query\Filtered($query, $term); -$results = $this->container->get('fos_elastica.finder.index.type')->find($filteredQuery); -``` - -### Date format example - -If you want to specify a [date format](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-date-format.html): - -```yaml -fos_elastica: - clients: - default: { host: localhost, port: 9200 } - indexes: - site: - types: - user: - mappings: - username: { type: string } - lastlogin: { type: date, format: basic_date_time } - birthday: { type: date, format: "yyyy-MM-dd" } -``` - -#### Dynamic templates - -Dynamic templates allow to define mapping templates that will be -applied when dynamic introduction of fields / objects happens. - -[Documentation](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-root-object-type.html#_dynamic_templates) - -```yaml -fos_elastica: - clients: - default: { host: localhost, port: 9200 } - indexes: - site: - types: - user: - dynamic_templates: - my_template_1: - match: apples_* - mapping: - type: float - my_template_2: - match: * - match_mapping_type: string - mapping: - type: string - index: not_analyzed - mappings: - username: { type: string } -``` + Resources/meta/LICENSE diff --git a/Resources/doc/cookbook/custom-repositories.md b/Resources/doc/cookbook/custom-repositories.md new file mode 100644 index 0000000..47dc3fe --- /dev/null +++ b/Resources/doc/cookbook/custom-repositories.md @@ -0,0 +1,72 @@ +##### Custom Repositories + +As well as the default repository you can create a custom repository for an entity and add +methods for particular searches. These need to extend `FOS\ElasticaBundle\Repository` to have +access to the finder: + +``` +find($query); + } +} +``` + +To use the custom repository specify it in the mapping for the entity: + + fos_elastica: + clients: + default: { host: localhost, port: 9200 } + indexes: + website: + client: default + types: + user: + mappings: + # your mappings + persistence: + driver: orm + model: Application\UserBundle\Entity\User + provider: ~ + finder: ~ + repository: Acme\ElasticaBundle\SearchRepository\UserRepository + +Then the custom queries will be available when using the repository returned from the manager: + + /** var FOS\ElasticaBundle\Manager\RepositoryManager */ + $repositoryManager = $container->get('fos_elastica.manager'); + + /** var FOS\ElasticaBundle\Repository */ + $repository = $repositoryManager->getRepository('UserBundle:User'); + + /** var array of Acme\UserBundle\Entity\User */ + $users = $repository->findWithCustomQuery('bob'); + +Alternatively you can specify the custom repository using an annotation in the entity: + +``` +userType = $userType; + } + + /** + * Insert the repository objects in the type index + * + * @param \Closure $loggerClosure + * @param array $options + */ + public function populate(\Closure $loggerClosure = null, array $options = array()) + { + if ($loggerClosure) { + $loggerClosure('Indexing users'); + } + + $document = new Document(); + $document->setData(array('username' => 'Bob')); + $this->userType->addDocuments(array($document)); + } +} +``` + +You will find a more complete implementation example in `src/FOS/ElasticaBundle/Doctrine/AbstractProvider.php`. diff --git a/Resources/doc/cookbook/suppress-server-errors.md b/Resources/doc/cookbook/suppress-server-errors.md new file mode 100644 index 0000000..aa74276 --- /dev/null +++ b/Resources/doc/cookbook/suppress-server-errors.md @@ -0,0 +1,36 @@ +Suppressing Server Errors +======================== + +By default, exceptions from the Elastica client library will propagate through +the bundle's Client class. For instance, if the Elasticsearch server is offline, +issuing a request will result in an `Elastica\Exception\Connection` being thrown. +Depending on your needs, it may be desirable to suppress these exceptions and +allow searches to fail silently. + +One way to achieve this is to override the `fos_elastica.client.class` service +container parameter with a custom class. In the following example, we override +the `Client::request()` method and return the equivalent of an empty search +response if an exception occurred. + +``` + **Propel** doesn't support this feature yet. + +### Checking an entity method for listener + +If you use listeners to update your index, you may need to validate your +entities before you index them (e.g. only index "public" entities). Typically, +you'll want the listener to be consistent with the provider's query criteria. +This may be achieved by using the `is_indexable_callback` config parameter: + +```yaml + persistence: + listener: + is_indexable_callback: "isPublic" +``` + +If `is_indexable_callback` is a string and the entity has a method with the +specified name, the listener will only index entities for which the method +returns `true`. Additionally, you may provide a service and method name pair: + +```yaml + persistence: + listener: + is_indexable_callback: [ "%custom_service_id%", "isIndexable" ] +``` + +In this case, the callback_class will be the `isIndexable()` method on the specified +service and the object being considered for indexing will be passed as the only +argument. This allows you to do more complex validation (e.g. ACL checks). + +If you have the [Symfony ExpressionLanguage](https://github.com/symfony/expression-language) +component installed, you can use expressions to evaluate the callback: + +```yaml + persistence: + listener: + is_indexable_callback: "user.isActive() && user.hasRole('ROLE_USER')" +``` + +As you might expect, new entities will only be indexed if the callback_class returns +`true`. Additionally, modified entities will be updated or removed from the +index depending on whether the callback_class returns `true` or `false`, respectively. +The delete listener disregards the callback_class. + +> **Propel** doesn't support this feature yet. \ No newline at end of file diff --git a/Resources/doc/usage.md b/Resources/doc/usage.md new file mode 100644 index 0000000..4c962e0 --- /dev/null +++ b/Resources/doc/usage.md @@ -0,0 +1,177 @@ +FOSElasticaBundle Usage +======================= + +Basic Searching with a Finder +----------------------------- + +The most useful searching method is to use a finder defined by the type configuration. +A finder will return results that have been hydrated by the configured persistence backend, +allowing you to use relationships of returned entities. For more information about +configuration options for this kind of searching, please see the [types](types.md) +documentation. + +```php +$finder = $this->container->get('fos_elastica.finder.search.user'); + +// Option 1. Returns all users who have example.net in any of their mapped fields +$results = $finder->find('example.net'); + +// Option 2. Returns a set of hybrid results that contain all Elasticsearch results +// and their transformed counterparts. Each result is an instance of a HybridResult +$results = $finder->findHybrid('example.net'); + +// Option 3a. Pagerfanta'd resultset +/** var Pagerfanta\Pagerfanta */ +$userPaginator = $finder->findPaginated('bob'); +$countOfResults = $userPaginator->getNbResults(); + +// Option 3b. KnpPaginator resultset + +``` + +Faceted Searching +----------------- + +When searching with facets, the facets can be retrieved when using the paginated +methods on the finder. + +```php +$query = new \Elastica\Query(); +$facet = new \Elastica\Facet\Terms('tags'); +$facet->setField('companyGroup'); +$query->addFacet($facet); + +$companies = $finder->findPaginated($query); +$companies->setMaxPerPage($params['limit']); +$companies->setCurrentPage($params['page']); + +$facets = $companies->getAdapter()->getFacets()); +``` + +Searching the entire index +-------------------------- + +You can also define a finder that will work on the entire index. Adjust your index +configuration as per below: + +```yaml +fos_elastica: + indexes: + website: + finder: ~ +``` + +You can now use the index wide finder service `fos_elastica.finder.website`: + +```php +/** var FOS\ElasticaBundle\Finder\MappedFinder */ +$finder = $container->get('fos_elastica.finder.website'); + +// Returns a mixed array of any objects mapped +$results = $finder->find('bob'); +``` + +Type Repositories +----------------- + +In the case where you need many different methods for different searching terms, it +may be better to separate methods for each type into their own dedicated repository +classes, just like Doctrine ORM's EntityRepository classes. + +The manager class that handles repositories has a service key of `fos_elastica.manager`. +The manager will default to handling ORM entities, and the configuration must be changed +for MongoDB users. + +```yaml +fos_elastica: + default_manager: mongodb +``` + +An example for using a repository: + +```php +/** var FOS\ElasticaBundle\Manager\RepositoryManager */ +$repositoryManager = $container->get('fos_elastica.manager'); + +/** var FOS\ElasticaBundle\Repository */ +$repository = $repositoryManager->getRepository('UserBundle:User'); + +/** var array of Acme\UserBundle\Entity\User */ +$users = $repository->find('bob'); +``` + +For more information about customising repositories, see the cookbook entry +[Custom Repositories](custom-repositories.md). + +Using a custom query builder method for transforming results +------------------------------------------------------------ + +When returning results from Elasticsearch to be transformed by the bundle, the default +`createQueryBuilder` method on each objects Repository class will be called. In many +circumstances this is not ideal and you'd prefer to use a different method to join in +any entity relations that are required on the page that will be displaying the results. + +```yaml + user: + elastica_to_model_transformer: + query_builder_method: createSearchQueryBuilder +``` + +Advanced Searching Example +-------------------------- + +If you would like to perform more advanced queries, here is one example using +the snowball stemming algorithm. + +It searches for Article entities using `title`, `tags`, and `categoryIds`. +Results must match at least one specified `categoryIds`, and should match the +`title` or `tags` criteria. Additionally, we define a snowball analyzer to +apply to queries against the `title` field. + +Assuming a type is configured as follows: + +```yaml +fos_elastica: + indexes: + site: + settings: + index: + analysis: + analyzer: + my_analyzer: + type: snowball + language: English + types: + article: + mappings: + title: { boost: 10, analyzer: my_analyzer } + tags: + categoryIds: + persistence: + driver: orm + model: Acme\DemoBundle\Entity\Article + provider: ~ + finder: ~ +``` + +The following code will execute a search against the Elasticsearch server: + +```php +$finder = $this->container->get('fos_elastica.finder.site.article'); +$boolQuery = new \Elastica\Query\Bool(); + +$fieldQuery = new \Elastica\Query\Text(); +$fieldQuery->setFieldQuery('title', 'I am a title string'); +$fieldQuery->setFieldParam('title', 'analyzer', 'my_analyzer'); +$boolQuery->addShould($fieldQuery); + +$tagsQuery = new \Elastica\Query\Terms(); +$tagsQuery->setTerms('tags', array('tag1', 'tag2')); +$boolQuery->addShould($tagsQuery); + +$categoryQuery = new \Elastica\Query\Terms(); +$categoryQuery->setTerms('categoryIds', array('1', '2', '3')); +$boolQuery->addMust($categoryQuery); + +$data = $finder->find($boolQuery); +``` From d33c5d0ece19f5758f4bc6679f26e4fdd17d7f49 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Tue, 17 Dec 2013 21:38:08 +1100 Subject: [PATCH 130/447] Fix tests --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ad1f366..8f6a9d8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,4 +6,4 @@ php: before_script: - echo "extension = mongo.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini - - composer install --dev + - composer install --dev --prefer-source From 4ee81dc010f987497169128f891bc4139b90fea9 Mon Sep 17 00:00:00 2001 From: Lea Haensenberger Date: Mon, 6 Jan 2014 09:20:44 +0100 Subject: [PATCH 131/447] Adding support for enabling timestamps --- DependencyInjection/Configuration.php | 20 ++++++++++++++++++++ DependencyInjection/FOSElasticaExtension.php | 3 +++ 2 files changed, 23 insertions(+) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index e9088e8..dd55ba1 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -299,6 +299,7 @@ class Configuration implements ConfigurationInterface ->append($this->getRoutingNode()) ->append($this->getParentNode()) ->append($this->getAllNode()) + ->append($this->getTimestampNode()) ->end() ; @@ -647,4 +648,23 @@ class Configuration implements ConfigurationInterface return $node; } + + /** + * Returns the array node used for "_timestamp" + */ + protected function getTimestampNode() + { + $builder = new TreeBuilder(); + $node = $builder->root('_timestamp'); + + $node + ->children() + ->scalarNode('enabled')->defaultValue(true)->end() + ->scalarNode('path')->end() + ->scalarNode('format')->end() + ->end() + ; + + return $node; + } } diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 8b85629..a38b90a 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -246,6 +246,9 @@ class FOSElasticaExtension extends Extension if (isset($type['_all'])) { $this->indexConfigs[$indexName]['config']['mappings'][$name]['_all'] = $type['_all']; } + if (isset($type['_timestamp'])) { + $this->indexConfigs[$indexName]['config']['mappings'][$name]['_timestamp'] = $type['_timestamp']; + } if (!empty($type['dynamic_templates'])) { $this->indexConfigs[$indexName]['config']['mappings'][$name]['dynamic_templates'] = array(); foreach ($type['dynamic_templates'] as $templateName => $templateData) { From 274fc0099186980d730da1c6f7249b1b899125ad Mon Sep 17 00:00:00 2001 From: Lea Haensenberger Date: Mon, 6 Jan 2014 10:19:11 +0100 Subject: [PATCH 132/447] Add store and index options to timestamp --- DependencyInjection/Configuration.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index dd55ba1..5cdd52a 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -662,6 +662,8 @@ class Configuration implements ConfigurationInterface ->scalarNode('enabled')->defaultValue(true)->end() ->scalarNode('path')->end() ->scalarNode('format')->end() + ->scalarNode('store')->end() + ->scalarNode('index')->end() ->end() ; From 73ee750515b0f62a83c3198b2327589f3f644e98 Mon Sep 17 00:00:00 2001 From: Vermi Date: Fri, 10 Jan 2014 16:25:45 +0100 Subject: [PATCH 133/447] Removing "->performNoDeepMerging()"in indexes configuration, allowing custom Bundle defining new types in an existing index. Configuration is injected in the new Bundle using prependExtensionConfig() --- DependencyInjection/Configuration.php | 1 - 1 file changed, 1 deletion(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index e9088e8..bea6cc0 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -132,7 +132,6 @@ class Configuration implements ConfigurationInterface ->arrayNode('indexes') ->useAttributeAsKey('name') ->prototype('array') - ->performNoDeepMerging() ->children() ->scalarNode('index_name')->end() ->scalarNode('client')->end() From 74813768358f42b3348e6f07a4b7a4179ee73259 Mon Sep 17 00:00:00 2001 From: nurikabe Date: Sat, 11 Jan 2014 16:28:15 +0000 Subject: [PATCH 134/447] Use bulk insert. Still working on bulk update/delete which is not yet suppored in Elastica. --- Doctrine/Listener.php | 5 +++-- Tests/Doctrine/AbstractListenerTest.php | 6 ++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Doctrine/Listener.php b/Doctrine/Listener.php index 383e02f..8c1d99f 100644 --- a/Doctrine/Listener.php +++ b/Doctrine/Listener.php @@ -214,9 +214,10 @@ class Listener implements EventSubscriber */ private function persistScheduled() { - foreach ($this->scheduledForInsertion as $entity) { - $this->objectPersister->insertOne($entity); + if (count($this->scheduledForInsertion)) { + $this->objectPersister->insertMany($this->scheduledForInsertion); } + foreach ($this->scheduledForUpdate as $entity) { $this->objectPersister->replaceOne($entity); } diff --git a/Tests/Doctrine/AbstractListenerTest.php b/Tests/Doctrine/AbstractListenerTest.php index a6ad2aa..3278be1 100644 --- a/Tests/Doctrine/AbstractListenerTest.php +++ b/Tests/Doctrine/AbstractListenerTest.php @@ -22,8 +22,8 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase $this->assertEquals($entity, current($listener->scheduledForInsertion)); $persister->expects($this->once()) - ->method('insertOne') - ->with($entity); + ->method('insertMany') + ->with($listener->scheduledForInsertion); $listener->postFlush($eventArgs); } @@ -46,6 +46,8 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase $persister->expects($this->never()) ->method('insertOne'); + $persister->expects($this->never()) + ->method('insertMany'); $listener->postFlush($eventArgs); } From 4287a91d506cbc92a1436d21175775ee2dea8c0d Mon Sep 17 00:00:00 2001 From: Tom A Date: Thu, 16 Jan 2014 23:05:44 -0500 Subject: [PATCH 135/447] Add similarity as a valid field mapping. http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-core-types.html#similarity --- DependencyInjection/Configuration.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index e9088e8..43f9db4 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -399,7 +399,8 @@ class Configuration implements ConfigurationInterface ->scalarNode('identifier')->defaultValue('id')->end() ->end() ->end() - ->scalarNode('format')->end(); + ->scalarNode('format')->end() + ->scalarNode('similarity')->end(); ; if (isset($nestings['fields'])) { From bbacad4bab2f6375a1bf9d841b7f64de17811047 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?T=C3=B3th=20G=C3=A1bor?= Date: Tue, 10 Dec 2013 18:07:22 +0100 Subject: [PATCH 136/447] no-stop-on-error option added to populate command --- Command/PopulateCommand.php | 1 + Doctrine/AbstractProvider.php | 15 +++++++++++- Tests/Doctrine/AbstractProviderTest.php | 32 +++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) mode change 100755 => 100644 Command/PopulateCommand.php diff --git a/Command/PopulateCommand.php b/Command/PopulateCommand.php old mode 100755 new mode 100644 index 7297523..661f70d --- a/Command/PopulateCommand.php +++ b/Command/PopulateCommand.php @@ -45,6 +45,7 @@ class PopulateCommand extends ContainerAwareCommand ->addOption('offset', null, InputOption::VALUE_REQUIRED, 'Start indexing at offset', 0) ->addOption('sleep', null, InputOption::VALUE_REQUIRED, 'Sleep time between persisting iterations (microseconds)', 0) ->addOption('batch-size', null, InputOption::VALUE_REQUIRED, 'Index packet size (overrides provider config option)') + ->addOption('no-stop-on-error', null, InputOption::VALUE_NONE, 'Do not stop on errors') ->setDescription('Populates search indexes from providers') ; } diff --git a/Doctrine/AbstractProvider.php b/Doctrine/AbstractProvider.php index 1fb41f5..2346c80 100644 --- a/Doctrine/AbstractProvider.php +++ b/Doctrine/AbstractProvider.php @@ -3,6 +3,7 @@ namespace FOS\ElasticaBundle\Doctrine; use Doctrine\Common\Persistence\ManagerRegistry; +use Elastica\Exception\Bulk\ResponseException as BulkResponseException; use FOS\ElasticaBundle\Persister\ObjectPersisterInterface; use FOS\ElasticaBundle\Provider\AbstractProvider as BaseAbstractProvider; @@ -23,6 +24,7 @@ abstract class AbstractProvider extends BaseAbstractProvider parent::__construct($objectPersister, $objectClass, array_merge(array( 'clear_object_manager' => true, 'query_builder_method' => 'createQueryBuilder', + 'stop_on_error' => true, ), $options)); $this->managerRegistry = $managerRegistry; @@ -38,6 +40,7 @@ abstract class AbstractProvider extends BaseAbstractProvider $offset = isset($options['offset']) ? intval($options['offset']) : 0; $sleep = isset($options['sleep']) ? intval($options['sleep']) : 0; $batchSize = isset($options['batch-size']) ? intval($options['batch-size']) : $this->options['batch_size']; + $stopOnError = isset($options['no-stop-on-error']) ? empty($options['no-stop-on-error']) : $this->options['stop_on_error']; for (; $offset < $nbObjects; $offset += $batchSize) { if ($loggerClosure) { @@ -45,7 +48,17 @@ abstract class AbstractProvider extends BaseAbstractProvider } $objects = $this->fetchSlice($queryBuilder, $batchSize, $offset); - $this->objectPersister->insertMany($objects); + if (!$stopOnError) { + $this->objectPersister->insertMany($objects); + } else { + try { + $this->objectPersister->insertMany($objects); + } catch(BulkResponseException $e) { + if ($loggerClosure) { + $loggerClosure(sprintf('%s',$e->getMessage())); + } + } + } if ($this->options['clear_object_manager']) { $this->managerRegistry->getManagerForClass($this->objectClass)->clear(); diff --git a/Tests/Doctrine/AbstractProviderTest.php b/Tests/Doctrine/AbstractProviderTest.php index 0a9aceb..a3836bd 100644 --- a/Tests/Doctrine/AbstractProviderTest.php +++ b/Tests/Doctrine/AbstractProviderTest.php @@ -135,6 +135,28 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase $this->assertTrue($loggerClosureInvoked); } + public function testPopulateNotStopOnError() + { + $nbObjects = 1; + $objects = array(1); + + $provider = $this->getMockAbstractProvider(); + + $provider->expects($this->any()) + ->method('countObjects') + ->will($this->returnValue($nbObjects)); + + $provider->expects($this->any()) + ->method('fetchSlice') + ->will($this->returnValue($objects)); + + $this->objectPersister->expects($this->any()) + ->method('insertMany') + ->will($this->throwException($this->getMockBulkResponseException())); + + $provider->populate(null, array('no-stop-on-error' => true)); + } + /** * @return \FOS\ElasticaBundle\Doctrine\AbstractProvider|\PHPUnit_Framework_MockObject_MockObject */ @@ -148,6 +170,16 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase )); } + /** + * @return \Elastica\Exception\Bulk\ResponseException + */ + private function getMockBulkResponseException() + { + return $this->getMockBuilder('Elastica\Exception\Bulk\ResponseException') + ->disableOriginalConstructor() + ->getMock(); + } + /** * @return \Doctrine\Common\Persistence\ManagerRegistry|\PHPUnit_Framework_MockObject_MockObject */ From b6d010a9d7e7801c17cb618d8984d70eacff8f15 Mon Sep 17 00:00:00 2001 From: nurikabe Date: Thu, 23 Jan 2014 16:20:11 +0000 Subject: [PATCH 137/447] Bulk update. Still working on bulk delete for indexes and types in Elastica. --- Doctrine/Listener.php | 8 ++------ Persister/ObjectPersister.php | 17 +++++++++++------ Persister/ObjectPersisterInterface.php | 10 +++++++--- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/Doctrine/Listener.php b/Doctrine/Listener.php index 8c1d99f..d6314dc 100644 --- a/Doctrine/Listener.php +++ b/Doctrine/Listener.php @@ -214,13 +214,9 @@ class Listener implements EventSubscriber */ private function persistScheduled() { - if (count($this->scheduledForInsertion)) { - $this->objectPersister->insertMany($this->scheduledForInsertion); - } + $this->objectPersister->bulkPersist($this->scheduledForInsertion, ObjectPersisterInterface::BULK_INSERT); + $this->objectPersister->bulkPersist($this->scheduledForUpdate, ObjectPersisterInterface::BULK_REPLACE); - foreach ($this->scheduledForUpdate as $entity) { - $this->objectPersister->replaceOne($entity); - } foreach ($this->scheduledForDeletion as $entity) { $this->objectPersister->deleteOne($entity); } diff --git a/Persister/ObjectPersister.php b/Persister/ObjectPersister.php index 450e43b..b5a1be7 100644 --- a/Persister/ObjectPersister.php +++ b/Persister/ObjectPersister.php @@ -83,19 +83,24 @@ class ObjectPersister implements ObjectPersisterInterface } catch (NotFoundException $e) {} } - /** - * Inserts an array of objects in the type + * Bulk update an array of objects in the type for the given method * * @param array $objects array of domain model objects - **/ - public function insertMany(array $objects) + * @param string Method to call + */ + public function bulkPersist(array $objects, $method) { + if (!count($objects)) { + return; + } + $documents = array(); foreach ($objects as $object) { $documents[] = $this->transformToElasticaDocument($object); } - $this->type->addDocuments($documents); + + $this->type->$method($documents); } /** @@ -108,4 +113,4 @@ class ObjectPersister implements ObjectPersisterInterface { return $this->transformer->transform($object, $this->fields); } -} +} \ No newline at end of file diff --git a/Persister/ObjectPersisterInterface.php b/Persister/ObjectPersisterInterface.php index a50bcc8..5c4ecd2 100644 --- a/Persister/ObjectPersisterInterface.php +++ b/Persister/ObjectPersisterInterface.php @@ -10,6 +10,9 @@ namespace FOS\ElasticaBundle\Persister; */ interface ObjectPersisterInterface { + const BULK_INSERT = 'addDocuments'; + const BULK_REPLACE = 'updateDocuments'; + /** * Insert one object into the type * The object will be transformed to an elastica document @@ -42,9 +45,10 @@ interface ObjectPersisterInterface function deleteById($id); /** - * Inserts an array of objects in the type + * Bulk update an array of objects in the type for the given method * * @param array $objects array of domain model objects - **/ - function insertMany(array $objects); + * @param string Method to call + */ + function bulkPersist(array $objects, $method); } From 62dc3aaca04c1dc2fe62e763d8dde20d897d6f0d Mon Sep 17 00:00:00 2001 From: pkraeutli Date: Fri, 24 Jan 2014 14:20:10 +0100 Subject: [PATCH 138/447] Populate command: use isInteractive() instead of option --- Command/PopulateCommand.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Command/PopulateCommand.php b/Command/PopulateCommand.php index 7297523..38bff70 100755 --- a/Command/PopulateCommand.php +++ b/Command/PopulateCommand.php @@ -67,10 +67,9 @@ class PopulateCommand extends ContainerAwareCommand $index = $input->getOption('index'); $type = $input->getOption('type'); $reset = $input->getOption('no-reset') ? false : true; - $noInteraction = $input->getOption('no-interaction'); $options = $input->getOptions(); - if (!$noInteraction && $reset && $input->getOption('offset')) { + if ($input->isInteractive() && $reset && $input->getOption('offset')) { /** @var DialogHelper $dialog */ $dialog = $this->getHelperSet()->get('dialog'); if (!$dialog->askConfirmation($output, 'You chose to reset the index and start indexing with an offset. Do you really want to do that?', true)) { From 1c7da33526dea333dfd2eed81bfb04de5031a261 Mon Sep 17 00:00:00 2001 From: Simon Perdrisat Date: Tue, 28 Jan 2014 11:34:54 +0100 Subject: [PATCH 139/447] [doc] repository methode has to return the query --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3006bd1..f78c97f 100644 --- a/README.md +++ b/README.md @@ -526,7 +526,7 @@ class UserRepository extends Repository public function findWithCustomQuery($searchText) { // build $query with Elastica objects - $this->find($query); + return $this->find($query); } } ``` From 076d51ac40dcbbe8fdd69223ab2d7a0377b60ced Mon Sep 17 00:00:00 2001 From: Piotr Antosik Date: Wed, 29 Jan 2014 17:50:42 +0100 Subject: [PATCH 140/447] Services classes as parameters --- Resources/config/config.xml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Resources/config/config.xml b/Resources/config/config.xml index 1fb2c1d..85cfbed 100644 --- a/Resources/config/config.xml +++ b/Resources/config/config.xml @@ -14,6 +14,10 @@ FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerCollection FOS\ElasticaBundle\Provider\ProviderRegistry Symfony\Component\PropertyAccess\PropertyAccessor + FOS\ElasticaBundle\Persister\ObjectPersister + FOS\ElasticaBundle\Persister\ObjectSerializerPersister + FOS\ElasticaBundle\Transformer\ModelToElasticaAutoTransformer + FOS\ElasticaBundle\Transformer\ModelToElasticaIdentifierTransformer @@ -37,7 +41,7 @@
    - + @@ -49,21 +53,21 @@ - + - + - + From 5480e037e3a005edd548d44a7bc31fb66e406db9 Mon Sep 17 00:00:00 2001 From: Laszlo Horvath Date: Thu, 30 Jan 2014 12:39:48 +0100 Subject: [PATCH 141/447] adding ttl for documents --- DependencyInjection/Configuration.php | 21 ++++++++++++++++++++ DependencyInjection/FOSElasticaExtension.php | 3 +++ 2 files changed, 24 insertions(+) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index ca97a4d..4ed88af 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -299,6 +299,7 @@ class Configuration implements ConfigurationInterface ->append($this->getParentNode()) ->append($this->getAllNode()) ->append($this->getTimestampNode()) + ->append($this->getTtlNode()) ->end() ; @@ -669,4 +670,24 @@ class Configuration implements ConfigurationInterface return $node; } + + /** + * Returns the array node used for "_ttl" + */ + protected function getTtlNode() + { + $builder = new TreeBuilder(); + $node = $builder->root('_ttl'); + + $node + ->children() + ->scalarNode('enabled')->defaultValue(true)->end() + ->scalarNode('default')->end() + ->scalarNode('store')->end() + ->scalarNode('index')->end() + ->end() + ; + + return $node; + } } diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index a38b90a..52070fd 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -249,6 +249,9 @@ class FOSElasticaExtension extends Extension if (isset($type['_timestamp'])) { $this->indexConfigs[$indexName]['config']['mappings'][$name]['_timestamp'] = $type['_timestamp']; } + if (isset($type['_ttl'])) { + $this->indexConfigs[$indexName]['config']['mappings'][$name]['_ttl'] = $type['_ttl']; + } if (!empty($type['dynamic_templates'])) { $this->indexConfigs[$indexName]['config']['mappings'][$name]['dynamic_templates'] = array(); foreach ($type['dynamic_templates'] as $templateName => $templateData) { From 5e54dcd9558efe686523dae6e0d1cfc0662d429c Mon Sep 17 00:00:00 2001 From: Fabien Somnier Date: Thu, 30 Jan 2014 13:01:13 +0100 Subject: [PATCH 142/447] Add RAM (current & peak) in populate evolution information --- Doctrine/AbstractProvider.php | 5 ++++- Propel/Provider.php | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Doctrine/AbstractProvider.php b/Doctrine/AbstractProvider.php index 1fb41f5..eebfc79 100644 --- a/Doctrine/AbstractProvider.php +++ b/Doctrine/AbstractProvider.php @@ -54,11 +54,14 @@ abstract class AbstractProvider extends BaseAbstractProvider usleep($sleep); if ($loggerClosure) { + $memory = round(memory_get_usage() / (1024*1024),0); // to get usage in Mo + $memoryMax = round(memory_get_peak_usage() / (1024*1024)); // to get max usage in Mo + $message = '(RAM : current='.$memory.'Mo peak='.$memoryMax.'Mo)'; $stepNbObjects = count($objects); $stepCount = $stepNbObjects + $offset; $percentComplete = 100 * $stepCount / $nbObjects; $objectsPerSecond = $stepNbObjects / (microtime(true) - $stepStartTime); - $loggerClosure(sprintf('%0.1f%% (%d/%d), %d objects/s', $percentComplete, $stepCount, $nbObjects, $objectsPerSecond)); + $loggerClosure(sprintf('%0.1f%% (%d/%d), %d objects/s %s', $percentComplete, $stepCount, $nbObjects, $objectsPerSecond, $message)); } } } diff --git a/Propel/Provider.php b/Propel/Provider.php index c319691..3eb1c4f 100644 --- a/Propel/Provider.php +++ b/Propel/Provider.php @@ -37,11 +37,14 @@ class Provider extends AbstractProvider usleep($sleep); if ($loggerClosure) { + $memory = round(memory_get_usage() / (1024*1024),0); // to get usage in Mo + $memoryMax = round(memory_get_peak_usage() / (1024*1024)); // to get usage in Mo + $message = '(RAM : current='.$memory.'Mo peak='.$memoryMax.'Mo)'; $stepNbObjects = count($objects); $stepCount = $stepNbObjects + $offset; $percentComplete = 100 * $stepCount / $nbObjects; $objectsPerSecond = $stepNbObjects / (microtime(true) - $stepStartTime); - $loggerClosure(sprintf('%0.1f%% (%d/%d), %d objects/s', $percentComplete, $stepCount, $nbObjects, $objectsPerSecond)); + $loggerClosure(sprintf('%0.1f%% (%d/%d), %d objects/s %s', $percentComplete, $stepCount, $nbObjects, $objectsPerSecond, $message)); } } } From 1dcaadbe6f99b42b346e04239c0c8fd7812bbf51 Mon Sep 17 00:00:00 2001 From: nurikabe Date: Sat, 1 Feb 2014 02:14:21 +0000 Subject: [PATCH 143/447] Bulk delete --- Doctrine/Listener.php | 17 +++++++----- Persister/ObjectPersister.php | 37 +++++++++++++++++++++----- Persister/ObjectPersisterInterface.php | 24 ++++++++++++----- README.md | 4 +-- 4 files changed, 59 insertions(+), 23 deletions(-) diff --git a/Doctrine/Listener.php b/Doctrine/Listener.php index d6314dc..c254513 100644 --- a/Doctrine/Listener.php +++ b/Doctrine/Listener.php @@ -210,21 +210,24 @@ class Listener implements EventSubscriber } /** - * Persist scheduled action to ElasticSearch + * Persist scheduled objects to ElasticSearch */ private function persistScheduled() { - $this->objectPersister->bulkPersist($this->scheduledForInsertion, ObjectPersisterInterface::BULK_INSERT); - $this->objectPersister->bulkPersist($this->scheduledForUpdate, ObjectPersisterInterface::BULK_REPLACE); - - foreach ($this->scheduledForDeletion as $entity) { - $this->objectPersister->deleteOne($entity); + if (count($this->scheduledForInsertion)) { + $this->objectPersister->insertMany($this->scheduledForInsertion); + } + if (count($this->scheduledForUpdate)) { + $this->objectPersister->replaceMany($this->scheduledForUpdate); + } + if (count($this->scheduledForDeletion)) { + $this->objectPersister->deleteMany($this->scheduledForDeletion); } } /** * Iterate through scheduled actions before flushing to emulate 2.x behavior. Note that the ElasticSearch index - * will fall out of sync with the data source in event of a crash on flush. + * will fall out of sync with the source data in the event of a crash during flush. */ public function preFlush(EventArgs $eventArgs) { diff --git a/Persister/ObjectPersister.php b/Persister/ObjectPersister.php index b5a1be7..3592a78 100644 --- a/Persister/ObjectPersister.php +++ b/Persister/ObjectPersister.php @@ -84,23 +84,46 @@ class ObjectPersister implements ObjectPersisterInterface } /** - * Bulk update an array of objects in the type for the given method + * Bulk insert an array of objects in the type for the given method * * @param array $objects array of domain model objects * @param string Method to call */ - public function bulkPersist(array $objects, $method) + public function insertMany(array $objects) { - if (!count($objects)) { - return; - } - $documents = array(); foreach ($objects as $object) { $documents[] = $this->transformToElasticaDocument($object); } + $this->type->addDocuments($documents); + } - $this->type->$method($documents); + /** + * Bulk updates an array of objects in the type + * + * @param array $objects array of domain model objects + */ + public function replaceMany(array $objects) + { + $documents = array(); + foreach ($objects as $object) { + $documents[] = $this->transformToElasticaDocument($object); + } + $this->type->updateDocuments($documents); + } + + /** + * Bulk deletes an array of objects in the type + * + * @param array $objects array of domain model objects + */ + public function deleteMany(array $objects) + { + $documents = array(); + foreach ($objects as $object) { + $documents[] = $this->transformToElasticaDocument($object); + } + $this->type->deleteDocuments($documents); } /** diff --git a/Persister/ObjectPersisterInterface.php b/Persister/ObjectPersisterInterface.php index 5c4ecd2..a25aafc 100644 --- a/Persister/ObjectPersisterInterface.php +++ b/Persister/ObjectPersisterInterface.php @@ -10,9 +10,6 @@ namespace FOS\ElasticaBundle\Persister; */ interface ObjectPersisterInterface { - const BULK_INSERT = 'addDocuments'; - const BULK_REPLACE = 'updateDocuments'; - /** * Insert one object into the type * The object will be transformed to an elastica document @@ -41,14 +38,27 @@ interface ObjectPersisterInterface * @param mixed $id * * @return null - **/ + */ function deleteById($id); /** - * Bulk update an array of objects in the type for the given method + * Bulk inserts an array of objects in the type * * @param array $objects array of domain model objects - * @param string Method to call */ - function bulkPersist(array $objects, $method); + function insertMany(array $objects); + + /** + * Bulk updates an array of objects in the type + * + * @param array $objects array of domain model objects + */ + function replaceMany(array $objects); + + /** + * Bulk deletes an array of objects in the type + * + * @param array $objects array of domain model objects + */ + function deleteMany(array $objects); } diff --git a/README.md b/README.md index b3a4c5d..cb6e5f8 100644 --- a/README.md +++ b/README.md @@ -627,8 +627,8 @@ to `true`: delete: true immediate: true -> Updating ElasticSearch before flushing may cause the ElasticSearch index to fall out of sync with the -> original data in the event of a crash. +> Using `immediate` to update ElasticSearch before flush completes may cause the ElasticSearch index to fall out of +> sync with the source database in the event of a crash during the flush itself, such as in the case of a bad query. ### Checking an entity method for listener From 559d7c13f277d534fbf883ae5d989c0fe4e1adce Mon Sep 17 00:00:00 2001 From: nurikabe Date: Sat, 1 Feb 2014 03:37:47 +0000 Subject: [PATCH 144/447] Update tests --- Tests/Doctrine/AbstractListenerTest.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Tests/Doctrine/AbstractListenerTest.php b/Tests/Doctrine/AbstractListenerTest.php index 3278be1..a9eff66 100644 --- a/Tests/Doctrine/AbstractListenerTest.php +++ b/Tests/Doctrine/AbstractListenerTest.php @@ -65,8 +65,8 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase $this->assertEquals($entity, current($listener->scheduledForUpdate)); $persister->expects($this->once()) - ->method('replaceOne') - ->with($entity); + ->method('replaceMany') + ->with(array($entity)); $persister->expects($this->never()) ->method('deleteById'); @@ -105,8 +105,8 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase $persister->expects($this->never()) ->method('replaceOne'); $persister->expects($this->once()) - ->method('deleteOne') - ->with($entity); + ->method('deleteMany') + ->with(array($entity)); $listener->postFlush($eventArgs); } @@ -136,8 +136,8 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase $this->assertEquals($entity, current($listener->scheduledForDeletion)); $persister->expects($this->once()) - ->method('deleteOne') - ->with($entity); + ->method('deleteMany') + ->with(array($entity)); $listener->postFlush($eventArgs); } @@ -167,8 +167,8 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase $this->assertEquals($entity, current($listener->scheduledForDeletion)); $persister->expects($this->once()) - ->method('deleteOne') - ->with($entity); + ->method('deleteMany') + ->with(array($entity)); $listener->postFlush($eventArgs); } From f348ebd0265aaa1d46e09c8aca5f6d646f27263c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Sch=C3=B6nthal?= Date: Mon, 3 Feb 2014 09:47:16 +0100 Subject: [PATCH 145/447] fixes ignore_missing option and unknown index --- Transformer/ElasticaToModelTransformerCollection.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Transformer/ElasticaToModelTransformerCollection.php b/Transformer/ElasticaToModelTransformerCollection.php index a261e81..f65f8db 100644 --- a/Transformer/ElasticaToModelTransformerCollection.php +++ b/Transformer/ElasticaToModelTransformerCollection.php @@ -67,7 +67,9 @@ class ElasticaToModelTransformerCollection implements ElasticaToModelTransformer $result = array(); foreach ($elasticaObjects as $object) { - $result[] = $transformed[$object->getType()][$object->getId()]; + if (array_key_exists($object->getId(), $transformed[$object->getType()])) { + $result[] = $transformed[$object->getType()][$object->getId()]; + } } return $result; From a121a777743525f46c65dc29d983c8eb92720664 Mon Sep 17 00:00:00 2001 From: Fabien Somnier Date: Mon, 3 Feb 2014 17:50:35 +0100 Subject: [PATCH 146/447] Avoid index reset error in case of unexistant index --- Command/PopulateCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Command/PopulateCommand.php b/Command/PopulateCommand.php index 7297523..9d00db1 100755 --- a/Command/PopulateCommand.php +++ b/Command/PopulateCommand.php @@ -107,7 +107,7 @@ class PopulateCommand extends ContainerAwareCommand */ private function populateIndex(OutputInterface $output, $index, $reset, $options) { - if ($reset) { + if ($reset && $this->indexManager->getIndex($index)->exists()) { $output->writeln(sprintf('Resetting %s', $index)); $this->resetter->resetIndex($index); } From 48b785e8764a887f903cbb81476b4368f5588bd5 Mon Sep 17 00:00:00 2001 From: Fabien Somnier Date: Mon, 3 Feb 2014 18:12:20 +0100 Subject: [PATCH 147/447] New method getMemoryUsage to get RAM information message --- Doctrine/AbstractProvider.php | 5 +---- Propel/Provider.php | 5 +---- Provider/AbstractProvider.php | 12 ++++++++++++ 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/Doctrine/AbstractProvider.php b/Doctrine/AbstractProvider.php index eebfc79..796a5e4 100644 --- a/Doctrine/AbstractProvider.php +++ b/Doctrine/AbstractProvider.php @@ -54,14 +54,11 @@ abstract class AbstractProvider extends BaseAbstractProvider usleep($sleep); if ($loggerClosure) { - $memory = round(memory_get_usage() / (1024*1024),0); // to get usage in Mo - $memoryMax = round(memory_get_peak_usage() / (1024*1024)); // to get max usage in Mo - $message = '(RAM : current='.$memory.'Mo peak='.$memoryMax.'Mo)'; $stepNbObjects = count($objects); $stepCount = $stepNbObjects + $offset; $percentComplete = 100 * $stepCount / $nbObjects; $objectsPerSecond = $stepNbObjects / (microtime(true) - $stepStartTime); - $loggerClosure(sprintf('%0.1f%% (%d/%d), %d objects/s %s', $percentComplete, $stepCount, $nbObjects, $objectsPerSecond, $message)); + $loggerClosure(sprintf('%0.1f%% (%d/%d), %d objects/s %s', $percentComplete, $stepCount, $nbObjects, $objectsPerSecond, $this->getMemoryUsage())); } } } diff --git a/Propel/Provider.php b/Propel/Provider.php index 3eb1c4f..393beba 100644 --- a/Propel/Provider.php +++ b/Propel/Provider.php @@ -37,14 +37,11 @@ class Provider extends AbstractProvider usleep($sleep); if ($loggerClosure) { - $memory = round(memory_get_usage() / (1024*1024),0); // to get usage in Mo - $memoryMax = round(memory_get_peak_usage() / (1024*1024)); // to get usage in Mo - $message = '(RAM : current='.$memory.'Mo peak='.$memoryMax.'Mo)'; $stepNbObjects = count($objects); $stepCount = $stepNbObjects + $offset; $percentComplete = 100 * $stepCount / $nbObjects; $objectsPerSecond = $stepNbObjects / (microtime(true) - $stepStartTime); - $loggerClosure(sprintf('%0.1f%% (%d/%d), %d objects/s %s', $percentComplete, $stepCount, $nbObjects, $objectsPerSecond, $message)); + $loggerClosure(sprintf('%0.1f%% (%d/%d), %d objects/s %s', $percentComplete, $stepCount, $nbObjects, $objectsPerSecond, $this->getMemoryUsage())); } } } diff --git a/Provider/AbstractProvider.php b/Provider/AbstractProvider.php index 06883a3..48da5d7 100644 --- a/Provider/AbstractProvider.php +++ b/Provider/AbstractProvider.php @@ -26,4 +26,16 @@ abstract class AbstractProvider implements ProviderInterface 'batch_size' => 100, ), $options); } + + /** + * Get string with RAM usage information (current and peak) + * + * @return string + */ + protected function getMemoryUsage() { + $memory = round(memory_get_usage() / (1024*1024),0); // to get usage in Mo + $memoryMax = round(memory_get_peak_usage() / (1024*1024)); // to get max usage in Mo + $message = '(RAM : current='.$memory.'Mo peak='.$memoryMax.'Mo)'; + return $message; + } } From 04390b37d1bacb16cce87384e0c33914ace7b967 Mon Sep 17 00:00:00 2001 From: tgallice Date: Tue, 4 Feb 2014 10:07:58 +0100 Subject: [PATCH 148/447] Force slash at the end of the url parameter --- DependencyInjection/Configuration.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 4ed88af..0c6ca82 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -101,7 +101,12 @@ class Configuration implements ConfigurationInterface ->arrayNode('servers') ->prototype('array') ->children() - ->scalarNode('url')->end() + ->scalarNode('url') + ->validate() + ->ifTrue(function($v) { return substr($v['url'], -1) !== '/'; }) + ->then(function($v) { return $v['url'].'/'; }) + ->end() + ->end() ->scalarNode('host')->end() ->scalarNode('port')->end() ->scalarNode('logger') From d04a403f71f82b46c3a3314031595b0c60b9dee9 Mon Sep 17 00:00:00 2001 From: Hung Tran Date: Tue, 4 Feb 2014 19:41:38 -0600 Subject: [PATCH 149/447] added support for setting search options --- Finder/FinderInterface.php | 3 ++- Finder/PaginatedFinderInterface.php | 6 ++++-- Finder/TransformedFinder.php | 23 +++++++++++++---------- Paginator/RawPaginatorAdapter.php | 10 ++++++++-- Paginator/TransformedPaginatorAdapter.php | 4 ++-- Repository.php | 16 ++++++++-------- 6 files changed, 37 insertions(+), 25 deletions(-) diff --git a/Finder/FinderInterface.php b/Finder/FinderInterface.php index 4805d58..7c257de 100644 --- a/Finder/FinderInterface.php +++ b/Finder/FinderInterface.php @@ -9,7 +9,8 @@ interface FinderInterface * * @param mixed $query Can be a string, an array or an \Elastica\Query object * @param int $limit How many results to get + * @param array $options * @return array results */ - function find($query, $limit = null); + function find($query, $limit = null, $options = array()); } diff --git a/Finder/PaginatedFinderInterface.php b/Finder/PaginatedFinderInterface.php index 3581cda..fa10b70 100644 --- a/Finder/PaginatedFinderInterface.php +++ b/Finder/PaginatedFinderInterface.php @@ -12,15 +12,17 @@ interface PaginatedFinderInterface extends FinderInterface * Searches for query results and returns them wrapped in a paginator * * @param mixed $query Can be a string, an array or an \Elastica\Query object + * @param array $options * @return Pagerfanta paginated results */ - function findPaginated($query); + function findPaginated($query, $options = array()); /** * Creates a paginator adapter for this query * * @param mixed $query + * @param array $options * @return PaginatorAdapterInterface */ - function createPaginatorAdapter($query); + function createPaginatorAdapter($query, $options = array()); } diff --git a/Finder/TransformedFinder.php b/Finder/TransformedFinder.php index 4c8aa98..9080701 100644 --- a/Finder/TransformedFinder.php +++ b/Finder/TransformedFinder.php @@ -29,18 +29,19 @@ class TransformedFinder implements PaginatedFinderInterface * * @param string $query * @param integer $limit + * @param array $options * @return array of model objects **/ - public function find($query, $limit = null) + public function find($query, $limit = null, $options = array()) { - $results = $this->search($query, $limit); + $results = $this->search($query, $limit, $options); return $this->transformer->transform($results); } - public function findHybrid($query, $limit = null) + public function findHybrid($query, $limit = null, $options = array()) { - $results = $this->search($query, $limit); + $results = $this->search($query, $limit, $options); return $this->transformer->hybridTransform($results); } @@ -64,15 +65,16 @@ class TransformedFinder implements PaginatedFinderInterface /** * @param $query * @param null|int $limit + * @param array $options * @return array */ - protected function search($query, $limit = null) + protected function search($query, $limit = null, $options = array()) { $queryObject = Query::create($query); if (null !== $limit) { $queryObject->setSize($limit); } - $results = $this->searchable->search($queryObject)->getResults(); + $results = $this->searchable->search($queryObject, $options)->getResults(); return $results; } @@ -81,12 +83,13 @@ class TransformedFinder implements PaginatedFinderInterface * Gets a paginator wrapping the result of a search * * @param string $query + * @param array $options * @return Pagerfanta */ - public function findPaginated($query) + public function findPaginated($query, $options = array()) { $queryObject = Query::create($query); - $paginatorAdapter = $this->createPaginatorAdapter($queryObject); + $paginatorAdapter = $this->createPaginatorAdapter($queryObject, $options); return new Pagerfanta(new FantaPaginatorAdapter($paginatorAdapter)); } @@ -94,10 +97,10 @@ class TransformedFinder implements PaginatedFinderInterface /** * {@inheritdoc} */ - public function createPaginatorAdapter($query) + public function createPaginatorAdapter($query, $options = array()) { $query = Query::create($query); - return new TransformedPaginatorAdapter($this->searchable, $query, $this->transformer); + return new TransformedPaginatorAdapter($this->searchable, $query, $options, $this->transformer); } } diff --git a/Paginator/RawPaginatorAdapter.php b/Paginator/RawPaginatorAdapter.php index d4b5357..e99746f 100644 --- a/Paginator/RawPaginatorAdapter.php +++ b/Paginator/RawPaginatorAdapter.php @@ -22,6 +22,11 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface */ private $query; + /** + * @var array search options + */ + private $options; + /** * @var integer the number of hits */ @@ -38,10 +43,11 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface * @param SearchableInterface $searchable the object to search in * @param Query $query the query to search */ - public function __construct(SearchableInterface $searchable, Query $query) + public function __construct(SearchableInterface $searchable, Query $query, array $options = array()) { $this->searchable = $searchable; $this->query = $query; + $this->options = $options; } /** @@ -72,7 +78,7 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface $query->setFrom($offset); $query->setSize($itemCountPerPage); - $resultSet = $this->searchable->search($query); + $resultSet = $this->searchable->search($query, $this->options); $this->totalHits = $resultSet->getTotalHits(); $this->facets = $resultSet->getFacets(); return $resultSet; diff --git a/Paginator/TransformedPaginatorAdapter.php b/Paginator/TransformedPaginatorAdapter.php index 7bc038a..10976f7 100644 --- a/Paginator/TransformedPaginatorAdapter.php +++ b/Paginator/TransformedPaginatorAdapter.php @@ -18,9 +18,9 @@ class TransformedPaginatorAdapter extends RawPaginatorAdapter * @param Query $query the query to search * @param ElasticaToModelTransformerInterface $transformer the transformer for fetching the results */ - public function __construct(SearchableInterface $searchable, Query $query, ElasticaToModelTransformerInterface $transformer) + public function __construct(SearchableInterface $searchable, Query $query, array $options = array(), ElasticaToModelTransformerInterface $transformer) { - parent::__construct($searchable, $query); + parent::__construct($searchable, $query, $options); $this->transformer = $transformer; } diff --git a/Repository.php b/Repository.php index 413f1e4..70b2a21 100644 --- a/Repository.php +++ b/Repository.php @@ -19,23 +19,23 @@ class Repository $this->finder = $finder; } - public function find($query, $limit=null) + public function find($query, $limit = null, $options = array()) { - return $this->finder->find($query, $limit); + return $this->finder->find($query, $limit, $options); } - public function findHybrid($query, $limit=null) + public function findHybrid($query, $limit = null, $options = array()) { - return $this->finder->findHybrid($query, $limit); + return $this->finder->findHybrid($query, $limit, $options); } - public function findPaginated($query) + public function findPaginated($query, $options = array()) { - return $this->finder->findPaginated($query); + return $this->finder->findPaginated($query, $options); } - public function createPaginatorAdapter($query) + public function createPaginatorAdapter($query, $options = array()) { - return $this->finder->createPaginatorAdapter($query); + return $this->finder->createPaginatorAdapter($query, $options); } } From 5be3a8c22ea9577f12200b42b14318899c1260de Mon Sep 17 00:00:00 2001 From: Hung Tran Date: Wed, 5 Feb 2014 11:21:14 -0600 Subject: [PATCH 150/447] added query string to collector and updated tests --- Client.php | 2 +- Logger/ElasticaLogger.php | 6 ++++-- Resources/views/Collector/elastica.html.twig | 3 ++- Tests/ClientTest.php | 1 + Tests/Logger/ElasticaLoggerTest.php | 4 +++- 5 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Client.php b/Client.php index ea0c572..7719095 100644 --- a/Client.php +++ b/Client.php @@ -27,7 +27,7 @@ class Client extends ElasticaClient 'transport' => $connection->getTransport(), ); - $this->_logger->logQuery($path, $method, $data, $time, $connection_array); + $this->_logger->logQuery($path, $method, $data, $time, $connection_array, $query); } return $response; diff --git a/Logger/ElasticaLogger.php b/Logger/ElasticaLogger.php index 7aacac5..60f28db 100644 --- a/Logger/ElasticaLogger.php +++ b/Logger/ElasticaLogger.php @@ -37,10 +37,11 @@ class ElasticaLogger implements LoggerInterface * @param string $path Path to call * @param string $method Rest method to use (GET, POST, DELETE, PUT) * @param array $data arguments + * @param array $query arguments * @param float $time execution time * @param array $connection host, port and transport of the query */ - public function logQuery($path, $method, $data, $time, $connection = array()) + public function logQuery($path, $method, $data, $time, $connection = array(), $query = array()) { if ($this->debug) { $this->queries[] = array( @@ -48,7 +49,8 @@ class ElasticaLogger implements LoggerInterface 'method' => $method, 'data' => $data, 'executionMS' => $time, - 'connection' => $connection + 'connection' => $connection, + 'queryString' => $query, ); } diff --git a/Resources/views/Collector/elastica.html.twig b/Resources/views/Collector/elastica.html.twig index 0eb50a6..637dae7 100644 --- a/Resources/views/Collector/elastica.html.twig +++ b/Resources/views/Collector/elastica.html.twig @@ -44,6 +44,7 @@ {% for key, query in collector.queries %}
  • Path: {{ query.path }}
    + Query: {{ query.queryString|url_encode }}
    Method: {{ query.method }} ({{ query.connection.transport }} on {{ query.connection.host }}:{{ query.connection.port }})
    {{ query.data|json_encode }} @@ -60,7 +61,7 @@ {% endif %}
  • diff --git a/Tests/ClientTest.php b/Tests/ClientTest.php index c8509cf..8a9d91a 100644 --- a/Tests/ClientTest.php +++ b/Tests/ClientTest.php @@ -24,6 +24,7 @@ class ClientTest extends \PHPUnit_Framework_TestCase Request::GET, $this->isType('array'), $this->isType('float'), + $this->isType('array'), $this->isType('array') ); diff --git a/Tests/Logger/ElasticaLoggerTest.php b/Tests/Logger/ElasticaLoggerTest.php index 30ce30c..96adf53 100644 --- a/Tests/Logger/ElasticaLoggerTest.php +++ b/Tests/Logger/ElasticaLoggerTest.php @@ -70,6 +70,7 @@ class ElasticaLoggerTest extends \PHPUnit_Framework_TestCase $data = array('data'); $time = 12; $connection = array('host' => 'localhost', 'port' => '8999', 'transport' => 'https'); + $query = array('search_type' => 'dfs_query_then_fetch'); $expected = array( 'path' => $path, @@ -77,9 +78,10 @@ class ElasticaLoggerTest extends \PHPUnit_Framework_TestCase 'data' => $data, 'executionMS' => $time, 'connection' => $connection, + 'queryString' => $query, ); - $elasticaLogger->logQuery($path, $method, $data, $time, $connection); + $elasticaLogger->logQuery($path, $method, $data, $time, $connection, $query); $returnedQueries = $elasticaLogger->getQueries(); $this->assertEquals($expected, $returnedQueries[0]); } From 3b1a756e6f89e828b2f9f2c5b280d0f86a72637c Mon Sep 17 00:00:00 2001 From: Richard Miller Date: Thu, 6 Feb 2014 21:11:12 +0000 Subject: [PATCH 151/447] Add support for using aliases to allow hot swapping of indexes when populating --- Client.php | 5 + Command/PopulateCommand.php | 1 + DependencyInjection/Configuration.php | 5 +- DependencyInjection/FOSElasticaExtension.php | 5 + DynamicIndex.php | 28 ++++ Resetter.php | 136 ++++++++++++++++++- Resources/config/config.xml | 2 +- 7 files changed, 176 insertions(+), 6 deletions(-) create mode 100644 DynamicIndex.php diff --git a/Client.php b/Client.php index ea0c572..67252ec 100644 --- a/Client.php +++ b/Client.php @@ -32,4 +32,9 @@ class Client extends ElasticaClient return $response; } + + public function getIndex($name) + { + return new DynamicIndex($this, $name); + } } diff --git a/Command/PopulateCommand.php b/Command/PopulateCommand.php index 7297523..31ecc4b 100755 --- a/Command/PopulateCommand.php +++ b/Command/PopulateCommand.php @@ -124,6 +124,7 @@ class PopulateCommand extends ContainerAwareCommand } $output->writeln(sprintf('Refreshing %s', $index)); + $this->resetter->postPopulate($index); $this->indexManager->getIndex($index)->refresh(); } diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 4ed88af..403de85 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -134,6 +134,7 @@ class Configuration implements ConfigurationInterface ->prototype('array') ->children() ->scalarNode('index_name')->end() + ->booleanNode('use_alias')->defaultValue(false)->end() ->scalarNode('client')->end() ->scalarNode('finder') ->treatNullLike(true) @@ -670,7 +671,7 @@ class Configuration implements ConfigurationInterface return $node; } - + /** * Returns the array node used for "_ttl" */ @@ -689,5 +690,5 @@ class Configuration implements ConfigurationInterface ; return $node; - } + } } diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 52070fd..a67be0f 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -124,6 +124,7 @@ class FOSElasticaExtension extends Extension $indexIds[$name] = $indexId; $this->indexConfigs[$name] = array( 'index' => new Reference($indexId), + 'name_or_alias' => $indexName, 'config' => array( 'mappings' => array() ) @@ -134,6 +135,10 @@ class FOSElasticaExtension extends Extension if (!empty($index['settings'])) { $this->indexConfigs[$name]['config']['settings'] = $index['settings']; } + if ($index['use_alias']) { + $this->indexConfigs[$name]['use_alias'] = true; + } + $this->loadTypes(isset($index['types']) ? $index['types'] : array(), $container, $name, $indexId, $typePrototypeConfig); } diff --git a/DynamicIndex.php b/DynamicIndex.php new file mode 100644 index 0000000..cbec8e9 --- /dev/null +++ b/DynamicIndex.php @@ -0,0 +1,28 @@ + + */ +class DynamicIndex extends Index +{ + /** + * Reassign index name + * + * While it's technically a regular setter for name property, it's specifically named overrideName, but not setName + * since it's used for a very specific case and normally should not be used + * + * @param string $name Index name + * + * @return void + */ + public function overrideName($name) + { + $this->_name = $name; + } +} diff --git a/Resetter.php b/Resetter.php index 26a6bb5..b8e7b80 100644 --- a/Resetter.php +++ b/Resetter.php @@ -2,6 +2,8 @@ namespace FOS\ElasticaBundle; +use Elastica\Exception\ExceptionInterface; +use Elastica\Index; use Elastica\Type\Mapping; /** @@ -26,8 +28,8 @@ class Resetter */ public function resetAllIndexes() { - foreach ($this->indexConfigsByName as $indexConfig) { - $indexConfig['index']->create($indexConfig['config'], true); + foreach (array_keys($this->indexConfigsByName) as $name) { + $this->resetIndex($name); } } @@ -40,7 +42,17 @@ class Resetter public function resetIndex($indexName) { $indexConfig = $this->getIndexConfig($indexName); - $indexConfig['index']->create($indexConfig['config'], true); + $esIndex = $indexConfig['index']; + if (isset($indexConfig['use_alias']) && $indexConfig['use_alias']) { + $name = $indexConfig['name_or_alias']; + $name .= date('-Y-m-d-Gis'); + $esIndex->overrideName($name); + $esIndex->create($indexConfig['config']); + + return; + } + + $esIndex->create($indexConfig['config'], true); } /** @@ -102,4 +114,122 @@ class Resetter return $this->indexConfigsByName[$indexName]; } + + public function postPopulate($indexName) + { + $indexConfig = $this->getIndexConfig($indexName); + if (isset($indexConfig['use_alias']) && $indexConfig['use_alias']) { + $this->switchIndexAlias($indexName); + } + } + + /** + * Switches the alias for given index to the newly populated index + * and deletes the old index + * + * @param string $indexName Index name + * + * @throws \RuntimeException + */ + private function switchIndexAlias($indexName) + { + $indexConfig = $this->getIndexConfig($indexName); + $esIndex = $indexConfig['index']; + $aliasName = $indexConfig['name_or_alias']; + $oldIndexName = false; + $newIndexName = $esIndex->getName(); + + $aliasedIndexes = $this->getAliasedIndexes($esIndex, $aliasName); + + if (count($aliasedIndexes) > 1) { + throw new \RuntimeException( + sprintf( + 'Alias %s is used for multiple indexes: [%s]. + Make sure it\'s either not used or is assigned to one index only', + $aliasName, + join(', ', $aliasedIndexes) + ) + ); + } + + // Change the alias to point to the new index + // Elastica's addAlias can't be used directly, because in current (0.19.x) version it's not atomic + // In 0.20.x it's atomic, but it doesn't return the old index name + $aliasUpdateRequest = array('actions' => array()); + if (count($aliasedIndexes) == 1) { + // if the alias is set - add an action to remove it + $oldIndexName = $aliasedIndexes[0]; + $aliasUpdateRequest['actions'][] = array( + 'remove' => array('index' => $oldIndexName, 'alias' => $aliasName) + ); + } + + // add an action to point the alias to the new index + $aliasUpdateRequest['actions'][] = array( + 'add' => array('index' => $newIndexName, 'alias' => $aliasName) + ); + + try { + $esIndex->getClient()->request('_aliases', 'POST', $aliasUpdateRequest); + } catch (ExceptionInterface $renameAliasException) { + $additionalError = ''; + // if we failed to move the alias, delete the newly built index + try { + $esIndex->delete(); + } catch (ExceptionInterface $deleteNewIndexException) { + $additionalError = sprintf( + 'Tried to delete newly built index %s, but also failed: %s', + $newIndexName, + $deleteNewIndexException->getError() + ); + } + + throw new \RuntimeException( + sprintf( + 'Failed to updated index alias: %s. %s', + $renameAliasException->getMessage(), + $additionalError ?: sprintf('Newly built index %s was deleted', $newIndexName) + ) + ); + } + + // Delete the old index after the alias has been switched + if ($oldIndexName) { + $oldIndex = new Index($esIndex->getClient(), $oldIndexName); + try { + $oldIndex->delete(); + } catch (ExceptionInterface $deleteOldIndexException) { + throw new \RuntimeException( + sprintf( + 'Failed to delete old index %s with message: %s', + $oldIndexName, + $deleteOldIndexException->getMessage() + ) + ); + } + } + } + + /** + * Returns array of indexes which are mapped to given alias + * + * @param Index $esIndex ES Index + * @param string $aliasName Alias name + * + * @return array + */ + private function getAliasedIndexes(Index $esIndex, $aliasName) + { + $aliasesInfo = $esIndex->getClient()->request('_aliases', 'GET')->getData(); + $aliasedIndexes = array(); + + foreach ($aliasesInfo as $indexName => $indexInfo) { + $aliases = array_keys($indexInfo['aliases']); + if (in_array($aliasName, $aliases)) { + $aliasedIndexes[] = $indexName; + } + } + + return $aliasedIndexes; + } } diff --git a/Resources/config/config.xml b/Resources/config/config.xml index 85cfbed..4419b4a 100644 --- a/Resources/config/config.xml +++ b/Resources/config/config.xml @@ -6,7 +6,7 @@ FOS\ElasticaBundle\Client - Elastica\Index + FOS\ElasticaBundle\DynamicIndex Elastica\Type FOS\ElasticaBundle\Logger\ElasticaLogger FOS\ElasticaBundle\DataCollector\ElasticaDataCollector From 03bf793b656a11646ae74a351ce46dd3de74b045 Mon Sep 17 00:00:00 2001 From: Richard Miller Date: Mon, 10 Feb 2014 10:55:13 +0000 Subject: [PATCH 152/447] Make real index name use uniqid so can be reset within a second --- Resetter.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Resetter.php b/Resetter.php index b8e7b80..4a7f13b 100644 --- a/Resetter.php +++ b/Resetter.php @@ -45,7 +45,7 @@ class Resetter $esIndex = $indexConfig['index']; if (isset($indexConfig['use_alias']) && $indexConfig['use_alias']) { $name = $indexConfig['name_or_alias']; - $name .= date('-Y-m-d-Gis'); + $name .= uniqid(); $esIndex->overrideName($name); $esIndex->create($indexConfig['config']); @@ -124,7 +124,7 @@ class Resetter } /** - * Switches the alias for given index to the newly populated index + * Switches the alias for given index (by key) to the newly populated index * and deletes the old index * * @param string $indexName Index name From 1402bdc9e63911510e093d22deb7b8290856719c Mon Sep 17 00:00:00 2001 From: Lea Haensenberger Date: Thu, 13 Feb 2014 09:11:05 +0100 Subject: [PATCH 153/447] Keep all special mapping fields for types when resetting a single type. Field list is according to the current documentation of elasticsearch 0.90 --- Resetter.php | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Resetter.php b/Resetter.php index 26a6bb5..d0f3014 100644 --- a/Resetter.php +++ b/Resetter.php @@ -74,12 +74,11 @@ class Resetter { $mapping = Mapping::create($indexConfig['properties']); - if (isset($indexConfig['_parent'])) { - $mapping->setParam('_parent', array('type' => $indexConfig['_parent']['type'])); - } - - if (isset($indexConfig['dynamic_templates'])) { - $mapping->setParam('dynamic_templates', $indexConfig['dynamic_templates']); + $mappingSpecialFields = array('_uid', '_id', '_source', '_all', '_analyzer', '_boost', '_parent', '_routing', '_index', '_size', '_timestamp', '_ttl'); + foreach ($mappingSpecialFields as $specialField) { + if (isset($indexConfig[$specialField])) { + $mapping->setParam($specialField, $indexConfig[$specialField]); + } } return $mapping; From ead3c95c88ed11756d0fdfbf11f9c7a8dfe84271 Mon Sep 17 00:00:00 2001 From: Lea Haensenberger Date: Thu, 13 Feb 2014 09:45:27 +0100 Subject: [PATCH 154/447] Keep dynamic templates --- Resetter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resetter.php b/Resetter.php index d0f3014..d193c9d 100644 --- a/Resetter.php +++ b/Resetter.php @@ -74,7 +74,7 @@ class Resetter { $mapping = Mapping::create($indexConfig['properties']); - $mappingSpecialFields = array('_uid', '_id', '_source', '_all', '_analyzer', '_boost', '_parent', '_routing', '_index', '_size', '_timestamp', '_ttl'); + $mappingSpecialFields = array('_uid', '_id', '_source', '_all', '_analyzer', '_boost', '_parent', '_routing', '_index', '_size', '_timestamp', '_ttl', 'dynamic_templates'); foreach ($mappingSpecialFields as $specialField) { if (isset($indexConfig[$specialField])) { $mapping->setParam($specialField, $indexConfig[$specialField]); From 765e400278fff2e59030e47bdead2f8240ef1fef Mon Sep 17 00:00:00 2001 From: Lea Haensenberger Date: Thu, 13 Feb 2014 10:06:10 +0100 Subject: [PATCH 155/447] handle _parent separately --- Resetter.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Resetter.php b/Resetter.php index d193c9d..69620a2 100644 --- a/Resetter.php +++ b/Resetter.php @@ -74,13 +74,17 @@ class Resetter { $mapping = Mapping::create($indexConfig['properties']); - $mappingSpecialFields = array('_uid', '_id', '_source', '_all', '_analyzer', '_boost', '_parent', '_routing', '_index', '_size', '_timestamp', '_ttl', 'dynamic_templates'); + $mappingSpecialFields = array('_uid', '_id', '_source', '_all', '_analyzer', '_boost', '_routing', '_index', '_size', '_timestamp', '_ttl', 'dynamic_templates'); foreach ($mappingSpecialFields as $specialField) { if (isset($indexConfig[$specialField])) { $mapping->setParam($specialField, $indexConfig[$specialField]); } } + if (isset($indexConfig['_parent'])) { + $mapping->setParam('_parent', array('type' => $indexConfig['_parent']['type'])); + } + return $mapping; } From 3065c96a2ca51ec03f5aa32877a75079faa8b413 Mon Sep 17 00:00:00 2001 From: Patrick McAndrew Date: Fri, 14 Feb 2014 17:32:22 +0000 Subject: [PATCH 156/447] Add ability to specify server timeout --- DependencyInjection/Configuration.php | 1 + 1 file changed, 1 insertion(+) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 79cadf2..b2a1756 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -102,6 +102,7 @@ class Configuration implements ConfigurationInterface ->scalarNode('url')->end() ->scalarNode('host')->end() ->scalarNode('port')->end() + ->scalarNode('timeout')->end() ->end() ->end() ->end() From 7d2776e27aad52dc7808a5db55e795b436790aef Mon Sep 17 00:00:00 2001 From: Hung Tran Date: Tue, 18 Feb 2014 10:12:31 -0600 Subject: [PATCH 157/447] fixed phpdoc --- Logger/ElasticaLogger.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Logger/ElasticaLogger.php b/Logger/ElasticaLogger.php index 60f28db..0e0a9c0 100644 --- a/Logger/ElasticaLogger.php +++ b/Logger/ElasticaLogger.php @@ -37,9 +37,9 @@ class ElasticaLogger implements LoggerInterface * @param string $path Path to call * @param string $method Rest method to use (GET, POST, DELETE, PUT) * @param array $data arguments - * @param array $query arguments * @param float $time execution time * @param array $connection host, port and transport of the query + * @param array $query arguments */ public function logQuery($path, $method, $data, $time, $connection = array(), $query = array()) { From b8cc6d758c3fb8a6397184bb423deebbae38208b Mon Sep 17 00:00:00 2001 From: Karel Souffriau Date: Wed, 19 Feb 2014 09:31:22 +0100 Subject: [PATCH 158/447] CS fix in AbstractProvider --- Provider/AbstractProvider.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Provider/AbstractProvider.php b/Provider/AbstractProvider.php index 48da5d7..8f5ad60 100644 --- a/Provider/AbstractProvider.php +++ b/Provider/AbstractProvider.php @@ -32,10 +32,12 @@ abstract class AbstractProvider implements ProviderInterface * * @return string */ - protected function getMemoryUsage() { + protected function getMemoryUsage() + { $memory = round(memory_get_usage() / (1024*1024),0); // to get usage in Mo $memoryMax = round(memory_get_peak_usage() / (1024*1024)); // to get max usage in Mo $message = '(RAM : current='.$memory.'Mo peak='.$memoryMax.'Mo)'; + return $message; } } From 41bf07ec5995e47d95fb4b01d0434eb04e283680 Mon Sep 17 00:00:00 2001 From: Karel Souffriau Date: Wed, 19 Feb 2014 11:01:54 +0100 Subject: [PATCH 159/447] Fixed issues in #426 --- Command/PopulateCommand.php | 4 +++- Doctrine/AbstractProvider.php | 6 +++--- Tests/Doctrine/AbstractProviderTest.php | 4 +++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Command/PopulateCommand.php b/Command/PopulateCommand.php index 07badd7..b13ddc3 100644 --- a/Command/PopulateCommand.php +++ b/Command/PopulateCommand.php @@ -45,7 +45,7 @@ class PopulateCommand extends ContainerAwareCommand ->addOption('offset', null, InputOption::VALUE_REQUIRED, 'Start indexing at offset', 0) ->addOption('sleep', null, InputOption::VALUE_REQUIRED, 'Sleep time between persisting iterations (microseconds)', 0) ->addOption('batch-size', null, InputOption::VALUE_REQUIRED, 'Index packet size (overrides provider config option)') - ->addOption('no-stop-on-error', null, InputOption::VALUE_NONE, 'Do not stop on errors') + ->addOption('ignore-errors', null, InputOption::VALUE_NONE, 'Do not stop on errors') ->setDescription('Populates search indexes from providers') ; } @@ -70,6 +70,8 @@ class PopulateCommand extends ContainerAwareCommand $reset = $input->getOption('no-reset') ? false : true; $options = $input->getOptions(); + $options['ignore-errors'] = $input->hasOption('ignore-errors'); + if ($input->isInteractive() && $reset && $input->getOption('offset')) { /** @var DialogHelper $dialog */ $dialog = $this->getHelperSet()->get('dialog'); diff --git a/Doctrine/AbstractProvider.php b/Doctrine/AbstractProvider.php index 109cfa0..9d1575c 100644 --- a/Doctrine/AbstractProvider.php +++ b/Doctrine/AbstractProvider.php @@ -23,8 +23,8 @@ abstract class AbstractProvider extends BaseAbstractProvider { parent::__construct($objectPersister, $objectClass, array_merge(array( 'clear_object_manager' => true, + 'ignore_errors' => false, 'query_builder_method' => 'createQueryBuilder', - 'stop_on_error' => true, ), $options)); $this->managerRegistry = $managerRegistry; @@ -40,7 +40,7 @@ abstract class AbstractProvider extends BaseAbstractProvider $offset = isset($options['offset']) ? intval($options['offset']) : 0; $sleep = isset($options['sleep']) ? intval($options['sleep']) : 0; $batchSize = isset($options['batch-size']) ? intval($options['batch-size']) : $this->options['batch_size']; - $stopOnError = isset($options['no-stop-on-error']) ? empty($options['no-stop-on-error']) : $this->options['stop_on_error']; + $ignoreErrors = isset($options['ignore-errors']) ? $options['ignore-errors'] : $this->options['ignore_errors']; for (; $offset < $nbObjects; $offset += $batchSize) { if ($loggerClosure) { @@ -48,7 +48,7 @@ abstract class AbstractProvider extends BaseAbstractProvider } $objects = $this->fetchSlice($queryBuilder, $batchSize, $offset); - if (!$stopOnError) { + if (!$ignoreErrors) { $this->objectPersister->insertMany($objects); } else { try { diff --git a/Tests/Doctrine/AbstractProviderTest.php b/Tests/Doctrine/AbstractProviderTest.php index a3836bd..2492eed 100644 --- a/Tests/Doctrine/AbstractProviderTest.php +++ b/Tests/Doctrine/AbstractProviderTest.php @@ -154,7 +154,9 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase ->method('insertMany') ->will($this->throwException($this->getMockBulkResponseException())); - $provider->populate(null, array('no-stop-on-error' => true)); + $this->setExpectedException('Elastica\Exception\Bulk\ResponseException'); + + $provider->populate(null, array('ignore-errors' => false)); } /** From 44180793fcef2b15671d2d75364c69154dc6e447 Mon Sep 17 00:00:00 2001 From: Karel Souffriau Date: Wed, 19 Feb 2014 12:29:51 +0100 Subject: [PATCH 160/447] Add changelog file for 3.0 --- CHANGELOG-3.0.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 CHANGELOG-3.0.md diff --git a/CHANGELOG-3.0.md b/CHANGELOG-3.0.md new file mode 100644 index 0000000..534a25e --- /dev/null +++ b/CHANGELOG-3.0.md @@ -0,0 +1,17 @@ +CHANGELOG for 3.0.x +=================== + +This changelog references the relevant changes (bug and security fixes) done +in 3.0 minor versions. + +To get the diff for a specific change, go to +https://github.com/FriendsOfSymfony/FOSElasticaBundle/commit/XXX where XXX is +the commit hash. To get the diff between two versions, go to +https://github.com/FriendsOfSymfony/FOSElasticaBundle/compare/v3.0.0...v3.0.1 + +To generate a changelog summary since the last version, run +`git log --no-merges --oneline v3.0.0...3.0.x` + +* 3.0.0-ALPHA2 (2014-xx-xx) + + * 41bf07e: Renamed the `no-stop-on-error` option in PopulateCommand to `ignore-errors` From 63cca11a0b0a0a89f368d71a5afcb3944800d2eb Mon Sep 17 00:00:00 2001 From: Karel Souffriau Date: Wed, 19 Feb 2014 12:43:44 +0100 Subject: [PATCH 161/447] Tweak: use hasOption() in PopulateCommand instead of checking for booleans --- Command/PopulateCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Command/PopulateCommand.php b/Command/PopulateCommand.php index b13ddc3..7d8a46e 100644 --- a/Command/PopulateCommand.php +++ b/Command/PopulateCommand.php @@ -67,7 +67,7 @@ class PopulateCommand extends ContainerAwareCommand { $index = $input->getOption('index'); $type = $input->getOption('type'); - $reset = $input->getOption('no-reset') ? false : true; + $reset = $input->hasOption('no-reset'); $options = $input->getOptions(); $options['ignore-errors'] = $input->hasOption('ignore-errors'); From 891dd51abebcdeaaa7ac4de017a8ef0a5868fa42 Mon Sep 17 00:00:00 2001 From: Karel Souffriau Date: Wed, 19 Feb 2014 12:50:48 +0100 Subject: [PATCH 162/447] Fixed bug made in #479 --- Command/PopulateCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Command/PopulateCommand.php b/Command/PopulateCommand.php index 7d8a46e..afed5ed 100644 --- a/Command/PopulateCommand.php +++ b/Command/PopulateCommand.php @@ -67,7 +67,7 @@ class PopulateCommand extends ContainerAwareCommand { $index = $input->getOption('index'); $type = $input->getOption('type'); - $reset = $input->hasOption('no-reset'); + $reset = !$input->hasOption('no-reset'); $options = $input->getOptions(); $options['ignore-errors'] = $input->hasOption('ignore-errors'); From 1c74f61b4ef5cf1b2d1c9b83c5814f173d7edddf Mon Sep 17 00:00:00 2001 From: Karel Souffriau Date: Wed, 19 Feb 2014 12:58:02 +0100 Subject: [PATCH 163/447] AbstractProvider cleanup --- Provider/AbstractProvider.php | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/Provider/AbstractProvider.php b/Provider/AbstractProvider.php index 8f5ad60..2761a25 100644 --- a/Provider/AbstractProvider.php +++ b/Provider/AbstractProvider.php @@ -4,10 +4,24 @@ namespace FOS\ElasticaBundle\Provider; use FOS\ElasticaBundle\Persister\ObjectPersisterInterface; +/** + * AbstractProvider + */ abstract class AbstractProvider implements ProviderInterface { - protected $objectClass; + /** + * @var ObjectPersisterInterface + */ protected $objectPersister; + + /** + * @var string + */ + protected $objectClass; + + /** + * @var array + */ protected $options; /** @@ -34,10 +48,9 @@ abstract class AbstractProvider implements ProviderInterface */ protected function getMemoryUsage() { - $memory = round(memory_get_usage() / (1024*1024),0); // to get usage in Mo - $memoryMax = round(memory_get_peak_usage() / (1024*1024)); // to get max usage in Mo - $message = '(RAM : current='.$memory.'Mo peak='.$memoryMax.'Mo)'; + $memory = round(memory_get_usage() / (1024 * 1024)); // to get usage in Mo + $memoryMax = round(memory_get_peak_usage() / (1024 * 1024)); // to get max usage in Mo - return $message; + return sprintf('(RAM : current=%uMo peak=%uMo)', $memory, $memoryMax); } } From 6f8b3a5a0f028edfb99ad714b0c448c05c36ca00 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Fri, 21 Feb 2014 08:58:43 +1100 Subject: [PATCH 164/447] Fix populate command option --- Command/PopulateCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Command/PopulateCommand.php b/Command/PopulateCommand.php index afed5ed..a67df94 100644 --- a/Command/PopulateCommand.php +++ b/Command/PopulateCommand.php @@ -67,7 +67,7 @@ class PopulateCommand extends ContainerAwareCommand { $index = $input->getOption('index'); $type = $input->getOption('type'); - $reset = !$input->hasOption('no-reset'); + $reset = !$input->getOption('no-reset'); $options = $input->getOptions(); $options['ignore-errors'] = $input->hasOption('ignore-errors'); From eecdd3474a2ddb2b46dc98fffc4b4bb641dfaed6 Mon Sep 17 00:00:00 2001 From: Matteo Galli Date: Fri, 21 Feb 2014 16:47:42 +0100 Subject: [PATCH 165/447] Fixes #459 --- DependencyInjection/FOSElasticaExtension.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 52070fd..96e1fdf 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -4,6 +4,7 @@ namespace FOS\ElasticaBundle\DependencyInjection; use Symfony\Component\HttpKernel\DependencyInjection\Extension; use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; +use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\DefinitionDecorator; @@ -198,6 +199,10 @@ class FOSElasticaExtension extends Extension if (isset($type['serializer']['version'])) { $callbackDef->addMethodCall('setVersion', array($type['serializer']['version'])); } + $callbackClassImplementedInterfaces = class_implements($this->serializerConfig['callback_class']); // PHP < 5.4 friendly + if (isset($callbackClassImplementedInterfaces['Symfony\Component\DependencyInjection\ContainerAwareInterface'])) { + $callbackDef->addMethodCall('setContainer', array(new Reference('service_container'))); + } $container->setDefinition($callbackId, $callbackDef); From 2b04f6cf34807854226794ff78dd3f4f207f73ed Mon Sep 17 00:00:00 2001 From: Karel Souffriau Date: Tue, 25 Feb 2014 11:05:26 +0100 Subject: [PATCH 166/447] ElasticaLogger cleanup --- Logger/ElasticaLogger.php | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/Logger/ElasticaLogger.php b/Logger/ElasticaLogger.php index 0e0a9c0..5b1269f 100644 --- a/Logger/ElasticaLogger.php +++ b/Logger/ElasticaLogger.php @@ -14,32 +14,42 @@ use Psr\Log\LoggerInterface; */ class ElasticaLogger implements LoggerInterface { + /** + * @var LoggerInterface + */ protected $logger; - protected $queries; + + /** + * @var array + */ + protected $queries = array(); + + /** + * @var boolean + */ protected $debug; /** * Constructor. * * @param LoggerInterface|null $logger The Symfony logger - * @param bool $debug + * @param boolean $debug */ public function __construct(LoggerInterface $logger = null, $debug = false) { $this->logger = $logger; - $this->queries = array(); $this->debug = $debug; } /** * Logs a query. * - * @param string $path Path to call - * @param string $method Rest method to use (GET, POST, DELETE, PUT) - * @param array $data arguments - * @param float $time execution time - * @param array $connection host, port and transport of the query - * @param array $query arguments + * @param string $path Path to call + * @param string $method Rest method to use (GET, POST, DELETE, PUT) + * @param array $data Arguments + * @param float $time Execution time + * @param array $connection Host, port and transport of the query + * @param array $query Arguments */ public function logQuery($path, $method, $data, $time, $connection = array(), $query = array()) { From 418b9d72cec839d1b5f2dcb73cbd83bdd276bdbe Mon Sep 17 00:00:00 2001 From: tgallice Date: Tue, 4 Mar 2014 17:54:49 +0100 Subject: [PATCH 167/447] Rework configuration validation to fix #461 --- DependencyInjection/Configuration.php | 4 ++-- .../DependencyInjection/ConfigurationTest.php | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 107744d..4488bf2 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -103,8 +103,8 @@ class Configuration implements ConfigurationInterface ->children() ->scalarNode('url') ->validate() - ->ifTrue(function($v) { return substr($v['url'], -1) !== '/'; }) - ->then(function($v) { return $v['url'].'/'; }) + ->ifTrue(function($url) { return substr($url, -1) !== '/'; }) + ->then(function($url) { return $url.'/'; }) ->end() ->end() ->scalarNode('host')->end() diff --git a/Tests/DependencyInjection/ConfigurationTest.php b/Tests/DependencyInjection/ConfigurationTest.php index 35b2af3..0f0d374 100644 --- a/Tests/DependencyInjection/ConfigurationTest.php +++ b/Tests/DependencyInjection/ConfigurationTest.php @@ -3,6 +3,7 @@ namespace FOS\ElasticaBundle\Tests\Resetter\DependencyInjection; use FOS\ElasticaBundle\DependencyInjection\Configuration; +use Symfony\Component\Config\Definition\Processor; /** * ConfigurationTest @@ -85,4 +86,21 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('Symfony\Component\Config\Definition\ScalarNode', $mapping['index']); $this->assertNull($mapping['index']->getDefaultValue()); } + + public function testSlashIsAddedAtTheEndOfServerUrl() + { + $config = array( + 'clients' => array( + 'default' => array( + 'url' => 'http://www.github.com', + ), + ), + ); + + $processor = new Processor(); + + $configuration = $processor->processConfiguration($this->configuration, array($config)); + + $this->assertEquals('http://www.github.com/', $configuration['clients']['default']['servers'][0]['url']); + } } From a1f7449efc7e8190726812f987e6cba98e4bccbe Mon Sep 17 00:00:00 2001 From: Bastien Jaillot Date: Wed, 5 Mar 2014 15:59:38 +0100 Subject: [PATCH 168/447] [doc] inform about the override of Elastica logger Add a documentation related to this change: https://github.com/FriendsOfSymfony/FOSElasticaBundle/pull/395#issuecomment-27729759 --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f78c97f..aaaf0a5 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,7 @@ Most of the time, you will need only one. clients: default: { host: localhost, port: 9200 } +A client configuration can also override the Elastica logger to change the used class ```logger: ``` or to simply disable it ```logger: false```. Disabling the logger should be done on production because it can cause a memory leak. #### Declare a serializer From 7f53badad545a9e1d5b04a9b02c238fb7a5e30b7 Mon Sep 17 00:00:00 2001 From: Berny Cantos Date: Thu, 5 Sep 2013 13:45:36 +0200 Subject: [PATCH 169/447] Add support for include_in_{parent,root} for nested and objects --- DependencyInjection/Configuration.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 4488bf2..adcaf6a 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -415,6 +415,10 @@ class Configuration implements ConfigurationInterface } if (isset($nestings['properties'])) { + $node + ->booleanNode('include_in_parent')->end() + ->booleanNode('include_in_root')->end() + ; $this->addNestedFieldConfig($node, $nestings, 'properties'); } } From 0116a6ac4f88da2210660c0e6ca55515b0450656 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 6 Mar 2014 12:38:23 -0430 Subject: [PATCH 170/447] Add support for clients requiring basic HTTP authentication --- Client.php | 1 + DependencyInjection/Configuration.php | 8 +++++++- Logger/ElasticaLogger.php | 2 +- README.md | 17 +++++++++++++++++ 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/Client.php b/Client.php index 7719095..601fc77 100644 --- a/Client.php +++ b/Client.php @@ -25,6 +25,7 @@ class Client extends ElasticaClient 'host' => $connection->getHost(), 'port' => $connection->getPort(), 'transport' => $connection->getTransport(), + 'headers' => $connection->getConfig('headers'), ); $this->_logger->logQuery($path, $method, $data, $time, $connection_array, $query); diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 4488bf2..a01d1cb 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -78,7 +78,8 @@ class Configuration implements ConfigurationInterface array( 'host' => $v['host'], 'port' => $v['port'], - 'logger' => isset($v['logger']) ? $v['logger'] : null + 'logger' => isset($v['logger']) ? $v['logger'] : null, + 'headers' => isset($v['headers']) ? $v['headers'] : null, ) ) ); @@ -114,6 +115,11 @@ class Configuration implements ConfigurationInterface ->treatNullLike('fos_elastica.logger') ->treatTrueLike('fos_elastica.logger') ->end() + ->arrayNode('headers') + ->children() + ->scalarNode('Authorization')->end() + ->end() + ->end() ->scalarNode('timeout')->end() ->end() ->end() diff --git a/Logger/ElasticaLogger.php b/Logger/ElasticaLogger.php index 0e0a9c0..85acf70 100644 --- a/Logger/ElasticaLogger.php +++ b/Logger/ElasticaLogger.php @@ -38,7 +38,7 @@ class ElasticaLogger implements LoggerInterface * @param string $method Rest method to use (GET, POST, DELETE, PUT) * @param array $data arguments * @param float $time execution time - * @param array $connection host, port and transport of the query + * @param array $connection host, port, transport and headers of the query * @param array $query arguments */ public function logQuery($path, $method, $data, $time, $connection = array(), $query = array()) diff --git a/README.md b/README.md index f78c97f..cd1a1ba 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,23 @@ Most of the time, you will need only one. clients: default: { host: localhost, port: 9200 } +If your client requires Basic HTTP Authentication, you can specify an Authorization Header to +include in HTTP requests. The Authorization Header value is a ``base64`` encoded string that +includes the authentication username and password, and can be obtained by running the following +command in your terminal: + + php -r "Print 'Basic ' . base64_encode('your_auth_username' . ':' . 'your_auth_password');" + +A sample configuration with Basic HTTP Authentication is: + + #app/config/config.yml + fos_elastica: + clients: + default: + host: example.com + port: 80 + headers: + Authorization: "Basic jdumrGK7rY9TMuQOPng7GZycmxyMHNoir==" #### Declare a serializer From fe871c5ac48d2be18a2efef46cd2b14ca001fe1a Mon Sep 17 00:00:00 2001 From: Miha Vrhovnik Date: Tue, 11 Mar 2014 14:50:00 +0100 Subject: [PATCH 171/447] Fix wrong annotation --- Paginator/RawPaginatorAdapter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Paginator/RawPaginatorAdapter.php b/Paginator/RawPaginatorAdapter.php index e99746f..b74a9e4 100644 --- a/Paginator/RawPaginatorAdapter.php +++ b/Paginator/RawPaginatorAdapter.php @@ -33,7 +33,7 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface private $totalHits; /** - * @array for the facets + * @var array for the facets */ private $facets; From 726892c586949b8cf13ccca7fa7c1f3c3ca43f2d Mon Sep 17 00:00:00 2001 From: Lea Haensenberger Date: Thu, 13 Mar 2014 10:43:35 +0100 Subject: [PATCH 172/447] Ignore TypeMissingException when resetting a single type. This allows to create new types without having to recreate the whole index. --- Resetter.php | 9 ++++++++- Tests/ResetterTest.php | 29 +++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/Resetter.php b/Resetter.php index 69620a2..b22f6a1 100644 --- a/Resetter.php +++ b/Resetter.php @@ -2,6 +2,7 @@ namespace FOS\ElasticaBundle; +use Elastica\Exception\ResponseException; use Elastica\Type\Mapping; /** @@ -59,7 +60,13 @@ class Resetter } $type = $indexConfig['index']->getType($typeName); - $type->delete(); + try { + $type->delete(); + } catch (ResponseException $e) { + if (strpos($e->getMessage(), 'TypeMissingException') !== 0) { + throw $e; + } + } $mapping = $this->createMapping($indexConfig['config']['mappings'][$typeName]); $type->setMapping($mapping); } diff --git a/Tests/ResetterTest.php b/Tests/ResetterTest.php index aa0fbcc..b4e5649 100644 --- a/Tests/ResetterTest.php +++ b/Tests/ResetterTest.php @@ -2,6 +2,9 @@ namespace FOS\ElasticaBundle\Tests\Resetter; +use Elastica\Exception\ResponseException; +use Elastica\Request; +use Elastica\Response; use FOS\ElasticaBundle\Resetter; use Elastica\Type\Mapping; @@ -130,6 +133,32 @@ class ResetterTest extends \PHPUnit_Framework_TestCase $resetter->resetIndexType('foo', 'c'); } + public function testResetIndexTypeIgnoreTypeMissingException() + { + $type = $this->getMockElasticaType(); + + $this->indexConfigsByName['foo']['index']->expects($this->once()) + ->method('getType') + ->with('a') + ->will($this->returnValue($type)); + + $type->expects($this->once()) + ->method('delete') + ->will($this->throwException(new ResponseException( + new Request(''), + new Response(array('error' => 'TypeMissingException[[de_20131022] type[bla] missing]', 'status' => 404))) + )); + + $mapping = Mapping::create($this->indexConfigsByName['foo']['config']['mappings']['a']['properties']); + $mapping->setParam('dynamic_templates', $this->indexConfigsByName['foo']['config']['mappings']['a']['dynamic_templates']); + $type->expects($this->once()) + ->method('setMapping') + ->with($mapping); + + $resetter = new Resetter($this->indexConfigsByName); + $resetter->resetIndexType('foo', 'a'); + } + public function testIndexMappingForParent() { $type = $this->getMockElasticaType(); From 2f9896c893063b7142a0ac1d2980e05c9050f2df Mon Sep 17 00:00:00 2001 From: Lea Haensenberger Date: Thu, 13 Mar 2014 10:45:57 +0100 Subject: [PATCH 173/447] Check for TypeMissingException anywhere in exception message --- Resetter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resetter.php b/Resetter.php index b22f6a1..863524b 100644 --- a/Resetter.php +++ b/Resetter.php @@ -63,7 +63,7 @@ class Resetter try { $type->delete(); } catch (ResponseException $e) { - if (strpos($e->getMessage(), 'TypeMissingException') !== 0) { + if (strpos($e->getMessage(), 'TypeMissingException') === false) { throw $e; } } From cdd6e3af45a7fb9f97b53887416e0b3511763452 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Fri, 14 Mar 2014 08:59:59 +1100 Subject: [PATCH 174/447] Bump elastica version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 094eba5..e588494 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ "symfony/console": "~2.1", "symfony/form": "~2.1", "symfony/property-access": "~2.2", - "ruflin/elastica": "~0.20", + "ruflin/elastica": ">=0.20, <1.1-dev", "psr/log": "~1.0" }, "require-dev":{ From 6a26c63b2c5d0d56b9d4346e523b12ce25af6576 Mon Sep 17 00:00:00 2001 From: Piotr Antosik Date: Fri, 14 Mar 2014 18:41:49 +0100 Subject: [PATCH 175/447] fix some block comment --- Client.php | 3 +++ FOSElasticaBundle.php | 6 +++++- Paginator/RawPaginatorAdapter.php | 3 ++- Paginator/TransformedPaginatorAdapter.php | 5 +++-- Resetter.php | 1 + 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/Client.php b/Client.php index 7719095..ab819f8 100644 --- a/Client.php +++ b/Client.php @@ -11,6 +11,9 @@ use FOS\ElasticaBundle\Logger\ElasticaLogger; */ class Client extends ElasticaClient { + /** + * {@inheritdoc} + */ public function request($path, $method = Request::GET, $data = array(), array $query = array()) { $start = microtime(true); diff --git a/FOSElasticaBundle.php b/FOSElasticaBundle.php index 5ac1f2a..44424d3 100644 --- a/FOSElasticaBundle.php +++ b/FOSElasticaBundle.php @@ -8,10 +8,14 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Compiler\PassConfig; use Symfony\Component\HttpKernel\Bundle\Bundle; +/** + * Bundle. + * + */ class FOSElasticaBundle extends Bundle { /** - * @see Symfony\Component\HttpKernel\Bundle\Bundle::build() + * {@inheritdoc} */ public function build(ContainerBuilder $container) { diff --git a/Paginator/RawPaginatorAdapter.php b/Paginator/RawPaginatorAdapter.php index b74a9e4..8bd4ee2 100644 --- a/Paginator/RawPaginatorAdapter.php +++ b/Paginator/RawPaginatorAdapter.php @@ -41,7 +41,8 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface * @see PaginatorAdapterInterface::__construct * * @param SearchableInterface $searchable the object to search in - * @param Query $query the query to search + * @param Query $query the query to search + * @param array $options */ public function __construct(SearchableInterface $searchable, Query $query, array $options = array()) { diff --git a/Paginator/TransformedPaginatorAdapter.php b/Paginator/TransformedPaginatorAdapter.php index 10976f7..3b4716f 100644 --- a/Paginator/TransformedPaginatorAdapter.php +++ b/Paginator/TransformedPaginatorAdapter.php @@ -14,8 +14,9 @@ class TransformedPaginatorAdapter extends RawPaginatorAdapter private $transformer; /** - * @param SearchableInterface $searchable the object to search in - * @param Query $query the query to search + * @param SearchableInterface $searchable the object to search in + * @param Query $query the query to search + * @param array $options * @param ElasticaToModelTransformerInterface $transformer the transformer for fetching the results */ public function __construct(SearchableInterface $searchable, Query $query, array $options = array(), ElasticaToModelTransformerInterface $transformer) diff --git a/Resetter.php b/Resetter.php index 863524b..c97cd34 100644 --- a/Resetter.php +++ b/Resetter.php @@ -50,6 +50,7 @@ class Resetter * @param string $indexName * @param string $typeName * @throws \InvalidArgumentException if no index or type mapping exists for the given names + * @throws ResponseException */ public function resetIndexType($indexName, $typeName) { From dc01b189ed8ecb3670bd205fa2c8940547e60c40 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Mon, 17 Mar 2014 09:26:16 +1100 Subject: [PATCH 176/447] Update CHANGELOG-3.0.md --- CHANGELOG-3.0.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-3.0.md b/CHANGELOG-3.0.md index 534a25e..eb3e8c8 100644 --- a/CHANGELOG-3.0.md +++ b/CHANGELOG-3.0.md @@ -12,6 +12,14 @@ https://github.com/FriendsOfSymfony/FOSElasticaBundle/compare/v3.0.0...v3.0.1 To generate a changelog summary since the last version, run `git log --no-merges --oneline v3.0.0...3.0.x` -* 3.0.0-ALPHA2 (2014-xx-xx) +* 3.0.0-ALPHA3 (xxxx-xx-xx) + + * #463: allowing hot swappable reindexing + * #415: BC BREAK: document indexing occurs in postFlush rather than the pre* events previously. + +* 3.0.0-ALPHA2 (2014-03-17) * 41bf07e: Renamed the `no-stop-on-error` option in PopulateCommand to `ignore-errors` + * 418b9d7: Fixed validation of url configuration + * 726892c: Ignore TypeMissingException when resetting a single type. This allows to create new types without having to recreate the whole index. + * 7f53bad Add support for include_in_{parent,root} for nested and objects From 7d13823488c414cd42f794c1f3cacb82b6c96542 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Tue, 18 Mar 2014 09:10:44 +1100 Subject: [PATCH 177/447] Bump symfony requirement --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index e588494..8f22393 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ ], "require": { "php": ">=5.3.2", - "symfony/framework-bundle": "~2.1", + "symfony/framework-bundle": "~2.3", "symfony/console": "~2.1", "symfony/form": "~2.1", "symfony/property-access": "~2.2", From babe20800e6bff5af8bfd0de54bb72175dca0ff4 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Tue, 18 Mar 2014 09:12:11 +1100 Subject: [PATCH 178/447] Updated changelog --- CHANGELOG-3.0.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG-3.0.md b/CHANGELOG-3.0.md index eb3e8c8..a80d09d 100644 --- a/CHANGELOG-3.0.md +++ b/CHANGELOG-3.0.md @@ -16,6 +16,7 @@ To generate a changelog summary since the last version, run * #463: allowing hot swappable reindexing * #415: BC BREAK: document indexing occurs in postFlush rather than the pre* events previously. + * 7d13823: Dropped (broken) support for Symfony <2.3 * 3.0.0-ALPHA2 (2014-03-17) From de70e78b5370f6f9f014351e3169dfb035ed8415 Mon Sep 17 00:00:00 2001 From: rayrigam Date: Tue, 18 Mar 2014 18:14:03 -0430 Subject: [PATCH 179/447] Update Configuration.php Updated to support any HTTP request header type in the "headers" section. --- DependencyInjection/Configuration.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index a01d1cb..d629ea6 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -101,6 +101,7 @@ class Configuration implements ConfigurationInterface ->children() ->arrayNode('servers') ->prototype('array') + ->fixXmlConfig('header') ->children() ->scalarNode('url') ->validate() @@ -116,9 +117,8 @@ class Configuration implements ConfigurationInterface ->treatTrueLike('fos_elastica.logger') ->end() ->arrayNode('headers') - ->children() - ->scalarNode('Authorization')->end() - ->end() + ->useAttributeAsKey('name') + ->prototype('scalar')->end() ->end() ->scalarNode('timeout')->end() ->end() From 4dc08cd006f3260411d7bb26e74c61ec6268d959 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 18 Mar 2014 20:07:30 -0430 Subject: [PATCH 180/447] Added notice about added support for HTTP headers. --- CHANGELOG-3.0.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG-3.0.md b/CHANGELOG-3.0.md index a80d09d..fd2ecd5 100644 --- a/CHANGELOG-3.0.md +++ b/CHANGELOG-3.0.md @@ -17,6 +17,7 @@ To generate a changelog summary since the last version, run * #463: allowing hot swappable reindexing * #415: BC BREAK: document indexing occurs in postFlush rather than the pre* events previously. * 7d13823: Dropped (broken) support for Symfony <2.3 + * #496: Added support for HTTP headers * 3.0.0-ALPHA2 (2014-03-17) From 2009f8810911e1999aa8d2966b0c076854258daa Mon Sep 17 00:00:00 2001 From: Peter Mitchell Date: Wed, 19 Mar 2014 08:40:52 -0400 Subject: [PATCH 181/447] Make fetchSlice compatible with custom repo method If a user configures query_builder_method for the doctrine provider, and does not alias the root entity to equal Provider::ENTITY_ALIAS then a DQL error will occur during index population. > [Semantical Error] [...] near 'a.id ASC': Error: 'a' is not defined. Provider::countObjects already handles this by dynamically fetching the alias with QueryBuilder::getRootAliases, and Provider::fetchSlice should be doing the same. nb. "Provider" refers to FOS\ElasticaBundle\Doctrine\ORM\Provider --- Doctrine/ORM/Provider.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Doctrine/ORM/Provider.php b/Doctrine/ORM/Provider.php index 3549550..5d0164f 100644 --- a/Doctrine/ORM/Provider.php +++ b/Doctrine/ORM/Provider.php @@ -9,7 +9,7 @@ use FOS\ElasticaBundle\Exception\InvalidArgumentTypeException; class Provider extends AbstractProvider { const ENTITY_ALIAS = 'a'; - + /** * @see FOS\ElasticaBundle\Doctrine\AbstractProvider::countObjects() */ @@ -50,12 +50,13 @@ class Provider extends AbstractProvider */ $orderBy = $queryBuilder->getDQLPart('orderBy'); if (empty($orderBy)) { + $rootAliases = $queryBuilder->getRootAliases(); $identifierFieldNames = $this->managerRegistry ->getManagerForClass($this->objectClass) ->getClassMetadata($this->objectClass) ->getIdentifierFieldNames(); foreach ($identifierFieldNames as $fieldName) { - $queryBuilder->addOrderBy(static::ENTITY_ALIAS.'.'.$fieldName); + $queryBuilder->addOrderBy($rootAliases[0].'.'.$fieldName); } } From 455ff9e0f7dea27c45570859218211a45a9fe0ea Mon Sep 17 00:00:00 2001 From: Joris van de Sande Date: Mon, 24 Mar 2014 13:13:57 +0100 Subject: [PATCH 182/447] Unset fields if no nested fields are defined --- DependencyInjection/Configuration.php | 4 +++ .../DependencyInjection/ConfigurationTest.php | 30 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 0445748..40b26c6 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -334,6 +334,10 @@ class Configuration implements ConfigurationInterface $childrenNode = $node ->useAttributeAsKey('name') ->prototype('array') + ->validate() + ->ifTrue(function($v) { return isset($v['fields']) && empty($v['fields']); }) + ->then(function($v) { unset($v['fields']); return $v; }) + ->end() ->treatNullLike(array()) ->addDefaultsIfNotSet() ->children(); diff --git a/Tests/DependencyInjection/ConfigurationTest.php b/Tests/DependencyInjection/ConfigurationTest.php index 0f0d374..93143ec 100644 --- a/Tests/DependencyInjection/ConfigurationTest.php +++ b/Tests/DependencyInjection/ConfigurationTest.php @@ -103,4 +103,34 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase $this->assertEquals('http://www.github.com/', $configuration['clients']['default']['servers'][0]['url']); } + + public function testEmptyFieldsIndexIsUnset() + { + $config = array( + 'indexes' => array( + 'test' => array( + 'types' => array( + 'test' => array( + 'mappings' => array( + 'title' => array( + 'type' => 'string', + 'fields' => array( + 'autocomplete' => null + ) + ), + 'content' => null + ) + ) + ) + ) + ) + ); + + $processor = new Processor(); + + $configuration = $processor->processConfiguration(new Configuration(array($config)), array($config)); + + $this->assertArrayNotHasKey('fields', $configuration['indexes']['test']['types']['test']['mappings']['content']); + $this->assertArrayHasKey('fields', $configuration['indexes']['test']['types']['test']['mappings']['title']); + } } From 720917f609381921db52622a9796b2c13a84647a Mon Sep 17 00:00:00 2001 From: nurikabe Date: Mon, 24 Mar 2014 11:16:31 -0400 Subject: [PATCH 183/447] Clone entities on delete to preserve ids --- Doctrine/Listener.php | 7 +++++-- Tests/Doctrine/AbstractListenerTest.php | 8 ++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Doctrine/Listener.php b/Doctrine/Listener.php index c254513..43ac744 100644 --- a/Doctrine/Listener.php +++ b/Doctrine/Listener.php @@ -195,17 +195,20 @@ class Listener implements EventSubscriber $this->scheduledForUpdate[] = $entity; } else { // Delete if no longer indexable - $this->scheduledForDeletion[] = $entity; + $this->scheduledForDeletion[] = clone $entity; } } } + /** + * Delete objects preRemove instead of postRemove so that we have access to the id + */ public function preRemove(EventArgs $eventArgs) { $entity = $eventArgs->getEntity(); if ($entity instanceof $this->objectClass) { - $this->scheduledForDeletion[] = $entity; + $this->scheduledForDeletion[] = clone $entity; } } diff --git a/Tests/Doctrine/AbstractListenerTest.php b/Tests/Doctrine/AbstractListenerTest.php index a9eff66..8e49f24 100644 --- a/Tests/Doctrine/AbstractListenerTest.php +++ b/Tests/Doctrine/AbstractListenerTest.php @@ -133,7 +133,9 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase $listener = $this->createListener($persister, get_class($entity), array()); $listener->preRemove($eventArgs); - $this->assertEquals($entity, current($listener->scheduledForDeletion)); + $scheduledClone = current($listener->scheduledForDeletion); + $this->assertEquals($entity, $scheduledClone); + $this->assertNotSame($entity, $scheduledClone); $persister->expects($this->once()) ->method('deleteMany') @@ -164,7 +166,9 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase $listener = $this->createListener($persister, get_class($entity), array(), 'identifier'); $listener->preRemove($eventArgs); - $this->assertEquals($entity, current($listener->scheduledForDeletion)); + $scheduledClone = current($listener->scheduledForDeletion); + $this->assertEquals($entity, $scheduledClone); + $this->assertNotSame($entity, $scheduledClone); $persister->expects($this->once()) ->method('deleteMany') From 361d80a720e27ef63bc5bd6a188435a7a6b6102c Mon Sep 17 00:00:00 2001 From: nurikabe Date: Mon, 24 Mar 2014 11:18:55 -0400 Subject: [PATCH 184/447] Prevent division by zero error --- Doctrine/AbstractProvider.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Doctrine/AbstractProvider.php b/Doctrine/AbstractProvider.php index 9d1575c..3fafe50 100644 --- a/Doctrine/AbstractProvider.php +++ b/Doctrine/AbstractProvider.php @@ -70,7 +70,8 @@ abstract class AbstractProvider extends BaseAbstractProvider $stepNbObjects = count($objects); $stepCount = $stepNbObjects + $offset; $percentComplete = 100 * $stepCount / $nbObjects; - $objectsPerSecond = $stepNbObjects / (microtime(true) - $stepStartTime); + $timeDifference = microtime(true) - $stepStartTime; + $objectsPerSecond = $timeDifference ? ($stepNbObjects / $timeDifference) : $stepNbObjects; $loggerClosure(sprintf('%0.1f%% (%d/%d), %d objects/s %s', $percentComplete, $stepCount, $nbObjects, $objectsPerSecond, $this->getMemoryUsage())); } } From eb7758605e9255b4d8e8a90567c52ae50f15f617 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Wed, 26 Mar 2014 10:07:50 +1100 Subject: [PATCH 185/447] Documentation updates --- README.md | 6 +++- .../cookbook/elastica-client-http-headers.md | 18 ++++++++++ Resources/doc/cookbook/logging.md | 36 +++++++++++++++++++ Resources/doc/index.md | 8 +++-- Resources/doc/setup.md | 15 ++++---- Resources/doc/types.md | 16 ++++++++- 6 files changed, 87 insertions(+), 12 deletions(-) create mode 100644 Resources/doc/cookbook/elastica-client-http-headers.md create mode 100644 Resources/doc/cookbook/logging.md diff --git a/README.md b/README.md index ce5afab..8267e57 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,11 @@ FOSElasticaBundle This bundle provides integration with [ElasticSearch](http://www.elasticsearch.org) and [Elastica](https://github.com/ruflin/Elastica) with Symfony2. Features include: -- Features... +- Integrates the Elastica library into a Symfony2 environment +- Automatically generate mappings using a serializer +- Listeners for Doctrine events for automatic indexing + +> **Note** Propel support is limited and contributions fixing issues are welcome! [![Build Status](https://secure.travis-ci.org/FriendsOfSymfony/FOSElasticaBundle.png?branch=master)](http://travis-ci.org/FriendsOfSymfony/FOSElasticaBundle) [![Total Downloads](https://poser.pugx.org/FriendsOfSymfony/elastica-bundle/downloads.png)](https://packagist.org/packages/FriendsOfSymfony/elastica-bundle) [![Latest Stable Version](https://poser.pugx.org/FriendsOfSymfony/elastica-bundle/v/stable.png)](https://packagist.org/packages/FriendsOfSymfony/elastica-bundle) diff --git a/Resources/doc/cookbook/elastica-client-http-headers.md b/Resources/doc/cookbook/elastica-client-http-headers.md new file mode 100644 index 0000000..781d639 --- /dev/null +++ b/Resources/doc/cookbook/elastica-client-http-headers.md @@ -0,0 +1,18 @@ +Setting HTTP Headers on the Elastica Client +=========================================== + +It may be necessary to set HTTP headers on the Elastica client, for example an +Authorization header. + +They can be set using the headers configuration key: + +```yaml +# app/config/config.yml +fos_elastica: + clients: + default: + host: example.com + port: 80 + headers: + Authorization: "Basic jdumrGK7rY9TMuQOPng7GZycmxyMHNoir==" +``` diff --git a/Resources/doc/cookbook/logging.md b/Resources/doc/cookbook/logging.md new file mode 100644 index 0000000..b2d2e6c --- /dev/null +++ b/Resources/doc/cookbook/logging.md @@ -0,0 +1,36 @@ +Logging and its performance considerations +========================================== + +By default, FOSElasticaBundle sets a logger against each Elastica client configured and +logs all information sent to and received from Elasticsearch. This can lead to large +memory usage during population or reindexing of an index. + +FOSElasticaBundle provides an option to disable a logger by setting the property on the +client configuration to false: + +```yaml +# app/config/config.yml +fos_elastica: + clients: + default: + host: example.com + logger: false +``` + +It may be desirable to set this configuration property to `%kernel.debug%`, which would +only switch the logging capabilities of FOSElasticaBundle on when debugging is enabled. + +Custom Logger Service +--------------------- + +It is also possible to specify a custom logger instance to be injected into each client by +specifying the service id of the logger you wish to use. + +```yaml +# app/config/config.yml +fos_elastica: + clients: + default: + host: example.com + logger: 'acme.custom.logger' +``` diff --git a/Resources/doc/index.md b/Resources/doc/index.md index d9b6c65..1bc093e 100644 --- a/Resources/doc/index.md +++ b/Resources/doc/index.md @@ -1,7 +1,8 @@ FOSElasticaBundle Documentation =============================== -Available documentation for FOSElasticaBundle: +Available documentation for FOSElasticaBundle +--------------------------------------------- * [Setup](setup.md) * [Usage](usage.md) @@ -9,6 +10,9 @@ Available documentation for FOSElasticaBundle: * [Types](types.md) Cookbook Entries +---------------- * [Custom Repositories](cookbook/custom-repositories.md) -* [Suppressing server errors](cookbook/suppress-server-errors.md) \ No newline at end of file +* [HTTP Headers for Elastica](cookbook/elastica-client-http-headers.md) +* Performance - [Logging](cookbook/logging.md) +* [Suppressing server errors](cookbook/suppress-server-errors.md) diff --git a/Resources/doc/setup.md b/Resources/doc/setup.md index 7ae4018..e60c372 100644 --- a/Resources/doc/setup.md +++ b/Resources/doc/setup.md @@ -38,7 +38,7 @@ C) Basic Bundle Configuration ----------------------------- The basic minimal configuration for FOSElasticaBundle is one client with one Elasticsearch -index. In almost all cases, an application will only need a single index. An index can +index. In almost all cases, an application will only need a single index. An index can be considered comparable to a Doctrine Entity Manager, where the index will hold multiple type definitions. @@ -51,7 +51,7 @@ fos_elastica: search: ~ ``` -In this example, an Elastica index (an instance of `Elastica\Index`) is available as a +In this example, an Elastica index (an instance of `Elastica\Index`) is available as a service with the key `fos_elastica.index.search`. If the Elasticsearch index name needs to be different to the service name in your @@ -71,7 +71,7 @@ index of search_dev. D) Defining index types ----------------------- -By default, FOSElasticaBundle requires each type that is to be indexed to be mapped. +By default, FOSElasticaBundle requires each type that is to be indexed to be mapped. It is possible to use a serializer to avoid this requirement. To use a serializer, see the [serializer documentation](serializer.md) @@ -95,12 +95,10 @@ Each defined type is made available as a service, and in this case the service k `fos_elastica.index.search.user` and is an instance of `Elastica\Type`. FOSElasticaBundle requires a provider for each type that will notify when an object -that maps to a type has been modified. The bundle ships with support for Doctrine and +that maps to a type has been modified. The bundle ships with support for Doctrine and Propel objects. -Below is an example for the Doctrine ORM. For additional information regarding -integration with Doctrine or Propel or how to create a custom provider, see -[type-providers.md]. +Below is an example for the Doctrine ORM. ```yaml user: @@ -118,6 +116,7 @@ integration with Doctrine or Propel or how to create a custom provider, see provider: ~ listener: ~ finder: ~ + immediate: ~ ``` There are a significant number of options available for types, that can be @@ -127,7 +126,7 @@ E) Populating the Elasticsearch index ------------------------------------- When using the providers and listeners that come with the bundle, any new or modified -object will be indexed automatically. In some cases, where the database is modified +object will be indexed automatically. In some cases, where the database is modified externally, the Elasticsearch index must be updated manually. This can be achieved by running the console command: diff --git a/Resources/doc/types.md b/Resources/doc/types.md index a66971f..38fa045 100644 --- a/Resources/doc/types.md +++ b/Resources/doc/types.md @@ -261,4 +261,18 @@ As you might expect, new entities will only be indexed if the callback_class ret index depending on whether the callback_class returns `true` or `false`, respectively. The delete listener disregards the callback_class. -> **Propel** doesn't support this feature yet. \ No newline at end of file +> **Propel** doesn't support this feature yet. + +Flushing Method +--------------- + +FOSElasticaBundle, since 3.0.0 performs its indexing in the postFlush Doctrine event +instead of prePersist and preUpdate which means that indexing will only occur when there +has been a successful flush. This new default makes more sense but in the instance where +you want to perform indexing before the flush is confirmed you may set the `immediate` +option on a type persistence configuration to false. + +```yaml + persistence: + immediate: false +``` From e25a5420a59f44ae88ea77d94ca91e02f3a29a9c Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Wed, 26 Mar 2014 12:36:02 +1100 Subject: [PATCH 186/447] Logger enabled with debugging --- DependencyInjection/Configuration.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 5049c7d..348fd74 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -121,7 +121,7 @@ class Configuration implements ConfigurationInterface ->scalarNode('host')->end() ->scalarNode('port')->end() ->scalarNode('logger') - ->defaultValue('fos_elastica.logger') + ->defaultValue('%kernel.debug%') ->treatNullLike('fos_elastica.logger') ->treatTrueLike('fos_elastica.logger') ->end() From 9f27c1dade8b6ceb2d04763cdf5afa0eb708a257 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Wed, 26 Mar 2014 12:36:36 +1100 Subject: [PATCH 187/447] Update changelog --- CHANGELOG-3.0.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG-3.0.md b/CHANGELOG-3.0.md index fd2ecd5..abd05cd 100644 --- a/CHANGELOG-3.0.md +++ b/CHANGELOG-3.0.md @@ -14,6 +14,7 @@ To generate a changelog summary since the last version, run * 3.0.0-ALPHA3 (xxxx-xx-xx) + * a9c4c93: Logger is now only enabled in debug mode by default * #463: allowing hot swappable reindexing * #415: BC BREAK: document indexing occurs in postFlush rather than the pre* events previously. * 7d13823: Dropped (broken) support for Symfony <2.3 From 38b4074745ad5c1a58882523857b0aa8ffd46ad0 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Wed, 26 Mar 2014 12:40:27 +1100 Subject: [PATCH 188/447] Update logger documentation based on configuration change --- Resources/doc/cookbook/logging.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Resources/doc/cookbook/logging.md b/Resources/doc/cookbook/logging.md index b2d2e6c..726e77e 100644 --- a/Resources/doc/cookbook/logging.md +++ b/Resources/doc/cookbook/logging.md @@ -5,8 +5,10 @@ By default, FOSElasticaBundle sets a logger against each Elastica client configu logs all information sent to and received from Elasticsearch. This can lead to large memory usage during population or reindexing of an index. -FOSElasticaBundle provides an option to disable a logger by setting the property on the -client configuration to false: +By default FOSElasticaBundle will only enable a logger when debug mode is enabled, meaning +in a production environment there wont be a logger enabled. To enable a logger anyway, you +can set the logger property of a client configuration to true or a service id of a logging +service you wish to use. ```yaml # app/config/config.yml @@ -14,12 +16,9 @@ fos_elastica: clients: default: host: example.com - logger: false + logger: true ``` -It may be desirable to set this configuration property to `%kernel.debug%`, which would -only switch the logging capabilities of FOSElasticaBundle on when debugging is enabled. - Custom Logger Service --------------------- From a81a6305209df01d43bf32159f6ad4d7334acfea Mon Sep 17 00:00:00 2001 From: Joakim Friberg Date: Thu, 27 Mar 2014 16:33:20 +0100 Subject: [PATCH 189/447] Corrected bundle class name in install instructions --- Resources/doc/setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/doc/setup.md b/Resources/doc/setup.md index e60c372..4ae40af 100644 --- a/Resources/doc/setup.md +++ b/Resources/doc/setup.md @@ -29,7 +29,7 @@ public function registerBundles() { $bundles = array( // ... - new FOS\RestBundle\FOSRestBundle(), + new FOS\ElasticaBundle\FOSElasticaBundle(), ); } ``` From 0de48d2190b03583703c3084a1a8296e4d8cb17b Mon Sep 17 00:00:00 2001 From: nurikabe Date: Sat, 29 Mar 2014 18:36:06 -0400 Subject: [PATCH 190/447] Use identifiers for bulk delete rather than cloning objects --- Doctrine/Listener.php | 41 ++++++++++++++++++++++--- Persister/ObjectPersister.php | 10 ++++++ Persister/ObjectPersisterInterface.php | 7 +++++ Tests/Doctrine/AbstractListenerTest.php | 23 ++++++-------- 4 files changed, 63 insertions(+), 18 deletions(-) diff --git a/Doctrine/Listener.php b/Doctrine/Listener.php index 43ac744..b6217a6 100644 --- a/Doctrine/Listener.php +++ b/Doctrine/Listener.php @@ -9,7 +9,12 @@ use FOS\ElasticaBundle\Persister\ObjectPersister; use Symfony\Component\ExpressionLanguage\Expression; use Symfony\Component\ExpressionLanguage\ExpressionLanguage; use Symfony\Component\ExpressionLanguage\SyntaxError; +use Symfony\Component\PropertyAccess\PropertyAccess; +/** + * Automatically update ElasticSearch based on changes to the Doctrine source + * data. One listener is generated for each Doctrine entity / ElasticSearch type. + */ class Listener implements EventSubscriber { /** @@ -48,10 +53,14 @@ class Listener implements EventSubscriber protected $isIndexableCallback; /** - * Objects scheduled for insertion, replacement, or removal + * Objects scheduled for insertion and replacement */ public $scheduledForInsertion = array(); public $scheduledForUpdate = array(); + + /** + * IDs of objects scheduled for removal + */ public $scheduledForDeletion = array(); /** @@ -61,6 +70,13 @@ class Listener implements EventSubscriber */ protected $expressionLanguage; + /** + * PropertyAccessor instance + * + * @var PropertyAccessorInterface + */ + protected $propertyAccessor; + /** * Constructor. * @@ -75,6 +91,8 @@ class Listener implements EventSubscriber $this->objectClass = $objectClass; $this->events = $events; $this->esIdentifierField = $esIdentifierField; + + $this->propertyAccessor = PropertyAccess::createPropertyAccessor(); } /** @@ -195,20 +213,21 @@ class Listener implements EventSubscriber $this->scheduledForUpdate[] = $entity; } else { // Delete if no longer indexable - $this->scheduledForDeletion[] = clone $entity; + $this->scheduleForDeletion($entity); } } } /** - * Delete objects preRemove instead of postRemove so that we have access to the id + * Delete objects preRemove instead of postRemove so that we have access to the id. Because this is called + * preRemove, first check that the entity is managed by Doctrine */ public function preRemove(EventArgs $eventArgs) { $entity = $eventArgs->getEntity(); if ($entity instanceof $this->objectClass) { - $this->scheduledForDeletion[] = clone $entity; + $this->scheduleForDeletion($entity); } } @@ -224,7 +243,7 @@ class Listener implements EventSubscriber $this->objectPersister->replaceMany($this->scheduledForUpdate); } if (count($this->scheduledForDeletion)) { - $this->objectPersister->deleteMany($this->scheduledForDeletion); + $this->objectPersister->deleteManyByIdentifiers($this->scheduledForDeletion); } } @@ -245,4 +264,16 @@ class Listener implements EventSubscriber { $this->persistScheduled(); } + + /** + * Record the specified identifier to delete. Do not need to entire object. + * @param mixed $object + * @return mixed + */ + protected function scheduleForDeletion($object) + { + if ($identifierValue = $this->propertyAccessor->getValue($object, $this->esIdentifierField)) { + $this->scheduledForDeletion[] = $identifierValue; + } + } } diff --git a/Persister/ObjectPersister.php b/Persister/ObjectPersister.php index 3592a78..64cf5db 100644 --- a/Persister/ObjectPersister.php +++ b/Persister/ObjectPersister.php @@ -126,6 +126,16 @@ class ObjectPersister implements ObjectPersisterInterface $this->type->deleteDocuments($documents); } + /** + * Bulk deletes records from an array of identifiers + * + * @param array $identifiers array of domain model object identifiers + */ + public function deleteManyByIdentifiers(array $identifiers) + { + $this->type->getIndex()->getClient()->deleteIds($identifiers, $this->type->getIndex(), $this->type); + } + /** * Transforms an object to an elastica document * diff --git a/Persister/ObjectPersisterInterface.php b/Persister/ObjectPersisterInterface.php index a25aafc..2b4c8ee 100644 --- a/Persister/ObjectPersisterInterface.php +++ b/Persister/ObjectPersisterInterface.php @@ -61,4 +61,11 @@ interface ObjectPersisterInterface * @param array $objects array of domain model objects */ function deleteMany(array $objects); + + /** + * Bulk deletes records from an array of identifiers + * + * @param array $identifiers array of domain model object identifiers + */ + public function deleteManyByIdentifiers(array $identifiers); } diff --git a/Tests/Doctrine/AbstractListenerTest.php b/Tests/Doctrine/AbstractListenerTest.php index 8e49f24..ee657f1 100644 --- a/Tests/Doctrine/AbstractListenerTest.php +++ b/Tests/Doctrine/AbstractListenerTest.php @@ -100,13 +100,13 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase $listener->postUpdate($eventArgs); $this->assertEmpty($listener->scheduledForUpdate); - $this->assertEquals($entity, current($listener->scheduledForDeletion)); + $this->assertEquals($entity->getId(), current($listener->scheduledForDeletion)); $persister->expects($this->never()) ->method('replaceOne'); $persister->expects($this->once()) - ->method('deleteMany') - ->with(array($entity)); + ->method('deleteManyByIdentifiers') + ->with(array($entity->getId())); $listener->postFlush($eventArgs); } @@ -133,13 +133,11 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase $listener = $this->createListener($persister, get_class($entity), array()); $listener->preRemove($eventArgs); - $scheduledClone = current($listener->scheduledForDeletion); - $this->assertEquals($entity, $scheduledClone); - $this->assertNotSame($entity, $scheduledClone); + $this->assertEquals($entity->getId(), current($listener->scheduledForDeletion)); $persister->expects($this->once()) - ->method('deleteMany') - ->with(array($entity)); + ->method('deleteManyByIdentifiers') + ->with(array($entity->getId())); $listener->postFlush($eventArgs); } @@ -151,6 +149,7 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase $persister = $this->getMockPersister(); $entity = new Listener\Entity(1); + $entity->identifier = 'foo'; $eventArgs = $this->createLifecycleEventArgs($entity, $objectManager); $objectManager->expects($this->any()) @@ -166,13 +165,11 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase $listener = $this->createListener($persister, get_class($entity), array(), 'identifier'); $listener->preRemove($eventArgs); - $scheduledClone = current($listener->scheduledForDeletion); - $this->assertEquals($entity, $scheduledClone); - $this->assertNotSame($entity, $scheduledClone); + $this->assertEquals($entity->identifier, current($listener->scheduledForDeletion)); $persister->expects($this->once()) - ->method('deleteMany') - ->with(array($entity)); + ->method('deleteManyByIdentifiers') + ->with(array($entity->identifier)); $listener->postFlush($eventArgs); } From f15ca028596a9226fcff636138533a1a39f39ce5 Mon Sep 17 00:00:00 2001 From: Joseph Bielawski Date: Mon, 31 Mar 2014 11:59:37 +0200 Subject: [PATCH 191/447] Fix documentation for client overwriting. --- .../doc/cookbook/suppress-server-errors.md | 33 +++++++++++++++---- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/Resources/doc/cookbook/suppress-server-errors.md b/Resources/doc/cookbook/suppress-server-errors.md index aa74276..d89ffd6 100644 --- a/Resources/doc/cookbook/suppress-server-errors.md +++ b/Resources/doc/cookbook/suppress-server-errors.md @@ -1,5 +1,5 @@ Suppressing Server Errors -======================== +========================= By default, exceptions from the Elastica client library will propagate through the bundle's Client class. For instance, if the Elasticsearch server is offline, @@ -12,25 +12,44 @@ container parameter with a custom class. In the following example, we override the `Client::request()` method and return the equivalent of an empty search response if an exception occurred. -``` +Sample client code: +------------------- + +```php + + + + + Acme\ElasticaBundle\Client + + + From 588c4e2d025bea489547dcc2e0bc068f4d97919e Mon Sep 17 00:00:00 2001 From: Joris van de Sande Date: Mon, 31 Mar 2014 12:52:29 +0200 Subject: [PATCH 192/447] Unset nested "fields" for deeper nested configs too --- DependencyInjection/Configuration.php | 4 ++++ Tests/DependencyInjection/ConfigurationTest.php | 16 +++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 348fd74..e77919c 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -458,6 +458,10 @@ class Configuration implements ConfigurationInterface ->arrayNode($property) ->useAttributeAsKey('name') ->prototype('array') + ->validate() + ->ifTrue(function($v) { return isset($v['fields']) && empty($v['fields']); }) + ->then(function($v) { unset($v['fields']); return $v; }) + ->end() ->treatNullLike(array()) ->addDefaultsIfNotSet() ->children(); diff --git a/Tests/DependencyInjection/ConfigurationTest.php b/Tests/DependencyInjection/ConfigurationTest.php index 93143ec..5919ea7 100644 --- a/Tests/DependencyInjection/ConfigurationTest.php +++ b/Tests/DependencyInjection/ConfigurationTest.php @@ -118,7 +118,19 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase 'autocomplete' => null ) ), - 'content' => null + 'content' => null, + 'children' => array( + 'type' => 'nested', + 'properties' => array( + 'title' => array( + 'type' => 'string', + 'fields' => array( + 'autocomplete' => null + ) + ), + 'content' => null + ) + ) ) ) ) @@ -132,5 +144,7 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase $this->assertArrayNotHasKey('fields', $configuration['indexes']['test']['types']['test']['mappings']['content']); $this->assertArrayHasKey('fields', $configuration['indexes']['test']['types']['test']['mappings']['title']); + $this->assertArrayNotHasKey('fields', $configuration['indexes']['test']['types']['test']['mappings']['children']['properties']['content']); + $this->assertArrayHasKey('fields', $configuration['indexes']['test']['types']['test']['mappings']['children']['properties']['title']); } } From 20810fa4150e1c739ad2c848d81af61b738e76e0 Mon Sep 17 00:00:00 2001 From: baggachipz Date: Mon, 31 Mar 2014 15:16:32 -0400 Subject: [PATCH 193/447] Upsert-type functionality for existing ORM Entities This is an attempt to fix the issue: https://github.com/FriendsOfSymfony/FOSElasticaBundle/issues/526 It will cause a significant slowdown in a large batch, but it appears to be the only way to prevent an exception from bubbling up during a normal use case. --- Persister/ObjectPersister.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Persister/ObjectPersister.php b/Persister/ObjectPersister.php index 3592a78..aa20561 100644 --- a/Persister/ObjectPersister.php +++ b/Persister/ObjectPersister.php @@ -107,7 +107,15 @@ class ObjectPersister implements ObjectPersisterInterface { $documents = array(); foreach ($objects as $object) { - $documents[] = $this->transformToElasticaDocument($object); + $document = $this->transformToElasticaDocument($object); + + try { + $this->type->getDocument($document->getId()); + } catch (NotFoundException $e) { + $this->type->addDocument($document); + } + + $documents[] = $document; } $this->type->updateDocuments($documents); } @@ -136,4 +144,4 @@ class ObjectPersister implements ObjectPersisterInterface { return $this->transformer->transform($object, $this->fields); } -} \ No newline at end of file +} From a89856be504b0d87808b188f6cddcc6b0a427887 Mon Sep 17 00:00:00 2001 From: nurikabe Date: Wed, 2 Apr 2014 07:18:46 -0400 Subject: [PATCH 194/447] Reset / create new index even if the index doesn't exist --- Command/PopulateCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Command/PopulateCommand.php b/Command/PopulateCommand.php index 98834c7..af5fd5d 100644 --- a/Command/PopulateCommand.php +++ b/Command/PopulateCommand.php @@ -109,7 +109,7 @@ class PopulateCommand extends ContainerAwareCommand */ private function populateIndex(OutputInterface $output, $index, $reset, $options) { - if ($reset && $this->indexManager->getIndex($index)->exists()) { + if ($reset) { $output->writeln(sprintf('Resetting %s', $index)); $this->resetter->resetIndex($index); } From 1628413e65bcfc4457f8f627de8b836964d1512c Mon Sep 17 00:00:00 2001 From: Josh Worden Date: Wed, 2 Apr 2014 10:06:24 -0500 Subject: [PATCH 195/447] Added support for getting documents in unified Doctrine Listener --- Doctrine/Listener.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Doctrine/Listener.php b/Doctrine/Listener.php index b6217a6..47c3c9a 100644 --- a/Doctrine/Listener.php +++ b/Doctrine/Listener.php @@ -197,7 +197,7 @@ class Listener implements EventSubscriber public function postPersist(EventArgs $eventArgs) { - $entity = $eventArgs->getEntity(); + $entity = (method_exists($eventArgs, 'getEntity')) ? $eventArgs->getEntity() : $eventArgs->getDocument(); if ($entity instanceof $this->objectClass && $this->isObjectIndexable($entity)) { $this->scheduledForInsertion[] = $entity; @@ -206,7 +206,7 @@ class Listener implements EventSubscriber public function postUpdate(EventArgs $eventArgs) { - $entity = $eventArgs->getEntity(); + $entity = (method_exists($eventArgs, 'getEntity')) ? $eventArgs->getEntity() : $eventArgs->getDocument(); if ($entity instanceof $this->objectClass) { if ($this->isObjectIndexable($entity)) { @@ -224,7 +224,7 @@ class Listener implements EventSubscriber */ public function preRemove(EventArgs $eventArgs) { - $entity = $eventArgs->getEntity(); + $entity = (method_exists($eventArgs, 'getEntity')) ? $eventArgs->getEntity() : $eventArgs->getDocument(); if ($entity instanceof $this->objectClass) { $this->scheduleForDeletion($entity); From e74acb1e4fd577a4aa51e166e0f2b9e2e9f06db4 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 3 Apr 2014 08:00:52 +1100 Subject: [PATCH 196/447] Revert "Avoid index reset error in case of unexistant index" This reverts commit a121a777743525f46c65dc29d983c8eb92720664. --- Command/PopulateCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Command/PopulateCommand.php b/Command/PopulateCommand.php index 98834c7..af5fd5d 100644 --- a/Command/PopulateCommand.php +++ b/Command/PopulateCommand.php @@ -109,7 +109,7 @@ class PopulateCommand extends ContainerAwareCommand */ private function populateIndex(OutputInterface $output, $index, $reset, $options) { - if ($reset && $this->indexManager->getIndex($index)->exists()) { + if ($reset) { $output->writeln(sprintf('Resetting %s', $index)); $this->resetter->resetIndex($index); } From 13c2d10e399317af9b9aa24d55b382befb3830cf Mon Sep 17 00:00:00 2001 From: Patrick Zahnd Date: Fri, 13 Sep 2013 15:34:59 +0200 Subject: [PATCH 197/447] Added knp paginator sort functionality to PaginateElasticaQuerySubscriber --- Paginator/RawPaginatorAdapter.php | 10 +++++ Resources/config/config.xml | 3 ++ .../PaginateElasticaQuerySubscriber.php | 43 +++++++++++++++++++ 3 files changed, 56 insertions(+) diff --git a/Paginator/RawPaginatorAdapter.php b/Paginator/RawPaginatorAdapter.php index 8bd4ee2..9136bc0 100644 --- a/Paginator/RawPaginatorAdapter.php +++ b/Paginator/RawPaginatorAdapter.php @@ -126,4 +126,14 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface return $this->facets; } + + /** + * Returns the Query + * + * @return Query the search query + */ + public function getQuery() + { + return $this->query; + } } diff --git a/Resources/config/config.xml b/Resources/config/config.xml index 4419b4a..b9da716 100644 --- a/Resources/config/config.xml +++ b/Resources/config/config.xml @@ -86,6 +86,9 @@ + + + diff --git a/Subscriber/PaginateElasticaQuerySubscriber.php b/Subscriber/PaginateElasticaQuerySubscriber.php index cbe508d..fc775c7 100644 --- a/Subscriber/PaginateElasticaQuerySubscriber.php +++ b/Subscriber/PaginateElasticaQuerySubscriber.php @@ -9,9 +9,20 @@ use FOS\ElasticaBundle\Paginator\PartialResultsInterface; class PaginateElasticaQuerySubscriber implements EventSubscriberInterface { + private $container; + + public function setContainer($container) + { + $this->container = $container; + } + public function items(ItemsEvent $event) { if ($event->target instanceof PaginatorAdapterInterface) { + + // Add sort to query + $this->addPagingSort($event); + /** @var $results PartialResultsInterface */ $results = $event->target->getResults($event->getOffset(), $event->getLimit()); @@ -26,6 +37,38 @@ class PaginateElasticaQuerySubscriber implements EventSubscriberInterface } } + /** + * Adds knp paging sort to query + * + * @param ItemsEvent $event + * @return void + */ + protected function addPagingSort(ItemsEvent $event) + { + $request = $this->container->get('request'); + $options = $event->options; + $sortField = $request->get($options['sortFieldParameterName']); + + if (!empty($sortField)) { + // determine sort direction + $dir = 'asc'; + $sortDirection = $request->get($options['sortDirectionParameterName']); + if ('desc' === strtolower($sortDirection)) { + $dir = 'desc'; + } + + // check if the requested sort field is in the sort whitelist + if (isset($options['sortFieldWhitelist']) && !in_array($sortField, $options['sortFieldWhitelist'])) { + throw new \UnexpectedValueException(sprintf('Cannot sort by: [%s] this field is not in whitelist', $sortField)); + } + + // set sort on active query + $event->target->getQuery()->setSort(array( + $sortField => array('order' => $dir), + )); + } + } + public static function getSubscribedEvents() { return array( From 1bc148569baa3b7ad8ac31211e93c629d5fe7cda Mon Sep 17 00:00:00 2001 From: Piotr Antosik Date: Mon, 24 Feb 2014 13:47:26 +0100 Subject: [PATCH 198/447] Added knp paginator sort functionality to PaginateElasticaQuerySubscriber --- Resources/config/config.xml | 6 +++--- .../PaginateElasticaQuerySubscriber.php | 20 +++++++++---------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/Resources/config/config.xml b/Resources/config/config.xml index b9da716..1e49590 100644 --- a/Resources/config/config.xml +++ b/Resources/config/config.xml @@ -85,10 +85,10 @@ - - - + + + diff --git a/Subscriber/PaginateElasticaQuerySubscriber.php b/Subscriber/PaginateElasticaQuerySubscriber.php index fc775c7..0b7cfd6 100644 --- a/Subscriber/PaginateElasticaQuerySubscriber.php +++ b/Subscriber/PaginateElasticaQuerySubscriber.php @@ -2,6 +2,7 @@ namespace FOS\ElasticaBundle\Subscriber; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Knp\Component\Pager\Event\ItemsEvent; use FOS\ElasticaBundle\Paginator\PaginatorAdapterInterface; @@ -9,19 +10,18 @@ use FOS\ElasticaBundle\Paginator\PartialResultsInterface; class PaginateElasticaQuerySubscriber implements EventSubscriberInterface { - private $container; + private $request; - public function setContainer($container) + public function setRequest(Request $request = null) { - $this->container = $container; + $this->request = $request; } public function items(ItemsEvent $event) { if ($event->target instanceof PaginatorAdapterInterface) { - // Add sort to query - $this->addPagingSort($event); + $this->setSorting($event); /** @var $results PartialResultsInterface */ $results = $event->target->getResults($event->getOffset(), $event->getLimit()); @@ -40,19 +40,17 @@ class PaginateElasticaQuerySubscriber implements EventSubscriberInterface /** * Adds knp paging sort to query * - * @param ItemsEvent $event - * @return void + * @param ItemsEvent $event */ - protected function addPagingSort(ItemsEvent $event) + protected function setSorting(ItemsEvent $event) { - $request = $this->container->get('request'); $options = $event->options; - $sortField = $request->get($options['sortFieldParameterName']); + $sortField = $this->request->get($options['sortFieldParameterName']); if (!empty($sortField)) { // determine sort direction $dir = 'asc'; - $sortDirection = $request->get($options['sortDirectionParameterName']); + $sortDirection = $this->request->get($options['sortDirectionParameterName']); if ('desc' === strtolower($sortDirection)) { $dir = 'desc'; } From b6e2583455e9397b45e25167f527351458e6c410 Mon Sep 17 00:00:00 2001 From: Josh Worden Date: Fri, 4 Apr 2014 10:47:50 -0500 Subject: [PATCH 199/447] Added getDoctrineObject method to retrieve an entity or document from a LifecycleEventArgs instance in the unified Listener class --- Doctrine/Listener.php | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/Doctrine/Listener.php b/Doctrine/Listener.php index 47c3c9a..ad5641e 100644 --- a/Doctrine/Listener.php +++ b/Doctrine/Listener.php @@ -179,6 +179,34 @@ class Listener implements EventSubscriber return strtolower($ref->getShortName()); } + /** + * Provides unified method for retrieving a doctrine object from an EventArgs instance + * + * @param EventArgs $eventArgs + * @return object Entity | Document + * @throws \RuntimeException if no valid getter is found. + */ + private function getDoctrineObject(EventArgs $eventArgs) + { + + if (method_exists($eventArgs, 'getObject')) { + + return $eventArgs->getObject(); + + } elseif (method_exists($eventArgs, 'getEntity')) { + + return $eventArgs->getEntity(); + + } elseif (method_exists($eventArgs, 'getDocument')) { + + return $eventArgs->getDocument(); + + } + + throw new \RuntimeException('Unable to retrieve object from EventArgs.'); + + } + /** * @return bool|ExpressionLanguage */ @@ -197,7 +225,7 @@ class Listener implements EventSubscriber public function postPersist(EventArgs $eventArgs) { - $entity = (method_exists($eventArgs, 'getEntity')) ? $eventArgs->getEntity() : $eventArgs->getDocument(); + $entity = $this->getDoctrineObject($eventArgs); if ($entity instanceof $this->objectClass && $this->isObjectIndexable($entity)) { $this->scheduledForInsertion[] = $entity; @@ -206,7 +234,7 @@ class Listener implements EventSubscriber public function postUpdate(EventArgs $eventArgs) { - $entity = (method_exists($eventArgs, 'getEntity')) ? $eventArgs->getEntity() : $eventArgs->getDocument(); + $entity = $this->getDoctrineObject($eventArgs); if ($entity instanceof $this->objectClass) { if ($this->isObjectIndexable($entity)) { @@ -224,7 +252,7 @@ class Listener implements EventSubscriber */ public function preRemove(EventArgs $eventArgs) { - $entity = (method_exists($eventArgs, 'getEntity')) ? $eventArgs->getEntity() : $eventArgs->getDocument(); + $entity = $this->getDoctrineObject($eventArgs); if ($entity instanceof $this->objectClass) { $this->scheduleForDeletion($entity); From 6f444f1ce84cf85f51e801ffd70387211238aeba Mon Sep 17 00:00:00 2001 From: Evan Owens Date: Fri, 4 Apr 2014 15:51:55 -0400 Subject: [PATCH 200/447] Bulk upsert --- Persister/ObjectPersister.php | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/Persister/ObjectPersister.php b/Persister/ObjectPersister.php index e1c086d..38541c8 100644 --- a/Persister/ObjectPersister.php +++ b/Persister/ObjectPersister.php @@ -99,7 +99,7 @@ class ObjectPersister implements ObjectPersisterInterface } /** - * Bulk updates an array of objects in the type + * Bulk update an array of objects in the type. Create document if it does not already exist. * * @param array $objects array of domain model objects */ @@ -108,13 +108,7 @@ class ObjectPersister implements ObjectPersisterInterface $documents = array(); foreach ($objects as $object) { $document = $this->transformToElasticaDocument($object); - - try { - $this->type->getDocument($document->getId()); - } catch (NotFoundException $e) { - $this->type->addDocument($document); - } - + $document->setDocAsUpsert(true); $documents[] = $document; } $this->type->updateDocuments($documents); From 10f6149f8cff0e1162e2eb3c6c5181176fcd604d Mon Sep 17 00:00:00 2001 From: Evan Owens Date: Sat, 5 Apr 2014 07:04:52 +1000 Subject: [PATCH 201/447] Remove rogue paren --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8267e57..7909d2b 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Documentation Documentation for FOSElasticaBundle is in `Resources/doc/index.md` -[Read the documentation for 3.0.x (master))](https://github.com/FriendsOfSymfony/FOSElasticaBundle/blob/master/Resources/doc/index.md) +[Read the documentation for 3.0.x (master)](https://github.com/FriendsOfSymfony/FOSElasticaBundle/blob/master/Resources/doc/index.md) [Read the documentation for 2.1.x](https://github.com/FriendsOfSymfony/FOSElasticaBundle/blob/2.1.x/README.md) From 377b2843baf6f80f4c10f6aaa0f4b3a8b7f7c79c Mon Sep 17 00:00:00 2001 From: Evan Owens Date: Sat, 5 Apr 2014 07:12:16 +1000 Subject: [PATCH 202/447] Fix documentation about `immediate` Unless I misimplemented this, "immediate" means persist to ElasticSearch "immediately"; before flushing. Default behavior is false; persist to ElasticSearch postFlush. --- Resources/doc/types.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Resources/doc/types.md b/Resources/doc/types.md index 38fa045..e01b5ae 100644 --- a/Resources/doc/types.md +++ b/Resources/doc/types.md @@ -270,9 +270,9 @@ FOSElasticaBundle, since 3.0.0 performs its indexing in the postFlush Doctrine e instead of prePersist and preUpdate which means that indexing will only occur when there has been a successful flush. This new default makes more sense but in the instance where you want to perform indexing before the flush is confirmed you may set the `immediate` -option on a type persistence configuration to false. +option on a type persistence configuration to `true`. ```yaml persistence: - immediate: false + immediate: true ``` From 53332eb057b79ec75b94bf56c6281969cfff203b Mon Sep 17 00:00:00 2001 From: Evan Owens Date: Fri, 4 Apr 2014 18:32:48 -0400 Subject: [PATCH 203/447] Allow for catching/logging persistance errors per listener --- DependencyInjection/Configuration.php | 3 ++ DependencyInjection/FOSElasticaExtension.php | 6 ++- Doctrine/Listener.php | 7 +++- Persister/ObjectPersister.php | 42 +++++++++++++++++--- Resources/doc/types.md | 18 ++++++++- 5 files changed, 68 insertions(+), 8 deletions(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index e77919c..002c78e 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -289,6 +289,9 @@ class Configuration implements ConfigurationInterface ->scalarNode('update')->defaultTrue()->end() ->scalarNode('delete')->defaultTrue()->end() ->booleanNode('immediate')->defaultFalse()->end() + ->scalarNode('logger') + ->treatTrueLike('fos_elastica.logger') + ->end() ->scalarNode('service')->end() ->variableNode('is_indexable_callback')->defaultNull()->end() ->end() diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 1d1540f..7511e2b 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -432,8 +432,12 @@ class FOSElasticaExtension extends Extension $listenerDef = new DefinitionDecorator($abstractListenerId); $listenerDef->replaceArgument(0, new Reference($objectPersisterId)); $listenerDef->replaceArgument(1, $typeConfig['model']); - $listenerDef->replaceArgument(3, $typeConfig['identifier']); $listenerDef->replaceArgument(2, $this->getDoctrineEvents($typeConfig)); + $listenerDef->replaceArgument(3, $typeConfig['identifier']); + if (isset($typeConfig['listener']['logger'])) { + $listenerDef->replaceArgument(4, new Reference($typeConfig['listener']['logger'])); + } + switch ($typeConfig['driver']) { case 'orm': $listenerDef->addTag('doctrine.event_subscriber'); break; case 'mongodb': $listenerDef->addTag('doctrine_mongodb.odm.event_subscriber'); break; diff --git a/Doctrine/Listener.php b/Doctrine/Listener.php index b6217a6..ded3998 100644 --- a/Doctrine/Listener.php +++ b/Doctrine/Listener.php @@ -2,6 +2,7 @@ namespace FOS\ElasticaBundle\Doctrine; +use Psr\Log\LoggerInterface; use Doctrine\Common\EventArgs; use Doctrine\Common\EventSubscriber; use FOS\ElasticaBundle\Persister\ObjectPersisterInterface; @@ -85,13 +86,17 @@ class Listener implements EventSubscriber * @param array $events * @param string $esIdentifierField */ - public function __construct(ObjectPersisterInterface $objectPersister, $objectClass, array $events, $esIdentifierField = 'id') + public function __construct(ObjectPersisterInterface $objectPersister, $objectClass, array $events, $esIdentifierField = 'id', $logger = null) { $this->objectPersister = $objectPersister; $this->objectClass = $objectClass; $this->events = $events; $this->esIdentifierField = $esIdentifierField; + if ($logger) { + $this->objectPersister->setLogger($logger); + } + $this->propertyAccessor = PropertyAccess::createPropertyAccessor(); } diff --git a/Persister/ObjectPersister.php b/Persister/ObjectPersister.php index 38541c8..cea6167 100644 --- a/Persister/ObjectPersister.php +++ b/Persister/ObjectPersister.php @@ -2,6 +2,8 @@ namespace FOS\ElasticaBundle\Persister; +use Psr\Log\LoggerInterface; +use Elastica\Exception\BulkException; use Elastica\Exception\NotFoundException; use FOS\ElasticaBundle\Transformer\ModelToElasticaTransformerInterface; use Elastica\Type; @@ -19,6 +21,7 @@ class ObjectPersister implements ObjectPersisterInterface protected $transformer; protected $objectClass; protected $fields; + protected $logger; public function __construct(Type $type, ModelToElasticaTransformerInterface $transformer, $objectClass, array $fields) { @@ -28,6 +31,18 @@ class ObjectPersister implements ObjectPersisterInterface $this->fields = $fields; } + public function setLogger(LoggerInterface $logger) + { + $this->logger = $logger; + } + + private function log(BulkException $e) + { + if ($this->logger) { + $this->logger->error($e); + } + } + /** * Insert one object into the type * The object will be transformed to an elastica document @@ -95,7 +110,11 @@ class ObjectPersister implements ObjectPersisterInterface foreach ($objects as $object) { $documents[] = $this->transformToElasticaDocument($object); } - $this->type->addDocuments($documents); + try { + $this->type->addDocuments($documents); + } catch (BulkException $e) { + $this->log($e); + } } /** @@ -111,7 +130,12 @@ class ObjectPersister implements ObjectPersisterInterface $document->setDocAsUpsert(true); $documents[] = $document; } - $this->type->updateDocuments($documents); + + try { + $this->type->updateDocuments($documents); + } catch (BulkException $e) { + $this->log($e); + } } /** @@ -125,7 +149,11 @@ class ObjectPersister implements ObjectPersisterInterface foreach ($objects as $object) { $documents[] = $this->transformToElasticaDocument($object); } - $this->type->deleteDocuments($documents); + try { + $this->type->deleteDocuments($documents); + } catch (BulkException $e) { + $this->log($e); + } } /** @@ -135,7 +163,11 @@ class ObjectPersister implements ObjectPersisterInterface */ public function deleteManyByIdentifiers(array $identifiers) { - $this->type->getIndex()->getClient()->deleteIds($identifiers, $this->type->getIndex(), $this->type); + try { + $this->type->getIndex()->getClient()->deleteIds($identifiers, $this->type->getIndex(), $this->type); + } catch (BulkException $e) { + $this->log($e); + } } /** @@ -148,4 +180,4 @@ class ObjectPersister implements ObjectPersisterInterface { return $this->transformer->transform($object, $this->fields); } -} +} \ No newline at end of file diff --git a/Resources/doc/types.md b/Resources/doc/types.md index 38fa045..7e0fe05 100644 --- a/Resources/doc/types.md +++ b/Resources/doc/types.md @@ -274,5 +274,21 @@ option on a type persistence configuration to false. ```yaml persistence: - immediate: false + listener: + is_indexable_callback: "user.isActive() && user.hasRole('ROLE_USER')" ``` + +Logging Errors +-------------- + +By default FOSElasticaBundle will not catch errors thrown by Elastica/ElasticSearch. +Configure a logger per listener if you would rather catch and log these. + +```yaml + persistence: + listener: + logger: true +``` + +Specifying `true` will use the default Elastica logger. Alternatively define your own +logger service id. From a4834716945cf6be391c9a8f24626fc42fe67c9e Mon Sep 17 00:00:00 2001 From: nurikabe Date: Fri, 4 Apr 2014 22:56:47 -0400 Subject: [PATCH 204/447] Set listener loggers to fos_elastica.logger if null --- DependencyInjection/Configuration.php | 1 + Persister/ObjectPersister.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 002c78e..1bdcdcd 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -290,6 +290,7 @@ class Configuration implements ConfigurationInterface ->scalarNode('delete')->defaultTrue()->end() ->booleanNode('immediate')->defaultFalse()->end() ->scalarNode('logger') + ->treatNullLike('fos_elastica.logger') ->treatTrueLike('fos_elastica.logger') ->end() ->scalarNode('service')->end() diff --git a/Persister/ObjectPersister.php b/Persister/ObjectPersister.php index cea6167..98165ef 100644 --- a/Persister/ObjectPersister.php +++ b/Persister/ObjectPersister.php @@ -180,4 +180,4 @@ class ObjectPersister implements ObjectPersisterInterface { return $this->transformer->transform($object, $this->fields); } -} \ No newline at end of file +} From 998c69bfc38328bfe66e9cd263262dc7a34d7274 Mon Sep 17 00:00:00 2001 From: Hugo Henrique Date: Sun, 6 Apr 2014 15:17:02 -0300 Subject: [PATCH 205/447] Update usage.md This link to documentation custom repositories is broken --- Resources/doc/usage.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/doc/usage.md b/Resources/doc/usage.md index 4c962e0..fd6a878 100644 --- a/Resources/doc/usage.md +++ b/Resources/doc/usage.md @@ -101,7 +101,7 @@ $users = $repository->find('bob'); ``` For more information about customising repositories, see the cookbook entry -[Custom Repositories](custom-repositories.md). +[Custom Repositories](cookbook/custom-repositories.md). Using a custom query builder method for transforming results ------------------------------------------------------------ From 22e5a1d4ab1ca8efb3da6ad803268c68cceba491 Mon Sep 17 00:00:00 2001 From: Joshua Worden Date: Mon, 7 Apr 2014 10:58:11 -0500 Subject: [PATCH 206/447] CS fix --- Doctrine/Listener.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Doctrine/Listener.php b/Doctrine/Listener.php index ad5641e..5d89e63 100644 --- a/Doctrine/Listener.php +++ b/Doctrine/Listener.php @@ -190,17 +190,11 @@ class Listener implements EventSubscriber { if (method_exists($eventArgs, 'getObject')) { - return $eventArgs->getObject(); - } elseif (method_exists($eventArgs, 'getEntity')) { - return $eventArgs->getEntity(); - } elseif (method_exists($eventArgs, 'getDocument')) { - return $eventArgs->getDocument(); - } throw new \RuntimeException('Unable to retrieve object from EventArgs.'); From f07e55417d4fb679b616fa5c9208ac36278c0629 Mon Sep 17 00:00:00 2001 From: nurikabe Date: Mon, 7 Apr 2014 16:16:37 -0400 Subject: [PATCH 207/447] Re-throw exception if no logger defined --- Persister/ObjectPersister.php | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Persister/ObjectPersister.php b/Persister/ObjectPersister.php index 98165ef..c279ec7 100644 --- a/Persister/ObjectPersister.php +++ b/Persister/ObjectPersister.php @@ -36,11 +36,20 @@ class ObjectPersister implements ObjectPersisterInterface $this->logger = $logger; } + /** + * Log exception if logger defined for persister belonging to the current listener, otherwise re-throw + * + * @param BulkException $e + * @throws BulkException + * @return null + */ private function log(BulkException $e) { - if ($this->logger) { - $this->logger->error($e); + if (! $this->logger) { + throw $e; } + + $this->logger->error($e); } /** From b3fdf7b256bc66f27fef1d6e851411a8755f199c Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 10 Apr 2014 13:05:23 +1000 Subject: [PATCH 208/447] Logger for a listener is false by default --- DependencyInjection/Configuration.php | 1 + 1 file changed, 1 insertion(+) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 1bdcdcd..b0a7b59 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -290,6 +290,7 @@ class Configuration implements ConfigurationInterface ->scalarNode('delete')->defaultTrue()->end() ->booleanNode('immediate')->defaultFalse()->end() ->scalarNode('logger') + ->defaultFalse() ->treatNullLike('fos_elastica.logger') ->treatTrueLike('fos_elastica.logger') ->end() From 1bc085141b5a5e368b09a57245a40883815351e7 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 10 Apr 2014 13:14:03 +1000 Subject: [PATCH 209/447] Fix logger option for listeners --- DependencyInjection/FOSElasticaExtension.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 7511e2b..51cb94f 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -208,7 +208,7 @@ class FOSElasticaExtension extends Extension } $callbackClassImplementedInterfaces = class_implements($this->serializerConfig['callback_class']); // PHP < 5.4 friendly if (isset($callbackClassImplementedInterfaces['Symfony\Component\DependencyInjection\ContainerAwareInterface'])) { - $callbackDef->addMethodCall('setContainer', array(new Reference('service_container'))); + $callbackDef->addMethodCall('setContainer', array(new Reference('service_container'))); } $container->setDefinition($callbackId, $callbackDef); @@ -434,7 +434,7 @@ class FOSElasticaExtension extends Extension $listenerDef->replaceArgument(1, $typeConfig['model']); $listenerDef->replaceArgument(2, $this->getDoctrineEvents($typeConfig)); $listenerDef->replaceArgument(3, $typeConfig['identifier']); - if (isset($typeConfig['listener']['logger'])) { + if ($typeConfig['listener']['logger']) { $listenerDef->replaceArgument(4, new Reference($typeConfig['listener']['logger'])); } From 088452cf8895f1ee2776f03abff470d434bac4e3 Mon Sep 17 00:00:00 2001 From: Dylan Schoenmakers Date: Thu, 3 Apr 2014 18:50:03 +0900 Subject: [PATCH 210/447] Added example to usage.md Added example for using a custom query builder method to usage.md. --- Resources/doc/usage.md | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/Resources/doc/usage.md b/Resources/doc/usage.md index 4c962e0..89120e2 100644 --- a/Resources/doc/usage.md +++ b/Resources/doc/usage.md @@ -112,11 +112,35 @@ circumstances this is not ideal and you'd prefer to use a different method to jo any entity relations that are required on the page that will be displaying the results. ```yaml - user: + user: + persistence: elastica_to_model_transformer: query_builder_method: createSearchQueryBuilder ``` +An example for using a custom query builder method: + +```php +class UserRepository extends EntityRepository +{ + /** + * Used by Elastica to transform results to model + * + * @param string $entityAlias + * @return Doctrine\ORM\QueryBuilder + */ + public function createSearchQueryBuilder($entityAlias) + { + $qb = $this->createQueryBuilder($entityAlias); + + $qb->select($entityAlias, 'g') + ->innerJoin($entityAlias.'.groups', 'g'); + + return $qb; + } +} +``` + Advanced Searching Example -------------------------- From 4cfe24ae028e93ad7c5324e7808b577cf766ca5d Mon Sep 17 00:00:00 2001 From: Joshua Worden Date: Thu, 10 Apr 2014 07:38:01 -0500 Subject: [PATCH 211/447] Update CS --- Doctrine/Listener.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/Doctrine/Listener.php b/Doctrine/Listener.php index 5d89e63..2b6df94 100644 --- a/Doctrine/Listener.php +++ b/Doctrine/Listener.php @@ -188,7 +188,6 @@ class Listener implements EventSubscriber */ private function getDoctrineObject(EventArgs $eventArgs) { - if (method_exists($eventArgs, 'getObject')) { return $eventArgs->getObject(); } elseif (method_exists($eventArgs, 'getEntity')) { @@ -198,7 +197,6 @@ class Listener implements EventSubscriber } throw new \RuntimeException('Unable to retrieve object from EventArgs.'); - } /** From 449c33aea3fbb50966157c442908646a69d17051 Mon Sep 17 00:00:00 2001 From: Bob van de Vijver Date: Sat, 12 Apr 2014 13:30:52 +0200 Subject: [PATCH 212/447] Fixes multiple updates on multiple flush executions --- Doctrine/Listener.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Doctrine/Listener.php b/Doctrine/Listener.php index 763ddec..ff9fc60 100644 --- a/Doctrine/Listener.php +++ b/Doctrine/Listener.php @@ -258,17 +258,21 @@ class Listener implements EventSubscriber /** * Persist scheduled objects to ElasticSearch + * After persisting, clear the scheduled queue to prevent multiple data updates when using multiple flush calls */ private function persistScheduled() { if (count($this->scheduledForInsertion)) { $this->objectPersister->insertMany($this->scheduledForInsertion); + $this->scheduledForInsertion = array(); } if (count($this->scheduledForUpdate)) { $this->objectPersister->replaceMany($this->scheduledForUpdate); + $this->scheduledForUpdate = array(); } if (count($this->scheduledForDeletion)) { $this->objectPersister->deleteManyByIdentifiers($this->scheduledForDeletion); + $this->scheduledForDeletion = array(); } } From 165696a5a0372db7634772ca8e1ee9847a4022ea Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Tue, 15 Apr 2014 08:43:11 +1000 Subject: [PATCH 213/447] Bump Elastica requirement --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 8f22393..8dd19b6 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ "symfony/console": "~2.1", "symfony/form": "~2.1", "symfony/property-access": "~2.2", - "ruflin/elastica": ">=0.20, <1.1-dev", + "ruflin/elastica": ">=0.90.2.0, <1.1-dev", "psr/log": "~1.0" }, "require-dev":{ From 4e638a0492896223808c36350ac60f4b35549b48 Mon Sep 17 00:00:00 2001 From: Ahmed Mohamed Date: Wed, 16 Apr 2014 05:27:23 +0200 Subject: [PATCH 214/447] Ensure non-empty properties under fields mappings --- Transformer/ModelToElasticaAutoTransformer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Transformer/ModelToElasticaAutoTransformer.php b/Transformer/ModelToElasticaAutoTransformer.php index 3107d0a..9694a3b 100644 --- a/Transformer/ModelToElasticaAutoTransformer.php +++ b/Transformer/ModelToElasticaAutoTransformer.php @@ -71,7 +71,7 @@ class ModelToElasticaAutoTransformer implements ModelToElasticaTransformerInterf $value = $this->propertyAccessor->getValue($object, $key); - if (isset($mapping['type']) && in_array($mapping['type'], array('nested', 'object')) && isset($mapping['properties'])) { + if (isset($mapping['type']) && in_array($mapping['type'], array('nested', 'object')) && isset($mapping['properties']) && !empty($mapping['properties'])) { /* $value is a nested document or object. Transform $value into * an array of documents, respective the mapped properties. */ From d33f2e547f8a35277f9835a18e137b82892d9627 Mon Sep 17 00:00:00 2001 From: Piotr Antosik Date: Thu, 17 Apr 2014 10:14:53 +0200 Subject: [PATCH 215/447] Fix immediate doc --- Resources/doc/types.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Resources/doc/types.md b/Resources/doc/types.md index 99c3668..e55df5a 100644 --- a/Resources/doc/types.md +++ b/Resources/doc/types.md @@ -274,7 +274,8 @@ option on a type persistence configuration to `true`. ```yaml persistence: - immediate: true + listener: + immediate: true ``` Logging Errors From 2bd6aba7ef0a722e690a550c21445d2faf81f09f Mon Sep 17 00:00:00 2001 From: ben Date: Fri, 18 Apr 2014 13:57:08 +0200 Subject: [PATCH 216/447] Added GeoShape mapping options --- DependencyInjection/Configuration.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index b0a7b59..bb67e42 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -423,6 +423,9 @@ class Configuration implements ConfigurationInterface ->booleanNode('include_in_all')->defaultValue(true)->end() ->booleanNode('enabled')->defaultValue(true)->end() ->scalarNode('lat_lon')->end() + ->scalarNode('tree')->end() + ->scalarNode('precision')->end() + ->scalarNode('tree_levels')->end() ->scalarNode('index_name')->end() ->booleanNode('omit_norms')->end() ->scalarNode('index_options')->end() From 0dcb77d7491ef2f2bdd87db357b393c8b790f28b Mon Sep 17 00:00:00 2001 From: Ruslan Zavacky Date: Sat, 19 Apr 2014 18:31:56 +0300 Subject: [PATCH 217/447] More classes exposed as parameters. --- Resources/config/config.xml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Resources/config/config.xml b/Resources/config/config.xml index 1e49590..c10568d 100644 --- a/Resources/config/config.xml +++ b/Resources/config/config.xml @@ -8,6 +8,10 @@ FOS\ElasticaBundle\Client FOS\ElasticaBundle\DynamicIndex Elastica\Type + FOS\ElasticaBundle\IndexManager + FOS\ElasticaBundle\Resetter + FOS\ElasticaBundle\Finder\TransformedFinder + FOS\ElasticaBundle\Subscriber\PaginateElasticaQuerySubscriber FOS\ElasticaBundle\Logger\ElasticaLogger FOS\ElasticaBundle\DataCollector\ElasticaDataCollector FOS\ElasticaBundle\Manager\RepositoryManager @@ -32,12 +36,12 @@ - + - + @@ -48,7 +52,7 @@ - + @@ -84,7 +88,7 @@
    - + From 806452813a33b19641fa9172b7acf96d58f0b587 Mon Sep 17 00:00:00 2001 From: Ahmed Mohamed Date: Sun, 20 Apr 2014 03:41:41 +0200 Subject: [PATCH 218/447] Add test multiple objects mapping of at least one auto-mapped and at least one manually mapped --- .../ModelToElasticaAutoTransformerTest.php | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php index 646d1a4..1fa6a8e 100644 --- a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php +++ b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php @@ -107,6 +107,11 @@ class POPO return array('foo' => 'foo', 'bar' => 'foo', 'id' => 1); } + public function getNestedObject() + { + return array('key1' => (object)array('id' => 1, 'key1sub1' => 'value1sub1', 'key1sub2' => 'value1sub2')); + } + public function getUpper() { return (object) array('id' => 'parent', 'name' => 'a random name'); @@ -296,6 +301,51 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase ), $data['obj']); } + public function testObjectsMappingOfAtLeastOneAutoMappedObjectAndAtLeastOneManuallyMappedObject() + { + $transformer = $this->getTransformer(); + $document = $transformer->transform( + new POPO(), + array( + 'obj' => array('type' => 'object', 'properties' => array()), + 'nestedObject' => array( + 'type' => 'object', + 'properties' => array( + 'key1sub1' => array( + 'type' => 'string', + 'properties' => array() + ), + 'key1sub2' => array( + 'type' => 'string', + 'properties' => array() + ) + ) + ) + ) + ); + $data = $document->getData(); + + $this->assertTrue(array_key_exists('obj', $data)); + $this->assertTrue(array_key_exists('nestedObject', $data)); + $this->assertInternalType('array', $data['obj']); + $this->assertInternalType('array', $data['nestedObject']); + $this->assertEquals( + array( + 'foo' => 'foo', + 'bar' => 'foo', + 'id' => 1 + ), + $data['obj'] + ); + $this->assertEquals( + array( + 'key1sub1' => 'value1sub1', + 'key1sub2' => 'value1sub2' + ), + $data['nestedObject'][0] + ); + } + public function testParentMapping() { $transformer = $this->getTransformer(); From c9fd1cc5d99ba7d46050802b5dc9a78b44eb6dbc Mon Sep 17 00:00:00 2001 From: Ahmed Mohamed Date: Sun, 20 Apr 2014 06:11:20 +0200 Subject: [PATCH 219/447] Revert declaring PaginateElasticaQuerySubscriber as a paremeter, so not to break Knp compiler pass --- Resources/config/config.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Resources/config/config.xml b/Resources/config/config.xml index c10568d..7687250 100644 --- a/Resources/config/config.xml +++ b/Resources/config/config.xml @@ -11,7 +11,6 @@ FOS\ElasticaBundle\IndexManager FOS\ElasticaBundle\Resetter FOS\ElasticaBundle\Finder\TransformedFinder - FOS\ElasticaBundle\Subscriber\PaginateElasticaQuerySubscriber FOS\ElasticaBundle\Logger\ElasticaLogger FOS\ElasticaBundle\DataCollector\ElasticaDataCollector FOS\ElasticaBundle\Manager\RepositoryManager @@ -88,7 +87,7 @@ - + From 39f1033a34e28ab6013e63654b9ec72b9865f3ff Mon Sep 17 00:00:00 2001 From: Cassiano Date: Thu, 24 Apr 2014 09:39:22 -0300 Subject: [PATCH 220/447] Update Configuration.php Adding the option to set index_analyzer and search_analyzer to _all field. --- DependencyInjection/Configuration.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 40b26c6..b7ef2ab 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -667,6 +667,8 @@ class Configuration implements ConfigurationInterface $node ->children() ->scalarNode('enabled')->defaultValue(true)->end() + ->scalarNode('index_analyzer')->end() + ->scalarNode('search_analyzer')->end() ->end() ; From c93bbb9081c3915e457713990c02afc700c0a933 Mon Sep 17 00:00:00 2001 From: Evan Villemez Date: Thu, 1 May 2014 11:05:16 -0400 Subject: [PATCH 221/447] stop config from adding empty arrays into type mappings --- DependencyInjection/Configuration.php | 24 ++++++-- .../DependencyInjection/ConfigurationTest.php | 56 +++++++++++++++++++ 2 files changed, 76 insertions(+), 4 deletions(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index b0a7b59..e4fd323 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -351,8 +351,16 @@ class Configuration implements ConfigurationInterface ->useAttributeAsKey('name') ->prototype('array') ->validate() - ->ifTrue(function($v) { return isset($v['fields']) && empty($v['fields']); }) - ->then(function($v) { unset($v['fields']); return $v; }) + ->always() + ->then(function($v) { + foreach (array('fields','properties') as $prop) { + if (isset($v[$prop]) && empty($v[$prop])) { + unset($v[$prop]); + } + } + + return $v; + }) ->end() ->treatNullLike(array()) ->addDefaultsIfNotSet() @@ -464,8 +472,16 @@ class Configuration implements ConfigurationInterface ->useAttributeAsKey('name') ->prototype('array') ->validate() - ->ifTrue(function($v) { return isset($v['fields']) && empty($v['fields']); }) - ->then(function($v) { unset($v['fields']); return $v; }) + ->always() + ->then(function($v) { + foreach (array('fields','properties') as $prop) { + if (isset($v[$prop]) && empty($v[$prop])) { + unset($v[$prop]); + } + } + + return $v; + }) ->end() ->treatNullLike(array()) ->addDefaultsIfNotSet() diff --git a/Tests/DependencyInjection/ConfigurationTest.php b/Tests/DependencyInjection/ConfigurationTest.php index 5919ea7..08ada08 100644 --- a/Tests/DependencyInjection/ConfigurationTest.php +++ b/Tests/DependencyInjection/ConfigurationTest.php @@ -147,4 +147,60 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase $this->assertArrayNotHasKey('fields', $configuration['indexes']['test']['types']['test']['mappings']['children']['properties']['content']); $this->assertArrayHasKey('fields', $configuration['indexes']['test']['types']['test']['mappings']['children']['properties']['title']); } + + public function testEmptyPropertiesIndexIsUnset() + { + $config = array( + 'indexes' => array( + 'test' => array( + 'types' => array( + 'test' => array( + 'mappings' => array( + 'title' => array( + 'type' => 'string', + 'fields' => array( + 'autocomplete' => null + ) + ), + 'content' => null, + 'children' => array( + 'type' => 'object', + 'properties' => array( + 'title' => array( + 'type' => 'string', + 'fields' => array( + 'autocomplete' => null + ) + ), + 'content' => null, + 'tags' => array( + 'properties' => array( + 'tag' => array( + 'type' => 'string', + 'index' => 'not_analyzed' + ) + ) + ) + ) + ), + ) + ) + ) + ) + ) + ); + + $processor = new Processor(); + + $configuration = $processor->processConfiguration(new Configuration(array($config)), array($config)); + + $mapping = $configuration['indexes']['test']['types']['test']['mappings']; + $this->assertArrayNotHasKey('properties', $mapping['content']); + $this->assertArrayNotHasKey('properties', $mapping['title']); + $this->assertArrayHasKey('properties', $mapping['children']); + $this->assertArrayNotHasKey('properties', $mapping['children']['properties']['title']); + $this->assertArrayNotHasKey('properties', $mapping['children']['properties']['content']); + $this->assertArrayHasKey('properties', $mapping['children']['properties']['tags']); + $this->assertArrayNotHasKey('properties', $mapping['children']['properties']['tags']['properties']['tag']); + } } From d9f3fa1a595d82b4305b2706e44a65c6add05d16 Mon Sep 17 00:00:00 2001 From: Patrick McAndrew Date: Fri, 2 May 2014 15:07:15 +0100 Subject: [PATCH 222/447] commit 1dcaadbe6f99b42b346e04239c0c8fd7812bbf51 Persister/ObjectPersister.php line 112: $this->type->updateDocuments($documents); introduces a dependency on Elastica 0.9.10.0 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 8dd19b6..24801e7 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ "symfony/console": "~2.1", "symfony/form": "~2.1", "symfony/property-access": "~2.2", - "ruflin/elastica": ">=0.90.2.0, <1.1-dev", + "ruflin/elastica": ">=0.90.10.0, <1.1-dev", "psr/log": "~1.0" }, "require-dev":{ From ae02364e7c66fae05176e0462090a85fd0b16bf9 Mon Sep 17 00:00:00 2001 From: Lea Haensenberger Date: Mon, 5 May 2014 08:53:33 +0200 Subject: [PATCH 223/447] use elastica library 1.1 and higher --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 24801e7..580785d 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ "symfony/console": "~2.1", "symfony/form": "~2.1", "symfony/property-access": "~2.2", - "ruflin/elastica": ">=0.90.10.0, <1.1-dev", + "ruflin/elastica": ">=1.1-dev", "psr/log": "~1.0" }, "require-dev":{ From eaa9f8399744fb1966848e3bc2b83d1b2f5c9c54 Mon Sep 17 00:00:00 2001 From: Lea Haensenberger Date: Mon, 5 May 2014 11:55:48 +0200 Subject: [PATCH 224/447] remove empty fields arrays from mapping, this is not ignored anymore by elasticsearch 1.* --- DependencyInjection/FOSElasticaExtension.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 51cb94f..2019d5e 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -234,6 +234,7 @@ class FOSElasticaExtension extends Extension $this->indexConfigs[$indexName]['config']['mappings'][$name]['_routing'] = $type['_routing']; } if (isset($type['mappings']) && !empty($type['mappings'])) { + $this->cleanUpMapping($type['mappings']); $this->indexConfigs[$indexName]['config']['mappings'][$name]['properties'] = $type['mappings']; $typeName = sprintf('%s/%s', $indexName, $name); $this->typeFields[$typeName] = $type['mappings']; @@ -570,4 +571,14 @@ class FOSElasticaExtension extends Extension $container->setAlias('fos_elastica.manager', sprintf('fos_elastica.manager.%s', $defaultManagerService)); } + + protected function cleanUpMapping(&$mappings) + { + foreach ($mappings as &$fieldProperties) + if (empty($fieldProperties['fields'])) { + unset($fieldProperties['fields']); + } else { + $this->cleanUpMapping($fieldProperties['fields']); + } + } } From b1d64e358d2e4070668c4af158c9573daf33bda5 Mon Sep 17 00:00:00 2001 From: Lea Haensenberger Date: Mon, 5 May 2014 12:01:05 +0200 Subject: [PATCH 225/447] Also cleanup fields in properties of objects --- DependencyInjection/FOSElasticaExtension.php | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 2019d5e..ede7c21 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -574,11 +574,16 @@ class FOSElasticaExtension extends Extension protected function cleanUpMapping(&$mappings) { - foreach ($mappings as &$fieldProperties) - if (empty($fieldProperties['fields'])) { - unset($fieldProperties['fields']); - } else { - $this->cleanUpMapping($fieldProperties['fields']); + foreach ($mappings as &$fieldProperties) { + if (empty($fieldProperties['fields'])) { + unset($fieldProperties['fields']); + } else { + $this->cleanUpMapping($fieldProperties['fields']); + } + + if (!empty($fieldProperties['properties'])) { + $this->cleanUpMapping($fieldProperties['properties']); + } } } } From 5da8ee1a1655e8bd44c2db4e354b529dcf6c98f5 Mon Sep 17 00:00:00 2001 From: Lea Haensenberger Date: Tue, 6 May 2014 08:18:37 +0200 Subject: [PATCH 226/447] still supporting 0.9 versions of elastica --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 580785d..a991d38 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ "symfony/console": "~2.1", "symfony/form": "~2.1", "symfony/property-access": "~2.2", - "ruflin/elastica": ">=1.1-dev", + "ruflin/elastica": ">=0.90.10.0, <1.2-dev", "psr/log": "~1.0" }, "require-dev":{ From b0841c18ecb89a3ce3e2b8192411e9e9fdec3c00 Mon Sep 17 00:00:00 2001 From: caponica Date: Thu, 8 May 2014 00:26:30 +0100 Subject: [PATCH 227/447] Changed QueryBuilder method from ->where() to ->andWhere() so it works with customised QueryBuilders which have an existing where clause (instead of over-writing any existing DQL 'where' part) --- Doctrine/ORM/ElasticaToModelTransformer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doctrine/ORM/ElasticaToModelTransformer.php b/Doctrine/ORM/ElasticaToModelTransformer.php index 20ec6e8..a57a84c 100644 --- a/Doctrine/ORM/ElasticaToModelTransformer.php +++ b/Doctrine/ORM/ElasticaToModelTransformer.php @@ -29,7 +29,7 @@ class ElasticaToModelTransformer extends AbstractElasticaToModelTransformer $hydrationMode = $hydrate ? Query::HYDRATE_OBJECT : Query::HYDRATE_ARRAY; $qb = $this->getEntityQueryBuilder(); - $qb->where($qb->expr()->in(static::ENTITY_ALIAS.'.'.$this->options['identifier'], ':values')) + $qb->andWhere($qb->expr()->in(static::ENTITY_ALIAS.'.'.$this->options['identifier'], ':values')) ->setParameter('values', $identifierValues); return $qb->getQuery()->setHydrationMode($hydrationMode)->execute(); From e5754ef5fcc67bc3bc0815696a405e7e5770e814 Mon Sep 17 00:00:00 2001 From: Thomas Ploch Date: Tue, 13 May 2014 13:13:06 +0200 Subject: [PATCH 228/447] Make it possible to disable flush event through configuration --- DependencyInjection/Configuration.php | 1 + DependencyInjection/FOSElasticaExtension.php | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index b0a7b59..cb813a5 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -288,6 +288,7 @@ class Configuration implements ConfigurationInterface ->scalarNode('insert')->defaultTrue()->end() ->scalarNode('update')->defaultTrue()->end() ->scalarNode('delete')->defaultTrue()->end() + ->scalarNode('flush')->defaultTrue()->end() ->booleanNode('immediate')->defaultFalse()->end() ->scalarNode('logger') ->defaultFalse() diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index ede7c21..7d754f1 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -465,9 +465,6 @@ class FOSElasticaExtension extends Extension */ private function getDoctrineEvents(array $typeConfig) { - // Flush always calls depending on actions scheduled in lifecycle listeners - $typeConfig['listener']['flush'] = true; - switch ($typeConfig['driver']) { case 'orm': $eventsClass = '\Doctrine\ORM\Events'; From e1bbb87cfe011c0277a03e9ad66cdde2e521d86b Mon Sep 17 00:00:00 2001 From: Milan Magudia Date: Fri, 16 May 2014 16:24:37 +0100 Subject: [PATCH 229/447] Fix for Issue #543 Client has a dependency on a non-existent service "%kernel.debug%" --- DependencyInjection/Configuration.php | 7 +++++-- DependencyInjection/FOSElasticaExtension.php | 2 +- Tests/DependencyInjection/ConfigurationTest.php | 6 +++--- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 3c57558..fbdba94 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -16,10 +16,13 @@ class Configuration implements ConfigurationInterface private $supportedDrivers = array('orm', 'mongodb', 'propel'); private $configArray = array(); + private $debug; - public function __construct($configArray) + public function __construct($configArray, $debug) { + $this->configArray = $configArray; + $this->debug = $debug; } /** @@ -121,7 +124,7 @@ class Configuration implements ConfigurationInterface ->scalarNode('host')->end() ->scalarNode('port')->end() ->scalarNode('logger') - ->defaultValue('%kernel.debug%') + ->defaultValue(($this->debug) ? 'fos_elastica.logger' : false) ->treatNullLike('fos_elastica.logger') ->treatTrueLike('fos_elastica.logger') ->end() diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 7d754f1..f58cd5b 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -61,7 +61,7 @@ class FOSElasticaExtension extends Extension public function getConfiguration(array $config, ContainerBuilder $container) { - return new Configuration($config); + return new Configuration($config, $container->getParameter('kernel.debug')); } /** diff --git a/Tests/DependencyInjection/ConfigurationTest.php b/Tests/DependencyInjection/ConfigurationTest.php index 08ada08..38ffc58 100644 --- a/Tests/DependencyInjection/ConfigurationTest.php +++ b/Tests/DependencyInjection/ConfigurationTest.php @@ -17,7 +17,7 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase public function setUp() { - $this->configuration = new Configuration(array()); + $this->configuration = new Configuration(array(), false); } public function testEmptyConfigContainsFormatMappingOptionNode() @@ -140,7 +140,7 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase $processor = new Processor(); - $configuration = $processor->processConfiguration(new Configuration(array($config)), array($config)); + $configuration = $processor->processConfiguration(new Configuration(array($config), false), array($config)); $this->assertArrayNotHasKey('fields', $configuration['indexes']['test']['types']['test']['mappings']['content']); $this->assertArrayHasKey('fields', $configuration['indexes']['test']['types']['test']['mappings']['title']); @@ -192,7 +192,7 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase $processor = new Processor(); - $configuration = $processor->processConfiguration(new Configuration(array($config)), array($config)); + $configuration = $processor->processConfiguration(new Configuration(array($config), false), array($config)); $mapping = $configuration['indexes']['test']['types']['test']['mappings']; $this->assertArrayNotHasKey('properties', $mapping['content']); From 2c208a4f103446bd2e4bca15846d43d43ebd11ae Mon Sep 17 00:00:00 2001 From: Milan Magudia Date: Thu, 22 May 2014 16:18:08 +0100 Subject: [PATCH 230/447] Allow other transport options to be used i.e. Http, Https, Guzzle etc... --- DependencyInjection/Configuration.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index fbdba94..3dfe5ae 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -92,6 +92,7 @@ class Configuration implements ConfigurationInterface 'port' => $v['port'], 'logger' => isset($v['logger']) ? $v['logger'] : null, 'headers' => isset($v['headers']) ? $v['headers'] : null, + 'transport' => isset($v['transport']) ? $v['transport'] : null, ) ) ); @@ -132,6 +133,7 @@ class Configuration implements ConfigurationInterface ->useAttributeAsKey('name') ->prototype('scalar')->end() ->end() + ->scalarNode('transport')->end() ->scalarNode('timeout')->end() ->end() ->end() From 28d0ee925d1eb8369944985ae246d40bc3025034 Mon Sep 17 00:00:00 2001 From: Darius Staisiunas Date: Fri, 23 May 2014 12:55:33 +0300 Subject: [PATCH 231/447] added support for geohash --- DependencyInjection/Configuration.php | 1 + 1 file changed, 1 insertion(+) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index fbdba94..215f4a2 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -435,6 +435,7 @@ class Configuration implements ConfigurationInterface ->booleanNode('include_in_all')->defaultValue(true)->end() ->booleanNode('enabled')->defaultValue(true)->end() ->scalarNode('lat_lon')->end() + ->scalarNode('geohash')->end() ->scalarNode('index_name')->end() ->booleanNode('omit_norms')->end() ->scalarNode('index_options')->end() From 2029aba76a92d5eaffddb7998c1ef98aa264b318 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Mon, 31 Mar 2014 16:45:31 +1100 Subject: [PATCH 232/447] Ability for FOSElasticaBundle to disable persistence backend logging for population Update documentation and changelog --- CHANGELOG-3.0.md | 1 + DependencyInjection/Configuration.php | 3 ++- Doctrine/AbstractProvider.php | 27 ++++++++++++++++++++- Doctrine/MongoDB/Provider.php | 34 ++++++++++++++++++++++++++ Doctrine/ORM/Provider.php | 35 +++++++++++++++++++++++++++ Resources/doc/types.md | 15 ++++++++++++ 6 files changed, 113 insertions(+), 2 deletions(-) diff --git a/CHANGELOG-3.0.md b/CHANGELOG-3.0.md index abd05cd..9d74640 100644 --- a/CHANGELOG-3.0.md +++ b/CHANGELOG-3.0.md @@ -19,6 +19,7 @@ To generate a changelog summary since the last version, run * #415: BC BREAK: document indexing occurs in postFlush rather than the pre* events previously. * 7d13823: Dropped (broken) support for Symfony <2.3 * #496: Added support for HTTP headers + * #528: FOSElasticaBundle will disable Doctrine logging when populating for a large increase in speed * 3.0.0-ALPHA2 (2014-03-17) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index d26a516..dff773e 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -187,9 +187,10 @@ class Configuration implements ConfigurationInterface ->scalarNode('identifier')->defaultValue('id')->end() ->arrayNode('provider') ->children() - ->scalarNode('query_builder_method')->defaultValue('createQueryBuilder')->end() ->scalarNode('batch_size')->defaultValue(100)->end() ->scalarNode('clear_object_manager')->defaultTrue()->end() + ->scalarNode('disable_logger')->defaultValue('%kernel.debug%')->end() + ->scalarNode('query_builder_method')->defaultValue('createQueryBuilder')->end() ->scalarNode('service')->end() ->end() ->end() diff --git a/Doctrine/AbstractProvider.php b/Doctrine/AbstractProvider.php index 3fafe50..1c3f853 100644 --- a/Doctrine/AbstractProvider.php +++ b/Doctrine/AbstractProvider.php @@ -23,6 +23,7 @@ abstract class AbstractProvider extends BaseAbstractProvider { parent::__construct($objectPersister, $objectClass, array_merge(array( 'clear_object_manager' => true, + 'disable_logging' => false, 'ignore_errors' => false, 'query_builder_method' => 'createQueryBuilder', ), $options)); @@ -35,12 +36,17 @@ abstract class AbstractProvider extends BaseAbstractProvider */ public function populate(\Closure $loggerClosure = null, array $options = array()) { + if (!$this->options['disable_logging']) { + $logger = $this->disableLogging(); + } + $queryBuilder = $this->createQueryBuilder(); $nbObjects = $this->countObjects($queryBuilder); $offset = isset($options['offset']) ? intval($options['offset']) : 0; $sleep = isset($options['sleep']) ? intval($options['sleep']) : 0; $batchSize = isset($options['batch-size']) ? intval($options['batch-size']) : $this->options['batch_size']; $ignoreErrors = isset($options['ignore-errors']) ? $options['ignore-errors'] : $this->options['ignore_errors']; + $manager = $this->managerRegistry->getManagerForClass($this->objectClass); for (; $offset < $nbObjects; $offset += $batchSize) { if ($loggerClosure) { @@ -61,7 +67,7 @@ abstract class AbstractProvider extends BaseAbstractProvider } if ($this->options['clear_object_manager']) { - $this->managerRegistry->getManagerForClass($this->objectClass)->clear(); + $manager->clear(); } usleep($sleep); @@ -75,6 +81,10 @@ abstract class AbstractProvider extends BaseAbstractProvider $loggerClosure(sprintf('%0.1f%% (%d/%d), %d objects/s %s', $percentComplete, $stepCount, $nbObjects, $objectsPerSecond, $this->getMemoryUsage())); } } + + if (!$this->options['disable_logging']) { + $this->enableLogging($logger); + } } /** @@ -85,6 +95,21 @@ abstract class AbstractProvider extends BaseAbstractProvider */ protected abstract function countObjects($queryBuilder); + /** + * Disables logging and returns the logger that was previously set. + * + * @return mixed + */ + protected abstract function disableLogging(); + + /** + * Reenables the logger with the previously returned logger from disableLogging(); + * + * @param mixed $logger + * @return mixed + */ + protected abstract function enableLogging($logger); + /** * Fetches a slice of objects using the query builder. * diff --git a/Doctrine/MongoDB/Provider.php b/Doctrine/MongoDB/Provider.php index 16d9f76..9e1c5dd 100644 --- a/Doctrine/MongoDB/Provider.php +++ b/Doctrine/MongoDB/Provider.php @@ -8,6 +8,40 @@ use FOS\ElasticaBundle\Exception\InvalidArgumentTypeException; class Provider extends AbstractProvider { + /** + * Disables logging and returns the logger that was previously set. + * + * @return mixed + */ + protected function disableLogging() + { + $configuration = $this->managerRegistry + ->getManagerForClass($this->objectClass) + ->getConnection() + ->getConfiguration(); + + $logger = $configuration->getLoggerCallable(); + $configuration->setLoggerCallable(null); + + return $logger; + } + + /** + * Reenables the logger with the previously returned logger from disableLogging(); + * + * @param mixed $logger + * @return mixed + */ + protected function enableLogging($logger) + { + $configuration = $this->managerRegistry + ->getManagerForClass($this->objectClass) + ->getConnection() + ->getConfiguration(); + + $configuration->setLoggerCallable($logger); + } + /** * @see FOS\ElasticaBundle\Doctrine\AbstractProvider::countObjects() */ diff --git a/Doctrine/ORM/Provider.php b/Doctrine/ORM/Provider.php index 5d0164f..dfd6700 100644 --- a/Doctrine/ORM/Provider.php +++ b/Doctrine/ORM/Provider.php @@ -3,6 +3,7 @@ namespace FOS\ElasticaBundle\Doctrine\ORM; use Doctrine\ORM\QueryBuilder; +use Elastica\Exception\Bulk\ResponseException as BulkResponseException; use FOS\ElasticaBundle\Doctrine\AbstractProvider; use FOS\ElasticaBundle\Exception\InvalidArgumentTypeException; @@ -10,6 +11,40 @@ class Provider extends AbstractProvider { const ENTITY_ALIAS = 'a'; + /** + * Disables logging and returns the logger that was previously set. + * + * @return mixed + */ + protected function disableLogging() + { + $configuration = $this->managerRegistry + ->getManagerForClass($this->objectClass) + ->getConnection() + ->getConfiguration(); + + $logger = $configuration->getSQLLogger(); + $configuration->setSQLLogger(null); + + return $logger; + } + + /** + * Reenables the logger with the previously returned logger from disableLogging(); + * + * @param mixed $logger + * @return mixed + */ + protected function enableLogging($logger) + { + $configuration = $this->managerRegistry + ->getManagerForClass($this->objectClass) + ->getConnection() + ->getConfiguration(); + + $configuration->setSQLLogger($logger); + } + /** * @see FOS\ElasticaBundle\Doctrine\AbstractProvider::countObjects() */ diff --git a/Resources/doc/types.md b/Resources/doc/types.md index e55df5a..aa76a43 100644 --- a/Resources/doc/types.md +++ b/Resources/doc/types.md @@ -188,6 +188,21 @@ persistence configuration. identifier: searchId ``` +### Turning on the persistence backend logger in production + +FOSElasticaBundle will turn of your persistence backend's logging configuration by default +when Symfony2 is not in debug mode. + +To enable the logger (turn off this behaviour) set disable_logger to false for the +provider + +```yaml + user: + persistence: + provider: + disable_logger: false +``` + Listener Configuration ---------------------- From 6d2b7a836790dcb9ebe51e8f7ed606d560ef78bf Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Fri, 23 May 2014 20:36:19 +1000 Subject: [PATCH 233/447] Combine client normalisation into a single method --- DependencyInjection/Configuration.php | 31 +++++---------------------- 1 file changed, 5 insertions(+), 26 deletions(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index dff773e..b420143 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -60,16 +60,6 @@ class Configuration implements ConfigurationInterface return $treeBuilder; } - /** - * Generates the configuration tree. - * - * @return \Symfony\Component\DependencyInjection\Configuration\NodeInterface - */ - public function getConfigTree() - { - return $this->getConfigTreeBuilder()->buildTree(); - } - /** * Adds the configuration for the "clients" key */ @@ -83,28 +73,17 @@ class Configuration implements ConfigurationInterface ->prototype('array') ->performNoDeepMerging() ->beforeNormalization() - ->ifTrue(function($v) { return isset($v['host']) && isset($v['port']); }) + ->ifTrue(function($v) { return (isset($v['host']) && isset($v['port'])) || isset($v['url']); }) ->then(function($v) { return array( 'servers' => array( array( - 'host' => $v['host'], - 'port' => $v['port'], + 'host' => isset($v['host']) ? $v['host'] : null, + 'port' => isset($v['port']) ? $v['port'] : null, + 'url' => isset($v['url']) ? $v['url'] : null, 'logger' => isset($v['logger']) ? $v['logger'] : null, 'headers' => isset($v['headers']) ? $v['headers'] : null, - ) - ) - ); - }) - ->end() - ->beforeNormalization() - ->ifTrue(function($v) { return isset($v['url']); }) - ->then(function($v) { - return array( - 'servers' => array( - array( - 'url' => $v['url'], - 'logger' => isset($v['logger']) ? $v['logger'] : null + 'timeout' => isset($v['timeout']) ? $v['timeout'] : null, ) ) ); From 843c76b6cabd0fb71ef03cd95b9702e9dd41b2fc Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Fri, 23 May 2014 20:39:37 +1000 Subject: [PATCH 234/447] Move persistence node to its own method --- DependencyInjection/Configuration.php | 194 ++++++++++---------------- 1 file changed, 75 insertions(+), 119 deletions(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index b420143..c736b9a 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -149,62 +149,7 @@ class Configuration implements ConfigurationInterface ->children() ->scalarNode('index_analyzer')->end() ->scalarNode('search_analyzer')->end() - ->arrayNode('persistence') - ->validate() - ->ifTrue(function($v) { return isset($v['driver']) && 'propel' === $v['driver'] && isset($v['listener']); }) - ->thenInvalid('Propel doesn\'t support listeners') - ->ifTrue(function($v) { return isset($v['driver']) && 'propel' === $v['driver'] && isset($v['repository']); }) - ->thenInvalid('Propel doesn\'t support the "repository" parameter') - ->end() - ->children() - ->scalarNode('driver') - ->validate() - ->ifNotInArray($this->supportedDrivers) - ->thenInvalid('The driver %s is not supported. Please choose one of '.json_encode($this->supportedDrivers)) - ->end() - ->end() - ->scalarNode('identifier')->defaultValue('id')->end() - ->arrayNode('provider') - ->children() - ->scalarNode('batch_size')->defaultValue(100)->end() - ->scalarNode('clear_object_manager')->defaultTrue()->end() - ->scalarNode('disable_logger')->defaultValue('%kernel.debug%')->end() - ->scalarNode('query_builder_method')->defaultValue('createQueryBuilder')->end() - ->scalarNode('service')->end() - ->end() - ->end() - ->arrayNode('listener') - ->children() - ->scalarNode('insert')->defaultTrue()->end() - ->scalarNode('update')->defaultTrue()->end() - ->scalarNode('delete')->defaultTrue()->end() - ->scalarNode('persist')->defaultValue('postFlush')->end() - ->scalarNode('service')->end() - ->variableNode('is_indexable_callback')->defaultNull()->end() - ->end() - ->end() - ->arrayNode('finder') - ->children() - ->scalarNode('service')->end() - ->end() - ->end() - ->arrayNode('elastica_to_model_transformer') - ->addDefaultsIfNotSet() - ->children() - ->scalarNode('hydrate')->defaultTrue()->end() - ->scalarNode('ignore_missing')->defaultFalse()->end() - ->scalarNode('query_builder_method')->defaultValue('createQueryBuilder')->end() - ->scalarNode('service')->end() - ->end() - ->end() - ->arrayNode('model_to_elastica_transformer') - ->addDefaultsIfNotSet() - ->children() - ->scalarNode('service')->end() - ->end() - ->end() - ->end() - ->end() + ->append($this->getPersistenceNode()) ->end() ->end() ->variableNode('settings')->defaultValue(array())->end() @@ -241,69 +186,7 @@ class Configuration implements ConfigurationInterface ->end() ->scalarNode('index_analyzer')->end() ->scalarNode('search_analyzer')->end() - ->arrayNode('persistence') - ->validate() - ->ifTrue(function($v) { return isset($v['driver']) && 'propel' === $v['driver'] && isset($v['listener']); }) - ->thenInvalid('Propel doesn\'t support listeners') - ->ifTrue(function($v) { return isset($v['driver']) && 'propel' === $v['driver'] && isset($v['repository']); }) - ->thenInvalid('Propel doesn\'t support the "repository" parameter') - ->end() - ->children() - ->scalarNode('driver') - ->validate() - ->ifNotInArray($this->supportedDrivers) - ->thenInvalid('The driver %s is not supported. Please choose one of '.json_encode($this->supportedDrivers)) - ->end() - ->end() - ->scalarNode('model')->end() - ->scalarNode('repository')->end() - ->scalarNode('identifier')->defaultValue('id')->end() - ->arrayNode('provider') - ->children() - ->scalarNode('query_builder_method')->defaultValue('createQueryBuilder')->end() - ->scalarNode('batch_size')->defaultValue(100)->end() - ->scalarNode('clear_object_manager')->defaultTrue()->end() - ->scalarNode('service')->end() - ->end() - ->end() - ->arrayNode('listener') - ->children() - ->scalarNode('insert')->defaultTrue()->end() - ->scalarNode('update')->defaultTrue()->end() - ->scalarNode('delete')->defaultTrue()->end() - ->scalarNode('flush')->defaultTrue()->end() - ->booleanNode('immediate')->defaultFalse()->end() - ->scalarNode('logger') - ->defaultFalse() - ->treatNullLike('fos_elastica.logger') - ->treatTrueLike('fos_elastica.logger') - ->end() - ->scalarNode('service')->end() - ->variableNode('is_indexable_callback')->defaultNull()->end() - ->end() - ->end() - ->arrayNode('finder') - ->children() - ->scalarNode('service')->end() - ->end() - ->end() - ->arrayNode('elastica_to_model_transformer') - ->addDefaultsIfNotSet() - ->children() - ->scalarNode('hydrate')->defaultTrue()->end() - ->scalarNode('ignore_missing')->defaultFalse()->end() - ->scalarNode('query_builder_method')->defaultValue('createQueryBuilder')->end() - ->scalarNode('service')->end() - ->end() - ->end() - ->arrayNode('model_to_elastica_transformer') - ->addDefaultsIfNotSet() - ->children() - ->scalarNode('service')->end() - ->end() - ->end() - ->end() - ->end() + ->append($this->getPersistenceNode()) ->end() ->append($this->getIdNode()) ->append($this->getMappingsNode()) @@ -738,4 +621,77 @@ class Configuration implements ConfigurationInterface return $node; } + + /** + * @return ArrayNodeDefinition|\Symfony\Component\Config\Definition\Builder\NodeDefinition + */ + protected function getPersistenceNode() + { + $builder = new TreeBuilder(); + $node = $builder->root('persistence'); + + $node + ->validate() + ->ifTrue(function($v) { return isset($v['driver']) && 'propel' === $v['driver'] && isset($v['listener']); }) + ->thenInvalid('Propel doesn\'t support listeners') + ->ifTrue(function($v) { return isset($v['driver']) && 'propel' === $v['driver'] && isset($v['repository']); }) + ->thenInvalid('Propel doesn\'t support the "repository" parameter') + ->end() + ->children() + ->scalarNode('driver') + ->validate() + ->ifNotInArray($this->supportedDrivers) + ->thenInvalid('The driver %s is not supported. Please choose one of '.json_encode($this->supportedDrivers)) + ->end() + ->end() + ->scalarNode('model')->end() + ->scalarNode('repository')->end() + ->scalarNode('identifier')->defaultValue('id')->end() + ->arrayNode('provider') + ->children() + ->scalarNode('query_builder_method')->defaultValue('createQueryBuilder')->end() + ->scalarNode('batch_size')->defaultValue(100)->end() + ->scalarNode('clear_object_manager')->defaultTrue()->end() + ->scalarNode('service')->end() + ->end() + ->end() + ->arrayNode('listener') + ->children() + ->scalarNode('insert')->defaultTrue()->end() + ->scalarNode('update')->defaultTrue()->end() + ->scalarNode('delete')->defaultTrue()->end() + ->booleanNode('immediate')->defaultFalse()->end() + ->scalarNode('logger') + ->defaultFalse() + ->treatNullLike('fos_elastica.logger') + ->treatTrueLike('fos_elastica.logger') + ->end() + ->scalarNode('service')->end() + ->variableNode('is_indexable_callback')->defaultNull()->end() + ->end() + ->end() + ->arrayNode('finder') + ->children() + ->scalarNode('service')->end() + ->end() + ->end() + ->arrayNode('elastica_to_model_transformer') + ->addDefaultsIfNotSet() + ->children() + ->scalarNode('hydrate')->defaultTrue()->end() + ->scalarNode('ignore_missing')->defaultFalse()->end() + ->scalarNode('query_builder_method')->defaultValue('createQueryBuilder')->end() + ->scalarNode('service')->end() + ->end() + ->end() + ->arrayNode('model_to_elastica_transformer') + ->addDefaultsIfNotSet() + ->children() + ->scalarNode('service')->end() + ->end() + ->end() + ->end(); + + return $node; + } } From 41c4d77b20b0876561eeab1a381a0f11ca9c8941 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Fri, 23 May 2014 20:41:09 +1000 Subject: [PATCH 235/447] Move serializer node to its own method, add serializer to type_prototype --- DependencyInjection/Configuration.php | 33 +++++++++++++++++++-------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index c736b9a..a8b1d2f 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -150,6 +150,7 @@ class Configuration implements ConfigurationInterface ->scalarNode('index_analyzer')->end() ->scalarNode('search_analyzer')->end() ->append($this->getPersistenceNode()) + ->append($this->getSerializerNode()) ->end() ->end() ->variableNode('settings')->defaultValue(array())->end() @@ -174,19 +175,10 @@ class Configuration implements ConfigurationInterface ->prototype('array') ->treatNullLike(array()) ->children() - ->arrayNode('serializer') - ->addDefaultsIfNotSet() - ->children() - ->arrayNode('groups') - ->treatNullLike(array()) - ->prototype('scalar')->end() - ->end() - ->scalarNode('version')->end() - ->end() - ->end() ->scalarNode('index_analyzer')->end() ->scalarNode('search_analyzer')->end() ->append($this->getPersistenceNode()) + ->append($this->getSerializerNode()) ->end() ->append($this->getIdNode()) ->append($this->getMappingsNode()) @@ -694,4 +686,25 @@ class Configuration implements ConfigurationInterface return $node; } + + /** + * @return ArrayNodeDefinition|\Symfony\Component\Config\Definition\Builder\NodeDefinition + */ + protected function getSerializerNode() + { + $builder = new TreeBuilder(); + $node = $builder->root('serializer'); + + $node + ->addDefaultsIfNotSet() + ->children() + ->arrayNode('groups') + ->treatNullLike(array()) + ->prototype('scalar')->end() + ->end() + ->scalarNode('version')->end() + ->end(); + + return $node; + } } From 352e3b68ac26da2faf73125613619c30fa0b6590 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Fri, 23 May 2014 22:24:11 +1000 Subject: [PATCH 236/447] Add configuration tests --- .../DependencyInjection/ConfigurationTest.php | 200 ++++++++++-------- 1 file changed, 108 insertions(+), 92 deletions(-) diff --git a/Tests/DependencyInjection/ConfigurationTest.php b/Tests/DependencyInjection/ConfigurationTest.php index 38ffc58..e2fba93 100644 --- a/Tests/DependencyInjection/ConfigurationTest.php +++ b/Tests/DependencyInjection/ConfigurationTest.php @@ -11,141 +11,157 @@ use Symfony\Component\Config\Definition\Processor; class ConfigurationTest extends \PHPUnit_Framework_TestCase { /** - * @var Configuration + * @var Processor */ - private $configuration; + private $processor; public function setUp() { - $this->configuration = new Configuration(array(), false); + $this->processor = new Processor(); } - public function testEmptyConfigContainsFormatMappingOptionNode() + private function getConfigs(array $configArray) { - $tree = $this->configuration->getConfigTree(); - $children = $tree->getChildren(); - $children = $children['indexes']->getPrototype()->getChildren(); - $typeNodes = $children['types']->getPrototype()->getChildren(); - $mappings = $typeNodes['mappings']->getPrototype()->getChildren(); + $configuration = new Configuration($configArray, true); - $this->assertArrayHasKey('format', $mappings); - $this->assertInstanceOf('Symfony\Component\Config\Definition\ScalarNode', $mappings['format']); - $this->assertNull($mappings['format']->getDefaultValue()); + return $this->processor->processConfiguration($configuration, array($configArray)); } - public function testDynamicTemplateNodes() + public function testUnconfiguredConfiguration() { - $tree = $this->configuration->getConfigTree(); - $children = $tree->getChildren(); - $children = $children['indexes']->getPrototype()->getChildren(); - $typeNodes = $children['types']->getPrototype()->getChildren(); - $dynamicTemplates = $typeNodes['dynamic_templates']->getPrototype()->getChildren(); + $configuration = $this->getConfigs(array()); - $this->assertArrayHasKey('match', $dynamicTemplates); - $this->assertInstanceOf('Symfony\Component\Config\Definition\ScalarNode', $dynamicTemplates['match']); - $this->assertNull($dynamicTemplates['match']->getDefaultValue()); - - $this->assertArrayHasKey('match_mapping_type', $dynamicTemplates); - $this->assertInstanceOf('Symfony\Component\Config\Definition\ScalarNode', $dynamicTemplates['match_mapping_type']); - $this->assertNull($dynamicTemplates['match_mapping_type']->getDefaultValue()); - - $this->assertArrayHasKey('unmatch', $dynamicTemplates); - $this->assertInstanceOf('Symfony\Component\Config\Definition\ScalarNode', $dynamicTemplates['unmatch']); - $this->assertNull($dynamicTemplates['unmatch']->getDefaultValue()); - - $this->assertArrayHasKey('path_match', $dynamicTemplates); - $this->assertInstanceOf('Symfony\Component\Config\Definition\ScalarNode', $dynamicTemplates['path_match']); - $this->assertNull($dynamicTemplates['path_match']->getDefaultValue()); - - $this->assertArrayHasKey('path_unmatch', $dynamicTemplates); - $this->assertInstanceOf('Symfony\Component\Config\Definition\ScalarNode', $dynamicTemplates['path_unmatch']); - $this->assertNull($dynamicTemplates['path_unmatch']->getDefaultValue()); - - $this->assertArrayHasKey('match_pattern', $dynamicTemplates); - $this->assertInstanceOf('Symfony\Component\Config\Definition\ScalarNode', $dynamicTemplates['match_pattern']); - $this->assertNull($dynamicTemplates['match_pattern']->getDefaultValue()); - - $this->assertArrayHasKey('mapping', $dynamicTemplates); - $this->assertInstanceOf('Symfony\Component\Config\Definition\ArrayNode', $dynamicTemplates['mapping']); + $this->assertSame(array( + 'clients' => array(), + 'indexes' => array(), + 'default_manager' => 'orm' + ), $configuration); } - public function testDynamicTemplateMappingNodes() + public function testClientConfiguration() { - $tree = $this->configuration->getConfigTree(); - $children = $tree->getChildren(); - $children = $children['indexes']->getPrototype()->getChildren(); - $typeNodes = $children['types']->getPrototype()->getChildren(); - $dynamicTemplates = $typeNodes['dynamic_templates']->getPrototype()->getChildren(); - $mapping = $dynamicTemplates['mapping']->getChildren(); + $configuration = $this->getConfigs(array( + 'clients' => array( + 'default' => array( + 'url' => 'http://localhost:9200', + ), + 'clustered' => array( + 'servers' => array( + array( + 'url' => 'http://es1:9200', + 'headers' => array( + 'Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==' + ) + ), + array( + 'url' => 'http://es2:9200', + 'headers' => array( + 'Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==' + ) + ), + ) + ) + ) + )); - $this->assertArrayHasKey('type', $mapping); - $this->assertInstanceOf('Symfony\Component\Config\Definition\ScalarNode', $mapping['type']); - $this->assertSame('string', $mapping['type']->getDefaultValue()); + $this->assertCount(2, $configuration['clients']); + $this->assertCount(1, $configuration['clients']['default']['servers']); + $this->assertCount(0, $configuration['clients']['default']['servers'][0]['headers']); - $this->assertArrayHasKey('index', $mapping); - $this->assertInstanceOf('Symfony\Component\Config\Definition\ScalarNode', $mapping['index']); - $this->assertNull($mapping['index']->getDefaultValue()); + $this->assertCount(2, $configuration['clients']['clustered']['servers']); + $this->assertEquals('http://es2:9200/', $configuration['clients']['clustered']['servers'][1]['url']); + $this->assertCount(1, $configuration['clients']['clustered']['servers'][1]['headers']); + $this->assertEquals('Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==', $configuration['clients']['clustered']['servers'][0]['headers'][0]); + } + + public function testLogging() + { + $configuration = $this->getConfigs(array( + 'clients' => array( + 'logging_enabled' => array( + 'url' => 'http://localhost:9200', + 'logger' => true, + ), + 'logging_disabled' => array( + 'url' => 'http://localhost:9200', + 'logger' => false, + ), + 'logging_not_mentioned' => array( + 'url' => 'http://localhost:9200', + ), + 'logging_custom' => array( + 'url' => 'http://localhost:9200', + 'logger' => 'custom.service' + ), + ) + )); + + $this->assertCount(4, $configuration['clients']); + + $this->assertEquals('fos_elastica.logger', $configuration['clients']['logging_enabled']['servers'][0]['logger']); + $this->assertFalse($configuration['clients']['logging_disabled']['servers'][0]['logger']); + $this->assertEquals('fos_elastica.logger', $configuration['clients']['logging_not_mentioned']['servers'][0]['logger']); + $this->assertEquals('custom.service', $configuration['clients']['logging_custom']['servers'][0]['logger']); } public function testSlashIsAddedAtTheEndOfServerUrl() { $config = array( 'clients' => array( - 'default' => array( - 'url' => 'http://www.github.com', - ), + 'default' => array('url' => 'http://www.github.com'), ), - ); - - $processor = new Processor(); - - $configuration = $processor->processConfiguration($this->configuration, array($config)); + ); + $configuration = $this->getConfigs($config); $this->assertEquals('http://www.github.com/', $configuration['clients']['default']['servers'][0]['url']); } - public function testEmptyFieldsIndexIsUnset() + public function testTypeConfig() { - $config = array( + $configuration = $this->getConfigs(array( + 'clients' => array( + 'default' => array('url' => 'http://localhost:9200'), + ), 'indexes' => array( 'test' => array( + 'type_prototype' => array( + 'index_analyzer' => 'custom_analyzer', + 'persistence' => array( + 'identifier' => 'ID', + ), + 'serializer' => array( + 'groups' => array('Search'), + 'version' => 1 + ) + ), 'types' => array( 'test' => array( 'mappings' => array( - 'title' => array( - 'type' => 'string', - 'fields' => array( - 'autocomplete' => null - ) - ), - 'content' => null, + 'title' => array(), + 'published' => array('type' => 'datetime'), + 'body' => null, + ), + 'persistence' => array( + 'listener' => array( + 'logger' => true, + ) + ) + ), + 'test2' => array( + 'mappings' => array( + 'title' => null, 'children' => array( 'type' => 'nested', - 'properties' => array( - 'title' => array( - 'type' => 'string', - 'fields' => array( - 'autocomplete' => null - ) - ), - 'content' => null - ) ) ) ) ) ) ) - ); + )); - $processor = new Processor(); - - $configuration = $processor->processConfiguration(new Configuration(array($config), false), array($config)); - - $this->assertArrayNotHasKey('fields', $configuration['indexes']['test']['types']['test']['mappings']['content']); - $this->assertArrayHasKey('fields', $configuration['indexes']['test']['types']['test']['mappings']['title']); - $this->assertArrayNotHasKey('fields', $configuration['indexes']['test']['types']['test']['mappings']['children']['properties']['content']); - $this->assertArrayHasKey('fields', $configuration['indexes']['test']['types']['test']['mappings']['children']['properties']['title']); + $this->assertEquals('string', $configuration['indexes']['test']['types']['test']['mappings']['title']['type']); + $this->assertTrue($configuration['indexes']['test']['types']['test']['mappings']['title']['include_in_all']); } public function testEmptyPropertiesIndexIsUnset() From 3addfffc916f4ed09d774537a4f77728e6fd1ddb Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Fri, 23 May 2014 22:57:57 +1000 Subject: [PATCH 237/447] Added logging of server errors to example --- .../doc/cookbook/suppress-server-errors.md | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/Resources/doc/cookbook/suppress-server-errors.md b/Resources/doc/cookbook/suppress-server-errors.md index d89ffd6..e4e371e 100644 --- a/Resources/doc/cookbook/suppress-server-errors.md +++ b/Resources/doc/cookbook/suppress-server-errors.md @@ -32,6 +32,16 @@ class Client extends BaseClient try { return parent::request($path, $method, $data, $query); } catch (ExceptionInterface $e) { + if ($this->_logger) { + $this->_logger->warning('Failed to send a request to ElasticSearch', array( + 'exception' => $e->getMessage(), + 'path' => $path, + 'method' => $method, + 'data' => $data, + 'query' => $query + )); + } + return new Response('{"took":0,"timed_out":false,"hits":{"total":0,"max_score":0,"hits":[]}}'); } } @@ -41,15 +51,9 @@ class Client extends BaseClient Configuration change: --------------------- -```xml - +You must update a parameter in your `app/config/config.yml` file to point to your overridden client: - - - - Acme\ElasticaBundle\Client - - - +```yaml +parameters: + fos_elastica.client.class: Acme\ElasticaBundle\Client +``` From f8a445b46c939f04bc06a7f1d7631aca12ac618b Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Fri, 23 May 2014 23:11:45 +1000 Subject: [PATCH 238/447] Fix disabling of logger in DoctrineProvider --- DependencyInjection/Configuration.php | 5 ++++- Doctrine/AbstractProvider.php | 6 +++--- Resources/doc/types.md | 9 ++++----- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 154abcc..d84cd3c 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -189,7 +189,10 @@ class Configuration implements ConfigurationInterface ->children() ->scalarNode('batch_size')->defaultValue(100)->end() ->scalarNode('clear_object_manager')->defaultTrue()->end() - ->scalarNode('disable_logger')->defaultValue('%kernel.debug%')->end() + ->booleanNode('debug_logging') + ->defaultValue($this->debug) + ->treatNullLike($this->debug) + ->end() ->scalarNode('query_builder_method')->defaultValue('createQueryBuilder')->end() ->scalarNode('service')->end() ->end() diff --git a/Doctrine/AbstractProvider.php b/Doctrine/AbstractProvider.php index 1c3f853..b9ffda5 100644 --- a/Doctrine/AbstractProvider.php +++ b/Doctrine/AbstractProvider.php @@ -23,7 +23,7 @@ abstract class AbstractProvider extends BaseAbstractProvider { parent::__construct($objectPersister, $objectClass, array_merge(array( 'clear_object_manager' => true, - 'disable_logging' => false, + 'debug_logging' => false, 'ignore_errors' => false, 'query_builder_method' => 'createQueryBuilder', ), $options)); @@ -36,7 +36,7 @@ abstract class AbstractProvider extends BaseAbstractProvider */ public function populate(\Closure $loggerClosure = null, array $options = array()) { - if (!$this->options['disable_logging']) { + if (!$this->options['debug_logging']) { $logger = $this->disableLogging(); } @@ -82,7 +82,7 @@ abstract class AbstractProvider extends BaseAbstractProvider } } - if (!$this->options['disable_logging']) { + if (!$this->options['debug_logging']) { $this->enableLogging($logger); } } diff --git a/Resources/doc/types.md b/Resources/doc/types.md index aa76a43..aacb09e 100644 --- a/Resources/doc/types.md +++ b/Resources/doc/types.md @@ -191,16 +191,15 @@ persistence configuration. ### Turning on the persistence backend logger in production FOSElasticaBundle will turn of your persistence backend's logging configuration by default -when Symfony2 is not in debug mode. - -To enable the logger (turn off this behaviour) set disable_logger to false for the -provider +when Symfony2 is not in debug mode. You can force FOSElasticaBundle to always disable +logging by setting debug_logging to false, to leave logging alone by setting it to true, +or leave it set to its default value which will mirror %kernel.debug%. ```yaml user: persistence: provider: - disable_logger: false + debug_logging: false ``` Listener Configuration From f20392d78b912e4a50be9b9e1c87c95e9e3560dc Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Fri, 23 May 2014 23:19:55 +1000 Subject: [PATCH 239/447] Fix test failures for DoctrineProvider --- Tests/Doctrine/AbstractProviderTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Doctrine/AbstractProviderTest.php b/Tests/Doctrine/AbstractProviderTest.php index 2492eed..dcceccf 100644 --- a/Tests/Doctrine/AbstractProviderTest.php +++ b/Tests/Doctrine/AbstractProviderTest.php @@ -17,7 +17,7 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase } $this->objectClass = 'objectClass'; - $this->options = array(); + $this->options = array('debug_logging' => true); $this->objectPersister = $this->getMockObjectPersister(); $this->managerRegistry = $this->getMockManagerRegistry(); From e77aa0c180d662ecf99fafed8bca23ccee6400b2 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Fri, 23 May 2014 23:20:52 +1000 Subject: [PATCH 240/447] Test on php 5.5 --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 8f6a9d8..72632de 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,7 @@ language: php php: - 5.3 - 5.4 + - 5.5 before_script: - echo "extension = mongo.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini From a9ea78443fbed12b78cd5767829eb1f6f766f523 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Sat, 24 May 2014 00:17:59 +1000 Subject: [PATCH 241/447] Support Elastica proxy option --- DependencyInjection/Configuration.php | 1 + 1 file changed, 1 insertion(+) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index d0ec09f..9b2bc89 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -102,6 +102,7 @@ class Configuration implements ConfigurationInterface ->end() ->scalarNode('host')->end() ->scalarNode('port')->end() + ->scalarNode('proxy')->end() ->scalarNode('logger') ->defaultValue(($this->debug) ? 'fos_elastica.logger' : false) ->treatNullLike('fos_elastica.logger') From f9745c8d21895ecac980a1b4160fc6780cea2716 Mon Sep 17 00:00:00 2001 From: Delf Tonder Date: Sat, 24 May 2014 12:49:12 +0200 Subject: [PATCH 242/447] update setup.md - immediate is an listener option fixed yml config example (having immediate as an persistence option will result in parsing error) --- Resources/doc/setup.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Resources/doc/setup.md b/Resources/doc/setup.md index 4ae40af..9a39b95 100644 --- a/Resources/doc/setup.md +++ b/Resources/doc/setup.md @@ -114,9 +114,9 @@ Below is an example for the Doctrine ORM. driver: orm model: Acme\ApplicationBundle\Entity\User provider: ~ - listener: ~ + listener: + immediate: ~ finder: ~ - immediate: ~ ``` There are a significant number of options available for types, that can be From f97e66712a861067263567021f402c2ff04100fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Sj=C3=B6sten?= Date: Sun, 25 May 2014 00:31:40 +0100 Subject: [PATCH 243/447] Don't default url --- DependencyInjection/Configuration.php | 2 +- Tests/DependencyInjection/ConfigurationTest.php | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 9b2bc89..275b23d 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -96,7 +96,7 @@ class Configuration implements ConfigurationInterface ->children() ->scalarNode('url') ->validate() - ->ifTrue(function($url) { return substr($url, -1) !== '/'; }) + ->ifTrue(function($url) { return $url && substr($url, -1) !== '/'; }) ->then(function($url) { return $url.'/'; }) ->end() ->end() diff --git a/Tests/DependencyInjection/ConfigurationTest.php b/Tests/DependencyInjection/ConfigurationTest.php index e2fba93..bddd62e 100644 --- a/Tests/DependencyInjection/ConfigurationTest.php +++ b/Tests/DependencyInjection/ConfigurationTest.php @@ -219,4 +219,18 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase $this->assertArrayHasKey('properties', $mapping['children']['properties']['tags']); $this->assertArrayNotHasKey('properties', $mapping['children']['properties']['tags']['properties']['tag']); } + + public function testClientConfigurationNoUrl() + { + $configuration = $this->getConfigs(array( + 'clients' => array( + 'default' => array( + 'host' => 'localhost', + 'port' => 9200, + ), + ) + )); + + $this->assertTrue(empty($configuration['clients']['default']['servers'][0]['url'])); + } } From c38dc107e766ac100e2145db64d4fa7277ef517d Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Sun, 25 May 2014 17:34:44 +1000 Subject: [PATCH 244/447] Rename mappings to properties maintaining BC Fixes #407 --- DependencyInjection/Configuration.php | 18 +++++-- DependencyInjection/FOSElasticaExtension.php | 47 +++++++++---------- Resetter.php | 4 +- .../DependencyInjection/ConfigurationTest.php | 30 ++++++++++-- Tests/ResetterTest.php | 16 +++---- 5 files changed, 74 insertions(+), 41 deletions(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 275b23d..ac7d3a2 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -175,6 +175,16 @@ class Configuration implements ConfigurationInterface ->useAttributeAsKey('name') ->prototype('array') ->treatNullLike(array()) + // BC - Renaming 'mappings' node to 'properties' + ->beforeNormalization() + ->ifTrue(function($v) { return isset($v['mappings']); }) + ->then(function($v) { + $v['properties'] = $v['mappings']; + unset($v['mappings']); + + return $v; + }) + ->end() ->children() ->scalarNode('index_analyzer')->end() ->scalarNode('search_analyzer')->end() @@ -182,7 +192,7 @@ class Configuration implements ConfigurationInterface ->append($this->getSerializerNode()) ->end() ->append($this->getIdNode()) - ->append($this->getMappingsNode()) + ->append($this->getPropertiesNode()) ->append($this->getDynamicTemplateNode()) ->append($this->getSourceNode()) ->append($this->getBoostNode()) @@ -198,12 +208,12 @@ class Configuration implements ConfigurationInterface } /** - * Returns the array node used for "mappings". + * Returns the array node used for "properties". */ - protected function getMappingsNode() + protected function getPropertiesNode() { $builder = new TreeBuilder(); - $node = $builder->root('mappings'); + $node = $builder->root('properties'); $nestings = $this->getNestings(); diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index f58cd5b..1529544 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -4,7 +4,6 @@ namespace FOS\ElasticaBundle\DependencyInjection; use Symfony\Component\HttpKernel\DependencyInjection\Extension; use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; -use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\DefinitionDecorator; @@ -129,7 +128,7 @@ class FOSElasticaExtension extends Extension 'index' => new Reference($indexId), 'name_or_alias' => $indexName, 'config' => array( - 'mappings' => array() + 'properties' => array() ) ); if ($index['finder']) { @@ -217,30 +216,30 @@ class FOSElasticaExtension extends Extension } $container->setDefinition($typeId, $typeDef); - $this->indexConfigs[$indexName]['config']['mappings'][$name] = array( + $this->indexConfigs[$indexName]['config']['properties'][$name] = array( "_source" => array("enabled" => true), // Add a default setting for empty mapping settings ); if (isset($type['_id'])) { - $this->indexConfigs[$indexName]['config']['mappings'][$name]['_id'] = $type['_id']; + $this->indexConfigs[$indexName]['config']['properties'][$name]['_id'] = $type['_id']; } if (isset($type['_source'])) { - $this->indexConfigs[$indexName]['config']['mappings'][$name]['_source'] = $type['_source']; + $this->indexConfigs[$indexName]['config']['properties'][$name]['_source'] = $type['_source']; } if (isset($type['_boost'])) { - $this->indexConfigs[$indexName]['config']['mappings'][$name]['_boost'] = $type['_boost']; + $this->indexConfigs[$indexName]['config']['properties'][$name]['_boost'] = $type['_boost']; } if (isset($type['_routing'])) { - $this->indexConfigs[$indexName]['config']['mappings'][$name]['_routing'] = $type['_routing']; + $this->indexConfigs[$indexName]['config']['properties'][$name]['_routing'] = $type['_routing']; } - if (isset($type['mappings']) && !empty($type['mappings'])) { - $this->cleanUpMapping($type['mappings']); - $this->indexConfigs[$indexName]['config']['mappings'][$name]['properties'] = $type['mappings']; + if (isset($type['properties']) && !empty($type['properties'])) { + $this->cleanUpProperties($type['properties']); + $this->indexConfigs[$indexName]['config']['properties'][$name]['properties'] = $type['properties']; $typeName = sprintf('%s/%s', $indexName, $name); - $this->typeFields[$typeName] = $type['mappings']; + $this->typeFields[$typeName] = $type['properties']; } if (isset($type['_parent'])) { - $this->indexConfigs[$indexName]['config']['mappings'][$name]['_parent'] = array('type' => $type['_parent']['type']); + $this->indexConfigs[$indexName]['config']['properties'][$name]['_parent'] = array('type' => $type['_parent']['type']); $typeName = sprintf('%s/%s', $indexName, $name); $this->typeFields[$typeName]['_parent'] = $type['_parent']; } @@ -248,27 +247,27 @@ class FOSElasticaExtension extends Extension $this->loadTypePersistenceIntegration($type['persistence'], $container, $typeDef, $indexName, $name); } if (isset($type['index_analyzer'])) { - $this->indexConfigs[$indexName]['config']['mappings'][$name]['index_analyzer'] = $type['index_analyzer']; + $this->indexConfigs[$indexName]['config']['properties'][$name]['index_analyzer'] = $type['index_analyzer']; } if (isset($type['search_analyzer'])) { - $this->indexConfigs[$indexName]['config']['mappings'][$name]['search_analyzer'] = $type['search_analyzer']; + $this->indexConfigs[$indexName]['config']['properties'][$name]['search_analyzer'] = $type['search_analyzer']; } if (isset($type['index'])) { - $this->indexConfigs[$indexName]['config']['mappings'][$name]['index'] = $type['index']; + $this->indexConfigs[$indexName]['config']['properties'][$name]['index'] = $type['index']; } if (isset($type['_all'])) { - $this->indexConfigs[$indexName]['config']['mappings'][$name]['_all'] = $type['_all']; + $this->indexConfigs[$indexName]['config']['properties'][$name]['_all'] = $type['_all']; } if (isset($type['_timestamp'])) { - $this->indexConfigs[$indexName]['config']['mappings'][$name]['_timestamp'] = $type['_timestamp']; + $this->indexConfigs[$indexName]['config']['properties'][$name]['_timestamp'] = $type['_timestamp']; } if (isset($type['_ttl'])) { - $this->indexConfigs[$indexName]['config']['mappings'][$name]['_ttl'] = $type['_ttl']; + $this->indexConfigs[$indexName]['config']['properties'][$name]['_ttl'] = $type['_ttl']; } if (!empty($type['dynamic_templates'])) { - $this->indexConfigs[$indexName]['config']['mappings'][$name]['dynamic_templates'] = array(); + $this->indexConfigs[$indexName]['config']['properties'][$name]['dynamic_templates'] = array(); foreach ($type['dynamic_templates'] as $templateName => $templateData) { - $this->indexConfigs[$indexName]['config']['mappings'][$name]['dynamic_templates'][] = array($templateName => $templateData); + $this->indexConfigs[$indexName]['config']['properties'][$name]['dynamic_templates'][] = array($templateName => $templateData); } } } @@ -569,17 +568,17 @@ class FOSElasticaExtension extends Extension $container->setAlias('fos_elastica.manager', sprintf('fos_elastica.manager.%s', $defaultManagerService)); } - protected function cleanUpMapping(&$mappings) + protected function cleanUpProperties(&$properties) { - foreach ($mappings as &$fieldProperties) { + foreach ($properties as &$fieldProperties) { if (empty($fieldProperties['fields'])) { unset($fieldProperties['fields']); } else { - $this->cleanUpMapping($fieldProperties['fields']); + $this->cleanUpProperties($fieldProperties['fields']); } if (!empty($fieldProperties['properties'])) { - $this->cleanUpMapping($fieldProperties['properties']); + $this->cleanUpProperties($fieldProperties['properties']); } } } diff --git a/Resetter.php b/Resetter.php index fe963d0..d614f1b 100644 --- a/Resetter.php +++ b/Resetter.php @@ -68,7 +68,7 @@ class Resetter { $indexConfig = $this->getIndexConfig($indexName); - if (!isset($indexConfig['config']['mappings'][$typeName]['properties'])) { + if (!isset($indexConfig['config']['properties'][$typeName]['properties'])) { throw new \InvalidArgumentException(sprintf('The mapping for index "%s" and type "%s" does not exist.', $indexName, $typeName)); } @@ -80,7 +80,7 @@ class Resetter throw $e; } } - $mapping = $this->createMapping($indexConfig['config']['mappings'][$typeName]); + $mapping = $this->createMapping($indexConfig['config']['properties'][$typeName]); $type->setMapping($mapping); } diff --git a/Tests/DependencyInjection/ConfigurationTest.php b/Tests/DependencyInjection/ConfigurationTest.php index bddd62e..efaaa52 100644 --- a/Tests/DependencyInjection/ConfigurationTest.php +++ b/Tests/DependencyInjection/ConfigurationTest.php @@ -160,8 +160,8 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase ) )); - $this->assertEquals('string', $configuration['indexes']['test']['types']['test']['mappings']['title']['type']); - $this->assertTrue($configuration['indexes']['test']['types']['test']['mappings']['title']['include_in_all']); + $this->assertEquals('string', $configuration['indexes']['test']['types']['test']['properties']['title']['type']); + $this->assertTrue($configuration['indexes']['test']['types']['test']['properties']['title']['include_in_all']); } public function testEmptyPropertiesIndexIsUnset() @@ -210,7 +210,7 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase $configuration = $processor->processConfiguration(new Configuration(array($config), false), array($config)); - $mapping = $configuration['indexes']['test']['types']['test']['mappings']; + $mapping = $configuration['indexes']['test']['types']['test']['properties']; $this->assertArrayNotHasKey('properties', $mapping['content']); $this->assertArrayNotHasKey('properties', $mapping['title']); $this->assertArrayHasKey('properties', $mapping['children']); @@ -233,4 +233,28 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase $this->assertTrue(empty($configuration['clients']['default']['servers'][0]['url'])); } + + public function testMappingsRenamedToProperties() + { + $configuration = $this->getConfigs(array( + 'clients' => array( + 'default' => array('url' => 'http://localhost:9200'), + ), + 'indexes' => array( + 'test' => array( + 'types' => array( + 'test' => array( + 'mappings' => array( + 'title' => array(), + 'published' => array('type' => 'datetime'), + 'body' => null, + ) + ) + ) + ) + ) + )); + + $this->assertCount(3, $configuration['indexes']['test']['types']['test']['properties']); + } } diff --git a/Tests/ResetterTest.php b/Tests/ResetterTest.php index b4e5649..e27770f 100644 --- a/Tests/ResetterTest.php +++ b/Tests/ResetterTest.php @@ -18,7 +18,7 @@ class ResetterTest extends \PHPUnit_Framework_TestCase 'foo' => array( 'index' => $this->getMockElasticaIndex(), 'config' => array( - 'mappings' => array( + 'properties' => array( 'a' => array( 'dynamic_templates' => array(), 'properties' => array(), @@ -30,7 +30,7 @@ class ResetterTest extends \PHPUnit_Framework_TestCase 'bar' => array( 'index' => $this->getMockElasticaIndex(), 'config' => array( - 'mappings' => array( + 'properties' => array( 'a' => array('properties' => array()), 'b' => array('properties' => array()), ), @@ -39,7 +39,7 @@ class ResetterTest extends \PHPUnit_Framework_TestCase 'parent' => array( 'index' => $this->getMockElasticaIndex(), 'config' => array( - 'mappings' => array( + 'properties' => array( 'a' => array( 'properties' => array( 'field_2' => array() @@ -105,8 +105,8 @@ class ResetterTest extends \PHPUnit_Framework_TestCase $type->expects($this->once()) ->method('delete'); - $mapping = Mapping::create($this->indexConfigsByName['foo']['config']['mappings']['a']['properties']); - $mapping->setParam('dynamic_templates', $this->indexConfigsByName['foo']['config']['mappings']['a']['dynamic_templates']); + $mapping = Mapping::create($this->indexConfigsByName['foo']['config']['properties']['a']['properties']); + $mapping->setParam('dynamic_templates', $this->indexConfigsByName['foo']['config']['properties']['a']['dynamic_templates']); $type->expects($this->once()) ->method('setMapping') ->with($mapping); @@ -149,8 +149,8 @@ class ResetterTest extends \PHPUnit_Framework_TestCase new Response(array('error' => 'TypeMissingException[[de_20131022] type[bla] missing]', 'status' => 404))) )); - $mapping = Mapping::create($this->indexConfigsByName['foo']['config']['mappings']['a']['properties']); - $mapping->setParam('dynamic_templates', $this->indexConfigsByName['foo']['config']['mappings']['a']['dynamic_templates']); + $mapping = Mapping::create($this->indexConfigsByName['foo']['config']['properties']['a']['properties']); + $mapping->setParam('dynamic_templates', $this->indexConfigsByName['foo']['config']['properties']['a']['dynamic_templates']); $type->expects($this->once()) ->method('setMapping') ->with($mapping); @@ -171,7 +171,7 @@ class ResetterTest extends \PHPUnit_Framework_TestCase $type->expects($this->once()) ->method('delete'); - $mapping = Mapping::create($this->indexConfigsByName['parent']['config']['mappings']['a']['properties']); + $mapping = Mapping::create($this->indexConfigsByName['parent']['config']['properties']['a']['properties']); $mapping->setParam('_parent', array('type' => 'b')); $type->expects($this->once()) ->method('setMapping') From a79fa0242e834449ff075285764f878c3e2f5321 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Sun, 25 May 2014 20:08:01 +1000 Subject: [PATCH 245/447] Simplified Configuration.php --- DependencyInjection/Configuration.php | 238 +----------------- DependencyInjection/FOSElasticaExtension.php | 4 +- .../DependencyInjection/ConfigurationTest.php | 63 +---- 3 files changed, 15 insertions(+), 290 deletions(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 275b23d..0d0d238 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -15,13 +15,15 @@ class Configuration implements ConfigurationInterface */ private $supportedDrivers = array('orm', 'mongodb', 'propel'); - private $configArray = array(); + /** + * If the kernel is running in debug mode. + * + * @var bool + */ private $debug; - public function __construct($configArray, $debug) + public function __construct($debug) { - - $this->configArray = $configArray; $this->debug = $debug; } @@ -104,7 +106,7 @@ class Configuration implements ConfigurationInterface ->scalarNode('port')->end() ->scalarNode('proxy')->end() ->scalarNode('logger') - ->defaultValue(($this->debug) ? 'fos_elastica.logger' : false) + ->defaultValue($this->debug ? 'fos_elastica.logger' : false) ->treatNullLike('fos_elastica.logger') ->treatTrueLike('fos_elastica.logger') ->end() @@ -205,28 +207,10 @@ class Configuration implements ConfigurationInterface $builder = new TreeBuilder(); $node = $builder->root('mappings'); - $nestings = $this->getNestings(); - - $childrenNode = $node + $node ->useAttributeAsKey('name') - ->prototype('array') - ->validate() - ->always() - ->then(function($v) { - foreach (array('fields','properties') as $prop) { - if (isset($v[$prop]) && empty($v[$prop])) { - unset($v[$prop]); - } - } - - return $v; - }) - ->end() - ->treatNullLike(array()) - ->addDefaultsIfNotSet() - ->children(); - - $this->addFieldConfig($childrenNode, $nestings); + ->prototype('variable') + ->treatNullLike(array()); return $node; } @@ -249,7 +233,7 @@ class Configuration implements ConfigurationInterface ->scalarNode('path_match')->end() ->scalarNode('path_unmatch')->end() ->scalarNode('match_pattern')->end() - ->append($this->getDynamicTemplateMapping()) + ->append($this->getMappingsNode()) ->end() ->end() ; @@ -257,206 +241,6 @@ class Configuration implements ConfigurationInterface return $node; } - /** - * @return the array node used for mapping in dynamic templates - */ - protected function getDynamicTemplateMapping() - { - $builder = new TreeBuilder(); - $node = $builder->root('mapping'); - - $nestings = $this->getNestingsForDynamicTemplates(); - - $this->addFieldConfig($node->children(), $nestings); - - return $node; - } - - /** - * @param \Symfony\Component\Config\Definition\Builder\NodeBuilder $node The node to which to attach the field config to - * @param array $nestings the nested mappings for the current field level - */ - protected function addFieldConfig($node, $nestings) - { - $node - ->scalarNode('type')->defaultValue('string')->end() - ->scalarNode('boost')->end() - ->scalarNode('store')->end() - ->scalarNode('index')->end() - ->scalarNode('index_analyzer')->end() - ->scalarNode('search_analyzer')->end() - ->scalarNode('analyzer')->end() - ->scalarNode('term_vector')->end() - ->scalarNode('null_value')->end() - ->booleanNode('include_in_all')->defaultValue(true)->end() - ->booleanNode('enabled')->defaultValue(true)->end() - ->scalarNode('lat_lon')->end() - ->scalarNode('tree')->end() - ->scalarNode('precision')->end() - ->scalarNode('tree_levels')->end() - ->scalarNode('geohash')->end() - ->scalarNode('index_name')->end() - ->booleanNode('omit_norms')->end() - ->scalarNode('index_options')->end() - ->scalarNode('ignore_above')->end() - ->scalarNode('position_offset_gap')->end() - ->arrayNode('_parent') - ->treatNullLike(array()) - ->children() - ->scalarNode('type')->end() - ->scalarNode('identifier')->defaultValue('id')->end() - ->end() - ->end() - ->scalarNode('format')->end() - ->scalarNode('similarity')->end(); - ; - - if (isset($nestings['fields'])) { - $this->addNestedFieldConfig($node, $nestings, 'fields'); - } - - if (isset($nestings['properties'])) { - $node - ->booleanNode('include_in_parent')->end() - ->booleanNode('include_in_root')->end() - ; - $this->addNestedFieldConfig($node, $nestings, 'properties'); - } - } - - /** - * @param \Symfony\Component\Config\Definition\Builder\NodeBuilder $node The node to which to attach the nested config to - * @param array $nestings The nestings for the current field level - * @param string $property the name of the nested property ('fields' or 'properties') - */ - protected function addNestedFieldConfig($node, $nestings, $property) - { - $childrenNode = $node - ->arrayNode($property) - ->useAttributeAsKey('name') - ->prototype('array') - ->validate() - ->always() - ->then(function($v) { - foreach (array('fields','properties') as $prop) { - if (isset($v[$prop]) && empty($v[$prop])) { - unset($v[$prop]); - } - } - - return $v; - }) - ->end() - ->treatNullLike(array()) - ->addDefaultsIfNotSet() - ->children(); - - $this->addFieldConfig($childrenNode, $nestings[$property]); - - $childrenNode - ->end() - ->end() - ->end() - ; - } - - /** - * @return array The unique nested mappings for all types - */ - protected function getNestings() - { - if (!isset($this->configArray[0]['indexes'])) { - return array(); - } - - $nestings = array(); - foreach ($this->configArray[0]['indexes'] as $index) { - if (empty($index['types'])) { - continue; - } - - foreach ($index['types'] as $type) { - if (empty($type['mappings'])) { - continue; - } - - $nestings = array_merge_recursive($nestings, $this->getNestingsForType($type['mappings'], $nestings)); - } - } - return $nestings; - } - - /** - * @return array The unique nested mappings for all dynamic templates - */ - protected function getNestingsForDynamicTemplates() - { - if (!isset($this->configArray[0]['indexes'])) { - return array(); - } - - $nestings = array(); - foreach ($this->configArray[0]['indexes'] as $index) { - if (empty($index['types'])) { - continue; - } - - foreach ($index['types'] as $type) { - if (empty($type['dynamic_templates'])) { - continue; - } - - foreach ($type['dynamic_templates'] as $definition) { - $field = $definition['mapping']; - - if (isset($field['fields'])) { - $this->addPropertyNesting($field, $nestings, 'fields'); - } else if (isset($field['properties'])) { - $this->addPropertyNesting($field, $nestings, 'properties'); - } - } - - } - } - return $nestings; - } - - /** - * @param array $mappings The mappings for the current type - * @return array The nested mappings defined for this type - */ - protected function getNestingsForType(array $mappings = null) - { - if ($mappings === null) { - return array(); - } - - $nestings = array(); - - foreach ($mappings as $field) { - if (isset($field['fields'])) { - $this->addPropertyNesting($field, $nestings, 'fields'); - } else if (isset($field['properties'])) { - $this->addPropertyNesting($field, $nestings, 'properties'); - } - } - - return $nestings; - } - - /** - * @param array $field The field mapping definition - * @param array $nestings The nestings array - * @param string $property The nested property name ('fields' or 'properties') - */ - protected function addPropertyNesting($field, &$nestings, $property) - { - if (!isset($nestings[$property])) { - $nestings[$property] = array(); - } - $nestings[$property] = array_merge_recursive($nestings[$property], $this->getNestingsForType($field[$property])); - } - /** * Returns the array node used for "_id". */ diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index f58cd5b..806c273 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -22,7 +22,7 @@ class FOSElasticaExtension extends Extension public function load(array $configs, ContainerBuilder $container) { $configuration = $this->getConfiguration($configs, $container); - $config = $this->processConfiguration($configuration, $configs); + $config = $this->processConfiguration($configuration, $configs); $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); @@ -61,7 +61,7 @@ class FOSElasticaExtension extends Extension public function getConfiguration(array $config, ContainerBuilder $container) { - return new Configuration($config, $container->getParameter('kernel.debug')); + return new Configuration($container->getParameter('kernel.debug')); } /** diff --git a/Tests/DependencyInjection/ConfigurationTest.php b/Tests/DependencyInjection/ConfigurationTest.php index bddd62e..4a4da67 100644 --- a/Tests/DependencyInjection/ConfigurationTest.php +++ b/Tests/DependencyInjection/ConfigurationTest.php @@ -22,7 +22,7 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase private function getConfigs(array $configArray) { - $configuration = new Configuration($configArray, true); + $configuration = new Configuration(true); return $this->processor->processConfiguration($configuration, array($configArray)); } @@ -118,7 +118,7 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase public function testTypeConfig() { - $configuration = $this->getConfigs(array( + $this->getConfigs(array( 'clients' => array( 'default' => array('url' => 'http://localhost:9200'), ), @@ -159,65 +159,6 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase ) ) )); - - $this->assertEquals('string', $configuration['indexes']['test']['types']['test']['mappings']['title']['type']); - $this->assertTrue($configuration['indexes']['test']['types']['test']['mappings']['title']['include_in_all']); - } - - public function testEmptyPropertiesIndexIsUnset() - { - $config = array( - 'indexes' => array( - 'test' => array( - 'types' => array( - 'test' => array( - 'mappings' => array( - 'title' => array( - 'type' => 'string', - 'fields' => array( - 'autocomplete' => null - ) - ), - 'content' => null, - 'children' => array( - 'type' => 'object', - 'properties' => array( - 'title' => array( - 'type' => 'string', - 'fields' => array( - 'autocomplete' => null - ) - ), - 'content' => null, - 'tags' => array( - 'properties' => array( - 'tag' => array( - 'type' => 'string', - 'index' => 'not_analyzed' - ) - ) - ) - ) - ), - ) - ) - ) - ) - ) - ); - - $processor = new Processor(); - - $configuration = $processor->processConfiguration(new Configuration(array($config), false), array($config)); - - $mapping = $configuration['indexes']['test']['types']['test']['mappings']; - $this->assertArrayNotHasKey('properties', $mapping['content']); - $this->assertArrayNotHasKey('properties', $mapping['title']); - $this->assertArrayHasKey('properties', $mapping['children']); - $this->assertArrayNotHasKey('properties', $mapping['children']['properties']['title']); - $this->assertArrayNotHasKey('properties', $mapping['children']['properties']['content']); - $this->assertArrayHasKey('properties', $mapping['children']['properties']['tags']); - $this->assertArrayNotHasKey('properties', $mapping['children']['properties']['tags']['properties']['tag']); } public function testClientConfigurationNoUrl() From 53180e281041f7168943f54b6480582b536221ce Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Sun, 25 May 2014 20:14:51 +1000 Subject: [PATCH 246/447] Bring tidy in line with property renaming --- DependencyInjection/Configuration.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 208026b..60b0684 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -243,7 +243,7 @@ class Configuration implements ConfigurationInterface ->scalarNode('path_match')->end() ->scalarNode('path_unmatch')->end() ->scalarNode('match_pattern')->end() - ->append($this->getMappingsNode()) + ->append($this->getPropertiesNode()) ->end() ->end() ; From dad15d0b387cab71ca1fa68dc70f85ad4310ad38 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Mon, 21 Apr 2014 09:21:50 +1000 Subject: [PATCH 247/447] Deprecate top level classes --- CHANGELOG-3.0.md | 20 +- Client.php | 38 +-- DynamicIndex.php | 20 +- Elastica/Client.php | 47 ++++ Elastica/Index.php | 28 ++ Index/IndexManager.php | 63 +++++ Index/Resetter.php | 246 ++++++++++++++++++ IndexManager.php | 61 +---- Resetter.php | 240 +---------------- Resources/config/config.xml | 4 +- .../LoggingClientTest.php} | 6 +- Tests/{ => Index}/IndexManagerTest.php | 4 +- Tests/{ => Index}/ResetterTest.php | 4 +- 13 files changed, 425 insertions(+), 356 deletions(-) create mode 100644 Elastica/Client.php create mode 100644 Elastica/Index.php create mode 100644 Index/IndexManager.php create mode 100644 Index/Resetter.php rename Tests/{ClientTest.php => Elastica/LoggingClientTest.php} (86%) rename Tests/{ => Index}/IndexManagerTest.php (95%) rename Tests/{ => Index}/ResetterTest.php (98%) diff --git a/CHANGELOG-3.0.md b/CHANGELOG-3.0.md index 9d74640..095c268 100644 --- a/CHANGELOG-3.0.md +++ b/CHANGELOG-3.0.md @@ -12,7 +12,25 @@ https://github.com/FriendsOfSymfony/FOSElasticaBundle/compare/v3.0.0...v3.0.1 To generate a changelog summary since the last version, run `git log --no-merges --oneline v3.0.0...3.0.x` -* 3.0.0-ALPHA3 (xxxx-xx-xx) +* 3.0.0-ALPHA6 + + * Deprecated FOS\ElasticaBundle\Client in favour of FOS\ElasticaBundle\Elastica\Client + * Deprecated FOS\ElasticaBundle\DynamicIndex in favour of FOS\ElasticaBundle\Elastica\Index + * Deprecated FOS\ElasticaBundle\IndexManager in favour of FOS\ElasticaBundle\Index\IndexManager + * Deprecated FOS\ElasticaBundle\Resetter in favour of FOS\ElasticaBundle\Index\Resetter + +* 3.0.0-ALPHA5 (2014-05-23) + +* Doctrine Provider speed up by disabling persistence logging while populating documents + +* 3.0.0-ALPHA4 (2014-04-10) + + * Indexes are now capable of logging errors with Elastica + * Fixed deferred indexing of deleted documents + * Resetting an index will now create it even if it doesn't exist + * Bulk upserting of documents is now supported when populating + +* 3.0.0-ALPHA3 (2014-04-01) * a9c4c93: Logger is now only enabled in debug mode by default * #463: allowing hot swappable reindexing diff --git a/Client.php b/Client.php index 3eb98fe..f85756d 100644 --- a/Client.php +++ b/Client.php @@ -2,43 +2,11 @@ namespace FOS\ElasticaBundle; -use Elastica\Client as ElasticaClient; -use Elastica\Request; -use FOS\ElasticaBundle\Logger\ElasticaLogger; +use FOS\ElasticaBundle\Elastica\LoggingClient; /** - * @author Gordon Franke + * @deprecated Use \FOS\ElasticaBundle\Elastica\LoggingClient */ -class Client extends ElasticaClient +class Client extends LoggingClient { - /** - * {@inheritdoc} - */ - public function request($path, $method = Request::GET, $data = array(), array $query = array()) - { - $start = microtime(true); - $response = parent::request($path, $method, $data, $query); - - if (null !== $this->_logger and $this->_logger instanceof ElasticaLogger) { - $time = microtime(true) - $start; - - $connection = $this->getLastRequest()->getConnection(); - - $connection_array = array( - 'host' => $connection->getHost(), - 'port' => $connection->getPort(), - 'transport' => $connection->getTransport(), - 'headers' => $connection->getConfig('headers'), - ); - - $this->_logger->logQuery($path, $method, $data, $time, $connection_array, $query); - } - - return $response; - } - - public function getIndex($name) - { - return new DynamicIndex($this, $name); - } } diff --git a/DynamicIndex.php b/DynamicIndex.php index cbec8e9..484a0d6 100644 --- a/DynamicIndex.php +++ b/DynamicIndex.php @@ -2,27 +2,11 @@ namespace FOS\ElasticaBundle; -use Elastica\Index; +use FOS\ElasticaBundle\Elastica\Index; /** - * Elastica index capable of reassigning name dynamically - * - * @author Konstantin Tjuterev + * @deprecated Use \FOS\ElasticaBundle\Elastica\TransformingIndex */ class DynamicIndex extends Index { - /** - * Reassign index name - * - * While it's technically a regular setter for name property, it's specifically named overrideName, but not setName - * since it's used for a very specific case and normally should not be used - * - * @param string $name Index name - * - * @return void - */ - public function overrideName($name) - { - $this->_name = $name; - } } diff --git a/Elastica/Client.php b/Elastica/Client.php new file mode 100644 index 0000000..64a7d3d --- /dev/null +++ b/Elastica/Client.php @@ -0,0 +1,47 @@ + + */ +class Client extends BaseClient +{ + /** + * {@inheritdoc} + */ + public function request($path, $method = Request::GET, $data = array(), array $query = array()) + { + $start = microtime(true); + $response = parent::request($path, $method, $data, $query); + + if ($this->_logger and $this->_logger instanceof ElasticaLogger) { + $time = microtime(true) - $start; + + $connection = $this->getLastRequest()->getConnection(); + + $connection_array = array( + 'host' => $connection->getHost(), + 'port' => $connection->getPort(), + 'transport' => $connection->getTransport(), + 'headers' => $connection->getConfig('headers'), + ); + + $this->_logger->logQuery($path, $method, $data, $time, $connection_array, $query); + } + + return $response; + } + + public function getIndex($name) + { + return new Index($this, $name); + } +} diff --git a/Elastica/Index.php b/Elastica/Index.php new file mode 100644 index 0000000..35d49f9 --- /dev/null +++ b/Elastica/Index.php @@ -0,0 +1,28 @@ + + */ +class Index extends BaseIndex +{ + /** + * Reassign index name + * + * While it's technically a regular setter for name property, it's specifically named overrideName, but not setName + * since it's used for a very specific case and normally should not be used + * + * @param string $name Index name + * + * @return void + */ + public function overrideName($name) + { + $this->_name = $name; + } +} diff --git a/Index/IndexManager.php b/Index/IndexManager.php new file mode 100644 index 0000000..543ccae --- /dev/null +++ b/Index/IndexManager.php @@ -0,0 +1,63 @@ +indexesByName = $indexesByName; + $this->defaultIndexName = $defaultIndex->getName(); + } + + /** + * Gets all registered indexes + * + * @return array + */ + public function getAllIndexes() + { + return $this->indexesByName; + } + + /** + * Gets an index by its name + * + * @param string $name Index to return, or the default index if null + * @return Index + * @throws \InvalidArgumentException if no index exists for the given name + */ + public function getIndex($name = null) + { + if (null === $name) { + $name = $this->defaultIndexName; + } + + if (!isset($this->indexesByName[$name])) { + throw new \InvalidArgumentException(sprintf('The index "%s" does not exist', $name)); + } + + return $this->indexesByName[$name]; + } + + /** + * Gets the default index + * + * @return Index + */ + public function getDefaultIndex() + { + return $this->getIndex($this->defaultIndexName); + } +} diff --git a/Index/Resetter.php b/Index/Resetter.php new file mode 100644 index 0000000..99ae75e --- /dev/null +++ b/Index/Resetter.php @@ -0,0 +1,246 @@ +indexConfigsByName = $indexConfigsByName; + } + + /** + * Deletes and recreates all indexes + */ + public function resetAllIndexes() + { + foreach (array_keys($this->indexConfigsByName) as $name) { + $this->resetIndex($name); + } + } + + /** + * Deletes and recreates the named index + * + * @param string $indexName + * @throws \InvalidArgumentException if no index exists for the given name + */ + public function resetIndex($indexName) + { + $indexConfig = $this->getIndexConfig($indexName); + $esIndex = $indexConfig['index']; + if (isset($indexConfig['use_alias']) && $indexConfig['use_alias']) { + $name = $indexConfig['name_or_alias']; + $name .= uniqid(); + $esIndex->overrideName($name); + $esIndex->create($indexConfig['config']); + + return; + } + + $esIndex->create($indexConfig['config'], true); + } + + /** + * Deletes and recreates a mapping type for the named index + * + * @param string $indexName + * @param string $typeName + * @throws \InvalidArgumentException if no index or type mapping exists for the given names + * @throws ResponseException + */ + public function resetIndexType($indexName, $typeName) + { + $indexConfig = $this->getIndexConfig($indexName); + + if (!isset($indexConfig['config']['properties'][$typeName]['properties'])) { + throw new \InvalidArgumentException(sprintf('The mapping for index "%s" and type "%s" does not exist.', $indexName, $typeName)); + } + + $type = $indexConfig['index']->getType($typeName); + try { + $type->delete(); + } catch (ResponseException $e) { + if (strpos($e->getMessage(), 'TypeMissingException') === false) { + throw $e; + } + } + $mapping = $this->createMapping($indexConfig['config']['properties'][$typeName]); + $type->setMapping($mapping); + } + + /** + * create type mapping object + * + * @param array $indexConfig + * @return Mapping + */ + protected function createMapping($indexConfig) + { + $mapping = Mapping::create($indexConfig['properties']); + + $mappingSpecialFields = array('_uid', '_id', '_source', '_all', '_analyzer', '_boost', '_routing', '_index', '_size', '_timestamp', '_ttl', 'dynamic_templates'); + foreach ($mappingSpecialFields as $specialField) { + if (isset($indexConfig[$specialField])) { + $mapping->setParam($specialField, $indexConfig[$specialField]); + } + } + + if (isset($indexConfig['_parent'])) { + $mapping->setParam('_parent', array('type' => $indexConfig['_parent']['type'])); + } + + return $mapping; + } + + /** + * Gets an index config by its name + * + * @param string $indexName Index name + * + * @param $indexName + * @return array + * @throws \InvalidArgumentException if no index config exists for the given name + */ + protected function getIndexConfig($indexName) + { + if (!isset($this->indexConfigsByName[$indexName])) { + throw new \InvalidArgumentException(sprintf('The configuration for index "%s" does not exist.', $indexName)); + } + + return $this->indexConfigsByName[$indexName]; + } + + public function postPopulate($indexName) + { + $indexConfig = $this->getIndexConfig($indexName); + if (isset($indexConfig['use_alias']) && $indexConfig['use_alias']) { + $this->switchIndexAlias($indexName); + } + } + + /** + * Switches the alias for given index (by key) to the newly populated index + * and deletes the old index + * + * @param string $indexName Index name + * + * @throws \RuntimeException + */ + private function switchIndexAlias($indexName) + { + $indexConfig = $this->getIndexConfig($indexName); + $esIndex = $indexConfig['index']; + $aliasName = $indexConfig['name_or_alias']; + $oldIndexName = false; + $newIndexName = $esIndex->getName(); + + $aliasedIndexes = $this->getAliasedIndexes($esIndex, $aliasName); + + if (count($aliasedIndexes) > 1) { + throw new \RuntimeException( + sprintf( + 'Alias %s is used for multiple indexes: [%s]. + Make sure it\'s either not used or is assigned to one index only', + $aliasName, + join(', ', $aliasedIndexes) + ) + ); + } + + // Change the alias to point to the new index + // Elastica's addAlias can't be used directly, because in current (0.19.x) version it's not atomic + // In 0.20.x it's atomic, but it doesn't return the old index name + $aliasUpdateRequest = array('actions' => array()); + if (count($aliasedIndexes) == 1) { + // if the alias is set - add an action to remove it + $oldIndexName = $aliasedIndexes[0]; + $aliasUpdateRequest['actions'][] = array( + 'remove' => array('index' => $oldIndexName, 'alias' => $aliasName) + ); + } + + // add an action to point the alias to the new index + $aliasUpdateRequest['actions'][] = array( + 'add' => array('index' => $newIndexName, 'alias' => $aliasName) + ); + + try { + $esIndex->getClient()->request('_aliases', 'POST', $aliasUpdateRequest); + } catch (ExceptionInterface $renameAliasException) { + $additionalError = ''; + // if we failed to move the alias, delete the newly built index + try { + $esIndex->delete(); + } catch (ExceptionInterface $deleteNewIndexException) { + $additionalError = sprintf( + 'Tried to delete newly built index %s, but also failed: %s', + $newIndexName, + $deleteNewIndexException->getError() + ); + } + + throw new \RuntimeException( + sprintf( + 'Failed to updated index alias: %s. %s', + $renameAliasException->getMessage(), + $additionalError ?: sprintf('Newly built index %s was deleted', $newIndexName) + ) + ); + } + + // Delete the old index after the alias has been switched + if ($oldIndexName) { + $oldIndex = new Index($esIndex->getClient(), $oldIndexName); + try { + $oldIndex->delete(); + } catch (ExceptionInterface $deleteOldIndexException) { + throw new \RuntimeException( + sprintf( + 'Failed to delete old index %s with message: %s', + $oldIndexName, + $deleteOldIndexException->getMessage() + ) + ); + } + } + } + + /** + * Returns array of indexes which are mapped to given alias + * + * @param Index $esIndex ES Index + * @param string $aliasName Alias name + * + * @return array + */ + private function getAliasedIndexes(Index $esIndex, $aliasName) + { + $aliasesInfo = $esIndex->getClient()->request('_aliases', 'GET')->getData(); + $aliasedIndexes = array(); + + foreach ($aliasesInfo as $indexName => $indexInfo) { + $aliases = array_keys($indexInfo['aliases']); + if (in_array($aliasName, $aliases)) { + $aliasedIndexes[] = $indexName; + } + } + + return $aliasedIndexes; + } +} diff --git a/IndexManager.php b/IndexManager.php index e20a791..e7c74c8 100644 --- a/IndexManager.php +++ b/IndexManager.php @@ -2,62 +2,11 @@ namespace FOS\ElasticaBundle; -use Elastica\Index; +use FOS\ElasticaBundle\Index\IndexManager as BaseIndexManager; -class IndexManager +/** + * @deprecated Use \FOS\ElasticaBundle\Index\IndexManager + */ +class IndexManager extends BaseIndexManager { - protected $indexesByName; - protected $defaultIndexName; - - /** - * Constructor. - * - * @param array $indexesByName - * @param Index $defaultIndex - */ - public function __construct(array $indexesByName, Index $defaultIndex) - { - $this->indexesByName = $indexesByName; - $this->defaultIndexName = $defaultIndex->getName(); - } - - /** - * Gets all registered indexes - * - * @return array - */ - public function getAllIndexes() - { - return $this->indexesByName; - } - - /** - * Gets an index by its name - * - * @param string $name Index to return, or the default index if null - * @return Index - * @throws \InvalidArgumentException if no index exists for the given name - */ - public function getIndex($name = null) - { - if (null === $name) { - $name = $this->defaultIndexName; - } - - if (!isset($this->indexesByName[$name])) { - throw new \InvalidArgumentException(sprintf('The index "%s" does not exist', $name)); - } - - return $this->indexesByName[$name]; - } - - /** - * Gets the default index - * - * @return Index - */ - public function getDefaultIndex() - { - return $this->getIndex($this->defaultIndexName); - } } diff --git a/Resetter.php b/Resetter.php index d614f1b..2067579 100644 --- a/Resetter.php +++ b/Resetter.php @@ -2,245 +2,11 @@ namespace FOS\ElasticaBundle; -use Elastica\Exception\ExceptionInterface; -use Elastica\Index; -use Elastica\Exception\ResponseException; -use Elastica\Type\Mapping; +use FOS\ElasticaBundle\Index\Resetter as BaseResetter; /** - * Deletes and recreates indexes + * @deprecated Use \FOS\ElasticaBundle\Index\Resetter */ -class Resetter +class Resetter extends BaseResetter { - protected $indexConfigsByName; - - /** - * Constructor. - * - * @param array $indexConfigsByName - */ - public function __construct(array $indexConfigsByName) - { - $this->indexConfigsByName = $indexConfigsByName; - } - - /** - * Deletes and recreates all indexes - */ - public function resetAllIndexes() - { - foreach (array_keys($this->indexConfigsByName) as $name) { - $this->resetIndex($name); - } - } - - /** - * Deletes and recreates the named index - * - * @param string $indexName - * @throws \InvalidArgumentException if no index exists for the given name - */ - public function resetIndex($indexName) - { - $indexConfig = $this->getIndexConfig($indexName); - $esIndex = $indexConfig['index']; - if (isset($indexConfig['use_alias']) && $indexConfig['use_alias']) { - $name = $indexConfig['name_or_alias']; - $name .= uniqid(); - $esIndex->overrideName($name); - $esIndex->create($indexConfig['config']); - - return; - } - - $esIndex->create($indexConfig['config'], true); - } - - /** - * Deletes and recreates a mapping type for the named index - * - * @param string $indexName - * @param string $typeName - * @throws \InvalidArgumentException if no index or type mapping exists for the given names - * @throws ResponseException - */ - public function resetIndexType($indexName, $typeName) - { - $indexConfig = $this->getIndexConfig($indexName); - - if (!isset($indexConfig['config']['properties'][$typeName]['properties'])) { - throw new \InvalidArgumentException(sprintf('The mapping for index "%s" and type "%s" does not exist.', $indexName, $typeName)); - } - - $type = $indexConfig['index']->getType($typeName); - try { - $type->delete(); - } catch (ResponseException $e) { - if (strpos($e->getMessage(), 'TypeMissingException') === false) { - throw $e; - } - } - $mapping = $this->createMapping($indexConfig['config']['properties'][$typeName]); - $type->setMapping($mapping); - } - - /** - * create type mapping object - * - * @param array $indexConfig - * @return Mapping - */ - protected function createMapping($indexConfig) - { - $mapping = Mapping::create($indexConfig['properties']); - - $mappingSpecialFields = array('_uid', '_id', '_source', '_all', '_analyzer', '_boost', '_routing', '_index', '_size', '_timestamp', '_ttl', 'dynamic_templates'); - foreach ($mappingSpecialFields as $specialField) { - if (isset($indexConfig[$specialField])) { - $mapping->setParam($specialField, $indexConfig[$specialField]); - } - } - - if (isset($indexConfig['_parent'])) { - $mapping->setParam('_parent', array('type' => $indexConfig['_parent']['type'])); - } - - return $mapping; - } - - /** - * Gets an index config by its name - * - * @param string $indexName Index name - * - * @param $indexName - * @return array - * @throws \InvalidArgumentException if no index config exists for the given name - */ - protected function getIndexConfig($indexName) - { - if (!isset($this->indexConfigsByName[$indexName])) { - throw new \InvalidArgumentException(sprintf('The configuration for index "%s" does not exist.', $indexName)); - } - - return $this->indexConfigsByName[$indexName]; - } - - public function postPopulate($indexName) - { - $indexConfig = $this->getIndexConfig($indexName); - if (isset($indexConfig['use_alias']) && $indexConfig['use_alias']) { - $this->switchIndexAlias($indexName); - } - } - - /** - * Switches the alias for given index (by key) to the newly populated index - * and deletes the old index - * - * @param string $indexName Index name - * - * @throws \RuntimeException - */ - private function switchIndexAlias($indexName) - { - $indexConfig = $this->getIndexConfig($indexName); - $esIndex = $indexConfig['index']; - $aliasName = $indexConfig['name_or_alias']; - $oldIndexName = false; - $newIndexName = $esIndex->getName(); - - $aliasedIndexes = $this->getAliasedIndexes($esIndex, $aliasName); - - if (count($aliasedIndexes) > 1) { - throw new \RuntimeException( - sprintf( - 'Alias %s is used for multiple indexes: [%s]. - Make sure it\'s either not used or is assigned to one index only', - $aliasName, - join(', ', $aliasedIndexes) - ) - ); - } - - // Change the alias to point to the new index - // Elastica's addAlias can't be used directly, because in current (0.19.x) version it's not atomic - // In 0.20.x it's atomic, but it doesn't return the old index name - $aliasUpdateRequest = array('actions' => array()); - if (count($aliasedIndexes) == 1) { - // if the alias is set - add an action to remove it - $oldIndexName = $aliasedIndexes[0]; - $aliasUpdateRequest['actions'][] = array( - 'remove' => array('index' => $oldIndexName, 'alias' => $aliasName) - ); - } - - // add an action to point the alias to the new index - $aliasUpdateRequest['actions'][] = array( - 'add' => array('index' => $newIndexName, 'alias' => $aliasName) - ); - - try { - $esIndex->getClient()->request('_aliases', 'POST', $aliasUpdateRequest); - } catch (ExceptionInterface $renameAliasException) { - $additionalError = ''; - // if we failed to move the alias, delete the newly built index - try { - $esIndex->delete(); - } catch (ExceptionInterface $deleteNewIndexException) { - $additionalError = sprintf( - 'Tried to delete newly built index %s, but also failed: %s', - $newIndexName, - $deleteNewIndexException->getError() - ); - } - - throw new \RuntimeException( - sprintf( - 'Failed to updated index alias: %s. %s', - $renameAliasException->getMessage(), - $additionalError ?: sprintf('Newly built index %s was deleted', $newIndexName) - ) - ); - } - - // Delete the old index after the alias has been switched - if ($oldIndexName) { - $oldIndex = new Index($esIndex->getClient(), $oldIndexName); - try { - $oldIndex->delete(); - } catch (ExceptionInterface $deleteOldIndexException) { - throw new \RuntimeException( - sprintf( - 'Failed to delete old index %s with message: %s', - $oldIndexName, - $deleteOldIndexException->getMessage() - ) - ); - } - } - } - - /** - * Returns array of indexes which are mapped to given alias - * - * @param Index $esIndex ES Index - * @param string $aliasName Alias name - * - * @return array - */ - private function getAliasedIndexes(Index $esIndex, $aliasName) - { - $aliasesInfo = $esIndex->getClient()->request('_aliases', 'GET')->getData(); - $aliasedIndexes = array(); - - foreach ($aliasesInfo as $indexName => $indexInfo) { - $aliases = array_keys($indexInfo['aliases']); - if (in_array($aliasName, $aliases)) { - $aliasedIndexes[] = $indexName; - } - } - - return $aliasedIndexes; - } } diff --git a/Resources/config/config.xml b/Resources/config/config.xml index 7687250..cff2b49 100644 --- a/Resources/config/config.xml +++ b/Resources/config/config.xml @@ -5,8 +5,8 @@ xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> - FOS\ElasticaBundle\Client - FOS\ElasticaBundle\DynamicIndex + FOS\ElasticaBundle\Elastica\Client + FOS\ElasticaBundle\Elastica\Index Elastica\Type FOS\ElasticaBundle\IndexManager FOS\ElasticaBundle\Resetter diff --git a/Tests/ClientTest.php b/Tests/Elastica/LoggingClientTest.php similarity index 86% rename from Tests/ClientTest.php rename to Tests/Elastica/LoggingClientTest.php index 8a9d91a..b08a2cf 100644 --- a/Tests/ClientTest.php +++ b/Tests/Elastica/LoggingClientTest.php @@ -1,11 +1,11 @@ isType('array') ); - $client = $this->getMockBuilder('FOS\ElasticaBundle\Client') + $client = $this->getMockBuilder('FOS\ElasticaBundle\Elastica\LoggingClient') ->setMethods(array('getConnection')) ->getMock(); diff --git a/Tests/IndexManagerTest.php b/Tests/Index/IndexManagerTest.php similarity index 95% rename from Tests/IndexManagerTest.php rename to Tests/Index/IndexManagerTest.php index 0a8ea37..624f64e 100644 --- a/Tests/IndexManagerTest.php +++ b/Tests/Index/IndexManagerTest.php @@ -1,8 +1,8 @@ Date: Sun, 25 May 2014 18:51:14 +0200 Subject: [PATCH 248/447] fixing missing flush event handler In [commit](https://github.com/FriendsOfSymfony/FOSElasticaBundle/commit/843c76b6cabd0fb71ef03cd95b9702e9dd41b2fc#diff-850942b3ba24ab03a40aaa81b6152852) the configuration-definition for the flush listener was accidentally removed. As the flush listener is no longer set to be enabled in the extensions getDoctrineEvents method, the flush listener is not set. This results in a situation were we are only able to have the modified objects on the list for index-update, but never actually sending the update to the ES host. --- DependencyInjection/Configuration.php | 1 + 1 file changed, 1 insertion(+) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 275b23d..35d399f 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -654,6 +654,7 @@ class Configuration implements ConfigurationInterface ->scalarNode('insert')->defaultTrue()->end() ->scalarNode('update')->defaultTrue()->end() ->scalarNode('delete')->defaultTrue()->end() + ->scalarNode('flush')->defaultTrue()->end() ->booleanNode('immediate')->defaultFalse()->end() ->scalarNode('logger') ->defaultFalse() From 2e0aa064a2b1d71a6315e21d5d7fedabeb58a0ab Mon Sep 17 00:00:00 2001 From: Tornaldo Date: Sun, 1 Jun 2014 01:27:20 +0200 Subject: [PATCH 249/447] Update usage.md --- Resources/doc/usage.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/doc/usage.md b/Resources/doc/usage.md index c1d5982..91f13ae 100644 --- a/Resources/doc/usage.md +++ b/Resources/doc/usage.md @@ -184,7 +184,7 @@ The following code will execute a search against the Elasticsearch server: $finder = $this->container->get('fos_elastica.finder.site.article'); $boolQuery = new \Elastica\Query\Bool(); -$fieldQuery = new \Elastica\Query\Text(); +$fieldQuery = new \Elastica\Query\Match(); $fieldQuery->setFieldQuery('title', 'I am a title string'); $fieldQuery->setFieldParam('title', 'analyzer', 'my_analyzer'); $boolQuery->addShould($fieldQuery); From 6a822504bc0cad280c4c7a713d089d5bcb919c76 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Sun, 1 Jun 2014 15:57:29 +0200 Subject: [PATCH 250/447] use $this->container instead of $container --- Resources/doc/usage.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Resources/doc/usage.md b/Resources/doc/usage.md index 91f13ae..55d90ab 100644 --- a/Resources/doc/usage.md +++ b/Resources/doc/usage.md @@ -65,7 +65,7 @@ You can now use the index wide finder service `fos_elastica.finder.website`: ```php /** var FOS\ElasticaBundle\Finder\MappedFinder */ -$finder = $container->get('fos_elastica.finder.website'); +$finder = $this->container->get('fos_elastica.finder.website'); // Returns a mixed array of any objects mapped $results = $finder->find('bob'); @@ -91,7 +91,7 @@ An example for using a repository: ```php /** var FOS\ElasticaBundle\Manager\RepositoryManager */ -$repositoryManager = $container->get('fos_elastica.manager'); +$repositoryManager = $this->container->get('fos_elastica.manager'); /** var FOS\ElasticaBundle\Repository */ $repository = $repositoryManager->getRepository('UserBundle:User'); From 1dc6856ef9c28f253a2e47f3dfb3396a4b24b5c5 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Mon, 2 Jun 2014 00:40:03 +1000 Subject: [PATCH 251/447] Configuration rework --- DependencyInjection/Configuration.php | 2 +- DependencyInjection/FOSElasticaExtension.php | 406 ++++++++++--------- Resources/config/config.xml | 84 +--- Resources/config/index.xml | 39 ++ Resources/config/mongodb.xml | 4 +- Resources/config/orm.xml | 12 +- Resources/config/persister.xml | 27 ++ Resources/config/propel.xml | 3 - Resources/config/provider.xml | 18 + Resources/config/transformer.xml | 32 ++ Tests/Integration/MappingTest.php | 17 + 11 files changed, 372 insertions(+), 272 deletions(-) create mode 100644 Resources/config/index.xml create mode 100644 Resources/config/persister.xml create mode 100644 Resources/config/provider.xml create mode 100644 Resources/config/transformer.xml create mode 100644 Tests/Integration/MappingTest.php diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 60b0684..2acc9e5 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -288,7 +288,7 @@ class Configuration implements ConfigurationInterface ->end() ->scalarNode('compress')->end() ->scalarNode('compress_threshold')->end() - ->scalarNode('enabled')->end() + ->scalarNode('enabled')->defaultTrue()->end() ->end() ; diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index e896af2..c844f3a 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -13,9 +13,28 @@ use InvalidArgumentException; class FOSElasticaExtension extends Extension { - protected $indexConfigs = array(); - protected $typeFields = array(); - protected $loadedDrivers = array(); + /** + * Definition of elastica clients as configured by this extension. + * + * @var array + */ + private $clients = array(); + + /** + * An array of indexes as configured by the extension. + * + * @var array + */ + private $indexConfigs = array(); + + /** + * If we've encountered a type mapped to a specific persistence driver, it will be loaded + * here. + * + * @var array + */ + private $loadedDrivers = array(); + protected $serializerConfig = array(); public function load(array $configs, ContainerBuilder $container) @@ -30,7 +49,9 @@ class FOSElasticaExtension extends Extension return; } - $loader->load('config.xml'); + foreach (array('config', 'index', 'persister', 'provider', 'transformer') as $basename) { + $loader->load(sprintf('%s.xml', $basename)); + } if (empty($config['default_client'])) { $keys = array_keys($config['clients']); @@ -42,22 +63,24 @@ class FOSElasticaExtension extends Extension $config['default_index'] = reset($keys); } - $clientIdsByName = $this->loadClients($config['clients'], $container); $this->serializerConfig = isset($config['serializer']) ? $config['serializer'] : null; - $indexIdsByName = $this->loadIndexes($config['indexes'], $container, $clientIdsByName, $config['default_client']); - $indexRefsByName = array_map(function($id) { - return new Reference($id); - }, $indexIdsByName); - - $this->loadIndexManager($indexRefsByName, $container); - $this->loadResetter($this->indexConfigs, $container); + $this->loadClients($config['clients'], $container); $container->setAlias('fos_elastica.client', sprintf('fos_elastica.client.%s', $config['default_client'])); + + $this->loadIndexes($config['indexes'], $container); $container->setAlias('fos_elastica.index', sprintf('fos_elastica.index.%s', $config['default_index'])); + $this->loadIndexManager($container); + $this->createDefaultManagerAlias($config['default_manager'], $container); } + /** + * @param array $config + * @param ContainerBuilder $container + * @return Configuration|null|\Symfony\Component\Config\Definition\ConfigurationInterface + */ public function getConfiguration(array $config, ContainerBuilder $container) { return new Configuration($container->getParameter('kernel.debug')); @@ -70,24 +93,26 @@ class FOSElasticaExtension extends Extension * @param ContainerBuilder $container A ContainerBuilder instance * @return array */ - protected function loadClients(array $clients, ContainerBuilder $container) + private function loadClients(array $clients, ContainerBuilder $container) { - $clientIds = array(); foreach ($clients as $name => $clientConfig) { $clientId = sprintf('fos_elastica.client.%s', $name); - $clientDef = new Definition('%fos_elastica.client.class%', array($clientConfig)); + + $clientDef = new DefinitionDecorator('fos_elastica.client_prototype'); + $clientDef->replaceArgument(0, $clientConfig); + $logger = $clientConfig['servers'][0]['logger']; if (false !== $logger) { $clientDef->addMethodCall('setLogger', array(new Reference($logger))); } - $clientDef->addTag('fos_elastica.client'); $container->setDefinition($clientId, $clientDef); - $clientIds[$name] = $clientId; + $this->clients[$name] = array( + 'id' => $clientId, + 'reference' => new Reference($clientId) + ); } - - return $clientIds; } /** @@ -95,56 +120,44 @@ class FOSElasticaExtension extends Extension * * @param array $indexes An array of indexes configurations * @param ContainerBuilder $container A ContainerBuilder instance - * @param array $clientIdsByName - * @param $defaultClientName - * @param $serializerConfig * @throws \InvalidArgumentException * @return array */ - protected function loadIndexes(array $indexes, ContainerBuilder $container, array $clientIdsByName, $defaultClientName) + private function loadIndexes(array $indexes, ContainerBuilder $container) { - $indexIds = array(); foreach ($indexes as $name => $index) { - if (isset($index['client'])) { - $clientName = $index['client']; - if (!isset($clientIdsByName[$clientName])) { - throw new InvalidArgumentException(sprintf('The elastica client with name "%s" is not defined', $clientName)); - } - } else { - $clientName = $defaultClientName; - } - - $clientId = $clientIdsByName[$clientName]; $indexId = sprintf('fos_elastica.index.%s', $name); - $indexName = isset($index['index_name']) ? $index['index_name'] : $name; - $indexDefArgs = array($indexName); - $indexDef = new Definition('%fos_elastica.index.class%', $indexDefArgs); - $indexDef->setFactoryService($clientId); - $indexDef->setFactoryMethod('getIndex'); + $indexName = $index['index_name'] ?: $name; + + $indexDef = new DefinitionDecorator('fos_elastica.index_prototype'); + $indexDef->replaceArgument(0, $indexName); + + if ($index['client']) { + $client = $this->getClient($index['client']); + $indexDef->setFactoryService($client); + } + $container->setDefinition($indexId, $indexDef); - $typePrototypeConfig = isset($index['type_prototype']) ? $index['type_prototype'] : array(); - $indexIds[$name] = $indexId; + $reference = new Reference($indexId); + $this->indexConfigs[$name] = array( - 'index' => new Reference($indexId), - 'name_or_alias' => $indexName, 'config' => array( - 'properties' => array() - ) + 'properties' => array(), + 'settings' => $index['settings'] + ), + 'elasticsearch_name' => $indexName, + 'index' => $reference, + 'name' => $name, + 'type_prototype' => isset($index['type_prototype']) ? $index['type_prototype'] : array(), + 'use_alias' => $index['use_alias'], ); + if ($index['finder']) { - $this->loadIndexFinder($container, $name, $indexId); - } - if (!empty($index['settings'])) { - $this->indexConfigs[$name]['config']['settings'] = $index['settings']; - } - if ($index['use_alias']) { - $this->indexConfigs[$name]['use_alias'] = true; + $this->loadIndexFinder($container, $name, $reference); } - $this->loadTypes(isset($index['types']) ? $index['types'] : array(), $container, $name, $indexId, $typePrototypeConfig); + $this->loadTypes((array) $index['types'], $container, $this->indexConfigs[$name]); } - - return $indexIds; } /** @@ -152,10 +165,10 @@ class FOSElasticaExtension extends Extension * * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container * @param string $name The index name - * @param string $indexId The index service identifier + * @param Reference $index Reference to the related index * @return string */ - protected function loadIndexFinder(ContainerBuilder $container, $name, $indexId) + private function loadIndexFinder(ContainerBuilder $container, $name, Reference $index) { /* Note: transformer services may conflict with "collection.index", if * an index and type names were "collection" and an index, respectively. @@ -166,34 +179,60 @@ class FOSElasticaExtension extends Extension $finderId = sprintf('fos_elastica.finder.%s', $name); $finderDef = new DefinitionDecorator('fos_elastica.finder'); - $finderDef->replaceArgument(0, new Reference($indexId)); + $finderDef->replaceArgument(0, $index); $finderDef->replaceArgument(1, new Reference($transformerId)); $container->setDefinition($finderId, $finderDef); - - return $finderId; } /** * Loads the configured types. * - * @param array $types An array of types configurations - * @param ContainerBuilder $container A ContainerBuilder instance - * @param $indexName - * @param $indexId - * @param array $typePrototypeConfig - * @param $serializerConfig + * @param array $types + * @param ContainerBuilder $container + * @param array $indexConfig */ - protected function loadTypes(array $types, ContainerBuilder $container, $indexName, $indexId, array $typePrototypeConfig) + private function loadTypes(array $types, ContainerBuilder $container, array $indexConfig) { foreach ($types as $name => $type) { - $type = self::deepArrayUnion($typePrototypeConfig, $type); - $typeId = sprintf('%s.%s', $indexId, $name); - $typeDefArgs = array($name); - $typeDef = new Definition('%fos_elastica.type.class%', $typeDefArgs); - $typeDef->setFactoryService($indexId); - $typeDef->setFactoryMethod('getType'); - if ($this->serializerConfig) { + $indexName = $indexConfig['name']; + $type = self::deepArrayUnion($indexConfig['type_prototype'], $type); + + $typeId = sprintf('%s.%s', $indexName, $name); + $typeDef = new DefinitionDecorator('fos_elastica.type_prototype'); + $typeDef->replaceArgument(0, $name); + $typeDef->setFactoryService($indexConfig['reference']); + + if (isset($type['persistence'])) { + $this->loadTypePersistenceIntegration($type['persistence'], $container, $typeDef, $indexName, $name); + } + + foreach (array( + 'index_analyzer', + 'properties', + 'search_analyzer', + '_all', + '_boost', + '_id', + '_parent', + '_routing', + '_source', + '_timestamp', + '_ttl', + ) as $field) { + $this->indexConfigs[$indexName]['config']['properties'][$name][$field] = $type[$field]; + } + + if (!empty($type['dynamic_templates'])) { + $this->indexConfigs[$indexName]['config']['properties'][$name]['dynamic_templates'] = array(); + foreach ($type['dynamic_templates'] as $templateName => $templateData) { + $this->indexConfigs[$indexName]['config']['properties'][$name]['dynamic_templates'][] = array($templateName => $templateData); + } + } + + $container->setDefinition($typeId, $typeDef); + + /*if ($this->serializerConfig) { $callbackDef = new Definition($this->serializerConfig['callback_class']); $callbackId = sprintf('%s.%s.serializer.callback', $indexId, $name); @@ -213,63 +252,7 @@ class FOSElasticaExtension extends Extension $container->setDefinition($callbackId, $callbackDef); $typeDef->addMethodCall('setSerializer', array(array(new Reference($callbackId), 'serialize'))); - } - $container->setDefinition($typeId, $typeDef); - - $this->indexConfigs[$indexName]['config']['properties'][$name] = array( - "_source" => array("enabled" => true), // Add a default setting for empty mapping settings - ); - - if (isset($type['_id'])) { - $this->indexConfigs[$indexName]['config']['properties'][$name]['_id'] = $type['_id']; - } - if (isset($type['_source'])) { - $this->indexConfigs[$indexName]['config']['properties'][$name]['_source'] = $type['_source']; - } - if (isset($type['_boost'])) { - $this->indexConfigs[$indexName]['config']['properties'][$name]['_boost'] = $type['_boost']; - } - if (isset($type['_routing'])) { - $this->indexConfigs[$indexName]['config']['properties'][$name]['_routing'] = $type['_routing']; - } - if (isset($type['properties']) && !empty($type['properties'])) { - $this->cleanUpProperties($type['properties']); - $this->indexConfigs[$indexName]['config']['properties'][$name]['properties'] = $type['properties']; - $typeName = sprintf('%s/%s', $indexName, $name); - $this->typeFields[$typeName] = $type['properties']; - } - if (isset($type['_parent'])) { - $this->indexConfigs[$indexName]['config']['properties'][$name]['_parent'] = array('type' => $type['_parent']['type']); - $typeName = sprintf('%s/%s', $indexName, $name); - $this->typeFields[$typeName]['_parent'] = $type['_parent']; - } - if (isset($type['persistence'])) { - $this->loadTypePersistenceIntegration($type['persistence'], $container, $typeDef, $indexName, $name); - } - if (isset($type['index_analyzer'])) { - $this->indexConfigs[$indexName]['config']['properties'][$name]['index_analyzer'] = $type['index_analyzer']; - } - if (isset($type['search_analyzer'])) { - $this->indexConfigs[$indexName]['config']['properties'][$name]['search_analyzer'] = $type['search_analyzer']; - } - if (isset($type['index'])) { - $this->indexConfigs[$indexName]['config']['properties'][$name]['index'] = $type['index']; - } - if (isset($type['_all'])) { - $this->indexConfigs[$indexName]['config']['properties'][$name]['_all'] = $type['_all']; - } - if (isset($type['_timestamp'])) { - $this->indexConfigs[$indexName]['config']['properties'][$name]['_timestamp'] = $type['_timestamp']; - } - if (isset($type['_ttl'])) { - $this->indexConfigs[$indexName]['config']['properties'][$name]['_ttl'] = $type['_ttl']; - } - if (!empty($type['dynamic_templates'])) { - $this->indexConfigs[$indexName]['config']['properties'][$name]['dynamic_templates'] = array(); - foreach ($type['dynamic_templates'] as $templateName => $templateData) { - $this->indexConfigs[$indexName]['config']['properties'][$name]['dynamic_templates'][] = array($templateName => $templateData); - } - } + }*/ } } @@ -281,7 +264,7 @@ class FOSElasticaExtension extends Extension * * @return array The merged array */ - static protected function deepArrayUnion($array1, $array2) + private static function deepArrayUnion($array1, $array2) { foreach ($array2 as $key => $value) { if (is_array($value) && isset($array1[$key]) && is_array($array1[$key])) { @@ -303,30 +286,40 @@ class FOSElasticaExtension extends Extension * @param $indexName * @param $typeName */ - protected function loadTypePersistenceIntegration(array $typeConfig, ContainerBuilder $container, Definition $typeDef, $indexName, $typeName) + private function loadTypePersistenceIntegration(array $typeConfig, ContainerBuilder $container, Definition $typeDef, $indexName, $typeName) { $this->loadDriver($container, $typeConfig['driver']); $elasticaToModelTransformerId = $this->loadElasticaToModelTransformer($typeConfig, $container, $indexName, $typeName); $modelToElasticaTransformerId = $this->loadModelToElasticaTransformer($typeConfig, $container, $indexName, $typeName); - $objectPersisterId = $this->loadObjectPersister($typeConfig, $typeDef, $container, $indexName, $typeName, $modelToElasticaTransformerId); + $objectPersisterId = $this->loadObjectPersister($typeConfig, $typeDef, $container, $indexName, $typeName, $modelToElasticaTransformerId); if (isset($typeConfig['provider'])) { - $this->loadTypeProvider($typeConfig, $container, $objectPersisterId, $typeDef, $indexName, $typeName); + $this->loadTypeProvider($typeConfig, $container, $objectPersisterId, $indexName, $typeName); } if (isset($typeConfig['finder'])) { $this->loadTypeFinder($typeConfig, $container, $elasticaToModelTransformerId, $typeDef, $indexName, $typeName); } if (isset($typeConfig['listener'])) { - $this->loadTypeListener($typeConfig, $container, $objectPersisterId, $typeDef, $indexName, $typeName); + $this->loadTypeListener($typeConfig, $container, $objectPersisterId, $indexName, $typeName); } } - protected function loadElasticaToModelTransformer(array $typeConfig, ContainerBuilder $container, $indexName, $typeName) + /** + * Creates and loads an ElasticaToModelTransformer. + * + * @param array $typeConfig + * @param ContainerBuilder $container + * @param string $indexName + * @param string $typeName + * @return string + */ + private function loadElasticaToModelTransformer(array $typeConfig, ContainerBuilder $container, $indexName, $typeName) { if (isset($typeConfig['elastica_to_model_transformer']['service'])) { return $typeConfig['elastica_to_model_transformer']['service']; } + /* Note: transformer services may conflict with "prototype.driver", if * the index and type names were "prototype" and a driver, respectively. */ @@ -339,28 +332,32 @@ class FOSElasticaExtension extends Extension $argPos = ('propel' === $typeConfig['driver']) ? 0 : 1; $serviceDef->replaceArgument($argPos, $typeConfig['model']); - $serviceDef->replaceArgument($argPos + 1, array( - 'hydrate' => $typeConfig['elastica_to_model_transformer']['hydrate'], - 'identifier' => $typeConfig['identifier'], - 'ignore_missing' => $typeConfig['elastica_to_model_transformer']['ignore_missing'], - 'query_builder_method' => $typeConfig['elastica_to_model_transformer']['query_builder_method'] - )); + $serviceDef->replaceArgument($argPos + 1, array_merge($typeConfig['elastica_to_model_transformer'], array( + 'identifier' => $typeConfig['identifier'], + ))); $container->setDefinition($serviceId, $serviceDef); return $serviceId; } - protected function loadModelToElasticaTransformer(array $typeConfig, ContainerBuilder $container, $indexName, $typeName) + /** + * Creates and loads a ModelToElasticaTransformer for an index/type. + * + * @param array $typeConfig + * @param ContainerBuilder $container + * @param string $indexName + * @param string $typeName + * @return string + */ + private function loadModelToElasticaTransformer(array $typeConfig, ContainerBuilder $container, $indexName, $typeName) { if (isset($typeConfig['model_to_elastica_transformer']['service'])) { return $typeConfig['model_to_elastica_transformer']['service']; } - if ($this->serializerConfig) { - $abstractId = sprintf('fos_elastica.model_to_elastica_identifier_transformer'); - } else { - $abstractId = sprintf('fos_elastica.model_to_elastica_transformer'); - } + $abstractId = $this->serializerConfig ? + 'fos_elastica.model_to_elastica_identifier_transformer' : + 'fos_elastica.model_to_elastica_transformer'; $serviceId = sprintf('fos_elastica.model_to_elastica_transformer.%s.%s', $indexName, $typeName); $serviceDef = new DefinitionDecorator($abstractId); @@ -372,7 +369,18 @@ class FOSElasticaExtension extends Extension return $serviceId; } - protected function loadObjectPersister(array $typeConfig, Definition $typeDef, ContainerBuilder $container, $indexName, $typeName, $transformerId) + /** + * Creates and loads an object persister for a type. + * + * @param array $typeConfig + * @param Definition $typeDef + * @param ContainerBuilder $container + * @param string $indexName + * @param string $typeName + * @param string $transformerId + * @return string + */ + private function loadObjectPersister(array $typeConfig, Definition $typeDef, ContainerBuilder $container, $indexName, $typeName, $transformerId) { $arguments = array( $typeDef, @@ -386,8 +394,9 @@ class FOSElasticaExtension extends Extension $arguments[] = array(new Reference($callbackId), 'serialize'); } else { $abstractId = 'fos_elastica.object_persister'; - $arguments[] = $this->typeFields[sprintf('%s/%s', $indexName, $typeName)]; + $arguments[] = $this->indexConfigs[$indexName]['config']['properties'][$typeName]['properties']; } + $serviceId = sprintf('fos_elastica.object_persister.%s.%s', $indexName, $typeName); $serviceDef = new DefinitionDecorator($abstractId); foreach ($arguments as $i => $argument) { @@ -399,11 +408,22 @@ class FOSElasticaExtension extends Extension return $serviceId; } - protected function loadTypeProvider(array $typeConfig, ContainerBuilder $container, $objectPersisterId, $typeDef, $indexName, $typeName) + /** + * Loads a provider for a type. + * + * @param array $typeConfig + * @param ContainerBuilder $container + * @param string $objectPersisterId + * @param string $indexName + * @param string $typeName + * @return string + */ + private function loadTypeProvider(array $typeConfig, ContainerBuilder $container, $objectPersisterId, $indexName, $typeName) { if (isset($typeConfig['provider']['service'])) { return $typeConfig['provider']['service']; } + /* Note: provider services may conflict with "prototype.driver", if the * index and type names were "prototype" and a driver, respectively. */ @@ -414,16 +434,28 @@ class FOSElasticaExtension extends Extension $providerDef->replaceArgument(1, $typeConfig['model']); // Propel provider can simply ignore Doctrine-specific options $providerDef->replaceArgument(2, array_diff_key($typeConfig['provider'], array('service' => 1))); + $container->setDefinition($providerId, $providerDef); return $providerId; } - protected function loadTypeListener(array $typeConfig, ContainerBuilder $container, $objectPersisterId, $typeDef, $indexName, $typeName) + /** + * Loads doctrine listeners to handle indexing of new or updated objects. + * + * @param array $typeConfig + * @param ContainerBuilder $container + * @param string $objectPersisterId + * @param string $indexName + * @param string $typeName + * @return string + */ + private function loadTypeListener(array $typeConfig, ContainerBuilder $container, $objectPersisterId, $indexName, $typeName) { if (isset($typeConfig['listener']['service'])) { return $typeConfig['listener']['service']; } + /* Note: listener services may conflict with "prototype.driver", if the * index and type names were "prototype" and a driver, respectively. */ @@ -438,10 +470,6 @@ class FOSElasticaExtension extends Extension $listenerDef->replaceArgument(4, new Reference($typeConfig['listener']['logger'])); } - switch ($typeConfig['driver']) { - case 'orm': $listenerDef->addTag('doctrine.event_subscriber'); break; - case 'mongodb': $listenerDef->addTag('doctrine_mongodb.odm.event_subscriber'); break; - } if (isset($typeConfig['listener']['is_indexable_callback'])) { $callback = $typeConfig['listener']['is_indexable_callback']; @@ -493,7 +521,18 @@ class FOSElasticaExtension extends Extension return $events; } - protected function loadTypeFinder(array $typeConfig, ContainerBuilder $container, $elasticaToModelId, $typeDef, $indexName, $typeName) + /** + * Loads a Type specific Finder. + * + * @param array $typeConfig + * @param ContainerBuilder $container + * @param string $elasticaToModelId + * @param Definition $typeDef + * @param string $indexName + * @param string $typeName + * @return string + */ + private function loadTypeFinder(array $typeConfig, ContainerBuilder $container, $elasticaToModelId, Definition $typeDef, $indexName, $typeName) { if (isset($typeConfig['finder']['service'])) { $finderId = $typeConfig['finder']['service']; @@ -519,39 +558,39 @@ class FOSElasticaExtension extends Extension /** * Loads the index manager * - * @param array $indexRefsByName * @param ContainerBuilder $container **/ - protected function loadIndexManager(array $indexRefsByName, ContainerBuilder $container) + private function loadIndexManager(ContainerBuilder $container) { $managerDef = $container->getDefinition('fos_elastica.index_manager'); - $managerDef->replaceArgument(0, $indexRefsByName); + $managerDef->replaceArgument(0, array_keys($this->clients)); $managerDef->replaceArgument(1, new Reference('fos_elastica.index')); } /** - * Loads the resetter + * Makes sure a specific driver has been loaded. * - * @param array $indexConfigs - * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container + * @param ContainerBuilder $container + * @param string $driver */ - protected function loadResetter(array $indexConfigs, ContainerBuilder $container) - { - $resetterDef = $container->getDefinition('fos_elastica.resetter'); - $resetterDef->replaceArgument(0, $indexConfigs); - } - - protected function loadDriver(ContainerBuilder $container, $driver) + private function loadDriver(ContainerBuilder $container, $driver) { if (in_array($driver, $this->loadedDrivers)) { return; } + $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); $loader->load($driver.'.xml'); $this->loadedDrivers[] = $driver; } - protected function createDefaultManagerAlias($defaultManager, ContainerBuilder $container) + /** + * Creates a default manager alias for defined default manager or the first loaded driver. + * + * @param string $defaultManager + * @param ContainerBuilder $container + */ + private function createDefaultManagerAlias($defaultManager, ContainerBuilder $container) { if (0 == count($this->loadedDrivers)) { return; @@ -568,18 +607,19 @@ class FOSElasticaExtension extends Extension $container->setAlias('fos_elastica.manager', sprintf('fos_elastica.manager.%s', $defaultManagerService)); } - protected function cleanUpProperties(&$properties) + /** + * Returns a reference to a client given its configured name. + * + * @param string $clientName + * @return Reference + * @throws \InvalidArgumentException + */ + private function getClient($clientName) { - foreach ($properties as &$fieldProperties) { - if (empty($fieldProperties['fields'])) { - unset($fieldProperties['fields']); - } else { - $this->cleanUpProperties($fieldProperties['fields']); - } - - if (!empty($fieldProperties['properties'])) { - $this->cleanUpProperties($fieldProperties['properties']); - } + if (!array_key_exists($clientName, $this->clients)) { + throw new InvalidArgumentException(sprintf('The elastica client with name "%s" is not defined', $clientName)); } + + return $this->clients[$clientName]['reference']; } } diff --git a/Resources/config/config.xml b/Resources/config/config.xml index cff2b49..c1ac0f9 100644 --- a/Resources/config/config.xml +++ b/Resources/config/config.xml @@ -1,100 +1,34 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> - FOS\ElasticaBundle\Elastica\Client - FOS\ElasticaBundle\Elastica\Index - Elastica\Type - FOS\ElasticaBundle\IndexManager - FOS\ElasticaBundle\Resetter - FOS\ElasticaBundle\Finder\TransformedFinder + FOS\ElasticaBundle\Elastica\LoggingClient FOS\ElasticaBundle\Logger\ElasticaLogger FOS\ElasticaBundle\DataCollector\ElasticaDataCollector - FOS\ElasticaBundle\Manager\RepositoryManager - FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerCollection - FOS\ElasticaBundle\Provider\ProviderRegistry Symfony\Component\PropertyAccess\PropertyAccessor - FOS\ElasticaBundle\Persister\ObjectPersister - FOS\ElasticaBundle\Persister\ObjectSerializerPersister - FOS\ElasticaBundle\Transformer\ModelToElasticaAutoTransformer - FOS\ElasticaBundle\Transformer\ModelToElasticaIdentifierTransformer + + + + + %kernel.debug% + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Resources/config/index.xml b/Resources/config/index.xml new file mode 100644 index 0000000..85f5744 --- /dev/null +++ b/Resources/config/index.xml @@ -0,0 +1,39 @@ + + + + + + FOS\ElasticaBundle\Elastica\Index + Elastica\Type + FOS\ElasticaBundle\Index\IndexManager + FOS\ElasticaBundle\Index\Resetter + FOS\ElasticaBundle\Finder\TransformedFinder + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Resources/config/mongodb.xml b/Resources/config/mongodb.xml index 0af7aa1..0c6b2af 100644 --- a/Resources/config/mongodb.xml +++ b/Resources/config/mongodb.xml @@ -5,7 +5,6 @@ xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> - @@ -18,6 +17,7 @@ + @@ -33,7 +33,5 @@ - - diff --git a/Resources/config/orm.xml b/Resources/config/orm.xml index 5bd16e5..bf67688 100644 --- a/Resources/config/orm.xml +++ b/Resources/config/orm.xml @@ -1,11 +1,10 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> - @@ -19,6 +18,7 @@ + @@ -31,10 +31,8 @@ - - + + - - diff --git a/Resources/config/persister.xml b/Resources/config/persister.xml new file mode 100644 index 0000000..8bd4dca --- /dev/null +++ b/Resources/config/persister.xml @@ -0,0 +1,27 @@ + + + + + + FOS\ElasticaBundle\Persister\ObjectPersister + FOS\ElasticaBundle\Persister\ObjectSerializerPersister + + + + + + + + + + + + + + + + + + diff --git a/Resources/config/propel.xml b/Resources/config/propel.xml index 7a7d93e..4ccc867 100644 --- a/Resources/config/propel.xml +++ b/Resources/config/propel.xml @@ -4,7 +4,6 @@ xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> - @@ -22,7 +21,5 @@ - - diff --git a/Resources/config/provider.xml b/Resources/config/provider.xml new file mode 100644 index 0000000..0732d54 --- /dev/null +++ b/Resources/config/provider.xml @@ -0,0 +1,18 @@ + + + + + + FOS\ElasticaBundle\Provider\ProviderRegistry + + + + + + + + + + diff --git a/Resources/config/transformer.xml b/Resources/config/transformer.xml new file mode 100644 index 0000000..e3abbbc --- /dev/null +++ b/Resources/config/transformer.xml @@ -0,0 +1,32 @@ + + + + + + FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerCollection + FOS\ElasticaBundle\Transformer\ModelToElasticaAutoTransformer + FOS\ElasticaBundle\Transformer\ModelToElasticaIdentifierTransformer + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tests/Integration/MappingTest.php b/Tests/Integration/MappingTest.php new file mode 100644 index 0000000..be134ed --- /dev/null +++ b/Tests/Integration/MappingTest.php @@ -0,0 +1,17 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + + +namespace FOS\ElasticaBundle\Tests\Integration; + + +class MappingTest { + +} \ No newline at end of file From 8540f13bbf606ae409ba3c02f8d9243577d249d5 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Mon, 2 Jun 2014 21:35:51 +1000 Subject: [PATCH 252/447] Fix nested property configuration Fixes #592 --- DependencyInjection/Configuration.php | 10 ++-- .../DependencyInjection/ConfigurationTest.php | 48 ++++++++++++++++++- 2 files changed, 53 insertions(+), 5 deletions(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 7a12e95..db8ae6a 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -20,7 +20,6 @@ class Configuration implements ConfigurationInterface public function __construct($configArray, $debug) { - $this->configArray = $configArray; $this->debug = $debug; } @@ -386,13 +385,16 @@ class Configuration implements ConfigurationInterface } foreach ($index['types'] as $type) { - if (empty($type['mappings'])) { - continue; + if (array_key_exists('mappings', $type) and !empty($type['mappings'])) { + $nestings = array_merge_recursive($nestings, $this->getNestingsForType($type['mappings'], $nestings)); } - $nestings = array_merge_recursive($nestings, $this->getNestingsForType($type['mappings'], $nestings)); + if (array_key_exists('properties', $type) and !empty($type['properties'])) { + $nestings = array_merge_recursive($nestings, $this->getNestingsForType($type['properties'], $nestings)); + } } } + return $nestings; } diff --git a/Tests/DependencyInjection/ConfigurationTest.php b/Tests/DependencyInjection/ConfigurationTest.php index efaaa52..8f0e1b9 100644 --- a/Tests/DependencyInjection/ConfigurationTest.php +++ b/Tests/DependencyInjection/ConfigurationTest.php @@ -22,7 +22,7 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase private function getConfigs(array $configArray) { - $configuration = new Configuration($configArray, true); + $configuration = new Configuration(array($configArray), true); return $this->processor->processConfiguration($configuration, array($configArray)); } @@ -257,4 +257,50 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase $this->assertCount(3, $configuration['indexes']['test']['types']['test']['properties']); } + + public function testNestedProperties() + { + $configuration = $this->getConfigs(array( + 'clients' => array( + 'default' => array('url' => 'http://localhost:9200'), + ), + 'indexes' => array( + 'test' => array( + 'types' => array( + 'user' => array( + 'properties' => array( + 'field1' => array(), + ), + 'persistence' => array(), + ), + 'user_profile' => array( + '_parent' => array( + 'type' => 'user', + 'property' => 'owner', + ), + 'properties' => array( + 'field1' => array(), + 'field2' => array( + 'type' => 'nested', + 'properties' => array( + 'nested_field1' => array( + 'type' => 'integer' + ), + 'nested_field2' => array( + 'type' => 'object', + 'properties' => array( + 'id' => array( + 'type' => 'integer' + ) + ) + ) + ) + ) + ) + ) + ) + ) + ) + )); + } } From 366fb3960653392becd4cb63be334a459fe3fd18 Mon Sep 17 00:00:00 2001 From: Patrick McAndrew Date: Wed, 4 Jun 2014 17:26:25 +0100 Subject: [PATCH 253/447] fix method call --- Resetter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resetter.php b/Resetter.php index d614f1b..9fdcbca 100644 --- a/Resetter.php +++ b/Resetter.php @@ -191,7 +191,7 @@ class Resetter $additionalError = sprintf( 'Tried to delete newly built index %s, but also failed: %s', $newIndexName, - $deleteNewIndexException->getError() + $deleteNewIndexException->getMessage() ); } From 5009673b6a7b3bff3266b4766fe4e892e7a8b1a4 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Sun, 8 Jun 2014 22:35:38 +1000 Subject: [PATCH 254/447] Functional Tests v1 --- .travis.yml | 3 + Tests/Functional/MappingToElasticaTest.php | 52 +++++++++ Tests/Functional/WebTestCase.php | 40 +++++++ Tests/Functional/app/AppKernel.php | 118 +++++++++++++++++++++ Tests/Functional/app/Basic/bundles.php | 10 ++ Tests/Functional/app/Basic/config.yml | 53 +++++++++ Tests/Functional/app/config/config.yml | 8 ++ composer.json | 13 +-- 8 files changed, 291 insertions(+), 6 deletions(-) create mode 100644 Tests/Functional/MappingToElasticaTest.php create mode 100644 Tests/Functional/WebTestCase.php create mode 100644 Tests/Functional/app/AppKernel.php create mode 100644 Tests/Functional/app/Basic/bundles.php create mode 100644 Tests/Functional/app/Basic/config.yml create mode 100644 Tests/Functional/app/config/config.yml diff --git a/.travis.yml b/.travis.yml index 72632de..4fdf2b9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,3 +8,6 @@ php: before_script: - echo "extension = mongo.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini - composer install --dev --prefer-source + +services: + - elasticsearch \ No newline at end of file diff --git a/Tests/Functional/MappingToElasticaTest.php b/Tests/Functional/MappingToElasticaTest.php new file mode 100644 index 0000000..3c32e10 --- /dev/null +++ b/Tests/Functional/MappingToElasticaTest.php @@ -0,0 +1,52 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace FOS\ElasticaBundle\Tests\Functional; + +use Symfony\Bundle\FrameworkBundle\Client; + +/** + * @group functional + */ +class MappingToElasticaTest extends WebTestCase +{ + public function testReset() + { + $client = $this->createClient(array('test_case' => 'Basic')); + $resetter = $this->getResetter($client); + + $resetter->resetIndex('index'); + $resetter->resetIndexType('index', 'type'); + } + + /** + * @param Client $client + * @return \FOS\ElasticaBundle\Resetter $resetter + */ + private function getResetter(Client $client) + { + return $client->getContainer()->get('fos_elastica.resetter'); + } + + protected function setUp() + { + parent::setUp(); + + $this->deleteTmpDir('Basic'); + } + + protected function tearDown() + { + parent::tearDown(); + + $this->deleteTmpDir('Basic'); + } +} diff --git a/Tests/Functional/WebTestCase.php b/Tests/Functional/WebTestCase.php new file mode 100644 index 0000000..38f5489 --- /dev/null +++ b/Tests/Functional/WebTestCase.php @@ -0,0 +1,40 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace FOS\ElasticaBundle\Tests\Functional; + +use Symfony\Bundle\FrameworkBundle\Tests\Functional\WebTestCase as BaseWebTestCase; + +class WebTestCase extends BaseWebTestCase +{ + protected static function getKernelClass() + { + require_once __DIR__.'/app/AppKernel.php'; + + return 'FOS\ElasticaBundle\Tests\Functional\app\AppKernel'; + } + + protected static function createKernel(array $options = array()) + { + $class = self::getKernelClass(); + + if (!isset($options['test_case'])) { + throw new \InvalidArgumentException('The option "test_case" must be set.'); + } + + return new $class( + $options['test_case'], + isset($options['root_config']) ? $options['root_config'] : 'config.yml', + isset($options['environment']) ? $options['environment'] : 'foselasticabundle'.strtolower($options['test_case']), + isset($options['debug']) ? $options['debug'] : true + ); + } +} diff --git a/Tests/Functional/app/AppKernel.php b/Tests/Functional/app/AppKernel.php new file mode 100644 index 0000000..f47a5b3 --- /dev/null +++ b/Tests/Functional/app/AppKernel.php @@ -0,0 +1,118 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FOS\ElasticaBundle\Tests\Functional\app; + +// get the autoload file +$dir = __DIR__; +$lastDir = null; +while ($dir !== $lastDir) { + $lastDir = $dir; + + if (file_exists($dir.'/autoload.php')) { + require_once $dir.'/autoload.php'; + break; + } + + if (file_exists($dir.'/autoload.php.dist')) { + require_once $dir.'/autoload.php.dist'; + break; + } + + if (file_exists($dir.'/vendor/autoload.php')) { + require_once $dir.'/vendor/autoload.php'; + break; + } + + $dir = dirname($dir); +} + +use Symfony\Component\Config\Loader\LoaderInterface; +use Symfony\Component\Filesystem\Filesystem; +use Symfony\Component\HttpKernel\Kernel; + +/** + * App Test Kernel for functional tests. + * + * @author Johannes M. Schmitt + */ +class AppKernel extends Kernel +{ + private $testCase; + private $rootConfig; + + public function __construct($testCase, $rootConfig, $environment, $debug) + { + if (!is_dir(__DIR__.'/'.$testCase)) { + throw new \InvalidArgumentException(sprintf('The test case "%s" does not exist.', $testCase)); + } + $this->testCase = $testCase; + + $fs = new Filesystem(); + if (!$fs->isAbsolutePath($rootConfig) && !file_exists($rootConfig = __DIR__.'/'.$testCase.'/'.$rootConfig)) { + throw new \InvalidArgumentException(sprintf('The root config "%s" does not exist.', $rootConfig)); + } + $this->rootConfig = $rootConfig; + + parent::__construct($environment, $debug); + } + + public function registerBundles() + { + if (!file_exists($filename = $this->getRootDir().'/'.$this->testCase.'/bundles.php')) { + throw new \RuntimeException(sprintf('The bundles file "%s" does not exist.', $filename)); + } + + return include $filename; + } + + public function init() + { + } + + public function getRootDir() + { + return __DIR__; + } + + public function getCacheDir() + { + return sys_get_temp_dir().'/'.Kernel::VERSION.'/'.$this->testCase.'/cache/'.$this->environment; + } + + public function getLogDir() + { + return sys_get_temp_dir().'/'.Kernel::VERSION.'/'.$this->testCase.'/logs'; + } + + public function registerContainerConfiguration(LoaderInterface $loader) + { + $loader->load($this->rootConfig); + } + + public function serialize() + { + return serialize(array($this->testCase, $this->rootConfig, $this->getEnvironment(), $this->isDebug())); + } + + public function unserialize($str) + { + call_user_func_array(array($this, '__construct'), unserialize($str)); + } + + protected function getKernelParameters() + { + $parameters = parent::getKernelParameters(); + $parameters['kernel.test_case'] = $this->testCase; + + return $parameters; + } +} \ No newline at end of file diff --git a/Tests/Functional/app/Basic/bundles.php b/Tests/Functional/app/Basic/bundles.php new file mode 100644 index 0000000..9f23bdf --- /dev/null +++ b/Tests/Functional/app/Basic/bundles.php @@ -0,0 +1,10 @@ +=2.2,<2.5-dev", + "doctrine/orm": "~2.2", "doctrine/mongodb-odm": "1.0.*@dev", "propel/propel1": "1.6.*", "pagerfanta/pagerfanta": "1.0.*@dev", - "knplabs/knp-components": "1.2.*", - "symfony/expression-language" : "2.4.*@dev" + "knplabs/knp-components": "~1.2", + "symfony/browser-kit" : "~2.3", + "symfony/expression-language" : "~2.4" }, "suggest": { - "doctrine/orm": ">=2.2,<2.5-dev", + "doctrine/orm": "~2.2", "doctrine/mongodb-odm": "1.0.*@dev", "propel/propel1": "1.6.*", "pagerfanta/pagerfanta": "1.0.*@dev", - "knplabs/knp-components": "1.2.*", - "symfony/expression-language" : "2.4.*@dev" + "knplabs/knp-components": "~1.2", + "symfony/expression-language" : "~2.4" }, "autoload": { "psr-0": { "FOS\\ElasticaBundle": "" } From fe19df365a74373c19161449526d35beb708e49b Mon Sep 17 00:00:00 2001 From: Gilles Doge Date: Tue, 10 Jun 2014 18:18:30 +0200 Subject: [PATCH 255/447] Make the class of fos_elastica.paginator.subscriber service configurable --- Resources/config/config.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Resources/config/config.xml b/Resources/config/config.xml index 7687250..2b48e87 100644 --- a/Resources/config/config.xml +++ b/Resources/config/config.xml @@ -21,6 +21,7 @@ FOS\ElasticaBundle\Persister\ObjectSerializerPersister FOS\ElasticaBundle\Transformer\ModelToElasticaAutoTransformer FOS\ElasticaBundle\Transformer\ModelToElasticaIdentifierTransformer + FOS\ElasticaBundle\Subscriber\PaginateElasticaQuerySubscriber @@ -87,7 +88,7 @@ - + From 66d241099984810e26ae809629b23e7dcade116f Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Mon, 16 Jun 2014 15:57:27 +1000 Subject: [PATCH 256/447] Move Indexable callback calculations to a new service --- DependencyInjection/Configuration.php | 17 +- DependencyInjection/FOSElasticaExtension.php | 24 ++- Doctrine/Listener.php | 172 +++++------------- Persister/ObjectPersister.php | 21 +++ Provider/Indexable.php | 174 +++++++++++++++++++ Provider/IndexableInterface.php | 25 +++ Resources/config/config.xml | 5 + Resources/config/mongodb.xml | 3 +- Resources/config/orm.xml | 6 +- Tests/Doctrine/AbstractListenerTest.php | 142 +++++++-------- Tests/Functional/IndexableCallbackTest.php | 51 ++++++ Tests/Functional/TypeObj.php | 25 +++ Tests/Functional/app/Basic/config.yml | 2 +- Tests/Functional/app/ORM/bundles.php | 11 ++ Tests/Functional/app/ORM/config.yml | 44 +++++ Tests/Provider/IndexableTest.php | 91 ++++++++++ composer.json | 1 + 17 files changed, 584 insertions(+), 230 deletions(-) create mode 100644 Provider/Indexable.php create mode 100644 Provider/IndexableInterface.php create mode 100644 Tests/Functional/IndexableCallbackTest.php create mode 100644 Tests/Functional/TypeObj.php create mode 100644 Tests/Functional/app/ORM/bundles.php create mode 100644 Tests/Functional/app/ORM/config.yml create mode 100644 Tests/Provider/IndexableTest.php diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index ce1c982..f32f295 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -187,9 +187,23 @@ class Configuration implements ConfigurationInterface return $v; }) ->end() + ->beforeNormalization() + ->ifTrue(function ($v) { + return isset($v['persistence']) && + isset($v['persistence']['listener']) && + isset($v['persistence']['listener']['is_indexable_callback']); + }) + ->then(function ($v) { + $v['indexable_callback'] = $v['persistence']['listener']['is_indexable_callback']; + unset($v['persistence']['listener']['is_indexable_callback']); + + return $v; + }) + ->end() ->children() ->scalarNode('index_analyzer')->end() ->scalarNode('search_analyzer')->end() + ->scalarNode('indexable_callback')->end() ->append($this->getPersistenceNode()) ->append($this->getSerializerNode()) ->end() @@ -230,7 +244,7 @@ class Configuration implements ConfigurationInterface unset($v[$prop]); } } - + return $v; }) ->end() @@ -674,7 +688,6 @@ class Configuration implements ConfigurationInterface ->treatTrueLike('fos_elastica.logger') ->end() ->scalarNode('service')->end() - ->variableNode('is_indexable_callback')->defaultNull()->end() ->end() ->end() ->arrayNode('finder') diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 1529544..9e50c0b 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -186,8 +186,11 @@ class FOSElasticaExtension extends Extension */ protected function loadTypes(array $types, ContainerBuilder $container, $indexName, $indexId, array $typePrototypeConfig) { + $indexableCallbacks = array(); + foreach ($types as $name => $type) { $type = self::deepArrayUnion($typePrototypeConfig, $type); + $typeName = sprintf('%s/%s', $indexName, $name); $typeId = sprintf('%s.%s', $indexId, $name); $typeDefArgs = array($name); $typeDef = new Definition('%fos_elastica.type.class%', $typeDefArgs); @@ -240,7 +243,6 @@ class FOSElasticaExtension extends Extension } if (isset($type['_parent'])) { $this->indexConfigs[$indexName]['config']['properties'][$name]['_parent'] = array('type' => $type['_parent']['type']); - $typeName = sprintf('%s/%s', $indexName, $name); $this->typeFields[$typeName]['_parent'] = $type['_parent']; } if (isset($type['persistence'])) { @@ -252,6 +254,9 @@ class FOSElasticaExtension extends Extension if (isset($type['search_analyzer'])) { $this->indexConfigs[$indexName]['config']['properties'][$name]['search_analyzer'] = $type['search_analyzer']; } + if (isset($type['indexable_callback'])) { + $indexableCallbacks[$typeName] = $type['indexable_callback']; + } if (isset($type['index'])) { $this->indexConfigs[$indexName]['config']['properties'][$name]['index'] = $type['index']; } @@ -271,6 +276,9 @@ class FOSElasticaExtension extends Extension } } } + + $indexable = $container->getDefinition('fos_elastica.indexable'); + $indexable->replaceArgument(0, $indexableCallbacks); } /** @@ -431,8 +439,7 @@ class FOSElasticaExtension extends Extension $listenerId = sprintf('fos_elastica.listener.%s.%s', $indexName, $typeName); $listenerDef = new DefinitionDecorator($abstractListenerId); $listenerDef->replaceArgument(0, new Reference($objectPersisterId)); - $listenerDef->replaceArgument(1, $typeConfig['model']); - $listenerDef->replaceArgument(2, $this->getDoctrineEvents($typeConfig)); + $listenerDef->replaceArgument(1, $this->getDoctrineEvents($typeConfig)); $listenerDef->replaceArgument(3, $typeConfig['identifier']); if ($typeConfig['listener']['logger']) { $listenerDef->replaceArgument(4, new Reference($typeConfig['listener']['logger'])); @@ -442,18 +449,7 @@ class FOSElasticaExtension extends Extension case 'orm': $listenerDef->addTag('doctrine.event_subscriber'); break; case 'mongodb': $listenerDef->addTag('doctrine_mongodb.odm.event_subscriber'); break; } - if (isset($typeConfig['listener']['is_indexable_callback'])) { - $callback = $typeConfig['listener']['is_indexable_callback']; - if (is_array($callback)) { - list($class) = $callback + array(null); - if (is_string($class) && !class_exists($class)) { - $callback[0] = new Reference($class); - } - } - - $listenerDef->addMethodCall('setIsIndexableCallback', array($callback)); - } $container->setDefinition($listenerId, $listenerDef); return $listenerId; diff --git a/Doctrine/Listener.php b/Doctrine/Listener.php index ff9fc60..4a01aa1 100644 --- a/Doctrine/Listener.php +++ b/Doctrine/Listener.php @@ -2,15 +2,13 @@ namespace FOS\ElasticaBundle\Doctrine; -use Psr\Log\LoggerInterface; use Doctrine\Common\EventArgs; use Doctrine\Common\EventSubscriber; use FOS\ElasticaBundle\Persister\ObjectPersisterInterface; use FOS\ElasticaBundle\Persister\ObjectPersister; -use Symfony\Component\ExpressionLanguage\Expression; -use Symfony\Component\ExpressionLanguage\ExpressionLanguage; -use Symfony\Component\ExpressionLanguage\SyntaxError; +use FOS\ElasticaBundle\Provider\IndexableInterface; use Symfony\Component\PropertyAccess\PropertyAccess; +use Symfony\Component\PropertyAccess\PropertyAccessorInterface; /** * Automatically update ElasticSearch based on changes to the Doctrine source @@ -25,13 +23,6 @@ class Listener implements EventSubscriber */ protected $objectPersister; - /** - * Class of the domain model - * - * @var string - */ - protected $objectClass; - /** * List of subscribed events * @@ -46,13 +37,6 @@ class Listener implements EventSubscriber */ protected $esIdentifierField; - /** - * Callback for determining if an object should be indexed - * - * @var mixed - */ - protected $isIndexableCallback; - /** * Objects scheduled for insertion and replacement */ @@ -64,13 +48,6 @@ class Listener implements EventSubscriber */ public $scheduledForDeletion = array(); - /** - * An instance of ExpressionLanguage - * - * @var ExpressionLanguage - */ - protected $expressionLanguage; - /** * PropertyAccessor instance * @@ -78,26 +55,36 @@ class Listener implements EventSubscriber */ protected $propertyAccessor; + /** + * @var \FOS\ElasticaBundle\Provider\IndexableInterface + */ + private $indexable; + /** * Constructor. * * @param ObjectPersisterInterface $objectPersister - * @param string $objectClass - * @param array $events - * @param string $esIdentifierField + * @param array $events + * @param IndexableInterface $indexable + * @param string $esIdentifierField + * @param null $logger */ - public function __construct(ObjectPersisterInterface $objectPersister, $objectClass, array $events, $esIdentifierField = 'id', $logger = null) - { - $this->objectPersister = $objectPersister; - $this->objectClass = $objectClass; - $this->events = $events; - $this->esIdentifierField = $esIdentifierField; + public function __construct( + ObjectPersisterInterface $objectPersister, + array $events, + IndexableInterface $indexable, + $esIdentifierField = 'id', + $logger = null + ) { + $this->esIdentifierField = $esIdentifierField; + $this->events = $events; + $this->indexable = $indexable; + $this->objectPersister = $objectPersister; + $this->propertyAccessor = PropertyAccess::createPropertyAccessor(); if ($logger) { $this->objectPersister->setLogger($logger); } - - $this->propertyAccessor = PropertyAccess::createPropertyAccessor(); } /** @@ -108,82 +95,6 @@ class Listener implements EventSubscriber return $this->events; } - /** - * Set the callback for determining object index eligibility. - * - * If callback is a string, it must be public method on the object class - * that expects no arguments and returns a boolean. Otherwise, the callback - * should expect the object for consideration as its only argument and - * return a boolean. - * - * @param callback $callback - * @throws \RuntimeException if the callback is not callable - */ - public function setIsIndexableCallback($callback) - { - if (is_string($callback)) { - if (!is_callable(array($this->objectClass, $callback))) { - if (false !== ($expression = $this->getExpressionLanguage())) { - $callback = new Expression($callback); - try { - $expression->compile($callback, array($this->getExpressionVar())); - } catch (SyntaxError $e) { - throw new \RuntimeException(sprintf('Indexable callback %s::%s() is not callable or a valid expression.', $this->objectClass, $callback), 0, $e); - } - } else { - throw new \RuntimeException(sprintf('Indexable callback %s::%s() is not callable.', $this->objectClass, $callback)); - } - } - } elseif (!is_callable($callback)) { - if (is_array($callback)) { - list($class, $method) = $callback + array(null, null); - if (is_object($class)) { - $class = get_class($class); - } - - if ($class && $method) { - throw new \RuntimeException(sprintf('Indexable callback %s::%s() is not callable.', $class, $method)); - } - } - throw new \RuntimeException('Indexable callback is not callable.'); - } - - $this->isIndexableCallback = $callback; - } - - /** - * Return whether the object is indexable with respect to the callback. - * - * @param object $object - * @return boolean - */ - protected function isObjectIndexable($object) - { - if (!$this->isIndexableCallback) { - return true; - } - - if ($this->isIndexableCallback instanceof Expression) { - return $this->getExpressionLanguage()->evaluate($this->isIndexableCallback, array($this->getExpressionVar($object) => $object)); - } - - return is_string($this->isIndexableCallback) - ? call_user_func(array($object, $this->isIndexableCallback)) - : call_user_func($this->isIndexableCallback, $object); - } - - /** - * @param mixed $object - * @return string - */ - private function getExpressionVar($object = null) - { - $class = $object ?: $this->objectClass; - $ref = new \ReflectionClass($class); - - return strtolower($ref->getShortName()); - } - /** * Provides unified method for retrieving a doctrine object from an EventArgs instance * @@ -204,27 +115,11 @@ class Listener implements EventSubscriber throw new \RuntimeException('Unable to retrieve object from EventArgs.'); } - /** - * @return bool|ExpressionLanguage - */ - private function getExpressionLanguage() - { - if (null === $this->expressionLanguage) { - if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) { - return false; - } - - $this->expressionLanguage = new ExpressionLanguage(); - } - - return $this->expressionLanguage; - } - public function postPersist(EventArgs $eventArgs) { $entity = $this->getDoctrineObject($eventArgs); - if ($entity instanceof $this->objectClass && $this->isObjectIndexable($entity)) { + if ($this->objectPersister->handlesObject($entity) && $this->isObjectIndexable($entity)) { $this->scheduledForInsertion[] = $entity; } } @@ -233,7 +128,7 @@ class Listener implements EventSubscriber { $entity = $this->getDoctrineObject($eventArgs); - if ($entity instanceof $this->objectClass) { + if ($this->objectPersister->handlesObject($entity)) { if ($this->isObjectIndexable($entity)) { $this->scheduledForUpdate[] = $entity; } else { @@ -251,7 +146,7 @@ class Listener implements EventSubscriber { $entity = $this->getDoctrineObject($eventArgs); - if ($entity instanceof $this->objectClass) { + if ($this->objectPersister->handlesObject($entity)) { $this->scheduleForDeletion($entity); } } @@ -305,4 +200,19 @@ class Listener implements EventSubscriber $this->scheduledForDeletion[] = $identifierValue; } } + + /** + * Checks if the object is indexable or not. + * + * @param object $object + * @return bool + */ + private function isObjectIndexable($object) + { + return $this->indexable->isObjectIndexable( + $this->objectPersister->getType()->getIndex()->getName(), + $this->objectPersister->getType()->getName(), + $object + ); + } } diff --git a/Persister/ObjectPersister.php b/Persister/ObjectPersister.php index c279ec7..2b6a8af 100644 --- a/Persister/ObjectPersister.php +++ b/Persister/ObjectPersister.php @@ -31,6 +31,27 @@ class ObjectPersister implements ObjectPersisterInterface $this->fields = $fields; } + /** + * @internal Temporary method that will be removed. + * + * @return Type + */ + public function getType() + { + return $this->type; + } + + /** + * If the ObjectPersister handles a given object. + * + * @param object $object + * @return bool + */ + public function handlesObject($object) + { + return $object instanceof $this->objectClass; + } + public function setLogger(LoggerInterface $logger) { $this->logger = $logger; diff --git a/Provider/Indexable.php b/Provider/Indexable.php new file mode 100644 index 0000000..b388c58 --- /dev/null +++ b/Provider/Indexable.php @@ -0,0 +1,174 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FOS\ElasticaBundle\Provider; + +use Symfony\Component\ExpressionLanguage\Expression; +use Symfony\Component\ExpressionLanguage\ExpressionLanguage; +use Symfony\Component\ExpressionLanguage\SyntaxError; +use Symfony\Component\PropertyAccess\PropertyAccess; +use Symfony\Component\PropertyAccess\PropertyAccessorInterface; + +class Indexable implements IndexableInterface +{ + /** + * An array of raw configured callbacks for all types. + * + * @var array + */ + private $callbacks = array(); + + /** + * An instance of ExpressionLanguage + * + * @var ExpressionLanguage + */ + private $expressionLanguage; + + /** + * An array of initialised callbacks. + * + * @var array + */ + private $initialisedCallbacks = array(); + + /** + * PropertyAccessor instance + * + * @var PropertyAccessorInterface + */ + private $propertyAccessor; + + /** + * @param array $callbacks + */ + public function __construct(array $callbacks) + { + $this->callbacks = $callbacks; + $this->propertyAccessor = PropertyAccess::createPropertyAccessor(); + } + + /** + * Return whether the object is indexable with respect to the callback. + * + * @param string $indexName + * @param string $typeName + * @param mixed $object + * @return bool + */ + public function isObjectIndexable($indexName, $typeName, $object) + { + $type = sprintf('%s/%s', $indexName, $typeName); + $callback = $this->getCallback($type, $object); + if (!$callback) { + return true; + } + + if ($callback instanceof Expression) { + return $this->getExpressionLanguage()->evaluate($callback, array( + 'object' => $object, + $this->getExpressionVar($object) => $object + )); + } + + return is_string($callback) + ? call_user_func(array($object, $callback)) + : call_user_func($callback, $object); + } + + /** + * Builds and initialises a callback. + * + * @param string $type + * @param object $object + * @return mixed + */ + private function buildCallback($type, $object) + { + if (!array_key_exists($type, $this->callbacks)) { + throw new \InvalidArgumentException(sprintf('Callback for type "%s" is not configured', $type)); + } + + $callback = $this->callbacks[$type]; + + if (is_callable($callback) or is_callable(array($object, $callback))) { + return $callback; + } + + if (is_array($callback)) { + list($class, $method) = $callback + array(null, null); + if (is_object($class)) { + $class = get_class($class); + } + + if ($class && $method) { + throw new \InvalidArgumentException(sprintf('Callback for type "%s", "%s::%s()", is not callable.', $type, $class, $method)); + } + } + + if (is_string($callback) && $expression = $this->getExpressionLanguage()) { + $callback = new Expression($callback); + + try { + $expression->compile($callback, array('object', $this->getExpressionVar($object))); + + return $callback; + } catch (SyntaxError $e) { + throw new \InvalidArgumentException(sprintf('Callback for type "%s" is an invalid expression', $type), $e->getCode(), $e); + } + } + + throw new \InvalidArgumentException(sprintf('Callback for type "%s" is not a valid callback.', $type)); + } + + /** + * Retreives a cached callback, or creates a new callback if one is not found. + * + * @param string $type + * @param object $object + * @return mixed + */ + private function getCallback($type, $object) + { + if (!array_key_exists($type, $this->initialisedCallbacks)) { + $this->initialisedCallbacks[$type] = $this->buildCallback($type, $object); + } + + return $this->initialisedCallbacks[$type]; + } + + /** + * @return bool|ExpressionLanguage + */ + private function getExpressionLanguage() + { + if (null === $this->expressionLanguage) { + if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) { + return false; + } + + $this->expressionLanguage = new ExpressionLanguage(); + } + + return $this->expressionLanguage; + } + + /** + * @param mixed $object + * @return string + */ + private function getExpressionVar($object = null) + { + $ref = new \ReflectionClass($object); + + return strtolower($ref->getShortName()); + } +} diff --git a/Provider/IndexableInterface.php b/Provider/IndexableInterface.php new file mode 100644 index 0000000..4871b58 --- /dev/null +++ b/Provider/IndexableInterface.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FOS\ElasticaBundle\Provider; + +interface IndexableInterface +{ + /** + * Checks if an object passed should be indexable or not. + * + * @param string $indexName + * @param string $typeName + * @param mixed $object + * @return bool + */ + public function isObjectIndexable($indexName, $typeName, $object); +} diff --git a/Resources/config/config.xml b/Resources/config/config.xml index 7687250..f4b2606 100644 --- a/Resources/config/config.xml +++ b/Resources/config/config.xml @@ -9,6 +9,7 @@ FOS\ElasticaBundle\DynamicIndex Elastica\Type FOS\ElasticaBundle\IndexManager + FOS\ElasticaBundle\Provider\Indexable FOS\ElasticaBundle\Resetter FOS\ElasticaBundle\Finder\TransformedFinder FOS\ElasticaBundle\Logger\ElasticaLogger @@ -44,6 +45,10 @@ + + + + diff --git a/Resources/config/mongodb.xml b/Resources/config/mongodb.xml index 0af7aa1..e575e5d 100644 --- a/Resources/config/mongodb.xml +++ b/Resources/config/mongodb.xml @@ -15,9 +15,10 @@ - + + diff --git a/Resources/config/orm.xml b/Resources/config/orm.xml index 5bd16e5..43d1670 100644 --- a/Resources/config/orm.xml +++ b/Resources/config/orm.xml @@ -15,10 +15,10 @@ - - - + + + diff --git a/Tests/Doctrine/AbstractListenerTest.php b/Tests/Doctrine/AbstractListenerTest.php index ee657f1..de5ba0c 100644 --- a/Tests/Doctrine/AbstractListenerTest.php +++ b/Tests/Doctrine/AbstractListenerTest.php @@ -11,12 +11,12 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase { public function testObjectInsertedOnPersist() { - $persister = $this->getMockPersister(); - $entity = new Listener\Entity(1); + $persister = $this->getMockPersister($entity, 'index', 'type'); $eventArgs = $this->createLifecycleEventArgs($entity, $this->getMockObjectManager()); + $indexable = $this->getMockIndexable('index', 'type', $entity, true); - $listener = $this->createListener($persister, get_class($entity), array()); + $listener = $this->createListener($persister, array(), $indexable); $listener->postPersist($eventArgs); $this->assertEquals($entity, current($listener->scheduledForInsertion)); @@ -28,18 +28,14 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase $listener->postFlush($eventArgs); } - /** - * @dataProvider provideIsIndexableCallbacks - */ - public function testNonIndexableObjectNotInsertedOnPersist($isIndexableCallback) + public function testNonIndexableObjectNotInsertedOnPersist() { - $persister = $this->getMockPersister(); - - $entity = new Listener\Entity(1, false); + $entity = new Listener\Entity(1); + $persister = $this->getMockPersister($entity, 'index', 'type'); $eventArgs = $this->createLifecycleEventArgs($entity, $this->getMockObjectManager()); + $indexable = $this->getMockIndexable('index', 'type', $entity, false); - $listener = $this->createListener($persister, get_class($entity), array()); - $listener->setIsIndexableCallback($isIndexableCallback); + $listener = $this->createListener($persister, array(), $indexable); $listener->postPersist($eventArgs); $this->assertEmpty($listener->scheduledForInsertion); @@ -54,12 +50,12 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase public function testObjectReplacedOnUpdate() { - $persister = $this->getMockPersister(); - $entity = new Listener\Entity(1); + $persister = $this->getMockPersister($entity, 'index', 'type'); $eventArgs = $this->createLifecycleEventArgs($entity, $this->getMockObjectManager()); + $indexable = $this->getMockIndexable('index', 'type', $entity, true); - $listener = $this->createListener($persister, get_class($entity), array()); + $listener = $this->createListener($persister, array(), $indexable); $listener->postUpdate($eventArgs); $this->assertEquals($entity, current($listener->scheduledForUpdate)); @@ -73,17 +69,15 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase $listener->postFlush($eventArgs); } - /** - * @dataProvider provideIsIndexableCallbacks - */ - public function testNonIndexableObjectRemovedOnUpdate($isIndexableCallback) + public function testNonIndexableObjectRemovedOnUpdate() { $classMetadata = $this->getMockClassMetadata(); $objectManager = $this->getMockObjectManager(); - $persister = $this->getMockPersister(); - $entity = new Listener\Entity(1, false); + $entity = new Listener\Entity(1); + $persister = $this->getMockPersister($entity, 'index', 'type'); $eventArgs = $this->createLifecycleEventArgs($entity, $objectManager); + $indexable = $this->getMockIndexable('index', 'type', $entity, false); $objectManager->expects($this->any()) ->method('getClassMetadata') @@ -95,8 +89,7 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase ->with($entity, 'id') ->will($this->returnValue($entity->getId())); - $listener = $this->createListener($persister, get_class($entity), array()); - $listener->setIsIndexableCallback($isIndexableCallback); + $listener = $this->createListener($persister, array(), $indexable); $listener->postUpdate($eventArgs); $this->assertEmpty($listener->scheduledForUpdate); @@ -115,10 +108,11 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase { $classMetadata = $this->getMockClassMetadata(); $objectManager = $this->getMockObjectManager(); - $persister = $this->getMockPersister(); $entity = new Listener\Entity(1); + $persister = $this->getMockPersister($entity, 'index', 'type'); $eventArgs = $this->createLifecycleEventArgs($entity, $objectManager); + $indexable = $this->getMockIndexable('index', 'type', $entity); $objectManager->expects($this->any()) ->method('getClassMetadata') @@ -130,7 +124,7 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase ->with($entity, 'id') ->will($this->returnValue($entity->getId())); - $listener = $this->createListener($persister, get_class($entity), array()); + $listener = $this->createListener($persister, array(), $indexable); $listener->preRemove($eventArgs); $this->assertEquals($entity->getId(), current($listener->scheduledForDeletion)); @@ -146,11 +140,12 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase { $classMetadata = $this->getMockClassMetadata(); $objectManager = $this->getMockObjectManager(); - $persister = $this->getMockPersister(); $entity = new Listener\Entity(1); $entity->identifier = 'foo'; + $persister = $this->getMockPersister($entity, 'index', 'type'); $eventArgs = $this->createLifecycleEventArgs($entity, $objectManager); + $indexable = $this->getMockIndexable('index', 'type', $entity); $objectManager->expects($this->any()) ->method('getClassMetadata') @@ -162,7 +157,7 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase ->with($entity, 'identifier') ->will($this->returnValue($entity->getId())); - $listener = $this->createListener($persister, get_class($entity), array(), 'identifier'); + $listener = $this->createListener($persister, array(), $indexable, 'identifier'); $listener->preRemove($eventArgs); $this->assertEquals($entity->identifier, current($listener->scheduledForDeletion)); @@ -174,36 +169,6 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase $listener->postFlush($eventArgs); } - /** - * @dataProvider provideInvalidIsIndexableCallbacks - * @expectedException \RuntimeException - */ - public function testInvalidIsIndexableCallbacks($isIndexableCallback) - { - $listener = $this->createListener($this->getMockPersister(), 'FOS\ElasticaBundle\Tests\Doctrine\Listener\Entity', array()); - $listener->setIsIndexableCallback($isIndexableCallback); - } - - public function provideInvalidIsIndexableCallbacks() - { - return array( - array('nonexistentEntityMethod'), - array(array(new Listener\IndexableDecider(), 'internalMethod')), - array(42), - array('entity.getIsIndexable() && nonexistentEntityFunction()'), - ); - } - - public function provideIsIndexableCallbacks() - { - return array( - array('getIsIndexable'), - array(array(new Listener\IndexableDecider(), 'isIndexable')), - array(function(Listener\Entity $entity) { return $entity->getIsIndexable(); }), - array('entity.getIsIndexable()') - ); - } - abstract protected function getLifecycleEventArgsClass(); abstract protected function getListenerClass(); @@ -240,9 +205,48 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase ->getMock(); } - private function getMockPersister() + private function getMockPersister($object, $indexName, $typeName) { - return $this->getMock('FOS\ElasticaBundle\Persister\ObjectPersisterInterface'); + $mock = $this->getMockBuilder('FOS\ElasticaBundle\Persister\ObjectPersister') + ->disableOriginalConstructor() + ->getMock(); + + $mock->expects($this->any()) + ->method('handlesObject') + ->with($object) + ->will($this->returnValue(true)); + + $index = $this->getMockBuilder('Elastica\Index')->disableOriginalConstructor()->getMock(); + $index->expects($this->any()) + ->method('getName') + ->will($this->returnValue($indexName)); + $type = $this->getMockBuilder('Elastica\Type')->disableOriginalConstructor()->getMock(); + $type->expects($this->any()) + ->method('getName') + ->will($this->returnValue($typeName)); + $type->expects($this->any()) + ->method('getIndex') + ->will($this->returnValue($index)); + + $mock->expects($this->any()) + ->method('getType') + ->will($this->returnValue($type)); + + return $mock; + } + + private function getMockIndexable($indexName, $typeName, $object, $return = null) + { + $mock = $this->getMock('FOS\ElasticaBundle\Provider\IndexableInterface'); + + if (null !== $return) { + $mock->expects($this->once()) + ->method('isObjectIndexable') + ->with($indexName, $typeName, $object) + ->will($this->returnValue($return)); + } + + return $mock; } } @@ -251,33 +255,15 @@ namespace FOS\ElasticaBundle\Tests\Doctrine\Listener; class Entity { private $id; - private $isIndexable; - public function __construct($id, $isIndexable = true) + public function __construct($id) { $this->id = $id; - $this->isIndexable = $isIndexable; } public function getId() { return $this->id; } - - public function getIsIndexable() - { - return $this->isIndexable; - } } -class IndexableDecider -{ - public function isIndexable(Entity $entity) - { - return $entity->getIsIndexable(); - } - - protected function internalMethod() - { - } -} diff --git a/Tests/Functional/IndexableCallbackTest.php b/Tests/Functional/IndexableCallbackTest.php new file mode 100644 index 0000000..89fca1d --- /dev/null +++ b/Tests/Functional/IndexableCallbackTest.php @@ -0,0 +1,51 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace FOS\ElasticaBundle\Tests\Functional; + +/** + * @group functional + */ +class IndexableCallbackTest extends WebTestCase +{ + /** + * 2 reasons for this test: + * + * 1) To test that the configuration rename from is_indexable_callback under the listener + * key is respected, and + * 2) To test the Extension's set up of the Indexable service. + */ + public function testIndexableCallback() + { + $client = $this->createClient(array('test_case' => 'ORM')); + + /** @var \FOS\ElasticaBundle\Provider\Indexable $in */ + $in = $client->getContainer()->get('fos_elastica.indexable'); + + $this->assertTrue($in->isObjectIndexable('index', 'type', new TypeObj())); + $this->assertFalse($in->isObjectIndexable('index', 'type2', new TypeObj())); + $this->assertFalse($in->isObjectIndexable('index', 'type3', new TypeObj())); + } + + protected function setUp() + { + parent::setUp(); + + $this->deleteTmpDir('ORM'); + } + + protected function tearDown() + { + parent::tearDown(); + + $this->deleteTmpDir('ORM'); + } +} diff --git a/Tests/Functional/TypeObj.php b/Tests/Functional/TypeObj.php new file mode 100644 index 0000000..c264e7b --- /dev/null +++ b/Tests/Functional/TypeObj.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FOS\ElasticaBundle\Tests\Functional; + +class TypeObj +{ + public function isIndexable() + { + return true; + } + + public function isntIndexable() + { + return false; + } +} diff --git a/Tests/Functional/app/Basic/config.yml b/Tests/Functional/app/Basic/config.yml index 7025532..09e5aec 100644 --- a/Tests/Functional/app/Basic/config.yml +++ b/Tests/Functional/app/Basic/config.yml @@ -50,4 +50,4 @@ fos_elastica: _parent: type: "parent" property: "parent" - identifier: "id" \ No newline at end of file + identifier: "id" diff --git a/Tests/Functional/app/ORM/bundles.php b/Tests/Functional/app/ORM/bundles.php new file mode 100644 index 0000000..d0b6efb --- /dev/null +++ b/Tests/Functional/app/ORM/bundles.php @@ -0,0 +1,11 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FOS\ElasticaBundle\Tests\Provider; + +use FOS\ElasticaBundle\Provider\Indexable; + +class IndexableTest extends \PHPUnit_Framework_TestCase +{ + /** + * @dataProvider provideIsIndexableCallbacks + */ + public function testValidIndexableCallbacks($callback, $return) + { + $indexable = new Indexable(array( + 'index/type' => $callback + )); + $index = $indexable->isObjectIndexable('index', 'type', new Entity); + + $this->assertEquals($return, $index); + } + + /** + * @dataProvider provideInvalidIsIndexableCallbacks + * @expectedException \InvalidArgumentException + */ + public function testInvalidIsIndexableCallbacks($callback) + { + $indexable = new Indexable(array( + 'index/type' => $callback + )); + $indexable->isObjectIndexable('index', 'type', new Entity); + } + + public function provideInvalidIsIndexableCallbacks() + { + return array( + array('nonexistentEntityMethod'), + array(array(new IndexableDecider(), 'internalMethod')), + array(42), + array('entity.getIsIndexable() && nonexistentEntityFunction()'), + ); + } + + public function provideIsIndexableCallbacks() + { + return array( + array('isIndexable', false), + array(array(new IndexableDecider(), 'isIndexable'), true), + array(function(Entity $entity) { return $entity->maybeIndex(); }, true), + array('entity.maybeIndex()', true), + array('!object.isIndexable() && entity.property == "abc"', true), + array('entity.property != "abc"', false), + ); + } +} + +class Entity +{ + public $property = 'abc'; + + public function isIndexable() + { + return false; + } + + public function maybeIndex() + { + return true; + } +} + +class IndexableDecider +{ + public function isIndexable(Entity $entity) + { + return !$entity->isIndexable(); + } + + protected function internalMethod() + { + } +} diff --git a/composer.json b/composer.json index 8783822..d67e329 100644 --- a/composer.json +++ b/composer.json @@ -21,6 +21,7 @@ }, "require-dev":{ "doctrine/orm": "~2.2", + "doctrine/doctrine-bundle": "~1.2@beta", "doctrine/mongodb-odm": "1.0.*@dev", "propel/propel1": "1.6.*", "pagerfanta/pagerfanta": "1.0.*@dev", From e54cc3c2434cebc341f06d96596f11f14052094c Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Mon, 16 Jun 2014 16:17:04 +1000 Subject: [PATCH 257/447] Implement callback checking in the provider --- Doctrine/AbstractProvider.php | 24 +++++-- Persister/ObjectPersisterInterface.php | 7 ++ Provider/AbstractProvider.php | 35 ++++++++-- Tests/Doctrine/AbstractProviderTest.php | 88 ++++++++++++++++++++----- 4 files changed, 126 insertions(+), 28 deletions(-) diff --git a/Doctrine/AbstractProvider.php b/Doctrine/AbstractProvider.php index b9ffda5..0c43b2d 100644 --- a/Doctrine/AbstractProvider.php +++ b/Doctrine/AbstractProvider.php @@ -6,6 +6,7 @@ use Doctrine\Common\Persistence\ManagerRegistry; use Elastica\Exception\Bulk\ResponseException as BulkResponseException; use FOS\ElasticaBundle\Persister\ObjectPersisterInterface; use FOS\ElasticaBundle\Provider\AbstractProvider as BaseAbstractProvider; +use FOS\ElasticaBundle\Provider\IndexableInterface; abstract class AbstractProvider extends BaseAbstractProvider { @@ -15,13 +16,19 @@ abstract class AbstractProvider extends BaseAbstractProvider * Constructor. * * @param ObjectPersisterInterface $objectPersister - * @param string $objectClass - * @param array $options - * @param ManagerRegistry $managerRegistry + * @param IndexableInterface $indexable + * @param string $objectClass + * @param array $options + * @param ManagerRegistry $managerRegistry */ - public function __construct(ObjectPersisterInterface $objectPersister, $objectClass, array $options, $managerRegistry) - { - parent::__construct($objectPersister, $objectClass, array_merge(array( + public function __construct( + ObjectPersisterInterface $objectPersister, + IndexableInterface $indexable, + $objectClass, + array $options, + ManagerRegistry $managerRegistry + ) { + parent::__construct($objectPersister, $indexable, $objectClass, array_merge(array( 'clear_object_manager' => true, 'debug_logging' => false, 'ignore_errors' => false, @@ -53,6 +60,10 @@ abstract class AbstractProvider extends BaseAbstractProvider $stepStartTime = microtime(true); } $objects = $this->fetchSlice($queryBuilder, $batchSize, $offset); + if ($loggerClosure) { + $stepNbObjects = count($objects); + } + $objects = array_filter($objects, array($this, 'isObjectIndexable')); if (!$ignoreErrors) { $this->objectPersister->insertMany($objects); @@ -73,7 +84,6 @@ abstract class AbstractProvider extends BaseAbstractProvider usleep($sleep); if ($loggerClosure) { - $stepNbObjects = count($objects); $stepCount = $stepNbObjects + $offset; $percentComplete = 100 * $stepCount / $nbObjects; $timeDifference = microtime(true) - $stepStartTime; diff --git a/Persister/ObjectPersisterInterface.php b/Persister/ObjectPersisterInterface.php index 2b4c8ee..5953d5a 100644 --- a/Persister/ObjectPersisterInterface.php +++ b/Persister/ObjectPersisterInterface.php @@ -68,4 +68,11 @@ interface ObjectPersisterInterface * @param array $identifiers array of domain model object identifiers */ public function deleteManyByIdentifiers(array $identifiers); + + /** + * Returns the elastica type used by this persister + * + * @return \Elastica\Type + */ + public function getType(); } diff --git a/Provider/AbstractProvider.php b/Provider/AbstractProvider.php index 2761a25..8642be8 100644 --- a/Provider/AbstractProvider.php +++ b/Provider/AbstractProvider.php @@ -24,23 +24,48 @@ abstract class AbstractProvider implements ProviderInterface */ protected $options; + /** + * @var Indexable + */ + private $indexable; + /** * Constructor. * * @param ObjectPersisterInterface $objectPersister - * @param string $objectClass - * @param array $options + * @param IndexableInterface $indexable + * @param string $objectClass + * @param array $options */ - public function __construct(ObjectPersisterInterface $objectPersister, $objectClass, array $options = array()) - { - $this->objectPersister = $objectPersister; + public function __construct( + ObjectPersisterInterface $objectPersister, + IndexableInterface $indexable, + $objectClass, + array $options = array() + ) { + $this->indexable = $indexable; $this->objectClass = $objectClass; + $this->objectPersister = $objectPersister; $this->options = array_merge(array( 'batch_size' => 100, ), $options); } + /** + * Checks if a given object should be indexed or not. + * + * @param object $object + * @return bool + */ + protected function isObjectIndexable($object) + { + $typeName = $this->objectPersister->getType()->getName(); + $indexName = $this->objectPersister->getType()->getIndex()->getName(); + + return $this->indexable->isObjectIndexable($indexName, $typeName, $object); + } + /** * Get string with RAM usage information (current and peak) * diff --git a/Tests/Doctrine/AbstractProviderTest.php b/Tests/Doctrine/AbstractProviderTest.php index dcceccf..3640d16 100644 --- a/Tests/Doctrine/AbstractProviderTest.php +++ b/Tests/Doctrine/AbstractProviderTest.php @@ -9,24 +9,42 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase private $objectPersister; private $options; private $managerRegistry; + private $indexable; public function setUp() { - if (!interface_exists('Doctrine\Common\Persistence\ManagerRegistry')) { - $this->markTestSkipped('Doctrine Common is not available.'); - } + if (!interface_exists('Doctrine\Common\Persistence\ManagerRegistry')) { + $this->markTestSkipped('Doctrine Common is not available.'); + } - $this->objectClass = 'objectClass'; - $this->options = array('debug_logging' => true); + $this->objectClass = 'objectClass'; + $this->options = array('debug_logging' => true); - $this->objectPersister = $this->getMockObjectPersister(); - $this->managerRegistry = $this->getMockManagerRegistry(); - $this->objectManager = $this->getMockObjectManager(); + $this->objectPersister = $this->getMockObjectPersister(); + $this->managerRegistry = $this->getMockManagerRegistry(); + $this->objectManager = $this->getMockObjectManager(); + $this->indexable = $this->getMockIndexable(); - $this->managerRegistry->expects($this->any()) - ->method('getManagerForClass') - ->with($this->objectClass) - ->will($this->returnValue($this->objectManager)); + $index = $this->getMockBuilder('Elastica\Index')->disableOriginalConstructor()->getMock(); + $index->expects($this->any()) + ->method('getName') + ->will($this->returnValue('index')); + $type = $this->getMockBuilder('Elastica\Type')->disableOriginalConstructor()->getMock(); + $type->expects($this->any()) + ->method('getName') + ->will($this->returnValue('type')); + $type->expects($this->any()) + ->method('getIndex') + ->will($this->returnValue($index)); + + $this->objectPersister->expects($this->any()) + ->method('getType') + ->will($this->returnValue($type)); + + $this->managerRegistry->expects($this->any()) + ->method('getManagerForClass') + ->with($this->objectClass) + ->will($this->returnValue($this->objectManager)); } /** @@ -59,14 +77,13 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase ->with($queryBuilder, $batchSize, $offset) ->will($this->returnValue($objects)); - $this->objectPersister->expects($this->at($i)) - ->method('insertMany') - ->with($objects); - $this->objectManager->expects($this->at($i)) ->method('clear'); } + $this->objectPersister->expects($this->exactly(count($objectsByIteration))) + ->method('insertMany'); + $provider->populate(); } @@ -159,6 +176,36 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase $provider->populate(null, array('ignore-errors' => false)); } + public function testPopulateRunsIndexCallable() + { + $nbObjects = 2; + $objects = array(1, 2); + + $provider = $this->getMockAbstractProvider(); + $provider->expects($this->any()) + ->method('countObjects') + ->will($this->returnValue($nbObjects)); + $provider->expects($this->any()) + ->method('fetchSlice') + ->will($this->returnValue($objects)); + + $this->indexable->expects($this->at(0)) + ->method('isObjectIndexable') + ->with('index', 'type', 1) + ->will($this->returnValue(false)); + $this->indexable->expects($this->at(1)) + ->method('isObjectIndexable') + ->with('index', 'type', 2) + ->will($this->returnValue(true)); + + + $this->objectPersister->expects($this->once()) + ->method('insertMany') + ->with(array(1 => 2)); + + $provider->populate(); + } + /** * @return \FOS\ElasticaBundle\Doctrine\AbstractProvider|\PHPUnit_Framework_MockObject_MockObject */ @@ -166,6 +213,7 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase { return $this->getMockForAbstractClass('FOS\ElasticaBundle\Doctrine\AbstractProvider', array( $this->objectPersister, + $this->indexable, $this->objectClass, $this->options, $this->managerRegistry, @@ -205,6 +253,14 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase { return $this->getMock('FOS\ElasticaBundle\Persister\ObjectPersisterInterface'); } + + /** + * @return \FOS\ElasticaBundle\Provider\IndexableInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private function getMockIndexable() + { + return $this->getMock('FOS\ElasticaBundle\Provider\IndexableInterface'); + } } /** From 391e18dcbf9e165a4881119b3e321806ed1b0b0f Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Mon, 16 Jun 2014 16:20:17 +1000 Subject: [PATCH 258/447] Update changelog --- CHANGELOG-3.0.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-3.0.md b/CHANGELOG-3.0.md index 9d74640..f93832d 100644 --- a/CHANGELOG-3.0.md +++ b/CHANGELOG-3.0.md @@ -12,7 +12,17 @@ https://github.com/FriendsOfSymfony/FOSElasticaBundle/compare/v3.0.0...v3.0.1 To generate a changelog summary since the last version, run `git log --no-merges --oneline v3.0.0...3.0.x` -* 3.0.0-ALPHA3 (xxxx-xx-xx) +* 3.0.0-ALPHA6 (xxxx-xx-xx) + + * Moved `is_indexable_callback` from the listener properties to a type property called + `indexable_callback` which is run when both populating and listening for object + changes. + * BC BREAK `ObjectPersisterInterface` added method getType() (To be removed during + ObjectPersister refactoring before 3.0.0 stable when ObjectPersister will change) + * AbstractProvider constructor change: Second argument is now an `IndexableInterface` + instance. + +* 3.0.0-ALPHA3 (2014-04-01) * a9c4c93: Logger is now only enabled in debug mode by default * #463: allowing hot swappable reindexing From 629ca0df2eb0784fc90b812bb17c32d586ab3ade Mon Sep 17 00:00:00 2001 From: Patrick McAndrew Date: Mon, 16 Jun 2014 12:59:09 +0100 Subject: [PATCH 259/447] make sure headers is set prior to accessing --- Client.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Client.php b/Client.php index 3eb98fe..cfcfea6 100644 --- a/Client.php +++ b/Client.php @@ -28,7 +28,7 @@ class Client extends ElasticaClient 'host' => $connection->getHost(), 'port' => $connection->getPort(), 'transport' => $connection->getTransport(), - 'headers' => $connection->getConfig('headers'), + 'headers' => $connection->hasConfig('headers')?$connection->getConfig('headers'):array(), ); $this->_logger->logQuery($path, $method, $data, $time, $connection_array, $query); From 64be10447de535ee85f1cc2511ea55e943642df9 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Mon, 16 Jun 2014 22:33:04 +1000 Subject: [PATCH 260/447] Move Search annotation --- Annotation/Search.php | 16 ++++++++++++++++ CHANGELOG-3.0.md | 3 ++- Configuration/Search.php | 19 ++++++++++++++----- 3 files changed, 32 insertions(+), 6 deletions(-) create mode 100644 Annotation/Search.php diff --git a/Annotation/Search.php b/Annotation/Search.php new file mode 100644 index 0000000..26e1dbf --- /dev/null +++ b/Annotation/Search.php @@ -0,0 +1,16 @@ + + * @Annotation + * @Target("CLASS") + */ +class Search +{ + /** @var string */ + public $repositoryClass; +} diff --git a/CHANGELOG-3.0.md b/CHANGELOG-3.0.md index 095c268..62e347a 100644 --- a/CHANGELOG-3.0.md +++ b/CHANGELOG-3.0.md @@ -14,6 +14,7 @@ To generate a changelog summary since the last version, run * 3.0.0-ALPHA6 + * Annotation @Search moved to FOS\ElasticaBundle\Annotation\Search with FOS\ElasticaBundle\Configuration\Search deprecated * Deprecated FOS\ElasticaBundle\Client in favour of FOS\ElasticaBundle\Elastica\Client * Deprecated FOS\ElasticaBundle\DynamicIndex in favour of FOS\ElasticaBundle\Elastica\Index * Deprecated FOS\ElasticaBundle\IndexManager in favour of FOS\ElasticaBundle\Index\IndexManager @@ -21,7 +22,7 @@ To generate a changelog summary since the last version, run * 3.0.0-ALPHA5 (2014-05-23) -* Doctrine Provider speed up by disabling persistence logging while populating documents + * Doctrine Provider speed up by disabling persistence logging while populating documents * 3.0.0-ALPHA4 (2014-04-10) diff --git a/Configuration/Search.php b/Configuration/Search.php index cee10ab..1306f92 100644 --- a/Configuration/Search.php +++ b/Configuration/Search.php @@ -1,16 +1,25 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + namespace FOS\ElasticaBundle\Configuration; +use FOS\ElasticaBundle\Annotation\Search as BaseSearch; + /** * Annotation class for setting search repository. * - * @author Richard Miller * @Annotation + * @deprecated Use FOS\ElasticaBundle\Annotation\Search instead * @Target("CLASS") */ -class Search +class Search extends BaseSearch { - /** @var string */ - public $repositoryClass; -} +} From 7682d5a80a56cf7de2538c5370e1494fb418bbce Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Mon, 16 Jun 2014 22:33:31 +1000 Subject: [PATCH 261/447] Update composer.json --- composer.json | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/composer.json b/composer.json index 8783822..806d0b0 100644 --- a/composer.json +++ b/composer.json @@ -6,7 +6,8 @@ "homepage": "https://github.com/FriendsOfSymfony/FOSElasticaBundle", "license": "MIT", "authors": [ - { "name": "Thibault Duplessis", "email": "thibault.duplessis@gmail.com" }, + { "name": "FriendsOfSymfony Community", "homepage": "https://github.com/FriendsOfSymfony/FOSElasticaBundle/contributors" }, + { "name": "Tim Nagel", "email": "tim@nagel.com.au" }, { "name": "Richard Miller", "email": "richard.miller@limethinking.co.uk" }, { "name": "Jeremy Mikola", "email": "jmikola@gmail.com" } ], @@ -16,12 +17,13 @@ "symfony/console": "~2.1", "symfony/form": "~2.1", "symfony/property-access": "~2.2", - "ruflin/elastica": ">=0.90.10.0, <1.2-dev", + "ruflin/elastica": ">=0.90.10.0, <1.3-dev", "psr/log": "~1.0" }, "require-dev":{ "doctrine/orm": "~2.2", - "doctrine/mongodb-odm": "1.0.*@dev", + "doctrine/mongodb-odm": "1.0.*@beta", + "phpunit/phpunit": "~4.1", "propel/propel1": "1.6.*", "pagerfanta/pagerfanta": "1.0.*@dev", "knplabs/knp-components": "~1.2", @@ -37,9 +39,8 @@ "symfony/expression-language" : "~2.4" }, "autoload": { - "psr-0": { "FOS\\ElasticaBundle": "" } + "psr-4": { "FOS\\ElasticaBundle\\": "" } }, - "target-dir": "FOS/ElasticaBundle", "extra": { "branch-alias": { "dev-master": "3.0.x-dev" From 813a4a5d264644b8bdd04570724dff3c39b75b1d Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Mon, 16 Jun 2014 22:43:16 +1000 Subject: [PATCH 262/447] Fix previous commits --- Client.php | 4 ++-- DependencyInjection/Configuration.php | 8 +++---- DependencyInjection/FOSElasticaExtension.php | 22 +++++++++++++++---- Resources/config/config.xml | 13 +++++------ .../{LoggingClientTest.php => ClientTest.php} | 2 +- 5 files changed, 31 insertions(+), 18 deletions(-) rename Tests/Elastica/{LoggingClientTest.php => ClientTest.php} (98%) diff --git a/Client.php b/Client.php index f85756d..d0cee46 100644 --- a/Client.php +++ b/Client.php @@ -2,11 +2,11 @@ namespace FOS\ElasticaBundle; -use FOS\ElasticaBundle\Elastica\LoggingClient; +use FOS\ElasticaBundle\Elastica\Client as BaseClient; /** * @deprecated Use \FOS\ElasticaBundle\Elastica\LoggingClient */ -class Client extends LoggingClient +class Client extends BaseClient { } diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 754303b..7e8bca4 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -183,11 +183,11 @@ class Configuration implements ConfigurationInterface ->beforeNormalization() ->ifTrue(function($v) { return isset($v['mappings']); }) ->then(function($v) { - $v['properties'] = $v['mappings']; - unset($v['mappings']); + $v['properties'] = $v['mappings']; + unset($v['mappings']); - return $v; - }) + return $v; + }) ->end() ->children() ->scalarNode('index_analyzer')->end() diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index c844f3a..0b994c5 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -72,6 +72,7 @@ class FOSElasticaExtension extends Extension $container->setAlias('fos_elastica.index', sprintf('fos_elastica.index.%s', $config['default_index'])); $this->loadIndexManager($container); + $this->loadResetter($container); $this->createDefaultManagerAlias($config['default_manager'], $container); } @@ -132,7 +133,7 @@ class FOSElasticaExtension extends Extension $indexDef = new DefinitionDecorator('fos_elastica.index_prototype'); $indexDef->replaceArgument(0, $indexName); - if ($index['client']) { + if (isset($index['client'])) { $client = $this->getClient($index['client']); $indexDef->setFactoryService($client); } @@ -146,7 +147,7 @@ class FOSElasticaExtension extends Extension 'settings' => $index['settings'] ), 'elasticsearch_name' => $indexName, - 'index' => $reference, + 'reference' => $reference, 'name' => $name, 'type_prototype' => isset($index['type_prototype']) ? $index['type_prototype'] : array(), 'use_alias' => $index['use_alias'], @@ -220,7 +221,9 @@ class FOSElasticaExtension extends Extension '_timestamp', '_ttl', ) as $field) { - $this->indexConfigs[$indexName]['config']['properties'][$name][$field] = $type[$field]; + if (array_key_exists($field, $type)) { + $this->indexConfigs[$indexName]['config']['properties'][$name][$field] = $type[$field]; + } } if (!empty($type['dynamic_templates'])) { @@ -390,7 +393,7 @@ class FOSElasticaExtension extends Extension if ($this->serializerConfig) { $abstractId = 'fos_elastica.object_serializer_persister'; - $callbackId = sprintf('%s.%s.serializer.callback', $this->indexConfigs[$indexName]['index'], $typeName); + $callbackId = sprintf('%s.%s.serializer.callback', $this->indexConfigs[$indexName]['reference'], $typeName); $arguments[] = array(new Reference($callbackId), 'serialize'); } else { $abstractId = 'fos_elastica.object_persister'; @@ -622,4 +625,15 @@ class FOSElasticaExtension extends Extension return $this->clients[$clientName]['reference']; } + + /** + * Loads the resetter + * + * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container + */ + private function loadResetter(ContainerBuilder $container) + { + $resetterDef = $container->getDefinition('fos_elastica.resetter'); + $resetterDef->replaceArgument(0, $this->indexConfigs); + } } diff --git a/Resources/config/config.xml b/Resources/config/config.xml index c1ac0f9..3cb6280 100644 --- a/Resources/config/config.xml +++ b/Resources/config/config.xml @@ -5,7 +5,7 @@ xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> - FOS\ElasticaBundle\Elastica\LoggingClient + FOS\ElasticaBundle\Elastica\Client FOS\ElasticaBundle\Logger\ElasticaLogger FOS\ElasticaBundle\DataCollector\ElasticaDataCollector Symfony\Component\PropertyAccess\PropertyAccessor @@ -15,7 +15,11 @@ - + + + + + @@ -24,11 +28,6 @@ - - - - - diff --git a/Tests/Elastica/LoggingClientTest.php b/Tests/Elastica/ClientTest.php similarity index 98% rename from Tests/Elastica/LoggingClientTest.php rename to Tests/Elastica/ClientTest.php index b08a2cf..43ac7a2 100644 --- a/Tests/Elastica/LoggingClientTest.php +++ b/Tests/Elastica/ClientTest.php @@ -28,7 +28,7 @@ class LoggingClientTest extends \PHPUnit_Framework_TestCase $this->isType('array') ); - $client = $this->getMockBuilder('FOS\ElasticaBundle\Elastica\LoggingClient') + $client = $this->getMockBuilder('FOS\ElasticaBundle\Elastica\Client') ->setMethods(array('getConnection')) ->getMock(); From ada3942576a920c56c020fb9bde6b18a0bffacbf Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Mon, 16 Jun 2014 23:23:49 +1000 Subject: [PATCH 263/447] Config Source providers --- Configuration/IndexConfig.php | 122 ++++++++++++++++++ Configuration/Manager.php | 59 +++++++++ Configuration/ManagerInterface.php | 35 +++++ Configuration/Source/ContainerSource.php | 62 +++++++++ Configuration/Source/SourceInterface.php | 26 ++++ Configuration/TypeConfig.php | 31 +++++ .../Compiler/ConfigSourcePass.php | 36 ++++++ DependencyInjection/FOSElasticaExtension.php | 49 ++----- FOSElasticaBundle.php | 2 + Resources/config/config.xml | 4 + Resources/config/source.xml | 13 ++ Tests/Functional/ConfigurationManagerTest.php | 54 ++++++++ 12 files changed, 457 insertions(+), 36 deletions(-) create mode 100644 Configuration/IndexConfig.php create mode 100644 Configuration/Manager.php create mode 100644 Configuration/ManagerInterface.php create mode 100644 Configuration/Source/ContainerSource.php create mode 100644 Configuration/Source/SourceInterface.php create mode 100644 Configuration/TypeConfig.php create mode 100644 DependencyInjection/Compiler/ConfigSourcePass.php create mode 100644 Resources/config/source.xml create mode 100644 Tests/Functional/ConfigurationManagerTest.php diff --git a/Configuration/IndexConfig.php b/Configuration/IndexConfig.php new file mode 100644 index 0000000..684713e --- /dev/null +++ b/Configuration/IndexConfig.php @@ -0,0 +1,122 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FOS\ElasticaBundle\Configuration; + +class IndexConfig +{ + /** + * The name of the index for ElasticSearch. + * + * @var string + */ + private $elasticSearchName; + + /** + * The internal name of the index. May not be the same as the name used in ElasticSearch, + * especially if aliases are enabled. + * + * @var string + */ + private $name; + + /** + * An array of settings sent to ElasticSearch when creating the index. + * + * @var array + */ + private $settings; + + /** + * All types that belong to this index. + * + * @var TypeConfig[] + */ + private $types; + + /** + * Indicates if the index should use an alias, allowing an index repopulation to occur + * without overwriting the current index. + * + * @var bool + */ + private $useAlias = false; + + /** + * Constructor expects an array as generated by the Container Configuration builder. + * + * @param string $name + * @param TypeConfig[] $types + * @param array $config + */ + public function __construct($name, array $types, array $config) + { + $this->elasticSearchName = $config['elasticSearchName']; + $this->name = $name; + $this->settings = $config['settings']; + $this->types = $types; + $this->useAlias = $config['useAlias']; + } + + /** + * @return string + */ + public function getElasticSearchName() + { + return $this->elasticSearchName; + } + + /** + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * @return array + */ + public function getSettings() + { + return $this->settings; + } + + /** + * @param string $typeName + * @return TypeConfig + * @throws \InvalidArgumentException + */ + public function getType($typeName) + { + if (!array_key_exists($typeName, $this->types)) { + throw new \InvalidArgumentException(sprintf('Type "%s" does not exist on index "%s"', $typeName, $this->name)); + } + + return $this->types[$typeName]; + } + + /** + * @return \FOS\ElasticaBundle\Configuration\TypeConfig[] + */ + public function getTypes() + { + return $this->types; + } + + /** + * @return boolean + */ + public function getUseAlias() + { + return $this->useAlias; + } +} diff --git a/Configuration/Manager.php b/Configuration/Manager.php new file mode 100644 index 0000000..85afb99 --- /dev/null +++ b/Configuration/Manager.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FOS\ElasticaBundle\Configuration; + +/** + * Central manager for index and type configuration. + */ +class Manager implements ManagerInterface +{ + /** + * @var IndexConfig[] + */ + private $indexes = array(); + + /** + * @param Source\SourceInterface[] $sources + */ + public function __construct(array $sources) + { + foreach ($sources as $source) { + $this->indexes = array_merge($source->getConfiguration(), $this->indexes); + } + } + + public function getTypeConfiguration($indexName, $typeName) + { + $index = $this->getIndexConfiguration($indexName); + $type = $index->getType($typeName); + + if (!$type) { + throw new \InvalidArgumentException(sprintf('Type with name "%s" on index "%s" is not configured', $typeName, $indexName)); + } + + return $type; + } + + public function getIndexConfiguration($indexName) + { + if (!$this->hasIndexConfiguration($indexName)) { + throw new \InvalidArgumentException(sprintf('Index with name "%s" is not configured.', $indexName)); + } + + return $this->indexes[$indexName]; + } + + public function hasIndexConfiguration($indexName) + { + return isset($this->indexes[$indexName]); + } +} diff --git a/Configuration/ManagerInterface.php b/Configuration/ManagerInterface.php new file mode 100644 index 0000000..7852828 --- /dev/null +++ b/Configuration/ManagerInterface.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FOS\ElasticaBundle\Configuration; + +/** + * Central manager for index and type configuration. + */ +interface ManagerInterface +{ + /** + * Returns configuration for an index. + * + * @param $index + * @return IndexConfig + */ + public function getIndexConfiguration($index); + + /** + * Returns a type configuration. + * + * @param string $index + * @param string $type + * @return TypeConfig + */ + public function getTypeConfiguration($index, $type); +} \ No newline at end of file diff --git a/Configuration/Source/ContainerSource.php b/Configuration/Source/ContainerSource.php new file mode 100644 index 0000000..5fba57a --- /dev/null +++ b/Configuration/Source/ContainerSource.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FOS\ElasticaBundle\Configuration\Source; + +use FOS\ElasticaBundle\Configuration\IndexConfig; +use FOS\ElasticaBundle\Configuration\TypeConfig; + +/** + * Returns index and type configuration from the container. + */ +class ContainerSource implements SourceInterface +{ + /** + * The internal container representation of information. + * + * @var array + */ + private $configArray; + + public function __construct(array $configArray) + { + $this->configArray = $configArray; + } + + /** + * Should return all configuration available from the data source. + * + * @return IndexConfig[] + */ + public function getConfiguration() + { + $indexes = array(); + foreach ($this->configArray as $config) { + $types = array(); + foreach ($config['types'] as $typeConfig) { + $types[$typeConfig['name']] = new TypeConfig($typeConfig['name'], array( + 'dynamicTemplates' => $typeConfig['dynamic_templates'], + 'properties' => $typeConfig['properties'], + ), $config['type_prototype']); + } + + $index = new IndexConfig($config['name'], $types, array( + 'elasticSearchName' => $config['elasticsearch_name'], + 'settings' => $config['settings'], + 'useAlias' => $config['use_alias'], + )); + + $indexes[$config['name']] = $index; + } + + return $indexes; + } +} diff --git a/Configuration/Source/SourceInterface.php b/Configuration/Source/SourceInterface.php new file mode 100644 index 0000000..34e9901 --- /dev/null +++ b/Configuration/Source/SourceInterface.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FOS\ElasticaBundle\Configuration\Source; + +/** + * Represents a source of index and type information (ie, the Container configuration or + * annotations). + */ +interface SourceInterface +{ + /** + * Should return all configuration available from the data source. + * + * @return \FOS\ElasticaBundle\Configuration\IndexConfig[] + */ + public function getConfiguration(); +} diff --git a/Configuration/TypeConfig.php b/Configuration/TypeConfig.php new file mode 100644 index 0000000..c78a32a --- /dev/null +++ b/Configuration/TypeConfig.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FOS\ElasticaBundle\Configuration; + +class TypeConfig +{ + /** + * @var array + */ + private $config; + + /** + * @var string + */ + private $name; + + public function __construct($name, array $config, array $prototype) + { + $this->config = $config; + $this->name = $name; + } +} diff --git a/DependencyInjection/Compiler/ConfigSourcePass.php b/DependencyInjection/Compiler/ConfigSourcePass.php new file mode 100644 index 0000000..b35a665 --- /dev/null +++ b/DependencyInjection/Compiler/ConfigSourcePass.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FOS\ElasticaBundle\DependencyInjection\Compiler; + +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; + +class ConfigSourcePass implements CompilerPassInterface +{ + /** + * {@inheritDoc} + */ + public function process(ContainerBuilder $container) + { + if (!$container->hasDefinition('fos_elastica.config_manager')) { + return; + } + + $sources = array(); + foreach (array_keys($container->findTaggedServiceIds('fos_elastica.config_source')) as $id) { + $sources[] = new Reference($id); + } + + $container->getDefinition('fos_elastica.config_manager')->replaceArgument(0, $sources); + } +} diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 0b994c5..7699fd7 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -49,7 +49,7 @@ class FOSElasticaExtension extends Extension return; } - foreach (array('config', 'index', 'persister', 'provider', 'transformer') as $basename) { + foreach (array('config', 'index', 'persister', 'provider', 'source', 'transformer') as $basename) { $loader->load(sprintf('%s.xml', $basename)); } @@ -71,6 +71,8 @@ class FOSElasticaExtension extends Extension $this->loadIndexes($config['indexes'], $container); $container->setAlias('fos_elastica.index', sprintf('fos_elastica.index.%s', $config['default_index'])); + $container->getDefinition('fos_elastica.config_source.container')->replaceArgument(0, $this->indexConfigs); + $this->loadIndexManager($container); $this->loadResetter($container); @@ -142,13 +144,10 @@ class FOSElasticaExtension extends Extension $reference = new Reference($indexId); $this->indexConfigs[$name] = array( - 'config' => array( - 'properties' => array(), - 'settings' => $index['settings'] - ), 'elasticsearch_name' => $indexName, 'reference' => $reference, 'name' => $name, + 'settings' => $index['settings'], 'type_prototype' => isset($index['type_prototype']) ? $index['type_prototype'] : array(), 'use_alias' => $index['use_alias'], ); @@ -197,7 +196,6 @@ class FOSElasticaExtension extends Extension { foreach ($types as $name => $type) { $indexName = $indexConfig['name']; - $type = self::deepArrayUnion($indexConfig['type_prototype'], $type); $typeId = sprintf('%s.%s', $indexName, $name); $typeDef = new DefinitionDecorator('fos_elastica.type_prototype'); @@ -208,7 +206,14 @@ class FOSElasticaExtension extends Extension $this->loadTypePersistenceIntegration($type['persistence'], $container, $typeDef, $indexName, $name); } + $this->indexConfigs[$indexName]['types'][$name] = array( + 'dynamic_templates' => array(), + 'name' => $name, + 'properties' => array() + ); + foreach (array( + 'dynamic_templates', 'index_analyzer', 'properties', 'search_analyzer', @@ -222,14 +227,7 @@ class FOSElasticaExtension extends Extension '_ttl', ) as $field) { if (array_key_exists($field, $type)) { - $this->indexConfigs[$indexName]['config']['properties'][$name][$field] = $type[$field]; - } - } - - if (!empty($type['dynamic_templates'])) { - $this->indexConfigs[$indexName]['config']['properties'][$name]['dynamic_templates'] = array(); - foreach ($type['dynamic_templates'] as $templateName => $templateData) { - $this->indexConfigs[$indexName]['config']['properties'][$name]['dynamic_templates'][] = array($templateName => $templateData); + $this->indexConfigs[$indexName]['types'][$name]['properties'][$field] = $type[$field]; } } @@ -259,27 +257,6 @@ class FOSElasticaExtension extends Extension } } - /** - * Merges two arrays without reindexing numeric keys. - * - * @param array $array1 An array to merge - * @param array $array2 An array to merge - * - * @return array The merged array - */ - private static function deepArrayUnion($array1, $array2) - { - foreach ($array2 as $key => $value) { - if (is_array($value) && isset($array1[$key]) && is_array($array1[$key])) { - $array1[$key] = self::deepArrayUnion($array1[$key], $value); - } else { - $array1[$key] = $value; - } - } - - return $array1; - } - /** * Loads the optional provider and finder for a type * @@ -397,7 +374,7 @@ class FOSElasticaExtension extends Extension $arguments[] = array(new Reference($callbackId), 'serialize'); } else { $abstractId = 'fos_elastica.object_persister'; - $arguments[] = $this->indexConfigs[$indexName]['config']['properties'][$typeName]['properties']; + $arguments[] = $this->indexConfigs[$indexName]['types'][$typeName]['properties']; } $serviceId = sprintf('fos_elastica.object_persister.%s.%s', $indexName, $typeName); diff --git a/FOSElasticaBundle.php b/FOSElasticaBundle.php index 44424d3..ac4cc3d 100644 --- a/FOSElasticaBundle.php +++ b/FOSElasticaBundle.php @@ -2,6 +2,7 @@ namespace FOS\ElasticaBundle; +use FOS\ElasticaBundle\DependencyInjection\Compiler\ConfigSourcePass; use FOS\ElasticaBundle\DependencyInjection\Compiler\RegisterProvidersPass; use FOS\ElasticaBundle\DependencyInjection\Compiler\TransformerPass; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -23,5 +24,6 @@ class FOSElasticaBundle extends Bundle $container->addCompilerPass(new RegisterProvidersPass(), PassConfig::TYPE_BEFORE_REMOVING); $container->addCompilerPass(new TransformerPass()); + $container->addCompilerPass(new ConfigSourcePass()); } } diff --git a/Resources/config/config.xml b/Resources/config/config.xml index 3cb6280..4ee733f 100644 --- a/Resources/config/config.xml +++ b/Resources/config/config.xml @@ -17,6 +17,10 @@ + + + + diff --git a/Resources/config/source.xml b/Resources/config/source.xml new file mode 100644 index 0000000..c0f085c --- /dev/null +++ b/Resources/config/source.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/Tests/Functional/ConfigurationManagerTest.php b/Tests/Functional/ConfigurationManagerTest.php new file mode 100644 index 0000000..0574481 --- /dev/null +++ b/Tests/Functional/ConfigurationManagerTest.php @@ -0,0 +1,54 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace FOS\ElasticaBundle\Tests\Functional; + +use Symfony\Bundle\FrameworkBundle\Client; + +/** + * @group functional + */ +class ConfigurationManagerTest extends WebTestCase +{ + public function testContainerSource() + { + $client = $this->createClient(array('test_case' => 'Basic')); + $manager = $this->getManager($client); + + $index = $manager->getIndexConfiguration('index'); + var_dump($index); die; + } + + protected function setUp() + { + parent::setUp(); + + $this->deleteTmpDir('Basic'); + } + + protected function tearDown() + { + parent::tearDown(); + + $this->deleteTmpDir('Basic'); + } + + /** + * @param Client $client + * @return \FOS\ElasticaBundle\Configuration\Manager + */ + private function getManager(Client $client) + { + $manager = $client->getContainer()->get('fos_elastica.config_manager'); + + return $manager; + } +} From 0383811834eb9ac85e001f4c83964a07573cc93f Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Mon, 16 Jun 2014 23:28:53 +1000 Subject: [PATCH 264/447] Fix test, add test for failing mappings --- Tests/Doctrine/AbstractProviderTest.php | 9 ++++--- Tests/Functional/MappingToElasticaTest.php | 28 ++++++++++++++++++++-- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/Tests/Doctrine/AbstractProviderTest.php b/Tests/Doctrine/AbstractProviderTest.php index dcceccf..c53940c 100644 --- a/Tests/Doctrine/AbstractProviderTest.php +++ b/Tests/Doctrine/AbstractProviderTest.php @@ -2,6 +2,9 @@ namespace FOS\ElasticaBundle\Tests\Doctrine; +use Elastica\Bulk\ResponseSet; +use Elastica\Response; + class AbstractProviderTest extends \PHPUnit_Framework_TestCase { private $objectClass; @@ -177,9 +180,9 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase */ private function getMockBulkResponseException() { - return $this->getMockBuilder('Elastica\Exception\Bulk\ResponseException') - ->disableOriginalConstructor() - ->getMock(); + return $this->getMock('Elastica\Exception\Bulk\ResponseException', null, array( + new ResponseSet(new Response(array()), array()) + )); } /** diff --git a/Tests/Functional/MappingToElasticaTest.php b/Tests/Functional/MappingToElasticaTest.php index 3c32e10..bffcf76 100644 --- a/Tests/Functional/MappingToElasticaTest.php +++ b/Tests/Functional/MappingToElasticaTest.php @@ -18,13 +18,28 @@ use Symfony\Bundle\FrameworkBundle\Client; */ class MappingToElasticaTest extends WebTestCase { - public function testReset() + public function testResetIndexAddsMappings() { $client = $this->createClient(array('test_case' => 'Basic')); $resetter = $this->getResetter($client); - $resetter->resetIndex('index'); + + $type = $this->getType($client); + $mapping = $type->getMapping(); + + $this->assertNotEmpty($mapping, 'Mapping was populated'); + } + + public function testResetType() + { + $client = $this->createClient(array('test_case' => 'Basic')); + $resetter = $this->getResetter($client); $resetter->resetIndexType('index', 'type'); + + $type = $this->getType($client); + $mapping = $type->getMapping(); + + $this->assertNotEmpty($mapping, 'Mapping was populated'); } /** @@ -36,6 +51,15 @@ class MappingToElasticaTest extends WebTestCase return $client->getContainer()->get('fos_elastica.resetter'); } + /** + * @param Client $client + * @return \Elastica\Type + */ + private function getType(Client $client) + { + return $client->getContainer()->get('fos_elastica.index.index.type'); + } + protected function setUp() { parent::setUp(); From 934c6af8b8254c9f8be328ec842922a330e8c681 Mon Sep 17 00:00:00 2001 From: Patrick McAndrew Date: Mon, 16 Jun 2014 14:30:03 +0100 Subject: [PATCH 265/447] make PSR2 compliant --- Client.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Client.php b/Client.php index cfcfea6..265773a 100644 --- a/Client.php +++ b/Client.php @@ -28,7 +28,7 @@ class Client extends ElasticaClient 'host' => $connection->getHost(), 'port' => $connection->getPort(), 'transport' => $connection->getTransport(), - 'headers' => $connection->hasConfig('headers')?$connection->getConfig('headers'):array(), + 'headers' => $connection->hasConfig('headers') ? $connection->getConfig('headers') : array(), ); $this->_logger->logQuery($path, $method, $data, $time, $connection_array, $query); From 2e23f4a1bf31eb4e2775880c2ecd319717fac984 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Tue, 17 Jun 2014 10:07:10 +1000 Subject: [PATCH 266/447] Added documentation changes for indexable_callback --- Resources/doc/setup.md | 2 +- Resources/doc/types.md | 81 ++++++++++++++++++++---------------------- 2 files changed, 39 insertions(+), 44 deletions(-) diff --git a/Resources/doc/setup.md b/Resources/doc/setup.md index 9a39b95..485f290 100644 --- a/Resources/doc/setup.md +++ b/Resources/doc/setup.md @@ -7,7 +7,7 @@ A) Install FOSElasticaBundle FOSElasticaBundle is installed using [Composer](https://getcomposer.org). ```bash -$ php composer.phar require friendsofsymfony/elastica-bundle "3.0.*" +$ php composer.phar require friendsofsymfony/elastica-bundle "3.0.*@alpha" ``` ### Elasticsearch diff --git a/Resources/doc/types.md b/Resources/doc/types.md index aacb09e..be687d7 100644 --- a/Resources/doc/types.md +++ b/Resources/doc/types.md @@ -149,6 +149,44 @@ analyzer, you could write: title: { boost: 8, analyzer: my_analyzer } ``` +Testing if an object should be indexed +-------------------------------------- + +FOSElasticaBundle can be configured to automatically index changes made for +different kinds of objects if your persistence backend supports these methods, +but in some cases you might want to run an external service or call a property +on the object to see if it should be indexed. + +A property, `indexable_callback` is provided under the type configuration that +lets you configure this behaviour which will apply for any automated watching +for changes and for a repopulation of an index. + +In the example below, we're checking the enabled property on the user to only +index enabled users. + +```yaml + types: + users: + indexable_callback: 'enabled' +``` + +The callback option supports multiple approaches: + +* A method on the object itself provided as a string. `enabled` will call + `Object->enabled()` +* An array of a service id and a method which will be called with the object as the first + and only argument. `[ @my_custom_service, 'userIndexable' ]` will call the userIndexable + method on a service defined as my_custom_service. +* If you have the ExpressionLanguage component installed, A valid ExpressionLanguage + expression provided as a string. The object being indexed will be supplied as `object` + in the expression. `object.isEnabled() or object.shouldBeIndexedAnyway()`. For more + information on the ExpressionLanguage component and its capabilities see its + [documentation](http://symfony.com/doc/current/components/expression_language/index.html) + +In all cases, the callback should return a true or false, with true indicating it will be +indexed, and a false indicating the object should not be indexed, or should be removed +from the index if we are running an update. + Provider Configuration ---------------------- @@ -234,49 +272,6 @@ You can also choose to only listen for some of the events: > **Propel** doesn't support this feature yet. -### Checking an entity method for listener - -If you use listeners to update your index, you may need to validate your -entities before you index them (e.g. only index "public" entities). Typically, -you'll want the listener to be consistent with the provider's query criteria. -This may be achieved by using the `is_indexable_callback` config parameter: - -```yaml - persistence: - listener: - is_indexable_callback: "isPublic" -``` - -If `is_indexable_callback` is a string and the entity has a method with the -specified name, the listener will only index entities for which the method -returns `true`. Additionally, you may provide a service and method name pair: - -```yaml - persistence: - listener: - is_indexable_callback: [ "%custom_service_id%", "isIndexable" ] -``` - -In this case, the callback_class will be the `isIndexable()` method on the specified -service and the object being considered for indexing will be passed as the only -argument. This allows you to do more complex validation (e.g. ACL checks). - -If you have the [Symfony ExpressionLanguage](https://github.com/symfony/expression-language) -component installed, you can use expressions to evaluate the callback: - -```yaml - persistence: - listener: - is_indexable_callback: "user.isActive() && user.hasRole('ROLE_USER')" -``` - -As you might expect, new entities will only be indexed if the callback_class returns -`true`. Additionally, modified entities will be updated or removed from the -index depending on whether the callback_class returns `true` or `false`, respectively. -The delete listener disregards the callback_class. - -> **Propel** doesn't support this feature yet. - Flushing Method --------------- From b49437529c54f2ad9ffaef87019e5539a8b9372d Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Tue, 17 Jun 2014 10:41:11 +1000 Subject: [PATCH 267/447] Fix incorrect provider configuration --- Propel/Provider.php | 10 +++++++--- Resources/config/mongodb.xml | 2 +- Resources/config/orm.xml | 2 +- Resources/config/propel.xml | 2 +- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Propel/Provider.php b/Propel/Provider.php index 393beba..c242d47 100644 --- a/Propel/Provider.php +++ b/Propel/Provider.php @@ -30,14 +30,18 @@ class Provider extends AbstractProvider $objects = $queryClass::create() ->limit($batchSize) ->offset($offset) - ->find(); + ->find() + ->getArrayCopy(); + if ($loggerClosure) { + $stepNbObjects = count($objects); + } + $objects = array_filter($objects, array($this, 'isObjectIndexable')); - $this->objectPersister->insertMany($objects->getArrayCopy()); + $this->objectPersister->insertMany($objects); usleep($sleep); if ($loggerClosure) { - $stepNbObjects = count($objects); $stepCount = $stepNbObjects + $offset; $percentComplete = 100 * $stepCount / $nbObjects; $objectsPerSecond = $stepNbObjects / (microtime(true) - $stepStartTime); diff --git a/Resources/config/mongodb.xml b/Resources/config/mongodb.xml index e575e5d..ffa4f22 100644 --- a/Resources/config/mongodb.xml +++ b/Resources/config/mongodb.xml @@ -23,7 +23,7 @@ - + diff --git a/Resources/config/orm.xml b/Resources/config/orm.xml index 43d1670..351992a 100644 --- a/Resources/config/orm.xml +++ b/Resources/config/orm.xml @@ -23,7 +23,7 @@ - + diff --git a/Resources/config/propel.xml b/Resources/config/propel.xml index 7a7d93e..cbc8cd7 100644 --- a/Resources/config/propel.xml +++ b/Resources/config/propel.xml @@ -7,7 +7,7 @@ - + From e225d841edbd6633a0e864838af5b13f777b740b Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Tue, 17 Jun 2014 10:54:09 +1000 Subject: [PATCH 268/447] Wrong service. Whoops. --- Resources/config/mongodb.xml | 4 ++-- Resources/config/orm.xml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Resources/config/mongodb.xml b/Resources/config/mongodb.xml index ffa4f22..73b70c5 100644 --- a/Resources/config/mongodb.xml +++ b/Resources/config/mongodb.xml @@ -8,7 +8,7 @@ - + @@ -23,7 +23,7 @@ - + diff --git a/Resources/config/orm.xml b/Resources/config/orm.xml index 351992a..807a5bf 100644 --- a/Resources/config/orm.xml +++ b/Resources/config/orm.xml @@ -8,7 +8,7 @@ - + @@ -23,7 +23,7 @@ - + From aafb8c8e89d23fd455263bddc817874092c787b6 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Tue, 17 Jun 2014 12:03:38 +1000 Subject: [PATCH 269/447] Fix indexable callbacks with alias based indexes --- DependencyInjection/FOSElasticaExtension.php | 13 +++++++++--- Doctrine/Listener.php | 18 +++++++++-------- DynamicIndex.php | 21 ++++++++++++++++---- Persister/ObjectPersister.php | 10 ---------- Persister/ObjectPersisterInterface.php | 7 ------- Provider/AbstractProvider.php | 9 +++++---- Provider/Indexable.php | 2 +- Resources/config/mongodb.xml | 1 + Resources/config/orm.xml | 1 + Resources/config/propel.xml | 1 + Tests/Doctrine/AbstractListenerTest.php | 12 +++++------ Tests/Doctrine/AbstractProviderTest.php | 18 +---------------- Tests/Provider/IndexableTest.php | 8 ++++++++ 13 files changed, 61 insertions(+), 60 deletions(-) diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 9e50c0b..66a2cef 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -419,9 +419,12 @@ class FOSElasticaExtension extends Extension $providerDef = new DefinitionDecorator('fos_elastica.provider.prototype.' . $typeConfig['driver']); $providerDef->addTag('fos_elastica.provider', array('index' => $indexName, 'type' => $typeName)); $providerDef->replaceArgument(0, new Reference($objectPersisterId)); - $providerDef->replaceArgument(1, $typeConfig['model']); + $providerDef->replaceArgument(2, $typeConfig['model']); // Propel provider can simply ignore Doctrine-specific options - $providerDef->replaceArgument(2, array_diff_key($typeConfig['provider'], array('service' => 1))); + $providerDef->replaceArgument(3, array_merge(array_diff_key($typeConfig['provider'], array('service' => 1)), array( + 'indexName' => $indexName, + 'typeName' => $typeName, + ))); $container->setDefinition($providerId, $providerDef); return $providerId; @@ -440,7 +443,11 @@ class FOSElasticaExtension extends Extension $listenerDef = new DefinitionDecorator($abstractListenerId); $listenerDef->replaceArgument(0, new Reference($objectPersisterId)); $listenerDef->replaceArgument(1, $this->getDoctrineEvents($typeConfig)); - $listenerDef->replaceArgument(3, $typeConfig['identifier']); + $listenerDef->replaceArgument(3, array( + 'identifier' => $typeConfig['identifier'], + 'indexName' => $indexName, + 'typeName' => $typeName, + )); if ($typeConfig['listener']['logger']) { $listenerDef->replaceArgument(4, new Reference($typeConfig['listener']['logger'])); } diff --git a/Doctrine/Listener.php b/Doctrine/Listener.php index 4a01aa1..73a271d 100644 --- a/Doctrine/Listener.php +++ b/Doctrine/Listener.php @@ -31,11 +31,11 @@ class Listener implements EventSubscriber protected $events; /** - * Name of domain model field used as the ES identifier + * Configuration for the listener * * @var string */ - protected $esIdentifierField; + private $config; /** * Objects scheduled for insertion and replacement @@ -66,17 +66,19 @@ class Listener implements EventSubscriber * @param ObjectPersisterInterface $objectPersister * @param array $events * @param IndexableInterface $indexable - * @param string $esIdentifierField + * @param array $config * @param null $logger */ public function __construct( ObjectPersisterInterface $objectPersister, array $events, IndexableInterface $indexable, - $esIdentifierField = 'id', + array $config = array(), $logger = null ) { - $this->esIdentifierField = $esIdentifierField; + $this->config = array_merge(array( + 'identifier' => 'id', + ), $config); $this->events = $events; $this->indexable = $indexable; $this->objectPersister = $objectPersister; @@ -196,7 +198,7 @@ class Listener implements EventSubscriber */ protected function scheduleForDeletion($object) { - if ($identifierValue = $this->propertyAccessor->getValue($object, $this->esIdentifierField)) { + if ($identifierValue = $this->propertyAccessor->getValue($object, $this->config['identifier'])) { $this->scheduledForDeletion[] = $identifierValue; } } @@ -210,8 +212,8 @@ class Listener implements EventSubscriber private function isObjectIndexable($object) { return $this->indexable->isObjectIndexable( - $this->objectPersister->getType()->getIndex()->getName(), - $this->objectPersister->getType()->getName(), + $this->config['indexName'], + $this->config['typeName'], $object ); } diff --git a/DynamicIndex.php b/DynamicIndex.php index cbec8e9..f890234 100644 --- a/DynamicIndex.php +++ b/DynamicIndex.php @@ -11,18 +11,31 @@ use Elastica\Index; */ class DynamicIndex extends Index { + private $originalName; + /** * Reassign index name * - * While it's technically a regular setter for name property, it's specifically named overrideName, but not setName - * since it's used for a very specific case and normally should not be used + * While it's technically a regular setter for name property, it's specifically named + * overrideName, but not setName since it's used for a very specific case and normally + * should not be used. * * @param string $name Index name - * - * @return void */ public function overrideName($name) { + $this->originalName = $this->_name; $this->_name = $name; } + + /** + * Returns the original name of the index if the index has been renamed for reindexing + * or realiasing purposes. + * + * @return string + */ + public function getOriginalName() + { + return $this->originalName ?: $this->_name; + } } diff --git a/Persister/ObjectPersister.php b/Persister/ObjectPersister.php index 2b6a8af..54d5fd1 100644 --- a/Persister/ObjectPersister.php +++ b/Persister/ObjectPersister.php @@ -31,16 +31,6 @@ class ObjectPersister implements ObjectPersisterInterface $this->fields = $fields; } - /** - * @internal Temporary method that will be removed. - * - * @return Type - */ - public function getType() - { - return $this->type; - } - /** * If the ObjectPersister handles a given object. * diff --git a/Persister/ObjectPersisterInterface.php b/Persister/ObjectPersisterInterface.php index 5953d5a..2b4c8ee 100644 --- a/Persister/ObjectPersisterInterface.php +++ b/Persister/ObjectPersisterInterface.php @@ -68,11 +68,4 @@ interface ObjectPersisterInterface * @param array $identifiers array of domain model object identifiers */ public function deleteManyByIdentifiers(array $identifiers); - - /** - * Returns the elastica type used by this persister - * - * @return \Elastica\Type - */ - public function getType(); } diff --git a/Provider/AbstractProvider.php b/Provider/AbstractProvider.php index 8642be8..82ea914 100644 --- a/Provider/AbstractProvider.php +++ b/Provider/AbstractProvider.php @@ -60,10 +60,11 @@ abstract class AbstractProvider implements ProviderInterface */ protected function isObjectIndexable($object) { - $typeName = $this->objectPersister->getType()->getName(); - $indexName = $this->objectPersister->getType()->getIndex()->getName(); - - return $this->indexable->isObjectIndexable($indexName, $typeName, $object); + return $this->indexable->isObjectIndexable( + $this->options['indexName'], + $this->options['typeName'], + $object + ); } /** diff --git a/Provider/Indexable.php b/Provider/Indexable.php index b388c58..09168a1 100644 --- a/Provider/Indexable.php +++ b/Provider/Indexable.php @@ -94,7 +94,7 @@ class Indexable implements IndexableInterface private function buildCallback($type, $object) { if (!array_key_exists($type, $this->callbacks)) { - throw new \InvalidArgumentException(sprintf('Callback for type "%s" is not configured', $type)); + return null; } $callback = $this->callbacks[$type]; diff --git a/Resources/config/mongodb.xml b/Resources/config/mongodb.xml index 73b70c5..df2d2cc 100644 --- a/Resources/config/mongodb.xml +++ b/Resources/config/mongodb.xml @@ -9,6 +9,7 @@ + diff --git a/Resources/config/orm.xml b/Resources/config/orm.xml index 807a5bf..0cd6c42 100644 --- a/Resources/config/orm.xml +++ b/Resources/config/orm.xml @@ -9,6 +9,7 @@ + diff --git a/Resources/config/propel.xml b/Resources/config/propel.xml index cbc8cd7..962cb09 100644 --- a/Resources/config/propel.xml +++ b/Resources/config/propel.xml @@ -8,6 +8,7 @@ + diff --git a/Tests/Doctrine/AbstractListenerTest.php b/Tests/Doctrine/AbstractListenerTest.php index de5ba0c..1f238d6 100644 --- a/Tests/Doctrine/AbstractListenerTest.php +++ b/Tests/Doctrine/AbstractListenerTest.php @@ -16,7 +16,7 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase $eventArgs = $this->createLifecycleEventArgs($entity, $this->getMockObjectManager()); $indexable = $this->getMockIndexable('index', 'type', $entity, true); - $listener = $this->createListener($persister, array(), $indexable); + $listener = $this->createListener($persister, array(), $indexable, array('indexName' => 'index', 'typeName' => 'type')); $listener->postPersist($eventArgs); $this->assertEquals($entity, current($listener->scheduledForInsertion)); @@ -35,7 +35,7 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase $eventArgs = $this->createLifecycleEventArgs($entity, $this->getMockObjectManager()); $indexable = $this->getMockIndexable('index', 'type', $entity, false); - $listener = $this->createListener($persister, array(), $indexable); + $listener = $this->createListener($persister, array(), $indexable, array('indexName' => 'index', 'typeName' => 'type')); $listener->postPersist($eventArgs); $this->assertEmpty($listener->scheduledForInsertion); @@ -55,7 +55,7 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase $eventArgs = $this->createLifecycleEventArgs($entity, $this->getMockObjectManager()); $indexable = $this->getMockIndexable('index', 'type', $entity, true); - $listener = $this->createListener($persister, array(), $indexable); + $listener = $this->createListener($persister, array(), $indexable, array('indexName' => 'index', 'typeName' => 'type')); $listener->postUpdate($eventArgs); $this->assertEquals($entity, current($listener->scheduledForUpdate)); @@ -89,7 +89,7 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase ->with($entity, 'id') ->will($this->returnValue($entity->getId())); - $listener = $this->createListener($persister, array(), $indexable); + $listener = $this->createListener($persister, array(), $indexable, array('indexName' => 'index', 'typeName' => 'type')); $listener->postUpdate($eventArgs); $this->assertEmpty($listener->scheduledForUpdate); @@ -124,7 +124,7 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase ->with($entity, 'id') ->will($this->returnValue($entity->getId())); - $listener = $this->createListener($persister, array(), $indexable); + $listener = $this->createListener($persister, array(), $indexable, array('indexName' => 'index', 'typeName' => 'type')); $listener->preRemove($eventArgs); $this->assertEquals($entity->getId(), current($listener->scheduledForDeletion)); @@ -157,7 +157,7 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase ->with($entity, 'identifier') ->will($this->returnValue($entity->getId())); - $listener = $this->createListener($persister, array(), $indexable, 'identifier'); + $listener = $this->createListener($persister, array(), $indexable, array('identifier' => 'identifier', 'indexName' => 'index', 'typeName' => 'type')); $listener->preRemove($eventArgs); $this->assertEquals($entity->identifier, current($listener->scheduledForDeletion)); diff --git a/Tests/Doctrine/AbstractProviderTest.php b/Tests/Doctrine/AbstractProviderTest.php index e5f9735..cd0a58c 100644 --- a/Tests/Doctrine/AbstractProviderTest.php +++ b/Tests/Doctrine/AbstractProviderTest.php @@ -21,29 +21,13 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase } $this->objectClass = 'objectClass'; - $this->options = array('debug_logging' => true); + $this->options = array('debug_logging' => true, 'indexName' => 'index', 'typeName' => 'type'); $this->objectPersister = $this->getMockObjectPersister(); $this->managerRegistry = $this->getMockManagerRegistry(); $this->objectManager = $this->getMockObjectManager(); $this->indexable = $this->getMockIndexable(); - $index = $this->getMockBuilder('Elastica\Index')->disableOriginalConstructor()->getMock(); - $index->expects($this->any()) - ->method('getName') - ->will($this->returnValue('index')); - $type = $this->getMockBuilder('Elastica\Type')->disableOriginalConstructor()->getMock(); - $type->expects($this->any()) - ->method('getName') - ->will($this->returnValue('type')); - $type->expects($this->any()) - ->method('getIndex') - ->will($this->returnValue($index)); - - $this->objectPersister->expects($this->any()) - ->method('getType') - ->will($this->returnValue($type)); - $this->managerRegistry->expects($this->any()) ->method('getManagerForClass') ->with($this->objectClass) diff --git a/Tests/Provider/IndexableTest.php b/Tests/Provider/IndexableTest.php index 61d7f87..aae6484 100644 --- a/Tests/Provider/IndexableTest.php +++ b/Tests/Provider/IndexableTest.php @@ -15,6 +15,14 @@ use FOS\ElasticaBundle\Provider\Indexable; class IndexableTest extends \PHPUnit_Framework_TestCase { + public function testIndexableUnknown() + { + $indexable = new Indexable(array()); + $index = $indexable->isObjectIndexable('index', 'type', new Entity); + + $this->assertTrue($index); + } + /** * @dataProvider provideIsIndexableCallbacks */ From 089e7f0d2ee45810fa989eabf92a4919ec661a7e Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Tue, 17 Jun 2014 12:12:54 +1000 Subject: [PATCH 270/447] Add unstable badge [skip ci] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7909d2b..631951a 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Symfony2. Features include: > **Note** Propel support is limited and contributions fixing issues are welcome! -[![Build Status](https://secure.travis-ci.org/FriendsOfSymfony/FOSElasticaBundle.png?branch=master)](http://travis-ci.org/FriendsOfSymfony/FOSElasticaBundle) [![Total Downloads](https://poser.pugx.org/FriendsOfSymfony/elastica-bundle/downloads.png)](https://packagist.org/packages/FriendsOfSymfony/elastica-bundle) [![Latest Stable Version](https://poser.pugx.org/FriendsOfSymfony/elastica-bundle/v/stable.png)](https://packagist.org/packages/FriendsOfSymfony/elastica-bundle) +[![Build Status](https://secure.travis-ci.org/FriendsOfSymfony/FOSElasticaBundle.png?branch=master)](http://travis-ci.org/FriendsOfSymfony/FOSElasticaBundle) [![Total Downloads](https://poser.pugx.org/FriendsOfSymfony/elastica-bundle/downloads.png)](https://packagist.org/packages/FriendsOfSymfony/elastica-bundle) [![Latest Stable Version](https://poser.pugx.org/FriendsOfSymfony/elastica-bundle/v/stable.png)](https://packagist.org/packages/FriendsOfSymfony/elastica-bundle) [![Latest Unstable Version](https://poser.pugx.org/friendsofsymfony/elastica-bundle/v/unstable.svg)](https://packagist.org/packages/friendsofsymfony/elastica-bundle) Documentation ------------- From 1e07d3c7fe5993a22a7ef75c6f29564cfc34d6fc Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Mon, 16 Jun 2014 22:33:31 +1000 Subject: [PATCH 271/447] Update composer.json --- .travis.yml | 4 +++- composer.json | 11 ++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4fdf2b9..d6ba18a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,5 +9,7 @@ before_script: - echo "extension = mongo.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini - composer install --dev --prefer-source +script: vendor/bin/phpunit + services: - - elasticsearch \ No newline at end of file + - elasticsearch diff --git a/composer.json b/composer.json index d67e329..bde8b3e 100644 --- a/composer.json +++ b/composer.json @@ -6,7 +6,8 @@ "homepage": "https://github.com/FriendsOfSymfony/FOSElasticaBundle", "license": "MIT", "authors": [ - { "name": "Thibault Duplessis", "email": "thibault.duplessis@gmail.com" }, + { "name": "FriendsOfSymfony Community", "homepage": "https://github.com/FriendsOfSymfony/FOSElasticaBundle/contributors" }, + { "name": "Tim Nagel", "email": "tim@nagel.com.au" }, { "name": "Richard Miller", "email": "richard.miller@limethinking.co.uk" }, { "name": "Jeremy Mikola", "email": "jmikola@gmail.com" } ], @@ -16,13 +17,14 @@ "symfony/console": "~2.1", "symfony/form": "~2.1", "symfony/property-access": "~2.2", - "ruflin/elastica": ">=0.90.10.0, <1.2-dev", + "ruflin/elastica": ">=0.90.10.0, <1.3-dev", "psr/log": "~1.0" }, "require-dev":{ "doctrine/orm": "~2.2", "doctrine/doctrine-bundle": "~1.2@beta", - "doctrine/mongodb-odm": "1.0.*@dev", + "doctrine/mongodb-odm": "1.0.*@beta", + "phpunit/phpunit": "~4.1", "propel/propel1": "1.6.*", "pagerfanta/pagerfanta": "1.0.*@dev", "knplabs/knp-components": "~1.2", @@ -38,9 +40,8 @@ "symfony/expression-language" : "~2.4" }, "autoload": { - "psr-0": { "FOS\\ElasticaBundle": "" } + "psr-4": { "FOS\\ElasticaBundle\\": "" } }, - "target-dir": "FOS/ElasticaBundle", "extra": { "branch-alias": { "dev-master": "3.0.x-dev" From ec5c05e8becd6342b20dc0499759e290a6a6f0df Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Tue, 17 Jun 2014 23:22:58 +1000 Subject: [PATCH 272/447] dev --- Configuration/IndexConfig.php | 2 +- Configuration/Manager.php | 23 ++++---- Configuration/ManagerInterface.php | 9 +++- DependencyInjection/FOSElasticaExtension.php | 19 ++----- Index/IndexManager.php | 6 +-- Index/Resetter.php | 54 +++++++------------ Resources/config/index.xml | 5 +- Tests/Functional/ConfigurationManagerTest.php | 6 ++- 8 files changed, 59 insertions(+), 65 deletions(-) diff --git a/Configuration/IndexConfig.php b/Configuration/IndexConfig.php index 684713e..9add5e3 100644 --- a/Configuration/IndexConfig.php +++ b/Configuration/IndexConfig.php @@ -115,7 +115,7 @@ class IndexConfig /** * @return boolean */ - public function getUseAlias() + public function isUseAlias() { return $this->useAlias; } diff --git a/Configuration/Manager.php b/Configuration/Manager.php index 85afb99..4436986 100644 --- a/Configuration/Manager.php +++ b/Configuration/Manager.php @@ -31,6 +31,20 @@ class Manager implements ManagerInterface } } + public function getIndexConfiguration($indexName) + { + if (!$this->hasIndexConfiguration($indexName)) { + throw new \InvalidArgumentException(sprintf('Index with name "%s" is not configured.', $indexName)); + } + + return $this->indexes[$indexName]; + } + + public function getIndexNames() + { + return array_keys($this->indexes); + } + public function getTypeConfiguration($indexName, $typeName) { $index = $this->getIndexConfiguration($indexName); @@ -43,15 +57,6 @@ class Manager implements ManagerInterface return $type; } - public function getIndexConfiguration($indexName) - { - if (!$this->hasIndexConfiguration($indexName)) { - throw new \InvalidArgumentException(sprintf('Index with name "%s" is not configured.', $indexName)); - } - - return $this->indexes[$indexName]; - } - public function hasIndexConfiguration($indexName) { return isset($this->indexes[$indexName]); diff --git a/Configuration/ManagerInterface.php b/Configuration/ManagerInterface.php index 7852828..96d510f 100644 --- a/Configuration/ManagerInterface.php +++ b/Configuration/ManagerInterface.php @@ -24,6 +24,13 @@ interface ManagerInterface */ public function getIndexConfiguration($index); + /** + * Returns an array of known index names. + * + * @return array + */ + public function getIndexNames(); + /** * Returns a type configuration. * @@ -32,4 +39,4 @@ interface ManagerInterface * @return TypeConfig */ public function getTypeConfiguration($index, $type); -} \ No newline at end of file +} diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index d122218..4d76baf 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -74,7 +74,6 @@ class FOSElasticaExtension extends Extension $container->getDefinition('fos_elastica.config_source.container')->replaceArgument(0, $this->indexConfigs); $this->loadIndexManager($container); - $this->loadResetter($container); $this->createDefaultManagerAlias($config['default_manager'], $container); } @@ -549,9 +548,12 @@ class FOSElasticaExtension extends Extension **/ private function loadIndexManager(ContainerBuilder $container) { + $indexRefs = array_map(function ($index) { + return $index['reference']; + }, $this->indexConfigs); + $managerDef = $container->getDefinition('fos_elastica.index_manager'); - $managerDef->replaceArgument(0, array_keys($this->clients)); - $managerDef->replaceArgument(1, new Reference('fos_elastica.index')); + $managerDef->replaceArgument(0, $indexRefs); } /** @@ -609,15 +611,4 @@ class FOSElasticaExtension extends Extension return $this->clients[$clientName]['reference']; } - - /** - * Loads the resetter - * - * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container - */ - private function loadResetter(ContainerBuilder $container) - { - $resetterDef = $container->getDefinition('fos_elastica.resetter'); - $resetterDef->replaceArgument(0, $this->indexConfigs); - } } diff --git a/Index/IndexManager.php b/Index/IndexManager.php index 543ccae..9dd7bfe 100644 --- a/Index/IndexManager.php +++ b/Index/IndexManager.php @@ -2,12 +2,12 @@ namespace FOS\ElasticaBundle\Index; -use Elastica\Index; +use FOS\ElasticaBundle\Elastica\Index; class IndexManager { - protected $indexesByName; - protected $defaultIndexName; + private $indexesByName; + private $defaultIndexName; /** * Constructor. diff --git a/Index/Resetter.php b/Index/Resetter.php index 3356c27..aabad87 100644 --- a/Index/Resetter.php +++ b/Index/Resetter.php @@ -6,22 +6,27 @@ use Elastica\Exception\ExceptionInterface; use Elastica\Index; use Elastica\Exception\ResponseException; use Elastica\Type\Mapping; +use FOS\ElasticaBundle\Configuration\Manager; /** * Deletes and recreates indexes */ class Resetter { - protected $indexConfigsByName; + /*** + * @var \FOS\ElasticaBundle\Configuration\Manager + */ + private $configManager; /** - * Constructor. - * - * @param array $indexConfigsByName + * @var IndexManager */ - public function __construct(array $indexConfigsByName) + private $indexManager; + + public function __construct(Manager $configManager, IndexManager $indexManager) { - $this->indexConfigsByName = $indexConfigsByName; + $this->configManager = $configManager; + $this->indexManager = $indexManager; } /** @@ -29,7 +34,7 @@ class Resetter */ public function resetAllIndexes() { - foreach (array_keys($this->indexConfigsByName) as $name) { + foreach ($this->configManager->getIndexNames() as $name) { $this->resetIndex($name); } } @@ -42,18 +47,17 @@ class Resetter */ public function resetIndex($indexName) { - $indexConfig = $this->getIndexConfig($indexName); - $esIndex = $indexConfig['index']; - if (isset($indexConfig['use_alias']) && $indexConfig['use_alias']) { - $name = $indexConfig['name_or_alias']; - $name .= uniqid(); - $esIndex->overrideName($name); - $esIndex->create($indexConfig['config']); + $indexConfig = $this->configManager->getIndexConfiguration($indexName); + $index = $this->indexManager->getIndex($indexName); - return; + if ($indexConfig->isUseAlias()) { + $name = sprintf('%s_%s', $indexConfig->getElasticSearchName(), uniqid()); + + $index->overrideName($name); } - $esIndex->create($indexConfig['config'], true); + + $index->create($indexConfig['config'], true); } /** @@ -108,24 +112,6 @@ class Resetter return $mapping; } - /** - * Gets an index config by its name - * - * @param string $indexName Index name - * - * @param $indexName - * @return array - * @throws \InvalidArgumentException if no index config exists for the given name - */ - protected function getIndexConfig($indexName) - { - if (!isset($this->indexConfigsByName[$indexName])) { - throw new \InvalidArgumentException(sprintf('The configuration for index "%s" does not exist.', $indexName)); - } - - return $this->indexConfigsByName[$indexName]; - } - public function postPopulate($indexName) { $indexConfig = $this->getIndexConfig($indexName); diff --git a/Resources/config/index.xml b/Resources/config/index.xml index de1a52e..331bfdd 100644 --- a/Resources/config/index.xml +++ b/Resources/config/index.xml @@ -28,11 +28,12 @@ - + - + + diff --git a/Tests/Functional/ConfigurationManagerTest.php b/Tests/Functional/ConfigurationManagerTest.php index 0574481..88bfa8b 100644 --- a/Tests/Functional/ConfigurationManagerTest.php +++ b/Tests/Functional/ConfigurationManagerTest.php @@ -24,7 +24,11 @@ class ConfigurationManagerTest extends WebTestCase $manager = $this->getManager($client); $index = $manager->getIndexConfiguration('index'); - var_dump($index); die; + + $this->assertEquals('index', $index->getName()); + $this->assertCount(2, $index->getTypes()); + $this->assertInstanceOf('FOS\\ElasticaBundle\\Configuration\\TypeConfig', $index->getType('type')); + $this->assertInstanceOf('FOS\\ElasticaBundle\\Configuration\\TypeConfig', $index->getType('parent')); } protected function setUp() From 8905b4248c07e34c5b5e0c055e7a385e2775978e Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Wed, 18 Jun 2014 16:47:01 +1000 Subject: [PATCH 273/447] Rename Manager to ConfigManager --- Configuration/{Manager.php => ConfigManager.php} | 4 ++-- Resources/config/config.xml | 2 +- Resources/config/index.xml | 4 ++-- Tests/Functional/ConfigurationManagerTest.php | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) rename Configuration/{Manager.php => ConfigManager.php} (96%) diff --git a/Configuration/Manager.php b/Configuration/ConfigManager.php similarity index 96% rename from Configuration/Manager.php rename to Configuration/ConfigManager.php index 4436986..bef061b 100644 --- a/Configuration/Manager.php +++ b/Configuration/ConfigManager.php @@ -14,7 +14,7 @@ namespace FOS\ElasticaBundle\Configuration; /** * Central manager for index and type configuration. */ -class Manager implements ManagerInterface +class ConfigManager implements ManagerInterface { /** * @var IndexConfig[] @@ -61,4 +61,4 @@ class Manager implements ManagerInterface { return isset($this->indexes[$indexName]); } -} +} diff --git a/Resources/config/config.xml b/Resources/config/config.xml index 4ee733f..75531a5 100644 --- a/Resources/config/config.xml +++ b/Resources/config/config.xml @@ -17,7 +17,7 @@ - + diff --git a/Resources/config/index.xml b/Resources/config/index.xml index 331bfdd..ef9f4e7 100644 --- a/Resources/config/index.xml +++ b/Resources/config/index.xml @@ -5,12 +5,12 @@ xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> + FOS\ElasticaBundle\Finder\TransformedFinder FOS\ElasticaBundle\Elastica\Index - Elastica\Type FOS\ElasticaBundle\Provider\Indexable FOS\ElasticaBundle\Index\IndexManager FOS\ElasticaBundle\Index\Resetter - FOS\ElasticaBundle\Finder\TransformedFinder + Elastica\Type diff --git a/Tests/Functional/ConfigurationManagerTest.php b/Tests/Functional/ConfigurationManagerTest.php index 88bfa8b..6fdc1d7 100644 --- a/Tests/Functional/ConfigurationManagerTest.php +++ b/Tests/Functional/ConfigurationManagerTest.php @@ -47,7 +47,7 @@ class ConfigurationManagerTest extends WebTestCase /** * @param Client $client - * @return \FOS\ElasticaBundle\Configuration\Manager + * @return \FOS\ElasticaBundle\Configuration\ConfigManager */ private function getManager(Client $client) { From afbaf875b990f326d8b284c39ddef082ae6e0b3e Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Wed, 18 Jun 2014 16:48:00 +1000 Subject: [PATCH 274/447] Cache creation of indexes and types in Elastica to avoid recreation --- Elastica/Client.php | 13 ++++++++++++- Elastica/Index.php | 17 +++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/Elastica/Client.php b/Elastica/Client.php index 0db15b3..e921965 100644 --- a/Elastica/Client.php +++ b/Elastica/Client.php @@ -14,6 +14,13 @@ use FOS\ElasticaBundle\Logger\ElasticaLogger; */ class Client extends BaseClient { + /** + * Stores created indexes to avoid recreation. + * + * @var array + */ + private $indexCache = array(); + /** * {@inheritdoc} */ @@ -42,6 +49,10 @@ class Client extends BaseClient public function getIndex($name) { - return new Index($this, $name); + if (isset($this->indexCache[$name])) { + return $this->indexCache[$name]; + } + + return $this->indexCache[$name] = new Index($this, $name); } } diff --git a/Elastica/Index.php b/Elastica/Index.php index ec32c62..bf37c51 100644 --- a/Elastica/Index.php +++ b/Elastica/Index.php @@ -3,6 +3,7 @@ namespace FOS\ElasticaBundle\Elastica; use Elastica\Index as BaseIndex; +use Elastica\Type; /** * Overridden Elastica Index class that provides dynamic index name changes. @@ -13,6 +14,13 @@ class Index extends BaseIndex { private $originalName; + /** + * Stores created types to avoid recreation. + * + * @var array + */ + private $typeCache = array(); + /** * Returns the original name of the index if the index has been renamed for reindexing * or realiasing purposes. @@ -24,6 +32,15 @@ class Index extends BaseIndex return $this->originalName ?: $this->_name; } + public function getType($type) + { + if (isset($this->typeCache[$type])) { + return $this->typeCache[$type]; + } + + return $this->typeCache[$type] = parent::getType($type); + } + /** * Reassign index name * From b155f304e434b0cc0e0b6ee9310bd9b1e40e3c20 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Wed, 18 Jun 2014 16:49:38 +1000 Subject: [PATCH 275/447] Move IndexManager's resolution to tagged index services --- DependencyInjection/Compiler/IndexPass.php | 38 ++++++++++++++++++++ DependencyInjection/FOSElasticaExtension.php | 3 ++ FOSElasticaBundle.php | 4 ++- Index/IndexManager.php | 26 +++++++------- Resources/config/index.xml | 1 + 5 files changed, 58 insertions(+), 14 deletions(-) create mode 100644 DependencyInjection/Compiler/IndexPass.php diff --git a/DependencyInjection/Compiler/IndexPass.php b/DependencyInjection/Compiler/IndexPass.php new file mode 100644 index 0000000..e131214 --- /dev/null +++ b/DependencyInjection/Compiler/IndexPass.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FOS\ElasticaBundle\DependencyInjection\Compiler; + +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; + +class IndexPass implements CompilerPassInterface +{ + /** + * {@inheritDoc} + */ + public function process(ContainerBuilder $container) + { + if (!$container->hasDefinition('fos_elastica.index_manager')) { + return; + } + + $indexes = array(); + foreach ($container->findTaggedServiceIds('fos_elastica.index') as $id => $tags) { + foreach ($tags as $tag) { + $indexes[$tag['name']] = new Reference($id); + } + } + + $container->getDefinition('fos_elastica.index_manager')->replaceArgument(0, $indexes); + } +} diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 4d76baf..4730c0b 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -133,6 +133,9 @@ class FOSElasticaExtension extends Extension $indexDef = new DefinitionDecorator('fos_elastica.index_prototype'); $indexDef->replaceArgument(0, $indexName); + $indexDef->addTag('fos_elastica.index', array( + 'name' => $name, + )); if (isset($index['client'])) { $client = $this->getClient($index['client']); diff --git a/FOSElasticaBundle.php b/FOSElasticaBundle.php index ac4cc3d..3dec2a0 100644 --- a/FOSElasticaBundle.php +++ b/FOSElasticaBundle.php @@ -3,6 +3,7 @@ namespace FOS\ElasticaBundle; use FOS\ElasticaBundle\DependencyInjection\Compiler\ConfigSourcePass; +use FOS\ElasticaBundle\DependencyInjection\Compiler\IndexPass; use FOS\ElasticaBundle\DependencyInjection\Compiler\RegisterProvidersPass; use FOS\ElasticaBundle\DependencyInjection\Compiler\TransformerPass; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -22,8 +23,9 @@ class FOSElasticaBundle extends Bundle { parent::build($container); + $container->addCompilerPass(new ConfigSourcePass()); + $container->addCompilerPass(new IndexPass()); $container->addCompilerPass(new RegisterProvidersPass(), PassConfig::TYPE_BEFORE_REMOVING); $container->addCompilerPass(new TransformerPass()); - $container->addCompilerPass(new ConfigSourcePass()); } } diff --git a/Index/IndexManager.php b/Index/IndexManager.php index 9dd7bfe..38249a7 100644 --- a/Index/IndexManager.php +++ b/Index/IndexManager.php @@ -6,19 +6,19 @@ use FOS\ElasticaBundle\Elastica\Index; class IndexManager { - private $indexesByName; - private $defaultIndexName; + /** + * @var array + */ + private $indexes; /** - * Constructor. - * - * @param array $indexesByName + * @param array $indexes * @param Index $defaultIndex */ - public function __construct(array $indexesByName, Index $defaultIndex) + public function __construct(array $indexes, Index $defaultIndex) { - $this->indexesByName = $indexesByName; - $this->defaultIndexName = $defaultIndex->getName(); + $this->defaultIndex = $defaultIndex; + $this->indexes = $indexes; } /** @@ -28,7 +28,7 @@ class IndexManager */ public function getAllIndexes() { - return $this->indexesByName; + return $this->indexes; } /** @@ -41,14 +41,14 @@ class IndexManager public function getIndex($name = null) { if (null === $name) { - $name = $this->defaultIndexName; + return $this->defaultIndex; } - if (!isset($this->indexesByName[$name])) { + if (!isset($this->indexes[$name])) { throw new \InvalidArgumentException(sprintf('The index "%s" does not exist', $name)); } - return $this->indexesByName[$name]; + return $this->indexes[$name]; } /** @@ -58,6 +58,6 @@ class IndexManager */ public function getDefaultIndex() { - return $this->getIndex($this->defaultIndexName); + return $this->defaultIndex; } } diff --git a/Resources/config/index.xml b/Resources/config/index.xml index ef9f4e7..60b75a9 100644 --- a/Resources/config/index.xml +++ b/Resources/config/index.xml @@ -20,6 +20,7 @@ + From 949ea6963f6c642d4fb20550b4f78eb5cf6874e3 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Wed, 18 Jun 2014 19:55:33 +1000 Subject: [PATCH 276/447] Revert "Make the class of fos_elastica.paginator.subscriber service configurable" This reverts commit fe19df365a74373c19161449526d35beb708e49b. --- Resources/config/config.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Resources/config/config.xml b/Resources/config/config.xml index 5058626..f4b2606 100644 --- a/Resources/config/config.xml +++ b/Resources/config/config.xml @@ -22,7 +22,6 @@ FOS\ElasticaBundle\Persister\ObjectSerializerPersister FOS\ElasticaBundle\Transformer\ModelToElasticaAutoTransformer FOS\ElasticaBundle\Transformer\ModelToElasticaIdentifierTransformer - FOS\ElasticaBundle\Subscriber\PaginateElasticaQuerySubscriber @@ -93,7 +92,7 @@ - + From 3ae382c9331462ca5543b3686444877e4a177fe5 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Wed, 18 Jun 2014 20:02:05 +1000 Subject: [PATCH 277/447] Add tests to make sure KnpPaginator plays nice --- Tests/Functional/app/Basic/bundles.php | 7 +++++-- Tests/Functional/app/Basic/config.yml | 7 +++++++ Tests/Functional/app/config/config.yml | 2 +- composer.json | 4 +++- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Tests/Functional/app/Basic/bundles.php b/Tests/Functional/app/Basic/bundles.php index 9f23bdf..7bcaae8 100644 --- a/Tests/Functional/app/Basic/bundles.php +++ b/Tests/Functional/app/Basic/bundles.php @@ -1,10 +1,13 @@ Date: Wed, 18 Jun 2014 16:12:16 +0300 Subject: [PATCH 278/447] Added elapsed item to toolbar and menu Kind similar to doctrine toolbar item --- Resources/views/Collector/elastica.html.twig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Resources/views/Collector/elastica.html.twig b/Resources/views/Collector/elastica.html.twig index 637dae7..e6d7072 100644 --- a/Resources/views/Collector/elastica.html.twig +++ b/Resources/views/Collector/elastica.html.twig @@ -4,6 +4,9 @@ {% set icon %} elastica {{ collector.querycount }} + {% if collector.querycount > 0 %} + in {{ '%0.2f'|format(collector.time * 1000) }} ms + {% endif %} {% endset %} {% set text %}
    @@ -24,6 +27,7 @@ Elastica {{ collector.querycount }} + {{ '%0.0f'|format(collector.time * 1000) }} ms {% endblock %} From 4e990e0cee2371b083bf2875579018791bcda2ed Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Wed, 18 Jun 2014 17:13:29 +1000 Subject: [PATCH 279/447] Fixed mapping issues --- Configuration/IndexConfig.php | 6 +- Configuration/Source/ContainerSource.php | 10 +- Configuration/TypeConfig.php | 31 ++- DependencyInjection/FOSElasticaExtension.php | 66 ++++--- Index/AliasProcessor.php | 134 +++++++++++++ Index/MappingBuilder.php | 114 +++++++++++ Index/Resetter.php | 191 ++++--------------- Resources/config/config.xml | 3 + Resources/config/index.xml | 5 + Resources/config/mongodb.xml | 7 +- Resources/config/orm.xml | 8 +- Tests/FOSElasticaBundleTest.php | 19 +- Tests/Index/IndexManagerTest.php | 45 ++--- Tests/Index/ResetterTest.php | 51 ++++- 14 files changed, 453 insertions(+), 237 deletions(-) create mode 100644 Index/AliasProcessor.php create mode 100644 Index/MappingBuilder.php diff --git a/Configuration/IndexConfig.php b/Configuration/IndexConfig.php index 9add5e3..7416424 100644 --- a/Configuration/IndexConfig.php +++ b/Configuration/IndexConfig.php @@ -59,11 +59,11 @@ class IndexConfig */ public function __construct($name, array $types, array $config) { - $this->elasticSearchName = $config['elasticSearchName']; + $this->elasticSearchName = isset($config['elasticSearchName']) ? $config['elasticSearchName'] : $name; $this->name = $name; - $this->settings = $config['settings']; + $this->settings = isset($config['settings']) ? $config['settings'] : array(); $this->types = $types; - $this->useAlias = $config['useAlias']; + $this->useAlias = isset($config['useAlias']) ? $config['useAlias'] : false; } /** diff --git a/Configuration/Source/ContainerSource.php b/Configuration/Source/ContainerSource.php index 5fba57a..8d094c7 100644 --- a/Configuration/Source/ContainerSource.php +++ b/Configuration/Source/ContainerSource.php @@ -42,10 +42,12 @@ class ContainerSource implements SourceInterface foreach ($this->configArray as $config) { $types = array(); foreach ($config['types'] as $typeConfig) { - $types[$typeConfig['name']] = new TypeConfig($typeConfig['name'], array( - 'dynamicTemplates' => $typeConfig['dynamic_templates'], - 'properties' => $typeConfig['properties'], - ), $config['type_prototype']); + $types[$typeConfig['name']] = new TypeConfig( + $typeConfig['name'], + $typeConfig['mapping'], + $typeConfig['config'] + ); + // TODO: handle prototypes.. } $index = new IndexConfig($config['name'], $types, array( diff --git a/Configuration/TypeConfig.php b/Configuration/TypeConfig.php index c78a32a..5d3f084 100644 --- a/Configuration/TypeConfig.php +++ b/Configuration/TypeConfig.php @@ -18,14 +18,43 @@ class TypeConfig */ private $config; + /** + * @var array + */ + private $mapping; + /** * @var string */ private $name; - public function __construct($name, array $config, array $prototype) + public function __construct($name, array $mapping, array $config = array()) { $this->config = $config; + $this->mapping = $mapping; $this->name = $name; } + + /** + * @return array + */ + public function getMapping() + { + return $this->mapping; + } + + public function getModel() + { + return isset($this->config['persistence']['model']) ? + $this->config['persistence']['model'] : + null; + } + + /** + * @return string + */ + public function getName() + { + return $this->name; + } } diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 4730c0b..158bea5 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -201,19 +201,16 @@ class FOSElasticaExtension extends Extension foreach ($types as $name => $type) { $indexName = $indexConfig['name']; - $typeId = sprintf('%s.%s', $indexName, $name); + $typeId = sprintf('%s.%s', $indexConfig['reference'], $name); $typeDef = new DefinitionDecorator('fos_elastica.type_prototype'); $typeDef->replaceArgument(0, $name); $typeDef->setFactoryService($indexConfig['reference']); + $container->setDefinition($typeId, $typeDef); - if (isset($type['persistence'])) { - $this->loadTypePersistenceIntegration($type['persistence'], $container, $typeDef, $indexName, $name); - } - - $this->indexConfigs[$indexName]['types'][$name] = array( - 'dynamic_templates' => array(), + $typeConfig = array( 'name' => $name, - 'properties' => array() + 'mapping' => array(), // An array containing anything that gets sent directly to ElasticSearch + 'config' => array(), ); foreach (array( @@ -230,17 +227,32 @@ class FOSElasticaExtension extends Extension '_timestamp', '_ttl', ) as $field) { - if (array_key_exists($field, $type)) { - $this->indexConfigs[$indexName]['types'][$name]['properties'][$field] = $type[$field]; + if (isset($type[$field])) { + $typeConfig['mapping'][$field] = $type[$field]; } } + foreach (array( + 'persistence', + 'serializer' + ) as $field) { + $typeConfig['config'][$field] = array_key_exists($field, $type) ? + $type[$field] : + null; + } + + $this->indexConfigs[$indexName]['types'][$name] = $typeConfig; + + if (isset($type['persistence'])) { + $this->loadTypePersistenceIntegration($type['persistence'], $container, new Reference($typeId), $indexName, $name); + + $typeConfig['persistence'] = $type['persistence']; + } + if (isset($type['indexable_callback'])) { $indexableCallbacks[sprintf('%s/%s', $indexName, $name)] = $type['indexable_callback']; } - $container->setDefinition($typeId, $typeDef); - /*if ($this->serializerConfig) { $callbackDef = new Definition($this->serializerConfig['callback_class']); $callbackId = sprintf('%s.%s.serializer.callback', $indexId, $name); @@ -272,24 +284,24 @@ class FOSElasticaExtension extends Extension * Loads the optional provider and finder for a type * * @param array $typeConfig - * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container - * @param \Symfony\Component\DependencyInjection\Definition $typeDef - * @param $indexName - * @param $typeName + * @param ContainerBuilder $container + * @param Reference $typeRef + * @param string $indexName + * @param string $typeName */ - private function loadTypePersistenceIntegration(array $typeConfig, ContainerBuilder $container, Definition $typeDef, $indexName, $typeName) + private function loadTypePersistenceIntegration(array $typeConfig, ContainerBuilder $container, Reference $typeRef, $indexName, $typeName) { $this->loadDriver($container, $typeConfig['driver']); $elasticaToModelTransformerId = $this->loadElasticaToModelTransformer($typeConfig, $container, $indexName, $typeName); $modelToElasticaTransformerId = $this->loadModelToElasticaTransformer($typeConfig, $container, $indexName, $typeName); - $objectPersisterId = $this->loadObjectPersister($typeConfig, $typeDef, $container, $indexName, $typeName, $modelToElasticaTransformerId); + $objectPersisterId = $this->loadObjectPersister($typeConfig, $typeRef, $container, $indexName, $typeName, $modelToElasticaTransformerId); if (isset($typeConfig['provider'])) { $this->loadTypeProvider($typeConfig, $container, $objectPersisterId, $indexName, $typeName); } if (isset($typeConfig['finder'])) { - $this->loadTypeFinder($typeConfig, $container, $elasticaToModelTransformerId, $typeDef, $indexName, $typeName); + $this->loadTypeFinder($typeConfig, $container, $elasticaToModelTransformerId, $typeRef, $indexName, $typeName); } if (isset($typeConfig['listener'])) { $this->loadTypeListener($typeConfig, $container, $objectPersisterId, $indexName, $typeName); @@ -364,17 +376,17 @@ class FOSElasticaExtension extends Extension * Creates and loads an object persister for a type. * * @param array $typeConfig - * @param Definition $typeDef + * @param Reference $typeRef * @param ContainerBuilder $container * @param string $indexName * @param string $typeName * @param string $transformerId * @return string */ - private function loadObjectPersister(array $typeConfig, Definition $typeDef, ContainerBuilder $container, $indexName, $typeName, $transformerId) + private function loadObjectPersister(array $typeConfig, Reference $typeRef, ContainerBuilder $container, $indexName, $typeName, $transformerId) { $arguments = array( - $typeDef, + $typeRef, new Reference($transformerId), $typeConfig['model'], ); @@ -385,7 +397,7 @@ class FOSElasticaExtension extends Extension $arguments[] = array(new Reference($callbackId), 'serialize'); } else { $abstractId = 'fos_elastica.object_persister'; - $arguments[] = $this->indexConfigs[$indexName]['types'][$typeName]['properties']; + $arguments[] = $this->indexConfigs[$indexName]['types'][$typeName]['mapping']['properties']; } $serviceId = sprintf('fos_elastica.object_persister.%s.%s', $indexName, $typeName); @@ -515,20 +527,20 @@ class FOSElasticaExtension extends Extension * * @param array $typeConfig * @param ContainerBuilder $container - * @param string $elasticaToModelId - * @param Definition $typeDef + * @param $elasticaToModelId + * @param Reference $typeRef * @param string $indexName * @param string $typeName * @return string */ - private function loadTypeFinder(array $typeConfig, ContainerBuilder $container, $elasticaToModelId, Definition $typeDef, $indexName, $typeName) + private function loadTypeFinder(array $typeConfig, ContainerBuilder $container, $elasticaToModelId, Reference $typeRef, $indexName, $typeName) { if (isset($typeConfig['finder']['service'])) { $finderId = $typeConfig['finder']['service']; } else { $finderId = sprintf('fos_elastica.finder.%s.%s', $indexName, $typeName); $finderDef = new DefinitionDecorator('fos_elastica.finder'); - $finderDef->replaceArgument(0, $typeDef); + $finderDef->replaceArgument(0, $typeRef); $finderDef->replaceArgument(1, new Reference($elasticaToModelId)); $container->setDefinition($finderId, $finderDef); } diff --git a/Index/AliasProcessor.php b/Index/AliasProcessor.php new file mode 100644 index 0000000..5c4592d --- /dev/null +++ b/Index/AliasProcessor.php @@ -0,0 +1,134 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FOS\ElasticaBundle\Index; + +use Elastica\Exception\ExceptionInterface; +use FOS\ElasticaBundle\Configuration\IndexConfig; +use FOS\ElasticaBundle\Elastica\Client; +use FOS\ElasticaBundle\Elastica\Index; + +class AliasProcessor +{ + /** + * Sets the randomised root name for an index. + * + * @param IndexConfig $indexConfig + * @param Index $index + */ + public function setRootName(IndexConfig $indexConfig, Index $index) + { + $index->overrideName(sprintf('%s_%s', $indexConfig->getElasticSearchName(), uniqid())); + } + + /** + * Switches an index to become the new target for an alias. Only applies for + * indexes that are set to use aliases. + * + * @param IndexConfig $indexConfig + * @param Index $index + * @throws \RuntimeException + */ + public function switchIndexAlias(IndexConfig $indexConfig, Index $index) + { + $aliasName = $indexConfig->getElasticSearchName(); + $oldIndexName = false; + $newIndexName = $index->getName(); + + $aliasedIndexes = $this->getAliasedIndexes($aliasName); + + if (count($aliasedIndexes) > 1) { + throw new \RuntimeException( + sprintf( + 'Alias %s is used for multiple indexes: [%s]. + Make sure it\'s either not used or is assigned to one index only', + $aliasName, + join(', ', $aliasedIndexes) + ) + ); + } + + $aliasUpdateRequest = array('actions' => array()); + if (count($aliasedIndexes) == 1) { + // if the alias is set - add an action to remove it + $oldIndexName = $aliasedIndexes[0]; + $aliasUpdateRequest['actions'][] = array( + 'remove' => array('index' => $oldIndexName, 'alias' => $aliasName) + ); + } + + // add an action to point the alias to the new index + $aliasUpdateRequest['actions'][] = array( + 'add' => array('index' => $newIndexName, 'alias' => $aliasName) + ); + + try { + $this->client->request('_aliases', 'POST', $aliasUpdateRequest); + } catch (ExceptionInterface $renameAliasException) { + $additionalError = ''; + // if we failed to move the alias, delete the newly built index + try { + $index->delete(); + } catch (ExceptionInterface $deleteNewIndexException) { + $additionalError = sprintf( + 'Tried to delete newly built index %s, but also failed: %s', + $newIndexName, + $deleteNewIndexException->getMessage() + ); + } + + throw new \RuntimeException( + sprintf( + 'Failed to updated index alias: %s. %s', + $renameAliasException->getMessage(), + $additionalError ?: sprintf('Newly built index %s was deleted', $newIndexName) + ), 0, $renameAliasException + ); + } + + // Delete the old index after the alias has been switched + if ($oldIndexName) { + $oldIndex = new Index($this->client, $oldIndexName); + try { + $oldIndex->delete(); + } catch (ExceptionInterface $deleteOldIndexException) { + throw new \RuntimeException( + sprintf( + 'Failed to delete old index %s with message: %s', + $oldIndexName, + $deleteOldIndexException->getMessage() + ), 0, $deleteOldIndexException + ); + } + } + } + + /** + * Returns array of indexes which are mapped to given alias + * + * @param string $aliasName Alias name + * @return array + */ + private function getAliasedIndexes($aliasName) + { + $aliasesInfo = $this->client->request('_aliases', 'GET')->getData(); + $aliasedIndexes = array(); + + foreach ($aliasesInfo as $indexName => $indexInfo) { + $aliases = array_keys($indexInfo['aliases']); + if (in_array($aliasName, $aliases)) { + $aliasedIndexes[] = $indexName; + } + } + + return $aliasedIndexes; + } +} diff --git a/Index/MappingBuilder.php b/Index/MappingBuilder.php new file mode 100644 index 0000000..53524ac --- /dev/null +++ b/Index/MappingBuilder.php @@ -0,0 +1,114 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FOS\ElasticaBundle\Index; + +use FOS\ElasticaBundle\Configuration\IndexConfig; +use FOS\ElasticaBundle\Configuration\TypeConfig; + +class MappingBuilder +{ + /** + * Builds mappings for an entire index. + * + * @param IndexConfig $indexConfig + * @return array + */ + public function buildIndexMapping(IndexConfig $indexConfig) + { + $typeMappings = array(); + foreach ($indexConfig->getTypes() as $typeConfig) { + $typeMappings[$typeConfig->getName()] = $this->buildTypeMapping($typeConfig); + } + + $mapping = array( + 'mappings' => $typeMappings, + 'settings' => $indexConfig->getSettings(), + // 'warmers' => $indexConfig->getWarmers(), + ); + + return $mapping; + } + + /** + * Builds mappings for a single type. + * + * @param TypeConfig $typeConfig + * @return array + */ + public function buildTypeMapping(TypeConfig $typeConfig) + { + $mapping = array_merge($typeConfig->getMapping(), array( + // 'date_detection' => true, + // 'dynamic_date_formats' => array() + // 'dynamic_templates' => $typeConfig->getDynamicTemplates(), + // 'index_analyzer' => $typeConfig->getIndexAnalyzer(), + // 'numeric_detection' => false, + // 'properties' => array(), + // 'search_analyzer' => $typeConfig->getSearchAnalyzer(), + )); + + $this->fixProperties($mapping['properties']); + + if ($typeConfig->getModel()) { + $mapping['_meta']['model'] = $typeConfig->getModel(); + } + + return $mapping; + } + + + /** + * create type mapping object + * + * @param array $indexConfig + * @return Mapping + */ + protected function createMapping($indexConfig) + { + /*$mapping = $this->createMapping($indexConfig['config']['properties'][$typeName]);*/ + $mapping = Mapping::create($indexConfig['properties']); + + $mappingSpecialFields = array('_uid', '_id', '_source', '_all', '_analyzer', '_boost', '_routing', '_index', '_size', '_timestamp', '_ttl', 'dynamic_templates'); + foreach ($mappingSpecialFields as $specialField) { + if (isset($indexConfig[$specialField])) { + $mapping->setParam($specialField, $indexConfig[$specialField]); + } + } + + if (isset($indexConfig['_parent'])) { + $mapping->setParam('_parent', array('type' => $indexConfig['_parent']['type'])); + } + + return $mapping; + } + + /** + * Fixes any properties and applies basic defaults for any field that does not have + * required options. + * + * @param $properties + */ + private function fixProperties(&$properties) + { + foreach ($properties as $name => &$property) { + if (!isset($property['type'])) { + $property['type'] = 'string'; + } + if (!isset($property['store'])) { + $property['store'] = true; + } + if (isset($property['properties'])) { + $this->fixProperties($property['properties']); + } + } + } +} diff --git a/Index/Resetter.php b/Index/Resetter.php index aabad87..174c410 100644 --- a/Index/Resetter.php +++ b/Index/Resetter.php @@ -2,17 +2,23 @@ namespace FOS\ElasticaBundle\Index; -use Elastica\Exception\ExceptionInterface; use Elastica\Index; use Elastica\Exception\ResponseException; use Elastica\Type\Mapping; -use FOS\ElasticaBundle\Configuration\Manager; +use FOS\ElasticaBundle\Configuration\IndexConfig; +use FOS\ElasticaBundle\Configuration\ConfigManager; +use FOS\ElasticaBundle\Elastica\Client; /** * Deletes and recreates indexes */ class Resetter { + /** + * @var AliasProcessor + */ + private $aliasProcessor; + /*** * @var \FOS\ElasticaBundle\Configuration\Manager */ @@ -23,10 +29,17 @@ class Resetter */ private $indexManager; - public function __construct(Manager $configManager, IndexManager $indexManager) + /** + * @var MappingBuilder + */ + private $mappingBuilder; + + public function __construct(ConfigManager $configManager, IndexManager $indexManager, AliasProcessor $aliasProcessor, MappingBuilder $mappingBuilder) { + $this->aliasProcessor = $aliasProcessor; $this->configManager = $configManager; $this->indexManager = $indexManager; + $this->mappingBuilder = $mappingBuilder; } /** @@ -40,24 +53,28 @@ class Resetter } /** - * Deletes and recreates the named index + * Deletes and recreates the named index. If populating, creates a new index + * with a randomised name for an alias to be set after population. * * @param string $indexName + * @param bool $populating * @throws \InvalidArgumentException if no index exists for the given name */ - public function resetIndex($indexName) + public function resetIndex($indexName, $populating = false) { $indexConfig = $this->configManager->getIndexConfiguration($indexName); $index = $this->indexManager->getIndex($indexName); if ($indexConfig->isUseAlias()) { - $name = sprintf('%s_%s', $indexConfig->getElasticSearchName(), uniqid()); - - $index->overrideName($name); + $this->aliasProcessor->setRootName($indexConfig, $index); } + $mapping = $this->mappingBuilder->buildIndexMapping($indexConfig); + $index->create($mapping, true); - $index->create($indexConfig['config'], true); + if (!$populating and $indexConfig->isUseAlias()) { + $this->aliasProcessor->switchIndexAlias($indexConfig, $index); + } } /** @@ -70,13 +87,9 @@ class Resetter */ public function resetIndexType($indexName, $typeName) { - $indexConfig = $this->getIndexConfig($indexName); + $typeConfig = $this->configManager->getTypeConfiguration($indexName, $typeName); + $type = $this->indexManager->getIndex($indexName)->getType($typeName); - if (!isset($indexConfig['config']['properties'][$typeName]['properties'])) { - throw new \InvalidArgumentException(sprintf('The mapping for index "%s" and type "%s" does not exist.', $indexName, $typeName)); - } - - $type = $indexConfig['index']->getType($typeName); try { $type->delete(); } catch (ResponseException $e) { @@ -84,149 +97,27 @@ class Resetter throw $e; } } - $mapping = $this->createMapping($indexConfig['config']['properties'][$typeName]); + + $mapping = new Mapping; + foreach ($this->mappingBuilder->buildTypeMapping($typeConfig) as $name => $field) { + $mapping->setParam($name, $field); + } + $type->setMapping($mapping); } /** - * create type mapping object + * A command run when a population has finished. * - * @param array $indexConfig - * @return Mapping + * @param $indexName */ - protected function createMapping($indexConfig) - { - $mapping = Mapping::create($indexConfig['properties']); - - $mappingSpecialFields = array('_uid', '_id', '_source', '_all', '_analyzer', '_boost', '_routing', '_index', '_size', '_timestamp', '_ttl', 'dynamic_templates'); - foreach ($mappingSpecialFields as $specialField) { - if (isset($indexConfig[$specialField])) { - $mapping->setParam($specialField, $indexConfig[$specialField]); - } - } - - if (isset($indexConfig['_parent'])) { - $mapping->setParam('_parent', array('type' => $indexConfig['_parent']['type'])); - } - - return $mapping; - } - public function postPopulate($indexName) { - $indexConfig = $this->getIndexConfig($indexName); - if (isset($indexConfig['use_alias']) && $indexConfig['use_alias']) { - $this->switchIndexAlias($indexName); + $indexConfig = $this->configManager->getIndexConfiguration($indexName); + + if ($indexConfig->isUseAlias()) { + $index = $this->indexManager->getIndex($indexName); + $this->aliasProcessor->switchIndexAlias($indexConfig, $index); } } - - /** - * Switches the alias for given index (by key) to the newly populated index - * and deletes the old index - * - * @param string $indexName Index name - * - * @throws \RuntimeException - */ - private function switchIndexAlias($indexName) - { - $indexConfig = $this->getIndexConfig($indexName); - $esIndex = $indexConfig['index']; - $aliasName = $indexConfig['name_or_alias']; - $oldIndexName = false; - $newIndexName = $esIndex->getName(); - - $aliasedIndexes = $this->getAliasedIndexes($esIndex, $aliasName); - - if (count($aliasedIndexes) > 1) { - throw new \RuntimeException( - sprintf( - 'Alias %s is used for multiple indexes: [%s]. - Make sure it\'s either not used or is assigned to one index only', - $aliasName, - join(', ', $aliasedIndexes) - ) - ); - } - - // Change the alias to point to the new index - // Elastica's addAlias can't be used directly, because in current (0.19.x) version it's not atomic - // In 0.20.x it's atomic, but it doesn't return the old index name - $aliasUpdateRequest = array('actions' => array()); - if (count($aliasedIndexes) == 1) { - // if the alias is set - add an action to remove it - $oldIndexName = $aliasedIndexes[0]; - $aliasUpdateRequest['actions'][] = array( - 'remove' => array('index' => $oldIndexName, 'alias' => $aliasName) - ); - } - - // add an action to point the alias to the new index - $aliasUpdateRequest['actions'][] = array( - 'add' => array('index' => $newIndexName, 'alias' => $aliasName) - ); - - try { - $esIndex->getClient()->request('_aliases', 'POST', $aliasUpdateRequest); - } catch (ExceptionInterface $renameAliasException) { - $additionalError = ''; - // if we failed to move the alias, delete the newly built index - try { - $esIndex->delete(); - } catch (ExceptionInterface $deleteNewIndexException) { - $additionalError = sprintf( - 'Tried to delete newly built index %s, but also failed: %s', - $newIndexName, - $deleteNewIndexException->getMessage() - ); - } - - throw new \RuntimeException( - sprintf( - 'Failed to updated index alias: %s. %s', - $renameAliasException->getMessage(), - $additionalError ?: sprintf('Newly built index %s was deleted', $newIndexName) - ) - ); - } - - // Delete the old index after the alias has been switched - if ($oldIndexName) { - $oldIndex = new Index($esIndex->getClient(), $oldIndexName); - try { - $oldIndex->delete(); - } catch (ExceptionInterface $deleteOldIndexException) { - throw new \RuntimeException( - sprintf( - 'Failed to delete old index %s with message: %s', - $oldIndexName, - $deleteOldIndexException->getMessage() - ) - ); - } - } - } - - /** - * Returns array of indexes which are mapped to given alias - * - * @param Index $esIndex ES Index - * @param string $aliasName Alias name - * - * @return array - */ - private function getAliasedIndexes(Index $esIndex, $aliasName) - { - $aliasesInfo = $esIndex->getClient()->request('_aliases', 'GET')->getData(); - $aliasedIndexes = array(); - - foreach ($aliasesInfo as $indexName => $indexInfo) { - $aliases = array_keys($indexInfo['aliases']); - if (in_array($aliasName, $aliases)) { - $aliasedIndexes[] = $indexName; - } - } - - return $aliasedIndexes; - } } diff --git a/Resources/config/config.xml b/Resources/config/config.xml index 75531a5..6d86963 100644 --- a/Resources/config/config.xml +++ b/Resources/config/config.xml @@ -8,6 +8,7 @@ FOS\ElasticaBundle\Elastica\Client FOS\ElasticaBundle\Logger\ElasticaLogger FOS\ElasticaBundle\DataCollector\ElasticaDataCollector + FOS\ElasticaBundle\Index\MappingBuilder Symfony\Component\PropertyAccess\PropertyAccessor @@ -32,6 +33,8 @@ + + diff --git a/Resources/config/index.xml b/Resources/config/index.xml index 60b75a9..17a0ec9 100644 --- a/Resources/config/index.xml +++ b/Resources/config/index.xml @@ -5,6 +5,7 @@ xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> + FOS\ElasticaBundle\Index\AliasProcessor FOS\ElasticaBundle\Finder\TransformedFinder FOS\ElasticaBundle\Elastica\Index FOS\ElasticaBundle\Provider\Indexable @@ -14,6 +15,8 @@ + + @@ -35,6 +38,8 @@ + + diff --git a/Resources/config/mongodb.xml b/Resources/config/mongodb.xml index ed4787a..114ac5e 100644 --- a/Resources/config/mongodb.xml +++ b/Resources/config/mongodb.xml @@ -13,15 +13,16 @@ - + - + + - + diff --git a/Resources/config/orm.xml b/Resources/config/orm.xml index bbc1ec4..1f547b9 100644 --- a/Resources/config/orm.xml +++ b/Resources/config/orm.xml @@ -13,16 +13,16 @@ - + - - + + - + diff --git a/Tests/FOSElasticaBundleTest.php b/Tests/FOSElasticaBundleTest.php index 2bfc7f9..3828e8b 100644 --- a/Tests/FOSElasticaBundleTest.php +++ b/Tests/FOSElasticaBundleTest.php @@ -9,31 +9,16 @@ class FOSElasticaBundleTest extends \PHPUnit_Framework_TestCase { public function testCompilerPassesAreRegistered() { - $passes = array( - array ( - 'FOS\ElasticaBundle\DependencyInjection\Compiler\RegisterProvidersPass', - PassConfig::TYPE_BEFORE_REMOVING - ), - array ( - 'FOS\ElasticaBundle\DependencyInjection\Compiler\TransformerPass' - ), - ); - $container = $this ->getMock('Symfony\Component\DependencyInjection\ContainerBuilder'); $container - ->expects($this->at(0)) + ->expects($this->atLeastOnce()) ->method('addCompilerPass') - ->with($this->isInstanceOf($passes[0][0]), $passes[0][1]); + ->with($this->isInstanceOf('Symfony\\Component\\DependencyInjection\\Compiler\\CompilerPassInterface')); - $container - ->expects($this->at(1)) - ->method('addCompilerPass') - ->with($this->isInstanceOf($passes[1][0])); $bundle = new FOSElasticaBundle(); - $bundle->build($container); } } diff --git a/Tests/Index/IndexManagerTest.php b/Tests/Index/IndexManagerTest.php index 624f64e..98e4d8a 100644 --- a/Tests/Index/IndexManagerTest.php +++ b/Tests/Index/IndexManagerTest.php @@ -6,40 +6,41 @@ use FOS\ElasticaBundle\Index\IndexManager; class IndexManagerTest extends \PHPUnit_Framework_TestCase { - private $defaultIndexName; - private $indexesByName; - /** @var IndexManager */ + private $indexes = array(); + + /** + * @var IndexManager + */ private $indexManager; + public function setUp() { - $this->defaultIndexName = 'index2'; - $this->indexesByName = array( - 'index1' => 'test1', - 'index2' => 'test2', - ); + foreach (array('index1', 'index2', 'index3') as $indexName) { + $index = $this->getMockBuilder('FOS\\ElasticaBundle\\Elastica\\Index') + ->disableOriginalConstructor() + ->getMock(); - /** @var $defaultIndex \PHPUnit_Framework_MockObject_MockObject|\Elastica\Index */ - $defaultIndex = $this->getMockBuilder('Elastica\Index') - ->disableOriginalConstructor() - ->getMock(); + $index->expects($this->any()) + ->method('getName') + ->will($this->returnValue($indexName)); - $defaultIndex->expects($this->any()) - ->method('getName') - ->will($this->returnValue($this->defaultIndexName)); + $this->indexes[$indexName] = $index; + } - $this->indexManager = new IndexManager($this->indexesByName, $defaultIndex); + $this->indexManager = new IndexManager($this->indexes, $this->indexes['index2']); } public function testGetAllIndexes() { - $this->assertEquals($this->indexesByName, $this->indexManager->getAllIndexes()); + $this->assertEquals($this->indexes, $this->indexManager->getAllIndexes()); } public function testGetIndex() { - $this->assertEquals($this->indexesByName['index1'], $this->indexManager->getIndex('index1')); - $this->assertEquals($this->indexesByName['index2'], $this->indexManager->getIndex('index2')); + $this->assertEquals($this->indexes['index1'], $this->indexManager->getIndex('index1')); + $this->assertEquals($this->indexes['index2'], $this->indexManager->getIndex('index2')); + $this->assertEquals($this->indexes['index3'], $this->indexManager->getIndex('index3')); } /** @@ -47,12 +48,12 @@ class IndexManagerTest extends \PHPUnit_Framework_TestCase */ public function testGetIndexShouldThrowExceptionForInvalidName() { - $this->indexManager->getIndex('index3'); + $this->indexManager->getIndex('index4'); } public function testGetDefaultIndex() { - $this->assertEquals('test2', $this->indexManager->getIndex()); - $this->assertEquals('test2', $this->indexManager->getDefaultIndex()); + $this->assertEquals('index2', $this->indexManager->getIndex()->getName()); + $this->assertEquals('index2', $this->indexManager->getDefaultIndex()->getName()); } } diff --git a/Tests/Index/ResetterTest.php b/Tests/Index/ResetterTest.php index ae7fdf5..28f0a68 100644 --- a/Tests/Index/ResetterTest.php +++ b/Tests/Index/ResetterTest.php @@ -6,15 +6,40 @@ use Elastica\Exception\ResponseException; use Elastica\Request; use Elastica\Response; use Elastica\Type\Mapping; +use FOS\ElasticaBundle\Configuration\IndexConfig; use FOS\ElasticaBundle\Index\Resetter; class ResetterTest extends \PHPUnit_Framework_TestCase { - private $indexConfigsByName; + /** + * @var Resetter + */ + private $resetter; + + private $configManager; + private $indexManager; + private $aliasProcessor; + private $mappingBuilder; public function setUp() { - $this->indexConfigsByName = array( + $this->markTestIncomplete('To be rewritten'); + $this->configManager = $this->getMockBuilder('FOS\\ElasticaBundle\\Configuration\\ConfigManager') + ->disableOriginalConstructor() + ->getMock(); + $this->indexManager = $this->getMockBuilder('FOS\\ElasticaBundle\\Index\\IndexManager') + ->disableOriginalConstructor() + ->getMock(); + $this->aliasProcessor = $this->getMockBuilder('FOS\\ElasticaBundle\\Index\\AliasProcessor') + ->disableOriginalConstructor() + ->getMock(); + $this->mappingBuilder = $this->getMockBuilder('FOS\\ElasticaBundle\\Index\\MappingBuilder') + ->disableOriginalConstructor() + ->getMock(); + + $this->resetter = new Resetter($this->configManager, $this->indexManager, $this->aliasProcessor, $this->mappingBuilder); + + /*$this->indexConfigsByName = array( 'foo' => array( 'index' => $this->getMockElasticaIndex(), 'config' => array( @@ -54,12 +79,26 @@ class ResetterTest extends \PHPUnit_Framework_TestCase ), ), ), - ); + );*/ } public function testResetAllIndexes() { - $this->indexConfigsByName['foo']['index']->expects($this->once()) + $this->configManager->expects($this->once()) + ->method('getIndexNames') + ->will($this->returnValue(array('index1'))); + + $this->configManager->expects($this->once()) + ->method('getIndexConfiguration') + ->with('index1') + ->will($this->returnValue(new IndexConfig('index1', array(), array()))); + + $this->indexManager->expects($this->once()) + ->method('getIndex') + ->with('index1') + ->will($this->returnValue()); + + /*$this->indexConfigsByName['foo']['index']->expects($this->once()) ->method('create') ->with($this->indexConfigsByName['foo']['config'], true); @@ -67,8 +106,8 @@ class ResetterTest extends \PHPUnit_Framework_TestCase ->method('create') ->with($this->indexConfigsByName['bar']['config'], true); - $resetter = new Resetter($this->indexConfigsByName); - $resetter->resetAllIndexes(); + $resetter = new Resetter($this->indexConfigsByName);*/ + $this->resetter->resetAllIndexes(); } public function testResetIndex() From c97f0f1ddf9a0590bf8a978ee1131ce564860356 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 19 Jun 2014 11:14:13 +1000 Subject: [PATCH 280/447] Fix provider bailing if the indexable service filters an entire batch of objects --- Doctrine/AbstractProvider.php | 5 +++++ Propel/Provider.php | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/Doctrine/AbstractProvider.php b/Doctrine/AbstractProvider.php index 0c43b2d..44be6c7 100644 --- a/Doctrine/AbstractProvider.php +++ b/Doctrine/AbstractProvider.php @@ -64,6 +64,11 @@ abstract class AbstractProvider extends BaseAbstractProvider $stepNbObjects = count($objects); } $objects = array_filter($objects, array($this, 'isObjectIndexable')); + if (!$objects) { + $loggerClosure('Entire batch was filtered away, skipping...'); + + continue; + } if (!$ignoreErrors) { $this->objectPersister->insertMany($objects); diff --git a/Propel/Provider.php b/Propel/Provider.php index c242d47..38f7a61 100644 --- a/Propel/Provider.php +++ b/Propel/Provider.php @@ -36,6 +36,11 @@ class Provider extends AbstractProvider $stepNbObjects = count($objects); } $objects = array_filter($objects, array($this, 'isObjectIndexable')); + if (!$objects) { + $loggerClosure('Entire batch was filtered away, skipping...'); + + continue; + } $this->objectPersister->insertMany($objects); From ca6991d494e78844ce1007fecef5479a2a40b739 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Mon, 23 Jun 2014 23:05:57 +1000 Subject: [PATCH 281/447] Fix serializer --- DependencyInjection/FOSElasticaExtension.php | 55 ++++++++++++------- Resources/config/serializer.xml | 14 +++++ Tests/Functional/app/ORM/bundles.php | 4 +- Tests/Functional/app/ORM/config.yml | 4 ++ .../ModelToElasticaIdentifierTransformer.php | 1 + composer.json | 1 + 6 files changed, 57 insertions(+), 22 deletions(-) create mode 100644 Resources/config/serializer.xml diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 158bea5..aa00b18 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -5,7 +5,6 @@ namespace FOS\ElasticaBundle\DependencyInjection; use Symfony\Component\HttpKernel\DependencyInjection\Extension; use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\DefinitionDecorator; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\Config\FileLocator; @@ -35,8 +34,6 @@ class FOSElasticaExtension extends Extension */ private $loadedDrivers = array(); - protected $serializerConfig = array(); - public function load(array $configs, ContainerBuilder $container) { $configuration = $this->getConfiguration($configs, $container); @@ -63,7 +60,11 @@ class FOSElasticaExtension extends Extension $config['default_index'] = reset($keys); } - $this->serializerConfig = isset($config['serializer']) ? $config['serializer'] : null; + if (isset($config['serializer'])) { + $loader->load('serializer.xml'); + + $this->loadSerializer($config['serializer'], $container); + } $this->loadClients($config['clients'], $container); $container->setAlias('fos_elastica.client', sprintf('fos_elastica.client.%s', $config['default_client'])); @@ -253,27 +254,20 @@ class FOSElasticaExtension extends Extension $indexableCallbacks[sprintf('%s/%s', $indexName, $name)] = $type['indexable_callback']; } - /*if ($this->serializerConfig) { - $callbackDef = new Definition($this->serializerConfig['callback_class']); - $callbackId = sprintf('%s.%s.serializer.callback', $indexId, $name); + if ($container->hasDefinition('fos_elastica.serializer_callback_prototype')) { + $typeSerializerId = sprintf('%s.serializer.callback', $typeId); + $typeSerializerDef = new DefinitionDecorator('fos_elastica.serializer_callback_prototype'); - $typeDef->addMethodCall('setSerializer', array(array(new Reference($callbackId), 'serialize'))); - $callbackDef->addMethodCall('setSerializer', array(new Reference($this->serializerConfig['serializer']))); if (isset($type['serializer']['groups'])) { - $callbackDef->addMethodCall('setGroups', array($type['serializer']['groups'])); + $typeSerializerDef->addMethodCall('setGroups', array($type['serializer']['groups'])); } if (isset($type['serializer']['version'])) { - $callbackDef->addMethodCall('setVersion', array($type['serializer']['version'])); - } - $callbackClassImplementedInterfaces = class_implements($this->serializerConfig['callback_class']); // PHP < 5.4 friendly - if (isset($callbackClassImplementedInterfaces['Symfony\Component\DependencyInjection\ContainerAwareInterface'])) { - $callbackDef->addMethodCall('setContainer', array(new Reference('service_container'))); + $typeSerializerDef->addMethodCall('setVersion', array($type['serializer']['version'])); } - $container->setDefinition($callbackId, $callbackDef); - - $typeDef->addMethodCall('setSerializer', array(array(new Reference($callbackId), 'serialize'))); - }*/ + $typeDef->addMethodCall('setSerializer', array(array(new Reference($typeSerializerId), 'serialize'))); + $container->setDefinition($typeSerializerId, $typeSerializerDef); + } } $indexable = $container->getDefinition('fos_elastica.indexable'); @@ -358,7 +352,7 @@ class FOSElasticaExtension extends Extension return $typeConfig['model_to_elastica_transformer']['service']; } - $abstractId = $this->serializerConfig ? + $abstractId = $container->hasDefinition('fos_elastica.serializer_callback_prototype') ? 'fos_elastica.model_to_elastica_identifier_transformer' : 'fos_elastica.model_to_elastica_transformer'; @@ -391,7 +385,7 @@ class FOSElasticaExtension extends Extension $typeConfig['model'], ); - if ($this->serializerConfig) { + if ($container->hasDefinition('fos_elastica.serializer_callback_prototype')) { $abstractId = 'fos_elastica.object_serializer_persister'; $callbackId = sprintf('%s.%s.serializer.callback', $this->indexConfigs[$indexName]['reference'], $typeName); $arguments[] = array(new Reference($callbackId), 'serialize'); @@ -588,6 +582,25 @@ class FOSElasticaExtension extends Extension $this->loadedDrivers[] = $driver; } + /** + * Loads and configures the serializer prototype. + * + * @param array $config + * @param ContainerBuilder $container + */ + private function loadSerializer($config, ContainerBuilder $container) + { + $container->setAlias('fos_elastica.serializer', $config['serializer']); + + $serializer = $container->getDefinition('fos_elastica.serializer_callback_prototype'); + $serializer->setClass($config['callback_class']); + + $callbackClassImplementedInterfaces = class_implements($config['callback_class']); + if (isset($callbackClassImplementedInterfaces['Symfony\Component\DependencyInjection\ContainerAwareInterface'])) { + $serializer->addMethodCall('setContainer', array(new Reference('service_container'))); + } + } + /** * Creates a default manager alias for defined default manager or the first loaded driver. * diff --git a/Resources/config/serializer.xml b/Resources/config/serializer.xml new file mode 100644 index 0000000..8ee9646 --- /dev/null +++ b/Resources/config/serializer.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/Tests/Functional/app/ORM/bundles.php b/Tests/Functional/app/ORM/bundles.php index d0b6efb..25db3fe 100644 --- a/Tests/Functional/app/ORM/bundles.php +++ b/Tests/Functional/app/ORM/bundles.php @@ -3,9 +3,11 @@ use Doctrine\Bundle\DoctrineBundle\DoctrineBundle; use FOS\ElasticaBundle\FOSElasticaBundle; use Symfony\Bundle\FrameworkBundle\FrameworkBundle; +use JMS\SerializerBundle\JMSSerializerBundle; return array( new FrameworkBundle(), new FOSElasticaBundle(), - new DoctrineBundle() + new DoctrineBundle(), + new JMSSerializerBundle(), ); diff --git a/Tests/Functional/app/ORM/config.yml b/Tests/Functional/app/ORM/config.yml index 77e5f5b..340fa65 100644 --- a/Tests/Functional/app/ORM/config.yml +++ b/Tests/Functional/app/ORM/config.yml @@ -13,6 +13,7 @@ fos_elastica: clients: default: url: http://localhost:9200 + serializer: ~ indexes: index: index_name: foselastica_test_%kernel.environment% @@ -25,6 +26,9 @@ fos_elastica: model: FOS\ElasticaBundle\Tests\Functional\TypeObj listener: is_indexable_callback: 'object.isIndexable() && !object.isntIndexable()' + serializer: + groups: ['search'] + version: 1.1 type2: properties: field1: ~ diff --git a/Transformer/ModelToElasticaIdentifierTransformer.php b/Transformer/ModelToElasticaIdentifierTransformer.php index 654850f..7cf97e6 100644 --- a/Transformer/ModelToElasticaIdentifierTransformer.php +++ b/Transformer/ModelToElasticaIdentifierTransformer.php @@ -21,6 +21,7 @@ class ModelToElasticaIdentifierTransformer extends ModelToElasticaAutoTransforme public function transform($object, array $fields) { $identifier = $this->propertyAccessor->getValue($object, $this->options['identifier']); + return new Document($identifier); } } diff --git a/composer.json b/composer.json index bde8b3e..b65e0b2 100644 --- a/composer.json +++ b/composer.json @@ -24,6 +24,7 @@ "doctrine/orm": "~2.2", "doctrine/doctrine-bundle": "~1.2@beta", "doctrine/mongodb-odm": "1.0.*@beta", + "jms/serializer-bundle": "@stable", "phpunit/phpunit": "~4.1", "propel/propel1": "1.6.*", "pagerfanta/pagerfanta": "1.0.*@dev", From 9a62187329c0c6f7079db468b381bb1c3b611000 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Mon, 23 Jun 2014 23:50:52 +1000 Subject: [PATCH 282/447] Fix undefined index_name notice --- DependencyInjection/FOSElasticaExtension.php | 2 +- Tests/Functional/app/ORM/config.yml | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index aa00b18..9862076 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -130,7 +130,7 @@ class FOSElasticaExtension extends Extension { foreach ($indexes as $name => $index) { $indexId = sprintf('fos_elastica.index.%s', $name); - $indexName = $index['index_name'] ?: $name; + $indexName = isset($index['index_name']) ? $index['index_name']: $name; $indexDef = new DefinitionDecorator('fos_elastica.index_prototype'); $indexDef->replaceArgument(0, $indexName); diff --git a/Tests/Functional/app/ORM/config.yml b/Tests/Functional/app/ORM/config.yml index 340fa65..2c7c692 100644 --- a/Tests/Functional/app/ORM/config.yml +++ b/Tests/Functional/app/ORM/config.yml @@ -15,6 +15,11 @@ fos_elastica: url: http://localhost:9200 serializer: ~ indexes: + fos_elastica_test: + types: + type: + properties: + field1: ~ index: index_name: foselastica_test_%kernel.environment% types: From ae3605828ea5deed3f4c2424d1dc8f8879c8b4c0 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Tue, 24 Jun 2014 10:19:26 +1000 Subject: [PATCH 283/447] Fix AbstractProvider test --- Doctrine/AbstractProvider.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Doctrine/AbstractProvider.php b/Doctrine/AbstractProvider.php index 44be6c7..a662fd4 100644 --- a/Doctrine/AbstractProvider.php +++ b/Doctrine/AbstractProvider.php @@ -65,7 +65,9 @@ abstract class AbstractProvider extends BaseAbstractProvider } $objects = array_filter($objects, array($this, 'isObjectIndexable')); if (!$objects) { - $loggerClosure('Entire batch was filtered away, skipping...'); + if ($loggerClosure) { + $loggerClosure('Entire batch was filtered away, skipping...'); + } continue; } From 2437a098ba92422c0d5111e5f66fa46479cd1b3c Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Tue, 24 Jun 2014 10:20:15 +1000 Subject: [PATCH 284/447] Fix anonymous service error --- Resources/config/mongodb.xml | 5 ++--- Resources/config/orm.xml | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Resources/config/mongodb.xml b/Resources/config/mongodb.xml index 114ac5e..048d799 100644 --- a/Resources/config/mongodb.xml +++ b/Resources/config/mongodb.xml @@ -14,12 +14,11 @@ - + - - + diff --git a/Resources/config/orm.xml b/Resources/config/orm.xml index 1f547b9..ddc0e50 100644 --- a/Resources/config/orm.xml +++ b/Resources/config/orm.xml @@ -14,12 +14,11 @@ - + - - + From f6264f4149990f26c247419e4e6f26b34fadcd8d Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Tue, 24 Jun 2014 10:30:31 +1000 Subject: [PATCH 285/447] Fix AbstractProvider tests --- Tests/Doctrine/AbstractProviderTest.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Tests/Doctrine/AbstractProviderTest.php b/Tests/Doctrine/AbstractProviderTest.php index cd0a58c..99ed2de 100644 --- a/Tests/Doctrine/AbstractProviderTest.php +++ b/Tests/Doctrine/AbstractProviderTest.php @@ -54,6 +54,11 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase ->with($queryBuilder) ->will($this->returnValue($nbObjects)); + $this->indexable->expects($this->any()) + ->method('isObjectIndexable') + ->with('index', 'type', $this->anything()) + ->will($this->returnValue(true)); + $providerInvocationOffset = 2; foreach ($objectsByIteration as $i => $objects) { @@ -106,6 +111,11 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase ->method('fetchSlice') ->will($this->returnValue($objects)); + $this->indexable->expects($this->any()) + ->method('isObjectIndexable') + ->with('index', 'type', $this->anything()) + ->will($this->returnValue(true)); + $this->objectManager->expects($this->never()) ->method('clear'); @@ -127,6 +137,11 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase ->method('fetchSlice') ->will($this->returnValue($objects)); + $this->indexable->expects($this->any()) + ->method('isObjectIndexable') + ->with('index', 'type', $this->anything()) + ->will($this->returnValue(true)); + $loggerClosureInvoked = false; $loggerClosure = function () use (&$loggerClosureInvoked) { $loggerClosureInvoked = true; @@ -154,6 +169,11 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase ->method('fetchSlice') ->will($this->returnValue($objects)); + $this->indexable->expects($this->any()) + ->method('isObjectIndexable') + ->with('index', 'type', $this->anything()) + ->will($this->returnValue(true)); + $this->objectPersister->expects($this->any()) ->method('insertMany') ->will($this->throwException($this->getMockBulkResponseException())); From ae03b3f3cff1744bf7e819dcecb9b808abf310af Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Wed, 25 Jun 2014 13:18:02 +1000 Subject: [PATCH 286/447] Fix propel service definition --- Resources/config/propel.xml | 2 +- Tests/bootstrap.php | 19 ------------------- phpunit.xml.dist | 2 +- 3 files changed, 2 insertions(+), 21 deletions(-) delete mode 100644 Tests/bootstrap.php diff --git a/Resources/config/propel.xml b/Resources/config/propel.xml index 102935c..297e735 100644 --- a/Resources/config/propel.xml +++ b/Resources/config/propel.xml @@ -19,7 +19,7 @@ - + diff --git a/Tests/bootstrap.php b/Tests/bootstrap.php deleted file mode 100644 index 30fb165..0000000 --- a/Tests/bootstrap.php +++ /dev/null @@ -1,19 +0,0 @@ - - + ./Tests From 4d52c327aa2c43edbc38cf7ef5af45d2fa5bf80c Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Wed, 25 Jun 2014 13:24:02 +1000 Subject: [PATCH 287/447] Add back missing KnpPaginatorSubscriber service --- Resources/config/config.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Resources/config/config.xml b/Resources/config/config.xml index 6d86963..023688f 100644 --- a/Resources/config/config.xml +++ b/Resources/config/config.xml @@ -27,6 +27,13 @@ + + + + + + + %kernel.debug% From a879d3c1c98b4e706148928355d2a114720783ab Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 26 Jun 2014 17:29:16 +1000 Subject: [PATCH 288/447] Fix ClassCastException when no settings are present --- Index/MappingBuilder.php | 6 +++++- Tests/Functional/MappingToElasticaTest.php | 24 ++++++++++++++++++++++ Tests/Functional/app/ORM/config.yml | 5 +++-- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/Index/MappingBuilder.php b/Index/MappingBuilder.php index 53524ac..0751ce7 100644 --- a/Index/MappingBuilder.php +++ b/Index/MappingBuilder.php @@ -31,10 +31,14 @@ class MappingBuilder $mapping = array( 'mappings' => $typeMappings, - 'settings' => $indexConfig->getSettings(), // 'warmers' => $indexConfig->getWarmers(), ); + $settings = $indexConfig->getSettings(); + if ($settings) { + $mapping['settings'] = $settings; + } + return $mapping; } diff --git a/Tests/Functional/MappingToElasticaTest.php b/Tests/Functional/MappingToElasticaTest.php index bffcf76..390f854 100644 --- a/Tests/Functional/MappingToElasticaTest.php +++ b/Tests/Functional/MappingToElasticaTest.php @@ -42,6 +42,30 @@ class MappingToElasticaTest extends WebTestCase $this->assertNotEmpty($mapping, 'Mapping was populated'); } + public function testORMResetIndexAddsMappings() + { + $client = $this->createClient(array('test_case' => 'ORM')); + $resetter = $this->getResetter($client); + $resetter->resetIndex('index'); + + $type = $this->getType($client); + $mapping = $type->getMapping(); + + $this->assertNotEmpty($mapping, 'Mapping was populated'); + } + + public function testORMResetType() + { + $client = $this->createClient(array('test_case' => 'ORM')); + $resetter = $this->getResetter($client); + $resetter->resetIndexType('index', 'type'); + + $type = $this->getType($client); + $mapping = $type->getMapping(); + + $this->assertNotEmpty($mapping, 'Mapping was populated'); + } + /** * @param Client $client * @return \FOS\ElasticaBundle\Resetter $resetter diff --git a/Tests/Functional/app/ORM/config.yml b/Tests/Functional/app/ORM/config.yml index 2c7c692..448d62b 100644 --- a/Tests/Functional/app/ORM/config.yml +++ b/Tests/Functional/app/ORM/config.yml @@ -43,11 +43,12 @@ fos_elastica: listener: is_indexable_callback: 'object.isntIndexable()' type3: - properties: + mappings: field1: ~ persistence: driver: orm model: FOS\ElasticaBundle\Tests\Functional\TypeObj + finder: ~ + provider: ~ listener: is_indexable_callback: 'isntIndexable' - From 96dc613c7125670d237da725f8f28117a8bae573 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 26 Jun 2014 17:46:29 +1000 Subject: [PATCH 289/447] Fix array format for indexable_callback --- DependencyInjection/Configuration.php | 2 +- Provider/Indexable.php | 15 ++++++++++- Resources/config/index.xml | 1 + Resources/doc/types.md | 3 +++ Tests/Functional/IndexableCallbackTest.php | 3 ++- Tests/Functional/app/ORM/IndexableService.php | 25 +++++++++++++++++++ Tests/Functional/app/ORM/config.yml | 16 +++++++++++- 7 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 Tests/Functional/app/ORM/IndexableService.php diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 3564fd4..52088b6 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -205,7 +205,7 @@ class Configuration implements ConfigurationInterface ->children() ->scalarNode('index_analyzer')->end() ->scalarNode('search_analyzer')->end() - ->scalarNode('indexable_callback')->end() + ->variableNode('indexable_callback')->end() ->append($this->getPersistenceNode()) ->append($this->getSerializerNode()) ->end() diff --git a/Provider/Indexable.php b/Provider/Indexable.php index 09168a1..827b3a4 100644 --- a/Provider/Indexable.php +++ b/Provider/Indexable.php @@ -11,6 +11,7 @@ namespace FOS\ElasticaBundle\Provider; +use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\ExpressionLanguage\Expression; use Symfony\Component\ExpressionLanguage\ExpressionLanguage; use Symfony\Component\ExpressionLanguage\SyntaxError; @@ -26,6 +27,11 @@ class Indexable implements IndexableInterface */ private $callbacks = array(); + /** + * @var \Symfony\Component\DependencyInjection\ContainerInterface + */ + private $container; + /** * An instance of ExpressionLanguage * @@ -50,9 +56,10 @@ class Indexable implements IndexableInterface /** * @param array $callbacks */ - public function __construct(array $callbacks) + public function __construct(array $callbacks, ContainerInterface $container) { $this->callbacks = $callbacks; + $this->container = $container; $this->propertyAccessor = PropertyAccess::createPropertyAccessor(); } @@ -105,6 +112,12 @@ class Indexable implements IndexableInterface if (is_array($callback)) { list($class, $method) = $callback + array(null, null); + if (strpos($class, '@') === 0) { + $service = $this->container->get(substr($class, 1)); + + return array($service, $method); + } + if (is_object($class)) { $class = get_class($class); } diff --git a/Resources/config/index.xml b/Resources/config/index.xml index 17a0ec9..11586ff 100644 --- a/Resources/config/index.xml +++ b/Resources/config/index.xml @@ -19,6 +19,7 @@ + diff --git a/Resources/doc/types.md b/Resources/doc/types.md index be687d7..80d295b 100644 --- a/Resources/doc/types.md +++ b/Resources/doc/types.md @@ -177,6 +177,9 @@ The callback option supports multiple approaches: * An array of a service id and a method which will be called with the object as the first and only argument. `[ @my_custom_service, 'userIndexable' ]` will call the userIndexable method on a service defined as my_custom_service. +* An array of a class and a static method to call on that class which will be called with + the object as the only argument. `[ 'Acme\DemoBundle\IndexableChecker', 'isIndexable' ]` + will call Acme\DemoBundle\IndexableChecker::isIndexable($object) * If you have the ExpressionLanguage component installed, A valid ExpressionLanguage expression provided as a string. The object being indexed will be supplied as `object` in the expression. `object.isEnabled() or object.shouldBeIndexedAnyway()`. For more diff --git a/Tests/Functional/IndexableCallbackTest.php b/Tests/Functional/IndexableCallbackTest.php index 89fca1d..41ed402 100644 --- a/Tests/Functional/IndexableCallbackTest.php +++ b/Tests/Functional/IndexableCallbackTest.php @@ -31,8 +31,9 @@ class IndexableCallbackTest extends WebTestCase $in = $client->getContainer()->get('fos_elastica.indexable'); $this->assertTrue($in->isObjectIndexable('index', 'type', new TypeObj())); - $this->assertFalse($in->isObjectIndexable('index', 'type2', new TypeObj())); + $this->assertTrue($in->isObjectIndexable('index', 'type2', new TypeObj())); $this->assertFalse($in->isObjectIndexable('index', 'type3', new TypeObj())); + $this->assertFalse($in->isObjectIndexable('index', 'type4', new TypeObj())); } protected function setUp() diff --git a/Tests/Functional/app/ORM/IndexableService.php b/Tests/Functional/app/ORM/IndexableService.php new file mode 100644 index 0000000..018451e --- /dev/null +++ b/Tests/Functional/app/ORM/IndexableService.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FOS\ElasticaBundle\Tests\Functional\app\ORM; + +class IndexableService +{ + public function isIndexable($object) + { + return true; + } + + public static function isntIndexable($object) + { + return false; + } +} diff --git a/Tests/Functional/app/ORM/config.yml b/Tests/Functional/app/ORM/config.yml index 448d62b..9ba6830 100644 --- a/Tests/Functional/app/ORM/config.yml +++ b/Tests/Functional/app/ORM/config.yml @@ -9,6 +9,10 @@ doctrine: auto_generate_proxy_classes: false auto_mapping: false +services: + indexableService: + class: FOS\ElasticaBundle\Tests\Functional\app\ORM\IndexableService + fos_elastica: clients: default: @@ -41,7 +45,7 @@ fos_elastica: driver: orm model: FOS\ElasticaBundle\Tests\Functional\TypeObj listener: - is_indexable_callback: 'object.isntIndexable()' + is_indexable_callback: [ @indexableService, 'isIndexable' ] type3: mappings: field1: ~ @@ -52,3 +56,13 @@ fos_elastica: provider: ~ listener: is_indexable_callback: 'isntIndexable' + type4: + mappings: + field1: ~ + persistence: + driver: orm + model: FOS\ElasticaBundle\Tests\Functional\TypeObj + finder: ~ + provider: ~ + listener: + is_indexable_callback: [ 'FOS\ElasticaBundle\Tests\Functional\app\ORM\IndexableService', 'isntIndexable' ] From 77f2b99a3e83f8cb52865c9ddadae0c3a7fbb8fa Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 26 Jun 2014 18:01:34 +1000 Subject: [PATCH 290/447] Fix Indexable tests --- Provider/Indexable.php | 9 +++++---- Tests/Provider/IndexableTest.php | 21 ++++++++++++++++++--- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/Provider/Indexable.php b/Provider/Indexable.php index 827b3a4..197aeb8 100644 --- a/Provider/Indexable.php +++ b/Provider/Indexable.php @@ -112,16 +112,17 @@ class Indexable implements IndexableInterface if (is_array($callback)) { list($class, $method) = $callback + array(null, null); + + if (is_object($class)) { + $class = get_class($class); + } + if (strpos($class, '@') === 0) { $service = $this->container->get(substr($class, 1)); return array($service, $method); } - if (is_object($class)) { - $class = get_class($class); - } - if ($class && $method) { throw new \InvalidArgumentException(sprintf('Callback for type "%s", "%s::%s()", is not callable.', $type, $class, $method)); } diff --git a/Tests/Provider/IndexableTest.php b/Tests/Provider/IndexableTest.php index aae6484..6ef5669 100644 --- a/Tests/Provider/IndexableTest.php +++ b/Tests/Provider/IndexableTest.php @@ -12,12 +12,15 @@ namespace FOS\ElasticaBundle\Tests\Provider; use FOS\ElasticaBundle\Provider\Indexable; +use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; class IndexableTest extends \PHPUnit_Framework_TestCase { + public $container; + public function testIndexableUnknown() { - $indexable = new Indexable(array()); + $indexable = new Indexable(array(), $this->container); $index = $indexable->isObjectIndexable('index', 'type', new Entity); $this->assertTrue($index); @@ -30,7 +33,7 @@ class IndexableTest extends \PHPUnit_Framework_TestCase { $indexable = new Indexable(array( 'index/type' => $callback - )); + ), $this->container); $index = $indexable->isObjectIndexable('index', 'type', new Entity); $this->assertEquals($return, $index); @@ -44,7 +47,7 @@ class IndexableTest extends \PHPUnit_Framework_TestCase { $indexable = new Indexable(array( 'index/type' => $callback - )); + ), $this->container); $indexable->isObjectIndexable('index', 'type', new Entity); } @@ -63,12 +66,24 @@ class IndexableTest extends \PHPUnit_Framework_TestCase return array( array('isIndexable', false), array(array(new IndexableDecider(), 'isIndexable'), true), + array(array('@indexableService', 'isIndexable'), true), array(function(Entity $entity) { return $entity->maybeIndex(); }, true), array('entity.maybeIndex()', true), array('!object.isIndexable() && entity.property == "abc"', true), array('entity.property != "abc"', false), ); } + + protected function setUp() + { + $this->container = $this->getMockBuilder('Symfony\\Component\\DependencyInjection\\ContainerInterface') + ->getMock(); + + $this->container->expects($this->any()) + ->method('get') + ->with('indexableService') + ->will($this->returnValue(new IndexableDecider())); + } } class Entity From 474cbfa979e327080c4155dc6253491bbecd1043 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 26 Jun 2014 19:51:16 +1000 Subject: [PATCH 291/447] Added test coverage for ES store --- Index/MappingBuilder.php | 1 - Tests/Functional/MappingToElasticaTest.php | 6 ++++++ Tests/Functional/app/Basic/config.yml | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Index/MappingBuilder.php b/Index/MappingBuilder.php index 0751ce7..4a6c70a 100644 --- a/Index/MappingBuilder.php +++ b/Index/MappingBuilder.php @@ -69,7 +69,6 @@ class MappingBuilder return $mapping; } - /** * create type mapping object * diff --git a/Tests/Functional/MappingToElasticaTest.php b/Tests/Functional/MappingToElasticaTest.php index 390f854..f038212 100644 --- a/Tests/Functional/MappingToElasticaTest.php +++ b/Tests/Functional/MappingToElasticaTest.php @@ -28,6 +28,9 @@ class MappingToElasticaTest extends WebTestCase $mapping = $type->getMapping(); $this->assertNotEmpty($mapping, 'Mapping was populated'); + $this->assertArrayHasKey('store', $mapping['type']['properties']['field1']); + $this->assertTrue($mapping['type']['properties']['field1']['store']); + $this->assertArrayNotHasKey('store', $mapping['type']['properties']['field2']); } public function testResetType() @@ -40,6 +43,9 @@ class MappingToElasticaTest extends WebTestCase $mapping = $type->getMapping(); $this->assertNotEmpty($mapping, 'Mapping was populated'); + $this->assertArrayHasKey('store', $mapping['type']['properties']['field1']); + $this->assertTrue($mapping['type']['properties']['field1']['store']); + $this->assertArrayNotHasKey('store', $mapping['type']['properties']['field2']); } public function testORMResetIndexAddsMappings() diff --git a/Tests/Functional/app/Basic/config.yml b/Tests/Functional/app/Basic/config.yml index 174f9d5..0f2403b 100644 --- a/Tests/Functional/app/Basic/config.yml +++ b/Tests/Functional/app/Basic/config.yml @@ -38,6 +38,7 @@ fos_elastica: field1: ~ field2: type: integer + store: false date: { boost: 5 } title: { boost: 8, analyzer: my_analyzer } content: ~ From ad37a2835688ec88171caa893e3ae0e7ac4a1191 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Fri, 27 Jun 2014 15:08:08 +1000 Subject: [PATCH 292/447] Fix populating command setting alias before population --- Command/PopulateCommand.php | 2 +- Index/AliasProcessor.php | 12 +++++++----- Index/Resetter.php | 4 ++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Command/PopulateCommand.php b/Command/PopulateCommand.php index af5fd5d..f17ca4c 100644 --- a/Command/PopulateCommand.php +++ b/Command/PopulateCommand.php @@ -111,7 +111,7 @@ class PopulateCommand extends ContainerAwareCommand { if ($reset) { $output->writeln(sprintf('Resetting %s', $index)); - $this->resetter->resetIndex($index); + $this->resetter->resetIndex($index, true); } /** @var $providers ProviderInterface[] */ diff --git a/Index/AliasProcessor.php b/Index/AliasProcessor.php index 5c4592d..93877cd 100644 --- a/Index/AliasProcessor.php +++ b/Index/AliasProcessor.php @@ -39,11 +39,13 @@ class AliasProcessor */ public function switchIndexAlias(IndexConfig $indexConfig, Index $index) { + $client = $index->getClient(); + $aliasName = $indexConfig->getElasticSearchName(); $oldIndexName = false; $newIndexName = $index->getName(); - $aliasedIndexes = $this->getAliasedIndexes($aliasName); + $aliasedIndexes = $this->getAliasedIndexes($client, $aliasName); if (count($aliasedIndexes) > 1) { throw new \RuntimeException( @@ -71,7 +73,7 @@ class AliasProcessor ); try { - $this->client->request('_aliases', 'POST', $aliasUpdateRequest); + $client->request('_aliases', 'POST', $aliasUpdateRequest); } catch (ExceptionInterface $renameAliasException) { $additionalError = ''; // if we failed to move the alias, delete the newly built index @@ -96,7 +98,7 @@ class AliasProcessor // Delete the old index after the alias has been switched if ($oldIndexName) { - $oldIndex = new Index($this->client, $oldIndexName); + $oldIndex = new Index($client, $oldIndexName); try { $oldIndex->delete(); } catch (ExceptionInterface $deleteOldIndexException) { @@ -117,9 +119,9 @@ class AliasProcessor * @param string $aliasName Alias name * @return array */ - private function getAliasedIndexes($aliasName) + private function getAliasedIndexes(Client $client, $aliasName) { - $aliasesInfo = $this->client->request('_aliases', 'GET')->getData(); + $aliasesInfo = $client->request('_aliases', 'GET')->getData(); $aliasedIndexes = array(); foreach ($aliasesInfo as $indexName => $indexInfo) { diff --git a/Index/Resetter.php b/Index/Resetter.php index 174c410..3f07fa1 100644 --- a/Index/Resetter.php +++ b/Index/Resetter.php @@ -45,10 +45,10 @@ class Resetter /** * Deletes and recreates all indexes */ - public function resetAllIndexes() + public function resetAllIndexes($populating = false) { foreach ($this->configManager->getIndexNames() as $name) { - $this->resetIndex($name); + $this->resetIndex($name, $populating); } } From 78db0b9b6393f56af79185bd55c1dbcc0cca9652 Mon Sep 17 00:00:00 2001 From: Ron van der Molen Date: Sun, 29 Jun 2014 22:14:32 +0200 Subject: [PATCH 293/447] [FEATURE] Use static instantiation with max depth check --- Serializer/Callback.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Serializer/Callback.php b/Serializer/Callback.php index 9fe7064..38d93dc 100644 --- a/Serializer/Callback.php +++ b/Serializer/Callback.php @@ -43,7 +43,7 @@ class Callback public function serialize($object) { - $context = $this->serializer instanceof SerializerInterface ? new SerializationContext() : array(); + $context = $this->serializer instanceof SerializerInterface ? SerializationContext::create()->enableMaxDepthChecks() : array(); if ($this->groups) { $context->setGroups($this->groups); From c9a24436f3f27f7174db43e206d2093282694494 Mon Sep 17 00:00:00 2001 From: Tobias Schultze Date: Mon, 30 Jun 2014 16:19:10 +0200 Subject: [PATCH 294/447] dynamic templates are a list of hashes and have a mapping key (not properties) --- DependencyInjection/Configuration.php | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 52088b6..49b7b97 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -250,16 +250,21 @@ class Configuration implements ConfigurationInterface $node = $builder->root('dynamic_templates'); $node - ->useAttributeAsKey('name') ->prototype('array') - ->children() - ->scalarNode('match')->end() - ->scalarNode('unmatch')->end() - ->scalarNode('match_mapping_type')->end() - ->scalarNode('path_match')->end() - ->scalarNode('path_unmatch')->end() - ->scalarNode('match_pattern')->end() - ->append($this->getPropertiesNode()) + ->prototype('array') + ->children() + ->scalarNode('match')->end() + ->scalarNode('unmatch')->end() + ->scalarNode('match_mapping_type')->end() + ->scalarNode('path_match')->end() + ->scalarNode('path_unmatch')->end() + ->scalarNode('match_pattern')->end() + ->arrayNode('mapping') + ->prototype('variable') + ->treatNullLike(array()) + ->end() + ->end() + ->end() ->end() ->end() ; From 5d6567665955136caf3af10978403f55fa5dde1f Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Tue, 1 Jul 2014 10:09:25 +1000 Subject: [PATCH 295/447] Add tests and normalisation to support old dynamic_templates format --- DependencyInjection/Configuration.php | 20 ++++++++++++++++++ Index/MappingBuilder.php | 29 ++++----------------------- Tests/Functional/app/Basic/config.yml | 15 ++++++++++++++ 3 files changed, 39 insertions(+), 25 deletions(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 49b7b97..ae27860 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -189,6 +189,7 @@ class Configuration implements ConfigurationInterface return $v; }) ->end() + // BC - Support the old is_indexable_callback property ->beforeNormalization() ->ifTrue(function ($v) { return isset($v['persistence']) && @@ -202,6 +203,25 @@ class Configuration implements ConfigurationInterface return $v; }) ->end() + // Support multiple dynamic_template formats to match the old bundle style + // and the way ElasticSearch expects them + ->beforeNormalization() + ->ifTrue(function ($v) { return isset($v['dynamic_templates']); }) + ->then(function ($v) { + $dt = array(); + foreach ($v['dynamic_templates'] as $key => $type) { + if (is_numeric($key)) { + $dt[$key] = $type; + } else { + $dt[][$key] = $type; + } + } + + $v['dynamic_templates'] = $dt; + + return $v; + }) + ->end() ->children() ->scalarNode('index_analyzer')->end() ->scalarNode('search_analyzer')->end() diff --git a/Index/MappingBuilder.php b/Index/MappingBuilder.php index 4a6c70a..f3474be 100644 --- a/Index/MappingBuilder.php +++ b/Index/MappingBuilder.php @@ -60,6 +60,10 @@ class MappingBuilder // 'search_analyzer' => $typeConfig->getSearchAnalyzer(), )); + if (isset($mapping['dynamic_templates']) and empty($mapping['dynamic_templates'])) { + unset($mapping['dynamic_templates']); + } + $this->fixProperties($mapping['properties']); if ($typeConfig->getModel()) { @@ -69,31 +73,6 @@ class MappingBuilder return $mapping; } - /** - * create type mapping object - * - * @param array $indexConfig - * @return Mapping - */ - protected function createMapping($indexConfig) - { - /*$mapping = $this->createMapping($indexConfig['config']['properties'][$typeName]);*/ - $mapping = Mapping::create($indexConfig['properties']); - - $mappingSpecialFields = array('_uid', '_id', '_source', '_all', '_analyzer', '_boost', '_routing', '_index', '_size', '_timestamp', '_ttl', 'dynamic_templates'); - foreach ($mappingSpecialFields as $specialField) { - if (isset($indexConfig[$specialField])) { - $mapping->setParam($specialField, $indexConfig[$specialField]); - } - } - - if (isset($indexConfig['_parent'])) { - $mapping->setParam('_parent', array('type' => $indexConfig['_parent']['type'])); - } - - return $mapping; - } - /** * Fixes any properties and applies basic defaults for any field that does not have * required options. diff --git a/Tests/Functional/app/Basic/config.yml b/Tests/Functional/app/Basic/config.yml index 0f2403b..cdc6c53 100644 --- a/Tests/Functional/app/Basic/config.yml +++ b/Tests/Functional/app/Basic/config.yml @@ -29,11 +29,26 @@ fos_elastica: max_gram: 5 types: parent: + dynamic_templates: + dates: + match: "date_*" + mapping: + type: date mappings: field1: ~ field2: ~ type: search_analyzer: my_analyzer + dynamic_templates: + - dates: + match: "date_*" + mapping: + type: date + - strings: + match: "*" + mapping: + analyzer: english + type: string mappings: field1: ~ field2: From 7fcbb64a15fdf0a66a87acf9419456d7ce88ffd5 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Tue, 1 Jul 2014 18:02:30 +1000 Subject: [PATCH 296/447] Fix edge case for dynamic templates --- DependencyInjection/Configuration.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index ae27860..a63cfe6 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -210,8 +210,8 @@ class Configuration implements ConfigurationInterface ->then(function ($v) { $dt = array(); foreach ($v['dynamic_templates'] as $key => $type) { - if (is_numeric($key)) { - $dt[$key] = $type; + if (is_int($key)) { + $dt[] = $type; } else { $dt[][$key] = $type; } From 965b319d82f36469ee94163b28bcfe2591fe6196 Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Tue, 1 Jul 2014 14:40:03 +0300 Subject: [PATCH 297/447] [transformers] tell container that first argument is collection. --- Resources/config/transformer.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Resources/config/transformer.xml b/Resources/config/transformer.xml index e3abbbc..4ce5062 100644 --- a/Resources/config/transformer.xml +++ b/Resources/config/transformer.xml @@ -12,14 +12,14 @@ - + - + From c200e8fdfd9a8878525a06345f00d46de9d53598 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 3 Jul 2014 19:59:33 +1000 Subject: [PATCH 298/447] Add tests for attachment type --- .travis.yml | 2 ++ Tests/Functional/app/Basic/config.yml | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d6ba18a..a884d86 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,8 @@ php: - 5.5 before_script: + - sudo /usr/share/elasticsearch/bin/plugin -install elasticsearch/elasticsearch-mapper-attachments/2.0.0 + - sudo service elasticsearch restart - echo "extension = mongo.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini - composer install --dev --prefer-source diff --git a/Tests/Functional/app/Basic/config.yml b/Tests/Functional/app/Basic/config.yml index cdc6c53..beb0ded 100644 --- a/Tests/Functional/app/Basic/config.yml +++ b/Tests/Functional/app/Basic/config.yml @@ -49,7 +49,7 @@ fos_elastica: mapping: analyzer: english type: string - mappings: + properties: field1: ~ field2: type: integer @@ -68,6 +68,8 @@ fos_elastica: type: "object" properties: date: { boost: 5 } + agreement: + type: "attachment" lastlogin: { type: date, format: basic_date_time } birthday: { type: date, format: "yyyy-MM-dd" } _parent: From 55dcf6859ab9616028d2da2355b581737efb3802 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 3 Jul 2014 21:58:54 +1000 Subject: [PATCH 299/447] Rename servers to connections --- DependencyInjection/Configuration.php | 37 ++++++++++--------- DependencyInjection/FOSElasticaExtension.php | 2 +- .../doc/cookbook/multiple-connections.md | 16 ++++++++ Resources/doc/index.md | 2 + .../DependencyInjection/ConfigurationTest.php | 26 ++++++------- Tests/Functional/app/Basic/config.yml | 5 +++ 6 files changed, 56 insertions(+), 32 deletions(-) create mode 100644 Resources/doc/cookbook/multiple-connections.md diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index a63cfe6..874f51e 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -73,27 +73,28 @@ class Configuration implements ConfigurationInterface ->arrayNode('clients') ->useAttributeAsKey('id') ->prototype('array') - ->performNoDeepMerging() + // BC - Renaming 'servers' node to 'connections' ->beforeNormalization() - ->ifTrue(function($v) { return (isset($v['host']) && isset($v['port'])) || isset($v['url']); }) - ->then(function($v) { - return array( - 'servers' => array( - array( - 'host' => isset($v['host']) ? $v['host'] : null, - 'port' => isset($v['port']) ? $v['port'] : null, - 'url' => isset($v['url']) ? $v['url'] : null, - 'logger' => isset($v['logger']) ? $v['logger'] : null, - 'headers' => isset($v['headers']) ? $v['headers'] : null, - 'timeout' => isset($v['timeout']) ? $v['timeout'] : null, - 'transport' => isset($v['transport']) ? $v['transport'] : null, - ) - ) - ); - }) + ->ifTrue(function($v) { return isset($v['servers']); }) + ->then(function($v) { + $v['connections'] = $v['servers']; + unset($v['servers']); + + return $v; + }) + ->end() + // If there is no connections array key defined, assume a single connection. + ->beforeNormalization() + ->ifTrue(function ($v) { return is_array($v) && !array_key_exists('connections', $v); }) + ->then(function ($v) { + return array( + 'connections' => array($v) + ); + }) ->end() ->children() - ->arrayNode('servers') + ->arrayNode('connections') + ->requiresAtLeastOneElement() ->prototype('array') ->fixXmlConfig('header') ->children() diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 9862076..292a9a5 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -104,7 +104,7 @@ class FOSElasticaExtension extends Extension $clientDef = new DefinitionDecorator('fos_elastica.client_prototype'); $clientDef->replaceArgument(0, $clientConfig); - $logger = $clientConfig['servers'][0]['logger']; + $logger = $clientConfig['connections'][0]['logger']; if (false !== $logger) { $clientDef->addMethodCall('setLogger', array(new Reference($logger))); } diff --git a/Resources/doc/cookbook/multiple-connections.md b/Resources/doc/cookbook/multiple-connections.md new file mode 100644 index 0000000..7b5226c --- /dev/null +++ b/Resources/doc/cookbook/multiple-connections.md @@ -0,0 +1,16 @@ +Multiple Connections +==================== + +You can define multiple endpoints for an Elastica client by specifying them as +multiple connections in the client configuration: + +```yaml +fos_elastica: + clients: + default: + connections: + - url: http://es1.example.net:9200 + - url: http://es2.example.net:9200 +``` + +For more information on Elastica clustering see http://elastica.io/getting-started/installation.html#section-connect-cluster diff --git a/Resources/doc/index.md b/Resources/doc/index.md index 1bc093e..80a500c 100644 --- a/Resources/doc/index.md +++ b/Resources/doc/index.md @@ -15,4 +15,6 @@ Cookbook Entries * [Custom Repositories](cookbook/custom-repositories.md) * [HTTP Headers for Elastica](cookbook/elastica-client-http-headers.md) * Performance - [Logging](cookbook/logging.md) +* [Manual Providers](cookbook/manual-provider.md) +* [Clustering - Multiple Connections](cookbook/multiple-connections.md) * [Suppressing server errors](cookbook/suppress-server-errors.md) diff --git a/Tests/DependencyInjection/ConfigurationTest.php b/Tests/DependencyInjection/ConfigurationTest.php index b474117..7165052 100644 --- a/Tests/DependencyInjection/ConfigurationTest.php +++ b/Tests/DependencyInjection/ConfigurationTest.php @@ -46,7 +46,7 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase 'url' => 'http://localhost:9200', ), 'clustered' => array( - 'servers' => array( + 'connections' => array( array( 'url' => 'http://es1:9200', 'headers' => array( @@ -65,13 +65,13 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase )); $this->assertCount(2, $configuration['clients']); - $this->assertCount(1, $configuration['clients']['default']['servers']); - $this->assertCount(0, $configuration['clients']['default']['servers'][0]['headers']); + $this->assertCount(1, $configuration['clients']['default']['connections']); + $this->assertCount(0, $configuration['clients']['default']['connections'][0]['headers']); - $this->assertCount(2, $configuration['clients']['clustered']['servers']); - $this->assertEquals('http://es2:9200/', $configuration['clients']['clustered']['servers'][1]['url']); - $this->assertCount(1, $configuration['clients']['clustered']['servers'][1]['headers']); - $this->assertEquals('Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==', $configuration['clients']['clustered']['servers'][0]['headers'][0]); + $this->assertCount(2, $configuration['clients']['clustered']['connections']); + $this->assertEquals('http://es2:9200/', $configuration['clients']['clustered']['connections'][1]['url']); + $this->assertCount(1, $configuration['clients']['clustered']['connections'][1]['headers']); + $this->assertEquals('Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==', $configuration['clients']['clustered']['connections'][0]['headers'][0]); } public function testLogging() @@ -98,10 +98,10 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase $this->assertCount(4, $configuration['clients']); - $this->assertEquals('fos_elastica.logger', $configuration['clients']['logging_enabled']['servers'][0]['logger']); - $this->assertFalse($configuration['clients']['logging_disabled']['servers'][0]['logger']); - $this->assertEquals('fos_elastica.logger', $configuration['clients']['logging_not_mentioned']['servers'][0]['logger']); - $this->assertEquals('custom.service', $configuration['clients']['logging_custom']['servers'][0]['logger']); + $this->assertEquals('fos_elastica.logger', $configuration['clients']['logging_enabled']['connections'][0]['logger']); + $this->assertFalse($configuration['clients']['logging_disabled']['connections'][0]['logger']); + $this->assertEquals('fos_elastica.logger', $configuration['clients']['logging_not_mentioned']['connections'][0]['logger']); + $this->assertEquals('custom.service', $configuration['clients']['logging_custom']['connections'][0]['logger']); } public function testSlashIsAddedAtTheEndOfServerUrl() @@ -113,7 +113,7 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase ); $configuration = $this->getConfigs($config); - $this->assertEquals('http://www.github.com/', $configuration['clients']['default']['servers'][0]['url']); + $this->assertEquals('http://www.github.com/', $configuration['clients']['default']['connections'][0]['url']); } public function testTypeConfig() @@ -172,7 +172,7 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase ) )); - $this->assertTrue(empty($configuration['clients']['default']['servers'][0]['url'])); + $this->assertTrue(empty($configuration['clients']['default']['connections'][0]['url'])); } public function testMappingsRenamedToProperties() diff --git a/Tests/Functional/app/Basic/config.yml b/Tests/Functional/app/Basic/config.yml index beb0ded..e880fb1 100644 --- a/Tests/Functional/app/Basic/config.yml +++ b/Tests/Functional/app/Basic/config.yml @@ -11,6 +11,11 @@ twig: fos_elastica: clients: default: + connections: + - url: http://localhost:9200 + - host: localhost + port: 9200 + second_server: url: http://localhost:9200 indexes: index: From 815b836cdc067fffe32f74b863c7a7c433ecb4ff Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 3 Jul 2014 23:20:18 +1000 Subject: [PATCH 300/447] Add stopwatch support for Elastica\Client --- Elastica/Client.php | 26 ++++++++++++++++++++++++++ Resources/config/config.xml | 4 ++++ 2 files changed, 30 insertions(+) diff --git a/Elastica/Client.php b/Elastica/Client.php index e921965..1131ba5 100644 --- a/Elastica/Client.php +++ b/Elastica/Client.php @@ -5,6 +5,7 @@ namespace FOS\ElasticaBundle\Elastica; use Elastica\Client as BaseClient; use Elastica\Request; use FOS\ElasticaBundle\Logger\ElasticaLogger; +use Symfony\Component\Stopwatch\Stopwatch; /** * Extends the default Elastica client to provide logging for errors that occur @@ -21,11 +22,22 @@ class Client extends BaseClient */ private $indexCache = array(); + /** + * Symfony's debugging Stopwatch + * + * @var Stopwatch|null + */ + private $stopwatch; + /** * {@inheritdoc} */ public function request($path, $method = Request::GET, $data = array(), array $query = array()) { + if ($this->stopwatch) { + $this->stopwatch->start('es_request', 'fos_elastica'); + } + $start = microtime(true); $response = parent::request($path, $method, $data, $query); @@ -44,6 +56,10 @@ class Client extends BaseClient $this->_logger->logQuery($path, $method, $data, $time, $connection_array, $query); } + if ($this->stopwatch) { + $this->stopwatch->stop('es_request'); + } + return $response; } @@ -55,4 +71,14 @@ class Client extends BaseClient return $this->indexCache[$name] = new Index($this, $name); } + + /** + * Sets a stopwatch instance for debugging purposes. + * + * @param Stopwatch $stopwatch + */ + public function setStopwatch(Stopwatch $stopwatch = null) + { + $this->stopwatch = $stopwatch; + } } diff --git a/Resources/config/config.xml b/Resources/config/config.xml index 023688f..dcec2e8 100644 --- a/Resources/config/config.xml +++ b/Resources/config/config.xml @@ -16,6 +16,10 @@ + + + + From 21e5d906a7ec8fd696dbacd03eb176d3d053314c Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 3 Jul 2014 23:37:44 +1000 Subject: [PATCH 301/447] Simplify *One methods in the persister --- Persister/ObjectPersister.php | 18 ++++-------------- Tests/Persister/ObjectPersisterTest.php | 9 +++------ .../ObjectSerializerPersisterTest.php | 9 +++------ 3 files changed, 10 insertions(+), 26 deletions(-) diff --git a/Persister/ObjectPersister.php b/Persister/ObjectPersister.php index 54d5fd1..9604f7e 100644 --- a/Persister/ObjectPersister.php +++ b/Persister/ObjectPersister.php @@ -71,8 +71,7 @@ class ObjectPersister implements ObjectPersisterInterface */ public function insertOne($object) { - $document = $this->transformToElasticaDocument($object); - $this->type->addDocument($document); + $this->insertMany(array($object)); } /** @@ -83,11 +82,7 @@ class ObjectPersister implements ObjectPersisterInterface **/ public function replaceOne($object) { - $document = $this->transformToElasticaDocument($object); - try { - $this->type->deleteById($document->getId()); - } catch (NotFoundException $e) {} - $this->type->addDocument($document); + $this->replaceMany(array($object)); } /** @@ -98,10 +93,7 @@ class ObjectPersister implements ObjectPersisterInterface **/ public function deleteOne($object) { - $document = $this->transformToElasticaDocument($object); - try { - $this->type->deleteById($document->getId()); - } catch (NotFoundException $e) {} + $this->deleteMany(array($object)); } /** @@ -113,9 +105,7 @@ class ObjectPersister implements ObjectPersisterInterface **/ public function deleteById($id) { - try { - $this->type->deleteById($id); - } catch (NotFoundException $e) {} + $this->deleteManyByIdentifiers(array($id)); } /** diff --git a/Tests/Persister/ObjectPersisterTest.php b/Tests/Persister/ObjectPersisterTest.php index 497c286..77a8809 100644 --- a/Tests/Persister/ObjectPersisterTest.php +++ b/Tests/Persister/ObjectPersisterTest.php @@ -47,10 +47,7 @@ class ObjectPersisterTest extends \PHPUnit_Framework_TestCase ->disableOriginalConstructor() ->getMock(); $typeMock->expects($this->once()) - ->method('deleteById') - ->with($this->equalTo(123)); - $typeMock->expects($this->once()) - ->method('addDocument'); + ->method('updateDocuments'); $fields = array('name' => array()); @@ -91,7 +88,7 @@ class ObjectPersisterTest extends \PHPUnit_Framework_TestCase $typeMock->expects($this->never()) ->method('deleteById'); $typeMock->expects($this->once()) - ->method('addDocument'); + ->method('addDocuments'); $fields = array('name' => array()); @@ -130,7 +127,7 @@ class ObjectPersisterTest extends \PHPUnit_Framework_TestCase ->disableOriginalConstructor() ->getMock(); $typeMock->expects($this->once()) - ->method('deleteById'); + ->method('deleteDocuments'); $typeMock->expects($this->never()) ->method('addDocument'); diff --git a/Tests/Persister/ObjectSerializerPersisterTest.php b/Tests/Persister/ObjectSerializerPersisterTest.php index aae3a64..fe15c0c 100644 --- a/Tests/Persister/ObjectSerializerPersisterTest.php +++ b/Tests/Persister/ObjectSerializerPersisterTest.php @@ -42,10 +42,7 @@ class ObjectSerializerPersisterTest extends \PHPUnit_Framework_TestCase ->disableOriginalConstructor() ->getMock(); $typeMock->expects($this->once()) - ->method('deleteById') - ->with($this->equalTo(123)); - $typeMock->expects($this->once()) - ->method('addDocument'); + ->method('updateDocuments'); $serializerMock = $this->getMockBuilder('FOS\ElasticaBundle\Serializer\Callback')->getMock(); $serializerMock->expects($this->once())->method('serialize'); @@ -65,7 +62,7 @@ class ObjectSerializerPersisterTest extends \PHPUnit_Framework_TestCase $typeMock->expects($this->never()) ->method('deleteById'); $typeMock->expects($this->once()) - ->method('addDocument'); + ->method('addDocuments'); $serializerMock = $this->getMockBuilder('FOS\ElasticaBundle\Serializer\Callback')->getMock(); $serializerMock->expects($this->once())->method('serialize'); @@ -83,7 +80,7 @@ class ObjectSerializerPersisterTest extends \PHPUnit_Framework_TestCase ->disableOriginalConstructor() ->getMock(); $typeMock->expects($this->once()) - ->method('deleteById'); + ->method('deleteDocuments'); $typeMock->expects($this->never()) ->method('addDocument'); From d57d430ab3e29a7502ac31500ed65f6c962a4674 Mon Sep 17 00:00:00 2001 From: tamirvs Date: Wed, 18 Jun 2014 17:02:50 +0000 Subject: [PATCH 302/447] Ignore iterator keys when converting to array --- Tests/Functional/MappingToElasticaTest.php | 18 +++++++ Tests/Functional/SerializerTest.php | 48 +++++++++++++++++++ Tests/Functional/TypeObj.php | 8 ++++ Tests/Functional/app/Basic/config.yml | 2 +- Tests/Functional/app/ORM/config.yml | 9 ++-- Tests/Functional/app/Serializer/TypeObj.yml | 8 ++++ Tests/Functional/app/Serializer/bundles.php | 13 +++++ Tests/Functional/app/Serializer/config.yml | 42 ++++++++++++++++ .../ModelToElasticaAutoTransformer.php | 2 +- 9 files changed, 142 insertions(+), 8 deletions(-) create mode 100644 Tests/Functional/SerializerTest.php create mode 100644 Tests/Functional/app/Serializer/TypeObj.yml create mode 100644 Tests/Functional/app/Serializer/bundles.php create mode 100644 Tests/Functional/app/Serializer/config.yml diff --git a/Tests/Functional/MappingToElasticaTest.php b/Tests/Functional/MappingToElasticaTest.php index f038212..2474a1c 100644 --- a/Tests/Functional/MappingToElasticaTest.php +++ b/Tests/Functional/MappingToElasticaTest.php @@ -72,6 +72,22 @@ class MappingToElasticaTest extends WebTestCase $this->assertNotEmpty($mapping, 'Mapping was populated'); } + public function testMappingIteratorToArrayField() + { + $client = $this->createClient(array('test_case' => 'ORM')); + $persister = $client->getContainer()->get('fos_elastica.object_persister.index.type'); + + $object = new TypeObj(); + $object->id = 1; + $object->coll = new \ArrayIterator(array('foo', 'bar')); + $persister->insertOne($object); + + $object->coll = new \ArrayIterator(array('foo', 'bar', 'bazz')); + $object->coll->offsetUnset(1); + + $persister->replaceOne($object); + } + /** * @param Client $client * @return \FOS\ElasticaBundle\Resetter $resetter @@ -95,6 +111,7 @@ class MappingToElasticaTest extends WebTestCase parent::setUp(); $this->deleteTmpDir('Basic'); + $this->deleteTmpDir('ORM'); } protected function tearDown() @@ -102,5 +119,6 @@ class MappingToElasticaTest extends WebTestCase parent::tearDown(); $this->deleteTmpDir('Basic'); + $this->deleteTmpDir('ORM'); } } diff --git a/Tests/Functional/SerializerTest.php b/Tests/Functional/SerializerTest.php new file mode 100644 index 0000000..3a3b8cb --- /dev/null +++ b/Tests/Functional/SerializerTest.php @@ -0,0 +1,48 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace FOS\ElasticaBundle\Tests\Functional; + +/** + * @group functional + */ +class SerializerTest extends WebTestCase +{ + public function testMappingIteratorToArrayField() + { + $client = $this->createClient(array('test_case' => 'Serializer')); + $persister = $client->getContainer()->get('fos_elastica.object_persister.index.type'); + + $object = new TypeObj(); + $object->id = 1; + $object->coll = new \ArrayIterator(array('foo', 'bar')); + $persister->insertOne($object); + + $object->coll = new \ArrayIterator(array('foo', 'bar', 'bazz')); + $object->coll->offsetUnset(1); + + $persister->replaceOne($object); + } + + protected function setUp() + { + parent::setUp(); + + $this->deleteTmpDir('Serializer'); + } + + protected function tearDown() + { + parent::tearDown(); + + $this->deleteTmpDir('Serializer'); + } +} diff --git a/Tests/Functional/TypeObj.php b/Tests/Functional/TypeObj.php index c264e7b..46e5968 100644 --- a/Tests/Functional/TypeObj.php +++ b/Tests/Functional/TypeObj.php @@ -13,6 +13,9 @@ namespace FOS\ElasticaBundle\Tests\Functional; class TypeObj { + public $coll; + public $field1; + public function isIndexable() { return true; @@ -22,4 +25,9 @@ class TypeObj { return false; } + + public function getSerializableColl() + { + return iterator_to_array($this->coll, false); + } } diff --git a/Tests/Functional/app/Basic/config.yml b/Tests/Functional/app/Basic/config.yml index cdc6c53..a7550b9 100644 --- a/Tests/Functional/app/Basic/config.yml +++ b/Tests/Functional/app/Basic/config.yml @@ -14,7 +14,7 @@ fos_elastica: url: http://localhost:9200 indexes: index: - index_name: foselastica_test_%kernel.environment% + index_name: foselastica_basic_test_%kernel.environment% settings: analysis: analyzer: diff --git a/Tests/Functional/app/ORM/config.yml b/Tests/Functional/app/ORM/config.yml index 9ba6830..3dc0e63 100644 --- a/Tests/Functional/app/ORM/config.yml +++ b/Tests/Functional/app/ORM/config.yml @@ -17,27 +17,24 @@ fos_elastica: clients: default: url: http://localhost:9200 - serializer: ~ indexes: - fos_elastica_test: + fos_elastica_orm_test: types: type: properties: field1: ~ index: - index_name: foselastica_test_%kernel.environment% + index_name: foselastica_orm_test_%kernel.environment% types: type: properties: field1: ~ + coll: ~ persistence: driver: orm model: FOS\ElasticaBundle\Tests\Functional\TypeObj listener: is_indexable_callback: 'object.isIndexable() && !object.isntIndexable()' - serializer: - groups: ['search'] - version: 1.1 type2: properties: field1: ~ diff --git a/Tests/Functional/app/Serializer/TypeObj.yml b/Tests/Functional/app/Serializer/TypeObj.yml new file mode 100644 index 0000000..67d6335 --- /dev/null +++ b/Tests/Functional/app/Serializer/TypeObj.yml @@ -0,0 +1,8 @@ +FOS\ElasticaBundle\Tests\Functional\TypeObj: + properties: + field1: + type: string + virtualProperties: + getSerializableColl: + serializedName: coll + type: array diff --git a/Tests/Functional/app/Serializer/bundles.php b/Tests/Functional/app/Serializer/bundles.php new file mode 100644 index 0000000..25db3fe --- /dev/null +++ b/Tests/Functional/app/Serializer/bundles.php @@ -0,0 +1,13 @@ + Date: Fri, 4 Jul 2014 13:06:57 +1000 Subject: [PATCH 303/447] Documentation on aliased repopulation --- Resources/doc/cookbook/aliased-indexes.md | 45 +++++++++++++++++++++++ Resources/doc/index.md | 1 + 2 files changed, 46 insertions(+) create mode 100644 Resources/doc/cookbook/aliased-indexes.md diff --git a/Resources/doc/cookbook/aliased-indexes.md b/Resources/doc/cookbook/aliased-indexes.md new file mode 100644 index 0000000..b9049c5 --- /dev/null +++ b/Resources/doc/cookbook/aliased-indexes.md @@ -0,0 +1,45 @@ +Aliased Indexes +=============== + +You can set up FOSElasticaBundle to use aliases for indexes which allows you to run an +index population without resetting the index currently being used by the application. + +> *Note*: When you're using an alias, resetting an individual type will still cause a +> reset for that type. + +To configure FOSElasticaBundle to use aliases for an index, set the use_alias option to +true. + +```yaml +fos_elastica: + indexes: + website: + use_alias: true +``` + +The process for setting up aliases on an existing application is slightly more complicated +because the bundle is not able to set an alias as the same name as an index. You have some +options on how to handle this: + +1) Delete the index from Elasticsearch. This option will make searching unavailable in your + application until a population has completed itself, and an alias is created. + +2) Change the index_name parameter for your index to something new, and manually alias the + current index to the new index_name, which will then be replaced when you run a repopulate. + +```yaml +fos_elastica: + indexes: + website: + use_alias: true + index_name: website_prod +``` + +```bash +$ curl -XPOST 'http://localhost:9200/_aliases' -d ' +{ + "actions" : [ + { "add" : { "index" : "website", "alias" : "website_prod" } } + ] +}' +``` diff --git a/Resources/doc/index.md b/Resources/doc/index.md index 80a500c..349723b 100644 --- a/Resources/doc/index.md +++ b/Resources/doc/index.md @@ -12,6 +12,7 @@ Available documentation for FOSElasticaBundle Cookbook Entries ---------------- +* [Aliased Indexes](cookbook/aliased-indexes.md) * [Custom Repositories](cookbook/custom-repositories.md) * [HTTP Headers for Elastica](cookbook/elastica-client-http-headers.md) * Performance - [Logging](cookbook/logging.md) From d88d96bf55a1ba6b603d429d9bf6a217d945b1c5 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Fri, 4 Jul 2014 22:10:24 +1000 Subject: [PATCH 304/447] Fix invalid service reference in production --- Resources/config/config.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/config/config.xml b/Resources/config/config.xml index dcec2e8..06f0cda 100644 --- a/Resources/config/config.xml +++ b/Resources/config/config.xml @@ -18,7 +18,7 @@ - + From cdaf7105e03d6437e534f4d9a402f1674bab7cfc Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Sat, 5 Jul 2014 15:14:29 +1000 Subject: [PATCH 305/447] Bump dev version to 3.1 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 372320f..a1734dd 100644 --- a/composer.json +++ b/composer.json @@ -47,7 +47,7 @@ }, "extra": { "branch-alias": { - "dev-master": "3.0.x-dev" + "dev-master": "3.1.x-dev" } } } From d797af5b80ae98936c78eea4a6db7a9d80b2eaab Mon Sep 17 00:00:00 2001 From: Floran Brutel Date: Mon, 7 Jul 2014 18:35:23 +0200 Subject: [PATCH 306/447] Fix "Faceted Searching" doc --- Resources/doc/usage.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/doc/usage.md b/Resources/doc/usage.md index 55d90ab..37514b3 100644 --- a/Resources/doc/usage.md +++ b/Resources/doc/usage.md @@ -45,7 +45,7 @@ $companies = $finder->findPaginated($query); $companies->setMaxPerPage($params['limit']); $companies->setCurrentPage($params['page']); -$facets = $companies->getAdapter()->getFacets()); +$facets = $companies->getAdapter()->getFacets(); ``` Searching the entire index From 714502fa1f51bf7e9b372c799d811483b5db3b1c Mon Sep 17 00:00:00 2001 From: esodin Date: Thu, 17 Jul 2014 16:01:10 +0300 Subject: [PATCH 307/447] Issue: Parent is missing in the fields list that causes RoutingMissingException on flushing --- DependencyInjection/FOSElasticaExtension.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 292a9a5..89ac3dd 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -391,7 +391,13 @@ class FOSElasticaExtension extends Extension $arguments[] = array(new Reference($callbackId), 'serialize'); } else { $abstractId = 'fos_elastica.object_persister'; - $arguments[] = $this->indexConfigs[$indexName]['types'][$typeName]['mapping']['properties']; + $mapping = $this->indexConfigs[$indexName]['types'][$typeName]['mapping']; + $argument = $mapping['properties']; + if(isset($mapping['_parent'])){ + $argument['_parent'] = $mapping['_parent']; + } + $arguments[] = $argument; + } $serviceId = sprintf('fos_elastica.object_persister.%s.%s', $indexName, $typeName); From fad481d8222be4e6b49f3bcdaf120be76958d008 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Wed, 23 Jul 2014 20:00:14 +1000 Subject: [PATCH 308/447] Fix completion type --- Index/MappingBuilder.php | 16 +++++++++++++--- Tests/Functional/app/Basic/config.yml | 2 ++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/Index/MappingBuilder.php b/Index/MappingBuilder.php index f3474be..fc67420 100644 --- a/Index/MappingBuilder.php +++ b/Index/MappingBuilder.php @@ -16,6 +16,13 @@ use FOS\ElasticaBundle\Configuration\TypeConfig; class MappingBuilder { + /** + * Skip adding default information to certain fields. + * + * @var array + */ + private $skipTypes = array('completion'); + /** * Builds mappings for an entire index. * @@ -85,12 +92,15 @@ class MappingBuilder if (!isset($property['type'])) { $property['type'] = 'string'; } - if (!isset($property['store'])) { - $property['store'] = true; - } if (isset($property['properties'])) { $this->fixProperties($property['properties']); } + if (in_array($property['type'], $this->skipTypes)) { + continue; + } + if (!isset($property['store'])) { + $property['store'] = true; + } } } } diff --git a/Tests/Functional/app/Basic/config.yml b/Tests/Functional/app/Basic/config.yml index 3552b3d..607e3cc 100644 --- a/Tests/Functional/app/Basic/config.yml +++ b/Tests/Functional/app/Basic/config.yml @@ -60,6 +60,8 @@ fos_elastica: type: integer store: false date: { boost: 5 } + completion: + type: completion title: { boost: 8, analyzer: my_analyzer } content: ~ comments: From e5410a5b650cddd3e1b9f128c7701496b3bda5b9 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Wed, 23 Jul 2014 21:38:46 +1000 Subject: [PATCH 309/447] Fix indexable callbacks being overwritten by another index closes #663 --- DependencyInjection/FOSElasticaExtension.php | 15 ++++++++------- Tests/Functional/app/ORM/config.yml | 12 ++++++++++++ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 292a9a5..e523bf4 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -128,6 +128,8 @@ class FOSElasticaExtension extends Extension */ private function loadIndexes(array $indexes, ContainerBuilder $container) { + $indexableCallbacks = array(); + foreach ($indexes as $name => $index) { $indexId = sprintf('fos_elastica.index.%s', $name); $indexName = isset($index['index_name']) ? $index['index_name']: $name; @@ -159,8 +161,11 @@ class FOSElasticaExtension extends Extension $this->loadIndexFinder($container, $name, $reference); } - $this->loadTypes((array) $index['types'], $container, $this->indexConfigs[$name]); + $this->loadTypes((array) $index['types'], $container, $this->indexConfigs[$name], $indexableCallbacks); } + + $indexable = $container->getDefinition('fos_elastica.indexable'); + $indexable->replaceArgument(0, $indexableCallbacks); } /** @@ -194,11 +199,10 @@ class FOSElasticaExtension extends Extension * @param array $types * @param ContainerBuilder $container * @param array $indexConfig + * @param array $indexableCallbacks */ - private function loadTypes(array $types, ContainerBuilder $container, array $indexConfig) + private function loadTypes(array $types, ContainerBuilder $container, array $indexConfig, array &$indexableCallbacks) { - $indexableCallbacks = array(); - foreach ($types as $name => $type) { $indexName = $indexConfig['name']; @@ -269,9 +273,6 @@ class FOSElasticaExtension extends Extension $container->setDefinition($typeSerializerId, $typeSerializerDef); } } - - $indexable = $container->getDefinition('fos_elastica.indexable'); - $indexable->replaceArgument(0, $indexableCallbacks); } /** diff --git a/Tests/Functional/app/ORM/config.yml b/Tests/Functional/app/ORM/config.yml index 3dc0e63..02d7a92 100644 --- a/Tests/Functional/app/ORM/config.yml +++ b/Tests/Functional/app/ORM/config.yml @@ -63,3 +63,15 @@ fos_elastica: provider: ~ listener: is_indexable_callback: [ 'FOS\ElasticaBundle\Tests\Functional\app\ORM\IndexableService', 'isntIndexable' ] + second_index: + index_name: foselastica_orm_test_second_%kernel.environment% + types: + type: + properties: + field1: ~ + coll: ~ + persistence: + driver: orm + model: FOS\ElasticaBundle\Tests\Functional\TypeObj + listener: + is_indexable_callback: 'object.isIndexable() && !object.isntIndexable()' From 11ee25cfea23a1d2743bc875eb1ecacdaf3f5d8c Mon Sep 17 00:00:00 2001 From: Tobias Nyholm Date: Wed, 9 Jul 2014 12:29:01 +0200 Subject: [PATCH 310/447] Added PHP 5.6 --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index a884d86..034cd84 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ php: - 5.3 - 5.4 - 5.5 + - 5.6 before_script: - sudo /usr/share/elasticsearch/bin/plugin -install elasticsearch/elasticsearch-mapper-attachments/2.0.0 From 1ef55b1239a5b7c161da512d3a611d4cab9d30f9 Mon Sep 17 00:00:00 2001 From: esodin Date: Thu, 24 Jul 2014 17:03:26 +0300 Subject: [PATCH 311/447] Issue: Parent is missing in the fields list that causes RoutingMissingException on flushing - test --- .../FOSElasticaExtensionTest.php | 36 +++++++++++++++++++ .../DependencyInjection/config/config.yml | 21 +++++++++++ 2 files changed, 57 insertions(+) create mode 100644 Tests/Functional/DependencyInjection/FOSElasticaExtensionTest.php create mode 100644 Tests/Functional/DependencyInjection/config/config.yml diff --git a/Tests/Functional/DependencyInjection/FOSElasticaExtensionTest.php b/Tests/Functional/DependencyInjection/FOSElasticaExtensionTest.php new file mode 100644 index 0000000..f210136 --- /dev/null +++ b/Tests/Functional/DependencyInjection/FOSElasticaExtensionTest.php @@ -0,0 +1,36 @@ +setParameter('kernel.debug', true); + + $extension = new FOSElasticaExtension; + + $extension->load($config, $containerBuilder); + + $this->assertTrue($containerBuilder->hasDefinition('fos_elastica.object_persister.test_index.child_field')); + + $persisterCallDefinition = $containerBuilder->getDefinition('fos_elastica.object_persister.test_index.child_field'); + + $this->assertArrayHasKey('_parent', $persisterCallDefinition->getArguments()['index_3']); + } + +} \ No newline at end of file diff --git a/Tests/Functional/DependencyInjection/config/config.yml b/Tests/Functional/DependencyInjection/config/config.yml new file mode 100644 index 0000000..5528d18 --- /dev/null +++ b/Tests/Functional/DependencyInjection/config/config.yml @@ -0,0 +1,21 @@ +fos_elastica: + clients: + default: + url: http://localhost:9200 + indexes: + test_index: + client: default + types: + parent_field: + mappings: + text: ~ + persistence: + driver: orm + model: foo_model + child_field: + mappings: + text: ~ + persistence: + driver: orm + model: foo_model + _parent: { type: "parent_field", property: "parent" } From 001b38cf59839d7acf230d76e765e77235af0842 Mon Sep 17 00:00:00 2001 From: esodin Date: Thu, 24 Jul 2014 17:07:22 +0300 Subject: [PATCH 312/447] Issue: Parent is missing in the fields list that causes RoutingMissingException on flushing - test --- .../DependencyInjection/FOSElasticaExtensionTest.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Tests/Functional/DependencyInjection/FOSElasticaExtensionTest.php b/Tests/Functional/DependencyInjection/FOSElasticaExtensionTest.php index f210136..a02c35e 100644 --- a/Tests/Functional/DependencyInjection/FOSElasticaExtensionTest.php +++ b/Tests/Functional/DependencyInjection/FOSElasticaExtensionTest.php @@ -30,7 +30,10 @@ class FOSElasticaExtensionTest extends \PHPUnit_Framework_TestCase $persisterCallDefinition = $containerBuilder->getDefinition('fos_elastica.object_persister.test_index.child_field'); - $this->assertArrayHasKey('_parent', $persisterCallDefinition->getArguments()['index_3']); + $arguments = $persisterCallDefinition->getArguments()['index_3']; + + $this->assertArrayHasKey('_parent', $arguments); + $this->assertEquals('parent_field', $arguments['_parent']['type']); } } \ No newline at end of file From 659468ae3a47605d236bd726695a2bd65782cdfd Mon Sep 17 00:00:00 2001 From: esodin Date: Thu, 24 Jul 2014 17:36:45 +0300 Subject: [PATCH 313/447] Issue: Parent is missing in the fields list that causes RoutingMissingException on flushing - test --- .../DependencyInjection/FOSElasticaExtensionTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Tests/Functional/DependencyInjection/FOSElasticaExtensionTest.php b/Tests/Functional/DependencyInjection/FOSElasticaExtensionTest.php index a02c35e..06676ef 100644 --- a/Tests/Functional/DependencyInjection/FOSElasticaExtensionTest.php +++ b/Tests/Functional/DependencyInjection/FOSElasticaExtensionTest.php @@ -30,7 +30,8 @@ class FOSElasticaExtensionTest extends \PHPUnit_Framework_TestCase $persisterCallDefinition = $containerBuilder->getDefinition('fos_elastica.object_persister.test_index.child_field'); - $arguments = $persisterCallDefinition->getArguments()['index_3']; + $arguments = $persisterCallDefinition->getArguments(); + $arguments = $arguments['index_3']; $this->assertArrayHasKey('_parent', $arguments); $this->assertEquals('parent_field', $arguments['_parent']['type']); From 9befa90f4192701779181862fee5f7965af2b95d Mon Sep 17 00:00:00 2001 From: Pablo Date: Fri, 25 Jul 2014 17:59:24 +0200 Subject: [PATCH 314/447] Return repository in Manager Class MongoDB --- Doctrine/MongoDB/ElasticaToModelTransformer.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Doctrine/MongoDB/ElasticaToModelTransformer.php b/Doctrine/MongoDB/ElasticaToModelTransformer.php index 855a093..cea737f 100644 --- a/Doctrine/MongoDB/ElasticaToModelTransformer.php +++ b/Doctrine/MongoDB/ElasticaToModelTransformer.php @@ -22,6 +22,7 @@ class ElasticaToModelTransformer extends AbstractElasticaToModelTransformer { return $this->registry ->getManagerForClass($this->objectClass) + ->getRepository($this->objectClass) ->{$this->options['query_builder_method']}($this->objectClass) ->field($this->options['identifier'])->in($identifierValues) ->hydrate($hydrate) From 9a5b80e723f306e89f8d658d900b21276e010edf Mon Sep 17 00:00:00 2001 From: Lukasz Cybula Date: Thu, 31 Jul 2014 14:06:34 +0200 Subject: [PATCH 315/447] Ignore missing Doctrine results during hybridTransform() --- .../AbstractElasticaToModelTransformer.php | 10 ++- ...AbstractElasticaToModelTransformerTest.php | 66 +++++++++++++++++++ 2 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 Tests/Doctrine/AbstractElasticaToModelTransformerTest.php diff --git a/Doctrine/AbstractElasticaToModelTransformer.php b/Doctrine/AbstractElasticaToModelTransformer.php index 147067d..96f73bd 100755 --- a/Doctrine/AbstractElasticaToModelTransformer.php +++ b/Doctrine/AbstractElasticaToModelTransformer.php @@ -120,11 +120,17 @@ abstract class AbstractElasticaToModelTransformer implements ElasticaToModelTran public function hybridTransform(array $elasticaObjects) { + $indexedElasticaResults = array(); + foreach ($elasticaObjects as $elasticaObject) { + $indexedElasticaResults[$elasticaObject->getId()] = $elasticaObject; + } + $objects = $this->transform($elasticaObjects); $result = array(); - for ($i = 0; $i < count($elasticaObjects); $i++) { - $result[] = new HybridResult($elasticaObjects[$i], $objects[$i]); + foreach ($objects as $object) { + $id = $this->propertyAccessor->getValue($object, $this->options['identifier']); + $result[] = new HybridResult($indexedElasticaResults[$id], $object); } return $result; diff --git a/Tests/Doctrine/AbstractElasticaToModelTransformerTest.php b/Tests/Doctrine/AbstractElasticaToModelTransformerTest.php new file mode 100644 index 0000000..325171b --- /dev/null +++ b/Tests/Doctrine/AbstractElasticaToModelTransformerTest.php @@ -0,0 +1,66 @@ +getMock( + 'FOS\ElasticaBundle\Doctrine\ORM\ElasticaToModelTransformer', + array('findByIdentifiers'), + array($this->registry, $this->objectClass, array('ignore_missing' => true)) + ); + + $transformer->setPropertyAccessor(PropertyAccess::createPropertyAccessor()); + + $firstOrmResult = new \stdClass(); + $firstOrmResult->id = 1; + $secondOrmResult = new \stdClass(); + $secondOrmResult->id = 3; + $transformer->expects($this->once()) + ->method('findByIdentifiers') + ->with(array(1, 2, 3)) + ->willReturn(array($firstOrmResult, $secondOrmResult)); + + $firstElasticaResult = new Result(array('_id' => 1)); + $secondElasticaResult = new Result(array('_id' => 2)); + $thirdElasticaResult = new Result(array('_id' => 3)); + + $hybridResults = $transformer->hybridTransform(array($firstElasticaResult, $secondElasticaResult, $thirdElasticaResult)); + + $this->assertCount(2, $hybridResults); + $this->assertEquals($firstOrmResult, $hybridResults[0]->getTransformed()); + $this->assertEquals($firstElasticaResult, $hybridResults[0]->getResult()); + $this->assertEquals($secondOrmResult, $hybridResults[1]->getTransformed()); + $this->assertEquals($thirdElasticaResult, $hybridResults[1]->getResult()); + } + + protected function setUp() + { + if (!interface_exists('Doctrine\Common\Persistence\ManagerRegistry')) { + $this->markTestSkipped('Doctrine Common is not present'); + } + + $this->registry = $this->getMockBuilder('Doctrine\Common\Persistence\ManagerRegistry') + ->disableOriginalConstructor() + ->getMock(); + } +} From 9296534d306f6535e52e0d377fe1d5904f23a083 Mon Sep 17 00:00:00 2001 From: Luis Cordova Date: Wed, 6 Aug 2014 17:25:05 -0500 Subject: [PATCH 316/447] Update setup.md --- Resources/doc/setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/doc/setup.md b/Resources/doc/setup.md index 485f290..912c5d2 100644 --- a/Resources/doc/setup.md +++ b/Resources/doc/setup.md @@ -7,7 +7,7 @@ A) Install FOSElasticaBundle FOSElasticaBundle is installed using [Composer](https://getcomposer.org). ```bash -$ php composer.phar require friendsofsymfony/elastica-bundle "3.0.*@alpha" +$ php composer.phar require friendsofsymfony/elastica-bundle "~3.0.2" ``` ### Elasticsearch From c44f676224dbf532e14aecb05d381e3c26b9fee8 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 7 Aug 2014 09:25:09 +1000 Subject: [PATCH 317/447] Test mappings key being null still causes appropriate configuration changes --- DependencyInjection/Configuration.php | 4 ++-- Tests/Functional/ConfigurationManagerTest.php | 2 +- Tests/Functional/app/Basic/config.yml | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 874f51e..dd41b09 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -182,7 +182,7 @@ class Configuration implements ConfigurationInterface ->treatNullLike(array()) // BC - Renaming 'mappings' node to 'properties' ->beforeNormalization() - ->ifTrue(function($v) { return isset($v['mappings']); }) + ->ifTrue(function($v) { return array_key_exists('mappings', $v); }) ->then(function($v) { $v['properties'] = $v['mappings']; unset($v['mappings']); @@ -213,7 +213,7 @@ class Configuration implements ConfigurationInterface foreach ($v['dynamic_templates'] as $key => $type) { if (is_int($key)) { $dt[] = $type; - } else { + } else { $dt[][$key] = $type; } } diff --git a/Tests/Functional/ConfigurationManagerTest.php b/Tests/Functional/ConfigurationManagerTest.php index 6fdc1d7..7ef02c5 100644 --- a/Tests/Functional/ConfigurationManagerTest.php +++ b/Tests/Functional/ConfigurationManagerTest.php @@ -26,7 +26,7 @@ class ConfigurationManagerTest extends WebTestCase $index = $manager->getIndexConfiguration('index'); $this->assertEquals('index', $index->getName()); - $this->assertCount(2, $index->getTypes()); + $this->assertGreaterThanOrEqual(2, count($index->getTypes())); $this->assertInstanceOf('FOS\\ElasticaBundle\\Configuration\\TypeConfig', $index->getType('type')); $this->assertInstanceOf('FOS\\ElasticaBundle\\Configuration\\TypeConfig', $index->getType('parent')); } diff --git a/Tests/Functional/app/Basic/config.yml b/Tests/Functional/app/Basic/config.yml index 607e3cc..9feed34 100644 --- a/Tests/Functional/app/Basic/config.yml +++ b/Tests/Functional/app/Basic/config.yml @@ -83,3 +83,5 @@ fos_elastica: type: "parent" property: "parent" identifier: "id" + null_mappings: + mappings: ~ From f9eb6577d1556a6c071186a3750a8c56f7fd6001 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 7 Aug 2014 09:25:49 +1000 Subject: [PATCH 318/447] Add tests to cover no mappings for serializer enabled type --- Tests/Functional/SerializerTest.php | 7 +++++++ Tests/Functional/app/Serializer/config.yml | 8 ++++++++ 2 files changed, 15 insertions(+) diff --git a/Tests/Functional/SerializerTest.php b/Tests/Functional/SerializerTest.php index 3a3b8cb..81fbc8f 100644 --- a/Tests/Functional/SerializerTest.php +++ b/Tests/Functional/SerializerTest.php @@ -32,6 +32,13 @@ class SerializerTest extends WebTestCase $persister->replaceOne($object); } + public function testUnmappedType() + { + $client = $this->createClient(array('test_case' => 'Serializer')); + $resetter = $client->getContainer()->get('fos_elastica.resetter'); + $resetter->resetIndex('index'); + } + protected function setUp() { parent::setUp(); diff --git a/Tests/Functional/app/Serializer/config.yml b/Tests/Functional/app/Serializer/config.yml index ccd18f4..9bea4ba 100644 --- a/Tests/Functional/app/Serializer/config.yml +++ b/Tests/Functional/app/Serializer/config.yml @@ -40,3 +40,11 @@ fos_elastica: serializer: groups: ['search', 'Default'] version: 1.1 + unmapped: + persistence: + driver: orm + model: FOS\ElasticaBundle\Tests\Functional\TypeObj + serializer: + groups: ['search', 'Default'] + version: 1.1 + From dafe8abe0e2794d7bf13ff05eb5ef5bc030ad241 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 7 Aug 2014 09:32:30 +1000 Subject: [PATCH 319/447] Output ES version --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 034cd84..76a2969 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,7 @@ php: - 5.6 before_script: + - /usr/share/elasticsearch -v - sudo /usr/share/elasticsearch/bin/plugin -install elasticsearch/elasticsearch-mapper-attachments/2.0.0 - sudo service elasticsearch restart - echo "extension = mongo.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini From f5987a48b95d4dbd1e481878f0749cf3491bfa90 Mon Sep 17 00:00:00 2001 From: Josh Worden Date: Thu, 7 Aug 2014 16:33:14 -0500 Subject: [PATCH 320/447] BC Break: Restored noDeepMerging to Configuration When performNoDeepMerging is not used, Symfony environment-specific server configurations no longer work. --- DependencyInjection/Configuration.php | 1 + 1 file changed, 1 insertion(+) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 874f51e..df223a7 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -73,6 +73,7 @@ class Configuration implements ConfigurationInterface ->arrayNode('clients') ->useAttributeAsKey('id') ->prototype('array') + ->performNoDeepMerging() // BC - Renaming 'servers' node to 'connections' ->beforeNormalization() ->ifTrue(function($v) { return isset($v['servers']); }) From 20033709cf8ce84b169235de4e20bd888a6f8206 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 7 Aug 2014 09:36:23 +1000 Subject: [PATCH 321/447] Fix empty mappings for old ES versions --- .travis.yml | 2 +- Configuration/TypeConfig.php | 26 ++++++++++++++++++ DependencyInjection/FOSElasticaExtension.php | 6 ++-- Index/MappingBuilder.php | 29 +++++++++++++++----- Tests/Functional/MappingToElasticaTest.php | 10 +++++-- Tests/Functional/app/Basic/config.yml | 2 ++ 6 files changed, 62 insertions(+), 13 deletions(-) diff --git a/.travis.yml b/.travis.yml index 76a2969..8ccaa8d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ php: - 5.6 before_script: - - /usr/share/elasticsearch -v + - /usr/share/elasticsearch/bin/elasticsearch -v - sudo /usr/share/elasticsearch/bin/plugin -install elasticsearch/elasticsearch-mapper-attachments/2.0.0 - sudo service elasticsearch restart - echo "extension = mongo.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini diff --git a/Configuration/TypeConfig.php b/Configuration/TypeConfig.php index 5d3f084..3f1c939 100644 --- a/Configuration/TypeConfig.php +++ b/Configuration/TypeConfig.php @@ -35,6 +35,14 @@ class TypeConfig $this->name = $name; } + /** + * @return string|null + */ + public function getIndexAnalyzer() + { + return $this->getConfig('index_analyzer'); + } + /** * @return array */ @@ -43,6 +51,9 @@ class TypeConfig return $this->mapping; } + /** + * @return string|null + */ public function getModel() { return isset($this->config['persistence']['model']) ? @@ -57,4 +68,19 @@ class TypeConfig { return $this->name; } + + /** + * @return string|null + */ + public function getSearchAnalyzer() + { + return $this->getConfig('search_analyzer'); + } + + private function getConfig($key) + { + return isset($this->config[$key]) ? + $this->config[$key] : + null; + } } diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index e523bf4..aefa7fe 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -220,9 +220,7 @@ class FOSElasticaExtension extends Extension foreach (array( 'dynamic_templates', - 'index_analyzer', 'properties', - 'search_analyzer', '_all', '_boost', '_id', @@ -239,7 +237,9 @@ class FOSElasticaExtension extends Extension foreach (array( 'persistence', - 'serializer' + 'serializer', + 'index_analyzer', + 'search_analyzer', ) as $field) { $typeConfig['config'][$field] = array_key_exists($field, $type) ? $type[$field] : diff --git a/Index/MappingBuilder.php b/Index/MappingBuilder.php index fc67420..21ae871 100644 --- a/Index/MappingBuilder.php +++ b/Index/MappingBuilder.php @@ -18,7 +18,7 @@ class MappingBuilder { /** * Skip adding default information to certain fields. - * + * * @var array */ private $skipTypes = array('completion'); @@ -36,10 +36,11 @@ class MappingBuilder $typeMappings[$typeConfig->getName()] = $this->buildTypeMapping($typeConfig); } - $mapping = array( - 'mappings' => $typeMappings, - // 'warmers' => $indexConfig->getWarmers(), - ); + $mapping = array(); + if ($typeMappings) { + $mapping['mappings'] = $typeMappings; + } + // 'warmers' => $indexConfig->getWarmers(), $settings = $indexConfig->getSettings(); if ($settings) { @@ -61,22 +62,36 @@ class MappingBuilder // 'date_detection' => true, // 'dynamic_date_formats' => array() // 'dynamic_templates' => $typeConfig->getDynamicTemplates(), - // 'index_analyzer' => $typeConfig->getIndexAnalyzer(), // 'numeric_detection' => false, // 'properties' => array(), - // 'search_analyzer' => $typeConfig->getSearchAnalyzer(), )); + if ($typeConfig->getIndexAnalyzer()) { + $mapping['index_analyzer'] = $typeConfig->getIndexAnalyzer(); + } + + if ($typeConfig->getSearchAnalyzer()) { + $mapping['search_analyzer'] = $typeConfig->getSearchAnalyzer(); + } + if (isset($mapping['dynamic_templates']) and empty($mapping['dynamic_templates'])) { unset($mapping['dynamic_templates']); } $this->fixProperties($mapping['properties']); + if (!$mapping['properties']) { + unset($mapping['properties']); + } if ($typeConfig->getModel()) { $mapping['_meta']['model'] = $typeConfig->getModel(); } + if (!$mapping) { + // Empty mapping, we want it encoded as a {} instead of a [] + $mapping = new \stdClass; + } + return $mapping; } diff --git a/Tests/Functional/MappingToElasticaTest.php b/Tests/Functional/MappingToElasticaTest.php index 2474a1c..f42df61 100644 --- a/Tests/Functional/MappingToElasticaTest.php +++ b/Tests/Functional/MappingToElasticaTest.php @@ -31,6 +31,12 @@ class MappingToElasticaTest extends WebTestCase $this->assertArrayHasKey('store', $mapping['type']['properties']['field1']); $this->assertTrue($mapping['type']['properties']['field1']['store']); $this->assertArrayNotHasKey('store', $mapping['type']['properties']['field2']); + + $parent = $this->getType($client, 'parent'); + $mapping = $parent->getMapping(); + + $this->assertEquals('my_analyzer', $mapping['parent']['index_analyzer']); + $this->assertEquals('whitespace', $mapping['parent']['search_analyzer']); } public function testResetType() @@ -101,9 +107,9 @@ class MappingToElasticaTest extends WebTestCase * @param Client $client * @return \Elastica\Type */ - private function getType(Client $client) + private function getType(Client $client, $type = 'type') { - return $client->getContainer()->get('fos_elastica.index.index.type'); + return $client->getContainer()->get('fos_elastica.index.index.' . $type); } protected function setUp() diff --git a/Tests/Functional/app/Basic/config.yml b/Tests/Functional/app/Basic/config.yml index 9feed34..3c3d369 100644 --- a/Tests/Functional/app/Basic/config.yml +++ b/Tests/Functional/app/Basic/config.yml @@ -42,6 +42,8 @@ fos_elastica: mappings: field1: ~ field2: ~ + search_analyzer: whitespace + index_analyzer: my_analyzer type: search_analyzer: my_analyzer dynamic_templates: From 27385046cae6a560ca778b0f682fde7cb395494c Mon Sep 17 00:00:00 2001 From: Oleg Andreyev Date: Fri, 8 Aug 2014 09:29:30 +0300 Subject: [PATCH 322/447] changing AliasProcessor::setRootName, so to use "Y-m-d-His" instead of random string --- Index/AliasProcessor.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Index/AliasProcessor.php b/Index/AliasProcessor.php index 93877cd..6b7da75 100644 --- a/Index/AliasProcessor.php +++ b/Index/AliasProcessor.php @@ -26,7 +26,12 @@ class AliasProcessor */ public function setRootName(IndexConfig $indexConfig, Index $index) { - $index->overrideName(sprintf('%s_%s', $indexConfig->getElasticSearchName(), uniqid())); + $index->overrideName( + sprintf('%s_%s', + $indexConfig->getElasticSearchName(), + date('Y-m-d-His') + ) + ); } /** @@ -116,7 +121,9 @@ class AliasProcessor /** * Returns array of indexes which are mapped to given alias * + * @param Client $client * @param string $aliasName Alias name + * * @return array */ private function getAliasedIndexes(Client $client, $aliasName) From 33ee047f83175ada2ef471db8ce5f8e5ab4a6050 Mon Sep 17 00:00:00 2001 From: Luis Cordova Date: Sat, 9 Aug 2014 07:50:00 -0500 Subject: [PATCH 323/447] fix dependency on elastic extension i had a weird error in which just installing the bundle with "friendsofsymfony/elastica-bundle": "~3.0.2", game me a version back even before it had a composer! :blush: i checked and found out composer gets really confused or glitchy with packages not following semver. In any case 1.3.0 is out, and i remove the 4th digit which i think composer ignores totally or gets confused about. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index a1734dd..2fd9d3c 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ "symfony/console": "~2.1", "symfony/form": "~2.1", "symfony/property-access": "~2.2", - "ruflin/elastica": ">=0.90.10.0, <1.3-dev", + "ruflin/elastica": ">=0.90.10.0, <1.4-dev", "psr/log": "~1.0" }, "require-dev":{ From 22a2a223cc6a7b1915054ee9fedf2f46b1a801c1 Mon Sep 17 00:00:00 2001 From: Floran Brutel Date: Sun, 17 Aug 2014 12:16:15 +0200 Subject: [PATCH 324/447] Update version in setup.md Use "~3.0" instead of "~3.0.2" to get version 3.0.3 and future minor versions --- Resources/doc/setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/doc/setup.md b/Resources/doc/setup.md index 912c5d2..6a1c2ae 100644 --- a/Resources/doc/setup.md +++ b/Resources/doc/setup.md @@ -7,7 +7,7 @@ A) Install FOSElasticaBundle FOSElasticaBundle is installed using [Composer](https://getcomposer.org). ```bash -$ php composer.phar require friendsofsymfony/elastica-bundle "~3.0.2" +$ php composer.phar require friendsofsymfony/elastica-bundle "~3.0" ``` ### Elasticsearch From 69c2214bc5c9b910fb0021bd69fda8e6ae9e3503 Mon Sep 17 00:00:00 2001 From: Floran Brutel Date: Mon, 18 Aug 2014 13:30:45 +0200 Subject: [PATCH 325/447] Use the new Search annotation Use "FOS\ElasticaBundle\Annotation\Search" instead of "FOS\ElasticaBundle\Configuration\Search" in the repository manager. Update the cookbook --- Manager/RepositoryManager.php | 2 +- Resources/doc/cookbook/custom-repositories.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Manager/RepositoryManager.php b/Manager/RepositoryManager.php index 3cf8e96..be07b42 100644 --- a/Manager/RepositoryManager.php +++ b/Manager/RepositoryManager.php @@ -59,7 +59,7 @@ class RepositoryManager implements RepositoryManagerInterface } $refClass = new \ReflectionClass($entityName); - $annotation = $this->reader->getClassAnnotation($refClass, 'FOS\\ElasticaBundle\\Configuration\\Search'); + $annotation = $this->reader->getClassAnnotation($refClass, 'FOS\\ElasticaBundle\\Annotation\\Search'); if ($annotation) { $this->entities[$entityName]['repositoryName'] = $annotation->repositoryClass; diff --git a/Resources/doc/cookbook/custom-repositories.md b/Resources/doc/cookbook/custom-repositories.md index 47dc3fe..9eff5f7 100644 --- a/Resources/doc/cookbook/custom-repositories.md +++ b/Resources/doc/cookbook/custom-repositories.md @@ -58,7 +58,7 @@ Alternatively you can specify the custom repository using an annotation in the e namespace Application\UserBundle\Entity; -use FOS\ElasticaBundle\Configuration\Search; +use FOS\ElasticaBundle\Annotation\Search; /** * @Search(repositoryClass="Acme\ElasticaBundle\SearchRepository\UserRepository") From 0425379420ff69e9633d8579dea7a2200e7e547b Mon Sep 17 00:00:00 2001 From: Patrick McAndrew Date: Mon, 11 Aug 2014 17:17:38 +0100 Subject: [PATCH 326/447] add back fos_elastica.client tag that was removed in e78950ddb7b3e6c3ae402a042276dc81c4ee0dac --- DependencyInjection/FOSElasticaExtension.php | 1 + 1 file changed, 1 insertion(+) diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index aefa7fe..cdf109b 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -108,6 +108,7 @@ class FOSElasticaExtension extends Extension if (false !== $logger) { $clientDef->addMethodCall('setLogger', array(new Reference($logger))); } + $clientDef->addTag('fos_elastica.client'); $container->setDefinition($clientId, $clientDef); From 598a59927ef9ed318a4ab9cfbc9672dea4947894 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 21 Aug 2014 21:48:19 +1000 Subject: [PATCH 327/447] Update travis testing --- .scrutinizer.yml | 5 +++++ .travis.yml | 19 ++++++++++++++++--- composer.json | 1 - 3 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 .scrutinizer.yml diff --git a/.scrutinizer.yml b/.scrutinizer.yml new file mode 100644 index 0000000..e2cb043 --- /dev/null +++ b/.scrutinizer.yml @@ -0,0 +1,5 @@ +imports: + - php + +tools: + external_code_coverage: true diff --git a/.travis.yml b/.travis.yml index 8ccaa8d..02f3ab8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,18 +2,31 @@ language: php php: - 5.3 - - 5.4 - 5.5 - 5.6 +matrix: + include: + - php: 5.5 + env: SYMFONY_VERSION='2.3.*' + - php: 5.5 + env: SYMFONY_VERSION='2.5.*' + - php: 5.5 + env: SYMFONY_VERSION='dev-master' + before_script: - /usr/share/elasticsearch/bin/elasticsearch -v - sudo /usr/share/elasticsearch/bin/plugin -install elasticsearch/elasticsearch-mapper-attachments/2.0.0 - sudo service elasticsearch restart - - echo "extension = mongo.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini + - sh -c 'if [ "$TRAVIS_PHP_VERSION" != "hhvm" ]; then echo "extension = mongo.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi;' + - sh -c 'if [ "$SYMFONY_VERSION" != "" ]; then composer require --dev --no-update symfony/symfony=$SYMFONY_VERSION; fi;' - composer install --dev --prefer-source -script: vendor/bin/phpunit +script: vendor/bin/phpunit --coverage-clover=coverage.clover services: - elasticsearch + +after_script: + - wget https://scrutinizer-ci.com/ocular.phar + - php ocular.phar code-coverage:upload --format=php-clover coverage.clover diff --git a/composer.json b/composer.json index 2fd9d3c..bb30928 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,6 @@ "require-dev":{ "doctrine/orm": "~2.2", "doctrine/doctrine-bundle": "~1.2@beta", - "doctrine/mongodb-odm": "1.0.*@beta", "jms/serializer-bundle": "@stable", "phpunit/phpunit": "~4.1", "propel/propel1": "1.6.*", From 6bea3c2154176bc68fc80cd6a9d8b0b7e9272a67 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 21 Aug 2014 23:23:20 +1000 Subject: [PATCH 328/447] Add code quality badge --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 631951a..01afa6d 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ Symfony2. Features include: > **Note** Propel support is limited and contributions fixing issues are welcome! [![Build Status](https://secure.travis-ci.org/FriendsOfSymfony/FOSElasticaBundle.png?branch=master)](http://travis-ci.org/FriendsOfSymfony/FOSElasticaBundle) [![Total Downloads](https://poser.pugx.org/FriendsOfSymfony/elastica-bundle/downloads.png)](https://packagist.org/packages/FriendsOfSymfony/elastica-bundle) [![Latest Stable Version](https://poser.pugx.org/FriendsOfSymfony/elastica-bundle/v/stable.png)](https://packagist.org/packages/FriendsOfSymfony/elastica-bundle) [![Latest Unstable Version](https://poser.pugx.org/friendsofsymfony/elastica-bundle/v/unstable.svg)](https://packagist.org/packages/friendsofsymfony/elastica-bundle) +[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/FriendsOfSymfony/FOSElasticaBundle/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/FriendsOfSymfony/FOSElasticaBundle/?branch=master) Documentation ------------- From 2958833012b977ab6f6a831e03bdc28c8c5d6279 Mon Sep 17 00:00:00 2001 From: Patrick McAndrew Date: Thu, 28 Aug 2014 17:59:58 +0100 Subject: [PATCH 329/447] Ability to delete an index if expecting an alias --- Command/ResetCommand.php | 4 +++- Exception/AliasIsIndexException.php | 12 ++++++++++++ Index/AliasProcessor.php | 29 +++++++++++++++++++++++++++-- Index/Resetter.php | 9 +++++---- 4 files changed, 47 insertions(+), 7 deletions(-) create mode 100644 Exception/AliasIsIndexException.php diff --git a/Command/ResetCommand.php b/Command/ResetCommand.php index 06cfe48..ed14e6c 100755 --- a/Command/ResetCommand.php +++ b/Command/ResetCommand.php @@ -33,6 +33,7 @@ class ResetCommand extends ContainerAwareCommand ->setName('fos:elastica:reset') ->addOption('index', null, InputOption::VALUE_OPTIONAL, 'The index to reset') ->addOption('type', null, InputOption::VALUE_OPTIONAL, 'The type to reset') + ->addOption('force', null, InputOption::VALUE_NONE, 'Force index deletion if same name as alias') ->setDescription('Reset search indexes') ; } @@ -53,6 +54,7 @@ class ResetCommand extends ContainerAwareCommand { $index = $input->getOption('index'); $type = $input->getOption('type'); + $force = (true == $input->getOption('force')); if (null === $index && null !== $type) { throw new \InvalidArgumentException('Cannot specify type option without an index.'); @@ -69,7 +71,7 @@ class ResetCommand extends ContainerAwareCommand foreach ($indexes as $index) { $output->writeln(sprintf('Resetting %s', $index)); - $this->resetter->resetIndex($index); + $this->resetter->resetIndex($index, false, $force); } } } diff --git a/Exception/AliasIsIndexException.php b/Exception/AliasIsIndexException.php new file mode 100644 index 0000000..87f546b --- /dev/null +++ b/Exception/AliasIsIndexException.php @@ -0,0 +1,12 @@ +getClient(); @@ -45,7 +47,16 @@ class AliasProcessor $oldIndexName = false; $newIndexName = $index->getName(); - $aliasedIndexes = $this->getAliasedIndexes($client, $aliasName); + $aliasedIndexes = array(); + try { + $aliasedIndexes = $this->getAliasedIndexes($client, $aliasName); + } catch(AliasIsIndexException $e) { + if ($force) { + $this->deleteIndex($client, $aliasName); + } else { + throw new \RuntimeException($e->getMessage()); + } + } if (count($aliasedIndexes) > 1) { throw new \RuntimeException( @@ -125,6 +136,9 @@ class AliasProcessor $aliasedIndexes = array(); foreach ($aliasesInfo as $indexName => $indexInfo) { + if ($indexName == $aliasName) { + throw new AliasIsIndexException($indexName); + } $aliases = array_keys($indexInfo['aliases']); if (in_array($aliasName, $aliases)) { $aliasedIndexes[] = $indexName; @@ -133,4 +147,15 @@ class AliasProcessor return $aliasedIndexes; } + + /** + * Delete an index + * + * @param string $indexName Index name to delete + */ + private function deleteIndex($client, $indexName) + { + $path = sprintf("%s", $indexName); + $client->request($path, \Elastica\Request::DELETE); + } } diff --git a/Index/Resetter.php b/Index/Resetter.php index 3f07fa1..c93ae2d 100644 --- a/Index/Resetter.php +++ b/Index/Resetter.php @@ -45,10 +45,10 @@ class Resetter /** * Deletes and recreates all indexes */ - public function resetAllIndexes($populating = false) + public function resetAllIndexes($populating = false, $force = false) { foreach ($this->configManager->getIndexNames() as $name) { - $this->resetIndex($name, $populating); + $this->resetIndex($name, $populating, $force); } } @@ -58,9 +58,10 @@ class Resetter * * @param string $indexName * @param bool $populating + * @param bool $force If index exists with same name as alias, remove it * @throws \InvalidArgumentException if no index exists for the given name */ - public function resetIndex($indexName, $populating = false) + public function resetIndex($indexName, $populating = false, $force = false) { $indexConfig = $this->configManager->getIndexConfiguration($indexName); $index = $this->indexManager->getIndex($indexName); @@ -73,7 +74,7 @@ class Resetter $index->create($mapping, true); if (!$populating and $indexConfig->isUseAlias()) { - $this->aliasProcessor->switchIndexAlias($indexConfig, $index); + $this->aliasProcessor->switchIndexAlias($indexConfig, $index, $force); } } From 76dcd2f62e0da9188011002db62ce692f0052a16 Mon Sep 17 00:00:00 2001 From: Patrick McAndrew Date: Fri, 29 Aug 2014 15:52:46 +0100 Subject: [PATCH 330/447] fix warning if no aliases PHP Warning: array_keys() expects parameter 1 to be array, AliasProcessor.php on line 128 --- Index/AliasProcessor.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Index/AliasProcessor.php b/Index/AliasProcessor.php index 93877cd..a900b33 100644 --- a/Index/AliasProcessor.php +++ b/Index/AliasProcessor.php @@ -125,9 +125,11 @@ class AliasProcessor $aliasedIndexes = array(); foreach ($aliasesInfo as $indexName => $indexInfo) { - $aliases = array_keys($indexInfo['aliases']); - if (in_array($aliasName, $aliases)) { - $aliasedIndexes[] = $indexName; + if (isset($indexInfo['aliases'])) { + $aliases = array_keys($indexInfo['aliases']); + if (in_array($aliasName, $aliases)) { + $aliasedIndexes[] = $indexName; + } } } From c4210a5c6dbab548342765936b8079ff4840ba13 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 4 Sep 2014 09:37:27 +1000 Subject: [PATCH 331/447] Fix previous merge --- Index/AliasProcessor.php | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/Index/AliasProcessor.php b/Index/AliasProcessor.php index b38b5e3..29cfdc5 100644 --- a/Index/AliasProcessor.php +++ b/Index/AliasProcessor.php @@ -11,10 +11,10 @@ namespace FOS\ElasticaBundle\Index; +use Elastica\Client; use Elastica\Exception\ExceptionInterface; use Elastica\Request; use FOS\ElasticaBundle\Configuration\IndexConfig; -use FOS\ElasticaBundle\Elastica\Client; use FOS\ElasticaBundle\Elastica\Index; use FOS\ElasticaBundle\Exception\AliasIsIndexException; @@ -54,13 +54,12 @@ class AliasProcessor try { $aliasedIndexes = $this->getAliasedIndexes($client, $aliasName); } catch(AliasIsIndexException $e) { - if ($force) { - $this->deleteIndex($client, $aliasName); - - return; + if (!$force) { + throw $e; } - throw $e; + $this->deleteIndex($client, $aliasName); + $aliasedIndexes = array(); } if (count($aliasedIndexes) > 1) { @@ -75,7 +74,7 @@ class AliasProcessor } $aliasUpdateRequest = array('actions' => array()); - if (count($aliasedIndexes) == 1) { + if (count($aliasedIndexes) === 1) { // if the alias is set - add an action to remove it $oldIndexName = $aliasedIndexes[0]; $aliasUpdateRequest['actions'][] = array( @@ -135,7 +134,7 @@ class AliasProcessor * @param Client $client * @param string $aliasName Alias name * @return array - * @throws \FOS\ElasticaBundle\Exception\AliasIsIndexException + * @throws AliasIsIndexException */ private function getAliasedIndexes(Client $client, $aliasName) { @@ -146,11 +145,13 @@ class AliasProcessor if ($indexName === $aliasName) { throw new AliasIsIndexException($indexName); } - if (isset($indexInfo['aliases'])) { - $aliases = array_keys($indexInfo['aliases']); - if (in_array($aliasName, $aliases)) { - $aliasedIndexes[] = $indexName; - } + if (!isset($indexInfo['aliases'])) { + continue; + } + + $aliases = array_keys($indexInfo['aliases']); + if (in_array($aliasName, $aliases)) { + $aliasedIndexes[] = $indexName; } } From 1d5fe44ca4e8a70359dc108f2fd364cf30d93990 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Sun, 24 Aug 2014 19:50:56 +1000 Subject: [PATCH 332/447] Fix CS from scrutiniser-ci --- Configuration/TypeConfig.php | 3 +++ DependencyInjection/Configuration.php | 2 +- DependencyInjection/FOSElasticaExtension.php | 4 ++-- Doctrine/Listener.php | 19 +++++++++------- Doctrine/ORM/Provider.php | 1 - Elastica/Index.php | 4 +++- Index/Resetter.php | 4 +--- Manager/RepositoryManager.php | 3 +++ Paginator/RawPaginatorAdapter.php | 4 ++-- Persister/ObjectPersister.php | 1 - Persister/ObjectSerializerPersister.php | 3 +++ Propel/ElasticaToModelTransformer.php | 1 + Repository.php | 22 +++++++++++++++++++ Tests/Doctrine/AbstractListenerTest.php | 20 +++++++++++++++++ Tests/FOSElasticaBundleTest.php | 1 - .../ObjectSerializerPersisterTest.php | 2 -- ...asticaToModelTransformerCollectionTest.php | 3 +++ 17 files changed, 75 insertions(+), 22 deletions(-) diff --git a/Configuration/TypeConfig.php b/Configuration/TypeConfig.php index 3f1c939..fc9041d 100644 --- a/Configuration/TypeConfig.php +++ b/Configuration/TypeConfig.php @@ -77,6 +77,9 @@ class TypeConfig return $this->getConfig('search_analyzer'); } + /** + * @param string $key + */ private function getConfig($key) { return isset($this->config[$key]) ? diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 552f61b..3c5d18c 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -30,7 +30,7 @@ class Configuration implements ConfigurationInterface /** * Generates the configuration tree. * - * @return \Symfony\Component\Config\Definition\NodeInterface + * @return TreeBuilder */ public function getConfigTreeBuilder() { diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index cdf109b..804be44 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -82,7 +82,7 @@ class FOSElasticaExtension extends Extension /** * @param array $config * @param ContainerBuilder $container - * @return Configuration|null|\Symfony\Component\Config\Definition\ConfigurationInterface + * @return Configuration */ public function getConfiguration(array $config, ContainerBuilder $container) { @@ -523,7 +523,7 @@ class FOSElasticaExtension extends Extension * * @param array $typeConfig * @param ContainerBuilder $container - * @param $elasticaToModelId + * @param string $elasticaToModelId * @param Reference $typeRef * @param string $indexName * @param string $typeName diff --git a/Doctrine/Listener.php b/Doctrine/Listener.php index 73a271d..bd8b2c0 100644 --- a/Doctrine/Listener.php +++ b/Doctrine/Listener.php @@ -174,27 +174,30 @@ class Listener implements EventSubscriber } /** - * Iterate through scheduled actions before flushing to emulate 2.x behavior. Note that the ElasticSearch index - * will fall out of sync with the source data in the event of a crash during flush. + * Iterate through scheduled actions before flushing to emulate 2.x behavior. + * Note that the ElasticSearch index will fall out of sync with the source + * data in the event of a crash during flush. + * + * This method is only called in legacy configurations of the listener. */ - public function preFlush(EventArgs $eventArgs) + public function preFlush() { $this->persistScheduled(); } /** - * Iterating through scheduled actions *after* flushing ensures that the ElasticSearch index will be affected - * only if the query is successful + * Iterating through scheduled actions *after* flushing ensures that the + * ElasticSearch index will be affected only if the query is successful. */ - public function postFlush(EventArgs $eventArgs) + public function postFlush() { $this->persistScheduled(); } /** * Record the specified identifier to delete. Do not need to entire object. - * @param mixed $object - * @return mixed + * + * @param object $object */ protected function scheduleForDeletion($object) { diff --git a/Doctrine/ORM/Provider.php b/Doctrine/ORM/Provider.php index dfd6700..7e2ac12 100644 --- a/Doctrine/ORM/Provider.php +++ b/Doctrine/ORM/Provider.php @@ -3,7 +3,6 @@ namespace FOS\ElasticaBundle\Doctrine\ORM; use Doctrine\ORM\QueryBuilder; -use Elastica\Exception\Bulk\ResponseException as BulkResponseException; use FOS\ElasticaBundle\Doctrine\AbstractProvider; use FOS\ElasticaBundle\Exception\InvalidArgumentTypeException; diff --git a/Elastica/Index.php b/Elastica/Index.php index bf37c51..49c656e 100644 --- a/Elastica/Index.php +++ b/Elastica/Index.php @@ -3,7 +3,6 @@ namespace FOS\ElasticaBundle\Elastica; use Elastica\Index as BaseIndex; -use Elastica\Type; /** * Overridden Elastica Index class that provides dynamic index name changes. @@ -32,6 +31,9 @@ class Index extends BaseIndex return $this->originalName ?: $this->_name; } + /** + * @param string $type + */ public function getType($type) { if (isset($this->typeCache[$type])) { diff --git a/Index/Resetter.php b/Index/Resetter.php index c93ae2d..9b65a8f 100644 --- a/Index/Resetter.php +++ b/Index/Resetter.php @@ -5,9 +5,7 @@ namespace FOS\ElasticaBundle\Index; use Elastica\Index; use Elastica\Exception\ResponseException; use Elastica\Type\Mapping; -use FOS\ElasticaBundle\Configuration\IndexConfig; use FOS\ElasticaBundle\Configuration\ConfigManager; -use FOS\ElasticaBundle\Elastica\Client; /** * Deletes and recreates indexes @@ -110,7 +108,7 @@ class Resetter /** * A command run when a population has finished. * - * @param $indexName + * @param string $indexName */ public function postPopulate($indexName) { diff --git a/Manager/RepositoryManager.php b/Manager/RepositoryManager.php index be07b42..7697b58 100644 --- a/Manager/RepositoryManager.php +++ b/Manager/RepositoryManager.php @@ -69,6 +69,9 @@ class RepositoryManager implements RepositoryManagerInterface return 'FOS\ElasticaBundle\Repository'; } + /** + * @param string $entityName + */ private function createRepository($entityName) { if (!class_exists($repositoryName = $this->getRepositoryName($entityName))) { diff --git a/Paginator/RawPaginatorAdapter.php b/Paginator/RawPaginatorAdapter.php index 9136bc0..f05205a 100644 --- a/Paginator/RawPaginatorAdapter.php +++ b/Paginator/RawPaginatorAdapter.php @@ -54,8 +54,8 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface /** * Returns the paginated results. * - * @param $offset - * @param $itemCountPerPage + * @param integer $offset + * @param integer $itemCountPerPage * @throws \InvalidArgumentException * @return ResultSet */ diff --git a/Persister/ObjectPersister.php b/Persister/ObjectPersister.php index 9604f7e..0fe40c3 100644 --- a/Persister/ObjectPersister.php +++ b/Persister/ObjectPersister.php @@ -4,7 +4,6 @@ namespace FOS\ElasticaBundle\Persister; use Psr\Log\LoggerInterface; use Elastica\Exception\BulkException; -use Elastica\Exception\NotFoundException; use FOS\ElasticaBundle\Transformer\ModelToElasticaTransformerInterface; use Elastica\Type; use Elastica\Document; diff --git a/Persister/ObjectSerializerPersister.php b/Persister/ObjectSerializerPersister.php index 1a15656..3e33f8d 100644 --- a/Persister/ObjectSerializerPersister.php +++ b/Persister/ObjectSerializerPersister.php @@ -17,6 +17,9 @@ class ObjectSerializerPersister extends ObjectPersister { protected $serializer; + /** + * @param string $objectClass + */ public function __construct(Type $type, ModelToElasticaTransformerInterface $transformer, $objectClass, $serializer) { parent::__construct($type, $transformer, $objectClass, array()); diff --git a/Propel/ElasticaToModelTransformer.php b/Propel/ElasticaToModelTransformer.php index af5f8ab..e3602e5 100644 --- a/Propel/ElasticaToModelTransformer.php +++ b/Propel/ElasticaToModelTransformer.php @@ -170,6 +170,7 @@ class ElasticaToModelTransformer implements ElasticaToModelTransformerInterface /** * @see https://github.com/doctrine/common/blob/master/lib/Doctrine/Common/Util/Inflector.php + * @param string $str */ private function camelize($str) { diff --git a/Repository.php b/Repository.php index 70b2a21..fcc2784 100644 --- a/Repository.php +++ b/Repository.php @@ -19,21 +19,43 @@ class Repository $this->finder = $finder; } + /** + * @param mixed $query + * @param integer $limit + * @param array $options + * @return array + */ public function find($query, $limit = null, $options = array()) { return $this->finder->find($query, $limit, $options); } + /** + * @param mixed $query + * @param integer $limit + * @param array $options + * @return mixed + */ public function findHybrid($query, $limit = null, $options = array()) { return $this->finder->findHybrid($query, $limit, $options); } + /** + * @param mixed $query + * @param array $options + * @return \Pagerfanta\Pagerfanta + */ public function findPaginated($query, $options = array()) { return $this->finder->findPaginated($query, $options); } + /** + * @param string $query + * @param array $options + * @return Paginator\PaginatorAdapterInterface + */ public function createPaginatorAdapter($query, $options = array()) { return $this->finder->createPaginatorAdapter($query, $options); diff --git a/Tests/Doctrine/AbstractListenerTest.php b/Tests/Doctrine/AbstractListenerTest.php index 1f238d6..7242255 100644 --- a/Tests/Doctrine/AbstractListenerTest.php +++ b/Tests/Doctrine/AbstractListenerTest.php @@ -173,8 +173,14 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase abstract protected function getListenerClass(); + /** + * @return string + */ abstract protected function getObjectManagerClass(); + /** + * @return string + */ abstract protected function getClassMetadataClass(); private function createLifecycleEventArgs() @@ -205,6 +211,11 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase ->getMock(); } + /** + * @param Listener\Entity $object + * @param string $indexName + * @param string $typeName + */ private function getMockPersister($object, $indexName, $typeName) { $mock = $this->getMockBuilder('FOS\ElasticaBundle\Persister\ObjectPersister') @@ -235,6 +246,12 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase return $mock; } + /** + * @param string $indexName + * @param string $typeName + * @param Listener\Entity $object + * @param boolean $return + */ private function getMockIndexable($indexName, $typeName, $object, $return = null) { $mock = $this->getMock('FOS\ElasticaBundle\Provider\IndexableInterface'); @@ -256,6 +273,9 @@ class Entity { private $id; + /** + * @param integer $id + */ public function __construct($id) { $this->id = $id; diff --git a/Tests/FOSElasticaBundleTest.php b/Tests/FOSElasticaBundleTest.php index 3828e8b..4290e1d 100644 --- a/Tests/FOSElasticaBundleTest.php +++ b/Tests/FOSElasticaBundleTest.php @@ -3,7 +3,6 @@ namespace FOS\ElasticaBundle\Tests\Resetter; use FOS\ElasticaBundle\FOSElasticaBundle; -use Symfony\Component\DependencyInjection\Compiler\PassConfig; class FOSElasticaBundleTest extends \PHPUnit_Framework_TestCase { diff --git a/Tests/Persister/ObjectSerializerPersisterTest.php b/Tests/Persister/ObjectSerializerPersisterTest.php index fe15c0c..914b5dd 100644 --- a/Tests/Persister/ObjectSerializerPersisterTest.php +++ b/Tests/Persister/ObjectSerializerPersisterTest.php @@ -2,9 +2,7 @@ namespace FOS\ElasticaBundle\Tests\ObjectSerializerPersister; -use FOS\ElasticaBundle\Persister\ObjectPersister; use FOS\ElasticaBundle\Persister\ObjectSerializerPersister; -use FOS\ElasticaBundle\Transformer\ModelToElasticaAutoTransformer; use FOS\ElasticaBundle\Transformer\ModelToElasticaIdentifierTransformer; use Symfony\Component\PropertyAccess\PropertyAccess; diff --git a/Tests/Transformer/ElasticaToModelTransformerCollectionTest.php b/Tests/Transformer/ElasticaToModelTransformerCollectionTest.php index eb4d8e4..c3fc323 100644 --- a/Tests/Transformer/ElasticaToModelTransformerCollectionTest.php +++ b/Tests/Transformer/ElasticaToModelTransformerCollectionTest.php @@ -157,6 +157,9 @@ class POPO public $id; public $data; + /** + * @param integer $id + */ public function __construct($id, $data) { $this->data = $data; From 428a1014ca244c5d864252f44ce336b9a0774452 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Sun, 24 Aug 2014 19:53:24 +1000 Subject: [PATCH 333/447] Move query logging into its own method --- Elastica/Client.php | 49 +++++++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/Elastica/Client.php b/Elastica/Client.php index 1131ba5..372b395 100644 --- a/Elastica/Client.php +++ b/Elastica/Client.php @@ -30,7 +30,11 @@ class Client extends BaseClient private $stopwatch; /** - * {@inheritdoc} + * @param string $path + * @param string $method + * @param array $data + * @param array $query + * @return \Elastica\Response */ public function request($path, $method = Request::GET, $data = array(), array $query = array()) { @@ -41,20 +45,7 @@ class Client extends BaseClient $start = microtime(true); $response = parent::request($path, $method, $data, $query); - if ($this->_logger and $this->_logger instanceof ElasticaLogger) { - $time = microtime(true) - $start; - - $connection = $this->getLastRequest()->getConnection(); - - $connection_array = array( - 'host' => $connection->getHost(), - 'port' => $connection->getPort(), - 'transport' => $connection->getTransport(), - 'headers' => $connection->hasConfig('headers') ? $connection->getConfig('headers') : array(), - ); - - $this->_logger->logQuery($path, $method, $data, $time, $connection_array, $query); - } + $this->logQuery($path, $method, $data, $query, $start); if ($this->stopwatch) { $this->stopwatch->stop('es_request'); @@ -81,4 +72,32 @@ class Client extends BaseClient { $this->stopwatch = $stopwatch; } + + /** + * Log the query if we have an instance of ElasticaLogger. + * + * @param string $path + * @param string $method + * @param array $data + * @param array $query + * @param int $start + */ + private function logQuery($path, $method, $data, array $query, $start) + { + if (!$this->_logger or !$this->_logger instanceof ElasticaLogger) { + return; + } + + $time = microtime(true) - $start; + $connection = $this->getLastRequest()->getConnection(); + + $connection_array = array( + 'host' => $connection->getHost(), + 'port' => $connection->getPort(), + 'transport' => $connection->getTransport(), + 'headers' => $connection->hasConfig('headers') ? $connection->getConfig('headers') : array(), + ); + + $this->_logger->logQuery($path, $method, $data, $time, $connection_array, $query); + } } From d0ce82ac2afb8ba685b200276e5eab84d94c4ced Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Sun, 21 Sep 2014 20:05:35 +1000 Subject: [PATCH 334/447] Adjust DoctrineListener to remove unnecessary method getDoctrineObject --- CHANGELOG-3.1.md | 14 ++++++++++ Doctrine/Listener.php | 60 ++++++++++++++++++++++++------------------- 2 files changed, 47 insertions(+), 27 deletions(-) create mode 100644 CHANGELOG-3.1.md diff --git a/CHANGELOG-3.1.md b/CHANGELOG-3.1.md new file mode 100644 index 0000000..0170373 --- /dev/null +++ b/CHANGELOG-3.1.md @@ -0,0 +1,14 @@ +CHANGELOG for 3.0.x +=================== + +This changelog references the relevant changes (bug and security fixes) done +in 3.1 versions. + +To get the diff for a specific change, go to +https://github.com/FriendsOfSymfony/FOSElasticaBundle/commit/XXX where XXX is +the commit hash. To get the diff between two versions, go to +https://github.com/FriendsOfSymfony/FOSElasticaBundle/compare/v3.0.4...v3.1.0 + +* 3.1.0 + +* BC BREAK: `DoctrineListener#scheduleForDeletion` access changed to private. diff --git a/Doctrine/Listener.php b/Doctrine/Listener.php index bd8b2c0..039ddaa 100644 --- a/Doctrine/Listener.php +++ b/Doctrine/Listener.php @@ -2,8 +2,8 @@ namespace FOS\ElasticaBundle\Doctrine; -use Doctrine\Common\EventArgs; use Doctrine\Common\EventSubscriber; +use Doctrine\Common\Persistence\Event\LifecycleEventArgs; use FOS\ElasticaBundle\Persister\ObjectPersisterInterface; use FOS\ElasticaBundle\Persister\ObjectPersister; use FOS\ElasticaBundle\Provider\IndexableInterface; @@ -38,13 +38,23 @@ class Listener implements EventSubscriber private $config; /** - * Objects scheduled for insertion and replacement + * Objects scheduled for insertion. + * + * @var array */ public $scheduledForInsertion = array(); + + /** + * Objects scheduled to be updated or removed. + * + * @var array + */ public $scheduledForUpdate = array(); /** * IDs of objects scheduled for removal + * + * @var array */ public $scheduledForDeletion = array(); @@ -56,7 +66,7 @@ class Listener implements EventSubscriber protected $propertyAccessor; /** - * @var \FOS\ElasticaBundle\Provider\IndexableInterface + * @var IndexableInterface */ private $indexable; @@ -98,37 +108,27 @@ class Listener implements EventSubscriber } /** - * Provides unified method for retrieving a doctrine object from an EventArgs instance + * Looks for new objects that should be indexed. * - * @param EventArgs $eventArgs - * @return object Entity | Document - * @throws \RuntimeException if no valid getter is found. + * @param LifecycleEventArgs $eventArgs */ - private function getDoctrineObject(EventArgs $eventArgs) + public function postPersist(LifecycleEventArgs $eventArgs) { - if (method_exists($eventArgs, 'getObject')) { - return $eventArgs->getObject(); - } elseif (method_exists($eventArgs, 'getEntity')) { - return $eventArgs->getEntity(); - } elseif (method_exists($eventArgs, 'getDocument')) { - return $eventArgs->getDocument(); - } - - throw new \RuntimeException('Unable to retrieve object from EventArgs.'); - } - - public function postPersist(EventArgs $eventArgs) - { - $entity = $this->getDoctrineObject($eventArgs); + $entity = $eventArgs->getObject(); if ($this->objectPersister->handlesObject($entity) && $this->isObjectIndexable($entity)) { $this->scheduledForInsertion[] = $entity; } } - public function postUpdate(EventArgs $eventArgs) + /** + * Looks for objects being updated that should be indexed or removed from the index. + * + * @param LifecycleEventArgs $eventArgs + */ + public function postUpdate(LifecycleEventArgs $eventArgs) { - $entity = $this->getDoctrineObject($eventArgs); + $entity = $eventArgs->getObject(); if ($this->objectPersister->handlesObject($entity)) { if ($this->isObjectIndexable($entity)) { @@ -143,10 +143,12 @@ class Listener implements EventSubscriber /** * Delete objects preRemove instead of postRemove so that we have access to the id. Because this is called * preRemove, first check that the entity is managed by Doctrine + * + * @param LifecycleEventArgs $eventArgs */ - public function preRemove(EventArgs $eventArgs) + public function preRemove(LifecycleEventArgs $eventArgs) { - $entity = $this->getDoctrineObject($eventArgs); + $entity = $eventArgs->getObject(); if ($this->objectPersister->handlesObject($entity)) { $this->scheduleForDeletion($entity); @@ -179,6 +181,10 @@ class Listener implements EventSubscriber * data in the event of a crash during flush. * * This method is only called in legacy configurations of the listener. + * + * @deprecated This method should only be called in applications that depend + * on the behaviour that entities are indexed regardless of if a + * flush is successful. */ public function preFlush() { @@ -199,7 +205,7 @@ class Listener implements EventSubscriber * * @param object $object */ - protected function scheduleForDeletion($object) + private function scheduleForDeletion($object) { if ($identifierValue = $this->propertyAccessor->getValue($object, $this->config['identifier'])) { $this->scheduledForDeletion[] = $identifierValue; From 71a86cada54ebc94d5723808b0616c7e378a3a27 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Sun, 21 Sep 2014 20:06:06 +1000 Subject: [PATCH 335/447] BC BREAK: Add `handlesObject` method to ObjectPersisterInterface --- CHANGELOG-3.1.md | 2 ++ Persister/ObjectPersisterInterface.php | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/CHANGELOG-3.1.md b/CHANGELOG-3.1.md index 0170373..ee9af70 100644 --- a/CHANGELOG-3.1.md +++ b/CHANGELOG-3.1.md @@ -12,3 +12,5 @@ https://github.com/FriendsOfSymfony/FOSElasticaBundle/compare/v3.0.4...v3.1.0 * 3.1.0 * BC BREAK: `DoctrineListener#scheduleForDeletion` access changed to private. +* BC BREAK: `ObjectPersisterInterface` gains the method `handlesObject` that + returns a boolean value if it will handle a given object or not. diff --git a/Persister/ObjectPersisterInterface.php b/Persister/ObjectPersisterInterface.php index 2b4c8ee..0df7f7e 100644 --- a/Persister/ObjectPersisterInterface.php +++ b/Persister/ObjectPersisterInterface.php @@ -68,4 +68,12 @@ interface ObjectPersisterInterface * @param array $identifiers array of domain model object identifiers */ public function deleteManyByIdentifiers(array $identifiers); + + /** + * If the object persister handles the given object. + * + * @param object $object + * @return bool + */ + public function handlesObject($object); } From b3f87e414f5a5b04a351e741d437a40c988bdbdb Mon Sep 17 00:00:00 2001 From: Michael Schramm Date: Fri, 5 Sep 2014 02:52:37 +0200 Subject: [PATCH 336/447] move classes to parametes --- Resources/config/mongodb.xml | 16 ++++++++++++---- Resources/config/orm.xml | 15 +++++++++++---- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/Resources/config/mongodb.xml b/Resources/config/mongodb.xml index 048d799..8e15533 100644 --- a/Resources/config/mongodb.xml +++ b/Resources/config/mongodb.xml @@ -4,8 +4,16 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> + + FOS\ElasticaBundle\Doctrine\MongoDB\Provider + FOS\ElasticaBundle\Doctrine\Listener + FOS\ElasticaBundle\Doctrine\MongoDB\ElasticaToModelTransformer + FOS\ElasticaBundle\Doctrine\RepositoryManager + + + - + @@ -13,7 +21,7 @@ - + @@ -21,7 +29,7 @@ - + @@ -30,7 +38,7 @@ - + diff --git a/Resources/config/orm.xml b/Resources/config/orm.xml index ddc0e50..94f21d4 100644 --- a/Resources/config/orm.xml +++ b/Resources/config/orm.xml @@ -4,8 +4,15 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> + + FOS\ElasticaBundle\Doctrine\ORM\Provider + FOS\ElasticaBundle\Doctrine\Listener + FOS\ElasticaBundle\Doctrine\ORM\ElasticaToModelTransformer + FOS\ElasticaBundle\Doctrine\RepositoryManager + + - + @@ -13,7 +20,7 @@ - + @@ -21,7 +28,7 @@ - + @@ -30,7 +37,7 @@ - + From 25d56d0a0f4a7a9bfe65390220ed567204cd030b Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Fri, 3 Oct 2014 08:21:02 +1000 Subject: [PATCH 337/447] 3.1.x requires doctrine 2.4+ --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index bb30928..833621a 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ "psr/log": "~1.0" }, "require-dev":{ - "doctrine/orm": "~2.2", + "doctrine/orm": "~2.4", "doctrine/doctrine-bundle": "~1.2@beta", "jms/serializer-bundle": "@stable", "phpunit/phpunit": "~4.1", @@ -34,7 +34,7 @@ "symfony/twig-bundle": "~2.3" }, "suggest": { - "doctrine/orm": "~2.2", + "doctrine/orm": "~2.4", "doctrine/mongodb-odm": "1.0.*@dev", "propel/propel1": "1.6.*", "pagerfanta/pagerfanta": "1.0.*@dev", From 67ae04430993f20432ad199ec725489b849bf237 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Wed, 8 Oct 2014 08:59:45 +1100 Subject: [PATCH 338/447] #724 Fix debug_logging option on the provider --- DependencyInjection/Configuration.php | 6 +++++- Tests/Functional/app/ORM/config.yml | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 3c5d18c..b204f0c 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -480,9 +480,13 @@ class Configuration implements ConfigurationInterface ->scalarNode('identifier')->defaultValue('id')->end() ->arrayNode('provider') ->children() - ->scalarNode('query_builder_method')->defaultValue('createQueryBuilder')->end() ->scalarNode('batch_size')->defaultValue(100)->end() ->scalarNode('clear_object_manager')->defaultTrue()->end() + ->scalarNode('debug_logging') + ->defaultValue($this->debug) + ->treatNullLike(true) + ->end() + ->scalarNode('query_builder_method')->defaultValue('createQueryBuilder')->end() ->scalarNode('service')->end() ->end() ->end() diff --git a/Tests/Functional/app/ORM/config.yml b/Tests/Functional/app/ORM/config.yml index 02d7a92..98c9221 100644 --- a/Tests/Functional/app/ORM/config.yml +++ b/Tests/Functional/app/ORM/config.yml @@ -35,6 +35,8 @@ fos_elastica: model: FOS\ElasticaBundle\Tests\Functional\TypeObj listener: is_indexable_callback: 'object.isIndexable() && !object.isntIndexable()' + provider: + debug_logging: true type2: properties: field1: ~ From 7fa7e44beea138994e49fc52633ffa701ecc58ac Mon Sep 17 00:00:00 2001 From: Gnucki Date: Wed, 8 Oct 2014 10:44:49 +0200 Subject: [PATCH 339/447] Fix mongodb populate falling down performances for big collections --- Doctrine/AbstractProvider.php | 6 ++++-- Doctrine/MongoDB/Provider.php | 14 ++++++++++++-- Doctrine/ORM/Provider.php | 2 +- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/Doctrine/AbstractProvider.php b/Doctrine/AbstractProvider.php index a662fd4..d897c96 100644 --- a/Doctrine/AbstractProvider.php +++ b/Doctrine/AbstractProvider.php @@ -54,12 +54,13 @@ abstract class AbstractProvider extends BaseAbstractProvider $batchSize = isset($options['batch-size']) ? intval($options['batch-size']) : $this->options['batch_size']; $ignoreErrors = isset($options['ignore-errors']) ? $options['ignore-errors'] : $this->options['ignore_errors']; $manager = $this->managerRegistry->getManagerForClass($this->objectClass); + $objects = array(); for (; $offset < $nbObjects; $offset += $batchSize) { if ($loggerClosure) { $stepStartTime = microtime(true); } - $objects = $this->fetchSlice($queryBuilder, $batchSize, $offset); + $objects = $this->fetchSlice($queryBuilder, $batchSize, $offset, $objects); if ($loggerClosure) { $stepNbObjects = count($objects); } @@ -133,9 +134,10 @@ abstract class AbstractProvider extends BaseAbstractProvider * @param object $queryBuilder * @param integer $limit * @param integer $offset + * @param array $previousSlice * @return array */ - protected abstract function fetchSlice($queryBuilder, $limit, $offset); + protected abstract function fetchSlice($queryBuilder, $limit, $offset, array $previousSlice); /** * Creates the query builder, which will be used to fetch objects to index. diff --git a/Doctrine/MongoDB/Provider.php b/Doctrine/MongoDB/Provider.php index 9e1c5dd..ae711ec 100644 --- a/Doctrine/MongoDB/Provider.php +++ b/Doctrine/MongoDB/Provider.php @@ -59,15 +59,25 @@ class Provider extends AbstractProvider /** * @see FOS\ElasticaBundle\Doctrine\AbstractProvider::fetchSlice() */ - protected function fetchSlice($queryBuilder, $limit, $offset) + protected function fetchSlice($queryBuilder, $limit, $offset, array $previousSlice) { if (!$queryBuilder instanceof Builder) { throw new InvalidArgumentTypeException($queryBuilder, 'Doctrine\ODM\MongoDB\Query\Builder'); } + $lastObject = array_pop($previousSlice); + + if ($lastObject) { + $queryBuilder + ->field('_id')->gt($lastObject->getId()) + ->skip(0); + } else { + $queryBuilder->skip($offset); + } + return $queryBuilder ->limit($limit) - ->skip($offset) + ->sort(array('_id' => 'asc')) ->getQuery() ->execute() ->toArray(); diff --git a/Doctrine/ORM/Provider.php b/Doctrine/ORM/Provider.php index 7e2ac12..701c6c5 100644 --- a/Doctrine/ORM/Provider.php +++ b/Doctrine/ORM/Provider.php @@ -70,7 +70,7 @@ class Provider extends AbstractProvider /** * @see FOS\ElasticaBundle\Doctrine\AbstractProvider::fetchSlice() */ - protected function fetchSlice($queryBuilder, $limit, $offset) + protected function fetchSlice($queryBuilder, $limit, $offset, array $previousSlice) { if (!$queryBuilder instanceof QueryBuilder) { throw new InvalidArgumentTypeException($queryBuilder, 'Doctrine\ORM\QueryBuilder'); From 4c4e9ffe36385f5b5c69c02b38741af98516ea19 Mon Sep 17 00:00:00 2001 From: Cassiano Date: Wed, 8 Oct 2014 14:27:50 -0300 Subject: [PATCH 340/447] Update RawPartialResults.php --- Paginator/RawPartialResults.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Paginator/RawPartialResults.php b/Paginator/RawPartialResults.php index a4afb00..908986f 100644 --- a/Paginator/RawPartialResults.php +++ b/Paginator/RawPartialResults.php @@ -49,4 +49,16 @@ class RawPartialResults implements PartialResultsInterface return null; } -} \ No newline at end of file + + /** + * {@inheritDoc} + */ + public function getAggregations() + { + if ($this->resultSet->hasAggregations()) { + return $this->resultSet->getAggregations(); + } + + return null; + } +} From f9ce1dcd4e37a5247825a20fd01a53ca329aaf57 Mon Sep 17 00:00:00 2001 From: Cassiano Date: Wed, 8 Oct 2014 14:30:03 -0300 Subject: [PATCH 341/447] Update RawPaginatorAdapter.php --- Paginator/RawPaginatorAdapter.php | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/Paginator/RawPaginatorAdapter.php b/Paginator/RawPaginatorAdapter.php index 8bd4ee2..8aadeb1 100644 --- a/Paginator/RawPaginatorAdapter.php +++ b/Paginator/RawPaginatorAdapter.php @@ -36,6 +36,11 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface * @var array for the facets */ private $facets; + + /** + * @var array for the aggregations + */ + private $aggregations /** * @see PaginatorAdapterInterface::__construct @@ -82,6 +87,7 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface $resultSet = $this->searchable->search($query, $this->options); $this->totalHits = $resultSet->getTotalHits(); $this->facets = $resultSet->getFacets(); + $this->aggregations = $resultSet->getAggregations(); return $resultSet; } @@ -126,4 +132,28 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface return $this->facets; } + + /** + * Returns Aggregations + * + * @return mixed + */ + public function getAggregations() { + if (!isset($this->aggregations)) { + $this->aggregations = $this->searchable->search($this->query)->getAggregations(); + } + + return $this->aggregations; + } + + + /** + * Returns the Query + * + * @return Query the search query + */ + public function getQuery() + { + return $this->query; + } } From 197bb3ebad1502b660371d5013d8f0ea69e2214d Mon Sep 17 00:00:00 2001 From: Cassiano Date: Wed, 8 Oct 2014 14:31:19 -0300 Subject: [PATCH 342/447] Update PartialResultsInterface.php --- Paginator/PartialResultsInterface.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Paginator/PartialResultsInterface.php b/Paginator/PartialResultsInterface.php index 9efe7f3..1b0ae60 100644 --- a/Paginator/PartialResultsInterface.php +++ b/Paginator/PartialResultsInterface.php @@ -28,4 +28,11 @@ interface PartialResultsInterface * @return array */ function getFacets(); -} \ No newline at end of file + + /** + * Returns the aggregations + * + * @return array + */ + function getAggregations(); +} From d2de7ba6e81d6b728392c8599ca3d52b57a938dc Mon Sep 17 00:00:00 2001 From: Cassiano Date: Wed, 8 Oct 2014 14:31:39 -0300 Subject: [PATCH 343/447] Update PaginatorAdapterInterface.php --- Paginator/PaginatorAdapterInterface.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Paginator/PaginatorAdapterInterface.php b/Paginator/PaginatorAdapterInterface.php index 25786a0..65271f0 100644 --- a/Paginator/PaginatorAdapterInterface.php +++ b/Paginator/PaginatorAdapterInterface.php @@ -31,4 +31,11 @@ interface PaginatorAdapterInterface * @return mixed */ function getFacets(); + + /** + * Returns Aggregations + * + * @return mixed + */ + function getAggregations(); } From 7c6fe4eaab8a2f2d61da9cc25a7b9bd80859be5c Mon Sep 17 00:00:00 2001 From: Cassiano Date: Wed, 8 Oct 2014 14:32:24 -0300 Subject: [PATCH 344/447] Update FantaPaginatorAdapter.php --- Paginator/FantaPaginatorAdapter.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Paginator/FantaPaginatorAdapter.php b/Paginator/FantaPaginatorAdapter.php index 2ad6983..812afa8 100644 --- a/Paginator/FantaPaginatorAdapter.php +++ b/Paginator/FantaPaginatorAdapter.php @@ -39,6 +39,18 @@ class FantaPaginatorAdapter implements AdapterInterface { return $this->adapter->getFacets(); } + + /** + * Returns Aggregations + * + * @return mixed + * + * @api + */ + public function getAggregations() + { + return $this->adapter->getAggregations(); + } /** * Returns a slice of the results. From 196aed6630654c81c4356ee67e2972a4a596252d Mon Sep 17 00:00:00 2001 From: Cassiano Date: Wed, 8 Oct 2014 14:33:15 -0300 Subject: [PATCH 345/447] Update PaginateElasticaQuerySubscriber.php --- Subscriber/PaginateElasticaQuerySubscriber.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Subscriber/PaginateElasticaQuerySubscriber.php b/Subscriber/PaginateElasticaQuerySubscriber.php index cbe508d..82d30ea 100644 --- a/Subscriber/PaginateElasticaQuerySubscriber.php +++ b/Subscriber/PaginateElasticaQuerySubscriber.php @@ -21,6 +21,10 @@ class PaginateElasticaQuerySubscriber implements EventSubscriberInterface if (null != $facets) { $event->setCustomPaginationParameter('facets', $facets); } + $aggregations = $results->getAggregations(); + if (null != $aggregations) { + $event->setCustomPaginationParameter('aggregations', $aggregations); + } $event->stopPropagation(); } @@ -32,4 +36,4 @@ class PaginateElasticaQuerySubscriber implements EventSubscriberInterface 'knp_pager.items' => array('items', 1) ); } -} \ No newline at end of file +} From 6f4e389dfd07bbe92a789f816c307e187006f6b3 Mon Sep 17 00:00:00 2001 From: Cassiano Date: Wed, 8 Oct 2014 15:19:48 -0300 Subject: [PATCH 346/447] Update RawPaginatorAdapter.php --- Paginator/RawPaginatorAdapter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Paginator/RawPaginatorAdapter.php b/Paginator/RawPaginatorAdapter.php index 8aadeb1..62dc95e 100644 --- a/Paginator/RawPaginatorAdapter.php +++ b/Paginator/RawPaginatorAdapter.php @@ -40,7 +40,7 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface /** * @var array for the aggregations */ - private $aggregations + private $aggregations; /** * @see PaginatorAdapterInterface::__construct From e7634d8ba26534288cf8622a9e9a93d7eefd0ff9 Mon Sep 17 00:00:00 2001 From: Cassiano Date: Wed, 8 Oct 2014 17:15:57 -0300 Subject: [PATCH 347/447] Update RawPaginatorAdapter.php --- Paginator/RawPaginatorAdapter.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Paginator/RawPaginatorAdapter.php b/Paginator/RawPaginatorAdapter.php index 7e2d49b..e6b6887 100644 --- a/Paginator/RawPaginatorAdapter.php +++ b/Paginator/RawPaginatorAdapter.php @@ -132,7 +132,6 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface return $this->facets; } -<<<<<<< HEAD /** * Returns Aggregations @@ -146,9 +145,6 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface return $this->aggregations; } - -======= ->>>>>>> upstream/master /** * Returns the Query From 445f2f93f652f6cf1a0b827a0bde362d10ed69f3 Mon Sep 17 00:00:00 2001 From: Gnucki Date: Mon, 13 Oct 2014 15:40:31 +0200 Subject: [PATCH 348/447] Add slice fetching abstraction --- Doctrine/AbstractProvider.php | 28 +++++++++++++++--- Doctrine/MongoDB/Provider.php | 14 ++------- Doctrine/MongoDB/SliceFetcher.php | 44 ++++++++++++++++++++++++++++ Doctrine/ORM/Provider.php | 2 +- Doctrine/ORM/SliceFetcher.php | 47 ++++++++++++++++++++++++++++++ Doctrine/SliceFetcherInterface.php | 23 +++++++++++++++ Resources/config/mongodb.xml | 8 +++-- Resources/config/orm.xml | 21 ++++++++----- 8 files changed, 160 insertions(+), 27 deletions(-) create mode 100644 Doctrine/MongoDB/SliceFetcher.php create mode 100644 Doctrine/ORM/SliceFetcher.php create mode 100644 Doctrine/SliceFetcherInterface.php diff --git a/Doctrine/AbstractProvider.php b/Doctrine/AbstractProvider.php index d897c96..a66e476 100644 --- a/Doctrine/AbstractProvider.php +++ b/Doctrine/AbstractProvider.php @@ -11,6 +11,7 @@ use FOS\ElasticaBundle\Provider\IndexableInterface; abstract class AbstractProvider extends BaseAbstractProvider { protected $managerRegistry; + protected $sliceFetcher; /** * Constructor. @@ -20,13 +21,15 @@ abstract class AbstractProvider extends BaseAbstractProvider * @param string $objectClass * @param array $options * @param ManagerRegistry $managerRegistry + * @param SliceFetcherInterface $sliceFetcher */ public function __construct( ObjectPersisterInterface $objectPersister, IndexableInterface $indexable, $objectClass, array $options, - ManagerRegistry $managerRegistry + ManagerRegistry $managerRegistry, + SliceFetcherInterface $sliceFetcher = null ) { parent::__construct($objectPersister, $indexable, $objectClass, array_merge(array( 'clear_object_manager' => true, @@ -36,6 +39,7 @@ abstract class AbstractProvider extends BaseAbstractProvider ), $options)); $this->managerRegistry = $managerRegistry; + $this->sliceFetcher = $sliceFetcher; } /** @@ -60,7 +64,24 @@ abstract class AbstractProvider extends BaseAbstractProvider if ($loggerClosure) { $stepStartTime = microtime(true); } - $objects = $this->fetchSlice($queryBuilder, $batchSize, $offset, $objects); + + if ($this->sliceFetcher) { + $identifierFieldNames = $this->managerRegistry + ->getManagerForClass($this->objectClass) + ->getClassMetadata($this->objectClass) + ->getIdentifierFieldNames(); + + $objects = $this->sliceFetcher->fetch( + $queryBuilder, + $batchSize, + $offset, + $objects, + $identifierFieldNames + ); + } else { + $objects = $this->fetchSlice($queryBuilder, $batchSize, $offset); + } + if ($loggerClosure) { $stepNbObjects = count($objects); } @@ -134,10 +155,9 @@ abstract class AbstractProvider extends BaseAbstractProvider * @param object $queryBuilder * @param integer $limit * @param integer $offset - * @param array $previousSlice * @return array */ - protected abstract function fetchSlice($queryBuilder, $limit, $offset, array $previousSlice); + protected abstract function fetchSlice($queryBuilder, $limit, $offset); /** * Creates the query builder, which will be used to fetch objects to index. diff --git a/Doctrine/MongoDB/Provider.php b/Doctrine/MongoDB/Provider.php index ae711ec..6a9ab19 100644 --- a/Doctrine/MongoDB/Provider.php +++ b/Doctrine/MongoDB/Provider.php @@ -59,25 +59,15 @@ class Provider extends AbstractProvider /** * @see FOS\ElasticaBundle\Doctrine\AbstractProvider::fetchSlice() */ - protected function fetchSlice($queryBuilder, $limit, $offset, array $previousSlice) + protected function fetchSlice($queryBuilder, $limit, $offset) { if (!$queryBuilder instanceof Builder) { throw new InvalidArgumentTypeException($queryBuilder, 'Doctrine\ODM\MongoDB\Query\Builder'); } - $lastObject = array_pop($previousSlice); - - if ($lastObject) { - $queryBuilder - ->field('_id')->gt($lastObject->getId()) - ->skip(0); - } else { - $queryBuilder->skip($offset); - } - return $queryBuilder + ->skip($offset) ->limit($limit) - ->sort(array('_id' => 'asc')) ->getQuery() ->execute() ->toArray(); diff --git a/Doctrine/MongoDB/SliceFetcher.php b/Doctrine/MongoDB/SliceFetcher.php new file mode 100644 index 0000000..f90783e --- /dev/null +++ b/Doctrine/MongoDB/SliceFetcher.php @@ -0,0 +1,44 @@ + + */ +class SliceFetcher implements SliceFetcherInterface +{ + /** + * {@inheritdoc} + */ + public function fetch($queryBuilder, $limit, $offset, array $previousSlice, array $identifierFieldNames) + { + if (!$queryBuilder instanceof Builder) { + throw new InvalidArgumentTypeException($queryBuilder, 'Doctrine\ODM\MongoDB\Query\Builder'); + } + + $lastObject = array_pop($previousSlice); + + if ($lastObject) { + $queryBuilder + ->field('_id')->gt($lastObject->getId()) + ->skip(0) + ; + } else { + $queryBuilder->skip($offset); + } + + return $queryBuilder + ->limit($limit) + ->sort(array('_id' => 'asc')) + ->getQuery() + ->execute() + ->toArray() + ; + } +} diff --git a/Doctrine/ORM/Provider.php b/Doctrine/ORM/Provider.php index 701c6c5..7e2ac12 100644 --- a/Doctrine/ORM/Provider.php +++ b/Doctrine/ORM/Provider.php @@ -70,7 +70,7 @@ class Provider extends AbstractProvider /** * @see FOS\ElasticaBundle\Doctrine\AbstractProvider::fetchSlice() */ - protected function fetchSlice($queryBuilder, $limit, $offset, array $previousSlice) + protected function fetchSlice($queryBuilder, $limit, $offset) { if (!$queryBuilder instanceof QueryBuilder) { throw new InvalidArgumentTypeException($queryBuilder, 'Doctrine\ORM\QueryBuilder'); diff --git a/Doctrine/ORM/SliceFetcher.php b/Doctrine/ORM/SliceFetcher.php new file mode 100644 index 0000000..d7f81e1 --- /dev/null +++ b/Doctrine/ORM/SliceFetcher.php @@ -0,0 +1,47 @@ + + */ +class SliceFetcher implements SliceFetcherInterface +{ + /** + * {@inheritdoc} + */ + public function fetch($queryBuilder, $limit, $offset, array $previousSlice, array $identifierFieldNames) + { + if (!$queryBuilder instanceof QueryBuilder) { + throw new InvalidArgumentTypeException($queryBuilder, 'Doctrine\ORM\QueryBuilder'); + } + + /** + * An orderBy DQL part is required to avoid feching the same row twice. + * @see http://stackoverflow.com/questions/6314879/does-limit-offset-length-require-order-by-for-pagination + * @see http://www.postgresql.org/docs/current/static/queries-limit.html + * @see http://www.sqlite.org/lang_select.html#orderby + */ + $orderBy = $queryBuilder->getDQLPart('orderBy'); + if (empty($orderBy)) { + $rootAliases = $queryBuilder->getRootAliases(); + + foreach ($identifierFieldNames as $fieldName) { + $queryBuilder->addOrderBy($rootAliases[0].'.'.$fieldName); + } + } + + return $queryBuilder + ->setFirstResult($offset) + ->setMaxResults($limit) + ->getQuery() + ->getResult() + ; + } +} diff --git a/Doctrine/SliceFetcherInterface.php b/Doctrine/SliceFetcherInterface.php new file mode 100644 index 0000000..9df7152 --- /dev/null +++ b/Doctrine/SliceFetcherInterface.php @@ -0,0 +1,23 @@ + + */ +interface SliceFetcherInterface +{ + /** + * Fetches a slice of objects using the query builder. + * + * @param object $queryBuilder + * @param integer $limit + * @param integer $offset + * @param array $previousSlice + * @param array $identifierFieldNames + * @return array + */ + function fetch($queryBuilder, $limit, $offset, array $previousSlice, array $identifierFieldNames); +} diff --git a/Resources/config/mongodb.xml b/Resources/config/mongodb.xml index 8e15533..84baf3e 100644 --- a/Resources/config/mongodb.xml +++ b/Resources/config/mongodb.xml @@ -5,20 +5,24 @@ xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> + FOS\ElasticaBundle\Doctrine\MongoDB\SliceFetcher FOS\ElasticaBundle\Doctrine\MongoDB\Provider FOS\ElasticaBundle\Doctrine\Listener FOS\ElasticaBundle\Doctrine\MongoDB\ElasticaToModelTransformer FOS\ElasticaBundle\Doctrine\RepositoryManager - + + + - + + diff --git a/Resources/config/orm.xml b/Resources/config/orm.xml index 94f21d4..ea95245 100644 --- a/Resources/config/orm.xml +++ b/Resources/config/orm.xml @@ -4,20 +4,25 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> - - FOS\ElasticaBundle\Doctrine\ORM\Provider - FOS\ElasticaBundle\Doctrine\Listener - FOS\ElasticaBundle\Doctrine\ORM\ElasticaToModelTransformer - FOS\ElasticaBundle\Doctrine\RepositoryManager - - + + FOS\ElasticaBundle\Doctrine\ORM\SliceFetcher + FOS\ElasticaBundle\Doctrine\ORM\Provider + FOS\ElasticaBundle\Doctrine\Listener + FOS\ElasticaBundle\Doctrine\ORM\ElasticaToModelTransformer + FOS\ElasticaBundle\Doctrine\RepositoryManager + + + + + - + + From be75b387a57976f0426a1a8a2f1ead01383558da Mon Sep 17 00:00:00 2001 From: Gnucki Date: Mon, 13 Oct 2014 15:41:29 +0200 Subject: [PATCH 349/447] Add slice fetching abstraction --- Doctrine/AbstractProvider.php | 28 +++++++++++++++--- Doctrine/MongoDB/Provider.php | 14 ++------- Doctrine/MongoDB/SliceFetcher.php | 44 ++++++++++++++++++++++++++++ Doctrine/ORM/Provider.php | 2 +- Doctrine/ORM/SliceFetcher.php | 47 ++++++++++++++++++++++++++++++ Doctrine/SliceFetcherInterface.php | 23 +++++++++++++++ Resources/config/mongodb.xml | 8 +++-- Resources/config/orm.xml | 21 ++++++++----- 8 files changed, 160 insertions(+), 27 deletions(-) create mode 100644 Doctrine/MongoDB/SliceFetcher.php create mode 100644 Doctrine/ORM/SliceFetcher.php create mode 100644 Doctrine/SliceFetcherInterface.php diff --git a/Doctrine/AbstractProvider.php b/Doctrine/AbstractProvider.php index d897c96..a66e476 100644 --- a/Doctrine/AbstractProvider.php +++ b/Doctrine/AbstractProvider.php @@ -11,6 +11,7 @@ use FOS\ElasticaBundle\Provider\IndexableInterface; abstract class AbstractProvider extends BaseAbstractProvider { protected $managerRegistry; + protected $sliceFetcher; /** * Constructor. @@ -20,13 +21,15 @@ abstract class AbstractProvider extends BaseAbstractProvider * @param string $objectClass * @param array $options * @param ManagerRegistry $managerRegistry + * @param SliceFetcherInterface $sliceFetcher */ public function __construct( ObjectPersisterInterface $objectPersister, IndexableInterface $indexable, $objectClass, array $options, - ManagerRegistry $managerRegistry + ManagerRegistry $managerRegistry, + SliceFetcherInterface $sliceFetcher = null ) { parent::__construct($objectPersister, $indexable, $objectClass, array_merge(array( 'clear_object_manager' => true, @@ -36,6 +39,7 @@ abstract class AbstractProvider extends BaseAbstractProvider ), $options)); $this->managerRegistry = $managerRegistry; + $this->sliceFetcher = $sliceFetcher; } /** @@ -60,7 +64,24 @@ abstract class AbstractProvider extends BaseAbstractProvider if ($loggerClosure) { $stepStartTime = microtime(true); } - $objects = $this->fetchSlice($queryBuilder, $batchSize, $offset, $objects); + + if ($this->sliceFetcher) { + $identifierFieldNames = $this->managerRegistry + ->getManagerForClass($this->objectClass) + ->getClassMetadata($this->objectClass) + ->getIdentifierFieldNames(); + + $objects = $this->sliceFetcher->fetch( + $queryBuilder, + $batchSize, + $offset, + $objects, + $identifierFieldNames + ); + } else { + $objects = $this->fetchSlice($queryBuilder, $batchSize, $offset); + } + if ($loggerClosure) { $stepNbObjects = count($objects); } @@ -134,10 +155,9 @@ abstract class AbstractProvider extends BaseAbstractProvider * @param object $queryBuilder * @param integer $limit * @param integer $offset - * @param array $previousSlice * @return array */ - protected abstract function fetchSlice($queryBuilder, $limit, $offset, array $previousSlice); + protected abstract function fetchSlice($queryBuilder, $limit, $offset); /** * Creates the query builder, which will be used to fetch objects to index. diff --git a/Doctrine/MongoDB/Provider.php b/Doctrine/MongoDB/Provider.php index ae711ec..6a9ab19 100644 --- a/Doctrine/MongoDB/Provider.php +++ b/Doctrine/MongoDB/Provider.php @@ -59,25 +59,15 @@ class Provider extends AbstractProvider /** * @see FOS\ElasticaBundle\Doctrine\AbstractProvider::fetchSlice() */ - protected function fetchSlice($queryBuilder, $limit, $offset, array $previousSlice) + protected function fetchSlice($queryBuilder, $limit, $offset) { if (!$queryBuilder instanceof Builder) { throw new InvalidArgumentTypeException($queryBuilder, 'Doctrine\ODM\MongoDB\Query\Builder'); } - $lastObject = array_pop($previousSlice); - - if ($lastObject) { - $queryBuilder - ->field('_id')->gt($lastObject->getId()) - ->skip(0); - } else { - $queryBuilder->skip($offset); - } - return $queryBuilder + ->skip($offset) ->limit($limit) - ->sort(array('_id' => 'asc')) ->getQuery() ->execute() ->toArray(); diff --git a/Doctrine/MongoDB/SliceFetcher.php b/Doctrine/MongoDB/SliceFetcher.php new file mode 100644 index 0000000..f90783e --- /dev/null +++ b/Doctrine/MongoDB/SliceFetcher.php @@ -0,0 +1,44 @@ + + */ +class SliceFetcher implements SliceFetcherInterface +{ + /** + * {@inheritdoc} + */ + public function fetch($queryBuilder, $limit, $offset, array $previousSlice, array $identifierFieldNames) + { + if (!$queryBuilder instanceof Builder) { + throw new InvalidArgumentTypeException($queryBuilder, 'Doctrine\ODM\MongoDB\Query\Builder'); + } + + $lastObject = array_pop($previousSlice); + + if ($lastObject) { + $queryBuilder + ->field('_id')->gt($lastObject->getId()) + ->skip(0) + ; + } else { + $queryBuilder->skip($offset); + } + + return $queryBuilder + ->limit($limit) + ->sort(array('_id' => 'asc')) + ->getQuery() + ->execute() + ->toArray() + ; + } +} diff --git a/Doctrine/ORM/Provider.php b/Doctrine/ORM/Provider.php index 701c6c5..7e2ac12 100644 --- a/Doctrine/ORM/Provider.php +++ b/Doctrine/ORM/Provider.php @@ -70,7 +70,7 @@ class Provider extends AbstractProvider /** * @see FOS\ElasticaBundle\Doctrine\AbstractProvider::fetchSlice() */ - protected function fetchSlice($queryBuilder, $limit, $offset, array $previousSlice) + protected function fetchSlice($queryBuilder, $limit, $offset) { if (!$queryBuilder instanceof QueryBuilder) { throw new InvalidArgumentTypeException($queryBuilder, 'Doctrine\ORM\QueryBuilder'); diff --git a/Doctrine/ORM/SliceFetcher.php b/Doctrine/ORM/SliceFetcher.php new file mode 100644 index 0000000..d7f81e1 --- /dev/null +++ b/Doctrine/ORM/SliceFetcher.php @@ -0,0 +1,47 @@ + + */ +class SliceFetcher implements SliceFetcherInterface +{ + /** + * {@inheritdoc} + */ + public function fetch($queryBuilder, $limit, $offset, array $previousSlice, array $identifierFieldNames) + { + if (!$queryBuilder instanceof QueryBuilder) { + throw new InvalidArgumentTypeException($queryBuilder, 'Doctrine\ORM\QueryBuilder'); + } + + /** + * An orderBy DQL part is required to avoid feching the same row twice. + * @see http://stackoverflow.com/questions/6314879/does-limit-offset-length-require-order-by-for-pagination + * @see http://www.postgresql.org/docs/current/static/queries-limit.html + * @see http://www.sqlite.org/lang_select.html#orderby + */ + $orderBy = $queryBuilder->getDQLPart('orderBy'); + if (empty($orderBy)) { + $rootAliases = $queryBuilder->getRootAliases(); + + foreach ($identifierFieldNames as $fieldName) { + $queryBuilder->addOrderBy($rootAliases[0].'.'.$fieldName); + } + } + + return $queryBuilder + ->setFirstResult($offset) + ->setMaxResults($limit) + ->getQuery() + ->getResult() + ; + } +} diff --git a/Doctrine/SliceFetcherInterface.php b/Doctrine/SliceFetcherInterface.php new file mode 100644 index 0000000..9df7152 --- /dev/null +++ b/Doctrine/SliceFetcherInterface.php @@ -0,0 +1,23 @@ + + */ +interface SliceFetcherInterface +{ + /** + * Fetches a slice of objects using the query builder. + * + * @param object $queryBuilder + * @param integer $limit + * @param integer $offset + * @param array $previousSlice + * @param array $identifierFieldNames + * @return array + */ + function fetch($queryBuilder, $limit, $offset, array $previousSlice, array $identifierFieldNames); +} diff --git a/Resources/config/mongodb.xml b/Resources/config/mongodb.xml index 8e15533..84baf3e 100644 --- a/Resources/config/mongodb.xml +++ b/Resources/config/mongodb.xml @@ -5,20 +5,24 @@ xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> + FOS\ElasticaBundle\Doctrine\MongoDB\SliceFetcher FOS\ElasticaBundle\Doctrine\MongoDB\Provider FOS\ElasticaBundle\Doctrine\Listener FOS\ElasticaBundle\Doctrine\MongoDB\ElasticaToModelTransformer FOS\ElasticaBundle\Doctrine\RepositoryManager - + + + - + + diff --git a/Resources/config/orm.xml b/Resources/config/orm.xml index 94f21d4..ea95245 100644 --- a/Resources/config/orm.xml +++ b/Resources/config/orm.xml @@ -4,20 +4,25 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> - - FOS\ElasticaBundle\Doctrine\ORM\Provider - FOS\ElasticaBundle\Doctrine\Listener - FOS\ElasticaBundle\Doctrine\ORM\ElasticaToModelTransformer - FOS\ElasticaBundle\Doctrine\RepositoryManager - - + + FOS\ElasticaBundle\Doctrine\ORM\SliceFetcher + FOS\ElasticaBundle\Doctrine\ORM\Provider + FOS\ElasticaBundle\Doctrine\Listener + FOS\ElasticaBundle\Doctrine\ORM\ElasticaToModelTransformer + FOS\ElasticaBundle\Doctrine\RepositoryManager + + + + + - + + From 1b01aef46fa2e5cf111a5a231d46b9e3006cce95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ugo=20M=C3=A9da?= Date: Thu, 16 Oct 2014 15:46:40 +0200 Subject: [PATCH 350/447] Add missing KnpPaginator example in the usage documentation --- Resources/doc/usage.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Resources/doc/usage.md b/Resources/doc/usage.md index 37514b3..de8e1a0 100644 --- a/Resources/doc/usage.md +++ b/Resources/doc/usage.md @@ -26,7 +26,9 @@ $userPaginator = $finder->findPaginated('bob'); $countOfResults = $userPaginator->getNbResults(); // Option 3b. KnpPaginator resultset - +$paginator = $this->get('knp_paginator'); +$results = $finder->createPaginatorAdapter('bob'); +$pagination = $paginator->paginate($results, $page, 10); ``` Faceted Searching From 901ea49a3248cb00aee4eccd1869d9b9af8bb3b4 Mon Sep 17 00:00:00 2001 From: Gnucki Date: Sun, 2 Nov 2014 14:22:26 +0100 Subject: [PATCH 351/447] Factorize manager call --- Doctrine/AbstractProvider.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Doctrine/AbstractProvider.php b/Doctrine/AbstractProvider.php index a66e476..b4799fd 100644 --- a/Doctrine/AbstractProvider.php +++ b/Doctrine/AbstractProvider.php @@ -66,8 +66,7 @@ abstract class AbstractProvider extends BaseAbstractProvider } if ($this->sliceFetcher) { - $identifierFieldNames = $this->managerRegistry - ->getManagerForClass($this->objectClass) + $identifierFieldNames = $manager ->getClassMetadata($this->objectClass) ->getIdentifierFieldNames(); From 1369a01dd73ce0b620e1d7e51df40b3c25130725 Mon Sep 17 00:00:00 2001 From: Gnucki Date: Sun, 2 Nov 2014 14:24:28 +0100 Subject: [PATCH 352/447] Add slice fetching abstraction --- Tests/Doctrine/AbstractProviderTest.php | 95 ++++++++++++++++++++++--- 1 file changed, 85 insertions(+), 10 deletions(-) diff --git a/Tests/Doctrine/AbstractProviderTest.php b/Tests/Doctrine/AbstractProviderTest.php index 99ed2de..0c3ac17 100644 --- a/Tests/Doctrine/AbstractProviderTest.php +++ b/Tests/Doctrine/AbstractProviderTest.php @@ -13,6 +13,7 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase private $options; private $managerRegistry; private $indexable; + private $sliceFetcher; public function setUp() { @@ -32,6 +33,8 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase ->method('getManagerForClass') ->with($this->objectClass) ->will($this->returnValue($this->objectManager)); + + $this->sliceFetcher = $this->getMockSliceFetcher(); } /** @@ -45,6 +48,54 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase $queryBuilder = new \stdClass(); + $provider->expects($this->once()) + ->method('createQueryBuilder') + ->will($this->returnValue($queryBuilder)); + + $provider->expects($this->once()) + ->method('countObjects') + ->with($queryBuilder) + ->will($this->returnValue($nbObjects)); + + $this->indexable->expects($this->any()) + ->method('isObjectIndexable') + ->with('index', 'type', $this->anything()) + ->will($this->returnValue(true)); + + $providerInvocationOffset = 2; + $previousSlice = array(); + + foreach ($objectsByIteration as $i => $objects) { + $offset = $objects[0] - 1; + + $this->sliceFetcher->expects($this->at($i)) + ->method('fetch') + ->with($queryBuilder, $batchSize, $offset, $previousSlice, array('id')) + ->will($this->returnValue($objects)); + + $this->objectManager->expects($this->at($i)) + ->method('clear'); + + $previousSlice = $objects; + } + + $this->objectPersister->expects($this->exactly(count($objectsByIteration))) + ->method('insertMany'); + + $provider->populate(); + } + + /** + * @dataProvider providePopulateIterations + */ + public function testPopulateIterationsWithoutSliceFetcher($nbObjects, $objectsByIteration, $batchSize) + { + $this->options['batch_size'] = $batchSize; + + $provider = $this->getMockAbstractProvider(false); + + $queryBuilder = new \stdClass(); + $provider->expects($this->once()) ->method('createQueryBuilder') ->will($this->returnValue($queryBuilder)); @@ -107,8 +158,8 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase ->method('countObjects') ->will($this->returnValue($nbObjects)); - $provider->expects($this->any()) - ->method('fetchSlice') + $this->sliceFetcher->expects($this->any()) + ->method('fetch') ->will($this->returnValue($objects)); $this->indexable->expects($this->any()) @@ -133,8 +184,8 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase ->method('countObjects') ->will($this->returnValue($nbObjects)); - $provider->expects($this->any()) - ->method('fetchSlice') + $this->sliceFetcher->expects($this->any()) + ->method('fetch') ->will($this->returnValue($objects)); $this->indexable->expects($this->any()) @@ -165,8 +216,8 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase ->method('countObjects') ->will($this->returnValue($nbObjects)); - $provider->expects($this->any()) - ->method('fetchSlice') + $this->sliceFetcher->expects($this->any()) + ->method('fetch') ->will($this->returnValue($objects)); $this->indexable->expects($this->any()) @@ -192,8 +243,9 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase $provider->expects($this->any()) ->method('countObjects') ->will($this->returnValue($nbObjects)); - $provider->expects($this->any()) - ->method('fetchSlice') + + $this->sliceFetcher->expects($this->any()) + ->method('fetch') ->will($this->returnValue($objects)); $this->indexable->expects($this->at(0)) @@ -214,9 +266,11 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase } /** + * @param boolean $setSliceFetcher Whether or not to set the slice fetcher. + * * @return \FOS\ElasticaBundle\Doctrine\AbstractProvider|\PHPUnit_Framework_MockObject_MockObject */ - private function getMockAbstractProvider() + private function getMockAbstractProvider($setSliceFetcher = true) { return $this->getMockForAbstractClass('FOS\ElasticaBundle\Doctrine\AbstractProvider', array( $this->objectPersister, @@ -224,6 +278,7 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase $this->objectClass, $this->options, $this->managerRegistry, + $setSliceFetcher ? $this->sliceFetcher : null )); } @@ -250,7 +305,17 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase */ private function getMockObjectManager() { - return $this->getMock(__NAMESPACE__ . '\ObjectManager'); + $mock = $this->getMock(__NAMESPACE__ . '\ObjectManager'); + + $mock->expects($this->any()) + ->method('getClassMetadata') + ->will($this->returnSelf()); + + $mock->expects($this->any()) + ->method('getIdentifierFieldNames') + ->will($this->returnValue(array('id'))); + + return $mock; } /** @@ -268,6 +333,14 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase { return $this->getMock('FOS\ElasticaBundle\Provider\IndexableInterface'); } + + /** + * @return \FOS\ElasticaBundle\Doctrine\SliceFetcherInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private function getMockSliceFetcher() + { + return $this->getMock('FOS\ElasticaBundle\Doctrine\SliceFetcherInterface'); + } } /** @@ -277,4 +350,6 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase interface ObjectManager { function clear(); + function getClassMetadata(); + function getIdentifierFieldNames(); } From 2a7459f3276719d1f0d65d2d40d2ffdebd76d1be Mon Sep 17 00:00:00 2001 From: Piotr Antosik Date: Mon, 10 Nov 2014 14:05:56 +0100 Subject: [PATCH 353/447] Fix changelog header --- CHANGELOG-3.1.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG-3.1.md b/CHANGELOG-3.1.md index ee9af70..730126f 100644 --- a/CHANGELOG-3.1.md +++ b/CHANGELOG-3.1.md @@ -1,4 +1,4 @@ -CHANGELOG for 3.0.x +CHANGELOG for 3.1.x =================== This changelog references the relevant changes (bug and security fixes) done From e6d50c584cf4e60389fee2921397c6237dfb8b11 Mon Sep 17 00:00:00 2001 From: Nikolai Zujev Date: Thu, 13 Nov 2014 17:14:36 +0200 Subject: [PATCH 354/447] Clean filtered objects if the entire batch was filtered away, to prevent memory allocation issue. --- Doctrine/AbstractProvider.php | 4 ++++ Tests/Doctrine/AbstractProviderTest.php | 26 +++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/Doctrine/AbstractProvider.php b/Doctrine/AbstractProvider.php index a662fd4..92be6ce 100644 --- a/Doctrine/AbstractProvider.php +++ b/Doctrine/AbstractProvider.php @@ -69,6 +69,10 @@ abstract class AbstractProvider extends BaseAbstractProvider $loggerClosure('Entire batch was filtered away, skipping...'); } + if ($this->options['clear_object_manager']) { + $manager->clear(); + } + continue; } diff --git a/Tests/Doctrine/AbstractProviderTest.php b/Tests/Doctrine/AbstractProviderTest.php index 99ed2de..a129a6c 100644 --- a/Tests/Doctrine/AbstractProviderTest.php +++ b/Tests/Doctrine/AbstractProviderTest.php @@ -122,6 +122,32 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase $provider->populate(); } + public function testPopulateShouldClearObjectManagerForFilteredBatch() + { + $nbObjects = 1; + $objects = array(1); + + $provider = $this->getMockAbstractProvider(); + + $provider->expects($this->any()) + ->method('countObjects') + ->will($this->returnValue($nbObjects)); + + $provider->expects($this->any()) + ->method('fetchSlice') + ->will($this->returnValue($objects)); + + $this->indexable->expects($this->any()) + ->method('isObjectIndexable') + ->with('index', 'type', $this->anything()) + ->will($this->returnValue(false)); + + $this->objectManager->expects($this->once()) + ->method('clear'); + + $provider->populate(); + } + public function testPopulateInvokesLoggerClosure() { $nbObjects = 1; From 1e2da2d84ff974270a5946db0013e4e7237b532a Mon Sep 17 00:00:00 2001 From: Sebastian Krebs Date: Fri, 21 Nov 2014 14:21:26 +0100 Subject: [PATCH 355/447] Update custom-repositories.md to use code highlighting Looks better this way --- Resources/doc/cookbook/custom-repositories.md | 54 ++++++++++--------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/Resources/doc/cookbook/custom-repositories.md b/Resources/doc/cookbook/custom-repositories.md index 9eff5f7..866f72d 100644 --- a/Resources/doc/cookbook/custom-repositories.md +++ b/Resources/doc/cookbook/custom-repositories.md @@ -4,7 +4,7 @@ As well as the default repository you can create a custom repository for an enti methods for particular searches. These need to extend `FOS\ElasticaBundle\Repository` to have access to the finder: -``` +```php get('fos_elastica.manager'); +```php +/** var FOS\ElasticaBundle\Manager\RepositoryManager */ +$repositoryManager = $container->get('fos_elastica.manager'); - /** var FOS\ElasticaBundle\Repository */ - $repository = $repositoryManager->getRepository('UserBundle:User'); +/** var FOS\ElasticaBundle\Repository */ +$repository = $repositoryManager->getRepository('UserBundle:User'); - /** var array of Acme\UserBundle\Entity\User */ - $users = $repository->findWithCustomQuery('bob'); +/** var array of Acme\UserBundle\Entity\User */ +$users = $repository->findWithCustomQuery('bob'); +``` Alternatively you can specify the custom repository using an annotation in the entity: -``` +```php Date: Wed, 26 Nov 2014 16:25:23 +0100 Subject: [PATCH 356/447] RawPaginatorAdapter::getTotalHits() can retrieve the genuine total hits returned by elasticsearch --- Paginator/RawPaginatorAdapter.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Paginator/RawPaginatorAdapter.php b/Paginator/RawPaginatorAdapter.php index f05205a..9a15695 100644 --- a/Paginator/RawPaginatorAdapter.php +++ b/Paginator/RawPaginatorAdapter.php @@ -100,15 +100,18 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface /** * Returns the number of results. * + * @param boolean $genuineTotal make the function return the `hits.total` + * value of the search result in all cases, instead of limiting it to the + * `size` request parameter. * @return integer The number of results. */ - public function getTotalHits() + public function getTotalHits($genuineTotal = false) { if ( ! isset($this->totalHits)) { $this->totalHits = $this->searchable->search($this->query)->getTotalHits(); } - return $this->query->hasParam('size') + return $this->query->hasParam('size') && !$genuineTotal ? min($this->totalHits, (integer) $this->query->getParam('size')) : $this->totalHits; } From c4ee9fa83eff5a848ecbad2881015d184b1c5254 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 29 Nov 2014 17:17:31 +0100 Subject: [PATCH 357/447] Updated installation instructions --- Resources/doc/setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/doc/setup.md b/Resources/doc/setup.md index 6a1c2ae..16e427f 100644 --- a/Resources/doc/setup.md +++ b/Resources/doc/setup.md @@ -7,7 +7,7 @@ A) Install FOSElasticaBundle FOSElasticaBundle is installed using [Composer](https://getcomposer.org). ```bash -$ php composer.phar require friendsofsymfony/elastica-bundle "~3.0" +$ php composer.phar require friendsofsymfony/elastica-bundle ``` ### Elasticsearch From c45dcd955db6f05cca8914df9898366b0c810b07 Mon Sep 17 00:00:00 2001 From: Nikolai Zujev Date: Thu, 13 Nov 2014 17:14:36 +0200 Subject: [PATCH 358/447] Clean filtered objects if the entire batch was filtered away, to prevent memory allocation issue. --- Doctrine/AbstractProvider.php | 4 ++++ Tests/Doctrine/AbstractProviderTest.php | 26 +++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/Doctrine/AbstractProvider.php b/Doctrine/AbstractProvider.php index a662fd4..92be6ce 100644 --- a/Doctrine/AbstractProvider.php +++ b/Doctrine/AbstractProvider.php @@ -69,6 +69,10 @@ abstract class AbstractProvider extends BaseAbstractProvider $loggerClosure('Entire batch was filtered away, skipping...'); } + if ($this->options['clear_object_manager']) { + $manager->clear(); + } + continue; } diff --git a/Tests/Doctrine/AbstractProviderTest.php b/Tests/Doctrine/AbstractProviderTest.php index 99ed2de..a129a6c 100644 --- a/Tests/Doctrine/AbstractProviderTest.php +++ b/Tests/Doctrine/AbstractProviderTest.php @@ -122,6 +122,32 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase $provider->populate(); } + public function testPopulateShouldClearObjectManagerForFilteredBatch() + { + $nbObjects = 1; + $objects = array(1); + + $provider = $this->getMockAbstractProvider(); + + $provider->expects($this->any()) + ->method('countObjects') + ->will($this->returnValue($nbObjects)); + + $provider->expects($this->any()) + ->method('fetchSlice') + ->will($this->returnValue($objects)); + + $this->indexable->expects($this->any()) + ->method('isObjectIndexable') + ->with('index', 'type', $this->anything()) + ->will($this->returnValue(false)); + + $this->objectManager->expects($this->once()) + ->method('clear'); + + $provider->populate(); + } + public function testPopulateInvokesLoggerClosure() { $nbObjects = 1; From 2664fec35e3edc88a41602bb5e728fa7711755d0 Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Fri, 14 Nov 2014 16:33:17 +0100 Subject: [PATCH 359/447] adjust to symfony 3.0 development having started. whenever there is a new 2.x branch in symfony, we should add it to the matrix --- .travis.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 02f3ab8..2fe1ced 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,7 @@ language: php php: - 5.3 + - 5.4 - 5.5 - 5.6 @@ -9,10 +10,12 @@ matrix: include: - php: 5.5 env: SYMFONY_VERSION='2.3.*' + - php: 5.5 + env: SYMFONY_VERSION='2.4.*' - php: 5.5 env: SYMFONY_VERSION='2.5.*' - php: 5.5 - env: SYMFONY_VERSION='dev-master' + env: SYMFONY_VERSION='2.6.*' before_script: - /usr/share/elasticsearch/bin/elasticsearch -v From 97848ca0d05bb1a648b024bd18ec0fc31214c738 Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Wed, 17 Dec 2014 14:23:00 +0100 Subject: [PATCH 360/447] Removed the testing on Symfony dev-master dev-master is Symfony 3.0, and we are not yet marking it as compatible --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 02f3ab8..a83f9b9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,7 @@ language: php php: - 5.3 + - 5.4 - 5.5 - 5.6 @@ -11,8 +12,6 @@ matrix: env: SYMFONY_VERSION='2.3.*' - php: 5.5 env: SYMFONY_VERSION='2.5.*' - - php: 5.5 - env: SYMFONY_VERSION='dev-master' before_script: - /usr/share/elasticsearch/bin/elasticsearch -v From eaa32cbf22acf6594c816a5b99abb92152c004ad Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Tue, 23 Dec 2014 15:19:52 +0100 Subject: [PATCH 361/447] Fix the BC layer for indexable callbacks Using services was not based on a @ prefix in the string in the old API but based on the existence of the class. --- DependencyInjection/Configuration.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index b204f0c..a506853 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -199,7 +199,17 @@ class Configuration implements ConfigurationInterface isset($v['persistence']['listener']['is_indexable_callback']); }) ->then(function ($v) { - $v['indexable_callback'] = $v['persistence']['listener']['is_indexable_callback']; + $callback = $v['persistence']['listener']['is_indexable_callback']; + + if (is_array($callback)) { + list($class) = $callback + array(null); + + if (is_string($class) && !class_exists($class)) { + $callback[0] = '@'.$class; + } + } + + $v['indexable_callback'] = $callback; unset($v['persistence']['listener']['is_indexable_callback']); return $v; From 1f7acc563a04102cf64bf9d2eb4e691c69f08ce7 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Wed, 24 Dec 2014 09:09:45 +1100 Subject: [PATCH 362/447] Ignore strings starting with @ --- DependencyInjection/Configuration.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index a506853..fa2c048 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -204,7 +204,7 @@ class Configuration implements ConfigurationInterface if (is_array($callback)) { list($class) = $callback + array(null); - if (is_string($class) && !class_exists($class)) { + if ($class[0] !== '@' && is_string($class) && !class_exists($class)) { $callback[0] = '@'.$class; } } From 3975ed3d5b69d88a3654d3421df9a096ee12f152 Mon Sep 17 00:00:00 2001 From: Danijel Brkic Date: Wed, 19 Nov 2014 14:21:31 +0100 Subject: [PATCH 363/447] Built-in templates use a base64 encoded image for the toolbar --- Resources/views/Collector/elastica.html.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/views/Collector/elastica.html.twig b/Resources/views/Collector/elastica.html.twig index e6d7072..82a3dcf 100644 --- a/Resources/views/Collector/elastica.html.twig +++ b/Resources/views/Collector/elastica.html.twig @@ -23,7 +23,7 @@ {% block menu %} - + Elastica {{ collector.querycount }} From 5eaff9e61ba19a3af16614a767193a001308c930 Mon Sep 17 00:00:00 2001 From: DjangoFR Date: Thu, 4 Dec 2014 16:40:10 +0100 Subject: [PATCH 364/447] removed unused image (being base64 encoded - see #742) --- Resources/public/images/elastica.png | Bin 1049 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Resources/public/images/elastica.png diff --git a/Resources/public/images/elastica.png b/Resources/public/images/elastica.png deleted file mode 100644 index dbde0146fc9dab7535af943404cd5ef7e35128ae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1049 zcmV+!1m^pRP)Px#0%A)?L;(MXkIcUS000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipn+4h=D% z5t_#U00W&#L_t(I%XQOBY}8d0$MNsE_doL=W;(Rf4wmw;MQo`&)Tj#)f|`&Rf?^^Y zSx7=$sL_Qcw4!Ar*pQ$L1x$d5u`XDs!G+O4XiP9X)G81N1ZWKf5omanPCM`ay~jn1 zu_XQ$XZ6X+$-Ut$V0z;{X0RiIZiIW%*xS3S9@xInBAYvr@WPTCO`Ge z)ZypF+9UC2>PVT!8M7X0ZfTRD(<2XRv%6v+p#8qK*IU=M zPU}ChxJPHjPPO$lxs-&&B_7mFOSY!6jl<{1ijA_!&a-sTt&eMA)j`>zQNyv;t7#i2 z5Tg_e1EG(%g}EEU*PApO5a>cxHdgn^0s~{oTxbF;1}ia%CB{yK&046xB}JDoiW+XR zzxSM`4AuwEVANm;uvp?II#<3Bjey4}idQF48BhqLDc*<`4X^|RSc(2D4UHzFn8SEf z6$N$-R_^#zt|>V^kr9jrjE@t!yuUWPQWGng17%m^Z~{=-US;Hw!PeYMEBGtvBa4r}n9tNvyJqGwdAiGQ^aJ|R(f)}q-#Pl4)j$Gb zC`CMwxSi?j+5^F%?j=v?60IGld!95a`x%mWQ420Dn4aIAjUqcJ5%dHb&yCZC$* zIqDY`Kgoth@pzJapPIr#7WHMm%&~m39*ugUThYrtZXz5iHN3lY_r^c2Wp;l(w4UBc zww!gFq6YV7RG>X<|8Cy(w#WG2WE$&+(ub4NAW#(2nw=YZ5h5U<1Q;w;JQ1agCY@*u z0#zN=q<-peg9C&r22jdGI3j#1s_|pK3V~MiD_!l|!2{z}@Hir(3GPb%8*acqd)&1> T1X+Rr00000NkvXXu0mjf+yUwb From 156884527c78c2f6d72df016b86c35a5d9048380 Mon Sep 17 00:00:00 2001 From: Evan Owens Date: Tue, 30 Dec 2014 08:43:50 -0500 Subject: [PATCH 365/447] Update example FOS\ElasticaBundle\Client has been deprecated. --- Resources/doc/cookbook/suppress-server-errors.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/doc/cookbook/suppress-server-errors.md b/Resources/doc/cookbook/suppress-server-errors.md index e4e371e..72c7b38 100644 --- a/Resources/doc/cookbook/suppress-server-errors.md +++ b/Resources/doc/cookbook/suppress-server-errors.md @@ -23,7 +23,7 @@ namespace Acme\ElasticaBundle; use Elastica\Exception\ExceptionInterface; use Elastica\Request; use Elastica\Response; -use FOS\ElasticaBundle\Client as BaseClient; +use FOS\ElasticaBundle\Elastica\Client as BaseClient; class Client extends BaseClient { From d731443aa5ad7a12c133bd1d7b97fa242c546e1e Mon Sep 17 00:00:00 2001 From: Dmitry Korotovsky Date: Sat, 18 Oct 2014 21:25:38 +0400 Subject: [PATCH 366/447] Avoid Doctrine\Listener::getSubscribedEvents() call on each page where doctrine is active --- DependencyInjection/FOSElasticaExtension.php | 12 +++++++---- Doctrine/Listener.php | 21 +------------------- Resources/config/orm.xml | 1 - Tests/Doctrine/AbstractListenerTest.php | 12 +++++------ 4 files changed, 15 insertions(+), 31 deletions(-) diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 804be44..51b092b 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -464,18 +464,22 @@ class FOSElasticaExtension extends Extension $listenerId = sprintf('fos_elastica.listener.%s.%s', $indexName, $typeName); $listenerDef = new DefinitionDecorator($abstractListenerId); $listenerDef->replaceArgument(0, new Reference($objectPersisterId)); - $listenerDef->replaceArgument(1, $this->getDoctrineEvents($typeConfig)); - $listenerDef->replaceArgument(3, array( + $listenerDef->replaceArgument(2, array( 'identifier' => $typeConfig['identifier'], 'indexName' => $indexName, 'typeName' => $typeName, )); if ($typeConfig['listener']['logger']) { - $listenerDef->replaceArgument(4, new Reference($typeConfig['listener']['logger'])); + $listenerDef->replaceArgument(3, new Reference($typeConfig['listener']['logger'])); } switch ($typeConfig['driver']) { - case 'orm': $listenerDef->addTag('doctrine.event_subscriber'); break; + case 'orm': + foreach ($this->getDoctrineEvents($typeConfig) as $event) { + $listenerDef->addTag('doctrine.event_listener', array('event' => $event)); + } + + break; case 'mongodb': $listenerDef->addTag('doctrine_mongodb.odm.event_subscriber'); break; } diff --git a/Doctrine/Listener.php b/Doctrine/Listener.php index 039ddaa..aabee53 100644 --- a/Doctrine/Listener.php +++ b/Doctrine/Listener.php @@ -2,7 +2,6 @@ namespace FOS\ElasticaBundle\Doctrine; -use Doctrine\Common\EventSubscriber; use Doctrine\Common\Persistence\Event\LifecycleEventArgs; use FOS\ElasticaBundle\Persister\ObjectPersisterInterface; use FOS\ElasticaBundle\Persister\ObjectPersister; @@ -14,7 +13,7 @@ use Symfony\Component\PropertyAccess\PropertyAccessorInterface; * Automatically update ElasticSearch based on changes to the Doctrine source * data. One listener is generated for each Doctrine entity / ElasticSearch type. */ -class Listener implements EventSubscriber +class Listener { /** * Object persister @@ -23,13 +22,6 @@ class Listener implements EventSubscriber */ protected $objectPersister; - /** - * List of subscribed events - * - * @var array - */ - protected $events; - /** * Configuration for the listener * @@ -74,14 +66,12 @@ class Listener implements EventSubscriber * Constructor. * * @param ObjectPersisterInterface $objectPersister - * @param array $events * @param IndexableInterface $indexable * @param array $config * @param null $logger */ public function __construct( ObjectPersisterInterface $objectPersister, - array $events, IndexableInterface $indexable, array $config = array(), $logger = null @@ -89,7 +79,6 @@ class Listener implements EventSubscriber $this->config = array_merge(array( 'identifier' => 'id', ), $config); - $this->events = $events; $this->indexable = $indexable; $this->objectPersister = $objectPersister; $this->propertyAccessor = PropertyAccess::createPropertyAccessor(); @@ -99,14 +88,6 @@ class Listener implements EventSubscriber } } - /** - * @see Doctrine\Common\EventSubscriber::getSubscribedEvents() - */ - public function getSubscribedEvents() - { - return $this->events; - } - /** * Looks for new objects that should be indexed. * diff --git a/Resources/config/orm.xml b/Resources/config/orm.xml index 94f21d4..2d033ee 100644 --- a/Resources/config/orm.xml +++ b/Resources/config/orm.xml @@ -22,7 +22,6 @@ - diff --git a/Tests/Doctrine/AbstractListenerTest.php b/Tests/Doctrine/AbstractListenerTest.php index 7242255..6415053 100644 --- a/Tests/Doctrine/AbstractListenerTest.php +++ b/Tests/Doctrine/AbstractListenerTest.php @@ -16,7 +16,7 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase $eventArgs = $this->createLifecycleEventArgs($entity, $this->getMockObjectManager()); $indexable = $this->getMockIndexable('index', 'type', $entity, true); - $listener = $this->createListener($persister, array(), $indexable, array('indexName' => 'index', 'typeName' => 'type')); + $listener = $this->createListener($persister, $indexable, array('indexName' => 'index', 'typeName' => 'type')); $listener->postPersist($eventArgs); $this->assertEquals($entity, current($listener->scheduledForInsertion)); @@ -35,7 +35,7 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase $eventArgs = $this->createLifecycleEventArgs($entity, $this->getMockObjectManager()); $indexable = $this->getMockIndexable('index', 'type', $entity, false); - $listener = $this->createListener($persister, array(), $indexable, array('indexName' => 'index', 'typeName' => 'type')); + $listener = $this->createListener($persister, $indexable, array('indexName' => 'index', 'typeName' => 'type')); $listener->postPersist($eventArgs); $this->assertEmpty($listener->scheduledForInsertion); @@ -55,7 +55,7 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase $eventArgs = $this->createLifecycleEventArgs($entity, $this->getMockObjectManager()); $indexable = $this->getMockIndexable('index', 'type', $entity, true); - $listener = $this->createListener($persister, array(), $indexable, array('indexName' => 'index', 'typeName' => 'type')); + $listener = $this->createListener($persister, $indexable, array('indexName' => 'index', 'typeName' => 'type')); $listener->postUpdate($eventArgs); $this->assertEquals($entity, current($listener->scheduledForUpdate)); @@ -89,7 +89,7 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase ->with($entity, 'id') ->will($this->returnValue($entity->getId())); - $listener = $this->createListener($persister, array(), $indexable, array('indexName' => 'index', 'typeName' => 'type')); + $listener = $this->createListener($persister, $indexable, array('indexName' => 'index', 'typeName' => 'type')); $listener->postUpdate($eventArgs); $this->assertEmpty($listener->scheduledForUpdate); @@ -124,7 +124,7 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase ->with($entity, 'id') ->will($this->returnValue($entity->getId())); - $listener = $this->createListener($persister, array(), $indexable, array('indexName' => 'index', 'typeName' => 'type')); + $listener = $this->createListener($persister, $indexable, array('indexName' => 'index', 'typeName' => 'type')); $listener->preRemove($eventArgs); $this->assertEquals($entity->getId(), current($listener->scheduledForDeletion)); @@ -157,7 +157,7 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase ->with($entity, 'identifier') ->will($this->returnValue($entity->getId())); - $listener = $this->createListener($persister, array(), $indexable, array('identifier' => 'identifier', 'indexName' => 'index', 'typeName' => 'type')); + $listener = $this->createListener($persister, $indexable, array('identifier' => 'identifier', 'indexName' => 'index', 'typeName' => 'type')); $listener->preRemove($eventArgs); $this->assertEquals($entity->identifier, current($listener->scheduledForDeletion)); From 7fac93ff8bcd4f26118f7f032bd88ee8a0fdc844 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Sun, 4 Jan 2015 20:16:32 +1100 Subject: [PATCH 367/447] Fix mongodb doctrine listener --- CHANGELOG-3.1.md | 11 +++++++---- DependencyInjection/FOSElasticaExtension.php | 16 +++++++++++----- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/CHANGELOG-3.1.md b/CHANGELOG-3.1.md index 730126f..0ce44ad 100644 --- a/CHANGELOG-3.1.md +++ b/CHANGELOG-3.1.md @@ -9,8 +9,11 @@ https://github.com/FriendsOfSymfony/FOSElasticaBundle/commit/XXX where XXX is the commit hash. To get the diff between two versions, go to https://github.com/FriendsOfSymfony/FOSElasticaBundle/compare/v3.0.4...v3.1.0 -* 3.1.0 +* 3.1.0 (Unreleased) -* BC BREAK: `DoctrineListener#scheduleForDeletion` access changed to private. -* BC BREAK: `ObjectPersisterInterface` gains the method `handlesObject` that - returns a boolean value if it will handle a given object or not. + * BC BREAK: `Doctrine\Listener#scheduleForDeletion` access changed to private. + * BC BREAK: `ObjectPersisterInterface` gains the method `handlesObject` that + returns a boolean value if it will handle a given object or not. + * Removed `Doctrine\Listener#getSubscribedEvents`. The container + configuration now configures tags with the methods to call to avoid loading + this class on every request where doctrine is active. diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 51b092b..565ba33 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -473,14 +473,20 @@ class FOSElasticaExtension extends Extension $listenerDef->replaceArgument(3, new Reference($typeConfig['listener']['logger'])); } + $tagName = null; switch ($typeConfig['driver']) { case 'orm': - foreach ($this->getDoctrineEvents($typeConfig) as $event) { - $listenerDef->addTag('doctrine.event_listener', array('event' => $event)); - } - + $tagName = 'doctrine.event_listener'; break; - case 'mongodb': $listenerDef->addTag('doctrine_mongodb.odm.event_subscriber'); break; + case 'mongodb': + $tagName = 'doctrine_mongodb.odm.event_listener'; + break; + } + + if ($tagName) { + foreach ($this->getDoctrineEvents($typeConfig) as $event) { + $listenerDef->addTag($tagName, array('event' => $event)); + } } $container->setDefinition($listenerId, $listenerDef); From e361b7c53b4f1381c0551b1c20f12b0b915b5145 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Sun, 4 Jan 2015 21:58:53 +1100 Subject: [PATCH 368/447] Implement additional configuration options for types. --- CHANGELOG-3.1.md | 4 +++- Configuration/TypeConfig.php | 24 ++++++++++++++++++++ DependencyInjection/Configuration.php | 3 +++ DependencyInjection/FOSElasticaExtension.php | 3 +++ Index/MappingBuilder.php | 20 ++++++++++------ Index/Resetter.php | 3 +++ Tests/Functional/MappingToElasticaTest.php | 4 ++++ Tests/Functional/app/Basic/config.yml | 3 +++ Tests/Functional/app/Serializer/config.yml | 2 +- 9 files changed, 57 insertions(+), 9 deletions(-) diff --git a/CHANGELOG-3.1.md b/CHANGELOG-3.1.md index 0ce44ad..a03de37 100644 --- a/CHANGELOG-3.1.md +++ b/CHANGELOG-3.1.md @@ -14,6 +14,8 @@ https://github.com/FriendsOfSymfony/FOSElasticaBundle/compare/v3.0.4...v3.1.0 * BC BREAK: `Doctrine\Listener#scheduleForDeletion` access changed to private. * BC BREAK: `ObjectPersisterInterface` gains the method `handlesObject` that returns a boolean value if it will handle a given object or not. - * Removed `Doctrine\Listener#getSubscribedEvents`. The container + * BC BREAK: Removed `Doctrine\Listener#getSubscribedEvents`. The container configuration now configures tags with the methods to call to avoid loading this class on every request where doctrine is active. + * Added ability to configure `date_detection`, `numeric_detection` and + `dynamic_date_formats` for types. diff --git a/Configuration/TypeConfig.php b/Configuration/TypeConfig.php index fc9041d..a46cd34 100644 --- a/Configuration/TypeConfig.php +++ b/Configuration/TypeConfig.php @@ -35,6 +35,22 @@ class TypeConfig $this->name = $name; } + /** + * @return bool|null + */ + public function getDateDetection() + { + return $this->getConfig('date_detection'); + } + + /** + * @return array + */ + public function getDynamicDateFormats() + { + return $this->getConfig('dynamic_date_formats'); + } + /** * @return string|null */ @@ -61,6 +77,14 @@ class TypeConfig null; } + /** + * @return bool|null + */ + public function getNumericDetection() + { + return $this->getConfig('numeric_detection'); + } + /** * @return string */ diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index b204f0c..760966e 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -225,7 +225,10 @@ class Configuration implements ConfigurationInterface }) ->end() ->children() + ->booleanNode('date_detection')->end() + ->arrayNode('dynamic_date_formats')->prototype('scalar')->end()->end() ->scalarNode('index_analyzer')->end() + ->booleanNode('numeric_detection')->end() ->scalarNode('search_analyzer')->end() ->variableNode('indexable_callback')->end() ->append($this->getPersistenceNode()) diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 565ba33..529bd29 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -241,6 +241,9 @@ class FOSElasticaExtension extends Extension 'serializer', 'index_analyzer', 'search_analyzer', + 'date_detection', + 'dynamic_date_formats', + 'numeric_detection', ) as $field) { $typeConfig['config'][$field] = array_key_exists($field, $type) ? $type[$field] : diff --git a/Index/MappingBuilder.php b/Index/MappingBuilder.php index 21ae871..996db5f 100644 --- a/Index/MappingBuilder.php +++ b/Index/MappingBuilder.php @@ -58,13 +58,19 @@ class MappingBuilder */ public function buildTypeMapping(TypeConfig $typeConfig) { - $mapping = array_merge($typeConfig->getMapping(), array( - // 'date_detection' => true, - // 'dynamic_date_formats' => array() - // 'dynamic_templates' => $typeConfig->getDynamicTemplates(), - // 'numeric_detection' => false, - // 'properties' => array(), - )); + $mapping = $typeConfig->getMapping(); + + if (null !== $typeConfig->getDynamicDateFormats()) { + $mapping['dynamic_date_formats'] = $typeConfig->getDynamicDateFormats(); + } + + if (null !== $typeConfig->getDateDetection()) { + $mapping['date_detection'] = $typeConfig->getDateDetection(); + } + + if (null !== $typeConfig->getNumericDetection()) { + $mapping['numeric_detection'] = $typeConfig->getNumericDetection(); + } if ($typeConfig->getIndexAnalyzer()) { $mapping['index_analyzer'] = $typeConfig->getIndexAnalyzer(); diff --git a/Index/Resetter.php b/Index/Resetter.php index 9b65a8f..68a43dd 100644 --- a/Index/Resetter.php +++ b/Index/Resetter.php @@ -42,6 +42,9 @@ class Resetter /** * Deletes and recreates all indexes + * + * @param bool $populating + * @param bool $force */ public function resetAllIndexes($populating = false, $force = false) { diff --git a/Tests/Functional/MappingToElasticaTest.php b/Tests/Functional/MappingToElasticaTest.php index f42df61..229a1a2 100644 --- a/Tests/Functional/MappingToElasticaTest.php +++ b/Tests/Functional/MappingToElasticaTest.php @@ -49,6 +49,9 @@ class MappingToElasticaTest extends WebTestCase $mapping = $type->getMapping(); $this->assertNotEmpty($mapping, 'Mapping was populated'); + $this->assertFalse($mapping['type']['date_detection']); + $this->assertTrue($mapping['type']['numeric_detection']); + $this->assertEquals(array('yyyy-MM-dd'), $mapping['type']['dynamic_date_formats']); $this->assertArrayHasKey('store', $mapping['type']['properties']['field1']); $this->assertTrue($mapping['type']['properties']['field1']['store']); $this->assertArrayNotHasKey('store', $mapping['type']['properties']['field2']); @@ -105,6 +108,7 @@ class MappingToElasticaTest extends WebTestCase /** * @param Client $client + * @param string $type * @return \Elastica\Type */ private function getType(Client $client, $type = 'type') diff --git a/Tests/Functional/app/Basic/config.yml b/Tests/Functional/app/Basic/config.yml index 3c3d369..690bf5e 100644 --- a/Tests/Functional/app/Basic/config.yml +++ b/Tests/Functional/app/Basic/config.yml @@ -46,6 +46,8 @@ fos_elastica: index_analyzer: my_analyzer type: search_analyzer: my_analyzer + date_detection: false + dynamic_date_formats: [ 'yyyy-MM-dd' ] dynamic_templates: - dates: match: "date_*" @@ -56,6 +58,7 @@ fos_elastica: mapping: analyzer: english type: string + numeric_detection: true properties: field1: ~ field2: diff --git a/Tests/Functional/app/Serializer/config.yml b/Tests/Functional/app/Serializer/config.yml index 9bea4ba..de7caec 100644 --- a/Tests/Functional/app/Serializer/config.yml +++ b/Tests/Functional/app/Serializer/config.yml @@ -28,7 +28,7 @@ fos_elastica: serializer: ~ indexes: index: - index_name: foselastica_test_%kernel.environment% + index_name: foselastica_ser_test_%kernel.environment% types: type: properties: From 92aab4bcf66ccb992195ad574457d706fcad63e6 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Sun, 4 Jan 2015 22:02:54 +1100 Subject: [PATCH 369/447] Add PR# to changelog --- CHANGELOG-3.1.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG-3.1.md b/CHANGELOG-3.1.md index a03de37..8880675 100644 --- a/CHANGELOG-3.1.md +++ b/CHANGELOG-3.1.md @@ -16,6 +16,6 @@ https://github.com/FriendsOfSymfony/FOSElasticaBundle/compare/v3.0.4...v3.1.0 returns a boolean value if it will handle a given object or not. * BC BREAK: Removed `Doctrine\Listener#getSubscribedEvents`. The container configuration now configures tags with the methods to call to avoid loading - this class on every request where doctrine is active. + this class on every request where doctrine is active. #729 * Added ability to configure `date_detection`, `numeric_detection` and - `dynamic_date_formats` for types. + `dynamic_date_formats` for types. #753 From 6ef6092f3f532a219517e94c7c3fc1fe147b9de0 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Sun, 4 Jan 2015 22:03:19 +1100 Subject: [PATCH 370/447] Update 3.0 changeling --- CHANGELOG-3.0.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG-3.0.md b/CHANGELOG-3.0.md index 2596a29..1a49023 100644 --- a/CHANGELOG-3.0.md +++ b/CHANGELOG-3.0.md @@ -12,6 +12,11 @@ https://github.com/FriendsOfSymfony/FOSElasticaBundle/compare/v3.0.0...v3.0.1 To generate a changelog summary since the last version, run `git log --no-merges --oneline v3.0.0...3.0.x` +* 3.0.6 (Unreleased) + + * Removed unused public image asset for the web development toolbar + * Fixed is_indexable_callback BC code to support array notation + * 3.0.0-ALPHA6 * Moved `is_indexable_callback` from the listener properties to a type property called From 9f5ce217dcf5e628274a7767e20a413e5e0b1197 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Sun, 4 Jan 2015 22:08:20 +1100 Subject: [PATCH 371/447] Release 3.0.6 --- CHANGELOG-3.0.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG-3.0.md b/CHANGELOG-3.0.md index 1a49023..3b9b2ac 100644 --- a/CHANGELOG-3.0.md +++ b/CHANGELOG-3.0.md @@ -12,10 +12,12 @@ https://github.com/FriendsOfSymfony/FOSElasticaBundle/compare/v3.0.0...v3.0.1 To generate a changelog summary since the last version, run `git log --no-merges --oneline v3.0.0...3.0.x` -* 3.0.6 (Unreleased) +* 3.0.6 (2015-01-04) - * Removed unused public image asset for the web development toolbar - * Fixed is_indexable_callback BC code to support array notation + * Removed unused public image asset for the web development toolbar #742 + * Fixed is_indexable_callback BC code to support array notation #761 + * Fixed debug_logger for type providers #724 + * Clean the OM if we filter away the entire batch #737 * 3.0.0-ALPHA6 From 303af508b2029dd199b3a1b21d93fe30114587e9 Mon Sep 17 00:00:00 2001 From: Oleg Andreyev Date: Fri, 21 Nov 2014 16:25:40 +0200 Subject: [PATCH 372/447] adding populate events --- Command/PopulateCommand.php | 74 ++++++++++------ DependencyInjection/FOSElasticaExtension.php | 2 +- Event/PopulateEvent.php | 93 ++++++++++++++++++++ EventListener/PopulateListener.php | 59 +++++++++++++ Resources/config/listener.xml | 18 ++++ 5 files changed, 217 insertions(+), 29 deletions(-) create mode 100644 Event/PopulateEvent.php create mode 100644 EventListener/PopulateListener.php create mode 100644 Resources/config/listener.xml diff --git a/Command/PopulateCommand.php b/Command/PopulateCommand.php index f17ca4c..89d2ebc 100644 --- a/Command/PopulateCommand.php +++ b/Command/PopulateCommand.php @@ -2,15 +2,16 @@ namespace FOS\ElasticaBundle\Command; +use FOS\ElasticaBundle\Event\PopulateEvent; use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; use Symfony\Component\Console\Helper\DialogHelper; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -use FOS\ElasticaBundle\IndexManager; +use FOS\ElasticaBundle\Index\IndexManager; use FOS\ElasticaBundle\Provider\ProviderRegistry; -use FOS\ElasticaBundle\Resetter; use FOS\ElasticaBundle\Provider\ProviderInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; /** * Populate the search index @@ -28,9 +29,9 @@ class PopulateCommand extends ContainerAwareCommand private $providerRegistry; /** - * @var Resetter + * @var EventDispatcherInterface */ - private $resetter; + private $eventDispatcher; /** * @see Symfony\Component\Console\Command\Command::configure() @@ -57,7 +58,7 @@ class PopulateCommand extends ContainerAwareCommand { $this->indexManager = $this->getContainer()->get('fos_elastica.index_manager'); $this->providerRegistry = $this->getContainer()->get('fos_elastica.provider_registry'); - $this->resetter = $this->getContainer()->get('fos_elastica.resetter'); + $this->eventDispatcher = $this->getContainer()->get('event_dispatcher'); } /** @@ -109,24 +110,12 @@ class PopulateCommand extends ContainerAwareCommand */ private function populateIndex(OutputInterface $output, $index, $reset, $options) { - if ($reset) { - $output->writeln(sprintf('Resetting %s', $index)); - $this->resetter->resetIndex($index, true); - } - /** @var $providers ProviderInterface[] */ $providers = $this->providerRegistry->getIndexProviders($index); - foreach ($providers as $type => $provider) { - $loggerClosure = function($message) use ($output, $index, $type) { - $output->writeln(sprintf('Populating %s/%s, %s', $index, $type, $message)); - }; - - $provider->populate($loggerClosure, $options); - } + $this->populate($output, $providers, $index, null, $reset, $options); $output->writeln(sprintf('Refreshing %s', $index)); - $this->resetter->postPopulate($index); $this->indexManager->getIndex($index)->refresh(); } @@ -141,19 +130,48 @@ class PopulateCommand extends ContainerAwareCommand */ private function populateIndexType(OutputInterface $output, $index, $type, $reset, $options) { - if ($reset) { - $output->writeln(sprintf('Resetting %s/%s', $index, $type)); - $this->resetter->resetIndexType($index, $type); - } - - $loggerClosure = function($message) use ($output, $index, $type) { - $output->writeln(sprintf('Populating %s/%s, %s', $index, $type, $message)); - }; - $provider = $this->providerRegistry->getProvider($index, $type); - $provider->populate($loggerClosure, $options); + + $this->populate($output, array($type => $provider), $index, $type, $reset, $options); $output->writeln(sprintf('Refreshing %s', $index)); $this->indexManager->getIndex($index)->refresh(); } + + /** + * @param OutputInterface $output + * @param ProviderInterface[] $providers + * @param string $index + * @param string $type + * @param boolean $reset + * @param array $options + */ + private function populate(OutputInterface $output, array $providers, $index, $type, $reset, $options) + { + if ($reset) { + if ($type) { + $output->writeln(sprintf('Resetting %s/%s', $index, $type)); + } else { + $output->writeln(sprintf('Resetting %s', $index)); + } + } + + $this->eventDispatcher->dispatch(PopulateEvent::PRE_INDEX_POPULATE, new PopulateEvent($index, $type, $reset, $options)); + + foreach ($providers as $providerType => $provider) { + $event = new PopulateEvent($index, $providerType, $reset, $options); + + $this->eventDispatcher->dispatch(PopulateEvent::PRE_TYPE_POPULATE, $event); + + $loggerClosure = function($message) use ($output, $index, $providerType) { + $output->writeln(sprintf('Populating %s/%s, %s', $index, $providerType, $message)); + }; + + $provider->populate($loggerClosure, $options); + + $this->eventDispatcher->dispatch(PopulateEvent::POST_TYPE_POPULATE, $event); + } + + $this->eventDispatcher->dispatch(PopulateEvent::POST_INDEX_POPULATE, new PopulateEvent($index, $type, $reset, $options)); + } } diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 565ba33..705da12 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -46,7 +46,7 @@ class FOSElasticaExtension extends Extension return; } - foreach (array('config', 'index', 'persister', 'provider', 'source', 'transformer') as $basename) { + foreach (array('config', 'index', 'persister', 'provider', 'source', 'transformer', 'listener') as $basename) { $loader->load(sprintf('%s.xml', $basename)); } diff --git a/Event/PopulateEvent.php b/Event/PopulateEvent.php new file mode 100644 index 0000000..9bf9dbb --- /dev/null +++ b/Event/PopulateEvent.php @@ -0,0 +1,93 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FOS\ElasticaBundle\Event; + +use Symfony\Component\EventDispatcher\Event; + +/** + * Populate Event + * + * @author Oleg Andreyev + */ +class PopulateEvent extends Event +{ + const PRE_INDEX_POPULATE = 'elastica.index.index_pre_populate'; + const POST_INDEX_POPULATE = 'elastica.index.index_post_populate'; + + const PRE_TYPE_POPULATE = 'elastica.index.type_pre_populate'; + const POST_TYPE_POPULATE = 'elastica.index.type_post_populate'; + + /** + * @var string + */ + private $index; + + /** + * @var string + */ + private $type; + + /** + * @var bool + */ + private $reset; + + /** + * @var array + */ + private $options; + + /** + * @param string $index + * @param string $type + * @param boolean $reset + * @param array $options + */ + public function __construct($index, $type, $reset, $options) + { + $this->index = $index; + $this->type = $type; + $this->reset = $reset; + $this->options = $options; + } + + /** + * @return string + */ + public function getIndex() + { + return $this->index; + } + + /** + * @return string + */ + public function getType() + { + return $this->type; + } + + /** + * @return boolean + */ + public function isReset() + { + return $this->reset; + } + + /** + * @return array + */ + public function getOptions() + { + return $this->options; + } +} diff --git a/EventListener/PopulateListener.php b/EventListener/PopulateListener.php new file mode 100644 index 0000000..a2a0f5a --- /dev/null +++ b/EventListener/PopulateListener.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FOS\ElasticaBundle\EventListener; + +use FOS\ElasticaBundle\Event\PopulateEvent; +use FOS\ElasticaBundle\Index\Resetter; + +/** + * PopulateListener + * + * @author Oleg Andreyev + */ +class PopulateListener +{ + /** + * @var Resetter + */ + private $resetter; + + /** + * @param Resetter $resetter + */ + public function __construct(Resetter $resetter) + { + $this->resetter = $resetter; + } + + /** + * @param PopulateEvent $event + */ + public function preIndexPopulate(PopulateEvent $event) + { + if (!$event->isReset()) { + return; + } + + if (null !== $event->getType()) { + $this->resetter->resetIndexType($event->getIndex(), $event->getType()); + } else { + $this->resetter->resetIndex($event->getIndex(), true); + } + } + + /** + * @param PopulateEvent $event + */ + public function postIndexPopulate(PopulateEvent $event) + { + $this->resetter->postPopulate($event->getIndex()); + } +} diff --git a/Resources/config/listener.xml b/Resources/config/listener.xml new file mode 100644 index 0000000..6c586bf --- /dev/null +++ b/Resources/config/listener.xml @@ -0,0 +1,18 @@ + + + + + + FOS\ElasticaBundle\EventListener\PopulateListener + + + + + + + + + + From afbe1e03a1cf9e3e978decbf26ac0b3b1877dcae Mon Sep 17 00:00:00 2001 From: Oleg Andreyev Date: Sun, 4 Jan 2015 13:34:59 +0200 Subject: [PATCH 373/447] adding unit test for PopulateListener --- Event/PopulateEvent.php | 8 +-- Tests/EventListener/PopulateListenerTest.php | 54 ++++++++++++++++++++ 2 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 Tests/EventListener/PopulateListenerTest.php diff --git a/Event/PopulateEvent.php b/Event/PopulateEvent.php index 9bf9dbb..305c393 100644 --- a/Event/PopulateEvent.php +++ b/Event/PopulateEvent.php @@ -46,10 +46,10 @@ class PopulateEvent extends Event private $options; /** - * @param string $index - * @param string $type - * @param boolean $reset - * @param array $options + * @param string $index + * @param string|null $type + * @param boolean $reset + * @param array $options */ public function __construct($index, $type, $reset, $options) { diff --git a/Tests/EventListener/PopulateListenerTest.php b/Tests/EventListener/PopulateListenerTest.php new file mode 100644 index 0000000..6388e79 --- /dev/null +++ b/Tests/EventListener/PopulateListenerTest.php @@ -0,0 +1,54 @@ +resetter = $this->getMockBuilder('FOS\ElasticaBundle\Index\Resetter') + ->disableOriginalConstructor() + ->getMock(); + + $this->listener = new PopulateListener($this->resetter); + } + + public function testPostIndexPopulate() + { + $this->resetter->expects($this->once())->method('postPopulate')->with('indexName'); + $this->listener->postIndexPopulate(new PopulateEvent('indexName', null, true, array())); + } + + public function testPreIndexPopulateWhenNoResetRequired() + { + $this->resetter->expects($this->never())->method('resetIndex'); + $this->resetter->expects($this->never())->method('resetIndexType'); + $this->listener->preIndexPopulate(new PopulateEvent('indexName', null, false, array())); + } + + public function testPreIndexPopulateWhenResetIsRequiredAndNoTypeIsSpecified() + { + $this->resetter->expects($this->once())->method('resetIndex')->with('indexName'); + $this->listener->preIndexPopulate(new PopulateEvent('indexName', null, true, array())); + } + + public function testPreIndexPopulateWhenResetIsRequiredAndTypeIsSpecified() + { + $this->resetter->expects($this->once())->method('resetIndexType')->with('indexName', 'indexType'); + $this->listener->preIndexPopulate(new PopulateEvent('indexName', 'indexType', true, array())); + } +} From 7efcdad97c3278407e08c74221641a8a7faf258d Mon Sep 17 00:00:00 2001 From: Oleg Andreyev Date: Sun, 4 Jan 2015 14:00:12 +0200 Subject: [PATCH 374/447] adding ResetEvent (pre/post index and pre/post type reset), injected EventDispatcher into Resetter --- Event/ResetEvent.php | 85 ++++++++++++++++++++++++++++++++++++ Index/Resetter.php | 44 ++++++++++++++++--- Resources/config/index.xml | 1 + Tests/Index/ResetterTest.php | 5 ++- 4 files changed, 127 insertions(+), 8 deletions(-) create mode 100644 Event/ResetEvent.php diff --git a/Event/ResetEvent.php b/Event/ResetEvent.php new file mode 100644 index 0000000..04034af --- /dev/null +++ b/Event/ResetEvent.php @@ -0,0 +1,85 @@ + + */ +class ResetEvent extends Event +{ + const PRE_INDEX_RESET = 'elastica.index.pre_reset'; + const POST_INDEX_RESET = 'elastica.index.post_reset'; + + const PRE_TYPE_RESET = 'elastica.index.type_pre_reset'; + const POST_TYPE_RESET = 'elastica.index.type_post_reset'; + + /** + * @var string + */ + private $indexName; + + /** + * @var string + */ + private $indexType; + + /** + * @var bool + */ + private $populating; + + /** + * @var bool + */ + private $force; + + /** + * @param string $indexName + * @param string $indexType + * @param bool $populating + * @param bool $force + */ + public function __construct($indexName, $indexType, $populating = false, $force = false) + { + $this->indexName = $indexName; + $this->indexType = $indexType; + $this->populating = (bool)$populating; + $this->force = (bool)$force; + } + + /** + * @return string + */ + public function getIndexName() + { + return $this->indexName; + } + + /** + * @return string + */ + public function getIndexType() + { + return $this->indexType; + } + + /** + * @return boolean + */ + public function isPopulating() + { + return $this->populating; + } + + /** + * @return boolean + */ + public function isForce() + { + return $this->force; + } +} \ No newline at end of file diff --git a/Index/Resetter.php b/Index/Resetter.php index 9b65a8f..996bfdf 100644 --- a/Index/Resetter.php +++ b/Index/Resetter.php @@ -6,6 +6,8 @@ use Elastica\Index; use Elastica\Exception\ResponseException; use Elastica\Type\Mapping; use FOS\ElasticaBundle\Configuration\ConfigManager; +use FOS\ElasticaBundle\Event\ResetEvent; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; /** * Deletes and recreates indexes @@ -18,7 +20,7 @@ class Resetter private $aliasProcessor; /*** - * @var \FOS\ElasticaBundle\Configuration\Manager + * @var ConfigManager */ private $configManager; @@ -32,12 +34,30 @@ class Resetter */ private $mappingBuilder; - public function __construct(ConfigManager $configManager, IndexManager $indexManager, AliasProcessor $aliasProcessor, MappingBuilder $mappingBuilder) - { - $this->aliasProcessor = $aliasProcessor; - $this->configManager = $configManager; - $this->indexManager = $indexManager; - $this->mappingBuilder = $mappingBuilder; + /** + * @var EventDispatcherInterface + */ + private $eventDispatcher; + + /** + * @param ConfigManager $configManager + * @param IndexManager $indexManager + * @param AliasProcessor $aliasProcessor + * @param MappingBuilder $mappingBuilder + * @param EventDispatcherInterface $eventDispatcher + */ + public function __construct( + ConfigManager $configManager, + IndexManager $indexManager, + AliasProcessor $aliasProcessor, + MappingBuilder $mappingBuilder, + EventDispatcherInterface $eventDispatcher + ) { + $this->aliasProcessor = $aliasProcessor; + $this->configManager = $configManager; + $this->indexManager = $indexManager; + $this->mappingBuilder = $mappingBuilder; + $this->eventDispatcher = $eventDispatcher; } /** @@ -61,6 +81,9 @@ class Resetter */ public function resetIndex($indexName, $populating = false, $force = false) { + $event = new ResetEvent($indexName, null, $populating, $force); + $this->eventDispatcher->dispatch(ResetEvent::PRE_INDEX_RESET, $event); + $indexConfig = $this->configManager->getIndexConfiguration($indexName); $index = $this->indexManager->getIndex($indexName); @@ -74,6 +97,8 @@ class Resetter if (!$populating and $indexConfig->isUseAlias()) { $this->aliasProcessor->switchIndexAlias($indexConfig, $index, $force); } + + $this->eventDispatcher->dispatch(ResetEvent::POST_INDEX_RESET, $event); } /** @@ -86,6 +111,9 @@ class Resetter */ public function resetIndexType($indexName, $typeName) { + $event = new ResetEvent($indexName, $typeName); + $this->eventDispatcher->dispatch(ResetEvent::PRE_TYPE_RESET, $event); + $typeConfig = $this->configManager->getTypeConfiguration($indexName, $typeName); $type = $this->indexManager->getIndex($indexName)->getType($typeName); @@ -103,6 +131,8 @@ class Resetter } $type->setMapping($mapping); + + $this->eventDispatcher->dispatch(ResetEvent::POST_TYPE_RESET, $event); } /** diff --git a/Resources/config/index.xml b/Resources/config/index.xml index 11586ff..3ae2e50 100644 --- a/Resources/config/index.xml +++ b/Resources/config/index.xml @@ -41,6 +41,7 @@ + diff --git a/Tests/Index/ResetterTest.php b/Tests/Index/ResetterTest.php index 28f0a68..35a0bd9 100644 --- a/Tests/Index/ResetterTest.php +++ b/Tests/Index/ResetterTest.php @@ -36,8 +36,11 @@ class ResetterTest extends \PHPUnit_Framework_TestCase $this->mappingBuilder = $this->getMockBuilder('FOS\\ElasticaBundle\\Index\\MappingBuilder') ->disableOriginalConstructor() ->getMock(); + $this->resetter = $this->getMockBuilder('FOS\ElasticaBundle\Index\Resetter') + ->disableOriginalConstructor() + ->getMock(); - $this->resetter = new Resetter($this->configManager, $this->indexManager, $this->aliasProcessor, $this->mappingBuilder); + $this->resetter = new Resetter($this->configManager, $this->indexManager, $this->aliasProcessor, $this->mappingBuilder, $this->resetter); /*$this->indexConfigsByName = array( 'foo' => array( From 7c90660e02e45e7dbab20bfd2b3e5159c089a29d Mon Sep 17 00:00:00 2001 From: Oleg Andreyev Date: Sun, 4 Jan 2015 20:57:08 +0200 Subject: [PATCH 375/447] attempt to make scrutinizer happy, about duplicate code in test --- Tests/EventListener/PopulateListenerTest.php | 49 +++++++++++++++----- 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/Tests/EventListener/PopulateListenerTest.php b/Tests/EventListener/PopulateListenerTest.php index 6388e79..3d653d3 100644 --- a/Tests/EventListener/PopulateListenerTest.php +++ b/Tests/EventListener/PopulateListenerTest.php @@ -33,22 +33,47 @@ class PopulateListenerTest extends \PHPUnit_Framework_TestCase $this->listener->postIndexPopulate(new PopulateEvent('indexName', null, true, array())); } - public function testPreIndexPopulateWhenNoResetRequired() + public function preIndexPopulateDataProvider() { - $this->resetter->expects($this->never())->method('resetIndex'); - $this->resetter->expects($this->never())->method('resetIndexType'); - $this->listener->preIndexPopulate(new PopulateEvent('indexName', null, false, array())); + return array( + array( + array( + array('resetIndex', $this->never()), + array('resetIndexType', $this->never()) + ), + array('indexName', true), + new PopulateEvent('indexName', null, false, array()) + ), + array( + array( + array('resetIndex', $this->once()) + ), + array('indexName', true), + new PopulateEvent('indexName', null, true, array()) + ), + array( + array( + array('resetIndexType', $this->once()) + ), + array('indexName', 'indexType'), + new PopulateEvent('indexName', 'indexType', true, array()) + ) + ); } - public function testPreIndexPopulateWhenResetIsRequiredAndNoTypeIsSpecified() + /** + * @param array $asserts + * @param array $withArgs + * @param PopulateEvent $event + * + * @dataProvider preIndexPopulateDataProvider + */ + public function testPreIndexPopulate(array $asserts, array $withArgs, PopulateEvent $event) { - $this->resetter->expects($this->once())->method('resetIndex')->with('indexName'); - $this->listener->preIndexPopulate(new PopulateEvent('indexName', null, true, array())); - } + foreach ($asserts as $assert) { + $this->resetter->expects($assert[1])->method($assert[0])->with($withArgs[0], $withArgs[1]); + } - public function testPreIndexPopulateWhenResetIsRequiredAndTypeIsSpecified() - { - $this->resetter->expects($this->once())->method('resetIndexType')->with('indexName', 'indexType'); - $this->listener->preIndexPopulate(new PopulateEvent('indexName', 'indexType', true, array())); + $this->listener->preIndexPopulate($event); } } From a0f11ff36f012455df8ba081fce36913832a460d Mon Sep 17 00:00:00 2001 From: Vladimir Kartaviy Date: Wed, 7 Jan 2015 16:45:18 +0200 Subject: [PATCH 376/447] Fix ODM listener service arguments It became broken after https://github.com/FriendsOfSymfony/FOSElasticaBundle/commit/d731443aa5ad7a12c133bd1d7b97fa242c546e1e commit --- Resources/config/mongodb.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/Resources/config/mongodb.xml b/Resources/config/mongodb.xml index 8e15533..703c1d2 100644 --- a/Resources/config/mongodb.xml +++ b/Resources/config/mongodb.xml @@ -23,7 +23,6 @@ - From 905265ea0ebd0f0166de3f8ace63bcc995cb1cee Mon Sep 17 00:00:00 2001 From: Vladimir Kartaviy Date: Wed, 7 Jan 2015 16:49:46 +0200 Subject: [PATCH 377/447] "multi_field" type fields are not normalized Fix for #764 --- Index/MappingBuilder.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Index/MappingBuilder.php b/Index/MappingBuilder.php index 21ae871..9782e84 100644 --- a/Index/MappingBuilder.php +++ b/Index/MappingBuilder.php @@ -107,6 +107,9 @@ class MappingBuilder if (!isset($property['type'])) { $property['type'] = 'string'; } + if ($property['type'] == 'multi_field' && isset($property['fields'])) { + $this->fixProperties($property['fields']); + } if (isset($property['properties'])) { $this->fixProperties($property['properties']); } From 2ce2d7e61053a7b7efbce73113ec455d23409eca Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Fri, 9 Jan 2015 08:55:57 +1100 Subject: [PATCH 378/447] Add test for multi_field --- CHANGELOG-3.0.md | 4 ++++ Tests/Functional/app/Basic/config.yml | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/CHANGELOG-3.0.md b/CHANGELOG-3.0.md index 3b9b2ac..ecb5dad 100644 --- a/CHANGELOG-3.0.md +++ b/CHANGELOG-3.0.md @@ -12,6 +12,10 @@ https://github.com/FriendsOfSymfony/FOSElasticaBundle/compare/v3.0.0...v3.0.1 To generate a changelog summary since the last version, run `git log --no-merges --oneline v3.0.0...3.0.x` +* 3.0.7 (Unreleased) + + * Fixed multi_field properties not being normalised #769 + * 3.0.6 (2015-01-04) * Removed unused public image asset for the web development toolbar #742 diff --git a/Tests/Functional/app/Basic/config.yml b/Tests/Functional/app/Basic/config.yml index 3c3d369..ebd1ea0 100644 --- a/Tests/Functional/app/Basic/config.yml +++ b/Tests/Functional/app/Basic/config.yml @@ -71,6 +71,11 @@ fos_elastica: properties: date: { boost: 5 } content: ~ + multiple: + type: "multi_field" + properties: + name: ~ + position: ~ user: type: "object" approver: From a28b9d3069f2baf3af57cef2925319ae10d81cbf Mon Sep 17 00:00:00 2001 From: Wouter J Date: Thu, 25 Sep 2014 10:52:51 +0200 Subject: [PATCH 379/447] Applied standard installation template --- Resources/doc/setup.md | 46 +++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/Resources/doc/setup.md b/Resources/doc/setup.md index 16e427f..c4f6784 100644 --- a/Resources/doc/setup.md +++ b/Resources/doc/setup.md @@ -1,40 +1,50 @@ Step 1: Setting up the bundle ============================= -A) Install FOSElasticaBundle ----------------------------- +A: Download the Bundle +---------------------- -FOSElasticaBundle is installed using [Composer](https://getcomposer.org). +Open a command console, enter your project directory and execute the +following command to download the latest stable version of this bundle: ```bash -$ php composer.phar require friendsofsymfony/elastica-bundle +$ composer require friendsofsymfony/elastica-bundle "~3.0" ``` +This command requires you to have Composer installed globally, as explained +in the [installation chapter](https://getcomposer.org/doc/00-intro.md) +of the Composer documentation. + ### Elasticsearch -Instructions for installing and deploying Elasticsearch may be found -[here](http://www.elasticsearch.org/guide/reference/setup/installation/). +Instructions for installing and deploying Elasticsearch may be found [here](http://www.elasticsearch.org/guide/reference/setup/installation/). +Step 2: Enable the Bundle +------------------------- -B) Enable FOSElasticaBundle ---------------------------- - -Enable FOSElasticaBundle in your AppKernel: +Then, enable the bundle by adding the following line in the `app/AppKernel.php` +file of your project: ```php Date: Tue, 20 Jan 2015 14:00:10 +1100 Subject: [PATCH 380/447] Dispatch an event when transforming objects --- CHANGELOG-3.1.md | 2 + Event/TransformEvent.php | 78 +++++++++++++++++++ Resources/config/transformer.xml | 3 +- Resources/doc/cookbook/custom-properties.md | 33 ++++++++ Resources/doc/index.md | 1 + .../ModelToElasticaAutoTransformerTest.php | 25 +++++- .../ModelToElasticaAutoTransformer.php | 18 ++++- 7 files changed, 154 insertions(+), 6 deletions(-) create mode 100644 Event/TransformEvent.php create mode 100644 Resources/doc/cookbook/custom-properties.md diff --git a/CHANGELOG-3.1.md b/CHANGELOG-3.1.md index 8880675..12fbb05 100644 --- a/CHANGELOG-3.1.md +++ b/CHANGELOG-3.1.md @@ -19,3 +19,5 @@ https://github.com/FriendsOfSymfony/FOSElasticaBundle/compare/v3.0.4...v3.1.0 this class on every request where doctrine is active. #729 * Added ability to configure `date_detection`, `numeric_detection` and `dynamic_date_formats` for types. #753 + * New event `POST_TRANSFORM` which allows developers to add custom properties to + Elastica Documents for indexing. diff --git a/Event/TransformEvent.php b/Event/TransformEvent.php new file mode 100644 index 0000000..4f6871f --- /dev/null +++ b/Event/TransformEvent.php @@ -0,0 +1,78 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FOS\ElasticaBundle\Event; + +use Symfony\Component\EventDispatcher\Event; + +class TransformEvent extends Event +{ + const POST_TRANSFORM = 'fos_elastica.post_transform'; + + /** + * @var mixed + */ + private $document; + + /** + * @var array + */ + private $fields; + + /** + * @var mixed + */ + private $object; + + /** + * @param mixed $document + * @param array $fields + * @param mixed $object + */ + public function __construct($document, array $fields, $object) + { + $this->document = $document; + $this->fields = $fields; + $this->object = $object; + } + + /** + * @return mixed + */ + public function getDocument() + { + return $this->document; + } + + /** + * @return array + */ + public function getFields() + { + return $this->fields; + } + + /** + * @return mixed + */ + public function getObject() + { + return $this->object; + } + + /** + * @param mixed $document + */ + public function setDocument($document) + { + $this->document = $document; + } +} diff --git a/Resources/config/transformer.xml b/Resources/config/transformer.xml index 4ce5062..0957152 100644 --- a/Resources/config/transformer.xml +++ b/Resources/config/transformer.xml @@ -12,7 +12,8 @@ - + + diff --git a/Resources/doc/cookbook/custom-properties.md b/Resources/doc/cookbook/custom-properties.md new file mode 100644 index 0000000..cc7751e --- /dev/null +++ b/Resources/doc/cookbook/custom-properties.md @@ -0,0 +1,33 @@ +##### Custom Repositories + +Since FOSElasticaBundle 3.1.0, we now dispatch an event for each transformation of an +object into an Elastica document which allows you to set custom properties on the Elastica +document for indexing. + +Set up an event listener or subscriber for +`FOS\ElasticaBundle\Event\TransformEvent::POST_TRANSFORM` to be able to inject your own +parameters. + +```php +class CustomPropertyListener implements EventSubscriberInterface +{ + private $anotherService; + + // ... + + public function addCustomProperty(TransformEvent $event) + { + $document = $event->getDocument(); + $custom = $this->anotherService->calculateCustom($event->getObject()); + + $document->set('custom', $custom); + } + + public static function getSubscribedEvents() + { + return array( + TransformEvent::POST_TRANSFORM => 'addCustomProperty', + ); + } +} +``` diff --git a/Resources/doc/index.md b/Resources/doc/index.md index 349723b..c856798 100644 --- a/Resources/doc/index.md +++ b/Resources/doc/index.md @@ -13,6 +13,7 @@ Cookbook Entries ---------------- * [Aliased Indexes](cookbook/aliased-indexes.md) +* [Custom Indexed Properties](cookbook/custom-properties.md) * [Custom Repositories](cookbook/custom-repositories.md) * [HTTP Headers for Elastica](cookbook/elastica-client-http-headers.md) * Performance - [Logging](cookbook/logging.md) diff --git a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php index 1fa6a8e..bb52129 100644 --- a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php +++ b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php @@ -2,6 +2,7 @@ namespace FOS\ElasticaBundle\Tests\Transformer\ModelToElasticaAutoTransformer; +use FOS\ElasticaBundle\Event\TransformEvent; use FOS\ElasticaBundle\Transformer\ModelToElasticaAutoTransformer; use Symfony\Component\PropertyAccess\PropertyAccess; @@ -132,6 +133,21 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase } } + public function testTransformerDispatches() + { + $dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface') + ->getMock(); + $dispatcher->expects($this->once()) + ->method('dispatch') + ->with( + TransformEvent::POST_TRANSFORM, + $this->isInstanceOf('FOS\ElasticaBundle\Event\TransformEvent') + ); + + $transformer = $this->getTransformer($dispatcher); + $transformer->transform(new POPO(), array()); + } + public function testThatCanTransformObject() { $transformer = $this->getTransformer(); @@ -295,8 +311,8 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase $this->assertTrue(array_key_exists('obj', $data)); $this->assertInternalType('array', $data['obj']); $this->assertEquals(array( - 'foo' => 'foo', - 'bar' => 'foo', + 'foo' => 'foo', + 'bar' => 'foo', 'id' => 1 ), $data['obj']); } @@ -387,11 +403,12 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase } /** + * @param null|\Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher * @return ModelToElasticaAutoTransformer */ - private function getTransformer() + private function getTransformer($dispatcher = null) { - $transformer = new ModelToElasticaAutoTransformer(); + $transformer = new ModelToElasticaAutoTransformer(array(), $dispatcher); $transformer->setPropertyAccessor(PropertyAccess::getPropertyAccessor()); return $transformer; diff --git a/Transformer/ModelToElasticaAutoTransformer.php b/Transformer/ModelToElasticaAutoTransformer.php index 106db15..eff29d2 100644 --- a/Transformer/ModelToElasticaAutoTransformer.php +++ b/Transformer/ModelToElasticaAutoTransformer.php @@ -2,6 +2,8 @@ namespace FOS\ElasticaBundle\Transformer; +use FOS\ElasticaBundle\Event\TransformEvent; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; use Elastica\Document; @@ -12,6 +14,11 @@ use Elastica\Document; */ class ModelToElasticaAutoTransformer implements ModelToElasticaTransformerInterface { + /** + * @var EventDispatcherInterface + */ + protected $dispatcher; + /** * Optional parameters * @@ -32,10 +39,12 @@ class ModelToElasticaAutoTransformer implements ModelToElasticaTransformerInterf * Instanciates a new Mapper * * @param array $options + * @param EventDispatcherInterface $dispatcher */ - public function __construct(array $options = array()) + public function __construct(array $options = array(), EventDispatcherInterface $dispatcher = null) { $this->options = array_merge($this->options, $options); + $this->dispatcher = $dispatcher; } /** @@ -92,6 +101,13 @@ class ModelToElasticaAutoTransformer implements ModelToElasticaTransformerInterf $document->set($key, $this->normalizeValue($value)); } + if ($this->dispatcher) { + $event = new TransformEvent($document, $fields, $object); + $this->dispatcher->dispatch(TransformEvent::POST_TRANSFORM, $event); + + $document = $event->getDocument(); + } + return $document; } From 5060fa4d4aaf790bda59180abb8b945535117239 Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Wed, 21 Jan 2015 17:51:56 +0100 Subject: [PATCH 381/447] Move the test file to a better location The test of the DI extension is not a functional test. --- .../FOSElasticaExtensionTest.php | 16 ++++------------ .../fixtures}/config.yml | 0 2 files changed, 4 insertions(+), 12 deletions(-) rename Tests/{Functional => }/DependencyInjection/FOSElasticaExtensionTest.php (79%) rename Tests/{Functional/DependencyInjection/config => DependencyInjection/fixtures}/config.yml (100%) diff --git a/Tests/Functional/DependencyInjection/FOSElasticaExtensionTest.php b/Tests/DependencyInjection/FOSElasticaExtensionTest.php similarity index 79% rename from Tests/Functional/DependencyInjection/FOSElasticaExtensionTest.php rename to Tests/DependencyInjection/FOSElasticaExtensionTest.php index 06676ef..feb520f 100644 --- a/Tests/Functional/DependencyInjection/FOSElasticaExtensionTest.php +++ b/Tests/DependencyInjection/FOSElasticaExtensionTest.php @@ -1,8 +1,6 @@ setParameter('kernel.debug', true); @@ -36,5 +29,4 @@ class FOSElasticaExtensionTest extends \PHPUnit_Framework_TestCase $this->assertArrayHasKey('_parent', $arguments); $this->assertEquals('parent_field', $arguments['_parent']['type']); } - -} \ No newline at end of file +} diff --git a/Tests/Functional/DependencyInjection/config/config.yml b/Tests/DependencyInjection/fixtures/config.yml similarity index 100% rename from Tests/Functional/DependencyInjection/config/config.yml rename to Tests/DependencyInjection/fixtures/config.yml From 32d190f554d4a9efa68cadeae3974c77d14b349f Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Wed, 21 Jan 2015 18:10:33 +0100 Subject: [PATCH 382/447] Bump the changelog for 3.0.7 --- CHANGELOG-3.0.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-3.0.md b/CHANGELOG-3.0.md index ecb5dad..70bd181 100644 --- a/CHANGELOG-3.0.md +++ b/CHANGELOG-3.0.md @@ -12,8 +12,9 @@ https://github.com/FriendsOfSymfony/FOSElasticaBundle/compare/v3.0.0...v3.0.1 To generate a changelog summary since the last version, run `git log --no-merges --oneline v3.0.0...3.0.x` -* 3.0.7 (Unreleased) +* 3.0.7 (2015-01-21) + * Fixed the indexing of parent/child relations, broken since 3.0 #774 * Fixed multi_field properties not being normalised #769 * 3.0.6 (2015-01-04) From 401446e1c4129b37838461f9aec848e049805b9e Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 22 Jan 2015 09:06:21 +1100 Subject: [PATCH 383/447] Add integration testing around _parent mapping --- Tests/Functional/MappingToElasticaTest.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Tests/Functional/MappingToElasticaTest.php b/Tests/Functional/MappingToElasticaTest.php index f42df61..2c9235a 100644 --- a/Tests/Functional/MappingToElasticaTest.php +++ b/Tests/Functional/MappingToElasticaTest.php @@ -32,11 +32,15 @@ class MappingToElasticaTest extends WebTestCase $this->assertTrue($mapping['type']['properties']['field1']['store']); $this->assertArrayNotHasKey('store', $mapping['type']['properties']['field2']); - $parent = $this->getType($client, 'parent'); - $mapping = $parent->getMapping(); + $type = $this->getType($client, 'type'); + $mapping = $type->getMapping()['type']; + $this->assertEquals('parent', $mapping['_parent']['type']); - $this->assertEquals('my_analyzer', $mapping['parent']['index_analyzer']); - $this->assertEquals('whitespace', $mapping['parent']['search_analyzer']); + $parent = $this->getType($client, 'parent'); + $mapping = $parent->getMapping()['parent']; + + $this->assertEquals('my_analyzer', $mapping['index_analyzer']); + $this->assertEquals('whitespace', $mapping['search_analyzer']); } public function testResetType() From c901d605529eb7a4b5a2cf7552640b082f0b19c5 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 22 Jan 2015 09:10:46 +1100 Subject: [PATCH 384/447] Clarified what index_name does. Closes #731 --- Resources/doc/setup.md | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/Resources/doc/setup.md b/Resources/doc/setup.md index 6a1c2ae..a977ff7 100644 --- a/Resources/doc/setup.md +++ b/Resources/doc/setup.md @@ -48,25 +48,28 @@ fos_elastica: clients: default: { host: localhost, port: 9200 } indexes: - search: ~ + app: ~ ``` In this example, an Elastica index (an instance of `Elastica\Index`) is available as a -service with the key `fos_elastica.index.search`. +service with the key `fos_elastica.index.app`. -If the Elasticsearch index name needs to be different to the service name in your -application, for example, renaming the search index based on different environments. +You may want the index `app` to be named something else on ElasticSearch depending on +if your application is running in a different env or other conditions that suit your +application. To set your customer index to a name that depends on the environment of your +Symfony application, use the example below: ```yaml #app/config/config.yml fos_elastica: indexes: - search: - index_name: search_dev + app: + index_name: app_%kernel.env% ``` -In this case, the service `fos_elastica.index.search` will be using an Elasticsearch -index of search_dev. +In this case, the service `fos_elastica.index.app` will relate to an ElasticSearch index +that varies depending on your kernel's environment. For example, in dev it will relate to +`app_dev`. D) Defining index types ----------------------- @@ -81,7 +84,7 @@ will end up being indexed. ```yaml fos_elastica: indexes: - search: + app: types: user: mappings: @@ -92,7 +95,7 @@ fos_elastica: ``` Each defined type is made available as a service, and in this case the service key is -`fos_elastica.index.search.user` and is an instance of `Elastica\Type`. +`fos_elastica.index.app.user` and is an instance of `Elastica\Type`. FOSElasticaBundle requires a provider for each type that will notify when an object that maps to a type has been modified. The bundle ships with support for Doctrine and From 7471c13d75f2c98b30775acbc4f13422ba25558a Mon Sep 17 00:00:00 2001 From: CedCannes Date: Mon, 19 Jan 2015 23:55:52 +0100 Subject: [PATCH 385/447] Update manual-provider.md Typo in class path --- Resources/doc/cookbook/manual-provider.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/doc/cookbook/manual-provider.md b/Resources/doc/cookbook/manual-provider.md index f4365da..ed5568e 100644 --- a/Resources/doc/cookbook/manual-provider.md +++ b/Resources/doc/cookbook/manual-provider.md @@ -8,7 +8,7 @@ index and type for which the service will provide. # app/config/config.yml services: acme.search_provider.user: - class: Acme\UserBundle\Search\UserProvider + class: Acme\UserBundle\Provider\UserProvider arguments: - @fos_elastica.index.website.user tags: From 64fa26e3d9fa38b9fdda1280a72bf5f820046fdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michae=CC=88l=20Perrin?= Date: Wed, 17 Dec 2014 12:44:57 +0100 Subject: [PATCH 386/447] Fix PHP notice when using indexes without defined types --- Configuration/Source/ContainerSource.php | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/Configuration/Source/ContainerSource.php b/Configuration/Source/ContainerSource.php index 8d094c7..da77009 100644 --- a/Configuration/Source/ContainerSource.php +++ b/Configuration/Source/ContainerSource.php @@ -41,13 +41,16 @@ class ContainerSource implements SourceInterface $indexes = array(); foreach ($this->configArray as $config) { $types = array(); - foreach ($config['types'] as $typeConfig) { - $types[$typeConfig['name']] = new TypeConfig( - $typeConfig['name'], - $typeConfig['mapping'], - $typeConfig['config'] - ); - // TODO: handle prototypes.. + + if (isset($config['types'])) { + foreach ($config['types'] as $typeConfig) { + $types[$typeConfig['name']] = new TypeConfig( + $typeConfig['name'], + $typeConfig['mapping'], + $typeConfig['config'] + ); + // TODO: handle prototypes.. + } } $index = new IndexConfig($config['name'], $types, array( From b9b0c1b961d8cfaac02e0787af0ee7f4cbc5c9a0 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 22 Jan 2015 09:33:46 +1100 Subject: [PATCH 387/447] Move TypeConfig creation to its own method --- Configuration/Source/ContainerSource.php | 38 ++++++++++++++++-------- Tests/Functional/app/Basic/config.yml | 1 + 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/Configuration/Source/ContainerSource.php b/Configuration/Source/ContainerSource.php index da77009..abcdf1b 100644 --- a/Configuration/Source/ContainerSource.php +++ b/Configuration/Source/ContainerSource.php @@ -40,19 +40,7 @@ class ContainerSource implements SourceInterface { $indexes = array(); foreach ($this->configArray as $config) { - $types = array(); - - if (isset($config['types'])) { - foreach ($config['types'] as $typeConfig) { - $types[$typeConfig['name']] = new TypeConfig( - $typeConfig['name'], - $typeConfig['mapping'], - $typeConfig['config'] - ); - // TODO: handle prototypes.. - } - } - + $types = $this->getTypes($config); $index = new IndexConfig($config['name'], $types, array( 'elasticSearchName' => $config['elasticsearch_name'], 'settings' => $config['settings'], @@ -64,4 +52,28 @@ class ContainerSource implements SourceInterface return $indexes; } + + /** + * Builds TypeConfig objects for each type. + * + * @param array $config + * @return array + */ + protected function getTypes($config) + { + $types = array(); + + if (isset($config['types'])) { + foreach ($config['types'] as $typeConfig) { + $types[$typeConfig['name']] = new TypeConfig( + $typeConfig['name'], + $typeConfig['mapping'], + $typeConfig['config'] + ); + // TODO: handle prototypes.. + } + } + + return $types; + } } diff --git a/Tests/Functional/app/Basic/config.yml b/Tests/Functional/app/Basic/config.yml index ebd1ea0..3d0e120 100644 --- a/Tests/Functional/app/Basic/config.yml +++ b/Tests/Functional/app/Basic/config.yml @@ -92,3 +92,4 @@ fos_elastica: identifier: "id" null_mappings: mappings: ~ + empty_index: ~ From 55abe132c658ce6612a72a22fb7f7df46f838b0c Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 22 Jan 2015 09:36:33 +1100 Subject: [PATCH 388/447] Update changelog --- CHANGELOG-3.0.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG-3.0.md b/CHANGELOG-3.0.md index 70bd181..d7a826f 100644 --- a/CHANGELOG-3.0.md +++ b/CHANGELOG-3.0.md @@ -12,6 +12,10 @@ https://github.com/FriendsOfSymfony/FOSElasticaBundle/compare/v3.0.0...v3.0.1 To generate a changelog summary since the last version, run `git log --no-merges --oneline v3.0.0...3.0.x` +* 3.0.8 (Unreleased) + + * Fixed handling of empty indexes #760 + * 3.0.7 (2015-01-21) * Fixed the indexing of parent/child relations, broken since 3.0 #774 From e772ca645017285bc7bfaa29f63b54a60fd1f622 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 22 Jan 2015 11:23:51 +1100 Subject: [PATCH 389/447] Fix php 5.3 compatibility --- Tests/Functional/MappingToElasticaTest.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Tests/Functional/MappingToElasticaTest.php b/Tests/Functional/MappingToElasticaTest.php index 2c9235a..8fec8a9 100644 --- a/Tests/Functional/MappingToElasticaTest.php +++ b/Tests/Functional/MappingToElasticaTest.php @@ -33,14 +33,14 @@ class MappingToElasticaTest extends WebTestCase $this->assertArrayNotHasKey('store', $mapping['type']['properties']['field2']); $type = $this->getType($client, 'type'); - $mapping = $type->getMapping()['type']; - $this->assertEquals('parent', $mapping['_parent']['type']); + $mapping = $type->getMapping(); + $this->assertEquals('parent', $mapping['type']['_parent']['type']); $parent = $this->getType($client, 'parent'); - $mapping = $parent->getMapping()['parent']; + $mapping = $parent->getMapping(); - $this->assertEquals('my_analyzer', $mapping['index_analyzer']); - $this->assertEquals('whitespace', $mapping['search_analyzer']); + $this->assertEquals('my_analyzer', $mapping['type']['index_analyzer']); + $this->assertEquals('whitespace', $mapping['type']['search_analyzer']); } public function testResetType() From 030b194c7b884a435e98b31bfbc4358a43312a03 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 22 Jan 2015 11:49:28 +1100 Subject: [PATCH 390/447] Fix tests --- Tests/Functional/MappingToElasticaTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/Functional/MappingToElasticaTest.php b/Tests/Functional/MappingToElasticaTest.php index 8fec8a9..11c0db6 100644 --- a/Tests/Functional/MappingToElasticaTest.php +++ b/Tests/Functional/MappingToElasticaTest.php @@ -39,8 +39,8 @@ class MappingToElasticaTest extends WebTestCase $parent = $this->getType($client, 'parent'); $mapping = $parent->getMapping(); - $this->assertEquals('my_analyzer', $mapping['type']['index_analyzer']); - $this->assertEquals('whitespace', $mapping['type']['search_analyzer']); + $this->assertEquals('my_analyzer', $mapping['parent']['index_analyzer']); + $this->assertEquals('whitespace', $mapping['parent']['search_analyzer']); } public function testResetType() From 81f5f983c0f4c9727eefcec36a5301d6619f7564 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Sun, 25 Jan 2015 19:06:41 +1100 Subject: [PATCH 391/447] Fix line break --- DependencyInjection/FOSElasticaExtension.php | 1 - 1 file changed, 1 deletion(-) diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 046a5ac..5d30739 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -399,7 +399,6 @@ class FOSElasticaExtension extends Extension $argument['_parent'] = $mapping['_parent']; } $arguments[] = $argument; - } $serviceId = sprintf('fos_elastica.object_persister.%s.%s', $indexName, $typeName); From 906e2e0749cb93ffe00f50416d5f369356e79272 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Sat, 1 Nov 2014 19:33:05 +1100 Subject: [PATCH 392/447] Ability to set connectionStrategy for elastica clients --- CHANGELOG-3.0.md | 1 + DependencyInjection/Configuration.php | 11 +++++ .../doc/cookbook/multiple-connections.md | 5 ++ Tests/Functional/ClientTest.php | 48 +++++++++++++++++++ Tests/Functional/app/Basic/config.yml | 5 ++ 5 files changed, 70 insertions(+) create mode 100644 Tests/Functional/ClientTest.php diff --git a/CHANGELOG-3.0.md b/CHANGELOG-3.0.md index d7a826f..599d1f9 100644 --- a/CHANGELOG-3.0.md +++ b/CHANGELOG-3.0.md @@ -15,6 +15,7 @@ To generate a changelog summary since the last version, run * 3.0.8 (Unreleased) * Fixed handling of empty indexes #760 + * Added support for `connectionStrategy` Elastica configuration #732 * 3.0.7 (2015-01-21) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index fa2c048..7ebce1b 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -84,6 +84,16 @@ class Configuration implements ConfigurationInterface return $v; }) ->end() + // Elastica names its properties with camel case, support both + ->beforeNormalization() + ->ifTrue(function ($v) { return isset($v['connection_strategy']); }) + ->then(function ($v) { + $v['connectionStrategy'] = $v['connection_strategy']; + unset($v['connection_strategy']); + + return $v; + }) + ->end() // If there is no connections array key defined, assume a single connection. ->beforeNormalization() ->ifTrue(function ($v) { return is_array($v) && !array_key_exists('connections', $v); }) @@ -124,6 +134,7 @@ class Configuration implements ConfigurationInterface ->end() ->scalarNode('timeout')->end() ->scalarNode('headers')->end() + ->scalarNode('connectionStrategy')->defaultValue('Simple')->end() ->end() ->end() ->end() diff --git a/Resources/doc/cookbook/multiple-connections.md b/Resources/doc/cookbook/multiple-connections.md index 7b5226c..9544359 100644 --- a/Resources/doc/cookbook/multiple-connections.md +++ b/Resources/doc/cookbook/multiple-connections.md @@ -11,6 +11,11 @@ fos_elastica: connections: - url: http://es1.example.net:9200 - url: http://es2.example.net:9200 + connection_strategy: RoundRobin ``` +Elastica allows for definition of different connection strategies and by default +supports `RoundRobin` and `Simple`. You can see definitions for these strategies +in the `Elastica\Connection\Strategy` namespace. + For more information on Elastica clustering see http://elastica.io/getting-started/installation.html#section-connect-cluster diff --git a/Tests/Functional/ClientTest.php b/Tests/Functional/ClientTest.php new file mode 100644 index 0000000..8a6357a --- /dev/null +++ b/Tests/Functional/ClientTest.php @@ -0,0 +1,48 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace FOS\ElasticaBundle\Tests\Functional; + +use Symfony\Bundle\FrameworkBundle\Client; + +/** + * @group functional + */ +class ClientTest extends WebTestCase +{ + public function testContainerSource() + { + $client = $this->createClient(array('test_case' => 'Basic')); + + $es = $client->getContainer()->get('fos_elastica.client.default'); + $this->assertInstanceOf('Elastica\\Connection\\Strategy\\RoundRobin', $es->getConnectionStrategy()); + + $es = $client->getContainer()->get('fos_elastica.client.second_server'); + $this->assertInstanceOf('Elastica\\Connection\\Strategy\\RoundRobin', $es->getConnectionStrategy()); + + $es = $client->getContainer()->get('fos_elastica.client.third'); + $this->assertInstanceOf('Elastica\\Connection\\Strategy\\Simple', $es->getConnectionStrategy()); + } + + protected function setUp() + { + parent::setUp(); + + $this->deleteTmpDir('Basic'); + } + + protected function tearDown() + { + parent::tearDown(); + + $this->deleteTmpDir('Basic'); + } +} diff --git a/Tests/Functional/app/Basic/config.yml b/Tests/Functional/app/Basic/config.yml index 3d0e120..41a869e 100644 --- a/Tests/Functional/app/Basic/config.yml +++ b/Tests/Functional/app/Basic/config.yml @@ -15,7 +15,12 @@ fos_elastica: - url: http://localhost:9200 - host: localhost port: 9200 + connectionStrategy: RoundRobin second_server: + connections: + - url: http://localhost:9200 + connection_strategy: RoundRobin + third: url: http://localhost:9200 indexes: index: From 6bb2def21ea467b3eda1c9542b4716a85f698c88 Mon Sep 17 00:00:00 2001 From: Pablo Martelletti Date: Wed, 7 Jan 2015 14:42:15 -0300 Subject: [PATCH 393/447] Use ProgressBar in populate commande when available. --- Command/PopulateCommand.php | 27 +++++++++++++++++++++------ Doctrine/AbstractProvider.php | 14 +++++++++++++- Propel/Provider.php | 5 ++++- 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/Command/PopulateCommand.php b/Command/PopulateCommand.php index f17ca4c..6f27e5b 100644 --- a/Command/PopulateCommand.php +++ b/Command/PopulateCommand.php @@ -11,6 +11,7 @@ use FOS\ElasticaBundle\IndexManager; use FOS\ElasticaBundle\Provider\ProviderRegistry; use FOS\ElasticaBundle\Resetter; use FOS\ElasticaBundle\Provider\ProviderInterface; +use Symfony\Component\Console\Helper\ProgressBar; /** * Populate the search index @@ -109,20 +110,34 @@ class PopulateCommand extends ContainerAwareCommand */ private function populateIndex(OutputInterface $output, $index, $reset, $options) { + + /** @var $providers ProviderInterface[] */ + $providers = $this->providerRegistry->getIndexProviders($index); + if ($reset) { $output->writeln(sprintf('Resetting %s', $index)); $this->resetter->resetIndex($index, true); } - /** @var $providers ProviderInterface[] */ - $providers = $this->providerRegistry->getIndexProviders($index); - foreach ($providers as $type => $provider) { - $loggerClosure = function($message) use ($output, $index, $type) { - $output->writeln(sprintf('Populating %s/%s, %s', $index, $type, $message)); - }; + if (class_exists('Symfony\Component\Console\Helper\ProgressBar')) { + $output->writeln(sprintf('Populating %s/%s', $index, $type)); + $progressBar = new ProgressBar($output, $provider->getTotalObjects()); + $progressBar->setFormat('debug'); + $progressBar->start(); + $loggerClosure = function($number) use ($progressBar) { + $progressBar->advance($number); + }; + } else { + $loggerClosure = function($message) use ($output, $index, $type) { + $output->writeln(sprintf('Populating %s/%s, %s', $index, $type, $message)); + }; + } + $options['progress-bar'] = true; $provider->populate($loggerClosure, $options); + + if (isset($progressBar)) $progressBar->finish(); } $output->writeln(sprintf('Refreshing %s', $index)); diff --git a/Doctrine/AbstractProvider.php b/Doctrine/AbstractProvider.php index 92be6ce..9901fef 100644 --- a/Doctrine/AbstractProvider.php +++ b/Doctrine/AbstractProvider.php @@ -7,6 +7,7 @@ use Elastica\Exception\Bulk\ResponseException as BulkResponseException; use FOS\ElasticaBundle\Persister\ObjectPersisterInterface; use FOS\ElasticaBundle\Provider\AbstractProvider as BaseAbstractProvider; use FOS\ElasticaBundle\Provider\IndexableInterface; +use Symfony\Component\Console\Helper\ProgressBar; abstract class AbstractProvider extends BaseAbstractProvider { @@ -53,6 +54,7 @@ abstract class AbstractProvider extends BaseAbstractProvider $sleep = isset($options['sleep']) ? intval($options['sleep']) : 0; $batchSize = isset($options['batch-size']) ? intval($options['batch-size']) : $this->options['batch_size']; $ignoreErrors = isset($options['ignore-errors']) ? $options['ignore-errors'] : $this->options['ignore_errors']; + $progressBar = isset($options['progress-bar']) ? boolval($options['progress-bar']) : false; $manager = $this->managerRegistry->getManagerForClass($this->objectClass); for (; $offset < $nbObjects; $offset += $batchSize) { @@ -94,12 +96,14 @@ abstract class AbstractProvider extends BaseAbstractProvider usleep($sleep); - if ($loggerClosure) { + if ($loggerClosure && !$progressBar) { $stepCount = $stepNbObjects + $offset; $percentComplete = 100 * $stepCount / $nbObjects; $timeDifference = microtime(true) - $stepStartTime; $objectsPerSecond = $timeDifference ? ($stepNbObjects / $timeDifference) : $stepNbObjects; $loggerClosure(sprintf('%0.1f%% (%d/%d), %d objects/s %s', $percentComplete, $stepCount, $nbObjects, $objectsPerSecond, $this->getMemoryUsage())); + } else if ($loggerClosure && $progressBar) { + $loggerClosure($stepNbObjects); } } @@ -108,6 +112,14 @@ abstract class AbstractProvider extends BaseAbstractProvider } } + /** + * @return int|mixed + */ + public function getTotalObjects() + { + return $this->countObjects($this->createQueryBuilder()); + } + /** * Counts objects that would be indexed using the query builder. * diff --git a/Propel/Provider.php b/Propel/Provider.php index 38f7a61..f4966da 100644 --- a/Propel/Provider.php +++ b/Propel/Provider.php @@ -20,6 +20,7 @@ class Provider extends AbstractProvider $nbObjects = $queryClass::create()->count(); $offset = isset($options['offset']) ? intval($options['offset']) : 0; $sleep = isset($options['sleep']) ? intval($options['sleep']) : 0; + $progressBar = isset($options['progress-bar']) ? boolval($options['progress-bar']) : false; $batchSize = isset($options['batch-size']) ? intval($options['batch-size']) : $this->options['batch_size']; for (; $offset < $nbObjects; $offset += $batchSize) { @@ -46,11 +47,13 @@ class Provider extends AbstractProvider usleep($sleep); - if ($loggerClosure) { + if ($loggerClosure && !$progressBar) { $stepCount = $stepNbObjects + $offset; $percentComplete = 100 * $stepCount / $nbObjects; $objectsPerSecond = $stepNbObjects / (microtime(true) - $stepStartTime); $loggerClosure(sprintf('%0.1f%% (%d/%d), %d objects/s %s', $percentComplete, $stepCount, $nbObjects, $objectsPerSecond, $this->getMemoryUsage())); + } else if ($loggerClosure && $progressBar) { + $loggerClosure($stepNbObjects); } } } From 67c0b7950571b02c5627641e6e97c7b1f14332e7 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 22 Jan 2015 11:18:51 +1100 Subject: [PATCH 394/447] Tidy up ProgressBar use, move most calculations for loggerClosure into PopulateCommand rather than in AbstractProvider --- CHANGELOG-3.1.md | 4 ++ Command/PopulateCommand.php | 127 ++++++++++++++++++++++++++-------- Doctrine/AbstractProvider.php | 55 ++++----------- Propel/Provider.php | 28 ++------ Provider/AbstractProvider.php | 1 + 5 files changed, 120 insertions(+), 95 deletions(-) diff --git a/CHANGELOG-3.1.md b/CHANGELOG-3.1.md index 12fbb05..fe42514 100644 --- a/CHANGELOG-3.1.md +++ b/CHANGELOG-3.1.md @@ -21,3 +21,7 @@ https://github.com/FriendsOfSymfony/FOSElasticaBundle/compare/v3.0.4...v3.1.0 `dynamic_date_formats` for types. #753 * New event `POST_TRANSFORM` which allows developers to add custom properties to Elastica Documents for indexing. + * When available, the `fos:elastica:populate` command will now use the + ProgressBar helper instead of outputting strings. You can use verbosity + controls on the command to output additional information like memory + usage, runtime and estimated time. diff --git a/Command/PopulateCommand.php b/Command/PopulateCommand.php index 6f27e5b..ac37cab 100644 --- a/Command/PopulateCommand.php +++ b/Command/PopulateCommand.php @@ -100,6 +100,81 @@ class PopulateCommand extends ContainerAwareCommand } } + /** + * @param ProviderInterface $provider + * @param OutputInterface $output + * @param string $input + * @param string $type + * @param array $options + */ + private function doPopulateType(ProviderInterface $provider, OutputInterface $output, $input, $type, $options) + { + $loggerClosure = $this->getLoggerClosure($output, $input, $type); + + $provider->populate($loggerClosure, $options); + } + + /** + * Builds a loggerClosure to be called from inside the Provider to update the command + * line. + * + * @param OutputInterface $output + * @param string $index + * @param string $type + * @return callable + */ + private function getLoggerClosure(OutputInterface $output, $index, $type) + { + if (!class_exists('Symfony\Component\Console\Helper\ProgressBar')) { + $lastStep = null; + $current = 0; + + return function ($increment, $totalObjects) use ($output, $index, $type, &$lastStep, &$current) { + if ($increment > $totalObjects) { + $increment = $totalObjects; + } + + $currentTime = microtime(true); + $timeDifference = $currentTime - $lastStep; + $objectsPerSecond = $lastStep ? ($increment / $timeDifference) : $increment; + $lastStep = $currentTime; + $current += $increment; + $percent = 100 * $current / $totalObjects; + + $output->writeln(sprintf( + 'Populating %s/%s %0.1f%% (%d/%d), %d objects/s (RAM: current=%uMo peak=%uMo)', + $index, + $type, + $percent, + $current, + $totalObjects, + $objectsPerSecond, + round(memory_get_usage() / (1024 * 1024)), + round(memory_get_peak_usage() / (1024 * 1024)) + )); + }; + } + + ProgressBar::setFormatDefinition('normal', " %current%/%max% [%bar%] %percent:3s%%\n%message%"); + ProgressBar::setFormatDefinition('verbose', " %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%\n%message%"); + ProgressBar::setFormatDefinition('very_verbose', " %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s%\n%message%"); + ProgressBar::setFormatDefinition('debug', " %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%\n%message%"); + $progress = null; + + return function ($increment, $totalObjects) use (&$progress, $output, $index, $type) { + if (null === $progress) { + $progress = new ProgressBar($output, $totalObjects); + } + + $progress->setMessage(sprintf('Populating %s/%s', $index, $type)); + $progress->advance($increment); + + if ($progress->getProgress() >= $progress->getMaxSteps()) { + $progress->finish(); + } + }; + } + /** * Recreates an index, populates its types, and refreshes the index. * @@ -110,39 +185,19 @@ class PopulateCommand extends ContainerAwareCommand */ private function populateIndex(OutputInterface $output, $index, $reset, $options) { - - /** @var $providers ProviderInterface[] */ - $providers = $this->providerRegistry->getIndexProviders($index); - if ($reset) { $output->writeln(sprintf('Resetting %s', $index)); $this->resetter->resetIndex($index, true); } + /** @var $providers ProviderInterface[] */ + $providers = $this->providerRegistry->getIndexProviders($index); + foreach ($providers as $type => $provider) { - if (class_exists('Symfony\Component\Console\Helper\ProgressBar')) { - $output->writeln(sprintf('Populating %s/%s', $index, $type)); - $progressBar = new ProgressBar($output, $provider->getTotalObjects()); - $progressBar->setFormat('debug'); - $progressBar->start(); - $loggerClosure = function($number) use ($progressBar) { - $progressBar->advance($number); - }; - } else { - $loggerClosure = function($message) use ($output, $index, $type) { - $output->writeln(sprintf('Populating %s/%s, %s', $index, $type, $message)); - }; - } - - $options['progress-bar'] = true; - $provider->populate($loggerClosure, $options); - - if (isset($progressBar)) $progressBar->finish(); + $this->doPopulateType($provider, $output, $index, $type, $options); } - $output->writeln(sprintf('Refreshing %s', $index)); - $this->resetter->postPopulate($index); - $this->indexManager->getIndex($index)->refresh(); + $this->refreshIndex($output, $index); } /** @@ -161,12 +216,24 @@ class PopulateCommand extends ContainerAwareCommand $this->resetter->resetIndexType($index, $type); } - $loggerClosure = function($message) use ($output, $index, $type) { - $output->writeln(sprintf('Populating %s/%s, %s', $index, $type, $message)); - }; - $provider = $this->providerRegistry->getProvider($index, $type); - $provider->populate($loggerClosure, $options); + $this->doPopulateType($provider, $output, $index, $type, $options); + + $this->refreshIndex($output, $index, false); + } + + /** + * Refreshes an index. + * + * @param OutputInterface $output + * @param string $index + * @param bool $postPopulate + */ + private function refreshIndex(OutputInterface $output, $index, $postPopulate = true) + { + if ($postPopulate) { + $this->resetter->postPopulate($index); + } $output->writeln(sprintf('Refreshing %s', $index)); $this->indexManager->getIndex($index)->refresh(); diff --git a/Doctrine/AbstractProvider.php b/Doctrine/AbstractProvider.php index 9901fef..80d0716 100644 --- a/Doctrine/AbstractProvider.php +++ b/Doctrine/AbstractProvider.php @@ -7,7 +7,6 @@ use Elastica\Exception\Bulk\ResponseException as BulkResponseException; use FOS\ElasticaBundle\Persister\ObjectPersisterInterface; use FOS\ElasticaBundle\Provider\AbstractProvider as BaseAbstractProvider; use FOS\ElasticaBundle\Provider\IndexableInterface; -use Symfony\Component\Console\Helper\ProgressBar; abstract class AbstractProvider extends BaseAbstractProvider { @@ -40,7 +39,7 @@ abstract class AbstractProvider extends BaseAbstractProvider } /** - * @see FOS\ElasticaBundle\Provider\ProviderInterface::populate() + * {@inheritDoc} */ public function populate(\Closure $loggerClosure = null, array $options = array()) { @@ -54,38 +53,22 @@ abstract class AbstractProvider extends BaseAbstractProvider $sleep = isset($options['sleep']) ? intval($options['sleep']) : 0; $batchSize = isset($options['batch-size']) ? intval($options['batch-size']) : $this->options['batch_size']; $ignoreErrors = isset($options['ignore-errors']) ? $options['ignore-errors'] : $this->options['ignore_errors']; - $progressBar = isset($options['progress-bar']) ? boolval($options['progress-bar']) : false; $manager = $this->managerRegistry->getManagerForClass($this->objectClass); for (; $offset < $nbObjects; $offset += $batchSize) { - if ($loggerClosure) { - $stepStartTime = microtime(true); - } $objects = $this->fetchSlice($queryBuilder, $batchSize, $offset); - if ($loggerClosure) { - $stepNbObjects = count($objects); - } $objects = array_filter($objects, array($this, 'isObjectIndexable')); - if (!$objects) { - if ($loggerClosure) { - $loggerClosure('Entire batch was filtered away, skipping...'); - } - if ($this->options['clear_object_manager']) { - $manager->clear(); - } - - continue; - } - - if (!$ignoreErrors) { - $this->objectPersister->insertMany($objects); - } else { - try { + if ($objects) { + if (!$ignoreErrors) { $this->objectPersister->insertMany($objects); - } catch(BulkResponseException $e) { - if ($loggerClosure) { - $loggerClosure(sprintf('%s',$e->getMessage())); + } else { + try { + $this->objectPersister->insertMany($objects); + } catch(BulkResponseException $e) { + if ($loggerClosure) { + $loggerClosure(sprintf('%s',$e->getMessage())); + } } } } @@ -96,14 +79,8 @@ abstract class AbstractProvider extends BaseAbstractProvider usleep($sleep); - if ($loggerClosure && !$progressBar) { - $stepCount = $stepNbObjects + $offset; - $percentComplete = 100 * $stepCount / $nbObjects; - $timeDifference = microtime(true) - $stepStartTime; - $objectsPerSecond = $timeDifference ? ($stepNbObjects / $timeDifference) : $stepNbObjects; - $loggerClosure(sprintf('%0.1f%% (%d/%d), %d objects/s %s', $percentComplete, $stepCount, $nbObjects, $objectsPerSecond, $this->getMemoryUsage())); - } else if ($loggerClosure && $progressBar) { - $loggerClosure($stepNbObjects); + if ($loggerClosure) { + $loggerClosure($batchSize, $nbObjects); } } @@ -112,14 +89,6 @@ abstract class AbstractProvider extends BaseAbstractProvider } } - /** - * @return int|mixed - */ - public function getTotalObjects() - { - return $this->countObjects($this->createQueryBuilder()); - } - /** * Counts objects that would be indexed using the query builder. * diff --git a/Propel/Provider.php b/Propel/Provider.php index f4966da..a3af1bd 100644 --- a/Propel/Provider.php +++ b/Propel/Provider.php @@ -12,7 +12,7 @@ use FOS\ElasticaBundle\Provider\AbstractProvider; class Provider extends AbstractProvider { /** - * @see FOS\ElasticaBundle\Provider\ProviderInterface::populate() + * {@inheritDoc} */ public function populate(\Closure $loggerClosure = null, array $options = array()) { @@ -20,40 +20,24 @@ class Provider extends AbstractProvider $nbObjects = $queryClass::create()->count(); $offset = isset($options['offset']) ? intval($options['offset']) : 0; $sleep = isset($options['sleep']) ? intval($options['sleep']) : 0; - $progressBar = isset($options['progress-bar']) ? boolval($options['progress-bar']) : false; $batchSize = isset($options['batch-size']) ? intval($options['batch-size']) : $this->options['batch_size']; for (; $offset < $nbObjects; $offset += $batchSize) { - if ($loggerClosure) { - $stepStartTime = microtime(true); - } - $objects = $queryClass::create() ->limit($batchSize) ->offset($offset) ->find() ->getArrayCopy(); - if ($loggerClosure) { - $stepNbObjects = count($objects); - } + $objects = array_filter($objects, array($this, 'isObjectIndexable')); - if (!$objects) { - $loggerClosure('Entire batch was filtered away, skipping...'); - - continue; + if ($objects) { + $this->objectPersister->insertMany($objects); } - $this->objectPersister->insertMany($objects); - usleep($sleep); - if ($loggerClosure && !$progressBar) { - $stepCount = $stepNbObjects + $offset; - $percentComplete = 100 * $stepCount / $nbObjects; - $objectsPerSecond = $stepNbObjects / (microtime(true) - $stepStartTime); - $loggerClosure(sprintf('%0.1f%% (%d/%d), %d objects/s %s', $percentComplete, $stepCount, $nbObjects, $objectsPerSecond, $this->getMemoryUsage())); - } else if ($loggerClosure && $progressBar) { - $loggerClosure($stepNbObjects); + if ($loggerClosure) { + $loggerClosure($batchSize, $nbObjects); } } } diff --git a/Provider/AbstractProvider.php b/Provider/AbstractProvider.php index 82ea914..842518d 100644 --- a/Provider/AbstractProvider.php +++ b/Provider/AbstractProvider.php @@ -70,6 +70,7 @@ abstract class AbstractProvider implements ProviderInterface /** * Get string with RAM usage information (current and peak) * + * @deprecated To be removed in 4.0 * @return string */ protected function getMemoryUsage() From 58eed2dc7f06a86507477805e23e32b0d029293a Mon Sep 17 00:00:00 2001 From: Allan Brault Date: Mon, 26 Jan 2015 16:59:55 +0100 Subject: [PATCH 395/447] Update PopulateCommand.php in the case i have 110 objects, it was doing : Populating abc/Index 90.9% (100/110) Populating abc/index 181.8% (200/110) now : Populating abc/Index 90.9% (100/110) Populating abc/index 100.0% (110/110) --- Command/PopulateCommand.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Command/PopulateCommand.php b/Command/PopulateCommand.php index ac37cab..3f24a7f 100644 --- a/Command/PopulateCommand.php +++ b/Command/PopulateCommand.php @@ -130,8 +130,8 @@ class PopulateCommand extends ContainerAwareCommand $current = 0; return function ($increment, $totalObjects) use ($output, $index, $type, &$lastStep, &$current) { - if ($increment > $totalObjects) { - $increment = $totalObjects; + if ($current + $increment > $totalObjects) { + $increment = $totalObjects - $current; } $currentTime = microtime(true); From 6992beeb471b6d8a9622fc4d3761fbbc5714bada Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Sat, 31 Jan 2015 18:24:47 +1100 Subject: [PATCH 396/447] Update Elastica dependency --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index bb30928..b0f4b13 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ "symfony/console": "~2.1", "symfony/form": "~2.1", "symfony/property-access": "~2.2", - "ruflin/elastica": ">=0.90.10.0, <1.4-dev", + "ruflin/elastica": ">=0.90.10.0, <1.5-dev", "psr/log": "~1.0" }, "require-dev":{ From 2401b1083c2113a52f9846488f7bca264da23f4f Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Sat, 31 Jan 2015 18:31:57 +1100 Subject: [PATCH 397/447] Bump version --- CHANGELOG-3.0.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-3.0.md b/CHANGELOG-3.0.md index 599d1f9..973269d 100644 --- a/CHANGELOG-3.0.md +++ b/CHANGELOG-3.0.md @@ -12,10 +12,11 @@ https://github.com/FriendsOfSymfony/FOSElasticaBundle/compare/v3.0.0...v3.0.1 To generate a changelog summary since the last version, run `git log --no-merges --oneline v3.0.0...3.0.x` -* 3.0.8 (Unreleased) +* 3.0.8 (2014-01-31) * Fixed handling of empty indexes #760 * Added support for `connectionStrategy` Elastica configuration #732 + * Allow Elastica 1.4 * 3.0.7 (2015-01-21) From 72589f8341d9dc3ad78f07a45fb2b8a158a3c350 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Fri, 6 Feb 2015 22:07:13 +1100 Subject: [PATCH 398/447] Fix ProgressBar for Symfony 2.5 --- Command/PopulateCommand.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Command/PopulateCommand.php b/Command/PopulateCommand.php index 3f24a7f..5869c9c 100644 --- a/Command/PopulateCommand.php +++ b/Command/PopulateCommand.php @@ -164,6 +164,7 @@ class PopulateCommand extends ContainerAwareCommand return function ($increment, $totalObjects) use (&$progress, $output, $index, $type) { if (null === $progress) { $progress = new ProgressBar($output, $totalObjects); + $progress->start(); } $progress->setMessage(sprintf('Populating %s/%s', $index, $type)); From 797d06628639cc649515985076b992287142697d Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Fri, 6 Feb 2015 23:50:39 +1100 Subject: [PATCH 399/447] Additional change for 2.5 ProgressBar support getProgress() is not available and getStep() throws a deprecation warning. --- Command/PopulateCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Command/PopulateCommand.php b/Command/PopulateCommand.php index 5869c9c..5817c4c 100644 --- a/Command/PopulateCommand.php +++ b/Command/PopulateCommand.php @@ -170,7 +170,7 @@ class PopulateCommand extends ContainerAwareCommand $progress->setMessage(sprintf('Populating %s/%s', $index, $type)); $progress->advance($increment); - if ($progress->getProgress() >= $progress->getMaxSteps()) { + if ($progress->getProgressPercent() >= 1.0) { $progress->finish(); } }; From c5185a0307dded8f73bf30898f87386a60f0a644 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Mon, 9 Feb 2015 09:32:39 +1100 Subject: [PATCH 400/447] Added capability to define property paths --- CHANGELOG-3.1.md | 6 +++ Index/MappingBuilder.php | 2 + Resources/doc/cookbook/custom-properties.md | 2 +- Resources/doc/types.md | 28 ++++++++++ Tests/Functional/PropertyPathTest.php | 54 +++++++++++++++++++ Tests/Functional/TypeObj.php | 2 + Tests/Functional/app/ORM/config.yml | 12 +++++ .../ModelToElasticaAutoTransformerTest.php | 14 +++++ .../ModelToElasticaAutoTransformer.php | 11 +++- 9 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 Tests/Functional/PropertyPathTest.php diff --git a/CHANGELOG-3.1.md b/CHANGELOG-3.1.md index fe42514..19bec1f 100644 --- a/CHANGELOG-3.1.md +++ b/CHANGELOG-3.1.md @@ -25,3 +25,9 @@ https://github.com/FriendsOfSymfony/FOSElasticaBundle/compare/v3.0.4...v3.1.0 ProgressBar helper instead of outputting strings. You can use verbosity controls on the command to output additional information like memory usage, runtime and estimated time. + * Added new option `property_path` to a type property definition to allow + customisation of the property path used to retrieve data from objects. + Setting `property_path` to `false` will configure the Transformer to ignore + that property while transforming. Combined with the above POST_TRANSFORM event + developers can now create calculated dynamic properties on Elastica documents + for indexing. #794 diff --git a/Index/MappingBuilder.php b/Index/MappingBuilder.php index 5756751..92beaf7 100644 --- a/Index/MappingBuilder.php +++ b/Index/MappingBuilder.php @@ -110,6 +110,8 @@ class MappingBuilder private function fixProperties(&$properties) { foreach ($properties as $name => &$property) { + unset($property['property_path']); + if (!isset($property['type'])) { $property['type'] = 'string'; } diff --git a/Resources/doc/cookbook/custom-properties.md b/Resources/doc/cookbook/custom-properties.md index cc7751e..1d7687e 100644 --- a/Resources/doc/cookbook/custom-properties.md +++ b/Resources/doc/cookbook/custom-properties.md @@ -1,4 +1,4 @@ -##### Custom Repositories +##### Custom Properties Since FOSElasticaBundle 3.1.0, we now dispatch an event for each transformation of an object into an Elastica document which allows you to set custom properties on the Elastica diff --git a/Resources/doc/types.md b/Resources/doc/types.md index 80d295b..2d575cd 100644 --- a/Resources/doc/types.md +++ b/Resources/doc/types.md @@ -1,6 +1,34 @@ Type configuration ================== +Custom Property Paths +--------------------- + +Since FOSElasticaBundle 3.1.0, it is now possible to define custom property paths +to be used for data retrieval from the underlying model. + +```yaml + user: + mappings: + username: + property_path: indexableUsername + firstName: + property_path: names[first] +``` + +This feature uses the Symfony PropertyAccessor component and supports all features +that the component supports. + +The above example would retrieve an indexed field `username` from the property +`User->indexableUsername`, and the indexed field `firstName` would be populated from a +key `first` from an array on `User->names`. + +Setting the property path to `false` will disable transformation of that value. In this +case the mapping will be created but no value will be populated while indexing. You can +populate this value by listening to the `POST_TRANSFORM` event emitted by this bundle. +See [cookbook/custom-properties.md](cookbook/custom-properties.md) for more information +about this event. + Handling missing results with FOSElasticaBundle ----------------------------------------------- diff --git a/Tests/Functional/PropertyPathTest.php b/Tests/Functional/PropertyPathTest.php new file mode 100644 index 0000000..860cb86 --- /dev/null +++ b/Tests/Functional/PropertyPathTest.php @@ -0,0 +1,54 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace FOS\ElasticaBundle\Tests\Functional; + +use Elastica\Query\Match; + +/** + * @group functional + */ +class PropertyPathTest extends WebTestCase +{ + public function testContainerSource() + { + $client = $this->createClient(array('test_case' => 'ORM')); + /** @var \FOS\ElasticaBundle\Persister\ObjectPersister $persister */ + $persister = $client->getContainer()->get('fos_elastica.object_persister.index.property_paths_type'); + $obj = new TypeObj(); + $obj->coll = 'Hello'; + $persister->insertOne($obj); + + /** @var \Elastica\Index $elClient */ + $index = $client->getContainer()->get('fos_elastica.index.index'); + $index->flush(true); + + $query = new Match(); + $query->setField('something', 'Hello'); + $search = $index->createSearch($query); + + $this->assertEquals(1, $search->count()); + } + + protected function setUp() + { + parent::setUp(); + + $this->deleteTmpDir('Basic'); + } + + protected function tearDown() + { + parent::tearDown(); + + $this->deleteTmpDir('Basic'); + } +} diff --git a/Tests/Functional/TypeObj.php b/Tests/Functional/TypeObj.php index 46e5968..39e9fe9 100644 --- a/Tests/Functional/TypeObj.php +++ b/Tests/Functional/TypeObj.php @@ -13,8 +13,10 @@ namespace FOS\ElasticaBundle\Tests\Functional; class TypeObj { + public $id = 5; public $coll; public $field1; + public $field2; public function isIndexable() { diff --git a/Tests/Functional/app/ORM/config.yml b/Tests/Functional/app/ORM/config.yml index 98c9221..d2ff931 100644 --- a/Tests/Functional/app/ORM/config.yml +++ b/Tests/Functional/app/ORM/config.yml @@ -65,6 +65,18 @@ fos_elastica: provider: ~ listener: is_indexable_callback: [ 'FOS\ElasticaBundle\Tests\Functional\app\ORM\IndexableService', 'isntIndexable' ] + property_paths_type: + persistence: + driver: orm + model: FOS\ElasticaBundle\Tests\Functional\TypeObj + provider: ~ + properties: + field1: + property_path: field2 + something: + property_path: coll + dynamic: + property_path: false second_index: index_name: foselastica_orm_test_second_%kernel.environment% types: diff --git a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php index bb52129..4852037 100644 --- a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php +++ b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php @@ -148,6 +148,20 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase $transformer->transform(new POPO(), array()); } + public function testPropertyPath() + { + $transformer = $this->getTransformer(); + + $document = $transformer->transform(new POPO(), array('name' => array('property_path' => false))); + $this->assertInstanceOf('Elastica\Document', $document); + $this->assertFalse($document->has('name')); + + $document = $transformer->transform(new POPO(), array('realName' => array('property_path' => 'name'))); + $this->assertInstanceOf('Elastica\Document', $document); + $this->assertTrue($document->has('realName')); + $this->assertEquals('someName', $document->get('realName')); + } + public function testThatCanTransformObject() { $transformer = $this->getTransformer(); diff --git a/Transformer/ModelToElasticaAutoTransformer.php b/Transformer/ModelToElasticaAutoTransformer.php index eff29d2..6a9fbca 100644 --- a/Transformer/ModelToElasticaAutoTransformer.php +++ b/Transformer/ModelToElasticaAutoTransformer.php @@ -75,16 +75,24 @@ class ModelToElasticaAutoTransformer implements ModelToElasticaTransformerInterf $property = (null !== $mapping['property'])?$mapping['property']:$mapping['type']; $value = $this->propertyAccessor->getValue($object, $property); $document->setParent($this->propertyAccessor->getValue($value, $mapping['identifier'])); + continue; } - $value = $this->propertyAccessor->getValue($object, $key); + $path = isset($mapping['property_path']) ? + $mapping['property_path'] : + $key; + if (false === $path) { + continue; + } + $value = $this->propertyAccessor->getValue($object, $path); if (isset($mapping['type']) && in_array($mapping['type'], array('nested', 'object')) && isset($mapping['properties']) && !empty($mapping['properties'])) { /* $value is a nested document or object. Transform $value into * an array of documents, respective the mapped properties. */ $document->set($key, $this->transformNested($value, $mapping['properties'])); + continue; } @@ -95,6 +103,7 @@ class ModelToElasticaAutoTransformer implements ModelToElasticaTransformerInterf } else { $document->addFileContent($key, $value); } + continue; } From 70fe702ccf0670db1ffc72a9f24550302b4451ca Mon Sep 17 00:00:00 2001 From: Marichez Pierre Date: Sat, 7 Mar 2015 22:06:32 +0100 Subject: [PATCH 401/447] Update usage.md Fix indent in yml --- Resources/doc/usage.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/doc/usage.md b/Resources/doc/usage.md index 37514b3..588532c 100644 --- a/Resources/doc/usage.md +++ b/Resources/doc/usage.md @@ -160,7 +160,7 @@ fos_elastica: site: settings: index: - analysis: + analysis: analyzer: my_analyzer: type: snowball From 72a981ab51cad1d4b85f186c850876a9ff669f82 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Tue, 10 Mar 2015 21:49:26 +1100 Subject: [PATCH 402/447] Attempted fix for php 5.3 --- Tests/Transformer/ModelToElasticaAutoTransformerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php index 4852037..1dbf5fd 100644 --- a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php +++ b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php @@ -280,7 +280,7 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase $document = $transformer->transform(new POPO(), array( 'sub' => array( 'type' => 'nested', - 'properties' => array('foo' => '~') + 'properties' => array('foo' => array()) ) )); $data = $document->getData(); From 55bfee22e8bb38c3248c22b2e8f97c69aeeec010 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Tue, 10 Mar 2015 21:54:07 +1100 Subject: [PATCH 403/447] Cache composer --- .travis.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a83f9b9..fbb22d1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,9 @@ language: php +cache: + directories: + - $HOME/.composer/cache + php: - 5.3 - 5.4 @@ -21,7 +25,8 @@ before_script: - sh -c 'if [ "$SYMFONY_VERSION" != "" ]; then composer require --dev --no-update symfony/symfony=$SYMFONY_VERSION; fi;' - composer install --dev --prefer-source -script: vendor/bin/phpunit --coverage-clover=coverage.clover +script: + - vendor/bin/phpunit --coverage-clover=coverage.clover services: - elasticsearch From 4c87d24fc12d3e08580bd6aecbfdd3b289e316f2 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Wed, 11 Mar 2015 14:30:10 +1100 Subject: [PATCH 404/447] Changes after review --- CHANGELOG-3.1.md | 6 ++ Command/PopulateCommand.php | 30 +++---- DependencyInjection/FOSElasticaExtension.php | 2 +- Event/IndexPopulateEvent.php | 11 ++- Event/{ResetEvent.php => IndexResetEvent.php} | 71 ++++++++--------- Event/TypePopulateEvent.php | 43 ++-------- Event/TypeResetEvent.php | 61 ++++++++++++++ EventListener/PopulateListener.php | 59 -------------- Index/Resetter.php | 37 ++++----- Resources/config/listener.xml | 18 ----- Tests/EventListener/PopulateListenerTest.php | 79 ------------------- 11 files changed, 148 insertions(+), 269 deletions(-) rename Event/{ResetEvent.php => IndexResetEvent.php} (52%) create mode 100644 Event/TypeResetEvent.php delete mode 100644 EventListener/PopulateListener.php delete mode 100644 Resources/config/listener.xml delete mode 100644 Tests/EventListener/PopulateListenerTest.php diff --git a/CHANGELOG-3.1.md b/CHANGELOG-3.1.md index 19bec1f..51ad513 100644 --- a/CHANGELOG-3.1.md +++ b/CHANGELOG-3.1.md @@ -31,3 +31,9 @@ https://github.com/FriendsOfSymfony/FOSElasticaBundle/compare/v3.0.4...v3.1.0 that property while transforming. Combined with the above POST_TRANSFORM event developers can now create calculated dynamic properties on Elastica documents for indexing. #794 + * New events `PRE_INDEX_POPULATE`, `POST_INDEX_POPULATE`, `PRE_TYPE_POPULATE` and + `POST_TYPE_POPULATE` allow for monitoring when an index is about to be or has + just been populated. #744 + * New events `PRE_INDEX_RESET`, `POST_INDEX_RESET`, `PRE_TYPE_RESET` and + `POST_TYPE_RESET` are run before and after operations that will reset an + index. #744 diff --git a/Command/PopulateCommand.php b/Command/PopulateCommand.php index 8b6c0f2..3e6b684 100644 --- a/Command/PopulateCommand.php +++ b/Command/PopulateCommand.php @@ -109,24 +109,6 @@ class PopulateCommand extends ContainerAwareCommand } } - /** - * @param ProviderInterface $provider - * @param OutputInterface $output - * @param string $index - * @param string $type - * @param array $options - */ - private function doPopulateType(ProviderInterface $provider, OutputInterface $output, $index, $type, $options) - { - $event = new TypePopulateEvent($index, $type, $options); - $this->dispatcher->dispatch(TypePopulateEvent::PRE_TYPE_POPULATE, $event); - - $loggerClosure = $this->getLoggerClosure($output, $index, $type); - $provider->populate($loggerClosure, $event->getOptions()); - - $this->dispatcher->dispatch(TypePopulateEvent::POST_TYPE_POPULATE, $event); - } - /** * Builds a loggerClosure to be called from inside the Provider to update the command * line. @@ -210,7 +192,7 @@ class PopulateCommand extends ContainerAwareCommand $providers = $this->providerRegistry->getIndexProviders($index); foreach ($providers as $type => $provider) { - $this->doPopulateType($provider, $output, $index, $type, $event->getOptions()); + $this->populateIndexType($output, $index, $type, false, $event->getOptions()); } $this->dispatcher->dispatch(IndexPopulateEvent::POST_INDEX_POPULATE, $event); @@ -229,13 +211,19 @@ class PopulateCommand extends ContainerAwareCommand */ private function populateIndexType(OutputInterface $output, $index, $type, $reset, $options) { - if ($reset) { + $event = new TypePopulateEvent($index, $type, $reset, $options); + $this->dispatcher->dispatch(TypePopulateEvent::PRE_TYPE_POPULATE, $event); + + if ($event->isReset()) { $output->writeln(sprintf('Resetting %s/%s', $index, $type)); $this->resetter->resetIndexType($index, $type); } $provider = $this->providerRegistry->getProvider($index, $type); - $this->doPopulateType($provider, $output, $index, $type, $options); + $loggerClosure = $this->getLoggerClosure($output, $index, $type); + $provider->populate($loggerClosure, $event->getOptions()); + + $this->dispatcher->dispatch(TypePopulateEvent::POST_TYPE_POPULATE, $event); $this->refreshIndex($output, $index, false); } diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 1e446f7..9c1912e 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -46,7 +46,7 @@ class FOSElasticaExtension extends Extension return; } - foreach (array('config', 'index', 'persister', 'provider', 'source', 'transformer', 'listener') as $basename) { + foreach (array('config', 'index', 'persister', 'provider', 'source', 'transformer') as $basename) { $loader->load(sprintf('%s.xml', $basename)); } diff --git a/Event/IndexPopulateEvent.php b/Event/IndexPopulateEvent.php index 5074f05..56b1e83 100644 --- a/Event/IndexPopulateEvent.php +++ b/Event/IndexPopulateEvent.php @@ -1,4 +1,5 @@ */ @@ -72,4 +73,12 @@ class IndexPopulateEvent extends Event { return $this->options; } + + /** + * @param boolean $reset + */ + public function setReset($reset) + { + $this->reset = $reset; + } } diff --git a/Event/ResetEvent.php b/Event/IndexResetEvent.php similarity index 52% rename from Event/ResetEvent.php rename to Event/IndexResetEvent.php index 04034af..0caf241 100644 --- a/Event/ResetEvent.php +++ b/Event/IndexResetEvent.php @@ -1,70 +1,69 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + namespace FOS\ElasticaBundle\Event; use Symfony\Component\EventDispatcher\Event; /** - * ResetEvent + * Index ResetEvent * * @author Oleg Andreyev */ -class ResetEvent extends Event +class IndexResetEvent extends Event { const PRE_INDEX_RESET = 'elastica.index.pre_reset'; const POST_INDEX_RESET = 'elastica.index.post_reset'; - const PRE_TYPE_RESET = 'elastica.index.type_pre_reset'; - const POST_TYPE_RESET = 'elastica.index.type_post_reset'; - - /** - * @var string - */ - private $indexName; - - /** - * @var string - */ - private $indexType; - - /** - * @var bool - */ - private $populating; - /** * @var bool */ private $force; /** - * @param string $indexName - * @param string $indexType + * @var string + */ + private $index; + + /** + * @var bool + */ + private $populating; + + /** + * @param string $index * @param bool $populating * @param bool $force */ - public function __construct($indexName, $indexType, $populating = false, $force = false) + public function __construct($index, $populating, $force) { - $this->indexName = $indexName; - $this->indexType = $indexType; - $this->populating = (bool)$populating; - $this->force = (bool)$force; + $this->force = $force; + $this->index = $index; + $this->populating = $populating; } /** * @return string */ - public function getIndexName() + public function getIndex() { - return $this->indexName; + return $this->index; } /** - * @return string + * @return boolean */ - public function getIndexType() + public function isForce() { - return $this->indexType; + return $this->force; } /** @@ -76,10 +75,10 @@ class ResetEvent extends Event } /** - * @return boolean + * @param boolean $force */ - public function isForce() + public function setForce($force) { - return $this->force; + $this->force = $force; } -} \ No newline at end of file +} diff --git a/Event/TypePopulateEvent.php b/Event/TypePopulateEvent.php index 9239c15..e04bdd8 100644 --- a/Event/TypePopulateEvent.php +++ b/Event/TypePopulateEvent.php @@ -1,4 +1,5 @@ */ -class TypePopulateEvent extends Event +class TypePopulateEvent extends IndexPopulateEvent { const PRE_TYPE_POPULATE = 'elastica.index.type_pre_populate'; const POST_TYPE_POPULATE = 'elastica.index.type_post_populate'; - /** - * @var string - */ - private $index; - /** * @var string */ private $type; - /** - * @var array - */ - private $options; - /** * @param string $index * @param string $type + * @param bool $reset * @param array $options */ - public function __construct($index, $type, $options) + public function __construct($index, $type, $reset, $options) { - $this->index = $index; - $this->type = $type; - $this->options = $options; - } + parent::__construct($index, $reset, $options); - /** - * @return string - */ - public function getIndex() - { - return $this->index; + $this->type = $type; } /** @@ -64,17 +48,4 @@ class TypePopulateEvent extends Event { return $this->type; } - - /** - * @return array - */ - public function getOptions() - { - return $this->options; - } - - public function setOptions($options) - { - $this->options = $options; - } } diff --git a/Event/TypeResetEvent.php b/Event/TypeResetEvent.php new file mode 100644 index 0000000..37c2cf8 --- /dev/null +++ b/Event/TypeResetEvent.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FOS\ElasticaBundle\Event; + +use Symfony\Component\EventDispatcher\Event; + +/** + * Type ResetEvent + * + * @author Oleg Andreyev + */ +class TypeResetEvent extends Event +{ + const PRE_TYPE_RESET = 'elastica.index.type_pre_reset'; + const POST_TYPE_RESET = 'elastica.index.type_post_reset'; + + /** + * @var string + */ + private $index; + + /** + * @var string + */ + private $type; + + /** + * @param string $index + * @param string $type + */ + public function __construct($index, $type) + { + $this->type = $type; + $this->index = $index; + } + + /** + * @return string + */ + public function getIndex() + { + return $this->index; + } + + /** + * @return string + */ + public function getType() + { + return $this->type; + } +} diff --git a/EventListener/PopulateListener.php b/EventListener/PopulateListener.php deleted file mode 100644 index a2a0f5a..0000000 --- a/EventListener/PopulateListener.php +++ /dev/null @@ -1,59 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FOS\ElasticaBundle\EventListener; - -use FOS\ElasticaBundle\Event\PopulateEvent; -use FOS\ElasticaBundle\Index\Resetter; - -/** - * PopulateListener - * - * @author Oleg Andreyev - */ -class PopulateListener -{ - /** - * @var Resetter - */ - private $resetter; - - /** - * @param Resetter $resetter - */ - public function __construct(Resetter $resetter) - { - $this->resetter = $resetter; - } - - /** - * @param PopulateEvent $event - */ - public function preIndexPopulate(PopulateEvent $event) - { - if (!$event->isReset()) { - return; - } - - if (null !== $event->getType()) { - $this->resetter->resetIndexType($event->getIndex(), $event->getType()); - } else { - $this->resetter->resetIndex($event->getIndex(), true); - } - } - - /** - * @param PopulateEvent $event - */ - public function postIndexPopulate(PopulateEvent $event) - { - $this->resetter->postPopulate($event->getIndex()); - } -} diff --git a/Index/Resetter.php b/Index/Resetter.php index d2b3cea..1eb91a5 100644 --- a/Index/Resetter.php +++ b/Index/Resetter.php @@ -6,7 +6,8 @@ use Elastica\Index; use Elastica\Exception\ResponseException; use Elastica\Type\Mapping; use FOS\ElasticaBundle\Configuration\ConfigManager; -use FOS\ElasticaBundle\Event\ResetEvent; +use FOS\ElasticaBundle\Event\IndexResetEvent; +use FOS\ElasticaBundle\Event\TypeResetEvent; use Symfony\Component\EventDispatcher\EventDispatcherInterface; /** @@ -24,6 +25,11 @@ class Resetter */ private $configManager; + /** + * @var EventDispatcherInterface + */ + private $dispatcher; + /** * @var IndexManager */ @@ -34,11 +40,6 @@ class Resetter */ private $mappingBuilder; - /** - * @var EventDispatcherInterface - */ - private $eventDispatcher; - /** * @param ConfigManager $configManager * @param IndexManager $indexManager @@ -53,11 +54,11 @@ class Resetter MappingBuilder $mappingBuilder, EventDispatcherInterface $eventDispatcher ) { - $this->aliasProcessor = $aliasProcessor; - $this->configManager = $configManager; - $this->indexManager = $indexManager; - $this->mappingBuilder = $mappingBuilder; - $this->eventDispatcher = $eventDispatcher; + $this->aliasProcessor = $aliasProcessor; + $this->configManager = $configManager; + $this->dispatcher = $eventDispatcher; + $this->indexManager = $indexManager; + $this->mappingBuilder = $mappingBuilder; } /** @@ -84,8 +85,8 @@ class Resetter */ public function resetIndex($indexName, $populating = false, $force = false) { - $event = new ResetEvent($indexName, null, $populating, $force); - $this->eventDispatcher->dispatch(ResetEvent::PRE_INDEX_RESET, $event); + $event = new IndexResetEvent($indexName, $populating, $force); + $this->dispatcher->dispatch(IndexResetEvent::PRE_INDEX_RESET, $event); $indexConfig = $this->configManager->getIndexConfiguration($indexName); $index = $this->indexManager->getIndex($indexName); @@ -101,7 +102,7 @@ class Resetter $this->aliasProcessor->switchIndexAlias($indexConfig, $index, $force); } - $this->eventDispatcher->dispatch(ResetEvent::POST_INDEX_RESET, $event); + $this->dispatcher->dispatch(IndexResetEvent::POST_INDEX_RESET, $event); } /** @@ -114,8 +115,8 @@ class Resetter */ public function resetIndexType($indexName, $typeName) { - $event = new ResetEvent($indexName, $typeName); - $this->eventDispatcher->dispatch(ResetEvent::PRE_TYPE_RESET, $event); + $event = new TypeResetEvent($indexName, $typeName); + $this->dispatcher->dispatch(TypeResetEvent::PRE_TYPE_RESET, $event); $typeConfig = $this->configManager->getTypeConfiguration($indexName, $typeName); $type = $this->indexManager->getIndex($indexName)->getType($typeName); @@ -128,14 +129,14 @@ class Resetter } } - $mapping = new Mapping; + $mapping = new Mapping(); foreach ($this->mappingBuilder->buildTypeMapping($typeConfig) as $name => $field) { $mapping->setParam($name, $field); } $type->setMapping($mapping); - $this->eventDispatcher->dispatch(ResetEvent::POST_TYPE_RESET, $event); + $this->dispatcher->dispatch(TypeResetEvent::POST_TYPE_RESET, $event); } /** diff --git a/Resources/config/listener.xml b/Resources/config/listener.xml deleted file mode 100644 index 6c586bf..0000000 --- a/Resources/config/listener.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - FOS\ElasticaBundle\EventListener\PopulateListener - - - - - - - - - - diff --git a/Tests/EventListener/PopulateListenerTest.php b/Tests/EventListener/PopulateListenerTest.php deleted file mode 100644 index 3d653d3..0000000 --- a/Tests/EventListener/PopulateListenerTest.php +++ /dev/null @@ -1,79 +0,0 @@ -resetter = $this->getMockBuilder('FOS\ElasticaBundle\Index\Resetter') - ->disableOriginalConstructor() - ->getMock(); - - $this->listener = new PopulateListener($this->resetter); - } - - public function testPostIndexPopulate() - { - $this->resetter->expects($this->once())->method('postPopulate')->with('indexName'); - $this->listener->postIndexPopulate(new PopulateEvent('indexName', null, true, array())); - } - - public function preIndexPopulateDataProvider() - { - return array( - array( - array( - array('resetIndex', $this->never()), - array('resetIndexType', $this->never()) - ), - array('indexName', true), - new PopulateEvent('indexName', null, false, array()) - ), - array( - array( - array('resetIndex', $this->once()) - ), - array('indexName', true), - new PopulateEvent('indexName', null, true, array()) - ), - array( - array( - array('resetIndexType', $this->once()) - ), - array('indexName', 'indexType'), - new PopulateEvent('indexName', 'indexType', true, array()) - ) - ); - } - - /** - * @param array $asserts - * @param array $withArgs - * @param PopulateEvent $event - * - * @dataProvider preIndexPopulateDataProvider - */ - public function testPreIndexPopulate(array $asserts, array $withArgs, PopulateEvent $event) - { - foreach ($asserts as $assert) { - $this->resetter->expects($assert[1])->method($assert[0])->with($withArgs[0], $withArgs[1]); - } - - $this->listener->preIndexPopulate($event); - } -} From cb7b4c1dcaddde70d5937fd9ea7905497d36c533 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Wed, 11 Mar 2015 15:09:48 +1100 Subject: [PATCH 405/447] Configurable ProgressBar format definition overrides --- Command/PopulateCommand.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/Command/PopulateCommand.php b/Command/PopulateCommand.php index 5817c4c..ceaef64 100644 --- a/Command/PopulateCommand.php +++ b/Command/PopulateCommand.php @@ -47,18 +47,26 @@ class PopulateCommand extends ContainerAwareCommand ->addOption('sleep', null, InputOption::VALUE_REQUIRED, 'Sleep time between persisting iterations (microseconds)', 0) ->addOption('batch-size', null, InputOption::VALUE_REQUIRED, 'Index packet size (overrides provider config option)') ->addOption('ignore-errors', null, InputOption::VALUE_NONE, 'Do not stop on errors') + ->addOption('no-overwrite-format', null, InputOption::VALUE_NONE, 'Prevent this command from overwriting ProgressBar\'s formats') ->setDescription('Populates search indexes from providers') ; } /** - * @see Symfony\Component\Console\Command\Command::initialize() + * {@inheritDoc} */ protected function initialize(InputInterface $input, OutputInterface $output) { $this->indexManager = $this->getContainer()->get('fos_elastica.index_manager'); $this->providerRegistry = $this->getContainer()->get('fos_elastica.provider_registry'); $this->resetter = $this->getContainer()->get('fos_elastica.resetter'); + + if (!$input->getOption('no-overwrite-format')) { + ProgressBar::setFormatDefinition('normal', " %current%/%max% [%bar%] %percent:3s%%\n%message%"); + ProgressBar::setFormatDefinition('verbose', " %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%\n%message%"); + ProgressBar::setFormatDefinition('very_verbose', " %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s%\n%message%"); + ProgressBar::setFormatDefinition('debug', " %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%\n%message%"); + } } /** @@ -155,10 +163,6 @@ class PopulateCommand extends ContainerAwareCommand }; } - ProgressBar::setFormatDefinition('normal', " %current%/%max% [%bar%] %percent:3s%%\n%message%"); - ProgressBar::setFormatDefinition('verbose', " %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%\n%message%"); - ProgressBar::setFormatDefinition('very_verbose', " %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s%\n%message%"); - ProgressBar::setFormatDefinition('debug', " %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%\n%message%"); $progress = null; return function ($increment, $totalObjects) use (&$progress, $output, $index, $type) { From 47785260a46b482ffa75fd65c44e12173ddac95b Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Wed, 11 Mar 2015 15:11:13 +1100 Subject: [PATCH 406/447] Fix an error that PopulateCommand would always ignore errors --- CHANGELOG-3.1.md | 2 ++ Command/PopulateCommand.php | 13 ++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/CHANGELOG-3.1.md b/CHANGELOG-3.1.md index 19bec1f..a5937c7 100644 --- a/CHANGELOG-3.1.md +++ b/CHANGELOG-3.1.md @@ -31,3 +31,5 @@ https://github.com/FriendsOfSymfony/FOSElasticaBundle/compare/v3.0.4...v3.1.0 that property while transforming. Combined with the above POST_TRANSFORM event developers can now create calculated dynamic properties on Elastica documents for indexing. #794 + * Fixed a case where ProgressCommand would always ignore errors regardless of + --ignore-errors being passed or not. diff --git a/Command/PopulateCommand.php b/Command/PopulateCommand.php index ceaef64..3bb6290 100644 --- a/Command/PopulateCommand.php +++ b/Command/PopulateCommand.php @@ -70,16 +70,15 @@ class PopulateCommand extends ContainerAwareCommand } /** - * @see Symfony\Component\Console\Command\Command::execute() + * {@inheritDoc} */ protected function execute(InputInterface $input, OutputInterface $output) { - $index = $input->getOption('index'); - $type = $input->getOption('type'); - $reset = !$input->getOption('no-reset'); - $options = $input->getOptions(); - - $options['ignore-errors'] = $input->hasOption('ignore-errors'); + $index = $input->getOption('index'); + $type = $input->getOption('type'); + $reset = !$input->getOption('no-reset'); + $options = $input->getOptions(); + $options['ignore-errors'] = $input->getOption('ignore-errors'); if ($input->isInteractive() && $reset && $input->getOption('offset')) { /** @var DialogHelper $dialog */ From ef2671dd36e69d7343091ec6a2a8a102b875fac4 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Wed, 11 Mar 2015 15:11:42 +1100 Subject: [PATCH 407/447] Moved the progress helper closure building to a dedicated class --- Command/PopulateCommand.php | 66 +++------------------ Command/ProgressClosureBuilder.php | 94 ++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 59 deletions(-) create mode 100644 Command/ProgressClosureBuilder.php diff --git a/Command/PopulateCommand.php b/Command/PopulateCommand.php index 3bb6290..e4ed4c9 100644 --- a/Command/PopulateCommand.php +++ b/Command/PopulateCommand.php @@ -23,6 +23,11 @@ class PopulateCommand extends ContainerAwareCommand */ private $indexManager; + /** + * @var ProgressClosureBuilder + */ + private $progressClosureBuilder; + /** * @var ProviderRegistry */ @@ -60,6 +65,7 @@ class PopulateCommand extends ContainerAwareCommand $this->indexManager = $this->getContainer()->get('fos_elastica.index_manager'); $this->providerRegistry = $this->getContainer()->get('fos_elastica.provider_registry'); $this->resetter = $this->getContainer()->get('fos_elastica.resetter'); + $this->progressClosureBuilder = new ProgressClosureBuilder(); if (!$input->getOption('no-overwrite-format')) { ProgressBar::setFormatDefinition('normal', " %current%/%max% [%bar%] %percent:3s%%\n%message%"); @@ -116,69 +122,11 @@ class PopulateCommand extends ContainerAwareCommand */ private function doPopulateType(ProviderInterface $provider, OutputInterface $output, $input, $type, $options) { - $loggerClosure = $this->getLoggerClosure($output, $input, $type); + $loggerClosure = $this->progressClosureBuilder->build($output, 'Populating', $input, $type); $provider->populate($loggerClosure, $options); } - /** - * Builds a loggerClosure to be called from inside the Provider to update the command - * line. - * - * @param OutputInterface $output - * @param string $index - * @param string $type - * @return callable - */ - private function getLoggerClosure(OutputInterface $output, $index, $type) - { - if (!class_exists('Symfony\Component\Console\Helper\ProgressBar')) { - $lastStep = null; - $current = 0; - - return function ($increment, $totalObjects) use ($output, $index, $type, &$lastStep, &$current) { - if ($current + $increment > $totalObjects) { - $increment = $totalObjects - $current; - } - - $currentTime = microtime(true); - $timeDifference = $currentTime - $lastStep; - $objectsPerSecond = $lastStep ? ($increment / $timeDifference) : $increment; - $lastStep = $currentTime; - $current += $increment; - $percent = 100 * $current / $totalObjects; - - $output->writeln(sprintf( - 'Populating %s/%s %0.1f%% (%d/%d), %d objects/s (RAM: current=%uMo peak=%uMo)', - $index, - $type, - $percent, - $current, - $totalObjects, - $objectsPerSecond, - round(memory_get_usage() / (1024 * 1024)), - round(memory_get_peak_usage() / (1024 * 1024)) - )); - }; - } - - $progress = null; - - return function ($increment, $totalObjects) use (&$progress, $output, $index, $type) { - if (null === $progress) { - $progress = new ProgressBar($output, $totalObjects); - $progress->start(); - } - - $progress->setMessage(sprintf('Populating %s/%s', $index, $type)); - $progress->advance($increment); - - if ($progress->getProgressPercent() >= 1.0) { - $progress->finish(); - } - }; - } - /** * Recreates an index, populates its types, and refreshes the index. * diff --git a/Command/ProgressClosureBuilder.php b/Command/ProgressClosureBuilder.php new file mode 100644 index 0000000..c312899 --- /dev/null +++ b/Command/ProgressClosureBuilder.php @@ -0,0 +1,94 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FOS\ElasticaBundle\Command; + +use Symfony\Component\Console\Helper\ProgressBar; +use Symfony\Component\Console\Output\OutputInterface; + +class ProgressClosureBuilder +{ + /** + * Builds a loggerClosure to be called from inside the Provider to update the command + * line. + * + * @param OutputInterface $output + * @param string $action + * @param string $index + * @param string $type + * @return callable + */ + public function build(OutputInterface $output, $action, $index, $type) + { + if (!class_exists('Symfony\Component\Console\Helper\ProgressBar')) { + return $this->buildLegacy($output, $action, $index, $type); + } + + $progress = null; + + return function ($increment, $totalObjects) use (&$progress, $output, $action, $index, $type) { + if (null === $progress) { + $progress = new ProgressBar($output, $totalObjects); + $progress->start(); + } + + $progress->setMessage(sprintf('%s %s/%s', $action, $index, $type)); + $progress->advance($increment); + + if ($progress->getProgressPercent() >= 1.0) { + $progress->finish(); + } + }; + } + + /** + * Builds a legacy closure that outputs lines for each step. Used in cases + * where the ProgressBar component doesnt exist or does not have the correct + * methods to support what we need. + * + * @param OutputInterface $output + * @param string $action + * @param string $index + * @param string $type + * @return callable + */ + private function buildLegacy(OutputInterface $output, $action, $index, $type) + { + $lastStep = null; + $current = 0; + + return function ($increment, $totalObjects) use ($output, $action, $index, $type, &$lastStep, &$current) { + if ($current + $increment > $totalObjects) { + $increment = $totalObjects - $current; + } + + $currentTime = microtime(true); + $timeDifference = $currentTime - $lastStep; + $objectsPerSecond = $lastStep ? ($increment / $timeDifference) : $increment; + $lastStep = $currentTime; + $current += $increment; + $percent = 100 * $current / $totalObjects; + + $output->writeln(sprintf( + '%s %s/%s %0.1f%% (%d/%d), %d objects/s (RAM: current=%uMo peak=%uMo)', + $action, + $index, + $type, + $percent, + $current, + $totalObjects, + $objectsPerSecond, + round(memory_get_usage() / (1024 * 1024)), + round(memory_get_peak_usage() / (1024 * 1024)) + )); + }; + } +} From 4a564401b417cab6cf163a34e8a9a9d8b1699a7d Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Wed, 11 Mar 2015 15:17:06 +1100 Subject: [PATCH 408/447] Symfony <=2.5 uses the legacy progress closure --- Command/ProgressClosureBuilder.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Command/ProgressClosureBuilder.php b/Command/ProgressClosureBuilder.php index c312899..b918511 100644 --- a/Command/ProgressClosureBuilder.php +++ b/Command/ProgressClosureBuilder.php @@ -28,7 +28,8 @@ class ProgressClosureBuilder */ public function build(OutputInterface $output, $action, $index, $type) { - if (!class_exists('Symfony\Component\Console\Helper\ProgressBar')) { + if (!class_exists('Symfony\Component\Console\Helper\ProgressBar') || + !is_callable(array('Symfony\Component\Console\Helper\ProgressBar', 'getProgress'))) { return $this->buildLegacy($output, $action, $index, $type); } @@ -42,10 +43,6 @@ class ProgressClosureBuilder $progress->setMessage(sprintf('%s %s/%s', $action, $index, $type)); $progress->advance($increment); - - if ($progress->getProgressPercent() >= 1.0) { - $progress->finish(); - } }; } From cf9f7c6be8650329bc571e978bd8e43e5dec6560 Mon Sep 17 00:00:00 2001 From: Evgeniy Sokolov Date: Mon, 2 Feb 2015 10:38:01 +0100 Subject: [PATCH 409/447] fix error for empty type configuration --- DependencyInjection/Configuration.php | 4 ++++ .../DependencyInjection/ConfigurationTest.php | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 7ebce1b..0b01277 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -192,6 +192,10 @@ class Configuration implements ConfigurationInterface ->useAttributeAsKey('name') ->prototype('array') ->treatNullLike(array()) + ->beforeNormalization() + ->ifNull() + ->thenEmptyArray() + ->end() // BC - Renaming 'mappings' node to 'properties' ->beforeNormalization() ->ifTrue(function($v) { return array_key_exists('mappings', $v); }) diff --git a/Tests/DependencyInjection/ConfigurationTest.php b/Tests/DependencyInjection/ConfigurationTest.php index 7165052..30e0f7a 100644 --- a/Tests/DependencyInjection/ConfigurationTest.php +++ b/Tests/DependencyInjection/ConfigurationTest.php @@ -199,6 +199,24 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase $this->assertCount(3, $configuration['indexes']['test']['types']['test']['properties']); } + public function testUnconfiguredType() + { + $configuration = $this->getConfigs(array( + 'clients' => array( + 'default' => array('url' => 'http://localhost:9200'), + ), + 'indexes' => array( + 'test' => array( + 'types' => array( + 'test' => null + ) + ) + ) + )); + + $this->assertArrayHasKey('properties', $configuration['indexes']['test']['types']['test']); + } + public function testNestedProperties() { $this->getConfigs(array( From cbb247978a4fc216eb52bff9b285d8166e197f7f Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Wed, 11 Mar 2015 15:37:34 +1100 Subject: [PATCH 410/447] Update changeling for aggregations --- CHANGELOG-3.1.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG-3.1.md b/CHANGELOG-3.1.md index 19bec1f..5dc440f 100644 --- a/CHANGELOG-3.1.md +++ b/CHANGELOG-3.1.md @@ -17,6 +17,8 @@ https://github.com/FriendsOfSymfony/FOSElasticaBundle/compare/v3.0.4...v3.1.0 * BC BREAK: Removed `Doctrine\Listener#getSubscribedEvents`. The container configuration now configures tags with the methods to call to avoid loading this class on every request where doctrine is active. #729 + * BC BREAK: Added methods for retrieving aggregations when paginating results. + The `PaginationAdapterInterface` has a new method, `getAggregations`. #726 * Added ability to configure `date_detection`, `numeric_detection` and `dynamic_date_formats` for types. #753 * New event `POST_TRANSFORM` which allows developers to add custom properties to From f834499a2cbcb3b10ec736cd527e21f0d647152b Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Wed, 11 Mar 2015 15:54:04 +1100 Subject: [PATCH 411/447] Fixes after review --- CHANGELOG-3.1.md | 3 +++ Doctrine/AbstractProvider.php | 9 ++++++++- Tests/Doctrine/AbstractProviderTest.php | 6 +++--- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/CHANGELOG-3.1.md b/CHANGELOG-3.1.md index 5dc440f..978f2e9 100644 --- a/CHANGELOG-3.1.md +++ b/CHANGELOG-3.1.md @@ -33,3 +33,6 @@ https://github.com/FriendsOfSymfony/FOSElasticaBundle/compare/v3.0.4...v3.1.0 that property while transforming. Combined with the above POST_TRANSFORM event developers can now create calculated dynamic properties on Elastica documents for indexing. #794 + * Added a `SliceFetcher` abstraction for Doctrine providers that get more + information about the previous slice allowing for optimising queries during + population. #725 diff --git a/Doctrine/AbstractProvider.php b/Doctrine/AbstractProvider.php index 451b9b5..37ed830 100644 --- a/Doctrine/AbstractProvider.php +++ b/Doctrine/AbstractProvider.php @@ -10,8 +10,15 @@ use FOS\ElasticaBundle\Provider\IndexableInterface; abstract class AbstractProvider extends BaseAbstractProvider { + /** + * @var SliceFetcherInterface + */ + private $sliceFetcher; + + /** + * @var ManagerRegistry + */ protected $managerRegistry; - protected $sliceFetcher; /** * Constructor. diff --git a/Tests/Doctrine/AbstractProviderTest.php b/Tests/Doctrine/AbstractProviderTest.php index 07ff84e..623ab19 100644 --- a/Tests/Doctrine/AbstractProviderTest.php +++ b/Tests/Doctrine/AbstractProviderTest.php @@ -178,14 +178,14 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase $nbObjects = 1; $objects = array(1); - $provider = $this->getMockAbstractProvider(); + $provider = $this->getMockAbstractProvider(true); $provider->expects($this->any()) ->method('countObjects') ->will($this->returnValue($nbObjects)); - $provider->expects($this->any()) - ->method('fetchSlice') + $this->sliceFetcher->expects($this->any()) + ->method('fetch') ->will($this->returnValue($objects)); $this->indexable->expects($this->any()) From 0009c858a783c929f507376b3ebec7bad4574948 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Wed, 11 Mar 2015 21:31:23 +1100 Subject: [PATCH 412/447] Fixes for errors when with the progress closure --- Command/ProgressClosureBuilder.php | 14 ++++++++++++-- Doctrine/AbstractProvider.php | 2 +- Provider/ProviderInterface.php | 5 +++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/Command/ProgressClosureBuilder.php b/Command/ProgressClosureBuilder.php index b918511..53bcb18 100644 --- a/Command/ProgressClosureBuilder.php +++ b/Command/ProgressClosureBuilder.php @@ -35,12 +35,18 @@ class ProgressClosureBuilder $progress = null; - return function ($increment, $totalObjects) use (&$progress, $output, $action, $index, $type) { + return function ($increment, $totalObjects, $message = null) use (&$progress, $output, $action, $index, $type) { if (null === $progress) { $progress = new ProgressBar($output, $totalObjects); $progress->start(); } + if (null !== $message) { + $progress->clear(); + $output->writeln(sprintf('%s %s', $action, $message)); + $progress->display(); + } + $progress->setMessage(sprintf('%s %s/%s', $action, $index, $type)); $progress->advance($increment); }; @@ -62,11 +68,15 @@ class ProgressClosureBuilder $lastStep = null; $current = 0; - return function ($increment, $totalObjects) use ($output, $action, $index, $type, &$lastStep, &$current) { + return function ($increment, $totalObjects, $message = null) use ($output, $action, $index, $type, &$lastStep, &$current) { if ($current + $increment > $totalObjects) { $increment = $totalObjects - $current; } + if (null !== $message) { + $output->writeln(sprintf('%s %s', $action, $message)); + } + $currentTime = microtime(true); $timeDifference = $currentTime - $lastStep; $objectsPerSecond = $lastStep ? ($increment / $timeDifference) : $increment; diff --git a/Doctrine/AbstractProvider.php b/Doctrine/AbstractProvider.php index 80d0716..2d5d264 100644 --- a/Doctrine/AbstractProvider.php +++ b/Doctrine/AbstractProvider.php @@ -67,7 +67,7 @@ abstract class AbstractProvider extends BaseAbstractProvider $this->objectPersister->insertMany($objects); } catch(BulkResponseException $e) { if ($loggerClosure) { - $loggerClosure(sprintf('%s',$e->getMessage())); + $loggerClosure($batchSize, $nbObjects, sprintf('%s', $e->getMessage())); } } } diff --git a/Provider/ProviderInterface.php b/Provider/ProviderInterface.php index e8d7ea4..188f2a1 100644 --- a/Provider/ProviderInterface.php +++ b/Provider/ProviderInterface.php @@ -12,6 +12,11 @@ interface ProviderInterface /** * Persists all domain objects to ElasticSearch for this provider. * + * The closure can expect 2 or 3 arguments: + * * The step size + * * The total number of objects + * * A message to output in error conditions (not normally provided) + * * @param \Closure $loggerClosure * @param array $options * @return From 19e9abaa5324b95291b2c585f1a86c8dcb88c2e7 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Wed, 11 Mar 2015 22:21:56 +1100 Subject: [PATCH 413/447] Update documentation links for 3.1 and 3.0 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 01afa6d..797d629 100644 --- a/README.md +++ b/README.md @@ -18,9 +18,9 @@ Documentation Documentation for FOSElasticaBundle is in `Resources/doc/index.md` -[Read the documentation for 3.0.x (master)](https://github.com/FriendsOfSymfony/FOSElasticaBundle/blob/master/Resources/doc/index.md) +[Read the documentation for 3.1.x](https://github.com/FriendsOfSymfony/FOSElasticaBundle/blob/master/Resources/doc/index.md) -[Read the documentation for 2.1.x](https://github.com/FriendsOfSymfony/FOSElasticaBundle/blob/2.1.x/README.md) +[Read the documentation for 3.0.x](https://github.com/FriendsOfSymfony/FOSElasticaBundle/blob/3.0.x/Resources/doc/index.md) Installation ------------ From 14af7488408420618164b2c31f252e89259b2f70 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 12 Mar 2015 17:41:26 +1100 Subject: [PATCH 414/447] Fix bad merge --- Command/PopulateCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Command/PopulateCommand.php b/Command/PopulateCommand.php index ed686d9..afe18b3 100644 --- a/Command/PopulateCommand.php +++ b/Command/PopulateCommand.php @@ -169,7 +169,7 @@ class PopulateCommand extends ContainerAwareCommand } $provider = $this->providerRegistry->getProvider($index, $type); - $loggerClosure = $this->getLoggerClosure($output, $index, $type); + $loggerClosure = $this->progressClosureBuilder->build($output, 'Populating', $index, $type); $provider->populate($loggerClosure, $event->getOptions()); $this->dispatcher->dispatch(TypePopulateEvent::POST_TYPE_POPULATE, $event); From 81186e40db298621b345c90202de24bdcc37598f Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 12 Mar 2015 20:35:25 +1100 Subject: [PATCH 415/447] Bump master to 3.2-dev --- composer.json | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/composer.json b/composer.json index 917e839..9705a04 100644 --- a/composer.json +++ b/composer.json @@ -22,31 +22,23 @@ }, "require-dev":{ "doctrine/orm": "~2.4", - "doctrine/doctrine-bundle": "~1.2@beta", + "doctrine/doctrine-bundle": "~1.2", "jms/serializer-bundle": "@stable", "phpunit/phpunit": "~4.1", "propel/propel1": "1.6.*", - "pagerfanta/pagerfanta": "1.0.*@dev", + "pagerfanta/pagerfanta": "~1.0", "knplabs/knp-components": "~1.2", "knplabs/knp-paginator-bundle": "~2.4", "symfony/browser-kit" : "~2.3", "symfony/expression-language" : "~2.4", "symfony/twig-bundle": "~2.3" }, - "suggest": { - "doctrine/orm": "~2.4", - "doctrine/mongodb-odm": "1.0.*@dev", - "propel/propel1": "1.6.*", - "pagerfanta/pagerfanta": "1.0.*@dev", - "knplabs/knp-components": "~1.2", - "symfony/expression-language" : "~2.4" - }, "autoload": { "psr-4": { "FOS\\ElasticaBundle\\": "" } }, "extra": { "branch-alias": { - "dev-master": "3.1.x-dev" + "dev-master": "3.2.x-dev" } } } From dd388e4b25f188656ae5026bd078ebc9c4cde26f Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 12 Mar 2015 21:20:00 +1100 Subject: [PATCH 416/447] CS fixes --- Command/PopulateCommand.php | 6 +- Command/ResetCommand.php | 2 +- Command/SearchCommand.php | 2 +- Configuration/IndexConfig.php | 6 +- Configuration/ManagerInterface.php | 2 + Configuration/Search.php | 3 +- Configuration/Source/ContainerSource.php | 1 + Configuration/Source/SourceInterface.php | 2 +- .../Compiler/ConfigSourcePass.php | 2 +- .../Compiler/RegisterProvidersPass.php | 1 + .../Compiler/TransformerPass.php | 2 +- DependencyInjection/Configuration.php | 28 ++--- DependencyInjection/FOSElasticaExtension.php | 109 ++++++++++-------- .../AbstractElasticaToModelTransformer.php | 32 ++--- Doctrine/AbstractProvider.php | 27 +++-- Doctrine/Listener.php | 35 +++--- .../MongoDB/ElasticaToModelTransformer.php | 9 +- Doctrine/MongoDB/Provider.php | 3 +- Doctrine/ORM/ElasticaToModelTransformer.php | 11 +- Doctrine/ORM/Provider.php | 5 +- Doctrine/RepositoryManager.php | 4 +- Elastica/Client.php | 13 ++- Elastica/Index.php | 4 +- Exception/AliasIsIndexException.php | 1 - FOSElasticaBundle.php | 1 - Finder/FinderInterface.php | 9 +- Finder/PaginatedFinderInterface.php | 12 +- Finder/TransformedFinder.php | 22 ++-- HybridResult.php | 2 +- Index/AliasProcessor.php | 21 ++-- Index/IndexManager.php | 8 +- Index/MappingBuilder.php | 4 +- Index/Resetter.php | 14 ++- Manager/RepositoryManager.php | 5 +- Manager/RepositoryManagerInterface.php | 3 +- Paginator/FantaPaginatorAdapter.php | 2 +- Paginator/PaginatorAdapterInterface.php | 8 +- Paginator/PartialResultsInterface.php | 10 +- Paginator/RawPaginatorAdapter.php | 16 ++- Paginator/RawPartialResults.php | 8 +- Paginator/TransformedPaginatorAdapter.php | 6 +- Paginator/TransformedPartialResults.php | 6 +- Persister/ObjectPersister.php | 28 +++-- Persister/ObjectPersisterInterface.php | 34 +++--- Persister/ObjectSerializerPersister.php | 5 +- Propel/ElasticaToModelTransformer.php | 10 +- Propel/Provider.php | 4 +- Provider/AbstractProvider.php | 11 +- Provider/Indexable.php | 14 ++- Provider/IndexableInterface.php | 3 +- Provider/ProviderInterface.php | 5 +- Provider/ProviderRegistry.php | 6 +- Repository.php | 14 ++- Resources/config/orm.xml | 2 +- .../PaginateElasticaQuerySubscriber.php | 6 +- Tests/Command/ResetCommandTest.php | 3 +- .../DependencyInjection/ConfigurationTest.php | 86 +++++++------- .../FOSElasticaExtensionTest.php | 4 +- ...AbstractElasticaToModelTransformerTest.php | 2 +- Tests/Doctrine/AbstractListenerTest.php | 13 +-- Tests/Doctrine/AbstractProviderTest.php | 9 +- .../ORM/ElasticaToModelTransformerTest.php | 2 +- Tests/Doctrine/RepositoryManagerTest.php | 8 +- Tests/Elastica/ClientTest.php | 4 +- Tests/FOSElasticaBundleTest.php | 1 - Tests/Functional/ConfigurationManagerTest.php | 1 + Tests/Functional/IndexableCallbackTest.php | 2 +- Tests/Functional/MappingToElasticaTest.php | 4 +- Tests/Functional/app/AppKernel.php | 2 +- Tests/Functional/app/Serializer/config.yml | 1 - Tests/Index/IndexManagerTest.php | 1 - Tests/Integration/MappingTest.php | 8 +- Tests/Logger/ElasticaLoggerTest.php | 5 +- Tests/Manager/RepositoryManagerTest.php | 9 +- Tests/Persister/ObjectPersisterTest.php | 6 +- .../ObjectSerializerPersisterTest.php | 6 +- Tests/Provider/IndexableTest.php | 12 +- Tests/RepositoryTest.php | 56 +++------ ...asticaToModelTransformerCollectionTest.php | 10 +- .../ModelToElasticaAutoTransformerTest.php | 60 +++++----- .../ElasticaToModelTransformerCollection.php | 7 +- .../ElasticaToModelTransformerInterface.php | 15 +-- Transformer/HighlightableModelInterface.php | 32 ++--- .../ModelToElasticaAutoTransformer.php | 27 +++-- .../ModelToElasticaIdentifierTransformer.php | 4 +- .../ModelToElasticaTransformerInterface.php | 9 +- 86 files changed, 535 insertions(+), 483 deletions(-) diff --git a/Command/PopulateCommand.php b/Command/PopulateCommand.php index f17ca4c..6111658 100644 --- a/Command/PopulateCommand.php +++ b/Command/PopulateCommand.php @@ -13,7 +13,7 @@ use FOS\ElasticaBundle\Resetter; use FOS\ElasticaBundle\Provider\ProviderInterface; /** - * Populate the search index + * Populate the search index. */ class PopulateCommand extends ContainerAwareCommand { @@ -118,7 +118,7 @@ class PopulateCommand extends ContainerAwareCommand $providers = $this->providerRegistry->getIndexProviders($index); foreach ($providers as $type => $provider) { - $loggerClosure = function($message) use ($output, $index, $type) { + $loggerClosure = function ($message) use ($output, $index, $type) { $output->writeln(sprintf('Populating %s/%s, %s', $index, $type, $message)); }; @@ -146,7 +146,7 @@ class PopulateCommand extends ContainerAwareCommand $this->resetter->resetIndexType($index, $type); } - $loggerClosure = function($message) use ($output, $index, $type) { + $loggerClosure = function ($message) use ($output, $index, $type) { $output->writeln(sprintf('Populating %s/%s, %s', $index, $type, $message)); }; diff --git a/Command/ResetCommand.php b/Command/ResetCommand.php index ce05e96..85c5483 100755 --- a/Command/ResetCommand.php +++ b/Command/ResetCommand.php @@ -10,7 +10,7 @@ use FOS\ElasticaBundle\IndexManager; use FOS\ElasticaBundle\Resetter; /** - * Reset search indexes + * Reset search indexes. */ class ResetCommand extends ContainerAwareCommand { diff --git a/Command/SearchCommand.php b/Command/SearchCommand.php index ec7cfb7..11183de 100644 --- a/Command/SearchCommand.php +++ b/Command/SearchCommand.php @@ -11,7 +11,7 @@ use Elastica\Query; use Elastica\Result; /** - * Searches a type + * Searches a type. */ class SearchCommand extends ContainerAwareCommand { diff --git a/Configuration/IndexConfig.php b/Configuration/IndexConfig.php index 7416424..749b10d 100644 --- a/Configuration/IndexConfig.php +++ b/Configuration/IndexConfig.php @@ -53,9 +53,9 @@ class IndexConfig /** * Constructor expects an array as generated by the Container Configuration builder. * - * @param string $name + * @param string $name * @param TypeConfig[] $types - * @param array $config + * @param array $config */ public function __construct($name, array $types, array $config) { @@ -92,7 +92,9 @@ class IndexConfig /** * @param string $typeName + * * @return TypeConfig + * * @throws \InvalidArgumentException */ public function getType($typeName) diff --git a/Configuration/ManagerInterface.php b/Configuration/ManagerInterface.php index 96d510f..742df1b 100644 --- a/Configuration/ManagerInterface.php +++ b/Configuration/ManagerInterface.php @@ -20,6 +20,7 @@ interface ManagerInterface * Returns configuration for an index. * * @param $index + * * @return IndexConfig */ public function getIndexConfiguration($index); @@ -36,6 +37,7 @@ interface ManagerInterface * * @param string $index * @param string $type + * * @return TypeConfig */ public function getTypeConfiguration($index, $type); diff --git a/Configuration/Search.php b/Configuration/Search.php index 1306f92..1d046c0 100644 --- a/Configuration/Search.php +++ b/Configuration/Search.php @@ -17,9 +17,10 @@ use FOS\ElasticaBundle\Annotation\Search as BaseSearch; * Annotation class for setting search repository. * * @Annotation + * * @deprecated Use FOS\ElasticaBundle\Annotation\Search instead * @Target("CLASS") */ class Search extends BaseSearch { -} +} diff --git a/Configuration/Source/ContainerSource.php b/Configuration/Source/ContainerSource.php index abcdf1b..25e6f86 100644 --- a/Configuration/Source/ContainerSource.php +++ b/Configuration/Source/ContainerSource.php @@ -57,6 +57,7 @@ class ContainerSource implements SourceInterface * Builds TypeConfig objects for each type. * * @param array $config + * * @return array */ protected function getTypes($config) diff --git a/Configuration/Source/SourceInterface.php b/Configuration/Source/SourceInterface.php index 34e9901..05a64d0 100644 --- a/Configuration/Source/SourceInterface.php +++ b/Configuration/Source/SourceInterface.php @@ -23,4 +23,4 @@ interface SourceInterface * @return \FOS\ElasticaBundle\Configuration\IndexConfig[] */ public function getConfiguration(); -} +} diff --git a/DependencyInjection/Compiler/ConfigSourcePass.php b/DependencyInjection/Compiler/ConfigSourcePass.php index b35a665..92a2489 100644 --- a/DependencyInjection/Compiler/ConfigSourcePass.php +++ b/DependencyInjection/Compiler/ConfigSourcePass.php @@ -33,4 +33,4 @@ class ConfigSourcePass implements CompilerPassInterface $container->getDefinition('fos_elastica.config_manager')->replaceArgument(0, $sources); } -} +} diff --git a/DependencyInjection/Compiler/RegisterProvidersPass.php b/DependencyInjection/Compiler/RegisterProvidersPass.php index c6c9e6e..4fd25b0 100644 --- a/DependencyInjection/Compiler/RegisterProvidersPass.php +++ b/DependencyInjection/Compiler/RegisterProvidersPass.php @@ -55,6 +55,7 @@ class RegisterProvidersPass implements CompilerPassInterface * Returns whether the class implements ProviderInterface. * * @param string $class + * * @return boolean */ private function isProviderImplementation($class) diff --git a/DependencyInjection/Compiler/TransformerPass.php b/DependencyInjection/Compiler/TransformerPass.php index 4281d0b..596c732 100644 --- a/DependencyInjection/Compiler/TransformerPass.php +++ b/DependencyInjection/Compiler/TransformerPass.php @@ -31,7 +31,7 @@ class TransformerPass implements CompilerPassInterface throw new InvalidArgumentException('The Transformer must have both a type and an index defined.'); } - $transformers[$tag['index']][$tag['type']]= new Reference($id); + $transformers[$tag['index']][$tag['type']] = new Reference($id); } } diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 0b01277..78886f1 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -63,7 +63,7 @@ class Configuration implements ConfigurationInterface } /** - * Adds the configuration for the "clients" key + * Adds the configuration for the "clients" key. */ private function addClientsSection(ArrayNodeDefinition $rootNode) { @@ -76,8 +76,8 @@ class Configuration implements ConfigurationInterface ->performNoDeepMerging() // BC - Renaming 'servers' node to 'connections' ->beforeNormalization() - ->ifTrue(function($v) { return isset($v['servers']); }) - ->then(function($v) { + ->ifTrue(function ($v) { return isset($v['servers']); }) + ->then(function ($v) { $v['connections'] = $v['servers']; unset($v['servers']); @@ -99,7 +99,7 @@ class Configuration implements ConfigurationInterface ->ifTrue(function ($v) { return is_array($v) && !array_key_exists('connections', $v); }) ->then(function ($v) { return array( - 'connections' => array($v) + 'connections' => array($v), ); }) ->end() @@ -111,8 +111,8 @@ class Configuration implements ConfigurationInterface ->children() ->scalarNode('url') ->validate() - ->ifTrue(function($url) { return $url && substr($url, -1) !== '/'; }) - ->then(function($url) { return $url.'/'; }) + ->ifTrue(function ($url) { return $url && substr($url, -1) !== '/'; }) + ->then(function ($url) { return $url.'/'; }) ->end() ->end() ->scalarNode('host')->end() @@ -143,7 +143,7 @@ class Configuration implements ConfigurationInterface } /** - * Adds the configuration for the "indexes" key + * Adds the configuration for the "indexes" key. */ private function addIndexesSection(ArrayNodeDefinition $rootNode) { @@ -198,8 +198,8 @@ class Configuration implements ConfigurationInterface ->end() // BC - Renaming 'mappings' node to 'properties' ->beforeNormalization() - ->ifTrue(function($v) { return array_key_exists('mappings', $v); }) - ->then(function($v) { + ->ifTrue(function ($v) { return array_key_exists('mappings', $v); }) + ->then(function ($v) { $v['properties'] = $v['mappings']; unset($v['mappings']); @@ -419,7 +419,7 @@ class Configuration implements ConfigurationInterface } /** - * Returns the array node used for "_all" + * Returns the array node used for "_all". */ protected function getAllNode() { @@ -438,7 +438,7 @@ class Configuration implements ConfigurationInterface } /** - * Returns the array node used for "_timestamp" + * Returns the array node used for "_timestamp". */ protected function getTimestampNode() { @@ -459,7 +459,7 @@ class Configuration implements ConfigurationInterface } /** - * Returns the array node used for "_ttl" + * Returns the array node used for "_ttl". */ protected function getTtlNode() { @@ -488,9 +488,9 @@ class Configuration implements ConfigurationInterface $node ->validate() - ->ifTrue(function($v) { return isset($v['driver']) && 'propel' === $v['driver'] && isset($v['listener']); }) + ->ifTrue(function ($v) { return isset($v['driver']) && 'propel' === $v['driver'] && isset($v['listener']); }) ->thenInvalid('Propel doesn\'t support listeners') - ->ifTrue(function($v) { return isset($v['driver']) && 'propel' === $v['driver'] && isset($v['repository']); }) + ->ifTrue(function ($v) { return isset($v['driver']) && 'propel' === $v['driver'] && isset($v['repository']); }) ->thenInvalid('Propel doesn\'t support the "repository" parameter') ->end() ->children() diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 5d30739..9f502e7 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -80,8 +80,9 @@ class FOSElasticaExtension extends Extension } /** - * @param array $config + * @param array $config * @param ContainerBuilder $container + * * @return Configuration */ public function getConfiguration(array $config, ContainerBuilder $container) @@ -92,8 +93,9 @@ class FOSElasticaExtension extends Extension /** * Loads the configured clients. * - * @param array $clients An array of clients configurations + * @param array $clients An array of clients configurations * @param ContainerBuilder $container A ContainerBuilder instance + * * @return array */ private function loadClients(array $clients, ContainerBuilder $container) @@ -114,7 +116,7 @@ class FOSElasticaExtension extends Extension $this->clients[$name] = array( 'id' => $clientId, - 'reference' => new Reference($clientId) + 'reference' => new Reference($clientId), ); } } @@ -122,9 +124,11 @@ class FOSElasticaExtension extends Extension /** * Loads the configured indexes. * - * @param array $indexes An array of indexes configurations + * @param array $indexes An array of indexes configurations * @param ContainerBuilder $container A ContainerBuilder instance + * * @throws \InvalidArgumentException + * * @return array */ private function loadIndexes(array $indexes, ContainerBuilder $container) @@ -133,7 +137,7 @@ class FOSElasticaExtension extends Extension foreach ($indexes as $name => $index) { $indexId = sprintf('fos_elastica.index.%s', $name); - $indexName = isset($index['index_name']) ? $index['index_name']: $name; + $indexName = isset($index['index_name']) ? $index['index_name'] : $name; $indexDef = new DefinitionDecorator('fos_elastica.index_prototype'); $indexDef->replaceArgument(0, $indexName); @@ -173,8 +177,9 @@ class FOSElasticaExtension extends Extension * Loads the configured index finders. * * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container - * @param string $name The index name - * @param Reference $index Reference to the related index + * @param string $name The index name + * @param Reference $index Reference to the related index + * * @return string */ private function loadIndexFinder(ContainerBuilder $container, $name, Reference $index) @@ -197,10 +202,10 @@ class FOSElasticaExtension extends Extension /** * Loads the configured types. * - * @param array $types + * @param array $types * @param ContainerBuilder $container - * @param array $indexConfig - * @param array $indexableCallbacks + * @param array $indexConfig + * @param array $indexableCallbacks */ private function loadTypes(array $types, ContainerBuilder $container, array $indexConfig, array &$indexableCallbacks) { @@ -277,13 +282,13 @@ class FOSElasticaExtension extends Extension } /** - * Loads the optional provider and finder for a type + * Loads the optional provider and finder for a type. * - * @param array $typeConfig + * @param array $typeConfig * @param ContainerBuilder $container - * @param Reference $typeRef - * @param string $indexName - * @param string $typeName + * @param Reference $typeRef + * @param string $indexName + * @param string $typeName */ private function loadTypePersistenceIntegration(array $typeConfig, ContainerBuilder $container, Reference $typeRef, $indexName, $typeName) { @@ -307,10 +312,11 @@ class FOSElasticaExtension extends Extension /** * Creates and loads an ElasticaToModelTransformer. * - * @param array $typeConfig + * @param array $typeConfig * @param ContainerBuilder $container - * @param string $indexName - * @param string $typeName + * @param string $indexName + * @param string $typeName + * * @return string */ private function loadElasticaToModelTransformer(array $typeConfig, ContainerBuilder $container, $indexName, $typeName) @@ -342,10 +348,11 @@ class FOSElasticaExtension extends Extension /** * Creates and loads a ModelToElasticaTransformer for an index/type. * - * @param array $typeConfig + * @param array $typeConfig * @param ContainerBuilder $container - * @param string $indexName - * @param string $typeName + * @param string $indexName + * @param string $typeName + * * @return string */ private function loadModelToElasticaTransformer(array $typeConfig, ContainerBuilder $container, $indexName, $typeName) @@ -361,7 +368,7 @@ class FOSElasticaExtension extends Extension $serviceId = sprintf('fos_elastica.model_to_elastica_transformer.%s.%s', $indexName, $typeName); $serviceDef = new DefinitionDecorator($abstractId); $serviceDef->replaceArgument(0, array( - 'identifier' => $typeConfig['identifier'] + 'identifier' => $typeConfig['identifier'], )); $container->setDefinition($serviceId, $serviceDef); @@ -371,12 +378,13 @@ class FOSElasticaExtension extends Extension /** * Creates and loads an object persister for a type. * - * @param array $typeConfig - * @param Reference $typeRef + * @param array $typeConfig + * @param Reference $typeRef * @param ContainerBuilder $container - * @param string $indexName - * @param string $typeName - * @param string $transformerId + * @param string $indexName + * @param string $typeName + * @param string $transformerId + * * @return string */ private function loadObjectPersister(array $typeConfig, Reference $typeRef, ContainerBuilder $container, $indexName, $typeName, $transformerId) @@ -395,7 +403,7 @@ class FOSElasticaExtension extends Extension $abstractId = 'fos_elastica.object_persister'; $mapping = $this->indexConfigs[$indexName]['types'][$typeName]['mapping']; $argument = $mapping['properties']; - if(isset($mapping['_parent'])){ + if (isset($mapping['_parent'])) { $argument['_parent'] = $mapping['_parent']; } $arguments[] = $argument; @@ -415,11 +423,12 @@ class FOSElasticaExtension extends Extension /** * Loads a provider for a type. * - * @param array $typeConfig + * @param array $typeConfig * @param ContainerBuilder $container - * @param string $objectPersisterId - * @param string $indexName - * @param string $typeName + * @param string $objectPersisterId + * @param string $indexName + * @param string $typeName + * * @return string */ private function loadTypeProvider(array $typeConfig, ContainerBuilder $container, $objectPersisterId, $indexName, $typeName) @@ -432,7 +441,7 @@ class FOSElasticaExtension extends Extension * index and type names were "prototype" and a driver, respectively. */ $providerId = sprintf('fos_elastica.provider.%s.%s', $indexName, $typeName); - $providerDef = new DefinitionDecorator('fos_elastica.provider.prototype.' . $typeConfig['driver']); + $providerDef = new DefinitionDecorator('fos_elastica.provider.prototype.'.$typeConfig['driver']); $providerDef->addTag('fos_elastica.provider', array('index' => $indexName, 'type' => $typeName)); $providerDef->replaceArgument(0, new Reference($objectPersisterId)); $providerDef->replaceArgument(2, $typeConfig['model']); @@ -449,11 +458,12 @@ class FOSElasticaExtension extends Extension /** * Loads doctrine listeners to handle indexing of new or updated objects. * - * @param array $typeConfig + * @param array $typeConfig * @param ContainerBuilder $container - * @param string $objectPersisterId - * @param string $indexName - * @param string $typeName + * @param string $objectPersisterId + * @param string $indexName + * @param string $typeName + * * @return string */ private function loadTypeListener(array $typeConfig, ContainerBuilder $container, $objectPersisterId, $indexName, $typeName) @@ -490,7 +500,7 @@ class FOSElasticaExtension extends Extension } /** - * Map Elastica to Doctrine events for the current driver + * Map Elastica to Doctrine events for the current driver. */ private function getDoctrineEvents(array $typeConfig) { @@ -511,7 +521,7 @@ class FOSElasticaExtension extends Extension 'insert' => array(constant($eventsClass.'::postPersist')), 'update' => array(constant($eventsClass.'::postUpdate')), 'delete' => array(constant($eventsClass.'::preRemove')), - 'flush' => array($typeConfig['listener']['immediate'] ? constant($eventsClass.'::preFlush') : constant($eventsClass.'::postFlush')) + 'flush' => array($typeConfig['listener']['immediate'] ? constant($eventsClass.'::preFlush') : constant($eventsClass.'::postFlush')), ); foreach ($eventMapping as $event => $doctrineEvents) { @@ -526,12 +536,13 @@ class FOSElasticaExtension extends Extension /** * Loads a Type specific Finder. * - * @param array $typeConfig + * @param array $typeConfig * @param ContainerBuilder $container - * @param string $elasticaToModelId - * @param Reference $typeRef - * @param string $indexName - * @param string $typeName + * @param string $elasticaToModelId + * @param Reference $typeRef + * @param string $indexName + * @param string $typeName + * * @return string */ private function loadTypeFinder(array $typeConfig, ContainerBuilder $container, $elasticaToModelId, Reference $typeRef, $indexName, $typeName) @@ -558,7 +569,7 @@ class FOSElasticaExtension extends Extension } /** - * Loads the index manager + * Loads the index manager. * * @param ContainerBuilder $container **/ @@ -576,7 +587,7 @@ class FOSElasticaExtension extends Extension * Makes sure a specific driver has been loaded. * * @param ContainerBuilder $container - * @param string $driver + * @param string $driver */ private function loadDriver(ContainerBuilder $container, $driver) { @@ -592,7 +603,7 @@ class FOSElasticaExtension extends Extension /** * Loads and configures the serializer prototype. * - * @param array $config + * @param array $config * @param ContainerBuilder $container */ private function loadSerializer($config, ContainerBuilder $container) @@ -611,7 +622,7 @@ class FOSElasticaExtension extends Extension /** * Creates a default manager alias for defined default manager or the first loaded driver. * - * @param string $defaultManager + * @param string $defaultManager * @param ContainerBuilder $container */ private function createDefaultManagerAlias($defaultManager, ContainerBuilder $container) @@ -635,7 +646,9 @@ class FOSElasticaExtension extends Extension * Returns a reference to a client given its configured name. * * @param string $clientName + * * @return Reference + * * @throws \InvalidArgumentException */ private function getClient($clientName) diff --git a/Doctrine/AbstractElasticaToModelTransformer.php b/Doctrine/AbstractElasticaToModelTransformer.php index 96f73bd..a9afb22 100755 --- a/Doctrine/AbstractElasticaToModelTransformer.php +++ b/Doctrine/AbstractElasticaToModelTransformer.php @@ -10,24 +10,24 @@ use Symfony\Component\PropertyAccess\PropertyAccessorInterface; /** * Maps Elastica documents with Doctrine objects * This mapper assumes an exact match between - * elastica documents ids and doctrine object ids + * elastica documents ids and doctrine object ids. */ abstract class AbstractElasticaToModelTransformer implements ElasticaToModelTransformerInterface { /** - * Manager registry + * Manager registry. */ protected $registry = null; /** - * Class of the model to map to the elastica documents + * Class of the model to map to the elastica documents. * * @var string */ protected $objectClass = null; /** - * Optional parameters + * Optional parameters. * * @var array */ @@ -39,18 +39,18 @@ abstract class AbstractElasticaToModelTransformer implements ElasticaToModelTran ); /** - * PropertyAccessor instance + * PropertyAccessor instance. * * @var PropertyAccessorInterface */ protected $propertyAccessor; /** - * Instantiates a new Mapper + * Instantiates a new Mapper. * * @param object $registry * @param string $objectClass - * @param array $options + * @param array $options */ public function __construct($registry, $objectClass, array $options = array()) { @@ -70,7 +70,7 @@ abstract class AbstractElasticaToModelTransformer implements ElasticaToModelTran } /** - * Set the PropertyAccessor + * Set the PropertyAccessor. * * @param PropertyAccessorInterface $propertyAccessor */ @@ -81,10 +81,12 @@ abstract class AbstractElasticaToModelTransformer implements ElasticaToModelTran /** * Transforms an array of elastica objects into an array of - * model objects fetched from the doctrine repository + * model objects fetched from the doctrine repository. * * @param array $elasticaObjects of elastica objects + * * @throws \RuntimeException + * * @return array **/ public function transform(array $elasticaObjects) @@ -110,8 +112,7 @@ abstract class AbstractElasticaToModelTransformer implements ElasticaToModelTran $idPos = array_flip($ids); $identifier = $this->options['identifier']; $propertyAccessor = $this->propertyAccessor; - usort($objects, function($a, $b) use ($idPos, $identifier, $propertyAccessor) - { + usort($objects, function ($a, $b) use ($idPos, $identifier, $propertyAccessor) { return $idPos[$propertyAccessor->getValue($a, $identifier)] > $idPos[$propertyAccessor->getValue($b, $identifier)]; }); @@ -145,11 +146,12 @@ abstract class AbstractElasticaToModelTransformer implements ElasticaToModelTran } /** - * Fetches objects by theses identifier values + * Fetches objects by theses identifier values. + * + * @param array $identifierValues ids values + * @param Boolean $hydrate whether or not to hydrate the objects, false returns arrays * - * @param array $identifierValues ids values - * @param Boolean $hydrate whether or not to hydrate the objects, false returns arrays * @return array of objects or arrays */ - protected abstract function findByIdentifiers(array $identifierValues, $hydrate); + abstract protected function findByIdentifiers(array $identifierValues, $hydrate); } diff --git a/Doctrine/AbstractProvider.php b/Doctrine/AbstractProvider.php index 92be6ce..26fce55 100644 --- a/Doctrine/AbstractProvider.php +++ b/Doctrine/AbstractProvider.php @@ -16,10 +16,10 @@ abstract class AbstractProvider extends BaseAbstractProvider * Constructor. * * @param ObjectPersisterInterface $objectPersister - * @param IndexableInterface $indexable - * @param string $objectClass - * @param array $options - * @param ManagerRegistry $managerRegistry + * @param IndexableInterface $indexable + * @param string $objectClass + * @param array $options + * @param ManagerRegistry $managerRegistry */ public function __construct( ObjectPersisterInterface $objectPersister, @@ -81,9 +81,9 @@ abstract class AbstractProvider extends BaseAbstractProvider } else { try { $this->objectPersister->insertMany($objects); - } catch(BulkResponseException $e) { + } catch (BulkResponseException $e) { if ($loggerClosure) { - $loggerClosure(sprintf('%s',$e->getMessage())); + $loggerClosure(sprintf('%s', $e->getMessage())); } } } @@ -112,24 +112,26 @@ abstract class AbstractProvider extends BaseAbstractProvider * Counts objects that would be indexed using the query builder. * * @param object $queryBuilder + * * @return integer */ - protected abstract function countObjects($queryBuilder); + abstract protected function countObjects($queryBuilder); /** * Disables logging and returns the logger that was previously set. * * @return mixed */ - protected abstract function disableLogging(); + abstract protected function disableLogging(); /** - * Reenables the logger with the previously returned logger from disableLogging(); + * Reenables the logger with the previously returned logger from disableLogging();. * * @param mixed $logger + * * @return mixed */ - protected abstract function enableLogging($logger); + abstract protected function enableLogging($logger); /** * Fetches a slice of objects using the query builder. @@ -137,14 +139,15 @@ abstract class AbstractProvider extends BaseAbstractProvider * @param object $queryBuilder * @param integer $limit * @param integer $offset + * * @return array */ - protected abstract function fetchSlice($queryBuilder, $limit, $offset); + abstract protected function fetchSlice($queryBuilder, $limit, $offset); /** * Creates the query builder, which will be used to fetch objects to index. * * @return object */ - protected abstract function createQueryBuilder(); + abstract protected function createQueryBuilder(); } diff --git a/Doctrine/Listener.php b/Doctrine/Listener.php index bd8b2c0..6276c12 100644 --- a/Doctrine/Listener.php +++ b/Doctrine/Listener.php @@ -17,39 +17,39 @@ use Symfony\Component\PropertyAccess\PropertyAccessorInterface; class Listener implements EventSubscriber { /** - * Object persister + * Object persister. * * @var ObjectPersister */ protected $objectPersister; /** - * List of subscribed events + * List of subscribed events. * * @var array */ protected $events; /** - * Configuration for the listener + * Configuration for the listener. * * @var string */ private $config; /** - * Objects scheduled for insertion and replacement + * Objects scheduled for insertion and replacement. */ public $scheduledForInsertion = array(); public $scheduledForUpdate = array(); /** - * IDs of objects scheduled for removal + * IDs of objects scheduled for removal. */ public $scheduledForDeletion = array(); /** - * PropertyAccessor instance + * PropertyAccessor instance. * * @var PropertyAccessorInterface */ @@ -64,10 +64,10 @@ class Listener implements EventSubscriber * Constructor. * * @param ObjectPersisterInterface $objectPersister - * @param array $events - * @param IndexableInterface $indexable - * @param array $config - * @param null $logger + * @param array $events + * @param IndexableInterface $indexable + * @param array $config + * @param null $logger */ public function __construct( ObjectPersisterInterface $objectPersister, @@ -98,11 +98,13 @@ class Listener implements EventSubscriber } /** - * Provides unified method for retrieving a doctrine object from an EventArgs instance + * Provides unified method for retrieving a doctrine object from an EventArgs instance. * - * @param EventArgs $eventArgs - * @return object Entity | Document - * @throws \RuntimeException if no valid getter is found. + * @param EventArgs $eventArgs + * + * @return object Entity | Document + * + * @throws \RuntimeException if no valid getter is found. */ private function getDoctrineObject(EventArgs $eventArgs) { @@ -142,7 +144,7 @@ class Listener implements EventSubscriber /** * Delete objects preRemove instead of postRemove so that we have access to the id. Because this is called - * preRemove, first check that the entity is managed by Doctrine + * preRemove, first check that the entity is managed by Doctrine. */ public function preRemove(EventArgs $eventArgs) { @@ -155,7 +157,7 @@ class Listener implements EventSubscriber /** * Persist scheduled objects to ElasticSearch - * After persisting, clear the scheduled queue to prevent multiple data updates when using multiple flush calls + * After persisting, clear the scheduled queue to prevent multiple data updates when using multiple flush calls. */ private function persistScheduled() { @@ -210,6 +212,7 @@ class Listener implements EventSubscriber * Checks if the object is indexable or not. * * @param object $object + * * @return bool */ private function isObjectIndexable($object) diff --git a/Doctrine/MongoDB/ElasticaToModelTransformer.php b/Doctrine/MongoDB/ElasticaToModelTransformer.php index cea737f..23a8292 100644 --- a/Doctrine/MongoDB/ElasticaToModelTransformer.php +++ b/Doctrine/MongoDB/ElasticaToModelTransformer.php @@ -7,15 +7,16 @@ use FOS\ElasticaBundle\Doctrine\AbstractElasticaToModelTransformer; /** * Maps Elastica documents with Doctrine objects * This mapper assumes an exact match between - * elastica documents ids and doctrine object ids + * elastica documents ids and doctrine object ids. */ class ElasticaToModelTransformer extends AbstractElasticaToModelTransformer { /** - * Fetch objects for theses identifier values + * Fetch objects for theses identifier values. + * + * @param array $identifierValues ids values + * @param Boolean $hydrate whether or not to hydrate the objects, false returns arrays * - * @param array $identifierValues ids values - * @param Boolean $hydrate whether or not to hydrate the objects, false returns arrays * @return array of objects or arrays */ protected function findByIdentifiers(array $identifierValues, $hydrate) diff --git a/Doctrine/MongoDB/Provider.php b/Doctrine/MongoDB/Provider.php index 9e1c5dd..2ed1454 100644 --- a/Doctrine/MongoDB/Provider.php +++ b/Doctrine/MongoDB/Provider.php @@ -27,9 +27,10 @@ class Provider extends AbstractProvider } /** - * Reenables the logger with the previously returned logger from disableLogging(); + * Reenables the logger with the previously returned logger from disableLogging();. * * @param mixed $logger + * * @return mixed */ protected function enableLogging($logger) diff --git a/Doctrine/ORM/ElasticaToModelTransformer.php b/Doctrine/ORM/ElasticaToModelTransformer.php index a57a84c..21d8640 100644 --- a/Doctrine/ORM/ElasticaToModelTransformer.php +++ b/Doctrine/ORM/ElasticaToModelTransformer.php @@ -8,17 +8,18 @@ use Doctrine\ORM\Query; /** * Maps Elastica documents with Doctrine objects * This mapper assumes an exact match between - * elastica documents ids and doctrine object ids + * elastica documents ids and doctrine object ids. */ class ElasticaToModelTransformer extends AbstractElasticaToModelTransformer { const ENTITY_ALIAS = 'o'; /** - * Fetch objects for theses identifier values + * Fetch objects for theses identifier values. + * + * @param array $identifierValues ids values + * @param Boolean $hydrate whether or not to hydrate the objects, false returns arrays * - * @param array $identifierValues ids values - * @param Boolean $hydrate whether or not to hydrate the objects, false returns arrays * @return array of objects or arrays */ protected function findByIdentifiers(array $identifierValues, $hydrate) @@ -36,7 +37,7 @@ class ElasticaToModelTransformer extends AbstractElasticaToModelTransformer } /** - * Retrieves a query builder to be used for querying by identifiers + * Retrieves a query builder to be used for querying by identifiers. * * @return \Doctrine\ORM\QueryBuilder */ diff --git a/Doctrine/ORM/Provider.php b/Doctrine/ORM/Provider.php index 7e2ac12..fc59667 100644 --- a/Doctrine/ORM/Provider.php +++ b/Doctrine/ORM/Provider.php @@ -29,9 +29,10 @@ class Provider extends AbstractProvider } /** - * Reenables the logger with the previously returned logger from disableLogging(); + * Reenables the logger with the previously returned logger from disableLogging();. * * @param mixed $logger + * * @return mixed */ protected function enableLogging($logger) @@ -76,7 +77,7 @@ class Provider extends AbstractProvider throw new InvalidArgumentTypeException($queryBuilder, 'Doctrine\ORM\QueryBuilder'); } - /** + /* * An orderBy DQL part is required to avoid feching the same row twice. * @see http://stackoverflow.com/questions/6314879/does-limit-offset-length-require-order-by-for-pagination * @see http://www.postgresql.org/docs/current/static/queries-limit.html diff --git a/Doctrine/RepositoryManager.php b/Doctrine/RepositoryManager.php index f8867eb..0d20f64 100644 --- a/Doctrine/RepositoryManager.php +++ b/Doctrine/RepositoryManager.php @@ -25,7 +25,7 @@ class RepositoryManager extends BaseManager } /** - * Return repository for entity + * Return repository for entity. * * Returns custom repository if one specified otherwise * returns a basic repository. @@ -35,7 +35,7 @@ class RepositoryManager extends BaseManager $realEntityName = $entityName; if (strpos($entityName, ':') !== false) { list($namespaceAlias, $simpleClassName) = explode(':', $entityName); - $realEntityName = $this->managerRegistry->getAliasNamespace($namespaceAlias) . '\\' . $simpleClassName; + $realEntityName = $this->managerRegistry->getAliasNamespace($namespaceAlias).'\\'.$simpleClassName; } return parent::getRepository($realEntityName); diff --git a/Elastica/Client.php b/Elastica/Client.php index 372b395..c244eb4 100644 --- a/Elastica/Client.php +++ b/Elastica/Client.php @@ -23,7 +23,7 @@ class Client extends BaseClient private $indexCache = array(); /** - * Symfony's debugging Stopwatch + * Symfony's debugging Stopwatch. * * @var Stopwatch|null */ @@ -32,8 +32,9 @@ class Client extends BaseClient /** * @param string $path * @param string $method - * @param array $data - * @param array $query + * @param array $data + * @param array $query + * * @return \Elastica\Response */ public function request($path, $method = Request::GET, $data = array(), array $query = array()) @@ -78,9 +79,9 @@ class Client extends BaseClient * * @param string $path * @param string $method - * @param array $data - * @param array $query - * @param int $start + * @param array $data + * @param array $query + * @param int $start */ private function logQuery($path, $method, $data, array $query, $start) { diff --git a/Elastica/Index.php b/Elastica/Index.php index 49c656e..ad3bd4d 100644 --- a/Elastica/Index.php +++ b/Elastica/Index.php @@ -44,14 +44,12 @@ class Index extends BaseIndex } /** - * Reassign index name + * Reassign index name. * * While it's technically a regular setter for name property, it's specifically named overrideName, but not setName * since it's used for a very specific case and normally should not be used * * @param string $name Index name - * - * @return void */ public function overrideName($name) { diff --git a/Exception/AliasIsIndexException.php b/Exception/AliasIsIndexException.php index 87f546b..1df7a62 100644 --- a/Exception/AliasIsIndexException.php +++ b/Exception/AliasIsIndexException.php @@ -9,4 +9,3 @@ class AliasIsIndexException extends \Exception parent::__construct(sprintf('Expected alias %s instead of index', $indexName)); } } - diff --git a/FOSElasticaBundle.php b/FOSElasticaBundle.php index 3dec2a0..0e6de66 100644 --- a/FOSElasticaBundle.php +++ b/FOSElasticaBundle.php @@ -12,7 +12,6 @@ use Symfony\Component\HttpKernel\Bundle\Bundle; /** * Bundle. - * */ class FOSElasticaBundle extends Bundle { diff --git a/Finder/FinderInterface.php b/Finder/FinderInterface.php index 7c257de..86dbf86 100644 --- a/Finder/FinderInterface.php +++ b/Finder/FinderInterface.php @@ -5,12 +5,13 @@ namespace FOS\ElasticaBundle\Finder; interface FinderInterface { /** - * Searches for query results within a given limit + * Searches for query results within a given limit. * - * @param mixed $query Can be a string, an array or an \Elastica\Query object - * @param int $limit How many results to get + * @param mixed $query Can be a string, an array or an \Elastica\Query object + * @param int $limit How many results to get * @param array $options + * * @return array results */ - function find($query, $limit = null, $options = array()); + public function find($query, $limit = null, $options = array()); } diff --git a/Finder/PaginatedFinderInterface.php b/Finder/PaginatedFinderInterface.php index fa10b70..1fc7a48 100644 --- a/Finder/PaginatedFinderInterface.php +++ b/Finder/PaginatedFinderInterface.php @@ -9,20 +9,22 @@ use Elastica\Query; interface PaginatedFinderInterface extends FinderInterface { /** - * Searches for query results and returns them wrapped in a paginator + * Searches for query results and returns them wrapped in a paginator. * - * @param mixed $query Can be a string, an array or an \Elastica\Query object + * @param mixed $query Can be a string, an array or an \Elastica\Query object * @param array $options + * * @return Pagerfanta paginated results */ - function findPaginated($query, $options = array()); + public function findPaginated($query, $options = array()); /** - * Creates a paginator adapter for this query + * Creates a paginator adapter for this query. * * @param mixed $query * @param array $options + * * @return PaginatorAdapterInterface */ - function createPaginatorAdapter($query, $options = array()); + public function createPaginatorAdapter($query, $options = array()); } diff --git a/Finder/TransformedFinder.php b/Finder/TransformedFinder.php index 9080701..44f6d2f 100644 --- a/Finder/TransformedFinder.php +++ b/Finder/TransformedFinder.php @@ -11,7 +11,7 @@ use Elastica\SearchableInterface; use Elastica\Query; /** - * Finds elastica documents and map them to persisted objects + * Finds elastica documents and map them to persisted objects. */ class TransformedFinder implements PaginatedFinderInterface { @@ -25,11 +25,12 @@ class TransformedFinder implements PaginatedFinderInterface } /** - * Search for a query string + * Search for a query string. * - * @param string $query + * @param string $query * @param integer $limit - * @param array $options + * @param array $options + * * @return array of model objects **/ public function find($query, $limit = null, $options = array()) @@ -50,8 +51,9 @@ class TransformedFinder implements PaginatedFinderInterface * Find documents similar to one with passed id. * * @param integer $id - * @param array $params - * @param array $query + * @param array $params + * @param array $query + * * @return array of model objects **/ public function moreLikeThis($id, $params = array(), $query = array()) @@ -65,7 +67,8 @@ class TransformedFinder implements PaginatedFinderInterface /** * @param $query * @param null|int $limit - * @param array $options + * @param array $options + * * @return array */ protected function search($query, $limit = null, $options = array()) @@ -80,10 +83,11 @@ class TransformedFinder implements PaginatedFinderInterface } /** - * Gets a paginator wrapping the result of a search + * Gets a paginator wrapping the result of a search. * * @param string $query - * @param array $options + * @param array $options + * * @return Pagerfanta */ public function findPaginated($query, $options = array()) diff --git a/HybridResult.php b/HybridResult.php index ebd0e99..81499ba 100644 --- a/HybridResult.php +++ b/HybridResult.php @@ -24,4 +24,4 @@ class HybridResult { return $this->result; } -} \ No newline at end of file +} diff --git a/Index/AliasProcessor.php b/Index/AliasProcessor.php index 29cfdc5..61c111e 100644 --- a/Index/AliasProcessor.php +++ b/Index/AliasProcessor.php @@ -24,7 +24,7 @@ class AliasProcessor * Sets the randomised root name for an index. * * @param IndexConfig $indexConfig - * @param Index $index + * @param Index $index */ public function setRootName(IndexConfig $indexConfig, Index $index) { @@ -38,8 +38,9 @@ class AliasProcessor * $force will delete an index encountered where an alias is expected. * * @param IndexConfig $indexConfig - * @param Index $index - * @param bool $force + * @param Index $index + * @param bool $force + * * @throws AliasIsIndexException * @throws \RuntimeException */ @@ -53,7 +54,7 @@ class AliasProcessor try { $aliasedIndexes = $this->getAliasedIndexes($client, $aliasName); - } catch(AliasIsIndexException $e) { + } catch (AliasIsIndexException $e) { if (!$force) { throw $e; } @@ -68,7 +69,7 @@ class AliasProcessor 'Alias %s is used for multiple indexes: [%s]. Make sure it\'s either not used or is assigned to one index only', $aliasName, - join(', ', $aliasedIndexes) + implode(', ', $aliasedIndexes) ) ); } @@ -78,13 +79,13 @@ class AliasProcessor // if the alias is set - add an action to remove it $oldIndexName = $aliasedIndexes[0]; $aliasUpdateRequest['actions'][] = array( - 'remove' => array('index' => $oldIndexName, 'alias' => $aliasName) + 'remove' => array('index' => $oldIndexName, 'alias' => $aliasName), ); } // add an action to point the alias to the new index $aliasUpdateRequest['actions'][] = array( - 'add' => array('index' => $newIndexName, 'alias' => $aliasName) + 'add' => array('index' => $newIndexName, 'alias' => $aliasName), ); try { @@ -129,11 +130,13 @@ class AliasProcessor } /** - * Returns array of indexes which are mapped to given alias + * Returns array of indexes which are mapped to given alias. * * @param Client $client * @param string $aliasName Alias name + * * @return array + * * @throws AliasIsIndexException */ private function getAliasedIndexes(Client $client, $aliasName) @@ -159,7 +162,7 @@ class AliasProcessor } /** - * Delete an index + * Delete an index. * * @param Client $client * @param string $indexName Index name to delete diff --git a/Index/IndexManager.php b/Index/IndexManager.php index 38249a7..13aecad 100644 --- a/Index/IndexManager.php +++ b/Index/IndexManager.php @@ -22,7 +22,7 @@ class IndexManager } /** - * Gets all registered indexes + * Gets all registered indexes. * * @return array */ @@ -32,10 +32,12 @@ class IndexManager } /** - * Gets an index by its name + * Gets an index by its name. * * @param string $name Index to return, or the default index if null + * * @return Index + * * @throws \InvalidArgumentException if no index exists for the given name */ public function getIndex($name = null) @@ -52,7 +54,7 @@ class IndexManager } /** - * Gets the default index + * Gets the default index. * * @return Index */ diff --git a/Index/MappingBuilder.php b/Index/MappingBuilder.php index 9782e84..0af3773 100644 --- a/Index/MappingBuilder.php +++ b/Index/MappingBuilder.php @@ -27,6 +27,7 @@ class MappingBuilder * Builds mappings for an entire index. * * @param IndexConfig $indexConfig + * * @return array */ public function buildIndexMapping(IndexConfig $indexConfig) @@ -54,6 +55,7 @@ class MappingBuilder * Builds mappings for a single type. * * @param TypeConfig $typeConfig + * * @return array */ public function buildTypeMapping(TypeConfig $typeConfig) @@ -89,7 +91,7 @@ class MappingBuilder if (!$mapping) { // Empty mapping, we want it encoded as a {} instead of a [] - $mapping = new \stdClass; + $mapping = new \stdClass(); } return $mapping; diff --git a/Index/Resetter.php b/Index/Resetter.php index 9b65a8f..d537dd8 100644 --- a/Index/Resetter.php +++ b/Index/Resetter.php @@ -8,7 +8,7 @@ use Elastica\Type\Mapping; use FOS\ElasticaBundle\Configuration\ConfigManager; /** - * Deletes and recreates indexes + * Deletes and recreates indexes. */ class Resetter { @@ -41,7 +41,7 @@ class Resetter } /** - * Deletes and recreates all indexes + * Deletes and recreates all indexes. */ public function resetAllIndexes($populating = false, $force = false) { @@ -55,8 +55,9 @@ class Resetter * with a randomised name for an alias to be set after population. * * @param string $indexName - * @param bool $populating - * @param bool $force If index exists with same name as alias, remove it + * @param bool $populating + * @param bool $force If index exists with same name as alias, remove it + * * @throws \InvalidArgumentException if no index exists for the given name */ public function resetIndex($indexName, $populating = false, $force = false) @@ -77,10 +78,11 @@ class Resetter } /** - * Deletes and recreates a mapping type for the named index + * Deletes and recreates a mapping type for the named index. * * @param string $indexName * @param string $typeName + * * @throws \InvalidArgumentException if no index or type mapping exists for the given names * @throws ResponseException */ @@ -97,7 +99,7 @@ class Resetter } } - $mapping = new Mapping; + $mapping = new Mapping(); foreach ($this->mappingBuilder->buildTypeMapping($typeConfig) as $name => $field) { $mapping->setParam($name, $field); } diff --git a/Manager/RepositoryManager.php b/Manager/RepositoryManager.php index 7697b58..1a0601c 100644 --- a/Manager/RepositoryManager.php +++ b/Manager/RepositoryManager.php @@ -25,13 +25,13 @@ class RepositoryManager implements RepositoryManagerInterface public function addEntity($entityName, FinderInterface $finder, $repositoryName = null) { - $this->entities[$entityName]= array(); + $this->entities[$entityName] = array(); $this->entities[$entityName]['finder'] = $finder; $this->entities[$entityName]['repositoryName'] = $repositoryName; } /** - * Return repository for entity + * Return repository for entity. * * Returns custom repository if one specified otherwise * returns a basic repository. @@ -63,6 +63,7 @@ class RepositoryManager implements RepositoryManagerInterface if ($annotation) { $this->entities[$entityName]['repositoryName'] = $annotation->repositoryClass; + return $annotation->repositoryClass; } diff --git a/Manager/RepositoryManagerInterface.php b/Manager/RepositoryManagerInterface.php index 1008371..0a38e0e 100644 --- a/Manager/RepositoryManagerInterface.php +++ b/Manager/RepositoryManagerInterface.php @@ -12,7 +12,6 @@ use FOS\ElasticaBundle\Finder\FinderInterface; */ interface RepositoryManagerInterface { - /** * Adds entity name and its finder. * Custom repository class name can also be added. @@ -24,7 +23,7 @@ interface RepositoryManagerInterface public function addEntity($entityName, FinderInterface $finder, $repositoryName = null); /** - * Return repository for entity + * Return repository for entity. * * Returns custom repository if one specified otherwise * returns a basic repository. diff --git a/Paginator/FantaPaginatorAdapter.php b/Paginator/FantaPaginatorAdapter.php index 2ad6983..2ac5412 100644 --- a/Paginator/FantaPaginatorAdapter.php +++ b/Paginator/FantaPaginatorAdapter.php @@ -29,7 +29,7 @@ class FantaPaginatorAdapter implements AdapterInterface } /** - * Returns Facets + * Returns Facets. * * @return mixed * diff --git a/Paginator/PaginatorAdapterInterface.php b/Paginator/PaginatorAdapterInterface.php index 25786a0..126373d 100644 --- a/Paginator/PaginatorAdapterInterface.php +++ b/Paginator/PaginatorAdapterInterface.php @@ -11,7 +11,7 @@ interface PaginatorAdapterInterface * * @api */ - function getTotalHits(); + public function getTotalHits(); /** * Returns an slice of the results. @@ -23,12 +23,12 @@ interface PaginatorAdapterInterface * * @api */ - function getResults($offset, $length); + public function getResults($offset, $length); /** - * Returns Facets + * Returns Facets. * * @return mixed */ - function getFacets(); + public function getFacets(); } diff --git a/Paginator/PartialResultsInterface.php b/Paginator/PartialResultsInterface.php index 9efe7f3..a4f8f7d 100644 --- a/Paginator/PartialResultsInterface.php +++ b/Paginator/PartialResultsInterface.php @@ -11,7 +11,7 @@ interface PartialResultsInterface * * @api */ - function toArray(); + public function toArray(); /** * Returns the number of results. @@ -20,12 +20,12 @@ interface PartialResultsInterface * * @api */ - function getTotalHits(); + public function getTotalHits(); /** - * Returns the facets + * Returns the facets. * * @return array */ - function getFacets(); -} \ No newline at end of file + public function getFacets(); +} diff --git a/Paginator/RawPaginatorAdapter.php b/Paginator/RawPaginatorAdapter.php index f05205a..cfbe24a 100644 --- a/Paginator/RawPaginatorAdapter.php +++ b/Paginator/RawPaginatorAdapter.php @@ -8,7 +8,7 @@ use Elastica\ResultSet; use InvalidArgumentException; /** - * Allows pagination of Elastica\Query. Does not map results + * Allows pagination of Elastica\Query. Does not map results. */ class RawPaginatorAdapter implements PaginatorAdapterInterface { @@ -41,7 +41,7 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface * @see PaginatorAdapterInterface::__construct * * @param SearchableInterface $searchable the object to search in - * @param Query $query the query to search + * @param Query $query the query to search * @param array $options */ public function __construct(SearchableInterface $searchable, Query $query, array $options = array()) @@ -56,7 +56,9 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface * * @param integer $offset * @param integer $itemCountPerPage + * * @throws \InvalidArgumentException + * * @return ResultSet */ protected function getElasticaResults($offset, $itemCountPerPage) @@ -82,6 +84,7 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface $resultSet = $this->searchable->search($query, $this->options); $this->totalHits = $resultSet->getTotalHits(); $this->facets = $resultSet->getFacets(); + return $resultSet; } @@ -90,6 +93,7 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface * * @param int $offset * @param int $itemCountPerPage + * * @return PartialResultsInterface */ public function getResults($offset, $itemCountPerPage) @@ -104,7 +108,7 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface */ public function getTotalHits() { - if ( ! isset($this->totalHits)) { + if (! isset($this->totalHits)) { $this->totalHits = $this->searchable->search($this->query)->getTotalHits(); } @@ -114,13 +118,13 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface } /** - * Returns Facets + * Returns Facets. * * @return mixed */ public function getFacets() { - if ( ! isset($this->facets)) { + if (! isset($this->facets)) { $this->facets = $this->searchable->search($this->query)->getFacets(); } @@ -128,7 +132,7 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface } /** - * Returns the Query + * Returns the Query. * * @return Query the search query */ diff --git a/Paginator/RawPartialResults.php b/Paginator/RawPartialResults.php index a4afb00..3a79abd 100644 --- a/Paginator/RawPartialResults.php +++ b/Paginator/RawPartialResults.php @@ -6,7 +6,7 @@ use Elastica\ResultSet; use Elastica\Result; /** - * Raw partial results transforms to a simple array + * Raw partial results transforms to a simple array. */ class RawPartialResults implements PartialResultsInterface { @@ -25,7 +25,7 @@ class RawPartialResults implements PartialResultsInterface */ public function toArray() { - return array_map(function(Result $result) { + return array_map(function (Result $result) { return $result->getSource(); }, $this->resultSet->getResults()); } @@ -47,6 +47,6 @@ class RawPartialResults implements PartialResultsInterface return $this->resultSet->getFacets(); } - return null; + return; } -} \ No newline at end of file +} diff --git a/Paginator/TransformedPaginatorAdapter.php b/Paginator/TransformedPaginatorAdapter.php index 3b4716f..bf152fb 100644 --- a/Paginator/TransformedPaginatorAdapter.php +++ b/Paginator/TransformedPaginatorAdapter.php @@ -7,15 +7,15 @@ use Elastica\SearchableInterface; use Elastica\Query; /** - * Allows pagination of \Elastica\Query + * Allows pagination of \Elastica\Query. */ class TransformedPaginatorAdapter extends RawPaginatorAdapter { private $transformer; /** - * @param SearchableInterface $searchable the object to search in - * @param Query $query the query to search + * @param SearchableInterface $searchable the object to search in + * @param Query $query the query to search * @param array $options * @param ElasticaToModelTransformerInterface $transformer the transformer for fetching the results */ diff --git a/Paginator/TransformedPartialResults.php b/Paginator/TransformedPartialResults.php index 13d716c..c9470c3 100644 --- a/Paginator/TransformedPartialResults.php +++ b/Paginator/TransformedPartialResults.php @@ -6,14 +6,14 @@ use FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface; use Elastica\ResultSet; /** - * Partial transformed result set + * Partial transformed result set. */ class TransformedPartialResults extends RawPartialResults { protected $transformer; /** - * @param ResultSet $resultSet + * @param ResultSet $resultSet * @param \FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface $transformer */ public function __construct(ResultSet $resultSet, ElasticaToModelTransformerInterface $transformer) @@ -30,4 +30,4 @@ class TransformedPartialResults extends RawPartialResults { return $this->transformer->transform($this->resultSet->getResults()); } -} \ No newline at end of file +} diff --git a/Persister/ObjectPersister.php b/Persister/ObjectPersister.php index 0fe40c3..a34e671 100644 --- a/Persister/ObjectPersister.php +++ b/Persister/ObjectPersister.php @@ -10,7 +10,7 @@ use Elastica\Document; /** * Inserts, replaces and deletes single documents in an elastica type - * Accepts domain model objects and converts them to elastica documents + * Accepts domain model objects and converts them to elastica documents. * * @author Thibault Duplessis */ @@ -34,6 +34,7 @@ class ObjectPersister implements ObjectPersisterInterface * If the ObjectPersister handles a given object. * * @param object $object + * * @return bool */ public function handlesObject($object) @@ -47,11 +48,11 @@ class ObjectPersister implements ObjectPersisterInterface } /** - * Log exception if logger defined for persister belonging to the current listener, otherwise re-throw + * Log exception if logger defined for persister belonging to the current listener, otherwise re-throw. * * @param BulkException $e + * * @throws BulkException - * @return null */ private function log(BulkException $e) { @@ -64,7 +65,7 @@ class ObjectPersister implements ObjectPersisterInterface /** * Insert one object into the type - * The object will be transformed to an elastica document + * The object will be transformed to an elastica document. * * @param object $object */ @@ -74,10 +75,9 @@ class ObjectPersister implements ObjectPersisterInterface } /** - * Replaces one object in the type + * Replaces one object in the type. * * @param object $object - * @return null **/ public function replaceOne($object) { @@ -85,10 +85,9 @@ class ObjectPersister implements ObjectPersisterInterface } /** - * Deletes one object in the type + * Deletes one object in the type. * * @param object $object - * @return null **/ public function deleteOne($object) { @@ -96,11 +95,9 @@ class ObjectPersister implements ObjectPersisterInterface } /** - * Deletes one object in the type by id + * Deletes one object in the type by id. * * @param mixed $id - * - * @return null **/ public function deleteById($id) { @@ -108,7 +105,7 @@ class ObjectPersister implements ObjectPersisterInterface } /** - * Bulk insert an array of objects in the type for the given method + * Bulk insert an array of objects in the type for the given method. * * @param array $objects array of domain model objects * @param string Method to call @@ -148,7 +145,7 @@ class ObjectPersister implements ObjectPersisterInterface } /** - * Bulk deletes an array of objects in the type + * Bulk deletes an array of objects in the type. * * @param array $objects array of domain model objects */ @@ -166,7 +163,7 @@ class ObjectPersister implements ObjectPersisterInterface } /** - * Bulk deletes records from an array of identifiers + * Bulk deletes records from an array of identifiers. * * @param array $identifiers array of domain model object identifiers */ @@ -180,9 +177,10 @@ class ObjectPersister implements ObjectPersisterInterface } /** - * Transforms an object to an elastica document + * Transforms an object to an elastica document. * * @param object $object + * * @return Document the elastica document */ public function transformToElasticaDocument($object) diff --git a/Persister/ObjectPersisterInterface.php b/Persister/ObjectPersisterInterface.php index 2b4c8ee..8575887 100644 --- a/Persister/ObjectPersisterInterface.php +++ b/Persister/ObjectPersisterInterface.php @@ -4,7 +4,7 @@ namespace FOS\ElasticaBundle\Persister; /** * Inserts, replaces and deletes single documents in an elastica type - * Accepts domain model objects and converts them to elastica documents + * Accepts domain model objects and converts them to elastica documents. * * @author Thibault Duplessis */ @@ -12,58 +12,56 @@ interface ObjectPersisterInterface { /** * Insert one object into the type - * The object will be transformed to an elastica document + * The object will be transformed to an elastica document. * * @param object $object */ - function insertOne($object); + public function insertOne($object); /** - * Replaces one object in the type + * Replaces one object in the type. * * @param object $object **/ - function replaceOne($object); + public function replaceOne($object); /** - * Deletes one object in the type + * Deletes one object in the type. * * @param object $object **/ - function deleteOne($object); + public function deleteOne($object); /** - * Deletes one object in the type by id + * Deletes one object in the type by id. * * @param mixed $id - * - * @return null */ - function deleteById($id); + public function deleteById($id); /** - * Bulk inserts an array of objects in the type + * Bulk inserts an array of objects in the type. * * @param array $objects array of domain model objects */ - function insertMany(array $objects); + public function insertMany(array $objects); /** - * Bulk updates an array of objects in the type + * Bulk updates an array of objects in the type. * * @param array $objects array of domain model objects */ - function replaceMany(array $objects); + public function replaceMany(array $objects); /** - * Bulk deletes an array of objects in the type + * Bulk deletes an array of objects in the type. * * @param array $objects array of domain model objects */ - function deleteMany(array $objects); + public function deleteMany(array $objects); /** - * Bulk deletes records from an array of identifiers + * Bulk deletes records from an array of identifiers. * * @param array $identifiers array of domain model object identifiers */ diff --git a/Persister/ObjectSerializerPersister.php b/Persister/ObjectSerializerPersister.php index 3e33f8d..018f851 100644 --- a/Persister/ObjectSerializerPersister.php +++ b/Persister/ObjectSerializerPersister.php @@ -9,7 +9,7 @@ use FOS\ElasticaBundle\Transformer\ModelToElasticaTransformerInterface; /** * Inserts, replaces and deletes single objects in an elastica type, making use * of elastica's serializer support to convert objects in to elastica documents. - * Accepts domain model objects and passes them directly to elastica + * Accepts domain model objects and passes them directly to elastica. * * @author Lea Haensenberber */ @@ -28,9 +28,10 @@ class ObjectSerializerPersister extends ObjectPersister /** * Transforms an object to an elastica document - * with just the identifier set + * with just the identifier set. * * @param object $object + * * @return Document the elastica document */ public function transformToElasticaDocument($object) diff --git a/Propel/ElasticaToModelTransformer.php b/Propel/ElasticaToModelTransformer.php index e3602e5..87c4047 100644 --- a/Propel/ElasticaToModelTransformer.php +++ b/Propel/ElasticaToModelTransformer.php @@ -44,7 +44,7 @@ class ElasticaToModelTransformer implements ElasticaToModelTransformerInterface * Constructor. * * @param string $objectClass - * @param array $options + * @param array $options */ public function __construct($objectClass, array $options = array()) { @@ -67,6 +67,7 @@ class ElasticaToModelTransformer implements ElasticaToModelTransformerInterface * fetched from the database. * * @param array $elasticaObjects + * * @return array|\ArrayObject */ public function transform(array $elasticaObjects) @@ -83,7 +84,7 @@ class ElasticaToModelTransformer implements ElasticaToModelTransformerInterface $identifier = $this->options['identifier']; $propertyAccessor = $this->propertyAccessor; - $sortCallback = function($a, $b) use ($idPos, $identifier, $propertyAccessor) { + $sortCallback = function ($a, $b) use ($idPos, $identifier, $propertyAccessor) { return $idPos[$propertyAccessor->getValue($a, $identifier)] > $idPos[$propertyAccessor->getValue($b, $identifier)]; }; @@ -135,6 +136,7 @@ class ElasticaToModelTransformer implements ElasticaToModelTransformerInterface * * @param array $identifierValues Identifier values * @param boolean $hydrate Whether or not to hydrate the results + * * @return array */ protected function findByIdentifiers(array $identifierValues, $hydrate) @@ -145,7 +147,7 @@ class ElasticaToModelTransformer implements ElasticaToModelTransformerInterface $query = $this->createQuery($this->objectClass, $this->options['identifier'], $identifierValues); - if ( ! $hydrate) { + if (! $hydrate) { return $query->toArray(); } @@ -158,6 +160,7 @@ class ElasticaToModelTransformer implements ElasticaToModelTransformerInterface * @param string $class Propel model class * @param string $identifierField Identifier field name (e.g. "id") * @param array $identifierValues Identifier values + * * @return \ModelCriteria */ protected function createQuery($class, $identifierField, array $identifierValues) @@ -170,6 +173,7 @@ class ElasticaToModelTransformer implements ElasticaToModelTransformerInterface /** * @see https://github.com/doctrine/common/blob/master/lib/Doctrine/Common/Util/Inflector.php + * * @param string $str */ private function camelize($str) diff --git a/Propel/Provider.php b/Propel/Provider.php index 38f7a61..ecace96 100644 --- a/Propel/Provider.php +++ b/Propel/Provider.php @@ -5,7 +5,7 @@ namespace FOS\ElasticaBundle\Propel; use FOS\ElasticaBundle\Provider\AbstractProvider; /** - * Propel provider + * Propel provider. * * @author William Durand */ @@ -16,7 +16,7 @@ class Provider extends AbstractProvider */ public function populate(\Closure $loggerClosure = null, array $options = array()) { - $queryClass = $this->objectClass . 'Query'; + $queryClass = $this->objectClass.'Query'; $nbObjects = $queryClass::create()->count(); $offset = isset($options['offset']) ? intval($options['offset']) : 0; $sleep = isset($options['sleep']) ? intval($options['sleep']) : 0; diff --git a/Provider/AbstractProvider.php b/Provider/AbstractProvider.php index 82ea914..83d2e06 100644 --- a/Provider/AbstractProvider.php +++ b/Provider/AbstractProvider.php @@ -5,7 +5,7 @@ namespace FOS\ElasticaBundle\Provider; use FOS\ElasticaBundle\Persister\ObjectPersisterInterface; /** - * AbstractProvider + * AbstractProvider. */ abstract class AbstractProvider implements ProviderInterface { @@ -33,9 +33,9 @@ abstract class AbstractProvider implements ProviderInterface * Constructor. * * @param ObjectPersisterInterface $objectPersister - * @param IndexableInterface $indexable - * @param string $objectClass - * @param array $options + * @param IndexableInterface $indexable + * @param string $objectClass + * @param array $options */ public function __construct( ObjectPersisterInterface $objectPersister, @@ -56,6 +56,7 @@ abstract class AbstractProvider implements ProviderInterface * Checks if a given object should be indexed or not. * * @param object $object + * * @return bool */ protected function isObjectIndexable($object) @@ -68,7 +69,7 @@ abstract class AbstractProvider implements ProviderInterface } /** - * Get string with RAM usage information (current and peak) + * Get string with RAM usage information (current and peak). * * @return string */ diff --git a/Provider/Indexable.php b/Provider/Indexable.php index 197aeb8..c72c9b9 100644 --- a/Provider/Indexable.php +++ b/Provider/Indexable.php @@ -33,7 +33,7 @@ class Indexable implements IndexableInterface private $container; /** - * An instance of ExpressionLanguage + * An instance of ExpressionLanguage. * * @var ExpressionLanguage */ @@ -47,7 +47,7 @@ class Indexable implements IndexableInterface private $initialisedCallbacks = array(); /** - * PropertyAccessor instance + * PropertyAccessor instance. * * @var PropertyAccessorInterface */ @@ -68,7 +68,8 @@ class Indexable implements IndexableInterface * * @param string $indexName * @param string $typeName - * @param mixed $object + * @param mixed $object + * * @return bool */ public function isObjectIndexable($indexName, $typeName, $object) @@ -82,7 +83,7 @@ class Indexable implements IndexableInterface if ($callback instanceof Expression) { return $this->getExpressionLanguage()->evaluate($callback, array( 'object' => $object, - $this->getExpressionVar($object) => $object + $this->getExpressionVar($object) => $object, )); } @@ -96,12 +97,13 @@ class Indexable implements IndexableInterface * * @param string $type * @param object $object + * * @return mixed */ private function buildCallback($type, $object) { if (!array_key_exists($type, $this->callbacks)) { - return null; + return; } $callback = $this->callbacks[$type]; @@ -148,6 +150,7 @@ class Indexable implements IndexableInterface * * @param string $type * @param object $object + * * @return mixed */ private function getCallback($type, $object) @@ -177,6 +180,7 @@ class Indexable implements IndexableInterface /** * @param mixed $object + * * @return string */ private function getExpressionVar($object = null) diff --git a/Provider/IndexableInterface.php b/Provider/IndexableInterface.php index 4871b58..0d9f047 100644 --- a/Provider/IndexableInterface.php +++ b/Provider/IndexableInterface.php @@ -18,7 +18,8 @@ interface IndexableInterface * * @param string $indexName * @param string $typeName - * @param mixed $object + * @param mixed $object + * * @return bool */ public function isObjectIndexable($indexName, $typeName, $object); diff --git a/Provider/ProviderInterface.php b/Provider/ProviderInterface.php index e8d7ea4..47b0ba1 100644 --- a/Provider/ProviderInterface.php +++ b/Provider/ProviderInterface.php @@ -3,7 +3,7 @@ namespace FOS\ElasticaBundle\Provider; /** - * Insert application domain objects into elastica types + * Insert application domain objects into elastica types. * * @author Thibault Duplessis */ @@ -14,7 +14,8 @@ interface ProviderInterface * * @param \Closure $loggerClosure * @param array $options + * * @return */ - function populate(\Closure $loggerClosure = null, array $options = array()); + public function populate(\Closure $loggerClosure = null, array $options = array()); } diff --git a/Provider/ProviderRegistry.php b/Provider/ProviderRegistry.php index 2142223..1c389ae 100644 --- a/Provider/ProviderRegistry.php +++ b/Provider/ProviderRegistry.php @@ -57,8 +57,10 @@ class ProviderRegistry implements ContainerAwareInterface * * Providers will be indexed by "type" strings in the returned array. * - * @param string $index + * @param string $index + * * @return array of ProviderInterface instances + * * @throws \InvalidArgumentException if no providers were registered for the index */ public function getIndexProviders($index) @@ -81,7 +83,9 @@ class ProviderRegistry implements ContainerAwareInterface * * @param string $index * @param string $type + * * @return ProviderInterface + * * @throws \InvalidArgumentException if no provider was registered for the index and type */ public function getProvider($index, $type) diff --git a/Repository.php b/Repository.php index fcc2784..04a51c5 100644 --- a/Repository.php +++ b/Repository.php @@ -20,9 +20,10 @@ class Repository } /** - * @param mixed $query + * @param mixed $query * @param integer $limit - * @param array $options + * @param array $options + * * @return array */ public function find($query, $limit = null, $options = array()) @@ -31,9 +32,10 @@ class Repository } /** - * @param mixed $query + * @param mixed $query * @param integer $limit - * @param array $options + * @param array $options + * * @return mixed */ public function findHybrid($query, $limit = null, $options = array()) @@ -44,6 +46,7 @@ class Repository /** * @param mixed $query * @param array $options + * * @return \Pagerfanta\Pagerfanta */ public function findPaginated($query, $options = array()) @@ -53,7 +56,8 @@ class Repository /** * @param string $query - * @param array $options + * @param array $options + * * @return Paginator\PaginatorAdapterInterface */ public function createPaginatorAdapter($query, $options = array()) diff --git a/Resources/config/orm.xml b/Resources/config/orm.xml index 94f21d4..d78ae8d 100644 --- a/Resources/config/orm.xml +++ b/Resources/config/orm.xml @@ -10,7 +10,7 @@ FOS\ElasticaBundle\Doctrine\ORM\ElasticaToModelTransformer FOS\ElasticaBundle\Doctrine\RepositoryManager - + diff --git a/Subscriber/PaginateElasticaQuerySubscriber.php b/Subscriber/PaginateElasticaQuerySubscriber.php index 0b7cfd6..6ae4912 100644 --- a/Subscriber/PaginateElasticaQuerySubscriber.php +++ b/Subscriber/PaginateElasticaQuerySubscriber.php @@ -38,7 +38,7 @@ class PaginateElasticaQuerySubscriber implements EventSubscriberInterface } /** - * Adds knp paging sort to query + * Adds knp paging sort to query. * * @param ItemsEvent $event */ @@ -70,7 +70,7 @@ class PaginateElasticaQuerySubscriber implements EventSubscriberInterface public static function getSubscribedEvents() { return array( - 'knp_pager.items' => array('items', 1) + 'knp_pager.items' => array('items', 1), ); } -} \ No newline at end of file +} diff --git a/Tests/Command/ResetCommandTest.php b/Tests/Command/ResetCommandTest.php index b6548aa..eb0aaa9 100644 --- a/Tests/Command/ResetCommandTest.php +++ b/Tests/Command/ResetCommandTest.php @@ -2,7 +2,6 @@ namespace FOS\ElasticaBundle\Tests\Command; - use FOS\ElasticaBundle\Command\ResetCommand; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Output\NullOutput; @@ -88,4 +87,4 @@ class ResetCommandTest extends \PHPUnit_Framework_TestCase new NullOutput() ); } -} \ No newline at end of file +} diff --git a/Tests/DependencyInjection/ConfigurationTest.php b/Tests/DependencyInjection/ConfigurationTest.php index 30e0f7a..062db5c 100644 --- a/Tests/DependencyInjection/ConfigurationTest.php +++ b/Tests/DependencyInjection/ConfigurationTest.php @@ -6,7 +6,7 @@ use FOS\ElasticaBundle\DependencyInjection\Configuration; use Symfony\Component\Config\Definition\Processor; /** - * ConfigurationTest + * ConfigurationTest. */ class ConfigurationTest extends \PHPUnit_Framework_TestCase { @@ -34,7 +34,7 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase $this->assertSame(array( 'clients' => array(), 'indexes' => array(), - 'default_manager' => 'orm' + 'default_manager' => 'orm', ), $configuration); } @@ -50,18 +50,18 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase array( 'url' => 'http://es1:9200', 'headers' => array( - 'Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==' - ) + 'Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==', + ), ), array( 'url' => 'http://es2:9200', 'headers' => array( - 'Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==' - ) + 'Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==', + ), ), - ) - ) - ) + ), + ), + ), )); $this->assertCount(2, $configuration['clients']); @@ -91,9 +91,9 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase ), 'logging_custom' => array( 'url' => 'http://localhost:9200', - 'logger' => 'custom.service' + 'logger' => 'custom.service', ), - ) + ), )); $this->assertCount(4, $configuration['clients']); @@ -131,8 +131,8 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase ), 'serializer' => array( 'groups' => array('Search'), - 'version' => 1 - ) + 'version' => 1, + ), ), 'types' => array( 'test' => array( @@ -144,20 +144,20 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase 'persistence' => array( 'listener' => array( 'logger' => true, - ) - ) + ), + ), ), 'test2' => array( 'mappings' => array( 'title' => null, 'children' => array( 'type' => 'nested', - ) - ) - ) - ) - ) - ) + ), + ), + ), + ), + ), + ), )); } @@ -169,7 +169,7 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase 'host' => 'localhost', 'port' => 9200, ), - ) + ), )); $this->assertTrue(empty($configuration['clients']['default']['connections'][0]['url'])); @@ -189,11 +189,11 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase 'title' => array(), 'published' => array('type' => 'datetime'), 'body' => null, - ) - ) - ) - ) - ) + ), + ), + ), + ), + ), )); $this->assertCount(3, $configuration['indexes']['test']['types']['test']['properties']); @@ -208,10 +208,10 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase 'indexes' => array( 'test' => array( 'types' => array( - 'test' => null - ) - ) - ) + 'test' => null, + ), + ), + ), )); $this->assertArrayHasKey('properties', $configuration['indexes']['test']['types']['test']); @@ -243,23 +243,23 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase 'type' => 'nested', 'properties' => array( 'nested_field1' => array( - 'type' => 'integer' + 'type' => 'integer', ), 'nested_field2' => array( 'type' => 'object', 'properties' => array( 'id' => array( - 'type' => 'integer' - ) - ) - ) - ) - ) - ) - ) - ) - ) - ) + 'type' => 'integer', + ), + ), + ), + ), + ), + ), + ), + ), + ), + ), )); } } diff --git a/Tests/DependencyInjection/FOSElasticaExtensionTest.php b/Tests/DependencyInjection/FOSElasticaExtensionTest.php index feb520f..1bef2b6 100644 --- a/Tests/DependencyInjection/FOSElasticaExtensionTest.php +++ b/Tests/DependencyInjection/FOSElasticaExtensionTest.php @@ -12,10 +12,10 @@ class FOSElasticaExtensionTest extends \PHPUnit_Framework_TestCase { $config = Yaml::parse(file_get_contents(__DIR__.'/fixtures/config.yml')); - $containerBuilder = new ContainerBuilder; + $containerBuilder = new ContainerBuilder(); $containerBuilder->setParameter('kernel.debug', true); - $extension = new FOSElasticaExtension; + $extension = new FOSElasticaExtension(); $extension->load($config, $containerBuilder); diff --git a/Tests/Doctrine/AbstractElasticaToModelTransformerTest.php b/Tests/Doctrine/AbstractElasticaToModelTransformerTest.php index 325171b..b026eb8 100644 --- a/Tests/Doctrine/AbstractElasticaToModelTransformerTest.php +++ b/Tests/Doctrine/AbstractElasticaToModelTransformerTest.php @@ -19,7 +19,7 @@ class AbstractElasticaToModelTransformerTest extends \PHPUnit_Framework_TestCase protected $objectClass = 'stdClass'; /** - * Tests if ignore_missing option is properly handled in transformHybrid() method + * Tests if ignore_missing option is properly handled in transformHybrid() method. */ public function testIgnoreMissingOptionDuringTransformHybrid() { diff --git a/Tests/Doctrine/AbstractListenerTest.php b/Tests/Doctrine/AbstractListenerTest.php index 7242255..623231b 100644 --- a/Tests/Doctrine/AbstractListenerTest.php +++ b/Tests/Doctrine/AbstractListenerTest.php @@ -3,7 +3,7 @@ namespace FOS\ElasticaBundle\Tests\Doctrine; /** - * See concrete MongoDB/ORM instances of this abstract test + * See concrete MongoDB/ORM instances of this abstract test. * * @author Richard Miller */ @@ -213,8 +213,8 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase /** * @param Listener\Entity $object - * @param string $indexName - * @param string $typeName + * @param string $indexName + * @param string $typeName */ private function getMockPersister($object, $indexName, $typeName) { @@ -247,10 +247,10 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase } /** - * @param string $indexName - * @param string $typeName + * @param string $indexName + * @param string $typeName * @param Listener\Entity $object - * @param boolean $return + * @param boolean $return */ private function getMockIndexable($indexName, $typeName, $object, $return = null) { @@ -286,4 +286,3 @@ class Entity return $this->id; } } - diff --git a/Tests/Doctrine/AbstractProviderTest.php b/Tests/Doctrine/AbstractProviderTest.php index a129a6c..50b28b7 100644 --- a/Tests/Doctrine/AbstractProviderTest.php +++ b/Tests/Doctrine/AbstractProviderTest.php @@ -84,7 +84,7 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase return array( array( 100, - array(range(1,100)), + array(range(1, 100)), 100, ), array( @@ -231,7 +231,6 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase ->with('index', 'type', 2) ->will($this->returnValue(true)); - $this->objectPersister->expects($this->once()) ->method('insertMany') ->with(array(1 => 2)); @@ -259,7 +258,7 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase private function getMockBulkResponseException() { return $this->getMock('Elastica\Exception\Bulk\ResponseException', null, array( - new ResponseSet(new Response(array()), array()) + new ResponseSet(new Response(array()), array()), )); } @@ -276,7 +275,7 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase */ private function getMockObjectManager() { - return $this->getMock(__NAMESPACE__ . '\ObjectManager'); + return $this->getMock(__NAMESPACE__.'\ObjectManager'); } /** @@ -302,5 +301,5 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase */ interface ObjectManager { - function clear(); + public function clear(); } diff --git a/Tests/Doctrine/ORM/ElasticaToModelTransformerTest.php b/Tests/Doctrine/ORM/ElasticaToModelTransformerTest.php index 14f3ffb..fe85331 100644 --- a/Tests/Doctrine/ORM/ElasticaToModelTransformerTest.php +++ b/Tests/Doctrine/ORM/ElasticaToModelTransformerTest.php @@ -109,7 +109,7 @@ class ElasticaToModelTransformerTest extends \PHPUnit_Framework_TestCase 'findAll', 'findBy', 'findOneBy', - 'getClassName' + 'getClassName', )); $this->manager->expects($this->any()) diff --git a/Tests/Doctrine/RepositoryManagerTest.php b/Tests/Doctrine/RepositoryManagerTest.php index ce7b14b..aa6117d 100644 --- a/Tests/Doctrine/RepositoryManagerTest.php +++ b/Tests/Doctrine/RepositoryManagerTest.php @@ -4,9 +4,13 @@ namespace FOS\ElasticaBundle\Tests\Doctrine; use FOS\ElasticaBundle\Doctrine\RepositoryManager; -class CustomRepository{} +class CustomRepository +{ +} -class Entity{} +class Entity +{ +} /** * @author Richard Miller diff --git a/Tests/Elastica/ClientTest.php b/Tests/Elastica/ClientTest.php index 43ac7a2..158b553 100644 --- a/Tests/Elastica/ClientTest.php +++ b/Tests/Elastica/ClientTest.php @@ -5,11 +5,11 @@ namespace FOS\ElasticaBundle\Tests\Client; use Elastica\Request; use Elastica\Transport\Null as NullTransport; -class LoggingClientTest extends \PHPUnit_Framework_TestCase +class ClientTest extends \PHPUnit_Framework_TestCase { public function testRequestsAreLogged() { - $transport = new NullTransport; + $transport = new NullTransport(); $connection = $this->getMock('Elastica\Connection'); $connection->expects($this->any())->method('getTransportObject')->will($this->returnValue($transport)); diff --git a/Tests/FOSElasticaBundleTest.php b/Tests/FOSElasticaBundleTest.php index 4290e1d..c9513db 100644 --- a/Tests/FOSElasticaBundleTest.php +++ b/Tests/FOSElasticaBundleTest.php @@ -16,7 +16,6 @@ class FOSElasticaBundleTest extends \PHPUnit_Framework_TestCase ->method('addCompilerPass') ->with($this->isInstanceOf('Symfony\\Component\\DependencyInjection\\Compiler\\CompilerPassInterface')); - $bundle = new FOSElasticaBundle(); $bundle->build($container); } diff --git a/Tests/Functional/ConfigurationManagerTest.php b/Tests/Functional/ConfigurationManagerTest.php index 7ef02c5..a6028b7 100644 --- a/Tests/Functional/ConfigurationManagerTest.php +++ b/Tests/Functional/ConfigurationManagerTest.php @@ -47,6 +47,7 @@ class ConfigurationManagerTest extends WebTestCase /** * @param Client $client + * * @return \FOS\ElasticaBundle\Configuration\ConfigManager */ private function getManager(Client $client) diff --git a/Tests/Functional/IndexableCallbackTest.php b/Tests/Functional/IndexableCallbackTest.php index 41ed402..3f84286 100644 --- a/Tests/Functional/IndexableCallbackTest.php +++ b/Tests/Functional/IndexableCallbackTest.php @@ -17,7 +17,7 @@ namespace FOS\ElasticaBundle\Tests\Functional; class IndexableCallbackTest extends WebTestCase { /** - * 2 reasons for this test: + * 2 reasons for this test:. * * 1) To test that the configuration rename from is_indexable_callback under the listener * key is respected, and diff --git a/Tests/Functional/MappingToElasticaTest.php b/Tests/Functional/MappingToElasticaTest.php index 11c0db6..3505659 100644 --- a/Tests/Functional/MappingToElasticaTest.php +++ b/Tests/Functional/MappingToElasticaTest.php @@ -100,6 +100,7 @@ class MappingToElasticaTest extends WebTestCase /** * @param Client $client + * * @return \FOS\ElasticaBundle\Resetter $resetter */ private function getResetter(Client $client) @@ -109,11 +110,12 @@ class MappingToElasticaTest extends WebTestCase /** * @param Client $client + * * @return \Elastica\Type */ private function getType(Client $client, $type = 'type') { - return $client->getContainer()->get('fos_elastica.index.index.' . $type); + return $client->getContainer()->get('fos_elastica.index.index.'.$type); } protected function setUp() diff --git a/Tests/Functional/app/AppKernel.php b/Tests/Functional/app/AppKernel.php index f47a5b3..d75910a 100644 --- a/Tests/Functional/app/AppKernel.php +++ b/Tests/Functional/app/AppKernel.php @@ -115,4 +115,4 @@ class AppKernel extends Kernel return $parameters; } -} \ No newline at end of file +} diff --git a/Tests/Functional/app/Serializer/config.yml b/Tests/Functional/app/Serializer/config.yml index 9bea4ba..a968968 100644 --- a/Tests/Functional/app/Serializer/config.yml +++ b/Tests/Functional/app/Serializer/config.yml @@ -47,4 +47,3 @@ fos_elastica: serializer: groups: ['search', 'Default'] version: 1.1 - diff --git a/Tests/Index/IndexManagerTest.php b/Tests/Index/IndexManagerTest.php index 98e4d8a..78a3d28 100644 --- a/Tests/Index/IndexManagerTest.php +++ b/Tests/Index/IndexManagerTest.php @@ -13,7 +13,6 @@ class IndexManagerTest extends \PHPUnit_Framework_TestCase */ private $indexManager; - public function setUp() { foreach (array('index1', 'index2', 'index3') as $indexName) { diff --git a/Tests/Integration/MappingTest.php b/Tests/Integration/MappingTest.php index be134ed..ae7e409 100644 --- a/Tests/Integration/MappingTest.php +++ b/Tests/Integration/MappingTest.php @@ -8,10 +8,8 @@ * with this source code in the file LICENSE. */ - namespace FOS\ElasticaBundle\Tests\Integration; - -class MappingTest { - -} \ No newline at end of file +class MappingTest +{ +} diff --git a/Tests/Logger/ElasticaLoggerTest.php b/Tests/Logger/ElasticaLoggerTest.php index 96adf53..7d90639 100644 --- a/Tests/Logger/ElasticaLoggerTest.php +++ b/Tests/Logger/ElasticaLoggerTest.php @@ -22,7 +22,8 @@ class ElasticaLoggerTest extends \PHPUnit_Framework_TestCase /** * @param string $level * @param string $message - * @param array $context + * @param array $context + * * @return ElasticaLogger */ private function getMockLoggerForLevelMessageAndContext($level, $message, $context) @@ -45,7 +46,7 @@ class ElasticaLoggerTest extends \PHPUnit_Framework_TestCase public function testGetZeroIfNoQueriesAdded() { - $elasticaLogger = new ElasticaLogger; + $elasticaLogger = new ElasticaLogger(); $this->assertEquals(0, $elasticaLogger->getNbQueries()); } diff --git a/Tests/Manager/RepositoryManagerTest.php b/Tests/Manager/RepositoryManagerTest.php index 8849035..71bb076 100644 --- a/Tests/Manager/RepositoryManagerTest.php +++ b/Tests/Manager/RepositoryManagerTest.php @@ -4,16 +4,19 @@ namespace FOS\ElasticaBundle\Tests\Manager; use FOS\ElasticaBundle\Manager\RepositoryManager; -class CustomRepository{} +class CustomRepository +{ +} -class Entity{} +class Entity +{ +} /** * @author Richard Miller */ class RepositoryManagerTest extends \PHPUnit_Framework_TestCase { - public function testThatGetRepositoryReturnsDefaultRepository() { /** @var $finderMock \PHPUnit_Framework_MockObject_MockObject|\FOS\ElasticaBundle\Finder\TransformedFinder */ diff --git a/Tests/Persister/ObjectPersisterTest.php b/Tests/Persister/ObjectPersisterTest.php index 77a8809..18390ae 100644 --- a/Tests/Persister/ObjectPersisterTest.php +++ b/Tests/Persister/ObjectPersisterTest.php @@ -33,9 +33,9 @@ class ObjectPersisterTest extends \PHPUnit_Framework_TestCase { public function setUp() { - if (!class_exists('Elastica\Type')) { - $this->markTestSkipped('The Elastica library classes are not available'); - } + if (!class_exists('Elastica\Type')) { + $this->markTestSkipped('The Elastica library classes are not available'); + } } public function testThatCanReplaceObject() diff --git a/Tests/Persister/ObjectSerializerPersisterTest.php b/Tests/Persister/ObjectSerializerPersisterTest.php index 914b5dd..31a999f 100644 --- a/Tests/Persister/ObjectSerializerPersisterTest.php +++ b/Tests/Persister/ObjectSerializerPersisterTest.php @@ -26,9 +26,9 @@ class ObjectSerializerPersisterTest extends \PHPUnit_Framework_TestCase { public function setUp() { - if (!class_exists('Elastica\Type')) { - $this->markTestSkipped('The Elastica library classes are not available'); - } + if (!class_exists('Elastica\Type')) { + $this->markTestSkipped('The Elastica library classes are not available'); + } } public function testThatCanReplaceObject() diff --git a/Tests/Provider/IndexableTest.php b/Tests/Provider/IndexableTest.php index 6ef5669..3080c88 100644 --- a/Tests/Provider/IndexableTest.php +++ b/Tests/Provider/IndexableTest.php @@ -21,7 +21,7 @@ class IndexableTest extends \PHPUnit_Framework_TestCase public function testIndexableUnknown() { $indexable = new Indexable(array(), $this->container); - $index = $indexable->isObjectIndexable('index', 'type', new Entity); + $index = $indexable->isObjectIndexable('index', 'type', new Entity()); $this->assertTrue($index); } @@ -32,9 +32,9 @@ class IndexableTest extends \PHPUnit_Framework_TestCase public function testValidIndexableCallbacks($callback, $return) { $indexable = new Indexable(array( - 'index/type' => $callback + 'index/type' => $callback, ), $this->container); - $index = $indexable->isObjectIndexable('index', 'type', new Entity); + $index = $indexable->isObjectIndexable('index', 'type', new Entity()); $this->assertEquals($return, $index); } @@ -46,9 +46,9 @@ class IndexableTest extends \PHPUnit_Framework_TestCase public function testInvalidIsIndexableCallbacks($callback) { $indexable = new Indexable(array( - 'index/type' => $callback + 'index/type' => $callback, ), $this->container); - $indexable->isObjectIndexable('index', 'type', new Entity); + $indexable->isObjectIndexable('index', 'type', new Entity()); } public function provideInvalidIsIndexableCallbacks() @@ -67,7 +67,7 @@ class IndexableTest extends \PHPUnit_Framework_TestCase array('isIndexable', false), array(array(new IndexableDecider(), 'isIndexable'), true), array(array('@indexableService', 'isIndexable'), true), - array(function(Entity $entity) { return $entity->maybeIndex(); }, true), + array(function (Entity $entity) { return $entity->maybeIndex(); }, true), array('entity.maybeIndex()', true), array('!object.isIndexable() && entity.property == "abc"', true), array('entity.property != "abc"', false), diff --git a/Tests/RepositoryTest.php b/Tests/RepositoryTest.php index c4d4efc..2d5bc66 100644 --- a/Tests/RepositoryTest.php +++ b/Tests/RepositoryTest.php @@ -13,14 +13,7 @@ class RepositoryTest extends \PHPUnit_Framework_TestCase { $testQuery = 'Test Query'; - /** @var $typeMock \PHPUnit_Framework_MockObject_MockObject|\FOS\ElasticaBundle\Finder\TransformedFinder */ - $finderMock = $this->getMockBuilder('FOS\ElasticaBundle\Finder\TransformedFinder') - ->disableOriginalConstructor() - ->getMock(); - $finderMock->expects($this->once()) - ->method('find') - ->with($this->equalTo($testQuery)); - + $finderMock = $this->getFinderMock($testQuery); $repository = new Repository($finderMock); $repository->find($testQuery); } @@ -30,14 +23,7 @@ class RepositoryTest extends \PHPUnit_Framework_TestCase $testQuery = 'Test Query'; $testLimit = 20; - /** @var $typeMock \PHPUnit_Framework_MockObject_MockObject|\FOS\ElasticaBundle\Finder\TransformedFinder */ - $finderMock = $this->getMockBuilder('FOS\ElasticaBundle\Finder\TransformedFinder') - ->disableOriginalConstructor() - ->getMock(); - $finderMock->expects($this->once()) - ->method('find') - ->with($this->equalTo($testQuery), $this->equalTo($testLimit)); - + $finderMock = $this->getFinderMock($testQuery, $testLimit); $repository = new Repository($finderMock); $repository->find($testQuery, $testLimit); } @@ -46,14 +32,7 @@ class RepositoryTest extends \PHPUnit_Framework_TestCase { $testQuery = 'Test Query'; - /** @var $typeMock \PHPUnit_Framework_MockObject_MockObject|\FOS\ElasticaBundle\Finder\TransformedFinder */ - $finderMock = $this->getMockBuilder('FOS\ElasticaBundle\Finder\TransformedFinder') - ->disableOriginalConstructor() - ->getMock(); - $finderMock->expects($this->once()) - ->method('findPaginated') - ->with($this->equalTo($testQuery)); - + $finderMock = $this->getFinderMock($testQuery, array(), 'findPaginated'); $repository = new Repository($finderMock); $repository->findPaginated($testQuery); } @@ -62,14 +41,7 @@ class RepositoryTest extends \PHPUnit_Framework_TestCase { $testQuery = 'Test Query'; - /** @var $typeMock \PHPUnit_Framework_MockObject_MockObject|\FOS\ElasticaBundle\Finder\TransformedFinder */ - $finderMock = $this->getMockBuilder('FOS\ElasticaBundle\Finder\TransformedFinder') - ->disableOriginalConstructor() - ->getMock(); - $finderMock->expects($this->once()) - ->method('createPaginatorAdapter') - ->with($this->equalTo($testQuery)); - + $finderMock = $this->getFinderMock($testQuery, array(), 'createPaginatorAdapter'); $repository = new Repository($finderMock); $repository->createPaginatorAdapter($testQuery); } @@ -77,17 +49,27 @@ class RepositoryTest extends \PHPUnit_Framework_TestCase public function testThatFindHybridCallsFindHybridOnFinder() { $testQuery = 'Test Query'; - $testLimit = 20; - /** @var $typeMock \PHPUnit_Framework_MockObject_MockObject|\FOS\ElasticaBundle\Finder\TransformedFinder */ + $finderMock = $this->getFinderMock($testQuery, null, 'findHybrid'); + $repository = new Repository($finderMock); + $repository->findHybrid($testQuery); + } + + /** + * @param string $testQuery + * @param int $testLimit + * @param string $method + * @return \FOS\ElasticaBundle\Finder\TransformedFinder|\PHPUnit_Framework_MockObject_MockObject + */ + private function getFinderMock($testQuery, $testLimit = null, $method = 'find') + { $finderMock = $this->getMockBuilder('FOS\ElasticaBundle\Finder\TransformedFinder') ->disableOriginalConstructor() ->getMock(); $finderMock->expects($this->once()) - ->method('findHybrid') + ->method($method) ->with($this->equalTo($testQuery), $this->equalTo($testLimit)); - $repository = new Repository($finderMock); - $repository->findHybrid($testQuery, $testLimit); + return $finderMock; } } diff --git a/Tests/Transformer/ElasticaToModelTransformerCollectionTest.php b/Tests/Transformer/ElasticaToModelTransformerCollectionTest.php index c3fc323..d83f596 100644 --- a/Tests/Transformer/ElasticaToModelTransformerCollectionTest.php +++ b/Tests/Transformer/ElasticaToModelTransformerCollectionTest.php @@ -47,7 +47,7 @@ class ElasticaToModelTransformerCollectionTest extends \PHPUnit_Framework_TestCa $objectClasses = $this->collection->getObjectClass(); $this->assertEquals(array( 'type1' => 'FOS\ElasticaBundle\Tests\Transformer\POPO', - 'type2' => 'FOS\ElasticaBundle\Tests\Transformer\POPO2' + 'type2' => 'FOS\ElasticaBundle\Tests\Transformer\POPO2', ), $objectClasses); } @@ -89,8 +89,8 @@ class ElasticaToModelTransformerCollectionTest extends \PHPUnit_Framework_TestCa $this->transformers['type1']->expects($this->once()) ->method('transform') - ->with(array($document1,$document2)) - ->will($this->returnValue(array($result1,$result2))); + ->with(array($document1, $document2)) + ->will($this->returnValue(array($result1, $result2))); $results = $this->collection->transform(array($document1, $document2)); @@ -120,8 +120,8 @@ class ElasticaToModelTransformerCollectionTest extends \PHPUnit_Framework_TestCa return array( array( - $result, $transformedObject - ) + $result, $transformedObject, + ), ); } diff --git a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php index 1fa6a8e..ca71825 100644 --- a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php +++ b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php @@ -21,8 +21,8 @@ class POPO public function __construct() { $this->date = new \DateTime('1979-05-05'); - $this->file = new \SplFileInfo(__DIR__ . '/../fixtures/attachment.odt'); - $this->fileContents = file_get_contents(__DIR__ . '/../fixtures/attachment.odt'); + $this->file = new \SplFileInfo(__DIR__.'/../fixtures/attachment.odt'); + $this->fileContents = file_get_contents(__DIR__.'/../fixtures/attachment.odt'); } public function getId() @@ -47,7 +47,7 @@ class POPO { return array( 'key1' => 'value1', - 'key2' => 'value2' + 'key2' => 'value2', ); } @@ -109,7 +109,7 @@ class POPO public function getNestedObject() { - return array('key1' => (object)array('id' => 1, 'key1sub1' => 'value1sub1', 'key1sub2' => 'value1sub2')); + return array('key1' => (object) array('id' => 1, 'key1sub1' => 'value1sub1', 'key1sub2' => 'value1sub2')); } public function getUpper() @@ -152,7 +152,7 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase 'float' => array(), 'bool' => array(), 'date' => array(), - 'falseBool' => array() + 'falseBool' => array(), ) ); $data = $document->getData(); @@ -185,7 +185,7 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase $this->assertEquals( array( 'key1' => 'value1', - 'key2' => 'value2' + 'key2' => 'value2', ), $data['array'] ); } @@ -230,7 +230,7 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase $document = $transformer->transform(new POPO(), array('file' => array('type' => 'attachment'))); $data = $document->getData(); - $this->assertEquals(base64_encode(file_get_contents(__DIR__ . '/../fixtures/attachment.odt')), $data['file']); + $this->assertEquals(base64_encode(file_get_contents(__DIR__.'/../fixtures/attachment.odt')), $data['file']); } public function testFileContentsAddedForAttachmentMapping() @@ -240,7 +240,7 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase $data = $document->getData(); $this->assertEquals( - base64_encode(file_get_contents(__DIR__ . '/../fixtures/attachment.odt')), $data['fileContents'] + base64_encode(file_get_contents(__DIR__.'/../fixtures/attachment.odt')), $data['fileContents'] ); } @@ -250,8 +250,8 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase $document = $transformer->transform(new POPO(), array( 'sub' => array( 'type' => 'nested', - 'properties' => array('foo' => '~') - ) + 'properties' => array('foo' => '~'), + ), )); $data = $document->getData(); @@ -259,7 +259,7 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase $this->assertInternalType('array', $data['sub']); $this->assertEquals(array( array('foo' => 'foo'), - array('foo' => 'bar') + array('foo' => 'bar'), ), $data['sub']); } @@ -269,8 +269,8 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase $document = $transformer->transform(new POPO(), array( 'sub' => array( 'type' => 'object', - 'properties' => array('bar') - ) + 'properties' => array('bar'), + ), )); $data = $document->getData(); @@ -278,7 +278,7 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase $this->assertInternalType('array', $data['sub']); $this->assertEquals(array( array('bar' => 'foo'), - array('bar' => 'bar') + array('bar' => 'bar'), ), $data['sub']); } @@ -287,17 +287,17 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase $transformer = $this->getTransformer(); $document = $transformer->transform(new POPO(), array( 'obj' => array( - 'type' => 'object' - ) + 'type' => 'object', + ), )); $data = $document->getData(); $this->assertTrue(array_key_exists('obj', $data)); $this->assertInternalType('array', $data['obj']); $this->assertEquals(array( - 'foo' => 'foo', - 'bar' => 'foo', - 'id' => 1 + 'foo' => 'foo', + 'bar' => 'foo', + 'id' => 1, ), $data['obj']); } @@ -313,14 +313,14 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase 'properties' => array( 'key1sub1' => array( 'type' => 'string', - 'properties' => array() + 'properties' => array(), ), 'key1sub2' => array( 'type' => 'string', - 'properties' => array() - ) - ) - ) + 'properties' => array(), + ), + ), + ), ) ); $data = $document->getData(); @@ -333,14 +333,14 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase array( 'foo' => 'foo', 'bar' => 'foo', - 'id' => 1 + 'id' => 1, ), $data['obj'] ); $this->assertEquals( array( 'key1sub1' => 'value1sub1', - 'key1sub2' => 'value1sub2' + 'key1sub2' => 'value1sub2', ), $data['nestedObject'][0] ); @@ -350,7 +350,7 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase { $transformer = $this->getTransformer(); $document = $transformer->transform(new POPO(), array( - '_parent' => array('type' => 'upper', 'property'=>'upper', 'identifier' => 'id'), + '_parent' => array('type' => 'upper', 'property' => 'upper', 'identifier' => 'id'), )); $this->assertEquals("parent", $document->getParent()); @@ -360,7 +360,7 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase { $transformer = $this->getTransformer(); $document = $transformer->transform(new POPO(), array( - '_parent' => array('type' => 'upper', 'property'=>'upper', 'identifier' => 'name'), + '_parent' => array('type' => 'upper', 'property' => 'upper', 'identifier' => 'name'), )); $this->assertEquals("a random name", $document->getParent()); @@ -370,7 +370,7 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase { $transformer = $this->getTransformer(); $document = $transformer->transform(new POPO(), array( - '_parent' => array('type' => 'upper', 'property'=>null, 'identifier' => 'id'), + '_parent' => array('type' => 'upper', 'property' => null, 'identifier' => 'id'), )); $this->assertEquals("parent", $document->getParent()); @@ -380,7 +380,7 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase { $transformer = $this->getTransformer(); $document = $transformer->transform(new POPO(), array( - '_parent' => array('type' => 'upper', 'property'=>'upperAlias', 'identifier' => 'id'), + '_parent' => array('type' => 'upper', 'property' => 'upperAlias', 'identifier' => 'id'), )); $this->assertEquals("parent", $document->getParent()); diff --git a/Transformer/ElasticaToModelTransformerCollection.php b/Transformer/ElasticaToModelTransformerCollection.php index f65f8db..041e361 100644 --- a/Transformer/ElasticaToModelTransformerCollection.php +++ b/Transformer/ElasticaToModelTransformerCollection.php @@ -41,6 +41,7 @@ class ElasticaToModelTransformerCollection implements ElasticaToModelTransformer /** * @param Document[] $elasticaObjects + * * @return array */ public function transform(array $elasticaObjects) @@ -51,12 +52,12 @@ class ElasticaToModelTransformerCollection implements ElasticaToModelTransformer } $transformed = array(); - foreach ($sorted AS $type => $objects) { + foreach ($sorted as $type => $objects) { $transformedObjects = $this->transformers[$type]->transform($objects); - $identifierGetter = 'get' . ucfirst($this->transformers[$type]->getIdentifierField()); + $identifierGetter = 'get'.ucfirst($this->transformers[$type]->getIdentifierField()); $transformed[$type] = array_combine( array_map( - function($o) use ($identifierGetter) { + function ($o) use ($identifierGetter) { return $o->$identifierGetter(); }, $transformedObjects diff --git a/Transformer/ElasticaToModelTransformerInterface.php b/Transformer/ElasticaToModelTransformerInterface.php index 5635ef3..71cd651 100644 --- a/Transformer/ElasticaToModelTransformerInterface.php +++ b/Transformer/ElasticaToModelTransformerInterface.php @@ -3,32 +3,33 @@ namespace FOS\ElasticaBundle\Transformer; /** - * Maps Elastica documents with model objects + * Maps Elastica documents with model objects. */ interface ElasticaToModelTransformerInterface { /** * Transforms an array of elastica objects into an array of - * model objects fetched from the doctrine repository + * model objects fetched from the doctrine repository. * * @param array $elasticaObjects array of elastica objects + * * @return array of model objects **/ - function transform(array $elasticaObjects); + public function transform(array $elasticaObjects); - function hybridTransform(array $elasticaObjects); + public function hybridTransform(array $elasticaObjects); /** * Returns the object class used by the transformer. * * @return string */ - function getObjectClass(); + public function getObjectClass(); /** - * Returns the identifier field from the options + * Returns the identifier field from the options. * * @return string the identifier field */ - function getIdentifierField(); + public function getIdentifierField(); } diff --git a/Transformer/HighlightableModelInterface.php b/Transformer/HighlightableModelInterface.php index d55407e..70b8ed3 100644 --- a/Transformer/HighlightableModelInterface.php +++ b/Transformer/HighlightableModelInterface.php @@ -1,16 +1,16 @@ - 'id' + 'identifier' => 'id', ); /** - * PropertyAccessor instance + * PropertyAccessor instance. * * @var PropertyAccessorInterface */ protected $propertyAccessor; /** - * Instanciates a new Mapper + * Instanciates a new Mapper. * * @param array $options */ @@ -39,7 +39,7 @@ class ModelToElasticaAutoTransformer implements ModelToElasticaTransformerInterf } /** - * Set the PropertyAccessor + * Set the PropertyAccessor. * * @param PropertyAccessorInterface $propertyAccessor */ @@ -49,7 +49,7 @@ class ModelToElasticaAutoTransformer implements ModelToElasticaTransformerInterf } /** - * Transforms an object into an elastica object having the required keys + * Transforms an object into an elastica object having the required keys. * * @param object $object the object to convert * @param array $fields the keys we want to have in the returned array @@ -63,7 +63,7 @@ class ModelToElasticaAutoTransformer implements ModelToElasticaTransformerInterf foreach ($fields as $key => $mapping) { if ($key == '_parent') { - $property = (null !== $mapping['property'])?$mapping['property']:$mapping['type']; + $property = (null !== $mapping['property']) ? $mapping['property'] : $mapping['type']; $value = $this->propertyAccessor->getValue($object, $property); $document->setParent($this->propertyAccessor->getValue($value, $mapping['identifier'])); continue; @@ -96,10 +96,10 @@ class ModelToElasticaAutoTransformer implements ModelToElasticaTransformerInterf } /** - * transform a nested document or an object property into an array of ElasticaDocument + * transform a nested document or an object property into an array of ElasticaDocument. * * @param array|\Traversable|\ArrayAccess $objects the object to convert - * @param array $fields the keys we want to have in the returned array + * @param array $fields the keys we want to have in the returned array * * @return array */ @@ -123,7 +123,7 @@ class ModelToElasticaAutoTransformer implements ModelToElasticaTransformerInterf } /** - * Attempts to convert any type to a string or an array of strings + * Attempts to convert any type to a string or an array of strings. * * @param mixed $value * @@ -131,12 +131,11 @@ class ModelToElasticaAutoTransformer implements ModelToElasticaTransformerInterf */ protected function normalizeValue($value) { - $normalizeValue = function(&$v) - { + $normalizeValue = function (&$v) { if ($v instanceof \DateTime) { $v = $v->format('c'); } elseif (!is_scalar($v) && !is_null($v)) { - $v = (string)$v; + $v = (string) $v; } }; diff --git a/Transformer/ModelToElasticaIdentifierTransformer.php b/Transformer/ModelToElasticaIdentifierTransformer.php index 7cf97e6..6301be1 100644 --- a/Transformer/ModelToElasticaIdentifierTransformer.php +++ b/Transformer/ModelToElasticaIdentifierTransformer.php @@ -6,12 +6,12 @@ use Elastica\Document; /** * Creates an Elastica document with the ID of - * the Doctrine object as Elastica document ID + * the Doctrine object as Elastica document ID. */ class ModelToElasticaIdentifierTransformer extends ModelToElasticaAutoTransformer { /** - * Creates an elastica document with the id of the doctrine object as id + * Creates an elastica document with the id of the doctrine object as id. * * @param object $object the object to convert * @param array $fields the keys we want to have in the returned array diff --git a/Transformer/ModelToElasticaTransformerInterface.php b/Transformer/ModelToElasticaTransformerInterface.php index ec9ada3..0ad9f12 100644 --- a/Transformer/ModelToElasticaTransformerInterface.php +++ b/Transformer/ModelToElasticaTransformerInterface.php @@ -3,16 +3,17 @@ namespace FOS\ElasticaBundle\Transformer; /** - * Maps Elastica documents with model objects + * Maps Elastica documents with model objects. */ interface ModelToElasticaTransformerInterface { /** - * Transforms an object into an elastica object having the required keys + * Transforms an object into an elastica object having the required keys. * * @param object $object the object to convert - * @param array $fields the keys we want to have in the returned array + * @param array $fields the keys we want to have in the returned array + * * @return \Elastica\Document **/ - function transform($object, array $fields); + public function transform($object, array $fields); } From e796d6179b84a6678f1d063fc58aa88bad6979c4 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 12 Mar 2015 21:21:18 +1100 Subject: [PATCH 417/447] Elastica, Doctrine\Common and Doctrine\ORM are required for tests --- Tests/Doctrine/AbstractElasticaToModelTransformerTest.php | 4 ---- Tests/Doctrine/AbstractProviderTest.php | 4 ---- Tests/Doctrine/ORM/ElasticaToModelTransformerTest.php | 7 ------- Tests/Doctrine/ORM/ListenerTest.php | 7 ------- Tests/Doctrine/RepositoryManagerTest.php | 7 ------- Tests/Persister/ObjectPersisterTest.php | 7 ------- Tests/Persister/ObjectSerializerPersisterTest.php | 7 ------- Tests/Transformer/ModelToElasticaAutoTransformerTest.php | 7 ------- .../ModelToElasticaIdentifierTransformerTest.php | 7 ------- 9 files changed, 57 deletions(-) diff --git a/Tests/Doctrine/AbstractElasticaToModelTransformerTest.php b/Tests/Doctrine/AbstractElasticaToModelTransformerTest.php index b026eb8..1185e74 100644 --- a/Tests/Doctrine/AbstractElasticaToModelTransformerTest.php +++ b/Tests/Doctrine/AbstractElasticaToModelTransformerTest.php @@ -55,10 +55,6 @@ class AbstractElasticaToModelTransformerTest extends \PHPUnit_Framework_TestCase protected function setUp() { - if (!interface_exists('Doctrine\Common\Persistence\ManagerRegistry')) { - $this->markTestSkipped('Doctrine Common is not present'); - } - $this->registry = $this->getMockBuilder('Doctrine\Common\Persistence\ManagerRegistry') ->disableOriginalConstructor() ->getMock(); diff --git a/Tests/Doctrine/AbstractProviderTest.php b/Tests/Doctrine/AbstractProviderTest.php index 50b28b7..2510e7e 100644 --- a/Tests/Doctrine/AbstractProviderTest.php +++ b/Tests/Doctrine/AbstractProviderTest.php @@ -16,10 +16,6 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase public function setUp() { - if (!interface_exists('Doctrine\Common\Persistence\ManagerRegistry')) { - $this->markTestSkipped('Doctrine Common is not available.'); - } - $this->objectClass = 'objectClass'; $this->options = array('debug_logging' => true, 'indexName' => 'index', 'typeName' => 'type'); diff --git a/Tests/Doctrine/ORM/ElasticaToModelTransformerTest.php b/Tests/Doctrine/ORM/ElasticaToModelTransformerTest.php index fe85331..607aeef 100644 --- a/Tests/Doctrine/ORM/ElasticaToModelTransformerTest.php +++ b/Tests/Doctrine/ORM/ElasticaToModelTransformerTest.php @@ -82,13 +82,6 @@ class ElasticaToModelTransformerTest extends \PHPUnit_Framework_TestCase protected function setUp() { - if (!interface_exists('Doctrine\Common\Persistence\ManagerRegistry')) { - $this->markTestSkipped('Doctrine Common is not present'); - } - if (!class_exists('Doctrine\ORM\EntityManager')) { - $this->markTestSkipped('Doctrine Common is not present'); - } - $this->registry = $this->getMockBuilder('Doctrine\Common\Persistence\ManagerRegistry') ->disableOriginalConstructor() ->getMock(); diff --git a/Tests/Doctrine/ORM/ListenerTest.php b/Tests/Doctrine/ORM/ListenerTest.php index 12a89b2..36cacc6 100644 --- a/Tests/Doctrine/ORM/ListenerTest.php +++ b/Tests/Doctrine/ORM/ListenerTest.php @@ -6,13 +6,6 @@ use FOS\ElasticaBundle\Tests\Doctrine\ListenerTest as BaseListenerTest; class ListenerTest extends BaseListenerTest { - public function setUp() - { - if (!class_exists('Doctrine\ORM\EntityManager')) { - $this->markTestSkipped('Doctrine ORM is not available.'); - } - } - protected function getClassMetadataClass() { return 'Doctrine\ORM\Mapping\ClassMetadata'; diff --git a/Tests/Doctrine/RepositoryManagerTest.php b/Tests/Doctrine/RepositoryManagerTest.php index aa6117d..39f9c34 100644 --- a/Tests/Doctrine/RepositoryManagerTest.php +++ b/Tests/Doctrine/RepositoryManagerTest.php @@ -17,13 +17,6 @@ class Entity */ class RepositoryManagerTest extends \PHPUnit_Framework_TestCase { - public function setUp() - { - if (!interface_exists('Doctrine\Common\Persistence\ManagerRegistry')) { - $this->markTestSkipped('Doctrine Common is not available.'); - } - } - public function testThatGetRepositoryReturnsDefaultRepository() { /** @var $finderMock \PHPUnit_Framework_MockObject_MockObject|\FOS\ElasticaBundle\Finder\TransformedFinder */ diff --git a/Tests/Persister/ObjectPersisterTest.php b/Tests/Persister/ObjectPersisterTest.php index 18390ae..c3da687 100644 --- a/Tests/Persister/ObjectPersisterTest.php +++ b/Tests/Persister/ObjectPersisterTest.php @@ -31,13 +31,6 @@ class InvalidObjectPersister extends ObjectPersister class ObjectPersisterTest extends \PHPUnit_Framework_TestCase { - public function setUp() - { - if (!class_exists('Elastica\Type')) { - $this->markTestSkipped('The Elastica library classes are not available'); - } - } - public function testThatCanReplaceObject() { $transformer = $this->getTransformer(); diff --git a/Tests/Persister/ObjectSerializerPersisterTest.php b/Tests/Persister/ObjectSerializerPersisterTest.php index 31a999f..0b348d1 100644 --- a/Tests/Persister/ObjectSerializerPersisterTest.php +++ b/Tests/Persister/ObjectSerializerPersisterTest.php @@ -24,13 +24,6 @@ class POPO class ObjectSerializerPersisterTest extends \PHPUnit_Framework_TestCase { - public function setUp() - { - if (!class_exists('Elastica\Type')) { - $this->markTestSkipped('The Elastica library classes are not available'); - } - } - public function testThatCanReplaceObject() { $transformer = $this->getTransformer(); diff --git a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php index ca71825..a49cb33 100644 --- a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php +++ b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php @@ -125,13 +125,6 @@ class POPO class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase { - public function setUp() - { - if (!class_exists('Elastica\Document')) { - $this->markTestSkipped('The Elastica library classes are not available'); - } - } - public function testThatCanTransformObject() { $transformer = $this->getTransformer(); diff --git a/Tests/Transformer/ModelToElasticaIdentifierTransformerTest.php b/Tests/Transformer/ModelToElasticaIdentifierTransformerTest.php index f1a77d4..14d678e 100644 --- a/Tests/Transformer/ModelToElasticaIdentifierTransformerTest.php +++ b/Tests/Transformer/ModelToElasticaIdentifierTransformerTest.php @@ -23,13 +23,6 @@ class POPO class ModelToElasticaIdentifierTransformerTest extends \PHPUnit_Framework_TestCase { - public function setUp() - { - if (!class_exists('Elastica\Document')) { - $this->markTestSkipped('The Elastica library classes are not available'); - } - } - public function testGetDocumentWithIdentifierOnly() { $transformer = $this->getTransformer(); From a8f41fa5efa9cee7cae2da625cf12bb1ba1f4b72 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 12 Mar 2015 21:47:19 +1100 Subject: [PATCH 418/447] We do not provide API guarantees --- Paginator/FantaPaginatorAdapter.php | 6 ------ Paginator/PaginatorAdapterInterface.php | 4 ---- Paginator/PartialResultsInterface.php | 4 ---- 3 files changed, 14 deletions(-) diff --git a/Paginator/FantaPaginatorAdapter.php b/Paginator/FantaPaginatorAdapter.php index 2ac5412..1e48747 100644 --- a/Paginator/FantaPaginatorAdapter.php +++ b/Paginator/FantaPaginatorAdapter.php @@ -20,8 +20,6 @@ class FantaPaginatorAdapter implements AdapterInterface * Returns the number of results. * * @return integer The number of results. - * - * @api */ public function getNbResults() { @@ -32,8 +30,6 @@ class FantaPaginatorAdapter implements AdapterInterface * Returns Facets. * * @return mixed - * - * @api */ public function getFacets() { @@ -47,8 +43,6 @@ class FantaPaginatorAdapter implements AdapterInterface * @param integer $length The length. * * @return array|\Traversable The slice. - * - * @api */ public function getSlice($offset, $length) { diff --git a/Paginator/PaginatorAdapterInterface.php b/Paginator/PaginatorAdapterInterface.php index 126373d..f689d84 100644 --- a/Paginator/PaginatorAdapterInterface.php +++ b/Paginator/PaginatorAdapterInterface.php @@ -8,8 +8,6 @@ interface PaginatorAdapterInterface * Returns the number of results. * * @return integer The number of results. - * - * @api */ public function getTotalHits(); @@ -20,8 +18,6 @@ interface PaginatorAdapterInterface * @param integer $length The length. * * @return PartialResultsInterface - * - * @api */ public function getResults($offset, $length); diff --git a/Paginator/PartialResultsInterface.php b/Paginator/PartialResultsInterface.php index a4f8f7d..266a7ed 100644 --- a/Paginator/PartialResultsInterface.php +++ b/Paginator/PartialResultsInterface.php @@ -8,8 +8,6 @@ interface PartialResultsInterface * Returns the paginated results. * * @return array - * - * @api */ public function toArray(); @@ -17,8 +15,6 @@ interface PartialResultsInterface * Returns the number of results. * * @return integer The number of results. - * - * @api */ public function getTotalHits(); From 89db88c2a026809e65f4bd53f5e11c19df6e8a02 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 12 Mar 2015 21:45:24 +1100 Subject: [PATCH 419/447] CS fixes for 3.1 --- Command/PopulateCommand.php | 5 ++--- Command/ProgressClosureBuilder.php | 14 ++++++++------ Doctrine/AbstractProvider.php | 7 ++++--- Doctrine/MongoDB/SliceFetcher.php | 2 +- Doctrine/ORM/SliceFetcher.php | 6 +++--- Doctrine/SliceFetcherInterface.php | 5 +++-- Event/IndexPopulateEvent.php | 8 ++++---- Event/IndexResetEvent.php | 2 +- Event/TypePopulateEvent.php | 6 +++--- Event/TypeResetEvent.php | 2 +- Paginator/FantaPaginatorAdapter.php | 4 ++-- Paginator/PaginatorAdapterInterface.php | 4 ++-- Paginator/PartialResultsInterface.php | 4 ++-- Paginator/RawPaginatorAdapter.php | 18 +++++++++++------- Persister/ObjectPersisterInterface.php | 1 + Provider/AbstractProvider.php | 1 + Resources/config/orm.xml | 2 +- Tests/RepositoryTest.php | 3 ++- .../ModelToElasticaAutoTransformerTest.php | 1 + Transformer/ModelToElasticaAutoTransformer.php | 2 +- 20 files changed, 54 insertions(+), 43 deletions(-) diff --git a/Command/PopulateCommand.php b/Command/PopulateCommand.php index 092a1e1..e3d2918 100644 --- a/Command/PopulateCommand.php +++ b/Command/PopulateCommand.php @@ -3,7 +3,6 @@ namespace FOS\ElasticaBundle\Command; use FOS\ElasticaBundle\Event\IndexPopulateEvent; -use FOS\ElasticaBundle\Event\PopulateEvent; use FOS\ElasticaBundle\Event\TypePopulateEvent; use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; use Symfony\Component\Console\Helper\DialogHelper; @@ -181,8 +180,8 @@ class PopulateCommand extends ContainerAwareCommand * Refreshes an index. * * @param OutputInterface $output - * @param string $index - * @param bool $postPopulate + * @param string $index + * @param bool $postPopulate */ private function refreshIndex(OutputInterface $output, $index, $postPopulate = true) { diff --git a/Command/ProgressClosureBuilder.php b/Command/ProgressClosureBuilder.php index 53bcb18..f244bc3 100644 --- a/Command/ProgressClosureBuilder.php +++ b/Command/ProgressClosureBuilder.php @@ -21,9 +21,10 @@ class ProgressClosureBuilder * line. * * @param OutputInterface $output - * @param string $action - * @param string $index - * @param string $type + * @param string $action + * @param string $index + * @param string $type + * * @return callable */ public function build(OutputInterface $output, $action, $index, $type) @@ -58,9 +59,10 @@ class ProgressClosureBuilder * methods to support what we need. * * @param OutputInterface $output - * @param string $action - * @param string $index - * @param string $type + * @param string $action + * @param string $index + * @param string $type + * * @return callable */ private function buildLegacy(OutputInterface $output, $action, $index, $type) diff --git a/Doctrine/AbstractProvider.php b/Doctrine/AbstractProvider.php index 28fba5d..e250e56 100644 --- a/Doctrine/AbstractProvider.php +++ b/Doctrine/AbstractProvider.php @@ -77,7 +77,7 @@ abstract class AbstractProvider extends BaseAbstractProvider } else { try { $this->objectPersister->insertMany($objects); - } catch(BulkResponseException $e) { + } catch (BulkResponseException $e) { if ($loggerClosure) { $loggerClosure($batchSize, $nbObjects, sprintf('%s', $e->getMessage())); } @@ -106,9 +106,10 @@ abstract class AbstractProvider extends BaseAbstractProvider * the fetchSlice methods defined in the ORM/MongoDB subclasses. * * @param $queryBuilder - * @param int $limit - * @param int $offset + * @param int $limit + * @param int $offset * @param array $lastSlice + * * @return array */ protected function getSlice($queryBuilder, $limit, $offset, $lastSlice) diff --git a/Doctrine/MongoDB/SliceFetcher.php b/Doctrine/MongoDB/SliceFetcher.php index f90783e..4723da6 100644 --- a/Doctrine/MongoDB/SliceFetcher.php +++ b/Doctrine/MongoDB/SliceFetcher.php @@ -7,7 +7,7 @@ use FOS\ElasticaBundle\Exception\InvalidArgumentTypeException; use FOS\ElasticaBundle\Doctrine\SliceFetcherInterface; /** - * Fetches a slice of objects + * Fetches a slice of objects. * * @author Thomas Prelot */ diff --git a/Doctrine/ORM/SliceFetcher.php b/Doctrine/ORM/SliceFetcher.php index d7f81e1..86ad1b4 100644 --- a/Doctrine/ORM/SliceFetcher.php +++ b/Doctrine/ORM/SliceFetcher.php @@ -7,7 +7,7 @@ use FOS\ElasticaBundle\Exception\InvalidArgumentTypeException; use FOS\ElasticaBundle\Doctrine\SliceFetcherInterface; /** - * Fetches a slice of objects + * Fetches a slice of objects. * * @author Thomas Prelot */ @@ -22,7 +22,7 @@ class SliceFetcher implements SliceFetcherInterface throw new InvalidArgumentTypeException($queryBuilder, 'Doctrine\ORM\QueryBuilder'); } - /** + /* * An orderBy DQL part is required to avoid feching the same row twice. * @see http://stackoverflow.com/questions/6314879/does-limit-offset-length-require-order-by-for-pagination * @see http://www.postgresql.org/docs/current/static/queries-limit.html @@ -31,7 +31,7 @@ class SliceFetcher implements SliceFetcherInterface $orderBy = $queryBuilder->getDQLPart('orderBy'); if (empty($orderBy)) { $rootAliases = $queryBuilder->getRootAliases(); - + foreach ($identifierFieldNames as $fieldName) { $queryBuilder->addOrderBy($rootAliases[0].'.'.$fieldName); } diff --git a/Doctrine/SliceFetcherInterface.php b/Doctrine/SliceFetcherInterface.php index 9df7152..a028abf 100644 --- a/Doctrine/SliceFetcherInterface.php +++ b/Doctrine/SliceFetcherInterface.php @@ -3,7 +3,7 @@ namespace FOS\ElasticaBundle\Doctrine; /** - * Fetches a slice of objects + * Fetches a slice of objects. * * @author Thomas Prelot */ @@ -17,7 +17,8 @@ interface SliceFetcherInterface * @param integer $offset * @param array $previousSlice * @param array $identifierFieldNames + * * @return array */ - function fetch($queryBuilder, $limit, $offset, array $previousSlice, array $identifierFieldNames); + public function fetch($queryBuilder, $limit, $offset, array $previousSlice, array $identifierFieldNames); } diff --git a/Event/IndexPopulateEvent.php b/Event/IndexPopulateEvent.php index 56b1e83..ab61f0a 100644 --- a/Event/IndexPopulateEvent.php +++ b/Event/IndexPopulateEvent.php @@ -14,7 +14,7 @@ namespace FOS\ElasticaBundle\Event; use Symfony\Component\EventDispatcher\Event; /** - * Index Populate Event + * Index Populate Event. * * @author Oleg Andreyev */ @@ -39,9 +39,9 @@ class IndexPopulateEvent extends Event private $options; /** - * @param string $index - * @param boolean $reset - * @param array $options + * @param string $index + * @param boolean $reset + * @param array $options */ public function __construct($index, $reset, $options) { diff --git a/Event/IndexResetEvent.php b/Event/IndexResetEvent.php index 0caf241..3fb3625 100644 --- a/Event/IndexResetEvent.php +++ b/Event/IndexResetEvent.php @@ -14,7 +14,7 @@ namespace FOS\ElasticaBundle\Event; use Symfony\Component\EventDispatcher\Event; /** - * Index ResetEvent + * Index ResetEvent. * * @author Oleg Andreyev */ diff --git a/Event/TypePopulateEvent.php b/Event/TypePopulateEvent.php index e04bdd8..dd744f5 100644 --- a/Event/TypePopulateEvent.php +++ b/Event/TypePopulateEvent.php @@ -14,7 +14,7 @@ namespace FOS\ElasticaBundle\Event; use Symfony\Component\EventDispatcher\Event; /** - * Type Populate Event + * Type Populate Event. * * @author Oleg Andreyev */ @@ -31,8 +31,8 @@ class TypePopulateEvent extends IndexPopulateEvent /** * @param string $index * @param string $type - * @param bool $reset - * @param array $options + * @param bool $reset + * @param array $options */ public function __construct($index, $type, $reset, $options) { diff --git a/Event/TypeResetEvent.php b/Event/TypeResetEvent.php index 37c2cf8..0b21a06 100644 --- a/Event/TypeResetEvent.php +++ b/Event/TypeResetEvent.php @@ -14,7 +14,7 @@ namespace FOS\ElasticaBundle\Event; use Symfony\Component\EventDispatcher\Event; /** - * Type ResetEvent + * Type ResetEvent. * * @author Oleg Andreyev */ diff --git a/Paginator/FantaPaginatorAdapter.php b/Paginator/FantaPaginatorAdapter.php index 60e46bf..8f9a60a 100644 --- a/Paginator/FantaPaginatorAdapter.php +++ b/Paginator/FantaPaginatorAdapter.php @@ -35,9 +35,9 @@ class FantaPaginatorAdapter implements AdapterInterface { return $this->adapter->getFacets(); } - + /** - * Returns Aggregations + * Returns Aggregations. * * @return mixed * diff --git a/Paginator/PaginatorAdapterInterface.php b/Paginator/PaginatorAdapterInterface.php index 47f7f53..adf7df2 100644 --- a/Paginator/PaginatorAdapterInterface.php +++ b/Paginator/PaginatorAdapterInterface.php @@ -27,9 +27,9 @@ interface PaginatorAdapterInterface * @return mixed */ public function getFacets(); - + /** - * Returns Aggregations + * Returns Aggregations. * * @return mixed */ diff --git a/Paginator/PartialResultsInterface.php b/Paginator/PartialResultsInterface.php index f8434cc..156d27f 100644 --- a/Paginator/PartialResultsInterface.php +++ b/Paginator/PartialResultsInterface.php @@ -24,9 +24,9 @@ interface PartialResultsInterface * @return array */ public function getFacets(); - + /** - * Returns the aggregations + * Returns the aggregations. * * @return array */ diff --git a/Paginator/RawPaginatorAdapter.php b/Paginator/RawPaginatorAdapter.php index dd3acee..4dfb32a 100644 --- a/Paginator/RawPaginatorAdapter.php +++ b/Paginator/RawPaginatorAdapter.php @@ -36,7 +36,7 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface * @var array for the facets */ private $facets; - + /** * @var array for the aggregations */ @@ -110,9 +110,12 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface /** * Returns the number of results. * - * @param boolean $genuineTotal make the function return the `hits.total` - * value of the search result in all cases, instead of limiting it to the - * `size` request parameter. + * If genuineTotal is provided as true, total hits is returned from the + * hits.total value from the search results instead of just returning + * the requested size. + * + * @param boolean $genuineTotal + * * @return integer The number of results. */ public function getTotalHits($genuineTotal = false) @@ -139,13 +142,14 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface return $this->facets; } - + /** - * Returns Aggregations + * Returns Aggregations. * * @return mixed */ - public function getAggregations() { + public function getAggregations() + { if (!isset($this->aggregations)) { $this->aggregations = $this->searchable->search($this->query)->getAggregations(); } diff --git a/Persister/ObjectPersisterInterface.php b/Persister/ObjectPersisterInterface.php index e9df2b2..9163320 100644 --- a/Persister/ObjectPersisterInterface.php +++ b/Persister/ObjectPersisterInterface.php @@ -71,6 +71,7 @@ interface ObjectPersisterInterface * If the object persister handles the given object. * * @param object $object + * * @return bool */ public function handlesObject($object); diff --git a/Provider/AbstractProvider.php b/Provider/AbstractProvider.php index 6de96ca..05fa525 100644 --- a/Provider/AbstractProvider.php +++ b/Provider/AbstractProvider.php @@ -72,6 +72,7 @@ abstract class AbstractProvider implements ProviderInterface * Get string with RAM usage information (current and peak). * * @deprecated To be removed in 4.0 + * * @return string */ protected function getMemoryUsage() diff --git a/Resources/config/orm.xml b/Resources/config/orm.xml index 19a2bf5..4172500 100644 --- a/Resources/config/orm.xml +++ b/Resources/config/orm.xml @@ -11,7 +11,7 @@ FOS\ElasticaBundle\Doctrine\ORM\ElasticaToModelTransformer FOS\ElasticaBundle\Doctrine\RepositoryManager - + diff --git a/Tests/RepositoryTest.php b/Tests/RepositoryTest.php index 2d5bc66..3f0509a 100644 --- a/Tests/RepositoryTest.php +++ b/Tests/RepositoryTest.php @@ -57,8 +57,9 @@ class RepositoryTest extends \PHPUnit_Framework_TestCase /** * @param string $testQuery - * @param int $testLimit + * @param int $testLimit * @param string $method + * * @return \FOS\ElasticaBundle\Finder\TransformedFinder|\PHPUnit_Framework_MockObject_MockObject */ private function getFinderMock($testQuery, $testLimit = null, $method = 'find') diff --git a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php index 6148749..8d07aeb 100644 --- a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php +++ b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php @@ -411,6 +411,7 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase /** * @param null|\Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher + * * @return ModelToElasticaAutoTransformer */ private function getTransformer($dispatcher = null) diff --git a/Transformer/ModelToElasticaAutoTransformer.php b/Transformer/ModelToElasticaAutoTransformer.php index 8884e62..6452a1f 100644 --- a/Transformer/ModelToElasticaAutoTransformer.php +++ b/Transformer/ModelToElasticaAutoTransformer.php @@ -38,7 +38,7 @@ class ModelToElasticaAutoTransformer implements ModelToElasticaTransformerInterf /** * Instanciates a new Mapper. * - * @param array $options + * @param array $options * @param EventDispatcherInterface $dispatcher */ public function __construct(array $options = array(), EventDispatcherInterface $dispatcher = null) From 4e087af50d1002d0a8206d866ba1a74373190adb Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 12 Mar 2015 22:41:48 +1100 Subject: [PATCH 420/447] Fix issues with CS merge --- DependencyInjection/FOSElasticaExtension.php | 7 ++++--- Resources/config/orm.xml | 2 +- Tests/Doctrine/AbstractProviderTest.php | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index f127470..b26e50c 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -487,9 +487,10 @@ class FOSElasticaExtension extends Extension 'indexName' => $indexName, 'typeName' => $typeName, )); - if ($typeConfig['listener']['logger']) { - $listenerDef->replaceArgument(3, new Reference($typeConfig['listener']['logger'])); - } + $listenerDef->replaceArgument(3, $typeConfig['listener']['logger'] ? + new Reference($typeConfig['listener']['logger']) : + null + ); $tagName = null; switch ($typeConfig['driver']) { diff --git a/Resources/config/orm.xml b/Resources/config/orm.xml index 4172500..8127db2 100644 --- a/Resources/config/orm.xml +++ b/Resources/config/orm.xml @@ -29,7 +29,7 @@ - + diff --git a/Tests/Doctrine/AbstractProviderTest.php b/Tests/Doctrine/AbstractProviderTest.php index cd4c63f..24e3d15 100644 --- a/Tests/Doctrine/AbstractProviderTest.php +++ b/Tests/Doctrine/AbstractProviderTest.php @@ -19,7 +19,7 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase { $this->objectClass = 'objectClass'; $this->options = array('debug_logging' => true, 'indexName' => 'index', 'typeName' => 'type'); -< + $this->objectPersister = $this->getMockObjectPersister(); $this->managerRegistry = $this->getMockManagerRegistry(); $this->objectManager = $this->getMockObjectManager(); From f72c51503a53712fb752396e069973391f117b7b Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Thu, 12 Mar 2015 17:44:57 +0100 Subject: [PATCH 421/447] Fix the service definitions when the logger is not set in listener The empty tag is parsed to an empty string, not to null. And this is not a valid value for the service --- Resources/config/mongodb.xml | 2 +- Resources/config/orm.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Resources/config/mongodb.xml b/Resources/config/mongodb.xml index 8e15533..398a0ca 100644 --- a/Resources/config/mongodb.xml +++ b/Resources/config/mongodb.xml @@ -26,7 +26,7 @@ - + null diff --git a/Resources/config/orm.xml b/Resources/config/orm.xml index d78ae8d..554bd3e 100644 --- a/Resources/config/orm.xml +++ b/Resources/config/orm.xml @@ -25,7 +25,7 @@ - + null From b6c252aac3f68324a980bbcf14b75de544a59997 Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Thu, 12 Mar 2015 17:54:08 +0100 Subject: [PATCH 422/447] Update the changelog for 3.0.9 --- CHANGELOG-3.0.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG-3.0.md b/CHANGELOG-3.0.md index 973269d..57ca45c 100644 --- a/CHANGELOG-3.0.md +++ b/CHANGELOG-3.0.md @@ -12,6 +12,11 @@ https://github.com/FriendsOfSymfony/FOSElasticaBundle/compare/v3.0.0...v3.0.1 To generate a changelog summary since the last version, run `git log --no-merges --oneline v3.0.0...3.0.x` +* 3.0.9 (2015-03-12) + + * Fix a bug in the BC layer of the type configuration for empty configs + * Fix the service definition for the Doctrine listener when the logger is not enabled + * 3.0.8 (2014-01-31) * Fixed handling of empty indexes #760 From 4af9f442fd940953c5211e509d3ecaca13f6c832 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 12 Mar 2015 22:17:57 +1100 Subject: [PATCH 423/447] Move common sorting code to base Transformer class --- .../AbstractElasticaToModelTransformer.php | 26 ++-------- Propel/ElasticaToModelTransformer.php | 26 ++-------- .../AbstractElasticaToModelTransformer.php | 51 +++++++++++++++++++ 3 files changed, 57 insertions(+), 46 deletions(-) create mode 100644 Transformer/AbstractElasticaToModelTransformer.php diff --git a/Doctrine/AbstractElasticaToModelTransformer.php b/Doctrine/AbstractElasticaToModelTransformer.php index a9afb22..603eafa 100755 --- a/Doctrine/AbstractElasticaToModelTransformer.php +++ b/Doctrine/AbstractElasticaToModelTransformer.php @@ -3,7 +3,7 @@ namespace FOS\ElasticaBundle\Doctrine; use FOS\ElasticaBundle\HybridResult; -use FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface; +use FOS\ElasticaBundle\Transformer\AbstractElasticaToModelTransformer as BaseTransformer; use FOS\ElasticaBundle\Transformer\HighlightableModelInterface; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; @@ -12,7 +12,7 @@ use Symfony\Component\PropertyAccess\PropertyAccessorInterface; * This mapper assumes an exact match between * elastica documents ids and doctrine object ids. */ -abstract class AbstractElasticaToModelTransformer implements ElasticaToModelTransformerInterface +abstract class AbstractElasticaToModelTransformer extends BaseTransformer { /** * Manager registry. @@ -38,13 +38,6 @@ abstract class AbstractElasticaToModelTransformer implements ElasticaToModelTran 'query_builder_method' => 'createQueryBuilder', ); - /** - * PropertyAccessor instance. - * - * @var PropertyAccessorInterface - */ - protected $propertyAccessor; - /** * Instantiates a new Mapper. * @@ -69,16 +62,6 @@ abstract class AbstractElasticaToModelTransformer implements ElasticaToModelTran return $this->objectClass; } - /** - * Set the PropertyAccessor. - * - * @param PropertyAccessorInterface $propertyAccessor - */ - public function setPropertyAccessor(PropertyAccessorInterface $propertyAccessor) - { - $this->propertyAccessor = $propertyAccessor; - } - /** * Transforms an array of elastica objects into an array of * model objects fetched from the doctrine repository. @@ -111,10 +94,7 @@ abstract class AbstractElasticaToModelTransformer implements ElasticaToModelTran // sort objects in the order of ids $idPos = array_flip($ids); $identifier = $this->options['identifier']; - $propertyAccessor = $this->propertyAccessor; - usort($objects, function ($a, $b) use ($idPos, $identifier, $propertyAccessor) { - return $idPos[$propertyAccessor->getValue($a, $identifier)] > $idPos[$propertyAccessor->getValue($b, $identifier)]; - }); + usort($objects, $this->getSortingClosure($idPos, $identifier)); return $objects; } diff --git a/Propel/ElasticaToModelTransformer.php b/Propel/ElasticaToModelTransformer.php index 87c4047..c80daa2 100644 --- a/Propel/ElasticaToModelTransformer.php +++ b/Propel/ElasticaToModelTransformer.php @@ -3,6 +3,7 @@ namespace FOS\ElasticaBundle\Propel; use FOS\ElasticaBundle\HybridResult; +use FOS\ElasticaBundle\Transformer\AbstractElasticaToModelTransformer; use FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; @@ -14,7 +15,7 @@ use Symfony\Component\PropertyAccess\PropertyAccessorInterface; * * @author William Durand */ -class ElasticaToModelTransformer implements ElasticaToModelTransformerInterface +class ElasticaToModelTransformer extends AbstractElasticaToModelTransformer { /** * Propel model class to map to Elastica documents. @@ -33,13 +34,6 @@ class ElasticaToModelTransformer implements ElasticaToModelTransformerInterface 'identifier' => 'id', ); - /** - * PropertyAccessor instance. - * - * @var PropertyAccessorInterface - */ - protected $propertyAccessor; - /** * Constructor. * @@ -52,16 +46,6 @@ class ElasticaToModelTransformer implements ElasticaToModelTransformerInterface $this->options = array_merge($this->options, $options); } - /** - * Set the PropertyAccessor instance. - * - * @param PropertyAccessorInterface $propertyAccessor - */ - public function setPropertyAccessor(PropertyAccessorInterface $propertyAccessor) - { - $this->propertyAccessor = $propertyAccessor; - } - /** * Transforms an array of Elastica document into an array of Propel entities * fetched from the database. @@ -82,11 +66,7 @@ class ElasticaToModelTransformer implements ElasticaToModelTransformerInterface // Sort objects in the order of their IDs $idPos = array_flip($ids); $identifier = $this->options['identifier']; - $propertyAccessor = $this->propertyAccessor; - - $sortCallback = function ($a, $b) use ($idPos, $identifier, $propertyAccessor) { - return $idPos[$propertyAccessor->getValue($a, $identifier)] > $idPos[$propertyAccessor->getValue($b, $identifier)]; - }; + $sortCallback = $this->getSortingClosure($idPos, $identifier); if (is_object($objects)) { $objects->uasort($sortCallback); diff --git a/Transformer/AbstractElasticaToModelTransformer.php b/Transformer/AbstractElasticaToModelTransformer.php new file mode 100644 index 0000000..2b1de5c --- /dev/null +++ b/Transformer/AbstractElasticaToModelTransformer.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FOS\ElasticaBundle\Transformer; + +use Symfony\Component\PropertyAccess\PropertyAccessorInterface; + +abstract class AbstractElasticaToModelTransformer implements ElasticaToModelTransformerInterface +{ + /** + * PropertyAccessor instance. + * + * @var PropertyAccessorInterface + */ + protected $propertyAccessor; + + /** + * Set the PropertyAccessor instance. + * + * @param PropertyAccessorInterface $propertyAccessor + */ + public function setPropertyAccessor(PropertyAccessorInterface $propertyAccessor) + { + $this->propertyAccessor = $propertyAccessor; + } + + /** + * Returns a sorting closure to be used with usort() to put retrieved objects + * back in the order that they were returned by ElasticSearch. + * + * @param array $idPos + * @param string $identifierPath + * @return callable + */ + protected function getSortingClosure(array $idPos, $identifierPath) + { + $propertyAccessor = $this->propertyAccessor; + + return function ($a, $b) use ($idPos, $identifierPath, $propertyAccessor) { + return $idPos[$propertyAccessor->getValue($a, $identifierPath)] > $idPos[$propertyAccessor->getValue($b, $identifierPath)]; + }; + } +} From d5a9b7b235bdbdbc757ed7c28b7608fe40f1312b Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 12 Mar 2015 22:21:53 +1100 Subject: [PATCH 424/447] Add missing method to HighlightableModelInterface. This is not a BC break - the method has always been required and lacking the method would cause a fatal error. --- Transformer/HighlightableModelInterface.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Transformer/HighlightableModelInterface.php b/Transformer/HighlightableModelInterface.php index 70b8ed3..96c6c7c 100644 --- a/Transformer/HighlightableModelInterface.php +++ b/Transformer/HighlightableModelInterface.php @@ -3,10 +3,17 @@ namespace FOS\ElasticaBundle\Transformer; /** - * Maps Elastica documents with model objects. + * Indicates that the model should have elastica highlights injected. */ interface HighlightableModelInterface { + /** + * Returns a unique identifier for the model. + * + * @return mixed + */ + public function getId(); + /** * Set ElasticSearch highlight data. * From 84e5831a813f53f236a4b3027ee49dd71bc99895 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 12 Mar 2015 23:08:32 +1100 Subject: [PATCH 425/447] Fixing scrutinizer issues --- DependencyInjection/FOSElasticaExtension.php | 3 +-- .../AbstractElasticaToModelTransformer.php | 10 ++++++---- Doctrine/AbstractProvider.php | 2 +- Doctrine/Listener.php | 8 ++++---- Index/IndexManager.php | 5 +++++ Index/MappingBuilder.php | 6 +++--- Persister/ObjectPersisterInterface.php | 18 +++++++++--------- Persister/ObjectSerializerPersister.php | 6 +++++- Propel/ElasticaToModelTransformer.php | 2 +- Serializer/Callback.php | 12 ++++-------- Tests/Doctrine/AbstractProviderTest.php | 1 - Tests/Functional/app/ORM/IndexableService.php | 4 ++-- ...lasticaToModelTransformerCollectionTest.php | 2 +- .../ElasticaToModelTransformerCollection.php | 2 +- 14 files changed, 43 insertions(+), 38 deletions(-) diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index b26e50c..ec45e25 100644 --- a/DependencyInjection/FOSElasticaExtension.php +++ b/DependencyInjection/FOSElasticaExtension.php @@ -502,7 +502,7 @@ class FOSElasticaExtension extends Extension break; } - if ($tagName) { + if (null !== $tagName) { foreach ($this->getDoctrineEvents($typeConfig) as $event) { $listenerDef->addTag($tagName, array('event' => $event)); } @@ -527,7 +527,6 @@ class FOSElasticaExtension extends Extension break; default: throw new InvalidArgumentException(sprintf('Cannot determine events for driver "%s"', $typeConfig['driver'])); - break; } $events = array(); diff --git a/Doctrine/AbstractElasticaToModelTransformer.php b/Doctrine/AbstractElasticaToModelTransformer.php index 603eafa..0263f42 100755 --- a/Doctrine/AbstractElasticaToModelTransformer.php +++ b/Doctrine/AbstractElasticaToModelTransformer.php @@ -2,10 +2,10 @@ namespace FOS\ElasticaBundle\Doctrine; +use Doctrine\Common\Persistence\ManagerRegistry; use FOS\ElasticaBundle\HybridResult; use FOS\ElasticaBundle\Transformer\AbstractElasticaToModelTransformer as BaseTransformer; use FOS\ElasticaBundle\Transformer\HighlightableModelInterface; -use Symfony\Component\PropertyAccess\PropertyAccessorInterface; /** * Maps Elastica documents with Doctrine objects @@ -16,6 +16,8 @@ abstract class AbstractElasticaToModelTransformer extends BaseTransformer { /** * Manager registry. + * + * @var ManagerRegistry */ protected $registry = null; @@ -41,11 +43,11 @@ abstract class AbstractElasticaToModelTransformer extends BaseTransformer /** * Instantiates a new Mapper. * - * @param object $registry + * @param ManagerRegistry $registry * @param string $objectClass * @param array $options */ - public function __construct($registry, $objectClass, array $options = array()) + public function __construct(ManagerRegistry $registry, $objectClass, array $options = array()) { $this->registry = $registry; $this->objectClass = $objectClass; @@ -118,7 +120,7 @@ abstract class AbstractElasticaToModelTransformer extends BaseTransformer } /** - * {@inheritdoc} + * {@inheritDoc} */ public function getIdentifierField() { diff --git a/Doctrine/AbstractProvider.php b/Doctrine/AbstractProvider.php index e250e56..9845edc 100644 --- a/Doctrine/AbstractProvider.php +++ b/Doctrine/AbstractProvider.php @@ -71,7 +71,7 @@ abstract class AbstractProvider extends BaseAbstractProvider $objects = $this->getSlice($queryBuilder, $batchSize, $offset, $objects); $objects = array_filter($objects, array($this, 'isObjectIndexable')); - if ($objects) { + if (!empty($objects)) { if (!$ignoreErrors) { $this->objectPersister->insertMany($objects); } else { diff --git a/Doctrine/Listener.php b/Doctrine/Listener.php index c35b947..a1d3585 100644 --- a/Doctrine/Listener.php +++ b/Doctrine/Listener.php @@ -3,8 +3,8 @@ namespace FOS\ElasticaBundle\Doctrine; use Doctrine\Common\Persistence\Event\LifecycleEventArgs; -use FOS\ElasticaBundle\Persister\ObjectPersisterInterface; use FOS\ElasticaBundle\Persister\ObjectPersister; +use FOS\ElasticaBundle\Persister\ObjectPersisterInterface; use FOS\ElasticaBundle\Provider\IndexableInterface; use Psr\Log\LoggerInterface; use Symfony\Component\PropertyAccess\PropertyAccess; @@ -19,14 +19,14 @@ class Listener /** * Object persister. * - * @var ObjectPersister + * @var ObjectPersisterInterface */ protected $objectPersister; /** * Configuration for the listener. * - * @var string + * @var array */ private $config; @@ -84,7 +84,7 @@ class Listener $this->objectPersister = $objectPersister; $this->propertyAccessor = PropertyAccess::createPropertyAccessor(); - if ($logger) { + if ($logger && $this->objectPersister instanceof ObjectPersister) { $this->objectPersister->setLogger($logger); } } diff --git a/Index/IndexManager.php b/Index/IndexManager.php index 13aecad..98ce870 100644 --- a/Index/IndexManager.php +++ b/Index/IndexManager.php @@ -6,6 +6,11 @@ use FOS\ElasticaBundle\Elastica\Index; class IndexManager { + /** + * @var Index + */ + private $defaultIndex; + /** * @var array */ diff --git a/Index/MappingBuilder.php b/Index/MappingBuilder.php index 93a3fcc..e03bf54 100644 --- a/Index/MappingBuilder.php +++ b/Index/MappingBuilder.php @@ -38,13 +38,13 @@ class MappingBuilder } $mapping = array(); - if ($typeMappings) { + if (!empty($typeMappings)) { $mapping['mappings'] = $typeMappings; } // 'warmers' => $indexConfig->getWarmers(), $settings = $indexConfig->getSettings(); - if ($settings) { + if (!empty($settings)) { $mapping['settings'] = $settings; } @@ -95,7 +95,7 @@ class MappingBuilder $mapping['_meta']['model'] = $typeConfig->getModel(); } - if (!$mapping) { + if (empty($mapping)) { // Empty mapping, we want it encoded as a {} instead of a [] $mapping = new \stdClass(); } diff --git a/Persister/ObjectPersisterInterface.php b/Persister/ObjectPersisterInterface.php index 9163320..f624971 100644 --- a/Persister/ObjectPersisterInterface.php +++ b/Persister/ObjectPersisterInterface.php @@ -10,6 +10,15 @@ namespace FOS\ElasticaBundle\Persister; */ interface ObjectPersisterInterface { + /** + * Checks if this persister can handle the given object or not. + * + * @param mixed $object + * + * @return boolean + */ + public function handlesObject($object); + /** * Insert one object into the type * The object will be transformed to an elastica document. @@ -66,13 +75,4 @@ interface ObjectPersisterInterface * @param array $identifiers array of domain model object identifiers */ public function deleteManyByIdentifiers(array $identifiers); - - /** - * If the object persister handles the given object. - * - * @param object $object - * - * @return bool - */ - public function handlesObject($object); } diff --git a/Persister/ObjectSerializerPersister.php b/Persister/ObjectSerializerPersister.php index 018f851..792aa9a 100644 --- a/Persister/ObjectSerializerPersister.php +++ b/Persister/ObjectSerializerPersister.php @@ -18,12 +18,16 @@ class ObjectSerializerPersister extends ObjectPersister protected $serializer; /** + * @param Type $type + * @param ModelToElasticaTransformerInterface $transformer * @param string $objectClass + * @param callable $serializer */ public function __construct(Type $type, ModelToElasticaTransformerInterface $transformer, $objectClass, $serializer) { parent::__construct($type, $transformer, $objectClass, array()); - $this->serializer = $serializer; + + $this->serializer = $serializer; } /** diff --git a/Propel/ElasticaToModelTransformer.php b/Propel/ElasticaToModelTransformer.php index c80daa2..d143478 100644 --- a/Propel/ElasticaToModelTransformer.php +++ b/Propel/ElasticaToModelTransformer.php @@ -85,7 +85,7 @@ class ElasticaToModelTransformer extends AbstractElasticaToModelTransformer $objects = $this->transform($elasticaObjects); $result = array(); - for ($i = 0; $i < count($elasticaObjects); $i++) { + for ($i = 0, $j = count($elasticaObjects); $i < $j; $i++) { $result[] = new HybridResult($elasticaObjects[$i], $objects[$i]); } diff --git a/Serializer/Callback.php b/Serializer/Callback.php index 38d93dc..004d133 100644 --- a/Serializer/Callback.php +++ b/Serializer/Callback.php @@ -23,10 +23,8 @@ class Callback { $this->groups = $groups; - if ($this->groups) { - if (!$this->serializer instanceof SerializerInterface) { - throw new \RuntimeException('Setting serialization groups requires using "JMS\Serializer\Serializer".'); - } + if (!empty($this->groups) && !$this->serializer instanceof SerializerInterface) { + throw new \RuntimeException('Setting serialization groups requires using "JMS\Serializer\Serializer".'); } } @@ -34,10 +32,8 @@ class Callback { $this->version = $version; - if ($this->version) { - if (!$this->serializer instanceof SerializerInterface) { - throw new \RuntimeException('Setting serialization version requires using "JMS\Serializer\Serializer".'); - } + if ($this->version && !$this->serializer instanceof SerializerInterface) { + throw new \RuntimeException('Setting serialization version requires using "JMS\Serializer\Serializer".'); } } diff --git a/Tests/Doctrine/AbstractProviderTest.php b/Tests/Doctrine/AbstractProviderTest.php index 24e3d15..7b41837 100644 --- a/Tests/Doctrine/AbstractProviderTest.php +++ b/Tests/Doctrine/AbstractProviderTest.php @@ -58,7 +58,6 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase ->with('index', 'type', $this->anything()) ->will($this->returnValue(true)); - $providerInvocationOffset = 2; $previousSlice = array(); foreach ($objectsByIteration as $i => $objects) { diff --git a/Tests/Functional/app/ORM/IndexableService.php b/Tests/Functional/app/ORM/IndexableService.php index 018451e..8f17bd0 100644 --- a/Tests/Functional/app/ORM/IndexableService.php +++ b/Tests/Functional/app/ORM/IndexableService.php @@ -13,12 +13,12 @@ namespace FOS\ElasticaBundle\Tests\Functional\app\ORM; class IndexableService { - public function isIndexable($object) + public function isIndexable() { return true; } - public static function isntIndexable($object) + public static function isntIndexable() { return false; } diff --git a/Tests/Transformer/ElasticaToModelTransformerCollectionTest.php b/Tests/Transformer/ElasticaToModelTransformerCollectionTest.php index d83f596..56a7200 100644 --- a/Tests/Transformer/ElasticaToModelTransformerCollectionTest.php +++ b/Tests/Transformer/ElasticaToModelTransformerCollectionTest.php @@ -37,7 +37,7 @@ class ElasticaToModelTransformerCollectionTest extends \PHPUnit_Framework_TestCa $this->collection = new ElasticaToModelTransformerCollection($this->transformers = array( 'type1' => $transformer1, 'type2' => $transformer2, - ), array()); + )); } public function testGetObjectClass() diff --git a/Transformer/ElasticaToModelTransformerCollection.php b/Transformer/ElasticaToModelTransformerCollection.php index 041e361..9920f43 100644 --- a/Transformer/ElasticaToModelTransformerCollection.php +++ b/Transformer/ElasticaToModelTransformerCollection.php @@ -81,7 +81,7 @@ class ElasticaToModelTransformerCollection implements ElasticaToModelTransformer $objects = $this->transform($elasticaObjects); $result = array(); - for ($i = 0; $i < count($elasticaObjects); $i++) { + for ($i = 0, $j = count($elasticaObjects); $i < $j; $i++) { $result[] = new HybridResult($elasticaObjects[$i], $objects[$i]); } From 6a07f7b24ee2fb44d4bf069f09568f6a521920c3 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Fri, 13 Mar 2015 19:10:24 +1100 Subject: [PATCH 426/447] More QA --- Paginator/RawPaginatorAdapter.php | 2 +- Tests/Command/ResetCommandTest.php | 2 +- Tests/Doctrine/AbstractListenerTest.php | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Paginator/RawPaginatorAdapter.php b/Paginator/RawPaginatorAdapter.php index 4dfb32a..c270f00 100644 --- a/Paginator/RawPaginatorAdapter.php +++ b/Paginator/RawPaginatorAdapter.php @@ -74,7 +74,7 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface ? (integer) $this->query->getParam('size') : null; - if ($size && $size < $offset + $itemCountPerPage) { + if (null !== $size && $size < $offset + $itemCountPerPage) { $itemCountPerPage = $size - $offset; } diff --git a/Tests/Command/ResetCommandTest.php b/Tests/Command/ResetCommandTest.php index eb0aaa9..d63b380 100644 --- a/Tests/Command/ResetCommandTest.php +++ b/Tests/Command/ResetCommandTest.php @@ -9,8 +9,8 @@ use Symfony\Component\DependencyInjection\Container; class ResetCommandTest extends \PHPUnit_Framework_TestCase { + private $command; private $resetter; - private $indexManager; public function setup() diff --git a/Tests/Doctrine/AbstractListenerTest.php b/Tests/Doctrine/AbstractListenerTest.php index d6e2cb7..dcaf7d6 100644 --- a/Tests/Doctrine/AbstractListenerTest.php +++ b/Tests/Doctrine/AbstractListenerTest.php @@ -272,6 +272,7 @@ namespace FOS\ElasticaBundle\Tests\Doctrine\Listener; class Entity { private $id; + public $identifier; /** * @param integer $id From bb4618c101e8cda1419414688fa3020b3dfb40c6 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Fri, 13 Mar 2015 19:34:56 +1100 Subject: [PATCH 427/447] Even more QA --- Event/IndexEvent.php | 38 +++++++++++++++++++ Event/IndexPopulateEvent.php | 20 ++-------- Event/IndexResetEvent.php | 22 ++--------- Event/TypeResetEvent.php | 18 ++------- Propel/Provider.php | 2 +- Provider/AbstractProvider.php | 2 +- Serializer/Callback.php | 4 +- Tests/Persister/ObjectPersisterTest.php | 2 +- .../ObjectSerializerPersisterTest.php | 2 +- Tests/RepositoryTest.php | 4 +- .../ModelToElasticaAutoTransformerTest.php | 2 +- ...delToElasticaIdentifierTransformerTest.php | 2 +- 12 files changed, 58 insertions(+), 60 deletions(-) create mode 100644 Event/IndexEvent.php diff --git a/Event/IndexEvent.php b/Event/IndexEvent.php new file mode 100644 index 0000000..ed71d78 --- /dev/null +++ b/Event/IndexEvent.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FOS\ElasticaBundle\Event; + +use Symfony\Component\EventDispatcher\Event; + +class IndexEvent extends Event +{ + /** + * @var string + */ + private $index; + + /** + * @param string $index + */ + public function __construct($index) + { + $this->index = $index; + } + + /** + * @return string + */ + public function getIndex() + { + return $this->index; + } +} diff --git a/Event/IndexPopulateEvent.php b/Event/IndexPopulateEvent.php index ab61f0a..b35105a 100644 --- a/Event/IndexPopulateEvent.php +++ b/Event/IndexPopulateEvent.php @@ -11,23 +11,16 @@ namespace FOS\ElasticaBundle\Event; -use Symfony\Component\EventDispatcher\Event; - /** * Index Populate Event. * * @author Oleg Andreyev */ -class IndexPopulateEvent extends Event +class IndexPopulateEvent extends IndexEvent { const PRE_INDEX_POPULATE = 'elastica.index.index_pre_populate'; const POST_INDEX_POPULATE = 'elastica.index.index_post_populate'; - /** - * @var string - */ - private $index; - /** * @var bool */ @@ -45,19 +38,12 @@ class IndexPopulateEvent extends Event */ public function __construct($index, $reset, $options) { - $this->index = $index; + parent::__construct($index); + $this->reset = $reset; $this->options = $options; } - /** - * @return string - */ - public function getIndex() - { - return $this->index; - } - /** * @return boolean */ diff --git a/Event/IndexResetEvent.php b/Event/IndexResetEvent.php index 3fb3625..871915a 100644 --- a/Event/IndexResetEvent.php +++ b/Event/IndexResetEvent.php @@ -11,14 +11,12 @@ namespace FOS\ElasticaBundle\Event; -use Symfony\Component\EventDispatcher\Event; - /** * Index ResetEvent. * * @author Oleg Andreyev */ -class IndexResetEvent extends Event +class IndexResetEvent extends IndexEvent { const PRE_INDEX_RESET = 'elastica.index.pre_reset'; const POST_INDEX_RESET = 'elastica.index.post_reset'; @@ -28,11 +26,6 @@ class IndexResetEvent extends Event */ private $force; - /** - * @var string - */ - private $index; - /** * @var bool */ @@ -45,17 +38,10 @@ class IndexResetEvent extends Event */ public function __construct($index, $populating, $force) { - $this->force = $force; - $this->index = $index; - $this->populating = $populating; - } + parent::__construct($index); - /** - * @return string - */ - public function getIndex() - { - return $this->index; + $this->force = $force; + $this->populating = $populating; } /** diff --git a/Event/TypeResetEvent.php b/Event/TypeResetEvent.php index 0b21a06..98fa2f4 100644 --- a/Event/TypeResetEvent.php +++ b/Event/TypeResetEvent.php @@ -18,16 +18,11 @@ use Symfony\Component\EventDispatcher\Event; * * @author Oleg Andreyev */ -class TypeResetEvent extends Event +class TypeResetEvent extends IndexEvent { const PRE_TYPE_RESET = 'elastica.index.type_pre_reset'; const POST_TYPE_RESET = 'elastica.index.type_post_reset'; - /** - * @var string - */ - private $index; - /** * @var string */ @@ -39,16 +34,9 @@ class TypeResetEvent extends Event */ public function __construct($index, $type) { - $this->type = $type; - $this->index = $index; - } + parent::__construct($index); - /** - * @return string - */ - public function getIndex() - { - return $this->index; + $this->type = $type; } /** diff --git a/Propel/Provider.php b/Propel/Provider.php index f8397f9..f28faa4 100644 --- a/Propel/Provider.php +++ b/Propel/Provider.php @@ -30,7 +30,7 @@ class Provider extends AbstractProvider ->getArrayCopy(); $objects = array_filter($objects, array($this, 'isObjectIndexable')); - if ($objects) { + if (!empty($objects)) { $this->objectPersister->insertMany($objects); } diff --git a/Provider/AbstractProvider.php b/Provider/AbstractProvider.php index 05fa525..a743d17 100644 --- a/Provider/AbstractProvider.php +++ b/Provider/AbstractProvider.php @@ -25,7 +25,7 @@ abstract class AbstractProvider implements ProviderInterface protected $options; /** - * @var Indexable + * @var IndexableInterface */ private $indexable; diff --git a/Serializer/Callback.php b/Serializer/Callback.php index 004d133..61da997 100644 --- a/Serializer/Callback.php +++ b/Serializer/Callback.php @@ -8,7 +8,7 @@ use JMS\Serializer\SerializerInterface; class Callback { protected $serializer; - protected $groups; + protected $groups = array(); protected $version; public function setSerializer($serializer) @@ -41,7 +41,7 @@ class Callback { $context = $this->serializer instanceof SerializerInterface ? SerializationContext::create()->enableMaxDepthChecks() : array(); - if ($this->groups) { + if (!empty($this->groups)) { $context->setGroups($this->groups); } diff --git a/Tests/Persister/ObjectPersisterTest.php b/Tests/Persister/ObjectPersisterTest.php index c3da687..06039f0 100644 --- a/Tests/Persister/ObjectPersisterTest.php +++ b/Tests/Persister/ObjectPersisterTest.php @@ -203,7 +203,7 @@ class ObjectPersisterTest extends \PHPUnit_Framework_TestCase private function getTransformer() { $transformer = new ModelToElasticaAutoTransformer(); - $transformer->setPropertyAccessor(PropertyAccess::getPropertyAccessor()); + $transformer->setPropertyAccessor(PropertyAccess::createPropertyAccessor()); return $transformer; } diff --git a/Tests/Persister/ObjectSerializerPersisterTest.php b/Tests/Persister/ObjectSerializerPersisterTest.php index 0b348d1..0536d06 100644 --- a/Tests/Persister/ObjectSerializerPersisterTest.php +++ b/Tests/Persister/ObjectSerializerPersisterTest.php @@ -112,7 +112,7 @@ class ObjectSerializerPersisterTest extends \PHPUnit_Framework_TestCase private function getTransformer() { $transformer = new ModelToElasticaIdentifierTransformer(); - $transformer->setPropertyAccessor(PropertyAccess::getPropertyAccessor()); + $transformer->setPropertyAccessor(PropertyAccess::createPropertyAccessor()); return $transformer; } diff --git a/Tests/RepositoryTest.php b/Tests/RepositoryTest.php index 3f0509a..7702af2 100644 --- a/Tests/RepositoryTest.php +++ b/Tests/RepositoryTest.php @@ -57,10 +57,10 @@ class RepositoryTest extends \PHPUnit_Framework_TestCase /** * @param string $testQuery - * @param int $testLimit + * @param mixed $testLimit * @param string $method * - * @return \FOS\ElasticaBundle\Finder\TransformedFinder|\PHPUnit_Framework_MockObject_MockObject + * @return \FOS\ElasticaBundle\Finder\TransformedFinder */ private function getFinderMock($testQuery, $testLimit = null, $method = 'find') { diff --git a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php index 8d07aeb..f45134e 100644 --- a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php +++ b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php @@ -417,7 +417,7 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase private function getTransformer($dispatcher = null) { $transformer = new ModelToElasticaAutoTransformer(array(), $dispatcher); - $transformer->setPropertyAccessor(PropertyAccess::getPropertyAccessor()); + $transformer->setPropertyAccessor(PropertyAccess::createPropertyAccessor()); return $transformer; } diff --git a/Tests/Transformer/ModelToElasticaIdentifierTransformerTest.php b/Tests/Transformer/ModelToElasticaIdentifierTransformerTest.php index 14d678e..aa3d7b7 100644 --- a/Tests/Transformer/ModelToElasticaIdentifierTransformerTest.php +++ b/Tests/Transformer/ModelToElasticaIdentifierTransformerTest.php @@ -51,7 +51,7 @@ class ModelToElasticaIdentifierTransformerTest extends \PHPUnit_Framework_TestCa private function getTransformer() { $transformer = new ModelToElasticaIdentifierTransformer(); - $transformer->setPropertyAccessor(PropertyAccess::getPropertyAccessor()); + $transformer->setPropertyAccessor(PropertyAccess::createPropertyAccessor()); return $transformer; } From 9cf0117c71229ba62050f4de02233d540f7baad8 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Sat, 14 Mar 2015 00:51:07 +1100 Subject: [PATCH 428/447] AliasProcessor --- Exception/AliasIsIndexException.php | 2 +- Index/AliasProcessor.php | 145 ++++++++++-------- Tests/Index/AliasProcessorTest.php | 223 ++++++++++++++++++++++++++++ 3 files changed, 305 insertions(+), 65 deletions(-) create mode 100644 Tests/Index/AliasProcessorTest.php diff --git a/Exception/AliasIsIndexException.php b/Exception/AliasIsIndexException.php index 1df7a62..9af6ee3 100644 --- a/Exception/AliasIsIndexException.php +++ b/Exception/AliasIsIndexException.php @@ -6,6 +6,6 @@ class AliasIsIndexException extends \Exception { public function __construct($indexName) { - parent::__construct(sprintf('Expected alias %s instead of index', $indexName)); + parent::__construct(sprintf('Expected %s to be an alias but it is an index.', $indexName)); } } diff --git a/Index/AliasProcessor.php b/Index/AliasProcessor.php index c4f1464..f4e4d00 100644 --- a/Index/AliasProcessor.php +++ b/Index/AliasProcessor.php @@ -54,37 +54,47 @@ class AliasProcessor $client = $index->getClient(); $aliasName = $indexConfig->getElasticSearchName(); - $oldIndexName = false; + $oldIndexName = null; $newIndexName = $index->getName(); try { - $aliasedIndexes = $this->getAliasedIndexes($client, $aliasName); + $oldIndexName = $this->getAliasedIndex($client, $aliasName); } catch (AliasIsIndexException $e) { if (!$force) { throw $e; } $this->deleteIndex($client, $aliasName); - $aliasedIndexes = array(); } - if (count($aliasedIndexes) > 1) { - throw new \RuntimeException( - sprintf( - 'Alias %s is used for multiple indexes: [%s]. - Make sure it\'s either not used or is assigned to one index only', - $aliasName, - implode(', ', $aliasedIndexes) - ) - ); + try { + $aliasUpdateRequest = $this->buildAliasUpdateRequest($oldIndexName, $aliasName, $newIndexName); + $client->request('_aliases', 'POST', $aliasUpdateRequest); + } catch (ExceptionInterface $e) { + $this->cleanupRenameFailure($client, $newIndexName, $e); } + // Delete the old index after the alias has been switched + if (null !== $oldIndexName) { + $this->deleteIndex($client, $oldIndexName); + } + } + + /** + * Builds an ElasticSearch request to rename or create an alias. + * + * @param string|null $aliasedIndex + * @param string $aliasName + * @param string $newIndexName + * @return array + */ + private function buildAliasUpdateRequest($aliasedIndex, $aliasName, $newIndexName) + { $aliasUpdateRequest = array('actions' => array()); - if (count($aliasedIndexes) === 1) { + if (null !== $aliasedIndex) { // if the alias is set - add an action to remove it - $oldIndexName = $aliasedIndexes[0]; $aliasUpdateRequest['actions'][] = array( - 'remove' => array('index' => $oldIndexName, 'alias' => $aliasName), + 'remove' => array('index' => $aliasedIndex, 'alias' => $aliasName), ); } @@ -93,58 +103,68 @@ class AliasProcessor 'add' => array('index' => $newIndexName, 'alias' => $aliasName), ); - try { - $client->request('_aliases', 'POST', $aliasUpdateRequest); - } catch (ExceptionInterface $renameAliasException) { - $additionalError = ''; - // if we failed to move the alias, delete the newly built index - try { - $index->delete(); - } catch (ExceptionInterface $deleteNewIndexException) { - $additionalError = sprintf( - 'Tried to delete newly built index %s, but also failed: %s', - $newIndexName, - $deleteNewIndexException->getMessage() - ); - } + return $aliasUpdateRequest; + } - throw new \RuntimeException( - sprintf( - 'Failed to updated index alias: %s. %s', - $renameAliasException->getMessage(), - $additionalError ?: sprintf('Newly built index %s was deleted', $newIndexName) - ), 0, $renameAliasException + /** + * Cleans up an index when we encounter a failure to rename the alias. + * + * @param Client $client + * @param $indexName + * @param \Exception $renameAliasException + */ + private function cleanupRenameFailure(Client $client, $indexName, \Exception $renameAliasException) + { + $additionalError = ''; + try { + $this->deleteIndex($client, $indexName); + } catch (ExceptionInterface $deleteNewIndexException) { + $additionalError = sprintf( + 'Tried to delete newly built index %s, but also failed: %s', + $indexName, + $deleteNewIndexException->getMessage() ); } - // Delete the old index after the alias has been switched - if ($oldIndexName) { - $oldIndex = new Index($client, $oldIndexName); - try { - $oldIndex->delete(); - } catch (ExceptionInterface $deleteOldIndexException) { - throw new \RuntimeException( - sprintf( - 'Failed to delete old index %s with message: %s', - $oldIndexName, - $deleteOldIndexException->getMessage() - ), 0, $deleteOldIndexException - ); - } + throw new \RuntimeException(sprintf( + 'Failed to updated index alias: %s. %s', + $renameAliasException->getMessage(), + $additionalError ?: sprintf('Newly built index %s was deleted', $indexName) + ), 0, $renameAliasException); + } + + /** + * Delete an index. + * + * @param Client $client + * @param string $indexName Index name to delete + */ + private function deleteIndex(Client $client, $indexName) + { + try { + $path = sprintf("%s", $indexName); + $client->request($path, Request::DELETE); + } catch (ExceptionInterface $deleteOldIndexException) { + throw new \RuntimeException(sprintf( + 'Failed to delete index %s with message: %s', + $indexName, + $deleteOldIndexException->getMessage() + ), 0, $deleteOldIndexException); } } /** - * Returns array of indexes which are mapped to given alias. + * Returns the name of a single index that an alias points to or throws + * an exception if there is more than one. * * @param Client $client * @param string $aliasName Alias name * - * @return array + * @return string|null * * @throws AliasIsIndexException */ - private function getAliasedIndexes(Client $client, $aliasName) + private function getAliasedIndex(Client $client, $aliasName) { $aliasesInfo = $client->request('_aliases', 'GET')->getData(); $aliasedIndexes = array(); @@ -163,18 +183,15 @@ class AliasProcessor } } - return $aliasedIndexes; - } + if (count($aliasedIndexes) > 1) { + throw new \RuntimeException(sprintf( + 'Alias %s is used for multiple indexes: [%s]. Make sure it\'s'. + 'either not used or is assigned to one index only', + $aliasName, + implode(', ', $aliasedIndexes) + )); + } - /** - * Delete an index. - * - * @param Client $client - * @param string $indexName Index name to delete - */ - private function deleteIndex(Client $client, $indexName) - { - $path = sprintf("%s", $indexName); - $client->request($path, Request::DELETE); + return array_shift($aliasedIndexes); } } diff --git a/Tests/Index/AliasProcessorTest.php b/Tests/Index/AliasProcessorTest.php new file mode 100644 index 0000000..f1592b2 --- /dev/null +++ b/Tests/Index/AliasProcessorTest.php @@ -0,0 +1,223 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FOS\ElasticaBundle\Tests\Index; + +use Elastica\Exception\ResponseException; +use Elastica\Request; +use Elastica\Response; +use FOS\ElasticaBundle\Configuration\IndexConfig; +use FOS\ElasticaBundle\Index\AliasProcessor; + +class AliasProcessorTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var AliasProcessor + */ + private $processor; + + /** + * @dataProvider getSetRootNameData + * @param string $name + * @param array $configArray + * @param string $resultStartsWith + */ + public function testSetRootName($name, $configArray, $resultStartsWith) + { + $indexConfig = new IndexConfig($name, array(), $configArray); + $index = $this->getMockBuilder('FOS\\ElasticaBundle\\Elastica\\Index') + ->disableOriginalConstructor() + ->getMock(); + $index->expects($this->once()) + ->method('overrideName') + ->with($this->stringStartsWith($resultStartsWith)); + + $this->processor->setRootName($indexConfig, $index); + } + + public function testSwitchAliasNoAliasSet() + { + $indexConfig = new IndexConfig('name', array(), array()); + list($index, $client) = $this->getMockedIndex('unique_name'); + + $client->expects($this->at(0)) + ->method('request') + ->with('_aliases', 'GET') + ->willReturn(new Response(array())); + $client->expects($this->at(1)) + ->method('request') + ->with('_aliases', 'POST', array('actions' => array( + array('add' => array('index' => 'unique_name', 'alias' => 'name')) + ))); + + $this->processor->switchIndexAlias($indexConfig, $index, false); + } + + public function testSwitchAliasExistingAliasSet() + { + $indexConfig = new IndexConfig('name', array(), array()); + list($index, $client) = $this->getMockedIndex('unique_name'); + + $client->expects($this->at(0)) + ->method('request') + ->with('_aliases', 'GET') + ->willReturn(new Response(array( + 'old_unique_name' => array('aliases' => array('name')) + ))); + $client->expects($this->at(1)) + ->method('request') + ->with('_aliases', 'POST', array('actions' => array( + array('remove' => array('index' => 'old_unique_name', 'alias' => 'name')), + array('add' => array('index' => 'unique_name', 'alias' => 'name')) + ))); + + $this->processor->switchIndexAlias($indexConfig, $index, false); + } + + /** + * @expectedException \RuntimeException + */ + public function testSwitchAliasThrowsWhenMoreThanOneExists() + { + $indexConfig = new IndexConfig('name', array(), array()); + list($index, $client) = $this->getMockedIndex('unique_name'); + + $client->expects($this->at(0)) + ->method('request') + ->with('_aliases', 'GET') + ->willReturn(new Response(array( + 'old_unique_name' => array('aliases' => array('name')), + 'another_old_unique_name' => array('aliases' => array('name')) + ))); + + $this->processor->switchIndexAlias($indexConfig, $index, false); + } + + /** + * @expectedException \FOS\ElasticaBundle\Exception\AliasIsIndexException + */ + public function testSwitchAliasThrowsWhenAliasIsAnIndex() + { + $indexConfig = new IndexConfig('name', array(), array()); + list($index, $client) = $this->getMockedIndex('unique_name'); + + $client->expects($this->at(0)) + ->method('request') + ->with('_aliases', 'GET') + ->willReturn(new Response(array( + 'name' => array(), + ))); + + $this->processor->switchIndexAlias($indexConfig, $index, false); + } + + public function testSwitchAliasDeletesIndexCollisionIfForced() + { + $indexConfig = new IndexConfig('name', array(), array()); + list($index, $client) = $this->getMockedIndex('unique_name'); + + $client->expects($this->at(0)) + ->method('request') + ->with('_aliases', 'GET') + ->willReturn(new Response(array( + 'name' => array(), + ))); + $client->expects($this->at(1)) + ->method('request') + ->with('name', 'DELETE'); + + $this->processor->switchIndexAlias($indexConfig, $index, true); + } + + public function testSwitchAliasDeletesOldIndex() + { + $indexConfig = new IndexConfig('name', array(), array()); + list($index, $client) = $this->getMockedIndex('unique_name'); + + $client->expects($this->at(0)) + ->method('request') + ->with('_aliases', 'GET') + ->willReturn(new Response(array( + 'old_unique_name' => array('aliases' => array('name')), + ))); + $client->expects($this->at(1)) + ->method('request') + ->with('_aliases', 'POST', array('actions' => array( + array('remove' => array('index' => 'old_unique_name', 'alias' => 'name')), + array('add' => array('index' => 'unique_name', 'alias' => 'name')) + ))); + $client->expects($this->at(2)) + ->method('request') + ->with('old_unique_name', 'DELETE'); + + $this->processor->switchIndexAlias($indexConfig, $index, true); + } + + public function testSwitchAliasCleansUpOnRenameFailure() + { + $indexConfig = new IndexConfig('name', array(), array()); + list($index, $client) = $this->getMockedIndex('unique_name'); + + $client->expects($this->at(0)) + ->method('request') + ->with('_aliases', 'GET') + ->willReturn(new Response(array( + 'old_unique_name' => array('aliases' => array('name')), + ))); + $client->expects($this->at(1)) + ->method('request') + ->with('_aliases', 'POST', array('actions' => array( + array('remove' => array('index' => 'old_unique_name', 'alias' => 'name')), + array('add' => array('index' => 'unique_name', 'alias' => 'name')) + ))) + ->will($this->throwException(new ResponseException(new Request(''), new Response('')))); + $client->expects($this->at(2)) + ->method('request') + ->with('unique_name', 'DELETE'); + // Not an annotation: we do not want a RuntimeException until now. + $this->setExpectedException('RuntimeException'); + + $this->processor->switchIndexAlias($indexConfig, $index, true); + } + + public function getSetRootNameData() + { + return array( + array('name', array(), 'name_'), + array('name', array('elasticSearchName' => 'notname'), 'notname_') + ); + } + + protected function setUp() + { + $this->processor = new AliasProcessor(); + } + + private function getMockedIndex($name) + { + $index = $this->getMockBuilder('FOS\\ElasticaBundle\\Elastica\\Index') + ->disableOriginalConstructor() + ->getMock(); + + $client = $this->getMockBuilder('Elastica\\Client') + ->disableOriginalConstructor() + ->getMock(); + $index->expects($this->any()) + ->method('getClient') + ->willReturn($client); + + $index->expects($this->any()) + ->method('getName') + ->willReturn($name); + + return array($index, $client); + } +} From 72a9dfa267ff5d302a4b0b595e1a74d88021cc06 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Sat, 14 Mar 2015 16:08:50 +1100 Subject: [PATCH 429/447] Indexable service improvements --- CHANGELOG-3.1.md | 1 + Index/AliasProcessor.php | 2 +- Provider/Indexable.php | 112 ++++++++++++++++++++++--------- Resources/doc/types.md | 7 +- Tests/Provider/IndexableTest.php | 7 ++ 5 files changed, 95 insertions(+), 34 deletions(-) diff --git a/CHANGELOG-3.1.md b/CHANGELOG-3.1.md index 478840e..10d7887 100644 --- a/CHANGELOG-3.1.md +++ b/CHANGELOG-3.1.md @@ -44,3 +44,4 @@ https://github.com/FriendsOfSymfony/FOSElasticaBundle/compare/v3.0.4...v3.1.0 * New events `PRE_INDEX_RESET`, `POST_INDEX_RESET`, `PRE_TYPE_RESET` and `POST_TYPE_RESET` are run before and after operations that will reset an index. #744 + * Added indexable callback support for the __invoke method of a service. #823 diff --git a/Index/AliasProcessor.php b/Index/AliasProcessor.php index f4e4d00..d8f608d 100644 --- a/Index/AliasProcessor.php +++ b/Index/AliasProcessor.php @@ -110,7 +110,7 @@ class AliasProcessor * Cleans up an index when we encounter a failure to rename the alias. * * @param Client $client - * @param $indexName + * @param string $indexName * @param \Exception $renameAliasException */ private function cleanupRenameFailure(Client $client, $indexName, \Exception $renameAliasException) diff --git a/Provider/Indexable.php b/Provider/Indexable.php index c72c9b9..6946b54 100644 --- a/Provider/Indexable.php +++ b/Provider/Indexable.php @@ -55,6 +55,7 @@ class Indexable implements IndexableInterface /** * @param array $callbacks + * @param ContainerInterface $container */ public function __construct(array $callbacks, ContainerInterface $container) { @@ -112,39 +113,48 @@ class Indexable implements IndexableInterface return $callback; } - if (is_array($callback)) { - list($class, $method) = $callback + array(null, null); - - if (is_object($class)) { - $class = get_class($class); - } - - if (strpos($class, '@') === 0) { - $service = $this->container->get(substr($class, 1)); - - return array($service, $method); - } - - if ($class && $method) { - throw new \InvalidArgumentException(sprintf('Callback for type "%s", "%s::%s()", is not callable.', $type, $class, $method)); - } + if (is_array($callback) && !is_object($callback[0])) { + return $this->processArrayToCallback($type, $callback); } - if (is_string($callback) && $expression = $this->getExpressionLanguage()) { - $callback = new Expression($callback); - - try { - $expression->compile($callback, array('object', $this->getExpressionVar($object))); - - return $callback; - } catch (SyntaxError $e) { - throw new \InvalidArgumentException(sprintf('Callback for type "%s" is an invalid expression', $type), $e->getCode(), $e); - } + if (is_string($callback)) { + return $this->buildExpressionCallback($type, $object, $callback); } throw new \InvalidArgumentException(sprintf('Callback for type "%s" is not a valid callback.', $type)); } + /** + * Processes a string expression into an Expression. + * + * @param string $type + * @param mixed $object + * @param string $callback + * + * @return Expression + */ + private function buildExpressionCallback($type, $object, $callback) + { + $expression = $this->getExpressionLanguage(); + if (!$expression) { + throw new \RuntimeException('Unable to process an expression without the ExpressionLanguage component.'); + } + + try { + $callback = new Expression($callback); + $expression->compile($callback, array( + 'object', $this->getExpressionVar($object) + )); + + return $callback; + } catch (SyntaxError $e) { + throw new \InvalidArgumentException(sprintf( + 'Callback for type "%s" is an invalid expression', + $type + ), $e->getCode(), $e); + } + } + /** * Retreives a cached callback, or creates a new callback if one is not found. * @@ -163,15 +173,13 @@ class Indexable implements IndexableInterface } /** - * @return bool|ExpressionLanguage + * Returns the ExpressionLanguage class if it is available. + * + * @return ExpressionLanguage|null */ private function getExpressionLanguage() { - if (null === $this->expressionLanguage) { - if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) { - return false; - } - + if (null === $this->expressionLanguage && class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) { $this->expressionLanguage = new ExpressionLanguage(); } @@ -179,14 +187,54 @@ class Indexable implements IndexableInterface } /** + * Returns the variable name to be used to access the object when using the ExpressionLanguage + * component to parse and evaluate an expression. + * * @param mixed $object * * @return string */ private function getExpressionVar($object = null) { + if (!is_object($object)) { + return 'object'; + } + $ref = new \ReflectionClass($object); return strtolower($ref->getShortName()); } + + /** + * Processes an array into a callback. Replaces the first element with a service if + * it begins with an @. + * + * @param string $type + * @param array $callback + * @return array + */ + private function processArrayToCallback($type, array $callback) + { + list($class, $method) = $callback + array(null, '__invoke'); + + if (strpos($class, '@') === 0) { + $service = $this->container->get(substr($class, 1)); + $callback = array($service, $method); + + if (!is_callable($callback)) { + throw new \InvalidArgumentException(sprintf( + 'Method "%s" on service "%s" is not callable.', + $method, + substr($class, 1) + )); + } + + return $callback; + } + + throw new \InvalidArgumentException(sprintf( + 'Unable to parse callback array for type "%s"', + $type + )); + } } diff --git a/Resources/doc/types.md b/Resources/doc/types.md index 2d575cd..0e82c60 100644 --- a/Resources/doc/types.md +++ b/Resources/doc/types.md @@ -201,13 +201,18 @@ index enabled users. The callback option supports multiple approaches: * A method on the object itself provided as a string. `enabled` will call - `Object->enabled()` + `Object->enabled()`. Note that this does not support chaining methods with dot notation + like property paths. To achieve something similar use the ExpressionLanguage option + below. * An array of a service id and a method which will be called with the object as the first and only argument. `[ @my_custom_service, 'userIndexable' ]` will call the userIndexable method on a service defined as my_custom_service. * An array of a class and a static method to call on that class which will be called with the object as the only argument. `[ 'Acme\DemoBundle\IndexableChecker', 'isIndexable' ]` will call Acme\DemoBundle\IndexableChecker::isIndexable($object) +* A single element array with a service id can be used if the service has an __invoke + method. Such an invoke method must accept a single parameter for the object to be indexed. + `[ @my_custom_invokable_service ]` * If you have the ExpressionLanguage component installed, A valid ExpressionLanguage expression provided as a string. The object being indexed will be supplied as `object` in the expression. `object.isEnabled() or object.shouldBeIndexedAnyway()`. For more diff --git a/Tests/Provider/IndexableTest.php b/Tests/Provider/IndexableTest.php index 3080c88..f8a4564 100644 --- a/Tests/Provider/IndexableTest.php +++ b/Tests/Provider/IndexableTest.php @@ -55,6 +55,7 @@ class IndexableTest extends \PHPUnit_Framework_TestCase { return array( array('nonexistentEntityMethod'), + array(array('@indexableService', 'internalMethod')), array(array(new IndexableDecider(), 'internalMethod')), array(42), array('entity.getIsIndexable() && nonexistentEntityFunction()'), @@ -67,6 +68,7 @@ class IndexableTest extends \PHPUnit_Framework_TestCase array('isIndexable', false), array(array(new IndexableDecider(), 'isIndexable'), true), array(array('@indexableService', 'isIndexable'), true), + array(array('@indexableService'), true), array(function (Entity $entity) { return $entity->maybeIndex(); }, true), array('entity.maybeIndex()', true), array('!object.isIndexable() && entity.property == "abc"', true), @@ -111,4 +113,9 @@ class IndexableDecider protected function internalMethod() { } + + public function __invoke($object) + { + return true; + } } From d4f01e8d2e479b660ba5675c7257c78a5e9e8b89 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Sat, 14 Mar 2015 18:47:24 +1100 Subject: [PATCH 430/447] Cast result from ExpressionLanguage eval to bool --- Provider/Indexable.php | 2 +- Tests/Provider/IndexableTest.php | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Provider/Indexable.php b/Provider/Indexable.php index 6946b54..c26da5a 100644 --- a/Provider/Indexable.php +++ b/Provider/Indexable.php @@ -82,7 +82,7 @@ class Indexable implements IndexableInterface } if ($callback instanceof Expression) { - return $this->getExpressionLanguage()->evaluate($callback, array( + return (bool) $this->getExpressionLanguage()->evaluate($callback, array( 'object' => $object, $this->getExpressionVar($object) => $object, )); diff --git a/Tests/Provider/IndexableTest.php b/Tests/Provider/IndexableTest.php index f8a4564..e122ec1 100644 --- a/Tests/Provider/IndexableTest.php +++ b/Tests/Provider/IndexableTest.php @@ -73,6 +73,8 @@ class IndexableTest extends \PHPUnit_Framework_TestCase array('entity.maybeIndex()', true), array('!object.isIndexable() && entity.property == "abc"', true), array('entity.property != "abc"', false), + array('["array", "values"]', true), + array('[]', false) ); } From 3bb2f384babf9f72461ddab6f332c7989376ad81 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Sat, 14 Mar 2015 19:53:05 +1100 Subject: [PATCH 431/447] Provider refactoring --- Doctrine/AbstractProvider.php | 159 +++++++++++------------- Doctrine/MongoDB/Provider.php | 10 +- Doctrine/ORM/Provider.php | 12 +- Doctrine/ORM/SliceFetcher.php | 3 + Propel/Provider.php | 32 +++-- Provider/AbstractProvider.php | 127 +++++++++++++++++-- Tests/Doctrine/AbstractProviderTest.php | 4 +- 7 files changed, 232 insertions(+), 115 deletions(-) diff --git a/Doctrine/AbstractProvider.php b/Doctrine/AbstractProvider.php index 9845edc..f56fe52 100644 --- a/Doctrine/AbstractProvider.php +++ b/Doctrine/AbstractProvider.php @@ -7,6 +7,7 @@ use Elastica\Exception\Bulk\ResponseException as BulkResponseException; use FOS\ElasticaBundle\Persister\ObjectPersisterInterface; use FOS\ElasticaBundle\Provider\AbstractProvider as BaseAbstractProvider; use FOS\ElasticaBundle\Provider\IndexableInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; abstract class AbstractProvider extends BaseAbstractProvider { @@ -26,7 +27,7 @@ abstract class AbstractProvider extends BaseAbstractProvider * @param ObjectPersisterInterface $objectPersister * @param IndexableInterface $indexable * @param string $objectClass - * @param array $options + * @param array $baseOptions * @param ManagerRegistry $managerRegistry * @param SliceFetcherInterface $sliceFetcher */ @@ -34,71 +35,106 @@ abstract class AbstractProvider extends BaseAbstractProvider ObjectPersisterInterface $objectPersister, IndexableInterface $indexable, $objectClass, - array $options, + array $baseOptions, ManagerRegistry $managerRegistry, SliceFetcherInterface $sliceFetcher = null ) { - parent::__construct($objectPersister, $indexable, $objectClass, array_merge(array( - 'clear_object_manager' => true, - 'debug_logging' => false, - 'ignore_errors' => false, - 'query_builder_method' => 'createQueryBuilder', - ), $options)); + parent::__construct($objectPersister, $indexable, $objectClass, $baseOptions); $this->managerRegistry = $managerRegistry; $this->sliceFetcher = $sliceFetcher; } + /** + * Counts objects that would be indexed using the query builder. + * + * @param object $queryBuilder + * + * @return integer + */ + abstract protected function countObjects($queryBuilder); + + /** + * Creates the query builder, which will be used to fetch objects to index. + * + * @param string $method + * + * @return object + */ + abstract protected function createQueryBuilder($method); + + /** + * Fetches a slice of objects using the query builder. + * + * @param object $queryBuilder + * @param integer $limit + * @param integer $offset + * + * @return array + */ + abstract protected function fetchSlice($queryBuilder, $limit, $offset); + /** * {@inheritDoc} */ - public function populate(\Closure $loggerClosure = null, array $options = array()) + protected function doPopulate($options, \Closure $loggerClosure = null) { - if (!$this->options['debug_logging']) { - $logger = $this->disableLogging(); - } - - $queryBuilder = $this->createQueryBuilder(); - $nbObjects = $this->countObjects($queryBuilder); - $offset = isset($options['offset']) ? intval($options['offset']) : 0; - $sleep = isset($options['sleep']) ? intval($options['sleep']) : 0; - $batchSize = isset($options['batch-size']) ? intval($options['batch-size']) : $this->options['batch_size']; - $ignoreErrors = isset($options['ignore-errors']) ? $options['ignore-errors'] : $this->options['ignore_errors']; $manager = $this->managerRegistry->getManagerForClass($this->objectClass); - $objects = array(); - for (; $offset < $nbObjects; $offset += $batchSize) { - $objects = $this->getSlice($queryBuilder, $batchSize, $offset, $objects); - $objects = array_filter($objects, array($this, 'isObjectIndexable')); + $queryBuilder = $this->createQueryBuilder($options['query_builder_method']); + $nbObjects = $this->countObjects($queryBuilder); + $offset = $options['offset']; - if (!empty($objects)) { - if (!$ignoreErrors) { + $objects = array(); + for (; $offset < $nbObjects; $offset += $options['batch_size']) { + try { + $objects = $this->getSlice($queryBuilder, $options['batch_size'], $offset, $objects); + $objects = $this->filterObjects($options, $objects); + + if (!empty($objects)) { $this->objectPersister->insertMany($objects); - } else { - try { - $this->objectPersister->insertMany($objects); - } catch (BulkResponseException $e) { - if ($loggerClosure) { - $loggerClosure($batchSize, $nbObjects, sprintf('%s', $e->getMessage())); - } - } + } + } catch (BulkResponseException $e) { + if (!$options['ignore_errors']) { + throw $e; + } + + if (null !== $loggerClosure) { + $loggerClosure( + $options['batch_size'], + $nbObjects, + sprintf('%s', $e->getMessage()) + ); } } - if ($this->options['clear_object_manager']) { + if ($options['clear_object_manager']) { $manager->clear(); } - usleep($sleep); + usleep($options['sleep']); - if ($loggerClosure) { - $loggerClosure($batchSize, $nbObjects); + if (null !== $loggerClosure) { + $loggerClosure($options['batch_size'], $nbObjects); } } + } - if (!$this->options['debug_logging']) { - $this->enableLogging($logger); - } + /** + * {@inheritDoc} + */ + protected function configureOptions() + { + parent::configureOptions(); + + $this->resolver->setDefaults(array( + 'clear_object_manager' => true, + 'debug_logging' => false, + 'ignore_errors' => false, + 'offset' => 0, + 'query_builder_method' => 'createQueryBuilder', + 'sleep' => 0 + )); } /** @@ -131,47 +167,4 @@ abstract class AbstractProvider extends BaseAbstractProvider $identifierFieldNames ); } - - /** - * Counts objects that would be indexed using the query builder. - * - * @param object $queryBuilder - * - * @return integer - */ - abstract protected function countObjects($queryBuilder); - - /** - * Disables logging and returns the logger that was previously set. - * - * @return mixed - */ - abstract protected function disableLogging(); - - /** - * Reenables the logger with the previously returned logger from disableLogging();. - * - * @param mixed $logger - * - * @return mixed - */ - abstract protected function enableLogging($logger); - - /** - * Fetches a slice of objects using the query builder. - * - * @param object $queryBuilder - * @param integer $limit - * @param integer $offset - * - * @return array - */ - abstract protected function fetchSlice($queryBuilder, $limit, $offset); - - /** - * Creates the query builder, which will be used to fetch objects to index. - * - * @return object - */ - abstract protected function createQueryBuilder(); } diff --git a/Doctrine/MongoDB/Provider.php b/Doctrine/MongoDB/Provider.php index 6b2bd2c..e4b08c5 100644 --- a/Doctrine/MongoDB/Provider.php +++ b/Doctrine/MongoDB/Provider.php @@ -44,7 +44,7 @@ class Provider extends AbstractProvider } /** - * @see FOS\ElasticaBundle\Doctrine\AbstractProvider::countObjects() + * {@inheritDoc} */ protected function countObjects($queryBuilder) { @@ -58,7 +58,7 @@ class Provider extends AbstractProvider } /** - * @see FOS\ElasticaBundle\Doctrine\AbstractProvider::fetchSlice() + * {@inheritDoc} */ protected function fetchSlice($queryBuilder, $limit, $offset) { @@ -75,13 +75,13 @@ class Provider extends AbstractProvider } /** - * @see FOS\ElasticaBundle\Doctrine\AbstractProvider::createQueryBuilder() + * {@inheritDoc} */ - protected function createQueryBuilder() + protected function createQueryBuilder($method) { return $this->managerRegistry ->getManagerForClass($this->objectClass) ->getRepository($this->objectClass) - ->{$this->options['query_builder_method']}(); + ->{$method}(); } } diff --git a/Doctrine/ORM/Provider.php b/Doctrine/ORM/Provider.php index fc59667..303242a 100644 --- a/Doctrine/ORM/Provider.php +++ b/Doctrine/ORM/Provider.php @@ -46,7 +46,7 @@ class Provider extends AbstractProvider } /** - * @see FOS\ElasticaBundle\Doctrine\AbstractProvider::countObjects() + * {@inheritDoc} */ protected function countObjects($queryBuilder) { @@ -69,7 +69,9 @@ class Provider extends AbstractProvider } /** - * @see FOS\ElasticaBundle\Doctrine\AbstractProvider::fetchSlice() + * This method should remain in sync with SliceFetcher::fetch until it is deprecated and removed. + * + * {@inheritDoc} */ protected function fetchSlice($queryBuilder, $limit, $offset) { @@ -103,14 +105,14 @@ class Provider extends AbstractProvider } /** - * @see FOS\ElasticaBundle\Doctrine\AbstractProvider::createQueryBuilder() + * {@inheritDoc} */ - protected function createQueryBuilder() + protected function createQueryBuilder($method) { return $this->managerRegistry ->getManagerForClass($this->objectClass) ->getRepository($this->objectClass) // ORM query builders require an alias argument - ->{$this->options['query_builder_method']}(static::ENTITY_ALIAS); + ->{$method}(static::ENTITY_ALIAS); } } diff --git a/Doctrine/ORM/SliceFetcher.php b/Doctrine/ORM/SliceFetcher.php index 86ad1b4..ac6c816 100644 --- a/Doctrine/ORM/SliceFetcher.php +++ b/Doctrine/ORM/SliceFetcher.php @@ -14,6 +14,9 @@ use FOS\ElasticaBundle\Doctrine\SliceFetcherInterface; class SliceFetcher implements SliceFetcherInterface { /** + * This method should remain in sync with Provider::fetchSlice until that method is deprecated and + * removed. + * * {@inheritdoc} */ public function fetch($queryBuilder, $limit, $offset, array $previousSlice, array $identifierFieldNames) diff --git a/Propel/Provider.php b/Propel/Provider.php index f28faa4..57d7176 100644 --- a/Propel/Provider.php +++ b/Propel/Provider.php @@ -14,31 +14,43 @@ class Provider extends AbstractProvider /** * {@inheritDoc} */ - public function populate(\Closure $loggerClosure = null, array $options = array()) + public function doPopulate($options, \Closure $loggerClosure = null) { $queryClass = $this->objectClass.'Query'; $nbObjects = $queryClass::create()->count(); - $offset = isset($options['offset']) ? intval($options['offset']) : 0; - $sleep = isset($options['sleep']) ? intval($options['sleep']) : 0; - $batchSize = isset($options['batch-size']) ? intval($options['batch-size']) : $this->options['batch_size']; - for (; $offset < $nbObjects; $offset += $batchSize) { + $offset = $options['offset']; + + for (; $offset < $nbObjects; $offset += $options['batch_size']) { $objects = $queryClass::create() - ->limit($batchSize) + ->limit($options['batch_size']) ->offset($offset) ->find() ->getArrayCopy(); - - $objects = array_filter($objects, array($this, 'isObjectIndexable')); + $objects = $this->filterObjects($options, $objects); if (!empty($objects)) { $this->objectPersister->insertMany($objects); } - usleep($sleep); + usleep($options['sleep']); if ($loggerClosure) { - $loggerClosure($batchSize, $nbObjects); + $loggerClosure($options['batch_size'], $nbObjects); } } } + + /** + * {@inheritDoc} + */ + protected function disableLogging() + { + } + + /** + * {@inheritDoc} + */ + protected function enableLogging($logger) + { + } } diff --git a/Provider/AbstractProvider.php b/Provider/AbstractProvider.php index a743d17..87614cd 100644 --- a/Provider/AbstractProvider.php +++ b/Provider/AbstractProvider.php @@ -3,6 +3,7 @@ namespace FOS\ElasticaBundle\Provider; use FOS\ElasticaBundle\Persister\ObjectPersisterInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; /** * AbstractProvider. @@ -10,9 +11,9 @@ use FOS\ElasticaBundle\Persister\ObjectPersisterInterface; abstract class AbstractProvider implements ProviderInterface { /** - * @var ObjectPersisterInterface + * @var array */ - protected $objectPersister; + protected $baseOptions; /** * @var string @@ -20,9 +21,14 @@ abstract class AbstractProvider implements ProviderInterface protected $objectClass; /** - * @var array + * @var ObjectPersisterInterface */ - protected $options; + protected $objectPersister; + + /** + * @var OptionsResolver + */ + protected $resolver; /** * @var IndexableInterface @@ -35,26 +41,114 @@ abstract class AbstractProvider implements ProviderInterface * @param ObjectPersisterInterface $objectPersister * @param IndexableInterface $indexable * @param string $objectClass - * @param array $options + * @param array $baseOptions */ public function __construct( ObjectPersisterInterface $objectPersister, IndexableInterface $indexable, $objectClass, - array $options = array() + array $baseOptions = array() ) { + $this->baseOptions = $baseOptions; $this->indexable = $indexable; $this->objectClass = $objectClass; $this->objectPersister = $objectPersister; + $this->resolver = new OptionsResolver(); + $this->configureOptions(); + } - $this->options = array_merge(array( + /** + * {@inheritDoc} + */ + public function populate(\Closure $loggerClosure = null, array $options = array()) + { + $options = $this->resolveOptions($options); + + $logger = !$options['debug_logging'] ? + $this->disableLogging() : + null; + + $this->doPopulate($options, $loggerClosure); + + if (null !== $logger) { + $this->enableLogging($logger); + } + } + + /** + * Disables logging and returns the logger that was previously set. + * + * @return mixed + */ + abstract protected function disableLogging(); + + /** + * Perform actual population. + * + * @param array $options + * @param \Closure $loggerClosure + */ + abstract protected function doPopulate($options, \Closure $loggerClosure = null); + + /** + * Reenables the logger with the previously returned logger from disableLogging();. + * + * @param mixed $logger + * + * @return mixed + */ + abstract protected function enableLogging($logger); + + /** + * Configures the option resolver. + */ + protected function configureOptions() + { + $this->resolver->setDefaults(array( 'batch_size' => 100, - ), $options); + 'skip_indexable_check' => false, + )); + + $this->resolver->setRequired(array( + 'indexName', + 'typeName', + )); + } + + + /** + * Filters objects away if they are not indexable. + * + * @param array $options + * @param array $objects + * @return array + */ + protected function filterObjects(array $options, array $objects) + { + if ($options['skip_indexable_check']) { + return $objects; + } + + $index = $options['indexName']; + $type = $options['typeName']; + + $return = array(); + foreach ($objects as $object) { + if (!$this->indexable->isObjectIndexable($index, $type, $object)) { + continue; + } + + $return[] = $object; + } + + return $return; } /** * Checks if a given object should be indexed or not. * + * @deprecated To be removed in 4.0 + * * @param object $object * * @return bool @@ -62,8 +156,8 @@ abstract class AbstractProvider implements ProviderInterface protected function isObjectIndexable($object) { return $this->indexable->isObjectIndexable( - $this->options['indexName'], - $this->options['typeName'], + $this->baseOptions['indexName'], + $this->baseOptions['typeName'], $object ); } @@ -82,4 +176,17 @@ abstract class AbstractProvider implements ProviderInterface return sprintf('(RAM : current=%uMo peak=%uMo)', $memory, $memoryMax); } + + /** + * Merges the base options provided by the class with options passed to the populate + * method and runs them through the resolver. + * + * @param array $options + * + * @return array + */ + protected function resolveOptions(array $options) + { + return $this->resolver->resolve(array_merge($this->baseOptions, $options)); + } } diff --git a/Tests/Doctrine/AbstractProviderTest.php b/Tests/Doctrine/AbstractProviderTest.php index 7b41837..aa28a4c 100644 --- a/Tests/Doctrine/AbstractProviderTest.php +++ b/Tests/Doctrine/AbstractProviderTest.php @@ -252,7 +252,7 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase $this->setExpectedException('Elastica\Exception\Bulk\ResponseException'); - $provider->populate(null, array('ignore-errors' => false)); + $provider->populate(null, array('ignore_errors' => false)); } public function testPopulateRunsIndexCallable() @@ -280,7 +280,7 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase $this->objectPersister->expects($this->once()) ->method('insertMany') - ->with(array(1 => 2)); + ->with(array(2)); $provider->populate(); } From 9c1c771799f030c8ae15b597714d36d697056c22 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Sat, 14 Mar 2015 19:54:01 +1100 Subject: [PATCH 432/447] Mark getSlice private --- Doctrine/AbstractProvider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doctrine/AbstractProvider.php b/Doctrine/AbstractProvider.php index f56fe52..ec198a8 100644 --- a/Doctrine/AbstractProvider.php +++ b/Doctrine/AbstractProvider.php @@ -148,7 +148,7 @@ abstract class AbstractProvider extends BaseAbstractProvider * * @return array */ - protected function getSlice($queryBuilder, $limit, $offset, $lastSlice) + private function getSlice($queryBuilder, $limit, $offset, $lastSlice) { if (!$this->sliceFetcher) { return $this->fetchSlice($queryBuilder, $limit, $offset); From ac98549eb563058a6367294d2a52d4e6edc9936a Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Sat, 14 Mar 2015 19:54:23 +1100 Subject: [PATCH 433/447] Fix translation of option keys for the Provider --- Command/PopulateCommand.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Command/PopulateCommand.php b/Command/PopulateCommand.php index e3d2918..08b501a 100644 --- a/Command/PopulateCommand.php +++ b/Command/PopulateCommand.php @@ -90,8 +90,12 @@ class PopulateCommand extends ContainerAwareCommand $index = $input->getOption('index'); $type = $input->getOption('type'); $reset = !$input->getOption('no-reset'); - $options = $input->getOptions(); - $options['ignore-errors'] = $input->getOption('ignore-errors'); + $options = array( + 'batch_size' => $input->getOption('batch-size'), + 'ignore_errors' => $input->getOption('ignore-errors'), + 'offset' => $input->getOption('offset'), + 'sleep' => $input->getOption('sleep') + ); if ($input->isInteractive() && $reset && $input->getOption('offset')) { /** @var DialogHelper $dialog */ From 5181b0293379d83a02ef593da40cd77bbe73dae9 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Sat, 14 Mar 2015 22:14:24 +1100 Subject: [PATCH 434/447] Resetter tests --- Index/Resetter.php | 12 +- Tests/Index/ResetterTest.php | 371 +++++++++++++++++++---------------- 2 files changed, 206 insertions(+), 177 deletions(-) diff --git a/Index/Resetter.php b/Index/Resetter.php index e144a62..2b39157 100644 --- a/Index/Resetter.php +++ b/Index/Resetter.php @@ -86,12 +86,12 @@ class Resetter */ public function resetIndex($indexName, $populating = false, $force = false) { - $event = new IndexResetEvent($indexName, $populating, $force); - $this->dispatcher->dispatch(IndexResetEvent::PRE_INDEX_RESET, $event); - $indexConfig = $this->configManager->getIndexConfiguration($indexName); $index = $this->indexManager->getIndex($indexName); + $event = new IndexResetEvent($indexName, $populating, $force); + $this->dispatcher->dispatch(IndexResetEvent::PRE_INDEX_RESET, $event); + if ($indexConfig->isUseAlias()) { $this->aliasProcessor->setRootName($indexConfig, $index); } @@ -117,12 +117,12 @@ class Resetter */ public function resetIndexType($indexName, $typeName) { - $event = new TypeResetEvent($indexName, $typeName); - $this->dispatcher->dispatch(TypeResetEvent::PRE_TYPE_RESET, $event); - $typeConfig = $this->configManager->getTypeConfiguration($indexName, $typeName); $type = $this->indexManager->getIndex($indexName)->getType($typeName); + $event = new TypeResetEvent($indexName, $typeName); + $this->dispatcher->dispatch(TypeResetEvent::PRE_TYPE_RESET, $event); + try { $type->delete(); } catch (ResponseException $e) { diff --git a/Tests/Index/ResetterTest.php b/Tests/Index/ResetterTest.php index 35a0bd9..9b4cd05 100644 --- a/Tests/Index/ResetterTest.php +++ b/Tests/Index/ResetterTest.php @@ -5,8 +5,14 @@ namespace FOS\ElasticaBundle\Tests\Index; use Elastica\Exception\ResponseException; use Elastica\Request; use Elastica\Response; +use Elastica\Type; use Elastica\Type\Mapping; use FOS\ElasticaBundle\Configuration\IndexConfig; +use FOS\ElasticaBundle\Configuration\TypeConfig; +use FOS\ElasticaBundle\Elastica\Index; +use FOS\ElasticaBundle\Event\IndexResetEvent; +use FOS\ElasticaBundle\Event\TypeResetEvent; +use FOS\ElasticaBundle\Index\AliasProcessor; use FOS\ElasticaBundle\Index\Resetter; class ResetterTest extends \PHPUnit_Framework_TestCase @@ -16,230 +22,253 @@ class ResetterTest extends \PHPUnit_Framework_TestCase */ private $resetter; - private $configManager; - private $indexManager; private $aliasProcessor; + private $configManager; + private $dispatcher; + private $elasticaClient; + private $indexManager; private $mappingBuilder; - public function setUp() - { - $this->markTestIncomplete('To be rewritten'); - $this->configManager = $this->getMockBuilder('FOS\\ElasticaBundle\\Configuration\\ConfigManager') - ->disableOriginalConstructor() - ->getMock(); - $this->indexManager = $this->getMockBuilder('FOS\\ElasticaBundle\\Index\\IndexManager') - ->disableOriginalConstructor() - ->getMock(); - $this->aliasProcessor = $this->getMockBuilder('FOS\\ElasticaBundle\\Index\\AliasProcessor') - ->disableOriginalConstructor() - ->getMock(); - $this->mappingBuilder = $this->getMockBuilder('FOS\\ElasticaBundle\\Index\\MappingBuilder') - ->disableOriginalConstructor() - ->getMock(); - $this->resetter = $this->getMockBuilder('FOS\ElasticaBundle\Index\Resetter') - ->disableOriginalConstructor() - ->getMock(); - - $this->resetter = new Resetter($this->configManager, $this->indexManager, $this->aliasProcessor, $this->mappingBuilder, $this->resetter); - - /*$this->indexConfigsByName = array( - 'foo' => array( - 'index' => $this->getMockElasticaIndex(), - 'config' => array( - 'properties' => array( - 'a' => array( - 'dynamic_templates' => array(), - 'properties' => array(), - ), - 'b' => array('properties' => array()), - ), - ), - ), - 'bar' => array( - 'index' => $this->getMockElasticaIndex(), - 'config' => array( - 'properties' => array( - 'a' => array('properties' => array()), - 'b' => array('properties' => array()), - ), - ), - ), - 'parent' => array( - 'index' => $this->getMockElasticaIndex(), - 'config' => array( - 'properties' => array( - 'a' => array( - 'properties' => array( - 'field_2' => array() - ), - '_parent' => array( - 'type' => 'b', - 'property' => 'b', - 'identifier' => 'id' - ), - ), - 'b' => array('properties' => array()), - ), - ), - ), - );*/ - } - public function testResetAllIndexes() { + $indexName = 'index1'; + $indexConfig = new IndexConfig($indexName, array(), array()); + $this->mockIndex($indexName, $indexConfig); + $this->configManager->expects($this->once()) ->method('getIndexNames') - ->will($this->returnValue(array('index1'))); + ->will($this->returnValue(array($indexName))); - $this->configManager->expects($this->once()) - ->method('getIndexConfiguration') - ->with('index1') - ->will($this->returnValue(new IndexConfig('index1', array(), array()))); + $this->dispatcherExpects(array( + array(IndexResetEvent::PRE_INDEX_RESET, $this->isInstanceOf('FOS\\ElasticaBundle\\Event\\IndexResetEvent')), + array(IndexResetEvent::POST_INDEX_RESET, $this->isInstanceOf('FOS\\ElasticaBundle\\Event\\IndexResetEvent')) + )); - $this->indexManager->expects($this->once()) - ->method('getIndex') - ->with('index1') - ->will($this->returnValue()); + $this->elasticaClient->expects($this->exactly(2)) + ->method('request') + ->withConsecutive( + array('index1/', 'DELETE'), + array('index1/', 'PUT', array(), array()) + ); - /*$this->indexConfigsByName['foo']['index']->expects($this->once()) - ->method('create') - ->with($this->indexConfigsByName['foo']['config'], true); - - $this->indexConfigsByName['bar']['index']->expects($this->once()) - ->method('create') - ->with($this->indexConfigsByName['bar']['config'], true); - - $resetter = new Resetter($this->indexConfigsByName);*/ $this->resetter->resetAllIndexes(); } public function testResetIndex() { - $this->indexConfigsByName['foo']['index']->expects($this->once()) - ->method('create') - ->with($this->indexConfigsByName['foo']['config'], true); + $indexConfig = new IndexConfig('index1', array(), array()); + $this->mockIndex('index1', $indexConfig); - $this->indexConfigsByName['bar']['index']->expects($this->never()) - ->method('create'); + $this->dispatcherExpects(array( + array(IndexResetEvent::PRE_INDEX_RESET, $this->isInstanceOf('FOS\\ElasticaBundle\\Event\\IndexResetEvent')), + array(IndexResetEvent::POST_INDEX_RESET, $this->isInstanceOf('FOS\\ElasticaBundle\\Event\\IndexResetEvent')) + )); - $resetter = new Resetter($this->indexConfigsByName); - $resetter->resetIndex('foo'); + $this->elasticaClient->expects($this->exactly(2)) + ->method('request') + ->withConsecutive( + array('index1/', 'DELETE'), + array('index1/', 'PUT', array(), array()) + ); + + $this->resetter->resetIndex('index1'); + } + + public function testResetIndexWithDifferentName() + { + $indexConfig = new IndexConfig('index1', array(), array( + 'elasticSearchName' => 'notIndex1' + )); + $this->mockIndex('index1', $indexConfig); + $this->dispatcherExpects(array( + array(IndexResetEvent::PRE_INDEX_RESET, $this->isInstanceOf('FOS\\ElasticaBundle\\Event\\IndexResetEvent')), + array(IndexResetEvent::POST_INDEX_RESET, $this->isInstanceOf('FOS\\ElasticaBundle\\Event\\IndexResetEvent')) + )); + + $this->elasticaClient->expects($this->exactly(2)) + ->method('request') + ->withConsecutive( + array('index1/', 'DELETE'), + array('index1/', 'PUT', array(), array()) + ); + + $this->resetter->resetIndex('index1'); + } + + public function testResetIndexWithDifferentNameAndAlias() + { + $indexConfig = new IndexConfig('index1', array(), array( + 'elasticSearchName' => 'notIndex1', + 'useAlias' => true + )); + $index = $this->mockIndex('index1', $indexConfig); + $this->dispatcherExpects(array( + array(IndexResetEvent::PRE_INDEX_RESET, $this->isInstanceOf('FOS\\ElasticaBundle\\Event\\IndexResetEvent')), + array(IndexResetEvent::POST_INDEX_RESET, $this->isInstanceOf('FOS\\ElasticaBundle\\Event\\IndexResetEvent')) + )); + + $this->aliasProcessor->expects($this->once()) + ->method('switchIndexAlias') + ->with($indexConfig, $index, false); + + $this->elasticaClient->expects($this->exactly(2)) + ->method('request') + ->withConsecutive( + array('index1/', 'DELETE'), + array('index1/', 'PUT', array(), array()) + ); + + $this->resetter->resetIndex('index1'); } /** * @expectedException \InvalidArgumentException */ - public function testResetIndexShouldThrowExceptionForInvalidIndex() + public function testFailureWhenMissingIndexDoesntDispatch() { - $resetter = new Resetter($this->indexConfigsByName); - $resetter->resetIndex('baz'); + $this->configManager->expects($this->once()) + ->method('getIndexConfiguration') + ->with('nonExistant') + ->will($this->throwException(new \InvalidArgumentException)); + + $this->indexManager->expects($this->never()) + ->method('getIndex'); + + $this->resetter->resetIndex('nonExistant'); } - public function testResetIndexType() + public function testResetType() { - $type = $this->getMockElasticaType(); + $typeConfig = new TypeConfig('type', array(), array()); + $this->mockType('type', 'index', $typeConfig); - $this->indexConfigsByName['foo']['index']->expects($this->once()) - ->method('getType') - ->with('a') - ->will($this->returnValue($type)); + $this->dispatcherExpects(array( + array(TypeResetEvent::PRE_TYPE_RESET, $this->isInstanceOf('FOS\\ElasticaBundle\\Event\\TypeResetEvent')), + array(TypeResetEvent::POST_TYPE_RESET, $this->isInstanceOf('FOS\\ElasticaBundle\\Event\\TypeResetEvent')) + )); - $type->expects($this->once()) - ->method('delete'); + $this->elasticaClient->expects($this->exactly(2)) + ->method('request') + ->withConsecutive( + array('index/type/', 'DELETE'), + array('index/type/_mapping', 'PUT', array('type' => array()), array()) + ); - $mapping = Mapping::create($this->indexConfigsByName['foo']['config']['properties']['a']['properties']); - $mapping->setParam('dynamic_templates', $this->indexConfigsByName['foo']['config']['properties']['a']['dynamic_templates']); - $type->expects($this->once()) - ->method('setMapping') - ->with($mapping); - - $resetter = new Resetter($this->indexConfigsByName); - $resetter->resetIndexType('foo', 'a'); + $this->resetter->resetIndexType('index', 'type'); } /** * @expectedException \InvalidArgumentException */ - public function testResetIndexTypeShouldThrowExceptionForInvalidIndex() + public function testNonExistantResetType() { - $resetter = new Resetter($this->indexConfigsByName); - $resetter->resetIndexType('baz', 'a'); + $this->configManager->expects($this->once()) + ->method('getTypeConfiguration') + ->with('index', 'nonExistant') + ->will($this->throwException(new \InvalidArgumentException)); + + $this->indexManager->expects($this->never()) + ->method('getIndex'); + + $this->resetter->resetIndexType('index', 'nonExistant'); } - /** - * @expectedException \InvalidArgumentException - */ - public function testResetIndexTypeShouldThrowExceptionForInvalidType() + public function testPostPopulateWithoutAlias() { - $resetter = new Resetter($this->indexConfigsByName); - $resetter->resetIndexType('foo', 'c'); + $this->mockIndex('index', new IndexConfig('index', array(), array())); + + $this->indexManager->expects($this->never()) + ->method('getIndex'); + $this->aliasProcessor->expects($this->never()) + ->method('switchIndexAlias'); + + $this->resetter->postPopulate('index'); } - public function testResetIndexTypeIgnoreTypeMissingException() + public function testPostPopulate() { - $type = $this->getMockElasticaType(); + $indexConfig = new IndexConfig('index', array(), array( 'useAlias' => true)); + $index = $this->mockIndex('index', $indexConfig); - $this->indexConfigsByName['foo']['index']->expects($this->once()) - ->method('getType') - ->with('a') - ->will($this->returnValue($type)); + $this->aliasProcessor->expects($this->once()) + ->method('switchIndexAlias') + ->with($indexConfig, $index); - $type->expects($this->once()) - ->method('delete') - ->will($this->throwException(new ResponseException( - new Request(''), - new Response(array('error' => 'TypeMissingException[[de_20131022] type[bla] missing]', 'status' => 404))) - )); - - $mapping = Mapping::create($this->indexConfigsByName['foo']['config']['properties']['a']['properties']); - $mapping->setParam('dynamic_templates', $this->indexConfigsByName['foo']['config']['properties']['a']['dynamic_templates']); - $type->expects($this->once()) - ->method('setMapping') - ->with($mapping); - - $resetter = new Resetter($this->indexConfigsByName); - $resetter->resetIndexType('foo', 'a'); + $this->resetter->postPopulate('index'); } - public function testIndexMappingForParent() + private function dispatcherExpects(array $events) { - $type = $this->getMockElasticaType(); + $expectation = $this->dispatcher->expects($this->exactly(count($events))) + ->method('dispatch'); - $this->indexConfigsByName['parent']['index']->expects($this->once()) - ->method('getType') - ->with('a') - ->will($this->returnValue($type)); - - $type->expects($this->once()) - ->method('delete'); - - $mapping = Mapping::create($this->indexConfigsByName['parent']['config']['properties']['a']['properties']); - $mapping->setParam('_parent', array('type' => 'b')); - $type->expects($this->once()) - ->method('setMapping') - ->with($mapping); - - $resetter = new Resetter($this->indexConfigsByName); - $resetter->resetIndexType('parent', 'a'); + call_user_func_array(array($expectation, 'withConsecutive'), $events); } - /** - * @return \Elastica\Index - */ - private function getMockElasticaIndex() + private function mockIndex($indexName, IndexConfig $config, $mapping = array()) { - return $this->getMockBuilder('Elastica\Index') + $this->configManager->expects($this->atLeast(1)) + ->method('getIndexConfiguration') + ->with($indexName) + ->will($this->returnValue($config)); + $index = new Index($this->elasticaClient, $indexName); + $this->indexManager->expects($this->any()) + ->method('getIndex') + ->with($indexName) + ->willReturn($index); + $this->mappingBuilder->expects($this->any()) + ->method('buildIndexMapping') + ->with($config) + ->willReturn($mapping); + + return $index; + } + + private function mockType($typeName, $indexName, TypeConfig $config, $mapping = array()) + { + $this->configManager->expects($this->atLeast(1)) + ->method('getTypeConfiguration') + ->with($indexName, $typeName) + ->will($this->returnValue($config)); + $index = new Index($this->elasticaClient, $indexName); + $this->indexManager->expects($this->once()) + ->method('getIndex') + ->with($indexName) + ->willReturn($index); + $this->mappingBuilder->expects($this->once()) + ->method('buildTypeMapping') + ->with($config) + ->willReturn($mapping); + + return $index; + } + + protected function setUp() + { + $this->aliasProcessor = $this->getMockBuilder('FOS\\ElasticaBundle\\Index\\AliasProcessor') ->disableOriginalConstructor() ->getMock(); - } - - /** - * @return \Elastica\Type - */ - private function getMockElasticaType() - { - return $this->getMockBuilder('Elastica\Type') + $this->configManager = $this->getMockBuilder('FOS\\ElasticaBundle\\Configuration\\ConfigManager') ->disableOriginalConstructor() ->getMock(); + $this->dispatcher = $this->getMockBuilder('Symfony\\Component\\EventDispatcher\\EventDispatcherInterface') + ->getMock(); + $this->elasticaClient = $this->getMockBuilder('Elastica\\Client') + ->disableOriginalConstructor() + ->getMock(); + $this->indexManager = $this->getMockBuilder('FOS\\ElasticaBundle\\Index\\IndexManager') + ->disableOriginalConstructor() + ->getMock(); + $this->mappingBuilder = $this->getMockBuilder('FOS\\ElasticaBundle\\Index\\MappingBuilder') + ->disableOriginalConstructor() + ->getMock(); + + $this->resetter = new Resetter( + $this->configManager, + $this->indexManager, + $this->aliasProcessor, + $this->mappingBuilder, + $this->dispatcher + ); } } From 447d29ab9c37c3ce913a0692fa0cd4c271aa5cd3 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Wed, 18 Mar 2015 09:38:47 +1100 Subject: [PATCH 435/447] Release 3.1.0 --- CHANGELOG-3.1.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG-3.1.md b/CHANGELOG-3.1.md index 10d7887..aa431e3 100644 --- a/CHANGELOG-3.1.md +++ b/CHANGELOG-3.1.md @@ -9,7 +9,7 @@ https://github.com/FriendsOfSymfony/FOSElasticaBundle/commit/XXX where XXX is the commit hash. To get the diff between two versions, go to https://github.com/FriendsOfSymfony/FOSElasticaBundle/compare/v3.0.4...v3.1.0 -* 3.1.0 (Unreleased) +* 3.1.0 (2015-03-18) * BC BREAK: `Doctrine\Listener#scheduleForDeletion` access changed to private. * BC BREAK: `ObjectPersisterInterface` gains the method `handlesObject` that From 8d8b04ead8729f1facf716ecb839d9dcfed46c9c Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Mon, 23 Mar 2015 21:39:13 +1100 Subject: [PATCH 436/447] Fixes populate command error --- Command/PopulateCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Command/PopulateCommand.php b/Command/PopulateCommand.php index 08b501a..adeeaad 100644 --- a/Command/PopulateCommand.php +++ b/Command/PopulateCommand.php @@ -74,7 +74,7 @@ class PopulateCommand extends ContainerAwareCommand $this->resetter = $this->getContainer()->get('fos_elastica.resetter'); $this->progressClosureBuilder = new ProgressClosureBuilder(); - if (!$input->getOption('no-overwrite-format')) { + if (!$input->getOption('no-overwrite-format') && class_exists('Symfony\\Component\\Console\\Helper\\ProgressBar')) { ProgressBar::setFormatDefinition('normal', " %current%/%max% [%bar%] %percent:3s%%\n%message%"); ProgressBar::setFormatDefinition('verbose', " %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%\n%message%"); ProgressBar::setFormatDefinition('very_verbose', " %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s%\n%message%"); From 49a0c22724a08f56bea1202aaca40a0e4aac8b5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Votruba?= Date: Thu, 26 Mar 2015 15:03:20 +0100 Subject: [PATCH 437/447] Setup.md - composer picks last stable version --- Resources/doc/setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/doc/setup.md b/Resources/doc/setup.md index ea3f769..fa98f67 100644 --- a/Resources/doc/setup.md +++ b/Resources/doc/setup.md @@ -8,7 +8,7 @@ Open a command console, enter your project directory and execute the following command to download the latest stable version of this bundle: ```bash -$ composer require friendsofsymfony/elastica-bundle "~3.0" +$ composer require friendsofsymfony/elastica-bundle ``` This command requires you to have Composer installed globally, as explained From ae4cfd7e048b90ea2fe7194d8d7bc93147c0cbdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Votruba?= Date: Thu, 26 Mar 2015 15:05:28 +0100 Subject: [PATCH 438/447] Setup.md: fix link to Elasticsearch installation --- Resources/doc/setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/doc/setup.md b/Resources/doc/setup.md index ea3f769..4cd98c2 100644 --- a/Resources/doc/setup.md +++ b/Resources/doc/setup.md @@ -17,7 +17,7 @@ of the Composer documentation. ### Elasticsearch -Instructions for installing and deploying Elasticsearch may be found [here](http://www.elasticsearch.org/guide/reference/setup/installation/). +Instructions for installing and deploying Elasticsearch may be found [here](https://www.elastic.co/downloads/elasticsearch). Step 2: Enable the Bundle ------------------------- From b6e01cd332ffa29ab354c9d882b5686f698c1d06 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Fri, 27 Mar 2015 11:45:03 +1100 Subject: [PATCH 439/447] Fix issues with Provider's batch_size and PopulateCommand's batch_size --- CHANGELOG-3.1.md | 6 ++++++ Command/PopulateCommand.php | 4 +++- Provider/AbstractProvider.php | 2 ++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-3.1.md b/CHANGELOG-3.1.md index aa431e3..63da912 100644 --- a/CHANGELOG-3.1.md +++ b/CHANGELOG-3.1.md @@ -9,6 +9,12 @@ https://github.com/FriendsOfSymfony/FOSElasticaBundle/commit/XXX where XXX is the commit hash. To get the diff between two versions, go to https://github.com/FriendsOfSymfony/FOSElasticaBundle/compare/v3.0.4...v3.1.0 +* 3.1.1 (2015-03-27) + + * Fix PopulateCommand trying to set formats for ProgressBar in Symfony < 2.5 + * Fix Provider implementations that depend on a batch size from going into + infinite loops + * 3.1.0 (2015-03-18) * BC BREAK: `Doctrine\Listener#scheduleForDeletion` access changed to private. diff --git a/Command/PopulateCommand.php b/Command/PopulateCommand.php index adeeaad..42af355 100644 --- a/Command/PopulateCommand.php +++ b/Command/PopulateCommand.php @@ -91,11 +91,13 @@ class PopulateCommand extends ContainerAwareCommand $type = $input->getOption('type'); $reset = !$input->getOption('no-reset'); $options = array( - 'batch_size' => $input->getOption('batch-size'), 'ignore_errors' => $input->getOption('ignore-errors'), 'offset' => $input->getOption('offset'), 'sleep' => $input->getOption('sleep') ); + if ($input->getOption('batch-size')) { + $options['batch_size'] = (int) $input->getOption('batch-size'); + } if ($input->isInteractive() && $reset && $input->getOption('offset')) { /** @var DialogHelper $dialog */ diff --git a/Provider/AbstractProvider.php b/Provider/AbstractProvider.php index 87614cd..af000f0 100644 --- a/Provider/AbstractProvider.php +++ b/Provider/AbstractProvider.php @@ -104,6 +104,8 @@ abstract class AbstractProvider implements ProviderInterface */ protected function configureOptions() { + $this->resolver->setAllowedTypes('batch_size', 'int'); + $this->resolver->setDefaults(array( 'batch_size' => 100, 'skip_indexable_check' => false, From 69470d7e20181f016d5fb40ed139a12800f888c1 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Fri, 27 Mar 2015 12:01:39 +1100 Subject: [PATCH 440/447] Fix the previous release. --- CHANGELOG-3.1.md | 4 ++++ Provider/AbstractProvider.php | 3 +-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG-3.1.md b/CHANGELOG-3.1.md index 63da912..1a23ece 100644 --- a/CHANGELOG-3.1.md +++ b/CHANGELOG-3.1.md @@ -9,6 +9,10 @@ https://github.com/FriendsOfSymfony/FOSElasticaBundle/commit/XXX where XXX is the commit hash. To get the diff between two versions, go to https://github.com/FriendsOfSymfony/FOSElasticaBundle/compare/v3.0.4...v3.1.0 +* 3.1.2 (2015-03-27) + + * Fix the previous release + * 3.1.1 (2015-03-27) * Fix PopulateCommand trying to set formats for ProgressBar in Symfony < 2.5 diff --git a/Provider/AbstractProvider.php b/Provider/AbstractProvider.php index af000f0..cf38432 100644 --- a/Provider/AbstractProvider.php +++ b/Provider/AbstractProvider.php @@ -104,12 +104,11 @@ abstract class AbstractProvider implements ProviderInterface */ protected function configureOptions() { - $this->resolver->setAllowedTypes('batch_size', 'int'); - $this->resolver->setDefaults(array( 'batch_size' => 100, 'skip_indexable_check' => false, )); + $this->resolver->setAllowedTypes('batch_size', 'int'); $this->resolver->setRequired(array( 'indexName', From e933a49d0741a454fae57f6f2e3779f7a4d0aeae Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 2 Apr 2015 10:23:30 +1100 Subject: [PATCH 441/447] Use deprecated optionsResolver interface --- Provider/AbstractProvider.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Provider/AbstractProvider.php b/Provider/AbstractProvider.php index cf38432..f05ab98 100644 --- a/Provider/AbstractProvider.php +++ b/Provider/AbstractProvider.php @@ -108,7 +108,9 @@ abstract class AbstractProvider implements ProviderInterface 'batch_size' => 100, 'skip_indexable_check' => false, )); - $this->resolver->setAllowedTypes('batch_size', 'int'); + $this->resolver->setAllowedTypes(array( + 'batch_size' => 'int' + )); $this->resolver->setRequired(array( 'indexName', From 7baf494c565fe22e3030be80fd7f39e3dc10c953 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 2 Apr 2015 10:34:08 +1100 Subject: [PATCH 442/447] release 3.1.3 --- CHANGELOG-3.1.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG-3.1.md b/CHANGELOG-3.1.md index 1a23ece..3ca3c77 100644 --- a/CHANGELOG-3.1.md +++ b/CHANGELOG-3.1.md @@ -9,6 +9,10 @@ https://github.com/FriendsOfSymfony/FOSElasticaBundle/commit/XXX where XXX is the commit hash. To get the diff between two versions, go to https://github.com/FriendsOfSymfony/FOSElasticaBundle/compare/v3.0.4...v3.1.0 +* 3.1.3 (2015-04-02) + + * Fix Symfony 2.3 compatibility + * 3.1.2 (2015-03-27) * Fix the previous release From 1287d9f0df854d564b6041ab3c1b943b8bd8b4f6 Mon Sep 17 00:00:00 2001 From: Thierry Marianne Date: Sun, 5 Apr 2015 22:07:41 +0200 Subject: [PATCH 443/447] Fix typo --- Doctrine/ORM/Provider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doctrine/ORM/Provider.php b/Doctrine/ORM/Provider.php index 303242a..85b5279 100644 --- a/Doctrine/ORM/Provider.php +++ b/Doctrine/ORM/Provider.php @@ -80,7 +80,7 @@ class Provider extends AbstractProvider } /* - * An orderBy DQL part is required to avoid feching the same row twice. + * An orderBy DQL part is required to avoid fetching the same row twice. * @see http://stackoverflow.com/questions/6314879/does-limit-offset-length-require-order-by-for-pagination * @see http://www.postgresql.org/docs/current/static/queries-limit.html * @see http://www.sqlite.org/lang_select.html#orderby From e71ec4ac8ab1b135494e85b691f53af8a4af075e Mon Sep 17 00:00:00 2001 From: Ka Yue Yeung Date: Sat, 18 Apr 2015 00:42:02 +0800 Subject: [PATCH 444/447] Count the number of results for the query directly --- Paginator/RawPaginatorAdapter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Paginator/RawPaginatorAdapter.php b/Paginator/RawPaginatorAdapter.php index c270f00..2eebde0 100644 --- a/Paginator/RawPaginatorAdapter.php +++ b/Paginator/RawPaginatorAdapter.php @@ -121,7 +121,7 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface public function getTotalHits($genuineTotal = false) { if (! isset($this->totalHits)) { - $this->totalHits = $this->searchable->search($this->query)->getTotalHits(); + $this->totalHits = $this->searchable->count($this->query); } return $this->query->hasParam('size') && !$genuineTotal From 8f7f24e6d3ea5e8de8cbac46a9e9df94b8c3e747 Mon Sep 17 00:00:00 2001 From: David Fuhr Date: Mon, 27 Apr 2015 23:00:50 +0200 Subject: [PATCH 445/447] Fixed parameter nam to kernel.environment The parameter %kernel.env% does not exist. It throws the error message 'You have requested a non-existent parameter "kernel.env". Did you mean this: "kernel.environment"?' --- Resources/doc/setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/doc/setup.md b/Resources/doc/setup.md index b2a6886..2692bb6 100644 --- a/Resources/doc/setup.md +++ b/Resources/doc/setup.md @@ -74,7 +74,7 @@ Symfony application, use the example below: fos_elastica: indexes: app: - index_name: app_%kernel.env% + index_name: app_%kernel.environment% ``` In this case, the service `fos_elastica.index.app` will relate to an ElasticSearch index From e3abbdc700ea7b8db1e1b61e735d0553d1693cdf Mon Sep 17 00:00:00 2001 From: Simon Vieille Date: Wed, 20 May 2015 11:12:03 +0200 Subject: [PATCH 446/447] Propel provider: default options --- Propel/Provider.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Propel/Provider.php b/Propel/Provider.php index 57d7176..f77a702 100644 --- a/Propel/Provider.php +++ b/Propel/Provider.php @@ -40,6 +40,23 @@ class Provider extends AbstractProvider } } + /** + * {@inheritDoc} + */ + protected function configureOptions() + { + parent::configureOptions(); + + $this->resolver->setDefaults(array( + 'clear_object_manager' => true, + 'debug_logging' => false, + 'ignore_errors' => false, + 'offset' => 0, + 'query_builder_method' => 'createQueryBuilder', + 'sleep' => 0 + )); + } + /** * {@inheritDoc} */ From 30e351b1d590d3100e77d91f71cf88865e8f50b7 Mon Sep 17 00:00:00 2001 From: Simon Vieille Date: Wed, 20 May 2015 11:13:43 +0200 Subject: [PATCH 447/447] Propel provider: query_builder_method set to null --- Propel/Provider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Propel/Provider.php b/Propel/Provider.php index f77a702..9864d53 100644 --- a/Propel/Provider.php +++ b/Propel/Provider.php @@ -52,7 +52,7 @@ class Provider extends AbstractProvider 'debug_logging' => false, 'ignore_errors' => false, 'offset' => 0, - 'query_builder_method' => 'createQueryBuilder', + 'query_builder_method' => null, 'sleep' => 0 )); }