Test Failed
Pull Request — master (#10)
by
unknown
08:12
created

SaveAll::getRelationshipLimit()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.7462

Importance

Changes 0
Metric Value
dl 0
loc 11
ccs 3
cts 7
cp 0.4286
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 6
nc 2
nop 1
crap 2.7462
1
<?php
2
3
namespace Sigep\EloquentEnhancements\Traits;
4
5
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
6
use Illuminate\Database\Eloquent\Relations\HasMany;
7
use Illuminate\Database\Eloquent\Relations\MorphMany;
8
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
9
use Illuminate\Database\Eloquent\Relations\BelongsTo;
10
11
trait SaveAll
12
{
13
    /**
14
     * Checks if $options has a callable to do the validation.
15
     * If is provided, call the function and merge erros, if any
16
     * @param array $options
17
     * @param string $path
18
     * @return bool
19
     */
20 1
    private function __handleValidator(array $options, $path)
21
    {
22 1
        $modelName = get_class($this);
23 1
        $validator = null;
24 1
        $response = true;
25
26 1
        if (!empty($options[$modelName]['validator']) && is_callable($options[$modelName]['validator'])) {
27
            $validator = $options[$modelName]['validator'];
28 1
        } elseif (!empty($options['validator']) && is_callable($options['validator'])) {
29
            $validator = $options['validator'];
30
        }
31
32 1
        if ($validator) {
33
            $isValid = call_user_func($validator, $this);
34
            if ($isValid !== true) {
35
                $this->mergeErrors($isValid->toArray(), $path);
36
                $response = false;
37
            }
38
        }
39
40 1
        return $response;
41
    }
42
43
    /**
44
     * Checks if $options has restrictions about what can be filled and
45
     * filters $data
46
     * @param array $options
47
     * @param array $data
48
     */
49 1
    private function __handleFill(array $options, array $data)
50
    {
51 1
        $modelName = get_class($this);
52 1
        if (!empty($options[$modelName]['fillable'])) {
53
            $newData = [];
54
            foreach ($options[$modelName]['fillable'] as $field) {
55
                if (isset($data[$field])) {
56
                    $newData[$field] = $data[$field];
57
                }
58
            }
59
            $data = $newData;
60
        }
61
62 1
        $this->fill($data);
0 ignored issues
show
Bug introduced by
It seems like fill() 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...
63 1
    }
64
65
    /**
66
     * create a new object and calls saveAll() method to save its relationships
67
     *
68
     * @param array $data
69
     * @param string $path used to control where put the error messages
70
     *
71
     * @return boolean
72
     */
73 1
    public function createAll(array $data = [], $options = [], $path = '')
74
    {
75 1
        $this->__handleFill($options, $data);
76 1
        $data = $this->checkBelongsTo($data, $options, $path);
77
78 1
        if ($this->errors()->count()) {
0 ignored issues
show
Bug introduced by
The method errors() does not exist on Sigep\EloquentEnhancements\Traits\SaveAll. Did you maybe mean mergeErrors()?

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...
79
            return false;
80
        }
81
82 1
        if (!$this->__handleValidator($options, $path) || !$this->save()) {
0 ignored issues
show
Bug introduced by
It seems like save() 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...
83
            return false;
84
        }
85
86 1
        $data = $this->fillForeignKeyRecursively($data);
87
88 1
        return $this->saveAll($data, $options, true, $path);
89
    }
90
91
    /**
92
     * Update current record and create/update its related data
93
     * The related data must be array and the key is the name of the relationship
94
     * We support relationships from relationships too.
95
     *
96
     * @param  array $data
97
     * @param  boolean $skipUpdate if true, current model will not be updated
98
     * @return boolean
99
     */
100 1
    public function saveAll(array $data = [], array $options = [], $skipUpdate = false, $path = '')
101
    {
102 1
        $this->__handleFill($options, $data);
103 1
        $data = $this->checkBelongsTo($data, $options, $path); // @is really necessary?
104
105 1
        if ($this->errors()->count()) {
0 ignored issues
show
Bug introduced by
The method errors() does not exist on Sigep\EloquentEnhancements\Traits\SaveAll. Did you maybe mean mergeErrors()?

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...
106
            return false;
107
        }
108
109 1
        if (!$skipUpdate) {
110
            if ($this->__handleValidator($options, $path) === false || $this->save() === false) {
0 ignored issues
show
Bug introduced by
It seems like save() 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...
111
                return false;
112
            }
113
        }
114
115 1
        $relationships = $this->getRelationshipsFromData($data);
116
117
        // save relationships
118 1
        foreach ($relationships as $relationship => $values) {
119 1
            $currentPath = $path ? "{$path}." : '';
120 1
            $currentPath .= $relationship;
121
122
            // check allowed amount of related objects
123
            // @todo this is the best way? maybe this must be on validation rules...?
124 1
            if ($this->checkRelationshipLimit($relationship, $values, $currentPath) === false) {
125
                return false;
126
            }
127
128 1
            if ($this->shouldDetachModels($relationship, $values)) {
129
                $this->$relationship()->withTimestamps()->detach();
130
            }
131
132 1
            if (!$this->addRelated($relationship, $values, $options, $currentPath)) {
133
                return false;
134
            }
135
        }
136
137
        // search for relationships that has limit and no data was send, to apply the minimum validation
138
        if (isset($this->relationshipsLimits)) {
139
            $relationshipsLimits = $this->relationshipsLimits;
0 ignored issues
show
Bug introduced by
The property relationshipsLimits 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...
140
            $checkRelationships = array_diff(array_keys($relationshipsLimits), array_keys($relationships));
141
142
            foreach ($checkRelationships as $checkRelationship) {
143
                $currentPath = $path ? "{$path}." : '';
144
                $currentPath .= $checkRelationship;
145
146
                if (!$this->checkRelationshipLimit($checkRelationship, [], $currentPath)) {
147
                    return false;
148
                }
149
            }
150
        }
151
152
        return true;
153
    }
154
155
    /**
156
     * Put the id of current object as foreign key in all arrays inside $data
157
     * Util when a relationship of a relationship depends of the id from current
158
     * model as foreign key to.
159
     * To avoid problems, data must to have the foreign key with "auto" value.
160
     * Just in case that the records belongs, for any reason, to another object
161
     *
162
     * @param array $data changed data
163
     *
164
     * @return array
165
     */
166 1
    private function fillForeignKeyRecursively(array $data)
167
    {
168 1
        $foreign = $this->getForeignKey();
0 ignored issues
show
Bug introduced by
It seems like getForeignKey() 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...
169
170 1
        foreach ($data as &$piece) {
171 1
            if (is_array($piece)) {
172 1
                $piece = $this->fillForeignKeyRecursively($piece);
173 1
            }
174 1
        }
175
176 1
        if (isset($data[$foreign]) && $data[$foreign] == 'auto' && $this->attributes[$this->primaryKey]) {
177
            $data[$foreign] = $this->attributes[$this->primaryKey];
0 ignored issues
show
Bug introduced by
The property attributes 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...
Bug introduced by
The property primaryKey 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...
178
        }
179
180 1
        return $data;
181
    }
182
183
    /**
184
 * Determines if sync() should be used to create records on belongsToMany relationships
185
 *
186
 * @param string $relationship name of relationship
187
 * @param array $data data to check
188
 *
189
 * @return bool
190
 */
191 1
    private function shouldUseSync($relationship, $data)
192
    {
193 1
        $relationship = $this->$relationship();
194 1
        if ($relationship instanceof BelongsToMany && count($data) === 1) {
195
            // check foreign key
196 1
            $foreignKey = last(explode('.', $relationship->getOtherKey()));
197 1
            if (isset($data[$foreignKey]) && is_array($data[$foreignKey])) {
198
                return true;
199
            }
200 1
        }
201
202 1
        return false;
203
    }
204
205
    /**
206
     * Determines if sync() should be used to create records on belongsToMany relationships
207
     *
208
     * @param string $relationship name of relationship
209
     * @param array $data data to check
210
     *
211
     * @return bool
212
     */
213 1
    private function shouldDetachModels($relationship, $data)
214
    {
215 1
        $relationship = $this->$relationship();
216 1
        if ($relationship instanceof BelongsToMany && count($data) >= 1 && is_array($data)) {
217 1
            foreach ($data as $element) {
218 1
                if (!is_array($element) || empty($element) || empty($element['id'])) {
219 1
                    return false;
220
                }
221
            }
222
            return true;
223
        }
224
225
        return false;
226
    }
227
228
    /**
229
     * This method is specific to create objects that are related with the current model on a
230
     * belongsTo relationship.
231
     * Useful to create a record that belongs to another record that don't exists yet.
232
     * This method will remove from $data data relative to belongsTo elements
233
     *
234
     * @param array $data
235
     * @param string $path
236
     * @return array
237
     */
238 1
    private function checkBelongsTo($data, array $options = [], $path = '') {
239 1
        $relationships = $this->getRelationshipsFromData($data);
240
241 1
        foreach ($relationships as $relationship => $values) {
242 1
            $relationshipObject = $this->$relationship();
243
244 1
            if ($relationshipObject instanceof BelongsTo === false) {
245 1
                continue;
246
            }
247
248
            $currentPath = $path ? "{$path}." : '';
249
            $currentPath .= $relationship;
250
251
            $foreignKey = $relationshipObject->getQualifiedForeignKeyName();
252
            if (!empty($values['id'])) {
253
                $this->$foreignKey = (int) $values['id'];
254
            } else {
255
                $object = $relationshipObject->getRelated();
256
                if (!$object->createAll($values, $options)) {
257
                    $this->mergeErrors($object->errors()->toArray(), $currentPath);
258
                } else {
259
                    $this->$foreignKey = $object->id;
260
                }
261
            }
262
263
            unset($data[$relationship]);
264 1
        }
265
266 1
        return $data;
267
    }
268
269
    /**
270
     * Get the specified limit for $relationship or false if not exists
271
     * @param $relationship name of the relationship
272
     * @return mixed
273
     */
274 1
    protected function getRelationshipLimit($relationship)
275
    {
276 1
        if (isset($this->relationshipsLimits[$relationship])) {
277
            return array_map (
278
                'intval',
279
                explode(':', $this->relationshipsLimits[$relationship])
280
            );
281
        }
282
283 1
        return false;
284
    }
285
286
    /**
287
     * Checks if amount of related objects are allowed
288
     * @param string $relationship relationship name
289
     * @param array $values
290
     * @param string $path
291
     * @return array modified $values
292
     */
293 1
    protected function checkRelationshipLimit($relationship, $values, $path)
294
    {
295 1
        $relationshipLimit = $this->getRelationshipLimit($relationship);
296 1
        if (!$relationshipLimit) {
297 1
            return $values;
298
        }
299
300
        if (count($values) === 1 && $this->shouldUseSync($relationship, $values)) {
301
            $sumRelationships = count(end($values));
302
        } else {
303
            $this->load($relationship);
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...
304
            $currentRelationships = $this->$relationship->count();
305
            $newRelationships = 0;
306
            $removeRelationships = [];
307
308
            // check if is associative
309
            if ($values && ctype_digit(implode('', array_keys($values))) === false) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $values of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
310
                return true; // @todo prevent this
311
            }
312
313
            foreach ($values as $key => $value) {
314
                $arrayIsEmpty = array_filter($value);
315
                if (empty($arrayIsEmpty)) {
316
                    unset($values[$key]);
317
                    continue;
318
                }
319
320
                if (!isset($value['id'])) {
321
                    $newRelationships++;
322
                    $removeRelationships[] = $key;
323
                }
324
            }
325
326
            $sumRelationships = $currentRelationships + $newRelationships;
327
        }
328
329
        $this->errors();
0 ignored issues
show
Bug introduced by
The method errors() does not exist on Sigep\EloquentEnhancements\Traits\SaveAll. Did you maybe mean mergeErrors()?

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...
330
        if ($sumRelationships < $relationshipLimit[0]) {
331
            $this->errors->add($path, 'validation.min', $relationshipLimit[0]);
0 ignored issues
show
Bug introduced by
The property errors 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...
332
        }
333
334
        if ($sumRelationships > $relationshipLimit[1]) {
335
            $this->errors->add($path, 'validation.max', $relationshipLimit[1]);
336
        }
337
338
        if ($this->errors->has($path)) {
339
            return false;
340
        }
341
342
        return true;
343
    }
344
345
    /**
346
     * Add related data to the current model recursively
347
     * @param string $relationshipName
348
     * @param array $values
349
     * @return bool
350
     */
351 1
    public function addRelated($relationshipName, array $values, array $options = [], $path = '')
352
    {
353 1
        $relationship = $this->$relationshipName();
354
355
        // if is a numeric array, recursive calls to add multiple related
356 1
        if (ctype_digit(implode('', array_keys($values))) === true) {
357 1
            $position = 0;
358 1
            foreach ($values as $value) {
359 1
                if (!$this->addRelated($relationshipName, $value, $options, $path . '.' . $position++)) {
360
                    return false;
361
                }
362
            }
363
364
            return true;
365
        }
366
367
        // if has not data, skip
368 1
        $arrayIsEmpty = array_filter($values);
369 1
        if (empty($arrayIsEmpty)) {
370
            return true;
371
        }
372
373 1
        if ($this->shouldUseSync($relationshipName, $values)) {
374
            $this->$relationshipName()->sync(end($values));
375
            return true;
376
        }
377
378
        // set foreign for hasMany relationships
379 1
        if ($relationship instanceof HasMany) {
380
            $values[last(explode('.', $relationship->getQualifiedForeignKeyName()))] = $this->attributes[$this->primaryKey];
381
        }
382
383
        // if is MorphToMany, put other foreign and fill the type
384 1
        if ($relationship instanceof MorphMany) {
385
            $values[$relationship->getPlainForeignKey()] = $this->attributes[$this->primaryKey];
386
            $values[$relationship->getPlainMorphType()] = get_class($this);
387
        }
388
389
        // if BelongsToMany, put current id in place
390 1
        if ($relationship instanceof BelongsToMany) {
391 1
            $values[last(explode('.', $relationship->getQualifiedForeignKeyName()))] = $this->attributes[$this->primaryKey];
392
            $belongsToManyOtherKey = last(explode('.', $relationship->getOtherKey()));
393
        }
394
395
        // get target Model
396
        if ($relationship instanceof HasManyThrough) {
397
            $model = $relationship->getParent();
398
        } else {
399
            $model = $relationship->getRelated();
400
        }
401
402
        // if has ID, delete or update
403
        if (!empty($values['id']) && $relationship instanceof BelongsToMany === false) {
404
            $obj = $model->find($values['id']);
405
            if (!$obj) {
406
                return false; // @todo transport error
407
            }
408
409
            // delete or update?
410
            if (!empty($values['_delete'])) {
411
                return $obj->delete();
412
            }
413
414
            if (!$obj->saveAll($values, $options)) {
415
                $this->mergeErrors($obj->errors()->toArray(), $path);
416
                return true;
417
            }
418
419
            return true;
420
        }
421
422
        // only BelongsToMany :)
423
        if (!empty($values['_delete'])) {
424
            $this->$relationshipName()->detach($values[last(explode('.', $relationship->getOtherKey()))]);
425
            return true;
426
        }
427
428
429
        if ((isset($belongsToManyOtherKey) && empty($values[$belongsToManyOtherKey]))) {
430
            $obj = $relationship->getRelated();
431
            // if has conditions, fill the values
432
            // this helps to add static values in relationships using its conditions
433
            // @todo experimental
434
            foreach ($relationship->getQuery()->getQuery()->wheres as $where) {
435
                $column = last(explode('.', $where['column']));
436
                if (!empty($where['value']) && empty($values[$column])) {
437
                    $values[$column] = $where['value'];
438
                }
439
            }
440
441
            if (empty($values['id'])) {
442
                if (!$obj->createAll($values, $options)) {
443
                    $this->mergeErrors($obj->errors()->toArray(), $path);
444
                    return false;
445
                }
446
                $values[$belongsToManyOtherKey] = $obj->id;
447
            }
448
449
        }
450
451
        if ($relationship instanceof HasMany || $relationship instanceof MorphMany) {
452
            $relationshipObject = $relationship->getRelated();
453
        } elseif ($relationship instanceof BelongsToMany) {
454
            // if has a relationshipModel, use the model. Else, use attach
455
            // attach doesn't return nothing :(
456
            if (empty($this->relationshipsModels[$relationshipName])) {
0 ignored issues
show
Bug introduced by
The property relationshipsModels 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...
457
                $field = last(explode('.', $relationship->getOtherKey()));
458
                if (!isset($values[$field])) {
459
                    $field = 'id';
460
                }
461
                $related = $this->$relationshipName->contains($values[$field]);
462
                if (empty($related)) {
463
                    $this->$relationshipName()->attach($values[$field]);
464
                }
465
466
                return true;
467
            }
468
469
            $relationshipObjectName = $this->relationshipsModels[$relationshipName];
470
471
            if (empty($values['id']) || !is_numeric($values['id'])) {
472
                $relationshipObject = new $relationshipObjectName;
473
            } else {
474
                if (!empty($values[$belongsToManyOtherKey])) {
475
                    $relationshipObject = $relationshipObjectName::find($values['id']);
476
                } else {
477
                    $relationshipObject = $relationship->getRelated()->find($values['id']);
478
479
                    if (!empty($relationshipObject)) {
480
                        //if (!$this->$relationshipName->contains($values['id'])) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
84% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
481
                            $this->$relationshipName()->withTimestamps()->attach($values['id']);
482
                        //}
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
483
//                        return true;
484
                    }
485
                }
486
487
                if (!$relationshipObject) {
488
                    $relationshipObject = new $relationshipObjectName; // @todo check this out
489
                }
490
            }
491
        } elseif ($relationship instanceof HasManyThrough) {
492
            $relationshipObject = $model;
493
        }
494
495
        $useMethod = (empty($values['id'])) ? 'createAll' : 'saveAll';
496
        if (!$relationshipObject->$useMethod($values, $options)) {
497
            $this->mergeErrors($relationshipObject->errors()->toArray(), $path);
0 ignored issues
show
Bug introduced by
The variable $relationshipObject does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
498
            return false;
499
        }
500
501
        return true;
502
    }
503
504
    /**
505
     * get values that are array in $data
506
     * use this function to extract relationships from Input::all(), for example
507
     * @param  array $data
508
     * @return array
509
     */
510 1
    public function getRelationshipsFromData(array $data = [])
511
    {
512 1
        $relationships = [];
513
514 1
        foreach ($data as $key => $value) {
515 1
            if (is_array($value) && !is_numeric($key) && method_exists($this, $key)) {
516 1
                $relationships[$key] = $value;
517 1
            }
518 1
        }
519
520 1
        return $relationships;
521
    }
522
523
    /**
524
     * Merge $objErrors with $this->errors using $path
525
     *
526
     * @param array $objErrors
527
     * @param string $path
528
     */
529
    protected function mergeErrors(array $objErrors, $path)
530
    {
531
        $thisErrors = $this->errors();
0 ignored issues
show
Bug introduced by
The method errors() does not exist on Sigep\EloquentEnhancements\Traits\SaveAll. Did you maybe mean mergeErrors()?

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...
532
        if ($path) {
533
            $path .= '.';
534
        }
535
        foreach ($objErrors as $field => $errors) {
536
            foreach ($errors as $error) {
537
                $thisErrors->add(
538
                    "{$path}{$field}",
539
                    $error
540
                );
541
            }
542
        }
543
        $this->setErrors($thisErrors);
0 ignored issues
show
Bug introduced by
It seems like setErrors() 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...
544
    }
545
}
546