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\Operation\Request; 12 13use FreeDSx\Asn1\Asn1; 14use FreeDSx\Asn1\Type\AbstractType; 15use FreeDSx\Asn1\Type\BooleanType; 16use FreeDSx\Asn1\Type\OctetStringType; 17use FreeDSx\Asn1\Type\SequenceType; 18use FreeDSx\Ldap\Entry\Dn; 19use FreeDSx\Ldap\Entry\Rdn; 20use FreeDSx\Ldap\Exception\ProtocolException; 21 22/** 23 * A Modify DN Request. RFC 4511, 4.9 24 * 25 * ModifyDNRequest ::= [APPLICATION 12] SEQUENCE { 26 * entry LDAPDN, 27 * newrdn RelativeLDAPDN, 28 * deleteoldrdn BOOLEAN, 29 * newSuperior [0] LDAPDN OPTIONAL } 30 * 31 * @author Chad Sikorra <Chad.Sikorra@gmail.com> 32 */ 33class ModifyDnRequest implements RequestInterface, DnRequestInterface 34{ 35 protected const APP_TAG = 12; 36 37 /** 38 * @var Dn 39 */ 40 protected $dn; 41 42 /** 43 * @var Rdn 44 */ 45 protected $newRdn; 46 47 /** 48 * @var bool 49 */ 50 protected $deleteOldRdn; 51 52 /** 53 * @var null|Dn 54 */ 55 protected $newParentDn; 56 57 /** 58 * @param string|Dn $dn 59 * @param string|Rdn $newRdn 60 * @param bool $deleteOldRdn 61 * @param null|string|Dn $newParentDn 62 */ 63 public function __construct($dn, $newRdn, bool $deleteOldRdn, $newParentDn = null) 64 { 65 $this->setDn($dn); 66 $this->setNewRdn($newRdn); 67 $this->setNewParentDn($newParentDn); 68 $this->deleteOldRdn = $deleteOldRdn; 69 } 70 71 /** 72 * @return Dn 73 */ 74 public function getDn(): Dn 75 { 76 return $this->dn; 77 } 78 79 /** 80 * @param string|Dn $dn 81 * @return $this 82 */ 83 public function setDn($dn) 84 { 85 $this->dn = $dn instanceof Dn ? $dn : new Dn($dn); 86 87 return $this; 88 } 89 90 /** 91 * @return Rdn 92 */ 93 public function getNewRdn(): Rdn 94 { 95 return $this->newRdn; 96 } 97 98 /** 99 * @param string|Rdn $newRdn 100 * @return $this 101 */ 102 public function setNewRdn($newRdn) 103 { 104 $this->newRdn = $newRdn instanceof Rdn ? $newRdn : Rdn::create($newRdn); 105 106 return $this; 107 } 108 109 /** 110 * @return bool 111 */ 112 public function getDeleteOldRdn(): bool 113 { 114 return $this->deleteOldRdn; 115 } 116 117 /** 118 * @param bool $deleteOldRdn 119 * @return $this 120 */ 121 public function setDeleteOldRdn(bool $deleteOldRdn) 122 { 123 $this->deleteOldRdn = $deleteOldRdn; 124 125 return $this; 126 } 127 128 /** 129 * @return null|Dn 130 */ 131 public function getNewParentDn(): ?Dn 132 { 133 return $this->newParentDn; 134 } 135 136 /** 137 * @param null|string|Dn $newParentDn 138 * @return $this 139 */ 140 public function setNewParentDn($newParentDn) 141 { 142 if ($newParentDn !== null) { 143 $newParentDn = $newParentDn instanceof Dn ? $newParentDn : new Dn($newParentDn); 144 } 145 $this->newParentDn = $newParentDn; 146 147 return $this; 148 } 149 150 /** 151 * {@inheritdoc} 152 */ 153 public static function fromAsn1(AbstractType $type) 154 { 155 if (!($type instanceof SequenceType && \count($type) >= 3 && \count($type) <= 4)) { 156 throw new ProtocolException('The modify dn request is malformed'); 157 } 158 $entry = $type->getChild(0); 159 $newRdn = $type->getChild(1); 160 $deleteOldRdn = $type->getChild(2); 161 $newSuperior = $type->getChild(3); 162 163 if (!($entry instanceof OctetStringType && $newRdn instanceof OctetStringType && $deleteOldRdn instanceof BooleanType)) { 164 throw new ProtocolException('The modify dn request is malformed'); 165 } 166 if ($newSuperior !== null && !($newSuperior->getTagClass() === AbstractType::TAG_CLASS_CONTEXT_SPECIFIC && $newSuperior->getTagNumber() === 0)) { 167 throw new ProtocolException('The modify dn request is malformed'); 168 } 169 if ($newSuperior !== null && !$newSuperior instanceof OctetStringType) { 170 throw new ProtocolException('The modify dn request is malformed'); 171 } 172 $newSuperior = ($newSuperior !== null) ? $newSuperior->getValue() : null; 173 174 return new self($entry->getValue(), $newRdn->getValue(), $deleteOldRdn->getValue(), $newSuperior); 175 } 176 177 /** 178 * {@inheritdoc} 179 */ 180 public function toAsn1(): AbstractType 181 { 182 /** @var \FreeDSx\Asn1\Type\SequenceType $asn1 */ 183 $asn1 = Asn1::application(self::APP_TAG, Asn1::sequence( 184 Asn1::octetString($this->dn->toString()), 185 // @todo Make a RDN type. Future validation purposes? 186 Asn1::octetString($this->newRdn->toString()), 187 Asn1::boolean($this->deleteOldRdn) 188 )); 189 if ($this->newParentDn !== null) { 190 $asn1->addChild(Asn1::context(0, Asn1::octetString($this->newParentDn->toString()))); 191 } 192 193 return $asn1; 194 } 195} 196