xref: /plugin/pureldap/vendor/freedsx/ldap/src/FreeDSx/Ldap/Entry/Dn.php (revision a1fd61bad19af47d542046b33c29833512eb7d62)
1<?php
2/**
3 * This file is part of the FreeDSx LDAP package.
4 *
5 * (c) Chad Sikorra <Chad.Sikorra@gmail.com>
6 *
7 * For the full copyright and license information, please view the LICENSE
8 * file that was distributed with this source code.
9 */
10
11namespace FreeDSx\Ldap\Entry;
12
13use FreeDSx\Ldap\Exception\InvalidArgumentException;
14use FreeDSx\Ldap\Exception\UnexpectedValueException;
15
16/**
17 * Represents a Distinguished Name.
18 *
19 * @author Chad Sikorra <Chad.Sikorra@gmail.com>
20 */
21class Dn implements \IteratorAggregate, \Countable
22{
23    /**
24     * @var string
25     */
26    protected $dn;
27
28    /**
29     * @var null|Rdn[]
30     */
31    protected $pieces;
32
33    /**
34     * @param string $dn
35     */
36    public function __construct(string $dn)
37    {
38        $this->dn = $dn;
39    }
40
41    /**
42     * @return Rdn
43     */
44    public function getRdn(): Rdn
45    {
46        if ($this->pieces === null) {
47            $this->parse();
48        }
49        if (!isset($this->pieces[0])) {
50            throw new UnexpectedValueException('The DN has no RDN.');
51        }
52
53        return $this->pieces[0];
54    }
55
56    /**
57     * @return null|Dn
58     */
59    public function getParent(): ?Dn
60    {
61        if ($this->pieces === null) {
62            $this->parse();
63        }
64        if (\count((array) $this->pieces) < 2) {
65            return null;
66        }
67
68        return new Dn(\implode(',', \array_slice((array) $this->pieces, 1)));
69    }
70
71    /**
72     * @return \ArrayIterator
73     */
74    public function getIterator()
75    {
76        return new \ArrayIterator($this->toArray());
77    }
78
79    /**
80     * @return string
81     */
82    public function toString(): string
83    {
84        return $this->dn;
85    }
86
87    /**
88     * @return int
89     */
90    public function count()
91    {
92        if ($this->pieces === null) {
93            $this->parse();
94        }
95
96        return \count((array) $this->pieces);
97    }
98
99    /**
100     * @return string
101     */
102    public function __toString()
103    {
104        return $this->dn;
105    }
106
107    /**
108     * @return Rdn[]
109     */
110    public function toArray(): array
111    {
112        if ($this->pieces !== null) {
113            return $this->pieces;
114        }
115        $this->parse();
116
117        return ($this->pieces === null) ? [] : $this->pieces;
118    }
119
120    /**
121     * @param string $dn
122     * @return bool
123     */
124    public static function isValid(string $dn): bool
125    {
126        try {
127            (new self($dn))->toArray();
128
129            return true;
130        } catch (UnexpectedValueException | InvalidArgumentException $e) {
131            return false;
132        }
133    }
134
135    /**
136     * @todo This needs proper handling. But the regex would probably be rather crazy.
137     */
138    protected function parse(): void
139    {
140        if ($this->dn === '') {
141            $this->pieces = [];
142
143            return;
144        }
145        $pieces = \preg_split('/(?<!\\\\),/', $this->dn);
146        $pieces = ($pieces === false) ? [] : $pieces;
147
148        if (\count($pieces) === 0) {
149            throw new UnexpectedValueException(sprintf(
150                'The DN value "%s" is not valid.',
151                $this->dn
152            ));
153        }
154
155        $rdns = [];
156        foreach ($pieces as $i => $piece) {
157            $rdns[$i] = Rdn::create(\ltrim($piece));
158        }
159
160        $this->pieces = $rdns;
161    }
162}
163