Metable   F
last analyzed

Complexity

Total Complexity 63

Size/Duplication

Total Lines 501
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Importance

Changes 0
Metric Value
wmc 63
lcom 1
cbo 7
dl 0
loc 501
rs 3.36
c 0
b 0
f 0

30 Methods

Rating   Name   Duplication   Size   Complexity  
A bootMetable() 0 17 2
A isMetaQueryable() 0 4 1
A metaQuery() 0 8 2
B metaSelect() 0 24 7
A metaJoinQuery() 0 12 3
A orderByMeta() 0 6 1
A pluckMeta() 0 12 2
A metaSelectListsKey() 0 12 3
A metaSingleResult() 0 4 1
A joinMeta() 0 16 1
A generateMetaAlias() 0 4 1
A metaHasQuery() 0 14 2
A getMetaBoolean() 0 8 1
A getMetaOperator() 0 8 3
B unbindNumerics() 0 14 8
A getMetaWhereConstraint() 0 18 4
A getMetaBetweenConstraint() 0 11 1
A saveMeta() 0 10 3
A allowsMeta() 0 6 2
A hasMeta() 0 4 1
A getMeta() 0 4 1
A getMetaByGroup() 0 4 1
A setMeta() 0 4 1
A metaAttributes() 0 4 1
A getMetaAttributes() 0 6 1
A getMetaAttributesAttribute() 0 4 1
A getMetaAttributesArray() 0 4 1
A loadMetaAttributes() 0 12 3
A reloadMetaAttributes() 0 6 2
A getAllowedMeta() 0 4 2

How to fix   Complexity   

Complex Class

Complex classes like Metable often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Metable, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Sofa\Eloquence;
4
5
use Sofa\Eloquence\Metable\Hooks;
6
use Sofa\Eloquence\Metable\Attribute;
7
use Sofa\Eloquence\Metable\AttributeBag;
8
use Sofa\Hookable\Contracts\ArgumentBag;
9
10
/**
11
 * @property array $allowedMeta
12
 */
13
trait Metable
14
{
15
    /**
16
     * Query methods customizable by this trait.
17
     *
18
     * @var array
19
     */
20
    protected $metaQueryable = [
21
        'where', 'whereBetween', 'whereIn', 'whereNull',
22
        'whereDate', 'whereYear', 'whereMonth', 'whereDay',
23
        'orderBy', 'pluck', 'value', 'aggregate',
24
    ];
25
26
    /**
27
     * Register hooks for the trait.
28
     *
29
     * @codeCoverageIgnore
30
     *
31
     * @return void
32
     */
33
    public static function bootMetable()
34
    {
35
        $hooks = new Hooks;
36
37
        foreach ([
38
                'setAttribute',
39
                'getAttribute',
40
                'toArray',
41
                'replicate',
42
                'save',
43
                '__isset',
44
                '__unset',
45
                'queryHook',
46
            ] as $method) {
47
            static::hook($method, $hooks->{$method}());
48
        }
49
    }
50
51
    /**
52
     * Determine wheter method called on the query is customizable by this trait.
53
     *
54
     * @param  string  $method
55
     * @return bool
56
     */
57
    protected function isMetaQueryable($method)
58
    {
59
        return in_array($method, $this->metaQueryable);
60
    }
61
62
    /**
63
     * Custom query handler for querying meta attributes.
64
     *
65
     * @param  \Sofa\Eloquence\Builder $query
66
     * @param  string $method
67
     * @param  \Sofa\Hookable\Contracts\ArgumentBag $args
68
     * @return mixed
69
     */
70
    protected function metaQuery(Builder $query, $method, ArgumentBag $args)
71
    {
72
        if (in_array($method, ['pluck', 'value', 'aggregate', 'orderBy', 'lists'])) {
73
            return $this->metaJoinQuery($query, $method, $args);
74
        }
75
76
        return $this->metaHasQuery($query, $method, $args);
77
    }
78
79
    /**
80
     * Adjust meta columns for select statement.
81
     *
82
     * @param  \Sofa\Eloquence\Builder $query
83
     * @param  \Sofa\Hookable\Contracts\ArgumentBag $args
84
     * @return void
85
     */
86
    protected function metaSelect(Builder $query, ArgumentBag $args)
87
    {
88
        $columns = $args->get('columns');
89
90
        foreach ($columns as $key => $column) {
91
            list($column, $alias) = $this->extractColumnAlias($column);
0 ignored issues
show
Bug introduced by
It seems like extractColumnAlias() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
92
93
            if ($this->hasColumn($column)) {
0 ignored issues
show
Bug introduced by
It seems like hasColumn() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
94
                $select = "{$this->getTable()}.{$column}";
0 ignored issues
show
Bug introduced by
It seems like getTable() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
95
96
                if ($column !== $alias) {
97
                    $select .= " as {$alias}";
98
                }
99
100
                $columns[$key] = $select;
101
            } elseif (is_string($column) && $column != '*' && strpos($column, '.') === false) {
102
                $table = $this->joinMeta($query, $column);
103
104
                $columns[$key] = "{$table}.meta_value as {$alias}";
105
            }
106
        }
107
108
        $args->set('columns', $columns);
109
    }
110
111
    /**
112
     * Join meta attributes table in order to call provided method.
113
     *
114
     * @param  \Sofa\Eloquence\Builder $query
115
     * @param  string $method
116
     * @param  \Sofa\Hookable\Contracts\ArgumentBag $args
117
     * @return mixed
118
     */
119
    protected function metaJoinQuery(Builder $query, $method, ArgumentBag $args)
120
    {
121
        $alias = $this->joinMeta($query, $args->get('column'));
122
123
        // For aggregates we need the actual function name
124
        // so it can be called directly on the builder.
125
        $method = $args->get('function') ?: $method;
126
127
        return (in_array($method, ['orderBy', 'lists', 'pluck']))
128
            ? $this->{"{$method}Meta"}($query, $args, $alias)
129
            : $this->metaSingleResult($query, $method, $alias);
130
    }
131
132
    /**
133
     * Order query by meta attribute.
134
     *
135
     * @param  \Sofa\Eloquence\Builder $query
136
     * @param  \Sofa\Hookable\Contracts\ArgumentBag $args
137
     * @param  string $alias
138
     * @return \Sofa\Eloquence\Builder
139
     */
140
    protected function orderByMeta(Builder $query, $args, $alias)
141
    {
142
        $query->with('metaAttributes')->getQuery()->orderBy("{$alias}.meta_value", $args->get('direction'));
143
144
        return $query;
145
    }
146
147
    /**
148
     * Get an array with the values of given meta attribute.
149
     *
150
     * @param  \Sofa\Eloquence\Builder $query
151
     * @param  \Sofa\Hookable\Contracts\ArgumentBag $args
152
     * @param  string $alias
153
     * @return array
154
     */
155
    protected function pluckMeta(Builder $query, ArgumentBag $args, $alias)
156
    {
157
        list($column, $key) = [$args->get('column'), $args->get('key')];
158
159
        $query->select("{$alias}.meta_value as {$column}");
160
161
        if (!is_null($key)) {
162
            $this->metaSelectListsKey($query, $key);
163
        }
164
165
        return $query->callParent('pluck', $args->all());
166
    }
167
168
    /**
169
     * Add select clause for key of the list array.
170
     *
171
     * @param  \Sofa\Eloquence\Builder $query
172
     * @param  string $key
173
     * @return \Sofa\Eloquence\Builder
174
     */
175
    protected function metaSelectListsKey(Builder $query, $key)
176
    {
177
        if (strpos($key, '.') !== false) {
178
            return $query->addSelect($key);
0 ignored issues
show
Bug introduced by
The method addSelect() does not exist on Sofa\Eloquence\Builder. Did you maybe mean select()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
179
        } elseif ($this->hasColumn($key)) {
0 ignored issues
show
Bug introduced by
It seems like hasColumn() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
180
            return $query->addSelect($this->getTable() . '.' . $key);
0 ignored issues
show
Bug introduced by
It seems like getTable() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
Bug introduced by
The method addSelect() does not exist on Sofa\Eloquence\Builder. Did you maybe mean select()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
181
        }
182
183
        $alias = $this->joinMeta($query, $key);
184
185
        return $query->addSelect("{$alias}.meta_value as {$key}");
0 ignored issues
show
Bug introduced by
The method addSelect() does not exist on Sofa\Eloquence\Builder. Did you maybe mean select()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
186
    }
187
188
    /**
189
     * Get single value result from the meta attribute.
190
     *
191
     * @param  \Sofa\Eloquence\Builder $query
192
     * @param  string $method
193
     * @param  string $alias
194
     * @return mixed
195
     */
196
    protected function metaSingleResult(Builder $query, $method, $alias)
197
    {
198
        return $query->getQuery()->select("{$alias}.meta_value")->{$method}("{$alias}.meta_value");
199
    }
200
201
    /**
202
     * Join meta attributes table.
203
     *
204
     * @param  \Sofa\Eloquence\Builder $query
205
     * @param  string $column
206
     * @return string
207
     */
208
    protected function joinMeta(Builder $query, $column)
209
    {
210
        $query->prefixColumnsForJoin();
211
212
        $alias = $this->generateMetaAlias();
213
214
        $table = (new Attribute)->getTable();
215
216
        $query->leftJoin("{$table} as {$alias}", function ($join) use ($alias, $column) {
0 ignored issues
show
Bug introduced by
The call to leftJoin() misses some required arguments starting with $operator.
Loading history...
217
            $join->on("{$alias}.metable_id", '=', $this->getQualifiedKeyName())
0 ignored issues
show
Bug introduced by
It seems like getQualifiedKeyName() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
218
                ->where("{$alias}.metable_type", '=', $this->getMorphClass())
0 ignored issues
show
Bug introduced by
It seems like getMorphClass() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
219
                ->where("{$alias}.meta_key", '=', $column);
220
        });
221
222
        return $alias;
223
    }
224
225
    /**
226
     * Generate unique alias for meta attributes table.
227
     *
228
     * @return string
229
     */
230
    protected function generateMetaAlias()
231
    {
232
        return md5(microtime(true)) . '_meta_alias';
233
    }
234
235
    /**
236
     * Add whereHas subquery on the meta attributes relation.
237
     *
238
     * @param  \Sofa\Eloquence\Builder $query
239
     * @param  string $method
240
     * @param  \Sofa\Hookable\Contracts\ArgumentBag $args
241
     * @return \Sofa\Eloquence\Builder
242
     */
243
    protected function metaHasQuery(Builder $query, $method, ArgumentBag $args)
244
    {
245
        $boolean = $this->getMetaBoolean($args);
246
247
        $operator = $this->getMetaOperator($method, $args);
248
249
        if (in_array($method, ['whereBetween', 'where'])) {
250
            $this->unbindNumerics($args);
251
        }
252
253
        return $query
0 ignored issues
show
Bug introduced by
The method with does only exist in Illuminate\Database\Eloquent\Builder, but not in Illuminate\Database\Eloq...ns\QueriesRelationships.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
254
            ->has('metaAttributes', $operator, 1, $boolean, $this->getMetaWhereConstraint($method, $args))
255
            ->with('metaAttributes');
256
    }
257
258
    /**
259
     * Get boolean called on the original method and set it to default.
260
     *
261
     * @param  \Sofa\EloquenceArgumentBag $args
262
     * @return string
263
     */
264
    protected function getMetaBoolean(ArgumentBag $args)
265
    {
266
        $boolean = $args->get('boolean');
267
268
        $args->set('boolean', 'and');
269
270
        return $boolean;
271
    }
272
273
    /**
274
     * Determine the operator for count relation query.
275
     *
276
     * @param  string $method
277
     * @param  \Sofa\Hookable\Contracts\ArgumentBag $args
278
     * @return string
279
     */
280
    protected function getMetaOperator($method, ArgumentBag $args)
281
    {
282
        if ($not = $args->get('not')) {
283
            $args->set('not', false);
284
        }
285
286
        return ($not ^ $this->isWhereNull($method, $args)) ? '<' : '>=';
0 ignored issues
show
Bug introduced by
It seems like isWhereNull() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
287
    }
288
289
    /**
290
     * Integers and floats must be passed in raw form in order to avoid string
291
     * comparison, due to the fact that all meta values are stored as strings.
292
     *
293
     * @param  \Sofa\Hookable\Contracts\ArgumentBag $args
294
     * @return void
295
     */
296
    protected function unbindNumerics(ArgumentBag $args)
297
    {
298
        if (($value = $args->get('value')) && (is_int($value) || is_float($value))) {
299
            $args->set('value', $this->raw($value));
0 ignored issues
show
Bug introduced by
It seems like raw() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
300
        } elseif ($values = $args->get('values')) {
301
            foreach ($values as $key => $value) {
302
                if (is_int($value) || is_float($value)) {
303
                    $values[$key] = $this->raw($value);
0 ignored issues
show
Bug introduced by
It seems like raw() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
304
                }
305
            }
306
307
            $args->set('values', $values);
308
        }
309
    }
310
311
    /**
312
     * Get the relation constraint closure.
313
     *
314
     * @param  string $method
315
     * @param  \Sofa\Hookable\Contracts\ArgumentBag $args
316
     * @return \Closure
317
     */
318
    protected function getMetaWhereConstraint($method, ArgumentBag $args)
319
    {
320
        $column = $args->get('column');
321
322
        $args->set('column', 'meta_value');
323
324
        if ($method === 'whereBetween') {
325
            return $this->getMetaBetweenConstraint($column, $args->get('values'));
326
        }
327
328
        return function ($query) use ($column, $method, $args) {
329
            $query->where('meta_key', $column);
330
331
            if ($args->get('value') || $args->get('values')) {
332
                call_user_func_array([$query, $method], $args->all());
333
            }
334
        };
335
    }
336
337
    /**
338
     * Query Builder whereBetween override required to pass raw numeric values.
339
     *
340
     * @param  string $column
341
     * @param  array  $values
342
     * @return \Closure
343
     */
344
    protected function getMetaBetweenConstraint($column, array $values)
345
    {
346
        $min = $values[0];
347
        $max = $values[1];
348
349
        return function ($query) use ($column, $min, $max) {
350
            $query->where('meta_key', $column)
351
                ->where('meta_value', '>=', $min)
352
                ->where('meta_value', '<=', $max);
353
        };
354
    }
355
356
    /**
357
     * Save new or updated meta attributes and delete the ones that were unset.
358
     *
359
     * @return void
360
     */
361
    protected function saveMeta()
362
    {
363
        foreach ($this->getMetaAttributes() as $attribute) {
364
            if (is_null($attribute->getValue())) {
365
                $attribute->delete();
366
            } else {
367
                $this->metaAttributes()->save($attribute);
368
            }
369
        }
370
    }
371
372
    /**
373
     * Determine whether meta attribute is allowed for the model.
374
     *
375
     * @param  string $key
376
     * @return bool
377
     */
378
    public function allowsMeta($key)
379
    {
380
        $allowed = $this->getAllowedMeta();
381
382
        return empty($allowed) || in_array($key, $allowed);
383
    }
384
385
    /**
386
     * Determine whether meta attribute exists on the model.
387
     *
388
     * @param  string $key
389
     * @return bool
390
     */
391
    public function hasMeta($key)
392
    {
393
        return array_key_exists($key, $this->getMetaAttributesArray());
394
    }
395
396
    /**
397
     * Get meta attribute value.
398
     *
399
     * @param  string $key
400
     * @return mixed
401
     */
402
    public function getMeta($key)
403
    {
404
        return $this->getMetaAttributes()->getValue($key);
405
    }
406
407
    /**
408
     * Get meta attribute values by group.
409
     *
410
     * @param  string $key
0 ignored issues
show
Bug introduced by
There is no parameter named $key. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
411
     * @return mixed
412
     */
413
    public function getMetaByGroup($group)
414
    {
415
        return $this->getMetaAttributes()->getMetaByGroup($group);
416
    }
417
418
    /**
419
     * Set meta attribute.
420
     *
421
     * @param  string $key
422
     * @param  mixed  $value
423
     * @return void
424
     */
425
    public function setMeta($key, $value, $group = null)
426
    {
427
        $this->getMetaAttributes()->set($key, $value, $group);
428
    }
429
430
    /**
431
     * Meta attributes relation.
432
     *
433
     * @codeCoverageIgnore
434
     *
435
     * @return \Illuminate\Database\Eloquent\Relations\MorphMany
436
     */
437
    public function metaAttributes()
438
    {
439
        return $this->morphMany('Sofa\Eloquence\Metable\Attribute', 'metable');
0 ignored issues
show
Bug introduced by
It seems like morphMany() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
440
    }
441
442
    /**
443
     * Get meta attributes as collection.
444
     *
445
     * @return \Sofa\Eloquence\Metable\AttributeBag
446
     */
447
    public function getMetaAttributes()
448
    {
449
        $this->loadMetaAttributes();
450
451
        return $this->getRelation('metaAttributes');
0 ignored issues
show
Bug introduced by
It seems like getRelation() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
452
    }
453
454
    /**
455
     * Accessor for metaAttributes property
456
     *
457
     * @return \Sofa\Eloquence\Metable\AttributeBag
458
     */
459
    public function getMetaAttributesAttribute()
460
    {
461
        return $this->getMetaAttributes();
462
    }
463
464
    /**
465
     * Get meta attributes as associative array.
466
     *
467
     * @return array
468
     */
469
    public function getMetaAttributesArray()
470
    {
471
        return $this->getMetaAttributes()->toArray();
472
    }
473
474
    /**
475
     * Load meta attributes relation.
476
     *
477
     * @return void
478
     */
479
    protected function loadMetaAttributes()
480
    {
481
        if (!array_key_exists('metaAttributes', $this->relations)) {
0 ignored issues
show
Bug introduced by
The property relations does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
482
            $this->reloadMetaAttributes();
483
        }
484
485
        $attributes = $this->getRelation('metaAttributes');
0 ignored issues
show
Bug introduced by
It seems like getRelation() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
486
487
        if (!$attributes instanceof AttributeBag) {
488
            $this->setRelation('metaAttributes', (new Attribute)->newBag($attributes->all()));
0 ignored issues
show
Bug introduced by
It seems like setRelation() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
489
        }
490
    }
491
492
    /**
493
     * Reload meta attributes from db or set empty bag for newly created model.
494
     *
495
     * @return $this
496
     */
497
    protected function reloadMetaAttributes()
498
    {
499
        return ($this->exists)
0 ignored issues
show
Bug introduced by
The property exists does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
500
            ? $this->load('metaAttributes')
0 ignored issues
show
Bug introduced by
It seems like load() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
501
            : $this->setRelation('metaAttributes', (new Attribute)->newBag());
0 ignored issues
show
Bug introduced by
It seems like setRelation() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
502
    }
503
504
    /**
505
     * Get allowed meta attributes array.
506
     *
507
     * @return array
508
     */
509
    public function getAllowedMeta()
510
    {
511
        return (property_exists($this, 'allowedMeta')) ? $this->allowedMeta : [];
512
    }
513
}
514