Skip to content

Commit

Permalink
Implemented one more test to link function, in which an already exist…
Browse files Browse the repository at this point in the history
…ing link is present in the input data. Implemented replaceLinks method and a test for it.
  • Loading branch information
mylux committed Oct 18, 2015
1 parent 1089927 commit bdf5d76
Show file tree
Hide file tree
Showing 2 changed files with 169 additions and 2 deletions.
61 changes: 60 additions & 1 deletion src/ORM/Association/HasMany.php
Expand Up @@ -214,7 +214,7 @@ public function link(EntityInterface $sourceEntity, array $targetEntities, array

$currentEntities = (new Collection((array)$sourceEntity->get($property)))->append($targetEntities);

$sourceEntity->set($property, $currentEntities->toList());
$sourceEntity->set($property, array_unique($currentEntities->toList()));

$savedEntity = $this->saveAssociated($sourceEntity);

Expand Down Expand Up @@ -291,6 +291,65 @@ function ($assoc) use ($targetEntities) {
}
}

/**
* Replaces existing association links between the source entity and the target
* with the ones passed. This method does a smart cleanup, links that are already
* persisted and present in `$targetEntities` will not be deleted, new links will
* be created for the passed target entities that are not already in the database
* and the rest will be removed.
*
* For example, if an author has many articles, such as 'article1','article 2' and 'article 3' and you pass
* to this method an array containing the entities for articles 'article 1' and 'article 4',
* only the link for 'article 1' will be kept in database, the links for 'article 2' and 'article 3' will be
* deleted and the link for 'article 4' will be created.
*
* Existing links are not deleted and created again, they are either left untouched
* or updated.
*
* This method does not check link uniqueness.
*
* On success, the passed `$sourceEntity` will contain `$targetEntities` as value
* in the corresponding property for this association.
*
* Additional options for new links to be saved can be passed in the third argument,
* check `Table::save()` for information on the accepted options.
*
* ### Example:
*
* ```
* $author->articles = [$article1, $article2, $article3, $article4];
* $authors->save($author);
* $articles = [$article1, $article3];
* $authors->association('articles')->replaceLinks($author, $articles);
* ```
*
* `$author->get('articles')` will contain only `[$article1, $article3]` at the end
*
* @param \Cake\Datasource\EntityInterface $sourceEntity an entity persisted in the source table for
* this association
* @param array $targetEntities list of entities from the target table to be linked
* @param array $options list of options to be passed to `save` persisting or
* updating new links
* @throws \InvalidArgumentException if non persisted entities are passed or if
* any of them is lacking a primary key value
* @return bool success
*/
public function replaceLinks(EntityInterface $sourceEntity, array $targetEntities, array $options = [])
{
$property = $this->property();
$sourceEntity->set($property, $targetEntities);
$saveStrategy = $this->saveStrategy();
$this->saveStrategy(self::SAVE_REPLACE);
$result = $this->saveAssociated($sourceEntity, $options);
$ok = ($result instanceof EntityInterface);

if ($ok) {
$sourceEntity = $result;
}
$this->saveStrategy($saveStrategy);
return $ok;
}

/**
* Deletes/sets null the related objects according to the dependency between source and targets and foreign key nullability
* Skips deleting records present in $remainingEntities
Expand Down
110 changes: 109 additions & 1 deletion tests/TestCase/ORM/TableTest.php
Expand Up @@ -3968,7 +3968,61 @@ public function testLinkHasManyReplaceSaveStrategy()
$sizeArticles++;

$this->assertEquals($authors->Articles->findAllByAuthorId($author->id)->count(), $sizeArticles);
$this->assertEquals(count($author->articles), $sizeArticles);
$this->assertEquals($sizeArticles, count($author->articles));
}

/**
* Integration test for linking entities with HasMany. The input contains already linked entities and they should not appeat duplicated
*
* @return void
*/
public function testLinkHasManyExisting()
{
$authors = TableRegistry::get('Authors');
$articles = TableRegistry::get('Articles');

$authors->hasMany('Articles', [
'foreignKey' => 'author_id',
'saveStrategy' => 'replace'
]);

$author = $authors->newEntity(['name' => 'mylux']);
$author = $authors->save($author);

$newArticles = $articles->newEntities(
[
[
'title' => 'New bakery next corner',
'body' => 'They sell tastefull cakes'
],
[
'title' => 'Spicy cake recipe',
'body' => 'chocolate and peppers'
]
]
);

$this->assertTrue($authors->Articles->link($author, $newArticles));

$sizeArticles = count($newArticles);

$newArticles = array_merge(
$author->articles,
$articles->newEntities(
[
[
'title' => 'Nothing but the cake',
'body' => 'It is all that we need'
]
]
)
);
$this->assertTrue($authors->Articles->link($author, $newArticles));

$sizeArticles++;

$this->assertEquals($sizeArticles, $authors->Articles->findAllByAuthorId($author->id)->count());
$this->assertEquals($sizeArticles, count($author->articles));
}

/**
Expand Down Expand Up @@ -4217,6 +4271,60 @@ public function testReplacelinksBelongsToManyWithJoint()
$this->assertEquals(3, $article->tags[1]->id);
}

public function testReplaceLinksHasMany()
{
$authors = TableRegistry::get('Authors');
$articles = TableRegistry::get('Articles');

$authors->hasMany('Articles', [
'foreignKey' => 'author_id'
]);

$author = $authors->newEntity(['name' => 'mylux']);
$author = $authors->save($author);

$newArticles = $articles->newEntities(
[
[
'title' => 'New bakery next corner',
'body' => 'They sell tastefull cakes'
],
[
'title' => 'Spicy cake recipe',
'body' => 'chocolate and peppers'
]
]
);

$sizeArticles = count($newArticles);

$this->assertTrue($authors->Articles->link($author, $newArticles));

$this->assertEquals($authors->Articles->findAllByAuthorId($author->id)->count(), $sizeArticles);
$this->assertEquals(count($author->articles), $sizeArticles);

$newArticles = array_merge(
$author->articles,
$articles->newEntities(
[
[
'title' => 'Cheese cake recipe',
'body' => 'The secrets of mixing salt and sugar'
],
[
'title' => 'Not another piece of cake',
'body' => 'This is the best'
]
]
)
);
unset($newArticles[0]);

$this->assertTrue($authors->Articles->replaceLinks($author, $newArticles));
$this->assertEquals(count($newArticles), count($author->articles));
$this->assertEquals((new Collection($newArticles))->extract('title'), (new Collection($author->articles))->extract('title'));
}

/**
* Tests that it is possible to call find with no arguments
*
Expand Down

0 comments on commit bdf5d76

Please sign in to comment.