Merge remote-tracking branch 'cup-of-giraf/nested'

Conflicts:
	DependencyInjection/Configuration.php
This commit is contained in:
Richard Miller 2012-11-28 21:13:04 +00:00
commit 62b28a813e
7 changed files with 203 additions and 4 deletions

View file

@ -267,6 +267,13 @@ class Configuration
->end()
->end()
->end()
->arrayNode('_parent')
->treatNullLike(array())
->children()
->scalarNode('type')->end()
->scalarNode('identifier')->defaultValue('id')->end()
->end()
->end()
->arrayNode('properties')
->useAttributeAsKey('name')
->prototype('array')

View file

@ -40,7 +40,6 @@ abstract class AbstractProvider extends BaseAbstractProvider
if ($loggerClosure) {
$stepStartTime = microtime(true);
}
$objects = $this->fetchSlice($queryBuilder, $this->options['batch_size'], $offset);
$this->objectPersister->insertMany($objects);

View file

@ -139,6 +139,41 @@ Elasticsearch type is comparable to Doctrine entity repository.
Our type is now available as a service: `foq_elastica.index.website.user`. It is an instance of `Elastica_Type`.
### Declaring parent field
foq_elastica:
clients:
default: { host: localhost, port: 9200 }
indexes:
website:
client: default
types:
comment:
mappings:
post: {_parent: { type: "post", identifier: "id" } }
date: { boost: 5 }
content: ~
### Declaring `nested` or `object`
foq_elastica:
clients:
default: { host: localhost, port: 9200 }
indexes:
website:
client: default
types:
post:
mappings:
date: { boost: 5 }
title: { boost: 3 }
content: ~
comments:
type: "nested"
properties:
date: { boost: 5 }
content: ~
### Populate the types
php app/console foq:elastica:populate

View file

@ -58,7 +58,27 @@ class Resetter
$type = $indexConfig['index']->getType($typeName);
$type->delete();
$type->setMapping($indexConfig['config']['mappings'][$typeName]['properties']);
$mapping = $this->createMapping($indexConfig['config']['mappings'][$typeName]);
$type->setMapping($mapping);
}
/**
* create type mapping object
*
* @param array $indexConfig
* @return Elastica_Type_Mapping
*/
protected function createMapping($indexConfig)
{
$mapping = \Elastica_Type_Mapping::create($indexConfig['properties']);
foreach($indexConfig['properties'] as $field => $type) {
if (!empty($type['_parent']) && $type['_parent'] !== '~') {
$mapping->setParam('_parent', array('type' => $type['_parent']['type']));
}
}
return $mapping;
}
/**

View file

@ -29,6 +29,17 @@ class ResetterTest extends \PHPUnit_Framework_TestCase
),
),
),
'parent' => array(
'index' => $this->getMockElasticaIndex(),
'config' => array(
'mappings' => array(
'a' => array('properties' => array(
'field_1' => array('_parent' => array('type' => 'b', 'identifier' => 'id')),
'field_2' => array())),
'b' => array('properties' => array()),
),
),
),
);
}
@ -80,9 +91,10 @@ class ResetterTest extends \PHPUnit_Framework_TestCase
$type->expects($this->once())
->method('delete');
$mapping = \Elastica_Type_Mapping::create($this->indexConfigsByName['foo']['config']['mappings']['a']['properties']);
$type->expects($this->once())
->method('setMapping')
->with($this->indexConfigsByName['foo']['config']['mappings']['a']['properties']);
->with($mapping);
$resetter = new Resetter($this->indexConfigsByName);
$resetter->resetIndexType('foo', 'a');
@ -106,6 +118,28 @@ class ResetterTest extends \PHPUnit_Framework_TestCase
$resetter->resetIndexType('foo', 'c');
}
public function testIndexMappingForParent()
{
$type = $this->getMockElasticaType();
$this->indexConfigsByName['parent']['index']->expects($this->once())
->method('getType')
->with('a')
->will($this->returnValue($type));
$type->expects($this->once())
->method('delete');
$mapping = \Elastica_Type_Mapping::create($this->indexConfigsByName['parent']['config']['mappings']['a']['properties']);
$mapping->setParam('_parent', array('type' => 'b'));
$type->expects($this->once())
->method('setMapping')
->with($mapping);
$resetter = new Resetter($this->indexConfigsByName);
$resetter->resetIndexType('parent', 'a');
}
/**
* @return Elastica_Index
*/

View file

@ -92,6 +92,19 @@ class POPO
{
return $this->file;
}
public function getSub()
{
return array(
(object) array('foo' => 'foo', 'bar' => 'foo', 'id' => 1),
(object) array('foo' => 'bar', 'bar' => 'bar', 'id' => 2),
);
}
public function getUpper()
{
return (object) array('id' => 'parent', 'name' => 'a random name');
}
}
class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase
@ -215,4 +228,66 @@ class ModelToElasticaAutoTransformerTest extends \PHPUnit_Framework_TestCase
base64_encode(file_get_contents(__DIR__ . '/../fixtures/attachment.odt')), $data['fileContents']
);
}
public function testNestedMapping()
{
$transformer = new ModelToElasticaAutoTransformer();
$document = $transformer->transform(new POPO(), array(
'sub' => array(
'type' => 'nested',
'properties' => array('foo' => '~')
)
));
$data = $document->getData();
$this->assertTrue(array_key_exists('sub', $data));
$this->assertInternalType('array', $data['sub']);
$this->assertEquals(array(
array('foo' => 'foo'),
array('foo' => 'bar')
), $data['sub']);
}
public function tesObjectMapping()
{
$transformer = new ModelToElasticaAutoTransformer();
$document = $transformer->transform(new POPO(), array(
'sub' => array(
'type' => 'object',
'properties' => array('bar')
)
));
$data = $document->getData();
$this->assertTrue(array_key_exists('sub', $data));
$this->assertInternalType('array', $data['sub']);
$this->assertEquals(array(
array('bar' => 'foo'),
array('bar' => 'bar')
), $data['sub']);
}
public function testParentMapping()
{
$transformer = new ModelToElasticaAutoTransformer();
$document = $transformer->transform(new POPO(), array(
'upper' => array(
'_parent' => array('type' => 'upper', 'identifier' => 'id'),
)
));
$this->assertEquals("parent", $document->getParent());
}
public function testParentMappingWithCustomIdentifier()
{
$transformer = new ModelToElasticaAutoTransformer();
$document = $transformer->transform(new POPO(), array(
'upper' => array(
'_parent' => array('type' => 'upper', 'identifier' => 'name'),
)
));
$this->assertEquals("a random name", $document->getParent());
}
}

View file

@ -45,7 +45,17 @@ class ModelToElasticaAutoTransformer implements ModelToElasticaTransformerInterf
$document = new \Elastica_Document($identifier);
foreach ($fields as $key => $mapping) {
$property = new PropertyPath($key);
if (isset($mapping['type']) && $mapping['type'] == 'attachment') {
if (!empty($mapping['_parent']) && $mapping['_parent'] !== '~') {
$parent = $property->getValue($object);
$identifierProperty = new PropertyPath($mapping['_parent']['identifier']);
$document->setParent($identifierProperty->getValue($parent));
} else if (isset($mapping['type']) && in_array($mapping['type'], array('nested', 'object'))) {
$submapping = $mapping['properties'];
$subcollection = $property->getValue($object);
$document->add($key, $this->transformNested($subcollection, $submapping, $document));
} else if (isset($mapping['type']) && $mapping['type'] == 'multi_field') {
throw new \Exception('Please implement me !');
} else if (isset($mapping['type']) && $mapping['type'] == 'attachment') {
$attachment = $property->getValue($object);
if ($attachment instanceof \SplFileInfo) {
$document->addFile($key, $attachment->getPathName());
@ -59,6 +69,25 @@ class ModelToElasticaAutoTransformer implements ModelToElasticaTransformerInterf
return $document;
}
/**
* transform a nested document or an object property into an array of ElasticaDocument
*
* @param array $objects the object to convert
* @param array $fields the keys we want to have in the returned array
* @param Elastica_Document $parent the parent document
* @return array
*/
protected function transformNested($objects, array $fields, $parent)
{
$documents = array();
foreach($objects as $object) {
$document = $this->transform($object, $fields);
$documents[] = $document->getData();
}
return $documents;
}
/**
* Attempts to convert any type to a string or an array of strings
*