Skip to content

Commit 526c7b9

Browse files
committed
Implemented BelongsToMany saving
1 parent cfe3752 commit 526c7b9

File tree

2 files changed

+106
-2
lines changed

2 files changed

+106
-2
lines changed

Cake/ORM/Association/BelongsToMany.php

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,78 @@ public function isOwningSide() {
266266
* @see Table::save()
267267
*/
268268
public function save(Entity $entity, $options = []) {
269-
return $entity;
269+
$property = $this->property();
270+
$targetEntity = $entity->get($this->property());
271+
$success = false;
272+
273+
if ($targetEntity) {
274+
$success = $this->_saveTarget($entity, $targetEntity, $options);
275+
}
276+
277+
return $success;
278+
}
279+
280+
protected function _saveTarget($parentEntity, $entities, $options) {
281+
if (!(is_array($entities) || $entities instanceof \Traversable)) {
282+
$name = $this->property();
283+
$message = __d('cake_dev', 'Could not save %s, it cannot be traversed', $name);
284+
throw new \InvalidArgumentException($message);
285+
}
286+
287+
$table = $this->target();
288+
$persited = [];
289+
foreach ($entities as $entity) {
290+
$saved = $table->save($entity, $options);
291+
if (!$saved && !empty($options['atomic'])) {
292+
return false;
293+
}
294+
if ($saved) {
295+
$persited[] = $saved;
296+
}
297+
}
298+
299+
$this->_saveLinks($parentEntity, $persited, $options);
300+
301+
return $parentEntity;
302+
}
303+
304+
protected function _saveLinks($sourceEntity, $targetEntities, $options) {
305+
$target = $this->target();
306+
$pivot = $this->pivot();
307+
$source = $this->source();
308+
$entityClass = $pivot->entityClass();
309+
$belongsTo = $pivot->association($target->alias());
310+
$property = $belongsTo->property();
311+
$foreignKey = (array)$this->foreignKey();
312+
$assocForeignKey = (array)$belongsTo->foreignKey();
313+
$targetPrimaryKey = (array)$target->primaryKey();
314+
$sourcePrimaryKey = (array)$source->primaryKey();
315+
$jointProperty = $target->association($pivot->alias())->property();
316+
317+
foreach ($targetEntities as $e) {
318+
$joint = $e->get($property);
319+
if (!$joint) {
320+
$joint = new $entityClass;
321+
$joint->isNew(true);
322+
}
323+
324+
$joint->set(array_combine(
325+
$foreignKey,
326+
$sourceEntity->extract($sourcePrimaryKey)
327+
));
328+
$joint->set(array_combine($assocForeignKey, $e->extract($targetPrimaryKey)));
329+
$saved = $pivot->save($joint, $options);
330+
331+
if (!$saved && !empty($options['atomic'])) {
332+
return false;
333+
}
334+
335+
if ($saved) {
336+
$e->set($jointProperty, $joint);
337+
}
338+
}
339+
340+
return true;
270341
}
271342

272343
/**

Cake/Test/TestCase/ORM/TableTest.php

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2225,11 +2225,44 @@ public function testSaveBelongsToWithValidationErrorNotAtomic() {
22252225
->validator()
22262226
->add('name', 'num', ['rule' => 'numeric']);
22272227

2228-
$this->assertSame($entity, $table->save($entity));
2228+
$this->assertSame($entity, $table->save($entity, ['atomic' => false]));
22292229
$this->assertFalse($entity->isNew());
22302230
$this->assertTrue($entity->author->isNew());
22312231
$this->assertNull($entity->get('author_id'));
22322232
$this->assertNotEmpty($entity->author->errors('name'));
22332233
}
22342234

2235+
/**
2236+
* Tests saving belongsToMany records
2237+
*
2238+
* @group save
2239+
* @return void
2240+
*/
2241+
public function testSaveBelongsToMany() {
2242+
$entity = new \Cake\ORM\Entity([
2243+
'title' => 'A Title',
2244+
'body' => 'A body'
2245+
]);
2246+
$entity->tags = [
2247+
new \Cake\ORM\Entity([
2248+
'name' => 'Something New'
2249+
]),
2250+
new \Cake\ORM\Entity([
2251+
'name' => 'Another Something'
2252+
])
2253+
];
2254+
$table = TableRegistry::get('articles');
2255+
$table->belongsToMany('tags');
2256+
$this->assertSame($entity, $table->save($entity));
2257+
$this->assertFalse($entity->isNew());
2258+
$this->assertFalse($entity->tags[0]->isNew());
2259+
$this->assertFalse($entity->tags[1]->isNew());
2260+
$this->assertEquals(4, $entity->tags[0]->id);
2261+
$this->assertEquals(5, $entity->tags[1]->id);
2262+
$this->assertEquals(4, $entity->tags[0]->extraInfo->article_id);
2263+
$this->assertEquals(4, $entity->tags[1]->extraInfo->article_id);
2264+
$this->assertEquals(4, $entity->tags[0]->extraInfo->tag_id);
2265+
$this->assertEquals(5, $entity->tags[1]->extraInfo->tag_id);
2266+
}
2267+
22352268
}

0 commit comments

Comments
 (0)