Passed
Push — main ( a6da94...0d356a )
by Breno
01:59
created

Attributes::add()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 8
rs 10
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
4
namespace BrenoRoosevelt\PhpAttributes;
5
6
use ArrayIterator;
7
use Attribute;
8
use BrenoRoosevelt\PhpAttributes\Specification\AttributeName;
9
use BrenoRoosevelt\PhpAttributes\Specification\AttributeTarget;
10
use Countable;
11
use IteratorAggregate;
12
use ReflectionAttribute;
13
use function array_filter;
14
use function array_map;
15
use function count;
16
17
class Attributes implements IteratorAggregate, Countable
18
{
19
    /** @var ParsedAttribute[] */
20
    private array $attributes;
21
22
    final public function __construct(ParsedAttribute ...$attributes)
23
    {
24
        $this->attributes = $attributes;
25
    }
26
27
    public static function from(
28
        object|string|array $class,
29
        int $target = Attribute::TARGET_ALL,
30
        string $attribute = null,
31
        int $flags = 0
32
    ): Attributes {
33
        return (new AttributesFactory)->from($class, $target, $attribute, $flags);
34
    }
35
36
    public function filter(callable $fn): self
37
    {
38
        return new self(...array_filter($this->attributes, $fn));
39
    }
40
41
    public function merge(self $attributes) :self
42
    {
43
        $merged = array_merge($this->attributes, $attributes->attributes);
44
        return new self(...$merged);
45
    }
46
47
    public function add(ParsedAttribute ...$attributes) :self
48
    {
49
        $new = $this->attributes;
50
        foreach ($attributes as $attribute) {
51
            $new[] = $attribute;
52
        }
53
54
        return new self(...$new);
55
    }
56
57
    public function where(Specification $specification): self
58
    {
59
        return $this->filter(fn(ParsedAttribute $attribute) => $specification->isSatisfiedBy($attribute));
60
    }
61
62
    public function whereAttribute(string $attributeName): self
63
    {
64
        return $this->where(new AttributeName($attributeName));
65
    }
66
67
    public function whereTarget(int $target): self
68
    {
69
        return $this->where(new AttributeTarget($target));
70
    }
71
72
    public function first(): self
73
    {
74
        return $this->isEmpty() ? new self() : new self($this->attributes[0]);
75
    }
76
77
    public function isEmpty(): bool
78
    {
79
        return empty($this->attributes);
80
    }
81
82
    public function instances(): array
83
    {
84
        return array_map(
85
            fn(ParsedAttribute $attribute) => $attribute->attribute()->newInstance(),
86
            $this->attributes
87
        );
88
    }
89
90
    public function firstInstance(mixed $default = null): mixed
91
    {
92
        return isset($this->attributes[0]) ? $this->attributes[0]->attribute()->newInstance() : $default;
93
    }
94
95
    /**
96
     * @return ReflectionAttribute[]
97
     */
98
    public function attributes(): array
99
    {
100
        return array_map(
101
            fn(ParsedAttribute $attribute) => $attribute->attribute(),
102
            $this->attributes
103
        );
104
    }
105
106
    public function targets(): array
107
    {
108
        return array_map(
109
            fn(ParsedAttribute $attribute) => $attribute->target(),
110
            $this->attributes
111
        );
112
    }
113
114
    public function hasAttribute(string $attributeName): bool
115
    {
116
        return $this->whereAttribute($attributeName)->count() > 0;
117
    }
118
119
    public function hasMany(string $attributeName): bool
120
    {
121
        return $this->whereAttribute($attributeName)->count() > 1;
122
    }
123
124
    public function hasTarget(int $target): bool
125
    {
126
        return $this->whereTarget($target)->count() > 0;
127
    }
128
129
    public function count(): int
130
    {
131
        return count($this->attributes);
132
    }
133
134
    /**
135
     * @return ParsedAttribute[]
136
     */
137
    public function toArray(): array
138
    {
139
        return $this->attributes;
140
    }
141
142
    public function getIterator(): ArrayIterator
143
    {
144
        return new ArrayIterator($this->attributes);
145
    }
146
}
147