Merge remote-tracking branch 'origin/serializer-transformer' into serializer-integration

Conflicts:
	DependencyInjection/FOSElasticaExtension.php
	Resources/config/config.xml
This commit is contained in:
Damien Alexandre 2013-11-29 10:07:13 +01:00
commit d546b4d3f3
7 changed files with 351 additions and 15 deletions

View file

@ -16,6 +16,7 @@ class FOSElasticaExtension extends Extension
protected $indexConfigs = array();
protected $typeFields = array();
protected $loadedDrivers = array();
protected $serializerConfig = array();
public function load(array $configs, ContainerBuilder $container)
{
@ -40,8 +41,8 @@ class FOSElasticaExtension extends Extension
}
$clientIdsByName = $this->loadClients($config['clients'], $container);
$serializerConfig = isset($config['serializer']) ? $config['serializer'] : null;
$indexIdsByName = $this->loadIndexes($config['indexes'], $container, $clientIdsByName, $config['default_client'], $serializerConfig);
$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);
@ -94,7 +95,7 @@ class FOSElasticaExtension extends Extension
* @throws \InvalidArgumentException
* @return array
*/
protected function loadIndexes(array $indexes, ContainerBuilder $container, array $clientIdsByName, $defaultClientName, $serializerConfig)
protected function loadIndexes(array $indexes, ContainerBuilder $container, array $clientIdsByName, $defaultClientName)
{
$indexIds = array();
foreach ($indexes as $name => $index) {
@ -129,7 +130,7 @@ class FOSElasticaExtension extends Extension
if (!empty($index['settings'])) {
$this->indexConfigs[$name]['config']['settings'] = $index['settings'];
}
$this->loadTypes(isset($index['types']) ? $index['types'] : array(), $container, $name, $indexId, $typePrototypeConfig, $serializerConfig);
$this->loadTypes(isset($index['types']) ? $index['types'] : array(), $container, $name, $indexId, $typePrototypeConfig);
}
return $indexIds;
@ -171,7 +172,7 @@ class FOSElasticaExtension extends Extension
* @param $indexId
* @param array $typePrototypeConfig
*/
protected function loadTypes(array $types, ContainerBuilder $container, $indexName, $indexId, array $typePrototypeConfig, $serializerConfig)
protected function loadTypes(array $types, ContainerBuilder $container, $indexName, $indexId, array $typePrototypeConfig)
{
foreach ($types as $name => $type) {
$type = self::deepArrayUnion($typePrototypeConfig, $type);
@ -180,12 +181,12 @@ class FOSElasticaExtension extends Extension
$typeDef = new Definition('%fos_elastica.type.class%', $typeDefArgs);
$typeDef->setFactoryService($indexId);
$typeDef->setFactoryMethod('getType');
if ($serializerConfig) {
$callbackDef = new Definition($serializerConfig['callback_class']);
if ($this->serializerConfig) {
$callbackDef = new Definition($this->serializerConfig['callback_class']);
$callbackId = sprintf('%s.%s.serializer.callback', $indexId, $name);
$typeDef->addMethodCall('setSerializer', array(array(new Reference($callbackId), 'serialize')));
$callbackDef->addMethodCall('setSerializer', array(new Reference($serializerConfig['serializer'])));
$callbackDef->addMethodCall('setSerializer', array(new Reference($this->serializerConfig['serializer'])));
if (isset($type['serializer']['groups'])) {
$callbackDef->addMethodCall('setGroups', array($type['serializer']['groups']));
}
@ -324,8 +325,14 @@ class FOSElasticaExtension extends Extension
return $typeConfig['model_to_elastica_transformer']['service'];
}
if ($this->serializerConfig) {
$abstractId = sprintf('fos_elastica.model_to_elastica_identifier_transformer');
} else {
$abstractId = sprintf('fos_elastica.model_to_elastica_transformer');
}
$serviceId = sprintf('fos_elastica.model_to_elastica_transformer.%s.%s', $indexName, $typeName);
$serviceDef = new DefinitionDecorator('fos_elastica.model_to_elastica_transformer');
$serviceDef = new DefinitionDecorator($abstractId);
$serviceDef->replaceArgument(0, array(
'identifier' => $typeConfig['identifier']
));
@ -336,12 +343,24 @@ class FOSElasticaExtension extends Extension
protected function loadObjectPersister(array $typeConfig, Definition $typeDef, ContainerBuilder $container, $indexName, $typeName, $transformerId)
{
$arguments = array(
$typeDef,
new Reference($transformerId),
$typeConfig['model'],
);
if ($this->serializerConfig) {
$abstractId = 'fos_elastica.object_serializer_persister';
} else {
$abstractId = 'fos_elastica.object_persister';
$arguments[] = $this->typeFields[sprintf('%s/%s', $indexName, $typeName)];
}
$serviceId = sprintf('fos_elastica.object_persister.%s.%s', $indexName, $typeName);
$serviceDef = new DefinitionDecorator('fos_elastica.object_persister');
$serviceDef->replaceArgument(0, $typeDef);
$serviceDef->replaceArgument(1, new Reference($transformerId));
$serviceDef->replaceArgument(2, $typeConfig['model']);
$serviceDef->replaceArgument(3, $this->typeFields[sprintf('%s/%s', $indexName, $typeName)]);
$serviceDef = new DefinitionDecorator($abstractId);
foreach ($arguments as $i => $argument) {
$serviceDef->replaceArgument($i, $argument);
}
$container->setDefinition($serviceId, $serviceDef);
return $serviceId;

View file

@ -0,0 +1,97 @@
<?php
namespace FOS\ElasticaBundle\Persister;
use Elastica\Type;
use FOS\ElasticaBundle\Transformer\ModelToElasticaTransformerInterface;
/**
* Inserts, replaces and deletes single objects in an elastica type, making use
* of elastica's serializer support to convert objects in to elastica documents.
* Accepts domain model objects and passes them directly to elastica
*
* @author Lea Haensenberber <lea.haensenberger@gmail.com>
*/
class ObjectSerializerPersister extends ObjectPersister
{
public function __construct(Type $type, ModelToElasticaTransformerInterface $transformer, $objectClass)
{
$this->type = $type;
$this->transformer = $transformer;
$this->objectClass = $objectClass;
}
/**
* Insert one object into the type
* The object will be transformed to an elastica document
*
* @param object $object
*/
public function insertOne($object)
{
$document = $this->transformToElasticaDocument($object);
$this->type->addObject($object, $document);
}
/**
* Replaces one object in the type
*
* @param object $object
* @return null
*/
public function replaceOne($object)
{
$document = $this->transformToElasticaDocument($object);
$this->type->deleteById($document->getId());
$this->type->addObject($object, $document);
}
/**
* Deletes one object in the type
*
* @param object $object
* @return null
**/
public function deleteOne($object)
{
$document = $this->transformToElasticaDocument($object);
$this->type->deleteById($document->getId());
}
/**
* Deletes one object in the type by id
*
* @param mixed $id
*
* @return null
**/
public function deleteById($id)
{
$this->type->deleteById($id);
}
/**
* Inserts an array of objects in the type
*
* @param array $objects array of domain model objects
**/
public function insertMany(array $objects)
{
foreach ($objects as $object) {
$this->insertOne($object);
}
}
/**
* Transforms an object to an elastica document
* with just the identifier set
*
* @param object $object
* @return Document the elastica document
*/
public function transformToElasticaDocument($object)
{
return $this->transformer->transform($object, array());
}
}

View file

@ -49,6 +49,12 @@
<argument /> <!-- transformer -->
</service>
<service id="fos_elastica.object_serializer_persister" class="FOS\ElasticaBundle\Persister\ObjectSerializerPersister" abstract="true">
<argument /> <!-- type -->
<argument /> <!-- model to elastica transformer -->
<argument /> <!-- model -->
</service>
<service id="fos_elastica.model_to_elastica_transformer" class="FOS\ElasticaBundle\Transformer\ModelToElasticaAutoTransformer" public="false" abstract="true">
<argument /> <!-- options -->
<call method="setPropertyAccessor">
@ -56,6 +62,13 @@
</call>
</service>
<service id="fos_elastica.model_to_elastica_identifier_transformer" class="FOS\ElasticaBundle\Transformer\ModelToElasticaIdentifierTransformer" 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>

View file

@ -0,0 +1,117 @@
<?php
namespace FOS\ElasticaBundle\Tests\ObjectSerializerPersister;
use FOS\ElasticaBundle\Persister\ObjectPersister;
use FOS\ElasticaBundle\Persister\ObjectSerializerPersister;
use FOS\ElasticaBundle\Transformer\ModelToElasticaAutoTransformer;
use FOS\ElasticaBundle\Transformer\ModelToElasticaIdentifierTransformer;
use Symfony\Component\PropertyAccess\PropertyAccess;
class POPO
{
public $id = 123;
public $name = 'popoName';
public function getId()
{
return $this->id;
}
public function getName()
{
return $this->name;
}
}
class ObjectSerializerPersisterTest extends \PHPUnit_Framework_TestCase
{
public function setUp()
{
if (!class_exists('Elastica\Type')) {
$this->markTestSkipped('The Elastica library classes are not available');
}
}
public function testThatCanReplaceObject()
{
$transformer = $this->getTransformer();
/** @var $typeMock \PHPUnit_Framework_MockObject_MockObject|\Elastica\Type */
$typeMock = $this->getMockBuilder('Elastica\Type')
->disableOriginalConstructor()
->getMock();
$typeMock->expects($this->once())
->method('deleteById')
->with($this->equalTo(123));
$typeMock->expects($this->once())
->method('addObject');
$objectPersister = new ObjectSerializerPersister($typeMock, $transformer, 'SomeClass');
$objectPersister->replaceOne(new POPO());
}
public function testThatCanInsertObject()
{
$transformer = $this->getTransformer();
/** @var $typeMock \PHPUnit_Framework_MockObject_MockObject|\Elastica\Type */
$typeMock = $this->getMockBuilder('Elastica\Type')
->disableOriginalConstructor()
->getMock();
$typeMock->expects($this->never())
->method('deleteById');
$typeMock->expects($this->once())
->method('addObject');
$objectPersister = new ObjectSerializerPersister($typeMock, $transformer, 'SomeClass');
$objectPersister->insertOne(new POPO());
}
public function testThatCanDeleteObject()
{
$transformer = $this->getTransformer();
/** @var $typeMock \PHPUnit_Framework_MockObject_MockObject|\Elastica\Type */
$typeMock = $this->getMockBuilder('Elastica\Type')
->disableOriginalConstructor()
->getMock();
$typeMock->expects($this->once())
->method('deleteById');
$typeMock->expects($this->never())
->method('addObject');
$objectPersister = new ObjectSerializerPersister($typeMock, $transformer, 'SomeClass');
$objectPersister->deleteOne(new POPO());
}
public function testThatCanInsertManyObjects()
{
$transformer = $this->getTransformer();
/** @var $typeMock \PHPUnit_Framework_MockObject_MockObject|\Elastica\Type */
$typeMock = $this->getMockBuilder('Elastica\Type')
->disableOriginalConstructor()
->getMock();
$typeMock->expects($this->never())
->method('deleteById');
$typeMock->expects($this->exactly(2))
->method('addObject');
$typeMock->expects($this->never())
->method('addObjects');
$objectPersister = new ObjectSerializerPersister($typeMock, $transformer, 'SomeClass');
$objectPersister->insertMany(array(new POPO(), new POPO()));
}
/**
* @return ModelToElasticaIdentifierTransformer
*/
private function getTransformer()
{
$transformer = new ModelToElasticaIdentifierTransformer();
$transformer->setPropertyAccessor(PropertyAccess::getPropertyAccessor());
return $transformer;
}
}

View file

@ -118,7 +118,6 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase
public function setUp()
{
if (!class_exists('Elastica\Document')) {
;
$this->markTestSkipped('The Elastica library classes are not available');
}
}

View file

@ -0,0 +1,65 @@
<?php
namespace FOS\ElasticaBundle\Tests\Transformer\ModelToElasticaIdentifierTransformer;
use FOS\ElasticaBundle\Transformer\ModelToElasticaIdentifierTransformer;
use Symfony\Component\PropertyAccess\PropertyAccess;
class POPO
{
protected $id = 123;
protected $name = 'Name';
public function getId()
{
return $this->id;
}
public function getName()
{
return $this->name;
}
}
class ModelToElasticaIdentifierTransformerTest extends \PHPUnit_Framework_TestCase
{
public function setUp()
{
if (!class_exists('Elastica\Document')) {
$this->markTestSkipped('The Elastica library classes are not available');
}
}
public function testGetDocumentWithIdentifierOnly()
{
$transformer = $this->getTransformer();
$document = $transformer->transform(new POPO(), array());
$data = $document->getData();
$this->assertInstanceOf('Elastica\Document', $document);
$this->assertEquals(123, $document->getId());
$this->assertCount(0, $data);
}
public function testGetDocumentWithIdentifierOnlyWithFields()
{
$transformer = $this->getTransformer();
$document = $transformer->transform(new POPO(), array('name' => array()));
$data = $document->getData();
$this->assertInstanceOf('Elastica\Document', $document);
$this->assertEquals(123, $document->getId());
$this->assertCount(0, $data);
}
/**
* @return ModelToElasticaIdentifierTransformer
*/
private function getTransformer()
{
$transformer = new ModelToElasticaIdentifierTransformer();
$transformer->setPropertyAccessor(PropertyAccess::getPropertyAccessor());
return $transformer;
}
}

View file

@ -0,0 +1,26 @@
<?php
namespace FOS\ElasticaBundle\Transformer;
use Elastica\Document;
/**
* Creates an Elastica document with the ID of
* the Doctrine object as Elastica document ID
*/
class ModelToElasticaIdentifierTransformer extends ModelToElasticaAutoTransformer
{
/**
* Creates an elastica document with the id of the doctrine object as id
*
* @param object $object the object to convert
* @param array $fields the keys we want to have in the returned array
*
* @return Document
**/
public function transform($object, array $fields)
{
$identifier = $this->propertyAccessor->getValue($object, $this->options['identifier']);
return new Document($identifier);
}
}