blob: 83dfe7160da13bd2ad461aea537970436869cd5c [file] [log] [blame]
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02001<?php
2
3namespace LdapRecord\Models\Attributes;
4
5use LdapRecord\EscapesValues;
6use LdapRecord\Support\Arr;
7
8class DistinguishedNameBuilder
9{
10 use EscapesValues;
11
12 /**
13 * The components of the DN.
14 *
15 * @var array
16 */
17 protected $components = [];
18
19 /**
20 * Whether to output the DN in reverse.
21 *
22 * @var bool
23 */
24 protected $reverse = false;
25
26 /**
27 * Constructor.
28 *
29 * @param string|null $value
30 */
31 public function __construct($dn = null)
32 {
33 $this->components = array_map(function ($rdn) {
34 return DistinguishedName::explodeRdn($rdn);
35 }, DistinguishedName::make($dn)->components());
36 }
37
38 /**
39 * Forward missing method calls onto the Distinguished Name object.
40 *
41 * @param string $method
42 * @param array $args
43 *
44 * @return mixed
45 */
46 public function __call($method, $args)
47 {
48 return $this->get()->{$method}(...$args);
49 }
50
51 /**
52 * Get the distinguished name value.
53 *
54 * @return string
55 */
56 public function __toString()
57 {
58 return (string) $this->get();
59 }
60
61 /**
62 * Prepend an RDN onto the DN.
63 *
64 * @param string|array $attribute
65 * @param string|null $value
66 *
67 * @return $this
68 */
69 public function prepend($attribute, $value = null)
70 {
71 array_unshift(
72 $this->components,
73 ...$this->componentize($attribute, $value)
74 );
75
76 return $this;
77 }
78
79 /**
80 * Append an RDN onto the DN.
81 *
82 * @param string|array $attribute
83 * @param string|null $value
84 *
85 * @return $this
86 */
87 public function append($attribute, $value = null)
88 {
89 array_push(
90 $this->components,
91 ...$this->componentize($attribute, $value)
92 );
93
94 return $this;
95 }
96
97 /**
98 * Componentize the attribute and value.
99 *
100 * @param string|array $attribute
101 * @param string|null $value
102 *
103 * @return array
104 */
105 protected function componentize($attribute, $value = null)
106 {
107 // Here we will make the assumption that an array of
108 // RDN's have been given if the value is null, and
109 // attempt to break them into their components.
110 if (is_null($value)) {
111 $attributes = Arr::wrap($attribute);
112
113 $components = array_map([$this, 'makeComponentizedArray'], $attributes);
114 } else {
115 $components = [[$attribute, $value]];
116 }
117
118 return array_map(function ($component) {
119 [$attribute, $value] = $component;
120
121 return $this->makeAppendableComponent($attribute, $value);
122 }, $components);
123 }
124
125 /**
126 * Make a componentized array by exploding the value if it's a string.
127 *
128 * @param string $value
129 *
130 * @return array
131 */
132 protected function makeComponentizedArray($value)
133 {
134 return is_array($value) ? $value : DistinguishedName::explodeRdn($value);
135 }
136
137 /**
138 * Make an appendable component array from the attribute and value.
139 *
140 * @param string|array $attribute
141 * @param string|null $value
142 *
143 * @return array
144 */
145 protected function makeAppendableComponent($attribute, $value = null)
146 {
147 return [trim($attribute), $this->escape(trim($value))->dn()];
148 }
149
150 /**
151 * Pop an RDN off of the end of the DN.
152 *
153 * @param int $amount
154 * @param array $removed
155 *
156 * @return $this
157 */
158 public function pop($amount = 1, &$removed = [])
159 {
160 $removed = array_map(function ($component) {
161 return DistinguishedName::makeRdn($component);
162 }, array_splice($this->components, -$amount, $amount));
163
164 return $this;
165 }
166
167 /**
168 * Shift an RDN off of the beginning of the DN.
169 *
170 * @param int $amount
171 * @param array $removed
172 *
173 * @return $this
174 */
175 public function shift($amount = 1, &$removed = [])
176 {
177 $removed = array_map(function ($component) {
178 return DistinguishedName::makeRdn($component);
179 }, array_splice($this->components, 0, $amount));
180
181 return $this;
182 }
183
184 /**
185 * Whether to output the DN in reverse.
186 *
187 * @return $this
188 */
189 public function reverse()
190 {
191 $this->reverse = true;
192
193 return $this;
194 }
195
196 /**
197 * Get the components of the DN.
198 *
199 * @param null|string $type
200 *
201 * @return array
202 */
203 public function components($type = null)
204 {
205 return is_null($type)
206 ? $this->components
207 : $this->componentsOfType($type);
208 }
209
210 /**
211 * Get the components of a particular type.
212 *
213 * @param string $type
214 *
215 * @return array
216 */
217 protected function componentsOfType($type)
218 {
219 $components = array_filter($this->components, function ($component) use ($type) {
220 return ([$name] = $component) && strtolower($name) === strtolower($type);
221 });
222
223 return array_values($components);
224 }
225
226 /**
227 * Get the fully qualified DN.
228 *
229 * @return DistinguishedName
230 */
231 public function get()
232 {
233 return new DistinguishedName($this->build());
234 }
235
236 /**
237 * Build the distinguished name from the components.
238 *
239 * @return $this
240 */
241 protected function build()
242 {
243 $components = $this->reverse
244 ? array_reverse($this->components)
245 : $this->components;
246
247 return implode(',', array_map(function ($component) {
248 return DistinguishedName::makeRdn($component);
249 }, $components));
250 }
251}