Compare commits
3 commits
Author | SHA1 | Date | |
---|---|---|---|
7d06cc429b | |||
15d3f1e4f8 | |||
4c961a757d |
|
@ -12,7 +12,19 @@ https://github.com/FriendsOfSymfony/FOSElasticaBundle/compare/v3.0.0...v3.0.1
|
|||
To generate a changelog summary since the last version, run
|
||||
`git log --no-merges --oneline v3.0.0...3.0.x`
|
||||
|
||||
* 3.0.0-ALPHA3 (xxxx-xx-xx)
|
||||
* 3.0.0
|
||||
|
||||
* Deprecated FOS\ElasticaBundle\Client in favour of FOS\ElasticaBundle\Elastica\LoggingClient
|
||||
* Deprecated FOS\ElasticaBundle\DynamicIndex in favour of FOS\ElasticaBundle\Elastica\TransformingIndex
|
||||
* Deprecated FOS\ElasticaBundle\IndexManager in favour of FOS\ElasticaBundle\Index\IndexManager
|
||||
* Deprecated FOS\ElasticaBundle\Resetter in favour of FOS\ElasticaBundle\Index\Resetter
|
||||
|
||||
* 3.0.0-ALPHA4 (2014-04-10)
|
||||
|
||||
* Indexes are now capable of logging errors with Elastica
|
||||
* Fixed deferred indexing of deleted documents
|
||||
|
||||
* 3.0.0-ALPHA3 (2014-04-01)
|
||||
|
||||
* a9c4c93: Logger is now only enabled in debug mode by default
|
||||
* #463: allowing hot swappable reindexing
|
||||
|
|
38
Client.php
38
Client.php
|
@ -2,43 +2,11 @@
|
|||
|
||||
namespace FOS\ElasticaBundle;
|
||||
|
||||
use Elastica\Client as ElasticaClient;
|
||||
use Elastica\Request;
|
||||
use FOS\ElasticaBundle\Logger\ElasticaLogger;
|
||||
use FOS\ElasticaBundle\Elastica\LoggingClient;
|
||||
|
||||
/**
|
||||
* @author Gordon Franke <info@nevalon.de>
|
||||
* @deprecated Use \FOS\ElasticaBundle\Elastica\LoggingClient
|
||||
*/
|
||||
class Client extends ElasticaClient
|
||||
class Client extends LoggingClient
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function request($path, $method = Request::GET, $data = array(), array $query = array())
|
||||
{
|
||||
$start = microtime(true);
|
||||
$response = parent::request($path, $method, $data, $query);
|
||||
|
||||
if (null !== $this->_logger and $this->_logger instanceof ElasticaLogger) {
|
||||
$time = microtime(true) - $start;
|
||||
|
||||
$connection = $this->getLastRequest()->getConnection();
|
||||
|
||||
$connection_array = array(
|
||||
'host' => $connection->getHost(),
|
||||
'port' => $connection->getPort(),
|
||||
'transport' => $connection->getTransport(),
|
||||
'headers' => $connection->getConfig('headers'),
|
||||
);
|
||||
|
||||
$this->_logger->logQuery($path, $method, $data, $time, $connection_array, $query);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function getIndex($name)
|
||||
{
|
||||
return new DynamicIndex($this, $name);
|
||||
}
|
||||
}
|
||||
|
|
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);
|
||||
}
|
||||
}
|
|
@ -4,7 +4,6 @@ namespace FOS\ElasticaBundle\DependencyInjection;
|
|||
|
||||
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
||||
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
|
||||
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\DefinitionDecorator;
|
||||
|
@ -14,6 +13,13 @@ use InvalidArgumentException;
|
|||
|
||||
class FOSElasticaExtension extends Extension
|
||||
{
|
||||
/**
|
||||
* Stores references to all defined clients loaded by the extension.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $clients = array();
|
||||
|
||||
protected $indexConfigs = array();
|
||||
protected $typeFields = array();
|
||||
protected $loadedDrivers = array();
|
||||
|
@ -21,9 +27,7 @@ class FOSElasticaExtension extends Extension
|
|||
|
||||
public function load(array $configs, ContainerBuilder $container)
|
||||
{
|
||||
$configuration = $this->getConfiguration($configs, $container);
|
||||
$config = $this->processConfiguration($configuration, $configs);
|
||||
|
||||
$config = $this->processConfiguration(new Configuration($configs, $container), $configs);
|
||||
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
|
||||
|
||||
if (empty($config['clients']) || empty($config['indexes'])) {
|
||||
|
@ -43,25 +47,19 @@ class FOSElasticaExtension extends Extension
|
|||
$config['default_index'] = reset($keys);
|
||||
}
|
||||
|
||||
$clientIdsByName = $this->loadClients($config['clients'], $container);
|
||||
$this->serializerConfig = isset($config['serializer']) ? $config['serializer'] : null;
|
||||
$indexIdsByName = $this->loadIndexes($config['indexes'], $container, $clientIdsByName, $config['default_client']);
|
||||
$indexRefsByName = array_map(function($id) {
|
||||
return new Reference($id);
|
||||
}, $indexIdsByName);
|
||||
|
||||
$this->loadIndexManager($indexRefsByName, $container);
|
||||
$this->loadResetter($this->indexConfigs, $container);
|
||||
|
||||
$this->loadClients($config['clients'], $container);
|
||||
$container->setAlias('fos_elastica.client', sprintf('fos_elastica.client.%s', $config['default_client']));
|
||||
|
||||
// XX serializer can be done better....
|
||||
// $this->serializerConfig = isset($config['serializer']) ? $config['serializer'] : null;
|
||||
|
||||
$this->loadIndexes($config['indexes'], $container);
|
||||
$container->setAlias('fos_elastica.index', sprintf('fos_elastica.index.%s', $config['default_index']));
|
||||
|
||||
$this->createDefaultManagerAlias($config['default_manager'], $container);
|
||||
}
|
||||
$this->loadIndexManager($container);
|
||||
$this->loadResetter($container);
|
||||
|
||||
public function getConfiguration(array $config, ContainerBuilder $container)
|
||||
{
|
||||
return new Configuration($config);
|
||||
$this->createDefaultManagerAlias($config['default_manager'], $container);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -73,22 +71,24 @@ class FOSElasticaExtension extends Extension
|
|||
*/
|
||||
protected function loadClients(array $clients, ContainerBuilder $container)
|
||||
{
|
||||
$clientIds = array();
|
||||
foreach ($clients as $name => $clientConfig) {
|
||||
$clientId = sprintf('fos_elastica.client.%s', $name);
|
||||
$clientDef = new Definition('%fos_elastica.client.class%', array($clientConfig));
|
||||
|
||||
$clientDef = new DefinitionDecorator('fos_elastica.client_prototype');
|
||||
$clientDef->replaceArgument(0, $clientConfig);
|
||||
|
||||
$logger = $clientConfig['servers'][0]['logger'];
|
||||
if (false !== $logger) {
|
||||
$clientDef->addMethodCall('setLogger', array(new Reference($logger)));
|
||||
}
|
||||
$clientDef->addTag('fos_elastica.client');
|
||||
|
||||
$container->setDefinition($clientId, $clientDef);
|
||||
|
||||
$clientIds[$name] = $clientId;
|
||||
$this->clients[$name] = array(
|
||||
'id' => $clientId,
|
||||
'reference' => new Reference($clientId)
|
||||
);
|
||||
}
|
||||
|
||||
return $clientIds;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -96,35 +96,29 @@ class FOSElasticaExtension extends Extension
|
|||
*
|
||||
* @param array $indexes An array of indexes configurations
|
||||
* @param ContainerBuilder $container A ContainerBuilder instance
|
||||
* @param array $clientIdsByName
|
||||
* @param $defaultClientName
|
||||
* @param $serializerConfig
|
||||
* @throws \InvalidArgumentException
|
||||
* @return array
|
||||
*/
|
||||
protected function loadIndexes(array $indexes, ContainerBuilder $container, array $clientIdsByName, $defaultClientName)
|
||||
protected function loadIndexes(array $indexes, ContainerBuilder $container)
|
||||
{
|
||||
$indexIds = array();
|
||||
|
||||
foreach ($indexes as $name => $index) {
|
||||
if (isset($index['client'])) {
|
||||
$clientName = $index['client'];
|
||||
if (!isset($clientIdsByName[$clientName])) {
|
||||
throw new InvalidArgumentException(sprintf('The elastica client with name "%s" is not defined', $clientName));
|
||||
}
|
||||
} else {
|
||||
$clientName = $defaultClientName;
|
||||
$indexId = sprintf('fos_elastica.index.%s', $name);
|
||||
$indexName = $index['index_name'] ?: $name;
|
||||
|
||||
$indexDef = new DefinitionDecorator('fos_elastica.index_prototype');
|
||||
$indexDef->replaceArgument(0, $indexName);
|
||||
|
||||
if ($index['client']) {
|
||||
$client = $this->getClient($index['client']);
|
||||
$indexDef->setFactoryService($client);
|
||||
}
|
||||
|
||||
$clientId = $clientIdsByName[$clientName];
|
||||
$indexId = sprintf('fos_elastica.index.%s', $name);
|
||||
$indexName = isset($index['index_name']) ? $index['index_name'] : $name;
|
||||
$indexDefArgs = array($indexName);
|
||||
$indexDef = new Definition('%fos_elastica.index.class%', $indexDefArgs);
|
||||
$indexDef->setFactoryService($clientId);
|
||||
$indexDef->setFactoryMethod('getIndex');
|
||||
$container->setDefinition($indexId, $indexDef);
|
||||
|
||||
$typePrototypeConfig = isset($index['type_prototype']) ? $index['type_prototype'] : array();
|
||||
$indexIds[$name] = $indexId;
|
||||
|
||||
$this->indexConfigs[$name] = array(
|
||||
'index' => new Reference($indexId),
|
||||
'name_or_alias' => $indexName,
|
||||
|
@ -132,10 +126,13 @@ class FOSElasticaExtension extends Extension
|
|||
'mappings' => array()
|
||||
)
|
||||
);
|
||||
|
||||
if ($index['finder']) {
|
||||
// XX Deprecated
|
||||
$this->loadIndexFinder($container, $name, $indexId);
|
||||
}
|
||||
if (!empty($index['settings'])) {
|
||||
// XX What is this for?
|
||||
$this->indexConfigs[$name]['config']['settings'] = $index['settings'];
|
||||
}
|
||||
if ($index['use_alias']) {
|
||||
|
@ -522,26 +519,26 @@ class FOSElasticaExtension extends Extension
|
|||
/**
|
||||
* Loads the index manager
|
||||
*
|
||||
* @param array $indexRefsByName
|
||||
* @param ContainerBuilder $container
|
||||
**/
|
||||
protected function loadIndexManager(array $indexRefsByName, ContainerBuilder $container)
|
||||
*/
|
||||
protected function loadIndexManager(ContainerBuilder $container)
|
||||
{
|
||||
$indexRefs = array_map(function ($index) { return $index['index']; }, $this->indexConfigs);
|
||||
|
||||
$managerDef = $container->getDefinition('fos_elastica.index_manager');
|
||||
$managerDef->replaceArgument(0, $indexRefsByName);
|
||||
$managerDef->replaceArgument(0, $indexRefs);
|
||||
$managerDef->replaceArgument(1, new Reference('fos_elastica.index'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the resetter
|
||||
*
|
||||
* @param array $indexConfigs
|
||||
* @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
|
||||
* @param ContainerBuilder $container
|
||||
*/
|
||||
protected function loadResetter(array $indexConfigs, ContainerBuilder $container)
|
||||
protected function loadResetter(ContainerBuilder $container)
|
||||
{
|
||||
$resetterDef = $container->getDefinition('fos_elastica.resetter');
|
||||
$resetterDef->replaceArgument(0, $indexConfigs);
|
||||
$resetterDef->replaceArgument(0, $this->indexConfigs);
|
||||
}
|
||||
|
||||
protected function loadDriver(ContainerBuilder $container, $driver)
|
||||
|
@ -549,6 +546,7 @@ class FOSElasticaExtension extends Extension
|
|||
if (in_array($driver, $this->loadedDrivers)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
|
||||
$loader->load($driver.'.xml');
|
||||
$this->loadedDrivers[] = $driver;
|
||||
|
@ -570,4 +568,20 @@ class FOSElasticaExtension extends Extension
|
|||
|
||||
$container->setAlias('fos_elastica.manager', sprintf('fos_elastica.manager.%s', $defaultManagerService));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to a client.
|
||||
*
|
||||
* @param string $clientName
|
||||
* @return Reference
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
private function getClient($clientName)
|
||||
{
|
||||
if (!array_key_exists($clientName, $this->clients)) {
|
||||
throw new InvalidArgumentException(sprintf('The elastica client with name "%s" is not defined', $clientName));
|
||||
}
|
||||
|
||||
return $this->clients[$clientName]['reference'];
|
||||
}
|
||||
}
|
||||
|
|
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;
|
||||
}
|
||||
}
|
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());
|
||||
}
|
||||
}
|
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);
|
||||
}
|
||||
}
|
|
@ -2,27 +2,11 @@
|
|||
|
||||
namespace FOS\ElasticaBundle;
|
||||
|
||||
use Elastica\Index;
|
||||
use FOS\ElasticaBundle\Elastica\TransformingIndex;
|
||||
|
||||
/**
|
||||
* Elastica index capable of reassigning name dynamically
|
||||
*
|
||||
* @author Konstantin Tjuterev <kostik.lv@gmail.com>
|
||||
* @deprecated Use \FOS\ElasticaBundle\Elastica\TransformingIndex
|
||||
*/
|
||||
class DynamicIndex extends Index
|
||||
class DynamicIndex extends TransformingIndex
|
||||
{
|
||||
/**
|
||||
* Reassign index name
|
||||
*
|
||||
* While it's technically a regular setter for name property, it's specifically named overrideName, but not setName
|
||||
* since it's used for a very specific case and normally should not be used
|
||||
*
|
||||
* @param string $name Index name
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function overrideName($name)
|
||||
{
|
||||
$this->_name = $name;
|
||||
}
|
||||
}
|
||||
|
|
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());
|
||||
}
|
||||
}
|
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));
|
||||
}
|
||||
}
|
|
@ -1,28 +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
|
||||
*/
|
||||
function findPaginated($query, $options = array());
|
||||
|
||||
/**
|
||||
* Creates a paginator adapter for this query
|
||||
*
|
||||
* @param mixed $query
|
||||
* @param array $options
|
||||
* @return PaginatorAdapterInterface
|
||||
*/
|
||||
function createPaginatorAdapter($query, $options = array());
|
||||
}
|
|
@ -13,7 +13,7 @@ use Elastica\Query;
|
|||
/**
|
||||
* Finds elastica documents and map them to persisted objects
|
||||
*/
|
||||
class TransformedFinder implements PaginatedFinderInterface
|
||||
class TransformedFinder implements FinderInterface
|
||||
{
|
||||
protected $searchable;
|
||||
protected $transformer;
|
||||
|
@ -31,7 +31,7 @@ class TransformedFinder implements PaginatedFinderInterface
|
|||
* @param integer $limit
|
||||
* @param array $options
|
||||
* @return array of model objects
|
||||
**/
|
||||
*/
|
||||
public function find($query, $limit = null, $options = array())
|
||||
{
|
||||
$results = $this->search($query, $limit, $options);
|
||||
|
@ -78,29 +78,4 @@ class TransformedFinder implements PaginatedFinderInterface
|
|||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a paginator wrapping the result of a search
|
||||
*
|
||||
* @param string $query
|
||||
* @param array $options
|
||||
* @return Pagerfanta
|
||||
*/
|
||||
public function findPaginated($query, $options = array())
|
||||
{
|
||||
$queryObject = Query::create($query);
|
||||
$paginatorAdapter = $this->createPaginatorAdapter($queryObject, $options);
|
||||
|
||||
return new Pagerfanta(new FantaPaginatorAdapter($paginatorAdapter));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createPaginatorAdapter($query, $options = array())
|
||||
{
|
||||
$query = Query::create($query);
|
||||
|
||||
return new TransformedPaginatorAdapter($this->searchable, $query, $options, $this->transformer);
|
||||
}
|
||||
}
|
||||
|
|
68
Index/IndexManager.php
Normal file
68
Index/IndexManager.php
Normal file
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Index;
|
||||
|
||||
use FOS\ElasticaBundle\Elastica\TransformingIndex;
|
||||
|
||||
class IndexManager
|
||||
{
|
||||
/**
|
||||
* @var TransformingIndex[]
|
||||
*/
|
||||
protected $indexesByName;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $defaultIndexName;
|
||||
|
||||
/**
|
||||
* @param TransformingIndex[] $indexesByName
|
||||
* @param TransformingIndex $defaultIndex
|
||||
*/
|
||||
public function __construct(array $indexesByName, TransformingIndex $defaultIndex)
|
||||
{
|
||||
$this->indexesByName = $indexesByName;
|
||||
$this->defaultIndexName = $defaultIndex->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all registered indexes
|
||||
*
|
||||
* @return TransformingIndex[]
|
||||
*/
|
||||
public function getAllIndexes()
|
||||
{
|
||||
return $this->indexesByName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an index by its name
|
||||
*
|
||||
* @param string $name Index to return, or the default index if null
|
||||
* @return TransformingIndex
|
||||
* @throws \InvalidArgumentException if no index exists for the given name
|
||||
*/
|
||||
public function getIndex($name = null)
|
||||
{
|
||||
if (null === $name) {
|
||||
$name = $this->defaultIndexName;
|
||||
}
|
||||
|
||||
if (!isset($this->indexesByName[$name])) {
|
||||
throw new \InvalidArgumentException(sprintf('The index "%s" does not exist', $name));
|
||||
}
|
||||
|
||||
return $this->indexesByName[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default index
|
||||
*
|
||||
* @return TransformingIndex
|
||||
*/
|
||||
public function getDefaultIndex()
|
||||
{
|
||||
return $this->getIndex($this->defaultIndexName);
|
||||
}
|
||||
}
|
246
Index/Resetter.php
Normal file
246
Index/Resetter.php
Normal file
|
@ -0,0 +1,246 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Index;
|
||||
|
||||
use Elastica\Exception\ExceptionInterface;
|
||||
use Elastica\Index;
|
||||
use Elastica\Exception\ResponseException;
|
||||
use Elastica\Type\Mapping;
|
||||
|
||||
/**
|
||||
* Deletes and recreates indexes
|
||||
*/
|
||||
class Resetter
|
||||
{
|
||||
protected $indexConfigsByName;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $indexConfigsByName
|
||||
*/
|
||||
public function __construct(array $indexConfigsByName)
|
||||
{
|
||||
$this->indexConfigsByName = $indexConfigsByName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes and recreates all indexes
|
||||
*/
|
||||
public function resetAllIndexes()
|
||||
{
|
||||
foreach (array_keys($this->indexConfigsByName) as $name) {
|
||||
$this->resetIndex($name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes and recreates the named index
|
||||
*
|
||||
* @param string $indexName
|
||||
* @throws \InvalidArgumentException if no index exists for the given name
|
||||
*/
|
||||
public function resetIndex($indexName)
|
||||
{
|
||||
$indexConfig = $this->getIndexConfig($indexName);
|
||||
$esIndex = $indexConfig['index'];
|
||||
if (isset($indexConfig['use_alias']) && $indexConfig['use_alias']) {
|
||||
$name = $indexConfig['name_or_alias'];
|
||||
$name .= uniqid();
|
||||
$esIndex->overrideName($name);
|
||||
$esIndex->create($indexConfig['config']);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$esIndex->create($indexConfig['config'], true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes and recreates a mapping type for the named index
|
||||
*
|
||||
* @param string $indexName
|
||||
* @param string $typeName
|
||||
* @throws \InvalidArgumentException if no index or type mapping exists for the given names
|
||||
* @throws ResponseException
|
||||
*/
|
||||
public function resetIndexType($indexName, $typeName)
|
||||
{
|
||||
$indexConfig = $this->getIndexConfig($indexName);
|
||||
|
||||
if (!isset($indexConfig['config']['mappings'][$typeName]['properties'])) {
|
||||
throw new \InvalidArgumentException(sprintf('The mapping for index "%s" and type "%s" does not exist.', $indexName, $typeName));
|
||||
}
|
||||
|
||||
$type = $indexConfig['index']->getType($typeName);
|
||||
try {
|
||||
$type->delete();
|
||||
} catch (ResponseException $e) {
|
||||
if (strpos($e->getMessage(), 'TypeMissingException') === false) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
$mapping = $this->createMapping($indexConfig['config']['mappings'][$typeName]);
|
||||
$type->setMapping($mapping);
|
||||
}
|
||||
|
||||
/**
|
||||
* create type mapping object
|
||||
*
|
||||
* @param array $indexConfig
|
||||
* @return Mapping
|
||||
*/
|
||||
protected function createMapping($indexConfig)
|
||||
{
|
||||
$mapping = Mapping::create($indexConfig['properties']);
|
||||
|
||||
$mappingSpecialFields = array('_uid', '_id', '_source', '_all', '_analyzer', '_boost', '_routing', '_index', '_size', '_timestamp', '_ttl', 'dynamic_templates');
|
||||
foreach ($mappingSpecialFields as $specialField) {
|
||||
if (isset($indexConfig[$specialField])) {
|
||||
$mapping->setParam($specialField, $indexConfig[$specialField]);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($indexConfig['_parent'])) {
|
||||
$mapping->setParam('_parent', array('type' => $indexConfig['_parent']['type']));
|
||||
}
|
||||
|
||||
return $mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an index config by its name
|
||||
*
|
||||
* @param string $indexName Index name
|
||||
*
|
||||
* @param $indexName
|
||||
* @return array
|
||||
* @throws \InvalidArgumentException if no index config exists for the given name
|
||||
*/
|
||||
protected function getIndexConfig($indexName)
|
||||
{
|
||||
if (!isset($this->indexConfigsByName[$indexName])) {
|
||||
throw new \InvalidArgumentException(sprintf('The configuration for index "%s" does not exist.', $indexName));
|
||||
}
|
||||
|
||||
return $this->indexConfigsByName[$indexName];
|
||||
}
|
||||
|
||||
public function postPopulate($indexName)
|
||||
{
|
||||
$indexConfig = $this->getIndexConfig($indexName);
|
||||
if (isset($indexConfig['use_alias']) && $indexConfig['use_alias']) {
|
||||
$this->switchIndexAlias($indexName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches the alias for given index (by key) to the newly populated index
|
||||
* and deletes the old index
|
||||
*
|
||||
* @param string $indexName Index name
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
private function switchIndexAlias($indexName)
|
||||
{
|
||||
$indexConfig = $this->getIndexConfig($indexName);
|
||||
$esIndex = $indexConfig['index'];
|
||||
$aliasName = $indexConfig['name_or_alias'];
|
||||
$oldIndexName = false;
|
||||
$newIndexName = $esIndex->getName();
|
||||
|
||||
$aliasedIndexes = $this->getAliasedIndexes($esIndex, $aliasName);
|
||||
|
||||
if (count($aliasedIndexes) > 1) {
|
||||
throw new \RuntimeException(
|
||||
sprintf(
|
||||
'Alias %s is used for multiple indexes: [%s].
|
||||
Make sure it\'s either not used or is assigned to one index only',
|
||||
$aliasName,
|
||||
join(', ', $aliasedIndexes)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Change the alias to point to the new index
|
||||
// Elastica's addAlias can't be used directly, because in current (0.19.x) version it's not atomic
|
||||
// In 0.20.x it's atomic, but it doesn't return the old index name
|
||||
$aliasUpdateRequest = array('actions' => array());
|
||||
if (count($aliasedIndexes) == 1) {
|
||||
// if the alias is set - add an action to remove it
|
||||
$oldIndexName = $aliasedIndexes[0];
|
||||
$aliasUpdateRequest['actions'][] = array(
|
||||
'remove' => array('index' => $oldIndexName, 'alias' => $aliasName)
|
||||
);
|
||||
}
|
||||
|
||||
// add an action to point the alias to the new index
|
||||
$aliasUpdateRequest['actions'][] = array(
|
||||
'add' => array('index' => $newIndexName, 'alias' => $aliasName)
|
||||
);
|
||||
|
||||
try {
|
||||
$esIndex->getClient()->request('_aliases', 'POST', $aliasUpdateRequest);
|
||||
} catch (ExceptionInterface $renameAliasException) {
|
||||
$additionalError = '';
|
||||
// if we failed to move the alias, delete the newly built index
|
||||
try {
|
||||
$esIndex->delete();
|
||||
} catch (ExceptionInterface $deleteNewIndexException) {
|
||||
$additionalError = sprintf(
|
||||
'Tried to delete newly built index %s, but also failed: %s',
|
||||
$newIndexName,
|
||||
$deleteNewIndexException->getError()
|
||||
);
|
||||
}
|
||||
|
||||
throw new \RuntimeException(
|
||||
sprintf(
|
||||
'Failed to updated index alias: %s. %s',
|
||||
$renameAliasException->getMessage(),
|
||||
$additionalError ?: sprintf('Newly built index %s was deleted', $newIndexName)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Delete the old index after the alias has been switched
|
||||
if ($oldIndexName) {
|
||||
$oldIndex = new Index($esIndex->getClient(), $oldIndexName);
|
||||
try {
|
||||
$oldIndex->delete();
|
||||
} catch (ExceptionInterface $deleteOldIndexException) {
|
||||
throw new \RuntimeException(
|
||||
sprintf(
|
||||
'Failed to delete old index %s with message: %s',
|
||||
$oldIndexName,
|
||||
$deleteOldIndexException->getMessage()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns array of indexes which are mapped to given alias
|
||||
*
|
||||
* @param Index $esIndex ES Index
|
||||
* @param string $aliasName Alias name
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getAliasedIndexes(Index $esIndex, $aliasName)
|
||||
{
|
||||
$aliasesInfo = $esIndex->getClient()->request('_aliases', 'GET')->getData();
|
||||
$aliasedIndexes = array();
|
||||
|
||||
foreach ($aliasesInfo as $indexName => $indexInfo) {
|
||||
$aliases = array_keys($indexInfo['aliases']);
|
||||
if (in_array($aliasName, $aliases)) {
|
||||
$aliasedIndexes[] = $indexName;
|
||||
}
|
||||
}
|
||||
|
||||
return $aliasedIndexes;
|
||||
}
|
||||
}
|
|
@ -2,62 +2,11 @@
|
|||
|
||||
namespace FOS\ElasticaBundle;
|
||||
|
||||
use Elastica\Index;
|
||||
use FOS\ElasticaBundle\Index\IndexManager as BaseIndexManager;
|
||||
|
||||
class IndexManager
|
||||
/**
|
||||
* @deprecated Use \FOS\ElasticaBundle\Index\IndexManager
|
||||
*/
|
||||
class IndexManager extends BaseIndexManager
|
||||
{
|
||||
protected $indexesByName;
|
||||
protected $defaultIndexName;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $indexesByName
|
||||
* @param Index $defaultIndex
|
||||
*/
|
||||
public function __construct(array $indexesByName, Index $defaultIndex)
|
||||
{
|
||||
$this->indexesByName = $indexesByName;
|
||||
$this->defaultIndexName = $defaultIndex->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all registered indexes
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAllIndexes()
|
||||
{
|
||||
return $this->indexesByName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an index by its name
|
||||
*
|
||||
* @param string $name Index to return, or the default index if null
|
||||
* @return Index
|
||||
* @throws \InvalidArgumentException if no index exists for the given name
|
||||
*/
|
||||
public function getIndex($name = null)
|
||||
{
|
||||
if (null === $name) {
|
||||
$name = $this->defaultIndexName;
|
||||
}
|
||||
|
||||
if (!isset($this->indexesByName[$name])) {
|
||||
throw new \InvalidArgumentException(sprintf('The index "%s" does not exist', $name));
|
||||
}
|
||||
|
||||
return $this->indexesByName[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default index
|
||||
*
|
||||
* @return Index
|
||||
*/
|
||||
public function getDefaultIndex()
|
||||
{
|
||||
return $this->getIndex($this->defaultIndexName);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,57 +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.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getNbResults()
|
||||
{
|
||||
return $this->adapter->getTotalHits();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Facets
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getFacets()
|
||||
{
|
||||
return $this->adapter->getFacets();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a slice of the results.
|
||||
*
|
||||
* @param integer $offset The offset.
|
||||
* @param integer $length The length.
|
||||
*
|
||||
* @return array|\Traversable The slice.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getSlice($offset, $length)
|
||||
{
|
||||
return $this->adapter->getResults($offset, $length)->toArray();
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Paginator;
|
||||
|
||||
interface PaginatorAdapterInterface
|
||||
{
|
||||
/**
|
||||
* Returns the number of results.
|
||||
*
|
||||
* @return integer The number of results.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
function getTotalHits();
|
||||
|
||||
/**
|
||||
* Returns an slice of the results.
|
||||
*
|
||||
* @param integer $offset The offset.
|
||||
* @param integer $length The length.
|
||||
*
|
||||
* @return PartialResultsInterface
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
function getResults($offset, $length);
|
||||
|
||||
/**
|
||||
* Returns Facets
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function getFacets();
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Paginator;
|
||||
|
||||
interface PartialResultsInterface
|
||||
{
|
||||
/**
|
||||
* Returns the paginated results.
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
function toArray();
|
||||
|
||||
/**
|
||||
* Returns the number of results.
|
||||
*
|
||||
* @return integer The number of results.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
function getTotalHits();
|
||||
|
||||
/**
|
||||
* Returns the facets
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function getFacets();
|
||||
}
|
|
@ -1,139 +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;
|
||||
|
||||
/**
|
||||
* @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 $offset
|
||||
* @param $itemCountPerPage
|
||||
* @throws \InvalidArgumentException
|
||||
* @return ResultSet
|
||||
*/
|
||||
protected function getElasticaResults($offset, $itemCountPerPage)
|
||||
{
|
||||
$offset = (integer) $offset;
|
||||
$itemCountPerPage = (integer) $itemCountPerPage;
|
||||
$size = $this->query->hasParam('size')
|
||||
? (integer) $this->query->getParam('size')
|
||||
: null;
|
||||
|
||||
if ($size && $size < $offset + $itemCountPerPage) {
|
||||
$itemCountPerPage = $size - $offset;
|
||||
}
|
||||
|
||||
if ($itemCountPerPage < 1) {
|
||||
throw new InvalidArgumentException('$itemCountPerPage must be greater than zero');
|
||||
}
|
||||
|
||||
$query = clone $this->query;
|
||||
$query->setFrom($offset);
|
||||
$query->setSize($itemCountPerPage);
|
||||
|
||||
$resultSet = $this->searchable->search($query, $this->options);
|
||||
$this->totalHits = $resultSet->getTotalHits();
|
||||
$this->facets = $resultSet->getFacets();
|
||||
return $resultSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the paginated results.
|
||||
*
|
||||
* @param int $offset
|
||||
* @param int $itemCountPerPage
|
||||
* @return PartialResultsInterface
|
||||
*/
|
||||
public function getResults($offset, $itemCountPerPage)
|
||||
{
|
||||
return new RawPartialResults($this->getElasticaResults($offset, $itemCountPerPage));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of results.
|
||||
*
|
||||
* @return integer The number of results.
|
||||
*/
|
||||
public function getTotalHits()
|
||||
{
|
||||
if ( ! isset($this->totalHits)) {
|
||||
$this->totalHits = $this->searchable->search($this->query)->getTotalHits();
|
||||
}
|
||||
|
||||
return $this->query->hasParam('size')
|
||||
? min($this->totalHits, (integer) $this->query->getParam('size'))
|
||||
: $this->totalHits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Facets
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getFacets()
|
||||
{
|
||||
if ( ! isset($this->facets)) {
|
||||
$this->facets = $this->searchable->search($this->query)->getFacets();
|
||||
}
|
||||
|
||||
return $this->facets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Query
|
||||
*
|
||||
* @return Query the search query
|
||||
*/
|
||||
public function getQuery()
|
||||
{
|
||||
return $this->query;
|
||||
}
|
||||
}
|
|
@ -1,52 +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 null;
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
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);
|
||||
}
|
||||
}
|
238
Resetter.php
238
Resetter.php
|
@ -2,245 +2,11 @@
|
|||
|
||||
namespace FOS\ElasticaBundle;
|
||||
|
||||
use Elastica\Exception\ExceptionInterface;
|
||||
use Elastica\Index;
|
||||
use Elastica\Exception\ResponseException;
|
||||
use Elastica\Type\Mapping;
|
||||
use FOS\ElasticaBundle\Index\Resetter as BaseResetter;
|
||||
|
||||
/**
|
||||
* Deletes and recreates indexes
|
||||
*/
|
||||
class Resetter
|
||||
class Resetter extends BaseResetter
|
||||
{
|
||||
protected $indexConfigsByName;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $indexConfigsByName
|
||||
*/
|
||||
public function __construct(array $indexConfigsByName)
|
||||
{
|
||||
$this->indexConfigsByName = $indexConfigsByName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes and recreates all indexes
|
||||
*/
|
||||
public function resetAllIndexes()
|
||||
{
|
||||
foreach (array_keys($this->indexConfigsByName) as $name) {
|
||||
$this->resetIndex($name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes and recreates the named index
|
||||
*
|
||||
* @param string $indexName
|
||||
* @throws \InvalidArgumentException if no index exists for the given name
|
||||
*/
|
||||
public function resetIndex($indexName)
|
||||
{
|
||||
$indexConfig = $this->getIndexConfig($indexName);
|
||||
$esIndex = $indexConfig['index'];
|
||||
if (isset($indexConfig['use_alias']) && $indexConfig['use_alias']) {
|
||||
$name = $indexConfig['name_or_alias'];
|
||||
$name .= uniqid();
|
||||
$esIndex->overrideName($name);
|
||||
$esIndex->create($indexConfig['config']);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$esIndex->create($indexConfig['config'], true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes and recreates a mapping type for the named index
|
||||
*
|
||||
* @param string $indexName
|
||||
* @param string $typeName
|
||||
* @throws \InvalidArgumentException if no index or type mapping exists for the given names
|
||||
* @throws ResponseException
|
||||
*/
|
||||
public function resetIndexType($indexName, $typeName)
|
||||
{
|
||||
$indexConfig = $this->getIndexConfig($indexName);
|
||||
|
||||
if (!isset($indexConfig['config']['mappings'][$typeName]['properties'])) {
|
||||
throw new \InvalidArgumentException(sprintf('The mapping for index "%s" and type "%s" does not exist.', $indexName, $typeName));
|
||||
}
|
||||
|
||||
$type = $indexConfig['index']->getType($typeName);
|
||||
try {
|
||||
$type->delete();
|
||||
} catch (ResponseException $e) {
|
||||
if (strpos($e->getMessage(), 'TypeMissingException') === false) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
$mapping = $this->createMapping($indexConfig['config']['mappings'][$typeName]);
|
||||
$type->setMapping($mapping);
|
||||
}
|
||||
|
||||
/**
|
||||
* create type mapping object
|
||||
*
|
||||
* @param array $indexConfig
|
||||
* @return Mapping
|
||||
*/
|
||||
protected function createMapping($indexConfig)
|
||||
{
|
||||
$mapping = Mapping::create($indexConfig['properties']);
|
||||
|
||||
$mappingSpecialFields = array('_uid', '_id', '_source', '_all', '_analyzer', '_boost', '_routing', '_index', '_size', '_timestamp', '_ttl', 'dynamic_templates');
|
||||
foreach ($mappingSpecialFields as $specialField) {
|
||||
if (isset($indexConfig[$specialField])) {
|
||||
$mapping->setParam($specialField, $indexConfig[$specialField]);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($indexConfig['_parent'])) {
|
||||
$mapping->setParam('_parent', array('type' => $indexConfig['_parent']['type']));
|
||||
}
|
||||
|
||||
return $mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an index config by its name
|
||||
*
|
||||
* @param string $indexName Index name
|
||||
*
|
||||
* @param $indexName
|
||||
* @return array
|
||||
* @throws \InvalidArgumentException if no index config exists for the given name
|
||||
*/
|
||||
protected function getIndexConfig($indexName)
|
||||
{
|
||||
if (!isset($this->indexConfigsByName[$indexName])) {
|
||||
throw new \InvalidArgumentException(sprintf('The configuration for index "%s" does not exist.', $indexName));
|
||||
}
|
||||
|
||||
return $this->indexConfigsByName[$indexName];
|
||||
}
|
||||
|
||||
public function postPopulate($indexName)
|
||||
{
|
||||
$indexConfig = $this->getIndexConfig($indexName);
|
||||
if (isset($indexConfig['use_alias']) && $indexConfig['use_alias']) {
|
||||
$this->switchIndexAlias($indexName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches the alias for given index (by key) to the newly populated index
|
||||
* and deletes the old index
|
||||
*
|
||||
* @param string $indexName Index name
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
private function switchIndexAlias($indexName)
|
||||
{
|
||||
$indexConfig = $this->getIndexConfig($indexName);
|
||||
$esIndex = $indexConfig['index'];
|
||||
$aliasName = $indexConfig['name_or_alias'];
|
||||
$oldIndexName = false;
|
||||
$newIndexName = $esIndex->getName();
|
||||
|
||||
$aliasedIndexes = $this->getAliasedIndexes($esIndex, $aliasName);
|
||||
|
||||
if (count($aliasedIndexes) > 1) {
|
||||
throw new \RuntimeException(
|
||||
sprintf(
|
||||
'Alias %s is used for multiple indexes: [%s].
|
||||
Make sure it\'s either not used or is assigned to one index only',
|
||||
$aliasName,
|
||||
join(', ', $aliasedIndexes)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Change the alias to point to the new index
|
||||
// Elastica's addAlias can't be used directly, because in current (0.19.x) version it's not atomic
|
||||
// In 0.20.x it's atomic, but it doesn't return the old index name
|
||||
$aliasUpdateRequest = array('actions' => array());
|
||||
if (count($aliasedIndexes) == 1) {
|
||||
// if the alias is set - add an action to remove it
|
||||
$oldIndexName = $aliasedIndexes[0];
|
||||
$aliasUpdateRequest['actions'][] = array(
|
||||
'remove' => array('index' => $oldIndexName, 'alias' => $aliasName)
|
||||
);
|
||||
}
|
||||
|
||||
// add an action to point the alias to the new index
|
||||
$aliasUpdateRequest['actions'][] = array(
|
||||
'add' => array('index' => $newIndexName, 'alias' => $aliasName)
|
||||
);
|
||||
|
||||
try {
|
||||
$esIndex->getClient()->request('_aliases', 'POST', $aliasUpdateRequest);
|
||||
} catch (ExceptionInterface $renameAliasException) {
|
||||
$additionalError = '';
|
||||
// if we failed to move the alias, delete the newly built index
|
||||
try {
|
||||
$esIndex->delete();
|
||||
} catch (ExceptionInterface $deleteNewIndexException) {
|
||||
$additionalError = sprintf(
|
||||
'Tried to delete newly built index %s, but also failed: %s',
|
||||
$newIndexName,
|
||||
$deleteNewIndexException->getError()
|
||||
);
|
||||
}
|
||||
|
||||
throw new \RuntimeException(
|
||||
sprintf(
|
||||
'Failed to updated index alias: %s. %s',
|
||||
$renameAliasException->getMessage(),
|
||||
$additionalError ?: sprintf('Newly built index %s was deleted', $newIndexName)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Delete the old index after the alias has been switched
|
||||
if ($oldIndexName) {
|
||||
$oldIndex = new Index($esIndex->getClient(), $oldIndexName);
|
||||
try {
|
||||
$oldIndex->delete();
|
||||
} catch (ExceptionInterface $deleteOldIndexException) {
|
||||
throw new \RuntimeException(
|
||||
sprintf(
|
||||
'Failed to delete old index %s with message: %s',
|
||||
$oldIndexName,
|
||||
$deleteOldIndexException->getMessage()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns array of indexes which are mapped to given alias
|
||||
*
|
||||
* @param Index $esIndex ES Index
|
||||
* @param string $aliasName Alias name
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getAliasedIndexes(Index $esIndex, $aliasName)
|
||||
{
|
||||
$aliasesInfo = $esIndex->getClient()->request('_aliases', 'GET')->getData();
|
||||
$aliasedIndexes = array();
|
||||
|
||||
foreach ($aliasesInfo as $indexName => $indexInfo) {
|
||||
$aliases = array_keys($indexInfo['aliases']);
|
||||
if (in_array($aliasName, $aliases)) {
|
||||
$aliasedIndexes[] = $indexName;
|
||||
}
|
||||
}
|
||||
|
||||
return $aliasedIndexes;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,97 +5,30 @@
|
|||
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\Client</parameter>
|
||||
<parameter key="fos_elastica.index.class">FOS\ElasticaBundle\DynamicIndex</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>
|
||||
<parameter key="fos_elastica.paginator_subscriber.class">FOS\ElasticaBundle\Subscriber\PaginateElasticaQuerySubscriber</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.manager.class">FOS\ElasticaBundle\Manager\RepositoryManager</parameter>
|
||||
<parameter key="fos_elastica.elastica_to_model_transformer.collection.class">FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerCollection</parameter>
|
||||
<parameter key="fos_elastica.provider_registry.class">FOS\ElasticaBundle\Provider\ProviderRegistry</parameter>
|
||||
<parameter key="fos_elastica.property_accessor.class">Symfony\Component\PropertyAccess\PropertyAccessor</parameter>
|
||||
<parameter key="fos_elastica.object_persister.class">FOS\ElasticaBundle\Persister\ObjectPersister</parameter>
|
||||
<parameter key="fos_elastica.object_serializer_persister.class">FOS\ElasticaBundle\Persister\ObjectSerializerPersister</parameter>
|
||||
<parameter key="fos_elastica.model_to_elastica_transformer.class">FOS\ElasticaBundle\Transformer\ModelToElasticaAutoTransformer</parameter>
|
||||
<parameter key="fos_elastica.model_to_elastica_identifier_transformer.class">FOS\ElasticaBundle\Transformer\ModelToElasticaIdentifierTransformer</parameter>
|
||||
</parameters>
|
||||
|
||||
<services>
|
||||
<service id="fos_elastica.client_prototype" class="%fos_elastica.client.class%" abstract="true">
|
||||
<argument type="collection" /> <!-- configuration -->
|
||||
<argument /> <!-- callback -->
|
||||
<argument type="service" id="fos_elastica.transformer.combined" />
|
||||
</service>
|
||||
|
||||
<service id="fos_elastica.logger" class="%fos_elastica.logger.class%">
|
||||
<argument type="service" id="logger" on-invalid="null" />
|
||||
<argument>%kernel.debug%</argument>
|
||||
<tag name="monolog.logger" channel="elastica" />
|
||||
</service>
|
||||
|
||||
<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.index_manager" class="%fos_elastica.index_manager.class%">
|
||||
<argument /> <!-- indexes -->
|
||||
<argument /> <!-- default index -->
|
||||
</service>
|
||||
|
||||
<service id="fos_elastica.resetter" class="%fos_elastica.resetter.class%">
|
||||
<argument /> <!-- index configs -->
|
||||
</service>
|
||||
|
||||
<service id="fos_elastica.object_persister" class="%fos_elastica.object_persister.class%" abstract="true">
|
||||
<argument /> <!-- type -->
|
||||
<argument /> <!-- model to elastica transformer -->
|
||||
<argument /> <!-- model -->
|
||||
<argument /> <!-- properties mapping -->
|
||||
</service>
|
||||
|
||||
<service id="fos_elastica.finder" class="%fos_elastica.finder.class%" public="true" abstract="true">
|
||||
<argument /> <!-- searchable -->
|
||||
<argument /> <!-- transformer -->
|
||||
</service>
|
||||
|
||||
<service id="fos_elastica.object_serializer_persister" class="%fos_elastica.object_serializer_persister.class%" abstract="true">
|
||||
<argument /> <!-- type -->
|
||||
<argument /> <!-- model to elastica transformer -->
|
||||
<argument /> <!-- model -->
|
||||
<argument /> <!-- serializer -->
|
||||
</service>
|
||||
|
||||
<service id="fos_elastica.model_to_elastica_transformer" class="%fos_elastica.model_to_elastica_transformer.class%" public="false" abstract="true">
|
||||
<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 /> <!-- options -->
|
||||
<call method="setPropertyAccessor">
|
||||
<argument type="service" id="fos_elastica.property_accessor" />
|
||||
</call>
|
||||
</service>
|
||||
|
||||
<service id="fos_elastica.elastica_to_model_transformer.collection" class="%fos_elastica.elastica_to_model_transformer.collection.class%" public="true" abstract="true">
|
||||
<argument type="collection" /> <!-- transformers -->
|
||||
</service>
|
||||
|
||||
<service id="fos_elastica.provider_registry" class="%fos_elastica.provider_registry.class%">
|
||||
<call method="setContainer">
|
||||
<argument type="service" id="service_container" />
|
||||
</call>
|
||||
</service>
|
||||
|
||||
<service id="fos_elastica.paginator.subscriber" class="%fos_elastica.paginator_subscriber.class%">
|
||||
<call method="setRequest">
|
||||
<argument type="service" id="request" on-invalid="null" strict="false" />
|
||||
</call>
|
||||
<tag name="knp_paginator.subscriber" />
|
||||
</service>
|
||||
|
||||
<service id="fos_elastica.property_accessor" class="%fos_elastica.property_accessor.class%" />
|
||||
</services>
|
||||
|
||||
</container>
|
||||
|
|
35
Resources/config/index.xml
Normal file
35
Resources/config/index.xml
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?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.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.index_prototype" factory-service="fos_elastica.client" factory-method="getIndex" abstract="true">
|
||||
<argument /> <!-- index name -->
|
||||
</service>
|
||||
|
||||
<service id="fos_elastica.index_manager" class="%fos_elastica.index_manager.class%">
|
||||
<argument /> <!-- indexes -->
|
||||
<argument /> <!-- default index -->
|
||||
</service>
|
||||
|
||||
<service id="fos_elastica.resetter" class="%fos_elastica.resetter.class%">
|
||||
<argument /> <!-- index configs -->
|
||||
</service>
|
||||
|
||||
<!-- Abstract definition for all finders. -->
|
||||
<service id="fos_elastica.finder" class="%fos_elastica.finder.class%" public="true" abstract="true">
|
||||
<argument /> <!-- searchable -->
|
||||
<argument /> <!-- transformer -->
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
|
@ -31,8 +31,8 @@
|
|||
</service>
|
||||
|
||||
<service id="fos_elastica.manager.orm" class="FOS\ElasticaBundle\Doctrine\RepositoryManager">
|
||||
<argument type="service" id="doctrine"/>
|
||||
<argument type="service" id="annotation_reader"/>
|
||||
<argument type="service" id="doctrine" />
|
||||
<argument type="service" id="annotation_reader" />
|
||||
</service>
|
||||
|
||||
</services>
|
||||
|
|
27
Resources/config/persister.xml
Normal file
27
Resources/config/persister.xml
Normal file
|
@ -0,0 +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.object_persister.class">FOS\ElasticaBundle\Persister\ObjectPersister</parameter>
|
||||
<parameter key="fos_elastica.object_serializer_persister.class">FOS\ElasticaBundle\Persister\ObjectSerializerPersister</parameter>
|
||||
</parameters>
|
||||
|
||||
<services>
|
||||
<service id="fos_elastica.object_persister" class="%fos_elastica.object_persister.class%" abstract="true">
|
||||
<argument /> <!-- type -->
|
||||
<argument /> <!-- model to elastica transformer -->
|
||||
<argument /> <!-- model -->
|
||||
<argument /> <!-- properties mapping -->
|
||||
</service>
|
||||
|
||||
<service id="fos_elastica.object_serializer_persister" class="%fos_elastica.object_serializer_persister.class%" abstract="true">
|
||||
<argument /> <!-- type -->
|
||||
<argument /> <!-- model to elastica transformer -->
|
||||
<argument /> <!-- model -->
|
||||
<argument /> <!-- serializer -->
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
18
Resources/config/provider.xml
Normal file
18
Resources/config/provider.xml
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?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.provider_registry.class">FOS\ElasticaBundle\Provider\ProviderRegistry</parameter>
|
||||
</parameters>
|
||||
|
||||
<services>
|
||||
<service id="fos_elastica.provider_registry" class="%fos_elastica.provider_registry.class%">
|
||||
<call method="setContainer">
|
||||
<argument type="service" id="service_container" />
|
||||
</call>
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
32
Resources/config/transformer.xml
Normal file
32
Resources/config/transformer.xml
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?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.elastica_to_model_transformer.collection.class">FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerCollection</parameter>
|
||||
<parameter key="fos_elastica.model_to_elastica_transformer.class">FOS\ElasticaBundle\Transformer\ModelToElasticaAutoTransformer</parameter>
|
||||
<parameter key="fos_elastica.model_to_elastica_identifier_transformer.class">FOS\ElasticaBundle\Transformer\ModelToElasticaIdentifierTransformer</parameter>
|
||||
</parameters>
|
||||
|
||||
<services>
|
||||
<service id="fos_elastica.model_to_elastica_transformer" class="%fos_elastica.model_to_elastica_transformer.class%" public="false" abstract="true">
|
||||
<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 /> <!-- options -->
|
||||
<call method="setPropertyAccessor">
|
||||
<argument type="service" id="fos_elastica.property_accessor" />
|
||||
</call>
|
||||
</service>
|
||||
|
||||
<service id="fos_elastica.elastica_to_model_transformer.collection" class="%fos_elastica.elastica_to_model_transformer.collection.class%" public="true" abstract="true">
|
||||
<argument type="collection" /> <!-- transformers -->
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
|
@ -1,43 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Tests\Resetter;
|
||||
|
||||
use Elastica\Request;
|
||||
use Elastica\Transport\Null as NullTransport;
|
||||
|
||||
class ClientTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testRequestsAreLogged()
|
||||
{
|
||||
$transport = new NullTransport;
|
||||
|
||||
$connection = $this->getMock('Elastica\Connection');
|
||||
$connection->expects($this->any())->method('getTransportObject')->will($this->returnValue($transport));
|
||||
$connection->expects($this->any())->method('toArray')->will($this->returnValue(array()));
|
||||
|
||||
$logger = $this->getMock('FOS\ElasticaBundle\Logger\ElasticaLogger');
|
||||
$logger
|
||||
->expects($this->once())
|
||||
->method('logQuery')
|
||||
->with(
|
||||
'foo',
|
||||
Request::GET,
|
||||
$this->isType('array'),
|
||||
$this->isType('float'),
|
||||
$this->isType('array'),
|
||||
$this->isType('array')
|
||||
);
|
||||
|
||||
$client = $this->getMockBuilder('FOS\ElasticaBundle\Client')
|
||||
->setMethods(array('getConnection'))
|
||||
->getMock();
|
||||
|
||||
$client->expects($this->any())->method('getConnection')->will($this->returnValue($connection));
|
||||
|
||||
$client->setLogger($logger);
|
||||
|
||||
$response = $client->request('foo');
|
||||
|
||||
$this->assertInstanceOf('Elastica\Response', $response);
|
||||
}
|
||||
}
|
68
Tests/Elastica/LoggingClientTest.php
Normal file
68
Tests/Elastica/LoggingClientTest.php
Normal file
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Tests\Client;
|
||||
|
||||
use Elastica\Request;
|
||||
use Elastica\Transport\Null as NullTransport;
|
||||
use FOS\ElasticaBundle\Elastica\LoggingClient;
|
||||
|
||||
class LoggingClientTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testOverriddenElasticaMethods()
|
||||
{
|
||||
$resultTransformer = $this->getMockBuilder('FOS\ElasticaBundle\Transformer\CombinedResultTransformer')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$client = new LoggingClient(array(), null, $resultTransformer);
|
||||
$index = $client->getIndex('index');
|
||||
$type = $index->getType('type');
|
||||
|
||||
$this->assertInstanceOf('FOS\ElasticaBundle\Elastica\TransformingIndex', $index);
|
||||
$this->assertInstanceOf('FOS\ElasticaBundle\Elastica\TransformingType', $type);
|
||||
}
|
||||
|
||||
public function testGetResultTransformer()
|
||||
{
|
||||
$resultTransformer = $this->getMockBuilder('FOS\ElasticaBundle\Transformer\CombinedResultTransformer')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$client = new LoggingClient(array(), null, $resultTransformer);
|
||||
|
||||
$this->assertSame($resultTransformer, $client->getResultTransformer());
|
||||
}
|
||||
|
||||
public function testRequestsAreLogged()
|
||||
{
|
||||
$transport = new NullTransport;
|
||||
|
||||
$connection = $this->getMock('Elastica\Connection');
|
||||
$connection->expects($this->any())->method('getTransportObject')->will($this->returnValue($transport));
|
||||
$connection->expects($this->any())->method('toArray')->will($this->returnValue(array()));
|
||||
|
||||
$logger = $this->getMock('FOS\ElasticaBundle\Logger\ElasticaLogger');
|
||||
$logger
|
||||
->expects($this->once())
|
||||
->method('logQuery')
|
||||
->with(
|
||||
'foo',
|
||||
Request::GET,
|
||||
$this->isType('array'),
|
||||
$this->isType('float'),
|
||||
$this->isType('array'),
|
||||
$this->isType('array')
|
||||
);
|
||||
|
||||
$client = $this->getMockBuilder('FOS\ElasticaBundle\Elastica\LoggingClient')
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(array('getConnection'))
|
||||
->getMock();
|
||||
|
||||
$client->expects($this->any())->method('getConnection')->will($this->returnValue($connection));
|
||||
|
||||
$client->setLogger($logger);
|
||||
|
||||
$response = $client->request('foo');
|
||||
|
||||
$this->assertInstanceOf('Elastica\Response', $response);
|
||||
}
|
||||
}
|
42
Tests/Elastica/TransformingIndexTest.php
Normal file
42
Tests/Elastica/TransformingIndexTest.php
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Tests\Client;
|
||||
|
||||
use FOS\ElasticaBundle\Elastica\TransformingIndex;
|
||||
|
||||
class TransformingIndexTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @var \FOS\ElasticaBundle\Elastica\TransformingIndex
|
||||
*/
|
||||
private $index;
|
||||
|
||||
/**
|
||||
* @var \FOS\ElasticaBundle\Elastica\LoggingClient
|
||||
*/
|
||||
private $client;
|
||||
|
||||
public function testCreateSearch()
|
||||
{
|
||||
$search = $this->index->createSearch();
|
||||
|
||||
$this->assertInstanceOf('FOS\ElasticaBundle\Elastica\TransformingSearch', $search);
|
||||
}
|
||||
|
||||
public function testOverrideName()
|
||||
{
|
||||
$this->assertEquals('testindex', $this->index->getName());
|
||||
|
||||
$this->index->overrideName('newindex');
|
||||
|
||||
$this->assertEquals('newindex', $this->index->getName());
|
||||
}
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$this->client = $this->getMockBuilder('FOS\ElasticaBundle\Elastica\LoggingClient')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->index = new TransformingIndex($this->client, 'testindex');
|
||||
}
|
||||
}
|
42
Tests/Elastica/TransformingResultSetTest.php
Normal file
42
Tests/Elastica/TransformingResultSetTest.php
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Tests\Client;
|
||||
|
||||
use Elastica\Query;
|
||||
use Elastica\Response;
|
||||
use FOS\ElasticaBundle\Elastica\TransformingResult;
|
||||
use FOS\ElasticaBundle\Elastica\TransformingResultSet;
|
||||
|
||||
class TransformingResultSetTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testTransformingResult()
|
||||
{
|
||||
$response = new Response(array('hits' => array(
|
||||
'hits' => array(
|
||||
array(),
|
||||
array(),
|
||||
array(),
|
||||
)
|
||||
)));
|
||||
$query = new Query();
|
||||
$transformer = $this->getMockBuilder('FOS\ElasticaBundle\Transformer\CombinedResultTransformer')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$resultSet = new TransformingResultSet($response, $query, $transformer);
|
||||
|
||||
$this->assertCount(3, $resultSet);
|
||||
$this->assertInstanceOf('FOS\ElasticaBundle\Elastica\TransformingResult', $resultSet[0]);
|
||||
|
||||
$transformer->expects($this->once())
|
||||
->method('transform')
|
||||
->with($resultSet->getResults());
|
||||
|
||||
$resultSet->transform();
|
||||
$resultSet->transform();
|
||||
|
||||
$this->assertSame(array(
|
||||
0 => null, 1 => null, 2 => null
|
||||
), $resultSet->getTransformed());
|
||||
}
|
||||
}
|
22
Tests/Elastica/TransformingResultTest.php
Normal file
22
Tests/Elastica/TransformingResultTest.php
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Tests\Client;
|
||||
|
||||
use FOS\ElasticaBundle\Elastica\TransformingResult;
|
||||
|
||||
class TransformingResultTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testTransformingResult()
|
||||
{
|
||||
$resultSet = $this->getMockBuilder('FOS\ElasticaBundle\Elastica\TransformingResultSet')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$result = new TransformingResult(array(), $resultSet);
|
||||
|
||||
$resultSet->expects($this->exactly(2))
|
||||
->method('transform');
|
||||
|
||||
$result->getTransformed();
|
||||
$result->getTransformed();
|
||||
}
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Tests\IndexManager;
|
||||
namespace FOS\ElasticaBundle\Tests\Index;
|
||||
|
||||
use FOS\ElasticaBundle\IndexManager;
|
||||
use FOS\ElasticaBundle\Index\IndexManager;
|
||||
|
||||
class IndexManagerTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
|
@ -1,12 +1,12 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Tests\Resetter;
|
||||
namespace FOS\ElasticaBundle\Tests\Index;
|
||||
|
||||
use Elastica\Exception\ResponseException;
|
||||
use Elastica\Request;
|
||||
use Elastica\Response;
|
||||
use FOS\ElasticaBundle\Resetter;
|
||||
use Elastica\Type\Mapping;
|
||||
use FOS\ElasticaBundle\Index\Resetter;
|
||||
|
||||
class ResetterTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
71
Transformer/CombinedResultTransformer.php
Normal file
71
Transformer/CombinedResultTransformer.php
Normal file
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Transformer;
|
||||
|
||||
use FOS\ElasticaBundle\Elastica\TransformingResult;
|
||||
|
||||
/**
|
||||
* Transforms results from an index wide query with multiple types.
|
||||
*
|
||||
* @author Tim Nagel <tim@nagel.com.au>
|
||||
*/
|
||||
class CombinedResultTransformer
|
||||
{
|
||||
/**
|
||||
* @var \FOS\ElasticaBundle\Type\TypeConfiguration
|
||||
*/
|
||||
private $configurations;
|
||||
|
||||
/**
|
||||
* @var ResultTransformerInterface
|
||||
*/
|
||||
private $transformer;
|
||||
|
||||
/**
|
||||
* @param \FOS\ElasticaBundle\Type\TypeConfiguration[] $configurations
|
||||
* @param ResultTransformerInterface $transformer
|
||||
*/
|
||||
public function __construct(array $configurations, ResultTransformerInterface $transformer)
|
||||
{
|
||||
$this->configurations = $configurations;
|
||||
$this->transformer = $transformer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms Elastica results into Models.
|
||||
*
|
||||
* @param TransformingResult[] $results
|
||||
* @return object[]
|
||||
*/
|
||||
public function transform($results)
|
||||
{
|
||||
$grouped = array();
|
||||
|
||||
foreach ($results as $result) {
|
||||
$grouped[$result->getType()][] = $result;
|
||||
}
|
||||
|
||||
foreach ($grouped as $type => $group) {
|
||||
$this->transformer->transform($this->getConfiguration($type), $group);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the transformer for a given type.
|
||||
*
|
||||
* @param string $type
|
||||
* @return \FOS\ElasticaBundle\Type\TypeConfiguration
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
private function getConfiguration($type)
|
||||
{
|
||||
if (!array_key_exists($type, $this->configurations)) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Configuration for type "%s" is not registered with this combined transformer.',
|
||||
$type
|
||||
));
|
||||
}
|
||||
|
||||
return $this->configurations[$type];
|
||||
}
|
||||
}
|
79
Transformer/ResultTransformer.php
Normal file
79
Transformer/ResultTransformer.php
Normal file
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Transformer;
|
||||
|
||||
use FOS\ElasticaBundle\Exception\MissingModelException;
|
||||
use FOS\ElasticaBundle\Exception\UnexpectedObjectException;
|
||||
use FOS\ElasticaBundle\Type\LookupManager;
|
||||
use FOS\ElasticaBundle\Type\TypeConfiguration;
|
||||
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
|
||||
|
||||
/**
|
||||
* Handles transforming results into models.
|
||||
*/
|
||||
class ResultTransformer implements ResultTransformerInterface
|
||||
{
|
||||
/**
|
||||
* @var \FOS\ElasticaBundle\Type\LookupManager
|
||||
*/
|
||||
private $lookupManager;
|
||||
|
||||
/**
|
||||
* @var \Symfony\Component\PropertyAccess\PropertyAccessorInterface
|
||||
*/
|
||||
private $propertyAccessor;
|
||||
|
||||
public function __construct(
|
||||
LookupManager $lookupManager,
|
||||
PropertyAccessorInterface $propertyAccessor
|
||||
) {
|
||||
$this->lookupManager = $lookupManager;
|
||||
$this->propertyAccessor = $propertyAccessor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms Elastica results into Models.
|
||||
*
|
||||
* @param TypeConfiguration $configuration
|
||||
* @param \FOS\ElasticaBundle\Elastica\TransformingResult[] $results
|
||||
* @throws \FOS\ElasticaBundle\Exception\MissingModelException
|
||||
* @throws \FOS\ElasticaBundle\Exception\UnexpectedObjectException
|
||||
*/
|
||||
public function transform(TypeConfiguration $configuration, $results)
|
||||
{
|
||||
$results = $this->processResults($results);
|
||||
$lookup = $this->lookupManager->getLookup($configuration->getType());
|
||||
$objects = $lookup->lookup($configuration, array_keys($results));
|
||||
|
||||
if (!$configuration->isIgnoreMissing() and count($objects) < count($results)) {
|
||||
throw new MissingModelException(count($objects), count($results));
|
||||
}
|
||||
|
||||
$identifierProperty = $configuration->getIdentifierProperty();
|
||||
foreach ($objects as $object) {
|
||||
$id = $this->propertyAccessor->getValue($object, $identifierProperty);
|
||||
|
||||
if (!array_key_exists($id, $results)) {
|
||||
throw new UnexpectedObjectException($id);
|
||||
}
|
||||
|
||||
$results[$id]->setTransformed($object);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the results array into a more usable format for the transformation.
|
||||
*
|
||||
* @param \FOS\ElasticaBundle\Elastica\TransformingResult[] $results
|
||||
* @return \FOS\ElasticaBundle\Elastica\TransformingResult[]
|
||||
*/
|
||||
private function processResults($results)
|
||||
{
|
||||
$sorted = array();
|
||||
foreach ($results as $result) {
|
||||
$sorted[$result->getId()] = $result;
|
||||
}
|
||||
|
||||
return $sorted;
|
||||
}
|
||||
}
|
16
Transformer/ResultTransformerInterface.php
Normal file
16
Transformer/ResultTransformerInterface.php
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Transformer;
|
||||
|
||||
use FOS\ElasticaBundle\Type\TypeConfiguration;
|
||||
|
||||
interface ResultTransformerInterface
|
||||
{
|
||||
/**
|
||||
* Transforms Elastica results into Models.
|
||||
*
|
||||
* @param TypeConfiguration $configuration
|
||||
* @param array $results
|
||||
*/
|
||||
public function transform(TypeConfiguration $configuration, $results);
|
||||
}
|
27
Type/LookupInterface.php
Normal file
27
Type/LookupInterface.php
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Type;
|
||||
|
||||
/**
|
||||
* A service that provides lookup capabilities for a type.
|
||||
*
|
||||
* @author Tim Nagel <tim@nagel.com.au>
|
||||
*/
|
||||
interface LookupInterface
|
||||
{
|
||||
/**
|
||||
* Returns the lookup key.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getKey();
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
35
Type/LookupManager.php
Normal file
35
Type/LookupManager.php
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Type;
|
||||
|
||||
class LookupManager
|
||||
{
|
||||
/**
|
||||
* @var LookupInterface[]
|
||||
*/
|
||||
private $lookups = array();
|
||||
|
||||
/**
|
||||
* @param LookupInterface[] $lookups
|
||||
*/
|
||||
public function __construct($lookups)
|
||||
{
|
||||
foreach ($lookups as $lookup) {
|
||||
$this->lookups[$lookup->getKey()] = $lookup;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
* @return LookupInterface
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function getLookup($type)
|
||||
{
|
||||
if (!array_key_exists($type, $this->lookups)) {
|
||||
throw new \InvalidArgumentException(sprintf('Lookup with key "%s" does not exist', $type));
|
||||
}
|
||||
|
||||
return $this->lookups[$type];
|
||||
}
|
||||
}
|
102
Type/TypeConfiguration.php
Normal file
102
Type/TypeConfiguration.php
Normal file
|
@ -0,0 +1,102 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Type;
|
||||
|
||||
/**
|
||||
* A data object that contains configuration information about a specific type.
|
||||
*
|
||||
* @author Tim Nagel <tim@nagel.com.au>
|
||||
*/
|
||||
final class TypeConfiguration
|
||||
{
|
||||
/**
|
||||
* The identifier property that is used to retrieve an identifier from the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $identifierProperty;
|
||||
|
||||
/**
|
||||
* Returns the fully qualified class for the model that this type represents.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $modelClass;
|
||||
|
||||
/**
|
||||
* Returns the repository method that will create a query builder or associated
|
||||
* query object for lookup purposes.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $repositoryMethod;
|
||||
|
||||
/**
|
||||
* Returns the name of the type.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $type;
|
||||
|
||||
/**
|
||||
* If the lookup should hydrate models to objects or leave data as an array.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $hydrate = true;
|
||||
|
||||
/**
|
||||
* If the type should ignore missing results from a lookup.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $ignoreMissing = false;
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
public function isHydrate()
|
||||
{
|
||||
return $this->hydrate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getIdentifierProperty()
|
||||
{
|
||||
return $this->identifierProperty;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
public function isIgnoreMissing()
|
||||
{
|
||||
return $this->ignoreMissing;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getModelClass()
|
||||
{
|
||||
return $this->modelClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getRepositoryMethod()
|
||||
{
|
||||
return $this->repositoryMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@
|
|||
],
|
||||
"require": {
|
||||
"php": ">=5.3.2",
|
||||
"doctrine/inflector": "~1.0",
|
||||
"symfony/framework-bundle": "~2.3",
|
||||
"symfony/console": "~2.1",
|
||||
"symfony/form": "~2.1",
|
||||
|
|
Loading…
Reference in a new issue