From c5185a0307dded8f73bf30898f87386a60f0a644 Mon Sep 17 00:00:00 2001 From: Tim Nagel Date: Mon, 9 Feb 2015 09:32:39 +1100 Subject: [PATCH] Added capability to define property paths --- CHANGELOG-3.1.md | 6 +++ Index/MappingBuilder.php | 2 + Resources/doc/cookbook/custom-properties.md | 2 +- Resources/doc/types.md | 28 ++++++++++ Tests/Functional/PropertyPathTest.php | 54 +++++++++++++++++++ Tests/Functional/TypeObj.php | 2 + Tests/Functional/app/ORM/config.yml | 12 +++++ .../ModelToElasticaAutoTransformerTest.php | 14 +++++ .../ModelToElasticaAutoTransformer.php | 11 +++- 9 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 Tests/Functional/PropertyPathTest.php diff --git a/CHANGELOG-3.1.md b/CHANGELOG-3.1.md index fe42514..19bec1f 100644 --- a/CHANGELOG-3.1.md +++ b/CHANGELOG-3.1.md @@ -25,3 +25,9 @@ https://github.com/FriendsOfSymfony/FOSElasticaBundle/compare/v3.0.4...v3.1.0 ProgressBar helper instead of outputting strings. You can use verbosity controls on the command to output additional information like memory usage, runtime and estimated time. + * Added new option `property_path` to a type property definition to allow + customisation of the property path used to retrieve data from objects. + Setting `property_path` to `false` will configure the Transformer to ignore + that property while transforming. Combined with the above POST_TRANSFORM event + developers can now create calculated dynamic properties on Elastica documents + for indexing. #794 diff --git a/Index/MappingBuilder.php b/Index/MappingBuilder.php index 5756751..92beaf7 100644 --- a/Index/MappingBuilder.php +++ b/Index/MappingBuilder.php @@ -110,6 +110,8 @@ class MappingBuilder private function fixProperties(&$properties) { foreach ($properties as $name => &$property) { + unset($property['property_path']); + if (!isset($property['type'])) { $property['type'] = 'string'; } diff --git a/Resources/doc/cookbook/custom-properties.md b/Resources/doc/cookbook/custom-properties.md index cc7751e..1d7687e 100644 --- a/Resources/doc/cookbook/custom-properties.md +++ b/Resources/doc/cookbook/custom-properties.md @@ -1,4 +1,4 @@ -##### Custom Repositories +##### Custom Properties Since FOSElasticaBundle 3.1.0, we now dispatch an event for each transformation of an object into an Elastica document which allows you to set custom properties on the Elastica diff --git a/Resources/doc/types.md b/Resources/doc/types.md index 80d295b..2d575cd 100644 --- a/Resources/doc/types.md +++ b/Resources/doc/types.md @@ -1,6 +1,34 @@ Type configuration ================== +Custom Property Paths +--------------------- + +Since FOSElasticaBundle 3.1.0, it is now possible to define custom property paths +to be used for data retrieval from the underlying model. + +```yaml + user: + mappings: + username: + property_path: indexableUsername + firstName: + property_path: names[first] +``` + +This feature uses the Symfony PropertyAccessor component and supports all features +that the component supports. + +The above example would retrieve an indexed field `username` from the property +`User->indexableUsername`, and the indexed field `firstName` would be populated from a +key `first` from an array on `User->names`. + +Setting the property path to `false` will disable transformation of that value. In this +case the mapping will be created but no value will be populated while indexing. You can +populate this value by listening to the `POST_TRANSFORM` event emitted by this bundle. +See [cookbook/custom-properties.md](cookbook/custom-properties.md) for more information +about this event. + Handling missing results with FOSElasticaBundle ----------------------------------------------- diff --git a/Tests/Functional/PropertyPathTest.php b/Tests/Functional/PropertyPathTest.php new file mode 100644 index 0000000..860cb86 --- /dev/null +++ b/Tests/Functional/PropertyPathTest.php @@ -0,0 +1,54 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace FOS\ElasticaBundle\Tests\Functional; + +use Elastica\Query\Match; + +/** + * @group functional + */ +class PropertyPathTest extends WebTestCase +{ + public function testContainerSource() + { + $client = $this->createClient(array('test_case' => 'ORM')); + /** @var \FOS\ElasticaBundle\Persister\ObjectPersister $persister */ + $persister = $client->getContainer()->get('fos_elastica.object_persister.index.property_paths_type'); + $obj = new TypeObj(); + $obj->coll = 'Hello'; + $persister->insertOne($obj); + + /** @var \Elastica\Index $elClient */ + $index = $client->getContainer()->get('fos_elastica.index.index'); + $index->flush(true); + + $query = new Match(); + $query->setField('something', 'Hello'); + $search = $index->createSearch($query); + + $this->assertEquals(1, $search->count()); + } + + protected function setUp() + { + parent::setUp(); + + $this->deleteTmpDir('Basic'); + } + + protected function tearDown() + { + parent::tearDown(); + + $this->deleteTmpDir('Basic'); + } +} diff --git a/Tests/Functional/TypeObj.php b/Tests/Functional/TypeObj.php index 46e5968..39e9fe9 100644 --- a/Tests/Functional/TypeObj.php +++ b/Tests/Functional/TypeObj.php @@ -13,8 +13,10 @@ namespace FOS\ElasticaBundle\Tests\Functional; class TypeObj { + public $id = 5; public $coll; public $field1; + public $field2; public function isIndexable() { diff --git a/Tests/Functional/app/ORM/config.yml b/Tests/Functional/app/ORM/config.yml index 98c9221..d2ff931 100644 --- a/Tests/Functional/app/ORM/config.yml +++ b/Tests/Functional/app/ORM/config.yml @@ -65,6 +65,18 @@ fos_elastica: provider: ~ listener: is_indexable_callback: [ 'FOS\ElasticaBundle\Tests\Functional\app\ORM\IndexableService', 'isntIndexable' ] + property_paths_type: + persistence: + driver: orm + model: FOS\ElasticaBundle\Tests\Functional\TypeObj + provider: ~ + properties: + field1: + property_path: field2 + something: + property_path: coll + dynamic: + property_path: false second_index: index_name: foselastica_orm_test_second_%kernel.environment% types: diff --git a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php index bb52129..4852037 100644 --- a/Tests/Transformer/ModelToElasticaAutoTransformerTest.php +++ b/Tests/Transformer/ModelToElasticaAutoTransformerTest.php @@ -148,6 +148,20 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase $transformer->transform(new POPO(), array()); } + public function testPropertyPath() + { + $transformer = $this->getTransformer(); + + $document = $transformer->transform(new POPO(), array('name' => array('property_path' => false))); + $this->assertInstanceOf('Elastica\Document', $document); + $this->assertFalse($document->has('name')); + + $document = $transformer->transform(new POPO(), array('realName' => array('property_path' => 'name'))); + $this->assertInstanceOf('Elastica\Document', $document); + $this->assertTrue($document->has('realName')); + $this->assertEquals('someName', $document->get('realName')); + } + public function testThatCanTransformObject() { $transformer = $this->getTransformer(); diff --git a/Transformer/ModelToElasticaAutoTransformer.php b/Transformer/ModelToElasticaAutoTransformer.php index eff29d2..6a9fbca 100644 --- a/Transformer/ModelToElasticaAutoTransformer.php +++ b/Transformer/ModelToElasticaAutoTransformer.php @@ -75,16 +75,24 @@ class ModelToElasticaAutoTransformer implements ModelToElasticaTransformerInterf $property = (null !== $mapping['property'])?$mapping['property']:$mapping['type']; $value = $this->propertyAccessor->getValue($object, $property); $document->setParent($this->propertyAccessor->getValue($value, $mapping['identifier'])); + continue; } - $value = $this->propertyAccessor->getValue($object, $key); + $path = isset($mapping['property_path']) ? + $mapping['property_path'] : + $key; + if (false === $path) { + continue; + } + $value = $this->propertyAccessor->getValue($object, $path); if (isset($mapping['type']) && in_array($mapping['type'], array('nested', 'object')) && isset($mapping['properties']) && !empty($mapping['properties'])) { /* $value is a nested document or object. Transform $value into * an array of documents, respective the mapped properties. */ $document->set($key, $this->transformNested($value, $mapping['properties'])); + continue; } @@ -95,6 +103,7 @@ class ModelToElasticaAutoTransformer implements ModelToElasticaTransformerInterf } else { $document->addFileContent($key, $value); } + continue; }