1 | <?php |
||||
2 | /** |
||||
3 | * BEdita, API-first content management framework |
||||
4 | * Copyright 2016 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\API\Model\Action; |
||||
15 | |||||
16 | use BEdita\Core\Model\Action\BaseAction; |
||||
17 | use Cake\Database\Expression\QueryExpression; |
||||
18 | use Cake\Datasource\Exception\RecordNotFoundException; |
||||
19 | use Cake\ORM\Association; |
||||
20 | use Cake\ORM\Association\BelongsTo; |
||||
21 | use Cake\ORM\Association\BelongsToMany; |
||||
22 | use Cake\ORM\Association\HasOne; |
||||
23 | use Cake\Utility\Hash; |
||||
24 | |||||
25 | /** |
||||
26 | * Command to update links between entities. |
||||
27 | * |
||||
28 | * @since 4.0.0 |
||||
29 | */ |
||||
30 | class UpdateAssociatedAction extends BaseAction |
||||
31 | { |
||||
32 | /** |
||||
33 | * Add associated action. |
||||
34 | * |
||||
35 | * @var \BEdita\Core\Model\Action\UpdateAssociatedAction |
||||
36 | */ |
||||
37 | protected $Action; |
||||
38 | |||||
39 | /** |
||||
40 | * Request instance. |
||||
41 | * |
||||
42 | * @var \Cake\Http\ServerRequest |
||||
43 | */ |
||||
44 | protected $request; |
||||
45 | |||||
46 | /** |
||||
47 | * @inheritDoc |
||||
48 | */ |
||||
49 | protected function initialize(array $data) |
||||
50 | { |
||||
51 | $this->Action = $this->getConfig('action'); |
||||
52 | $this->request = $this->getConfig('request'); |
||||
53 | } |
||||
54 | |||||
55 | /** |
||||
56 | * @inheritDoc |
||||
57 | */ |
||||
58 | public function execute(array $data = []) |
||||
59 | { |
||||
60 | $association = $this->Action->getConfig('association'); |
||||
61 | if (!($association instanceof Association)) { |
||||
62 | throw new \LogicException(__d('bedita', 'Unknown association type')); |
||||
63 | } |
||||
64 | |||||
65 | $entity = $association->getSource()->get($data['primaryKey']); |
||||
66 | |||||
67 | $requestData = $this->request->getData(); |
||||
68 | if (!Hash::numeric(array_keys($requestData))) { |
||||
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||||
69 | $requestData = [$requestData]; |
||||
70 | } |
||||
71 | |||||
72 | $relatedEntities = $this->getTargetEntities($requestData, $association); |
||||
0 ignored issues
–
show
It seems like
$requestData can also be of type null ; however, parameter $data of BEdita\API\Model\Action\...on::getTargetEntities() does only seem to accept array , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
73 | $count = count($relatedEntities); |
||||
74 | if ($count === 0) { |
||||
75 | $relatedEntities = []; |
||||
76 | } elseif ($count === 1 && ($association instanceof BelongsTo || $association instanceof HasOne)) { |
||||
77 | $relatedEntities = reset($relatedEntities); |
||||
78 | } |
||||
79 | |||||
80 | return $this->Action->execute(compact('entity', 'relatedEntities')); |
||||
81 | } |
||||
82 | |||||
83 | /** |
||||
84 | * Get target entities. |
||||
85 | * |
||||
86 | * @param array $data Request data. |
||||
87 | * @param \Cake\ORM\Association $association Association. |
||||
88 | * @return \Cake\Datasource\EntityInterface[] |
||||
89 | */ |
||||
90 | protected function getTargetEntities(array $data, Association $association) |
||||
91 | { |
||||
92 | $target = $association->getTarget(); |
||||
93 | $primaryKeyField = $target->getPrimaryKey(); |
||||
94 | $targetPKField = $target->aliasField($primaryKeyField); |
||||
0 ignored issues
–
show
It seems like
$primaryKeyField can also be of type string[] ; however, parameter $field of Cake\ORM\Table::aliasField() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
95 | |||||
96 | $targetPrimaryKeys = array_unique(Hash::extract($data, '{*}.id')); |
||||
0 ignored issues
–
show
It seems like
Cake\Utility\Hash::extract($data, '{*}.id') can also be of type ArrayAccess ; however, parameter $array of array_unique() does only seem to accept array , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
97 | if (empty($targetPrimaryKeys)) { |
||||
98 | return []; |
||||
99 | } |
||||
100 | |||||
101 | $targetEntities = $target->find() |
||||
102 | ->where(function (QueryExpression $exp) use ($targetPKField, $targetPrimaryKeys) { |
||||
103 | return $exp->in($targetPKField, $targetPrimaryKeys); |
||||
104 | }); |
||||
105 | $targetEntities = $targetEntities->all()->indexBy($primaryKeyField)->toArray(); |
||||
106 | /** @var \Cake\Datasource\EntityInterface[] $targetEntities */ |
||||
107 | |||||
108 | // sort following the original order |
||||
109 | uksort( |
||||
110 | $targetEntities, |
||||
111 | function ($a, $b) use ($targetPrimaryKeys) { |
||||
112 | return array_search($a, $targetPrimaryKeys) - array_search($b, $targetPrimaryKeys); |
||||
113 | } |
||||
114 | ); |
||||
115 | |||||
116 | foreach ($data as $datum) { |
||||
117 | $id = Hash::get($datum, 'id'); |
||||
118 | $type = Hash::get($datum, 'type'); |
||||
119 | if (!isset($targetEntities[$id]) || ($targetEntities[$id]->has('type') && $targetEntities[$id]->get('type') !== $type)) { |
||||
120 | throw new RecordNotFoundException(__('Record not found in table "{0}"', $type ?: $target->getTable())); |
||||
121 | } |
||||
122 | |||||
123 | $meta = Hash::get($datum, '_meta.relation'); |
||||
124 | if (!$this->request->is('delete') && $association instanceof BelongsToMany && $meta !== null) { |
||||
125 | $targetEntities[$id]->_joinData = $meta; |
||||
126 | } |
||||
127 | } |
||||
128 | |||||
129 | return $targetEntities; |
||||
130 | } |
||||
131 | } |
||||
132 |