xref: /plugin/pureldap/vendor/freedsx/ldap/src/FreeDSx/Ldap/Entry/Dn.php (revision dad993c57a70866aa1db59c43f043769c2eb7ed0)
10b3fd2d3SAndreas Gohr<?php
2*dad993c5SAndreas Gohr
30b3fd2d3SAndreas Gohr/**
40b3fd2d3SAndreas Gohr * This file is part of the FreeDSx LDAP package.
50b3fd2d3SAndreas Gohr *
60b3fd2d3SAndreas Gohr * (c) Chad Sikorra <Chad.Sikorra@gmail.com>
70b3fd2d3SAndreas Gohr *
80b3fd2d3SAndreas Gohr * For the full copyright and license information, please view the LICENSE
90b3fd2d3SAndreas Gohr * file that was distributed with this source code.
100b3fd2d3SAndreas Gohr */
110b3fd2d3SAndreas Gohr
120b3fd2d3SAndreas Gohrnamespace FreeDSx\Ldap\Entry;
130b3fd2d3SAndreas Gohr
14*dad993c5SAndreas Gohruse ArrayIterator;
15*dad993c5SAndreas Gohruse Countable;
160b3fd2d3SAndreas Gohruse FreeDSx\Ldap\Exception\InvalidArgumentException;
170b3fd2d3SAndreas Gohruse FreeDSx\Ldap\Exception\UnexpectedValueException;
18*dad993c5SAndreas Gohruse IteratorAggregate;
19*dad993c5SAndreas Gohruse Traversable;
20*dad993c5SAndreas Gohruse function array_slice;
21*dad993c5SAndreas Gohruse function count;
22*dad993c5SAndreas Gohruse function implode;
23*dad993c5SAndreas Gohruse function ltrim;
24*dad993c5SAndreas Gohruse function preg_split;
250b3fd2d3SAndreas Gohr
260b3fd2d3SAndreas Gohr/**
270b3fd2d3SAndreas Gohr * Represents a Distinguished Name.
280b3fd2d3SAndreas Gohr *
290b3fd2d3SAndreas Gohr * @author Chad Sikorra <Chad.Sikorra@gmail.com>
300b3fd2d3SAndreas Gohr */
31*dad993c5SAndreas Gohrclass Dn implements IteratorAggregate, Countable
320b3fd2d3SAndreas Gohr{
330b3fd2d3SAndreas Gohr    /**
340b3fd2d3SAndreas Gohr     * @var string
350b3fd2d3SAndreas Gohr     */
360b3fd2d3SAndreas Gohr    protected $dn;
370b3fd2d3SAndreas Gohr
380b3fd2d3SAndreas Gohr    /**
390b3fd2d3SAndreas Gohr     * @var null|Rdn[]
400b3fd2d3SAndreas Gohr     */
410b3fd2d3SAndreas Gohr    protected $pieces;
420b3fd2d3SAndreas Gohr
430b3fd2d3SAndreas Gohr    /**
440b3fd2d3SAndreas Gohr     * @param string $dn
450b3fd2d3SAndreas Gohr     */
460b3fd2d3SAndreas Gohr    public function __construct(string $dn)
470b3fd2d3SAndreas Gohr    {
480b3fd2d3SAndreas Gohr        $this->dn = $dn;
490b3fd2d3SAndreas Gohr    }
500b3fd2d3SAndreas Gohr
510b3fd2d3SAndreas Gohr    /**
520b3fd2d3SAndreas Gohr     * @return Rdn
53*dad993c5SAndreas Gohr     * @throws UnexpectedValueException
540b3fd2d3SAndreas Gohr     */
550b3fd2d3SAndreas Gohr    public function getRdn(): Rdn
560b3fd2d3SAndreas Gohr    {
570b3fd2d3SAndreas Gohr        if ($this->pieces === null) {
580b3fd2d3SAndreas Gohr            $this->parse();
590b3fd2d3SAndreas Gohr        }
600b3fd2d3SAndreas Gohr        if (!isset($this->pieces[0])) {
610b3fd2d3SAndreas Gohr            throw new UnexpectedValueException('The DN has no RDN.');
620b3fd2d3SAndreas Gohr        }
630b3fd2d3SAndreas Gohr
640b3fd2d3SAndreas Gohr        return $this->pieces[0];
650b3fd2d3SAndreas Gohr    }
660b3fd2d3SAndreas Gohr
670b3fd2d3SAndreas Gohr    /**
680b3fd2d3SAndreas Gohr     * @return null|Dn
69*dad993c5SAndreas Gohr     * @throws UnexpectedValueException
700b3fd2d3SAndreas Gohr     */
710b3fd2d3SAndreas Gohr    public function getParent(): ?Dn
720b3fd2d3SAndreas Gohr    {
730b3fd2d3SAndreas Gohr        if ($this->pieces === null) {
740b3fd2d3SAndreas Gohr            $this->parse();
750b3fd2d3SAndreas Gohr        }
76*dad993c5SAndreas Gohr        if (count((array) $this->pieces) < 2) {
770b3fd2d3SAndreas Gohr            return null;
780b3fd2d3SAndreas Gohr        }
790b3fd2d3SAndreas Gohr
80*dad993c5SAndreas Gohr        return new Dn(implode(',', array_slice((array) $this->pieces, 1)));
810b3fd2d3SAndreas Gohr    }
820b3fd2d3SAndreas Gohr
830b3fd2d3SAndreas Gohr    /**
84*dad993c5SAndreas Gohr     * @inheritDoc
85*dad993c5SAndreas Gohr     * @@psalm-return \ArrayIterator<array-key, Rdn>
86*dad993c5SAndreas Gohr     * @throws UnexpectedValueException
870b3fd2d3SAndreas Gohr     */
88*dad993c5SAndreas Gohr    public function getIterator(): Traversable
890b3fd2d3SAndreas Gohr    {
90*dad993c5SAndreas Gohr        return new ArrayIterator($this->toArray());
910b3fd2d3SAndreas Gohr    }
920b3fd2d3SAndreas Gohr
930b3fd2d3SAndreas Gohr    /**
940b3fd2d3SAndreas Gohr     * @return string
950b3fd2d3SAndreas Gohr     */
960b3fd2d3SAndreas Gohr    public function toString(): string
970b3fd2d3SAndreas Gohr    {
980b3fd2d3SAndreas Gohr        return $this->dn;
990b3fd2d3SAndreas Gohr    }
1000b3fd2d3SAndreas Gohr
1010b3fd2d3SAndreas Gohr    /**
102*dad993c5SAndreas Gohr     * @inheritDoc
103*dad993c5SAndreas Gohr     * @psalm-return 0|positive-int
104*dad993c5SAndreas Gohr     * @throws UnexpectedValueException
1050b3fd2d3SAndreas Gohr     */
106*dad993c5SAndreas Gohr    public function count(): int
1070b3fd2d3SAndreas Gohr    {
1080b3fd2d3SAndreas Gohr        if ($this->pieces === null) {
1090b3fd2d3SAndreas Gohr            $this->parse();
1100b3fd2d3SAndreas Gohr        }
1110b3fd2d3SAndreas Gohr
112*dad993c5SAndreas Gohr        return count((array) $this->pieces);
1130b3fd2d3SAndreas Gohr    }
1140b3fd2d3SAndreas Gohr
1150b3fd2d3SAndreas Gohr    /**
1160b3fd2d3SAndreas Gohr     * @return string
1170b3fd2d3SAndreas Gohr     */
1180b3fd2d3SAndreas Gohr    public function __toString()
1190b3fd2d3SAndreas Gohr    {
1200b3fd2d3SAndreas Gohr        return $this->dn;
1210b3fd2d3SAndreas Gohr    }
1220b3fd2d3SAndreas Gohr
1230b3fd2d3SAndreas Gohr    /**
1240b3fd2d3SAndreas Gohr     * @return Rdn[]
125*dad993c5SAndreas Gohr     * @throws UnexpectedValueException
1260b3fd2d3SAndreas Gohr     */
1270b3fd2d3SAndreas Gohr    public function toArray(): array
1280b3fd2d3SAndreas Gohr    {
1290b3fd2d3SAndreas Gohr        if ($this->pieces !== null) {
1300b3fd2d3SAndreas Gohr            return $this->pieces;
1310b3fd2d3SAndreas Gohr        }
1320b3fd2d3SAndreas Gohr        $this->parse();
1330b3fd2d3SAndreas Gohr
1340b3fd2d3SAndreas Gohr        return ($this->pieces === null) ? [] : $this->pieces;
1350b3fd2d3SAndreas Gohr    }
1360b3fd2d3SAndreas Gohr
1370b3fd2d3SAndreas Gohr    /**
1380b3fd2d3SAndreas Gohr     * @param string $dn
1390b3fd2d3SAndreas Gohr     * @return bool
1400b3fd2d3SAndreas Gohr     */
1410b3fd2d3SAndreas Gohr    public static function isValid(string $dn): bool
1420b3fd2d3SAndreas Gohr    {
1430b3fd2d3SAndreas Gohr        try {
1440b3fd2d3SAndreas Gohr            (new self($dn))->toArray();
1450b3fd2d3SAndreas Gohr
1460b3fd2d3SAndreas Gohr            return true;
1470b3fd2d3SAndreas Gohr        } catch (UnexpectedValueException | InvalidArgumentException $e) {
1480b3fd2d3SAndreas Gohr            return false;
1490b3fd2d3SAndreas Gohr        }
1500b3fd2d3SAndreas Gohr    }
1510b3fd2d3SAndreas Gohr
1520b3fd2d3SAndreas Gohr    /**
1530b3fd2d3SAndreas Gohr     * @todo This needs proper handling. But the regex would probably be rather crazy.
154*dad993c5SAndreas Gohr     *
155*dad993c5SAndreas Gohr     * @throws UnexpectedValueException
1560b3fd2d3SAndreas Gohr     */
1570b3fd2d3SAndreas Gohr    protected function parse(): void
1580b3fd2d3SAndreas Gohr    {
1590b3fd2d3SAndreas Gohr        if ($this->dn === '') {
1600b3fd2d3SAndreas Gohr            $this->pieces = [];
1610b3fd2d3SAndreas Gohr
1620b3fd2d3SAndreas Gohr            return;
1630b3fd2d3SAndreas Gohr        }
164*dad993c5SAndreas Gohr        $pieces = preg_split('/(?<!\\\\),/', $this->dn);
1650b3fd2d3SAndreas Gohr        $pieces = ($pieces === false) ? [] : $pieces;
1660b3fd2d3SAndreas Gohr
167*dad993c5SAndreas Gohr        if (count($pieces) === 0) {
1680b3fd2d3SAndreas Gohr            throw new UnexpectedValueException(sprintf(
1690b3fd2d3SAndreas Gohr                'The DN value "%s" is not valid.',
1700b3fd2d3SAndreas Gohr                $this->dn
1710b3fd2d3SAndreas Gohr            ));
1720b3fd2d3SAndreas Gohr        }
1730b3fd2d3SAndreas Gohr
1740b3fd2d3SAndreas Gohr        $rdns = [];
1750b3fd2d3SAndreas Gohr        foreach ($pieces as $i => $piece) {
176*dad993c5SAndreas Gohr            $rdns[$i] = Rdn::create(ltrim($piece));
1770b3fd2d3SAndreas Gohr        }
1780b3fd2d3SAndreas Gohr
1790b3fd2d3SAndreas Gohr        $this->pieces = $rdns;
1800b3fd2d3SAndreas Gohr    }
1810b3fd2d3SAndreas Gohr}
182