Added finder capability for an index
This commit is contained in:
parent
fdc0d3c227
commit
9c4ef3d8bd
48
DependencyInjection/Compiler/TransformerPass.php
Normal file
48
DependencyInjection/Compiler/TransformerPass.php
Normal file
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
namespace FOQ\ElasticaBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\DefinitionDecorator;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Registers Transformer implementations into the TransformerCollection.
|
||||
*
|
||||
* @author Tim Nagel <tim@nagel.com.au>
|
||||
*/
|
||||
class TransformerPass implements CompilerPassInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
if (!$container->hasDefinition('foq_elastica.elastica_to_model_transformer.collection.prototype')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$transformers = array();
|
||||
|
||||
foreach ($container->findTaggedServiceIds('foq_elastica.elastica_to_model_transformer') as $id => $tags) {
|
||||
foreach ($tags as $tag) {
|
||||
if (empty($tag['index']) || empty($tag['type'])) {
|
||||
throw new InvalidArgumentException('The Transformer must have both a type and an index defined.');
|
||||
}
|
||||
|
||||
$transformers[$tag['index']][$tag['type']]= new Reference($id);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($transformers as $index => $indexTransformers) {
|
||||
if (!$container->hasDefinition(sprintf('foq_elastica.elastica_to_model_transformer.collection.%s', $index))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$index = $container->getDefinition(sprintf('foq_elastica.elastica_to_model_transformer.collection.%s', $index));
|
||||
$index->replaceArgument(0, $indexTransformers);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -71,6 +71,7 @@ class Configuration
|
|||
->performNoDeepMerging()
|
||||
->children()
|
||||
->scalarNode('client')->end()
|
||||
->scalarNode('finder')->end()
|
||||
->arrayNode('type_prototype')
|
||||
->children()
|
||||
->arrayNode('persistence')
|
||||
|
|
|
@ -113,6 +113,9 @@ class FOQElasticaExtension extends Extension
|
|||
'mappings' => array()
|
||||
)
|
||||
);
|
||||
if (isset($index['finder'])) {
|
||||
$this->loadIndexFinder($container, $name, $indexId);
|
||||
}
|
||||
if (!empty($index['settings'])) {
|
||||
$this->indexConfigs[$name]['config']['settings'] = $index['settings'];
|
||||
}
|
||||
|
@ -122,6 +125,32 @@ class FOQElasticaExtension extends Extension
|
|||
return $indexIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the configured index finders.
|
||||
*
|
||||
* @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
|
||||
* @param string $name The index name
|
||||
* @param string $indexId The index service identifier
|
||||
* @return string
|
||||
*/
|
||||
protected function loadIndexFinder(ContainerBuilder $container, $name, $indexId)
|
||||
{
|
||||
$abstractTransformerId = 'foq_elastica.elastica_to_model_transformer.collection.prototype';
|
||||
$transformerId = sprintf('foq_elastica.elastica_to_model_transformer.collection.%s', $name);
|
||||
$transformerDef = new DefinitionDecorator($abstractTransformerId);
|
||||
$container->setDefinition($transformerId, $transformerDef);
|
||||
|
||||
$abstractFinderId = 'foq_elastica.finder.prototype';
|
||||
$finderId = sprintf('foq_elastica.finder.%s', $name);
|
||||
$finderDef = new DefinitionDecorator($abstractFinderId);
|
||||
$finderDef->replaceArgument(0, new Reference($indexId));
|
||||
$finderDef->replaceArgument(1, new Reference($transformerId));
|
||||
|
||||
$container->setDefinition($finderId, $finderDef);
|
||||
|
||||
return $finderId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the configured types.
|
||||
*
|
||||
|
@ -203,6 +232,7 @@ class FOQElasticaExtension extends Extension
|
|||
$abstractId = sprintf('foq_elastica.elastica_to_model_transformer.prototype.%s', $typeConfig['driver']);
|
||||
$serviceId = sprintf('foq_elastica.elastica_to_model_transformer.%s.%s', $indexName, $typeName);
|
||||
$serviceDef = new DefinitionDecorator($abstractId);
|
||||
$serviceDef->addTag('foq_elastica.elastica_to_model_transformer', array('type' => $typeName, 'index' => $indexName));
|
||||
|
||||
// Doctrine has a mandatory service as first argument
|
||||
$argPos = ('propel' === $typeConfig['driver']) ? 0 : 1;
|
||||
|
@ -379,5 +409,4 @@ class FOQElasticaExtension extends Extension
|
|||
|
||||
$container->setAlias('foq_elastica.manager', sprintf('foq_elastica.manager.%s', $defaultManagerService));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -48,6 +48,16 @@ abstract class AbstractElasticaToModelTransformer implements ElasticaToModelTran
|
|||
$this->options = array_merge($this->options, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object class that is used for conversion.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getObjectClass()
|
||||
{
|
||||
return $this->objectClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms an array of elastica objects into an array of
|
||||
* model objects fetched from the doctrine repository
|
||||
|
|
|
@ -5,6 +5,7 @@ namespace FOQ\ElasticaBundle;
|
|||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||
use FOQ\ElasticaBundle\DependencyInjection\Compiler\AddProviderPass;
|
||||
use FOQ\ElasticaBundle\DependencyInjection\Compiler\TransformerPass;
|
||||
|
||||
class FOQElasticaBundle extends Bundle
|
||||
{
|
||||
|
@ -13,5 +14,6 @@ class FOQElasticaBundle extends Bundle
|
|||
parent::build($container);
|
||||
|
||||
$container->addCompilerPass(new AddProviderPass());
|
||||
$container->addCompilerPass(new TransformerPass());
|
||||
}
|
||||
}
|
||||
|
|
19
README.md
19
README.md
|
@ -303,6 +303,25 @@ You can even get paginated results!
|
|||
/** var Pagerfanta\Pagerfanta */
|
||||
$userPaginator = $finder->findPaginated('bob');
|
||||
|
||||
##### Index wide finder
|
||||
|
||||
You can also define a finder that will work on the entire index. Adjust your index
|
||||
configuration as per below:
|
||||
|
||||
foq_elastica:
|
||||
indexes:
|
||||
website:
|
||||
client: default
|
||||
finder:
|
||||
|
||||
You can now use the index wide finder service `foq_elastica.finder.website`:
|
||||
|
||||
/** var FOQ\ElasticaBundle\Finder\MappedFinder */
|
||||
$finder = $container->get('foq_elastica.finder.website');
|
||||
|
||||
// Returns a mixed array of any objects mapped
|
||||
$results = $finder->find('bob');
|
||||
|
||||
### Realtime, selective index update
|
||||
|
||||
If you use the Doctrine integration, you can let ElasticaBundle update the indexes automatically
|
||||
|
|
|
@ -11,6 +11,10 @@
|
|||
<parameter key="foq_elastica.logger.class">FOQ\ElasticaBundle\Logger\ElasticaLogger</parameter>
|
||||
<parameter key="foq_elastica.data_collector.class">FOQ\ElasticaBundle\DataCollector\ElasticaDataCollector</parameter>
|
||||
<parameter key="foq_elastica.manager.class">FOQ\ElasticaBundle\Manager\RepositoryManager</parameter>
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
<parameter key="foq_elastica.elastica_to_model_transformer.collection.class">FOQ\ElasticaBundle\Transformer\ElasticaToModelTransformerCollection</parameter>
|
||||
>>>>>>> Added finder capability for an index
|
||||
</parameters>
|
||||
|
||||
|
||||
|
@ -63,6 +67,10 @@
|
|||
<argument /> <!-- options -->
|
||||
</service>
|
||||
|
||||
<service id="foq_elastica.elastica_to_model_transformer.collection.prototype" class="%foq_elastica.elastica_to_model_transformer.collection.class%" public="true" abstract="true">
|
||||
<argument type="collection" /> <!-- transformers -->
|
||||
<argument type="collection" /> <!-- options -->
|
||||
</service>
|
||||
</services>
|
||||
|
||||
</container>
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
|
||||
namespace FOQ\ElasticaBundle\Tests\Transformer;
|
||||
|
||||
use FOQ\ElasticaBundle\Transformer\ElasticaToModelTransformerCollection;
|
||||
|
||||
class ElasticaToModelTransformerCollectionTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @var \FOQ\ElasticaBundle\Transformer\ElasticaToModelTransformerCollection
|
||||
*/
|
||||
protected $collection;
|
||||
protected $transformers = array();
|
||||
|
||||
protected function collectionSetup()
|
||||
{
|
||||
$transformer1 = $this->getMock('FOQ\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface');
|
||||
$transformer1->expects($this->any())
|
||||
->method('getObjectClass')
|
||||
->will($this->returnValue('FOQ\ElasticaBundle\Tests\Transformer\POPO'));
|
||||
|
||||
$transformer2 = $this->getMock('FOQ\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface');
|
||||
$transformer2->expects($this->any())
|
||||
->method('getObjectClass')
|
||||
->will($this->returnValue('FOQ\ElasticaBundle\Tests\Transformer\POPO2'));
|
||||
|
||||
$this->collection = new ElasticaToModelTransformerCollection($this->transformers = array(
|
||||
'type1' => $transformer1,
|
||||
'type2' => $transformer2,
|
||||
), array());
|
||||
}
|
||||
|
||||
public function testGetObjectClass()
|
||||
{
|
||||
$this->collectionSetup();
|
||||
|
||||
$objectClasses = $this->collection->getObjectClass();
|
||||
$this->assertEquals(array(
|
||||
'type1' => 'FOQ\ElasticaBundle\Tests\Transformer\POPO',
|
||||
'type2' => 'FOQ\ElasticaBundle\Tests\Transformer\POPO2'
|
||||
), $objectClasses);
|
||||
}
|
||||
|
||||
public function testTransformDelegatesToTransformers()
|
||||
{
|
||||
$this->collectionSetup();
|
||||
|
||||
$document1 = new \Elastica_Document(123, array('data' => 'lots of data'), 'type1');
|
||||
$document2 = new \Elastica_Document(124, array('data' => 'not so much data'), 'type2');
|
||||
$result1 = new POPO(123, 'lots of data');
|
||||
$result2 = new POPO2(124, 'not so much data');
|
||||
|
||||
$this->transformers['type1']->expects($this->once())
|
||||
->method('transform')
|
||||
->with(array($document1))
|
||||
->will($this->returnValue(array($result1)));
|
||||
|
||||
$this->transformers['type2']->expects($this->once())
|
||||
->method('transform')
|
||||
->with(array($document2))
|
||||
->will($this->returnValue(array($result2)));
|
||||
|
||||
$results = $this->collection->transform(array($document1, $document2));
|
||||
|
||||
$this->assertEquals(array(
|
||||
$result1,
|
||||
$result2,
|
||||
), $results);
|
||||
}
|
||||
}
|
||||
|
||||
class POPO
|
||||
{
|
||||
public $id;
|
||||
public $data;
|
||||
|
||||
public function __construct($id, $data)
|
||||
{
|
||||
$this->data = $data;
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
}
|
||||
|
||||
class POPO2 extends POPO
|
||||
{
|
||||
|
||||
}
|
65
Transformer/ElasticaToModelTransformerCollection.php
Normal file
65
Transformer/ElasticaToModelTransformerCollection.php
Normal file
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
namespace FOQ\ElasticaBundle\Transformer;
|
||||
|
||||
/**
|
||||
* Holds a collection of transformers for an index wide transformation.
|
||||
*
|
||||
* @author Tim Nagel <tim@nagel.com.au>
|
||||
*/
|
||||
class ElasticaToModelTransformerCollection implements ElasticaToModelTransformerInterface
|
||||
{
|
||||
protected $transformers = array();
|
||||
protected $options = array(
|
||||
'identifier' => 'id'
|
||||
);
|
||||
|
||||
public function __construct(array $transformers, array $options)
|
||||
{
|
||||
$this->transformers = $transformers;
|
||||
$this->options = array_merge($this->options, $options);
|
||||
}
|
||||
|
||||
public function getObjectClass()
|
||||
{
|
||||
return array_map(function ($transformer) {
|
||||
return $transformer->getObjectClass();
|
||||
}, $this->transformers);
|
||||
}
|
||||
|
||||
public function transform(array $elasticaObjects)
|
||||
{
|
||||
$sorted = array();
|
||||
$order = array();
|
||||
foreach ($elasticaObjects as $object) {
|
||||
$sorted[$object->getType()][] = $object;
|
||||
$order[] = sprintf('%s-%s', $object->getType(), $object->getId());
|
||||
}
|
||||
|
||||
$transformed = array();
|
||||
foreach ($sorted AS $type => $objects) {
|
||||
$transformed = array_merge($transformed, $this->transformers[$type]->transform($objects));
|
||||
}
|
||||
|
||||
$positions = array_flip($order);
|
||||
$identifierGetter = 'get' . ucfirst($this->options['identifier']);
|
||||
$classMap = $this->getTypeToClassMap();
|
||||
|
||||
usort($transformed, function($a, $b) use ($positions, $identifierGetter, $classMap)
|
||||
{
|
||||
$aType = array_search(get_class($a), $classMap);
|
||||
$bType = array_search(get_class($b), $classMap);
|
||||
|
||||
return $positions["{$aType}-{$a->$identifierGetter()}"] > $positions["{$bType}-{$b->$identifierGetter()}"];
|
||||
});
|
||||
|
||||
return $transformed;
|
||||
}
|
||||
|
||||
protected function getTypeToClassMap()
|
||||
{
|
||||
return array_map(function ($transformer) {
|
||||
return $transformer->getObjectClass();
|
||||
}, $this->transformers);
|
||||
}
|
||||
}
|
|
@ -15,4 +15,11 @@ interface ElasticaToModelTransformerInterface
|
|||
* @return array of model objects
|
||||
**/
|
||||
function transform(array $elasticaObjects);
|
||||
|
||||
/**
|
||||
* Returns the object class used by the transformer.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function getObjectClass();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue