Skip to content

Commit

Permalink
Fix EntityContext operations on collections.
Browse files Browse the repository at this point in the history
There were a few cases where EntityContext would hit a fatal error when
dealing with collections/arrays. This fixes that and also introduces
a minor optimization for array properties.
  • Loading branch information
markstory committed Feb 12, 2014
1 parent ff74050 commit f031b3c
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 11 deletions.
51 changes: 41 additions & 10 deletions src/View/Form/EntityContext.php
Expand Up @@ -66,6 +66,14 @@ class EntityContext implements ContextInterface {
*/
protected $_rootName;

/**
* Boolean to track whether or not the entity is a
* collection.
*
* @var boolean
*/
protected $_isCollection = false;

/**
* A dictionary of tables
*
Expand Down Expand Up @@ -107,8 +115,8 @@ public function __construct(Request $request, array $context) {
*/
protected function _prepare() {
$table = $this->_context['table'];
$entity = $this->_context['entity'];
if (empty($table)) {
$entity = $this->_context['entity'];
if (is_array($entity) || $entity instanceof Traversable) {
$entity = (new Collection($entity))->first();
}
Expand All @@ -126,6 +134,10 @@ protected function _prepare() {
'Unable to find table class for current entity'
);
}
$this->_isCollection = (
is_array($entity) ||
$entity instanceof Traversable
);
$alias = $this->_rootName = $table->alias();
$this->_tables[$alias] = $table;
}
Expand Down Expand Up @@ -178,8 +190,11 @@ public function val($field) {
return null;
}
$parts = explode('.', $field);
list($entity, $prop) = $this->_getEntity($parts);
return $entity->get(array_pop($parts));
list($entity) = $this->_getEntity($parts);
if ($entity instanceof Entity) {
return $entity->get(array_pop($parts));
}
return null;
}

/**
Expand All @@ -194,8 +209,12 @@ public function val($field) {
* @throws \RuntimeException When properties cannot be read.
*/
protected function _getEntity($path) {
$oneElement = count($path) === 1;
if ($oneElement && $this->_isCollection) {
return [false, false];
}
$entity = $this->_context['entity'];
if (count($path) === 1) {
if ($oneElement) {
return [$entity, $this->_rootName];
}

Expand Down Expand Up @@ -228,14 +247,20 @@ protected function _getEntity($path) {
* @return mixed
*/
protected function _getProp($target, $field) {
if (is_array($target) || $target instanceof Traversable) {
if (is_array($target) && isset($target[$field])) {
return $target[$field];
}
if ($target instanceof Entity) {
return $target->get($field);
}
if ($target instanceof Traversable) {
foreach ($target as $i => $val) {
if ($i == $field) {
return $val;
}
}
return false;
}
return $target->get($field);
}

/**
Expand All @@ -251,12 +276,17 @@ public function isRequired($field) {
$parts = explode('.', $field);
list($entity, $prop) = $this->_getEntity($parts);

$isNew = true;
if ($entity instanceof Entity) {
$isNew = $entity->isNew();
}

$validator = $this->_getValidator($prop);
$field = array_pop($parts);
if (!$validator->hasField($field)) {
return false;
}
$allowed = $validator->isEmptyAllowed($field, $entity->isNew());
$allowed = $validator->isEmptyAllowed($field, $isNew);
return $allowed === false;
}

Expand Down Expand Up @@ -353,10 +383,11 @@ public function hasError($field) {
public function error($field) {
$parts = explode('.', $field);
list($entity, $prop) = $this->_getEntity($parts);
if (!$entity) {
return [];

if ($entity instanceof Entity) {
return $entity->errors(array_pop($parts));
}
return $entity->errors(array_pop($parts));
return [];
}

}
13 changes: 12 additions & 1 deletion tests/TestCase/View/Form/EntityContextTest.php
Expand Up @@ -225,6 +225,9 @@ public function testValOnCollections($collection) {

$result = $context->val('1.user.username');
$this->assertEquals('jose', $result);

$this->assertNull($context->val('nope'));
$this->assertNull($context->val('99.title'));
}

/**
Expand All @@ -246,6 +249,9 @@ public function testErrorsOnCollections($collection) {
$this->assertFalse($context->hasError('1.title'));
$this->assertEquals(['Not long enough'], $context->error('1.body'));
$this->assertTrue($context->hasError('1.body'));

$this->assertFalse($context->hasError('nope'));
$this->assertFalse($context->hasError('99.title'));
}

/**
Expand All @@ -265,6 +271,7 @@ public function testSchemaOnCollections($collection) {
$this->assertEquals('text', $context->type('1.body'));
$this->assertEquals('string', $context->type('0.user.username'));
$this->assertEquals('string', $context->type('1.user.username'));
$this->assertEquals('string', $context->type('99.title'));
$this->assertNull($context->type('0.nope'));

$expected = ['length' => 255, 'precision' => null];
Expand All @@ -288,10 +295,14 @@ public function testValidatorsOnCollections($collection) {
'Users' => 'custom',
]
]);
$this->assertFalse($context->isRequired('nope'));

$this->assertTrue($context->isRequired('0.title'));
$this->assertFalse($context->isRequired('1.body'));
$this->assertTrue($context->isRequired('0.user.username'));
$this->assertFalse($context->isRequired('1.body'));

$this->assertTrue($context->isRequired('99.title'));
$this->assertFalse($context->isRequired('99.nope'));
}

/**
Expand Down

0 comments on commit f031b3c

Please sign in to comment.