Skip to content

Commit

Permalink
Merge pull request #184 from lilHermit/fixes/honour-hydration-options…
Browse files Browse the repository at this point in the history
…-of-embeds

Fixes/honour hydration options of embeds
  • Loading branch information
lorenzo authored Sep 6, 2018
2 parents e8ee0bf + 642beb7 commit ee06cf6
Show file tree
Hide file tree
Showing 7 changed files with 454 additions and 19 deletions.
43 changes: 42 additions & 1 deletion src/Association/Embedded.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
namespace Cake\ElasticSearch\Association;

use Cake\Core\App;
use Cake\ElasticSearch\Index;
use Cake\Utility\Inflector;

/**
Expand Down Expand Up @@ -46,6 +47,13 @@ abstract class Embedded
*/
protected $property;

/**
* The index class this embed is linked to
*
* @var string
*/
protected $indexClass;

/**
* Constructor
*
Expand All @@ -57,7 +65,8 @@ public function __construct($alias, $options = [])
$this->alias = $alias;
$properties = [
'entityClass',
'property'
'property',
'indexClass'
];
$options += [
'entityClass' => $alias
Expand Down Expand Up @@ -119,6 +128,38 @@ public function entityClass($name = null)
return $this->entityClass;
}

/**
* Get/set the index class used for this embed.
*
* @param string|null|Index $name The class name to set.
*
* @return string The class name.
*/
public function indexClass($name = null)
{
if ($name === null && !$this->indexClass) {
$alias = Inflector::pluralize($this->alias);
$class = App::className($alias . 'Index', 'Model/Index');

if ($class) {
return $this->indexClass = $class;
} else {
return $this->indexClass = '\Cake\ElasticSearch\Index';
}
}

if ($name !== null) {
if ($name instanceof Index) {
$this->indexClass = get_class($name);
} elseif (is_string($name)) {
$class = App::className($name, 'Model/Index');
$this->indexClass = $class;
}
}

return $this->indexClass;
}

/**
* Get the alias for this embed.
*
Expand Down
66 changes: 48 additions & 18 deletions src/Marshaller.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,26 @@ public function __construct(Index $index)
public function one(array $data, array $options = [])
{
$entityClass = $this->index->entityClass();
$entity = new $entityClass();
$entity = $this->createAndHydrate($entityClass, $data, $options);
$entity->setSource($this->index->getRegistryAlias());

return $entity;
}

/**
* Creates and Hydrates Document whilst honouring accessibleFields etc
*
* @param string $class Class name of Document to create
* @param array $data The data to hydrate with
* @param array $options Options to control the hydration
* @param string $indexClass Index class to get embeds from (for nesting)
*
* @return Document
*/
protected function createAndHydrate($class, array $data, array $options = [], $indexClass = null)
{
$entity = new $class();

$options += ['associated' => []];

list($data, $options) = $this->_prepareDataAndOptions($data, $options);
Expand All @@ -77,24 +95,34 @@ public function one(array $data, array $options = [])
unset($data[$badKey]);
}

foreach ($this->index->embedded() as $embed) {
if ($indexClass === null) {
$embeds = $this->index->embedded();
} else {
$index = IndexRegistry::get($indexClass);
$embeds = $index->embedded();
}

foreach ($embeds as $embed) {
$property = $embed->property();
if (in_array($embed->getAlias(), $options['associated']) &&
isset($data[$property])
) {
$data[$property] = $this->newNested($embed, $data[$property]);
$alias = $embed->getAlias();
if (isset($data[$property])) {
if (isset($options['associated'][$alias])) {
$entity->set($property, $this->newNested($embed, $data[$property], $options['associated'][$alias]));
unset($data[$property]);
} elseif (in_array($alias, $options['associated'])) {
$entity->set($property, $this->newNested($embed, $data[$property]));
unset($data[$property]);
}
}
}

if (!isset($options['fieldList'])) {
$entity->set($data);

return $entity;
}

foreach ((array)$options['fieldList'] as $field) {
if (array_key_exists($field, $data)) {
$entity->set($field, $data[$field]);
} else {
foreach ((array)$options['fieldList'] as $field) {
if (array_key_exists($field, $data)) {
$entity->set($field, $data[$field]);
}
}
}

Expand All @@ -104,22 +132,24 @@ public function one(array $data, array $options = [])
/**
* Marshal an embedded document.
*
* @param \Cake\ElasticSearch\Association\Embedded $embed The embed definition.
* @param array $data The data to marshal
* @param \Cake\ElasticSearch\Association\Embedded $embed The embed definition.
* @param array $data The data to marshal
* @param array $options The options to pass on
*
* @return array|\Cake\ElasticSearch\Document Either a document or an array of documents.
*/
protected function newNested(Embedded $embed, array $data)
protected function newNested(Embedded $embed, array $data, array $options = [])
{
$class = $embed->entityClass();
if ($embed->type() === Embedded::ONE_TO_ONE) {
return new $class($data);
return $this->createAndHydrate($class, $data, $options, $embed->indexClass());
}

if ($embed->type() === Embedded::ONE_TO_MANY) {
$children = [];
foreach ($data as $row) {
if (is_array($row)) {
$children[] = new $class($row);
$children[] = $this->createAndHydrate($class, $row, $options, $embed->indexClass());
}
}

Expand Down
18 changes: 18 additions & 0 deletions tests/TestCase/EmbeddedDocumentTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ public function testEmbedOne()
$this->assertNull($this->index->embedOne('Address'));
$assocs = $this->index->embedded();
$this->assertCount(1, $assocs);
$this->assertInstanceOf('Cake\ElasticSearch\Association\EmbedOne', $assocs[0]);
$this->assertEquals('\Cake\ElasticSearch\Document', $assocs[0]->entityClass());
$this->assertEquals('\Cake\ElasticSearch\Index', $assocs[0]->indexClass());
$this->assertEquals('address', $assocs[0]->property());
}

Expand Down Expand Up @@ -115,6 +117,22 @@ public function testFindWithEmbedOne()
$this->assertCount(1, $rows);
}

/**
* Test defining many embedded documents.
*
* @return void
*/
public function testEmbedMany()
{
$this->assertNull($this->index->embedMany('Address'));
$assocs = $this->index->embedded();
$this->assertCount(1, $assocs);
$this->assertInstanceOf('Cake\ElasticSearch\Association\EmbedMany', $assocs[0]);
$this->assertEquals('\Cake\ElasticSearch\Document', $assocs[0]->entityClass());
$this->assertEquals('\Cake\ElasticSearch\Index', $assocs[0]->indexClass());
$this->assertEquals('address', $assocs[0]->property());
}

/**
* Test fetching with embedded has many documents.
*
Expand Down
Loading

0 comments on commit ee06cf6

Please sign in to comment.