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\Behavior; |
||||
15 | |||||
16 | use Cake\Collection\CollectionInterface; |
||||
17 | use Cake\Datasource\EntityInterface; |
||||
18 | use Cake\Datasource\Exception\RecordNotFoundException; |
||||
19 | use Cake\Event\Event; |
||||
20 | use Cake\ORM\Behavior; |
||||
21 | use Cake\ORM\Query; |
||||
22 | use Cake\ORM\TableRegistry; |
||||
23 | |||||
24 | /** |
||||
25 | * CustomProperties behavior |
||||
26 | * |
||||
27 | * @since 4.0.0 |
||||
28 | */ |
||||
29 | class CustomPropertiesBehavior extends Behavior |
||||
30 | { |
||||
31 | |||||
32 | /** |
||||
33 | * {@inheritDoc} |
||||
34 | */ |
||||
35 | protected $_defaultConfig = [ |
||||
36 | 'field' => 'custom_props', |
||||
37 | ]; |
||||
38 | |||||
39 | /** |
||||
40 | * The custom properties available. |
||||
41 | * It is an array with properties name as key and Property entity as value |
||||
42 | * |
||||
43 | * @var array |
||||
44 | */ |
||||
45 | protected $available = null; |
||||
46 | |||||
47 | /** |
||||
48 | * {@inheritDoc} |
||||
49 | */ |
||||
50 | public function initialize(array $config) |
||||
51 | { |
||||
52 | parent::initialize($config); |
||||
53 | |||||
54 | $table = $this->getTable(); |
||||
55 | if (!$table->hasBehavior('ObjectType')) { |
||||
56 | $table->addBehavior('BEdita/Core.ObjectType'); |
||||
57 | } |
||||
58 | } |
||||
59 | |||||
60 | /** |
||||
61 | * Getter for object type. |
||||
62 | * |
||||
63 | * @param array $args Method arguments. |
||||
64 | * @return \BEdita\Core\Model\Entity\ObjectType |
||||
65 | */ |
||||
66 | protected function objectType(...$args) |
||||
67 | { |
||||
68 | return $this->getTable()->behaviors()->call('objectType', $args); |
||||
69 | } |
||||
70 | |||||
71 | /** |
||||
72 | * Get available properties for object type |
||||
73 | * |
||||
74 | * @return \BEdita\Core\Model\Entity\Property[] |
||||
75 | */ |
||||
76 | public function getAvailable() |
||||
77 | { |
||||
78 | if ($this->available !== null) { |
||||
79 | return $this->available; |
||||
80 | } |
||||
81 | |||||
82 | try { |
||||
83 | $objectType = $this->objectType($this->getTable()->getAlias()); |
||||
84 | $properties = TableRegistry::get('Properties')->find('type', ['dynamic']) |
||||
85 | ->find('objectType', [$objectType->id]) |
||||
86 | ->where(['enabled' => true]) |
||||
87 | ->all(); |
||||
88 | } catch (RecordNotFoundException $e) { |
||||
89 | return []; |
||||
90 | } |
||||
91 | |||||
92 | $this->available = collection($properties)->indexBy('name')->toArray(); |
||||
93 | |||||
94 | return $this->available; |
||||
95 | } |
||||
96 | |||||
97 | /** |
||||
98 | * Return the default values of available properties |
||||
99 | * |
||||
100 | * @return array |
||||
101 | */ |
||||
102 | public function getDefaultValues() |
||||
103 | { |
||||
104 | return array_fill_keys(array_keys($this->getAvailable()), null); |
||||
105 | } |
||||
106 | |||||
107 | /** |
||||
108 | * Set custom properties keys as main properties |
||||
109 | * |
||||
110 | * @param \Cake\Event\Event $event Fired event. |
||||
111 | * @param \Cake\ORM\Query $query Query object instance. |
||||
112 | * @return void |
||||
113 | */ |
||||
114 | public function beforeFind(Event $event, Query $query) |
||||
0 ignored issues
–
show
|
|||||
115 | { |
||||
116 | $query->formatResults(function (CollectionInterface $results) { |
||||
117 | return $results->map(function ($row) { |
||||
118 | return $this->promoteProperties($row); |
||||
119 | }); |
||||
120 | }); |
||||
121 | } |
||||
122 | |||||
123 | /** |
||||
124 | * Set custom properties in their dedicated field. |
||||
125 | * |
||||
126 | * @param \Cake\Event\Event $event Fired event. |
||||
127 | * @param \Cake\Datasource\EntityInterface $entity Entity. |
||||
128 | * @return void |
||||
129 | */ |
||||
130 | public function beforeSave(Event $event, EntityInterface $entity) |
||||
0 ignored issues
–
show
The parameter
$event is not used and could be removed.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for parameters that have been defined for a function or method, but which are not used in the method body.
Loading history...
|
|||||
131 | { |
||||
132 | $this->demoteProperties($entity); |
||||
133 | } |
||||
134 | |||||
135 | /** |
||||
136 | * Promote the properties in configured `field` to first-class citizen properties. |
||||
137 | * Missing properties in `$entity` but available will be filled with default values. |
||||
138 | * |
||||
139 | * @param \Cake\Datasource\EntityInterface|array $entity The entity or the array to work on |
||||
140 | * @return \Cake\Datasource\EntityInterface|array |
||||
141 | */ |
||||
142 | protected function promoteProperties($entity) |
||||
143 | { |
||||
144 | $field = $this->getConfig('field'); |
||||
145 | if ((!is_array($entity) && !($entity instanceof EntityInterface)) || !$this->isFieldSet($entity, $field)) { |
||||
146 | return $entity; |
||||
147 | } |
||||
148 | |||||
149 | if (empty($entity[$field]) || !is_array($entity[$field])) { |
||||
150 | $entity[$field] = []; |
||||
151 | } |
||||
152 | $entity[$field] = $entity[$field] + $this->getDefaultValues(); |
||||
153 | |||||
154 | if (empty($entity[$field])) { |
||||
155 | return $entity; |
||||
156 | } |
||||
157 | |||||
158 | $customProps = $entity[$field]; |
||||
159 | if ($entity instanceof EntityInterface) { |
||||
160 | $entity->setHidden([$field], true); |
||||
161 | } else { |
||||
162 | unset($entity[$field]); |
||||
163 | } |
||||
164 | |||||
165 | if (is_array($entity)) { |
||||
166 | return array_merge($entity, $customProps); |
||||
167 | } |
||||
168 | |||||
169 | $entity->set($customProps, ['guard' => false])->clean(); |
||||
170 | |||||
171 | return $entity; |
||||
172 | } |
||||
173 | |||||
174 | /** |
||||
175 | * Send custom properties back to where they came from. |
||||
176 | * |
||||
177 | * @param \Cake\Datasource\EntityInterface $entity Entity being saved. |
||||
178 | * @return void |
||||
179 | */ |
||||
180 | protected function demoteProperties(EntityInterface $entity) |
||||
181 | { |
||||
182 | $field = $this->getConfig('field'); |
||||
183 | $value = (array)$entity->get($field); |
||||
184 | |||||
185 | $dirty = false; |
||||
186 | $available = $this->getAvailable(); |
||||
187 | foreach ($available as $property) { |
||||
188 | $propertyName = $property->name; |
||||
189 | if (!$this->isFieldSet($entity, $propertyName) || !$entity->isDirty($propertyName)) { |
||||
190 | continue; |
||||
191 | } |
||||
192 | |||||
193 | $dirty = true; |
||||
194 | $value[$propertyName] = $entity->get($propertyName); |
||||
195 | } |
||||
196 | |||||
197 | if ($dirty) { |
||||
198 | $entity->set($field, $value); |
||||
199 | } |
||||
200 | } |
||||
201 | |||||
202 | /** |
||||
203 | * Check if configured field containing custom properties is set in `$entity`. |
||||
204 | * |
||||
205 | * A field is considered "set" if it is present in `$entity` with any value, including `NULL`. |
||||
206 | * |
||||
207 | * @param \Cake\Datasource\EntityInterface|array $entity The entity or the array to check. |
||||
208 | * @param string $field The field being looked for. |
||||
209 | * @return bool |
||||
210 | */ |
||||
211 | protected function isFieldSet($entity, $field) |
||||
212 | { |
||||
213 | $allProperties = $entity; |
||||
214 | if ($entity instanceof EntityInterface) { |
||||
215 | $hidden = $entity->getHidden(); |
||||
216 | try { |
||||
217 | $entity->setHidden([]); |
||||
218 | $allProperties = $entity->toArray(); |
||||
219 | } finally { |
||||
220 | $entity->setHidden($hidden); |
||||
221 | } |
||||
222 | } |
||||
223 | |||||
224 | return array_key_exists($field, $allProperties); |
||||
225 | } |
||||
226 | } |
||||
227 |
This check looks for parameters that have been defined for a function or method, but which are not used in the method body.