GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( a9bc98...b864c9 )
by butschster
10:50
created

NamedFormElement::unique()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 1
rs 9.4285
1
<?php
2
3
namespace SleepingOwl\Admin\Form\Element;
4
5
use Request;
6
use LogicException;
7
use Illuminate\Database\Eloquent\Model;
8
use SleepingOwl\Admin\Form\FormElement;
9
use Illuminate\Contracts\Support\Htmlable;
10
use Illuminate\Database\Eloquent\Relations\HasOne;
11
use Illuminate\Database\Eloquent\Relations\MorphOne;
12
use Illuminate\Database\Eloquent\Relations\Relation;
13
use Illuminate\Database\Eloquent\Relations\BelongsTo;
14
use SleepingOwl\Admin\Exceptions\Form\FormElementException;
15
16
abstract class NamedFormElement extends FormElement
17
{
18
    /**
19
     * @var string
20
     */
21
    protected $path;
22
23
    /**
24
     * @var string
25
     */
26
    protected $name;
27
28
    /**
29
     * @var string
30
     */
31
    protected $attribute;
32
33
    /**
34
     * @var string
35
     */
36
    protected $label;
37
38
    /**
39
     * @var string
40
     */
41
    protected $helpText;
42
43
    /**
44
     * @var mixed
45
     */
46
    protected $defaultValue;
47
48
    /**
49
     * @var \Closure
50
     */
51
    protected $mutator;
52
53
    /**
54
     * @param string $path
55
     * @param string|null $label
56
     *
57
     * @throws FormElementException
58
     */
59
    public function __construct($path, $label = null)
60
    {
61
        if (empty($path)) {
62
            throw new FormElementException('You must specify field path');
63
        }
64
65
        $this->setPath($path);
66
        $this->setLabel($label);
67
68
        $parts = explode('.', $path);
69
        $this->setName($this->composeName($parts));
70
        $this->setAttribute(end($parts));
71
72
        parent::__construct();
73
    }
74
75
    /**
76
     * Compose html name from array like this: 'first[second][third]'.
77
     *
78
     * @param array $parts
79
     *
80
     * @return string
81
     */
82
    private function composeName(array $parts)
83
    {
84
        $name = array_shift($parts);
85
86
        while (! empty($parts)) {
87
            $part = array_shift($parts);
88
            $name .= "[$part]";
89
        }
90
91
        return $name;
92
    }
93
94
    /**
95
     * @return string
96
     */
97
    public function getPath()
98
    {
99
        return $this->path;
100
    }
101
102
    /**
103
     * @param string $path
104
     *
105
     * @return $this
106
     */
107
    public function setPath($path)
108
    {
109
        $this->path = $path;
110
111
        return $this;
112
    }
113
114
    /**
115
     * @return string
116
     */
117
    public function getName()
118
    {
119
        return $this->name;
120
    }
121
122
    /**
123
     * @param string $name
124
     *
125
     * @return $this
126
     */
127
    public function setName($name)
128
    {
129
        $this->name = $name;
130
131
        return $this;
132
    }
133
134
    /**
135
     * @return string
136
     */
137
    public function getLabel()
138
    {
139
        return $this->label;
140
    }
141
142
    /**
143
     * @param string $label
144
     *
145
     * @return $this
146
     */
147
    public function setLabel($label)
148
    {
149
        $this->label = $label;
150
151
        return $this;
152
    }
153
154
    /**
155
     * @return string
156
     */
157
    public function getAttribute()
158
    {
159
        return $this->attribute;
160
    }
161
162
    /**
163
     * @param string $attribute
164
     *
165
     * @return $this
166
     */
167
    public function setAttribute($attribute)
168
    {
169
        $this->attribute = $attribute;
170
171
        return $this;
172
    }
173
174
    /**
175
     * @return mixed
176
     */
177
    public function getDefaultValue()
178
    {
179
        return $this->defaultValue;
180
    }
181
182
    /**
183
     * @param mixed $defaultValue
184
     *
185
     * @return $this
186
     */
187
    public function setDefaultValue($defaultValue)
188
    {
189
        $this->defaultValue = $defaultValue;
190
191
        return $this;
192
    }
193
194
    /**
195
     * @return string
196
     */
197
    public function getHelpText()
198
    {
199
        if ($this->helpText instanceof Htmlable) {
200
            return $this->helpText->toHtml();
201
        }
202
203
        return $this->helpText;
204
    }
205
206
    /**
207
     * @param string|Htmlable $helpText
208
     *
209
     * @return $this
210
     */
211
    public function setHelpText($helpText)
212
    {
213
        $this->helpText = $helpText;
0 ignored issues
show
Documentation Bug introduced by
It seems like $helpText can also be of type object<Illuminate\Contracts\Support\Htmlable>. However, the property $helpText is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

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

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
214
215
        return $this;
216
    }
217
218
    /**
219
     * @param string|null $message
220
     *
221
     * @return $this
222
     */
223
    public function required($message = null)
224
    {
225
        $this->addValidationRule('required', $message);
226
227
        return $this;
228
    }
229
230
    /**
231
     * @param string|null $message
232
     *
233
     * @return $this
234
     */
235
    public function unique($message = null)
236
    {
237
        $this->addValidationRule('_unique');
238
239
        if (! is_null($message)) {
240
            $this->addValidationMessage('unique', $message);
241
        }
242
243
        return $this;
244
    }
245
246
    /**
247
     * @return array
248
     */
249
    public function getValidationMessages()
250
    {
251
        $messages = parent::getValidationMessages();
252
253
        foreach ($messages as $rule => $message) {
254
            $messages[$this->getName().'.'.$rule] = $message;
255
            unset($messages[$rule]);
256
        }
257
258
        return $messages;
259
    }
260
261
    /**
262
     * @return array
263
     */
264
    public function getValidationLabels()
265
    {
266
        return [$this->getPath() => $this->getLabel()];
267
    }
268
269
    /**
270
     * @return array|string
271
     */
272
    public function getValueFromRequest()
273
    {
274
        if (Request::hasSession() && ! is_null($value = Request::old($this->getPath()))) {
275
            return $value;
276
        }
277
278
        return Request::input($this->getPath());
279
    }
280
281
    /**
282
     * TODO: HACK Needs refactoring and reasoning.
283
     * @return mixed
284
     */
285
    public function getValue()
286
    {
287
        if (! is_null($value = $this->getValueFromRequest())) {
288
            return $value;
289
        }
290
291
        $model = $this->getModel();
292
        $value = $this->getDefaultValue();
293
294
        if (is_null($model) or ! $model->exists) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
295
            return $value;
296
        }
297
298
        $relations = explode('.', $this->getPath());
299
        $count = count($relations);
300
301
        if ($count === 1) {
302
            return $model->getAttribute($this->getAttribute());
303
        }
304
305
        foreach ($relations as $relation) {
306
            if ($model->{$relation} instanceof Model) {
307
                $model = $model->{$relation};
308
                continue;
309
            }
310
311
            if ($count === 2) {
312
                return $model->getAttribute($relation);
313
            }
314
315
            throw new LogicException("Can not fetch value for field '{$this->getPath()}'. Probably relation definition is incorrect");
316
        }
317
318
        return $value;
319
    }
320
321
    /**
322
     * If FormElement has `_unique` rule, it will get all appropriate
323
     * validation rules based on underlying model.
324
     *
325
     * @return array
326
     */
327
    public function getValidationRules()
328
    {
329
        $rules = parent::getValidationRules();
330
331
        foreach ($rules as &$rule) {
332
            if ($rule !== '_unique') {
333
                continue;
334
            }
335
336
            $model = $this->resolvePath();
337
            $table = $model->getTable();
338
339
            $rule = 'unique:'.$table.','.$this->getAttribute();
340
            if ($model->exists) {
341
                $rule .= ','.$model->getKey();
342
            }
343
        }
344
        unset($rule);
345
346
        return [$this->getPath() => $rules];
347
    }
348
349
    /**
350
     * Get model related to form element.
351
     *
352
     * @return mixed
353
     */
354
    public function resolvePath()
355
    {
356
        $model = $this->getModel();
357
        $relations = explode('.', $this->getPath());
358
        $count = count($relations);
359
360
        if ($count === 1) {
361
            return $model;
362
        }
363
364
        foreach ($relations as $relation) {
365
            if ($count === 1) {
366
                return $model;
367
            }
368
369
            if ($model->exists && ($value = $model->getAttribute($relation)) instanceof Model) {
370
                $model = $value;
371
372
                $count--;
373
                continue;
374
            }
375
376
            if (method_exists($model, $relation)) {
377
                $relation = $model->{$relation}();
378
379
                if ($relation instanceof Relation) {
380
                    $model = $relation->getModel();
381
                    $count--;
382
                    continue;
383
                }
384
            }
385
386
            break;
387
        }
388
389
        throw new LogicException("Can not resolve path for field '{$this->getPath()}'. Probably relation definition is incorrect");
390
    }
391
392
    /**
393
     * @return array
394
     */
395
    public function toArray()
396
    {
397
        return parent::toArray() + [
398
            'id' => $this->getName(),
399
            'name' => $this->getName(),
400
            'path' => $this->getPath(),
401
            'label' => $this->getLabel(),
402
            'helpText' => $this->getHelpText(),
403
            'required' => in_array('required', $this->validationRules),
404
        ];
405
    }
406
407
    public function save()
408
    {
409
        $attribute = $this->getAttribute();
410
        $model = $this->getModel();
411
        $value = $this->getValueFromRequest();
412
413
        $relations = explode('.', $this->getPath());
414
        $count = count($relations);
415
        $i = 1;
416
417
        if ($count > 1) {
418
            $i++;
419
            $previousModel = $model;
420
421
            /* @var Model $model */
422
            foreach ($relations as $relation) {
423
                $relatedModel = null;
424
                if ($previousModel->getAttribute($relation) instanceof Model) {
425
                    $relatedModel = &$previousModel->getAttribute($relation);
426
                } elseif (method_exists($previousModel, $relation)) {
427
428
                    /* @var Relation $relation */
429
                    $relationObject = $previousModel->{$relation}();
430
                    switch (get_class($relationObject)) {
431
                        case BelongsTo::class:
432
                            $relationObject->associate($relatedModel = $relationObject->getRelated());
433
                            break;
434
                        case HasOne::class:
435
                        case MorphOne::class:
436
                            $relatedModel = $relationObject->getRelated()->newInstance();
437
                            $relatedModel->setAttribute($relationObject->getPlainForeignKey(), $relationObject->getParentKey());
438
                            $model->setRelation($relation, $relatedModel);
0 ignored issues
show
Documentation introduced by
$relation is of type object<Illuminate\Databa...ent\Relations\Relation>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
439
                            break;
440
                    }
441
                }
442
443
                $previousModel = $relatedModel;
444
                if ($i === $count) {
445
                    break;
446
                } elseif (is_null($relatedModel)) {
447
                    throw new LogicException("Field «{$this->getPath()}» can't be mapped to relations of model ".get_class($model).'. Probably some dot delimeted segment is not a supported relation type');
448
                }
449
            }
450
451
            $model = $previousModel;
452
        }
453
454
        $this->setValue($model, $attribute, $this->prepareValue($value));
455
    }
456
457
    /**
458
     * Field->mutate(function($value) {
459
     *     return bcrypt($value);
460
     * }).
461
     *
462
     * @param \Closure $mutator
463
     *
464
     * @return $this
465
     */
466
    public function mutateValue(\Closure $mutator)
467
    {
468
        $this->mutator = $mutator;
469
470
        return $this;
471
    }
472
473
    /**
474
     * @return bool
475
     */
476
    public function hasMutator()
477
    {
478
        return is_callable($this->mutator);
479
    }
480
481
    /**
482
     * @param Model  $model
483
     * @param string $attribute
484
     * @param mixed  $value
485
     */
486
    protected function setValue(Model $model, $attribute, $value)
487
    {
488
        $model->setAttribute($attribute, $value);
489
    }
490
491
    /**
492
     * @param mixed $value
493
     *
494
     * @return mixed
495
     */
496
    protected function prepareValue($value)
497
    {
498
        if ($this->hasMutator()) {
499
            $value = call_user_func($this->mutator, $value);
500
        }
501
502
        return $value;
503
    }
504
}
505