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