Enums::handleInvoke()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 2
nc 2
nop 2
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Cerbero\Enum;
6
7
use Closure;
8
use Generator;
9
use GlobIterator;
10
use UnitEnum;
0 ignored issues
show
Bug introduced by
The type UnitEnum was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
11
12
/**
13
 * The enums manager.
14
 */
15
class Enums
16
{
17
    /**
18
     * The application base path.
19
     *
20
     * @var string
21
     */
22
    protected static ?string $basePath = null;
23
24
    /**
25
     * The glob paths to find enums in.
26
     *
27
     * @var string[]
28
     */
29
    protected static array $paths = [];
30
31
    /**
32
     * The TypeScript path to sync enums in.
33
     *
34
     * @var Closure(class-string<UnitEnum>|string $enum): string|string
35
     */
36
    protected static Closure|string $typeScript = 'resources/js/enums/index.ts';
37
38
    /**
39
     * The logic to run when an inaccessible enum method is called.
40
     *
41
     * @var ?Closure(class-string<UnitEnum> $enum, string $name, array<array-key, mixed> $arguments): mixed
42
     */
43
    protected static ?Closure $onStaticCall = null;
44
45
    /**
46
     * The logic to run when an inaccessible case method is called.
47
     *
48
     * @var ?Closure(UnitEnum $case, string $name, array<array-key, mixed> $arguments): mixed
49
     */
50
    protected static ?Closure $onCall = null;
51
52
    /**
53
     * The logic to run when a case is invoked.
54
     *
55
     * @var ?Closure(UnitEnum $case, mixed ...$arguments): mixed
56
     */
57
    protected static ?Closure $onInvoke = null;
58
59
    /**
60
     * Set the application base path.
61
     */
62 11
    public static function setBasePath(string $path): void
63
    {
64 11
        static::$basePath = path($path);
65
    }
66
67
    /**
68
     * Retrieve the application base path, optionally appending the given path.
69
     */
70 21
    public static function basePath(?string $path = null): string
71
    {
72 21
        $basePath = static::$basePath ?: dirname(__DIR__, 4);
73
74 21
        return $path === null ? $basePath : $basePath . DIRECTORY_SEPARATOR . ltrim(path($path), '\/');
75
    }
76
77
    /**
78
     * Set the glob paths to find all the application enums.
79
     */
80 5
    public static function setPaths(string ...$paths): void
81
    {
82 5
        static::$paths = array_map(path(...), $paths);
0 ignored issues
show
Bug introduced by
The type Cerbero\Enum\path was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
83
    }
84
85
    /**
86
     * Retrieve the paths to find all the application enums.
87
     *
88
     * @return string[]
89
     */
90 11
    public static function paths(): array
91
    {
92 11
        return static::$paths;
93
    }
94
95
    /**
96
     * Set the TypeScript path to sync enums in.
97
     *
98
     * @param callable(class-string<UnitEnum>|string $enum): string|string $path
99
     */
100 4
    public static function setTypeScript(callable|string $path): void
101
    {
102
        /** @phpstan-ignore assign.propertyType */
103 4
        static::$typeScript = is_callable($path) ? $path(...) : $path;
0 ignored issues
show
Documentation Bug introduced by
It seems like is_callable($path) ? $path(...) : $path can also be of type string. However, the property $typeScript is declared as type Closure. 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...
104
    }
105
106
    /**
107
     * Retrieve the TypeScript path, optionally for the given enum.
108
     *
109
     * @param class-string<UnitEnum>|string $enum
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<UnitEnum>|string at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<UnitEnum>|string.
Loading history...
110
     * @return string
111
     */
112 7
    public static function typeScript(string $enum = ''): string
113
    {
114 7
        return static::$typeScript instanceof Closure ? (static::$typeScript)($enum) : static::$typeScript;
115
    }
116
117
    /**
118
     * Yield the namespaces of all the application enums.
119
     *
120
     * @return Generator<int, class-string<UnitEnum>>
121
     */
122 2
    public static function namespaces(): Generator
123
    {
124 2
        $psr4 = psr4();
125
126 2
        foreach (static::paths() as $path) {
127 2
            $pattern = static::basePath($path) . DIRECTORY_SEPARATOR . '*.php';
128
129 2
            foreach (new GlobIterator($pattern) as $fileInfo) {
130
                /** @var \SplFileInfo $fileInfo */
131 2
                $enumPath = (string) $fileInfo->getRealPath();
132
133 2
                foreach ($psr4 as $root => $relative) {
134 2
                    $absolute = static::basePath($relative) . DIRECTORY_SEPARATOR;
135
136 2
                    if (str_starts_with($enumPath, $absolute)) {
137 2
                        $enum = strtr($enumPath, [$absolute => $root, '/' => '\\', '.php' => '']);
138
139 2
                        if (enum_exists($enum)) {
0 ignored issues
show
Bug introduced by
The function enum_exists was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

139
                        if (/** @scrutinizer ignore-call */ enum_exists($enum)) {
Loading history...
140 2
                            yield $enum;
141
                        }
142
                    }
143
                }
144
            }
145
        }
146
    }
147
148
    /**
149
     * Set the logic to run when an inaccessible enum method is called.
150
     *
151
     * @param callable(class-string<UnitEnum> $enum, string $name, array<array-key, mixed> $arguments): mixed $callback
152
     */
153 2
    public static function onStaticCall(callable $callback): void
154
    {
155 2
        static::$onStaticCall = $callback(...);
156
    }
157
158
    /**
159
     * Handle the call to an inaccessible enum method.
160
     *
161
     * @param class-string<UnitEnum> $enum
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<UnitEnum> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<UnitEnum>.
Loading history...
162
     * @param array<array-key, mixed> $arguments
163
     */
164 4
    public static function handleStaticCall(string $enum, string $name, array $arguments): mixed
165
    {
166 4
        return static::$onStaticCall
167 2
            ? (static::$onStaticCall)($enum, $name, $arguments)
168 4
            : $enum::fromName($name)->value(); /** @phpstan-ignore method.nonObject */
169
    }
170
171
    /**
172
     * Set the logic to run when an inaccessible case method is called.
173
     *
174
     * @param callable(UnitEnum $case, string $name, array<array-key, mixed> $arguments): mixed $callback
175
     */
176 2
    public static function onCall(callable $callback): void
177
    {
178 2
        static::$onCall = $callback(...);
179
    }
180
181
    /**
182
     * Handle the call to an inaccessible case method.
183
     *
184
     * @param array<array-key, mixed> $arguments
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<array-key, mixed> at position 2 could not be parsed: Unknown type name 'array-key' at position 2 in array<array-key, mixed>.
Loading history...
185
     */
186 14
    public static function handleCall(UnitEnum $case, string $name, array $arguments): mixed
187
    {
188 14
        return static::$onCall ? (static::$onCall)($case, $name, $arguments) : $case->resolveMetaAttribute($name);
189
    }
190
191
    /**
192
     * Set the logic to run when a case is invoked.
193
     *
194
     * @param callable(UnitEnum $case, mixed ...$arguments): mixed $callback
195
     */
196 2
    public static function onInvoke(callable $callback): void
197
    {
198 2
        static::$onInvoke = $callback(...);
199
    }
200
201
    /**
202
     * Handle the invocation of a case.
203
     */
204 2
    public static function handleInvoke(UnitEnum $case, mixed ...$arguments): mixed
205
    {
206 2
        return static::$onInvoke ? (static::$onInvoke)($case, ...$arguments) : $case->value();
207
    }
208
}
209