Completed
Push — master ( 1362fd...ca1b11 )
by Joni
09:41
created

RDN::first()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
3
namespace X501\ASN1;
4
5
use ASN1\Type\Constructed\Set;
6
use ASN1\Type\UnspecifiedType;
7
use X501\ASN1\AttributeValue\AttributeValue;
8
9
10
/**
11
 * Implements <i>RelativeDistinguishedName</i> ASN.1 type.
12
 *
13
 * @link
14
 *       https://www.itu.int/ITU-T/formal-language/itu-t/x/x501/2012/InformationFramework.html#InformationFramework.RelativeDistinguishedName
15
 */
16
class RDN implements \Countable, \IteratorAggregate
17
{
18
	/**
19
	 * Attributes.
20
	 *
21
	 * @var AttributeTypeAndValue[] $_attribs
22
	 */
23
	protected $_attribs;
24
	
25
	/**
26
	 * Constructor
27
	 *
28
	 * @param AttributeTypeAndValue ...$attribs One or more attributes
29
	 */
30 39
	public function __construct(AttributeTypeAndValue ...$attribs) {
31 39
		if (!count($attribs)) {
32 1
			throw new \UnexpectedValueException(
33 1
				"RDN must have at least one AttributeTypeAndValue.");
34
		}
35 38
		$this->_attribs = $attribs;
36 38
	}
37
	
38
	/**
39
	 * Convenience method to initialize RDN from AttributeValue objects.
40
	 *
41
	 * @param AttributeValue ...$values One or more attributes
42
	 * @return self
43
	 */
44 1
	public static function fromAttributeValues(AttributeValue ...$values) {
45 1
		$attribs = array_map(
46
			function (AttributeValue $value) {
47 1
				return new AttributeTypeAndValue(
48 1
					new AttributeType($value->oid()), $value);
49 1
			}, $values);
50 1
		return new self(...$attribs);
51
	}
52
	
53
	/**
54
	 * Initialize from ASN.1.
55
	 *
56
	 * @param Set $set
57
	 * @return self
58
	 */
59 4
	public static function fromASN1(Set $set) {
60 4
		$attribs = array_map(
61
			function (UnspecifiedType $el) {
62 4
				return AttributeTypeAndValue::fromASN1($el->asSequence());
63 4
			}, $set->elements());
64 4
		return new self(...$attribs);
65
	}
66
	
67
	/**
68
	 * Generate ASN.1 structure.
69
	 *
70
	 * @return Set
71
	 */
72 4
	public function toASN1() {
73 4
		$elements = array_map(
74
			function (AttributeTypeAndValue $tv) {
75 4
				return $tv->toASN1();
76 4
			}, $this->_attribs);
77 4
		$set = new Set(...$elements);
78 4
		return $set->sortedSetOf();
79
	}
80
	
81
	/**
82
	 * Get name-component string conforming to RFC 2253.
83
	 *
84
	 * @link https://tools.ietf.org/html/rfc2253#section-2.2
85
	 * @return string
86
	 */
87 15
	public function toString() {
88 15
		$parts = array_map(
89 15
			function (AttributeTypeAndValue $tv) {
90 15
				return $tv->toString();
91 15
			}, $this->_attribs);
92 15
		return implode("+", $parts);
93
	}
94
	
95
	/**
96
	 * Check whether RDN is semantically equal to other.
97
	 *
98
	 * @param RDN $other Object to compare to
99
	 * @return bool
100
	 */
101 22
	public function equals(RDN $other) {
102
		// if attribute count doesn't match
103 22
		if (count($this) != count($other)) {
104 1
			return false;
105
		}
106 21
		$attribs1 = $this->_attribs;
107 21
		$attribs2 = $other->_attribs;
108
		// if there's multiple attributes, sort using SET OF rules
109 21
		if (count($attribs1) > 1) {
110 2
			$attribs1 = self::fromASN1($this->toASN1())->_attribs;
111 2
			$attribs2 = self::fromASN1($other->toASN1())->_attribs;
112 2
		}
113 21
		for ($i = count($attribs1) - 1; $i >= 0; --$i) {
114 21
			$tv1 = $attribs1[$i];
115 21
			$tv2 = $attribs2[$i];
116 21
			if (!$tv1->equals($tv2)) {
117 8
				return false;
118
			}
119 16
		}
120 16
		return true;
121
	}
122
	
123
	/**
124
	 * Get all AttributeTypeAndValue objects.
125
	 *
126
	 * @return AttributeTypeAndValue[]
127
	 */
128 1
	public function all() {
129 1
		return $this->_attribs;
130
	}
131
	
132
	/**
133
	 * Get the first AttributeTypeAndValue object in RDN.
134
	 *
135
	 * @return AttributeTypeAndValue
136
	 */
137 1
	public function first() {
138 1
		return $this->_attribs[0];
139
	}
140
	
141
	/**
142
	 * Find the first AttributeTypeAndValue object of given OID.
143
	 *
144
	 * @param string $oid Object identifier in dotted format
145
	 * @return AttributeTypeAndValue|null Null if not found
146
	 */
147 4
	protected function _findFirstOf($oid) {
148 4
		foreach ($this->_attribs as $attr) {
149 4
			if ($attr->oid() == $oid) {
150 2
				return $attr;
151
			}
152 2
		}
153 2
		return null;
154
	}
155
	
156
	/**
157
	 * Check whether RDN has an attribute of given type.
158
	 *
159
	 * @param string $name Attribute name or OID
160
	 * @return boolean
161
	 */
162 2
	public function has($name) {
163 2
		$oid = AttributeType::attrNameToOID($name);
164 2
		return null !== $this->_findFirstOf($oid);
165
	}
166
	
167
	/**
168
	 * Get the first AttributeTypeAndValue object of given attribute type.
169
	 *
170
	 * @param string $name Attribute name or OID
171
	 * @throws \LogicException If attribute doesn't exists
172
	 * @return AttributeTypeAndValue
173
	 */
174 2
	public function firstOf($name) {
175 2
		$oid = AttributeType::attrNameToOID($name);
176 2
		$tv = $this->_findFirstOf($oid);
177 2
		if (null === $tv) {
178 1
			throw new \LogicException("No '$name' attribute.");
179
		}
180 1
		return $tv;
181
	}
182
	
183
	/**
184
	 *
185
	 * @see Countable::count()
186
	 * @return int
187
	 */
188 23
	public function count() {
189 23
		return count($this->_attribs);
190
	}
191
	
192
	/**
193
	 *
194
	 * @see IteratorAggregate::getIterator()
195
	 * @return \ArrayIterator
196
	 */
197 1
	public function getIterator() {
198 1
		return new \ArrayIterator($this->_attribs);
199
	}
200
	
201
	/**
202
	 *
203
	 * @return string
204
	 */
205 1
	public function __toString() {
206 1
		return $this->toString();
207
	}
208
}
209