Compare commits

..

No commits in common. "master" and "v3.0.4" have entirely different histories.

129 changed files with 1225 additions and 3229 deletions

View file

@ -1,12 +1,7 @@
language: php language: php
cache:
directories:
- $HOME/.composer/cache
php: php:
- 5.3 - 5.3
- 5.4
- 5.5 - 5.5
- 5.6 - 5.6
@ -16,6 +11,8 @@ matrix:
env: SYMFONY_VERSION='2.3.*' env: SYMFONY_VERSION='2.3.*'
- php: 5.5 - php: 5.5
env: SYMFONY_VERSION='2.5.*' env: SYMFONY_VERSION='2.5.*'
- php: 5.5
env: SYMFONY_VERSION='dev-master'
before_script: before_script:
- /usr/share/elasticsearch/bin/elasticsearch -v - /usr/share/elasticsearch/bin/elasticsearch -v
@ -25,8 +22,7 @@ before_script:
- sh -c 'if [ "$SYMFONY_VERSION" != "" ]; then composer require --dev --no-update symfony/symfony=$SYMFONY_VERSION; fi;' - sh -c 'if [ "$SYMFONY_VERSION" != "" ]; then composer require --dev --no-update symfony/symfony=$SYMFONY_VERSION; fi;'
- composer install --dev --prefer-source - composer install --dev --prefer-source
script: script: vendor/bin/phpunit --coverage-clover=coverage.clover
- vendor/bin/phpunit --coverage-clover=coverage.clover
services: services:
- elasticsearch - elasticsearch

View file

@ -12,29 +12,6 @@ https://github.com/FriendsOfSymfony/FOSElasticaBundle/compare/v3.0.0...v3.0.1
To generate a changelog summary since the last version, run To generate a changelog summary since the last version, run
`git log --no-merges --oneline v3.0.0...3.0.x` `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
* Added support for `connectionStrategy` Elastica configuration #732
* Allow Elastica 1.4
* 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)
* 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 * 3.0.0-ALPHA6
* Moved `is_indexable_callback` from the listener properties to a type property called * Moved `is_indexable_callback` from the listener properties to a type property called

View file

@ -1,61 +0,0 @@
CHANGELOG for 3.1.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.3 (2015-04-02)
* Fix Symfony 2.3 compatibility
* 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
* 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.
* BC BREAK: `ObjectPersisterInterface` gains the method `handlesObject` that
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. #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
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.
* 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
* Fixed a case where ProgressCommand would always ignore errors regardless of
--ignore-errors being passed or not.
* Added a `SliceFetcher` abstraction for Doctrine providers that get more
information about the previous slice allowing for optimising queries during
population. #725
* 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
* Added indexable callback support for the __invoke method of a service. #823

View file

@ -2,8 +2,6 @@
namespace FOS\ElasticaBundle\Command; namespace FOS\ElasticaBundle\Command;
use FOS\ElasticaBundle\Event\IndexPopulateEvent;
use FOS\ElasticaBundle\Event\TypePopulateEvent;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Helper\DialogHelper; use Symfony\Component\Console\Helper\DialogHelper;
use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputOption;
@ -12,28 +10,18 @@ use Symfony\Component\Console\Output\OutputInterface;
use FOS\ElasticaBundle\IndexManager; use FOS\ElasticaBundle\IndexManager;
use FOS\ElasticaBundle\Provider\ProviderRegistry; use FOS\ElasticaBundle\Provider\ProviderRegistry;
use FOS\ElasticaBundle\Resetter; use FOS\ElasticaBundle\Resetter;
use Symfony\Component\Console\Helper\ProgressBar; use FOS\ElasticaBundle\Provider\ProviderInterface;
/** /**
* Populate the search index. * Populate the search index
*/ */
class PopulateCommand extends ContainerAwareCommand class PopulateCommand extends ContainerAwareCommand
{ {
/**
* @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
*/
private $dispatcher;
/** /**
* @var IndexManager * @var IndexManager
*/ */
private $indexManager; private $indexManager;
/**
* @var ProgressClosureBuilder
*/
private $progressClosureBuilder;
/** /**
* @var ProviderRegistry * @var ProviderRegistry
*/ */
@ -58,46 +46,31 @@ class PopulateCommand extends ContainerAwareCommand
->addOption('sleep', null, InputOption::VALUE_REQUIRED, 'Sleep time between persisting iterations (microseconds)', 0) ->addOption('sleep', null, InputOption::VALUE_REQUIRED, 'Sleep time between persisting iterations (microseconds)', 0)
->addOption('batch-size', null, InputOption::VALUE_REQUIRED, 'Index packet size (overrides provider config option)') ->addOption('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('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') ->setDescription('Populates search indexes from providers')
; ;
} }
/** /**
* {@inheritDoc} * @see Symfony\Component\Console\Command\Command::initialize()
*/ */
protected function initialize(InputInterface $input, OutputInterface $output) protected function initialize(InputInterface $input, OutputInterface $output)
{ {
$this->dispatcher = $this->getContainer()->get('event_dispatcher');
$this->indexManager = $this->getContainer()->get('fos_elastica.index_manager'); $this->indexManager = $this->getContainer()->get('fos_elastica.index_manager');
$this->providerRegistry = $this->getContainer()->get('fos_elastica.provider_registry'); $this->providerRegistry = $this->getContainer()->get('fos_elastica.provider_registry');
$this->resetter = $this->getContainer()->get('fos_elastica.resetter'); $this->resetter = $this->getContainer()->get('fos_elastica.resetter');
$this->progressClosureBuilder = new ProgressClosureBuilder();
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%");
ProgressBar::setFormatDefinition('debug', " %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%\n%message%");
}
} }
/** /**
* {@inheritDoc} * @see Symfony\Component\Console\Command\Command::execute()
*/ */
protected function execute(InputInterface $input, OutputInterface $output) protected function execute(InputInterface $input, OutputInterface $output)
{ {
$index = $input->getOption('index'); $index = $input->getOption('index');
$type = $input->getOption('type'); $type = $input->getOption('type');
$reset = !$input->getOption('no-reset'); $reset = !$input->getOption('no-reset');
$options = array( $options = $input->getOptions();
'ignore_errors' => $input->getOption('ignore-errors'),
'offset' => $input->getOption('offset'), $options['ignore-errors'] = $input->hasOption('ignore-errors');
'sleep' => $input->getOption('sleep')
);
if ($input->getOption('batch-size')) {
$options['batch_size'] = (int) $input->getOption('batch-size');
}
if ($input->isInteractive() && $reset && $input->getOption('offset')) { if ($input->isInteractive() && $reset && $input->getOption('offset')) {
/** @var DialogHelper $dialog */ /** @var DialogHelper $dialog */
@ -136,22 +109,25 @@ class PopulateCommand extends ContainerAwareCommand
*/ */
private function populateIndex(OutputInterface $output, $index, $reset, $options) private function populateIndex(OutputInterface $output, $index, $reset, $options)
{ {
$event = new IndexPopulateEvent($index, $reset, $options); if ($reset) {
$this->dispatcher->dispatch(IndexPopulateEvent::PRE_INDEX_POPULATE, $event);
if ($event->isReset()) {
$output->writeln(sprintf('<info>Resetting</info> <comment>%s</comment>', $index)); $output->writeln(sprintf('<info>Resetting</info> <comment>%s</comment>', $index));
$this->resetter->resetIndex($index, true); $this->resetter->resetIndex($index, true);
} }
$types = array_keys($this->providerRegistry->getIndexProviders($index)); /** @var $providers ProviderInterface[] */
foreach ($types as $type) { $providers = $this->providerRegistry->getIndexProviders($index);
$this->populateIndexType($output, $index, $type, false, $event->getOptions());
foreach ($providers as $type => $provider) {
$loggerClosure = function($message) use ($output, $index, $type) {
$output->writeln(sprintf('<info>Populating</info> %s/%s, %s', $index, $type, $message));
};
$provider->populate($loggerClosure, $options);
} }
$this->dispatcher->dispatch(IndexPopulateEvent::POST_INDEX_POPULATE, $event); $output->writeln(sprintf('<info>Refreshing</info> <comment>%s</comment>', $index));
$this->resetter->postPopulate($index);
$this->refreshIndex($output, $index); $this->indexManager->getIndex($index)->refresh();
} }
/** /**
@ -165,35 +141,17 @@ class PopulateCommand extends ContainerAwareCommand
*/ */
private function populateIndexType(OutputInterface $output, $index, $type, $reset, $options) private function populateIndexType(OutputInterface $output, $index, $type, $reset, $options)
{ {
$event = new TypePopulateEvent($index, $type, $reset, $options); if ($reset) {
$this->dispatcher->dispatch(TypePopulateEvent::PRE_TYPE_POPULATE, $event);
if ($event->isReset()) {
$output->writeln(sprintf('<info>Resetting</info> <comment>%s/%s</comment>', $index, $type)); $output->writeln(sprintf('<info>Resetting</info> <comment>%s/%s</comment>', $index, $type));
$this->resetter->resetIndexType($index, $type); $this->resetter->resetIndexType($index, $type);
} }
$loggerClosure = function($message) use ($output, $index, $type) {
$output->writeln(sprintf('<info>Populating</info> %s/%s, %s', $index, $type, $message));
};
$provider = $this->providerRegistry->getProvider($index, $type); $provider = $this->providerRegistry->getProvider($index, $type);
$loggerClosure = $this->progressClosureBuilder->build($output, 'Populating', $index, $type); $provider->populate($loggerClosure, $options);
$provider->populate($loggerClosure, $event->getOptions());
$this->dispatcher->dispatch(TypePopulateEvent::POST_TYPE_POPULATE, $event);
$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('<info>Refreshing</info> <comment>%s</comment>', $index)); $output->writeln(sprintf('<info>Refreshing</info> <comment>%s</comment>', $index));
$this->indexManager->getIndex($index)->refresh(); $this->indexManager->getIndex($index)->refresh();

View file

@ -1,103 +0,0 @@
<?php
/**
* This file is part of the FOSElasticaBundle project.
*
* (c) Tim Nagel <tim@nagel.com.au>
*
* 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') ||
!is_callable(array('Symfony\Component\Console\Helper\ProgressBar', 'getProgress'))) {
return $this->buildLegacy($output, $action, $index, $type);
}
$progress = null;
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('<info>%s</info> <error>%s</error>', $action, $message));
$progress->display();
}
$progress->setMessage(sprintf('<info>%s</info> <comment>%s/%s</comment>', $action, $index, $type));
$progress->advance($increment);
};
}
/**
* 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, $message = null) use ($output, $action, $index, $type, &$lastStep, &$current) {
if ($current + $increment > $totalObjects) {
$increment = $totalObjects - $current;
}
if (null !== $message) {
$output->writeln(sprintf('<info>%s</info> <error>%s</error>', $action, $message));
}
$currentTime = microtime(true);
$timeDifference = $currentTime - $lastStep;
$objectsPerSecond = $lastStep ? ($increment / $timeDifference) : $increment;
$lastStep = $currentTime;
$current += $increment;
$percent = 100 * $current / $totalObjects;
$output->writeln(sprintf(
'<info>%s</info> <comment>%s/%s</comment> %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))
));
};
}
}

View file

@ -10,7 +10,7 @@ use FOS\ElasticaBundle\IndexManager;
use FOS\ElasticaBundle\Resetter; use FOS\ElasticaBundle\Resetter;
/** /**
* Reset search indexes. * Reset search indexes
*/ */
class ResetCommand extends ContainerAwareCommand class ResetCommand extends ContainerAwareCommand
{ {
@ -33,7 +33,6 @@ class ResetCommand extends ContainerAwareCommand
->setName('fos:elastica:reset') ->setName('fos:elastica:reset')
->addOption('index', null, InputOption::VALUE_OPTIONAL, 'The index to reset') ->addOption('index', null, InputOption::VALUE_OPTIONAL, 'The index to reset')
->addOption('type', null, InputOption::VALUE_OPTIONAL, 'The type 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') ->setDescription('Reset search indexes')
; ;
} }
@ -52,9 +51,8 @@ class ResetCommand extends ContainerAwareCommand
*/ */
protected function execute(InputInterface $input, OutputInterface $output) protected function execute(InputInterface $input, OutputInterface $output)
{ {
$index = $input->getOption('index'); $index = $input->getOption('index');
$type = $input->getOption('type'); $type = $input->getOption('type');
$force = (bool) $input->getOption('force');
if (null === $index && null !== $type) { if (null === $index && null !== $type) {
throw new \InvalidArgumentException('Cannot specify type option without an index.'); throw new \InvalidArgumentException('Cannot specify type option without an index.');
@ -71,7 +69,7 @@ class ResetCommand extends ContainerAwareCommand
foreach ($indexes as $index) { foreach ($indexes as $index) {
$output->writeln(sprintf('<info>Resetting</info> <comment>%s</comment>', $index)); $output->writeln(sprintf('<info>Resetting</info> <comment>%s</comment>', $index));
$this->resetter->resetIndex($index, false, $force); $this->resetter->resetIndex($index);
} }
} }
} }

View file

@ -11,7 +11,7 @@ use Elastica\Query;
use Elastica\Result; use Elastica\Result;
/** /**
* Searches a type. * Searches a type
*/ */
class SearchCommand extends ContainerAwareCommand class SearchCommand extends ContainerAwareCommand
{ {

View file

@ -53,9 +53,9 @@ class IndexConfig
/** /**
* Constructor expects an array as generated by the Container Configuration builder. * Constructor expects an array as generated by the Container Configuration builder.
* *
* @param string $name * @param string $name
* @param TypeConfig[] $types * @param TypeConfig[] $types
* @param array $config * @param array $config
*/ */
public function __construct($name, array $types, array $config) public function __construct($name, array $types, array $config)
{ {
@ -92,9 +92,7 @@ class IndexConfig
/** /**
* @param string $typeName * @param string $typeName
*
* @return TypeConfig * @return TypeConfig
*
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
*/ */
public function getType($typeName) public function getType($typeName)

View file

@ -20,7 +20,6 @@ interface ManagerInterface
* Returns configuration for an index. * Returns configuration for an index.
* *
* @param $index * @param $index
*
* @return IndexConfig * @return IndexConfig
*/ */
public function getIndexConfiguration($index); public function getIndexConfiguration($index);
@ -37,7 +36,6 @@ interface ManagerInterface
* *
* @param string $index * @param string $index
* @param string $type * @param string $type
*
* @return TypeConfig * @return TypeConfig
*/ */
public function getTypeConfiguration($index, $type); public function getTypeConfiguration($index, $type);

View file

@ -17,10 +17,9 @@ use FOS\ElasticaBundle\Annotation\Search as BaseSearch;
* Annotation class for setting search repository. * Annotation class for setting search repository.
* *
* @Annotation * @Annotation
*
* @deprecated Use FOS\ElasticaBundle\Annotation\Search instead * @deprecated Use FOS\ElasticaBundle\Annotation\Search instead
* @Target("CLASS") * @Target("CLASS")
*/ */
class Search extends BaseSearch class Search extends BaseSearch
{ {
} }

View file

@ -40,7 +40,16 @@ class ContainerSource implements SourceInterface
{ {
$indexes = array(); $indexes = array();
foreach ($this->configArray as $config) { foreach ($this->configArray as $config) {
$types = $this->getTypes($config); $types = array();
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( $index = new IndexConfig($config['name'], $types, array(
'elasticSearchName' => $config['elasticsearch_name'], 'elasticSearchName' => $config['elasticsearch_name'],
'settings' => $config['settings'], 'settings' => $config['settings'],
@ -52,29 +61,4 @@ class ContainerSource implements SourceInterface
return $indexes; 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;
}
} }

View file

@ -23,4 +23,4 @@ interface SourceInterface
* @return \FOS\ElasticaBundle\Configuration\IndexConfig[] * @return \FOS\ElasticaBundle\Configuration\IndexConfig[]
*/ */
public function getConfiguration(); public function getConfiguration();
} }

View file

@ -35,22 +35,6 @@ class TypeConfig
$this->name = $name; $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 * @return string|null
*/ */
@ -77,14 +61,6 @@ class TypeConfig
null; null;
} }
/**
* @return bool|null
*/
public function getNumericDetection()
{
return $this->getConfig('numeric_detection');
}
/** /**
* @return string * @return string
*/ */
@ -101,9 +77,6 @@ class TypeConfig
return $this->getConfig('search_analyzer'); return $this->getConfig('search_analyzer');
} }
/**
* @param string $key
*/
private function getConfig($key) private function getConfig($key)
{ {
return isset($this->config[$key]) ? return isset($this->config[$key]) ?

View file

@ -33,4 +33,4 @@ class ConfigSourcePass implements CompilerPassInterface
$container->getDefinition('fos_elastica.config_manager')->replaceArgument(0, $sources); $container->getDefinition('fos_elastica.config_manager')->replaceArgument(0, $sources);
} }
} }

View file

@ -55,7 +55,6 @@ class RegisterProvidersPass implements CompilerPassInterface
* Returns whether the class implements ProviderInterface. * Returns whether the class implements ProviderInterface.
* *
* @param string $class * @param string $class
*
* @return boolean * @return boolean
*/ */
private function isProviderImplementation($class) private function isProviderImplementation($class)

View file

@ -31,7 +31,7 @@ class TransformerPass implements CompilerPassInterface
throw new InvalidArgumentException('The Transformer must have both a type and an index defined.'); 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);
} }
} }

View file

@ -30,7 +30,7 @@ class Configuration implements ConfigurationInterface
/** /**
* Generates the configuration tree. * Generates the configuration tree.
* *
* @return TreeBuilder * @return \Symfony\Component\Config\Definition\NodeInterface
*/ */
public function getConfigTreeBuilder() public function getConfigTreeBuilder()
{ {
@ -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) private function addClientsSection(ArrayNodeDefinition $rootNode)
{ {
@ -76,30 +76,20 @@ class Configuration implements ConfigurationInterface
->performNoDeepMerging() ->performNoDeepMerging()
// BC - Renaming 'servers' node to 'connections' // BC - Renaming 'servers' node to 'connections'
->beforeNormalization() ->beforeNormalization()
->ifTrue(function ($v) { return isset($v['servers']); }) ->ifTrue(function($v) { return isset($v['servers']); })
->then(function ($v) { ->then(function($v) {
$v['connections'] = $v['servers']; $v['connections'] = $v['servers'];
unset($v['servers']); unset($v['servers']);
return $v; return $v;
}) })
->end() ->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. // If there is no connections array key defined, assume a single connection.
->beforeNormalization() ->beforeNormalization()
->ifTrue(function ($v) { return is_array($v) && !array_key_exists('connections', $v); }) ->ifTrue(function ($v) { return is_array($v) && !array_key_exists('connections', $v); })
->then(function ($v) { ->then(function ($v) {
return array( return array(
'connections' => array($v), 'connections' => array($v)
); );
}) })
->end() ->end()
@ -111,8 +101,8 @@ class Configuration implements ConfigurationInterface
->children() ->children()
->scalarNode('url') ->scalarNode('url')
->validate() ->validate()
->ifTrue(function ($url) { return $url && substr($url, -1) !== '/'; }) ->ifTrue(function($url) { return $url && substr($url, -1) !== '/'; })
->then(function ($url) { return $url.'/'; }) ->then(function($url) { return $url.'/'; })
->end() ->end()
->end() ->end()
->scalarNode('host')->end() ->scalarNode('host')->end()
@ -134,7 +124,6 @@ class Configuration implements ConfigurationInterface
->end() ->end()
->scalarNode('timeout')->end() ->scalarNode('timeout')->end()
->scalarNode('headers')->end() ->scalarNode('headers')->end()
->scalarNode('connectionStrategy')->defaultValue('Simple')->end()
->end() ->end()
->end() ->end()
->end() ->end()
@ -143,7 +132,7 @@ class Configuration implements ConfigurationInterface
} }
/** /**
* Adds the configuration for the "indexes" key. * Adds the configuration for the "indexes" key
*/ */
private function addIndexesSection(ArrayNodeDefinition $rootNode) private function addIndexesSection(ArrayNodeDefinition $rootNode)
{ {
@ -192,14 +181,10 @@ class Configuration implements ConfigurationInterface
->useAttributeAsKey('name') ->useAttributeAsKey('name')
->prototype('array') ->prototype('array')
->treatNullLike(array()) ->treatNullLike(array())
->beforeNormalization()
->ifNull()
->thenEmptyArray()
->end()
// BC - Renaming 'mappings' node to 'properties' // BC - Renaming 'mappings' node to 'properties'
->beforeNormalization() ->beforeNormalization()
->ifTrue(function ($v) { return array_key_exists('mappings', $v); }) ->ifTrue(function($v) { return array_key_exists('mappings', $v); })
->then(function ($v) { ->then(function($v) {
$v['properties'] = $v['mappings']; $v['properties'] = $v['mappings'];
unset($v['mappings']); unset($v['mappings']);
@ -214,17 +199,7 @@ class Configuration implements ConfigurationInterface
isset($v['persistence']['listener']['is_indexable_callback']); isset($v['persistence']['listener']['is_indexable_callback']);
}) })
->then(function ($v) { ->then(function ($v) {
$callback = $v['persistence']['listener']['is_indexable_callback']; $v['indexable_callback'] = $v['persistence']['listener']['is_indexable_callback'];
if (is_array($callback)) {
list($class) = $callback + array(null);
if ($class[0] !== '@' && is_string($class) && !class_exists($class)) {
$callback[0] = '@'.$class;
}
}
$v['indexable_callback'] = $callback;
unset($v['persistence']['listener']['is_indexable_callback']); unset($v['persistence']['listener']['is_indexable_callback']);
return $v; return $v;
@ -250,10 +225,7 @@ class Configuration implements ConfigurationInterface
}) })
->end() ->end()
->children() ->children()
->booleanNode('date_detection')->end()
->arrayNode('dynamic_date_formats')->prototype('scalar')->end()->end()
->scalarNode('index_analyzer')->end() ->scalarNode('index_analyzer')->end()
->booleanNode('numeric_detection')->end()
->scalarNode('search_analyzer')->end() ->scalarNode('search_analyzer')->end()
->variableNode('indexable_callback')->end() ->variableNode('indexable_callback')->end()
->append($this->getPersistenceNode()) ->append($this->getPersistenceNode())
@ -422,7 +394,7 @@ class Configuration implements ConfigurationInterface
} }
/** /**
* Returns the array node used for "_all". * Returns the array node used for "_all"
*/ */
protected function getAllNode() protected function getAllNode()
{ {
@ -441,7 +413,7 @@ class Configuration implements ConfigurationInterface
} }
/** /**
* Returns the array node used for "_timestamp". * Returns the array node used for "_timestamp"
*/ */
protected function getTimestampNode() protected function getTimestampNode()
{ {
@ -462,7 +434,7 @@ class Configuration implements ConfigurationInterface
} }
/** /**
* Returns the array node used for "_ttl". * Returns the array node used for "_ttl"
*/ */
protected function getTtlNode() protected function getTtlNode()
{ {
@ -491,9 +463,9 @@ class Configuration implements ConfigurationInterface
$node $node
->validate() ->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') ->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') ->thenInvalid('Propel doesn\'t support the "repository" parameter')
->end() ->end()
->children() ->children()
@ -508,13 +480,9 @@ class Configuration implements ConfigurationInterface
->scalarNode('identifier')->defaultValue('id')->end() ->scalarNode('identifier')->defaultValue('id')->end()
->arrayNode('provider') ->arrayNode('provider')
->children() ->children()
->scalarNode('query_builder_method')->defaultValue('createQueryBuilder')->end()
->scalarNode('batch_size')->defaultValue(100)->end() ->scalarNode('batch_size')->defaultValue(100)->end()
->scalarNode('clear_object_manager')->defaultTrue()->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() ->scalarNode('service')->end()
->end() ->end()
->end() ->end()

View file

@ -80,10 +80,9 @@ class FOSElasticaExtension extends Extension
} }
/** /**
* @param array $config * @param array $config
* @param ContainerBuilder $container * @param ContainerBuilder $container
* * @return Configuration|null|\Symfony\Component\Config\Definition\ConfigurationInterface
* @return Configuration
*/ */
public function getConfiguration(array $config, ContainerBuilder $container) public function getConfiguration(array $config, ContainerBuilder $container)
{ {
@ -93,9 +92,8 @@ class FOSElasticaExtension extends Extension
/** /**
* Loads the configured clients. * 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 * @param ContainerBuilder $container A ContainerBuilder instance
*
* @return array * @return array
*/ */
private function loadClients(array $clients, ContainerBuilder $container) private function loadClients(array $clients, ContainerBuilder $container)
@ -116,7 +114,7 @@ class FOSElasticaExtension extends Extension
$this->clients[$name] = array( $this->clients[$name] = array(
'id' => $clientId, 'id' => $clientId,
'reference' => new Reference($clientId), 'reference' => new Reference($clientId)
); );
} }
} }
@ -124,11 +122,9 @@ class FOSElasticaExtension extends Extension
/** /**
* Loads the configured indexes. * 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 * @param ContainerBuilder $container A ContainerBuilder instance
*
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
*
* @return array * @return array
*/ */
private function loadIndexes(array $indexes, ContainerBuilder $container) private function loadIndexes(array $indexes, ContainerBuilder $container)
@ -137,7 +133,7 @@ class FOSElasticaExtension extends Extension
foreach ($indexes as $name => $index) { foreach ($indexes as $name => $index) {
$indexId = sprintf('fos_elastica.index.%s', $name); $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 = new DefinitionDecorator('fos_elastica.index_prototype');
$indexDef->replaceArgument(0, $indexName); $indexDef->replaceArgument(0, $indexName);
@ -177,9 +173,8 @@ class FOSElasticaExtension extends Extension
* Loads the configured index finders. * Loads the configured index finders.
* *
* @param \Symfony\Component\DependencyInjection\ContainerBuilder $container * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
* @param string $name The index name * @param string $name The index name
* @param Reference $index Reference to the related index * @param Reference $index Reference to the related index
*
* @return string * @return string
*/ */
private function loadIndexFinder(ContainerBuilder $container, $name, Reference $index) private function loadIndexFinder(ContainerBuilder $container, $name, Reference $index)
@ -202,10 +197,10 @@ class FOSElasticaExtension extends Extension
/** /**
* Loads the configured types. * Loads the configured types.
* *
* @param array $types * @param array $types
* @param ContainerBuilder $container * @param ContainerBuilder $container
* @param array $indexConfig * @param array $indexConfig
* @param array $indexableCallbacks * @param array $indexableCallbacks
*/ */
private function loadTypes(array $types, ContainerBuilder $container, array $indexConfig, array &$indexableCallbacks) private function loadTypes(array $types, ContainerBuilder $container, array $indexConfig, array &$indexableCallbacks)
{ {
@ -246,9 +241,6 @@ class FOSElasticaExtension extends Extension
'serializer', 'serializer',
'index_analyzer', 'index_analyzer',
'search_analyzer', 'search_analyzer',
'date_detection',
'dynamic_date_formats',
'numeric_detection',
) as $field) { ) as $field) {
$typeConfig['config'][$field] = array_key_exists($field, $type) ? $typeConfig['config'][$field] = array_key_exists($field, $type) ?
$type[$field] : $type[$field] :
@ -285,13 +277,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 ContainerBuilder $container
* @param Reference $typeRef * @param Reference $typeRef
* @param string $indexName * @param string $indexName
* @param string $typeName * @param string $typeName
*/ */
private function loadTypePersistenceIntegration(array $typeConfig, ContainerBuilder $container, Reference $typeRef, $indexName, $typeName) private function loadTypePersistenceIntegration(array $typeConfig, ContainerBuilder $container, Reference $typeRef, $indexName, $typeName)
{ {
@ -315,11 +307,10 @@ class FOSElasticaExtension extends Extension
/** /**
* Creates and loads an ElasticaToModelTransformer. * Creates and loads an ElasticaToModelTransformer.
* *
* @param array $typeConfig * @param array $typeConfig
* @param ContainerBuilder $container * @param ContainerBuilder $container
* @param string $indexName * @param string $indexName
* @param string $typeName * @param string $typeName
*
* @return string * @return string
*/ */
private function loadElasticaToModelTransformer(array $typeConfig, ContainerBuilder $container, $indexName, $typeName) private function loadElasticaToModelTransformer(array $typeConfig, ContainerBuilder $container, $indexName, $typeName)
@ -351,11 +342,10 @@ class FOSElasticaExtension extends Extension
/** /**
* Creates and loads a ModelToElasticaTransformer for an index/type. * Creates and loads a ModelToElasticaTransformer for an index/type.
* *
* @param array $typeConfig * @param array $typeConfig
* @param ContainerBuilder $container * @param ContainerBuilder $container
* @param string $indexName * @param string $indexName
* @param string $typeName * @param string $typeName
*
* @return string * @return string
*/ */
private function loadModelToElasticaTransformer(array $typeConfig, ContainerBuilder $container, $indexName, $typeName) private function loadModelToElasticaTransformer(array $typeConfig, ContainerBuilder $container, $indexName, $typeName)
@ -371,7 +361,7 @@ class FOSElasticaExtension extends Extension
$serviceId = sprintf('fos_elastica.model_to_elastica_transformer.%s.%s', $indexName, $typeName); $serviceId = sprintf('fos_elastica.model_to_elastica_transformer.%s.%s', $indexName, $typeName);
$serviceDef = new DefinitionDecorator($abstractId); $serviceDef = new DefinitionDecorator($abstractId);
$serviceDef->replaceArgument(0, array( $serviceDef->replaceArgument(0, array(
'identifier' => $typeConfig['identifier'], 'identifier' => $typeConfig['identifier']
)); ));
$container->setDefinition($serviceId, $serviceDef); $container->setDefinition($serviceId, $serviceDef);
@ -381,13 +371,12 @@ class FOSElasticaExtension extends Extension
/** /**
* Creates and loads an object persister for a type. * Creates and loads an object persister for a type.
* *
* @param array $typeConfig * @param array $typeConfig
* @param Reference $typeRef * @param Reference $typeRef
* @param ContainerBuilder $container * @param ContainerBuilder $container
* @param string $indexName * @param string $indexName
* @param string $typeName * @param string $typeName
* @param string $transformerId * @param string $transformerId
*
* @return string * @return string
*/ */
private function loadObjectPersister(array $typeConfig, Reference $typeRef, ContainerBuilder $container, $indexName, $typeName, $transformerId) private function loadObjectPersister(array $typeConfig, Reference $typeRef, ContainerBuilder $container, $indexName, $typeName, $transformerId)
@ -404,12 +393,7 @@ class FOSElasticaExtension extends Extension
$arguments[] = array(new Reference($callbackId), 'serialize'); $arguments[] = array(new Reference($callbackId), 'serialize');
} else { } else {
$abstractId = 'fos_elastica.object_persister'; $abstractId = 'fos_elastica.object_persister';
$mapping = $this->indexConfigs[$indexName]['types'][$typeName]['mapping']; $arguments[] = $this->indexConfigs[$indexName]['types'][$typeName]['mapping']['properties'];
$argument = $mapping['properties'];
if (isset($mapping['_parent'])) {
$argument['_parent'] = $mapping['_parent'];
}
$arguments[] = $argument;
} }
$serviceId = sprintf('fos_elastica.object_persister.%s.%s', $indexName, $typeName); $serviceId = sprintf('fos_elastica.object_persister.%s.%s', $indexName, $typeName);
@ -426,12 +410,11 @@ class FOSElasticaExtension extends Extension
/** /**
* Loads a provider for a type. * Loads a provider for a type.
* *
* @param array $typeConfig * @param array $typeConfig
* @param ContainerBuilder $container * @param ContainerBuilder $container
* @param string $objectPersisterId * @param string $objectPersisterId
* @param string $indexName * @param string $indexName
* @param string $typeName * @param string $typeName
*
* @return string * @return string
*/ */
private function loadTypeProvider(array $typeConfig, ContainerBuilder $container, $objectPersisterId, $indexName, $typeName) private function loadTypeProvider(array $typeConfig, ContainerBuilder $container, $objectPersisterId, $indexName, $typeName)
@ -444,7 +427,7 @@ class FOSElasticaExtension extends Extension
* index and type names were "prototype" and a driver, respectively. * index and type names were "prototype" and a driver, respectively.
*/ */
$providerId = sprintf('fos_elastica.provider.%s.%s', $indexName, $typeName); $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->addTag('fos_elastica.provider', array('index' => $indexName, 'type' => $typeName));
$providerDef->replaceArgument(0, new Reference($objectPersisterId)); $providerDef->replaceArgument(0, new Reference($objectPersisterId));
$providerDef->replaceArgument(2, $typeConfig['model']); $providerDef->replaceArgument(2, $typeConfig['model']);
@ -461,12 +444,11 @@ class FOSElasticaExtension extends Extension
/** /**
* Loads doctrine listeners to handle indexing of new or updated objects. * Loads doctrine listeners to handle indexing of new or updated objects.
* *
* @param array $typeConfig * @param array $typeConfig
* @param ContainerBuilder $container * @param ContainerBuilder $container
* @param string $objectPersisterId * @param string $objectPersisterId
* @param string $indexName * @param string $indexName
* @param string $typeName * @param string $typeName
*
* @return string * @return string
*/ */
private function loadTypeListener(array $typeConfig, ContainerBuilder $container, $objectPersisterId, $indexName, $typeName) private function loadTypeListener(array $typeConfig, ContainerBuilder $container, $objectPersisterId, $indexName, $typeName)
@ -482,30 +464,19 @@ class FOSElasticaExtension extends Extension
$listenerId = sprintf('fos_elastica.listener.%s.%s', $indexName, $typeName); $listenerId = sprintf('fos_elastica.listener.%s.%s', $indexName, $typeName);
$listenerDef = new DefinitionDecorator($abstractListenerId); $listenerDef = new DefinitionDecorator($abstractListenerId);
$listenerDef->replaceArgument(0, new Reference($objectPersisterId)); $listenerDef->replaceArgument(0, new Reference($objectPersisterId));
$listenerDef->replaceArgument(2, array( $listenerDef->replaceArgument(1, $this->getDoctrineEvents($typeConfig));
$listenerDef->replaceArgument(3, array(
'identifier' => $typeConfig['identifier'], 'identifier' => $typeConfig['identifier'],
'indexName' => $indexName, 'indexName' => $indexName,
'typeName' => $typeName, 'typeName' => $typeName,
)); ));
$listenerDef->replaceArgument(3, $typeConfig['listener']['logger'] ? if ($typeConfig['listener']['logger']) {
new Reference($typeConfig['listener']['logger']) : $listenerDef->replaceArgument(4, new Reference($typeConfig['listener']['logger']));
null
);
$tagName = null;
switch ($typeConfig['driver']) {
case 'orm':
$tagName = 'doctrine.event_listener';
break;
case 'mongodb':
$tagName = 'doctrine_mongodb.odm.event_listener';
break;
} }
if (null !== $tagName) { switch ($typeConfig['driver']) {
foreach ($this->getDoctrineEvents($typeConfig) as $event) { case 'orm': $listenerDef->addTag('doctrine.event_subscriber'); break;
$listenerDef->addTag($tagName, array('event' => $event)); case 'mongodb': $listenerDef->addTag('doctrine_mongodb.odm.event_subscriber'); break;
}
} }
$container->setDefinition($listenerId, $listenerDef); $container->setDefinition($listenerId, $listenerDef);
@ -514,7 +485,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) private function getDoctrineEvents(array $typeConfig)
{ {
@ -527,6 +498,7 @@ class FOSElasticaExtension extends Extension
break; break;
default: default:
throw new InvalidArgumentException(sprintf('Cannot determine events for driver "%s"', $typeConfig['driver'])); throw new InvalidArgumentException(sprintf('Cannot determine events for driver "%s"', $typeConfig['driver']));
break;
} }
$events = array(); $events = array();
@ -534,7 +506,7 @@ class FOSElasticaExtension extends Extension
'insert' => array(constant($eventsClass.'::postPersist')), 'insert' => array(constant($eventsClass.'::postPersist')),
'update' => array(constant($eventsClass.'::postUpdate')), 'update' => array(constant($eventsClass.'::postUpdate')),
'delete' => array(constant($eventsClass.'::preRemove')), '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) { foreach ($eventMapping as $event => $doctrineEvents) {
@ -549,13 +521,12 @@ class FOSElasticaExtension extends Extension
/** /**
* Loads a Type specific Finder. * Loads a Type specific Finder.
* *
* @param array $typeConfig * @param array $typeConfig
* @param ContainerBuilder $container * @param ContainerBuilder $container
* @param string $elasticaToModelId * @param $elasticaToModelId
* @param Reference $typeRef * @param Reference $typeRef
* @param string $indexName * @param string $indexName
* @param string $typeName * @param string $typeName
*
* @return string * @return string
*/ */
private function loadTypeFinder(array $typeConfig, ContainerBuilder $container, $elasticaToModelId, Reference $typeRef, $indexName, $typeName) private function loadTypeFinder(array $typeConfig, ContainerBuilder $container, $elasticaToModelId, Reference $typeRef, $indexName, $typeName)
@ -582,7 +553,7 @@ class FOSElasticaExtension extends Extension
} }
/** /**
* Loads the index manager. * Loads the index manager
* *
* @param ContainerBuilder $container * @param ContainerBuilder $container
**/ **/
@ -600,7 +571,7 @@ class FOSElasticaExtension extends Extension
* Makes sure a specific driver has been loaded. * Makes sure a specific driver has been loaded.
* *
* @param ContainerBuilder $container * @param ContainerBuilder $container
* @param string $driver * @param string $driver
*/ */
private function loadDriver(ContainerBuilder $container, $driver) private function loadDriver(ContainerBuilder $container, $driver)
{ {
@ -616,7 +587,7 @@ class FOSElasticaExtension extends Extension
/** /**
* Loads and configures the serializer prototype. * Loads and configures the serializer prototype.
* *
* @param array $config * @param array $config
* @param ContainerBuilder $container * @param ContainerBuilder $container
*/ */
private function loadSerializer($config, ContainerBuilder $container) private function loadSerializer($config, ContainerBuilder $container)
@ -635,7 +606,7 @@ class FOSElasticaExtension extends Extension
/** /**
* Creates a default manager alias for defined default manager or the first loaded driver. * Creates a default manager alias for defined default manager or the first loaded driver.
* *
* @param string $defaultManager * @param string $defaultManager
* @param ContainerBuilder $container * @param ContainerBuilder $container
*/ */
private function createDefaultManagerAlias($defaultManager, ContainerBuilder $container) private function createDefaultManagerAlias($defaultManager, ContainerBuilder $container)
@ -659,9 +630,7 @@ class FOSElasticaExtension extends Extension
* Returns a reference to a client given its configured name. * Returns a reference to a client given its configured name.
* *
* @param string $clientName * @param string $clientName
*
* @return Reference * @return Reference
*
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
*/ */
private function getClient($clientName) private function getClient($clientName)

View file

@ -2,34 +2,32 @@
namespace FOS\ElasticaBundle\Doctrine; namespace FOS\ElasticaBundle\Doctrine;
use Doctrine\Common\Persistence\ManagerRegistry;
use FOS\ElasticaBundle\HybridResult; use FOS\ElasticaBundle\HybridResult;
use FOS\ElasticaBundle\Transformer\AbstractElasticaToModelTransformer as BaseTransformer; use FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface;
use FOS\ElasticaBundle\Transformer\HighlightableModelInterface; use FOS\ElasticaBundle\Transformer\HighlightableModelInterface;
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
/** /**
* Maps Elastica documents with Doctrine objects * Maps Elastica documents with Doctrine objects
* This mapper assumes an exact match between * This mapper assumes an exact match between
* elastica documents ids and doctrine object ids. * elastica documents ids and doctrine object ids
*/ */
abstract class AbstractElasticaToModelTransformer extends BaseTransformer abstract class AbstractElasticaToModelTransformer implements ElasticaToModelTransformerInterface
{ {
/** /**
* Manager registry. * Manager registry
*
* @var ManagerRegistry
*/ */
protected $registry = null; 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 * @var string
*/ */
protected $objectClass = null; protected $objectClass = null;
/** /**
* Optional parameters. * Optional parameters
* *
* @var array * @var array
*/ */
@ -41,13 +39,20 @@ abstract class AbstractElasticaToModelTransformer extends BaseTransformer
); );
/** /**
* Instantiates a new Mapper. * PropertyAccessor instance
* *
* @param ManagerRegistry $registry * @var PropertyAccessorInterface
* @param string $objectClass
* @param array $options
*/ */
public function __construct(ManagerRegistry $registry, $objectClass, array $options = array()) protected $propertyAccessor;
/**
* Instantiates a new Mapper
*
* @param object $registry
* @param string $objectClass
* @param array $options
*/
public function __construct($registry, $objectClass, array $options = array())
{ {
$this->registry = $registry; $this->registry = $registry;
$this->objectClass = $objectClass; $this->objectClass = $objectClass;
@ -64,14 +69,22 @@ abstract class AbstractElasticaToModelTransformer extends BaseTransformer
return $this->objectClass; 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 * 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 * @param array $elasticaObjects of elastica objects
*
* @throws \RuntimeException * @throws \RuntimeException
*
* @return array * @return array
**/ **/
public function transform(array $elasticaObjects) public function transform(array $elasticaObjects)
@ -96,7 +109,11 @@ abstract class AbstractElasticaToModelTransformer extends BaseTransformer
// sort objects in the order of ids // sort objects in the order of ids
$idPos = array_flip($ids); $idPos = array_flip($ids);
$identifier = $this->options['identifier']; $identifier = $this->options['identifier'];
usort($objects, $this->getSortingClosure($idPos, $identifier)); $propertyAccessor = $this->propertyAccessor;
usort($objects, function($a, $b) use ($idPos, $identifier, $propertyAccessor)
{
return $idPos[$propertyAccessor->getValue($a, $identifier)] > $idPos[$propertyAccessor->getValue($b, $identifier)];
});
return $objects; return $objects;
} }
@ -120,7 +137,7 @@ abstract class AbstractElasticaToModelTransformer extends BaseTransformer
} }
/** /**
* {@inheritDoc} * {@inheritdoc}
*/ */
public function getIdentifierField() public function getIdentifierField()
{ {
@ -128,12 +145,11 @@ abstract class AbstractElasticaToModelTransformer extends BaseTransformer
} }
/** /**
* 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 * @return array of objects or arrays
*/ */
abstract protected function findByIdentifiers(array $identifierValues, $hydrate); protected abstract function findByIdentifiers(array $identifierValues, $hydrate);
} }

View file

@ -7,61 +7,125 @@ use Elastica\Exception\Bulk\ResponseException as BulkResponseException;
use FOS\ElasticaBundle\Persister\ObjectPersisterInterface; use FOS\ElasticaBundle\Persister\ObjectPersisterInterface;
use FOS\ElasticaBundle\Provider\AbstractProvider as BaseAbstractProvider; use FOS\ElasticaBundle\Provider\AbstractProvider as BaseAbstractProvider;
use FOS\ElasticaBundle\Provider\IndexableInterface; use FOS\ElasticaBundle\Provider\IndexableInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
abstract class AbstractProvider extends BaseAbstractProvider abstract class AbstractProvider extends BaseAbstractProvider
{ {
/**
* @var SliceFetcherInterface
*/
private $sliceFetcher;
/**
* @var ManagerRegistry
*/
protected $managerRegistry; protected $managerRegistry;
/** /**
* Constructor. * Constructor.
* *
* @param ObjectPersisterInterface $objectPersister * @param ObjectPersisterInterface $objectPersister
* @param IndexableInterface $indexable * @param IndexableInterface $indexable
* @param string $objectClass * @param string $objectClass
* @param array $baseOptions * @param array $options
* @param ManagerRegistry $managerRegistry * @param ManagerRegistry $managerRegistry
* @param SliceFetcherInterface $sliceFetcher
*/ */
public function __construct( public function __construct(
ObjectPersisterInterface $objectPersister, ObjectPersisterInterface $objectPersister,
IndexableInterface $indexable, IndexableInterface $indexable,
$objectClass, $objectClass,
array $baseOptions, array $options,
ManagerRegistry $managerRegistry, ManagerRegistry $managerRegistry
SliceFetcherInterface $sliceFetcher = null
) { ) {
parent::__construct($objectPersister, $indexable, $objectClass, $baseOptions); parent::__construct($objectPersister, $indexable, $objectClass, array_merge(array(
'clear_object_manager' => true,
'debug_logging' => false,
'ignore_errors' => false,
'query_builder_method' => 'createQueryBuilder',
), $options));
$this->managerRegistry = $managerRegistry; $this->managerRegistry = $managerRegistry;
$this->sliceFetcher = $sliceFetcher; }
/**
* @see FOS\ElasticaBundle\Provider\ProviderInterface::populate()
*/
public function populate(\Closure $loggerClosure = null, array $options = array())
{
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);
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('<info>Entire batch was filtered away, skipping...</info>');
}
continue;
}
if (!$ignoreErrors) {
$this->objectPersister->insertMany($objects);
} else {
try {
$this->objectPersister->insertMany($objects);
} catch(BulkResponseException $e) {
if ($loggerClosure) {
$loggerClosure(sprintf('<error>%s</error>',$e->getMessage()));
}
}
}
if ($this->options['clear_object_manager']) {
$manager->clear();
}
usleep($sleep);
if ($loggerClosure) {
$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()));
}
}
if (!$this->options['debug_logging']) {
$this->enableLogging($logger);
}
} }
/** /**
* Counts objects that would be indexed using the query builder. * Counts objects that would be indexed using the query builder.
* *
* @param object $queryBuilder * @param object $queryBuilder
*
* @return integer * @return integer
*/ */
abstract protected function countObjects($queryBuilder); protected abstract function countObjects($queryBuilder);
/** /**
* Creates the query builder, which will be used to fetch objects to index. * Disables logging and returns the logger that was previously set.
* *
* @param string $method * @return mixed
*
* @return object
*/ */
abstract protected function createQueryBuilder($method); 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. * Fetches a slice of objects using the query builder.
@ -69,102 +133,14 @@ abstract class AbstractProvider extends BaseAbstractProvider
* @param object $queryBuilder * @param object $queryBuilder
* @param integer $limit * @param integer $limit
* @param integer $offset * @param integer $offset
*
* @return array * @return array
*/ */
abstract protected function fetchSlice($queryBuilder, $limit, $offset); protected abstract function fetchSlice($queryBuilder, $limit, $offset);
/** /**
* {@inheritDoc} * Creates the query builder, which will be used to fetch objects to index.
*/
protected function doPopulate($options, \Closure $loggerClosure = null)
{
$manager = $this->managerRegistry->getManagerForClass($this->objectClass);
$queryBuilder = $this->createQueryBuilder($options['query_builder_method']);
$nbObjects = $this->countObjects($queryBuilder);
$offset = $options['offset'];
$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);
}
} catch (BulkResponseException $e) {
if (!$options['ignore_errors']) {
throw $e;
}
if (null !== $loggerClosure) {
$loggerClosure(
$options['batch_size'],
$nbObjects,
sprintf('<error>%s</error>', $e->getMessage())
);
}
}
if ($options['clear_object_manager']) {
$manager->clear();
}
usleep($options['sleep']);
if (null !== $loggerClosure) {
$loggerClosure($options['batch_size'], $nbObjects);
}
}
}
/**
* {@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
));
}
/**
* If this Provider has a SliceFetcher defined, we use it instead of falling back to
* the fetchSlice methods defined in the ORM/MongoDB subclasses.
* *
* @param $queryBuilder * @return object
* @param int $limit
* @param int $offset
* @param array $lastSlice
*
* @return array
*/ */
private function getSlice($queryBuilder, $limit, $offset, $lastSlice) protected abstract function createQueryBuilder();
{
if (!$this->sliceFetcher) {
return $this->fetchSlice($queryBuilder, $limit, $offset);
}
$manager = $this->managerRegistry->getManagerForClass($this->objectClass);
$identifierFieldNames = $manager
->getClassMetadata($this->objectClass)
->getIdentifierFieldNames();
return $this->sliceFetcher->fetch(
$queryBuilder,
$limit,
$offset,
$lastSlice,
$identifierFieldNames
);
}
} }

View file

@ -2,11 +2,11 @@
namespace FOS\ElasticaBundle\Doctrine; namespace FOS\ElasticaBundle\Doctrine;
use Doctrine\Common\Persistence\Event\LifecycleEventArgs; use Doctrine\Common\EventArgs;
use FOS\ElasticaBundle\Persister\ObjectPersister; use Doctrine\Common\EventSubscriber;
use FOS\ElasticaBundle\Persister\ObjectPersisterInterface; use FOS\ElasticaBundle\Persister\ObjectPersisterInterface;
use FOS\ElasticaBundle\Persister\ObjectPersister;
use FOS\ElasticaBundle\Provider\IndexableInterface; use FOS\ElasticaBundle\Provider\IndexableInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\PropertyAccess\PropertyAccess; use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\PropertyAccess\PropertyAccessorInterface; use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
@ -14,52 +14,49 @@ use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
* Automatically update ElasticSearch based on changes to the Doctrine source * Automatically update ElasticSearch based on changes to the Doctrine source
* data. One listener is generated for each Doctrine entity / ElasticSearch type. * data. One listener is generated for each Doctrine entity / ElasticSearch type.
*/ */
class Listener class Listener implements EventSubscriber
{ {
/** /**
* Object persister. * Object persister
* *
* @var ObjectPersisterInterface * @var ObjectPersister
*/ */
protected $objectPersister; protected $objectPersister;
/** /**
* Configuration for the listener. * List of subscribed events
* *
* @var array * @var array
*/ */
protected $events;
/**
* Configuration for the listener
*
* @var string
*/
private $config; private $config;
/** /**
* Objects scheduled for insertion. * Objects scheduled for insertion and replacement
*
* @var array
*/ */
public $scheduledForInsertion = array(); public $scheduledForInsertion = array();
/**
* Objects scheduled to be updated or removed.
*
* @var array
*/
public $scheduledForUpdate = array(); public $scheduledForUpdate = array();
/** /**
* IDs of objects scheduled for removal. * IDs of objects scheduled for removal
*
* @var array
*/ */
public $scheduledForDeletion = array(); public $scheduledForDeletion = array();
/** /**
* PropertyAccessor instance. * PropertyAccessor instance
* *
* @var PropertyAccessorInterface * @var PropertyAccessorInterface
*/ */
protected $propertyAccessor; protected $propertyAccessor;
/** /**
* @var IndexableInterface * @var \FOS\ElasticaBundle\Provider\IndexableInterface
*/ */
private $indexable; private $indexable;
@ -67,50 +64,71 @@ class Listener
* Constructor. * Constructor.
* *
* @param ObjectPersisterInterface $objectPersister * @param ObjectPersisterInterface $objectPersister
* @param IndexableInterface $indexable * @param array $events
* @param array $config * @param IndexableInterface $indexable
* @param LoggerInterface $logger * @param array $config
* @param null $logger
*/ */
public function __construct( public function __construct(
ObjectPersisterInterface $objectPersister, ObjectPersisterInterface $objectPersister,
array $events,
IndexableInterface $indexable, IndexableInterface $indexable,
array $config = array(), array $config = array(),
LoggerInterface $logger = null $logger = null
) { ) {
$this->config = array_merge(array( $this->config = array_merge(array(
'identifier' => 'id', 'identifier' => 'id',
), $config); ), $config);
$this->events = $events;
$this->indexable = $indexable; $this->indexable = $indexable;
$this->objectPersister = $objectPersister; $this->objectPersister = $objectPersister;
$this->propertyAccessor = PropertyAccess::createPropertyAccessor(); $this->propertyAccessor = PropertyAccess::createPropertyAccessor();
if ($logger && $this->objectPersister instanceof ObjectPersister) { if ($logger) {
$this->objectPersister->setLogger($logger); $this->objectPersister->setLogger($logger);
} }
} }
/** /**
* Looks for new objects that should be indexed. * @see Doctrine\Common\EventSubscriber::getSubscribedEvents()
*
* @param LifecycleEventArgs $eventArgs
*/ */
public function postPersist(LifecycleEventArgs $eventArgs) public function getSubscribedEvents()
{ {
$entity = $eventArgs->getObject(); return $this->events;
}
/**
* Provides unified method for retrieving a doctrine object from an EventArgs instance
*
* @param EventArgs $eventArgs
* @return object Entity | Document
* @throws \RuntimeException if no valid getter is found.
*/
private function getDoctrineObject(EventArgs $eventArgs)
{
if (method_exists($eventArgs, 'getObject')) {
return $eventArgs->getObject();
} elseif (method_exists($eventArgs, 'getEntity')) {
return $eventArgs->getEntity();
} elseif (method_exists($eventArgs, 'getDocument')) {
return $eventArgs->getDocument();
}
throw new \RuntimeException('Unable to retrieve object from EventArgs.');
}
public function postPersist(EventArgs $eventArgs)
{
$entity = $this->getDoctrineObject($eventArgs);
if ($this->objectPersister->handlesObject($entity) && $this->isObjectIndexable($entity)) { if ($this->objectPersister->handlesObject($entity) && $this->isObjectIndexable($entity)) {
$this->scheduledForInsertion[] = $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 = $eventArgs->getObject(); $entity = $this->getDoctrineObject($eventArgs);
if ($this->objectPersister->handlesObject($entity)) { if ($this->objectPersister->handlesObject($entity)) {
if ($this->isObjectIndexable($entity)) { if ($this->isObjectIndexable($entity)) {
@ -124,13 +142,11 @@ class Listener
/** /**
* Delete objects preRemove instead of postRemove so that we have access to the id. Because this is called * 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
*
* @param LifecycleEventArgs $eventArgs
*/ */
public function preRemove(LifecycleEventArgs $eventArgs) public function preRemove(EventArgs $eventArgs)
{ {
$entity = $eventArgs->getObject(); $entity = $this->getDoctrineObject($eventArgs);
if ($this->objectPersister->handlesObject($entity)) { if ($this->objectPersister->handlesObject($entity)) {
$this->scheduleForDeletion($entity); $this->scheduleForDeletion($entity);
@ -139,7 +155,7 @@ class Listener
/** /**
* Persist scheduled objects to ElasticSearch * 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() private function persistScheduled()
{ {
@ -158,36 +174,29 @@ class Listener
} }
/** /**
* Iterate through scheduled actions before flushing to emulate 2.x behavior. * Iterate through scheduled actions before flushing to emulate 2.x behavior. Note that the ElasticSearch index
* Note that the ElasticSearch index will fall out of sync with the source * will fall out of sync with the source data in the event of a crash during flush.
* 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() public function preFlush(EventArgs $eventArgs)
{ {
$this->persistScheduled(); $this->persistScheduled();
} }
/** /**
* Iterating through scheduled actions *after* flushing ensures that the * Iterating through scheduled actions *after* flushing ensures that the ElasticSearch index will be affected
* ElasticSearch index will be affected only if the query is successful. * only if the query is successful
*/ */
public function postFlush() public function postFlush(EventArgs $eventArgs)
{ {
$this->persistScheduled(); $this->persistScheduled();
} }
/** /**
* Record the specified identifier to delete. Do not need to entire object. * Record the specified identifier to delete. Do not need to entire object.
* * @param mixed $object
* @param object $object * @return mixed
*/ */
private function scheduleForDeletion($object) protected function scheduleForDeletion($object)
{ {
if ($identifierValue = $this->propertyAccessor->getValue($object, $this->config['identifier'])) { if ($identifierValue = $this->propertyAccessor->getValue($object, $this->config['identifier'])) {
$this->scheduledForDeletion[] = $identifierValue; $this->scheduledForDeletion[] = $identifierValue;
@ -198,7 +207,6 @@ class Listener
* Checks if the object is indexable or not. * Checks if the object is indexable or not.
* *
* @param object $object * @param object $object
*
* @return bool * @return bool
*/ */
private function isObjectIndexable($object) private function isObjectIndexable($object)

View file

@ -7,16 +7,15 @@ use FOS\ElasticaBundle\Doctrine\AbstractElasticaToModelTransformer;
/** /**
* Maps Elastica documents with Doctrine objects * Maps Elastica documents with Doctrine objects
* This mapper assumes an exact match between * 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 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 * @return array of objects or arrays
*/ */
protected function findByIdentifiers(array $identifierValues, $hydrate) protected function findByIdentifiers(array $identifierValues, $hydrate)

View file

@ -27,10 +27,9 @@ 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 * @param mixed $logger
*
* @return mixed * @return mixed
*/ */
protected function enableLogging($logger) protected function enableLogging($logger)
@ -44,7 +43,7 @@ class Provider extends AbstractProvider
} }
/** /**
* {@inheritDoc} * @see FOS\ElasticaBundle\Doctrine\AbstractProvider::countObjects()
*/ */
protected function countObjects($queryBuilder) protected function countObjects($queryBuilder)
{ {
@ -58,7 +57,7 @@ class Provider extends AbstractProvider
} }
/** /**
* {@inheritDoc} * @see FOS\ElasticaBundle\Doctrine\AbstractProvider::fetchSlice()
*/ */
protected function fetchSlice($queryBuilder, $limit, $offset) protected function fetchSlice($queryBuilder, $limit, $offset)
{ {
@ -67,21 +66,21 @@ class Provider extends AbstractProvider
} }
return $queryBuilder return $queryBuilder
->skip($offset)
->limit($limit) ->limit($limit)
->skip($offset)
->getQuery() ->getQuery()
->execute() ->execute()
->toArray(); ->toArray();
} }
/** /**
* {@inheritDoc} * @see FOS\ElasticaBundle\Doctrine\AbstractProvider::createQueryBuilder()
*/ */
protected function createQueryBuilder($method) protected function createQueryBuilder()
{ {
return $this->managerRegistry return $this->managerRegistry
->getManagerForClass($this->objectClass) ->getManagerForClass($this->objectClass)
->getRepository($this->objectClass) ->getRepository($this->objectClass)
->{$method}(); ->{$this->options['query_builder_method']}();
} }
} }

View file

@ -1,44 +0,0 @@
<?php
namespace FOS\ElasticaBundle\Doctrine\MongoDB;
use Doctrine\ODM\MongoDB\Query\Builder;
use FOS\ElasticaBundle\Exception\InvalidArgumentTypeException;
use FOS\ElasticaBundle\Doctrine\SliceFetcherInterface;
/**
* Fetches a slice of objects.
*
* @author Thomas Prelot <tprelot@gmail.com>
*/
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()
;
}
}

View file

@ -8,18 +8,17 @@ use Doctrine\ORM\Query;
/** /**
* Maps Elastica documents with Doctrine objects * Maps Elastica documents with Doctrine objects
* This mapper assumes an exact match between * 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 class ElasticaToModelTransformer extends AbstractElasticaToModelTransformer
{ {
const ENTITY_ALIAS = 'o'; 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 * @return array of objects or arrays
*/ */
protected function findByIdentifiers(array $identifierValues, $hydrate) protected function findByIdentifiers(array $identifierValues, $hydrate)
@ -37,7 +36,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 * @return \Doctrine\ORM\QueryBuilder
*/ */

View file

@ -3,6 +3,7 @@
namespace FOS\ElasticaBundle\Doctrine\ORM; namespace FOS\ElasticaBundle\Doctrine\ORM;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
use Elastica\Exception\Bulk\ResponseException as BulkResponseException;
use FOS\ElasticaBundle\Doctrine\AbstractProvider; use FOS\ElasticaBundle\Doctrine\AbstractProvider;
use FOS\ElasticaBundle\Exception\InvalidArgumentTypeException; use FOS\ElasticaBundle\Exception\InvalidArgumentTypeException;
@ -29,10 +30,9 @@ 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 * @param mixed $logger
*
* @return mixed * @return mixed
*/ */
protected function enableLogging($logger) protected function enableLogging($logger)
@ -46,7 +46,7 @@ class Provider extends AbstractProvider
} }
/** /**
* {@inheritDoc} * @see FOS\ElasticaBundle\Doctrine\AbstractProvider::countObjects()
*/ */
protected function countObjects($queryBuilder) protected function countObjects($queryBuilder)
{ {
@ -69,9 +69,7 @@ class Provider extends AbstractProvider
} }
/** /**
* This method should remain in sync with SliceFetcher::fetch until it is deprecated and removed. * @see FOS\ElasticaBundle\Doctrine\AbstractProvider::fetchSlice()
*
* {@inheritDoc}
*/ */
protected function fetchSlice($queryBuilder, $limit, $offset) protected function fetchSlice($queryBuilder, $limit, $offset)
{ {
@ -79,8 +77,8 @@ class Provider extends AbstractProvider
throw new InvalidArgumentTypeException($queryBuilder, 'Doctrine\ORM\QueryBuilder'); throw new InvalidArgumentTypeException($queryBuilder, 'Doctrine\ORM\QueryBuilder');
} }
/* /**
* An orderBy DQL part is required to avoid fetching the same row twice. * 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://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.postgresql.org/docs/current/static/queries-limit.html
* @see http://www.sqlite.org/lang_select.html#orderby * @see http://www.sqlite.org/lang_select.html#orderby
@ -105,14 +103,14 @@ class Provider extends AbstractProvider
} }
/** /**
* {@inheritDoc} * @see FOS\ElasticaBundle\Doctrine\AbstractProvider::createQueryBuilder()
*/ */
protected function createQueryBuilder($method) protected function createQueryBuilder()
{ {
return $this->managerRegistry return $this->managerRegistry
->getManagerForClass($this->objectClass) ->getManagerForClass($this->objectClass)
->getRepository($this->objectClass) ->getRepository($this->objectClass)
// ORM query builders require an alias argument // ORM query builders require an alias argument
->{$method}(static::ENTITY_ALIAS); ->{$this->options['query_builder_method']}(static::ENTITY_ALIAS);
} }
} }

View file

@ -1,50 +0,0 @@
<?php
namespace FOS\ElasticaBundle\Doctrine\ORM;
use Doctrine\ORM\QueryBuilder;
use FOS\ElasticaBundle\Exception\InvalidArgumentTypeException;
use FOS\ElasticaBundle\Doctrine\SliceFetcherInterface;
/**
* Fetches a slice of objects.
*
* @author Thomas Prelot <tprelot@gmail.com>
*/
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)
{
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()
;
}
}

View file

@ -25,7 +25,7 @@ class RepositoryManager extends BaseManager
} }
/** /**
* Return repository for entity. * Return repository for entity
* *
* Returns custom repository if one specified otherwise * Returns custom repository if one specified otherwise
* returns a basic repository. * returns a basic repository.
@ -35,7 +35,7 @@ class RepositoryManager extends BaseManager
$realEntityName = $entityName; $realEntityName = $entityName;
if (strpos($entityName, ':') !== false) { if (strpos($entityName, ':') !== false) {
list($namespaceAlias, $simpleClassName) = explode(':', $entityName); list($namespaceAlias, $simpleClassName) = explode(':', $entityName);
$realEntityName = $this->managerRegistry->getAliasNamespace($namespaceAlias).'\\'.$simpleClassName; $realEntityName = $this->managerRegistry->getAliasNamespace($namespaceAlias) . '\\' . $simpleClassName;
} }
return parent::getRepository($realEntityName); return parent::getRepository($realEntityName);

View file

@ -1,24 +0,0 @@
<?php
namespace FOS\ElasticaBundle\Doctrine;
/**
* Fetches a slice of objects.
*
* @author Thomas Prelot <tprelot@gmail.com>
*/
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
*/
public function fetch($queryBuilder, $limit, $offset, array $previousSlice, array $identifierFieldNames);
}

View file

@ -23,19 +23,14 @@ class Client extends BaseClient
private $indexCache = array(); private $indexCache = array();
/** /**
* Symfony's debugging Stopwatch. * Symfony's debugging Stopwatch
* *
* @var Stopwatch|null * @var Stopwatch|null
*/ */
private $stopwatch; private $stopwatch;
/** /**
* @param string $path * {@inheritdoc}
* @param string $method
* @param array $data
* @param array $query
*
* @return \Elastica\Response
*/ */
public function request($path, $method = Request::GET, $data = array(), array $query = array()) public function request($path, $method = Request::GET, $data = array(), array $query = array())
{ {
@ -46,7 +41,20 @@ class Client extends BaseClient
$start = microtime(true); $start = microtime(true);
$response = parent::request($path, $method, $data, $query); $response = parent::request($path, $method, $data, $query);
$this->logQuery($path, $method, $data, $query, $start); 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);
}
if ($this->stopwatch) { if ($this->stopwatch) {
$this->stopwatch->stop('es_request'); $this->stopwatch->stop('es_request');
@ -73,32 +81,4 @@ class Client extends BaseClient
{ {
$this->stopwatch = $stopwatch; $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);
}
} }

View file

@ -3,6 +3,7 @@
namespace FOS\ElasticaBundle\Elastica; namespace FOS\ElasticaBundle\Elastica;
use Elastica\Index as BaseIndex; use Elastica\Index as BaseIndex;
use Elastica\Type;
/** /**
* Overridden Elastica Index class that provides dynamic index name changes. * Overridden Elastica Index class that provides dynamic index name changes.
@ -31,9 +32,6 @@ class Index extends BaseIndex
return $this->originalName ?: $this->_name; return $this->originalName ?: $this->_name;
} }
/**
* @param string $type
*/
public function getType($type) public function getType($type)
{ {
if (isset($this->typeCache[$type])) { if (isset($this->typeCache[$type])) {
@ -44,12 +42,14 @@ 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 * 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 * since it's used for a very specific case and normally should not be used
* *
* @param string $name Index name * @param string $name Index name
*
* @return void
*/ */
public function overrideName($name) public function overrideName($name)
{ {

View file

@ -1,38 +0,0 @@
<?php
/**
* This file is part of the FOSElasticaBundle project.
*
* (c) Tim Nagel <tim@nagel.com.au>
*
* 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;
}
}

View file

@ -1,70 +0,0 @@
<?php
/**
* This file is part of the FOSElasticaBundle project.
*
* (c) FriendsOfSymfony <https://github.com/FriendsOfSymfony/FOSElasticaBundle/graphs/contributors>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace FOS\ElasticaBundle\Event;
/**
* Index Populate Event.
*
* @author Oleg Andreyev <oleg.andreyev@intexsys.lv>
*/
class IndexPopulateEvent extends IndexEvent
{
const PRE_INDEX_POPULATE = 'elastica.index.index_pre_populate';
const POST_INDEX_POPULATE = 'elastica.index.index_post_populate';
/**
* @var bool
*/
private $reset;
/**
* @var array
*/
private $options;
/**
* @param string $index
* @param boolean $reset
* @param array $options
*/
public function __construct($index, $reset, $options)
{
parent::__construct($index);
$this->reset = $reset;
$this->options = $options;
}
/**
* @return boolean
*/
public function isReset()
{
return $this->reset;
}
/**
* @return array
*/
public function getOptions()
{
return $this->options;
}
/**
* @param boolean $reset
*/
public function setReset($reset)
{
$this->reset = $reset;
}
}

View file

@ -1,70 +0,0 @@
<?php
/**
* This file is part of the FOSElasticaBundle project.
*
* (c) Infinite Networks Pty Ltd <http://www.infinite.net.au>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace FOS\ElasticaBundle\Event;
/**
* Index ResetEvent.
*
* @author Oleg Andreyev <oleg.andreyev@intexsys.lv>
*/
class IndexResetEvent extends IndexEvent
{
const PRE_INDEX_RESET = 'elastica.index.pre_reset';
const POST_INDEX_RESET = 'elastica.index.post_reset';
/**
* @var bool
*/
private $force;
/**
* @var bool
*/
private $populating;
/**
* @param string $index
* @param bool $populating
* @param bool $force
*/
public function __construct($index, $populating, $force)
{
parent::__construct($index);
$this->force = $force;
$this->populating = $populating;
}
/**
* @return boolean
*/
public function isForce()
{
return $this->force;
}
/**
* @return boolean
*/
public function isPopulating()
{
return $this->populating;
}
/**
* @param boolean $force
*/
public function setForce($force)
{
$this->force = $force;
}
}

View file

@ -1,78 +0,0 @@
<?php
/**
* This file is part of the FOSElasticaBundle project.
*
* (c) Infinite Networks Pty Ltd <http://www.infinite.net.au>
*
* 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;
}
}

View file

@ -1,51 +0,0 @@
<?php
/**
* This file is part of the FOSElasticaBundle project.
*
* (c) FriendsOfSymfony <https://github.com/FriendsOfSymfony/FOSElasticaBundle/graphs/contributors>
*
* 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 Populate Event.
*
* @author Oleg Andreyev <oleg.andreyev@intexsys.lv>
*/
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 $type;
/**
* @param string $index
* @param string $type
* @param bool $reset
* @param array $options
*/
public function __construct($index, $type, $reset, $options)
{
parent::__construct($index, $reset, $options);
$this->type = $type;
}
/**
* @return string
*/
public function getType()
{
return $this->type;
}
}

View file

@ -1,49 +0,0 @@
<?php
/**
* This file is part of the FOSElasticaBundle project.
*
* (c) Infinite Networks Pty Ltd <http://www.infinite.net.au>
*
* 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 <oleg.andreyev@intexsys.lv>
*/
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 $type;
/**
* @param string $index
* @param string $type
*/
public function __construct($index, $type)
{
parent::__construct($index);
$this->type = $type;
}
/**
* @return string
*/
public function getType()
{
return $this->type;
}
}

View file

@ -1,11 +0,0 @@
<?php
namespace FOS\ElasticaBundle\Exception;
class AliasIsIndexException extends \Exception
{
public function __construct($indexName)
{
parent::__construct(sprintf('Expected %s to be an alias but it is an index.', $indexName));
}
}

View file

@ -12,6 +12,7 @@ use Symfony\Component\HttpKernel\Bundle\Bundle;
/** /**
* Bundle. * Bundle.
*
*/ */
class FOSElasticaBundle extends Bundle class FOSElasticaBundle extends Bundle
{ {

View file

@ -5,13 +5,12 @@ namespace FOS\ElasticaBundle\Finder;
interface FinderInterface 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 mixed $query Can be a string, an array or an \Elastica\Query object
* @param int $limit How many results to get * @param int $limit How many results to get
* @param array $options * @param array $options
*
* @return array results * @return array results
*/ */
public function find($query, $limit = null, $options = array()); function find($query, $limit = null, $options = array());
} }

View file

@ -9,22 +9,20 @@ use Elastica\Query;
interface PaginatedFinderInterface extends FinderInterface 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 * @param array $options
*
* @return Pagerfanta paginated results * @return Pagerfanta paginated results
*/ */
public function findPaginated($query, $options = array()); function findPaginated($query, $options = array());
/** /**
* Creates a paginator adapter for this query. * Creates a paginator adapter for this query
* *
* @param mixed $query * @param mixed $query
* @param array $options * @param array $options
*
* @return PaginatorAdapterInterface * @return PaginatorAdapterInterface
*/ */
public function createPaginatorAdapter($query, $options = array()); function createPaginatorAdapter($query, $options = array());
} }

View file

@ -11,7 +11,7 @@ use Elastica\SearchableInterface;
use Elastica\Query; 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 class TransformedFinder implements PaginatedFinderInterface
{ {
@ -25,12 +25,11 @@ class TransformedFinder implements PaginatedFinderInterface
} }
/** /**
* Search for a query string. * Search for a query string
* *
* @param string $query * @param string $query
* @param integer $limit * @param integer $limit
* @param array $options * @param array $options
*
* @return array of model objects * @return array of model objects
**/ **/
public function find($query, $limit = null, $options = array()) public function find($query, $limit = null, $options = array())
@ -51,9 +50,8 @@ class TransformedFinder implements PaginatedFinderInterface
* Find documents similar to one with passed id. * Find documents similar to one with passed id.
* *
* @param integer $id * @param integer $id
* @param array $params * @param array $params
* @param array $query * @param array $query
*
* @return array of model objects * @return array of model objects
**/ **/
public function moreLikeThis($id, $params = array(), $query = array()) public function moreLikeThis($id, $params = array(), $query = array())
@ -67,8 +65,7 @@ class TransformedFinder implements PaginatedFinderInterface
/** /**
* @param $query * @param $query
* @param null|int $limit * @param null|int $limit
* @param array $options * @param array $options
*
* @return array * @return array
*/ */
protected function search($query, $limit = null, $options = array()) protected function search($query, $limit = null, $options = array())
@ -83,11 +80,10 @@ 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 string $query
* @param array $options * @param array $options
*
* @return Pagerfanta * @return Pagerfanta
*/ */
public function findPaginated($query, $options = array()) public function findPaginated($query, $options = array())

View file

@ -24,4 +24,4 @@ class HybridResult
{ {
return $this->result; return $this->result;
} }
} }

View file

@ -11,12 +11,10 @@
namespace FOS\ElasticaBundle\Index; namespace FOS\ElasticaBundle\Index;
use Elastica\Client;
use Elastica\Exception\ExceptionInterface; use Elastica\Exception\ExceptionInterface;
use Elastica\Request;
use FOS\ElasticaBundle\Configuration\IndexConfig; use FOS\ElasticaBundle\Configuration\IndexConfig;
use FOS\ElasticaBundle\Elastica\Client;
use FOS\ElasticaBundle\Elastica\Index; use FOS\ElasticaBundle\Elastica\Index;
use FOS\ElasticaBundle\Exception\AliasIsIndexException;
class AliasProcessor class AliasProcessor
{ {
@ -24,174 +22,115 @@ class AliasProcessor
* Sets the randomised root name for an index. * Sets the randomised root name for an index.
* *
* @param IndexConfig $indexConfig * @param IndexConfig $indexConfig
* @param Index $index * @param Index $index
*/ */
public function setRootName(IndexConfig $indexConfig, Index $index) public function setRootName(IndexConfig $indexConfig, Index $index)
{ {
$index->overrideName( $index->overrideName(sprintf('%s_%s', $indexConfig->getElasticSearchName(), uniqid()));
sprintf('%s_%s',
$indexConfig->getElasticSearchName(),
date('Y-m-d-His')
)
);
} }
/** /**
* Switches an index to become the new target for an alias. Only applies for * Switches an index to become the new target for an alias. Only applies for
* indexes that are set to use aliases. * indexes that are set to use aliases.
* *
* $force will delete an index encountered where an alias is expected.
*
* @param IndexConfig $indexConfig * @param IndexConfig $indexConfig
* @param Index $index * @param Index $index
* @param bool $force
*
* @throws AliasIsIndexException
* @throws \RuntimeException * @throws \RuntimeException
*/ */
public function switchIndexAlias(IndexConfig $indexConfig, Index $index, $force = false) public function switchIndexAlias(IndexConfig $indexConfig, Index $index)
{ {
$client = $index->getClient(); $client = $index->getClient();
$aliasName = $indexConfig->getElasticSearchName(); $aliasName = $indexConfig->getElasticSearchName();
$oldIndexName = null; $oldIndexName = false;
$newIndexName = $index->getName(); $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); 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)
)
);
} }
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()); $aliasUpdateRequest = array('actions' => array());
if (null !== $aliasedIndex) { if (count($aliasedIndexes) == 1) {
// if the alias is set - add an action to remove it // if the alias is set - add an action to remove it
$oldIndexName = $aliasedIndexes[0];
$aliasUpdateRequest['actions'][] = array( $aliasUpdateRequest['actions'][] = array(
'remove' => array('index' => $aliasedIndex, 'alias' => $aliasName), 'remove' => array('index' => $oldIndexName, 'alias' => $aliasName)
); );
} }
// add an action to point the alias to the new index // add an action to point the alias to the new index
$aliasUpdateRequest['actions'][] = array( $aliasUpdateRequest['actions'][] = array(
'add' => array('index' => $newIndexName, 'alias' => $aliasName), 'add' => array('index' => $newIndexName, 'alias' => $aliasName)
); );
return $aliasUpdateRequest;
}
/**
* Cleans up an index when we encounter a failure to rename the alias.
*
* @param Client $client
* @param string $indexName
* @param \Exception $renameAliasException
*/
private function cleanupRenameFailure(Client $client, $indexName, \Exception $renameAliasException)
{
$additionalError = '';
try { try {
$this->deleteIndex($client, $indexName); $client->request('_aliases', 'POST', $aliasUpdateRequest);
} catch (ExceptionInterface $deleteNewIndexException) { } catch (ExceptionInterface $renameAliasException) {
$additionalError = sprintf( $additionalError = '';
'Tried to delete newly built index %s, but also failed: %s', // if we failed to move the alias, delete the newly built index
$indexName, try {
$deleteNewIndexException->getMessage() $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
); );
} }
throw new \RuntimeException(sprintf( // Delete the old index after the alias has been switched
'Failed to updated index alias: %s. %s', if ($oldIndexName) {
$renameAliasException->getMessage(), $oldIndex = new Index($client, $oldIndexName);
$additionalError ?: sprintf('Newly built index %s was deleted', $indexName) try {
), 0, $renameAliasException); $oldIndex->delete();
} } catch (ExceptionInterface $deleteOldIndexException) {
throw new \RuntimeException(
/** sprintf(
* Delete an index. 'Failed to delete old index %s with message: %s',
* $oldIndexName,
* @param Client $client $deleteOldIndexException->getMessage()
* @param string $indexName Index name to delete ), 0, $deleteOldIndexException
*/ );
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 the name of a single index that an alias points to or throws * Returns array of indexes which are mapped to given alias
* an exception if there is more than one.
* *
* @param Client $client
* @param string $aliasName Alias name * @param string $aliasName Alias name
* * @return array
* @return string|null
*
* @throws AliasIsIndexException
*/ */
private function getAliasedIndex(Client $client, $aliasName) private function getAliasedIndexes(Client $client, $aliasName)
{ {
$aliasesInfo = $client->request('_aliases', 'GET')->getData(); $aliasesInfo = $client->request('_aliases', 'GET')->getData();
$aliasedIndexes = array(); $aliasedIndexes = array();
foreach ($aliasesInfo as $indexName => $indexInfo) { foreach ($aliasesInfo as $indexName => $indexInfo) {
if ($indexName === $aliasName) {
throw new AliasIsIndexException($indexName);
}
if (!isset($indexInfo['aliases'])) {
continue;
}
$aliases = array_keys($indexInfo['aliases']); $aliases = array_keys($indexInfo['aliases']);
if (in_array($aliasName, $aliases)) { if (in_array($aliasName, $aliases)) {
$aliasedIndexes[] = $indexName; $aliasedIndexes[] = $indexName;
} }
} }
if (count($aliasedIndexes) > 1) { return $aliasedIndexes;
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)
));
}
return array_shift($aliasedIndexes);
} }
} }

View file

@ -6,11 +6,6 @@ use FOS\ElasticaBundle\Elastica\Index;
class IndexManager class IndexManager
{ {
/**
* @var Index
*/
private $defaultIndex;
/** /**
* @var array * @var array
*/ */
@ -27,7 +22,7 @@ class IndexManager
} }
/** /**
* Gets all registered indexes. * Gets all registered indexes
* *
* @return array * @return array
*/ */
@ -37,12 +32,10 @@ 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 * @param string $name Index to return, or the default index if null
*
* @return Index * @return Index
*
* @throws \InvalidArgumentException if no index exists for the given name * @throws \InvalidArgumentException if no index exists for the given name
*/ */
public function getIndex($name = null) public function getIndex($name = null)
@ -59,7 +52,7 @@ class IndexManager
} }
/** /**
* Gets the default index. * Gets the default index
* *
* @return Index * @return Index
*/ */

View file

@ -27,7 +27,6 @@ class MappingBuilder
* Builds mappings for an entire index. * Builds mappings for an entire index.
* *
* @param IndexConfig $indexConfig * @param IndexConfig $indexConfig
*
* @return array * @return array
*/ */
public function buildIndexMapping(IndexConfig $indexConfig) public function buildIndexMapping(IndexConfig $indexConfig)
@ -38,13 +37,13 @@ class MappingBuilder
} }
$mapping = array(); $mapping = array();
if (!empty($typeMappings)) { if ($typeMappings) {
$mapping['mappings'] = $typeMappings; $mapping['mappings'] = $typeMappings;
} }
// 'warmers' => $indexConfig->getWarmers(), // 'warmers' => $indexConfig->getWarmers(),
$settings = $indexConfig->getSettings(); $settings = $indexConfig->getSettings();
if (!empty($settings)) { if ($settings) {
$mapping['settings'] = $settings; $mapping['settings'] = $settings;
} }
@ -55,24 +54,17 @@ class MappingBuilder
* Builds mappings for a single type. * Builds mappings for a single type.
* *
* @param TypeConfig $typeConfig * @param TypeConfig $typeConfig
*
* @return array * @return array
*/ */
public function buildTypeMapping(TypeConfig $typeConfig) public function buildTypeMapping(TypeConfig $typeConfig)
{ {
$mapping = $typeConfig->getMapping(); $mapping = array_merge($typeConfig->getMapping(), array(
// 'date_detection' => true,
if (null !== $typeConfig->getDynamicDateFormats()) { // 'dynamic_date_formats' => array()
$mapping['dynamic_date_formats'] = $typeConfig->getDynamicDateFormats(); // 'dynamic_templates' => $typeConfig->getDynamicTemplates(),
} // 'numeric_detection' => false,
// 'properties' => array(),
if (null !== $typeConfig->getDateDetection()) { ));
$mapping['date_detection'] = $typeConfig->getDateDetection();
}
if (null !== $typeConfig->getNumericDetection()) {
$mapping['numeric_detection'] = $typeConfig->getNumericDetection();
}
if ($typeConfig->getIndexAnalyzer()) { if ($typeConfig->getIndexAnalyzer()) {
$mapping['index_analyzer'] = $typeConfig->getIndexAnalyzer(); $mapping['index_analyzer'] = $typeConfig->getIndexAnalyzer();
@ -95,9 +87,9 @@ class MappingBuilder
$mapping['_meta']['model'] = $typeConfig->getModel(); $mapping['_meta']['model'] = $typeConfig->getModel();
} }
if (empty($mapping)) { if (!$mapping) {
// Empty mapping, we want it encoded as a {} instead of a [] // Empty mapping, we want it encoded as a {} instead of a []
$mapping = new \stdClass(); $mapping = new \stdClass;
} }
return $mapping; return $mapping;
@ -112,14 +104,9 @@ class MappingBuilder
private function fixProperties(&$properties) private function fixProperties(&$properties)
{ {
foreach ($properties as $name => &$property) { foreach ($properties as $name => &$property) {
unset($property['property_path']);
if (!isset($property['type'])) { if (!isset($property['type'])) {
$property['type'] = 'string'; $property['type'] = 'string';
} }
if ($property['type'] == 'multi_field' && isset($property['fields'])) {
$this->fixProperties($property['fields']);
}
if (isset($property['properties'])) { if (isset($property['properties'])) {
$this->fixProperties($property['properties']); $this->fixProperties($property['properties']);
} }

View file

@ -5,13 +5,12 @@ namespace FOS\ElasticaBundle\Index;
use Elastica\Index; use Elastica\Index;
use Elastica\Exception\ResponseException; use Elastica\Exception\ResponseException;
use Elastica\Type\Mapping; use Elastica\Type\Mapping;
use FOS\ElasticaBundle\Configuration\IndexConfig;
use FOS\ElasticaBundle\Configuration\ConfigManager; use FOS\ElasticaBundle\Configuration\ConfigManager;
use FOS\ElasticaBundle\Event\IndexResetEvent; use FOS\ElasticaBundle\Elastica\Client;
use FOS\ElasticaBundle\Event\TypeResetEvent;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
/** /**
* Deletes and recreates indexes. * Deletes and recreates indexes
*/ */
class Resetter class Resetter
{ {
@ -21,15 +20,10 @@ class Resetter
private $aliasProcessor; private $aliasProcessor;
/*** /***
* @var ConfigManager * @var \FOS\ElasticaBundle\Configuration\Manager
*/ */
private $configManager; private $configManager;
/**
* @var EventDispatcherInterface
*/
private $dispatcher;
/** /**
* @var IndexManager * @var IndexManager
*/ */
@ -40,37 +34,21 @@ class Resetter
*/ */
private $mappingBuilder; private $mappingBuilder;
/** public function __construct(ConfigManager $configManager, IndexManager $indexManager, AliasProcessor $aliasProcessor, MappingBuilder $mappingBuilder)
* @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->aliasProcessor = $aliasProcessor;
$this->configManager = $configManager; $this->configManager = $configManager;
$this->dispatcher = $eventDispatcher;
$this->indexManager = $indexManager; $this->indexManager = $indexManager;
$this->mappingBuilder = $mappingBuilder; $this->mappingBuilder = $mappingBuilder;
} }
/** /**
* Deletes and recreates all indexes. * Deletes and recreates all indexes
*
* @param bool $populating
* @param bool $force
*/ */
public function resetAllIndexes($populating = false, $force = false) public function resetAllIndexes($populating = false)
{ {
foreach ($this->configManager->getIndexNames() as $name) { foreach ($this->configManager->getIndexNames() as $name) {
$this->resetIndex($name, $populating, $force); $this->resetIndex($name, $populating);
} }
} }
@ -79,19 +57,14 @@ class Resetter
* with a randomised name for an alias to be set after population. * with a randomised name for an alias to be set after population.
* *
* @param string $indexName * @param string $indexName
* @param bool $populating * @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 * @throws \InvalidArgumentException if no index exists for the given name
*/ */
public function resetIndex($indexName, $populating = false, $force = false) public function resetIndex($indexName, $populating = false)
{ {
$indexConfig = $this->configManager->getIndexConfiguration($indexName); $indexConfig = $this->configManager->getIndexConfiguration($indexName);
$index = $this->indexManager->getIndex($indexName); $index = $this->indexManager->getIndex($indexName);
$event = new IndexResetEvent($indexName, $populating, $force);
$this->dispatcher->dispatch(IndexResetEvent::PRE_INDEX_RESET, $event);
if ($indexConfig->isUseAlias()) { if ($indexConfig->isUseAlias()) {
$this->aliasProcessor->setRootName($indexConfig, $index); $this->aliasProcessor->setRootName($indexConfig, $index);
} }
@ -100,18 +73,15 @@ class Resetter
$index->create($mapping, true); $index->create($mapping, true);
if (!$populating and $indexConfig->isUseAlias()) { if (!$populating and $indexConfig->isUseAlias()) {
$this->aliasProcessor->switchIndexAlias($indexConfig, $index, $force); $this->aliasProcessor->switchIndexAlias($indexConfig, $index);
} }
$this->dispatcher->dispatch(IndexResetEvent::POST_INDEX_RESET, $event);
} }
/** /**
* 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 $indexName
* @param string $typeName * @param string $typeName
*
* @throws \InvalidArgumentException if no index or type mapping exists for the given names * @throws \InvalidArgumentException if no index or type mapping exists for the given names
* @throws ResponseException * @throws ResponseException
*/ */
@ -120,9 +90,6 @@ class Resetter
$typeConfig = $this->configManager->getTypeConfiguration($indexName, $typeName); $typeConfig = $this->configManager->getTypeConfiguration($indexName, $typeName);
$type = $this->indexManager->getIndex($indexName)->getType($typeName); $type = $this->indexManager->getIndex($indexName)->getType($typeName);
$event = new TypeResetEvent($indexName, $typeName);
$this->dispatcher->dispatch(TypeResetEvent::PRE_TYPE_RESET, $event);
try { try {
$type->delete(); $type->delete();
} catch (ResponseException $e) { } catch (ResponseException $e) {
@ -131,20 +98,18 @@ class Resetter
} }
} }
$mapping = new Mapping(); $mapping = new Mapping;
foreach ($this->mappingBuilder->buildTypeMapping($typeConfig) as $name => $field) { foreach ($this->mappingBuilder->buildTypeMapping($typeConfig) as $name => $field) {
$mapping->setParam($name, $field); $mapping->setParam($name, $field);
} }
$type->setMapping($mapping); $type->setMapping($mapping);
$this->dispatcher->dispatch(TypeResetEvent::POST_TYPE_RESET, $event);
} }
/** /**
* A command run when a population has finished. * A command run when a population has finished.
* *
* @param string $indexName * @param $indexName
*/ */
public function postPopulate($indexName) public function postPopulate($indexName)
{ {

View file

@ -25,13 +25,13 @@ class RepositoryManager implements RepositoryManagerInterface
public function addEntity($entityName, FinderInterface $finder, $repositoryName = null) public function addEntity($entityName, FinderInterface $finder, $repositoryName = null)
{ {
$this->entities[$entityName] = array(); $this->entities[$entityName]= array();
$this->entities[$entityName]['finder'] = $finder; $this->entities[$entityName]['finder'] = $finder;
$this->entities[$entityName]['repositoryName'] = $repositoryName; $this->entities[$entityName]['repositoryName'] = $repositoryName;
} }
/** /**
* Return repository for entity. * Return repository for entity
* *
* Returns custom repository if one specified otherwise * Returns custom repository if one specified otherwise
* returns a basic repository. * returns a basic repository.
@ -63,16 +63,12 @@ class RepositoryManager implements RepositoryManagerInterface
if ($annotation) { if ($annotation) {
$this->entities[$entityName]['repositoryName'] $this->entities[$entityName]['repositoryName']
= $annotation->repositoryClass; = $annotation->repositoryClass;
return $annotation->repositoryClass; return $annotation->repositoryClass;
} }
return 'FOS\ElasticaBundle\Repository'; return 'FOS\ElasticaBundle\Repository';
} }
/**
* @param string $entityName
*/
private function createRepository($entityName) private function createRepository($entityName)
{ {
if (!class_exists($repositoryName = $this->getRepositoryName($entityName))) { if (!class_exists($repositoryName = $this->getRepositoryName($entityName))) {

View file

@ -12,6 +12,7 @@ use FOS\ElasticaBundle\Finder\FinderInterface;
*/ */
interface RepositoryManagerInterface interface RepositoryManagerInterface
{ {
/** /**
* Adds entity name and its finder. * Adds entity name and its finder.
* Custom repository class name can also be added. * Custom repository class name can also be added.
@ -23,7 +24,7 @@ interface RepositoryManagerInterface
public function addEntity($entityName, FinderInterface $finder, $repositoryName = null); public function addEntity($entityName, FinderInterface $finder, $repositoryName = null);
/** /**
* Return repository for entity. * Return repository for entity
* *
* Returns custom repository if one specified otherwise * Returns custom repository if one specified otherwise
* returns a basic repository. * returns a basic repository.

View file

@ -20,6 +20,8 @@ class FantaPaginatorAdapter implements AdapterInterface
* Returns the number of results. * Returns the number of results.
* *
* @return integer The number of results. * @return integer The number of results.
*
* @api
*/ */
public function getNbResults() public function getNbResults()
{ {
@ -27,25 +29,15 @@ class FantaPaginatorAdapter implements AdapterInterface
} }
/** /**
* Returns Facets. * Returns Facets
*
* @return mixed
*/
public function getFacets()
{
return $this->adapter->getFacets();
}
/**
* Returns Aggregations.
* *
* @return mixed * @return mixed
* *
* @api * @api
*/ */
public function getAggregations() public function getFacets()
{ {
return $this->adapter->getAggregations(); return $this->adapter->getFacets();
} }
/** /**
@ -55,6 +47,8 @@ class FantaPaginatorAdapter implements AdapterInterface
* @param integer $length The length. * @param integer $length The length.
* *
* @return array|\Traversable The slice. * @return array|\Traversable The slice.
*
* @api
*/ */
public function getSlice($offset, $length) public function getSlice($offset, $length)
{ {

View file

@ -8,8 +8,10 @@ interface PaginatorAdapterInterface
* Returns the number of results. * Returns the number of results.
* *
* @return integer The number of results. * @return integer The number of results.
*
* @api
*/ */
public function getTotalHits(); function getTotalHits();
/** /**
* Returns an slice of the results. * Returns an slice of the results.
@ -18,20 +20,15 @@ interface PaginatorAdapterInterface
* @param integer $length The length. * @param integer $length The length.
* *
* @return PartialResultsInterface * @return PartialResultsInterface
*
* @api
*/ */
public function getResults($offset, $length); function getResults($offset, $length);
/** /**
* Returns Facets. * Returns Facets
* *
* @return mixed * @return mixed
*/ */
public function getFacets(); function getFacets();
/**
* Returns Aggregations.
*
* @return mixed
*/
public function getAggregations();
} }

View file

@ -8,27 +8,24 @@ interface PartialResultsInterface
* Returns the paginated results. * Returns the paginated results.
* *
* @return array * @return array
*
* @api
*/ */
public function toArray(); function toArray();
/** /**
* Returns the number of results. * Returns the number of results.
* *
* @return integer The number of results. * @return integer The number of results.
*
* @api
*/ */
public function getTotalHits(); function getTotalHits();
/** /**
* Returns the facets. * Returns the facets
* *
* @return array * @return array
*/ */
public function getFacets(); function getFacets();
}
/**
* Returns the aggregations.
*
* @return array
*/
public function getAggregations();
}

View file

@ -8,7 +8,7 @@ use Elastica\ResultSet;
use InvalidArgumentException; use InvalidArgumentException;
/** /**
* Allows pagination of Elastica\Query. Does not map results. * Allows pagination of Elastica\Query. Does not map results
*/ */
class RawPaginatorAdapter implements PaginatorAdapterInterface class RawPaginatorAdapter implements PaginatorAdapterInterface
{ {
@ -37,16 +37,11 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface
*/ */
private $facets; private $facets;
/**
* @var array for the aggregations
*/
private $aggregations;
/** /**
* @see PaginatorAdapterInterface::__construct * @see PaginatorAdapterInterface::__construct
* *
* @param SearchableInterface $searchable the object to search in * @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 * @param array $options
*/ */
public function __construct(SearchableInterface $searchable, Query $query, array $options = array()) public function __construct(SearchableInterface $searchable, Query $query, array $options = array())
@ -59,11 +54,9 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface
/** /**
* Returns the paginated results. * Returns the paginated results.
* *
* @param integer $offset * @param $offset
* @param integer $itemCountPerPage * @param $itemCountPerPage
*
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
*
* @return ResultSet * @return ResultSet
*/ */
protected function getElasticaResults($offset, $itemCountPerPage) protected function getElasticaResults($offset, $itemCountPerPage)
@ -74,7 +67,7 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface
? (integer) $this->query->getParam('size') ? (integer) $this->query->getParam('size')
: null; : null;
if (null !== $size && $size < $offset + $itemCountPerPage) { if ($size && $size < $offset + $itemCountPerPage) {
$itemCountPerPage = $size - $offset; $itemCountPerPage = $size - $offset;
} }
@ -89,8 +82,6 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface
$resultSet = $this->searchable->search($query, $this->options); $resultSet = $this->searchable->search($query, $this->options);
$this->totalHits = $resultSet->getTotalHits(); $this->totalHits = $resultSet->getTotalHits();
$this->facets = $resultSet->getFacets(); $this->facets = $resultSet->getFacets();
$this->aggregations = $resultSet->getAggregations();
return $resultSet; return $resultSet;
} }
@ -99,7 +90,6 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface
* *
* @param int $offset * @param int $offset
* @param int $itemCountPerPage * @param int $itemCountPerPage
*
* @return PartialResultsInterface * @return PartialResultsInterface
*/ */
public function getResults($offset, $itemCountPerPage) public function getResults($offset, $itemCountPerPage)
@ -110,33 +100,27 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface
/** /**
* Returns the number of results. * Returns the number of results.
* *
* 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. * @return integer The number of results.
*/ */
public function getTotalHits($genuineTotal = false) public function getTotalHits()
{ {
if (! isset($this->totalHits)) { if ( ! isset($this->totalHits)) {
$this->totalHits = $this->searchable->count($this->query); $this->totalHits = $this->searchable->search($this->query)->getTotalHits();
} }
return $this->query->hasParam('size') && !$genuineTotal return $this->query->hasParam('size')
? min($this->totalHits, (integer) $this->query->getParam('size')) ? min($this->totalHits, (integer) $this->query->getParam('size'))
: $this->totalHits; : $this->totalHits;
} }
/** /**
* Returns Facets. * Returns Facets
* *
* @return mixed * @return mixed
*/ */
public function getFacets() public function getFacets()
{ {
if (! isset($this->facets)) { if ( ! isset($this->facets)) {
$this->facets = $this->searchable->search($this->query)->getFacets(); $this->facets = $this->searchable->search($this->query)->getFacets();
} }
@ -144,21 +128,7 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface
} }
/** /**
* Returns Aggregations. * Returns the Query
*
* @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 * @return Query the search query
*/ */

View file

@ -6,7 +6,7 @@ use Elastica\ResultSet;
use Elastica\Result; use Elastica\Result;
/** /**
* Raw partial results transforms to a simple array. * Raw partial results transforms to a simple array
*/ */
class RawPartialResults implements PartialResultsInterface class RawPartialResults implements PartialResultsInterface
{ {
@ -25,7 +25,7 @@ class RawPartialResults implements PartialResultsInterface
*/ */
public function toArray() public function toArray()
{ {
return array_map(function (Result $result) { return array_map(function(Result $result) {
return $result->getSource(); return $result->getSource();
}, $this->resultSet->getResults()); }, $this->resultSet->getResults());
} }
@ -47,18 +47,6 @@ class RawPartialResults implements PartialResultsInterface
return $this->resultSet->getFacets(); return $this->resultSet->getFacets();
} }
return; return null;
} }
}
/**
* {@inheritDoc}
*/
public function getAggregations()
{
if ($this->resultSet->hasAggregations()) {
return $this->resultSet->getAggregations();
}
return;
}
}

View file

@ -7,15 +7,15 @@ use Elastica\SearchableInterface;
use Elastica\Query; use Elastica\Query;
/** /**
* Allows pagination of \Elastica\Query. * Allows pagination of \Elastica\Query
*/ */
class TransformedPaginatorAdapter extends RawPaginatorAdapter class TransformedPaginatorAdapter extends RawPaginatorAdapter
{ {
private $transformer; private $transformer;
/** /**
* @param SearchableInterface $searchable the object to search in * @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 * @param array $options
* @param ElasticaToModelTransformerInterface $transformer the transformer for fetching the results * @param ElasticaToModelTransformerInterface $transformer the transformer for fetching the results
*/ */

View file

@ -6,14 +6,14 @@ use FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface;
use Elastica\ResultSet; use Elastica\ResultSet;
/** /**
* Partial transformed result set. * Partial transformed result set
*/ */
class TransformedPartialResults extends RawPartialResults class TransformedPartialResults extends RawPartialResults
{ {
protected $transformer; protected $transformer;
/** /**
* @param ResultSet $resultSet * @param ResultSet $resultSet
* @param \FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface $transformer * @param \FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface $transformer
*/ */
public function __construct(ResultSet $resultSet, ElasticaToModelTransformerInterface $transformer) public function __construct(ResultSet $resultSet, ElasticaToModelTransformerInterface $transformer)
@ -30,4 +30,4 @@ class TransformedPartialResults extends RawPartialResults
{ {
return $this->transformer->transform($this->resultSet->getResults()); return $this->transformer->transform($this->resultSet->getResults());
} }
} }

View file

@ -4,13 +4,14 @@ namespace FOS\ElasticaBundle\Persister;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Elastica\Exception\BulkException; use Elastica\Exception\BulkException;
use Elastica\Exception\NotFoundException;
use FOS\ElasticaBundle\Transformer\ModelToElasticaTransformerInterface; use FOS\ElasticaBundle\Transformer\ModelToElasticaTransformerInterface;
use Elastica\Type; use Elastica\Type;
use Elastica\Document; use Elastica\Document;
/** /**
* Inserts, replaces and deletes single documents in an elastica type * 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 <thibault.duplessis@gmail.com> * @author Thibault Duplessis <thibault.duplessis@gmail.com>
*/ */
@ -34,7 +35,6 @@ class ObjectPersister implements ObjectPersisterInterface
* If the ObjectPersister handles a given object. * If the ObjectPersister handles a given object.
* *
* @param object $object * @param object $object
*
* @return bool * @return bool
*/ */
public function handlesObject($object) public function handlesObject($object)
@ -42,20 +42,17 @@ class ObjectPersister implements ObjectPersisterInterface
return $object instanceof $this->objectClass; return $object instanceof $this->objectClass;
} }
/**
* @param LoggerInterface $logger
*/
public function setLogger(LoggerInterface $logger) public function setLogger(LoggerInterface $logger)
{ {
$this->logger = $logger; $this->logger = $logger;
} }
/** /**
* 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 * @param BulkException $e
*
* @throws BulkException * @throws BulkException
* @return null
*/ */
private function log(BulkException $e) private function log(BulkException $e)
{ {
@ -68,7 +65,7 @@ class ObjectPersister implements ObjectPersisterInterface
/** /**
* Insert one object into the type * 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 * @param object $object
*/ */
@ -78,9 +75,10 @@ class ObjectPersister implements ObjectPersisterInterface
} }
/** /**
* Replaces one object in the type. * Replaces one object in the type
* *
* @param object $object * @param object $object
* @return null
**/ **/
public function replaceOne($object) public function replaceOne($object)
{ {
@ -88,9 +86,10 @@ class ObjectPersister implements ObjectPersisterInterface
} }
/** /**
* Deletes one object in the type. * Deletes one object in the type
* *
* @param object $object * @param object $object
* @return null
**/ **/
public function deleteOne($object) public function deleteOne($object)
{ {
@ -98,9 +97,11 @@ class ObjectPersister implements ObjectPersisterInterface
} }
/** /**
* Deletes one object in the type by id. * Deletes one object in the type by id
* *
* @param mixed $id * @param mixed $id
*
* @return null
**/ **/
public function deleteById($id) public function deleteById($id)
{ {
@ -108,7 +109,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 array $objects array of domain model objects
* @param string Method to call * @param string Method to call
@ -148,7 +149,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 * @param array $objects array of domain model objects
*/ */
@ -166,7 +167,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 * @param array $identifiers array of domain model object identifiers
*/ */
@ -180,10 +181,9 @@ class ObjectPersister implements ObjectPersisterInterface
} }
/** /**
* Transforms an object to an elastica document. * Transforms an object to an elastica document
* *
* @param object $object * @param object $object
*
* @return Document the elastica document * @return Document the elastica document
*/ */
public function transformToElasticaDocument($object) public function transformToElasticaDocument($object)

View file

@ -4,73 +4,66 @@ namespace FOS\ElasticaBundle\Persister;
/** /**
* Inserts, replaces and deletes single documents in an elastica type * 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 <thibault.duplessis@gmail.com> * @author Thibault Duplessis <thibault.duplessis@gmail.com>
*/ */
interface ObjectPersisterInterface 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 * 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 * @param object $object
*/ */
public function insertOne($object); function insertOne($object);
/** /**
* Replaces one object in the type. * Replaces one object in the type
* *
* @param object $object * @param object $object
**/ **/
public function replaceOne($object); function replaceOne($object);
/** /**
* Deletes one object in the type. * Deletes one object in the type
* *
* @param object $object * @param object $object
**/ **/
public function deleteOne($object); function deleteOne($object);
/** /**
* Deletes one object in the type by id. * Deletes one object in the type by id
* *
* @param mixed $id * @param mixed $id
*
* @return null
*/ */
public function deleteById($id); 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 * @param array $objects array of domain model objects
*/ */
public function insertMany(array $objects); 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 * @param array $objects array of domain model objects
*/ */
public function replaceMany(array $objects); 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 * @param array $objects array of domain model objects
*/ */
public function deleteMany(array $objects); 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 * @param array $identifiers array of domain model object identifiers
*/ */

View file

@ -9,7 +9,7 @@ use FOS\ElasticaBundle\Transformer\ModelToElasticaTransformerInterface;
/** /**
* Inserts, replaces and deletes single objects in an elastica type, making use * Inserts, replaces and deletes single objects in an elastica type, making use
* of elastica's serializer support to convert objects in to elastica documents. * 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 <lea.haensenberger@gmail.com> * @author Lea Haensenberber <lea.haensenberger@gmail.com>
*/ */
@ -17,25 +17,17 @@ class ObjectSerializerPersister extends ObjectPersister
{ {
protected $serializer; protected $serializer;
/**
* @param Type $type
* @param ModelToElasticaTransformerInterface $transformer
* @param string $objectClass
* @param callable $serializer
*/
public function __construct(Type $type, ModelToElasticaTransformerInterface $transformer, $objectClass, $serializer) public function __construct(Type $type, ModelToElasticaTransformerInterface $transformer, $objectClass, $serializer)
{ {
parent::__construct($type, $transformer, $objectClass, array()); parent::__construct($type, $transformer, $objectClass, array());
$this->serializer = $serializer;
$this->serializer = $serializer;
} }
/** /**
* Transforms an object to an elastica document * Transforms an object to an elastica document
* with just the identifier set. * with just the identifier set
* *
* @param object $object * @param object $object
*
* @return Document the elastica document * @return Document the elastica document
*/ */
public function transformToElasticaDocument($object) public function transformToElasticaDocument($object)

View file

@ -3,7 +3,6 @@
namespace FOS\ElasticaBundle\Propel; namespace FOS\ElasticaBundle\Propel;
use FOS\ElasticaBundle\HybridResult; use FOS\ElasticaBundle\HybridResult;
use FOS\ElasticaBundle\Transformer\AbstractElasticaToModelTransformer;
use FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface; use FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface;
use Symfony\Component\PropertyAccess\PropertyAccessorInterface; use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
@ -15,7 +14,7 @@ use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
* *
* @author William Durand <william.durand1@gmail.com> * @author William Durand <william.durand1@gmail.com>
*/ */
class ElasticaToModelTransformer extends AbstractElasticaToModelTransformer class ElasticaToModelTransformer implements ElasticaToModelTransformerInterface
{ {
/** /**
* Propel model class to map to Elastica documents. * Propel model class to map to Elastica documents.
@ -34,11 +33,18 @@ class ElasticaToModelTransformer extends AbstractElasticaToModelTransformer
'identifier' => 'id', 'identifier' => 'id',
); );
/**
* PropertyAccessor instance.
*
* @var PropertyAccessorInterface
*/
protected $propertyAccessor;
/** /**
* Constructor. * Constructor.
* *
* @param string $objectClass * @param string $objectClass
* @param array $options * @param array $options
*/ */
public function __construct($objectClass, array $options = array()) public function __construct($objectClass, array $options = array())
{ {
@ -46,12 +52,21 @@ class ElasticaToModelTransformer extends AbstractElasticaToModelTransformer
$this->options = array_merge($this->options, $options); $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 * Transforms an array of Elastica document into an array of Propel entities
* fetched from the database. * fetched from the database.
* *
* @param array $elasticaObjects * @param array $elasticaObjects
*
* @return array|\ArrayObject * @return array|\ArrayObject
*/ */
public function transform(array $elasticaObjects) public function transform(array $elasticaObjects)
@ -66,7 +81,11 @@ class ElasticaToModelTransformer extends AbstractElasticaToModelTransformer
// Sort objects in the order of their IDs // Sort objects in the order of their IDs
$idPos = array_flip($ids); $idPos = array_flip($ids);
$identifier = $this->options['identifier']; $identifier = $this->options['identifier'];
$sortCallback = $this->getSortingClosure($idPos, $identifier); $propertyAccessor = $this->propertyAccessor;
$sortCallback = function($a, $b) use ($idPos, $identifier, $propertyAccessor) {
return $idPos[$propertyAccessor->getValue($a, $identifier)] > $idPos[$propertyAccessor->getValue($b, $identifier)];
};
if (is_object($objects)) { if (is_object($objects)) {
$objects->uasort($sortCallback); $objects->uasort($sortCallback);
@ -85,7 +104,7 @@ class ElasticaToModelTransformer extends AbstractElasticaToModelTransformer
$objects = $this->transform($elasticaObjects); $objects = $this->transform($elasticaObjects);
$result = array(); $result = array();
for ($i = 0, $j = count($elasticaObjects); $i < $j; $i++) { for ($i = 0; $i < count($elasticaObjects); $i++) {
$result[] = new HybridResult($elasticaObjects[$i], $objects[$i]); $result[] = new HybridResult($elasticaObjects[$i], $objects[$i]);
} }
@ -116,7 +135,6 @@ class ElasticaToModelTransformer extends AbstractElasticaToModelTransformer
* *
* @param array $identifierValues Identifier values * @param array $identifierValues Identifier values
* @param boolean $hydrate Whether or not to hydrate the results * @param boolean $hydrate Whether or not to hydrate the results
*
* @return array * @return array
*/ */
protected function findByIdentifiers(array $identifierValues, $hydrate) protected function findByIdentifiers(array $identifierValues, $hydrate)
@ -127,7 +145,7 @@ class ElasticaToModelTransformer extends AbstractElasticaToModelTransformer
$query = $this->createQuery($this->objectClass, $this->options['identifier'], $identifierValues); $query = $this->createQuery($this->objectClass, $this->options['identifier'], $identifierValues);
if (! $hydrate) { if ( ! $hydrate) {
return $query->toArray(); return $query->toArray();
} }
@ -140,7 +158,6 @@ class ElasticaToModelTransformer extends AbstractElasticaToModelTransformer
* @param string $class Propel model class * @param string $class Propel model class
* @param string $identifierField Identifier field name (e.g. "id") * @param string $identifierField Identifier field name (e.g. "id")
* @param array $identifierValues Identifier values * @param array $identifierValues Identifier values
*
* @return \ModelCriteria * @return \ModelCriteria
*/ */
protected function createQuery($class, $identifierField, array $identifierValues) protected function createQuery($class, $identifierField, array $identifierValues)
@ -153,8 +170,6 @@ class ElasticaToModelTransformer extends AbstractElasticaToModelTransformer
/** /**
* @see https://github.com/doctrine/common/blob/master/lib/Doctrine/Common/Util/Inflector.php * @see https://github.com/doctrine/common/blob/master/lib/Doctrine/Common/Util/Inflector.php
*
* @param string $str
*/ */
private function camelize($str) private function camelize($str)
{ {

View file

@ -5,69 +5,53 @@ namespace FOS\ElasticaBundle\Propel;
use FOS\ElasticaBundle\Provider\AbstractProvider; use FOS\ElasticaBundle\Provider\AbstractProvider;
/** /**
* Propel provider. * Propel provider
* *
* @author William Durand <william.durand1@gmail.com> * @author William Durand <william.durand1@gmail.com>
*/ */
class Provider extends AbstractProvider class Provider extends AbstractProvider
{ {
/** /**
* {@inheritDoc} * @see FOS\ElasticaBundle\Provider\ProviderInterface::populate()
*/ */
public function doPopulate($options, \Closure $loggerClosure = null) public function populate(\Closure $loggerClosure = null, array $options = array())
{ {
$queryClass = $this->objectClass.'Query'; $queryClass = $this->objectClass . 'Query';
$nbObjects = $queryClass::create()->count(); $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'];
$offset = $options['offset']; for (; $offset < $nbObjects; $offset += $batchSize) {
if ($loggerClosure) {
$stepStartTime = microtime(true);
}
for (; $offset < $nbObjects; $offset += $options['batch_size']) {
$objects = $queryClass::create() $objects = $queryClass::create()
->limit($options['batch_size']) ->limit($batchSize)
->offset($offset) ->offset($offset)
->find() ->find()
->getArrayCopy(); ->getArrayCopy();
$objects = $this->filterObjects($options, $objects); if ($loggerClosure) {
if (!empty($objects)) { $stepNbObjects = count($objects);
$this->objectPersister->insertMany($objects); }
$objects = array_filter($objects, array($this, 'isObjectIndexable'));
if (!$objects) {
$loggerClosure('<info>Entire batch was filtered away, skipping...</info>');
continue;
} }
usleep($options['sleep']); $this->objectPersister->insertMany($objects);
usleep($sleep);
if ($loggerClosure) { if ($loggerClosure) {
$loggerClosure($options['batch_size'], $nbObjects); $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()));
} }
} }
} }
/**
* {@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' => null,
'sleep' => 0
));
}
/**
* {@inheritDoc}
*/
protected function disableLogging()
{
}
/**
* {@inheritDoc}
*/
protected function enableLogging($logger)
{
}
} }

View file

@ -3,17 +3,16 @@
namespace FOS\ElasticaBundle\Provider; namespace FOS\ElasticaBundle\Provider;
use FOS\ElasticaBundle\Persister\ObjectPersisterInterface; use FOS\ElasticaBundle\Persister\ObjectPersisterInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
/** /**
* AbstractProvider. * AbstractProvider
*/ */
abstract class AbstractProvider implements ProviderInterface abstract class AbstractProvider implements ProviderInterface
{ {
/** /**
* @var array * @var ObjectPersisterInterface
*/ */
protected $baseOptions; protected $objectPersister;
/** /**
* @var string * @var string
@ -21,17 +20,12 @@ abstract class AbstractProvider implements ProviderInterface
protected $objectClass; protected $objectClass;
/** /**
* @var ObjectPersisterInterface * @var array
*/ */
protected $objectPersister; protected $options;
/** /**
* @var OptionsResolver * @var Indexable
*/
protected $resolver;
/**
* @var IndexableInterface
*/ */
private $indexable; private $indexable;
@ -39,136 +33,42 @@ abstract class AbstractProvider implements ProviderInterface
* Constructor. * Constructor.
* *
* @param ObjectPersisterInterface $objectPersister * @param ObjectPersisterInterface $objectPersister
* @param IndexableInterface $indexable * @param IndexableInterface $indexable
* @param string $objectClass * @param string $objectClass
* @param array $baseOptions * @param array $options
*/ */
public function __construct( public function __construct(
ObjectPersisterInterface $objectPersister, ObjectPersisterInterface $objectPersister,
IndexableInterface $indexable, IndexableInterface $indexable,
$objectClass, $objectClass,
array $baseOptions = array() array $options = array()
) { ) {
$this->baseOptions = $baseOptions;
$this->indexable = $indexable; $this->indexable = $indexable;
$this->objectClass = $objectClass; $this->objectClass = $objectClass;
$this->objectPersister = $objectPersister; $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, 'batch_size' => 100,
'skip_indexable_check' => false, ), $options);
));
$this->resolver->setAllowedTypes(array(
'batch_size' => 'int'
));
$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. * Checks if a given object should be indexed or not.
* *
* @deprecated To be removed in 4.0
*
* @param object $object * @param object $object
*
* @return bool * @return bool
*/ */
protected function isObjectIndexable($object) protected function isObjectIndexable($object)
{ {
return $this->indexable->isObjectIndexable( return $this->indexable->isObjectIndexable(
$this->baseOptions['indexName'], $this->options['indexName'],
$this->baseOptions['typeName'], $this->options['typeName'],
$object $object
); );
} }
/** /**
* Get string with RAM usage information (current and peak). * Get string with RAM usage information (current and peak)
*
* @deprecated To be removed in 4.0
* *
* @return string * @return string
*/ */
@ -179,17 +79,4 @@ abstract class AbstractProvider implements ProviderInterface
return sprintf('(RAM : current=%uMo peak=%uMo)', $memory, $memoryMax); 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));
}
} }

View file

@ -33,7 +33,7 @@ class Indexable implements IndexableInterface
private $container; private $container;
/** /**
* An instance of ExpressionLanguage. * An instance of ExpressionLanguage
* *
* @var ExpressionLanguage * @var ExpressionLanguage
*/ */
@ -47,7 +47,7 @@ class Indexable implements IndexableInterface
private $initialisedCallbacks = array(); private $initialisedCallbacks = array();
/** /**
* PropertyAccessor instance. * PropertyAccessor instance
* *
* @var PropertyAccessorInterface * @var PropertyAccessorInterface
*/ */
@ -55,7 +55,6 @@ class Indexable implements IndexableInterface
/** /**
* @param array $callbacks * @param array $callbacks
* @param ContainerInterface $container
*/ */
public function __construct(array $callbacks, ContainerInterface $container) public function __construct(array $callbacks, ContainerInterface $container)
{ {
@ -69,8 +68,7 @@ class Indexable implements IndexableInterface
* *
* @param string $indexName * @param string $indexName
* @param string $typeName * @param string $typeName
* @param mixed $object * @param mixed $object
*
* @return bool * @return bool
*/ */
public function isObjectIndexable($indexName, $typeName, $object) public function isObjectIndexable($indexName, $typeName, $object)
@ -82,9 +80,9 @@ class Indexable implements IndexableInterface
} }
if ($callback instanceof Expression) { if ($callback instanceof Expression) {
return (bool) $this->getExpressionLanguage()->evaluate($callback, array( return $this->getExpressionLanguage()->evaluate($callback, array(
'object' => $object, 'object' => $object,
$this->getExpressionVar($object) => $object, $this->getExpressionVar($object) => $object
)); ));
} }
@ -98,13 +96,12 @@ class Indexable implements IndexableInterface
* *
* @param string $type * @param string $type
* @param object $object * @param object $object
*
* @return mixed * @return mixed
*/ */
private function buildCallback($type, $object) private function buildCallback($type, $object)
{ {
if (!array_key_exists($type, $this->callbacks)) { if (!array_key_exists($type, $this->callbacks)) {
return; return null;
} }
$callback = $this->callbacks[$type]; $callback = $this->callbacks[$type];
@ -113,54 +110,44 @@ class Indexable implements IndexableInterface
return $callback; return $callback;
} }
if (is_array($callback) && !is_object($callback[0])) { if (is_array($callback)) {
return $this->processArrayToCallback($type, $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_string($callback)) { if (is_string($callback) && $expression = $this->getExpressionLanguage()) {
return $this->buildExpressionCallback($type, $object, $callback); $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)); 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. * Retreives a cached callback, or creates a new callback if one is not found.
* *
* @param string $type * @param string $type
* @param object $object * @param object $object
*
* @return mixed * @return mixed
*/ */
private function getCallback($type, $object) private function getCallback($type, $object)
@ -173,13 +160,15 @@ class Indexable implements IndexableInterface
} }
/** /**
* Returns the ExpressionLanguage class if it is available. * @return bool|ExpressionLanguage
*
* @return ExpressionLanguage|null
*/ */
private function getExpressionLanguage() private function getExpressionLanguage()
{ {
if (null === $this->expressionLanguage && class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) { if (null === $this->expressionLanguage) {
if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) {
return false;
}
$this->expressionLanguage = new ExpressionLanguage(); $this->expressionLanguage = new ExpressionLanguage();
} }
@ -187,54 +176,13 @@ 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 * @param mixed $object
*
* @return string * @return string
*/ */
private function getExpressionVar($object = null) private function getExpressionVar($object = null)
{ {
if (!is_object($object)) {
return 'object';
}
$ref = new \ReflectionClass($object); $ref = new \ReflectionClass($object);
return strtolower($ref->getShortName()); 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
));
}
} }

View file

@ -18,8 +18,7 @@ interface IndexableInterface
* *
* @param string $indexName * @param string $indexName
* @param string $typeName * @param string $typeName
* @param mixed $object * @param mixed $object
*
* @return bool * @return bool
*/ */
public function isObjectIndexable($indexName, $typeName, $object); public function isObjectIndexable($indexName, $typeName, $object);

View file

@ -3,7 +3,7 @@
namespace FOS\ElasticaBundle\Provider; namespace FOS\ElasticaBundle\Provider;
/** /**
* Insert application domain objects into elastica types. * Insert application domain objects into elastica types
* *
* @author Thibault Duplessis <thibault.duplessis@gmail.com> * @author Thibault Duplessis <thibault.duplessis@gmail.com>
*/ */
@ -12,15 +12,9 @@ interface ProviderInterface
/** /**
* Persists all domain objects to ElasticSearch for this provider. * 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 \Closure $loggerClosure
* @param array $options * @param array $options
*
* @return * @return
*/ */
public function populate(\Closure $loggerClosure = null, array $options = array()); function populate(\Closure $loggerClosure = null, array $options = array());
} }

View file

@ -57,10 +57,8 @@ class ProviderRegistry implements ContainerAwareInterface
* *
* Providers will be indexed by "type" strings in the returned array. * Providers will be indexed by "type" strings in the returned array.
* *
* @param string $index * @param string $index
* * @return array of ProviderInterface instances
* @return ProviderInterface[]
*
* @throws \InvalidArgumentException if no providers were registered for the index * @throws \InvalidArgumentException if no providers were registered for the index
*/ */
public function getIndexProviders($index) public function getIndexProviders($index)
@ -83,9 +81,7 @@ class ProviderRegistry implements ContainerAwareInterface
* *
* @param string $index * @param string $index
* @param string $type * @param string $type
*
* @return ProviderInterface * @return ProviderInterface
*
* @throws \InvalidArgumentException if no provider was registered for the index and type * @throws \InvalidArgumentException if no provider was registered for the index and type
*/ */
public function getProvider($index, $type) public function getProvider($index, $type)

View file

@ -11,16 +11,15 @@ Symfony2. Features include:
> **Note** Propel support is limited and contributions fixing issues are welcome! > **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) [![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 Documentation
------------- -------------
Documentation for FOSElasticaBundle is in `Resources/doc/index.md` Documentation for FOSElasticaBundle is in `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 3.0.x (master)](https://github.com/FriendsOfSymfony/FOSElasticaBundle/blob/master/Resources/doc/index.md)
[Read the documentation for 3.0.x](https://github.com/FriendsOfSymfony/FOSElasticaBundle/blob/3.0.x/Resources/doc/index.md) [Read the documentation for 2.1.x](https://github.com/FriendsOfSymfony/FOSElasticaBundle/blob/2.1.x/README.md)
Installation Installation
------------ ------------

View file

@ -19,47 +19,21 @@ class Repository
$this->finder = $finder; $this->finder = $finder;
} }
/**
* @param mixed $query
* @param integer $limit
* @param array $options
*
* @return array
*/
public function find($query, $limit = null, $options = array()) public function find($query, $limit = null, $options = array())
{ {
return $this->finder->find($query, $limit, $options); 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()) public function findHybrid($query, $limit = null, $options = array())
{ {
return $this->finder->findHybrid($query, $limit, $options); return $this->finder->findHybrid($query, $limit, $options);
} }
/**
* @param mixed $query
* @param array $options
*
* @return \Pagerfanta\Pagerfanta
*/
public function findPaginated($query, $options = array()) public function findPaginated($query, $options = array())
{ {
return $this->finder->findPaginated($query, $options); return $this->finder->findPaginated($query, $options);
} }
/**
* @param string $query
* @param array $options
*
* @return Paginator\PaginatorAdapterInterface
*/
public function createPaginatorAdapter($query, $options = array()) public function createPaginatorAdapter($query, $options = array())
{ {
return $this->finder->createPaginatorAdapter($query, $options); return $this->finder->createPaginatorAdapter($query, $options);

View file

@ -41,7 +41,6 @@
<argument type="service" id="fos_elastica.index_manager" /> <argument type="service" id="fos_elastica.index_manager" />
<argument type="service" id="fos_elastica.alias_processor" /> <argument type="service" id="fos_elastica.alias_processor" />
<argument type="service" id="fos_elastica.mapping_builder" /> <argument type="service" id="fos_elastica.mapping_builder" />
<argument type="service" id="event_dispatcher"/>
</service> </service>
<!-- Abstract definition for all finders. --> <!-- Abstract definition for all finders. -->

View file

@ -4,35 +4,24 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="fos_elastica.slice_fetcher.mongodb.class">FOS\ElasticaBundle\Doctrine\MongoDB\SliceFetcher</parameter>
<parameter key="fos_elastica.provider.prototype.mongodb.class">FOS\ElasticaBundle\Doctrine\MongoDB\Provider</parameter>
<parameter key="fos_elastica.listener.prototype.mongodb.class">FOS\ElasticaBundle\Doctrine\Listener</parameter>
<parameter key="fos_elastica.elastica_to_model_transformer.prototype.mongodb.class">FOS\ElasticaBundle\Doctrine\MongoDB\ElasticaToModelTransformer</parameter>
<parameter key="fos_elastica.manager.mongodb.class">FOS\ElasticaBundle\Doctrine\RepositoryManager</parameter>
</parameters>
<services> <services>
<service id="fos_elastica.slice_fetcher.mongodb" class="%fos_elastica.slice_fetcher.mongodb.class%"> <service id="fos_elastica.provider.prototype.mongodb" class="FOS\ElasticaBundle\Doctrine\MongoDB\Provider" public="true" abstract="true">
</service>
<service id="fos_elastica.provider.prototype.mongodb" class="%fos_elastica.provider.prototype.mongodb.class%" public="true" abstract="true">
<argument /> <!-- object persister --> <argument /> <!-- object persister -->
<argument type="service" id="fos_elastica.indexable" /> <argument type="service" id="fos_elastica.indexable" />
<argument /> <!-- model --> <argument /> <!-- model -->
<argument type="collection" /> <!-- options --> <argument type="collection" /> <!-- options -->
<argument type="service" id="doctrine_mongodb" /> <!-- manager registry --> <argument type="service" id="doctrine_mongodb" />
<argument type="service" id="fos_elastica.slice_fetcher.mongodb" /> <!-- slice fetcher -->
</service> </service>
<service id="fos_elastica.listener.prototype.mongodb" class="%fos_elastica.listener.prototype.mongodb.class%" public="false" abstract="true"> <service id="fos_elastica.listener.prototype.mongodb" class="FOS\ElasticaBundle\Doctrine\Listener" public="false" abstract="true">
<argument /> <!-- object persister --> <argument /> <!-- object persister -->
<argument type="collection" /> <!-- events -->
<argument type="service" id="fos_elastica.indexable" /> <argument type="service" id="fos_elastica.indexable" />
<argument type="collection" /> <!-- configuration --> <argument type="collection" /> <!-- configuration -->
<argument>null</argument> <!-- logger --> <argument /> <!-- logger -->
</service> </service>
<service id="fos_elastica.elastica_to_model_transformer.prototype.mongodb" class="%fos_elastica.elastica_to_model_transformer.prototype.mongodb.class%" public="false" abstract="true"> <service id="fos_elastica.elastica_to_model_transformer.prototype.mongodb" class="FOS\ElasticaBundle\Doctrine\MongoDB\ElasticaToModelTransformer" public="false" abstract="true">
<argument type="service" id="doctrine_mongodb" /> <argument type="service" id="doctrine_mongodb" />
<argument /> <!-- model --> <argument /> <!-- model -->
<argument type="collection" /> <!-- options --> <argument type="collection" /> <!-- options -->
@ -41,7 +30,7 @@
</call> </call>
</service> </service>
<service id="fos_elastica.manager.mongodb" class="%fos_elastica.manager.mongodb.class%"> <service id="fos_elastica.manager.mongodb" class="FOS\ElasticaBundle\Doctrine\RepositoryManager">
<argument type="service" id="doctrine_mongodb"/> <argument type="service" id="doctrine_mongodb"/>
<argument type="service" id="annotation_reader"/> <argument type="service" id="annotation_reader"/>
</service> </service>

View file

@ -4,35 +4,24 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="fos_elastica.slice_fetcher.orm.class">FOS\ElasticaBundle\Doctrine\ORM\SliceFetcher</parameter>
<parameter key="fos_elastica.provider.prototype.orm.class">FOS\ElasticaBundle\Doctrine\ORM\Provider</parameter>
<parameter key="fos_elastica.listener.prototype.orm.class">FOS\ElasticaBundle\Doctrine\Listener</parameter>
<parameter key="fos_elastica.elastica_to_model_transformer.prototype.orm.class">FOS\ElasticaBundle\Doctrine\ORM\ElasticaToModelTransformer</parameter>
<parameter key="fos_elastica.manager.orm.class">FOS\ElasticaBundle\Doctrine\RepositoryManager</parameter>
</parameters>
<services> <services>
<service id="fos_elastica.slice_fetcher.orm" class="%fos_elastica.slice_fetcher.orm.class%"> <service id="fos_elastica.provider.prototype.orm" class="FOS\ElasticaBundle\Doctrine\ORM\Provider" public="true" abstract="true">
</service>
<service id="fos_elastica.provider.prototype.orm" class="%fos_elastica.provider.prototype.orm.class%" public="true" abstract="true">
<argument /> <!-- object persister --> <argument /> <!-- object persister -->
<argument type="service" id="fos_elastica.indexable" /> <argument type="service" id="fos_elastica.indexable" />
<argument /> <!-- model --> <argument /> <!-- model -->
<argument type="collection" /> <!-- options --> <argument type="collection" /> <!-- options -->
<argument type="service" id="doctrine" /> <!-- manager registry --> <argument type="service" id="doctrine" />
<argument type="service" id="fos_elastica.slice_fetcher.orm" /> <!-- slice fetcher -->
</service> </service>
<service id="fos_elastica.listener.prototype.orm" class="%fos_elastica.listener.prototype.orm.class%" public="false" abstract="true"> <service id="fos_elastica.listener.prototype.orm" class="FOS\ElasticaBundle\Doctrine\Listener" public="false" abstract="true">
<argument /> <!-- object persister --> <argument /> <!-- object persister -->
<argument type="collection" /> <!-- events -->
<argument type="service" id="fos_elastica.indexable" /> <argument type="service" id="fos_elastica.indexable" />
<argument type="collection" /> <!-- configuration --> <argument type="collection" /> <!-- configuration -->
<argument>null</argument> <!-- logger --> <argument on-invalid="ignore" /> <!-- logger -->
</service> </service>
<service id="fos_elastica.elastica_to_model_transformer.prototype.orm" class="%fos_elastica.elastica_to_model_transformer.prototype.orm.class%" public="false" abstract="true"> <service id="fos_elastica.elastica_to_model_transformer.prototype.orm" class="FOS\ElasticaBundle\Doctrine\ORM\ElasticaToModelTransformer" public="false" abstract="true">
<argument type="service" id="doctrine" /> <argument type="service" id="doctrine" />
<argument /> <!-- model --> <argument /> <!-- model -->
<argument type="collection" /> <!-- options --> <argument type="collection" /> <!-- options -->
@ -41,7 +30,7 @@
</call> </call>
</service> </service>
<service id="fos_elastica.manager.orm" class="%fos_elastica.manager.orm.class%"> <service id="fos_elastica.manager.orm" class="FOS\ElasticaBundle\Doctrine\RepositoryManager">
<argument type="service" id="doctrine" /> <argument type="service" id="doctrine" />
<argument type="service" id="annotation_reader" /> <argument type="service" id="annotation_reader" />
</service> </service>

View file

@ -12,8 +12,7 @@
<services> <services>
<service id="fos_elastica.model_to_elastica_transformer" class="%fos_elastica.model_to_elastica_transformer.class%" public="false" abstract="true"> <service id="fos_elastica.model_to_elastica_transformer" class="%fos_elastica.model_to_elastica_transformer.class%" public="false" abstract="true">
<argument type="collection" /> <!-- options --> <argument type="collection" /> <!-- options -->
<argument type="service" id="event_dispatcher" /> <!-- options -->
<call method="setPropertyAccessor"> <call method="setPropertyAccessor">
<argument type="service" id="fos_elastica.property_accessor" /> <argument type="service" id="fos_elastica.property_accessor" />
</call> </call>

View file

@ -1,33 +0,0 @@
##### 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
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',
);
}
}
```

View file

@ -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 methods for particular searches. These need to extend `FOS\ElasticaBundle\Repository` to have
access to the finder: access to the finder:
```php ```
<?php <?php
namespace Acme\ElasticaBundle\SearchRepository; namespace Acme\ElasticaBundle\SearchRepository;
@ -23,41 +23,37 @@ class UserRepository extends Repository
To use the custom repository specify it in the mapping for the entity: To use the custom repository specify it in the mapping for the entity:
```yaml fos_elastica:
fos_elastica: clients:
clients: default: { host: localhost, port: 9200 }
default: { host: localhost, port: 9200 } indexes:
indexes: website:
website: client: default
client: default types:
types: user:
user: mappings:
mappings: # your mappings
# your mappings persistence:
persistence: driver: orm
driver: orm model: Application\UserBundle\Entity\User
model: Application\UserBundle\Entity\User provider: ~
provider: ~ finder: ~
finder: ~ repository: Acme\ElasticaBundle\SearchRepository\UserRepository
repository: Acme\ElasticaBundle\SearchRepository\UserRepository
```
Then the custom queries will be available when using the repository returned from the manager: Then the custom queries will be available when using the repository returned from the manager:
```php /** var FOS\ElasticaBundle\Manager\RepositoryManager */
/** var FOS\ElasticaBundle\Manager\RepositoryManager */ $repositoryManager = $container->get('fos_elastica.manager');
$repositoryManager = $container->get('fos_elastica.manager');
/** var FOS\ElasticaBundle\Repository */ /** var FOS\ElasticaBundle\Repository */
$repository = $repositoryManager->getRepository('UserBundle:User'); $repository = $repositoryManager->getRepository('UserBundle:User');
/** var array of Acme\UserBundle\Entity\User */ /** var array of Acme\UserBundle\Entity\User */
$users = $repository->findWithCustomQuery('bob'); $users = $repository->findWithCustomQuery('bob');
```
Alternatively you can specify the custom repository using an annotation in the entity: Alternatively you can specify the custom repository using an annotation in the entity:
```php ```
<?php <?php
namespace Application\UserBundle\Entity; namespace Application\UserBundle\Entity;
@ -73,4 +69,4 @@ class User
//--- //---
} }
``` ```

View file

@ -8,7 +8,7 @@ index and type for which the service will provide.
# app/config/config.yml # app/config/config.yml
services: services:
acme.search_provider.user: acme.search_provider.user:
class: Acme\UserBundle\Provider\UserProvider class: Acme\UserBundle\Search\UserProvider
arguments: arguments:
- @fos_elastica.index.website.user - @fos_elastica.index.website.user
tags: tags:

View file

@ -11,11 +11,6 @@ fos_elastica:
connections: connections:
- url: http://es1.example.net:9200 - url: http://es1.example.net:9200
- url: http://es2.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 For more information on Elastica clustering see http://elastica.io/getting-started/installation.html#section-connect-cluster

View file

@ -23,7 +23,7 @@ namespace Acme\ElasticaBundle;
use Elastica\Exception\ExceptionInterface; use Elastica\Exception\ExceptionInterface;
use Elastica\Request; use Elastica\Request;
use Elastica\Response; use Elastica\Response;
use FOS\ElasticaBundle\Elastica\Client as BaseClient; use FOS\ElasticaBundle\Client as BaseClient;
class Client extends BaseClient class Client extends BaseClient
{ {

View file

@ -13,7 +13,6 @@ Cookbook Entries
---------------- ----------------
* [Aliased Indexes](cookbook/aliased-indexes.md) * [Aliased Indexes](cookbook/aliased-indexes.md)
* [Custom Indexed Properties](cookbook/custom-properties.md)
* [Custom Repositories](cookbook/custom-repositories.md) * [Custom Repositories](cookbook/custom-repositories.md)
* [HTTP Headers for Elastica](cookbook/elastica-client-http-headers.md) * [HTTP Headers for Elastica](cookbook/elastica-client-http-headers.md)
* Performance - [Logging](cookbook/logging.md) * Performance - [Logging](cookbook/logging.md)

View file

@ -1,50 +1,40 @@
Step 1: Setting up the bundle Step 1: Setting up the bundle
============================= =============================
A: Download the Bundle A) Install FOSElasticaBundle
---------------------- ----------------------------
Open a command console, enter your project directory and execute the FOSElasticaBundle is installed using [Composer](https://getcomposer.org).
following command to download the latest stable version of this bundle:
```bash ```bash
$ composer require friendsofsymfony/elastica-bundle $ php composer.phar 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 ### Elasticsearch
Instructions for installing and deploying Elasticsearch may be found [here](https://www.elastic.co/downloads/elasticsearch). Instructions for installing and deploying Elasticsearch may be found
[here](http://www.elasticsearch.org/guide/reference/setup/installation/).
Step 2: Enable the Bundle
-------------------------
Then, enable the bundle by adding the following line in the `app/AppKernel.php` B) Enable FOSElasticaBundle
file of your project: ---------------------------
Enable FOSElasticaBundle in your AppKernel:
```php ```php
<?php <?php
// app/AppKernel.php // app/AppKernel.php
// ... public function registerBundles()
class AppKernel extends Kernel
{ {
public function registerBundles() $bundles = array(
{
$bundles = array(
// ...
new FOS\ElasticaBundle\FOSElasticaBundle(),
);
// ... // ...
} new FOS\ElasticaBundle\FOSElasticaBundle(),
);
} }
``` ```
C: Basic Bundle Configuration C) Basic Bundle Configuration
----------------------------- -----------------------------
The basic minimal configuration for FOSElasticaBundle is one client with one Elasticsearch The basic minimal configuration for FOSElasticaBundle is one client with one Elasticsearch
@ -58,30 +48,27 @@ fos_elastica:
clients: clients:
default: { host: localhost, port: 9200 } default: { host: localhost, port: 9200 }
indexes: indexes:
app: ~ search: ~
``` ```
In this example, an Elastica index (an instance of `Elastica\Index`) is available as a In this example, an Elastica index (an instance of `Elastica\Index`) is available as a
service with the key `fos_elastica.index.app`. service with the key `fos_elastica.index.search`.
You may want the index `app` to be named something else on ElasticSearch depending on If the Elasticsearch index name needs to be different to the service name in your
if your application is running in a different env or other conditions that suit your application, for example, renaming the search index based on different environments.
application. To set your customer index to a name that depends on the environment of your
Symfony application, use the example below:
```yaml ```yaml
#app/config/config.yml #app/config/config.yml
fos_elastica: fos_elastica:
indexes: indexes:
app: search:
index_name: app_%kernel.environment% index_name: search_dev
``` ```
In this case, the service `fos_elastica.index.app` will relate to an ElasticSearch index In this case, the service `fos_elastica.index.search` will be using an Elasticsearch
that varies depending on your kernel's environment. For example, in dev it will relate to index of search_dev.
`app_dev`.
D: Defining index types D) Defining index types
----------------------- -----------------------
By default, FOSElasticaBundle requires each type that is to be indexed to be mapped. By default, FOSElasticaBundle requires each type that is to be indexed to be mapped.
@ -94,7 +81,7 @@ will end up being indexed.
```yaml ```yaml
fos_elastica: fos_elastica:
indexes: indexes:
app: search:
types: types:
user: user:
mappings: mappings:
@ -105,7 +92,7 @@ fos_elastica:
``` ```
Each defined type is made available as a service, and in this case the service key is Each defined type is made available as a service, and in this case the service key is
`fos_elastica.index.app.user` and is an instance of `Elastica\Type`. `fos_elastica.index.search.user` and is an instance of `Elastica\Type`.
FOSElasticaBundle requires a provider for each type that will notify when an object FOSElasticaBundle requires a provider for each type that will notify when an object
that maps to a type has been modified. The bundle ships with support for Doctrine and that maps to a type has been modified. The bundle ships with support for Doctrine and
@ -135,7 +122,7 @@ Below is an example for the Doctrine ORM.
There are a significant number of options available for types, that can be There are a significant number of options available for types, that can be
[found here](types.md) [found here](types.md)
E: Populating the Elasticsearch index E) Populating the Elasticsearch index
------------------------------------- -------------------------------------
When using the providers and listeners that come with the bundle, any new or modified When using the providers and listeners that come with the bundle, any new or modified
@ -150,7 +137,7 @@ $ php app/console fos:elastica:populate
The command will also create all indexes and types defined if they do not already exist The command will also create all indexes and types defined if they do not already exist
on the Elasticsearch server. on the Elasticsearch server.
F: Usage F) Usage
-------- --------
Usage documentation for the bundle is available [here](usage.md) Usage documentation for the bundle is available [here](usage.md)

View file

@ -1,34 +1,6 @@
Type configuration 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 Handling missing results with FOSElasticaBundle
----------------------------------------------- -----------------------------------------------
@ -201,18 +173,13 @@ index enabled users.
The callback option supports multiple approaches: The callback option supports multiple approaches:
* A method on the object itself provided as a string. `enabled` will call * A method on the object itself provided as a string. `enabled` will call
`Object->enabled()`. Note that this does not support chaining methods with dot notation `Object->enabled()`
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 * 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 and only argument. `[ @my_custom_service, 'userIndexable' ]` will call the userIndexable
method on a service defined as my_custom_service. 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 * 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' ]` the object as the only argument. `[ 'Acme\DemoBundle\IndexableChecker', 'isIndexable' ]`
will call Acme\DemoBundle\IndexableChecker::isIndexable($object) 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 * If you have the ExpressionLanguage component installed, A valid ExpressionLanguage
expression provided as a string. The object being indexed will be supplied as `object` expression provided as a string. The object being indexed will be supplied as `object`
in the expression. `object.isEnabled() or object.shouldBeIndexedAnyway()`. For more in the expression. `object.isEnabled() or object.shouldBeIndexedAnyway()`. For more

View file

@ -26,9 +26,7 @@ $userPaginator = $finder->findPaginated('bob');
$countOfResults = $userPaginator->getNbResults(); $countOfResults = $userPaginator->getNbResults();
// Option 3b. KnpPaginator resultset // Option 3b. KnpPaginator resultset
$paginator = $this->get('knp_paginator');
$results = $finder->createPaginatorAdapter('bob');
$pagination = $paginator->paginate($results, $page, 10);
``` ```
Faceted Searching Faceted Searching
@ -162,7 +160,7 @@ fos_elastica:
site: site:
settings: settings:
index: index:
analysis: analysis:
analyzer: analyzer:
my_analyzer: my_analyzer:
type: snowball type: snowball

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

View file

@ -23,7 +23,7 @@
{% block menu %} {% block menu %}
<span class="label"> <span class="label">
<span class="icon"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAcCAQAAADPJofWAAAAAXNSR0IArs4c6QAAAAJiS0dEAP+Hj8y/AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH2woEDg0xnxGaxwAAA51JREFUOMt100ts1FUUx/Hvufc/8x9mOrTTDpbysEVsqTzUqAsRgpqQGIJiIhtZSEJcqNGFJrSiZSPYkKALBUyAiLEuWKjBhdFAaEwwPNQqEAgEaA0FEWh4lE477/+9x0WLsST+Fmf1ycnJvecI/0knW4ENgZkhr5gVMtcEMmB64z1msCOCboR70tlkOuQdQREMBovF7tQt71/mXtzZQo8s89jLycFETiSqKd/v5wSY32VN18Ak3JGiR1d7an+Y3Z/Np7yVeCY/9czU4efF2iPxZ+wLXPgXP7WCTZ7MvvlnZlbqSJnGGbMeam5pk6HTIw9qs7tiH6D9vrbXW9e1Tus/sbhHZ8VOtfU1uZSExCUe1ExLtqayjcPnx4qNssjOs3TQrY9rYdVB2aFRw7HWq2kbJxCjFAsDoY+3hbkbw9ebNBsQ6EJVNlb3yQIDY8lcaAIsBisxiSXGToTNWqi/JUWXMIoabrK/95ymDNYHzmDUYAiwWOImOle+EI2AxyiKVydQGVAIoyneiBUNsAQEWIn+LA2NJqOYw3hUFQV2DFbu+FSuKTk9kRGMBoyPE7m8vza7UhMrmQNlV+NwAlDZXmXkkcHaeNamQBCEiLyeb7w631C71yxfr8/6YT8GUP6ifKlcf3xJX26kWNQyJfL+TvVs3S8rCw31hfRm2/KzL+iGQz8BnLjz8EVd5TPXF9wI/E0ZK/gr6SOLj7+Yz9RRu2bmMXm6y2/0A/rS0f6JL985+prVQAJiKEU8kLid6ezaA8Gh7iVP6BKtHad7njQr+xmSeFELLi2YovwlJ5Nbu07DNoLFoVNVrwBvh6feSMwSDcVuLvWF0y3Brd9mDlRlTsuVweGPCRzI+NOBW2rW3iYv5ZPfbrm7ji2fx1/Vkn7U/OGlivE4HA5Yh+yqUKFAYa3QfXcVf/R7Segy3wDGo4x3Tr3H3LLmqX6mZ5+jC4A5DO7jLR3SmAoYj8eTqx5uMR+UKErp78q2/e7ARNuLgE940bR1E9jpcKx+16MxJUd5+68XJp+a5DnqFxU/yYZG8XiSfJ+awkIW9WW+zLF8sh6NeqJb0cs+biIcKjW8u3T3xj+uZXZ/PbSe3km2nHWbogb3ZlSgPWz/bt71tsf432Qa64bSh5PTIFAU0pqdG3oRIiCgBBgsVTwRpYwmnWgMAlUd1aR+6m+DA4QqBlDKRDgifCqq8WO+CoFW9Ctd7dvBA+NV8DgiognuSv4bbsA/e9y1PQRZggAAAAAASUVORK5CYII=" alt="" /></span> <span class="icon"><img src="{{ asset('bundles/foselastica/images/elastica.png') }}" alt="" /></span>
<strong>Elastica</strong> <strong>Elastica</strong>
<span class="count"> <span class="count">
<span>{{ collector.querycount }}</span> <span>{{ collector.querycount }}</span>

View file

@ -8,7 +8,7 @@ use JMS\Serializer\SerializerInterface;
class Callback class Callback
{ {
protected $serializer; protected $serializer;
protected $groups = array(); protected $groups;
protected $version; protected $version;
public function setSerializer($serializer) public function setSerializer($serializer)
@ -23,8 +23,10 @@ class Callback
{ {
$this->groups = $groups; $this->groups = $groups;
if (!empty($this->groups) && !$this->serializer instanceof SerializerInterface) { if ($this->groups) {
throw new \RuntimeException('Setting serialization groups requires using "JMS\Serializer\Serializer".'); if (!$this->serializer instanceof SerializerInterface) {
throw new \RuntimeException('Setting serialization groups requires using "JMS\Serializer\Serializer".');
}
} }
} }
@ -32,8 +34,10 @@ class Callback
{ {
$this->version = $version; $this->version = $version;
if ($this->version && !$this->serializer instanceof SerializerInterface) { if ($this->version) {
throw new \RuntimeException('Setting serialization version requires using "JMS\Serializer\Serializer".'); if (!$this->serializer instanceof SerializerInterface) {
throw new \RuntimeException('Setting serialization version requires using "JMS\Serializer\Serializer".');
}
} }
} }
@ -41,7 +45,7 @@ class Callback
{ {
$context = $this->serializer instanceof SerializerInterface ? SerializationContext::create()->enableMaxDepthChecks() : array(); $context = $this->serializer instanceof SerializerInterface ? SerializationContext::create()->enableMaxDepthChecks() : array();
if (!empty($this->groups)) { if ($this->groups) {
$context->setGroups($this->groups); $context->setGroups($this->groups);
} }

View file

@ -32,17 +32,13 @@ class PaginateElasticaQuerySubscriber implements EventSubscriberInterface
if (null != $facets) { if (null != $facets) {
$event->setCustomPaginationParameter('facets', $facets); $event->setCustomPaginationParameter('facets', $facets);
} }
$aggregations = $results->getAggregations();
if (null != $aggregations) {
$event->setCustomPaginationParameter('aggregations', $aggregations);
}
$event->stopPropagation(); $event->stopPropagation();
} }
} }
/** /**
* Adds knp paging sort to query. * Adds knp paging sort to query
* *
* @param ItemsEvent $event * @param ItemsEvent $event
*/ */
@ -74,7 +70,7 @@ class PaginateElasticaQuerySubscriber implements EventSubscriberInterface
public static function getSubscribedEvents() public static function getSubscribedEvents()
{ {
return array( return array(
'knp_pager.items' => array('items', 1), 'knp_pager.items' => array('items', 1)
); );
} }
} }

View file

@ -2,6 +2,7 @@
namespace FOS\ElasticaBundle\Tests\Command; namespace FOS\ElasticaBundle\Tests\Command;
use FOS\ElasticaBundle\Command\ResetCommand; use FOS\ElasticaBundle\Command\ResetCommand;
use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\NullOutput; use Symfony\Component\Console\Output\NullOutput;
@ -9,8 +10,8 @@ use Symfony\Component\DependencyInjection\Container;
class ResetCommandTest extends \PHPUnit_Framework_TestCase class ResetCommandTest extends \PHPUnit_Framework_TestCase
{ {
private $command;
private $resetter; private $resetter;
private $indexManager; private $indexManager;
public function setup() public function setup()
@ -87,4 +88,4 @@ class ResetCommandTest extends \PHPUnit_Framework_TestCase
new NullOutput() new NullOutput()
); );
} }
} }

View file

@ -6,7 +6,7 @@ use FOS\ElasticaBundle\DependencyInjection\Configuration;
use Symfony\Component\Config\Definition\Processor; use Symfony\Component\Config\Definition\Processor;
/** /**
* ConfigurationTest. * ConfigurationTest
*/ */
class ConfigurationTest extends \PHPUnit_Framework_TestCase class ConfigurationTest extends \PHPUnit_Framework_TestCase
{ {
@ -34,7 +34,7 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase
$this->assertSame(array( $this->assertSame(array(
'clients' => array(), 'clients' => array(),
'indexes' => array(), 'indexes' => array(),
'default_manager' => 'orm', 'default_manager' => 'orm'
), $configuration); ), $configuration);
} }
@ -50,18 +50,18 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase
array( array(
'url' => 'http://es1:9200', 'url' => 'http://es1:9200',
'headers' => array( 'headers' => array(
'Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==', 'Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=='
), )
), ),
array( array(
'url' => 'http://es2:9200', 'url' => 'http://es2:9200',
'headers' => array( 'headers' => array(
'Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==', 'Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=='
), )
), ),
), )
), )
), )
)); ));
$this->assertCount(2, $configuration['clients']); $this->assertCount(2, $configuration['clients']);
@ -91,9 +91,9 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase
), ),
'logging_custom' => array( 'logging_custom' => array(
'url' => 'http://localhost:9200', 'url' => 'http://localhost:9200',
'logger' => 'custom.service', 'logger' => 'custom.service'
), ),
), )
)); ));
$this->assertCount(4, $configuration['clients']); $this->assertCount(4, $configuration['clients']);
@ -131,8 +131,8 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase
), ),
'serializer' => array( 'serializer' => array(
'groups' => array('Search'), 'groups' => array('Search'),
'version' => 1, 'version' => 1
), )
), ),
'types' => array( 'types' => array(
'test' => array( 'test' => array(
@ -144,20 +144,20 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase
'persistence' => array( 'persistence' => array(
'listener' => array( 'listener' => array(
'logger' => true, 'logger' => true,
), )
), )
), ),
'test2' => array( 'test2' => array(
'mappings' => array( 'mappings' => array(
'title' => null, 'title' => null,
'children' => array( 'children' => array(
'type' => 'nested', 'type' => 'nested',
), )
), )
), )
), )
), )
), )
)); ));
} }
@ -169,7 +169,7 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase
'host' => 'localhost', 'host' => 'localhost',
'port' => 9200, 'port' => 9200,
), ),
), )
)); ));
$this->assertTrue(empty($configuration['clients']['default']['connections'][0]['url'])); $this->assertTrue(empty($configuration['clients']['default']['connections'][0]['url']));
@ -189,34 +189,16 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase
'title' => array(), 'title' => array(),
'published' => array('type' => 'datetime'), 'published' => array('type' => 'datetime'),
'body' => null, 'body' => null,
), )
), )
), )
), )
), )
)); ));
$this->assertCount(3, $configuration['indexes']['test']['types']['test']['properties']); $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() public function testNestedProperties()
{ {
$this->getConfigs(array( $this->getConfigs(array(
@ -243,23 +225,23 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase
'type' => 'nested', 'type' => 'nested',
'properties' => array( 'properties' => array(
'nested_field1' => array( 'nested_field1' => array(
'type' => 'integer', 'type' => 'integer'
), ),
'nested_field2' => array( 'nested_field2' => array(
'type' => 'object', 'type' => 'object',
'properties' => array( 'properties' => array(
'id' => array( 'id' => array(
'type' => 'integer', 'type' => 'integer'
), )
), )
), )
), )
), )
), )
), )
), )
), )
), )
)); ));
} }
} }

View file

@ -1,32 +0,0 @@
<?php
namespace FOS\ElasticaBundle\Tests\DependencyInjection;
use FOS\ElasticaBundle\DependencyInjection\FOSElasticaExtension;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Yaml\Yaml;
class FOSElasticaExtensionTest extends \PHPUnit_Framework_TestCase
{
public function testShouldAddParentParamToObjectPersisterCall()
{
$config = Yaml::parse(file_get_contents(__DIR__.'/fixtures/config.yml'));
$containerBuilder = new ContainerBuilder();
$containerBuilder->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');
$arguments = $persisterCallDefinition->getArguments();
$arguments = $arguments['index_3'];
$this->assertArrayHasKey('_parent', $arguments);
$this->assertEquals('parent_field', $arguments['_parent']['type']);
}
}

View file

@ -1,21 +0,0 @@
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" }

View file

@ -19,7 +19,7 @@ class AbstractElasticaToModelTransformerTest extends \PHPUnit_Framework_TestCase
protected $objectClass = 'stdClass'; 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() public function testIgnoreMissingOptionDuringTransformHybrid()
{ {
@ -55,6 +55,10 @@ class AbstractElasticaToModelTransformerTest extends \PHPUnit_Framework_TestCase
protected function setUp() 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') $this->registry = $this->getMockBuilder('Doctrine\Common\Persistence\ManagerRegistry')
->disableOriginalConstructor() ->disableOriginalConstructor()
->getMock(); ->getMock();

View file

@ -3,7 +3,7 @@
namespace FOS\ElasticaBundle\Tests\Doctrine; 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 <info@limethinking.co.uk> * @author Richard Miller <info@limethinking.co.uk>
*/ */
@ -16,7 +16,7 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase
$eventArgs = $this->createLifecycleEventArgs($entity, $this->getMockObjectManager()); $eventArgs = $this->createLifecycleEventArgs($entity, $this->getMockObjectManager());
$indexable = $this->getMockIndexable('index', 'type', $entity, true); $indexable = $this->getMockIndexable('index', 'type', $entity, true);
$listener = $this->createListener($persister, $indexable, array('indexName' => 'index', 'typeName' => 'type')); $listener = $this->createListener($persister, array(), $indexable, array('indexName' => 'index', 'typeName' => 'type'));
$listener->postPersist($eventArgs); $listener->postPersist($eventArgs);
$this->assertEquals($entity, current($listener->scheduledForInsertion)); $this->assertEquals($entity, current($listener->scheduledForInsertion));
@ -35,7 +35,7 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase
$eventArgs = $this->createLifecycleEventArgs($entity, $this->getMockObjectManager()); $eventArgs = $this->createLifecycleEventArgs($entity, $this->getMockObjectManager());
$indexable = $this->getMockIndexable('index', 'type', $entity, false); $indexable = $this->getMockIndexable('index', 'type', $entity, false);
$listener = $this->createListener($persister, $indexable, array('indexName' => 'index', 'typeName' => 'type')); $listener = $this->createListener($persister, array(), $indexable, array('indexName' => 'index', 'typeName' => 'type'));
$listener->postPersist($eventArgs); $listener->postPersist($eventArgs);
$this->assertEmpty($listener->scheduledForInsertion); $this->assertEmpty($listener->scheduledForInsertion);
@ -55,7 +55,7 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase
$eventArgs = $this->createLifecycleEventArgs($entity, $this->getMockObjectManager()); $eventArgs = $this->createLifecycleEventArgs($entity, $this->getMockObjectManager());
$indexable = $this->getMockIndexable('index', 'type', $entity, true); $indexable = $this->getMockIndexable('index', 'type', $entity, true);
$listener = $this->createListener($persister, $indexable, array('indexName' => 'index', 'typeName' => 'type')); $listener = $this->createListener($persister, array(), $indexable, array('indexName' => 'index', 'typeName' => 'type'));
$listener->postUpdate($eventArgs); $listener->postUpdate($eventArgs);
$this->assertEquals($entity, current($listener->scheduledForUpdate)); $this->assertEquals($entity, current($listener->scheduledForUpdate));
@ -89,7 +89,7 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase
->with($entity, 'id') ->with($entity, 'id')
->will($this->returnValue($entity->getId())); ->will($this->returnValue($entity->getId()));
$listener = $this->createListener($persister, $indexable, array('indexName' => 'index', 'typeName' => 'type')); $listener = $this->createListener($persister, array(), $indexable, array('indexName' => 'index', 'typeName' => 'type'));
$listener->postUpdate($eventArgs); $listener->postUpdate($eventArgs);
$this->assertEmpty($listener->scheduledForUpdate); $this->assertEmpty($listener->scheduledForUpdate);
@ -124,7 +124,7 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase
->with($entity, 'id') ->with($entity, 'id')
->will($this->returnValue($entity->getId())); ->will($this->returnValue($entity->getId()));
$listener = $this->createListener($persister, $indexable, array('indexName' => 'index', 'typeName' => 'type')); $listener = $this->createListener($persister, array(), $indexable, array('indexName' => 'index', 'typeName' => 'type'));
$listener->preRemove($eventArgs); $listener->preRemove($eventArgs);
$this->assertEquals($entity->getId(), current($listener->scheduledForDeletion)); $this->assertEquals($entity->getId(), current($listener->scheduledForDeletion));
@ -157,7 +157,7 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase
->with($entity, 'identifier') ->with($entity, 'identifier')
->will($this->returnValue($entity->getId())); ->will($this->returnValue($entity->getId()));
$listener = $this->createListener($persister, $indexable, array('identifier' => 'identifier', 'indexName' => 'index', 'typeName' => 'type')); $listener = $this->createListener($persister, array(), $indexable, array('identifier' => 'identifier', 'indexName' => 'index', 'typeName' => 'type'));
$listener->preRemove($eventArgs); $listener->preRemove($eventArgs);
$this->assertEquals($entity->identifier, current($listener->scheduledForDeletion)); $this->assertEquals($entity->identifier, current($listener->scheduledForDeletion));
@ -173,14 +173,8 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase
abstract protected function getListenerClass(); abstract protected function getListenerClass();
/**
* @return string
*/
abstract protected function getObjectManagerClass(); abstract protected function getObjectManagerClass();
/**
* @return string
*/
abstract protected function getClassMetadataClass(); abstract protected function getClassMetadataClass();
private function createLifecycleEventArgs() private function createLifecycleEventArgs()
@ -211,11 +205,6 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase
->getMock(); ->getMock();
} }
/**
* @param Listener\Entity $object
* @param string $indexName
* @param string $typeName
*/
private function getMockPersister($object, $indexName, $typeName) private function getMockPersister($object, $indexName, $typeName)
{ {
$mock = $this->getMockBuilder('FOS\ElasticaBundle\Persister\ObjectPersister') $mock = $this->getMockBuilder('FOS\ElasticaBundle\Persister\ObjectPersister')
@ -246,12 +235,6 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase
return $mock; return $mock;
} }
/**
* @param string $indexName
* @param string $typeName
* @param Listener\Entity $object
* @param boolean $return
*/
private function getMockIndexable($indexName, $typeName, $object, $return = null) private function getMockIndexable($indexName, $typeName, $object, $return = null)
{ {
$mock = $this->getMock('FOS\ElasticaBundle\Provider\IndexableInterface'); $mock = $this->getMock('FOS\ElasticaBundle\Provider\IndexableInterface');
@ -272,11 +255,7 @@ namespace FOS\ElasticaBundle\Tests\Doctrine\Listener;
class Entity class Entity
{ {
private $id; private $id;
public $identifier;
/**
* @param integer $id
*/
public function __construct($id) public function __construct($id)
{ {
$this->id = $id; $this->id = $id;
@ -287,3 +266,4 @@ class Entity
return $this->id; return $this->id;
} }
} }

View file

@ -13,10 +13,13 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase
private $options; private $options;
private $managerRegistry; private $managerRegistry;
private $indexable; private $indexable;
private $sliceFetcher;
public function setUp() public function setUp()
{ {
if (!interface_exists('Doctrine\Common\Persistence\ManagerRegistry')) {
$this->markTestSkipped('Doctrine Common is not available.');
}
$this->objectClass = 'objectClass'; $this->objectClass = 'objectClass';
$this->options = array('debug_logging' => true, 'indexName' => 'index', 'typeName' => 'type'); $this->options = array('debug_logging' => true, 'indexName' => 'index', 'typeName' => 'type');
@ -29,8 +32,6 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase
->method('getManagerForClass') ->method('getManagerForClass')
->with($this->objectClass) ->with($this->objectClass)
->will($this->returnValue($this->objectManager)); ->will($this->returnValue($this->objectManager));
$this->sliceFetcher = $this->getMockSliceFetcher();
} }
/** /**
@ -44,53 +45,6 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase
$queryBuilder = new \stdClass(); $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));
$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()) $provider->expects($this->once())
->method('createQueryBuilder') ->method('createQueryBuilder')
->will($this->returnValue($queryBuilder)); ->will($this->returnValue($queryBuilder));
@ -130,7 +84,7 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase
return array( return array(
array( array(
100, 100,
array(range(1, 100)), array(range(1,100)),
100, 100,
), ),
array( array(
@ -153,8 +107,8 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase
->method('countObjects') ->method('countObjects')
->will($this->returnValue($nbObjects)); ->will($this->returnValue($nbObjects));
$this->sliceFetcher->expects($this->any()) $provider->expects($this->any())
->method('fetch') ->method('fetchSlice')
->will($this->returnValue($objects)); ->will($this->returnValue($objects));
$this->indexable->expects($this->any()) $this->indexable->expects($this->any())
@ -168,32 +122,6 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase
$provider->populate(); $provider->populate();
} }
public function testPopulateShouldClearObjectManagerForFilteredBatch()
{
$nbObjects = 1;
$objects = array(1);
$provider = $this->getMockAbstractProvider(true);
$provider->expects($this->any())
->method('countObjects')
->will($this->returnValue($nbObjects));
$this->sliceFetcher->expects($this->any())
->method('fetch')
->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() public function testPopulateInvokesLoggerClosure()
{ {
$nbObjects = 1; $nbObjects = 1;
@ -205,8 +133,8 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase
->method('countObjects') ->method('countObjects')
->will($this->returnValue($nbObjects)); ->will($this->returnValue($nbObjects));
$this->sliceFetcher->expects($this->any()) $provider->expects($this->any())
->method('fetch') ->method('fetchSlice')
->will($this->returnValue($objects)); ->will($this->returnValue($objects));
$this->indexable->expects($this->any()) $this->indexable->expects($this->any())
@ -237,8 +165,8 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase
->method('countObjects') ->method('countObjects')
->will($this->returnValue($nbObjects)); ->will($this->returnValue($nbObjects));
$this->sliceFetcher->expects($this->any()) $provider->expects($this->any())
->method('fetch') ->method('fetchSlice')
->will($this->returnValue($objects)); ->will($this->returnValue($objects));
$this->indexable->expects($this->any()) $this->indexable->expects($this->any())
@ -252,7 +180,7 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase
$this->setExpectedException('Elastica\Exception\Bulk\ResponseException'); $this->setExpectedException('Elastica\Exception\Bulk\ResponseException');
$provider->populate(null, array('ignore_errors' => false)); $provider->populate(null, array('ignore-errors' => false));
} }
public function testPopulateRunsIndexCallable() public function testPopulateRunsIndexCallable()
@ -264,9 +192,8 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase
$provider->expects($this->any()) $provider->expects($this->any())
->method('countObjects') ->method('countObjects')
->will($this->returnValue($nbObjects)); ->will($this->returnValue($nbObjects));
$provider->expects($this->any())
$this->sliceFetcher->expects($this->any()) ->method('fetchSlice')
->method('fetch')
->will($this->returnValue($objects)); ->will($this->returnValue($objects));
$this->indexable->expects($this->at(0)) $this->indexable->expects($this->at(0))
@ -278,19 +205,18 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase
->with('index', 'type', 2) ->with('index', 'type', 2)
->will($this->returnValue(true)); ->will($this->returnValue(true));
$this->objectPersister->expects($this->once()) $this->objectPersister->expects($this->once())
->method('insertMany') ->method('insertMany')
->with(array(2)); ->with(array(1 => 2));
$provider->populate(); $provider->populate();
} }
/** /**
* @param boolean $setSliceFetcher Whether or not to set the slice fetcher.
*
* @return \FOS\ElasticaBundle\Doctrine\AbstractProvider|\PHPUnit_Framework_MockObject_MockObject * @return \FOS\ElasticaBundle\Doctrine\AbstractProvider|\PHPUnit_Framework_MockObject_MockObject
*/ */
private function getMockAbstractProvider($setSliceFetcher = true) private function getMockAbstractProvider()
{ {
return $this->getMockForAbstractClass('FOS\ElasticaBundle\Doctrine\AbstractProvider', array( return $this->getMockForAbstractClass('FOS\ElasticaBundle\Doctrine\AbstractProvider', array(
$this->objectPersister, $this->objectPersister,
@ -298,7 +224,6 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase
$this->objectClass, $this->objectClass,
$this->options, $this->options,
$this->managerRegistry, $this->managerRegistry,
$setSliceFetcher ? $this->sliceFetcher : null
)); ));
} }
@ -308,7 +233,7 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase
private function getMockBulkResponseException() private function getMockBulkResponseException()
{ {
return $this->getMock('Elastica\Exception\Bulk\ResponseException', null, array( return $this->getMock('Elastica\Exception\Bulk\ResponseException', null, array(
new ResponseSet(new Response(array()), array()), new ResponseSet(new Response(array()), array())
)); ));
} }
@ -325,17 +250,7 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase
*/ */
private function getMockObjectManager() private function getMockObjectManager()
{ {
$mock = $this->getMock(__NAMESPACE__.'\ObjectManager'); return $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;
} }
/** /**
@ -353,14 +268,6 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase
{ {
return $this->getMock('FOS\ElasticaBundle\Provider\IndexableInterface'); 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');
}
} }
/** /**
@ -369,7 +276,5 @@ class AbstractProviderTest extends \PHPUnit_Framework_TestCase
*/ */
interface ObjectManager interface ObjectManager
{ {
public function clear(); function clear();
public function getClassMetadata();
public function getIdentifierFieldNames();
} }

View file

@ -82,6 +82,13 @@ class ElasticaToModelTransformerTest extends \PHPUnit_Framework_TestCase
protected function setUp() 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') $this->registry = $this->getMockBuilder('Doctrine\Common\Persistence\ManagerRegistry')
->disableOriginalConstructor() ->disableOriginalConstructor()
->getMock(); ->getMock();
@ -102,7 +109,7 @@ class ElasticaToModelTransformerTest extends \PHPUnit_Framework_TestCase
'findAll', 'findAll',
'findBy', 'findBy',
'findOneBy', 'findOneBy',
'getClassName', 'getClassName'
)); ));
$this->manager->expects($this->any()) $this->manager->expects($this->any())

View file

@ -6,6 +6,13 @@ use FOS\ElasticaBundle\Tests\Doctrine\ListenerTest as BaseListenerTest;
class ListenerTest extends BaseListenerTest class ListenerTest extends BaseListenerTest
{ {
public function setUp()
{
if (!class_exists('Doctrine\ORM\EntityManager')) {
$this->markTestSkipped('Doctrine ORM is not available.');
}
}
protected function getClassMetadataClass() protected function getClassMetadataClass()
{ {
return 'Doctrine\ORM\Mapping\ClassMetadata'; return 'Doctrine\ORM\Mapping\ClassMetadata';

View file

@ -4,19 +4,22 @@ namespace FOS\ElasticaBundle\Tests\Doctrine;
use FOS\ElasticaBundle\Doctrine\RepositoryManager; use FOS\ElasticaBundle\Doctrine\RepositoryManager;
class CustomRepository class CustomRepository{}
{
}
class Entity class Entity{}
{
}
/** /**
* @author Richard Miller <info@limethinking.co.uk> * @author Richard Miller <info@limethinking.co.uk>
*/ */
class RepositoryManagerTest extends \PHPUnit_Framework_TestCase 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() public function testThatGetRepositoryReturnsDefaultRepository()
{ {
/** @var $finderMock \PHPUnit_Framework_MockObject_MockObject|\FOS\ElasticaBundle\Finder\TransformedFinder */ /** @var $finderMock \PHPUnit_Framework_MockObject_MockObject|\FOS\ElasticaBundle\Finder\TransformedFinder */

View file

@ -5,11 +5,11 @@ namespace FOS\ElasticaBundle\Tests\Client;
use Elastica\Request; use Elastica\Request;
use Elastica\Transport\Null as NullTransport; use Elastica\Transport\Null as NullTransport;
class ClientTest extends \PHPUnit_Framework_TestCase class LoggingClientTest extends \PHPUnit_Framework_TestCase
{ {
public function testRequestsAreLogged() public function testRequestsAreLogged()
{ {
$transport = new NullTransport(); $transport = new NullTransport;
$connection = $this->getMock('Elastica\Connection'); $connection = $this->getMock('Elastica\Connection');
$connection->expects($this->any())->method('getTransportObject')->will($this->returnValue($transport)); $connection->expects($this->any())->method('getTransportObject')->will($this->returnValue($transport));

View file

@ -3,6 +3,7 @@
namespace FOS\ElasticaBundle\Tests\Resetter; namespace FOS\ElasticaBundle\Tests\Resetter;
use FOS\ElasticaBundle\FOSElasticaBundle; use FOS\ElasticaBundle\FOSElasticaBundle;
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
class FOSElasticaBundleTest extends \PHPUnit_Framework_TestCase class FOSElasticaBundleTest extends \PHPUnit_Framework_TestCase
{ {
@ -16,6 +17,7 @@ class FOSElasticaBundleTest extends \PHPUnit_Framework_TestCase
->method('addCompilerPass') ->method('addCompilerPass')
->with($this->isInstanceOf('Symfony\\Component\\DependencyInjection\\Compiler\\CompilerPassInterface')); ->with($this->isInstanceOf('Symfony\\Component\\DependencyInjection\\Compiler\\CompilerPassInterface'));
$bundle = new FOSElasticaBundle(); $bundle = new FOSElasticaBundle();
$bundle->build($container); $bundle->build($container);
} }

View file

@ -1,48 +0,0 @@
<?php
/**
* This file is part of the FOSElasticaBundle project.
*
* (c) Tim Nagel <tim@nagel.com.au>
*
* 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');
}
}

View file

@ -47,7 +47,6 @@ class ConfigurationManagerTest extends WebTestCase
/** /**
* @param Client $client * @param Client $client
*
* @return \FOS\ElasticaBundle\Configuration\ConfigManager * @return \FOS\ElasticaBundle\Configuration\ConfigManager
*/ */
private function getManager(Client $client) private function getManager(Client $client)

View file

@ -17,7 +17,7 @@ namespace FOS\ElasticaBundle\Tests\Functional;
class IndexableCallbackTest extends WebTestCase 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 * 1) To test that the configuration rename from is_indexable_callback under the listener
* key is respected, and * key is respected, and

Some files were not shown because too many files have changed in this diff Show more