Skip to content

Commit

Permalink
Merge pull request #5260 from cakephp/issue-5257
Browse files Browse the repository at this point in the history
Fix warnings and fatal errors when validating entities.
  • Loading branch information
lorenzo committed Nov 26, 2014
2 parents 66f532a + 1881631 commit d1e9de3
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 7 deletions.
28 changes: 21 additions & 7 deletions src/ORM/EntityValidator.php
Expand Up @@ -15,9 +15,16 @@
namespace Cake\ORM;

use ArrayObject;
use Cake\Datasource\EntityInterface;
use Cake\ORM\Association;
use Cake\ORM\Table;

/**
* Contains logic for validating entities and their associations
* Contains logic for validating entities and their associations.
*
* This class is generally used by the internals of the ORM. It
* provides methods for traversing a set of entities and their associated
* properties.
*
* @see \Cake\ORM\Table::validate()
* @see \Cake\ORM\Table::validateMany()
Expand Down Expand Up @@ -75,12 +82,13 @@ protected function _buildPropertyMap($include) {
* the table and traverses associations passed in $options to validate them
* as well.
*
* @param \Cake\ORM\Entity $entity The entity to be validated
* @param \Cake\Datasource\EntityInterface $entity The entity to be validated
* @param array|\ArrayObject $options options for validation, including an optional key of
* associations to also be validated.
* associations to also be validated. This argument should use the same format as the $options
* argument to \Cake\ORM\Table::save().
* @return bool true if all validations passed, false otherwise
*/
public function one(Entity $entity, $options = []) {
public function one(EntityInterface $entity, $options = []) {
$valid = true;
$types = [Association::ONE_TO_ONE, Association::MANY_TO_ONE];
$propertyMap = $this->_buildPropertyMap($options);
Expand All @@ -94,7 +102,7 @@ public function one(Entity $entity, $options = []) {
continue;
}
$isOne = in_array($association->type(), $types);
if ($isOne && !($value instanceof Entity)) {
if ($isOne && !($value instanceof EntityInterface)) {
$valid = false;
continue;
}
Expand All @@ -117,14 +125,21 @@ public function one(Entity $entity, $options = []) {
* Validates a list of entities by getting the correct validator for the related
* table and traverses associations passed in $include to validate them as well.
*
* If any of the entities in `$entities` does not implement `Cake\Datasource\EntityInterface`,
* it will be treated as an invalid result.
*
* @param array $entities List of entities to be validated
* @param array|\ArrayObject $options options for validation, including an optional key of
* associations to also be validated.
* associations to also be validated. This argument should use the same format as the $options
* argument to \Cake\ORM\Table::save().
* @return bool true if all validations passed, false otherwise
*/
public function many(array $entities, $options = []) {
$valid = true;
foreach ($entities as $entity) {
if (!($entity instanceof EntityInterface)) {
return false;
}
$valid = $this->one($entity, $options) && $valid;
}
return $valid;
Expand Down Expand Up @@ -156,7 +171,6 @@ protected function _processValidation($entity, $options) {
$success = $entity->validate($validator);

$event = $this->_table->dispatchEvent('Model.afterValidate', $pass);

if ($event->isStopped()) {
$success = (bool)$event->result;
}
Expand Down
40 changes: 40 additions & 0 deletions tests/TestCase/ORM/EntityValidatorTest.php
Expand Up @@ -158,6 +158,46 @@ public function testOneAssociationsSuccess() {
$this->assertTrue($entityValidator->one($article, $options));
}

/**
* test one() with associations that are not entities.
*
* This can happen when request data is not completely marshalled.
* incomplete associations should not cause warnings or fatal errors.
*
* @return void
*/
public function testOneAssociationsNoEntities() {
$article = $this->getMock('\Cake\ORM\Entity', ['validate']);
$comment1 = ['comment' => 'test'];
$comment2 = ['comment' => 'omg'];
$user = $this->getMock('\Cake\ORM\Entity', ['validate']);
$article->set('comments', [$comment1, $comment2]);

$validator1 = $this->getMock('\Cake\Validation\Validator');
$validator2 = $this->getMock('\Cake\Validation\Validator');

$validator1->expects($this->once())
->method('count')
->will($this->returnValue(1));

// Should not be called as comments are not entities.
$validator2->expects($this->never())
->method('count');

$this->articles->validator('default', $validator1);
$this->comments->validator('default', $validator2);

$entityValidator = new EntityValidator($this->articles);

$article->expects($this->once())
->method('validate')
->with($validator1)
->will($this->returnValue(true));

$options = ['associated' => ['Comments']];
$this->assertFalse($entityValidator->one($article, $options));
}

/**
* test one() with association data and one of them failing validation.
*
Expand Down

0 comments on commit d1e9de3

Please sign in to comment.