diff --git a/src/ORM/DomainChecker.php b/src/ORM/DomainChecker.php index 2919c23e85d..61c91f3b0f4 100644 --- a/src/ORM/DomainChecker.php +++ b/src/ORM/DomainChecker.php @@ -30,14 +30,17 @@ class DomainChecker { public function add(callable $rule) { $this->_rules[] = $rule; + return $this; } public function addCreate(callable $rule) { $this->_createRules[] = $rule; + return $this; } public function addUpdate(callable $rule) { $this->_updateRules[] = $rule; + return $this; } public function checkCreate(EntityInterface $entity) { @@ -45,7 +48,7 @@ public function checkCreate(EntityInterface $entity) { foreach (array_merge($this->_rules, $this->_createRules) as $rule) { $success = $rule($entity) && $success; } - return $succcess; + return $success; } public function checkUpdate(EntityInterface $entity) { @@ -53,7 +56,7 @@ public function checkUpdate(EntityInterface $entity) { foreach (array_merge($this->_rules, $this->_updateRules) as $rule) { $success = $rule($entity) && $success; } - return $succcess; + return $success; } } diff --git a/src/ORM/Table.php b/src/ORM/Table.php index 9021c0a023a..7d37903739e 100644 --- a/src/ORM/Table.php +++ b/src/ORM/Table.php @@ -29,6 +29,7 @@ use Cake\ORM\Association\HasMany; use Cake\ORM\Association\HasOne; use Cake\ORM\BehaviorRegistry; +use Cake\ORM\DomainChecker; use Cake\ORM\Exception\MissingEntityException; use Cake\ORM\Exception\RecordNotFoundException; use Cake\ORM\Marshaller; @@ -180,6 +181,14 @@ class Table implements RepositoryInterface, EventListenerInterface { */ protected $_validators = []; + +/** + * The domain rules to be applied to entities saved by this table + * + * @var \Cake\ORM\DomainChecker + */ + protected $_domainChecker; + /** * Initializes a new instance * @@ -1222,7 +1231,7 @@ protected function _processSave($entity, $options) { $entity->isNew(!$this->exists($conditions)); } - if ($options['checkDomain'] && !$this->checkDomainRules($entity)) { + if ($options['domainCheck'] && !$this->checkDomainRules($entity)) { return false; } @@ -1844,7 +1853,14 @@ public function checkDomainRules($entity) { } public function domainRules() { - return new DomainChecker; + if ($this->_domainChecker !== null) { + return $this->_domainChecker; + } + return $this->_domainChecker = $this->buildDomainRules(new DomainChecker); + } + + public function buildDomainRules(DomainChecker $rules) { + return $rules; } /** diff --git a/tests/TestCase/ORM/DomainRulesIntegrationTest.php b/tests/TestCase/ORM/DomainRulesIntegrationTest.php new file mode 100644 index 00000000000..2ebd07a81ae --- /dev/null +++ b/tests/TestCase/ORM/DomainRulesIntegrationTest.php @@ -0,0 +1,154 @@ + 'A Title', + 'body' => 'A body' + ]); + $entity->author = new Entity([ + 'name' => 'Jose' + ]); + + $table = TableRegistry::get('articles'); + $table->belongsTo('authors'); + $table->association('authors') + ->target() + ->domainRules() + ->add(function (Entity $author) { + $author->errors('name', ['This is an error']); + return false; + }); + + $this->assertFalse($table->save($entity)); + $this->assertTrue($entity->isNew()); + $this->assertTrue($entity->author->isNew()); + $this->assertNull($entity->get('author_id')); + $this->assertNotEmpty($entity->author->errors('name')); + } + +/** + * Tests saving hasOne association and returning a validation error will + * abort the saving process + * + * @group save + * @return void + */ + public function testSaveHasOneWithValidationError() { + $entity = new \Cake\ORM\Entity([ + 'name' => 'Jose' + ]); + $entity->article = new \Cake\ORM\Entity([ + 'title' => 'A Title', + 'body' => 'A body' + ]); + + $table = TableRegistry::get('authors'); + $table->hasOne('articles'); + $table->association('articles') + ->target() + ->domainRules() + ->add(function (Entity $entity) { + $entity->errors('title', ['Some error']); + return false; + }); + + $this->assertFalse($table->save($entity)); + $this->assertTrue($entity->isNew()); + $this->assertTrue($entity->article->isNew()); + $this->assertNull($entity->article->id); + $this->assertNull($entity->article->get('author_id')); + $this->assertFalse($entity->article->dirty('author_id')); + $this->assertNotEmpty($entity->article->errors('title')); + } + +/** + * Tests saving multiple entities in a hasMany association and getting and + * error while saving one of them. It should abort all the save operation + * when options are set to defaults + * + * @return void + */ + public function testSaveHasManyWithErrorsAtomic() { + $entity = new \Cake\ORM\Entity([ + 'name' => 'Jose' + ]); + $entity->articles = [ + new \Cake\ORM\Entity([ + 'title' => '1', + 'body' => 'A body' + ]), + new \Cake\ORM\Entity([ + 'title' => 'Another Title', + 'body' => 'Another body' + ]) + ]; + + $table = TableRegistry::get('authors'); + $table->hasMany('articles'); + $table->association('articles') + ->target() + ->domainRules() + ->add(function (Entity $entity) { + if ($entity->title !== '1') { + $entity->errors('title', ['an error']); + return false; + } + return true; + }); + + $this->assertFalse($table->save($entity)); + $this->assertTrue($entity->isNew()); + $this->assertTrue($entity->articles[0]->isNew()); + $this->assertTrue($entity->articles[1]->isNew()); + $this->assertNull($entity->articles[0]->id); + $this->assertNull($entity->articles[1]->id); + $this->assertNull($entity->articles[0]->author_id); + $this->assertNull($entity->articles[1]->author_id); + $this->assertEmpty($entity->articles[0]->errors()); + $this->assertNotEmpty($entity->articles[1]->errors()); + } + +}