|
1
|
|
|
<?php |
|
|
|
|
|
|
2
|
|
|
|
|
3
|
|
|
namespace Charcoal\Property; |
|
4
|
|
|
|
|
5
|
|
|
// Dependencies from `PHP` |
|
6
|
|
|
use \Exception; |
|
7
|
|
|
use \InvalidArgumentException; |
|
8
|
|
|
use \JsonSerializable; |
|
9
|
|
|
use \Serializable; |
|
10
|
|
|
|
|
11
|
|
|
// PSR-3 (logger) dependencies |
|
12
|
|
|
use \Psr\Log\LoggerAwareInterface; |
|
13
|
|
|
use \Psr\Log\LoggerAwareTrait; |
|
14
|
|
|
|
|
15
|
|
|
// Intra-module (`charcoal-core`) dependencies |
|
16
|
|
|
use \Charcoal\Model\DescribableInterface; |
|
17
|
|
|
use \Charcoal\Model\DescribableTrait; |
|
18
|
|
|
use \Charcoal\Translation\TranslationConfig; |
|
19
|
|
|
use \Charcoal\Translation\TranslationString; |
|
20
|
|
|
use \Charcoal\Validator\ValidatableInterface; |
|
21
|
|
|
use \Charcoal\Validator\ValidatableTrait; |
|
22
|
|
|
use \Charcoal\View\GenericView; |
|
23
|
|
|
use \Charcoal\View\ViewableInterface; |
|
24
|
|
|
use \Charcoal\View\ViewableTrait; |
|
25
|
|
|
|
|
26
|
|
|
// Local namespace dependencies |
|
27
|
|
|
use \Charcoal\Property\PropertyInterface; |
|
28
|
|
|
use \Charcoal\Property\PropertyValidator; |
|
29
|
|
|
use \Charcoal\Property\StorablePropertyInterface; |
|
30
|
|
|
use \Charcoal\Property\StorablePropertyTrait; |
|
31
|
|
|
|
|
32
|
|
|
/** |
|
33
|
|
|
* An abstract class that implements the full `PropertyInterface`. |
|
34
|
|
|
*/ |
|
35
|
|
|
abstract class AbstractProperty implements |
|
|
|
|
|
|
36
|
|
|
JsonSerializable, |
|
37
|
|
|
Serializable, |
|
38
|
|
|
PropertyInterface, |
|
39
|
|
|
DescribableInterface, |
|
40
|
|
|
LoggerAwareInterface, |
|
41
|
|
|
StorablePropertyInterface, |
|
42
|
|
|
ValidatableInterface, |
|
43
|
|
|
ViewableInterface |
|
44
|
|
|
{ |
|
45
|
|
|
use LoggerAwareTrait; |
|
46
|
|
|
use DescribableTrait; |
|
47
|
|
|
use StorablePropertyTrait; |
|
48
|
|
|
use ValidatableTrait; |
|
49
|
|
|
use ViewableTrait; |
|
50
|
|
|
|
|
51
|
|
|
/** |
|
52
|
|
|
* @var string $ident |
|
53
|
|
|
*/ |
|
54
|
|
|
private $ident = ''; |
|
55
|
|
|
|
|
56
|
|
|
/** |
|
57
|
|
|
* @var mixed $Val |
|
58
|
|
|
*/ |
|
59
|
|
|
protected $val; |
|
60
|
|
|
|
|
61
|
|
|
/** |
|
62
|
|
|
* @var TranslationString $label |
|
63
|
|
|
*/ |
|
64
|
|
|
private $label; |
|
65
|
|
|
|
|
66
|
|
|
/** |
|
67
|
|
|
* @var boolean $l10n |
|
68
|
|
|
*/ |
|
69
|
|
|
private $l10n = false; |
|
70
|
|
|
|
|
71
|
|
|
/** |
|
72
|
|
|
* @var boolean $hidden; |
|
73
|
|
|
*/ |
|
74
|
|
|
private $hidden = false; |
|
75
|
|
|
|
|
76
|
|
|
/** |
|
77
|
|
|
* @var boolean $multiple |
|
78
|
|
|
*/ |
|
79
|
|
|
private $multiple = false; |
|
80
|
|
|
|
|
81
|
|
|
/** |
|
82
|
|
|
* Array of options for multiple properties |
|
83
|
|
|
* - `separator` (default=",") How the values will be separated in the storage (sql). |
|
84
|
|
|
* - `min` (default=null) The min number of values. If null, <0 or NaN, then this is not taken into consideration. |
|
85
|
|
|
* - `max` (default=null) The max number of values. If null, <0 or NaN, then there is not limit. |
|
86
|
|
|
* @var mixed $multipleOptions |
|
87
|
|
|
*/ |
|
88
|
|
|
private $multipleOptions; |
|
89
|
|
|
|
|
90
|
|
|
/** |
|
91
|
|
|
* If true, this property *must* have a value |
|
92
|
|
|
* @var boolean $required |
|
93
|
|
|
*/ |
|
94
|
|
|
private $required = false; |
|
95
|
|
|
|
|
96
|
|
|
/** |
|
97
|
|
|
* Unique properties should not share he same value across 2 objects |
|
98
|
|
|
* @var boolean $unique |
|
99
|
|
|
*/ |
|
100
|
|
|
private $unique = false; |
|
101
|
|
|
|
|
102
|
|
|
/** |
|
103
|
|
|
* @var boolean $allowNull |
|
104
|
|
|
*/ |
|
105
|
|
|
private $allowNull = true; |
|
106
|
|
|
|
|
107
|
|
|
/** |
|
108
|
|
|
* Only the storable properties should be saved in storage. |
|
109
|
|
|
* @var boolean $storable |
|
110
|
|
|
*/ |
|
111
|
|
|
private $storable = true; |
|
112
|
|
|
|
|
113
|
|
|
/** |
|
114
|
|
|
* Inactive properties should be hidden everywhere / unused |
|
115
|
|
|
* @var boolean $active |
|
116
|
|
|
*/ |
|
117
|
|
|
private $active = true; |
|
118
|
|
|
|
|
119
|
|
|
/** |
|
120
|
|
|
* @var TranslationString $description |
|
121
|
|
|
*/ |
|
122
|
|
|
private $description = ''; |
|
123
|
|
|
|
|
124
|
|
|
/** |
|
125
|
|
|
* @var TranslationString $_notes |
|
126
|
|
|
*/ |
|
127
|
|
|
private $notes = ''; |
|
128
|
|
|
|
|
129
|
|
|
/** |
|
130
|
|
|
* Required dependencies: |
|
131
|
|
|
* - `logger` a PSR3-compliant logger. |
|
132
|
|
|
* |
|
133
|
|
|
* @param array $data Optional. Class Dependencies. |
|
134
|
|
|
*/ |
|
135
|
|
|
public function __construct(array $data = null) |
|
136
|
|
|
{ |
|
137
|
|
|
if (isset($data['logger'])) { |
|
138
|
|
|
$this->setLogger($data['logger']); |
|
139
|
|
|
} |
|
140
|
|
|
} |
|
141
|
|
|
|
|
142
|
|
|
/** |
|
143
|
|
|
* |
|
144
|
|
|
* |
|
145
|
|
|
* @return string |
|
146
|
|
|
*/ |
|
147
|
|
|
public function __toString() |
|
148
|
|
|
{ |
|
149
|
|
|
$val = $this->val(); |
|
150
|
|
|
if (is_string($val)) { |
|
151
|
|
|
return $val; |
|
152
|
|
|
} else { |
|
153
|
|
|
if (is_object($val)) { |
|
154
|
|
|
return (string)$val; |
|
155
|
|
|
} else { |
|
156
|
|
|
return ''; |
|
157
|
|
|
} |
|
158
|
|
|
} |
|
159
|
|
|
} |
|
160
|
|
|
|
|
161
|
|
|
/** |
|
162
|
|
|
* Get the "property type" string. |
|
163
|
|
|
* |
|
164
|
|
|
* ## Notes |
|
165
|
|
|
* - Type can not be set, so it must be explicitely provided by each implementing property classes. |
|
166
|
|
|
* |
|
167
|
|
|
* @return string |
|
168
|
|
|
*/ |
|
169
|
|
|
abstract public function type(); |
|
170
|
|
|
|
|
171
|
|
|
/** |
|
172
|
|
|
* This function takes an array and fill the property with its value. |
|
173
|
|
|
* |
|
174
|
|
|
* This method either calls a setter for each key (`set_{$key}()`) or sets a public member. |
|
175
|
|
|
* |
|
176
|
|
|
* For example, calling with `set_data(['ident'=>$ident])` would call `setIdent($ident)` |
|
177
|
|
|
* becasue `setIdent()` exists. |
|
178
|
|
|
* |
|
179
|
|
|
* But calling with `set_data(['foobar'=>$foo])` would set the `$foobar` member |
|
180
|
|
|
* on the metadata object, because the method `set_foobar()` does not exist. |
|
181
|
|
|
* |
|
182
|
|
|
* @param array $data The property data. |
|
183
|
|
|
* @return AbstractProperty Chainable |
|
184
|
|
|
*/ |
|
185
|
|
|
public function setData(array $data) |
|
186
|
|
|
{ |
|
187
|
|
|
foreach ($data as $prop => $val) { |
|
188
|
|
|
$setter = $this->setter($prop); |
|
189
|
|
|
if (is_callable([$this, $setter])) { |
|
190
|
|
|
$this->{$setter}($val); |
|
191
|
|
|
} else { |
|
192
|
|
|
// Set as public member if setter is not set on object. |
|
193
|
|
|
$this->{$prop} = $val; |
|
194
|
|
|
} |
|
195
|
|
|
} |
|
196
|
|
|
|
|
197
|
|
|
return $this; |
|
198
|
|
|
} |
|
199
|
|
|
|
|
200
|
|
|
/** |
|
201
|
|
|
* @param string $ident The property identifier. |
|
202
|
|
|
* @throws InvalidArgumentException If the ident parameter is not a string. |
|
203
|
|
|
* @return AbstractProperty Chainable |
|
204
|
|
|
*/ |
|
205
|
|
|
public function setIdent($ident) |
|
206
|
|
|
{ |
|
207
|
|
|
if (!is_string($ident)) { |
|
208
|
|
|
throw new InvalidArgumentException( |
|
209
|
|
|
'Ident needs to be string.' |
|
210
|
|
|
); |
|
211
|
|
|
} |
|
212
|
|
|
$this->ident = $ident; |
|
213
|
|
|
return $this; |
|
214
|
|
|
} |
|
215
|
|
|
|
|
216
|
|
|
/** |
|
217
|
|
|
* @throws Exception If trying to access getter before setter. |
|
218
|
|
|
* @return string |
|
219
|
|
|
*/ |
|
220
|
|
|
public function ident() |
|
221
|
|
|
{ |
|
222
|
|
|
if ($this->ident === null) { |
|
223
|
|
|
throw new Exception( |
|
224
|
|
|
'Can not get ident(): Ident was never set.' |
|
225
|
|
|
); |
|
226
|
|
|
} |
|
227
|
|
|
return $this->ident; |
|
228
|
|
|
} |
|
229
|
|
|
|
|
230
|
|
|
/** |
|
231
|
|
|
* @param mixed $val The property (raw) value. |
|
232
|
|
|
* @throws InvalidArgumentException If the value is invalid (null or not multiple when supposed to). |
|
233
|
|
|
* @return PropertyInterface Chainable |
|
234
|
|
|
*/ |
|
235
|
|
|
public function setVal($val) |
|
236
|
|
|
{ |
|
237
|
|
View Code Duplication |
if ($val === null) { |
|
|
|
|
|
|
238
|
|
|
if ($this->allowNull()) { |
|
239
|
|
|
$this->val = null; |
|
240
|
|
|
return $this; |
|
241
|
|
|
} else { |
|
242
|
|
|
throw new InvalidArgumentException( |
|
243
|
|
|
'Val can not be null (Not allowed)' |
|
244
|
|
|
); |
|
245
|
|
|
} |
|
246
|
|
|
} |
|
247
|
|
|
if ($this->multiple()) { |
|
248
|
|
|
if (is_string($val)) { |
|
249
|
|
|
$val = explode($this->multipleSeparator(), $val); |
|
250
|
|
|
} |
|
251
|
|
|
if (!is_array($val)) { |
|
252
|
|
|
throw new InvalidArgumentException( |
|
253
|
|
|
'Val is multiple so it must be a string (convertable to array by separator) or an array' |
|
254
|
|
|
); |
|
255
|
|
|
} |
|
256
|
|
|
} |
|
257
|
|
|
$this->val = $val; |
|
258
|
|
|
return $this; |
|
259
|
|
|
} |
|
260
|
|
|
|
|
261
|
|
|
/** |
|
262
|
|
|
* @return mixed |
|
263
|
|
|
*/ |
|
264
|
|
|
public function val() |
|
265
|
|
|
{ |
|
266
|
|
|
return $this->val; |
|
267
|
|
|
} |
|
268
|
|
|
|
|
269
|
|
|
|
|
270
|
|
|
|
|
271
|
|
|
/** |
|
272
|
|
|
* @param mixed $val Optional. The value to to convert to display. |
|
273
|
|
|
* @return string |
|
274
|
|
|
*/ |
|
275
|
|
|
public function displayVal($val = null) |
|
276
|
|
|
{ |
|
277
|
|
|
if ($val === null) { |
|
278
|
|
|
$val = $this->val(); |
|
279
|
|
|
} |
|
280
|
|
|
|
|
281
|
|
|
if ($val === null) { |
|
282
|
|
|
return ''; |
|
283
|
|
|
} |
|
284
|
|
|
|
|
285
|
|
|
$propertyValue = $val; |
|
286
|
|
|
|
|
287
|
|
|
if ($this->l10n() === true) { |
|
288
|
|
|
$translator = TranslationConfig::instance(); |
|
289
|
|
|
|
|
290
|
|
|
$propertyValue = $propertyValue[$translator->currentLanguage()]; |
|
291
|
|
|
} |
|
292
|
|
|
|
|
293
|
|
|
if ($this->multiple() === true) { |
|
294
|
|
|
if (is_array($propertyValue)) { |
|
295
|
|
|
$propertyValue = implode($this->multipleSeparator(), $propertyValue); |
|
296
|
|
|
} |
|
297
|
|
|
} |
|
298
|
|
|
return (string)$propertyValue; |
|
299
|
|
|
} |
|
300
|
|
|
|
|
301
|
|
|
/** |
|
302
|
|
|
* @param mixed $label The property label. |
|
303
|
|
|
* @return PropertyInterface Chainable |
|
304
|
|
|
*/ |
|
305
|
|
|
public function setLabel($label) |
|
306
|
|
|
{ |
|
307
|
|
|
$this->label = new TranslationString($label); |
|
308
|
|
|
return $this; |
|
309
|
|
|
} |
|
310
|
|
|
|
|
311
|
|
|
/** |
|
312
|
|
|
* @return string |
|
313
|
|
|
*/ |
|
314
|
|
|
public function label() |
|
315
|
|
|
{ |
|
316
|
|
|
if ($this->label === null) { |
|
317
|
|
|
return ucwords(str_replace(['.', '_'], ' ', $this->ident())); |
|
318
|
|
|
} |
|
319
|
|
|
return $this->label; |
|
320
|
|
|
} |
|
321
|
|
|
|
|
322
|
|
|
/** |
|
323
|
|
|
* @param boolean $l10n The l10n, or "translatable" flag. |
|
324
|
|
|
* @return PropertyInterface Chainable |
|
325
|
|
|
*/ |
|
326
|
|
|
public function setL10n($l10n) |
|
327
|
|
|
{ |
|
328
|
|
|
$this->l10n = !!$l10n; |
|
329
|
|
|
return $this; |
|
330
|
|
|
} |
|
331
|
|
|
|
|
332
|
|
|
/** |
|
333
|
|
|
* The l10n flag sets the property as being translatable, meaning the data is held for multple languages. |
|
334
|
|
|
* |
|
335
|
|
|
* @return boolean |
|
336
|
|
|
*/ |
|
337
|
|
|
public function l10n() |
|
338
|
|
|
{ |
|
339
|
|
|
return $this->l10n; |
|
340
|
|
|
} |
|
341
|
|
|
|
|
342
|
|
|
/** |
|
343
|
|
|
* @param boolean $hidden The hidden flag. |
|
344
|
|
|
* @return PropertyInterface Chainable |
|
345
|
|
|
*/ |
|
346
|
|
|
public function setHidden($hidden) |
|
347
|
|
|
{ |
|
348
|
|
|
$this->hidden = !!$hidden; |
|
349
|
|
|
return $this; |
|
350
|
|
|
} |
|
351
|
|
|
|
|
352
|
|
|
/** |
|
353
|
|
|
* @return boolean |
|
354
|
|
|
*/ |
|
355
|
|
|
public function hidden() |
|
356
|
|
|
{ |
|
357
|
|
|
return $this->hidden; |
|
358
|
|
|
} |
|
359
|
|
|
|
|
360
|
|
|
/** |
|
361
|
|
|
* @param boolean $multiple The multiple flag. |
|
362
|
|
|
* @return PropertyInterface Chainable |
|
363
|
|
|
*/ |
|
364
|
|
|
public function setMultiple($multiple) |
|
365
|
|
|
{ |
|
366
|
|
|
$this->multiple = !!$multiple; |
|
367
|
|
|
return $this; |
|
368
|
|
|
} |
|
369
|
|
|
|
|
370
|
|
|
/** |
|
371
|
|
|
* The multiple flags sets the property as being "repeatable", or allow to represent an array of multiple values. |
|
372
|
|
|
* |
|
373
|
|
|
* ## Notes |
|
374
|
|
|
* - The multiple flag can be forced to false (or true) in implementing property class. |
|
375
|
|
|
* - How a multiple behaves also depend on `multipleOptions`. |
|
376
|
|
|
* |
|
377
|
|
|
* @return boolean |
|
378
|
|
|
*/ |
|
379
|
|
|
public function multiple() |
|
380
|
|
|
{ |
|
381
|
|
|
return $this->multiple; |
|
382
|
|
|
} |
|
383
|
|
|
|
|
384
|
|
|
/** |
|
385
|
|
|
* Set the multiple options / configuration, when property is `multiple`. |
|
386
|
|
|
* |
|
387
|
|
|
* ## Options structure |
|
388
|
|
|
* - `separator` (string) The separator charactor. |
|
389
|
|
|
* - `min` (integer) The minimum number of values. (0 = no limit). |
|
390
|
|
|
* - `max` (integer) The maximum number of values. (0 = no limit). |
|
391
|
|
|
* |
|
392
|
|
|
* @param array $multipleOptions The property multiple options. |
|
393
|
|
|
* @return PropertyInterface Chainable |
|
394
|
|
|
*/ |
|
395
|
|
|
public function setMultipleOptions(array $multipleOptions) |
|
396
|
|
|
{ |
|
397
|
|
|
// The options are always merged with the defaults, to ensure minimum required array structure. |
|
398
|
|
|
$options = array_merge($this->defaultMultipleOptions(), $multipleOptions); |
|
399
|
|
|
$this->multipleOptions = $options; |
|
400
|
|
|
return $this; |
|
401
|
|
|
} |
|
402
|
|
|
|
|
403
|
|
|
/** |
|
404
|
|
|
* The options defining the property behavior when the multiple flag is set to true. |
|
405
|
|
|
* |
|
406
|
|
|
* @return array |
|
407
|
|
|
* @see self::defaultMultipleOptions |
|
408
|
|
|
*/ |
|
409
|
|
|
public function multipleOptions() |
|
410
|
|
|
{ |
|
411
|
|
|
if ($this->multipleOptions === null) { |
|
412
|
|
|
return $this->defaultMultipleOptions(); |
|
413
|
|
|
} |
|
414
|
|
|
return $this->multipleOptions; |
|
415
|
|
|
} |
|
416
|
|
|
|
|
417
|
|
|
/** |
|
418
|
|
|
* @return array |
|
419
|
|
|
*/ |
|
420
|
|
|
public function defaultMultipleOptions() |
|
421
|
|
|
{ |
|
422
|
|
|
return [ |
|
423
|
|
|
'separator' => ',', |
|
424
|
|
|
'min' => 0, |
|
425
|
|
|
'max' => 0 |
|
426
|
|
|
]; |
|
427
|
|
|
} |
|
428
|
|
|
|
|
429
|
|
|
/** |
|
430
|
|
|
* @return string |
|
431
|
|
|
*/ |
|
432
|
|
|
public function multipleSeparator() |
|
433
|
|
|
{ |
|
434
|
|
|
$multipleOptions = $this->multipleOptions(); |
|
435
|
|
|
return $multipleOptions['separator']; |
|
436
|
|
|
} |
|
437
|
|
|
|
|
438
|
|
|
/** |
|
439
|
|
|
* @param boolean $allow The property allow null flag. |
|
440
|
|
|
* @return PropertyInterface Chainable |
|
441
|
|
|
*/ |
|
442
|
|
|
public function setAllowNull($allow) |
|
443
|
|
|
{ |
|
444
|
|
|
$this->allowNull = !!$allow; |
|
445
|
|
|
return $this; |
|
446
|
|
|
} |
|
447
|
|
|
|
|
448
|
|
|
/** |
|
449
|
|
|
* The allow null flag sets the property as being able to be of a "null" value. |
|
450
|
|
|
* |
|
451
|
|
|
* ## Notes |
|
452
|
|
|
* - This flag typically modifies the storage database to also allow null values. |
|
453
|
|
|
* |
|
454
|
|
|
* @return boolean |
|
455
|
|
|
*/ |
|
456
|
|
|
public function allowNull() |
|
457
|
|
|
{ |
|
458
|
|
|
return $this->allowNull; |
|
459
|
|
|
} |
|
460
|
|
|
|
|
461
|
|
|
/** |
|
462
|
|
|
* @param boolean $required The property required flag. |
|
463
|
|
|
* @return PropertyInterface Chainable |
|
464
|
|
|
*/ |
|
465
|
|
|
public function setRequired($required) |
|
466
|
|
|
{ |
|
467
|
|
|
$this->required = !!$required; |
|
468
|
|
|
return $this; |
|
469
|
|
|
} |
|
470
|
|
|
|
|
471
|
|
|
/** |
|
472
|
|
|
* Required flag sets the property as being required, meaning not allowed to be null / empty. |
|
473
|
|
|
* |
|
474
|
|
|
* ## Notes |
|
475
|
|
|
* - The actual meaning of "required" might be different for implementing property class. |
|
476
|
|
|
* |
|
477
|
|
|
* @return boolean |
|
478
|
|
|
*/ |
|
479
|
|
|
public function required() |
|
480
|
|
|
{ |
|
481
|
|
|
return $this->required; |
|
482
|
|
|
} |
|
483
|
|
|
|
|
484
|
|
|
/** |
|
485
|
|
|
* @param boolean $unique The property unique flag. |
|
486
|
|
|
* @return PropertyInterface Chainable |
|
487
|
|
|
*/ |
|
488
|
|
|
public function setUnique($unique) |
|
489
|
|
|
{ |
|
490
|
|
|
$this->unique = !!$unique; |
|
491
|
|
|
return $this; |
|
492
|
|
|
} |
|
493
|
|
|
|
|
494
|
|
|
/** |
|
495
|
|
|
* @return boolean |
|
496
|
|
|
*/ |
|
497
|
|
|
public function unique() |
|
498
|
|
|
{ |
|
499
|
|
|
return $this->unique; |
|
500
|
|
|
} |
|
501
|
|
|
|
|
502
|
|
|
/** |
|
503
|
|
|
* @param boolean $active The property active flag. Inactive properties should have no effects. |
|
504
|
|
|
* @return PropertyInterface Chainable |
|
505
|
|
|
*/ |
|
506
|
|
|
public function setActive($active) |
|
507
|
|
|
{ |
|
508
|
|
|
$this->active = !!$active; |
|
509
|
|
|
return $this; |
|
510
|
|
|
} |
|
511
|
|
|
|
|
512
|
|
|
/** |
|
513
|
|
|
* @return boolean |
|
514
|
|
|
*/ |
|
515
|
|
|
public function active() |
|
516
|
|
|
{ |
|
517
|
|
|
return $this->active; |
|
518
|
|
|
} |
|
519
|
|
|
|
|
520
|
|
|
/** |
|
521
|
|
|
* @param boolean $storable The storable flag. |
|
522
|
|
|
* @return PropertyInterface Chainable |
|
523
|
|
|
*/ |
|
524
|
|
|
public function setStorable($storable) |
|
525
|
|
|
{ |
|
526
|
|
|
$this->storable = !!$storable; |
|
527
|
|
|
return $this; |
|
528
|
|
|
} |
|
529
|
|
|
|
|
530
|
|
|
/** |
|
531
|
|
|
* @return boolean |
|
532
|
|
|
*/ |
|
533
|
|
|
public function storable() |
|
534
|
|
|
{ |
|
535
|
|
|
return $this->storable; |
|
536
|
|
|
} |
|
537
|
|
|
|
|
538
|
|
|
/** |
|
539
|
|
|
* @param mixed $description The property description. |
|
540
|
|
|
* @return PropertyInterface Chainable |
|
541
|
|
|
*/ |
|
542
|
|
|
public function setDescription($description) |
|
543
|
|
|
{ |
|
544
|
|
|
$this->description = new TranslationString($description); |
|
545
|
|
|
return $this; |
|
546
|
|
|
} |
|
547
|
|
|
|
|
548
|
|
|
/** |
|
549
|
|
|
* @return string |
|
550
|
|
|
*/ |
|
551
|
|
|
public function description() |
|
552
|
|
|
{ |
|
553
|
|
|
return $this->description; |
|
554
|
|
|
} |
|
555
|
|
|
|
|
556
|
|
|
/** |
|
557
|
|
|
* @param mixed $notes The property notes. |
|
558
|
|
|
* @return PropertyInterface Chainable |
|
559
|
|
|
*/ |
|
560
|
|
|
public function setNotes($notes) |
|
561
|
|
|
{ |
|
562
|
|
|
$this->notes = new TranslationString($notes); |
|
563
|
|
|
return $this; |
|
564
|
|
|
} |
|
565
|
|
|
|
|
566
|
|
|
/** |
|
567
|
|
|
* @return string |
|
568
|
|
|
*/ |
|
569
|
|
|
public function notes() |
|
570
|
|
|
{ |
|
571
|
|
|
return $this->notes; |
|
572
|
|
|
} |
|
573
|
|
|
|
|
574
|
|
|
|
|
575
|
|
|
|
|
576
|
|
|
/** |
|
577
|
|
|
* The property's default validation methods/ |
|
578
|
|
|
* |
|
579
|
|
|
* - `required` |
|
580
|
|
|
* - `unique` |
|
581
|
|
|
* - `allowNull` |
|
582
|
|
|
* |
|
583
|
|
|
* ## Notes |
|
584
|
|
|
* - Those 3 base validation methods should always be merged, in implementing factory class. |
|
585
|
|
|
* |
|
586
|
|
|
* @return array |
|
587
|
|
|
*/ |
|
588
|
|
|
public function validationMethods() |
|
589
|
|
|
{ |
|
590
|
|
|
return [ |
|
591
|
|
|
'required', |
|
592
|
|
|
'unique', |
|
593
|
|
|
'allowNull' |
|
594
|
|
|
]; |
|
595
|
|
|
} |
|
596
|
|
|
|
|
597
|
|
|
/** |
|
598
|
|
|
* @return boolean |
|
599
|
|
|
*/ |
|
600
|
|
|
public function validateRequired() |
|
601
|
|
|
{ |
|
602
|
|
|
if ($this->required() && !$this->val()) { |
|
603
|
|
|
$this->validator()->error('Value is required.', 'required'); |
|
|
|
|
|
|
604
|
|
|
return false; |
|
605
|
|
|
} |
|
606
|
|
|
|
|
607
|
|
|
return true; |
|
608
|
|
|
} |
|
609
|
|
|
|
|
610
|
|
|
/** |
|
611
|
|
|
* @return boolean |
|
612
|
|
|
*/ |
|
613
|
|
|
public function validateUnique() |
|
614
|
|
|
{ |
|
615
|
|
|
if (!$this->unique()) { |
|
616
|
|
|
return true; |
|
617
|
|
|
} |
|
618
|
|
|
|
|
619
|
|
|
/** @todo Check in the model's storage if the value already exists. */ |
|
620
|
|
|
return true; |
|
621
|
|
|
} |
|
622
|
|
|
|
|
623
|
|
|
/** |
|
624
|
|
|
* @return boolean |
|
625
|
|
|
*/ |
|
626
|
|
|
public function validateAllowNull() |
|
627
|
|
|
{ |
|
628
|
|
|
if (!$this->allowNull() && $this->val() === null) { |
|
629
|
|
|
$this->validator()->error('Value can not be null.', 'allowNull'); |
|
|
|
|
|
|
630
|
|
|
return false; |
|
631
|
|
|
} |
|
632
|
|
|
return true; |
|
633
|
|
|
} |
|
634
|
|
|
|
|
635
|
|
|
/** |
|
636
|
|
|
* @param string $propertyIdent The ident of the property to retrieve. |
|
637
|
|
|
* @return mixed |
|
638
|
|
|
*/ |
|
639
|
|
|
protected function propertyValue($propertyIdent) |
|
640
|
|
|
{ |
|
641
|
|
|
if (isset($this->{$propertyIdent})) { |
|
642
|
|
|
return $this->{$propertyIdent}; |
|
643
|
|
|
} else { |
|
644
|
|
|
return null; |
|
645
|
|
|
} |
|
646
|
|
|
} |
|
647
|
|
|
|
|
648
|
|
|
/** |
|
649
|
|
|
* @param array $data Optional. Metadata data. |
|
650
|
|
|
* @return PropertyMetadata |
|
651
|
|
|
*/ |
|
652
|
|
|
protected function createMetadata(array $data = null) |
|
653
|
|
|
{ |
|
654
|
|
|
$metadata = new PropertyMetadata(); |
|
655
|
|
|
if (is_array($data)) { |
|
656
|
|
|
$metadata->setData($data); |
|
|
|
|
|
|
657
|
|
|
} |
|
658
|
|
|
return $metadata; |
|
659
|
|
|
} |
|
660
|
|
|
|
|
661
|
|
|
/** |
|
662
|
|
|
* ValidatableTrait > createValidator(). Create a Validator object |
|
663
|
|
|
* |
|
664
|
|
|
* @return ValidatorInterface |
|
665
|
|
|
*/ |
|
666
|
|
|
protected function createValidator() |
|
667
|
|
|
{ |
|
668
|
|
|
$validator = new PropertyValidator($this); |
|
669
|
|
|
return $validator; |
|
670
|
|
|
} |
|
671
|
|
|
|
|
672
|
|
|
/** |
|
673
|
|
|
* @param array $data Optional. View data. |
|
674
|
|
|
* @return ViewInterface |
|
675
|
|
|
*/ |
|
676
|
|
|
public function createView(array $data = null) |
|
677
|
|
|
{ |
|
678
|
|
|
$view = new GenericView([ |
|
679
|
|
|
'logger'=>$this->logger |
|
680
|
|
|
]); |
|
681
|
|
|
if ($data !== null) { |
|
682
|
|
|
$view->setData($data); |
|
683
|
|
|
} |
|
684
|
|
|
return $view; |
|
685
|
|
|
} |
|
686
|
|
|
|
|
687
|
|
|
/** |
|
688
|
|
|
* @return mixed |
|
689
|
|
|
*/ |
|
690
|
|
|
abstract public function save(); |
|
691
|
|
|
|
|
692
|
|
|
/** |
|
693
|
|
|
* Serializable > serialize() |
|
694
|
|
|
* |
|
695
|
|
|
* @return string |
|
696
|
|
|
*/ |
|
697
|
|
|
public function serialize() |
|
698
|
|
|
{ |
|
699
|
|
|
$data = $this->val(); |
|
700
|
|
|
return serialize($data); |
|
701
|
|
|
} |
|
702
|
|
|
/** |
|
703
|
|
|
* Serializable > unsierialize() |
|
704
|
|
|
* |
|
705
|
|
|
* @param string $data Serialized data. |
|
706
|
|
|
* @return void |
|
707
|
|
|
*/ |
|
708
|
|
|
public function unserialize($data) |
|
709
|
|
|
{ |
|
710
|
|
|
$data = unserialize($data); |
|
711
|
|
|
$this->setVal($data); |
|
712
|
|
|
} |
|
713
|
|
|
|
|
714
|
|
|
/** |
|
715
|
|
|
* JsonSerializable > jsonSerialize() |
|
716
|
|
|
* |
|
717
|
|
|
* @return mixed |
|
718
|
|
|
*/ |
|
719
|
|
|
public function jsonSerialize() |
|
720
|
|
|
{ |
|
721
|
|
|
return $this->val(); |
|
722
|
|
|
} |
|
723
|
|
|
|
|
724
|
|
|
/** |
|
725
|
|
|
* Allow an object to define how the key getter are called. |
|
726
|
|
|
* |
|
727
|
|
|
* @param string $key The key to get the getter from. |
|
728
|
|
|
* @return string The getter method name, for a given key. |
|
729
|
|
|
*/ |
|
730
|
|
|
protected function getter($key) |
|
731
|
|
|
{ |
|
732
|
|
|
$getter = $key; |
|
733
|
|
|
return $this->camelize($getter); |
|
734
|
|
|
} |
|
735
|
|
|
|
|
736
|
|
|
/** |
|
737
|
|
|
* Allow an object to define how the key setter are called. |
|
738
|
|
|
* |
|
739
|
|
|
* @param string $key The key to get the setter from. |
|
740
|
|
|
* @return string The setter method name, for a given key. |
|
741
|
|
|
*/ |
|
742
|
|
|
protected function setter($key) |
|
743
|
|
|
{ |
|
744
|
|
|
$setter = 'set_'.$key; |
|
745
|
|
|
return $this->camelize($setter); |
|
746
|
|
|
} |
|
747
|
|
|
|
|
748
|
|
|
/** |
|
749
|
|
|
* Transform a snake_case string to camelCase. |
|
750
|
|
|
* |
|
751
|
|
|
* @param string $str The snake_case string to camelize. |
|
752
|
|
|
* @return string The camelCase string. |
|
753
|
|
|
*/ |
|
754
|
|
|
private function camelize($str) |
|
755
|
|
|
{ |
|
756
|
|
|
return lcfirst(implode('', array_map('ucfirst', explode('_', $str)))); |
|
757
|
|
|
} |
|
758
|
|
|
} |
|
759
|
|
|
|
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.