1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* BEdita, API-first content management framework |
4
|
|
|
* Copyright 2017 ChannelWeb Srl, Chialab Srl |
5
|
|
|
* |
6
|
|
|
* This file is part of BEdita: you can redistribute it and/or modify |
7
|
|
|
* it under the terms of the GNU Lesser General Public License as published |
8
|
|
|
* by the Free Software Foundation, either version 3 of the License, or |
9
|
|
|
* (at your option) any later version. |
10
|
|
|
* |
11
|
|
|
* See LICENSE.LGPL or <http://gnu.org/licenses/lgpl-3.0.html> for more details. |
12
|
|
|
*/ |
13
|
|
|
|
14
|
|
|
namespace BEdita\Core\Model\Action; |
15
|
|
|
|
16
|
|
|
use BEdita\Core\ORM\Association\RelatedTo; |
17
|
|
|
use Cake\Datasource\EntityInterface; |
18
|
|
|
|
19
|
|
|
/** |
20
|
|
|
* Command to replace all objects related to another object. |
21
|
|
|
* |
22
|
|
|
* @since 4.0.0 |
23
|
|
|
*/ |
24
|
|
|
class SetRelatedObjectsAction extends UpdateRelatedObjectsAction |
25
|
|
|
{ |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* Count entities to be actually updated. |
29
|
|
|
* |
30
|
|
|
* @param \Cake\Datasource\EntityInterface $entity Source entity. |
31
|
|
|
* @param \Cake\Datasource\EntityInterface[] $relatedEntities Related entities. |
32
|
|
|
* @return array |
33
|
|
|
*/ |
34
|
|
|
protected function diff(EntityInterface $entity, $relatedEntities) |
35
|
|
|
{ |
36
|
|
|
$bindingKey = $this->Association->getBindingKey(); |
37
|
|
|
$existing = $this->existing($entity)->indexBy($this->Association->getTargetForeignKey())->toArray(); |
38
|
|
|
|
39
|
|
|
$junctionEntityClass = $this->Association->junction()->getEntityClass(); |
40
|
|
|
$ignoredKeys = array_flip( |
41
|
|
|
[$this->Association->getForeignKey(), $this->Association->getTargetForeignKey()] |
42
|
|
|
); |
43
|
|
|
|
44
|
|
|
$diff = $new = []; |
45
|
|
View Code Duplication |
foreach ($relatedEntities as $relatedEntity) { |
|
|
|
|
46
|
|
|
$primaryKey = $relatedEntity->get($bindingKey); |
|
|
|
|
47
|
|
|
$new[] = $primaryKey; |
48
|
|
|
if (!array_key_exists($primaryKey, $existing)) { |
49
|
|
|
// Relation was missing. |
50
|
|
|
$diff[] = $primaryKey; |
51
|
|
|
|
52
|
|
|
continue; |
53
|
|
|
} |
54
|
|
|
|
55
|
|
|
// Obtain new join data. |
56
|
|
|
$joinData = $this->Association->junction()->newEntity(); |
57
|
|
|
if (!empty($relatedEntity->_joinData) && $relatedEntity->_joinData instanceof $junctionEntityClass) { |
|
|
|
|
58
|
|
|
$joinData = $relatedEntity->_joinData; |
|
|
|
|
59
|
|
|
} |
60
|
|
|
|
61
|
|
|
// Extract meaningful values from both new and existing. |
62
|
|
|
$joinData = array_diff_key($joinData->getOriginalValues(), $ignoredKeys); |
63
|
|
|
$existingJoinData = array_diff_key($existing[$primaryKey]->getOriginalValues(), $ignoredKeys); |
64
|
|
|
|
65
|
|
|
// Compare existing and new join data. |
66
|
|
|
ksort($joinData); |
67
|
|
|
ksort($existingJoinData); |
68
|
|
|
if ($joinData !== $existingJoinData) { |
69
|
|
|
$diff[] = $primaryKey; |
70
|
|
|
} |
71
|
|
|
} |
72
|
|
|
|
73
|
|
|
$existing = array_keys($existing); |
74
|
|
|
foreach ($existing as $primaryKey) { |
75
|
|
|
if (in_array($primaryKey, $new)) { |
76
|
|
|
continue; |
77
|
|
|
} |
78
|
|
|
|
79
|
|
|
$diff[] = $primaryKey; |
80
|
|
|
} |
81
|
|
|
|
82
|
|
|
return $diff; |
83
|
|
|
} |
84
|
|
|
|
85
|
|
|
/** |
86
|
|
|
* {@inheritDoc} |
87
|
|
|
* |
88
|
|
|
* @return array|false |
89
|
|
|
*/ |
90
|
|
|
protected function update(EntityInterface $entity, $relatedEntities) |
91
|
|
|
{ |
92
|
|
View Code Duplication |
if (!($this->Association instanceof RelatedTo)) { |
|
|
|
|
93
|
|
|
$action = new SetAssociatedAction($this->getConfig()); |
94
|
|
|
|
95
|
|
|
return $action->execute(compact('entity', 'relatedEntities')); |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
$relatedEntities = $this->prepareRelatedEntities($relatedEntities); |
99
|
|
|
|
100
|
|
|
$diff = $this->diff($entity, $relatedEntities); |
101
|
|
|
|
102
|
|
|
return $this->Association->replaceLinks($entity, $relatedEntities) ? $diff : false; |
|
|
|
|
103
|
|
|
} |
104
|
|
|
} |
105
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.