GeneralNames::firstDN()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 9
ccs 6
cts 6
cp 1
rs 9.9666
c 0
b 0
f 0
nc 2
cc 2
nop 0
crap 2
1
<?php
2
3
declare(strict_types = 1);
4
5
namespace X509\GeneralName;
6
7
use ASN1\Type\UnspecifiedType;
8
use ASN1\Type\Constructed\Sequence;
9
use X501\ASN1\Name;
10
11
/**
12
 * Implements <i>GeneralNames</i> ASN.1 type.
13
 *
14
 * Provides convenience methods to retrieve the first value of commonly used
15
 * CHOICE types.
16
 *
17
 * @link https://tools.ietf.org/html/rfc5280#section-4.2.1.6
18
 */
19
class GeneralNames implements \Countable, \IteratorAggregate
20
{
21
    /**
22
     * GeneralName objects.
23
     *
24
     * @var GeneralName[] $_names
25
     */
26
    protected $_names;
27
    
28
    /**
29
     * Constructor.
30
     *
31
     * @param GeneralName ...$names One or more GeneralName objects
32
     */
33 66
    public function __construct(GeneralName ...$names)
34
    {
35 66
        $this->_names = $names;
36 66
    }
37
    
38
    /**
39
     * Initialize from ASN.1.
40
     *
41
     * @param Sequence $seq
42
     * @throws \UnexpectedValueException
43
     * @return self
44
     */
45 36
    public static function fromASN1(Sequence $seq): GeneralNames
46
    {
47 36
        if (!count($seq)) {
48 1
            throw new \UnexpectedValueException(
49 1
                "GeneralNames must have at least one GeneralName.");
50
        }
51 35
        $names = array_map(
52 35
            function (UnspecifiedType $el) {
53 35
                return GeneralName::fromASN1($el->asTagged());
54 35
            }, $seq->elements());
55 35
        return new self(...$names);
56
    }
57
    
58
    /**
59
     * Find first GeneralName by given tag.
60
     *
61
     * @param int $tag
62
     * @return GeneralName|null
63
     */
64 56
    protected function _findFirst(int $tag)
65
    {
66 56
        foreach ($this->_names as $name) {
67 56
            if ($name->tag() == $tag) {
68 56
                return $name;
69
            }
70
        }
71 2
        return null;
72
    }
73
    
74
    /**
75
     * Check whether GeneralNames contains a GeneralName of given type.
76
     *
77
     * @param int $tag One of <code>GeneralName::TAG_*</code> enumerations
78
     * @return bool
79
     */
80 2
    public function has(int $tag): bool
81
    {
82 2
        return null !== $this->_findFirst($tag);
83
    }
84
    
85
    /**
86
     * Get first GeneralName of given type.
87
     *
88
     * @param int $tag One of <code>GeneralName::TAG_*</code> enumerations
89
     * @throws \OutOfBoundsException
90
     * @return GeneralName
91
     */
92 54
    public function firstOf(int $tag): GeneralName
93
    {
94 54
        $name = $this->_findFirst($tag);
95 54
        if (!$name) {
96 1
            throw new \UnexpectedValueException("No GeneralName by tag $tag.");
97
        }
98 53
        return $name;
99
    }
100
    
101
    /**
102
     * Get all GeneralName objects of given type.
103
     *
104
     * @param int $tag One of <code>GeneralName::TAG_*</code> enumerations
105
     * @return GeneralName[]
106
     */
107 4
    public function allOf(int $tag): array
108
    {
109 4
        $names = array_filter($this->_names,
110 4
            function (GeneralName $name) use ($tag) {
111 4
                return $name->tag() == $tag;
112 4
            });
113 4
        return array_values($names);
114
    }
115
    
116
    /**
117
     * Get value of the first 'dNSName' type.
118
     *
119
     * @return string
120
     */
121 2
    public function firstDNS(): string
122
    {
123 2
        $gn = $this->firstOf(GeneralName::TAG_DNS_NAME);
124 2
        if (!$gn instanceof DNSName) {
125 1
            throw new \RuntimeException(
126 1
                DNSName::class . " expected, got " . get_class($gn));
127
        }
128 1
        return $gn->name();
129
    }
130
    
131
    /**
132
     * Get value of the first 'directoryName' type.
133
     *
134
     * @return Name
135
     */
136 37
    public function firstDN(): Name
137
    {
138 37
        $gn = $this->firstOf(GeneralName::TAG_DIRECTORY_NAME);
139 37
        if (!$gn instanceof DirectoryName) {
140 1
            throw new \RuntimeException(
141 1
                DirectoryName::class . " expected, got " . get_class($gn));
142
        }
143 36
        return $gn->dn();
144
    }
145
    
146
    /**
147
     * Get value of the first 'uniformResourceIdentifier' type.
148
     *
149
     * @return string
150
     */
151 3
    public function firstURI(): string
152
    {
153 3
        $gn = $this->firstOf(GeneralName::TAG_URI);
154 3
        if (!$gn instanceof UniformResourceIdentifier) {
155 1
            throw new \RuntimeException(
156
                UniformResourceIdentifier::class . " expected, got " .
157 1
                     get_class($gn));
158
        }
159 2
        return $gn->uri();
160
    }
161
    
162
    /**
163
     * Generate ASN.1 structure.
164
     *
165
     * @return Sequence
166
     */
167 53
    public function toASN1(): Sequence
168
    {
169 53
        if (!count($this->_names)) {
170 1
            throw new \LogicException(
171 1
                "GeneralNames must have at least one GeneralName.");
172
        }
173 52
        $elements = array_map(
174 52
            function (GeneralName $name) {
175 52
                return $name->toASN1();
176 52
            }, $this->_names);
177 52
        return new Sequence(...$elements);
178
    }
179
    
180
    /**
181
     *
182
     * @see \Countable::count()
183
     * @return int
184
     */
185 1
    public function count(): int
186
    {
187 1
        return count($this->_names);
188
    }
189
    
190
    /**
191
     * Get iterator for GeneralName objects.
192
     *
193
     * @see \IteratorAggregate::getIterator()
194
     * @return \ArrayIterator
195
     */
196 1
    public function getIterator(): \ArrayIterator
197
    {
198 1
        return new \ArrayIterator($this->_names);
199
    }
200
}
201