From 526c7b91102fe9f9a8462b598038025cb91e6af3 Mon Sep 17 00:00:00 2001 From: Jose Lorenzo Rodriguez Date: Thu, 28 Nov 2013 20:56:41 +0100 Subject: [PATCH] Implemented BelongsToMany saving --- Cake/ORM/Association/BelongsToMany.php | 73 +++++++++++++++++++++++++- Cake/Test/TestCase/ORM/TableTest.php | 35 +++++++++++- 2 files changed, 106 insertions(+), 2 deletions(-) diff --git a/Cake/ORM/Association/BelongsToMany.php b/Cake/ORM/Association/BelongsToMany.php index cce508ce70d..feea1f3402c 100644 --- a/Cake/ORM/Association/BelongsToMany.php +++ b/Cake/ORM/Association/BelongsToMany.php @@ -266,7 +266,78 @@ public function isOwningSide() { * @see Table::save() */ public function save(Entity $entity, $options = []) { - return $entity; + $property = $this->property(); + $targetEntity = $entity->get($this->property()); + $success = false; + + if ($targetEntity) { + $success = $this->_saveTarget($entity, $targetEntity, $options); + } + + return $success; + } + + protected function _saveTarget($parentEntity, $entities, $options) { + if (!(is_array($entities) || $entities instanceof \Traversable)) { + $name = $this->property(); + $message = __d('cake_dev', 'Could not save %s, it cannot be traversed', $name); + throw new \InvalidArgumentException($message); + } + + $table = $this->target(); + $persited = []; + foreach ($entities as $entity) { + $saved = $table->save($entity, $options); + if (!$saved && !empty($options['atomic'])) { + return false; + } + if ($saved) { + $persited[] = $saved; + } + } + + $this->_saveLinks($parentEntity, $persited, $options); + + return $parentEntity; + } + + protected function _saveLinks($sourceEntity, $targetEntities, $options) { + $target = $this->target(); + $pivot = $this->pivot(); + $source = $this->source(); + $entityClass = $pivot->entityClass(); + $belongsTo = $pivot->association($target->alias()); + $property = $belongsTo->property(); + $foreignKey = (array)$this->foreignKey(); + $assocForeignKey = (array)$belongsTo->foreignKey(); + $targetPrimaryKey = (array)$target->primaryKey(); + $sourcePrimaryKey = (array)$source->primaryKey(); + $jointProperty = $target->association($pivot->alias())->property(); + + foreach ($targetEntities as $e) { + $joint = $e->get($property); + if (!$joint) { + $joint = new $entityClass; + $joint->isNew(true); + } + + $joint->set(array_combine( + $foreignKey, + $sourceEntity->extract($sourcePrimaryKey) + )); + $joint->set(array_combine($assocForeignKey, $e->extract($targetPrimaryKey))); + $saved = $pivot->save($joint, $options); + + if (!$saved && !empty($options['atomic'])) { + return false; + } + + if ($saved) { + $e->set($jointProperty, $joint); + } + } + + return true; } /** diff --git a/Cake/Test/TestCase/ORM/TableTest.php b/Cake/Test/TestCase/ORM/TableTest.php index 90a759f321d..0b5af7e5f7b 100644 --- a/Cake/Test/TestCase/ORM/TableTest.php +++ b/Cake/Test/TestCase/ORM/TableTest.php @@ -2225,11 +2225,44 @@ public function testSaveBelongsToWithValidationErrorNotAtomic() { ->validator() ->add('name', 'num', ['rule' => 'numeric']); - $this->assertSame($entity, $table->save($entity)); + $this->assertSame($entity, $table->save($entity, ['atomic' => false])); $this->assertFalse($entity->isNew()); $this->assertTrue($entity->author->isNew()); $this->assertNull($entity->get('author_id')); $this->assertNotEmpty($entity->author->errors('name')); } +/** + * Tests saving belongsToMany records + * + * @group save + * @return void + */ + public function testSaveBelongsToMany() { + $entity = new \Cake\ORM\Entity([ + 'title' => 'A Title', + 'body' => 'A body' + ]); + $entity->tags = [ + new \Cake\ORM\Entity([ + 'name' => 'Something New' + ]), + new \Cake\ORM\Entity([ + 'name' => 'Another Something' + ]) + ]; + $table = TableRegistry::get('articles'); + $table->belongsToMany('tags'); + $this->assertSame($entity, $table->save($entity)); + $this->assertFalse($entity->isNew()); + $this->assertFalse($entity->tags[0]->isNew()); + $this->assertFalse($entity->tags[1]->isNew()); + $this->assertEquals(4, $entity->tags[0]->id); + $this->assertEquals(5, $entity->tags[1]->id); + $this->assertEquals(4, $entity->tags[0]->extraInfo->article_id); + $this->assertEquals(4, $entity->tags[1]->extraInfo->article_id); + $this->assertEquals(4, $entity->tags[0]->extraInfo->tag_id); + $this->assertEquals(5, $entity->tags[1]->extraInfo->tag_id); + } + }