Skip to content

Commit

Permalink
Implemented BelongsToMany::link
Browse files Browse the repository at this point in the history
  • Loading branch information
lorenzo committed Dec 8, 2013
1 parent 559a834 commit 744ae5c
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 1 deletion.
50 changes: 50 additions & 0 deletions Cake/ORM/Association/BelongsToMany.php
Expand Up @@ -386,6 +386,56 @@ protected function _saveLinks(Entity $sourceEntity, $targetEntities, $options) {
return true;
}

/**
* Associates the source entity to each of the target entities provided by
* creating links in the junction table. Both the source entity and each of
* the target entities are assumed to be already persisted, if the are marked
* as new or their status is unknown, an exception will be thrown.
*
* When using this method, all entities in `$targetEntities` will be appended to
* the source entity'property corresponding to this association object.
*
* This method does not check link uniqueness.
*
* ###Example:
*
* {{{
* $newTags = $tags->find('relevant')->execute();
* $articles->association('tags')->link($article, $newTags);
* }}}
*
* `$article->get('tags')` will contain all tags in `$newTags` after liking
*
* @param \Cake\ORM\Entity $sourceEntity the row belonging to the `source` side
* of this association
* @param array $targetEntities list of entities belonging to the `target` side
* of this association
* @param array $options list of options to be passed to the save method
* @throws \InvalidArgumentException when any of the values in $targetEntities is
* detected to not be already persisted
* @return boolean true on success, false otherwise
*/
public function link(Entity $sourceEntity, array $targetEntities, array $options = []) {
if ($sourceEntity->isNew() !== false) {
$error = __d('cake_dev', 'Source entity needs to be persisted before linking');
throw new \InvalidArgumentException($error);
}

$property = $this->property();
$links = $sourceEntity->get($property) ?: [];

foreach ($targetEntities as $entity) {
if ($entity->isNew() !== false) {
$error = __d('cake_dev', 'Cannot link not persisted entities');
throw new \InvalidArgumentException($error);
}
$links[] = $entity;
}

$sourceEntity->set($property, $links);
return $this->_saveLinks($sourceEntity, $targetEntities, $options);
}

/**
* Appends any conditions required to load the relevant set of records in the
* target table query given a filter key and some filtering values.
Expand Down
2 changes: 1 addition & 1 deletion Cake/Test/TestApp/Model/Repository/TagsTable.php
Expand Up @@ -21,7 +21,7 @@ class TagsTable extends Table {

public function initialize(array $config) {
$this->belongsTo('authors');
$this->belongsToMany('tags');
$this->belongsToMany('articles');
$this->hasMany('articlesTags', ['propertyName' => 'extraInfo']);
}

Expand Down
36 changes: 36 additions & 0 deletions Cake/Test/TestCase/ORM/TableTest.php
Expand Up @@ -2762,4 +2762,40 @@ public function testSaveDeepAssociationOptions() {
]));
}

/**
* Integration test for linking entities with belongsToMany
*
* @return void
*/
public function testLinkBelongsToMany() {
$table = TableRegistry::get('articles');
$table->belongsToMany('tags');
$tagsTable = TableRegistry::get('tags');
$options = ['markNew' => false];

$article = new \Cake\ORM\Entity([
'id' => 1,
], $options);

$newTag = new \TestApp\Model\Entity\Tag([
'name' => 'Foo'
]);
$tags[] = new \TestApp\Model\Entity\Tag([
'id' => 3
], $options);
$tags[] = $newTag;

$tagsTable->save($newTag);
$table->association('tags')->link($article, $tags);

$this->assertEquals($article->tags, $tags);
foreach ($tags as $tag) {
$this->assertFalse($tag->isNew());
}

$article = $table->find('all')->where(['id' => 1])->contain(['tags'])->first();
$this->assertEquals($article->tags[2]->id, $tags[0]->id);
$this->assertEquals($article->tags[3], $tags[1]);
}

}

0 comments on commit 744ae5c

Please sign in to comment.