Test Setup Failed
Push — master ( 000e9e...f38e71 )
by
unknown
09:27
created

AbstractSource::addOrders()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 1
1
<?php
2
3
namespace Charcoal\Source;
4
5
use Exception;
6
use InvalidArgumentException;
7
8
// From PSR-3
9
use Psr\Log\LoggerAwareInterface;
10
use Psr\Log\LoggerAwareTrait;
11
12
// From 'charcoal-config'
13
use Charcoal\Config\ConfigurableInterface;
14
use Charcoal\Config\ConfigurableTrait;
15
16
// From 'charcoal-core'
17
use Charcoal\Model\ModelInterface;
18
19
use Charcoal\Source\SourceConfig;
20
use Charcoal\Source\SourceInterface;
21
use Charcoal\Source\Filter;
22
use Charcoal\Source\FilterInterface;
23
use Charcoal\Source\Order;
24
use Charcoal\Source\OrderInterface;
25
use Charcoal\Source\Pagination;
26
use Charcoal\Source\PaginationInterface;
27
28
/**
29
 * Full implementation, as abstract class, of the SourceInterface.
30
 */
31
abstract class AbstractSource implements
32
    SourceInterface,
33
    ConfigurableInterface,
34
    LoggerAwareInterface
35
{
36
    use ConfigurableTrait;
37
    use LoggerAwareTrait;
38
39
    /**
40
     * @var ModelInterface $model
41
     */
42
    private $model = null;
43
44
    /**
45
     * @var array $properties
46
     */
47
    private $properties = [];
48
49
    /**
50
     * Array of `Filter` objects
51
     * @var array $filters
52
     */
53
    protected $filters = [];
54
55
    /**
56
     * Array of `Order` object
57
     * @var array $orders
58
     */
59
    protected $orders = [];
60
61
    /**
62
     * The `Pagination` object
63
     * @var Pagination|null $pagination
64
     */
65
    protected $pagination = null;
66
67
    /**
68
     * @param array|\ArrayAccess $dependencies The class dependencies.
69
     * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
70
     */
71
    public function __construct($dependencies)
72
    {
73
        $this->setLogger($dependencies['logger']);
74
    }
75
76
    /**
77
     * Reset everything but the model.
78
     *
79
     * @return AbstractSource Chainable
80
     */
81
    public function reset()
82
    {
83
        $this->properties = [];
84
        $this->filters = [];
85
        $this->orders = [];
86
        $this->pagination = null;
87
        return $this;
88
    }
89
90
    /**
91
     * Initialize the source's properties with an array of data.
92
     *
93
     * @param array $data The source data.
94
     * @return AbstractSource Chainable
95
     */
96
    public function setData(array $data)
97
    {
98
        foreach ($data as $prop => $val) {
99
            $func = [$this, $this->setter($prop)];
100
            if (is_callable($func)) {
101
                call_user_func($func, $val);
102
                unset($data[$prop]);
103
            } else {
104
                $this->{$prop} = $val;
105
            }
106
        }
107
        return $this;
108
    }
109
110
    /**
111
     * Set the source's Model.
112
     *
113
     * @param ModelInterface $model The source's model.
114
     * @return AbstractSource Chainable
115
     */
116
    public function setModel(ModelInterface $model)
117
    {
118
        $this->model = $model;
119
        return $this;
120
    }
121
122
    /**
123
     * Return the source's Model.
124
     *
125
     * @throws Exception If not model was previously set.
126
     * @return ModelInterface
127
     */
128
    public function model()
129
    {
130
        if ($this->model === null) {
131
            throw new Exception(
132
                'No model set.'
133
            );
134
        }
135
        return $this->model;
136
    }
137
138
    /**
139
     * @return boolean
140
     */
141
    public function hasModel()
142
    {
143
        return ($this->model !== null);
144
    }
145
146
    /**
147
     * Set the properties of the source to fetch.
148
     *
149
     * This method accepts an array of property identifiers (property ident, as string)
150
     * that will, if supported, be fetched from the source.
151
     *
152
     * If no properties are set, it is assumed that all the Model's properties are to be fetched.
153
     *
154
     * @param array $properties The properties.
155
     * @return ColelectionLoader Chainable
156
     */
157
    public function setProperties(array $properties)
158
    {
159
        $this->properties = [];
160
        foreach ($properties as $p) {
161
            $this->addProperty($p);
162
        }
163
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this; (Charcoal\Source\AbstractSource) is incompatible with the return type declared by the interface Charcoal\Source\SourceInterface::setProperties of type Charcoal\Source\ColelectionLoader.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
164
    }
165
166
    /**
167
     * @return array
168
     */
169
    public function properties()
170
    {
171
        return $this->properties;
172
    }
173
174
    /**
175
     * @param string $property Property ident.
176
     * @throws InvalidArgumentException If property is not a string or empty.
177
     * @return SourceInterface Chainable
178
     */
179 View Code Duplication
    public function addProperty($property)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
180
    {
181
        if (!is_string($property)) {
182
            throw new InvalidArgumentException(
183
                'Property must be a string.'
184
            );
185
        }
186
        if ($property=='') {
187
            throw new InvalidArgumentException(
188
                'Property can not be empty.'
189
            );
190
        }
191
        $this->properties[] = $property;
192
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this; (Charcoal\Source\AbstractSource) is incompatible with the return type declared by the interface Charcoal\Source\SourceInterface::addProperty of type Charcoal\Source\CollectionLoader.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
193
    }
194
195
    /**
196
     * @param array $filters The filters to set.
197
     * @return SourceInterface Chainable
198
     */
199
    public function setFilters(array $filters)
200
    {
201
        $this->filters = [];
202
        foreach ($filters as $f) {
203
            $this->addFilter($f);
204
        }
205
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this; (Charcoal\Source\AbstractSource) is incompatible with the return type declared by the interface Charcoal\Source\SourceInterface::setFilters of type Charcoal\Source\Collection.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
206
    }
207
208
    /**
209
     * @param array $filters The filters to add.
210
     * @return SourceInterface Chainable
211
     */
212
    public function addFilters(array $filters)
213
    {
214
        foreach ($filters as $f) {
215
            $this->addFilter($f);
216
        }
217
        return $this;
218
    }
219
220
    /**
221
     * @return array
222
     */
223
    public function filters()
224
    {
225
        return $this->filters;
226
    }
227
228
    /**
229
     * Add a collection filter to the loader.
230
     *
231
     * There are 3 different ways of adding a filter:
232
     * - as a `Filter` object, in which case it will be added directly.
233
     *   - `addFilter($obj);`
234
     * - as an array of options, which will be used to build the `Filter` object
235
     *   - `addFilter(['property' => 'foo', 'val' => 42, 'operator' => '<=']);`
236
     * - as 3 parameters: `property`, `val` and `options`
237
     *   - `addFilter('foo', 42, ['operator' => '<=']);`
238
     *
239
     * @param string|array|Filter $param   The filter property, or a Filter object / array.
240
     * @param mixed               $val     Optional: Only used if the first argument is a string.
241
     * @param array               $options Optional: Only used if the first argument is a string.
242
     * @throws InvalidArgumentException If property is not a string or empty.
243
     * @return SourceInterface (Chainable)
244
     */
245
    public function addFilter($param, $val = null, array $options = null)
246
    {
247
        if ($param instanceof FilterInterface) {
248
            $filter = $param;
249
        } elseif (is_array($param)) {
250
            $filter = $this->createFilter();
251
            $filter->setData($param);
252
        } elseif (is_string($param) && $val !== null) {
253
            $filter = $this->createFilter();
254
            $filter->setProperty($param);
255
            $filter->setVal($val);
256
            if (is_array($options)) {
257
                $filter->setData($options);
258
            }
259
        } else {
260
            throw new InvalidArgumentException(
261
                'Parameter must be an array or a property ident.'
262
            );
263
        }
264
265
        if ($this->hasModel()) {
266
            $property = $filter->property();
267 View Code Duplication
            if ($property) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
268
                $p = $this->model()->p($property);
269
                if ($p) {
270
                    if ($p->l10n()) {
271
                        $filter->setProperty($p->l10nIdent());
272
                    }
273
274
                    if ($p->multiple()) {
275
                        $filter->setOperator('FIND_IN_SET');
276
                    }
277
                }
278
            }
279
        }
280
281
        $this->filters[] = $filter;
282
283
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this; (Charcoal\Source\AbstractSource) is incompatible with the return type declared by the interface Charcoal\Source\SourceInterface::addFilter of type Charcoal\Source\CollectionLoader.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
284
    }
285
286
    /**
287
     * @return FilterInterface
288
     */
289
    protected function createFilter()
290
    {
291
        $filter = new Filter();
292
        return $filter;
293
    }
294
295
    /**
296
     * @param array $orders The orders to set.
297
     * @return AbstractSource Chainable
298
     */
299
    public function setOrders(array $orders)
300
    {
301
        $this->orders = [];
302
        foreach ($orders as $o) {
303
            $this->addOrder($o);
304
        }
305
        return $this;
306
    }
307
308
    /**
309
     * @param array $orders The orders to add.
310
     * @return AbstractSource Chainable
311
     */
312
    public function addOrders(array $orders)
313
    {
314
        foreach ($orders as $o) {
315
            $this->addOrder($o);
316
        }
317
        return $this;
318
    }
319
320
    /**
321
     * @return array
322
     */
323
    public function orders()
324
    {
325
        return $this->orders;
326
    }
327
328
    /**
329
     * @param string|array|Order $param        The order property, or an Order object / array.
330
     * @param string             $mode         Optional.
331
     * @param array              $orderOptions Optional.
332
     * @throws InvalidArgumentException If the param argument is invalid.
333
     * @return SourceInterface Chainable
334
     */
335
    public function addOrder($param, $mode = 'asc', array $orderOptions = null)
336
    {
337
        if ($param instanceof OrderInterface) {
338
            $order = $param;
339
        } elseif (is_array($param)) {
340
            $order = $this->createOrder();
341
            $order->setData($param);
342
        } elseif (is_string($param)) {
343
            $order = $this->createOrder();
344
            $order->setProperty($param);
345
            $order->setMode($mode);
346
            if (isset($orderOptions['values'])) {
347
                $order->setValues($orderOptions['values']);
348
            }
349
        } else {
350
            throw new InvalidArgumentException(
351
                'Parameter must be an OrderInterface object or a property ident.'
352
            );
353
        }
354
355 View Code Duplication
        if ($this->hasModel()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
356
            $property = $order->property();
357
            if ($property) {
358
                $p = $this->model()->p($property);
359
                if ($p) {
360
                    if ($p->l10n()) {
361
                        $order->setProperty($p->l10nIdent());
362
                    }
363
                }
364
            }
365
        }
366
367
        $this->orders[] = $order;
368
369
        return $this;
370
    }
371
372
    /**
373
     * @return OrderInterface
374
     */
375
    protected function createOrder()
376
    {
377
        $order = new Order();
378
        return $order;
379
    }
380
381
    /**
382
     * @param mixed $param The pagination object or array.
383
     * @throws InvalidArgumentException If the argument is not an object or array.
384
     * @return SourceInterface Chainable
385
     */
386
    public function setPagination($param)
387
    {
388
        if ($param instanceof PaginationInterface) {
389
            $this->pagination = $param;
0 ignored issues
show
Documentation Bug introduced by
It seems like $param of type object<Charcoal\Source\PaginationInterface> is incompatible with the declared type object<Charcoal\Source\Pagination>|null of property $pagination.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
390
        } elseif (is_array($param)) {
391
            $pagination = $this->createPagination();
392
            $pagination->setData($param);
393
            $this->pagination = $pagination;
0 ignored issues
show
Documentation Bug introduced by
It seems like $pagination of type object<Charcoal\Source\PaginationInterface> is incompatible with the declared type object<Charcoal\Source\Pagination>|null of property $pagination.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
394
        } else {
395
            throw new InvalidArgumentException(
396
                'Can not set pagination, invalid argument.'
397
            );
398
        }
399
        return $this;
400
    }
401
402
    /**
403
     * Get the pagination object.
404
     *
405
     * If the pagination wasn't set previously, a new (default / blank) Pagination object will be created.
406
     * (Always return a `PaginationInterface` object)
407
     *
408
     * @return PaginationInterface
409
     */
410
    public function pagination()
411
    {
412
        if ($this->pagination === null) {
413
            $this->pagination = $this->createPagination();
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->createPagination() of type object<Charcoal\Source\PaginationInterface> is incompatible with the declared type object<Charcoal\Source\Pagination>|null of property $pagination.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
414
        }
415
        return $this->pagination;
416
    }
417
418
    /**
419
     * @return PaginationInterface
420
     */
421
    protected function createPagination()
422
    {
423
        $pagination = new Pagination();
424
        return $pagination;
425
    }
426
427
    /**
428
     * @param integer $page The page number.
429
     * @throws InvalidArgumentException If the page argument is not numeric.
430
     * @return AbstractSource Chainable
431
     */
432
    public function setPage($page)
433
    {
434
        if (!is_numeric($page)) {
435
            throw new InvalidArgumentException(
436
                'Page must be an integer.'
437
            );
438
        }
439
        $this->pagination()->setPage((int)$page);
440
        return $this;
441
    }
442
443
    /**
444
     * @return integer
445
     */
446
    public function page()
447
    {
448
        return $this->pagination()->page();
449
    }
450
451
    /**
452
     * @param integer $num The number of items to retrieve per page.
453
     * @throws InvalidArgumentException If the num per page argument is not numeric.
454
     * @return AbstractSource Chainable
455
     */
456
    public function setNumPerPage($num)
457
    {
458
        if (!is_numeric($num)) {
459
            throw new InvalidArgumentException(
460
                'Num must be an integer.'
461
            );
462
        }
463
        $this->pagination()->setNumPerPage((int)$num);
464
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this; (Charcoal\Source\AbstractSource) is incompatible with the return type declared by the interface Charcoal\Source\SourceInterface::setNumPerPage of type Charcoal\Source\CollectionLoader.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
465
    }
466
467
    /**
468
     * @return integer
469
     */
470
    public function numPerPage()
471
    {
472
        return $this->pagination()->numPerPage();
473
    }
474
475
    /**
476
     * ConfigurableTrait > createConfig()
477
     *
478
     * @param array $data Optional.
479
     * @return SourceConfig
480
     */
481
    public function createConfig(array $data = null)
482
    {
483
        $config = new SourceConfig();
484
        if (is_array($data)) {
485
            $config->merge($data);
0 ignored issues
show
Unused Code introduced by
The call to the method Charcoal\Source\SourceConfig::merge() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
486
        }
487
        return $config;
488
    }
489
490
    /**
491
     * @param mixed             $ident The ID of the item to load.
492
     * @param StorableInterface $item  Optional item to load into.
493
     * @return StorableInterface
494
     */
495
    abstract public function loadItem($ident, StorableInterface $item = null);
496
497
    /**
498
     * @param StorableInterface|null $item The model to load items from.
499
     * @return array
500
     */
501
    abstract public function loadItems(StorableInterface $item = null);
502
503
    /**
504
     * Save an item (create a new row) in storage.
505
     *
506
     * @param StorableInterface $item The object to save.
507
     * @return mixed The created item ID, or false in case of an error.
508
     */
509
    abstract public function saveItem(StorableInterface $item);
510
511
    /**
512
     * Update an item in storage.
513
     *
514
     * @param StorableInterface $item       The object to update.
515
     * @param array             $properties The list of properties to update, if not all.
516
     * @return boolean Success / Failure
517
     */
518
    abstract public function updateItem(StorableInterface $item, array $properties = null);
519
520
    /**
521
     * Delete an item from storage
522
     *
523
     * @param StorableInterface $item Optional item to delete. If none, the current model object will be used..
524
     * @return boolean Success / Failure
525
     */
526
    abstract public function deleteItem(StorableInterface $item = null);
527
528
    /**
529
     * Allow an object to define how the key getter are called.
530
     *
531
     * @param string $key  The key to get the getter from.
532
     * @param string $case Optional. The type of case to return. camel, pascal or snake.
533
     * @return string The getter method name, for a given key.
534
     */
535 View Code Duplication
    protected function getter($key, $case = 'camel')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
536
    {
537
        $getter = $key;
538
539
        if ($case == 'camel') {
540
            return $this->camelize($getter);
541
        } elseif ($case == 'pascal') {
542
            return $this->pascalize($getter);
543
        } else {
544
            return $getter;
545
        }
546
    }
547
548
    /**
549
     * Allow an object to define how the key setter are called.
550
     *
551
     * @param string $key  The key to get the setter from.
552
     * @param string $case Optional. The type of case to return. camel, pascal or snake.
553
     * @return string The setter method name, for a given key.
554
     */
555 View Code Duplication
    protected function setter($key, $case = 'camel')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
556
    {
557
        $setter = 'set_'.$key;
558
559
        if ($case == 'camel') {
560
            return $this->camelize($setter);
561
        } elseif ($case == 'pascal') {
562
            return $this->pascalize($setter);
563
        } else {
564
            return $setter;
565
        }
566
    }
567
568
    /**
569
     * Transform a snake_case string to camelCase.
570
     *
571
     * @param string $str The snake_case string to camelize.
572
     * @return string The camelCase string.
573
     */
574
    private function camelize($str)
575
    {
576
        return lcfirst($this->pascalize($str));
577
    }
578
579
    /**
580
     * Transform a snake_case string to PamelCase.
581
     *
582
     * @param string $str The snake_case string to pascalize.
583
     * @return string The PamelCase string.
584
     */
585
    private function pascalize($str)
586
    {
587
        return implode('', array_map('ucfirst', explode('_', $str)));
588
    }
589
}
590