Completed
Pull Request — master (#17)
by
unknown
01:34
created

StateConfig::transitionableStates()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 16
rs 9.7333
c 0
b 0
f 0
cc 3
nc 3
nop 1
1
<?php
2
3
namespace Spatie\ModelStates;
4
5
use Illuminate\Database\Eloquent\Model;
6
use Spatie\ModelStates\Exceptions\InvalidConfig;
7
8
class StateConfig
9
{
10
    /** @var string */
11
    public $field;
12
13
    /** @var string|\Spatie\ModelStates\State */
14
    public $stateClass;
15
16
    /** @var string[] */
17
    public $allowedTransitions = [];
18
19
    /** @var string|null */
20
    public $defaultStateClass;
21
22
    public function __construct(string $field, string $stateClass)
23
    {
24
        if (! is_subclass_of($stateClass, State::class)) {
25
            throw InvalidConfig::doesNotExtendState($stateClass);
26
        }
27
28
        $this->field = $field;
29
30
        $this->stateClass = $stateClass;
31
    }
32
33
    public function default(string $defaultStateClass): StateConfig
34
    {
35
        $this->defaultStateClass = $defaultStateClass;
36
37
        return $this;
38
    }
39
40
    /**
41
     * @param string|array $from
42
     * @param string $to
43
     * @param string|null $transition
44
     *
45
     * @return \Spatie\ModelStates\StateConfig
46
     */
47
    public function allowTransition($from, string $to, string $transition = null): StateConfig
48
    {
49
        if (is_array($from)) {
50
            foreach ($from as $fromState) {
51
                $this->allowTransition($fromState, $to, $transition);
52
            }
53
54
            return $this;
55
        }
56
57
        if (! is_subclass_of($from, $this->stateClass)) {
58
            throw InvalidConfig::doesNotExtendBaseClass($from, $this->stateClass);
0 ignored issues
show
Bug introduced by
It seems like $this->stateClass can also be of type object<Spatie\ModelStates\State>; however, Spatie\ModelStates\Excep...oesNotExtendBaseClass() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
59
        }
60
61
        if (! is_subclass_of($to, $this->stateClass)) {
62
            throw InvalidConfig::doesNotExtendBaseClass($to, $this->stateClass);
0 ignored issues
show
Bug introduced by
It seems like $this->stateClass can also be of type object<Spatie\ModelStates\State>; however, Spatie\ModelStates\Excep...oesNotExtendBaseClass() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
63
        }
64
65
        if ($transition && ! is_subclass_of($transition, Transition::class)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $transition of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
66
            throw InvalidConfig::doesNotExtendTransition($transition);
67
        }
68
69
        $this->allowedTransitions[$this->createTransitionKey($from, $to)] = $transition;
70
71
        return $this;
72
    }
73
74
    public function allowTransitions(array $transitions): StateConfig
75
    {
76
        foreach ($transitions as $transition) {
77
            $this->allowTransition($transition[0], $transition[1], $transition[2] ?? null);
78
        }
79
80
        return $this;
81
    }
82
83
    /**
84
     * @param string $fromClass
85
     */
86
    public function transitionableStates(string $fromClass)
87
    {
88
        $transitionableStates = [];
89
90
        foreach ($this->allowedTransitions as $allowedTransition => $value) {
91
            [$from, $to] = explode('-', $allowedTransition);
0 ignored issues
show
Bug introduced by
The variable $from does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $to does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
92
93
            if ($from !== $fromClass) {
94
                continue;
95
            }
96
97
            $transitionableStates[] = $to::getMorphClass();
98
        }
99
100
        return $transitionableStates;
101
    }
102
103
    /**
104
     * @param string $from
105
     * @param string $to
106
     *
107
     * @return string|\Spatie\ModelStates\Transition|null
108
     */
109
    public function resolveTransition(Model $model, string $from, string $to)
110
    {
111
        $transitionKey = $this->createTransitionKey($from, $to);
112
113
        if (! array_key_exists($transitionKey, $this->allowedTransitions)) {
114
            return;
115
        }
116
117
        return $this->allowedTransitions[$transitionKey]
118
            ?? new DefaultTransition(
119
                $model,
120
                $this->field,
121
                $this->stateClass::make($to, $model)
122
            );
123
    }
124
125
    private function createTransitionKey(string $from, string $to): string
126
    {
127
        return "{$from}-{$to}";
128
    }
129
}
130