AttributeCollection::has()   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 1
Bugs 0 Features 0
Metric Value
eloc 1
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 1
b 0
f 0
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
declare(strict_types = 1);
4
5
namespace Sop\X501\ASN1\Collection;
6
7
use Sop\ASN1\Type\Structure;
8
use Sop\ASN1\Type\UnspecifiedType;
9
use Sop\X501\ASN1\Attribute;
10
use Sop\X501\ASN1\AttributeType;
11
use Sop\X501\ASN1\AttributeValue\AttributeValue;
12
13
/**
14
 * Base class for X.501 attribute containers.
15
 *
16
 * Implements methods for Countable and IteratorAggregate interfaces.
17
 */
18
abstract class AttributeCollection implements \Countable, \IteratorAggregate
19
{
20
    /**
21
     * Array of attributes.
22
     *
23
     * Always with consecutive indices.
24
     *
25
     * @var Attribute[]
26
     */
27
    protected $_attributes;
28
29
    /**
30
     * Constructor.
31
     *
32
     * @param Attribute ...$attribs List of attributes
33
     */
34 6
    public function __construct(Attribute ...$attribs)
35
    {
36 6
        $this->_attributes = $attribs;
37 6
    }
38
39
    /**
40
     * Initialize from attribute values.
41
     *
42
     * @param AttributeValue ...$values List of attribute values
43
     *
44
     * @return static
45
     */
46 4
    public static function fromAttributeValues(AttributeValue ...$values): self
47
    {
48 4
        return new static(...array_map(
49
            function (AttributeValue $value) {
50 4
                return $value->toAttribute();
51 4
            }, $values));
52
    }
53
54
    /**
55
     * Check whether attribute is present.
56
     *
57
     * @param string $name OID or attribute name
58
     *
59
     * @return bool
60
     */
61 2
    public function has(string $name): bool
62
    {
63 2
        return null !== $this->_findFirst($name);
64
    }
65
66
    /**
67
     * Get first attribute by OID or attribute name.
68
     *
69
     * @param string $name OID or attribute name
70
     *
71
     * @throws \UnexpectedValueException if attribute is not present
72
     *
73
     * @return Attribute
74
     */
75 3
    public function firstOf(string $name): Attribute
76
    {
77 3
        $attr = $this->_findFirst($name);
78 3
        if (!$attr) {
79 1
            throw new \UnexpectedValueException("No {$name} attribute.");
80
        }
81 2
        return $attr;
82
    }
83
84
    /**
85
     * Get all attributes of given name.
86
     *
87
     * @param string $name OID or attribute name
88
     *
89
     * @return Attribute[]
90
     */
91 2
    public function allOf(string $name): array
92
    {
93 2
        $oid = AttributeType::attrNameToOID($name);
94 2
        return array_values(
95 2
            array_filter($this->_attributes,
96
                function (Attribute $attr) use ($oid) {
97 2
                    return $attr->oid() === $oid;
98 2
                }));
99
    }
100
101
    /**
102
     * Get all attributes.
103
     *
104
     * @return Attribute[]
105
     */
106 3
    public function all(): array
107
    {
108 3
        return $this->_attributes;
109
    }
110
111
    /**
112
     * Get self with additional attributes added.
113
     *
114
     * @param Attribute ...$attribs List of attributes to add
115
     *
116
     * @return self
117
     */
118 1
    public function withAdditional(Attribute ...$attribs): self
119
    {
120 1
        $obj = clone $this;
121 1
        foreach ($attribs as $attr) {
122 1
            $obj->_attributes[] = $attr;
123
        }
124 1
        return $obj;
125
    }
126
127
    /**
128
     * Get self with single unique attribute added.
129
     *
130
     * All previous attributes of the same type are removed.
131
     *
132
     * @param Attribute $attr Attribute to add
133
     *
134
     * @return self
135
     */
136 1
    public function withUnique(Attribute $attr): self
137
    {
138 1
        $attribs = array_values(
139 1
            array_filter($this->_attributes,
140
                function (Attribute $a) use ($attr) {
141 1
                    return $a->oid() !== $attr->oid();
142 1
                }));
143 1
        $attribs[] = $attr;
144 1
        $obj = clone $this;
145 1
        $obj->_attributes = $attribs;
146 1
        return $obj;
147
    }
148
149
    /**
150
     * Get number of attributes.
151
     *
152
     * @see \Countable::count()
153
     *
154
     * @return int
155
     */
156 1
    public function count(): int
157
    {
158 1
        return count($this->_attributes);
159
    }
160
161
    /**
162
     * Get iterator for attributes.
163
     *
164
     * @see \IteratorAggregate::getIterator()
165
     *
166
     * @return \ArrayIterator|Attribute[]
167
     */
168 1
    public function getIterator(): \ArrayIterator
169
    {
170 1
        return new \ArrayIterator($this->_attributes);
171
    }
172
173
    /**
174
     * Find first attribute of given name or OID.
175
     *
176
     * @param string $name OID or attribute name
177
     *
178
     * @return null|Attribute
179
     */
180 5
    protected function _findFirst(string $name): ?Attribute
181
    {
182 5
        $oid = AttributeType::attrNameToOID($name);
183 5
        foreach ($this->_attributes as $attr) {
184 5
            if ($attr->oid() === $oid) {
185 5
                return $attr;
186
            }
187
        }
188 2
        return null;
189
    }
190
191
    /**
192
     * Initialize from ASN.1 constructed element.
193
     *
194
     * @param Structure $struct ASN.1 structure
195
     *
196
     * @return static
197
     */
198 3
    protected static function _fromASN1Structure(Structure $struct): self
199
    {
200 3
        return new static(...array_map(
201
            function (UnspecifiedType $el) {
202 3
                return static::_castAttributeValues(
203 3
                    Attribute::fromASN1($el->asSequence()));
204 3
            }, $struct->elements()));
205
    }
206
207
    /**
208
     * Cast Attribute's AttributeValues to implementation specific objects.
209
     *
210
     * Overridden in derived classes.
211
     *
212
     * @param Attribute $attribute Attribute to cast
213
     *
214
     * @return Attribute
215
     */
216 2
    protected static function _castAttributeValues(Attribute $attribute): Attribute
217
    {
218
        // pass through by default
219 2
        return $attribute;
220
    }
221
}
222