blob: 37f0e876baa1b862e5225a837fb594823226c6b3 [file] [log] [blame]
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02001<?php
2
3namespace LdapRecord\Models;
4
5use InvalidArgumentException;
6
7class BatchModification
8{
9 use DetectsResetIntegers;
10
11 /**
12 * The array keys to be used in batch modifications.
13 */
14 const KEY_ATTRIB = 'attrib';
15 const KEY_MODTYPE = 'modtype';
16 const KEY_VALUES = 'values';
17
18 /**
19 * The attribute of the modification.
20 *
21 * @var string|null
22 */
23 protected $attribute;
24
25 /**
26 * The original value of the attribute before modification.
27 *
28 * @var array
29 */
30 protected $original = [];
31
32 /**
33 * The values of the modification.
34 *
35 * @var array
36 */
37 protected $values = [];
38
39 /**
40 * The modtype integer of the batch modification.
41 *
42 * @var int|null
43 */
44 protected $type;
45
46 /**
47 * Constructor.
48 *
49 * @param string|null $attribute
50 * @param string|int|null $type
51 * @param array $values
52 */
53 public function __construct($attribute = null, $type = null, array $values = [])
54 {
55 $this->setAttribute($attribute)
56 ->setType($type)
57 ->setValues($values);
58 }
59
60 /**
61 * Set the original value of the attribute before modification.
62 *
63 * @param array|string $original
64 *
65 * @return $this
66 */
67 public function setOriginal($original = [])
68 {
69 $this->original = $this->normalizeAttributeValues($original);
70
71 return $this;
72 }
73
74 /**
75 * Returns the original value of the attribute before modification.
76 *
77 * @return array
78 */
79 public function getOriginal()
80 {
81 return $this->original;
82 }
83
84 /**
85 * Set the attribute of the modification.
86 *
87 * @param string $attribute
88 *
89 * @return $this
90 */
91 public function setAttribute($attribute)
92 {
93 $this->attribute = $attribute;
94
95 return $this;
96 }
97
98 /**
99 * Returns the attribute of the modification.
100 *
101 * @return string
102 */
103 public function getAttribute()
104 {
105 return $this->attribute;
106 }
107
108 /**
109 * Set the values of the modification.
110 *
111 * @param array $values
112 *
113 * @return $this
114 */
115 public function setValues(array $values = [])
116 {
117 // Null and empty values must also not be added to a batch
118 // modification. Passing null or empty values will result
119 // in an exception when trying to save the modification.
120 $this->values = array_filter($this->normalizeAttributeValues($values), function ($value) {
121 return is_numeric($value) && $this->valueIsResetInteger((int) $value) ?: ! empty($value);
122 });
123
124 return $this;
125 }
126
127 /**
128 * Normalize all of the attribute values.
129 *
130 * @param array|string $values
131 *
132 * @return array
133 */
134 protected function normalizeAttributeValues($values = [])
135 {
136 // We must convert all of the values to strings. Only strings can
137 // be used in batch modifications, otherwise we will we will
138 // receive an LDAP exception while attempting to save.
139 return array_map('strval', (array) $values);
140 }
141
142 /**
143 * Returns the values of the modification.
144 *
145 * @return array
146 */
147 public function getValues()
148 {
149 return $this->values;
150 }
151
152 /**
153 * Set the type of the modification.
154 *
155 * @param int|null $type
156 *
157 * @return $this
158 */
159 public function setType($type = null)
160 {
161 if (is_null($type)) {
162 return $this;
163 }
164
165 if (! $this->isValidType($type)) {
166 throw new InvalidArgumentException('Given batch modification type is invalid.');
167 }
168
169 $this->type = $type;
170
171 return $this;
172 }
173
174 /**
175 * Returns the type of the modification.
176 *
177 * @return int
178 */
179 public function getType()
180 {
181 return $this->type;
182 }
183
184 /**
185 * Determines if the batch modification is valid in its current state.
186 *
187 * @return bool
188 */
189 public function isValid()
190 {
191 return ! is_null($this->get());
192 }
193
194 /**
195 * Builds the type of modification automatically
196 * based on the current and original values.
197 *
198 * @return $this
199 */
200 public function build()
201 {
202 switch (true) {
203 case empty($this->original) && empty($this->values):
204 return $this;
205 case ! empty($this->original) && empty($this->values):
206 return $this->setType(LDAP_MODIFY_BATCH_REMOVE_ALL);
207 case empty($this->original) && ! empty($this->values):
208 return $this->setType(LDAP_MODIFY_BATCH_ADD);
209 default:
210 return $this->determineBatchTypeFromOriginal();
211 }
212 }
213
214 /**
215 * Determine the batch modification type from the original values.
216 *
217 * @return $this
218 */
219 protected function determineBatchTypeFromOriginal()
220 {
221 $added = $this->getAddedValues();
222 $removed = $this->getRemovedValues();
223
224 switch (true) {
225 case ! empty($added) && ! empty($removed):
226 return $this->setType(LDAP_MODIFY_BATCH_REPLACE);
227 case ! empty($added):
228 return $this->setValues($added)->setType(LDAP_MODIFY_BATCH_ADD);
229 case ! empty($removed):
230 return $this->setValues($removed)->setType(LDAP_MODIFY_BATCH_REMOVE);
231 default:
232 return $this;
233 }
234 }
235
236 /**
237 * Get the values that were added to the attribute.
238 *
239 * @return array
240 */
241 protected function getAddedValues()
242 {
243 return array_values(
244 array_diff($this->values, $this->original)
245 );
246 }
247
248 /**
249 * Get the values that were removed from the attribute.
250 *
251 * @return array
252 */
253 protected function getRemovedValues()
254 {
255 return array_values(
256 array_diff($this->original, $this->values)
257 );
258 }
259
260 /**
261 * Returns the built batch modification array.
262 *
263 * @return array|null
264 */
265 public function get()
266 {
267 switch ($this->type) {
268 case LDAP_MODIFY_BATCH_REMOVE_ALL:
269 // A values key cannot be provided when
270 // a remove all type is selected.
271 return [
272 static::KEY_ATTRIB => $this->attribute,
273 static::KEY_MODTYPE => $this->type,
274 ];
275 case LDAP_MODIFY_BATCH_REMOVE:
276 // Fallthrough.
277 case LDAP_MODIFY_BATCH_ADD:
278 // Fallthrough.
279 case LDAP_MODIFY_BATCH_REPLACE:
280 return [
281 static::KEY_ATTRIB => $this->attribute,
282 static::KEY_MODTYPE => $this->type,
283 static::KEY_VALUES => $this->values,
284 ];
285 default:
286 // If the modtype isn't recognized, we'll return null.
287 return;
288 }
289 }
290
291 /**
292 * Determines if the given modtype is valid.
293 *
294 * @param int $type
295 *
296 * @return bool
297 */
298 protected function isValidType($type)
299 {
300 return in_array($type, [
301 LDAP_MODIFY_BATCH_REMOVE_ALL,
302 LDAP_MODIFY_BATCH_REMOVE,
303 LDAP_MODIFY_BATCH_REPLACE,
304 LDAP_MODIFY_BATCH_ADD,
305 ]);
306 }
307}