Added capability to define property paths

This commit is contained in:
Tim Nagel 2015-02-09 09:32:39 +11:00
parent e1d5ef72d2
commit c5185a0307
9 changed files with 129 additions and 2 deletions

View file

@ -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

View file

@ -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';
}

View file

@ -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

View file

@ -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
-----------------------------------------------

View file

@ -0,0 +1,54 @@
<?php
/**
* This file is part of the FOSElasticaBundle project.
*
* (c) Tim Nagel <tim@nagel.com.au>
*
* 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');
}
}

View file

@ -13,8 +13,10 @@ namespace FOS\ElasticaBundle\Tests\Functional;
class TypeObj
{
public $id = 5;
public $coll;
public $field1;
public $field2;
public function isIndexable()
{

View file

@ -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:

View file

@ -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();

View file

@ -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;
}