1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Charcoal\Source; |
4
|
|
|
|
5
|
|
|
use InvalidArgumentException; |
6
|
|
|
|
7
|
|
|
// From PSR-3 |
8
|
|
|
use Psr\Log\LoggerAwareInterface; |
9
|
|
|
use Psr\Log\LoggerAwareTrait; |
10
|
|
|
|
11
|
|
|
// From 'charcoal-config' |
12
|
|
|
use Charcoal\Config\ConfigurableInterface; |
13
|
|
|
use Charcoal\Config\ConfigurableTrait; |
14
|
|
|
|
15
|
|
|
// From 'charcoal-property' |
16
|
|
|
use Charcoal\Property\PropertyInterface; |
17
|
|
|
|
18
|
|
|
// From 'charcoal-core' |
19
|
|
|
use Charcoal\Source\SourceConfig; |
20
|
|
|
use Charcoal\Source\SourceInterface; |
21
|
|
|
use Charcoal\Source\ModelAwareTrait; |
22
|
|
|
use Charcoal\Source\Filter; |
23
|
|
|
use Charcoal\Source\FilterInterface; |
24
|
|
|
use Charcoal\Source\FilterCollectionInterface; |
25
|
|
|
use Charcoal\Source\FilterCollectionTrait; |
26
|
|
|
use Charcoal\Source\Order; |
27
|
|
|
use Charcoal\Source\OrderInterface; |
28
|
|
|
use Charcoal\Source\OrderCollectionInterface; |
29
|
|
|
use Charcoal\Source\OrderCollectionTrait; |
30
|
|
|
use Charcoal\Source\Pagination; |
31
|
|
|
use Charcoal\Source\PaginationInterface; |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* Data Storage Source Handler. |
35
|
|
|
*/ |
36
|
|
|
abstract class AbstractSource implements |
37
|
|
|
SourceInterface, |
38
|
|
|
ConfigurableInterface, |
39
|
|
|
LoggerAwareInterface |
40
|
|
|
{ |
41
|
|
|
use ConfigurableTrait; |
42
|
|
|
use LoggerAwareTrait; |
43
|
|
|
use ModelAwareTrait; |
44
|
|
|
use FilterCollectionTrait { |
45
|
|
|
FilterCollectionTrait::addFilter as pushFilter; |
46
|
|
|
} |
47
|
|
|
use OrderCollectionTrait { |
48
|
|
|
OrderCollectionTrait::addOrder as pushOrder; |
49
|
|
|
} |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* The {@see self::$model}'s properties. |
53
|
|
|
* |
54
|
|
|
* Stored as an associative array to maintain uniqueness. |
55
|
|
|
* |
56
|
|
|
* @var array<string,boolean> |
57
|
|
|
*/ |
58
|
|
|
private $properties = []; |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* Store the source query pagination. |
62
|
|
|
* |
63
|
|
|
* @var PaginationInterface |
64
|
|
|
*/ |
65
|
|
|
protected $pagination; |
66
|
|
|
|
67
|
|
|
/** |
68
|
|
|
* Create a new source handler. |
69
|
|
|
* |
70
|
|
|
* @param array $data Class dependencies. |
71
|
|
|
*/ |
72
|
|
|
public function __construct(array $data) |
73
|
|
|
{ |
74
|
|
|
$this->setLogger($data['logger']); |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
/** |
78
|
|
|
* Reset everything but the model. |
79
|
|
|
* |
80
|
|
|
* @return self |
81
|
|
|
*/ |
82
|
|
|
public function reset() |
83
|
|
|
{ |
84
|
|
|
$this->properties = []; |
85
|
|
|
$this->filters = []; |
86
|
|
|
$this->orders = []; |
87
|
|
|
$this->pagination = null; |
88
|
|
|
|
89
|
|
|
return $this; |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
/** |
93
|
|
|
* Set the source's settings. |
94
|
|
|
* |
95
|
|
|
* @param array $data Data to assign to the source. |
96
|
|
|
* @return self |
97
|
|
|
*/ |
98
|
|
View Code Duplication |
public function setData(array $data) |
|
|
|
|
99
|
|
|
{ |
100
|
|
|
foreach ($data as $key => $val) { |
101
|
|
|
$setter = $this->setter($key); |
102
|
|
|
if (is_callable([ $this, $setter ])) { |
103
|
|
|
$this->{$setter}($val); |
104
|
|
|
} else { |
105
|
|
|
$this->{$key} = $val; |
106
|
|
|
} |
107
|
|
|
} |
108
|
|
|
|
109
|
|
|
return $this; |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
/** |
113
|
|
|
* Set the properties of the source to fetch. |
114
|
|
|
* |
115
|
|
|
* This method accepts an array of property identifiers |
116
|
|
|
* that will, if supported, be fetched from the source. |
117
|
|
|
* |
118
|
|
|
* If no properties are set, it is assumed that |
119
|
|
|
* all model propertiesare to be fetched. |
120
|
|
|
* |
121
|
|
|
* @param (string|PropertyInterface)[] $properties One or more property keys to set. |
122
|
|
|
* @return self |
123
|
|
|
*/ |
124
|
|
|
public function setProperties(array $properties) |
125
|
|
|
{ |
126
|
|
|
$this->properties = []; |
127
|
|
|
$this->addProperties($properties); |
128
|
|
|
|
129
|
|
|
return $this; |
130
|
|
|
} |
131
|
|
|
|
132
|
|
|
/** |
133
|
|
|
* Determine if the source has any properties to fetch. |
134
|
|
|
* |
135
|
|
|
* @return boolean TRUE if properties are defined, otherwise FALSE. |
136
|
|
|
*/ |
137
|
|
|
public function hasProperties() |
138
|
|
|
{ |
139
|
|
|
return !empty($this->properties); |
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
/** |
143
|
|
|
* Get the properties of the source to fetch. |
144
|
|
|
* |
145
|
|
|
* @return string[] |
146
|
|
|
*/ |
147
|
|
|
public function properties() |
148
|
|
|
{ |
149
|
|
|
return array_keys($this->properties); |
150
|
|
|
} |
151
|
|
|
|
152
|
|
|
/** |
153
|
|
|
* Add properties of the source to fetch. |
154
|
|
|
* |
155
|
|
|
* @param (string|PropertyInterface)[] $properties One or more property keys to append. |
156
|
|
|
* @return self |
157
|
|
|
*/ |
158
|
|
|
public function addProperties(array $properties) |
159
|
|
|
{ |
160
|
|
|
foreach ($properties as $property) { |
161
|
|
|
$this->addProperty($property); |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
return $this; |
165
|
|
|
} |
166
|
|
|
|
167
|
|
|
/** |
168
|
|
|
* Add a property of the source to fetch. |
169
|
|
|
* |
170
|
|
|
* @param string|PropertyInterface $property A property key to append. |
171
|
|
|
* @return self |
172
|
|
|
*/ |
173
|
|
|
public function addProperty($property) |
174
|
|
|
{ |
175
|
|
|
$property = $this->resolvePropertyName($property); |
176
|
|
|
$this->properties[$property] = true; |
177
|
|
|
return $this; |
178
|
|
|
} |
179
|
|
|
|
180
|
|
|
/** |
181
|
|
|
* Remove a property of the source to fetch. |
182
|
|
|
* |
183
|
|
|
* @param string|PropertyInterface $property A property key. |
184
|
|
|
* @return self |
185
|
|
|
*/ |
186
|
|
|
public function removeProperty($property) |
187
|
|
|
{ |
188
|
|
|
$property = $this->resolvePropertyName($property); |
189
|
|
|
unset($this->properties[$property]); |
190
|
|
|
return $this; |
191
|
|
|
} |
192
|
|
|
|
193
|
|
|
/** |
194
|
|
|
* Resolve the name for the given property, throws an Exception if not. |
195
|
|
|
* |
196
|
|
|
* @param mixed $property Property to resolve. |
197
|
|
|
* @throws InvalidArgumentException If property is not a string, empty, or invalid. |
198
|
|
|
* @return string The property name. |
199
|
|
|
*/ |
200
|
|
|
protected function resolvePropertyName($property) |
201
|
|
|
{ |
202
|
|
|
if ($property instanceof PropertyInterface) { |
203
|
|
|
$property = $property->ident(); |
204
|
|
|
} |
205
|
|
|
|
206
|
|
|
if (!is_string($property)) { |
207
|
|
|
throw new InvalidArgumentException( |
208
|
|
|
'Property must be a string.' |
209
|
|
|
); |
210
|
|
|
} |
211
|
|
|
|
212
|
|
|
if ($property === '') { |
213
|
|
|
throw new InvalidArgumentException( |
214
|
|
|
'Property can not be empty.' |
215
|
|
|
); |
216
|
|
|
} |
217
|
|
|
|
218
|
|
|
return $property; |
219
|
|
|
} |
220
|
|
|
|
221
|
|
|
/** |
222
|
|
|
* Append a query filter on the source. |
223
|
|
|
* |
224
|
|
|
* There are 3 different ways of adding a filter: |
225
|
|
|
* - as a `Filter` object, in which case it will be added directly. |
226
|
|
|
* - `addFilter($obj);` |
227
|
|
|
* - as an array of options, which will be used to build the `Filter` object |
228
|
|
|
* - `addFilter(['property' => 'foo', 'value' => 42, 'operator' => '<=']);` |
229
|
|
|
* - as 3 parameters: `property`, `value` and `options` |
230
|
|
|
* - `addFilter('foo', 42, ['operator' => '<=']);` |
231
|
|
|
* |
232
|
|
|
* @deprecated 0.3 To be replaced with FilterCollectionTrait::addFilter() |
233
|
|
|
* |
234
|
|
|
* @uses self::parseFilterWithModel() |
235
|
|
|
* @uses FilterCollectionTrait::processFilter() |
236
|
|
|
* @param mixed $param The property to filter by, |
237
|
|
|
* a {@see FilterInterface} object, |
238
|
|
|
* or a filter array structure. |
239
|
|
|
* @param mixed $value Optional value for the property to compare against. |
240
|
|
|
* Only used if the first argument is a string. |
241
|
|
|
* @param array $options Optional extra settings to apply on the filter. |
242
|
|
|
* @throws InvalidArgumentException If the $param argument is invalid. |
243
|
|
|
* @return self |
244
|
|
|
*/ |
245
|
|
View Code Duplication |
public function addFilter($param, $value = null, array $options = null) |
|
|
|
|
246
|
|
|
{ |
247
|
|
|
if (is_string($param) && $value !== null) { |
248
|
|
|
$expr = $this->createFilter(); |
249
|
|
|
$expr->setProperty($param); |
250
|
|
|
$expr->setValue($value); |
251
|
|
|
} else { |
252
|
|
|
$expr = $param; |
253
|
|
|
} |
254
|
|
|
|
255
|
|
|
$expr = $this->processFilter($expr); |
256
|
|
|
|
257
|
|
|
/** @deprecated 0.3 */ |
258
|
|
|
if (is_array($param) && isset($param['options'])) { |
259
|
|
|
$expr->setData($param['options']); |
|
|
|
|
260
|
|
|
} |
261
|
|
|
|
262
|
|
|
if (is_array($options)) { |
263
|
|
|
$expr->setData($options); |
264
|
|
|
} |
265
|
|
|
|
266
|
|
|
$this->filters[] = $this->parseFilterWithModel($expr); |
267
|
|
|
return $this; |
268
|
|
|
} |
269
|
|
|
|
270
|
|
|
/** |
271
|
|
|
* Process a query filter with the current model. |
272
|
|
|
* |
273
|
|
|
* @param FilterInterface $filter The expression object. |
274
|
|
|
* @return FilterInterface The parsed expression object. |
275
|
|
|
*/ |
276
|
|
|
protected function parseFilterWithModel(FilterInterface $filter) |
277
|
|
|
{ |
278
|
|
|
if ($this->hasModel()) { |
279
|
|
|
if ($filter->hasProperty()) { |
280
|
|
|
$model = $this->model(); |
281
|
|
|
$property = $filter->property(); |
282
|
|
|
if (is_string($property) && $model->hasProperty($property)) { |
283
|
|
|
$property = $model->property($property); |
284
|
|
|
|
285
|
|
|
if ($property->l10n()) { |
286
|
|
|
$filter->setProperty($property->l10nIdent()); |
287
|
|
|
} |
288
|
|
|
|
289
|
|
|
if ($property->multiple()) { |
290
|
|
|
$filter->setOperator('FIND_IN_SET'); |
291
|
|
|
} |
292
|
|
|
} |
293
|
|
|
} |
294
|
|
|
|
295
|
|
|
if ($filter instanceof FilterCollectionInterface) { |
296
|
|
|
$filter->traverseFilters(function (FilterInterface $expr) { |
|
|
|
|
297
|
|
|
$this->parseFilterWithModel($expr); |
298
|
|
|
}); |
299
|
|
|
} |
300
|
|
|
} |
301
|
|
|
|
302
|
|
|
return $filter; |
303
|
|
|
} |
304
|
|
|
|
305
|
|
|
/** |
306
|
|
|
* Create a new query filter expression. |
307
|
|
|
* |
308
|
|
|
* @see FilterCollectionTrait::createFilter() |
309
|
|
|
* @param array $data Optional expression data. |
310
|
|
|
* @return FilterInterface A new filter expression object. |
311
|
|
|
*/ |
312
|
|
|
protected function createFilter(array $data = null) |
313
|
|
|
{ |
314
|
|
|
$filter = new Filter(); |
315
|
|
|
if ($data !== null) { |
316
|
|
|
$filter->setData($data); |
317
|
|
|
} |
318
|
|
|
return $filter; |
319
|
|
|
} |
320
|
|
|
|
321
|
|
|
/** |
322
|
|
|
* Append a query order on the source. |
323
|
|
|
* |
324
|
|
|
* @deprecated 0.3 To be replaced with OrderCollectionTrait::addOrder() |
325
|
|
|
* |
326
|
|
|
* @uses self::parseOrderWithModel() |
327
|
|
|
* @uses OrderCollectionTrait::processOrder() |
328
|
|
|
* @param mixed $param The property to sort by, |
329
|
|
|
* a {@see OrderInterface} object, |
330
|
|
|
* or a order array structure. |
331
|
|
|
* @param string $mode Optional sorting mode. |
332
|
|
|
* Defaults to ascending if a property is provided. |
333
|
|
|
* @param array $options Optional extra settings to apply on the order. |
334
|
|
|
* @throws InvalidArgumentException If the $param argument is invalid. |
335
|
|
|
* @return self |
336
|
|
|
*/ |
337
|
|
View Code Duplication |
public function addOrder($param, $mode = 'asc', array $options = null) |
|
|
|
|
338
|
|
|
{ |
339
|
|
|
if (is_string($param) && $mode !== null) { |
340
|
|
|
$expr = $this->createOrder(); |
341
|
|
|
$expr->setProperty($param); |
342
|
|
|
$expr->setMode($mode); |
343
|
|
|
} else { |
344
|
|
|
$expr = $param; |
345
|
|
|
} |
346
|
|
|
|
347
|
|
|
$expr = $this->processOrder($expr); |
348
|
|
|
|
349
|
|
|
/** @deprecated 0.3 */ |
350
|
|
|
if (is_array($param) && isset($param['options'])) { |
351
|
|
|
$expr->setData($param['options']); |
|
|
|
|
352
|
|
|
} |
353
|
|
|
|
354
|
|
|
if (is_array($options)) { |
355
|
|
|
$expr->setData($options); |
356
|
|
|
} |
357
|
|
|
|
358
|
|
|
$this->orders[] = $this->parseOrderWithModel($expr); |
359
|
|
|
return $this; |
360
|
|
|
} |
361
|
|
|
|
362
|
|
|
/** |
363
|
|
|
* Process a query order with the current model. |
364
|
|
|
* |
365
|
|
|
* @param OrderInterface $order The expression object. |
366
|
|
|
* @return OrderInterface The parsed expression object. |
367
|
|
|
*/ |
368
|
|
|
protected function parseOrderWithModel(OrderInterface $order) |
369
|
|
|
{ |
370
|
|
|
if ($this->hasModel()) { |
371
|
|
|
if ($order->hasProperty()) { |
372
|
|
|
$model = $this->model(); |
373
|
|
|
$property = $order->property(); |
374
|
|
|
if (is_string($property) && $model->hasProperty($property)) { |
375
|
|
|
$property = $model->property($property); |
376
|
|
|
|
377
|
|
|
if ($property->l10n()) { |
378
|
|
|
$order->setProperty($property->l10nIdent()); |
379
|
|
|
} |
380
|
|
|
} |
381
|
|
|
} |
382
|
|
|
|
383
|
|
|
if ($order instanceof OrderCollectionInterface) { |
384
|
|
|
$order->traverseOrders(function (OrderInterface $expr) { |
|
|
|
|
385
|
|
|
$this->parseOrderWithModel($expr); |
386
|
|
|
}); |
387
|
|
|
} |
388
|
|
|
} |
389
|
|
|
|
390
|
|
|
return $order; |
391
|
|
|
} |
392
|
|
|
|
393
|
|
|
/** |
394
|
|
|
* Create a new query order expression. |
395
|
|
|
* |
396
|
|
|
* @param array $data Optional expression data. |
397
|
|
|
* @return OrderInterface |
398
|
|
|
*/ |
399
|
|
|
protected function createOrder(array $data = null) |
400
|
|
|
{ |
401
|
|
|
$order = new Order(); |
402
|
|
|
if ($data !== null) { |
403
|
|
|
$order->setData($data); |
404
|
|
|
} |
405
|
|
|
return $order; |
406
|
|
|
} |
407
|
|
|
|
408
|
|
|
/** |
409
|
|
|
* Set query pagination. |
410
|
|
|
* |
411
|
|
|
* @param mixed $param The pagination object or array. |
412
|
|
|
* @param integer|null $limit The number of results to fetch if $param is a page number. |
413
|
|
|
* @throws InvalidArgumentException If the $param argument is invalid. |
414
|
|
|
* @return self |
415
|
|
|
*/ |
416
|
|
|
public function setPagination($param, $limit = null) |
417
|
|
|
{ |
418
|
|
|
if ($param instanceof PaginationInterface) { |
419
|
|
|
$pager = $param; |
420
|
|
|
} elseif (is_numeric($param)) { |
421
|
|
|
$pager = $this->createPagination(); |
422
|
|
|
$pager->setPage($param); |
423
|
|
|
$pager->setNumPerPage($limit); |
424
|
|
|
} elseif (is_array($param)) { |
425
|
|
|
$pager = $this->createPagination(); |
426
|
|
|
$pager->setData($param); |
427
|
|
|
} else { |
428
|
|
|
throw new InvalidArgumentException( |
429
|
|
|
'Can not set pagination, invalid argument.' |
430
|
|
|
); |
431
|
|
|
} |
432
|
|
|
|
433
|
|
|
$this->pagination = $pager; |
434
|
|
|
|
435
|
|
|
return $this; |
436
|
|
|
} |
437
|
|
|
|
438
|
|
|
/** |
439
|
|
|
* Determine if the source has defined a query pagination. |
440
|
|
|
* |
441
|
|
|
* @return boolean |
442
|
|
|
*/ |
443
|
|
|
public function hasPagination() |
444
|
|
|
{ |
445
|
|
|
return ($this->pagination !== null); |
446
|
|
|
} |
447
|
|
|
|
448
|
|
|
/** |
449
|
|
|
* Get query pagination. |
450
|
|
|
* |
451
|
|
|
* If the pagination wasn't previously define, a new Pagination object will be created. |
452
|
|
|
* |
453
|
|
|
* @return PaginationInterface |
454
|
|
|
*/ |
455
|
|
|
public function pagination() |
456
|
|
|
{ |
457
|
|
|
if ($this->pagination === null) { |
458
|
|
|
$this->pagination = $this->createPagination(); |
459
|
|
|
} |
460
|
|
|
|
461
|
|
|
return $this->pagination; |
462
|
|
|
} |
463
|
|
|
|
464
|
|
|
/** |
465
|
|
|
* Create a new pagination clause. |
466
|
|
|
* |
467
|
|
|
* @param array $data Optional clause data. |
468
|
|
|
* @return PaginationInterface |
469
|
|
|
*/ |
470
|
|
|
protected function createPagination(array $data = null) |
471
|
|
|
{ |
472
|
|
|
$pagination = new Pagination(); |
473
|
|
|
if ($data !== null) { |
474
|
|
|
$pagination->setData($data); |
475
|
|
|
} |
476
|
|
|
return $pagination; |
477
|
|
|
} |
478
|
|
|
|
479
|
|
|
/** |
480
|
|
|
* Alias for {@see Pagination::setPage()}. |
481
|
|
|
* |
482
|
|
|
* @param integer $page The current page. |
483
|
|
|
* Pages should start at 1. |
484
|
|
|
* @return self |
485
|
|
|
*/ |
486
|
|
|
public function setPage($page) |
487
|
|
|
{ |
488
|
|
|
$this->pagination()->setPage($page); |
489
|
|
|
return $this; |
490
|
|
|
} |
491
|
|
|
|
492
|
|
|
/** |
493
|
|
|
* Alias for {@see Pagination::page()}. |
494
|
|
|
* |
495
|
|
|
* @return integer |
496
|
|
|
*/ |
497
|
|
|
public function page() |
498
|
|
|
{ |
499
|
|
|
return $this->pagination()->page(); |
500
|
|
|
} |
501
|
|
|
|
502
|
|
|
/** |
503
|
|
|
* Alias for {@see Pagination::setNumPerPage()}. |
504
|
|
|
* |
505
|
|
|
* @param integer $count The number of results to return, per page. |
506
|
|
|
* Use 0 to request all results. |
507
|
|
|
* @return self |
508
|
|
|
*/ |
509
|
|
|
public function setNumPerPage($count) |
510
|
|
|
{ |
511
|
|
|
$this->pagination()->setNumPerPage($count); |
512
|
|
|
return $this; |
513
|
|
|
} |
514
|
|
|
|
515
|
|
|
/** |
516
|
|
|
* Alias for {@see Pagination::numPerPage()}. |
517
|
|
|
* |
518
|
|
|
* @return integer |
519
|
|
|
*/ |
520
|
|
|
public function numPerPage() |
521
|
|
|
{ |
522
|
|
|
return $this->pagination()->numPerPage(); |
523
|
|
|
} |
524
|
|
|
|
525
|
|
|
/** |
526
|
|
|
* Create a new database source config. |
527
|
|
|
* |
528
|
|
|
* @see \Charcoal\Config\ConfigurableTrait |
529
|
|
|
* @param array $data Optional data. |
530
|
|
|
* @return SourceConfig |
531
|
|
|
*/ |
532
|
|
|
public function createConfig(array $data = null) |
533
|
|
|
{ |
534
|
|
|
$config = new SourceConfig($data); |
535
|
|
|
return $config; |
536
|
|
|
} |
537
|
|
|
|
538
|
|
|
/** |
539
|
|
|
* Load item by the primary key. |
540
|
|
|
* |
541
|
|
|
* @param mixed $ident Ident can be any scalar value. |
542
|
|
|
* @param StorableInterface $item Optional item to load into. |
543
|
|
|
* @return StorableInterface |
544
|
|
|
*/ |
545
|
|
|
abstract public function loadItem($ident, StorableInterface $item = null); |
546
|
|
|
|
547
|
|
|
/** |
548
|
|
|
* Load items for the given model. |
549
|
|
|
* |
550
|
|
|
* @param StorableInterface|null $item Optional model. |
551
|
|
|
* @return StorableInterface[] |
552
|
|
|
*/ |
553
|
|
|
abstract public function loadItems(StorableInterface $item = null); |
554
|
|
|
|
555
|
|
|
/** |
556
|
|
|
* Save an item (create a new row) in storage. |
557
|
|
|
* |
558
|
|
|
* @param StorableInterface $item The object to save. |
559
|
|
|
* @throws \Exception If a storage error occurs. |
560
|
|
|
* @return mixed The created item ID, otherwise FALSE. |
561
|
|
|
*/ |
562
|
|
|
abstract public function saveItem(StorableInterface $item); |
563
|
|
|
|
564
|
|
|
/** |
565
|
|
|
* Update an item in storage. |
566
|
|
|
* |
567
|
|
|
* @param StorableInterface $item The object to update. |
568
|
|
|
* @param array $properties The list of properties to update, if not all. |
569
|
|
|
* @return boolean TRUE if the item was updated, otherwise FALSE. |
570
|
|
|
*/ |
571
|
|
|
abstract public function updateItem(StorableInterface $item, array $properties = null); |
572
|
|
|
|
573
|
|
|
/** |
574
|
|
|
* Delete an item from storage. |
575
|
|
|
* |
576
|
|
|
* @param StorableInterface $item Optional item to delete. If none, the current model object will be used. |
577
|
|
|
* @throws UnexpectedValueException If the item does not have an ID. |
578
|
|
|
* @return boolean TRUE if the item was deleted, otherwise FALSE. |
579
|
|
|
*/ |
580
|
|
|
abstract public function deleteItem(StorableInterface $item = null); |
581
|
|
|
|
582
|
|
|
/** |
583
|
|
|
* Allow an object to define how the key getter are called. |
584
|
|
|
* |
585
|
|
|
* @param string $key The key to get the getter from. |
586
|
|
|
* @return string The getter method name, for a given key. |
587
|
|
|
*/ |
588
|
|
|
protected function getter($key) |
589
|
|
|
{ |
590
|
|
|
$getter = $key; |
591
|
|
|
return $this->camelize($getter); |
592
|
|
|
} |
593
|
|
|
|
594
|
|
|
/** |
595
|
|
|
* Allow an object to define how the key setter are called. |
596
|
|
|
* |
597
|
|
|
* @param string $key The key to get the setter from. |
598
|
|
|
* @return string The setter method name, for a given key. |
599
|
|
|
*/ |
600
|
|
|
protected function setter($key) |
601
|
|
|
{ |
602
|
|
|
$setter = 'set_'.$key; |
603
|
|
|
return $this->camelize($setter); |
604
|
|
|
} |
605
|
|
|
|
606
|
|
|
/** |
607
|
|
|
* Transform a snake_case string to camelCase. |
608
|
|
|
* |
609
|
|
|
* @param string $str The snake_case string to camelize. |
610
|
|
|
* @return string The camelcase'd string. |
611
|
|
|
*/ |
612
|
|
|
protected function camelize($str) |
613
|
|
|
{ |
614
|
|
|
return lcfirst(implode('', array_map('ucfirst', explode('_', $str)))); |
615
|
|
|
} |
616
|
|
|
} |
617
|
|
|
|
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.