Skip to content
Permalink
Browse files

Implement path based error reading.

Much like other parts of CakePHP, errors in entities should be readable
using a dot separated path.

* Implement code.
* Fix tests.

Refs #3807
  • Loading branch information...
markstory committed Jul 9, 2014
1 parent 3d22390 commit 42cdf10862fd9ae820564933df07255c8a526c17
Showing with 55 additions and 23 deletions.
  1. +49 −18 src/Datasource/EntityTrait.php
  2. +6 −5 tests/TestCase/ORM/EntityTest.php
@@ -16,6 +16,7 @@
use Cake\Utility\Inflector;
use Cake\Validation\Validator;
use \Traversable;
/**
* An entity represents a single result row from a repository. It exposes the
@@ -578,10 +579,10 @@ public function errors($field = null, $errors = null) {
if (is_string($field) && $errors === null) {
$errors = isset($this->_errors[$field]) ? $this->_errors[$field] : [];
if (!$errors) {
$errors = $this->_nestedErrors($field);
if ($errors) {
return $errors;
}
return $errors;
return $this->_nestedErrors($field);
}
if (!is_array($field)) {
@@ -591,7 +592,6 @@ public function errors($field = null, $errors = null) {
foreach ($field as $f => $error) {
$this->_errors[$f] = (array)$error;
}
return $this;
}
@@ -602,26 +602,57 @@ public function errors($field = null, $errors = null) {
* @return array errors in nested entity if any
*/
protected function _nestedErrors($field) {
if (!isset($this->_properties[$field])) {
return [];
$path = explode('.', $field);
// Only one path element, check for nested entity with error.
if (count($path) === 1) {
return $this->_readError($this->get($path[0]));
}
$value = $this->_properties[$field];
$errors = [];
if (is_array($value) || $value instanceof \Traversable) {
foreach ($value as $k => $v) {
if (!($v instanceof self)) {
break;
}
$errors[$k] = $v->errors();
$entity = $this;
while (count($path)) {
$part = array_shift($path);
if ($entity instanceof static) {
$val = $entity->get($part);
} elseif (is_array($entity)) {
$val = isset($entity[$part]) ? $entity[$part] : false;
}
return $errors;
}
if ($value instanceof self) {
return $value->errors();
if (
is_array($val) ||
$val instanceof Traversable ||
$val instanceof static
) {
$entity = $val;
} else {
$path[] = $part;
break;
}
}
if (count($path) <= 1) {
return $this->_readError($entity, array_pop($path));
}
return [];
}
/**
* Read the error(s) from one or many objects.
*
* @param array|\Cake\Datasource\EntityTrait $object The object to read errors from.
* @param string $path The field name for errors.
* @return array
*/
protected function _readError($object, $path = null) {
if ($object instanceof static) {
return $object->errors($path);
}
if (is_array($object)) {
return array_map(function($val) {
if ($val instanceof static) {
return $val->errors();
}
}, $object);
}
return [];
}
@@ -839,11 +839,12 @@ public function testErrorPathReading() {
$entity->errors('wrong', 'Bad stuff');
$assoc->errors('nope', 'Terrible things');
$this->assertEquals('Bad stuff', $entity->errors('wrong'));
$this->assertEquals('Terrible things', $entity->errors('many.0.nope'));
$this->assertEquals('Terrible things', $entity->errors('one.nope'));
$this->assertEquals(['nope' => 'Terrible things'], $entity->errors('one'));
$this->assertEquals(['nope' => 'Terrible things'], $entity->errors('many.0'));
$this->assertEquals(['Bad stuff'], $entity->errors('wrong'));
$this->assertEquals(['Terrible things'], $entity->errors('many.0.nope'));
$this->assertEquals(['Terrible things'], $entity->errors('one.nope'));
$this->assertEquals(['nope' => ['Terrible things']], $entity->errors('one'));
$this->assertEquals([0 => ['nope' => ['Terrible things']]], $entity->errors('many'));
$this->assertEquals(['nope' => ['Terrible things']], $entity->errors('many.0'));
$this->assertEquals([], $entity->errors('many.0.mistake'));
$this->assertEquals([], $entity->errors('one.mistake'));

0 comments on commit 42cdf10

Please sign in to comment.
You can’t perform that action at this time.