From f15ca028596a9226fcff636138533a1a39f39ce5 Mon Sep 17 00:00:00 2001 From: Joseph Bielawski Date: Mon, 31 Mar 2014 11:59:37 +0200 Subject: [PATCH 001/234] 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 2bd6aba7ef0a722e690a550c21445d2faf81f09f Mon Sep 17 00:00:00 2001 From: ben Date: Fri, 18 Apr 2014 13:57:08 +0200 Subject: [PATCH 002/234] 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 c9fd1cc5d99ba7d46050802b5dc9a78b44eb6dbc Mon Sep 17 00:00:00 2001 From: Ahmed Mohamed Date: Sun, 20 Apr 2014 06:11:20 +0200 Subject: [PATCH 003/234] 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 4c961a757d8b9cca38e1312f196f0a766192fb88 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Mon, 21 Apr 2014 09:21:50 +1000 Subject: [PATCH 004/234] Deprecate top level classes --- CHANGELOG-3.0.md | 14 +- Client.php | 38 +-- DynamicIndex.php | 22 +- Elastica/LoggingClient.php | 47 ++++ Elastica/TransformingIndex.php | 45 ++++ Index/IndexManager.php | 63 +++++ Index/Resetter.php | 246 ++++++++++++++++++ IndexManager.php | 61 +---- Resetter.php | 238 +---------------- Resources/config/config.xml | 4 +- .../LoggingClientTest.php} | 6 +- Tests/{ => Index}/IndexManagerTest.php | 4 +- Tests/{ => Index}/ResetterTest.php | 4 +- 13 files changed, 436 insertions(+), 356 deletions(-) create mode 100644 Elastica/LoggingClient.php create mode 100644 Elastica/TransformingIndex.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 abd05cd..e57fb4d 100644 --- a/CHANGELOG-3.0.md +++ b/CHANGELOG-3.0.md @@ -12,7 +12,19 @@ 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 + + * Deprecated FOS\ElasticaBundle\Client in favour of FOS\ElasticaBundle\Elastica\LoggingClient + * Deprecated FOS\ElasticaBundle\DynamicIndex in favour of FOS\ElasticaBundle\Elastica\TransformingIndex + * 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-ALPHA4 (2014-04-10) + + * Indexes are now capable of logging errors with Elastica + * Fixed deferred indexing of deleted documents + +* 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..992f650 100644 --- a/DynamicIndex.php +++ b/DynamicIndex.php @@ -2,27 +2,11 @@ namespace FOS\ElasticaBundle; -use Elastica\Index; +use FOS\ElasticaBundle\Elastica\TransformingIndex; /** - * Elastica index capable of reassigning name dynamically - * - * @author Konstantin Tjuterev + * @deprecated Use \FOS\ElasticaBundle\Elastica\TransformingIndex */ -class DynamicIndex extends Index +class DynamicIndex extends TransformingIndex { - /** - * 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/LoggingClient.php b/Elastica/LoggingClient.php new file mode 100644 index 0000000..0ff1997 --- /dev/null +++ b/Elastica/LoggingClient.php @@ -0,0 +1,47 @@ + + */ +class LoggingClient extends Client +{ + /** + * {@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/Elastica/TransformingIndex.php b/Elastica/TransformingIndex.php new file mode 100644 index 0000000..a0cc001 --- /dev/null +++ b/Elastica/TransformingIndex.php @@ -0,0 +1,45 @@ + + * @author Tim Nagel + */ +class TransformingIndex extends Index +{ + /** + * Indexes a + * @param string $query + * @param int|array $options + * @return \Elastica\Search + */ + public function createSearch($query = '', $options = null) + { + $search = new Search($this->getClient()); + $search->addIndex($this); + $search->setOptionsAndQuery($options, $query); + + return $search; + } + + /** + * 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..1151ed7 --- /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']['mappings'][$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']['mappings'][$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 fe963d0..dd24451 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 */ -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']['mappings'][$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']['mappings'][$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 c10568d..fbf6d1c 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\LoggingClient + FOS\ElasticaBundle\Elastica\TransformingIndex 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: Thu, 24 Apr 2014 09:39:22 -0300 Subject: [PATCH 005/234] 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 15d3f1e4f8dc8f9d1eb8a7b262aecbcee8a2b3b9 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Fri, 25 Apr 2014 21:31:04 +1000 Subject: [PATCH 006/234] New Api --- Doctrine/AbstractLookup.php | 22 ++++++ Doctrine/MongoDB/Lookup.php | 49 ++++++++++++ Doctrine/ORM/Lookup.php | 58 ++++++++++++++ Elastica/LoggingClient.php | 38 +++++++-- Elastica/TransformingIndex.php | 29 +++++-- Elastica/TransformingResult.php | 51 ++++++++++++ Elastica/TransformingResultSet.php | 82 ++++++++++++++++++++ Elastica/TransformingSearch.php | 73 +++++++++++++++++ Elastica/TransformingType.php | 25 ++++++ Exception/MissingModelException.php | 15 ++++ Exception/UnexpectedObjectException.php | 13 ++++ Propel/Lookup.php | 54 +++++++++++++ Tests/Elastica/LoggingClientTest.php | 25 ++++++ Tests/Elastica/TransformingIndexTest.php | 42 ++++++++++ Tests/Elastica/TransformingResultSetTest.php | 42 ++++++++++ Tests/Elastica/TransformingResultTest.php | 22 ++++++ Transformer/CombinedResultTransformer.php | 71 +++++++++++++++++ Transformer/ResultTransformer.php | 80 +++++++++++++++++++ Transformer/ResultTransformerInterface.php | 16 ++++ Type/LookupInterface.php | 27 +++++++ Type/LookupManager.php | 36 +++++++++ Type/TypeConfigurationInterface.php | 54 +++++++++++++ composer.json | 1 + 23 files changed, 912 insertions(+), 13 deletions(-) create mode 100644 Doctrine/AbstractLookup.php create mode 100644 Doctrine/MongoDB/Lookup.php create mode 100644 Doctrine/ORM/Lookup.php create mode 100644 Elastica/TransformingResult.php create mode 100644 Elastica/TransformingResultSet.php create mode 100644 Elastica/TransformingSearch.php create mode 100644 Elastica/TransformingType.php create mode 100644 Exception/MissingModelException.php create mode 100644 Exception/UnexpectedObjectException.php create mode 100644 Propel/Lookup.php create mode 100644 Tests/Elastica/TransformingIndexTest.php create mode 100644 Tests/Elastica/TransformingResultSetTest.php create mode 100644 Tests/Elastica/TransformingResultTest.php create mode 100644 Transformer/CombinedResultTransformer.php create mode 100644 Transformer/ResultTransformer.php create mode 100644 Transformer/ResultTransformerInterface.php create mode 100644 Type/LookupInterface.php create mode 100644 Type/LookupManager.php create mode 100644 Type/TypeConfigurationInterface.php diff --git a/Doctrine/AbstractLookup.php b/Doctrine/AbstractLookup.php new file mode 100644 index 0000000..6560bab --- /dev/null +++ b/Doctrine/AbstractLookup.php @@ -0,0 +1,22 @@ +registry = $registry; + } +} diff --git a/Doctrine/MongoDB/Lookup.php b/Doctrine/MongoDB/Lookup.php new file mode 100644 index 0000000..6c48759 --- /dev/null +++ b/Doctrine/MongoDB/Lookup.php @@ -0,0 +1,49 @@ +createQueryBuilder($configuration); + $qb->hydrate($configuration->isHydrate()); + + $qb->field($configuration->getIdentifierProperty()) + ->in($ids); + + return $qb->getQuery()->execute()->toArray(); + } + + /** + * @param TypeConfigurationInterface $configuration + * @return \Doctrine\ODM\MongoDB\Query\Builder + */ + private function createQueryBuilder(TypeConfigurationInterface $configuration) + { + $method = $configuration->getRepositoryMethod(); + $manager = $this->registry->getManagerForClass($configuration->getModelClass()); + + return $manager->{$method}($configuration->getModelClass()); + } +} diff --git a/Doctrine/ORM/Lookup.php b/Doctrine/ORM/Lookup.php new file mode 100644 index 0000000..2e2cfe3 --- /dev/null +++ b/Doctrine/ORM/Lookup.php @@ -0,0 +1,58 @@ +isHydrate() ? + Query::HYDRATE_OBJECT : + Query::HYDRATE_ARRAY; + + $qb = $this->createQueryBuilder($configuration); + + $qb->andWhere($qb->expr()->in( + sprintf('%s.%s', static::ENTITY_ALIAS, $configuration->getIdentifierProperty()), + ':identifiers' + )); + $qb->setParameter('identifiers', $ids); + + return $qb->getQuery()->execute(array(), $hydrationMode); + } + + /** + * @param TypeConfigurationInterface $configuration + * @return \Doctrine\ORM\QueryBuilder + */ + private function createQueryBuilder(TypeConfigurationInterface $configuration) + { + $repository = $this->registry->getRepository($configuration->getModelClass()); + $method = $configuration->getRepositoryMethod(); + + return $repository->{$method}(static::ENTITY_ALIAS); + } +} diff --git a/Elastica/LoggingClient.php b/Elastica/LoggingClient.php index 0ff1997..faecdfc 100644 --- a/Elastica/LoggingClient.php +++ b/Elastica/LoggingClient.php @@ -5,6 +5,7 @@ namespace FOS\ElasticaBundle\Elastica; use Elastica\Client as Client; use Elastica\Request; use FOS\ElasticaBundle\Logger\ElasticaLogger; +use FOS\ElasticaBundle\Transformer\CombinedResultTransformer; /** * Extends the default Elastica client to provide logging for errors that occur @@ -14,6 +15,38 @@ use FOS\ElasticaBundle\Logger\ElasticaLogger; */ class LoggingClient extends Client { + /** + * @var CombinedResultTransformer + */ + private $resultTransformer; + + public function __construct(array $config = array(), $callback = null, CombinedResultTransformer $resultTransformer) + { + parent::__construct($config, $callback); + + $this->resultTransformer = $resultTransformer; + } + + /** + * Overridden Elastica method to return TransformingIndex instances instead of the + * default Index instances. + * + * @param string $name + * @return TransformingIndex + */ + public function getIndex($name) + { + return new TransformingIndex($this, $name, $this->resultTransformer); + } + + /** + * @return CombinedResultTransformer + */ + public function getResultTransformer() + { + return $this->resultTransformer; + } + /** * {@inheritdoc} */ @@ -39,9 +72,4 @@ class LoggingClient extends Client return $response; } - - public function getIndex($name) - { - return new DynamicIndex($this, $name); - } } diff --git a/Elastica/TransformingIndex.php b/Elastica/TransformingIndex.php index a0cc001..2bab636 100644 --- a/Elastica/TransformingIndex.php +++ b/Elastica/TransformingIndex.php @@ -1,8 +1,11 @@ getClient()); + $search = new TransformingSearch($this->getClient()); $search->addIndex($this); $search->setOptionsAndQuery($options, $query); return $search; } + /** + * Returns a type object for the current index with the given name + * + * @param string $type Type name + * @return TransformingType Type object + */ + public function getType($type) + { + return new TransformingType($this, $type); + } + /** * Reassign index name * @@ -35,8 +50,6 @@ class TransformingIndex extends Index * 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/Elastica/TransformingResult.php b/Elastica/TransformingResult.php new file mode 100644 index 0000000..08d09bc --- /dev/null +++ b/Elastica/TransformingResult.php @@ -0,0 +1,51 @@ +resultSet = $resultSet; + } + + /** + * Returns the transformed result of the hit. + * + * @return mixed + */ + public function getTransformed() + { + if (null === $this->transformed) { + $this->resultSet->transform(); + } + + return $this->transformed; + } + + /** + * An internal method used to set the transformed result on the Result. + * + * @internal + */ + public function setTransformed($transformed) + { + $this->transformed = $transformed; + } +} diff --git a/Elastica/TransformingResultSet.php b/Elastica/TransformingResultSet.php new file mode 100644 index 0000000..c775cd3 --- /dev/null +++ b/Elastica/TransformingResultSet.php @@ -0,0 +1,82 @@ +resultTransformer = $resultTransformer; + } + + /** + * Overridden default method to set our TransformingResult objects. + * + * @param \Elastica\Response $response Response object + */ + protected function _init(Response $response) + { + $this->_response = $response; + $result = $response->getData(); + $this->_totalHits = isset($result['hits']['total']) ? $result['hits']['total'] : 0; + $this->_maxScore = isset($result['hits']['max_score']) ? $result['hits']['max_score'] : 0; + $this->_took = isset($result['took']) ? $result['took'] : 0; + $this->_timedOut = !empty($result['timed_out']); + if (isset($result['hits']['hits'])) { + foreach ($result['hits']['hits'] as $hit) { + $this->_results[] = new TransformingResult($hit, $this); + } + } + } + + /** + * Returns an array of transformed results. + * + * @return object[] + */ + public function getTransformed() + { + $this->transform(); + + return array_map(function (TransformingResult $result) { + return $result->getTransformed(); + }, $this->getResults()); + } + + /** + * Triggers the transformation of all Results. + */ + public function transform() + { + if ($this->transformed) { + return; + } + + if (!$this->count()) { + return; + } + + $this->resultTransformer->transform($this->getResults()); + $this->transformed = true; + } +} diff --git a/Elastica/TransformingSearch.php b/Elastica/TransformingSearch.php new file mode 100644 index 0000000..eee1a96 --- /dev/null +++ b/Elastica/TransformingSearch.php @@ -0,0 +1,73 @@ +value) + * @throws \Elastica\Exception\InvalidException + * @return TransformingResultSet + */ + public function search($query = '', $options = null) + { + $this->setOptionsAndQuery($options, $query); + + $query = $this->getQuery(); + $path = $this->getPath(); + + $params = $this->getOptions(); + + // Send scroll_id via raw HTTP body to handle cases of very large (> 4kb) ids. + if ('_search/scroll' == $path) { + $data = $params[self::OPTION_SCROLL_ID]; + unset($params[self::OPTION_SCROLL_ID]); + } else { + $data = $query->toArray(); + } + + $response = $this->getClient()->request( + $path, + Request::GET, + $data, + $params + ); + + return new TransformingResultSet($response, $query, $this->_client->getResultTransformer()); + } + + /** + * + * @param mixed $query + * @param $fullResult (default = false) By default only the total hit count is returned. If set to true, the full ResultSet including facets is returned. + * @return int|TransformingResultSet + */ + public function count($query = '', $fullResult = false) + { + $this->setOptionsAndQuery(null, $query); + + $query = $this->getQuery(); + $path = $this->getPath(); + + $response = $this->getClient()->request( + $path, + Request::GET, + $query->toArray(), + array(self::OPTION_SEARCH_TYPE => self::OPTION_SEARCH_TYPE_COUNT) + ); + $resultSet = new TransformingResultSet($response, $query, $this->_client->getResultTransformer()); + + return $fullResult ? $resultSet : $resultSet->getTotalHits(); + } +} diff --git a/Elastica/TransformingType.php b/Elastica/TransformingType.php new file mode 100644 index 0000000..f359c24 --- /dev/null +++ b/Elastica/TransformingType.php @@ -0,0 +1,25 @@ +getId() . '/_mlt'; + $query = Query::create($query); + $response = $this->request($path, Request::GET, $query->toArray(), $params); + + return new TransformingResultSet($response, $query, $this->_index->getClient()->getResultTransformer()); + } +} diff --git a/Exception/MissingModelException.php b/Exception/MissingModelException.php new file mode 100644 index 0000000..cfbb750 --- /dev/null +++ b/Exception/MissingModelException.php @@ -0,0 +1,15 @@ +createQuery($configuration, $ids); + + if (!$configuration->isHydrate()) { + return $query->toArray(); + } + + return $query->find(); + } + + /** + * Create a query to use in the findByIdentifiers() method. + * + * @param TypeConfigurationInterface $configuration + * @param array $ids + * @return \ModelCriteria + */ + protected function createQuery(TypeConfigurationInterface $configuration, array $ids) + { + $queryClass = $configuration->getModelClass() . 'Query'; + $query = $queryClass::create(); + $filterMethod = 'filterBy' . Inflector::camelize($configuration->getIdentifierProperty()); + + return $query->$filterMethod($ids); + } +} diff --git a/Tests/Elastica/LoggingClientTest.php b/Tests/Elastica/LoggingClientTest.php index b08a2cf..0b3e71d 100644 --- a/Tests/Elastica/LoggingClientTest.php +++ b/Tests/Elastica/LoggingClientTest.php @@ -4,9 +4,33 @@ namespace FOS\ElasticaBundle\Tests\Client; use Elastica\Request; use Elastica\Transport\Null as NullTransport; +use FOS\ElasticaBundle\Elastica\LoggingClient; class LoggingClientTest extends \PHPUnit_Framework_TestCase { + public function testOverriddenElasticaMethods() + { + $resultTransformer = $this->getMockBuilder('FOS\ElasticaBundle\Transformer\CombinedResultTransformer') + ->disableOriginalConstructor() + ->getMock(); + $client = new LoggingClient(array(), null, $resultTransformer); + $index = $client->getIndex('index'); + $type = $index->getType('type'); + + $this->assertInstanceOf('FOS\ElasticaBundle\Elastica\TransformingIndex', $index); + $this->assertInstanceOf('FOS\ElasticaBundle\Elastica\TransformingType', $type); + } + + public function testGetResultTransformer() + { + $resultTransformer = $this->getMockBuilder('FOS\ElasticaBundle\Transformer\CombinedResultTransformer') + ->disableOriginalConstructor() + ->getMock(); + $client = new LoggingClient(array(), null, $resultTransformer); + + $this->assertSame($resultTransformer, $client->getResultTransformer()); + } + public function testRequestsAreLogged() { $transport = new NullTransport; @@ -29,6 +53,7 @@ class LoggingClientTest extends \PHPUnit_Framework_TestCase ); $client = $this->getMockBuilder('FOS\ElasticaBundle\Elastica\LoggingClient') + ->disableOriginalConstructor() ->setMethods(array('getConnection')) ->getMock(); diff --git a/Tests/Elastica/TransformingIndexTest.php b/Tests/Elastica/TransformingIndexTest.php new file mode 100644 index 0000000..e652119 --- /dev/null +++ b/Tests/Elastica/TransformingIndexTest.php @@ -0,0 +1,42 @@ +index->createSearch(); + + $this->assertInstanceOf('FOS\ElasticaBundle\Elastica\TransformingSearch', $search); + } + + public function testOverrideName() + { + $this->assertEquals('testindex', $this->index->getName()); + + $this->index->overrideName('newindex'); + + $this->assertEquals('newindex', $this->index->getName()); + } + + protected function setUp() + { + $this->client = $this->getMockBuilder('FOS\ElasticaBundle\Elastica\LoggingClient') + ->disableOriginalConstructor() + ->getMock(); + $this->index = new TransformingIndex($this->client, 'testindex'); + } +} diff --git a/Tests/Elastica/TransformingResultSetTest.php b/Tests/Elastica/TransformingResultSetTest.php new file mode 100644 index 0000000..9b9b38a --- /dev/null +++ b/Tests/Elastica/TransformingResultSetTest.php @@ -0,0 +1,42 @@ + array( + 'hits' => array( + array(), + array(), + array(), + ) + ))); + $query = new Query(); + $transformer = $this->getMockBuilder('FOS\ElasticaBundle\Transformer\CombinedResultTransformer') + ->disableOriginalConstructor() + ->getMock(); + + $resultSet = new TransformingResultSet($response, $query, $transformer); + + $this->assertCount(3, $resultSet); + $this->assertInstanceOf('FOS\ElasticaBundle\Elastica\TransformingResult', $resultSet[0]); + + $transformer->expects($this->once()) + ->method('transform') + ->with($resultSet->getResults()); + + $resultSet->transform(); + $resultSet->transform(); + + $this->assertSame(array( + 0 => null, 1 => null, 2 => null + ), $resultSet->getTransformed()); + } +} diff --git a/Tests/Elastica/TransformingResultTest.php b/Tests/Elastica/TransformingResultTest.php new file mode 100644 index 0000000..286b7d1 --- /dev/null +++ b/Tests/Elastica/TransformingResultTest.php @@ -0,0 +1,22 @@ +getMockBuilder('FOS\ElasticaBundle\Elastica\TransformingResultSet') + ->disableOriginalConstructor() + ->getMock(); + $result = new TransformingResult(array(), $resultSet); + + $resultSet->expects($this->exactly(2)) + ->method('transform'); + + $result->getTransformed(); + $result->getTransformed(); + } +} diff --git a/Transformer/CombinedResultTransformer.php b/Transformer/CombinedResultTransformer.php new file mode 100644 index 0000000..791e601 --- /dev/null +++ b/Transformer/CombinedResultTransformer.php @@ -0,0 +1,71 @@ + + */ +class CombinedResultTransformer +{ + /** + * @var \FOS\ElasticaBundle\Type\TypeConfigurationInterface + */ + private $configurations; + + /** + * @var ResultTransformerInterface + */ + private $transformer; + + /** + * @param \FOS\ElasticaBundle\Type\TypeConfigurationInterface[] $configurations + * @param ResultTransformerInterface $transformer + */ + public function __construct(array $configurations, ResultTransformerInterface $transformer) + { + $this->configurations = $configurations; + $this->transformer = $transformer; + } + + /** + * Transforms Elastica results into Models. + * + * @param TransformingResult[] $results + * @return object[] + */ + public function transform($results) + { + $grouped = array(); + + foreach ($results as $result) { + $grouped[$result->getType()][] = $result; + } + + foreach ($grouped as $type => $group) { + $this->transformer->transform($this->getConfiguration($type), $group); + } + } + + /** + * Retrieves the transformer for a given type. + * + * @param string $type + * @return \FOS\ElasticaBundle\Type\TypeConfigurationInterface + * @throws \InvalidArgumentException + */ + private function getConfiguration($type) + { + if (!array_key_exists($type, $this->configurations)) { + throw new \InvalidArgumentException(sprintf( + 'Configuration for type "%s" is not registered with this combined transformer.', + $type + )); + } + + return $this->configurations[$type]; + } +} diff --git a/Transformer/ResultTransformer.php b/Transformer/ResultTransformer.php new file mode 100644 index 0000000..68b9364 --- /dev/null +++ b/Transformer/ResultTransformer.php @@ -0,0 +1,80 @@ +lookupManager = $lookupManager; + $this->propertyAccessor = $propertyAccessor; + } + + /** + * Transforms Elastica results into Models. + * + * @param TypeConfigurationInterface $configuration + * @param \FOS\ElasticaBundle\Elastica\TransformingResult[] $results + * @throws \FOS\ElasticaBundle\Exception\MissingModelException + * @throws \FOS\ElasticaBundle\Exception\UnexpectedObjectException + */ + public function transform(TypeConfigurationInterface $configuration, $results) + { + $results = $this->processResults($results); + $lookup = $this->lookupManager->getLookup($configuration->getType()); + $objects = $lookup->lookup($configuration, array_keys($results)); + + if (!$configuration->isIgnoreMissing() and count($objects) < count($results)) { + throw new MissingModelException(count($objects), count($results)); + } + + $identifierProperty = $configuration->getIdentifierProperty(); + foreach ($objects as $object) { + $id = $this->propertyAccessor->getValue($object, $identifierProperty); + + if (!array_key_exists($id, $results)) { + throw new UnexpectedObjectException($id); + } + + $results[$id]->setTransformed($object); + } + } + + /** + * Processes the results array into a more usable format for the transformation. + * + * @param \FOS\ElasticaBundle\Elastica\TransformingResult[] $results + * @return \FOS\ElasticaBundle\Elastica\TransformingResult[] + */ + private function processResults($results) + { + $sorted = array(); + foreach ($results as $result) { + $sorted[$result->getId()] = $result; + } + + return $sorted; + } +} diff --git a/Transformer/ResultTransformerInterface.php b/Transformer/ResultTransformerInterface.php new file mode 100644 index 0000000..c18fc7c --- /dev/null +++ b/Transformer/ResultTransformerInterface.php @@ -0,0 +1,16 @@ + + */ +interface LookupInterface +{ + /** + * Returns the lookup key. + * + * @return string + */ + public function getKey(); + + /** + * Look up objects of a specific type with ids as supplied. + * + * @param TypeConfigurationInterface $configuration + * @param int[] $ids + * @return object[] + */ + public function lookup(TypeConfigurationInterface $configuration, array $ids); +} diff --git a/Type/LookupManager.php b/Type/LookupManager.php new file mode 100644 index 0000000..0db0fd1 --- /dev/null +++ b/Type/LookupManager.php @@ -0,0 +1,36 @@ +lookups[$lookup->getKey()] = $lookup; + } + } + + + /** + * @param string $type + * @return LookupInterface + * @throws \InvalidArgumentException + */ + public function getLookup($type) + { + if (!array_key_exists($type, $this->lookups)) { + throw new \InvalidArgumentException(sprintf('Lookup with key "%s" does not exist', $type)); + } + + return $this->lookups[$type]; + } +} diff --git a/Type/TypeConfigurationInterface.php b/Type/TypeConfigurationInterface.php new file mode 100644 index 0000000..bee3388 --- /dev/null +++ b/Type/TypeConfigurationInterface.php @@ -0,0 +1,54 @@ + + */ +interface TypeConfigurationInterface +{ + /** + * The identifier property that is used to retrieve an identifier from the model. + * + * @return string + */ + public function getIdentifierProperty(); + + /** + * Returns the fully qualified class for the model that this type represents. + * + * @return string + */ + public function getModelClass(); + + /** + * Returns the repository method that will create a query builder or associated + * query object for lookup purposes. + * + * @return string + */ + public function getRepositoryMethod(); + + /** + * Returns the name of the type. + * + * @return string + */ + public function getType(); + + /** + * If the lookup should hydrate models to objects or leave data as an array. + * + * @return bool + */ + public function isHydrate(); + + /** + * If the type should ignore missing results from a lookup. + * + * @return bool + */ + public function isIgnoreMissing(); +} \ No newline at end of file diff --git a/composer.json b/composer.json index 8dd19b6..e827ac6 100644 --- a/composer.json +++ b/composer.json @@ -12,6 +12,7 @@ ], "require": { "php": ">=5.3.2", + "doctrine/inflector": "~1.0", "symfony/framework-bundle": "~2.3", "symfony/console": "~2.1", "symfony/form": "~2.1", From c93bbb9081c3915e457713990c02afc700c0a933 Mon Sep 17 00:00:00 2001 From: Evan Villemez Date: Thu, 1 May 2014 11:05:16 -0400 Subject: [PATCH 007/234] 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 008/234] 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 009/234] 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 010/234] 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 011/234] 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 012/234] 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 013/234] 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 014/234] 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 7d06cc429b16849d831372280c1307ec6311c155 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Thu, 15 May 2014 22:55:35 +1000 Subject: [PATCH 015/234] dev --- DependencyInjection/Compiler/LookupPass.php | 33 +++++ DependencyInjection/FOSElasticaExtension.php | 118 +++++++++------- Doctrine/MongoDB/Lookup.php | 10 +- Doctrine/ORM/Lookup.php | 10 +- Exception/UnexpectedObjectException.php | 2 +- Finder/PaginatedFinderInterface.php | 28 ---- Finder/TransformedFinder.php | 29 +--- Index/IndexManager.php | 23 +-- Paginator/FantaPaginatorAdapter.php | 57 -------- Paginator/PaginatorAdapterInterface.php | 34 ----- Paginator/PartialResultsInterface.php | 31 ----- Paginator/RawPaginatorAdapter.php | 139 ------------------- Paginator/RawPartialResults.php | 52 ------- Paginator/TransformedPaginatorAdapter.php | 36 ----- Paginator/TransformedPartialResults.php | 33 ----- Propel/Lookup.php | 10 +- Resources/config/config.xml | 79 +---------- Resources/config/index.xml | 35 +++++ Resources/config/orm.xml | 4 +- Resources/config/persister.xml | 27 ++++ Resources/config/provider.xml | 18 +++ Resources/config/transformer.xml | 32 +++++ Transformer/CombinedResultTransformer.php | 6 +- Transformer/ResultTransformer.php | 7 +- Transformer/ResultTransformerInterface.php | 6 +- Type/LookupInterface.php | 4 +- Type/LookupManager.php | 1 - Type/TypeConfiguration.php | 102 ++++++++++++++ Type/TypeConfigurationInterface.php | 54 ------- 29 files changed, 364 insertions(+), 656 deletions(-) create mode 100644 DependencyInjection/Compiler/LookupPass.php delete mode 100644 Finder/PaginatedFinderInterface.php delete mode 100644 Paginator/FantaPaginatorAdapter.php delete mode 100644 Paginator/PaginatorAdapterInterface.php delete mode 100644 Paginator/PartialResultsInterface.php delete mode 100644 Paginator/RawPaginatorAdapter.php delete mode 100644 Paginator/RawPartialResults.php delete mode 100644 Paginator/TransformedPaginatorAdapter.php delete mode 100644 Paginator/TransformedPartialResults.php 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 Type/TypeConfiguration.php delete mode 100644 Type/TypeConfigurationInterface.php diff --git a/DependencyInjection/Compiler/LookupPass.php b/DependencyInjection/Compiler/LookupPass.php new file mode 100644 index 0000000..e82a56f --- /dev/null +++ b/DependencyInjection/Compiler/LookupPass.php @@ -0,0 +1,33 @@ + + */ +class LookupPass implements CompilerPassInterface +{ + /** + * {@inheritDoc} + */ + public function process(ContainerBuilder $container) + { + if (!$container->hasDefinition('fos_elastica.lookup_manager')) { + return; + } + + $lookups = array(); + foreach ($container->findTaggedServiceIds('fos_elastica.lookup') as $id => $tags) { + $lookups[] = new Reference($id); + } + + $managerDefinition = $container->getDefinition('fos_elastica.lookup_manager'); + $managerDefinition->setArguments(0, $lookups); + } +} diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php index 51cb94f..6bf1880 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; @@ -14,6 +13,13 @@ use InvalidArgumentException; class FOSElasticaExtension extends Extension { + /** + * Stores references to all defined clients loaded by the extension. + * + * @var array + */ + private $clients = array(); + protected $indexConfigs = array(); protected $typeFields = array(); protected $loadedDrivers = array(); @@ -21,9 +27,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(new Configuration($configs, $container), $configs); $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); if (empty($config['clients']) || empty($config['indexes'])) { @@ -43,25 +47,19 @@ 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'])); + + // XX serializer can be done better.... + // $this->serializerConfig = isset($config['serializer']) ? $config['serializer'] : null; + + $this->loadIndexes($config['indexes'], $container); $container->setAlias('fos_elastica.index', sprintf('fos_elastica.index.%s', $config['default_index'])); - $this->createDefaultManagerAlias($config['default_manager'], $container); - } + $this->loadIndexManager($container); + $this->loadResetter($container); - public function getConfiguration(array $config, ContainerBuilder $container) - { - return new Configuration($config); + $this->createDefaultManagerAlias($config['default_manager'], $container); } /** @@ -73,22 +71,24 @@ class FOSElasticaExtension extends Extension */ protected 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; } /** @@ -96,35 +96,29 @@ 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) + protected 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; + $indexId = sprintf('fos_elastica.index.%s', $name); + $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); } - $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'); $container->setDefinition($indexId, $indexDef); + $typePrototypeConfig = isset($index['type_prototype']) ? $index['type_prototype'] : array(); - $indexIds[$name] = $indexId; + $this->indexConfigs[$name] = array( 'index' => new Reference($indexId), 'name_or_alias' => $indexName, @@ -132,10 +126,13 @@ class FOSElasticaExtension extends Extension 'mappings' => array() ) ); + if ($index['finder']) { + // XX Deprecated $this->loadIndexFinder($container, $name, $indexId); } if (!empty($index['settings'])) { + // XX What is this for? $this->indexConfigs[$name]['config']['settings'] = $index['settings']; } if ($index['use_alias']) { @@ -522,26 +519,26 @@ class FOSElasticaExtension extends Extension /** * Loads the index manager * - * @param array $indexRefsByName * @param ContainerBuilder $container - **/ - protected function loadIndexManager(array $indexRefsByName, ContainerBuilder $container) + */ + protected function loadIndexManager(ContainerBuilder $container) { + $indexRefs = array_map(function ($index) { return $index['index']; }, $this->indexConfigs); + $managerDef = $container->getDefinition('fos_elastica.index_manager'); - $managerDef->replaceArgument(0, $indexRefsByName); + $managerDef->replaceArgument(0, $indexRefs); $managerDef->replaceArgument(1, new Reference('fos_elastica.index')); } /** * Loads the resetter * - * @param array $indexConfigs - * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container + * @param ContainerBuilder $container */ - protected function loadResetter(array $indexConfigs, ContainerBuilder $container) + protected function loadResetter(ContainerBuilder $container) { $resetterDef = $container->getDefinition('fos_elastica.resetter'); - $resetterDef->replaceArgument(0, $indexConfigs); + $resetterDef->replaceArgument(0, $this->indexConfigs); } protected function loadDriver(ContainerBuilder $container, $driver) @@ -549,6 +546,7 @@ class FOSElasticaExtension extends Extension if (in_array($driver, $this->loadedDrivers)) { return; } + $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); $loader->load($driver.'.xml'); $this->loadedDrivers[] = $driver; @@ -570,4 +568,20 @@ class FOSElasticaExtension extends Extension $container->setAlias('fos_elastica.manager', sprintf('fos_elastica.manager.%s', $defaultManagerService)); } + + /** + * Returns a reference to a client. + * + * @param string $clientName + * @return Reference + * @throws \InvalidArgumentException + */ + private function getClient($clientName) + { + 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/Doctrine/MongoDB/Lookup.php b/Doctrine/MongoDB/Lookup.php index 6c48759..1951964 100644 --- a/Doctrine/MongoDB/Lookup.php +++ b/Doctrine/MongoDB/Lookup.php @@ -3,7 +3,7 @@ namespace FOS\ElasticaBundle\Doctrine\MongoDB; use FOS\ElasticaBundle\Doctrine\AbstractLookup; -use FOS\ElasticaBundle\Type\TypeConfigurationInterface; +use FOS\ElasticaBundle\Type\TypeConfiguration; class Lookup extends AbstractLookup { @@ -20,11 +20,11 @@ class Lookup extends AbstractLookup /** * Look up objects of a specific type with ids as supplied. * - * @param TypeConfigurationInterface $configuration + * @param TypeConfiguration $configuration * @param array $ids * @return array */ - public function lookup(TypeConfigurationInterface $configuration, array $ids) + public function lookup(TypeConfiguration $configuration, array $ids) { $qb = $this->createQueryBuilder($configuration); $qb->hydrate($configuration->isHydrate()); @@ -36,10 +36,10 @@ class Lookup extends AbstractLookup } /** - * @param TypeConfigurationInterface $configuration + * @param TypeConfiguration $configuration * @return \Doctrine\ODM\MongoDB\Query\Builder */ - private function createQueryBuilder(TypeConfigurationInterface $configuration) + private function createQueryBuilder(TypeConfiguration $configuration) { $method = $configuration->getRepositoryMethod(); $manager = $this->registry->getManagerForClass($configuration->getModelClass()); diff --git a/Doctrine/ORM/Lookup.php b/Doctrine/ORM/Lookup.php index 2e2cfe3..6ec2167 100644 --- a/Doctrine/ORM/Lookup.php +++ b/Doctrine/ORM/Lookup.php @@ -4,7 +4,7 @@ namespace FOS\ElasticaBundle\Doctrine\ORM; use Doctrine\ORM\Query; use FOS\ElasticaBundle\Doctrine\AbstractLookup; -use FOS\ElasticaBundle\Type\TypeConfigurationInterface; +use FOS\ElasticaBundle\Type\TypeConfiguration; class Lookup extends AbstractLookup { @@ -23,11 +23,11 @@ class Lookup extends AbstractLookup /** * Look up objects of a specific type with ids as supplied. * - * @param TypeConfigurationInterface $configuration + * @param TypeConfiguration $configuration * @param array $ids * @return array */ - public function lookup(TypeConfigurationInterface $configuration, array $ids) + public function lookup(TypeConfiguration $configuration, array $ids) { $hydrationMode = $configuration->isHydrate() ? Query::HYDRATE_OBJECT : @@ -45,10 +45,10 @@ class Lookup extends AbstractLookup } /** - * @param TypeConfigurationInterface $configuration + * @param TypeConfiguration $configuration * @return \Doctrine\ORM\QueryBuilder */ - private function createQueryBuilder(TypeConfigurationInterface $configuration) + private function createQueryBuilder(TypeConfiguration $configuration) { $repository = $this->registry->getRepository($configuration->getModelClass()); $method = $configuration->getRepositoryMethod(); diff --git a/Exception/UnexpectedObjectException.php b/Exception/UnexpectedObjectException.php index afe671d..d247778 100644 --- a/Exception/UnexpectedObjectException.php +++ b/Exception/UnexpectedObjectException.php @@ -8,6 +8,6 @@ class UnexpectedObjectException extends \Exception { public function __construct($id) { - parent::__construct(sprintf('Lookup returned an unknown object with id %d', $id)); + parent::__construct(sprintf('Lookup returned an unexpected object with id %d', $id)); } } diff --git a/Finder/PaginatedFinderInterface.php b/Finder/PaginatedFinderInterface.php deleted file mode 100644 index fa10b70..0000000 --- a/Finder/PaginatedFinderInterface.php +++ /dev/null @@ -1,28 +0,0 @@ -search($query, $limit, $options); @@ -78,29 +78,4 @@ class TransformedFinder implements PaginatedFinderInterface return $results; } - - /** - * Gets a paginator wrapping the result of a search - * - * @param string $query - * @param array $options - * @return Pagerfanta - */ - public function findPaginated($query, $options = array()) - { - $queryObject = Query::create($query); - $paginatorAdapter = $this->createPaginatorAdapter($queryObject, $options); - - return new Pagerfanta(new FantaPaginatorAdapter($paginatorAdapter)); - } - - /** - * {@inheritdoc} - */ - public function createPaginatorAdapter($query, $options = array()) - { - $query = Query::create($query); - - return new TransformedPaginatorAdapter($this->searchable, $query, $options, $this->transformer); - } } diff --git a/Index/IndexManager.php b/Index/IndexManager.php index 543ccae..dc270be 100644 --- a/Index/IndexManager.php +++ b/Index/IndexManager.php @@ -2,20 +2,25 @@ namespace FOS\ElasticaBundle\Index; -use Elastica\Index; +use FOS\ElasticaBundle\Elastica\TransformingIndex; class IndexManager { + /** + * @var TransformingIndex[] + */ protected $indexesByName; + + /** + * @var string + */ protected $defaultIndexName; /** - * Constructor. - * - * @param array $indexesByName - * @param Index $defaultIndex + * @param TransformingIndex[] $indexesByName + * @param TransformingIndex $defaultIndex */ - public function __construct(array $indexesByName, Index $defaultIndex) + public function __construct(array $indexesByName, TransformingIndex $defaultIndex) { $this->indexesByName = $indexesByName; $this->defaultIndexName = $defaultIndex->getName(); @@ -24,7 +29,7 @@ class IndexManager /** * Gets all registered indexes * - * @return array + * @return TransformingIndex[] */ public function getAllIndexes() { @@ -35,7 +40,7 @@ class IndexManager * Gets an index by its name * * @param string $name Index to return, or the default index if null - * @return Index + * @return TransformingIndex * @throws \InvalidArgumentException if no index exists for the given name */ public function getIndex($name = null) @@ -54,7 +59,7 @@ class IndexManager /** * Gets the default index * - * @return Index + * @return TransformingIndex */ public function getDefaultIndex() { diff --git a/Paginator/FantaPaginatorAdapter.php b/Paginator/FantaPaginatorAdapter.php deleted file mode 100644 index 2ad6983..0000000 --- a/Paginator/FantaPaginatorAdapter.php +++ /dev/null @@ -1,57 +0,0 @@ -adapter = $adapter; - } - - /** - * Returns the number of results. - * - * @return integer The number of results. - * - * @api - */ - public function getNbResults() - { - return $this->adapter->getTotalHits(); - } - - /** - * Returns Facets - * - * @return mixed - * - * @api - */ - public function getFacets() - { - return $this->adapter->getFacets(); - } - - /** - * Returns a slice of the results. - * - * @param integer $offset The offset. - * @param integer $length The length. - * - * @return array|\Traversable The slice. - * - * @api - */ - public function getSlice($offset, $length) - { - return $this->adapter->getResults($offset, $length)->toArray(); - } -} diff --git a/Paginator/PaginatorAdapterInterface.php b/Paginator/PaginatorAdapterInterface.php deleted file mode 100644 index 25786a0..0000000 --- a/Paginator/PaginatorAdapterInterface.php +++ /dev/null @@ -1,34 +0,0 @@ -searchable = $searchable; - $this->query = $query; - $this->options = $options; - } - - /** - * Returns the paginated results. - * - * @param $offset - * @param $itemCountPerPage - * @throws \InvalidArgumentException - * @return ResultSet - */ - 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->setSize($itemCountPerPage); - - $resultSet = $this->searchable->search($query, $this->options); - $this->totalHits = $resultSet->getTotalHits(); - $this->facets = $resultSet->getFacets(); - return $resultSet; - } - - /** - * Returns the paginated results. - * - * @param int $offset - * @param int $itemCountPerPage - * @return PartialResultsInterface - */ - public function getResults($offset, $itemCountPerPage) - { - return new RawPartialResults($this->getElasticaResults($offset, $itemCountPerPage)); - } - - /** - * Returns the number of results. - * - * @return integer The number of results. - */ - public function 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; - } - - /** - * Returns Facets - * - * @return mixed - */ - public function getFacets() - { - if ( ! isset($this->facets)) { - $this->facets = $this->searchable->search($this->query)->getFacets(); - } - - return $this->facets; - } - - /** - * Returns the Query - * - * @return Query the search query - */ - public function getQuery() - { - return $this->query; - } -} diff --git a/Paginator/RawPartialResults.php b/Paginator/RawPartialResults.php deleted file mode 100644 index a4afb00..0000000 --- a/Paginator/RawPartialResults.php +++ /dev/null @@ -1,52 +0,0 @@ -resultSet = $resultSet; - } - - /** - * {@inheritDoc} - */ - public function toArray() - { - return array_map(function(Result $result) { - return $result->getSource(); - }, $this->resultSet->getResults()); - } - - /** - * {@inheritDoc} - */ - public function getTotalHits() - { - return $this->resultSet->getTotalHits(); - } - - /** - * {@inheritDoc} - */ - public function getFacets() - { - if ($this->resultSet->hasFacets()) { - return $this->resultSet->getFacets(); - } - - return null; - } -} \ No newline at end of file diff --git a/Paginator/TransformedPaginatorAdapter.php b/Paginator/TransformedPaginatorAdapter.php deleted file mode 100644 index 3b4716f..0000000 --- a/Paginator/TransformedPaginatorAdapter.php +++ /dev/null @@ -1,36 +0,0 @@ -transformer = $transformer; - } - - /** - * {@inheritDoc} - */ - public function getResults($offset, $length) - { - return new TransformedPartialResults($this->getElasticaResults($offset, $length), $this->transformer); - } -} diff --git a/Paginator/TransformedPartialResults.php b/Paginator/TransformedPartialResults.php deleted file mode 100644 index 13d716c..0000000 --- a/Paginator/TransformedPartialResults.php +++ /dev/null @@ -1,33 +0,0 @@ -transformer = $transformer; - } - - /** - * {@inheritDoc} - */ - public function toArray() - { - return $this->transformer->transform($this->resultSet->getResults()); - } -} \ No newline at end of file diff --git a/Propel/Lookup.php b/Propel/Lookup.php index 61e4c94..1793b05 100644 --- a/Propel/Lookup.php +++ b/Propel/Lookup.php @@ -4,7 +4,7 @@ namespace FOS\ElasticaBundle\Propel; use Doctrine\Common\Util\Inflector; use FOS\ElasticaBundle\Type\LookupInterface; -use FOS\ElasticaBundle\Type\TypeConfigurationInterface; +use FOS\ElasticaBundle\Type\TypeConfiguration; class Lookup implements LookupInterface { @@ -21,11 +21,11 @@ class Lookup implements LookupInterface /** * Look up objects of a specific type with ids as supplied. * - * @param TypeConfigurationInterface $configuration + * @param TypeConfiguration $configuration * @param int[] $ids * @return object[] */ - public function lookup(TypeConfigurationInterface $configuration, array $ids) + public function lookup(TypeConfiguration $configuration, array $ids) { $query = $this->createQuery($configuration, $ids); @@ -39,11 +39,11 @@ class Lookup implements LookupInterface /** * Create a query to use in the findByIdentifiers() method. * - * @param TypeConfigurationInterface $configuration + * @param TypeConfiguration $configuration * @param array $ids * @return \ModelCriteria */ - protected function createQuery(TypeConfigurationInterface $configuration, array $ids) + protected function createQuery(TypeConfiguration $configuration, array $ids) { $queryClass = $configuration->getModelClass() . 'Query'; $query = $queryClass::create(); diff --git a/Resources/config/config.xml b/Resources/config/config.xml index fbf6d1c..08993dd 100644 --- a/Resources/config/config.xml +++ b/Resources/config/config.xml @@ -6,96 +6,29 @@ FOS\ElasticaBundle\Elastica\LoggingClient - FOS\ElasticaBundle\Elastica\TransformingIndex - 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 - 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..02b2948 --- /dev/null +++ b/Resources/config/index.xml @@ -0,0 +1,35 @@ + + + + + + FOS\ElasticaBundle\Elastica\TransformingIndex + Elastica\Type + FOS\ElasticaBundle\IndexManager + FOS\ElasticaBundle\Resetter + FOS\ElasticaBundle\Finder\TransformedFinder + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Resources/config/orm.xml b/Resources/config/orm.xml index 5bd16e5..d44d9ae 100644 --- a/Resources/config/orm.xml +++ b/Resources/config/orm.xml @@ -31,8 +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/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/Transformer/CombinedResultTransformer.php b/Transformer/CombinedResultTransformer.php index 791e601..50822ae 100644 --- a/Transformer/CombinedResultTransformer.php +++ b/Transformer/CombinedResultTransformer.php @@ -12,7 +12,7 @@ use FOS\ElasticaBundle\Elastica\TransformingResult; class CombinedResultTransformer { /** - * @var \FOS\ElasticaBundle\Type\TypeConfigurationInterface + * @var \FOS\ElasticaBundle\Type\TypeConfiguration */ private $configurations; @@ -22,7 +22,7 @@ class CombinedResultTransformer private $transformer; /** - * @param \FOS\ElasticaBundle\Type\TypeConfigurationInterface[] $configurations + * @param \FOS\ElasticaBundle\Type\TypeConfiguration[] $configurations * @param ResultTransformerInterface $transformer */ public function __construct(array $configurations, ResultTransformerInterface $transformer) @@ -54,7 +54,7 @@ class CombinedResultTransformer * Retrieves the transformer for a given type. * * @param string $type - * @return \FOS\ElasticaBundle\Type\TypeConfigurationInterface + * @return \FOS\ElasticaBundle\Type\TypeConfiguration * @throws \InvalidArgumentException */ private function getConfiguration($type) diff --git a/Transformer/ResultTransformer.php b/Transformer/ResultTransformer.php index 68b9364..31a4b9f 100644 --- a/Transformer/ResultTransformer.php +++ b/Transformer/ResultTransformer.php @@ -5,8 +5,7 @@ namespace FOS\ElasticaBundle\Transformer; use FOS\ElasticaBundle\Exception\MissingModelException; use FOS\ElasticaBundle\Exception\UnexpectedObjectException; use FOS\ElasticaBundle\Type\LookupManager; -use FOS\ElasticaBundle\Type\TypeConfigurationInterface; -use Psr\Log\LoggerInterface; +use FOS\ElasticaBundle\Type\TypeConfiguration; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; /** @@ -35,12 +34,12 @@ class ResultTransformer implements ResultTransformerInterface /** * Transforms Elastica results into Models. * - * @param TypeConfigurationInterface $configuration + * @param TypeConfiguration $configuration * @param \FOS\ElasticaBundle\Elastica\TransformingResult[] $results * @throws \FOS\ElasticaBundle\Exception\MissingModelException * @throws \FOS\ElasticaBundle\Exception\UnexpectedObjectException */ - public function transform(TypeConfigurationInterface $configuration, $results) + public function transform(TypeConfiguration $configuration, $results) { $results = $this->processResults($results); $lookup = $this->lookupManager->getLookup($configuration->getType()); diff --git a/Transformer/ResultTransformerInterface.php b/Transformer/ResultTransformerInterface.php index c18fc7c..ebce242 100644 --- a/Transformer/ResultTransformerInterface.php +++ b/Transformer/ResultTransformerInterface.php @@ -2,15 +2,15 @@ namespace FOS\ElasticaBundle\Transformer; -use FOS\ElasticaBundle\Type\TypeConfigurationInterface; +use FOS\ElasticaBundle\Type\TypeConfiguration; interface ResultTransformerInterface { /** * Transforms Elastica results into Models. * - * @param TypeConfigurationInterface $configuration + * @param TypeConfiguration $configuration * @param array $results */ - public function transform(TypeConfigurationInterface $configuration, $results); + public function transform(TypeConfiguration $configuration, $results); } diff --git a/Type/LookupInterface.php b/Type/LookupInterface.php index c956511..2f117b9 100644 --- a/Type/LookupInterface.php +++ b/Type/LookupInterface.php @@ -19,9 +19,9 @@ interface LookupInterface /** * Look up objects of a specific type with ids as supplied. * - * @param TypeConfigurationInterface $configuration + * @param TypeConfiguration $configuration * @param int[] $ids * @return object[] */ - public function lookup(TypeConfigurationInterface $configuration, array $ids); + public function lookup(TypeConfiguration $configuration, array $ids); } diff --git a/Type/LookupManager.php b/Type/LookupManager.php index 0db0fd1..15a7dc6 100644 --- a/Type/LookupManager.php +++ b/Type/LookupManager.php @@ -19,7 +19,6 @@ class LookupManager } } - /** * @param string $type * @return LookupInterface diff --git a/Type/TypeConfiguration.php b/Type/TypeConfiguration.php new file mode 100644 index 0000000..6a9ff0d --- /dev/null +++ b/Type/TypeConfiguration.php @@ -0,0 +1,102 @@ + + */ +final class TypeConfiguration +{ + /** + * The identifier property that is used to retrieve an identifier from the model. + * + * @var string + */ + private $identifierProperty; + + /** + * Returns the fully qualified class for the model that this type represents. + * + * @var string + */ + private $modelClass; + + /** + * Returns the repository method that will create a query builder or associated + * query object for lookup purposes. + * + * @var string + */ + private $repositoryMethod; + + /** + * Returns the name of the type. + * + * @var string + */ + private $type; + + /** + * If the lookup should hydrate models to objects or leave data as an array. + * + * @var bool + */ + private $hydrate = true; + + /** + * If the type should ignore missing results from a lookup. + * + * @var bool + */ + private $ignoreMissing = false; + + /** + * @return boolean + */ + public function isHydrate() + { + return $this->hydrate; + } + + /** + * @return string + */ + public function getIdentifierProperty() + { + return $this->identifierProperty; + } + + /** + * @return boolean + */ + public function isIgnoreMissing() + { + return $this->ignoreMissing; + } + + /** + * @return string + */ + public function getModelClass() + { + return $this->modelClass; + } + + /** + * @return string + */ + public function getRepositoryMethod() + { + return $this->repositoryMethod; + } + + /** + * @return string + */ + public function getType() + { + return $this->type; + } +} diff --git a/Type/TypeConfigurationInterface.php b/Type/TypeConfigurationInterface.php deleted file mode 100644 index bee3388..0000000 --- a/Type/TypeConfigurationInterface.php +++ /dev/null @@ -1,54 +0,0 @@ - - */ -interface TypeConfigurationInterface -{ - /** - * The identifier property that is used to retrieve an identifier from the model. - * - * @return string - */ - public function getIdentifierProperty(); - - /** - * Returns the fully qualified class for the model that this type represents. - * - * @return string - */ - public function getModelClass(); - - /** - * Returns the repository method that will create a query builder or associated - * query object for lookup purposes. - * - * @return string - */ - public function getRepositoryMethod(); - - /** - * Returns the name of the type. - * - * @return string - */ - public function getType(); - - /** - * If the lookup should hydrate models to objects or leave data as an array. - * - * @return bool - */ - public function isHydrate(); - - /** - * If the type should ignore missing results from a lookup. - * - * @return bool - */ - public function isIgnoreMissing(); -} \ No newline at end of file From e1bbb87cfe011c0277a03e9ad66cdde2e521d86b Mon Sep 17 00:00:00 2001 From: Milan Magudia Date: Fri, 16 May 2014 16:24:37 +0100 Subject: [PATCH 016/234] 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 017/234] 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 018/234] 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 019/234] 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 020/234] 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 021/234] 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 022/234] 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 023/234] 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 024/234] 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 025/234] 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 026/234] 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 027/234] 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 028/234] 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 029/234] 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 030/234] 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 031/234] 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 032/234] 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 033/234] 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 034/234] 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 035/234] 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 036/234] 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 037/234] 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 038/234] 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 039/234] 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 040/234] 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 041/234] 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 042/234] 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 043/234] 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 044/234] 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 045/234] 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 046/234] 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 047/234] 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 048/234] 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 049/234] 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 050/234] 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 051/234] 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 052/234] 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 053/234] 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 054/234] 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 055/234] 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 056/234] 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 057/234] 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 058/234] 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 059/234] 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 060/234] 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 061/234] 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 062/234] 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 063/234] 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 064/234] 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 065/234] 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 066/234] 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 067/234] 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 068/234] 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 069/234] 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 070/234] 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 071/234] 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 072/234] 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 073/234] 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 074/234] 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 075/234] 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 076/234] 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 077/234] 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 078/234] 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 079/234] 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 080/234] [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 081/234] 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 082/234] 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 083/234] 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 084/234] [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 085/234] 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 086/234] 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 087/234] 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 088/234] 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 089/234] 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 090/234] 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 091/234] 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 092/234] 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 093/234] 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 094/234] 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 095/234] 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 096/234] 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 097/234] 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 098/234] 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 099/234] 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 100/234] 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 101/234] 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 102/234] 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 103/234] 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 104/234] 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 105/234] 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 106/234] 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 107/234] 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 108/234] 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 109/234] 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 110/234] 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 111/234] 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 112/234] 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 113/234] 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 114/234] 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 115/234] 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 116/234] 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 117/234] 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 118/234] 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 119/234] 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 120/234] 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 121/234] 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 122/234] 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 123/234] 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 124/234] 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 125/234] #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 126/234] 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 127/234] 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 128/234] 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 129/234] 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 130/234] 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 131/234] 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 132/234] 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 133/234] 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 134/234] 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 135/234] 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 136/234] 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 137/234] 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 138/234] 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 139/234] 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 140/234] 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 141/234] 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 142/234] 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 143/234] 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 144/234] 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 145/234] 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 146/234] 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 147/234] 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 148/234] 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 149/234] 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 150/234] 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 151/234] 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 152/234] 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 153/234] 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 154/234] 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 155/234] 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 156/234] 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 157/234] 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 158/234] 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 159/234] 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 160/234] 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 161/234] 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 162/234] 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 163/234] 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 164/234] "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 165/234] 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 166/234] 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 167/234] 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 168/234] 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 169/234] 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 170/234] 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 171/234] 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 172/234] 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 173/234] 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 174/234] 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 175/234] 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 176/234] 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 177/234] 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 178/234] 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 179/234] 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 180/234] 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 181/234] 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 182/234] 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 183/234] 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 184/234] 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 185/234] 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 186/234] 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 187/234] 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 188/234] 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 189/234] 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 190/234] 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 191/234] 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 192/234] 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 193/234] 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 194/234] 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 195/234] 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 196/234] 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 197/234] 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 198/234] 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 199/234] 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 200/234] 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 201/234] 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 202/234] 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 203/234] 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 204/234] 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 205/234] 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 206/234] 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 207/234] 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 208/234] 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 209/234] 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 210/234] 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 211/234] 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 212/234] 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 213/234] 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 214/234] 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 215/234] 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 216/234] 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 217/234] 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 218/234] 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 219/234] 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 220/234] 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 221/234] 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 222/234] 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 223/234] 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 224/234] 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 225/234] 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 226/234] 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 227/234] 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 228/234] 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 229/234] 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 230/234] 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 231/234] 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 232/234] 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 233/234] 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 234/234] 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 )); }