SelfAware::isPure()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Cerbero\Enum\Concerns;
6
7
use BackedEnum;
0 ignored issues
show
Bug introduced by
The type BackedEnum 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...
8
use Cerbero\Enum\Attributes\Meta;
9
use ReflectionAttribute;
10
use ReflectionEnum;
0 ignored issues
show
Bug introduced by
The type ReflectionEnum 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
use ReflectionEnumUnitCase;
0 ignored issues
show
Bug introduced by
The type ReflectionEnumUnitCase 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...
12
use ReflectionMethod;
13
use ValueError;
14
15
/**
16
 * The trait to make an enum self-aware.
17
 */
18
trait SelfAware
19
{
20
    /**
21
     * Determine whether the enum is pure.
22
     */
23 98
    public static function isPure(): bool
24
    {
25 98
        return !self::isBacked();
26
    }
27
28
    /**
29
     * Determine whether the enum is backed.
30
     */
31 98
    public static function isBacked(): bool
32
    {
33
        /** @phpstan-ignore function.impossibleType */
34 98
        return is_subclass_of(self::class, BackedEnum::class);
35
    }
36
37
    /**
38
     * Determine whether the enum is backed by integer.
39
     */
40 1
    public static function isBackedByInteger(): bool
41
    {
42 1
        return (string) (new ReflectionEnum(self::class))->getBackingType() === 'int';
43
    }
44
45
    /**
46
     * Determine whether the enum is backed by string.
47
     */
48 1
    public static function isBackedByString(): bool
49
    {
50 1
        return (string) (new ReflectionEnum(self::class))->getBackingType() === 'string';
51
    }
52
53
    /**
54
     * Retrieve all the meta names of the enum.
55
     *
56
     * @return list<string>
0 ignored issues
show
Bug introduced by
The type Cerbero\Enum\Concerns\list 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...
57
     */
58 3
    public static function metaNames(): array
59
    {
60 3
        $meta = self::metaAttributeNames();
61 2
        $enum = new ReflectionEnum(self::class);
62
63 2
        foreach ($enum->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
64 2
            if (! $method->isStatic() && $method->getFileName() == $enum->getFileName()) {
65 2
                $meta[] = $method->getShortName();
66
            }
67
        }
68
69 2
        return array_values(array_unique($meta));
70
    }
71
72
    /**
73
     * Retrieve all the meta attribute names of the enum.
74
     *
75
     * @return list<string>
76
     */
77 10
    public static function metaAttributeNames(): array
78
    {
79 10
        $meta = [];
80 10
        $enum = new ReflectionEnum(self::class);
81
82 10
        foreach ($enum->getAttributes(Meta::class, ReflectionAttribute::IS_INSTANCEOF) as $attribute) {
83 9
            array_push($meta, ...$attribute->newInstance()->names());
84
        }
85
86 9
        foreach ($enum->getCases() as $case) {
87 8
            foreach ($case->getAttributes(Meta::class, ReflectionAttribute::IS_INSTANCEOF) as $attribute) {
88 8
                array_push($meta, ...$attribute->newInstance()->names());
89
            }
90
        }
91
92 9
        return array_values(array_unique($meta));
93
    }
94
95
    /**
96
     * Retrieve the given item of this case.
97
     *
98
     * @template TItemValue
99
     *
100
     * @param (callable(self): TItemValue)|string $item
0 ignored issues
show
Documentation Bug introduced by
The doc comment (callable(self): TItemValue)|string at position 1 could not be parsed: Expected ')' at position 1, but found 'callable'.
Loading history...
101
     * @return TItemValue
102
     * @throws ValueError
103
     */
104 44
    public function resolveItem(callable|string $item): mixed
105
    {
106
        return match (true) {
107 44
            is_string($item) && property_exists($this, $item) => $this->$item,
108 31
            is_callable($item) => $item($this),
109 44
            default => $this->resolveMeta($item),
0 ignored issues
show
Bug introduced by
It seems like $item can also be of type callable; however, parameter $meta of Cerbero\Enum\Concerns\SelfAware::resolveMeta() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

109
            default => $this->resolveMeta(/** @scrutinizer ignore-type */ $item),
Loading history...
110
        };
111
    }
112
113
    /**
114
     * Retrieve the given meta of this case.
115
     *
116
     * @throws ValueError
117
     */
118 35
    public function resolveMeta(string $meta): mixed
119
    {
120 35
        $enum = new ReflectionEnum($this);
121 35
        $enumFileName = $enum->getFileName();
122
123 35
        foreach ($enum->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
124 35
            if (! $method->isStatic() && $method->getFileName() == $enumFileName && $method->getShortName() == $meta) {
125 7
                return $this->$meta();
126
            }
127
        }
128
129 28
        return $this->resolveMetaAttribute($meta);
130
    }
131
132
    /**
133
     * Retrieve the given meta from the attributes.
134
     *
135
     * @throws ValueError
136
     */
137 44
    public function resolveMetaAttribute(string $meta): mixed
138
    {
139 44
        $case = new ReflectionEnumUnitCase($this, $this->name);
140
141 44
        foreach ($case->getAttributes(Meta::class, ReflectionAttribute::IS_INSTANCEOF) as $attribute) {
142 44
            if (($metadata = $attribute->newInstance())->has($meta)) {
143 40
                return $metadata->get($meta);
144
            }
145
        }
146
147 40
        foreach ($case->getEnum()->getAttributes(Meta::class, ReflectionAttribute::IS_INSTANCEOF) as $attribute) {
148 40
            if (($metadata = $attribute->newInstance())->has($meta)) {
149 36
                return $metadata->get($meta);
150
            }
151
        }
152
153 4
        throw new ValueError(sprintf('The case %s::%s has no "%s" meta set', self::class, $this->name, $meta));
154
    }
155
156
    /**
157
     * Retrieve the value of a backed case or the name of a pure case.
158
     */
159 2
    public function value(): string|int
160
    {
161
        /** @var string|int @phpstan-ignore property.notFound */
162 2
        return $this->value ?? $this->name;
163
    }
164
}
165