Compare commits
3 commits
Author | SHA1 | Date | |
---|---|---|---|
7d06cc429b | |||
15d3f1e4f8 | |||
4c961a757d |
|
@ -1,5 +0,0 @@
|
|||
imports:
|
||||
- php
|
||||
|
||||
tools:
|
||||
external_code_coverage: true
|
29
.travis.yml
29
.travis.yml
|
@ -1,36 +1,9 @@
|
|||
language: php
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.composer/cache
|
||||
|
||||
php:
|
||||
- 5.3
|
||||
- 5.4
|
||||
- 5.5
|
||||
- 5.6
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- php: 5.5
|
||||
env: SYMFONY_VERSION='2.3.*'
|
||||
- php: 5.5
|
||||
env: SYMFONY_VERSION='2.5.*'
|
||||
|
||||
before_script:
|
||||
- /usr/share/elasticsearch/bin/elasticsearch -v
|
||||
- sudo /usr/share/elasticsearch/bin/plugin -install elasticsearch/elasticsearch-mapper-attachments/2.0.0
|
||||
- sudo service elasticsearch restart
|
||||
- sh -c 'if [ "$TRAVIS_PHP_VERSION" != "hhvm" ]; then echo "extension = mongo.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi;'
|
||||
- sh -c 'if [ "$SYMFONY_VERSION" != "" ]; then composer require --dev --no-update symfony/symfony=$SYMFONY_VERSION; fi;'
|
||||
- echo "extension = mongo.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
|
||||
- composer install --dev --prefer-source
|
||||
|
||||
script:
|
||||
- vendor/bin/phpunit --coverage-clover=coverage.clover
|
||||
|
||||
services:
|
||||
- elasticsearch
|
||||
|
||||
after_script:
|
||||
- wget https://scrutinizer-ci.com/ocular.phar
|
||||
- php ocular.phar code-coverage:upload --format=php-clover coverage.clover
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Annotation;
|
||||
|
||||
/**
|
||||
* Annotation class for setting search repository.
|
||||
*
|
||||
* @author Richard Miller <info@limethinking.co.uk>
|
||||
* @Annotation
|
||||
* @Target("CLASS")
|
||||
*/
|
||||
class Search
|
||||
{
|
||||
/** @var string */
|
||||
public $repositoryClass;
|
||||
}
|
|
@ -12,52 +12,17 @@ https://github.com/FriendsOfSymfony/FOSElasticaBundle/compare/v3.0.0...v3.0.1
|
|||
To generate a changelog summary since the last version, run
|
||||
`git log --no-merges --oneline v3.0.0...3.0.x`
|
||||
|
||||
* 3.0.9 (2015-03-12)
|
||||
* 3.0.0
|
||||
|
||||
* 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
|
||||
|
||||
* Moved `is_indexable_callback` from the listener properties to a type property called
|
||||
`indexable_callback` which is run when both populating and listening for object
|
||||
changes.
|
||||
* AbstractProvider constructor change: Second argument is now an `IndexableInterface`
|
||||
instance.
|
||||
* Annotation @Search moved to FOS\ElasticaBundle\Annotation\Search with FOS\ElasticaBundle\Configuration\Search deprecated
|
||||
* Deprecated FOS\ElasticaBundle\Client in favour of FOS\ElasticaBundle\Elastica\Client
|
||||
* Deprecated FOS\ElasticaBundle\DynamicIndex in favour of FOS\ElasticaBundle\Elastica\Index
|
||||
* Deprecated FOS\ElasticaBundle\Client in favour of FOS\ElasticaBundle\Elastica\LoggingClient
|
||||
* Deprecated FOS\ElasticaBundle\DynamicIndex in favour of FOS\ElasticaBundle\Elastica\TransformingIndex
|
||||
* Deprecated FOS\ElasticaBundle\IndexManager in favour of FOS\ElasticaBundle\Index\IndexManager
|
||||
* Deprecated FOS\ElasticaBundle\Resetter in favour of FOS\ElasticaBundle\Index\Resetter
|
||||
|
||||
* 3.0.0-ALPHA5 (2014-05-23)
|
||||
|
||||
* Doctrine Provider speed up by disabling persistence logging while populating documents
|
||||
|
||||
* 3.0.0-ALPHA4 (2014-04-10)
|
||||
|
||||
* Indexes are now capable of logging errors with Elastica
|
||||
* Fixed deferred indexing of deleted documents
|
||||
* Resetting an index will now create it even if it doesn't exist
|
||||
* Bulk upserting of documents is now supported when populating
|
||||
|
||||
* 3.0.0-ALPHA3 (2014-04-01)
|
||||
|
||||
|
@ -66,7 +31,6 @@ To generate a changelog summary since the last version, run
|
|||
* #415: BC BREAK: document indexing occurs in postFlush rather than the pre* events previously.
|
||||
* 7d13823: Dropped (broken) support for Symfony <2.3
|
||||
* #496: Added support for HTTP headers
|
||||
* #528: FOSElasticaBundle will disable Doctrine logging when populating for a large increase in speed
|
||||
|
||||
* 3.0.0-ALPHA2 (2014-03-17)
|
||||
|
||||
|
|
|
@ -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
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
namespace FOS\ElasticaBundle;
|
||||
|
||||
use FOS\ElasticaBundle\Elastica\Client as BaseClient;
|
||||
use FOS\ElasticaBundle\Elastica\LoggingClient;
|
||||
|
||||
/**
|
||||
* @deprecated Use \FOS\ElasticaBundle\Elastica\LoggingClient
|
||||
*/
|
||||
class Client extends BaseClient
|
||||
class Client extends LoggingClient
|
||||
{
|
||||
}
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
namespace FOS\ElasticaBundle\Command;
|
||||
|
||||
use FOS\ElasticaBundle\Event\IndexPopulateEvent;
|
||||
use FOS\ElasticaBundle\Event\TypePopulateEvent;
|
||||
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
|
||||
use Symfony\Component\Console\Helper\DialogHelper;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
@ -12,28 +10,18 @@ use Symfony\Component\Console\Output\OutputInterface;
|
|||
use FOS\ElasticaBundle\IndexManager;
|
||||
use FOS\ElasticaBundle\Provider\ProviderRegistry;
|
||||
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
|
||||
{
|
||||
/**
|
||||
* @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
|
||||
*/
|
||||
private $dispatcher;
|
||||
|
||||
/**
|
||||
* @var IndexManager
|
||||
*/
|
||||
private $indexManager;
|
||||
|
||||
/**
|
||||
* @var ProgressClosureBuilder
|
||||
*/
|
||||
private $progressClosureBuilder;
|
||||
|
||||
/**
|
||||
* @var ProviderRegistry
|
||||
*/
|
||||
|
@ -58,46 +46,31 @@ class PopulateCommand extends ContainerAwareCommand
|
|||
->addOption('sleep', null, InputOption::VALUE_REQUIRED, 'Sleep time between persisting iterations (microseconds)', 0)
|
||||
->addOption('batch-size', null, InputOption::VALUE_REQUIRED, 'Index packet size (overrides provider config option)')
|
||||
->addOption('ignore-errors', null, InputOption::VALUE_NONE, 'Do not stop on errors')
|
||||
->addOption('no-overwrite-format', null, InputOption::VALUE_NONE, 'Prevent this command from overwriting ProgressBar\'s formats')
|
||||
->setDescription('Populates search indexes from providers')
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see Symfony\Component\Console\Command\Command::initialize()
|
||||
*/
|
||||
protected function initialize(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->dispatcher = $this->getContainer()->get('event_dispatcher');
|
||||
$this->indexManager = $this->getContainer()->get('fos_elastica.index_manager');
|
||||
$this->providerRegistry = $this->getContainer()->get('fos_elastica.provider_registry');
|
||||
$this->resetter = $this->getContainer()->get('fos_elastica.resetter');
|
||||
$this->progressClosureBuilder = new ProgressClosureBuilder();
|
||||
|
||||
if (!$input->getOption('no-overwrite-format') && 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)
|
||||
{
|
||||
$index = $input->getOption('index');
|
||||
$type = $input->getOption('type');
|
||||
$reset = !$input->getOption('no-reset');
|
||||
$options = array(
|
||||
'ignore_errors' => $input->getOption('ignore-errors'),
|
||||
'offset' => $input->getOption('offset'),
|
||||
'sleep' => $input->getOption('sleep')
|
||||
);
|
||||
if ($input->getOption('batch-size')) {
|
||||
$options['batch_size'] = (int) $input->getOption('batch-size');
|
||||
}
|
||||
$index = $input->getOption('index');
|
||||
$type = $input->getOption('type');
|
||||
$reset = !$input->getOption('no-reset');
|
||||
$options = $input->getOptions();
|
||||
|
||||
$options['ignore-errors'] = $input->hasOption('ignore-errors');
|
||||
|
||||
if ($input->isInteractive() && $reset && $input->getOption('offset')) {
|
||||
/** @var DialogHelper $dialog */
|
||||
|
@ -136,22 +109,25 @@ class PopulateCommand extends ContainerAwareCommand
|
|||
*/
|
||||
private function populateIndex(OutputInterface $output, $index, $reset, $options)
|
||||
{
|
||||
$event = new IndexPopulateEvent($index, $reset, $options);
|
||||
$this->dispatcher->dispatch(IndexPopulateEvent::PRE_INDEX_POPULATE, $event);
|
||||
|
||||
if ($event->isReset()) {
|
||||
if ($reset) {
|
||||
$output->writeln(sprintf('<info>Resetting</info> <comment>%s</comment>', $index));
|
||||
$this->resetter->resetIndex($index, true);
|
||||
$this->resetter->resetIndex($index);
|
||||
}
|
||||
|
||||
$types = array_keys($this->providerRegistry->getIndexProviders($index));
|
||||
foreach ($types as $type) {
|
||||
$this->populateIndexType($output, $index, $type, false, $event->getOptions());
|
||||
/** @var $providers ProviderInterface[] */
|
||||
$providers = $this->providerRegistry->getIndexProviders($index);
|
||||
|
||||
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);
|
||||
|
||||
$this->refreshIndex($output, $index);
|
||||
$output->writeln(sprintf('<info>Refreshing</info> <comment>%s</comment>', $index));
|
||||
$this->resetter->postPopulate($index);
|
||||
$this->indexManager->getIndex($index)->refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -165,35 +141,17 @@ class PopulateCommand extends ContainerAwareCommand
|
|||
*/
|
||||
private function populateIndexType(OutputInterface $output, $index, $type, $reset, $options)
|
||||
{
|
||||
$event = new TypePopulateEvent($index, $type, $reset, $options);
|
||||
$this->dispatcher->dispatch(TypePopulateEvent::PRE_TYPE_POPULATE, $event);
|
||||
|
||||
if ($event->isReset()) {
|
||||
if ($reset) {
|
||||
$output->writeln(sprintf('<info>Resetting</info> <comment>%s/%s</comment>', $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);
|
||||
$loggerClosure = $this->progressClosureBuilder->build($output, 'Populating', $index, $type);
|
||||
$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);
|
||||
}
|
||||
$provider->populate($loggerClosure, $options);
|
||||
|
||||
$output->writeln(sprintf('<info>Refreshing</info> <comment>%s</comment>', $index));
|
||||
$this->indexManager->getIndex($index)->refresh();
|
||||
|
|
|
@ -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))
|
||||
));
|
||||
};
|
||||
}
|
||||
}
|
|
@ -10,7 +10,7 @@ use FOS\ElasticaBundle\IndexManager;
|
|||
use FOS\ElasticaBundle\Resetter;
|
||||
|
||||
/**
|
||||
* Reset search indexes.
|
||||
* Reset search indexes
|
||||
*/
|
||||
class ResetCommand extends ContainerAwareCommand
|
||||
{
|
||||
|
@ -33,7 +33,6 @@ class ResetCommand extends ContainerAwareCommand
|
|||
->setName('fos:elastica:reset')
|
||||
->addOption('index', null, InputOption::VALUE_OPTIONAL, 'The index to reset')
|
||||
->addOption('type', null, InputOption::VALUE_OPTIONAL, 'The type to reset')
|
||||
->addOption('force', null, InputOption::VALUE_NONE, 'Force index deletion if same name as alias')
|
||||
->setDescription('Reset search indexes')
|
||||
;
|
||||
}
|
||||
|
@ -52,9 +51,8 @@ class ResetCommand extends ContainerAwareCommand
|
|||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$index = $input->getOption('index');
|
||||
$type = $input->getOption('type');
|
||||
$force = (bool) $input->getOption('force');
|
||||
$index = $input->getOption('index');
|
||||
$type = $input->getOption('type');
|
||||
|
||||
if (null === $index && null !== $type) {
|
||||
throw new \InvalidArgumentException('Cannot specify type option without an index.');
|
||||
|
@ -71,7 +69,7 @@ class ResetCommand extends ContainerAwareCommand
|
|||
|
||||
foreach ($indexes as $index) {
|
||||
$output->writeln(sprintf('<info>Resetting</info> <comment>%s</comment>', $index));
|
||||
$this->resetter->resetIndex($index, false, $force);
|
||||
$this->resetter->resetIndex($index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ use Elastica\Query;
|
|||
use Elastica\Result;
|
||||
|
||||
/**
|
||||
* Searches a type.
|
||||
* Searches a type
|
||||
*/
|
||||
class SearchCommand extends ContainerAwareCommand
|
||||
{
|
||||
|
|
|
@ -1,64 +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\Configuration;
|
||||
|
||||
/**
|
||||
* Central manager for index and type configuration.
|
||||
*/
|
||||
class ConfigManager implements ManagerInterface
|
||||
{
|
||||
/**
|
||||
* @var IndexConfig[]
|
||||
*/
|
||||
private $indexes = array();
|
||||
|
||||
/**
|
||||
* @param Source\SourceInterface[] $sources
|
||||
*/
|
||||
public function __construct(array $sources)
|
||||
{
|
||||
foreach ($sources as $source) {
|
||||
$this->indexes = array_merge($source->getConfiguration(), $this->indexes);
|
||||
}
|
||||
}
|
||||
|
||||
public function getIndexConfiguration($indexName)
|
||||
{
|
||||
if (!$this->hasIndexConfiguration($indexName)) {
|
||||
throw new \InvalidArgumentException(sprintf('Index with name "%s" is not configured.', $indexName));
|
||||
}
|
||||
|
||||
return $this->indexes[$indexName];
|
||||
}
|
||||
|
||||
public function getIndexNames()
|
||||
{
|
||||
return array_keys($this->indexes);
|
||||
}
|
||||
|
||||
public function getTypeConfiguration($indexName, $typeName)
|
||||
{
|
||||
$index = $this->getIndexConfiguration($indexName);
|
||||
$type = $index->getType($typeName);
|
||||
|
||||
if (!$type) {
|
||||
throw new \InvalidArgumentException(sprintf('Type with name "%s" on index "%s" is not configured', $typeName, $indexName));
|
||||
}
|
||||
|
||||
return $type;
|
||||
}
|
||||
|
||||
public function hasIndexConfiguration($indexName)
|
||||
{
|
||||
return isset($this->indexes[$indexName]);
|
||||
}
|
||||
}
|
|
@ -1,124 +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\Configuration;
|
||||
|
||||
class IndexConfig
|
||||
{
|
||||
/**
|
||||
* The name of the index for ElasticSearch.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $elasticSearchName;
|
||||
|
||||
/**
|
||||
* The internal name of the index. May not be the same as the name used in ElasticSearch,
|
||||
* especially if aliases are enabled.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
|
||||
/**
|
||||
* An array of settings sent to ElasticSearch when creating the index.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $settings;
|
||||
|
||||
/**
|
||||
* All types that belong to this index.
|
||||
*
|
||||
* @var TypeConfig[]
|
||||
*/
|
||||
private $types;
|
||||
|
||||
/**
|
||||
* Indicates if the index should use an alias, allowing an index repopulation to occur
|
||||
* without overwriting the current index.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $useAlias = false;
|
||||
|
||||
/**
|
||||
* Constructor expects an array as generated by the Container Configuration builder.
|
||||
*
|
||||
* @param string $name
|
||||
* @param TypeConfig[] $types
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct($name, array $types, array $config)
|
||||
{
|
||||
$this->elasticSearchName = isset($config['elasticSearchName']) ? $config['elasticSearchName'] : $name;
|
||||
$this->name = $name;
|
||||
$this->settings = isset($config['settings']) ? $config['settings'] : array();
|
||||
$this->types = $types;
|
||||
$this->useAlias = isset($config['useAlias']) ? $config['useAlias'] : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getElasticSearchName()
|
||||
{
|
||||
return $this->elasticSearchName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getSettings()
|
||||
{
|
||||
return $this->settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $typeName
|
||||
*
|
||||
* @return TypeConfig
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function getType($typeName)
|
||||
{
|
||||
if (!array_key_exists($typeName, $this->types)) {
|
||||
throw new \InvalidArgumentException(sprintf('Type "%s" does not exist on index "%s"', $typeName, $this->name));
|
||||
}
|
||||
|
||||
return $this->types[$typeName];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \FOS\ElasticaBundle\Configuration\TypeConfig[]
|
||||
*/
|
||||
public function getTypes()
|
||||
{
|
||||
return $this->types;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
public function isUseAlias()
|
||||
{
|
||||
return $this->useAlias;
|
||||
}
|
||||
}
|
|
@ -1,44 +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\Configuration;
|
||||
|
||||
/**
|
||||
* Central manager for index and type configuration.
|
||||
*/
|
||||
interface ManagerInterface
|
||||
{
|
||||
/**
|
||||
* Returns configuration for an index.
|
||||
*
|
||||
* @param $index
|
||||
*
|
||||
* @return IndexConfig
|
||||
*/
|
||||
public function getIndexConfiguration($index);
|
||||
|
||||
/**
|
||||
* Returns an array of known index names.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getIndexNames();
|
||||
|
||||
/**
|
||||
* Returns a type configuration.
|
||||
*
|
||||
* @param string $index
|
||||
* @param string $type
|
||||
*
|
||||
* @return TypeConfig
|
||||
*/
|
||||
public function getTypeConfiguration($index, $type);
|
||||
}
|
|
@ -1,26 +1,16 @@
|
|||
<?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\Configuration;
|
||||
|
||||
use FOS\ElasticaBundle\Annotation\Search as BaseSearch;
|
||||
|
||||
/**
|
||||
* Annotation class for setting search repository.
|
||||
*
|
||||
* @author Richard Miller <info@limethinking.co.uk>
|
||||
* @Annotation
|
||||
*
|
||||
* @deprecated Use FOS\ElasticaBundle\Annotation\Search instead
|
||||
* @Target("CLASS")
|
||||
*/
|
||||
class Search extends BaseSearch
|
||||
class Search
|
||||
{
|
||||
/** @var string */
|
||||
public $repositoryClass;
|
||||
}
|
||||
|
|
|
@ -1,80 +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\Configuration\Source;
|
||||
|
||||
use FOS\ElasticaBundle\Configuration\IndexConfig;
|
||||
use FOS\ElasticaBundle\Configuration\TypeConfig;
|
||||
|
||||
/**
|
||||
* Returns index and type configuration from the container.
|
||||
*/
|
||||
class ContainerSource implements SourceInterface
|
||||
{
|
||||
/**
|
||||
* The internal container representation of information.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $configArray;
|
||||
|
||||
public function __construct(array $configArray)
|
||||
{
|
||||
$this->configArray = $configArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should return all configuration available from the data source.
|
||||
*
|
||||
* @return IndexConfig[]
|
||||
*/
|
||||
public function getConfiguration()
|
||||
{
|
||||
$indexes = array();
|
||||
foreach ($this->configArray as $config) {
|
||||
$types = $this->getTypes($config);
|
||||
$index = new IndexConfig($config['name'], $types, array(
|
||||
'elasticSearchName' => $config['elasticsearch_name'],
|
||||
'settings' => $config['settings'],
|
||||
'useAlias' => $config['use_alias'],
|
||||
));
|
||||
|
||||
$indexes[$config['name']] = $index;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -1,26 +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\Configuration\Source;
|
||||
|
||||
/**
|
||||
* Represents a source of index and type information (ie, the Container configuration or
|
||||
* annotations).
|
||||
*/
|
||||
interface SourceInterface
|
||||
{
|
||||
/**
|
||||
* Should return all configuration available from the data source.
|
||||
*
|
||||
* @return \FOS\ElasticaBundle\Configuration\IndexConfig[]
|
||||
*/
|
||||
public function getConfiguration();
|
||||
}
|
|
@ -1,113 +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\Configuration;
|
||||
|
||||
class TypeConfig
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $config;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $mapping;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
|
||||
public function __construct($name, array $mapping, array $config = array())
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->mapping = $mapping;
|
||||
$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
|
||||
*/
|
||||
public function getIndexAnalyzer()
|
||||
{
|
||||
return $this->getConfig('index_analyzer');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getMapping()
|
||||
{
|
||||
return $this->mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getModel()
|
||||
{
|
||||
return isset($this->config['persistence']['model']) ?
|
||||
$this->config['persistence']['model'] :
|
||||
null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool|null
|
||||
*/
|
||||
public function getNumericDetection()
|
||||
{
|
||||
return $this->getConfig('numeric_detection');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getSearchAnalyzer()
|
||||
{
|
||||
return $this->getConfig('search_analyzer');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
*/
|
||||
private function getConfig($key)
|
||||
{
|
||||
return isset($this->config[$key]) ?
|
||||
$this->config[$key] :
|
||||
null;
|
||||
}
|
||||
}
|
|
@ -1,36 +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\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
class ConfigSourcePass implements CompilerPassInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
if (!$container->hasDefinition('fos_elastica.config_manager')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$sources = array();
|
||||
foreach (array_keys($container->findTaggedServiceIds('fos_elastica.config_source')) as $id) {
|
||||
$sources[] = new Reference($id);
|
||||
}
|
||||
|
||||
$container->getDefinition('fos_elastica.config_manager')->replaceArgument(0, $sources);
|
||||
}
|
||||
}
|
|
@ -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\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
class IndexPass implements CompilerPassInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
if (!$container->hasDefinition('fos_elastica.index_manager')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$indexes = array();
|
||||
foreach ($container->findTaggedServiceIds('fos_elastica.index') as $id => $tags) {
|
||||
foreach ($tags as $tag) {
|
||||
$indexes[$tag['name']] = new Reference($id);
|
||||
}
|
||||
}
|
||||
|
||||
$container->getDefinition('fos_elastica.index_manager')->replaceArgument(0, $indexes);
|
||||
}
|
||||
}
|
33
DependencyInjection/Compiler/LookupPass.php
Normal file
33
DependencyInjection/Compiler/LookupPass.php
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* Registers any lookup services into the LookupManager
|
||||
*
|
||||
* @author Tim Nagel <tim@nagel.com.au>
|
||||
*/
|
||||
class LookupPass implements CompilerPassInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
if (!$container->hasDefinition('fos_elastica.lookup_manager')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$lookups = array();
|
||||
foreach ($container->findTaggedServiceIds('fos_elastica.lookup') as $id => $tags) {
|
||||
$lookups[] = new Reference($id);
|
||||
}
|
||||
|
||||
$managerDefinition = $container->getDefinition('fos_elastica.lookup_manager');
|
||||
$managerDefinition->setArguments(0, $lookups);
|
||||
}
|
||||
}
|
|
@ -55,7 +55,6 @@ class RegisterProvidersPass implements CompilerPassInterface
|
|||
* Returns whether the class implements ProviderInterface.
|
||||
*
|
||||
* @param string $class
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
private function isProviderImplementation($class)
|
||||
|
|
|
@ -31,7 +31,7 @@ class TransformerPass implements CompilerPassInterface
|
|||
throw new InvalidArgumentException('The Transformer must have both a type and an index defined.');
|
||||
}
|
||||
|
||||
$transformers[$tag['index']][$tag['type']] = new Reference($id);
|
||||
$transformers[$tag['index']][$tag['type']]= new Reference($id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,22 +15,17 @@ class Configuration implements ConfigurationInterface
|
|||
*/
|
||||
private $supportedDrivers = array('orm', 'mongodb', 'propel');
|
||||
|
||||
/**
|
||||
* If the kernel is running in debug mode.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $debug;
|
||||
private $configArray = array();
|
||||
|
||||
public function __construct($debug)
|
||||
public function __construct($configArray)
|
||||
{
|
||||
$this->debug = $debug;
|
||||
$this->configArray = $configArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the configuration tree.
|
||||
*
|
||||
* @return TreeBuilder
|
||||
* @return \Symfony\Component\Config\Definition\NodeInterface
|
||||
*/
|
||||
public function getConfigTreeBuilder()
|
||||
{
|
||||
|
@ -63,7 +58,17 @@ class Configuration implements ConfigurationInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* Adds the configuration for the "clients" key.
|
||||
* Generates the configuration tree.
|
||||
*
|
||||
* @return \Symfony\Component\DependencyInjection\Configuration\NodeInterface
|
||||
*/
|
||||
public function getConfigTree()
|
||||
{
|
||||
return $this->getConfigTreeBuilder()->buildTree();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the configuration for the "clients" key
|
||||
*/
|
||||
private function addClientsSection(ArrayNodeDefinition $rootNode)
|
||||
{
|
||||
|
@ -74,52 +79,49 @@ class Configuration implements ConfigurationInterface
|
|||
->useAttributeAsKey('id')
|
||||
->prototype('array')
|
||||
->performNoDeepMerging()
|
||||
// BC - Renaming 'servers' node to 'connections'
|
||||
->beforeNormalization()
|
||||
->ifTrue(function ($v) { return isset($v['servers']); })
|
||||
->then(function ($v) {
|
||||
$v['connections'] = $v['servers'];
|
||||
unset($v['servers']);
|
||||
|
||||
return $v;
|
||||
})
|
||||
->ifTrue(function($v) { return isset($v['host']) && isset($v['port']); })
|
||||
->then(function($v) {
|
||||
return array(
|
||||
'servers' => array(
|
||||
array(
|
||||
'host' => $v['host'],
|
||||
'port' => $v['port'],
|
||||
'logger' => isset($v['logger']) ? $v['logger'] : null,
|
||||
'headers' => isset($v['headers']) ? $v['headers'] : null,
|
||||
)
|
||||
)
|
||||
);
|
||||
})
|
||||
->end()
|
||||
// Elastica names its properties with camel case, support both
|
||||
->beforeNormalization()
|
||||
->ifTrue(function ($v) { return isset($v['connection_strategy']); })
|
||||
->then(function ($v) {
|
||||
$v['connectionStrategy'] = $v['connection_strategy'];
|
||||
unset($v['connection_strategy']);
|
||||
|
||||
return $v;
|
||||
})
|
||||
->end()
|
||||
// If there is no connections array key defined, assume a single connection.
|
||||
->beforeNormalization()
|
||||
->ifTrue(function ($v) { return is_array($v) && !array_key_exists('connections', $v); })
|
||||
->then(function ($v) {
|
||||
return array(
|
||||
'connections' => array($v),
|
||||
);
|
||||
})
|
||||
->ifTrue(function($v) { return isset($v['url']); })
|
||||
->then(function($v) {
|
||||
return array(
|
||||
'servers' => array(
|
||||
array(
|
||||
'url' => $v['url'],
|
||||
'logger' => isset($v['logger']) ? $v['logger'] : null
|
||||
)
|
||||
)
|
||||
);
|
||||
})
|
||||
->end()
|
||||
->children()
|
||||
->arrayNode('connections')
|
||||
->requiresAtLeastOneElement()
|
||||
->arrayNode('servers')
|
||||
->prototype('array')
|
||||
->fixXmlConfig('header')
|
||||
->children()
|
||||
->scalarNode('url')
|
||||
->validate()
|
||||
->ifTrue(function ($url) { return $url && substr($url, -1) !== '/'; })
|
||||
->then(function ($url) { return $url.'/'; })
|
||||
->ifTrue(function($url) { return substr($url, -1) !== '/'; })
|
||||
->then(function($url) { return $url.'/'; })
|
||||
->end()
|
||||
->end()
|
||||
->scalarNode('host')->end()
|
||||
->scalarNode('port')->end()
|
||||
->scalarNode('proxy')->end()
|
||||
->scalarNode('logger')
|
||||
->defaultValue($this->debug ? 'fos_elastica.logger' : false)
|
||||
->defaultValue('%kernel.debug%')
|
||||
->treatNullLike('fos_elastica.logger')
|
||||
->treatTrueLike('fos_elastica.logger')
|
||||
->end()
|
||||
|
@ -127,14 +129,12 @@ class Configuration implements ConfigurationInterface
|
|||
->useAttributeAsKey('name')
|
||||
->prototype('scalar')->end()
|
||||
->end()
|
||||
->scalarNode('transport')->end()
|
||||
->scalarNode('timeout')->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->scalarNode('timeout')->end()
|
||||
->scalarNode('headers')->end()
|
||||
->scalarNode('connectionStrategy')->defaultValue('Simple')->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
|
@ -143,7 +143,7 @@ class Configuration implements ConfigurationInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* Adds the configuration for the "indexes" key.
|
||||
* Adds the configuration for the "indexes" key
|
||||
*/
|
||||
private function addIndexesSection(ArrayNodeDefinition $rootNode)
|
||||
{
|
||||
|
@ -167,8 +167,61 @@ class Configuration implements ConfigurationInterface
|
|||
->children()
|
||||
->scalarNode('index_analyzer')->end()
|
||||
->scalarNode('search_analyzer')->end()
|
||||
->append($this->getPersistenceNode())
|
||||
->append($this->getSerializerNode())
|
||||
->arrayNode('persistence')
|
||||
->validate()
|
||||
->ifTrue(function($v) { return isset($v['driver']) && 'propel' === $v['driver'] && isset($v['listener']); })
|
||||
->thenInvalid('Propel doesn\'t support listeners')
|
||||
->ifTrue(function($v) { return isset($v['driver']) && 'propel' === $v['driver'] && isset($v['repository']); })
|
||||
->thenInvalid('Propel doesn\'t support the "repository" parameter')
|
||||
->end()
|
||||
->children()
|
||||
->scalarNode('driver')
|
||||
->validate()
|
||||
->ifNotInArray($this->supportedDrivers)
|
||||
->thenInvalid('The driver %s is not supported. Please choose one of '.json_encode($this->supportedDrivers))
|
||||
->end()
|
||||
->end()
|
||||
->scalarNode('identifier')->defaultValue('id')->end()
|
||||
->arrayNode('provider')
|
||||
->children()
|
||||
->scalarNode('query_builder_method')->defaultValue('createQueryBuilder')->end()
|
||||
->scalarNode('batch_size')->defaultValue(100)->end()
|
||||
->scalarNode('clear_object_manager')->defaultTrue()->end()
|
||||
->scalarNode('service')->end()
|
||||
->end()
|
||||
->end()
|
||||
->arrayNode('listener')
|
||||
->children()
|
||||
->scalarNode('insert')->defaultTrue()->end()
|
||||
->scalarNode('update')->defaultTrue()->end()
|
||||
->scalarNode('delete')->defaultTrue()->end()
|
||||
->scalarNode('persist')->defaultValue('postFlush')->end()
|
||||
->scalarNode('service')->end()
|
||||
->variableNode('is_indexable_callback')->defaultNull()->end()
|
||||
->end()
|
||||
->end()
|
||||
->arrayNode('finder')
|
||||
->children()
|
||||
->scalarNode('service')->end()
|
||||
->end()
|
||||
->end()
|
||||
->arrayNode('elastica_to_model_transformer')
|
||||
->addDefaultsIfNotSet()
|
||||
->children()
|
||||
->scalarNode('hydrate')->defaultTrue()->end()
|
||||
->scalarNode('ignore_missing')->defaultFalse()->end()
|
||||
->scalarNode('query_builder_method')->defaultValue('createQueryBuilder')->end()
|
||||
->scalarNode('service')->end()
|
||||
->end()
|
||||
->end()
|
||||
->arrayNode('model_to_elastica_transformer')
|
||||
->addDefaultsIfNotSet()
|
||||
->children()
|
||||
->scalarNode('service')->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->variableNode('settings')->defaultValue(array())->end()
|
||||
|
@ -192,75 +245,84 @@ class Configuration implements ConfigurationInterface
|
|||
->useAttributeAsKey('name')
|
||||
->prototype('array')
|
||||
->treatNullLike(array())
|
||||
->beforeNormalization()
|
||||
->ifNull()
|
||||
->thenEmptyArray()
|
||||
->end()
|
||||
// BC - Renaming 'mappings' node to 'properties'
|
||||
->beforeNormalization()
|
||||
->ifTrue(function ($v) { return array_key_exists('mappings', $v); })
|
||||
->then(function ($v) {
|
||||
$v['properties'] = $v['mappings'];
|
||||
unset($v['mappings']);
|
||||
|
||||
return $v;
|
||||
})
|
||||
->end()
|
||||
// BC - Support the old is_indexable_callback property
|
||||
->beforeNormalization()
|
||||
->ifTrue(function ($v) {
|
||||
return isset($v['persistence']) &&
|
||||
isset($v['persistence']['listener']) &&
|
||||
isset($v['persistence']['listener']['is_indexable_callback']);
|
||||
})
|
||||
->then(function ($v) {
|
||||
$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']);
|
||||
|
||||
return $v;
|
||||
})
|
||||
->end()
|
||||
// Support multiple dynamic_template formats to match the old bundle style
|
||||
// and the way ElasticSearch expects them
|
||||
->beforeNormalization()
|
||||
->ifTrue(function ($v) { return isset($v['dynamic_templates']); })
|
||||
->then(function ($v) {
|
||||
$dt = array();
|
||||
foreach ($v['dynamic_templates'] as $key => $type) {
|
||||
if (is_int($key)) {
|
||||
$dt[] = $type;
|
||||
} else {
|
||||
$dt[][$key] = $type;
|
||||
}
|
||||
}
|
||||
|
||||
$v['dynamic_templates'] = $dt;
|
||||
|
||||
return $v;
|
||||
})
|
||||
->end()
|
||||
->children()
|
||||
->booleanNode('date_detection')->end()
|
||||
->arrayNode('dynamic_date_formats')->prototype('scalar')->end()->end()
|
||||
->arrayNode('serializer')
|
||||
->addDefaultsIfNotSet()
|
||||
->children()
|
||||
->arrayNode('groups')
|
||||
->treatNullLike(array())
|
||||
->prototype('scalar')->end()
|
||||
->end()
|
||||
->scalarNode('version')->end()
|
||||
->end()
|
||||
->end()
|
||||
->scalarNode('index_analyzer')->end()
|
||||
->booleanNode('numeric_detection')->end()
|
||||
->scalarNode('search_analyzer')->end()
|
||||
->variableNode('indexable_callback')->end()
|
||||
->append($this->getPersistenceNode())
|
||||
->append($this->getSerializerNode())
|
||||
->arrayNode('persistence')
|
||||
->validate()
|
||||
->ifTrue(function($v) { return isset($v['driver']) && 'propel' === $v['driver'] && isset($v['listener']); })
|
||||
->thenInvalid('Propel doesn\'t support listeners')
|
||||
->ifTrue(function($v) { return isset($v['driver']) && 'propel' === $v['driver'] && isset($v['repository']); })
|
||||
->thenInvalid('Propel doesn\'t support the "repository" parameter')
|
||||
->end()
|
||||
->children()
|
||||
->scalarNode('driver')
|
||||
->validate()
|
||||
->ifNotInArray($this->supportedDrivers)
|
||||
->thenInvalid('The driver %s is not supported. Please choose one of '.json_encode($this->supportedDrivers))
|
||||
->end()
|
||||
->end()
|
||||
->scalarNode('model')->end()
|
||||
->scalarNode('repository')->end()
|
||||
->scalarNode('identifier')->defaultValue('id')->end()
|
||||
->arrayNode('provider')
|
||||
->children()
|
||||
->scalarNode('query_builder_method')->defaultValue('createQueryBuilder')->end()
|
||||
->scalarNode('batch_size')->defaultValue(100)->end()
|
||||
->scalarNode('clear_object_manager')->defaultTrue()->end()
|
||||
->scalarNode('service')->end()
|
||||
->end()
|
||||
->end()
|
||||
->arrayNode('listener')
|
||||
->children()
|
||||
->scalarNode('insert')->defaultTrue()->end()
|
||||
->scalarNode('update')->defaultTrue()->end()
|
||||
->scalarNode('delete')->defaultTrue()->end()
|
||||
->booleanNode('immediate')->defaultFalse()->end()
|
||||
->scalarNode('logger')
|
||||
->defaultFalse()
|
||||
->treatNullLike('fos_elastica.logger')
|
||||
->treatTrueLike('fos_elastica.logger')
|
||||
->end()
|
||||
->scalarNode('service')->end()
|
||||
->variableNode('is_indexable_callback')->defaultNull()->end()
|
||||
->end()
|
||||
->end()
|
||||
->arrayNode('finder')
|
||||
->children()
|
||||
->scalarNode('service')->end()
|
||||
->end()
|
||||
->end()
|
||||
->arrayNode('elastica_to_model_transformer')
|
||||
->addDefaultsIfNotSet()
|
||||
->children()
|
||||
->scalarNode('hydrate')->defaultTrue()->end()
|
||||
->scalarNode('ignore_missing')->defaultFalse()->end()
|
||||
->scalarNode('query_builder_method')->defaultValue('createQueryBuilder')->end()
|
||||
->scalarNode('service')->end()
|
||||
->end()
|
||||
->end()
|
||||
->arrayNode('model_to_elastica_transformer')
|
||||
->addDefaultsIfNotSet()
|
||||
->children()
|
||||
->scalarNode('service')->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->append($this->getIdNode())
|
||||
->append($this->getPropertiesNode())
|
||||
->append($this->getMappingsNode())
|
||||
->append($this->getDynamicTemplateNode())
|
||||
->append($this->getSourceNode())
|
||||
->append($this->getBoostNode())
|
||||
|
@ -276,17 +338,27 @@ class Configuration implements ConfigurationInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the array node used for "properties".
|
||||
* Returns the array node used for "mappings".
|
||||
*/
|
||||
protected function getPropertiesNode()
|
||||
protected function getMappingsNode()
|
||||
{
|
||||
$builder = new TreeBuilder();
|
||||
$node = $builder->root('properties');
|
||||
$node = $builder->root('mappings');
|
||||
|
||||
$node
|
||||
$nestings = $this->getNestings();
|
||||
|
||||
$childrenNode = $node
|
||||
->useAttributeAsKey('name')
|
||||
->prototype('variable')
|
||||
->treatNullLike(array());
|
||||
->prototype('array')
|
||||
->validate()
|
||||
->ifTrue(function($v) { return isset($v['fields']) && empty($v['fields']); })
|
||||
->then(function($v) { unset($v['fields']); return $v; })
|
||||
->end()
|
||||
->treatNullLike(array())
|
||||
->addDefaultsIfNotSet()
|
||||
->children();
|
||||
|
||||
$this->addFieldConfig($childrenNode, $nestings);
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
@ -300,21 +372,16 @@ class Configuration implements ConfigurationInterface
|
|||
$node = $builder->root('dynamic_templates');
|
||||
|
||||
$node
|
||||
->useAttributeAsKey('name')
|
||||
->prototype('array')
|
||||
->prototype('array')
|
||||
->children()
|
||||
->scalarNode('match')->end()
|
||||
->scalarNode('unmatch')->end()
|
||||
->scalarNode('match_mapping_type')->end()
|
||||
->scalarNode('path_match')->end()
|
||||
->scalarNode('path_unmatch')->end()
|
||||
->scalarNode('match_pattern')->end()
|
||||
->arrayNode('mapping')
|
||||
->prototype('variable')
|
||||
->treatNullLike(array())
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->children()
|
||||
->scalarNode('match')->end()
|
||||
->scalarNode('unmatch')->end()
|
||||
->scalarNode('match_mapping_type')->end()
|
||||
->scalarNode('path_match')->end()
|
||||
->scalarNode('path_unmatch')->end()
|
||||
->scalarNode('match_pattern')->end()
|
||||
->append($this->getDynamicTemplateMapping())
|
||||
->end()
|
||||
->end()
|
||||
;
|
||||
|
@ -322,6 +389,194 @@ class Configuration implements ConfigurationInterface
|
|||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the array node used for mapping in dynamic templates
|
||||
*/
|
||||
protected function getDynamicTemplateMapping()
|
||||
{
|
||||
$builder = new TreeBuilder();
|
||||
$node = $builder->root('mapping');
|
||||
|
||||
$nestings = $this->getNestingsForDynamicTemplates();
|
||||
|
||||
$this->addFieldConfig($node->children(), $nestings);
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Symfony\Component\Config\Definition\Builder\NodeBuilder $node The node to which to attach the field config to
|
||||
* @param array $nestings the nested mappings for the current field level
|
||||
*/
|
||||
protected function addFieldConfig($node, $nestings)
|
||||
{
|
||||
$node
|
||||
->scalarNode('type')->defaultValue('string')->end()
|
||||
->scalarNode('boost')->end()
|
||||
->scalarNode('store')->end()
|
||||
->scalarNode('index')->end()
|
||||
->scalarNode('index_analyzer')->end()
|
||||
->scalarNode('search_analyzer')->end()
|
||||
->scalarNode('analyzer')->end()
|
||||
->scalarNode('term_vector')->end()
|
||||
->scalarNode('null_value')->end()
|
||||
->booleanNode('include_in_all')->defaultValue(true)->end()
|
||||
->booleanNode('enabled')->defaultValue(true)->end()
|
||||
->scalarNode('lat_lon')->end()
|
||||
->scalarNode('index_name')->end()
|
||||
->booleanNode('omit_norms')->end()
|
||||
->scalarNode('index_options')->end()
|
||||
->scalarNode('ignore_above')->end()
|
||||
->scalarNode('position_offset_gap')->end()
|
||||
->arrayNode('_parent')
|
||||
->treatNullLike(array())
|
||||
->children()
|
||||
->scalarNode('type')->end()
|
||||
->scalarNode('identifier')->defaultValue('id')->end()
|
||||
->end()
|
||||
->end()
|
||||
->scalarNode('format')->end()
|
||||
->scalarNode('similarity')->end();
|
||||
;
|
||||
|
||||
if (isset($nestings['fields'])) {
|
||||
$this->addNestedFieldConfig($node, $nestings, 'fields');
|
||||
}
|
||||
|
||||
if (isset($nestings['properties'])) {
|
||||
$node
|
||||
->booleanNode('include_in_parent')->end()
|
||||
->booleanNode('include_in_root')->end()
|
||||
;
|
||||
$this->addNestedFieldConfig($node, $nestings, 'properties');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Symfony\Component\Config\Definition\Builder\NodeBuilder $node The node to which to attach the nested config to
|
||||
* @param array $nestings The nestings for the current field level
|
||||
* @param string $property the name of the nested property ('fields' or 'properties')
|
||||
*/
|
||||
protected function addNestedFieldConfig($node, $nestings, $property)
|
||||
{
|
||||
$childrenNode = $node
|
||||
->arrayNode($property)
|
||||
->useAttributeAsKey('name')
|
||||
->prototype('array')
|
||||
->validate()
|
||||
->ifTrue(function($v) { return isset($v['fields']) && empty($v['fields']); })
|
||||
->then(function($v) { unset($v['fields']); return $v; })
|
||||
->end()
|
||||
->treatNullLike(array())
|
||||
->addDefaultsIfNotSet()
|
||||
->children();
|
||||
|
||||
$this->addFieldConfig($childrenNode, $nestings[$property]);
|
||||
|
||||
$childrenNode
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array The unique nested mappings for all types
|
||||
*/
|
||||
protected function getNestings()
|
||||
{
|
||||
if (!isset($this->configArray[0]['indexes'])) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$nestings = array();
|
||||
foreach ($this->configArray[0]['indexes'] as $index) {
|
||||
if (empty($index['types'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($index['types'] as $type) {
|
||||
if (empty($type['mappings'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$nestings = array_merge_recursive($nestings, $this->getNestingsForType($type['mappings'], $nestings));
|
||||
}
|
||||
}
|
||||
return $nestings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array The unique nested mappings for all dynamic templates
|
||||
*/
|
||||
protected function getNestingsForDynamicTemplates()
|
||||
{
|
||||
if (!isset($this->configArray[0]['indexes'])) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$nestings = array();
|
||||
foreach ($this->configArray[0]['indexes'] as $index) {
|
||||
if (empty($index['types'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($index['types'] as $type) {
|
||||
if (empty($type['dynamic_templates'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($type['dynamic_templates'] as $definition) {
|
||||
$field = $definition['mapping'];
|
||||
|
||||
if (isset($field['fields'])) {
|
||||
$this->addPropertyNesting($field, $nestings, 'fields');
|
||||
} else if (isset($field['properties'])) {
|
||||
$this->addPropertyNesting($field, $nestings, 'properties');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return $nestings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $mappings The mappings for the current type
|
||||
* @return array The nested mappings defined for this type
|
||||
*/
|
||||
protected function getNestingsForType(array $mappings = null)
|
||||
{
|
||||
if ($mappings === null) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$nestings = array();
|
||||
|
||||
foreach ($mappings as $field) {
|
||||
if (isset($field['fields'])) {
|
||||
$this->addPropertyNesting($field, $nestings, 'fields');
|
||||
} else if (isset($field['properties'])) {
|
||||
$this->addPropertyNesting($field, $nestings, 'properties');
|
||||
}
|
||||
}
|
||||
|
||||
return $nestings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $field The field mapping definition
|
||||
* @param array $nestings The nestings array
|
||||
* @param string $property The nested property name ('fields' or 'properties')
|
||||
*/
|
||||
protected function addPropertyNesting($field, &$nestings, $property)
|
||||
{
|
||||
if (!isset($nestings[$property])) {
|
||||
$nestings[$property] = array();
|
||||
}
|
||||
$nestings[$property] = array_merge_recursive($nestings[$property], $this->getNestingsForType($field[$property]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the array node used for "_id".
|
||||
*/
|
||||
|
@ -359,7 +614,7 @@ class Configuration implements ConfigurationInterface
|
|||
->end()
|
||||
->scalarNode('compress')->end()
|
||||
->scalarNode('compress_threshold')->end()
|
||||
->scalarNode('enabled')->defaultTrue()->end()
|
||||
->scalarNode('enabled')->end()
|
||||
->end()
|
||||
;
|
||||
|
||||
|
@ -422,7 +677,7 @@ class Configuration implements ConfigurationInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the array node used for "_all".
|
||||
* Returns the array node used for "_all"
|
||||
*/
|
||||
protected function getAllNode()
|
||||
{
|
||||
|
@ -432,8 +687,6 @@ class Configuration implements ConfigurationInterface
|
|||
$node
|
||||
->children()
|
||||
->scalarNode('enabled')->defaultValue(true)->end()
|
||||
->scalarNode('index_analyzer')->end()
|
||||
->scalarNode('search_analyzer')->end()
|
||||
->end()
|
||||
;
|
||||
|
||||
|
@ -441,7 +694,7 @@ class Configuration implements ConfigurationInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the array node used for "_timestamp".
|
||||
* Returns the array node used for "_timestamp"
|
||||
*/
|
||||
protected function getTimestampNode()
|
||||
{
|
||||
|
@ -462,7 +715,7 @@ class Configuration implements ConfigurationInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the array node used for "_ttl".
|
||||
* Returns the array node used for "_ttl"
|
||||
*/
|
||||
protected function getTtlNode()
|
||||
{
|
||||
|
@ -480,102 +733,4 @@ class Configuration implements ConfigurationInterface
|
|||
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ArrayNodeDefinition|\Symfony\Component\Config\Definition\Builder\NodeDefinition
|
||||
*/
|
||||
protected function getPersistenceNode()
|
||||
{
|
||||
$builder = new TreeBuilder();
|
||||
$node = $builder->root('persistence');
|
||||
|
||||
$node
|
||||
->validate()
|
||||
->ifTrue(function ($v) { return isset($v['driver']) && 'propel' === $v['driver'] && isset($v['listener']); })
|
||||
->thenInvalid('Propel doesn\'t support listeners')
|
||||
->ifTrue(function ($v) { return isset($v['driver']) && 'propel' === $v['driver'] && isset($v['repository']); })
|
||||
->thenInvalid('Propel doesn\'t support the "repository" parameter')
|
||||
->end()
|
||||
->children()
|
||||
->scalarNode('driver')
|
||||
->validate()
|
||||
->ifNotInArray($this->supportedDrivers)
|
||||
->thenInvalid('The driver %s is not supported. Please choose one of '.json_encode($this->supportedDrivers))
|
||||
->end()
|
||||
->end()
|
||||
->scalarNode('model')->end()
|
||||
->scalarNode('repository')->end()
|
||||
->scalarNode('identifier')->defaultValue('id')->end()
|
||||
->arrayNode('provider')
|
||||
->children()
|
||||
->scalarNode('batch_size')->defaultValue(100)->end()
|
||||
->scalarNode('clear_object_manager')->defaultTrue()->end()
|
||||
->scalarNode('debug_logging')
|
||||
->defaultValue($this->debug)
|
||||
->treatNullLike(true)
|
||||
->end()
|
||||
->scalarNode('query_builder_method')->defaultValue('createQueryBuilder')->end()
|
||||
->scalarNode('service')->end()
|
||||
->end()
|
||||
->end()
|
||||
->arrayNode('listener')
|
||||
->children()
|
||||
->scalarNode('insert')->defaultTrue()->end()
|
||||
->scalarNode('update')->defaultTrue()->end()
|
||||
->scalarNode('delete')->defaultTrue()->end()
|
||||
->scalarNode('flush')->defaultTrue()->end()
|
||||
->booleanNode('immediate')->defaultFalse()->end()
|
||||
->scalarNode('logger')
|
||||
->defaultFalse()
|
||||
->treatNullLike('fos_elastica.logger')
|
||||
->treatTrueLike('fos_elastica.logger')
|
||||
->end()
|
||||
->scalarNode('service')->end()
|
||||
->end()
|
||||
->end()
|
||||
->arrayNode('finder')
|
||||
->children()
|
||||
->scalarNode('service')->end()
|
||||
->end()
|
||||
->end()
|
||||
->arrayNode('elastica_to_model_transformer')
|
||||
->addDefaultsIfNotSet()
|
||||
->children()
|
||||
->scalarNode('hydrate')->defaultTrue()->end()
|
||||
->scalarNode('ignore_missing')->defaultFalse()->end()
|
||||
->scalarNode('query_builder_method')->defaultValue('createQueryBuilder')->end()
|
||||
->scalarNode('service')->end()
|
||||
->end()
|
||||
->end()
|
||||
->arrayNode('model_to_elastica_transformer')
|
||||
->addDefaultsIfNotSet()
|
||||
->children()
|
||||
->scalarNode('service')->end()
|
||||
->end()
|
||||
->end()
|
||||
->end();
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ArrayNodeDefinition|\Symfony\Component\Config\Definition\Builder\NodeDefinition
|
||||
*/
|
||||
protected function getSerializerNode()
|
||||
{
|
||||
$builder = new TreeBuilder();
|
||||
$node = $builder->root('serializer');
|
||||
|
||||
$node
|
||||
->addDefaultsIfNotSet()
|
||||
->children()
|
||||
->arrayNode('groups')
|
||||
->treatNullLike(array())
|
||||
->prototype('scalar')->end()
|
||||
->end()
|
||||
->scalarNode('version')->end()
|
||||
->end();
|
||||
|
||||
return $node;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ namespace FOS\ElasticaBundle\DependencyInjection;
|
|||
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
||||
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\DefinitionDecorator;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
|
@ -13,32 +14,20 @@ use InvalidArgumentException;
|
|||
class FOSElasticaExtension extends Extension
|
||||
{
|
||||
/**
|
||||
* Definition of elastica clients as configured by this extension.
|
||||
* Stores references to all defined clients loaded by the extension.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $clients = array();
|
||||
|
||||
/**
|
||||
* An array of indexes as configured by the extension.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $indexConfigs = array();
|
||||
|
||||
/**
|
||||
* If we've encountered a type mapped to a specific persistence driver, it will be loaded
|
||||
* here.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $loadedDrivers = array();
|
||||
protected $indexConfigs = array();
|
||||
protected $typeFields = array();
|
||||
protected $loadedDrivers = array();
|
||||
protected $serializerConfig = array();
|
||||
|
||||
public function load(array $configs, ContainerBuilder $container)
|
||||
{
|
||||
$configuration = $this->getConfiguration($configs, $container);
|
||||
$config = $this->processConfiguration($configuration, $configs);
|
||||
|
||||
$config = $this->processConfiguration(new Configuration($configs, $container), $configs);
|
||||
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
|
||||
|
||||
if (empty($config['clients']) || empty($config['indexes'])) {
|
||||
|
@ -46,9 +35,7 @@ class FOSElasticaExtension extends Extension
|
|||
return;
|
||||
}
|
||||
|
||||
foreach (array('config', 'index', 'persister', 'provider', 'source', 'transformer') as $basename) {
|
||||
$loader->load(sprintf('%s.xml', $basename));
|
||||
}
|
||||
$loader->load('config.xml');
|
||||
|
||||
if (empty($config['default_client'])) {
|
||||
$keys = array_keys($config['clients']);
|
||||
|
@ -60,45 +47,29 @@ class FOSElasticaExtension extends Extension
|
|||
$config['default_index'] = reset($keys);
|
||||
}
|
||||
|
||||
if (isset($config['serializer'])) {
|
||||
$loader->load('serializer.xml');
|
||||
|
||||
$this->loadSerializer($config['serializer'], $container);
|
||||
}
|
||||
|
||||
$this->loadClients($config['clients'], $container);
|
||||
$container->setAlias('fos_elastica.client', sprintf('fos_elastica.client.%s', $config['default_client']));
|
||||
|
||||
// XX serializer can be done better....
|
||||
// $this->serializerConfig = isset($config['serializer']) ? $config['serializer'] : null;
|
||||
|
||||
$this->loadIndexes($config['indexes'], $container);
|
||||
$container->setAlias('fos_elastica.index', sprintf('fos_elastica.index.%s', $config['default_index']));
|
||||
|
||||
$container->getDefinition('fos_elastica.config_source.container')->replaceArgument(0, $this->indexConfigs);
|
||||
|
||||
$this->loadIndexManager($container);
|
||||
$this->loadResetter($container);
|
||||
|
||||
$this->createDefaultManagerAlias($config['default_manager'], $container);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $config
|
||||
* @param ContainerBuilder $container
|
||||
*
|
||||
* @return Configuration
|
||||
*/
|
||||
public function getConfiguration(array $config, ContainerBuilder $container)
|
||||
{
|
||||
return new Configuration($container->getParameter('kernel.debug'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the configured clients.
|
||||
*
|
||||
* @param array $clients An array of clients configurations
|
||||
* @param array $clients An array of clients configurations
|
||||
* @param ContainerBuilder $container A ContainerBuilder instance
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function loadClients(array $clients, ContainerBuilder $container)
|
||||
protected function loadClients(array $clients, ContainerBuilder $container)
|
||||
{
|
||||
foreach ($clients as $name => $clientConfig) {
|
||||
$clientId = sprintf('fos_elastica.client.%s', $name);
|
||||
|
@ -106,17 +77,16 @@ class FOSElasticaExtension extends Extension
|
|||
$clientDef = new DefinitionDecorator('fos_elastica.client_prototype');
|
||||
$clientDef->replaceArgument(0, $clientConfig);
|
||||
|
||||
$logger = $clientConfig['connections'][0]['logger'];
|
||||
$logger = $clientConfig['servers'][0]['logger'];
|
||||
if (false !== $logger) {
|
||||
$clientDef->addMethodCall('setLogger', array(new Reference($logger)));
|
||||
}
|
||||
$clientDef->addTag('fos_elastica.client');
|
||||
|
||||
$container->setDefinition($clientId, $clientDef);
|
||||
|
||||
$this->clients[$name] = array(
|
||||
'id' => $clientId,
|
||||
'reference' => new Reference($clientId),
|
||||
'reference' => new Reference($clientId)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -124,65 +94,66 @@ class FOSElasticaExtension extends Extension
|
|||
/**
|
||||
* Loads the configured indexes.
|
||||
*
|
||||
* @param array $indexes An array of indexes configurations
|
||||
* @param array $indexes An array of indexes configurations
|
||||
* @param ContainerBuilder $container A ContainerBuilder instance
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function loadIndexes(array $indexes, ContainerBuilder $container)
|
||||
protected function loadIndexes(array $indexes, ContainerBuilder $container)
|
||||
{
|
||||
$indexableCallbacks = array();
|
||||
$indexIds = array();
|
||||
|
||||
foreach ($indexes as $name => $index) {
|
||||
$indexId = sprintf('fos_elastica.index.%s', $name);
|
||||
$indexName = isset($index['index_name']) ? $index['index_name'] : $name;
|
||||
$indexName = $index['index_name'] ?: $name;
|
||||
|
||||
$indexDef = new DefinitionDecorator('fos_elastica.index_prototype');
|
||||
$indexDef->replaceArgument(0, $indexName);
|
||||
$indexDef->addTag('fos_elastica.index', array(
|
||||
'name' => $name,
|
||||
));
|
||||
|
||||
if (isset($index['client'])) {
|
||||
if ($index['client']) {
|
||||
$client = $this->getClient($index['client']);
|
||||
$indexDef->setFactoryService($client);
|
||||
}
|
||||
|
||||
$container->setDefinition($indexId, $indexDef);
|
||||
$reference = new Reference($indexId);
|
||||
|
||||
$typePrototypeConfig = isset($index['type_prototype']) ? $index['type_prototype'] : array();
|
||||
|
||||
$this->indexConfigs[$name] = array(
|
||||
'elasticsearch_name' => $indexName,
|
||||
'reference' => $reference,
|
||||
'name' => $name,
|
||||
'settings' => $index['settings'],
|
||||
'type_prototype' => isset($index['type_prototype']) ? $index['type_prototype'] : array(),
|
||||
'use_alias' => $index['use_alias'],
|
||||
'index' => new Reference($indexId),
|
||||
'name_or_alias' => $indexName,
|
||||
'config' => array(
|
||||
'mappings' => array()
|
||||
)
|
||||
);
|
||||
|
||||
if ($index['finder']) {
|
||||
$this->loadIndexFinder($container, $name, $reference);
|
||||
// XX Deprecated
|
||||
$this->loadIndexFinder($container, $name, $indexId);
|
||||
}
|
||||
if (!empty($index['settings'])) {
|
||||
// XX What is this for?
|
||||
$this->indexConfigs[$name]['config']['settings'] = $index['settings'];
|
||||
}
|
||||
if ($index['use_alias']) {
|
||||
$this->indexConfigs[$name]['use_alias'] = true;
|
||||
}
|
||||
|
||||
$this->loadTypes((array) $index['types'], $container, $this->indexConfigs[$name], $indexableCallbacks);
|
||||
$this->loadTypes(isset($index['types']) ? $index['types'] : array(), $container, $name, $indexId, $typePrototypeConfig);
|
||||
}
|
||||
|
||||
$indexable = $container->getDefinition('fos_elastica.indexable');
|
||||
$indexable->replaceArgument(0, $indexableCallbacks);
|
||||
return $indexIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the configured index finders.
|
||||
*
|
||||
* @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
|
||||
* @param string $name The index name
|
||||
* @param Reference $index Reference to the related index
|
||||
*
|
||||
* @param string $name The index name
|
||||
* @param string $indexId The index service identifier
|
||||
* @return string
|
||||
*/
|
||||
private function loadIndexFinder(ContainerBuilder $container, $name, Reference $index)
|
||||
protected function loadIndexFinder(ContainerBuilder $container, $name, $indexId)
|
||||
{
|
||||
/* Note: transformer services may conflict with "collection.index", if
|
||||
* an index and type names were "collection" and an index, respectively.
|
||||
|
@ -193,141 +164,166 @@ class FOSElasticaExtension extends Extension
|
|||
|
||||
$finderId = sprintf('fos_elastica.finder.%s', $name);
|
||||
$finderDef = new DefinitionDecorator('fos_elastica.finder');
|
||||
$finderDef->replaceArgument(0, $index);
|
||||
$finderDef->replaceArgument(0, new Reference($indexId));
|
||||
$finderDef->replaceArgument(1, new Reference($transformerId));
|
||||
|
||||
$container->setDefinition($finderId, $finderDef);
|
||||
|
||||
return $finderId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the configured types.
|
||||
*
|
||||
* @param array $types
|
||||
* @param ContainerBuilder $container
|
||||
* @param array $indexConfig
|
||||
* @param array $indexableCallbacks
|
||||
* @param array $types An array of types configurations
|
||||
* @param ContainerBuilder $container A ContainerBuilder instance
|
||||
* @param $indexName
|
||||
* @param $indexId
|
||||
* @param array $typePrototypeConfig
|
||||
* @param $serializerConfig
|
||||
*/
|
||||
private function loadTypes(array $types, ContainerBuilder $container, array $indexConfig, array &$indexableCallbacks)
|
||||
protected function loadTypes(array $types, ContainerBuilder $container, $indexName, $indexId, array $typePrototypeConfig)
|
||||
{
|
||||
foreach ($types as $name => $type) {
|
||||
$indexName = $indexConfig['name'];
|
||||
|
||||
$typeId = sprintf('%s.%s', $indexConfig['reference'], $name);
|
||||
$typeDef = new DefinitionDecorator('fos_elastica.type_prototype');
|
||||
$typeDef->replaceArgument(0, $name);
|
||||
$typeDef->setFactoryService($indexConfig['reference']);
|
||||
$container->setDefinition($typeId, $typeDef);
|
||||
|
||||
$typeConfig = array(
|
||||
'name' => $name,
|
||||
'mapping' => array(), // An array containing anything that gets sent directly to ElasticSearch
|
||||
'config' => array(),
|
||||
);
|
||||
|
||||
foreach (array(
|
||||
'dynamic_templates',
|
||||
'properties',
|
||||
'_all',
|
||||
'_boost',
|
||||
'_id',
|
||||
'_parent',
|
||||
'_routing',
|
||||
'_source',
|
||||
'_timestamp',
|
||||
'_ttl',
|
||||
) as $field) {
|
||||
if (isset($type[$field])) {
|
||||
$typeConfig['mapping'][$field] = $type[$field];
|
||||
}
|
||||
}
|
||||
|
||||
foreach (array(
|
||||
'persistence',
|
||||
'serializer',
|
||||
'index_analyzer',
|
||||
'search_analyzer',
|
||||
'date_detection',
|
||||
'dynamic_date_formats',
|
||||
'numeric_detection',
|
||||
) as $field) {
|
||||
$typeConfig['config'][$field] = array_key_exists($field, $type) ?
|
||||
$type[$field] :
|
||||
null;
|
||||
}
|
||||
|
||||
$this->indexConfigs[$indexName]['types'][$name] = $typeConfig;
|
||||
|
||||
if (isset($type['persistence'])) {
|
||||
$this->loadTypePersistenceIntegration($type['persistence'], $container, new Reference($typeId), $indexName, $name);
|
||||
|
||||
$typeConfig['persistence'] = $type['persistence'];
|
||||
}
|
||||
|
||||
if (isset($type['indexable_callback'])) {
|
||||
$indexableCallbacks[sprintf('%s/%s', $indexName, $name)] = $type['indexable_callback'];
|
||||
}
|
||||
|
||||
if ($container->hasDefinition('fos_elastica.serializer_callback_prototype')) {
|
||||
$typeSerializerId = sprintf('%s.serializer.callback', $typeId);
|
||||
$typeSerializerDef = new DefinitionDecorator('fos_elastica.serializer_callback_prototype');
|
||||
$type = self::deepArrayUnion($typePrototypeConfig, $type);
|
||||
$typeId = sprintf('%s.%s', $indexId, $name);
|
||||
$typeDefArgs = array($name);
|
||||
$typeDef = new Definition('%fos_elastica.type.class%', $typeDefArgs);
|
||||
$typeDef->setFactoryService($indexId);
|
||||
$typeDef->setFactoryMethod('getType');
|
||||
if ($this->serializerConfig) {
|
||||
$callbackDef = new Definition($this->serializerConfig['callback_class']);
|
||||
$callbackId = sprintf('%s.%s.serializer.callback', $indexId, $name);
|
||||
|
||||
$typeDef->addMethodCall('setSerializer', array(array(new Reference($callbackId), 'serialize')));
|
||||
$callbackDef->addMethodCall('setSerializer', array(new Reference($this->serializerConfig['serializer'])));
|
||||
if (isset($type['serializer']['groups'])) {
|
||||
$typeSerializerDef->addMethodCall('setGroups', array($type['serializer']['groups']));
|
||||
$callbackDef->addMethodCall('setGroups', array($type['serializer']['groups']));
|
||||
}
|
||||
if (isset($type['serializer']['version'])) {
|
||||
$typeSerializerDef->addMethodCall('setVersion', array($type['serializer']['version']));
|
||||
$callbackDef->addMethodCall('setVersion', array($type['serializer']['version']));
|
||||
}
|
||||
$callbackClassImplementedInterfaces = class_implements($this->serializerConfig['callback_class']); // PHP < 5.4 friendly
|
||||
if (isset($callbackClassImplementedInterfaces['Symfony\Component\DependencyInjection\ContainerAwareInterface'])) {
|
||||
$callbackDef->addMethodCall('setContainer', array(new Reference('service_container')));
|
||||
}
|
||||
|
||||
$typeDef->addMethodCall('setSerializer', array(array(new Reference($typeSerializerId), 'serialize')));
|
||||
$container->setDefinition($typeSerializerId, $typeSerializerDef);
|
||||
$container->setDefinition($callbackId, $callbackDef);
|
||||
|
||||
$typeDef->addMethodCall('setSerializer', array(array(new Reference($callbackId), 'serialize')));
|
||||
}
|
||||
$container->setDefinition($typeId, $typeDef);
|
||||
|
||||
$this->indexConfigs[$indexName]['config']['mappings'][$name] = array(
|
||||
"_source" => array("enabled" => true), // Add a default setting for empty mapping settings
|
||||
);
|
||||
|
||||
if (isset($type['_id'])) {
|
||||
$this->indexConfigs[$indexName]['config']['mappings'][$name]['_id'] = $type['_id'];
|
||||
}
|
||||
if (isset($type['_source'])) {
|
||||
$this->indexConfigs[$indexName]['config']['mappings'][$name]['_source'] = $type['_source'];
|
||||
}
|
||||
if (isset($type['_boost'])) {
|
||||
$this->indexConfigs[$indexName]['config']['mappings'][$name]['_boost'] = $type['_boost'];
|
||||
}
|
||||
if (isset($type['_routing'])) {
|
||||
$this->indexConfigs[$indexName]['config']['mappings'][$name]['_routing'] = $type['_routing'];
|
||||
}
|
||||
if (isset($type['mappings']) && !empty($type['mappings'])) {
|
||||
$this->indexConfigs[$indexName]['config']['mappings'][$name]['properties'] = $type['mappings'];
|
||||
$typeName = sprintf('%s/%s', $indexName, $name);
|
||||
$this->typeFields[$typeName] = $type['mappings'];
|
||||
}
|
||||
if (isset($type['_parent'])) {
|
||||
$this->indexConfigs[$indexName]['config']['mappings'][$name]['_parent'] = array('type' => $type['_parent']['type']);
|
||||
$typeName = sprintf('%s/%s', $indexName, $name);
|
||||
$this->typeFields[$typeName]['_parent'] = $type['_parent'];
|
||||
}
|
||||
if (isset($type['persistence'])) {
|
||||
$this->loadTypePersistenceIntegration($type['persistence'], $container, $typeDef, $indexName, $name);
|
||||
}
|
||||
if (isset($type['index_analyzer'])) {
|
||||
$this->indexConfigs[$indexName]['config']['mappings'][$name]['index_analyzer'] = $type['index_analyzer'];
|
||||
}
|
||||
if (isset($type['search_analyzer'])) {
|
||||
$this->indexConfigs[$indexName]['config']['mappings'][$name]['search_analyzer'] = $type['search_analyzer'];
|
||||
}
|
||||
if (isset($type['index'])) {
|
||||
$this->indexConfigs[$indexName]['config']['mappings'][$name]['index'] = $type['index'];
|
||||
}
|
||||
if (isset($type['_all'])) {
|
||||
$this->indexConfigs[$indexName]['config']['mappings'][$name]['_all'] = $type['_all'];
|
||||
}
|
||||
if (isset($type['_timestamp'])) {
|
||||
$this->indexConfigs[$indexName]['config']['mappings'][$name]['_timestamp'] = $type['_timestamp'];
|
||||
}
|
||||
if (isset($type['_ttl'])) {
|
||||
$this->indexConfigs[$indexName]['config']['mappings'][$name]['_ttl'] = $type['_ttl'];
|
||||
}
|
||||
if (!empty($type['dynamic_templates'])) {
|
||||
$this->indexConfigs[$indexName]['config']['mappings'][$name]['dynamic_templates'] = array();
|
||||
foreach ($type['dynamic_templates'] as $templateName => $templateData) {
|
||||
$this->indexConfigs[$indexName]['config']['mappings'][$name]['dynamic_templates'][] = array($templateName => $templateData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the optional provider and finder for a type.
|
||||
* Merges two arrays without reindexing numeric keys.
|
||||
*
|
||||
* @param array $typeConfig
|
||||
* @param ContainerBuilder $container
|
||||
* @param Reference $typeRef
|
||||
* @param string $indexName
|
||||
* @param string $typeName
|
||||
* @param array $array1 An array to merge
|
||||
* @param array $array2 An array to merge
|
||||
*
|
||||
* @return array The merged array
|
||||
*/
|
||||
private function loadTypePersistenceIntegration(array $typeConfig, ContainerBuilder $container, Reference $typeRef, $indexName, $typeName)
|
||||
static protected function deepArrayUnion($array1, $array2)
|
||||
{
|
||||
foreach ($array2 as $key => $value) {
|
||||
if (is_array($value) && isset($array1[$key]) && is_array($array1[$key])) {
|
||||
$array1[$key] = self::deepArrayUnion($array1[$key], $value);
|
||||
} else {
|
||||
$array1[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $array1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the optional provider and finder for a type
|
||||
*
|
||||
* @param array $typeConfig
|
||||
* @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
|
||||
* @param \Symfony\Component\DependencyInjection\Definition $typeDef
|
||||
* @param $indexName
|
||||
* @param $typeName
|
||||
*/
|
||||
protected function loadTypePersistenceIntegration(array $typeConfig, ContainerBuilder $container, Definition $typeDef, $indexName, $typeName)
|
||||
{
|
||||
$this->loadDriver($container, $typeConfig['driver']);
|
||||
|
||||
$elasticaToModelTransformerId = $this->loadElasticaToModelTransformer($typeConfig, $container, $indexName, $typeName);
|
||||
$modelToElasticaTransformerId = $this->loadModelToElasticaTransformer($typeConfig, $container, $indexName, $typeName);
|
||||
$objectPersisterId = $this->loadObjectPersister($typeConfig, $typeRef, $container, $indexName, $typeName, $modelToElasticaTransformerId);
|
||||
$objectPersisterId = $this->loadObjectPersister($typeConfig, $typeDef, $container, $indexName, $typeName, $modelToElasticaTransformerId);
|
||||
|
||||
if (isset($typeConfig['provider'])) {
|
||||
$this->loadTypeProvider($typeConfig, $container, $objectPersisterId, $indexName, $typeName);
|
||||
$this->loadTypeProvider($typeConfig, $container, $objectPersisterId, $typeDef, $indexName, $typeName);
|
||||
}
|
||||
if (isset($typeConfig['finder'])) {
|
||||
$this->loadTypeFinder($typeConfig, $container, $elasticaToModelTransformerId, $typeRef, $indexName, $typeName);
|
||||
$this->loadTypeFinder($typeConfig, $container, $elasticaToModelTransformerId, $typeDef, $indexName, $typeName);
|
||||
}
|
||||
if (isset($typeConfig['listener'])) {
|
||||
$this->loadTypeListener($typeConfig, $container, $objectPersisterId, $indexName, $typeName);
|
||||
$this->loadTypeListener($typeConfig, $container, $objectPersisterId, $typeDef, $indexName, $typeName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and loads an ElasticaToModelTransformer.
|
||||
*
|
||||
* @param array $typeConfig
|
||||
* @param ContainerBuilder $container
|
||||
* @param string $indexName
|
||||
* @param string $typeName
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function loadElasticaToModelTransformer(array $typeConfig, ContainerBuilder $container, $indexName, $typeName)
|
||||
protected function loadElasticaToModelTransformer(array $typeConfig, ContainerBuilder $container, $indexName, $typeName)
|
||||
{
|
||||
if (isset($typeConfig['elastica_to_model_transformer']['service'])) {
|
||||
return $typeConfig['elastica_to_model_transformer']['service'];
|
||||
}
|
||||
|
||||
/* Note: transformer services may conflict with "prototype.driver", if
|
||||
* the index and type names were "prototype" and a driver, respectively.
|
||||
*/
|
||||
|
@ -340,78 +336,55 @@ class FOSElasticaExtension extends Extension
|
|||
$argPos = ('propel' === $typeConfig['driver']) ? 0 : 1;
|
||||
|
||||
$serviceDef->replaceArgument($argPos, $typeConfig['model']);
|
||||
$serviceDef->replaceArgument($argPos + 1, array_merge($typeConfig['elastica_to_model_transformer'], array(
|
||||
'identifier' => $typeConfig['identifier'],
|
||||
)));
|
||||
$container->setDefinition($serviceId, $serviceDef);
|
||||
|
||||
return $serviceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and loads a ModelToElasticaTransformer for an index/type.
|
||||
*
|
||||
* @param array $typeConfig
|
||||
* @param ContainerBuilder $container
|
||||
* @param string $indexName
|
||||
* @param string $typeName
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function loadModelToElasticaTransformer(array $typeConfig, ContainerBuilder $container, $indexName, $typeName)
|
||||
{
|
||||
if (isset($typeConfig['model_to_elastica_transformer']['service'])) {
|
||||
return $typeConfig['model_to_elastica_transformer']['service'];
|
||||
}
|
||||
|
||||
$abstractId = $container->hasDefinition('fos_elastica.serializer_callback_prototype') ?
|
||||
'fos_elastica.model_to_elastica_identifier_transformer' :
|
||||
'fos_elastica.model_to_elastica_transformer';
|
||||
|
||||
$serviceId = sprintf('fos_elastica.model_to_elastica_transformer.%s.%s', $indexName, $typeName);
|
||||
$serviceDef = new DefinitionDecorator($abstractId);
|
||||
$serviceDef->replaceArgument(0, array(
|
||||
'identifier' => $typeConfig['identifier'],
|
||||
$serviceDef->replaceArgument($argPos + 1, array(
|
||||
'hydrate' => $typeConfig['elastica_to_model_transformer']['hydrate'],
|
||||
'identifier' => $typeConfig['identifier'],
|
||||
'ignore_missing' => $typeConfig['elastica_to_model_transformer']['ignore_missing'],
|
||||
'query_builder_method' => $typeConfig['elastica_to_model_transformer']['query_builder_method']
|
||||
));
|
||||
$container->setDefinition($serviceId, $serviceDef);
|
||||
|
||||
return $serviceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and loads an object persister for a type.
|
||||
*
|
||||
* @param array $typeConfig
|
||||
* @param Reference $typeRef
|
||||
* @param ContainerBuilder $container
|
||||
* @param string $indexName
|
||||
* @param string $typeName
|
||||
* @param string $transformerId
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function loadObjectPersister(array $typeConfig, Reference $typeRef, ContainerBuilder $container, $indexName, $typeName, $transformerId)
|
||||
protected function loadModelToElasticaTransformer(array $typeConfig, ContainerBuilder $container, $indexName, $typeName)
|
||||
{
|
||||
if (isset($typeConfig['model_to_elastica_transformer']['service'])) {
|
||||
return $typeConfig['model_to_elastica_transformer']['service'];
|
||||
}
|
||||
|
||||
if ($this->serializerConfig) {
|
||||
$abstractId = sprintf('fos_elastica.model_to_elastica_identifier_transformer');
|
||||
} else {
|
||||
$abstractId = sprintf('fos_elastica.model_to_elastica_transformer');
|
||||
}
|
||||
|
||||
$serviceId = sprintf('fos_elastica.model_to_elastica_transformer.%s.%s', $indexName, $typeName);
|
||||
$serviceDef = new DefinitionDecorator($abstractId);
|
||||
$serviceDef->replaceArgument(0, array(
|
||||
'identifier' => $typeConfig['identifier']
|
||||
));
|
||||
$container->setDefinition($serviceId, $serviceDef);
|
||||
|
||||
return $serviceId;
|
||||
}
|
||||
|
||||
protected function loadObjectPersister(array $typeConfig, Definition $typeDef, ContainerBuilder $container, $indexName, $typeName, $transformerId)
|
||||
{
|
||||
$arguments = array(
|
||||
$typeRef,
|
||||
$typeDef,
|
||||
new Reference($transformerId),
|
||||
$typeConfig['model'],
|
||||
);
|
||||
|
||||
if ($container->hasDefinition('fos_elastica.serializer_callback_prototype')) {
|
||||
if ($this->serializerConfig) {
|
||||
$abstractId = 'fos_elastica.object_serializer_persister';
|
||||
$callbackId = sprintf('%s.%s.serializer.callback', $this->indexConfigs[$indexName]['reference'], $typeName);
|
||||
$callbackId = sprintf('%s.%s.serializer.callback', $this->indexConfigs[$indexName]['index'], $typeName);
|
||||
$arguments[] = array(new Reference($callbackId), 'serialize');
|
||||
} else {
|
||||
$abstractId = 'fos_elastica.object_persister';
|
||||
$mapping = $this->indexConfigs[$indexName]['types'][$typeName]['mapping'];
|
||||
$argument = $mapping['properties'];
|
||||
if (isset($mapping['_parent'])) {
|
||||
$argument['_parent'] = $mapping['_parent'];
|
||||
}
|
||||
$arguments[] = $argument;
|
||||
$arguments[] = $this->typeFields[sprintf('%s/%s', $indexName, $typeName)];
|
||||
}
|
||||
|
||||
$serviceId = sprintf('fos_elastica.object_persister.%s.%s', $indexName, $typeName);
|
||||
$serviceDef = new DefinitionDecorator($abstractId);
|
||||
foreach ($arguments as $i => $argument) {
|
||||
|
@ -423,58 +396,31 @@ class FOSElasticaExtension extends Extension
|
|||
return $serviceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a provider for a type.
|
||||
*
|
||||
* @param array $typeConfig
|
||||
* @param ContainerBuilder $container
|
||||
* @param string $objectPersisterId
|
||||
* @param string $indexName
|
||||
* @param string $typeName
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function loadTypeProvider(array $typeConfig, ContainerBuilder $container, $objectPersisterId, $indexName, $typeName)
|
||||
protected function loadTypeProvider(array $typeConfig, ContainerBuilder $container, $objectPersisterId, $typeDef, $indexName, $typeName)
|
||||
{
|
||||
if (isset($typeConfig['provider']['service'])) {
|
||||
return $typeConfig['provider']['service'];
|
||||
}
|
||||
|
||||
/* Note: provider services may conflict with "prototype.driver", if the
|
||||
* index and type names were "prototype" and a driver, respectively.
|
||||
*/
|
||||
$providerId = sprintf('fos_elastica.provider.%s.%s', $indexName, $typeName);
|
||||
$providerDef = new DefinitionDecorator('fos_elastica.provider.prototype.'.$typeConfig['driver']);
|
||||
$providerDef = new DefinitionDecorator('fos_elastica.provider.prototype.' . $typeConfig['driver']);
|
||||
$providerDef->addTag('fos_elastica.provider', array('index' => $indexName, 'type' => $typeName));
|
||||
$providerDef->replaceArgument(0, new Reference($objectPersisterId));
|
||||
$providerDef->replaceArgument(2, $typeConfig['model']);
|
||||
$providerDef->replaceArgument(1, $typeConfig['model']);
|
||||
// Propel provider can simply ignore Doctrine-specific options
|
||||
$providerDef->replaceArgument(3, array_merge(array_diff_key($typeConfig['provider'], array('service' => 1)), array(
|
||||
'indexName' => $indexName,
|
||||
'typeName' => $typeName,
|
||||
)));
|
||||
$providerDef->replaceArgument(2, array_diff_key($typeConfig['provider'], array('service' => 1)));
|
||||
$container->setDefinition($providerId, $providerDef);
|
||||
|
||||
return $providerId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads doctrine listeners to handle indexing of new or updated objects.
|
||||
*
|
||||
* @param array $typeConfig
|
||||
* @param ContainerBuilder $container
|
||||
* @param string $objectPersisterId
|
||||
* @param string $indexName
|
||||
* @param string $typeName
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function loadTypeListener(array $typeConfig, ContainerBuilder $container, $objectPersisterId, $indexName, $typeName)
|
||||
protected function loadTypeListener(array $typeConfig, ContainerBuilder $container, $objectPersisterId, $typeDef, $indexName, $typeName)
|
||||
{
|
||||
if (isset($typeConfig['listener']['service'])) {
|
||||
return $typeConfig['listener']['service'];
|
||||
}
|
||||
|
||||
/* Note: listener services may conflict with "prototype.driver", if the
|
||||
* index and type names were "prototype" and a driver, respectively.
|
||||
*/
|
||||
|
@ -482,42 +428,42 @@ class FOSElasticaExtension extends Extension
|
|||
$listenerId = sprintf('fos_elastica.listener.%s.%s', $indexName, $typeName);
|
||||
$listenerDef = new DefinitionDecorator($abstractListenerId);
|
||||
$listenerDef->replaceArgument(0, new Reference($objectPersisterId));
|
||||
$listenerDef->replaceArgument(2, array(
|
||||
'identifier' => $typeConfig['identifier'],
|
||||
'indexName' => $indexName,
|
||||
'typeName' => $typeName,
|
||||
));
|
||||
$listenerDef->replaceArgument(3, $typeConfig['listener']['logger'] ?
|
||||
new Reference($typeConfig['listener']['logger']) :
|
||||
null
|
||||
);
|
||||
$listenerDef->replaceArgument(1, $typeConfig['model']);
|
||||
$listenerDef->replaceArgument(2, $this->getDoctrineEvents($typeConfig));
|
||||
$listenerDef->replaceArgument(3, $typeConfig['identifier']);
|
||||
if ($typeConfig['listener']['logger']) {
|
||||
$listenerDef->replaceArgument(4, new Reference($typeConfig['listener']['logger']));
|
||||
}
|
||||
|
||||
$tagName = null;
|
||||
switch ($typeConfig['driver']) {
|
||||
case 'orm':
|
||||
$tagName = 'doctrine.event_listener';
|
||||
break;
|
||||
case 'mongodb':
|
||||
$tagName = 'doctrine_mongodb.odm.event_listener';
|
||||
break;
|
||||
case 'orm': $listenerDef->addTag('doctrine.event_subscriber'); break;
|
||||
case 'mongodb': $listenerDef->addTag('doctrine_mongodb.odm.event_subscriber'); break;
|
||||
}
|
||||
if (isset($typeConfig['listener']['is_indexable_callback'])) {
|
||||
$callback = $typeConfig['listener']['is_indexable_callback'];
|
||||
|
||||
if (null !== $tagName) {
|
||||
foreach ($this->getDoctrineEvents($typeConfig) as $event) {
|
||||
$listenerDef->addTag($tagName, array('event' => $event));
|
||||
if (is_array($callback)) {
|
||||
list($class) = $callback + array(null);
|
||||
if (is_string($class) && !class_exists($class)) {
|
||||
$callback[0] = new Reference($class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$listenerDef->addMethodCall('setIsIndexableCallback', array($callback));
|
||||
}
|
||||
$container->setDefinition($listenerId, $listenerDef);
|
||||
|
||||
return $listenerId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map Elastica to Doctrine events for the current driver.
|
||||
* Map Elastica to Doctrine events for the current driver
|
||||
*/
|
||||
private function getDoctrineEvents(array $typeConfig)
|
||||
{
|
||||
// Flush always calls depending on actions scheduled in lifecycle listeners
|
||||
$typeConfig['listener']['flush'] = true;
|
||||
|
||||
switch ($typeConfig['driver']) {
|
||||
case 'orm':
|
||||
$eventsClass = '\Doctrine\ORM\Events';
|
||||
|
@ -527,6 +473,7 @@ class FOSElasticaExtension extends Extension
|
|||
break;
|
||||
default:
|
||||
throw new InvalidArgumentException(sprintf('Cannot determine events for driver "%s"', $typeConfig['driver']));
|
||||
break;
|
||||
}
|
||||
|
||||
$events = array();
|
||||
|
@ -534,7 +481,7 @@ class FOSElasticaExtension extends Extension
|
|||
'insert' => array(constant($eventsClass.'::postPersist')),
|
||||
'update' => array(constant($eventsClass.'::postUpdate')),
|
||||
'delete' => array(constant($eventsClass.'::preRemove')),
|
||||
'flush' => array($typeConfig['listener']['immediate'] ? constant($eventsClass.'::preFlush') : constant($eventsClass.'::postFlush')),
|
||||
'flush' => array($typeConfig['listener']['immediate'] ? constant($eventsClass.'::preFlush') : constant($eventsClass.'::postFlush'))
|
||||
);
|
||||
|
||||
foreach ($eventMapping as $event => $doctrineEvents) {
|
||||
|
@ -546,26 +493,14 @@ class FOSElasticaExtension extends Extension
|
|||
return $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a Type specific Finder.
|
||||
*
|
||||
* @param array $typeConfig
|
||||
* @param ContainerBuilder $container
|
||||
* @param string $elasticaToModelId
|
||||
* @param Reference $typeRef
|
||||
* @param string $indexName
|
||||
* @param string $typeName
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function loadTypeFinder(array $typeConfig, ContainerBuilder $container, $elasticaToModelId, Reference $typeRef, $indexName, $typeName)
|
||||
protected function loadTypeFinder(array $typeConfig, ContainerBuilder $container, $elasticaToModelId, $typeDef, $indexName, $typeName)
|
||||
{
|
||||
if (isset($typeConfig['finder']['service'])) {
|
||||
$finderId = $typeConfig['finder']['service'];
|
||||
} else {
|
||||
$finderId = sprintf('fos_elastica.finder.%s.%s', $indexName, $typeName);
|
||||
$finderDef = new DefinitionDecorator('fos_elastica.finder');
|
||||
$finderDef->replaceArgument(0, $typeRef);
|
||||
$finderDef->replaceArgument(0, $typeDef);
|
||||
$finderDef->replaceArgument(1, new Reference($elasticaToModelId));
|
||||
$container->setDefinition($finderId, $finderDef);
|
||||
}
|
||||
|
@ -582,27 +517,31 @@ class FOSElasticaExtension extends Extension
|
|||
}
|
||||
|
||||
/**
|
||||
* Loads the index manager.
|
||||
* Loads the index manager
|
||||
*
|
||||
* @param ContainerBuilder $container
|
||||
**/
|
||||
private function loadIndexManager(ContainerBuilder $container)
|
||||
*/
|
||||
protected function loadIndexManager(ContainerBuilder $container)
|
||||
{
|
||||
$indexRefs = array_map(function ($index) {
|
||||
return $index['reference'];
|
||||
}, $this->indexConfigs);
|
||||
$indexRefs = array_map(function ($index) { return $index['index']; }, $this->indexConfigs);
|
||||
|
||||
$managerDef = $container->getDefinition('fos_elastica.index_manager');
|
||||
$managerDef->replaceArgument(0, $indexRefs);
|
||||
$managerDef->replaceArgument(1, new Reference('fos_elastica.index'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure a specific driver has been loaded.
|
||||
* Loads the resetter
|
||||
*
|
||||
* @param ContainerBuilder $container
|
||||
* @param string $driver
|
||||
*/
|
||||
private function loadDriver(ContainerBuilder $container, $driver)
|
||||
protected function loadResetter(ContainerBuilder $container)
|
||||
{
|
||||
$resetterDef = $container->getDefinition('fos_elastica.resetter');
|
||||
$resetterDef->replaceArgument(0, $this->indexConfigs);
|
||||
}
|
||||
|
||||
protected function loadDriver(ContainerBuilder $container, $driver)
|
||||
{
|
||||
if (in_array($driver, $this->loadedDrivers)) {
|
||||
return;
|
||||
|
@ -613,32 +552,7 @@ class FOSElasticaExtension extends Extension
|
|||
$this->loadedDrivers[] = $driver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads and configures the serializer prototype.
|
||||
*
|
||||
* @param array $config
|
||||
* @param ContainerBuilder $container
|
||||
*/
|
||||
private function loadSerializer($config, ContainerBuilder $container)
|
||||
{
|
||||
$container->setAlias('fos_elastica.serializer', $config['serializer']);
|
||||
|
||||
$serializer = $container->getDefinition('fos_elastica.serializer_callback_prototype');
|
||||
$serializer->setClass($config['callback_class']);
|
||||
|
||||
$callbackClassImplementedInterfaces = class_implements($config['callback_class']);
|
||||
if (isset($callbackClassImplementedInterfaces['Symfony\Component\DependencyInjection\ContainerAwareInterface'])) {
|
||||
$serializer->addMethodCall('setContainer', array(new Reference('service_container')));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a default manager alias for defined default manager or the first loaded driver.
|
||||
*
|
||||
* @param string $defaultManager
|
||||
* @param ContainerBuilder $container
|
||||
*/
|
||||
private function createDefaultManagerAlias($defaultManager, ContainerBuilder $container)
|
||||
protected function createDefaultManagerAlias($defaultManager, ContainerBuilder $container)
|
||||
{
|
||||
if (0 == count($this->loadedDrivers)) {
|
||||
return;
|
||||
|
@ -656,12 +570,10 @@ class FOSElasticaExtension extends Extension
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to a client given its configured name.
|
||||
* Returns a reference to a client.
|
||||
*
|
||||
* @param string $clientName
|
||||
*
|
||||
* @return Reference
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
private function getClient($clientName)
|
||||
|
|
|
@ -2,34 +2,32 @@
|
|||
|
||||
namespace FOS\ElasticaBundle\Doctrine;
|
||||
|
||||
use Doctrine\Common\Persistence\ManagerRegistry;
|
||||
use FOS\ElasticaBundle\HybridResult;
|
||||
use FOS\ElasticaBundle\Transformer\AbstractElasticaToModelTransformer as BaseTransformer;
|
||||
use FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface;
|
||||
use FOS\ElasticaBundle\Transformer\HighlightableModelInterface;
|
||||
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
|
||||
|
||||
/**
|
||||
* Maps Elastica documents with Doctrine objects
|
||||
* This mapper assumes an exact match between
|
||||
* elastica documents ids and doctrine object ids.
|
||||
* elastica documents ids and doctrine object ids
|
||||
*/
|
||||
abstract class AbstractElasticaToModelTransformer extends BaseTransformer
|
||||
abstract class AbstractElasticaToModelTransformer implements ElasticaToModelTransformerInterface
|
||||
{
|
||||
/**
|
||||
* Manager registry.
|
||||
*
|
||||
* @var ManagerRegistry
|
||||
* Manager registry
|
||||
*/
|
||||
protected $registry = null;
|
||||
|
||||
/**
|
||||
* Class of the model to map to the elastica documents.
|
||||
* Class of the model to map to the elastica documents
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $objectClass = null;
|
||||
|
||||
/**
|
||||
* Optional parameters.
|
||||
* Optional parameters
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
|
@ -41,13 +39,20 @@ abstract class AbstractElasticaToModelTransformer extends BaseTransformer
|
|||
);
|
||||
|
||||
/**
|
||||
* Instantiates a new Mapper.
|
||||
* PropertyAccessor instance
|
||||
*
|
||||
* @param ManagerRegistry $registry
|
||||
* @param string $objectClass
|
||||
* @param array $options
|
||||
* @var PropertyAccessorInterface
|
||||
*/
|
||||
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->objectClass = $objectClass;
|
||||
|
@ -64,14 +69,22 @@ abstract class AbstractElasticaToModelTransformer extends BaseTransformer
|
|||
return $this->objectClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the PropertyAccessor
|
||||
*
|
||||
* @param PropertyAccessorInterface $propertyAccessor
|
||||
*/
|
||||
public function setPropertyAccessor(PropertyAccessorInterface $propertyAccessor)
|
||||
{
|
||||
$this->propertyAccessor = $propertyAccessor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms an array of elastica objects into an array of
|
||||
* model objects fetched from the doctrine repository.
|
||||
* model objects fetched from the doctrine repository
|
||||
*
|
||||
* @param array $elasticaObjects of elastica objects
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*
|
||||
* @return array
|
||||
**/
|
||||
public function transform(array $elasticaObjects)
|
||||
|
@ -96,31 +109,29 @@ abstract class AbstractElasticaToModelTransformer extends BaseTransformer
|
|||
// sort objects in the order of ids
|
||||
$idPos = array_flip($ids);
|
||||
$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;
|
||||
}
|
||||
|
||||
public function hybridTransform(array $elasticaObjects)
|
||||
{
|
||||
$indexedElasticaResults = array();
|
||||
foreach ($elasticaObjects as $elasticaObject) {
|
||||
$indexedElasticaResults[$elasticaObject->getId()] = $elasticaObject;
|
||||
}
|
||||
|
||||
$objects = $this->transform($elasticaObjects);
|
||||
|
||||
$result = array();
|
||||
foreach ($objects as $object) {
|
||||
$id = $this->propertyAccessor->getValue($object, $this->options['identifier']);
|
||||
$result[] = new HybridResult($indexedElasticaResults[$id], $object);
|
||||
for ($i = 0; $i < count($elasticaObjects); $i++) {
|
||||
$result[] = new HybridResult($elasticaObjects[$i], $objects[$i]);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIdentifierField()
|
||||
{
|
||||
|
@ -128,12 +139,11 @@ abstract class AbstractElasticaToModelTransformer extends BaseTransformer
|
|||
}
|
||||
|
||||
/**
|
||||
* Fetches objects by theses identifier values.
|
||||
*
|
||||
* @param array $identifierValues ids values
|
||||
* @param Boolean $hydrate whether or not to hydrate the objects, false returns arrays
|
||||
* Fetches objects by theses identifier values
|
||||
*
|
||||
* @param array $identifierValues ids values
|
||||
* @param Boolean $hydrate whether or not to hydrate the objects, false returns arrays
|
||||
* @return array of objects or arrays
|
||||
*/
|
||||
abstract protected function findByIdentifiers(array $identifierValues, $hydrate);
|
||||
protected abstract function findByIdentifiers(array $identifierValues, $hydrate);
|
||||
}
|
||||
|
|
22
Doctrine/AbstractLookup.php
Normal file
22
Doctrine/AbstractLookup.php
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Doctrine;
|
||||
|
||||
use Doctrine\Common\Persistence\ManagerRegistry;
|
||||
use FOS\ElasticaBundle\Type\LookupInterface;
|
||||
|
||||
abstract class AbstractLookup implements LookupInterface
|
||||
{
|
||||
/**
|
||||
* @var \Doctrine\Common\Persistence\ManagerRegistry
|
||||
*/
|
||||
protected $registry;
|
||||
|
||||
/**
|
||||
* @param ManagerRegistry $registry
|
||||
*/
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
$this->registry = $registry;
|
||||
}
|
||||
}
|
|
@ -6,62 +6,84 @@ use Doctrine\Common\Persistence\ManagerRegistry;
|
|||
use Elastica\Exception\Bulk\ResponseException as BulkResponseException;
|
||||
use FOS\ElasticaBundle\Persister\ObjectPersisterInterface;
|
||||
use FOS\ElasticaBundle\Provider\AbstractProvider as BaseAbstractProvider;
|
||||
use FOS\ElasticaBundle\Provider\IndexableInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
abstract class AbstractProvider extends BaseAbstractProvider
|
||||
{
|
||||
/**
|
||||
* @var SliceFetcherInterface
|
||||
*/
|
||||
private $sliceFetcher;
|
||||
|
||||
/**
|
||||
* @var ManagerRegistry
|
||||
*/
|
||||
protected $managerRegistry;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param ObjectPersisterInterface $objectPersister
|
||||
* @param IndexableInterface $indexable
|
||||
* @param string $objectClass
|
||||
* @param array $baseOptions
|
||||
* @param array $options
|
||||
* @param ManagerRegistry $managerRegistry
|
||||
* @param SliceFetcherInterface $sliceFetcher
|
||||
*/
|
||||
public function __construct(
|
||||
ObjectPersisterInterface $objectPersister,
|
||||
IndexableInterface $indexable,
|
||||
$objectClass,
|
||||
array $baseOptions,
|
||||
ManagerRegistry $managerRegistry,
|
||||
SliceFetcherInterface $sliceFetcher = null
|
||||
) {
|
||||
parent::__construct($objectPersister, $indexable, $objectClass, $baseOptions);
|
||||
public function __construct(ObjectPersisterInterface $objectPersister, $objectClass, array $options, $managerRegistry)
|
||||
{
|
||||
parent::__construct($objectPersister, $objectClass, array_merge(array(
|
||||
'clear_object_manager' => true,
|
||||
'ignore_errors' => false,
|
||||
'query_builder_method' => 'createQueryBuilder',
|
||||
), $options));
|
||||
|
||||
$this->managerRegistry = $managerRegistry;
|
||||
$this->sliceFetcher = $sliceFetcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see FOS\ElasticaBundle\Provider\ProviderInterface::populate()
|
||||
*/
|
||||
public function populate(\Closure $loggerClosure = null, array $options = array())
|
||||
{
|
||||
$queryBuilder = $this->createQueryBuilder();
|
||||
$nbObjects = $this->countObjects($queryBuilder);
|
||||
$offset = isset($options['offset']) ? intval($options['offset']) : 0;
|
||||
$sleep = isset($options['sleep']) ? intval($options['sleep']) : 0;
|
||||
$batchSize = isset($options['batch-size']) ? intval($options['batch-size']) : $this->options['batch_size'];
|
||||
$ignoreErrors = isset($options['ignore-errors']) ? $options['ignore-errors'] : $this->options['ignore_errors'];
|
||||
|
||||
for (; $offset < $nbObjects; $offset += $batchSize) {
|
||||
if ($loggerClosure) {
|
||||
$stepStartTime = microtime(true);
|
||||
}
|
||||
$objects = $this->fetchSlice($queryBuilder, $batchSize, $offset);
|
||||
|
||||
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']) {
|
||||
$this->managerRegistry->getManagerForClass($this->objectClass)->clear();
|
||||
}
|
||||
|
||||
usleep($sleep);
|
||||
|
||||
if ($loggerClosure) {
|
||||
$stepNbObjects = count($objects);
|
||||
$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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts objects that would be indexed using the query builder.
|
||||
*
|
||||
* @param object $queryBuilder
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
abstract protected function countObjects($queryBuilder);
|
||||
|
||||
/**
|
||||
* Creates the query builder, which will be used to fetch objects to index.
|
||||
*
|
||||
* @param string $method
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
abstract protected function createQueryBuilder($method);
|
||||
protected abstract function countObjects($queryBuilder);
|
||||
|
||||
/**
|
||||
* Fetches a slice of objects using the query builder.
|
||||
|
@ -69,102 +91,14 @@ abstract class AbstractProvider extends BaseAbstractProvider
|
|||
* @param object $queryBuilder
|
||||
* @param integer $limit
|
||||
* @param integer $offset
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract protected function fetchSlice($queryBuilder, $limit, $offset);
|
||||
protected abstract function fetchSlice($queryBuilder, $limit, $offset);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
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.
|
||||
* Creates the query builder, which will be used to fetch objects to index.
|
||||
*
|
||||
* @param $queryBuilder
|
||||
* @param int $limit
|
||||
* @param int $offset
|
||||
* @param array $lastSlice
|
||||
*
|
||||
* @return array
|
||||
* @return object
|
||||
*/
|
||||
private function getSlice($queryBuilder, $limit, $offset, $lastSlice)
|
||||
{
|
||||
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
|
||||
);
|
||||
}
|
||||
protected abstract function createQueryBuilder();
|
||||
}
|
||||
|
|
|
@ -2,117 +2,238 @@
|
|||
|
||||
namespace FOS\ElasticaBundle\Doctrine;
|
||||
|
||||
use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
|
||||
use FOS\ElasticaBundle\Persister\ObjectPersister;
|
||||
use FOS\ElasticaBundle\Persister\ObjectPersisterInterface;
|
||||
use FOS\ElasticaBundle\Provider\IndexableInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Doctrine\Common\EventArgs;
|
||||
use Doctrine\Common\EventSubscriber;
|
||||
use FOS\ElasticaBundle\Persister\ObjectPersisterInterface;
|
||||
use FOS\ElasticaBundle\Persister\ObjectPersister;
|
||||
use Symfony\Component\ExpressionLanguage\Expression;
|
||||
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
|
||||
use Symfony\Component\ExpressionLanguage\SyntaxError;
|
||||
use Symfony\Component\PropertyAccess\PropertyAccess;
|
||||
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
|
||||
|
||||
/**
|
||||
* Automatically update ElasticSearch based on changes to the Doctrine source
|
||||
* data. One listener is generated for each Doctrine entity / ElasticSearch type.
|
||||
*/
|
||||
class Listener
|
||||
class Listener implements EventSubscriber
|
||||
{
|
||||
/**
|
||||
* Object persister.
|
||||
* Object persister
|
||||
*
|
||||
* @var ObjectPersisterInterface
|
||||
* @var ObjectPersister
|
||||
*/
|
||||
protected $objectPersister;
|
||||
|
||||
/**
|
||||
* Configuration for the listener.
|
||||
* Class of the domain model
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $objectClass;
|
||||
|
||||
/**
|
||||
* List of subscribed events
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $config;
|
||||
protected $events;
|
||||
|
||||
/**
|
||||
* Objects scheduled for insertion.
|
||||
* Name of domain model field used as the ES identifier
|
||||
*
|
||||
* @var array
|
||||
* @var string
|
||||
*/
|
||||
protected $esIdentifierField;
|
||||
|
||||
/**
|
||||
* Callback for determining if an object should be indexed
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $isIndexableCallback;
|
||||
|
||||
/**
|
||||
* Objects scheduled for insertion and replacement
|
||||
*/
|
||||
public $scheduledForInsertion = array();
|
||||
|
||||
/**
|
||||
* Objects scheduled to be updated or removed.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $scheduledForUpdate = array();
|
||||
|
||||
/**
|
||||
* IDs of objects scheduled for removal.
|
||||
*
|
||||
* @var array
|
||||
* IDs of objects scheduled for removal
|
||||
*/
|
||||
public $scheduledForDeletion = array();
|
||||
|
||||
/**
|
||||
* PropertyAccessor instance.
|
||||
* An instance of ExpressionLanguage
|
||||
*
|
||||
* @var ExpressionLanguage
|
||||
*/
|
||||
protected $expressionLanguage;
|
||||
|
||||
/**
|
||||
* PropertyAccessor instance
|
||||
*
|
||||
* @var PropertyAccessorInterface
|
||||
*/
|
||||
protected $propertyAccessor;
|
||||
|
||||
/**
|
||||
* @var IndexableInterface
|
||||
*/
|
||||
private $indexable;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param ObjectPersisterInterface $objectPersister
|
||||
* @param IndexableInterface $indexable
|
||||
* @param array $config
|
||||
* @param LoggerInterface $logger
|
||||
* @param string $objectClass
|
||||
* @param array $events
|
||||
* @param string $esIdentifierField
|
||||
*/
|
||||
public function __construct(
|
||||
ObjectPersisterInterface $objectPersister,
|
||||
IndexableInterface $indexable,
|
||||
array $config = array(),
|
||||
LoggerInterface $logger = null
|
||||
) {
|
||||
$this->config = array_merge(array(
|
||||
'identifier' => 'id',
|
||||
), $config);
|
||||
$this->indexable = $indexable;
|
||||
$this->objectPersister = $objectPersister;
|
||||
$this->propertyAccessor = PropertyAccess::createPropertyAccessor();
|
||||
public function __construct(ObjectPersisterInterface $objectPersister, $objectClass, array $events, $esIdentifierField = 'id', $logger = null)
|
||||
{
|
||||
$this->objectPersister = $objectPersister;
|
||||
$this->objectClass = $objectClass;
|
||||
$this->events = $events;
|
||||
$this->esIdentifierField = $esIdentifierField;
|
||||
|
||||
if ($logger && $this->objectPersister instanceof ObjectPersister) {
|
||||
if ($logger) {
|
||||
$this->objectPersister->setLogger($logger);
|
||||
}
|
||||
|
||||
$this->propertyAccessor = PropertyAccess::createPropertyAccessor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks for new objects that should be indexed.
|
||||
*
|
||||
* @param LifecycleEventArgs $eventArgs
|
||||
* @see Doctrine\Common\EventSubscriber::getSubscribedEvents()
|
||||
*/
|
||||
public function postPersist(LifecycleEventArgs $eventArgs)
|
||||
public function getSubscribedEvents()
|
||||
{
|
||||
$entity = $eventArgs->getObject();
|
||||
return $this->events;
|
||||
}
|
||||
|
||||
if ($this->objectPersister->handlesObject($entity) && $this->isObjectIndexable($entity)) {
|
||||
/**
|
||||
* Set the callback for determining object index eligibility.
|
||||
*
|
||||
* If callback is a string, it must be public method on the object class
|
||||
* that expects no arguments and returns a boolean. Otherwise, the callback
|
||||
* should expect the object for consideration as its only argument and
|
||||
* return a boolean.
|
||||
*
|
||||
* @param callback $callback
|
||||
* @throws \RuntimeException if the callback is not callable
|
||||
*/
|
||||
public function setIsIndexableCallback($callback)
|
||||
{
|
||||
if (is_string($callback)) {
|
||||
if (!is_callable(array($this->objectClass, $callback))) {
|
||||
if (false !== ($expression = $this->getExpressionLanguage())) {
|
||||
$callback = new Expression($callback);
|
||||
try {
|
||||
$expression->compile($callback, array($this->getExpressionVar()));
|
||||
} catch (SyntaxError $e) {
|
||||
throw new \RuntimeException(sprintf('Indexable callback %s::%s() is not callable or a valid expression.', $this->objectClass, $callback), 0, $e);
|
||||
}
|
||||
} else {
|
||||
throw new \RuntimeException(sprintf('Indexable callback %s::%s() is not callable.', $this->objectClass, $callback));
|
||||
}
|
||||
}
|
||||
} elseif (!is_callable($callback)) {
|
||||
if (is_array($callback)) {
|
||||
list($class, $method) = $callback + array(null, null);
|
||||
if (is_object($class)) {
|
||||
$class = get_class($class);
|
||||
}
|
||||
|
||||
if ($class && $method) {
|
||||
throw new \RuntimeException(sprintf('Indexable callback %s::%s() is not callable.', $class, $method));
|
||||
}
|
||||
}
|
||||
throw new \RuntimeException('Indexable callback is not callable.');
|
||||
}
|
||||
|
||||
$this->isIndexableCallback = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the object is indexable with respect to the callback.
|
||||
*
|
||||
* @param object $object
|
||||
* @return boolean
|
||||
*/
|
||||
protected function isObjectIndexable($object)
|
||||
{
|
||||
if (!$this->isIndexableCallback) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->isIndexableCallback instanceof Expression) {
|
||||
return $this->getExpressionLanguage()->evaluate($this->isIndexableCallback, array($this->getExpressionVar($object) => $object));
|
||||
}
|
||||
|
||||
return is_string($this->isIndexableCallback)
|
||||
? call_user_func(array($object, $this->isIndexableCallback))
|
||||
: call_user_func($this->isIndexableCallback, $object);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $object
|
||||
* @return string
|
||||
*/
|
||||
private function getExpressionVar($object = null)
|
||||
{
|
||||
$class = $object ?: $this->objectClass;
|
||||
$ref = new \ReflectionClass($class);
|
||||
|
||||
return strtolower($ref->getShortName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides unified method for retrieving a doctrine object from an EventArgs instance
|
||||
*
|
||||
* @param EventArgs $eventArgs
|
||||
* @return object Entity | Document
|
||||
* @throws \RuntimeException if no valid getter is found.
|
||||
*/
|
||||
private function getDoctrineObject(EventArgs $eventArgs)
|
||||
{
|
||||
if (method_exists($eventArgs, 'getObject')) {
|
||||
return $eventArgs->getObject();
|
||||
} elseif (method_exists($eventArgs, 'getEntity')) {
|
||||
return $eventArgs->getEntity();
|
||||
} elseif (method_exists($eventArgs, 'getDocument')) {
|
||||
return $eventArgs->getDocument();
|
||||
}
|
||||
|
||||
throw new \RuntimeException('Unable to retrieve object from EventArgs.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool|ExpressionLanguage
|
||||
*/
|
||||
private function getExpressionLanguage()
|
||||
{
|
||||
if (null === $this->expressionLanguage) {
|
||||
if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->expressionLanguage = new ExpressionLanguage();
|
||||
}
|
||||
|
||||
return $this->expressionLanguage;
|
||||
}
|
||||
|
||||
public function postPersist(EventArgs $eventArgs)
|
||||
{
|
||||
$entity = $this->getDoctrineObject($eventArgs);
|
||||
|
||||
if ($entity instanceof $this->objectClass && $this->isObjectIndexable($entity)) {
|
||||
$this->scheduledForInsertion[] = $entity;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks for objects being updated that should be indexed or removed from the index.
|
||||
*
|
||||
* @param LifecycleEventArgs $eventArgs
|
||||
*/
|
||||
public function postUpdate(LifecycleEventArgs $eventArgs)
|
||||
public function postUpdate(EventArgs $eventArgs)
|
||||
{
|
||||
$entity = $eventArgs->getObject();
|
||||
$entity = $this->getDoctrineObject($eventArgs);
|
||||
|
||||
if ($this->objectPersister->handlesObject($entity)) {
|
||||
if ($entity instanceof $this->objectClass) {
|
||||
if ($this->isObjectIndexable($entity)) {
|
||||
$this->scheduledForUpdate[] = $entity;
|
||||
} else {
|
||||
|
@ -124,22 +245,20 @@ class Listener
|
|||
|
||||
/**
|
||||
* Delete objects preRemove instead of postRemove so that we have access to the id. Because this is called
|
||||
* preRemove, first check that the entity is managed by Doctrine.
|
||||
*
|
||||
* @param LifecycleEventArgs $eventArgs
|
||||
* preRemove, first check that the entity is managed by Doctrine
|
||||
*/
|
||||
public function preRemove(LifecycleEventArgs $eventArgs)
|
||||
public function preRemove(EventArgs $eventArgs)
|
||||
{
|
||||
$entity = $eventArgs->getObject();
|
||||
$entity = $this->getDoctrineObject($eventArgs);
|
||||
|
||||
if ($this->objectPersister->handlesObject($entity)) {
|
||||
if ($entity instanceof $this->objectClass) {
|
||||
$this->scheduleForDeletion($entity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()
|
||||
{
|
||||
|
@ -158,55 +277,32 @@ class Listener
|
|||
}
|
||||
|
||||
/**
|
||||
* Iterate through scheduled actions before flushing to emulate 2.x behavior.
|
||||
* Note that the ElasticSearch index will fall out of sync with the source
|
||||
* data in the event of a crash during flush.
|
||||
*
|
||||
* This method is only called in legacy configurations of the listener.
|
||||
*
|
||||
* @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.
|
||||
* Iterate through scheduled actions before flushing to emulate 2.x behavior. Note that the ElasticSearch index
|
||||
* will fall out of sync with the source data in the event of a crash during flush.
|
||||
*/
|
||||
public function preFlush()
|
||||
public function preFlush(EventArgs $eventArgs)
|
||||
{
|
||||
$this->persistScheduled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterating through scheduled actions *after* flushing ensures that the
|
||||
* ElasticSearch index will be affected only if the query is successful.
|
||||
* Iterating through scheduled actions *after* flushing ensures that the ElasticSearch index will be affected
|
||||
* only if the query is successful
|
||||
*/
|
||||
public function postFlush()
|
||||
public function postFlush(EventArgs $eventArgs)
|
||||
{
|
||||
$this->persistScheduled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Record the specified identifier to delete. Do not need to entire object.
|
||||
*
|
||||
* @param object $object
|
||||
* @param mixed $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->esIdentifierField)) {
|
||||
$this->scheduledForDeletion[] = $identifierValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the object is indexable or not.
|
||||
*
|
||||
* @param object $object
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function isObjectIndexable($object)
|
||||
{
|
||||
return $this->indexable->isObjectIndexable(
|
||||
$this->config['indexName'],
|
||||
$this->config['typeName'],
|
||||
$object
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,23 +7,21 @@ use FOS\ElasticaBundle\Doctrine\AbstractElasticaToModelTransformer;
|
|||
/**
|
||||
* Maps Elastica documents with Doctrine objects
|
||||
* This mapper assumes an exact match between
|
||||
* elastica documents ids and doctrine object ids.
|
||||
* elastica documents ids and doctrine object ids
|
||||
*/
|
||||
class ElasticaToModelTransformer extends AbstractElasticaToModelTransformer
|
||||
{
|
||||
/**
|
||||
* Fetch objects for theses identifier values.
|
||||
*
|
||||
* @param array $identifierValues ids values
|
||||
* @param Boolean $hydrate whether or not to hydrate the objects, false returns arrays
|
||||
* Fetch objects for theses identifier values
|
||||
*
|
||||
* @param array $identifierValues ids values
|
||||
* @param Boolean $hydrate whether or not to hydrate the objects, false returns arrays
|
||||
* @return array of objects or arrays
|
||||
*/
|
||||
protected function findByIdentifiers(array $identifierValues, $hydrate)
|
||||
{
|
||||
return $this->registry
|
||||
->getManagerForClass($this->objectClass)
|
||||
->getRepository($this->objectClass)
|
||||
->{$this->options['query_builder_method']}($this->objectClass)
|
||||
->field($this->options['identifier'])->in($identifierValues)
|
||||
->hydrate($hydrate)
|
||||
|
|
49
Doctrine/MongoDB/Lookup.php
Normal file
49
Doctrine/MongoDB/Lookup.php
Normal file
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Doctrine\MongoDB;
|
||||
|
||||
use FOS\ElasticaBundle\Doctrine\AbstractLookup;
|
||||
use FOS\ElasticaBundle\Type\TypeConfiguration;
|
||||
|
||||
class Lookup extends AbstractLookup
|
||||
{
|
||||
/**
|
||||
* Returns the lookup key.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getKey()
|
||||
{
|
||||
return 'mongodb';
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up objects of a specific type with ids as supplied.
|
||||
*
|
||||
* @param TypeConfiguration $configuration
|
||||
* @param array $ids
|
||||
* @return array
|
||||
*/
|
||||
public function lookup(TypeConfiguration $configuration, array $ids)
|
||||
{
|
||||
$qb = $this->createQueryBuilder($configuration);
|
||||
$qb->hydrate($configuration->isHydrate());
|
||||
|
||||
$qb->field($configuration->getIdentifierProperty())
|
||||
->in($ids);
|
||||
|
||||
return $qb->getQuery()->execute()->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TypeConfiguration $configuration
|
||||
* @return \Doctrine\ODM\MongoDB\Query\Builder
|
||||
*/
|
||||
private function createQueryBuilder(TypeConfiguration $configuration)
|
||||
{
|
||||
$method = $configuration->getRepositoryMethod();
|
||||
$manager = $this->registry->getManagerForClass($configuration->getModelClass());
|
||||
|
||||
return $manager->{$method}($configuration->getModelClass());
|
||||
}
|
||||
}
|
|
@ -9,42 +9,7 @@ use FOS\ElasticaBundle\Exception\InvalidArgumentTypeException;
|
|||
class Provider extends AbstractProvider
|
||||
{
|
||||
/**
|
||||
* Disables logging and returns the logger that was previously set.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function disableLogging()
|
||||
{
|
||||
$configuration = $this->managerRegistry
|
||||
->getManagerForClass($this->objectClass)
|
||||
->getConnection()
|
||||
->getConfiguration();
|
||||
|
||||
$logger = $configuration->getLoggerCallable();
|
||||
$configuration->setLoggerCallable(null);
|
||||
|
||||
return $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reenables the logger with the previously returned logger from disableLogging();.
|
||||
*
|
||||
* @param mixed $logger
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function enableLogging($logger)
|
||||
{
|
||||
$configuration = $this->managerRegistry
|
||||
->getManagerForClass($this->objectClass)
|
||||
->getConnection()
|
||||
->getConfiguration();
|
||||
|
||||
$configuration->setLoggerCallable($logger);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see FOS\ElasticaBundle\Doctrine\AbstractProvider::countObjects()
|
||||
*/
|
||||
protected function countObjects($queryBuilder)
|
||||
{
|
||||
|
@ -58,7 +23,7 @@ class Provider extends AbstractProvider
|
|||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see FOS\ElasticaBundle\Doctrine\AbstractProvider::fetchSlice()
|
||||
*/
|
||||
protected function fetchSlice($queryBuilder, $limit, $offset)
|
||||
{
|
||||
|
@ -67,21 +32,21 @@ class Provider extends AbstractProvider
|
|||
}
|
||||
|
||||
return $queryBuilder
|
||||
->skip($offset)
|
||||
->limit($limit)
|
||||
->skip($offset)
|
||||
->getQuery()
|
||||
->execute()
|
||||
->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see FOS\ElasticaBundle\Doctrine\AbstractProvider::createQueryBuilder()
|
||||
*/
|
||||
protected function createQueryBuilder($method)
|
||||
protected function createQueryBuilder()
|
||||
{
|
||||
return $this->managerRegistry
|
||||
->getManagerForClass($this->objectClass)
|
||||
->getRepository($this->objectClass)
|
||||
->{$method}();
|
||||
->{$this->options['query_builder_method']}();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
;
|
||||
}
|
||||
}
|
|
@ -8,18 +8,17 @@ use Doctrine\ORM\Query;
|
|||
/**
|
||||
* Maps Elastica documents with Doctrine objects
|
||||
* This mapper assumes an exact match between
|
||||
* elastica documents ids and doctrine object ids.
|
||||
* elastica documents ids and doctrine object ids
|
||||
*/
|
||||
class ElasticaToModelTransformer extends AbstractElasticaToModelTransformer
|
||||
{
|
||||
const ENTITY_ALIAS = 'o';
|
||||
|
||||
/**
|
||||
* Fetch objects for theses identifier values.
|
||||
*
|
||||
* @param array $identifierValues ids values
|
||||
* @param Boolean $hydrate whether or not to hydrate the objects, false returns arrays
|
||||
* Fetch objects for theses identifier values
|
||||
*
|
||||
* @param array $identifierValues ids values
|
||||
* @param Boolean $hydrate whether or not to hydrate the objects, false returns arrays
|
||||
* @return array of objects or arrays
|
||||
*/
|
||||
protected function findByIdentifiers(array $identifierValues, $hydrate)
|
||||
|
@ -30,14 +29,14 @@ class ElasticaToModelTransformer extends AbstractElasticaToModelTransformer
|
|||
$hydrationMode = $hydrate ? Query::HYDRATE_OBJECT : Query::HYDRATE_ARRAY;
|
||||
|
||||
$qb = $this->getEntityQueryBuilder();
|
||||
$qb->andWhere($qb->expr()->in(static::ENTITY_ALIAS.'.'.$this->options['identifier'], ':values'))
|
||||
$qb->where($qb->expr()->in(static::ENTITY_ALIAS.'.'.$this->options['identifier'], ':values'))
|
||||
->setParameter('values', $identifierValues);
|
||||
|
||||
return $qb->getQuery()->setHydrationMode($hydrationMode)->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a query builder to be used for querying by identifiers.
|
||||
* Retrieves a query builder to be used for querying by identifiers
|
||||
*
|
||||
* @return \Doctrine\ORM\QueryBuilder
|
||||
*/
|
||||
|
|
58
Doctrine/ORM/Lookup.php
Normal file
58
Doctrine/ORM/Lookup.php
Normal file
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Doctrine\ORM;
|
||||
|
||||
use Doctrine\ORM\Query;
|
||||
use FOS\ElasticaBundle\Doctrine\AbstractLookup;
|
||||
use FOS\ElasticaBundle\Type\TypeConfiguration;
|
||||
|
||||
class Lookup extends AbstractLookup
|
||||
{
|
||||
const ENTITY_ALIAS = 'o';
|
||||
|
||||
/**
|
||||
* Returns the lookup key.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getKey()
|
||||
{
|
||||
return 'orm';
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up objects of a specific type with ids as supplied.
|
||||
*
|
||||
* @param TypeConfiguration $configuration
|
||||
* @param array $ids
|
||||
* @return array
|
||||
*/
|
||||
public function lookup(TypeConfiguration $configuration, array $ids)
|
||||
{
|
||||
$hydrationMode = $configuration->isHydrate() ?
|
||||
Query::HYDRATE_OBJECT :
|
||||
Query::HYDRATE_ARRAY;
|
||||
|
||||
$qb = $this->createQueryBuilder($configuration);
|
||||
|
||||
$qb->andWhere($qb->expr()->in(
|
||||
sprintf('%s.%s', static::ENTITY_ALIAS, $configuration->getIdentifierProperty()),
|
||||
':identifiers'
|
||||
));
|
||||
$qb->setParameter('identifiers', $ids);
|
||||
|
||||
return $qb->getQuery()->execute(array(), $hydrationMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TypeConfiguration $configuration
|
||||
* @return \Doctrine\ORM\QueryBuilder
|
||||
*/
|
||||
private function createQueryBuilder(TypeConfiguration $configuration)
|
||||
{
|
||||
$repository = $this->registry->getRepository($configuration->getModelClass());
|
||||
$method = $configuration->getRepositoryMethod();
|
||||
|
||||
return $repository->{$method}(static::ENTITY_ALIAS);
|
||||
}
|
||||
}
|
|
@ -11,42 +11,7 @@ class Provider extends AbstractProvider
|
|||
const ENTITY_ALIAS = 'a';
|
||||
|
||||
/**
|
||||
* Disables logging and returns the logger that was previously set.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function disableLogging()
|
||||
{
|
||||
$configuration = $this->managerRegistry
|
||||
->getManagerForClass($this->objectClass)
|
||||
->getConnection()
|
||||
->getConfiguration();
|
||||
|
||||
$logger = $configuration->getSQLLogger();
|
||||
$configuration->setSQLLogger(null);
|
||||
|
||||
return $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reenables the logger with the previously returned logger from disableLogging();.
|
||||
*
|
||||
* @param mixed $logger
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function enableLogging($logger)
|
||||
{
|
||||
$configuration = $this->managerRegistry
|
||||
->getManagerForClass($this->objectClass)
|
||||
->getConnection()
|
||||
->getConfiguration();
|
||||
|
||||
$configuration->setSQLLogger($logger);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see FOS\ElasticaBundle\Doctrine\AbstractProvider::countObjects()
|
||||
*/
|
||||
protected function countObjects($queryBuilder)
|
||||
{
|
||||
|
@ -69,9 +34,7 @@ class Provider extends AbstractProvider
|
|||
}
|
||||
|
||||
/**
|
||||
* This method should remain in sync with SliceFetcher::fetch until it is deprecated and removed.
|
||||
*
|
||||
* {@inheritDoc}
|
||||
* @see FOS\ElasticaBundle\Doctrine\AbstractProvider::fetchSlice()
|
||||
*/
|
||||
protected function fetchSlice($queryBuilder, $limit, $offset)
|
||||
{
|
||||
|
@ -79,8 +42,8 @@ class Provider extends AbstractProvider
|
|||
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://www.postgresql.org/docs/current/static/queries-limit.html
|
||||
* @see http://www.sqlite.org/lang_select.html#orderby
|
||||
|
@ -105,14 +68,14 @@ class Provider extends AbstractProvider
|
|||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see FOS\ElasticaBundle\Doctrine\AbstractProvider::createQueryBuilder()
|
||||
*/
|
||||
protected function createQueryBuilder($method)
|
||||
protected function createQueryBuilder()
|
||||
{
|
||||
return $this->managerRegistry
|
||||
->getManagerForClass($this->objectClass)
|
||||
->getRepository($this->objectClass)
|
||||
// ORM query builders require an alias argument
|
||||
->{$method}(static::ENTITY_ALIAS);
|
||||
->{$this->options['query_builder_method']}(static::ENTITY_ALIAS);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
;
|
||||
}
|
||||
}
|
|
@ -25,7 +25,7 @@ class RepositoryManager extends BaseManager
|
|||
}
|
||||
|
||||
/**
|
||||
* Return repository for entity.
|
||||
* Return repository for entity
|
||||
*
|
||||
* Returns custom repository if one specified otherwise
|
||||
* returns a basic repository.
|
||||
|
@ -35,7 +35,7 @@ class RepositoryManager extends BaseManager
|
|||
$realEntityName = $entityName;
|
||||
if (strpos($entityName, ':') !== false) {
|
||||
list($namespaceAlias, $simpleClassName) = explode(':', $entityName);
|
||||
$realEntityName = $this->managerRegistry->getAliasNamespace($namespaceAlias).'\\'.$simpleClassName;
|
||||
$realEntityName = $this->managerRegistry->getAliasNamespace($namespaceAlias) . '\\' . $simpleClassName;
|
||||
}
|
||||
|
||||
return parent::getRepository($realEntityName);
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
namespace FOS\ElasticaBundle;
|
||||
|
||||
use FOS\ElasticaBundle\Elastica\Index;
|
||||
use FOS\ElasticaBundle\Elastica\TransformingIndex;
|
||||
|
||||
/**
|
||||
* @deprecated Use \FOS\ElasticaBundle\Elastica\TransformingIndex
|
||||
*/
|
||||
class DynamicIndex extends Index
|
||||
class DynamicIndex extends TransformingIndex
|
||||
{
|
||||
}
|
||||
|
|
|
@ -1,104 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Elastica;
|
||||
|
||||
use Elastica\Client as BaseClient;
|
||||
use Elastica\Request;
|
||||
use FOS\ElasticaBundle\Logger\ElasticaLogger;
|
||||
use Symfony\Component\Stopwatch\Stopwatch;
|
||||
|
||||
/**
|
||||
* Extends the default Elastica client to provide logging for errors that occur
|
||||
* during communication with ElasticSearch.
|
||||
*
|
||||
* @author Gordon Franke <info@nevalon.de>
|
||||
*/
|
||||
class Client extends BaseClient
|
||||
{
|
||||
/**
|
||||
* Stores created indexes to avoid recreation.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $indexCache = array();
|
||||
|
||||
/**
|
||||
* Symfony's debugging Stopwatch.
|
||||
*
|
||||
* @var Stopwatch|null
|
||||
*/
|
||||
private $stopwatch;
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param string $method
|
||||
* @param array $data
|
||||
* @param array $query
|
||||
*
|
||||
* @return \Elastica\Response
|
||||
*/
|
||||
public function request($path, $method = Request::GET, $data = array(), array $query = array())
|
||||
{
|
||||
if ($this->stopwatch) {
|
||||
$this->stopwatch->start('es_request', 'fos_elastica');
|
||||
}
|
||||
|
||||
$start = microtime(true);
|
||||
$response = parent::request($path, $method, $data, $query);
|
||||
|
||||
$this->logQuery($path, $method, $data, $query, $start);
|
||||
|
||||
if ($this->stopwatch) {
|
||||
$this->stopwatch->stop('es_request');
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function getIndex($name)
|
||||
{
|
||||
if (isset($this->indexCache[$name])) {
|
||||
return $this->indexCache[$name];
|
||||
}
|
||||
|
||||
return $this->indexCache[$name] = new Index($this, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a stopwatch instance for debugging purposes.
|
||||
*
|
||||
* @param Stopwatch $stopwatch
|
||||
*/
|
||||
public function setStopwatch(Stopwatch $stopwatch = null)
|
||||
{
|
||||
$this->stopwatch = $stopwatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Elastica;
|
||||
|
||||
use Elastica\Index as BaseIndex;
|
||||
|
||||
/**
|
||||
* Overridden Elastica Index class that provides dynamic index name changes.
|
||||
*
|
||||
* @author Konstantin Tjuterev <kostik.lv@gmail.com>
|
||||
*/
|
||||
class Index extends BaseIndex
|
||||
{
|
||||
private $originalName;
|
||||
|
||||
/**
|
||||
* Stores created types to avoid recreation.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $typeCache = array();
|
||||
|
||||
/**
|
||||
* Returns the original name of the index if the index has been renamed for reindexing
|
||||
* or realiasing purposes.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getOriginalName()
|
||||
{
|
||||
return $this->originalName ?: $this->_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
*/
|
||||
public function getType($type)
|
||||
{
|
||||
if (isset($this->typeCache[$type])) {
|
||||
return $this->typeCache[$type];
|
||||
}
|
||||
|
||||
return $this->typeCache[$type] = parent::getType($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reassign index name.
|
||||
*
|
||||
* While it's technically a regular setter for name property, it's specifically named overrideName, but not setName
|
||||
* since it's used for a very specific case and normally should not be used
|
||||
*
|
||||
* @param string $name Index name
|
||||
*/
|
||||
public function overrideName($name)
|
||||
{
|
||||
$this->originalName = $this->_name;
|
||||
$this->_name = $name;
|
||||
}
|
||||
}
|
75
Elastica/LoggingClient.php
Normal file
75
Elastica/LoggingClient.php
Normal file
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Elastica;
|
||||
|
||||
use Elastica\Client as Client;
|
||||
use Elastica\Request;
|
||||
use FOS\ElasticaBundle\Logger\ElasticaLogger;
|
||||
use FOS\ElasticaBundle\Transformer\CombinedResultTransformer;
|
||||
|
||||
/**
|
||||
* Extends the default Elastica client to provide logging for errors that occur
|
||||
* during communication with ElasticSearch.
|
||||
*
|
||||
* @author Gordon Franke <info@nevalon.de>
|
||||
*/
|
||||
class LoggingClient extends Client
|
||||
{
|
||||
/**
|
||||
* @var CombinedResultTransformer
|
||||
*/
|
||||
private $resultTransformer;
|
||||
|
||||
public function __construct(array $config = array(), $callback = null, CombinedResultTransformer $resultTransformer)
|
||||
{
|
||||
parent::__construct($config, $callback);
|
||||
|
||||
$this->resultTransformer = $resultTransformer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden Elastica method to return TransformingIndex instances instead of the
|
||||
* default Index instances.
|
||||
*
|
||||
* @param string $name
|
||||
* @return TransformingIndex
|
||||
*/
|
||||
public function getIndex($name)
|
||||
{
|
||||
return new TransformingIndex($this, $name, $this->resultTransformer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return CombinedResultTransformer
|
||||
*/
|
||||
public function getResultTransformer()
|
||||
{
|
||||
return $this->resultTransformer;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function request($path, $method = Request::GET, $data = array(), array $query = array())
|
||||
{
|
||||
$start = microtime(true);
|
||||
$response = parent::request($path, $method, $data, $query);
|
||||
|
||||
if (null !== $this->_logger and $this->_logger instanceof ElasticaLogger) {
|
||||
$time = microtime(true) - $start;
|
||||
|
||||
$connection = $this->getLastRequest()->getConnection();
|
||||
|
||||
$connection_array = array(
|
||||
'host' => $connection->getHost(),
|
||||
'port' => $connection->getPort(),
|
||||
'transport' => $connection->getTransport(),
|
||||
'headers' => $connection->getConfig('headers'),
|
||||
);
|
||||
|
||||
$this->_logger->logQuery($path, $method, $data, $time, $connection_array, $query);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
58
Elastica/TransformingIndex.php
Normal file
58
Elastica/TransformingIndex.php
Normal file
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Elastica;
|
||||
|
||||
use Elastica\Client;
|
||||
use Elastica\Exception\InvalidException;
|
||||
use Elastica\Index;
|
||||
use FOS\ElasticaBundle\Transformer\CombinedResultTransformer;
|
||||
|
||||
/**
|
||||
* Overridden Elastica Index class that provides dynamic index name changes
|
||||
* and returns our own ResultSet instead of the Elastica ResultSet.
|
||||
*
|
||||
* @author Konstantin Tjuterev <kostik.lv@gmail.com>
|
||||
* @author Tim Nagel <tim@nagel.com.au>
|
||||
*/
|
||||
class TransformingIndex extends Index
|
||||
{
|
||||
/**
|
||||
* Creates a TransformingSearch instance instead of the default Elastica Search
|
||||
*
|
||||
* @param string $query
|
||||
* @param int|array $options
|
||||
* @return TransformingSearch
|
||||
*/
|
||||
public function createSearch($query = '', $options = null)
|
||||
{
|
||||
$search = new TransformingSearch($this->getClient());
|
||||
$search->addIndex($this);
|
||||
$search->setOptionsAndQuery($options, $query);
|
||||
|
||||
return $search;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a type object for the current index with the given name
|
||||
*
|
||||
* @param string $type Type name
|
||||
* @return TransformingType Type object
|
||||
*/
|
||||
public function getType($type)
|
||||
{
|
||||
return new TransformingType($this, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reassign index name
|
||||
*
|
||||
* While it's technically a regular setter for name property, it's specifically named overrideName, but not setName
|
||||
* since it's used for a very specific case and normally should not be used
|
||||
*
|
||||
* @param string $name Index name
|
||||
*/
|
||||
public function overrideName($name)
|
||||
{
|
||||
$this->_name = $name;
|
||||
}
|
||||
}
|
51
Elastica/TransformingResult.php
Normal file
51
Elastica/TransformingResult.php
Normal file
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Elastica;
|
||||
|
||||
use Elastica\Result;
|
||||
|
||||
class TransformingResult extends Result
|
||||
{
|
||||
/**
|
||||
* The transformed hit.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
private $transformed;
|
||||
|
||||
/**
|
||||
* @var TransformingResultSet
|
||||
*/
|
||||
private $resultSet;
|
||||
|
||||
public function __construct(array $hit, TransformingResultSet $resultSet)
|
||||
{
|
||||
parent::__construct($hit);
|
||||
|
||||
$this->resultSet = $resultSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the transformed result of the hit.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getTransformed()
|
||||
{
|
||||
if (null === $this->transformed) {
|
||||
$this->resultSet->transform();
|
||||
}
|
||||
|
||||
return $this->transformed;
|
||||
}
|
||||
|
||||
/**
|
||||
* An internal method used to set the transformed result on the Result.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function setTransformed($transformed)
|
||||
{
|
||||
$this->transformed = $transformed;
|
||||
}
|
||||
}
|
82
Elastica/TransformingResultSet.php
Normal file
82
Elastica/TransformingResultSet.php
Normal file
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Elastica;
|
||||
|
||||
use Elastica\Query;
|
||||
use Elastica\Response;
|
||||
use Elastica\ResultSet;
|
||||
use FOS\ElasticaBundle\Transformer\CombinedResultTransformer;
|
||||
use FOS\ElasticaBundle\Transformer\TransformerFactoryInterface;
|
||||
|
||||
class TransformingResultSet extends ResultSet
|
||||
{
|
||||
/**
|
||||
* @var \FOS\ElasticaBundle\Transformer\CombinedResultTransformer
|
||||
*/
|
||||
private $resultTransformer;
|
||||
|
||||
/**
|
||||
* If a transformation has already been performed on this ResultSet or not.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $transformed = false;
|
||||
|
||||
public function __construct(Response $response, Query $query, CombinedResultTransformer $resultTransformer)
|
||||
{
|
||||
parent::__construct($response, $query);
|
||||
|
||||
$this->resultTransformer = $resultTransformer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden default method to set our TransformingResult objects.
|
||||
*
|
||||
* @param \Elastica\Response $response Response object
|
||||
*/
|
||||
protected function _init(Response $response)
|
||||
{
|
||||
$this->_response = $response;
|
||||
$result = $response->getData();
|
||||
$this->_totalHits = isset($result['hits']['total']) ? $result['hits']['total'] : 0;
|
||||
$this->_maxScore = isset($result['hits']['max_score']) ? $result['hits']['max_score'] : 0;
|
||||
$this->_took = isset($result['took']) ? $result['took'] : 0;
|
||||
$this->_timedOut = !empty($result['timed_out']);
|
||||
if (isset($result['hits']['hits'])) {
|
||||
foreach ($result['hits']['hits'] as $hit) {
|
||||
$this->_results[] = new TransformingResult($hit, $this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of transformed results.
|
||||
*
|
||||
* @return object[]
|
||||
*/
|
||||
public function getTransformed()
|
||||
{
|
||||
$this->transform();
|
||||
|
||||
return array_map(function (TransformingResult $result) {
|
||||
return $result->getTransformed();
|
||||
}, $this->getResults());
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers the transformation of all Results.
|
||||
*/
|
||||
public function transform()
|
||||
{
|
||||
if ($this->transformed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$this->count()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->resultTransformer->transform($this->getResults());
|
||||
$this->transformed = true;
|
||||
}
|
||||
}
|
73
Elastica/TransformingSearch.php
Normal file
73
Elastica/TransformingSearch.php
Normal file
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Elastica;
|
||||
|
||||
use Elastica\Client;
|
||||
use Elastica\Request;
|
||||
use Elastica\Search;
|
||||
use FOS\ElasticaBundle\Transformer\CombinedResultTransformer;
|
||||
|
||||
/**
|
||||
* Overridden Elastica methods to return our TransformingResultSet
|
||||
*/
|
||||
class TransformingSearch extends Search
|
||||
{
|
||||
/**
|
||||
* Search in the set indices, types
|
||||
*
|
||||
* @param mixed $query
|
||||
* @param int|array $options OPTIONAL Limit or associative array of options (option=>value)
|
||||
* @throws \Elastica\Exception\InvalidException
|
||||
* @return TransformingResultSet
|
||||
*/
|
||||
public function search($query = '', $options = null)
|
||||
{
|
||||
$this->setOptionsAndQuery($options, $query);
|
||||
|
||||
$query = $this->getQuery();
|
||||
$path = $this->getPath();
|
||||
|
||||
$params = $this->getOptions();
|
||||
|
||||
// Send scroll_id via raw HTTP body to handle cases of very large (> 4kb) ids.
|
||||
if ('_search/scroll' == $path) {
|
||||
$data = $params[self::OPTION_SCROLL_ID];
|
||||
unset($params[self::OPTION_SCROLL_ID]);
|
||||
} else {
|
||||
$data = $query->toArray();
|
||||
}
|
||||
|
||||
$response = $this->getClient()->request(
|
||||
$path,
|
||||
Request::GET,
|
||||
$data,
|
||||
$params
|
||||
);
|
||||
|
||||
return new TransformingResultSet($response, $query, $this->_client->getResultTransformer());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param mixed $query
|
||||
* @param $fullResult (default = false) By default only the total hit count is returned. If set to true, the full ResultSet including facets is returned.
|
||||
* @return int|TransformingResultSet
|
||||
*/
|
||||
public function count($query = '', $fullResult = false)
|
||||
{
|
||||
$this->setOptionsAndQuery(null, $query);
|
||||
|
||||
$query = $this->getQuery();
|
||||
$path = $this->getPath();
|
||||
|
||||
$response = $this->getClient()->request(
|
||||
$path,
|
||||
Request::GET,
|
||||
$query->toArray(),
|
||||
array(self::OPTION_SEARCH_TYPE => self::OPTION_SEARCH_TYPE_COUNT)
|
||||
);
|
||||
$resultSet = new TransformingResultSet($response, $query, $this->_client->getResultTransformer());
|
||||
|
||||
return $fullResult ? $resultSet : $resultSet->getTotalHits();
|
||||
}
|
||||
}
|
25
Elastica/TransformingType.php
Normal file
25
Elastica/TransformingType.php
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Elastica;
|
||||
|
||||
use Elastica\Document;
|
||||
use Elastica\Query;
|
||||
use Elastica\Request;
|
||||
use Elastica\Type;
|
||||
|
||||
class TransformingType extends Type
|
||||
{
|
||||
/**
|
||||
* Overridden default method that returns our TransformingResultSet.
|
||||
*
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function moreLikeThis(Document $doc, $params = array(), $query = array())
|
||||
{
|
||||
$path = $doc->getId() . '/_mlt';
|
||||
$query = Query::create($query);
|
||||
$response = $this->request($path, Request::GET, $query->toArray(), $params);
|
||||
|
||||
return new TransformingResultSet($response, $query, $this->_index->getClient()->getResultTransformer());
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
15
Exception/MissingModelException.php
Normal file
15
Exception/MissingModelException.php
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Exception;
|
||||
|
||||
use Exception;
|
||||
|
||||
class MissingModelException extends \Exception
|
||||
{
|
||||
public function __construct($modelCount, $resultCount)
|
||||
{
|
||||
$message = sprintf('Expected to have %d models, but the lookup returned %d results', $resultCount, $modelCount);
|
||||
|
||||
parent::__construct($message);
|
||||
}
|
||||
}
|
13
Exception/UnexpectedObjectException.php
Normal file
13
Exception/UnexpectedObjectException.php
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Exception;
|
||||
|
||||
use Exception;
|
||||
|
||||
class UnexpectedObjectException extends \Exception
|
||||
{
|
||||
public function __construct($id)
|
||||
{
|
||||
parent::__construct(sprintf('Lookup returned an unexpected object with id %d', $id));
|
||||
}
|
||||
}
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
namespace FOS\ElasticaBundle;
|
||||
|
||||
use FOS\ElasticaBundle\DependencyInjection\Compiler\ConfigSourcePass;
|
||||
use FOS\ElasticaBundle\DependencyInjection\Compiler\IndexPass;
|
||||
use FOS\ElasticaBundle\DependencyInjection\Compiler\RegisterProvidersPass;
|
||||
use FOS\ElasticaBundle\DependencyInjection\Compiler\TransformerPass;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
@ -12,6 +10,7 @@ use Symfony\Component\HttpKernel\Bundle\Bundle;
|
|||
|
||||
/**
|
||||
* Bundle.
|
||||
*
|
||||
*/
|
||||
class FOSElasticaBundle extends Bundle
|
||||
{
|
||||
|
@ -22,8 +21,6 @@ class FOSElasticaBundle extends Bundle
|
|||
{
|
||||
parent::build($container);
|
||||
|
||||
$container->addCompilerPass(new ConfigSourcePass());
|
||||
$container->addCompilerPass(new IndexPass());
|
||||
$container->addCompilerPass(new RegisterProvidersPass(), PassConfig::TYPE_BEFORE_REMOVING);
|
||||
$container->addCompilerPass(new TransformerPass());
|
||||
}
|
||||
|
|
|
@ -5,13 +5,12 @@ namespace FOS\ElasticaBundle\Finder;
|
|||
interface FinderInterface
|
||||
{
|
||||
/**
|
||||
* Searches for query results within a given limit.
|
||||
* Searches for query results within a given limit
|
||||
*
|
||||
* @param mixed $query Can be a string, an array or an \Elastica\Query object
|
||||
* @param int $limit How many results to get
|
||||
* @param mixed $query Can be a string, an array or an \Elastica\Query object
|
||||
* @param int $limit How many results to get
|
||||
* @param array $options
|
||||
*
|
||||
* @return array results
|
||||
*/
|
||||
public function find($query, $limit = null, $options = array());
|
||||
function find($query, $limit = null, $options = array());
|
||||
}
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Finder;
|
||||
|
||||
use FOS\ElasticaBundle\Paginator\PaginatorAdapterInterface;
|
||||
use Pagerfanta\Pagerfanta;
|
||||
use Elastica\Query;
|
||||
|
||||
interface PaginatedFinderInterface extends FinderInterface
|
||||
{
|
||||
/**
|
||||
* Searches for query results and returns them wrapped in a paginator.
|
||||
*
|
||||
* @param mixed $query Can be a string, an array or an \Elastica\Query object
|
||||
* @param array $options
|
||||
*
|
||||
* @return Pagerfanta paginated results
|
||||
*/
|
||||
public function findPaginated($query, $options = array());
|
||||
|
||||
/**
|
||||
* Creates a paginator adapter for this query.
|
||||
*
|
||||
* @param mixed $query
|
||||
* @param array $options
|
||||
*
|
||||
* @return PaginatorAdapterInterface
|
||||
*/
|
||||
public function createPaginatorAdapter($query, $options = array());
|
||||
}
|
|
@ -11,9 +11,9 @@ use Elastica\SearchableInterface;
|
|||
use Elastica\Query;
|
||||
|
||||
/**
|
||||
* Finds elastica documents and map them to persisted objects.
|
||||
* Finds elastica documents and map them to persisted objects
|
||||
*/
|
||||
class TransformedFinder implements PaginatedFinderInterface
|
||||
class TransformedFinder implements FinderInterface
|
||||
{
|
||||
protected $searchable;
|
||||
protected $transformer;
|
||||
|
@ -25,14 +25,13 @@ class TransformedFinder implements PaginatedFinderInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* Search for a query string.
|
||||
* Search for a query string
|
||||
*
|
||||
* @param string $query
|
||||
* @param string $query
|
||||
* @param integer $limit
|
||||
* @param array $options
|
||||
*
|
||||
* @param array $options
|
||||
* @return array of model objects
|
||||
**/
|
||||
*/
|
||||
public function find($query, $limit = null, $options = array())
|
||||
{
|
||||
$results = $this->search($query, $limit, $options);
|
||||
|
@ -51,9 +50,8 @@ class TransformedFinder implements PaginatedFinderInterface
|
|||
* Find documents similar to one with passed id.
|
||||
*
|
||||
* @param integer $id
|
||||
* @param array $params
|
||||
* @param array $query
|
||||
*
|
||||
* @param array $params
|
||||
* @param array $query
|
||||
* @return array of model objects
|
||||
**/
|
||||
public function moreLikeThis($id, $params = array(), $query = array())
|
||||
|
@ -67,8 +65,7 @@ class TransformedFinder implements PaginatedFinderInterface
|
|||
/**
|
||||
* @param $query
|
||||
* @param null|int $limit
|
||||
* @param array $options
|
||||
*
|
||||
* @param array $options
|
||||
* @return array
|
||||
*/
|
||||
protected function search($query, $limit = null, $options = array())
|
||||
|
@ -81,30 +78,4 @@ class TransformedFinder implements PaginatedFinderInterface
|
|||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a paginator wrapping the result of a search.
|
||||
*
|
||||
* @param string $query
|
||||
* @param array $options
|
||||
*
|
||||
* @return Pagerfanta
|
||||
*/
|
||||
public function findPaginated($query, $options = array())
|
||||
{
|
||||
$queryObject = Query::create($query);
|
||||
$paginatorAdapter = $this->createPaginatorAdapter($queryObject, $options);
|
||||
|
||||
return new Pagerfanta(new FantaPaginatorAdapter($paginatorAdapter));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createPaginatorAdapter($query, $options = array())
|
||||
{
|
||||
$query = Query::create($query);
|
||||
|
||||
return new TransformedPaginatorAdapter($this->searchable, $query, $options, $this->transformer);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,4 +24,4 @@ class HybridResult
|
|||
{
|
||||
return $this->result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,197 +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\Index;
|
||||
|
||||
use Elastica\Client;
|
||||
use Elastica\Exception\ExceptionInterface;
|
||||
use Elastica\Request;
|
||||
use FOS\ElasticaBundle\Configuration\IndexConfig;
|
||||
use FOS\ElasticaBundle\Elastica\Index;
|
||||
use FOS\ElasticaBundle\Exception\AliasIsIndexException;
|
||||
|
||||
class AliasProcessor
|
||||
{
|
||||
/**
|
||||
* Sets the randomised root name for an index.
|
||||
*
|
||||
* @param IndexConfig $indexConfig
|
||||
* @param Index $index
|
||||
*/
|
||||
public function setRootName(IndexConfig $indexConfig, Index $index)
|
||||
{
|
||||
$index->overrideName(
|
||||
sprintf('%s_%s',
|
||||
$indexConfig->getElasticSearchName(),
|
||||
date('Y-m-d-His')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches an index to become the new target for an alias. Only applies for
|
||||
* indexes that are set to use aliases.
|
||||
*
|
||||
* $force will delete an index encountered where an alias is expected.
|
||||
*
|
||||
* @param IndexConfig $indexConfig
|
||||
* @param Index $index
|
||||
* @param bool $force
|
||||
*
|
||||
* @throws AliasIsIndexException
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function switchIndexAlias(IndexConfig $indexConfig, Index $index, $force = false)
|
||||
{
|
||||
$client = $index->getClient();
|
||||
|
||||
$aliasName = $indexConfig->getElasticSearchName();
|
||||
$oldIndexName = null;
|
||||
$newIndexName = $index->getName();
|
||||
|
||||
try {
|
||||
$oldIndexName = $this->getAliasedIndex($client, $aliasName);
|
||||
} catch (AliasIsIndexException $e) {
|
||||
if (!$force) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$this->deleteIndex($client, $aliasName);
|
||||
}
|
||||
|
||||
try {
|
||||
$aliasUpdateRequest = $this->buildAliasUpdateRequest($oldIndexName, $aliasName, $newIndexName);
|
||||
$client->request('_aliases', 'POST', $aliasUpdateRequest);
|
||||
} catch (ExceptionInterface $e) {
|
||||
$this->cleanupRenameFailure($client, $newIndexName, $e);
|
||||
}
|
||||
|
||||
// Delete the old index after the alias has been switched
|
||||
if (null !== $oldIndexName) {
|
||||
$this->deleteIndex($client, $oldIndexName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an ElasticSearch request to rename or create an alias.
|
||||
*
|
||||
* @param string|null $aliasedIndex
|
||||
* @param string $aliasName
|
||||
* @param string $newIndexName
|
||||
* @return array
|
||||
*/
|
||||
private function buildAliasUpdateRequest($aliasedIndex, $aliasName, $newIndexName)
|
||||
{
|
||||
$aliasUpdateRequest = array('actions' => array());
|
||||
if (null !== $aliasedIndex) {
|
||||
// if the alias is set - add an action to remove it
|
||||
$aliasUpdateRequest['actions'][] = array(
|
||||
'remove' => array('index' => $aliasedIndex, 'alias' => $aliasName),
|
||||
);
|
||||
}
|
||||
|
||||
// add an action to point the alias to the new index
|
||||
$aliasUpdateRequest['actions'][] = array(
|
||||
'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 {
|
||||
$this->deleteIndex($client, $indexName);
|
||||
} catch (ExceptionInterface $deleteNewIndexException) {
|
||||
$additionalError = sprintf(
|
||||
'Tried to delete newly built index %s, but also failed: %s',
|
||||
$indexName,
|
||||
$deleteNewIndexException->getMessage()
|
||||
);
|
||||
}
|
||||
|
||||
throw new \RuntimeException(sprintf(
|
||||
'Failed to updated index alias: %s. %s',
|
||||
$renameAliasException->getMessage(),
|
||||
$additionalError ?: sprintf('Newly built index %s was deleted', $indexName)
|
||||
), 0, $renameAliasException);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an index.
|
||||
*
|
||||
* @param Client $client
|
||||
* @param string $indexName Index name to delete
|
||||
*/
|
||||
private function deleteIndex(Client $client, $indexName)
|
||||
{
|
||||
try {
|
||||
$path = sprintf("%s", $indexName);
|
||||
$client->request($path, Request::DELETE);
|
||||
} catch (ExceptionInterface $deleteOldIndexException) {
|
||||
throw new \RuntimeException(sprintf(
|
||||
'Failed to delete index %s with message: %s',
|
||||
$indexName,
|
||||
$deleteOldIndexException->getMessage()
|
||||
), 0, $deleteOldIndexException);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of a single index that an alias points to or throws
|
||||
* an exception if there is more than one.
|
||||
*
|
||||
* @param Client $client
|
||||
* @param string $aliasName Alias name
|
||||
*
|
||||
* @return string|null
|
||||
*
|
||||
* @throws AliasIsIndexException
|
||||
*/
|
||||
private function getAliasedIndex(Client $client, $aliasName)
|
||||
{
|
||||
$aliasesInfo = $client->request('_aliases', 'GET')->getData();
|
||||
$aliasedIndexes = array();
|
||||
|
||||
foreach ($aliasesInfo as $indexName => $indexInfo) {
|
||||
if ($indexName === $aliasName) {
|
||||
throw new AliasIsIndexException($indexName);
|
||||
}
|
||||
if (!isset($indexInfo['aliases'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$aliases = array_keys($indexInfo['aliases']);
|
||||
if (in_array($aliasName, $aliases)) {
|
||||
$aliasedIndexes[] = $indexName;
|
||||
}
|
||||
}
|
||||
|
||||
if (count($aliasedIndexes) > 1) {
|
||||
throw new \RuntimeException(sprintf(
|
||||
'Alias %s is used for multiple indexes: [%s]. Make sure it\'s'.
|
||||
'either not used or is assigned to one index only',
|
||||
$aliasName,
|
||||
implode(', ', $aliasedIndexes)
|
||||
));
|
||||
}
|
||||
|
||||
return array_shift($aliasedIndexes);
|
||||
}
|
||||
}
|
|
@ -2,69 +2,67 @@
|
|||
|
||||
namespace FOS\ElasticaBundle\Index;
|
||||
|
||||
use FOS\ElasticaBundle\Elastica\Index;
|
||||
use FOS\ElasticaBundle\Elastica\TransformingIndex;
|
||||
|
||||
class IndexManager
|
||||
{
|
||||
/**
|
||||
* @var Index
|
||||
* @var TransformingIndex[]
|
||||
*/
|
||||
private $defaultIndex;
|
||||
protected $indexesByName;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
* @var string
|
||||
*/
|
||||
private $indexes;
|
||||
protected $defaultIndexName;
|
||||
|
||||
/**
|
||||
* @param array $indexes
|
||||
* @param Index $defaultIndex
|
||||
* @param TransformingIndex[] $indexesByName
|
||||
* @param TransformingIndex $defaultIndex
|
||||
*/
|
||||
public function __construct(array $indexes, Index $defaultIndex)
|
||||
public function __construct(array $indexesByName, TransformingIndex $defaultIndex)
|
||||
{
|
||||
$this->defaultIndex = $defaultIndex;
|
||||
$this->indexes = $indexes;
|
||||
$this->indexesByName = $indexesByName;
|
||||
$this->defaultIndexName = $defaultIndex->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all registered indexes.
|
||||
* Gets all registered indexes
|
||||
*
|
||||
* @return array
|
||||
* @return TransformingIndex[]
|
||||
*/
|
||||
public function getAllIndexes()
|
||||
{
|
||||
return $this->indexes;
|
||||
return $this->indexesByName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an index by its name.
|
||||
* Gets an index by its name
|
||||
*
|
||||
* @param string $name Index to return, or the default index if null
|
||||
*
|
||||
* @return Index
|
||||
*
|
||||
* @return TransformingIndex
|
||||
* @throws \InvalidArgumentException if no index exists for the given name
|
||||
*/
|
||||
public function getIndex($name = null)
|
||||
{
|
||||
if (null === $name) {
|
||||
return $this->defaultIndex;
|
||||
$name = $this->defaultIndexName;
|
||||
}
|
||||
|
||||
if (!isset($this->indexes[$name])) {
|
||||
if (!isset($this->indexesByName[$name])) {
|
||||
throw new \InvalidArgumentException(sprintf('The index "%s" does not exist', $name));
|
||||
}
|
||||
|
||||
return $this->indexes[$name];
|
||||
return $this->indexesByName[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default index.
|
||||
* Gets the default index
|
||||
*
|
||||
* @return Index
|
||||
* @return TransformingIndex
|
||||
*/
|
||||
public function getDefaultIndex()
|
||||
{
|
||||
return $this->defaultIndex;
|
||||
return $this->getIndex($this->defaultIndexName);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,134 +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\Index;
|
||||
|
||||
use FOS\ElasticaBundle\Configuration\IndexConfig;
|
||||
use FOS\ElasticaBundle\Configuration\TypeConfig;
|
||||
|
||||
class MappingBuilder
|
||||
{
|
||||
/**
|
||||
* Skip adding default information to certain fields.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $skipTypes = array('completion');
|
||||
|
||||
/**
|
||||
* Builds mappings for an entire index.
|
||||
*
|
||||
* @param IndexConfig $indexConfig
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function buildIndexMapping(IndexConfig $indexConfig)
|
||||
{
|
||||
$typeMappings = array();
|
||||
foreach ($indexConfig->getTypes() as $typeConfig) {
|
||||
$typeMappings[$typeConfig->getName()] = $this->buildTypeMapping($typeConfig);
|
||||
}
|
||||
|
||||
$mapping = array();
|
||||
if (!empty($typeMappings)) {
|
||||
$mapping['mappings'] = $typeMappings;
|
||||
}
|
||||
// 'warmers' => $indexConfig->getWarmers(),
|
||||
|
||||
$settings = $indexConfig->getSettings();
|
||||
if (!empty($settings)) {
|
||||
$mapping['settings'] = $settings;
|
||||
}
|
||||
|
||||
return $mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds mappings for a single type.
|
||||
*
|
||||
* @param TypeConfig $typeConfig
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function buildTypeMapping(TypeConfig $typeConfig)
|
||||
{
|
||||
$mapping = $typeConfig->getMapping();
|
||||
|
||||
if (null !== $typeConfig->getDynamicDateFormats()) {
|
||||
$mapping['dynamic_date_formats'] = $typeConfig->getDynamicDateFormats();
|
||||
}
|
||||
|
||||
if (null !== $typeConfig->getDateDetection()) {
|
||||
$mapping['date_detection'] = $typeConfig->getDateDetection();
|
||||
}
|
||||
|
||||
if (null !== $typeConfig->getNumericDetection()) {
|
||||
$mapping['numeric_detection'] = $typeConfig->getNumericDetection();
|
||||
}
|
||||
|
||||
if ($typeConfig->getIndexAnalyzer()) {
|
||||
$mapping['index_analyzer'] = $typeConfig->getIndexAnalyzer();
|
||||
}
|
||||
|
||||
if ($typeConfig->getSearchAnalyzer()) {
|
||||
$mapping['search_analyzer'] = $typeConfig->getSearchAnalyzer();
|
||||
}
|
||||
|
||||
if (isset($mapping['dynamic_templates']) and empty($mapping['dynamic_templates'])) {
|
||||
unset($mapping['dynamic_templates']);
|
||||
}
|
||||
|
||||
$this->fixProperties($mapping['properties']);
|
||||
if (!$mapping['properties']) {
|
||||
unset($mapping['properties']);
|
||||
}
|
||||
|
||||
if ($typeConfig->getModel()) {
|
||||
$mapping['_meta']['model'] = $typeConfig->getModel();
|
||||
}
|
||||
|
||||
if (empty($mapping)) {
|
||||
// Empty mapping, we want it encoded as a {} instead of a []
|
||||
$mapping = new \stdClass();
|
||||
}
|
||||
|
||||
return $mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes any properties and applies basic defaults for any field that does not have
|
||||
* required options.
|
||||
*
|
||||
* @param $properties
|
||||
*/
|
||||
private function fixProperties(&$properties)
|
||||
{
|
||||
foreach ($properties as $name => &$property) {
|
||||
unset($property['property_path']);
|
||||
|
||||
if (!isset($property['type'])) {
|
||||
$property['type'] = 'string';
|
||||
}
|
||||
if ($property['type'] == 'multi_field' && isset($property['fields'])) {
|
||||
$this->fixProperties($property['fields']);
|
||||
}
|
||||
if (isset($property['properties'])) {
|
||||
$this->fixProperties($property['properties']);
|
||||
}
|
||||
if (in_array($property['type'], $this->skipTypes)) {
|
||||
continue;
|
||||
}
|
||||
if (!isset($property['store'])) {
|
||||
$property['store'] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,127 +2,77 @@
|
|||
|
||||
namespace FOS\ElasticaBundle\Index;
|
||||
|
||||
use Elastica\Exception\ExceptionInterface;
|
||||
use Elastica\Index;
|
||||
use Elastica\Exception\ResponseException;
|
||||
use Elastica\Type\Mapping;
|
||||
use FOS\ElasticaBundle\Configuration\ConfigManager;
|
||||
use FOS\ElasticaBundle\Event\IndexResetEvent;
|
||||
use FOS\ElasticaBundle\Event\TypeResetEvent;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
/**
|
||||
* Deletes and recreates indexes.
|
||||
* Deletes and recreates indexes
|
||||
*/
|
||||
class Resetter
|
||||
{
|
||||
/**
|
||||
* @var AliasProcessor
|
||||
*/
|
||||
private $aliasProcessor;
|
||||
|
||||
/***
|
||||
* @var ConfigManager
|
||||
*/
|
||||
private $configManager;
|
||||
protected $indexConfigsByName;
|
||||
|
||||
/**
|
||||
* @var EventDispatcherInterface
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $indexConfigsByName
|
||||
*/
|
||||
private $dispatcher;
|
||||
|
||||
/**
|
||||
* @var IndexManager
|
||||
*/
|
||||
private $indexManager;
|
||||
|
||||
/**
|
||||
* @var MappingBuilder
|
||||
*/
|
||||
private $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->configManager = $configManager;
|
||||
$this->dispatcher = $eventDispatcher;
|
||||
$this->indexManager = $indexManager;
|
||||
$this->mappingBuilder = $mappingBuilder;
|
||||
public function __construct(array $indexConfigsByName)
|
||||
{
|
||||
$this->indexConfigsByName = $indexConfigsByName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes and recreates all indexes.
|
||||
*
|
||||
* @param bool $populating
|
||||
* @param bool $force
|
||||
* Deletes and recreates all indexes
|
||||
*/
|
||||
public function resetAllIndexes($populating = false, $force = false)
|
||||
public function resetAllIndexes()
|
||||
{
|
||||
foreach ($this->configManager->getIndexNames() as $name) {
|
||||
$this->resetIndex($name, $populating, $force);
|
||||
foreach (array_keys($this->indexConfigsByName) as $name) {
|
||||
$this->resetIndex($name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes and recreates the named index. If populating, creates a new index
|
||||
* with a randomised name for an alias to be set after population.
|
||||
* Deletes and recreates the named index
|
||||
*
|
||||
* @param string $indexName
|
||||
* @param bool $populating
|
||||
* @param bool $force If index exists with same name as alias, remove it
|
||||
*
|
||||
* @throws \InvalidArgumentException if no index exists for the given name
|
||||
*/
|
||||
public function resetIndex($indexName, $populating = false, $force = false)
|
||||
public function resetIndex($indexName)
|
||||
{
|
||||
$indexConfig = $this->configManager->getIndexConfiguration($indexName);
|
||||
$index = $this->indexManager->getIndex($indexName);
|
||||
$indexConfig = $this->getIndexConfig($indexName);
|
||||
$esIndex = $indexConfig['index'];
|
||||
if (isset($indexConfig['use_alias']) && $indexConfig['use_alias']) {
|
||||
$name = $indexConfig['name_or_alias'];
|
||||
$name .= uniqid();
|
||||
$esIndex->overrideName($name);
|
||||
$esIndex->create($indexConfig['config']);
|
||||
|
||||
$event = new IndexResetEvent($indexName, $populating, $force);
|
||||
$this->dispatcher->dispatch(IndexResetEvent::PRE_INDEX_RESET, $event);
|
||||
|
||||
if ($indexConfig->isUseAlias()) {
|
||||
$this->aliasProcessor->setRootName($indexConfig, $index);
|
||||
return;
|
||||
}
|
||||
|
||||
$mapping = $this->mappingBuilder->buildIndexMapping($indexConfig);
|
||||
$index->create($mapping, true);
|
||||
|
||||
if (!$populating and $indexConfig->isUseAlias()) {
|
||||
$this->aliasProcessor->switchIndexAlias($indexConfig, $index, $force);
|
||||
}
|
||||
|
||||
$this->dispatcher->dispatch(IndexResetEvent::POST_INDEX_RESET, $event);
|
||||
$esIndex->create($indexConfig['config'], true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes and recreates a mapping type for the named index.
|
||||
* Deletes and recreates a mapping type for the named index
|
||||
*
|
||||
* @param string $indexName
|
||||
* @param string $typeName
|
||||
*
|
||||
* @throws \InvalidArgumentException if no index or type mapping exists for the given names
|
||||
* @throws ResponseException
|
||||
*/
|
||||
public function resetIndexType($indexName, $typeName)
|
||||
{
|
||||
$typeConfig = $this->configManager->getTypeConfiguration($indexName, $typeName);
|
||||
$type = $this->indexManager->getIndex($indexName)->getType($typeName);
|
||||
$indexConfig = $this->getIndexConfig($indexName);
|
||||
|
||||
$event = new TypeResetEvent($indexName, $typeName);
|
||||
$this->dispatcher->dispatch(TypeResetEvent::PRE_TYPE_RESET, $event);
|
||||
if (!isset($indexConfig['config']['mappings'][$typeName]['properties'])) {
|
||||
throw new \InvalidArgumentException(sprintf('The mapping for index "%s" and type "%s" does not exist.', $indexName, $typeName));
|
||||
}
|
||||
|
||||
$type = $indexConfig['index']->getType($typeName);
|
||||
try {
|
||||
$type->delete();
|
||||
} catch (ResponseException $e) {
|
||||
|
@ -130,29 +80,167 @@ class Resetter
|
|||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
$mapping = new Mapping();
|
||||
foreach ($this->mappingBuilder->buildTypeMapping($typeConfig) as $name => $field) {
|
||||
$mapping->setParam($name, $field);
|
||||
}
|
||||
|
||||
$mapping = $this->createMapping($indexConfig['config']['mappings'][$typeName]);
|
||||
$type->setMapping($mapping);
|
||||
|
||||
$this->dispatcher->dispatch(TypeResetEvent::POST_TYPE_RESET, $event);
|
||||
}
|
||||
|
||||
/**
|
||||
* A command run when a population has finished.
|
||||
* create type mapping object
|
||||
*
|
||||
* @param string $indexName
|
||||
* @param array $indexConfig
|
||||
* @return Mapping
|
||||
*/
|
||||
protected function createMapping($indexConfig)
|
||||
{
|
||||
$mapping = Mapping::create($indexConfig['properties']);
|
||||
|
||||
$mappingSpecialFields = array('_uid', '_id', '_source', '_all', '_analyzer', '_boost', '_routing', '_index', '_size', '_timestamp', '_ttl', 'dynamic_templates');
|
||||
foreach ($mappingSpecialFields as $specialField) {
|
||||
if (isset($indexConfig[$specialField])) {
|
||||
$mapping->setParam($specialField, $indexConfig[$specialField]);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($indexConfig['_parent'])) {
|
||||
$mapping->setParam('_parent', array('type' => $indexConfig['_parent']['type']));
|
||||
}
|
||||
|
||||
return $mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an index config by its name
|
||||
*
|
||||
* @param string $indexName Index name
|
||||
*
|
||||
* @param $indexName
|
||||
* @return array
|
||||
* @throws \InvalidArgumentException if no index config exists for the given name
|
||||
*/
|
||||
protected function getIndexConfig($indexName)
|
||||
{
|
||||
if (!isset($this->indexConfigsByName[$indexName])) {
|
||||
throw new \InvalidArgumentException(sprintf('The configuration for index "%s" does not exist.', $indexName));
|
||||
}
|
||||
|
||||
return $this->indexConfigsByName[$indexName];
|
||||
}
|
||||
|
||||
public function postPopulate($indexName)
|
||||
{
|
||||
$indexConfig = $this->configManager->getIndexConfiguration($indexName);
|
||||
|
||||
if ($indexConfig->isUseAlias()) {
|
||||
$index = $this->indexManager->getIndex($indexName);
|
||||
$this->aliasProcessor->switchIndexAlias($indexConfig, $index);
|
||||
$indexConfig = $this->getIndexConfig($indexName);
|
||||
if (isset($indexConfig['use_alias']) && $indexConfig['use_alias']) {
|
||||
$this->switchIndexAlias($indexName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches the alias for given index (by key) to the newly populated index
|
||||
* and deletes the old index
|
||||
*
|
||||
* @param string $indexName Index name
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
private function switchIndexAlias($indexName)
|
||||
{
|
||||
$indexConfig = $this->getIndexConfig($indexName);
|
||||
$esIndex = $indexConfig['index'];
|
||||
$aliasName = $indexConfig['name_or_alias'];
|
||||
$oldIndexName = false;
|
||||
$newIndexName = $esIndex->getName();
|
||||
|
||||
$aliasedIndexes = $this->getAliasedIndexes($esIndex, $aliasName);
|
||||
|
||||
if (count($aliasedIndexes) > 1) {
|
||||
throw new \RuntimeException(
|
||||
sprintf(
|
||||
'Alias %s is used for multiple indexes: [%s].
|
||||
Make sure it\'s either not used or is assigned to one index only',
|
||||
$aliasName,
|
||||
join(', ', $aliasedIndexes)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Change the alias to point to the new index
|
||||
// Elastica's addAlias can't be used directly, because in current (0.19.x) version it's not atomic
|
||||
// In 0.20.x it's atomic, but it doesn't return the old index name
|
||||
$aliasUpdateRequest = array('actions' => array());
|
||||
if (count($aliasedIndexes) == 1) {
|
||||
// if the alias is set - add an action to remove it
|
||||
$oldIndexName = $aliasedIndexes[0];
|
||||
$aliasUpdateRequest['actions'][] = array(
|
||||
'remove' => array('index' => $oldIndexName, 'alias' => $aliasName)
|
||||
);
|
||||
}
|
||||
|
||||
// add an action to point the alias to the new index
|
||||
$aliasUpdateRequest['actions'][] = array(
|
||||
'add' => array('index' => $newIndexName, 'alias' => $aliasName)
|
||||
);
|
||||
|
||||
try {
|
||||
$esIndex->getClient()->request('_aliases', 'POST', $aliasUpdateRequest);
|
||||
} catch (ExceptionInterface $renameAliasException) {
|
||||
$additionalError = '';
|
||||
// if we failed to move the alias, delete the newly built index
|
||||
try {
|
||||
$esIndex->delete();
|
||||
} catch (ExceptionInterface $deleteNewIndexException) {
|
||||
$additionalError = sprintf(
|
||||
'Tried to delete newly built index %s, but also failed: %s',
|
||||
$newIndexName,
|
||||
$deleteNewIndexException->getError()
|
||||
);
|
||||
}
|
||||
|
||||
throw new \RuntimeException(
|
||||
sprintf(
|
||||
'Failed to updated index alias: %s. %s',
|
||||
$renameAliasException->getMessage(),
|
||||
$additionalError ?: sprintf('Newly built index %s was deleted', $newIndexName)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Delete the old index after the alias has been switched
|
||||
if ($oldIndexName) {
|
||||
$oldIndex = new Index($esIndex->getClient(), $oldIndexName);
|
||||
try {
|
||||
$oldIndex->delete();
|
||||
} catch (ExceptionInterface $deleteOldIndexException) {
|
||||
throw new \RuntimeException(
|
||||
sprintf(
|
||||
'Failed to delete old index %s with message: %s',
|
||||
$oldIndexName,
|
||||
$deleteOldIndexException->getMessage()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns array of indexes which are mapped to given alias
|
||||
*
|
||||
* @param Index $esIndex ES Index
|
||||
* @param string $aliasName Alias name
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getAliasedIndexes(Index $esIndex, $aliasName)
|
||||
{
|
||||
$aliasesInfo = $esIndex->getClient()->request('_aliases', 'GET')->getData();
|
||||
$aliasedIndexes = array();
|
||||
|
||||
foreach ($aliasesInfo as $indexName => $indexInfo) {
|
||||
$aliases = array_keys($indexInfo['aliases']);
|
||||
if (in_array($aliasName, $aliases)) {
|
||||
$aliasedIndexes[] = $indexName;
|
||||
}
|
||||
}
|
||||
|
||||
return $aliasedIndexes;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,13 +25,13 @@ class RepositoryManager implements RepositoryManagerInterface
|
|||
|
||||
public function addEntity($entityName, FinderInterface $finder, $repositoryName = null)
|
||||
{
|
||||
$this->entities[$entityName] = array();
|
||||
$this->entities[$entityName]= array();
|
||||
$this->entities[$entityName]['finder'] = $finder;
|
||||
$this->entities[$entityName]['repositoryName'] = $repositoryName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return repository for entity.
|
||||
* Return repository for entity
|
||||
*
|
||||
* Returns custom repository if one specified otherwise
|
||||
* returns a basic repository.
|
||||
|
@ -59,20 +59,16 @@ class RepositoryManager implements RepositoryManagerInterface
|
|||
}
|
||||
|
||||
$refClass = new \ReflectionClass($entityName);
|
||||
$annotation = $this->reader->getClassAnnotation($refClass, 'FOS\\ElasticaBundle\\Annotation\\Search');
|
||||
$annotation = $this->reader->getClassAnnotation($refClass, 'FOS\\ElasticaBundle\\Configuration\\Search');
|
||||
if ($annotation) {
|
||||
$this->entities[$entityName]['repositoryName']
|
||||
= $annotation->repositoryClass;
|
||||
|
||||
return $annotation->repositoryClass;
|
||||
}
|
||||
|
||||
return 'FOS\ElasticaBundle\Repository';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $entityName
|
||||
*/
|
||||
private function createRepository($entityName)
|
||||
{
|
||||
if (!class_exists($repositoryName = $this->getRepositoryName($entityName))) {
|
||||
|
|
|
@ -12,6 +12,7 @@ use FOS\ElasticaBundle\Finder\FinderInterface;
|
|||
*/
|
||||
interface RepositoryManagerInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* Adds entity name and its finder.
|
||||
* Custom repository class name can also be added.
|
||||
|
@ -23,7 +24,7 @@ interface RepositoryManagerInterface
|
|||
public function addEntity($entityName, FinderInterface $finder, $repositoryName = null);
|
||||
|
||||
/**
|
||||
* Return repository for entity.
|
||||
* Return repository for entity
|
||||
*
|
||||
* Returns custom repository if one specified otherwise
|
||||
* returns a basic repository.
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Paginator;
|
||||
|
||||
use Pagerfanta\Adapter\AdapterInterface;
|
||||
|
||||
class FantaPaginatorAdapter implements AdapterInterface
|
||||
{
|
||||
private $adapter;
|
||||
|
||||
/**
|
||||
* @param \FOS\ElasticaBundle\Paginator\PaginatorAdapterInterface $adapter
|
||||
*/
|
||||
public function __construct(PaginatorAdapterInterface $adapter)
|
||||
{
|
||||
$this->adapter = $adapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of results.
|
||||
*
|
||||
* @return integer The number of results.
|
||||
*/
|
||||
public function getNbResults()
|
||||
{
|
||||
return $this->adapter->getTotalHits();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Facets.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getFacets()
|
||||
{
|
||||
return $this->adapter->getFacets();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Aggregations.
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getAggregations()
|
||||
{
|
||||
return $this->adapter->getAggregations();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a slice of the results.
|
||||
*
|
||||
* @param integer $offset The offset.
|
||||
* @param integer $length The length.
|
||||
*
|
||||
* @return array|\Traversable The slice.
|
||||
*/
|
||||
public function getSlice($offset, $length)
|
||||
{
|
||||
return $this->adapter->getResults($offset, $length)->toArray();
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Paginator;
|
||||
|
||||
interface PaginatorAdapterInterface
|
||||
{
|
||||
/**
|
||||
* Returns the number of results.
|
||||
*
|
||||
* @return integer The number of results.
|
||||
*/
|
||||
public function getTotalHits();
|
||||
|
||||
/**
|
||||
* Returns an slice of the results.
|
||||
*
|
||||
* @param integer $offset The offset.
|
||||
* @param integer $length The length.
|
||||
*
|
||||
* @return PartialResultsInterface
|
||||
*/
|
||||
public function getResults($offset, $length);
|
||||
|
||||
/**
|
||||
* Returns Facets.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getFacets();
|
||||
|
||||
/**
|
||||
* Returns Aggregations.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getAggregations();
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Paginator;
|
||||
|
||||
interface PartialResultsInterface
|
||||
{
|
||||
/**
|
||||
* Returns the paginated results.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray();
|
||||
|
||||
/**
|
||||
* Returns the number of results.
|
||||
*
|
||||
* @return integer The number of results.
|
||||
*/
|
||||
public function getTotalHits();
|
||||
|
||||
/**
|
||||
* Returns the facets.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getFacets();
|
||||
|
||||
/**
|
||||
* Returns the aggregations.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAggregations();
|
||||
}
|
|
@ -1,169 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Paginator;
|
||||
|
||||
use Elastica\SearchableInterface;
|
||||
use Elastica\Query;
|
||||
use Elastica\ResultSet;
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Allows pagination of Elastica\Query. Does not map results.
|
||||
*/
|
||||
class RawPaginatorAdapter implements PaginatorAdapterInterface
|
||||
{
|
||||
/**
|
||||
* @var SearchableInterface the object to search in
|
||||
*/
|
||||
private $searchable;
|
||||
|
||||
/**
|
||||
* @var Query the query to search
|
||||
*/
|
||||
private $query;
|
||||
|
||||
/**
|
||||
* @var array search options
|
||||
*/
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* @var integer the number of hits
|
||||
*/
|
||||
private $totalHits;
|
||||
|
||||
/**
|
||||
* @var array for the facets
|
||||
*/
|
||||
private $facets;
|
||||
|
||||
/**
|
||||
* @var array for the aggregations
|
||||
*/
|
||||
private $aggregations;
|
||||
|
||||
/**
|
||||
* @see PaginatorAdapterInterface::__construct
|
||||
*
|
||||
* @param SearchableInterface $searchable the object to search in
|
||||
* @param Query $query the query to search
|
||||
* @param array $options
|
||||
*/
|
||||
public function __construct(SearchableInterface $searchable, Query $query, array $options = array())
|
||||
{
|
||||
$this->searchable = $searchable;
|
||||
$this->query = $query;
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the paginated results.
|
||||
*
|
||||
* @param integer $offset
|
||||
* @param integer $itemCountPerPage
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return ResultSet
|
||||
*/
|
||||
protected function getElasticaResults($offset, $itemCountPerPage)
|
||||
{
|
||||
$offset = (integer) $offset;
|
||||
$itemCountPerPage = (integer) $itemCountPerPage;
|
||||
$size = $this->query->hasParam('size')
|
||||
? (integer) $this->query->getParam('size')
|
||||
: null;
|
||||
|
||||
if (null !== $size && $size < $offset + $itemCountPerPage) {
|
||||
$itemCountPerPage = $size - $offset;
|
||||
}
|
||||
|
||||
if ($itemCountPerPage < 1) {
|
||||
throw new InvalidArgumentException('$itemCountPerPage must be greater than zero');
|
||||
}
|
||||
|
||||
$query = clone $this->query;
|
||||
$query->setFrom($offset);
|
||||
$query->setSize($itemCountPerPage);
|
||||
|
||||
$resultSet = $this->searchable->search($query, $this->options);
|
||||
$this->totalHits = $resultSet->getTotalHits();
|
||||
$this->facets = $resultSet->getFacets();
|
||||
$this->aggregations = $resultSet->getAggregations();
|
||||
|
||||
return $resultSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the paginated results.
|
||||
*
|
||||
* @param int $offset
|
||||
* @param int $itemCountPerPage
|
||||
*
|
||||
* @return PartialResultsInterface
|
||||
*/
|
||||
public function getResults($offset, $itemCountPerPage)
|
||||
{
|
||||
return new RawPartialResults($this->getElasticaResults($offset, $itemCountPerPage));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of results.
|
||||
*
|
||||
* If genuineTotal is provided as true, total hits is returned from the
|
||||
* hits.total value from the search results instead of just returning
|
||||
* the requested size.
|
||||
*
|
||||
* @param boolean $genuineTotal
|
||||
*
|
||||
* @return integer The number of results.
|
||||
*/
|
||||
public function getTotalHits($genuineTotal = false)
|
||||
{
|
||||
if (! isset($this->totalHits)) {
|
||||
$this->totalHits = $this->searchable->count($this->query);
|
||||
}
|
||||
|
||||
return $this->query->hasParam('size') && !$genuineTotal
|
||||
? min($this->totalHits, (integer) $this->query->getParam('size'))
|
||||
: $this->totalHits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Facets.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getFacets()
|
||||
{
|
||||
if (! isset($this->facets)) {
|
||||
$this->facets = $this->searchable->search($this->query)->getFacets();
|
||||
}
|
||||
|
||||
return $this->facets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Aggregations.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getAggregations()
|
||||
{
|
||||
if (!isset($this->aggregations)) {
|
||||
$this->aggregations = $this->searchable->search($this->query)->getAggregations();
|
||||
}
|
||||
|
||||
return $this->aggregations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Query.
|
||||
*
|
||||
* @return Query the search query
|
||||
*/
|
||||
public function getQuery()
|
||||
{
|
||||
return $this->query;
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Paginator;
|
||||
|
||||
use Elastica\ResultSet;
|
||||
use Elastica\Result;
|
||||
|
||||
/**
|
||||
* Raw partial results transforms to a simple array.
|
||||
*/
|
||||
class RawPartialResults implements PartialResultsInterface
|
||||
{
|
||||
protected $resultSet;
|
||||
|
||||
/**
|
||||
* @param ResultSet $resultSet
|
||||
*/
|
||||
public function __construct(ResultSet $resultSet)
|
||||
{
|
||||
$this->resultSet = $resultSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
return array_map(function (Result $result) {
|
||||
return $result->getSource();
|
||||
}, $this->resultSet->getResults());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getTotalHits()
|
||||
{
|
||||
return $this->resultSet->getTotalHits();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getFacets()
|
||||
{
|
||||
if ($this->resultSet->hasFacets()) {
|
||||
return $this->resultSet->getFacets();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getAggregations()
|
||||
{
|
||||
if ($this->resultSet->hasAggregations()) {
|
||||
return $this->resultSet->getAggregations();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Paginator;
|
||||
|
||||
use FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface;
|
||||
use Elastica\SearchableInterface;
|
||||
use Elastica\Query;
|
||||
|
||||
/**
|
||||
* Allows pagination of \Elastica\Query.
|
||||
*/
|
||||
class TransformedPaginatorAdapter extends RawPaginatorAdapter
|
||||
{
|
||||
private $transformer;
|
||||
|
||||
/**
|
||||
* @param SearchableInterface $searchable the object to search in
|
||||
* @param Query $query the query to search
|
||||
* @param array $options
|
||||
* @param ElasticaToModelTransformerInterface $transformer the transformer for fetching the results
|
||||
*/
|
||||
public function __construct(SearchableInterface $searchable, Query $query, array $options = array(), ElasticaToModelTransformerInterface $transformer)
|
||||
{
|
||||
parent::__construct($searchable, $query, $options);
|
||||
|
||||
$this->transformer = $transformer;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getResults($offset, $length)
|
||||
{
|
||||
return new TransformedPartialResults($this->getElasticaResults($offset, $length), $this->transformer);
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Paginator;
|
||||
|
||||
use FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface;
|
||||
use Elastica\ResultSet;
|
||||
|
||||
/**
|
||||
* Partial transformed result set.
|
||||
*/
|
||||
class TransformedPartialResults extends RawPartialResults
|
||||
{
|
||||
protected $transformer;
|
||||
|
||||
/**
|
||||
* @param ResultSet $resultSet
|
||||
* @param \FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface $transformer
|
||||
*/
|
||||
public function __construct(ResultSet $resultSet, ElasticaToModelTransformerInterface $transformer)
|
||||
{
|
||||
parent::__construct($resultSet);
|
||||
|
||||
$this->transformer = $transformer;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
return $this->transformer->transform($this->resultSet->getResults());
|
||||
}
|
||||
}
|
|
@ -4,13 +4,14 @@ namespace FOS\ElasticaBundle\Persister;
|
|||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Elastica\Exception\BulkException;
|
||||
use Elastica\Exception\NotFoundException;
|
||||
use FOS\ElasticaBundle\Transformer\ModelToElasticaTransformerInterface;
|
||||
use Elastica\Type;
|
||||
use Elastica\Document;
|
||||
|
||||
/**
|
||||
* 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>
|
||||
*/
|
||||
|
@ -30,32 +31,17 @@ class ObjectPersister implements ObjectPersisterInterface
|
|||
$this->fields = $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the ObjectPersister handles a given object.
|
||||
*
|
||||
* @param object $object
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function handlesObject($object)
|
||||
{
|
||||
return $object instanceof $this->objectClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param LoggerInterface $logger
|
||||
*/
|
||||
public function setLogger(LoggerInterface $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
|
||||
*
|
||||
* @throws BulkException
|
||||
* @return null
|
||||
*/
|
||||
private function log(BulkException $e)
|
||||
{
|
||||
|
@ -68,47 +54,61 @@ class ObjectPersister implements ObjectPersisterInterface
|
|||
|
||||
/**
|
||||
* Insert one object into the type
|
||||
* The object will be transformed to an elastica document.
|
||||
* The object will be transformed to an elastica document
|
||||
*
|
||||
* @param object $object
|
||||
*/
|
||||
public function insertOne($object)
|
||||
{
|
||||
$this->insertMany(array($object));
|
||||
$document = $this->transformToElasticaDocument($object);
|
||||
$this->type->addDocument($document);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces one object in the type.
|
||||
* Replaces one object in the type
|
||||
*
|
||||
* @param object $object
|
||||
* @return null
|
||||
**/
|
||||
public function replaceOne($object)
|
||||
{
|
||||
$this->replaceMany(array($object));
|
||||
$document = $this->transformToElasticaDocument($object);
|
||||
try {
|
||||
$this->type->deleteById($document->getId());
|
||||
} catch (NotFoundException $e) {}
|
||||
$this->type->addDocument($document);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes one object in the type.
|
||||
* Deletes one object in the type
|
||||
*
|
||||
* @param object $object
|
||||
* @return null
|
||||
**/
|
||||
public function deleteOne($object)
|
||||
{
|
||||
$this->deleteMany(array($object));
|
||||
$document = $this->transformToElasticaDocument($object);
|
||||
try {
|
||||
$this->type->deleteById($document->getId());
|
||||
} catch (NotFoundException $e) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes one object in the type by id.
|
||||
* Deletes one object in the type by id
|
||||
*
|
||||
* @param mixed $id
|
||||
*
|
||||
* @return null
|
||||
**/
|
||||
public function deleteById($id)
|
||||
{
|
||||
$this->deleteManyByIdentifiers(array($id));
|
||||
try {
|
||||
$this->type->deleteById($id);
|
||||
} catch (NotFoundException $e) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bulk insert an array of objects in the type for the given method.
|
||||
* Bulk insert an array of objects in the type for the given method
|
||||
*
|
||||
* @param array $objects array of domain model objects
|
||||
* @param string Method to call
|
||||
|
@ -148,7 +148,7 @@ class ObjectPersister implements ObjectPersisterInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* Bulk deletes an array of objects in the type.
|
||||
* Bulk deletes an array of objects in the type
|
||||
*
|
||||
* @param array $objects array of domain model objects
|
||||
*/
|
||||
|
@ -166,7 +166,7 @@ class ObjectPersister implements ObjectPersisterInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* Bulk deletes records from an array of identifiers.
|
||||
* Bulk deletes records from an array of identifiers
|
||||
*
|
||||
* @param array $identifiers array of domain model object identifiers
|
||||
*/
|
||||
|
@ -180,10 +180,9 @@ class ObjectPersister implements ObjectPersisterInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* Transforms an object to an elastica document.
|
||||
* Transforms an object to an elastica document
|
||||
*
|
||||
* @param object $object
|
||||
*
|
||||
* @return Document the elastica document
|
||||
*/
|
||||
public function transformToElasticaDocument($object)
|
||||
|
|
|
@ -4,73 +4,66 @@ namespace FOS\ElasticaBundle\Persister;
|
|||
|
||||
/**
|
||||
* Inserts, replaces and deletes single documents in an elastica type
|
||||
* Accepts domain model objects and converts them to elastica documents.
|
||||
* Accepts domain model objects and converts them to elastica documents
|
||||
*
|
||||
* @author Thibault Duplessis <thibault.duplessis@gmail.com>
|
||||
*/
|
||||
interface ObjectPersisterInterface
|
||||
{
|
||||
/**
|
||||
* Checks if this persister can handle the given object or not.
|
||||
*
|
||||
* @param mixed $object
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function handlesObject($object);
|
||||
|
||||
/**
|
||||
* Insert one object into the type
|
||||
* The object will be transformed to an elastica document.
|
||||
* The object will be transformed to an elastica document
|
||||
*
|
||||
* @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
|
||||
**/
|
||||
public function replaceOne($object);
|
||||
function replaceOne($object);
|
||||
|
||||
/**
|
||||
* Deletes one object in the type.
|
||||
* Deletes one object in the type
|
||||
*
|
||||
* @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
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
|
|
|
@ -9,7 +9,7 @@ use FOS\ElasticaBundle\Transformer\ModelToElasticaTransformerInterface;
|
|||
/**
|
||||
* Inserts, replaces and deletes single objects in an elastica type, making use
|
||||
* of elastica's serializer support to convert objects in to elastica documents.
|
||||
* Accepts domain model objects and passes them directly to elastica.
|
||||
* Accepts domain model objects and passes them directly to elastica
|
||||
*
|
||||
* @author Lea Haensenberber <lea.haensenberger@gmail.com>
|
||||
*/
|
||||
|
@ -17,25 +17,17 @@ class ObjectSerializerPersister extends ObjectPersister
|
|||
{
|
||||
protected $serializer;
|
||||
|
||||
/**
|
||||
* @param Type $type
|
||||
* @param ModelToElasticaTransformerInterface $transformer
|
||||
* @param string $objectClass
|
||||
* @param callable $serializer
|
||||
*/
|
||||
public function __construct(Type $type, ModelToElasticaTransformerInterface $transformer, $objectClass, $serializer)
|
||||
{
|
||||
parent::__construct($type, $transformer, $objectClass, array());
|
||||
|
||||
$this->serializer = $serializer;
|
||||
$this->serializer = $serializer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms an object to an elastica document
|
||||
* with just the identifier set.
|
||||
* with just the identifier set
|
||||
*
|
||||
* @param object $object
|
||||
*
|
||||
* @return Document the elastica document
|
||||
*/
|
||||
public function transformToElasticaDocument($object)
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
namespace FOS\ElasticaBundle\Propel;
|
||||
|
||||
use FOS\ElasticaBundle\HybridResult;
|
||||
use FOS\ElasticaBundle\Transformer\AbstractElasticaToModelTransformer;
|
||||
use FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface;
|
||||
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
|
||||
|
||||
|
@ -15,7 +14,7 @@ use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
|
|||
*
|
||||
* @author William Durand <william.durand1@gmail.com>
|
||||
*/
|
||||
class ElasticaToModelTransformer extends AbstractElasticaToModelTransformer
|
||||
class ElasticaToModelTransformer implements ElasticaToModelTransformerInterface
|
||||
{
|
||||
/**
|
||||
* Propel model class to map to Elastica documents.
|
||||
|
@ -34,11 +33,18 @@ class ElasticaToModelTransformer extends AbstractElasticaToModelTransformer
|
|||
'identifier' => 'id',
|
||||
);
|
||||
|
||||
/**
|
||||
* PropertyAccessor instance.
|
||||
*
|
||||
* @var PropertyAccessorInterface
|
||||
*/
|
||||
protected $propertyAccessor;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $objectClass
|
||||
* @param array $options
|
||||
* @param array $options
|
||||
*/
|
||||
public function __construct($objectClass, array $options = array())
|
||||
{
|
||||
|
@ -46,12 +52,21 @@ class ElasticaToModelTransformer extends AbstractElasticaToModelTransformer
|
|||
$this->options = array_merge($this->options, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the PropertyAccessor instance.
|
||||
*
|
||||
* @param PropertyAccessorInterface $propertyAccessor
|
||||
*/
|
||||
public function setPropertyAccessor(PropertyAccessorInterface $propertyAccessor)
|
||||
{
|
||||
$this->propertyAccessor = $propertyAccessor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms an array of Elastica document into an array of Propel entities
|
||||
* fetched from the database.
|
||||
*
|
||||
* @param array $elasticaObjects
|
||||
*
|
||||
* @return array|\ArrayObject
|
||||
*/
|
||||
public function transform(array $elasticaObjects)
|
||||
|
@ -66,7 +81,11 @@ class ElasticaToModelTransformer extends AbstractElasticaToModelTransformer
|
|||
// Sort objects in the order of their IDs
|
||||
$idPos = array_flip($ids);
|
||||
$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)) {
|
||||
$objects->uasort($sortCallback);
|
||||
|
@ -85,7 +104,7 @@ class ElasticaToModelTransformer extends AbstractElasticaToModelTransformer
|
|||
$objects = $this->transform($elasticaObjects);
|
||||
|
||||
$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]);
|
||||
}
|
||||
|
||||
|
@ -116,7 +135,6 @@ class ElasticaToModelTransformer extends AbstractElasticaToModelTransformer
|
|||
*
|
||||
* @param array $identifierValues Identifier values
|
||||
* @param boolean $hydrate Whether or not to hydrate the results
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function findByIdentifiers(array $identifierValues, $hydrate)
|
||||
|
@ -127,7 +145,7 @@ class ElasticaToModelTransformer extends AbstractElasticaToModelTransformer
|
|||
|
||||
$query = $this->createQuery($this->objectClass, $this->options['identifier'], $identifierValues);
|
||||
|
||||
if (! $hydrate) {
|
||||
if ( ! $hydrate) {
|
||||
return $query->toArray();
|
||||
}
|
||||
|
||||
|
@ -140,7 +158,6 @@ class ElasticaToModelTransformer extends AbstractElasticaToModelTransformer
|
|||
* @param string $class Propel model class
|
||||
* @param string $identifierField Identifier field name (e.g. "id")
|
||||
* @param array $identifierValues Identifier values
|
||||
*
|
||||
* @return \ModelCriteria
|
||||
*/
|
||||
protected function createQuery($class, $identifierField, array $identifierValues)
|
||||
|
@ -153,8 +170,6 @@ class ElasticaToModelTransformer extends AbstractElasticaToModelTransformer
|
|||
|
||||
/**
|
||||
* @see https://github.com/doctrine/common/blob/master/lib/Doctrine/Common/Util/Inflector.php
|
||||
*
|
||||
* @param string $str
|
||||
*/
|
||||
private function camelize($str)
|
||||
{
|
||||
|
|
54
Propel/Lookup.php
Normal file
54
Propel/Lookup.php
Normal file
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Propel;
|
||||
|
||||
use Doctrine\Common\Util\Inflector;
|
||||
use FOS\ElasticaBundle\Type\LookupInterface;
|
||||
use FOS\ElasticaBundle\Type\TypeConfiguration;
|
||||
|
||||
class Lookup implements LookupInterface
|
||||
{
|
||||
/**
|
||||
* Returns the lookup key.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getKey()
|
||||
{
|
||||
return 'propel';
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up objects of a specific type with ids as supplied.
|
||||
*
|
||||
* @param TypeConfiguration $configuration
|
||||
* @param int[] $ids
|
||||
* @return object[]
|
||||
*/
|
||||
public function lookup(TypeConfiguration $configuration, array $ids)
|
||||
{
|
||||
$query = $this->createQuery($configuration, $ids);
|
||||
|
||||
if (!$configuration->isHydrate()) {
|
||||
return $query->toArray();
|
||||
}
|
||||
|
||||
return $query->find();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a query to use in the findByIdentifiers() method.
|
||||
*
|
||||
* @param TypeConfiguration $configuration
|
||||
* @param array $ids
|
||||
* @return \ModelCriteria
|
||||
*/
|
||||
protected function createQuery(TypeConfiguration $configuration, array $ids)
|
||||
{
|
||||
$queryClass = $configuration->getModelClass() . 'Query';
|
||||
$query = $queryClass::create();
|
||||
$filterMethod = 'filterBy' . Inflector::camelize($configuration->getIdentifierProperty());
|
||||
|
||||
return $query->$filterMethod($ids);
|
||||
}
|
||||
}
|
|
@ -5,69 +5,44 @@ namespace FOS\ElasticaBundle\Propel;
|
|||
use FOS\ElasticaBundle\Provider\AbstractProvider;
|
||||
|
||||
/**
|
||||
* Propel provider.
|
||||
* Propel provider
|
||||
*
|
||||
* @author William Durand <william.durand1@gmail.com>
|
||||
*/
|
||||
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();
|
||||
$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 += $options['batch_size']) {
|
||||
$objects = $queryClass::create()
|
||||
->limit($options['batch_size'])
|
||||
->offset($offset)
|
||||
->find()
|
||||
->getArrayCopy();
|
||||
$objects = $this->filterObjects($options, $objects);
|
||||
if (!empty($objects)) {
|
||||
$this->objectPersister->insertMany($objects);
|
||||
for (; $offset < $nbObjects; $offset += $batchSize) {
|
||||
if ($loggerClosure) {
|
||||
$stepStartTime = microtime(true);
|
||||
}
|
||||
|
||||
usleep($options['sleep']);
|
||||
$objects = $queryClass::create()
|
||||
->limit($batchSize)
|
||||
->offset($offset)
|
||||
->find();
|
||||
|
||||
$this->objectPersister->insertMany($objects->getArrayCopy());
|
||||
|
||||
usleep($sleep);
|
||||
|
||||
if ($loggerClosure) {
|
||||
$loggerClosure($options['batch_size'], $nbObjects);
|
||||
$stepNbObjects = count($objects);
|
||||
$stepCount = $stepNbObjects + $offset;
|
||||
$percentComplete = 100 * $stepCount / $nbObjects;
|
||||
$objectsPerSecond = $stepNbObjects / (microtime(true) - $stepStartTime);
|
||||
$loggerClosure(sprintf('%0.1f%% (%d/%d), %d objects/s %s', $percentComplete, $stepCount, $nbObjects, $objectsPerSecond, $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)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,17 +3,16 @@
|
|||
namespace FOS\ElasticaBundle\Provider;
|
||||
|
||||
use FOS\ElasticaBundle\Persister\ObjectPersisterInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
/**
|
||||
* AbstractProvider.
|
||||
* AbstractProvider
|
||||
*/
|
||||
abstract class AbstractProvider implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
* @var ObjectPersisterInterface
|
||||
*/
|
||||
protected $baseOptions;
|
||||
protected $objectPersister;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
|
@ -21,154 +20,29 @@ abstract class AbstractProvider implements ProviderInterface
|
|||
protected $objectClass;
|
||||
|
||||
/**
|
||||
* @var ObjectPersisterInterface
|
||||
* @var array
|
||||
*/
|
||||
protected $objectPersister;
|
||||
|
||||
/**
|
||||
* @var OptionsResolver
|
||||
*/
|
||||
protected $resolver;
|
||||
|
||||
/**
|
||||
* @var IndexableInterface
|
||||
*/
|
||||
private $indexable;
|
||||
protected $options;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param ObjectPersisterInterface $objectPersister
|
||||
* @param IndexableInterface $indexable
|
||||
* @param string $objectClass
|
||||
* @param array $baseOptions
|
||||
* @param array $options
|
||||
*/
|
||||
public function __construct(
|
||||
ObjectPersisterInterface $objectPersister,
|
||||
IndexableInterface $indexable,
|
||||
$objectClass,
|
||||
array $baseOptions = array()
|
||||
) {
|
||||
$this->baseOptions = $baseOptions;
|
||||
$this->indexable = $indexable;
|
||||
$this->objectClass = $objectClass;
|
||||
public function __construct(ObjectPersisterInterface $objectPersister, $objectClass, array $options = array())
|
||||
{
|
||||
$this->objectPersister = $objectPersister;
|
||||
$this->resolver = new OptionsResolver();
|
||||
$this->configureOptions();
|
||||
}
|
||||
$this->objectClass = $objectClass;
|
||||
|
||||
/**
|
||||
* {@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(
|
||||
$this->options = array_merge(array(
|
||||
'batch_size' => 100,
|
||||
'skip_indexable_check' => false,
|
||||
));
|
||||
$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;
|
||||
), $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given object should be indexed or not.
|
||||
*
|
||||
* @deprecated To be removed in 4.0
|
||||
*
|
||||
* @param object $object
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isObjectIndexable($object)
|
||||
{
|
||||
return $this->indexable->isObjectIndexable(
|
||||
$this->baseOptions['indexName'],
|
||||
$this->baseOptions['typeName'],
|
||||
$object
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get string with RAM usage information (current and peak).
|
||||
*
|
||||
* @deprecated To be removed in 4.0
|
||||
* Get string with RAM usage information (current and peak)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
|
@ -179,17 +53,4 @@ abstract class AbstractProvider implements ProviderInterface
|
|||
|
||||
return sprintf('(RAM : current=%uMo peak=%uMo)', $memory, $memoryMax);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges the base options provided by the class with options passed to the populate
|
||||
* method and runs them through the resolver.
|
||||
*
|
||||
* @param array $options
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function resolveOptions(array $options)
|
||||
{
|
||||
return $this->resolver->resolve(array_merge($this->baseOptions, $options));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,240 +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\Provider;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\ExpressionLanguage\Expression;
|
||||
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
|
||||
use Symfony\Component\ExpressionLanguage\SyntaxError;
|
||||
use Symfony\Component\PropertyAccess\PropertyAccess;
|
||||
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
|
||||
|
||||
class Indexable implements IndexableInterface
|
||||
{
|
||||
/**
|
||||
* An array of raw configured callbacks for all types.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $callbacks = array();
|
||||
|
||||
/**
|
||||
* @var \Symfony\Component\DependencyInjection\ContainerInterface
|
||||
*/
|
||||
private $container;
|
||||
|
||||
/**
|
||||
* An instance of ExpressionLanguage.
|
||||
*
|
||||
* @var ExpressionLanguage
|
||||
*/
|
||||
private $expressionLanguage;
|
||||
|
||||
/**
|
||||
* An array of initialised callbacks.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $initialisedCallbacks = array();
|
||||
|
||||
/**
|
||||
* PropertyAccessor instance.
|
||||
*
|
||||
* @var PropertyAccessorInterface
|
||||
*/
|
||||
private $propertyAccessor;
|
||||
|
||||
/**
|
||||
* @param array $callbacks
|
||||
* @param ContainerInterface $container
|
||||
*/
|
||||
public function __construct(array $callbacks, ContainerInterface $container)
|
||||
{
|
||||
$this->callbacks = $callbacks;
|
||||
$this->container = $container;
|
||||
$this->propertyAccessor = PropertyAccess::createPropertyAccessor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the object is indexable with respect to the callback.
|
||||
*
|
||||
* @param string $indexName
|
||||
* @param string $typeName
|
||||
* @param mixed $object
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isObjectIndexable($indexName, $typeName, $object)
|
||||
{
|
||||
$type = sprintf('%s/%s', $indexName, $typeName);
|
||||
$callback = $this->getCallback($type, $object);
|
||||
if (!$callback) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($callback instanceof Expression) {
|
||||
return (bool) $this->getExpressionLanguage()->evaluate($callback, array(
|
||||
'object' => $object,
|
||||
$this->getExpressionVar($object) => $object,
|
||||
));
|
||||
}
|
||||
|
||||
return is_string($callback)
|
||||
? call_user_func(array($object, $callback))
|
||||
: call_user_func($callback, $object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and initialises a callback.
|
||||
*
|
||||
* @param string $type
|
||||
* @param object $object
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function buildCallback($type, $object)
|
||||
{
|
||||
if (!array_key_exists($type, $this->callbacks)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$callback = $this->callbacks[$type];
|
||||
|
||||
if (is_callable($callback) or is_callable(array($object, $callback))) {
|
||||
return $callback;
|
||||
}
|
||||
|
||||
if (is_array($callback) && !is_object($callback[0])) {
|
||||
return $this->processArrayToCallback($type, $callback);
|
||||
}
|
||||
|
||||
if (is_string($callback)) {
|
||||
return $this->buildExpressionCallback($type, $object, $callback);
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(sprintf('Callback for type "%s" is not a valid callback.', $type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a string expression into an Expression.
|
||||
*
|
||||
* @param string $type
|
||||
* @param mixed $object
|
||||
* @param string $callback
|
||||
*
|
||||
* @return Expression
|
||||
*/
|
||||
private function buildExpressionCallback($type, $object, $callback)
|
||||
{
|
||||
$expression = $this->getExpressionLanguage();
|
||||
if (!$expression) {
|
||||
throw new \RuntimeException('Unable to process an expression without the ExpressionLanguage component.');
|
||||
}
|
||||
|
||||
try {
|
||||
$callback = new Expression($callback);
|
||||
$expression->compile($callback, array(
|
||||
'object', $this->getExpressionVar($object)
|
||||
));
|
||||
|
||||
return $callback;
|
||||
} catch (SyntaxError $e) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Callback for type "%s" is an invalid expression',
|
||||
$type
|
||||
), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retreives a cached callback, or creates a new callback if one is not found.
|
||||
*
|
||||
* @param string $type
|
||||
* @param object $object
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function getCallback($type, $object)
|
||||
{
|
||||
if (!array_key_exists($type, $this->initialisedCallbacks)) {
|
||||
$this->initialisedCallbacks[$type] = $this->buildCallback($type, $object);
|
||||
}
|
||||
|
||||
return $this->initialisedCallbacks[$type];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ExpressionLanguage class if it is available.
|
||||
*
|
||||
* @return ExpressionLanguage|null
|
||||
*/
|
||||
private function getExpressionLanguage()
|
||||
{
|
||||
if (null === $this->expressionLanguage && class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) {
|
||||
$this->expressionLanguage = new ExpressionLanguage();
|
||||
}
|
||||
|
||||
return $this->expressionLanguage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the variable name to be used to access the object when using the ExpressionLanguage
|
||||
* component to parse and evaluate an expression.
|
||||
*
|
||||
* @param mixed $object
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getExpressionVar($object = null)
|
||||
{
|
||||
if (!is_object($object)) {
|
||||
return 'object';
|
||||
}
|
||||
|
||||
$ref = new \ReflectionClass($object);
|
||||
|
||||
return strtolower($ref->getShortName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes an array into a callback. Replaces the first element with a service if
|
||||
* it begins with an @.
|
||||
*
|
||||
* @param string $type
|
||||
* @param array $callback
|
||||
* @return array
|
||||
*/
|
||||
private function processArrayToCallback($type, array $callback)
|
||||
{
|
||||
list($class, $method) = $callback + array(null, '__invoke');
|
||||
|
||||
if (strpos($class, '@') === 0) {
|
||||
$service = $this->container->get(substr($class, 1));
|
||||
$callback = array($service, $method);
|
||||
|
||||
if (!is_callable($callback)) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Method "%s" on service "%s" is not callable.',
|
||||
$method,
|
||||
substr($class, 1)
|
||||
));
|
||||
}
|
||||
|
||||
return $callback;
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Unable to parse callback array for type "%s"',
|
||||
$type
|
||||
));
|
||||
}
|
||||
}
|
|
@ -1,26 +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\Provider;
|
||||
|
||||
interface IndexableInterface
|
||||
{
|
||||
/**
|
||||
* Checks if an object passed should be indexable or not.
|
||||
*
|
||||
* @param string $indexName
|
||||
* @param string $typeName
|
||||
* @param mixed $object
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isObjectIndexable($indexName, $typeName, $object);
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
namespace FOS\ElasticaBundle\Provider;
|
||||
|
||||
/**
|
||||
* Insert application domain objects into elastica types.
|
||||
* Insert application domain objects into elastica types
|
||||
*
|
||||
* @author Thibault Duplessis <thibault.duplessis@gmail.com>
|
||||
*/
|
||||
|
@ -12,15 +12,9 @@ interface ProviderInterface
|
|||
/**
|
||||
* Persists all domain objects to ElasticSearch for this provider.
|
||||
*
|
||||
* The closure can expect 2 or 3 arguments:
|
||||
* * The step size
|
||||
* * The total number of objects
|
||||
* * A message to output in error conditions (not normally provided)
|
||||
*
|
||||
* @param \Closure $loggerClosure
|
||||
* @param array $options
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public function populate(\Closure $loggerClosure = null, array $options = array());
|
||||
function populate(\Closure $loggerClosure = null, array $options = array());
|
||||
}
|
||||
|
|
|
@ -57,10 +57,8 @@ class ProviderRegistry implements ContainerAwareInterface
|
|||
*
|
||||
* Providers will be indexed by "type" strings in the returned array.
|
||||
*
|
||||
* @param string $index
|
||||
*
|
||||
* @return ProviderInterface[]
|
||||
*
|
||||
* @param string $index
|
||||
* @return array of ProviderInterface instances
|
||||
* @throws \InvalidArgumentException if no providers were registered for the index
|
||||
*/
|
||||
public function getIndexProviders($index)
|
||||
|
@ -83,9 +81,7 @@ class ProviderRegistry implements ContainerAwareInterface
|
|||
*
|
||||
* @param string $index
|
||||
* @param string $type
|
||||
*
|
||||
* @return ProviderInterface
|
||||
*
|
||||
* @throws \InvalidArgumentException if no provider was registered for the index and type
|
||||
*/
|
||||
public function getProvider($index, $type)
|
||||
|
|
|
@ -10,17 +10,16 @@ Symfony2. Features include:
|
|||
|
||||
> **Note** Propel support is limited and contributions fixing issues are welcome!
|
||||
|
||||
[![Build Status](https://secure.travis-ci.org/FriendsOfSymfony/FOSElasticaBundle.png?branch=master)](http://travis-ci.org/FriendsOfSymfony/FOSElasticaBundle) [![Total Downloads](https://poser.pugx.org/FriendsOfSymfony/elastica-bundle/downloads.png)](https://packagist.org/packages/FriendsOfSymfony/elastica-bundle) [![Latest Stable Version](https://poser.pugx.org/FriendsOfSymfony/elastica-bundle/v/stable.png)](https://packagist.org/packages/FriendsOfSymfony/elastica-bundle) [![Latest Unstable Version](https://poser.pugx.org/friendsofsymfony/elastica-bundle/v/unstable.svg)](https://packagist.org/packages/friendsofsymfony/elastica-bundle)
|
||||
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/FriendsOfSymfony/FOSElasticaBundle/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/FriendsOfSymfony/FOSElasticaBundle/?branch=master)
|
||||
[![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)
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
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
|
||||
------------
|
||||
|
|
|
@ -19,47 +19,21 @@ class Repository
|
|||
$this->finder = $finder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $query
|
||||
* @param integer $limit
|
||||
* @param array $options
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function find($query, $limit = null, $options = array())
|
||||
{
|
||||
return $this->finder->find($query, $limit, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $query
|
||||
* @param integer $limit
|
||||
* @param array $options
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function findHybrid($query, $limit = null, $options = array())
|
||||
{
|
||||
return $this->finder->findHybrid($query, $limit, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $query
|
||||
* @param array $options
|
||||
*
|
||||
* @return \Pagerfanta\Pagerfanta
|
||||
*/
|
||||
public function findPaginated($query, $options = array())
|
||||
{
|
||||
return $this->finder->findPaginated($query, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $query
|
||||
* @param array $options
|
||||
*
|
||||
* @return Paginator\PaginatorAdapterInterface
|
||||
*/
|
||||
public function createPaginatorAdapter($query, $options = array())
|
||||
{
|
||||
return $this->finder->createPaginatorAdapter($query, $options);
|
||||
|
|
|
@ -5,7 +5,7 @@ namespace FOS\ElasticaBundle;
|
|||
use FOS\ElasticaBundle\Index\Resetter as BaseResetter;
|
||||
|
||||
/**
|
||||
* @deprecated Use \FOS\ElasticaBundle\Index\Resetter
|
||||
* Deletes and recreates indexes
|
||||
*/
|
||||
class Resetter extends BaseResetter
|
||||
{
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<container xmlns="http://symfony.com/schema/dic/services"
|
||||
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">
|
||||
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">
|
||||
|
||||
<parameters>
|
||||
<parameter key="fos_elastica.client.class">FOS\ElasticaBundle\Elastica\Client</parameter>
|
||||
<parameter key="fos_elastica.client.class">FOS\ElasticaBundle\Elastica\LoggingClient</parameter>
|
||||
<parameter key="fos_elastica.logger.class">FOS\ElasticaBundle\Logger\ElasticaLogger</parameter>
|
||||
<parameter key="fos_elastica.data_collector.class">FOS\ElasticaBundle\DataCollector\ElasticaDataCollector</parameter>
|
||||
<parameter key="fos_elastica.mapping_builder.class">FOS\ElasticaBundle\Index\MappingBuilder</parameter>
|
||||
<parameter key="fos_elastica.property_accessor.class">Symfony\Component\PropertyAccess\PropertyAccessor</parameter>
|
||||
</parameters>
|
||||
|
||||
|
@ -16,26 +15,7 @@
|
|||
<service id="fos_elastica.client_prototype" class="%fos_elastica.client.class%" abstract="true">
|
||||
<argument type="collection" /> <!-- configuration -->
|
||||
<argument /> <!-- callback -->
|
||||
|
||||
<call method="setStopwatch">
|
||||
<argument type="service" id="debug.stopwatch" on-invalid="null" />
|
||||
</call>
|
||||
</service>
|
||||
|
||||
<service id="fos_elastica.config_manager" class="FOS\ElasticaBundle\Configuration\ConfigManager">
|
||||
<argument type="collection" /> <!-- collection of SourceInterface services -->
|
||||
</service>
|
||||
|
||||
<service id="fos_elastica.data_collector" class="%fos_elastica.data_collector.class%">
|
||||
<tag name="data_collector" template="FOSElasticaBundle:Collector:elastica" id="elastica" />
|
||||
<argument type="service" id="fos_elastica.logger" />
|
||||
</service>
|
||||
|
||||
<service id="fos_elastica.paginator.subscriber" class="FOS\ElasticaBundle\Subscriber\PaginateElasticaQuerySubscriber">
|
||||
<call method="setRequest">
|
||||
<argument type="service" id="request" on-invalid="null" strict="false" />
|
||||
</call>
|
||||
<tag name="knp_paginator.subscriber" />
|
||||
<argument type="service" id="fos_elastica.transformer.combined" />
|
||||
</service>
|
||||
|
||||
<service id="fos_elastica.logger" class="%fos_elastica.logger.class%">
|
||||
|
@ -44,7 +24,10 @@
|
|||
<tag name="monolog.logger" channel="elastica" />
|
||||
</service>
|
||||
|
||||
<service id="fos_elastica.mapping_builder" class="%fos_elastica.mapping_builder.class%" />
|
||||
<service id="fos_elastica.data_collector" class="%fos_elastica.data_collector.class%" public="true">
|
||||
<tag name="data_collector" template="FOSElasticaBundle:Collector:elastica" id="elastica" />
|
||||
<argument type="service" id="fos_elastica.logger" />
|
||||
</service>
|
||||
|
||||
<service id="fos_elastica.property_accessor" class="%fos_elastica.property_accessor.class%" />
|
||||
</services>
|
||||
|
|
|
@ -5,43 +5,25 @@
|
|||
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
|
||||
|
||||
<parameters>
|
||||
<parameter key="fos_elastica.alias_processor.class">FOS\ElasticaBundle\Index\AliasProcessor</parameter>
|
||||
<parameter key="fos_elastica.finder.class">FOS\ElasticaBundle\Finder\TransformedFinder</parameter>
|
||||
<parameter key="fos_elastica.index.class">FOS\ElasticaBundle\Elastica\Index</parameter>
|
||||
<parameter key="fos_elastica.indexable.class">FOS\ElasticaBundle\Provider\Indexable</parameter>
|
||||
<parameter key="fos_elastica.index_manager.class">FOS\ElasticaBundle\Index\IndexManager</parameter>
|
||||
<parameter key="fos_elastica.resetter.class">FOS\ElasticaBundle\Index\Resetter</parameter>
|
||||
<parameter key="fos_elastica.index.class">FOS\ElasticaBundle\Elastica\TransformingIndex</parameter>
|
||||
<parameter key="fos_elastica.type.class">Elastica\Type</parameter>
|
||||
<parameter key="fos_elastica.index_manager.class">FOS\ElasticaBundle\IndexManager</parameter>
|
||||
<parameter key="fos_elastica.resetter.class">FOS\ElasticaBundle\Resetter</parameter>
|
||||
<parameter key="fos_elastica.finder.class">FOS\ElasticaBundle\Finder\TransformedFinder</parameter>
|
||||
</parameters>
|
||||
|
||||
<services>
|
||||
<service id="fos_elastica.alias_processor" class="%fos_elastica.alias_processor.class%" />
|
||||
|
||||
<service id="fos_elastica.indexable" class="%fos_elastica.indexable.class%">
|
||||
<argument type="collection" /> <!-- array of indexable callbacks keyed by type name -->
|
||||
<argument type="service" id="service_container" />
|
||||
</service>
|
||||
|
||||
<service id="fos_elastica.index_prototype" class="%fos_elastica.index.class%" factory-service="fos_elastica.client" factory-method="getIndex" abstract="true">
|
||||
<service id="fos_elastica.index_prototype" factory-service="fos_elastica.client" factory-method="getIndex" abstract="true">
|
||||
<argument /> <!-- index name -->
|
||||
<!-- tagged with fos_elastica.index in the Extension -->
|
||||
</service>
|
||||
|
||||
<service id="fos_elastica.type_prototype" class="%fos_elastica.type.class%" factory-method="getType" abstract="true">
|
||||
<argument /> <!-- type name -->
|
||||
</service>
|
||||
|
||||
<service id="fos_elastica.index_manager" class="%fos_elastica.index_manager.class%">
|
||||
<argument /> <!-- indexes -->
|
||||
<argument type="service" id="fos_elastica.index" /> <!-- default index -->
|
||||
<argument /> <!-- default index -->
|
||||
</service>
|
||||
|
||||
<service id="fos_elastica.resetter" class="%fos_elastica.resetter.class%">
|
||||
<argument type="service" id="fos_elastica.config_manager" />
|
||||
<argument type="service" id="fos_elastica.index_manager" />
|
||||
<argument type="service" id="fos_elastica.alias_processor" />
|
||||
<argument type="service" id="fos_elastica.mapping_builder" />
|
||||
<argument type="service" id="event_dispatcher"/>
|
||||
<argument /> <!-- index configs -->
|
||||
</service>
|
||||
|
||||
<!-- Abstract definition for all finders. -->
|
||||
|
|
|
@ -4,35 +4,23 @@
|
|||
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">
|
||||
|
||||
<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>
|
||||
<service id="fos_elastica.slice_fetcher.mongodb" class="%fos_elastica.slice_fetcher.mongodb.class%">
|
||||
</service>
|
||||
|
||||
<service id="fos_elastica.provider.prototype.mongodb" class="%fos_elastica.provider.prototype.mongodb.class%" public="true" abstract="true">
|
||||
<service id="fos_elastica.provider.prototype.mongodb" class="FOS\ElasticaBundle\Doctrine\MongoDB\Provider" public="true" abstract="true">
|
||||
<argument /> <!-- object persister -->
|
||||
<argument type="service" id="fos_elastica.indexable" />
|
||||
<argument /> <!-- model -->
|
||||
<argument type="collection" /> <!-- options -->
|
||||
<argument type="service" id="doctrine_mongodb" /> <!-- manager registry -->
|
||||
<argument type="service" id="fos_elastica.slice_fetcher.mongodb" /> <!-- slice fetcher -->
|
||||
<argument type="service" id="doctrine_mongodb" />
|
||||
</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">
|
||||
<argument /> <!-- object persister -->
|
||||
<argument type="service" id="fos_elastica.indexable" />
|
||||
<argument type="collection" /> <!-- configuration -->
|
||||
<argument>null</argument> <!-- logger -->
|
||||
<argument /> <!-- model -->
|
||||
<argument type="collection" /> <!-- events -->
|
||||
<argument/> <!-- identifier -->
|
||||
</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">
|
||||
<argument type="service" id="doctrine_mongodb" />
|
||||
<argument /> <!-- model -->
|
||||
<argument type="collection" /> <!-- options -->
|
||||
|
@ -41,9 +29,11 @@
|
|||
</call>
|
||||
</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="annotation_reader"/>
|
||||
</service>
|
||||
|
||||
</services>
|
||||
|
||||
</container>
|
||||
|
|
|
@ -1,38 +1,27 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<container xmlns="http://symfony.com/schema/dic/services"
|
||||
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">
|
||||
|
||||
<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>
|
||||
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">
|
||||
|
||||
<services>
|
||||
<service id="fos_elastica.slice_fetcher.orm" class="%fos_elastica.slice_fetcher.orm.class%">
|
||||
</service>
|
||||
|
||||
<service id="fos_elastica.provider.prototype.orm" class="%fos_elastica.provider.prototype.orm.class%" public="true" abstract="true">
|
||||
<service id="fos_elastica.provider.prototype.orm" class="FOS\ElasticaBundle\Doctrine\ORM\Provider" public="true" abstract="true">
|
||||
<argument /> <!-- object persister -->
|
||||
<argument type="service" id="fos_elastica.indexable" />
|
||||
<argument /> <!-- model -->
|
||||
<argument type="collection" /> <!-- options -->
|
||||
<argument type="service" id="doctrine" /> <!-- manager registry -->
|
||||
<argument type="service" id="fos_elastica.slice_fetcher.orm" /> <!-- slice fetcher -->
|
||||
<argument type="service" id="doctrine" />
|
||||
</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">
|
||||
<argument /> <!-- object persister -->
|
||||
<argument type="service" id="fos_elastica.indexable" />
|
||||
<argument type="collection" /> <!-- configuration -->
|
||||
<argument>null</argument> <!-- logger -->
|
||||
<argument /> <!-- model -->
|
||||
<argument type="collection" /> <!-- events -->
|
||||
<argument/> <!-- identifier -->
|
||||
<argument /> <!-- check method -->
|
||||
</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">
|
||||
<argument type="service" id="doctrine" />
|
||||
<argument /> <!-- model -->
|
||||
<argument type="collection" /> <!-- options -->
|
||||
|
@ -41,9 +30,11 @@
|
|||
</call>
|
||||
</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="annotation_reader" />
|
||||
</service>
|
||||
|
||||
</services>
|
||||
|
||||
</container>
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
|
||||
|
||||
<services>
|
||||
|
||||
<service id="fos_elastica.provider.prototype.propel" class="FOS\ElasticaBundle\Propel\Provider" public="true" abstract="true">
|
||||
<argument /> <!-- object persister -->
|
||||
<argument type="service" id="fos_elastica.indexable" />
|
||||
<argument /> <!-- model -->
|
||||
<argument type="collection" /> <!-- options -->
|
||||
</service>
|
||||
|
@ -19,8 +19,10 @@
|
|||
</call>
|
||||
</service>
|
||||
|
||||
<service id="fos_elastica.manager.propel" class="FOS\ElasticaBundle\Doctrine\RepositoryManager">
|
||||
<service id="fos_elastica.manager.propel" class="%fos_elastica.manager.class%">
|
||||
<argument type="service" id="annotation_reader"/>
|
||||
</service>
|
||||
|
||||
</services>
|
||||
|
||||
</container>
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<container xmlns="http://symfony.com/schema/dic/services"
|
||||
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">
|
||||
|
||||
<services>
|
||||
<service id="fos_elastica.serializer_callback_prototype" public="false" abstract="true">
|
||||
<call method="setSerializer">
|
||||
<argument type="service" id="fos_elastica.serializer" />
|
||||
</call>
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
|
@ -1,13 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<container xmlns="http://symfony.com/schema/dic/services"
|
||||
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">
|
||||
|
||||
<services>
|
||||
<service id="fos_elastica.config_source.container" class="FOS\ElasticaBundle\Configuration\Source\ContainerSource" public="false">
|
||||
<argument type="collection" /> <!-- index configs -->
|
||||
<tag name="fos_elastica.config_source" />
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
|
@ -12,15 +12,14 @@
|
|||
|
||||
<services>
|
||||
<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="service" id="event_dispatcher" /> <!-- options -->
|
||||
<argument /> <!-- options -->
|
||||
<call method="setPropertyAccessor">
|
||||
<argument type="service" id="fos_elastica.property_accessor" />
|
||||
</call>
|
||||
</service>
|
||||
|
||||
<service id="fos_elastica.model_to_elastica_identifier_transformer" class="%fos_elastica.model_to_elastica_identifier_transformer.class%" public="false" abstract="true">
|
||||
<argument type="collection" /> <!-- options -->
|
||||
<argument /> <!-- options -->
|
||||
<call method="setPropertyAccessor">
|
||||
<argument type="service" id="fos_elastica.property_accessor" />
|
||||
</call>
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
Aliased Indexes
|
||||
===============
|
||||
|
||||
You can set up FOSElasticaBundle to use aliases for indexes which allows you to run an
|
||||
index population without resetting the index currently being used by the application.
|
||||
|
||||
> *Note*: When you're using an alias, resetting an individual type will still cause a
|
||||
> reset for that type.
|
||||
|
||||
To configure FOSElasticaBundle to use aliases for an index, set the use_alias option to
|
||||
true.
|
||||
|
||||
```yaml
|
||||
fos_elastica:
|
||||
indexes:
|
||||
website:
|
||||
use_alias: true
|
||||
```
|
||||
|
||||
The process for setting up aliases on an existing application is slightly more complicated
|
||||
because the bundle is not able to set an alias as the same name as an index. You have some
|
||||
options on how to handle this:
|
||||
|
||||
1) Delete the index from Elasticsearch. This option will make searching unavailable in your
|
||||
application until a population has completed itself, and an alias is created.
|
||||
|
||||
2) Change the index_name parameter for your index to something new, and manually alias the
|
||||
current index to the new index_name, which will then be replaced when you run a repopulate.
|
||||
|
||||
```yaml
|
||||
fos_elastica:
|
||||
indexes:
|
||||
website:
|
||||
use_alias: true
|
||||
index_name: website_prod
|
||||
```
|
||||
|
||||
```bash
|
||||
$ curl -XPOST 'http://localhost:9200/_aliases' -d '
|
||||
{
|
||||
"actions" : [
|
||||
{ "add" : { "index" : "website", "alias" : "website_prod" } }
|
||||
]
|
||||
}'
|
||||
```
|
|
@ -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',
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
|
@ -4,7 +4,7 @@ As well as the default repository you can create a custom repository for an enti
|
|||
methods for particular searches. These need to extend `FOS\ElasticaBundle\Repository` to have
|
||||
access to the finder:
|
||||
|
||||
```php
|
||||
```
|
||||
<?php
|
||||
|
||||
namespace Acme\ElasticaBundle\SearchRepository;
|
||||
|
@ -23,46 +23,42 @@ class UserRepository extends Repository
|
|||
|
||||
To use the custom repository specify it in the mapping for the entity:
|
||||
|
||||
```yaml
|
||||
fos_elastica:
|
||||
clients:
|
||||
default: { host: localhost, port: 9200 }
|
||||
indexes:
|
||||
website:
|
||||
client: default
|
||||
types:
|
||||
user:
|
||||
mappings:
|
||||
# your mappings
|
||||
persistence:
|
||||
driver: orm
|
||||
model: Application\UserBundle\Entity\User
|
||||
provider: ~
|
||||
finder: ~
|
||||
repository: Acme\ElasticaBundle\SearchRepository\UserRepository
|
||||
```
|
||||
fos_elastica:
|
||||
clients:
|
||||
default: { host: localhost, port: 9200 }
|
||||
indexes:
|
||||
website:
|
||||
client: default
|
||||
types:
|
||||
user:
|
||||
mappings:
|
||||
# your mappings
|
||||
persistence:
|
||||
driver: orm
|
||||
model: Application\UserBundle\Entity\User
|
||||
provider: ~
|
||||
finder: ~
|
||||
repository: Acme\ElasticaBundle\SearchRepository\UserRepository
|
||||
|
||||
Then the custom queries will be available when using the repository returned from the manager:
|
||||
|
||||
```php
|
||||
/** var FOS\ElasticaBundle\Manager\RepositoryManager */
|
||||
$repositoryManager = $container->get('fos_elastica.manager');
|
||||
/** var FOS\ElasticaBundle\Manager\RepositoryManager */
|
||||
$repositoryManager = $container->get('fos_elastica.manager');
|
||||
|
||||
/** var FOS\ElasticaBundle\Repository */
|
||||
$repository = $repositoryManager->getRepository('UserBundle:User');
|
||||
/** var FOS\ElasticaBundle\Repository */
|
||||
$repository = $repositoryManager->getRepository('UserBundle:User');
|
||||
|
||||
/** var array of Acme\UserBundle\Entity\User */
|
||||
$users = $repository->findWithCustomQuery('bob');
|
||||
```
|
||||
/** var array of Acme\UserBundle\Entity\User */
|
||||
$users = $repository->findWithCustomQuery('bob');
|
||||
|
||||
Alternatively you can specify the custom repository using an annotation in the entity:
|
||||
|
||||
```php
|
||||
```
|
||||
<?php
|
||||
|
||||
namespace Application\UserBundle\Entity;
|
||||
|
||||
use FOS\ElasticaBundle\Annotation\Search;
|
||||
use FOS\ElasticaBundle\Configuration\Search;
|
||||
|
||||
/**
|
||||
* @Search(repositoryClass="Acme\ElasticaBundle\SearchRepository\UserRepository")
|
||||
|
@ -73,4 +69,4 @@ class User
|
|||
//---
|
||||
|
||||
}
|
||||
```
|
||||
```
|
|
@ -8,7 +8,7 @@ index and type for which the service will provide.
|
|||
# app/config/config.yml
|
||||
services:
|
||||
acme.search_provider.user:
|
||||
class: Acme\UserBundle\Provider\UserProvider
|
||||
class: Acme\UserBundle\Search\UserProvider
|
||||
arguments:
|
||||
- @fos_elastica.index.website.user
|
||||
tags:
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue