Skip to content

Commit

Permalink
Implemented BelongsToMany saving
Browse files Browse the repository at this point in the history
  • Loading branch information
lorenzo committed Nov 28, 2013
1 parent cfe3752 commit 526c7b9
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 2 deletions.
73 changes: 72 additions & 1 deletion Cake/ORM/Association/BelongsToMany.php
Expand Up @@ -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;
}

/**
Expand Down
35 changes: 34 additions & 1 deletion Cake/Test/TestCase/ORM/TableTest.php
Expand Up @@ -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);
}

}

0 comments on commit 526c7b9

Please sign in to comment.