* * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FreeDSx\Ldap\Operation\Request; use FreeDSx\Asn1\Asn1; use FreeDSx\Asn1\Type\AbstractType; use FreeDSx\Asn1\Type\BooleanType; use FreeDSx\Asn1\Type\IncompleteType; use FreeDSx\Asn1\Type\OctetStringType; use FreeDSx\Asn1\Type\SequenceType; use FreeDSx\Ldap\Entry\Dn; use FreeDSx\Ldap\Entry\Rdn; use FreeDSx\Ldap\Exception\ProtocolException; use FreeDSx\Ldap\Protocol\LdapEncoder; use function count; /** * A Modify DN Request. RFC 4511, 4.9 * * ModifyDNRequest ::= [APPLICATION 12] SEQUENCE { * entry LDAPDN, * newrdn RelativeLDAPDN, * deleteoldrdn BOOLEAN, * newSuperior [0] LDAPDN OPTIONAL } * * @author Chad Sikorra */ class ModifyDnRequest implements RequestInterface, DnRequestInterface { protected const APP_TAG = 12; /** * @var Dn */ protected $dn; /** * @var Rdn */ protected $newRdn; /** * @var bool */ protected $deleteOldRdn; /** * @var null|Dn */ protected $newParentDn; /** * @param string|Dn $dn * @param string|Rdn $newRdn * @param bool $deleteOldRdn * @param null|string|Dn $newParentDn */ public function __construct($dn, $newRdn, bool $deleteOldRdn, $newParentDn = null) { $this->setDn($dn); $this->setNewRdn($newRdn); $this->setNewParentDn($newParentDn); $this->deleteOldRdn = $deleteOldRdn; } /** * @return Dn */ public function getDn(): Dn { return $this->dn; } /** * @param string|Dn $dn * @return $this */ public function setDn($dn) { $this->dn = $dn instanceof Dn ? $dn : new Dn($dn); return $this; } /** * @return Rdn */ public function getNewRdn(): Rdn { return $this->newRdn; } /** * @param string|Rdn $newRdn * @return $this */ public function setNewRdn($newRdn) { $this->newRdn = $newRdn instanceof Rdn ? $newRdn : Rdn::create($newRdn); return $this; } /** * @return bool */ public function getDeleteOldRdn(): bool { return $this->deleteOldRdn; } /** * @param bool $deleteOldRdn * @return $this */ public function setDeleteOldRdn(bool $deleteOldRdn) { $this->deleteOldRdn = $deleteOldRdn; return $this; } /** * @return null|Dn */ public function getNewParentDn(): ?Dn { return $this->newParentDn; } /** * @param null|string|Dn $newParentDn * @return $this */ public function setNewParentDn($newParentDn) { if ($newParentDn !== null) { $newParentDn = $newParentDn instanceof Dn ? $newParentDn : new Dn($newParentDn); } $this->newParentDn = $newParentDn; return $this; } /** * {@inheritDoc} * @return self */ public static function fromAsn1(AbstractType $type) { if (!($type instanceof SequenceType && count($type) >= 3 && count($type) <= 4)) { throw new ProtocolException('The modify dn request is malformed'); } $entry = $type->getChild(0); $newRdn = $type->getChild(1); $deleteOldRdn = $type->getChild(2); $newSuperior = $type->getChild(3); if (!($entry instanceof OctetStringType && $newRdn instanceof OctetStringType && $deleteOldRdn instanceof BooleanType)) { throw new ProtocolException('The modify dn request is malformed'); } if ($newSuperior !== null && !($newSuperior->getTagClass() === AbstractType::TAG_CLASS_CONTEXT_SPECIFIC && $newSuperior->getTagNumber() === 0)) { throw new ProtocolException('The modify dn request is malformed'); } $newSuperior = ($newSuperior instanceof IncompleteType) ? (new LdapEncoder())->complete($newSuperior, AbstractType::TAG_TYPE_OCTET_STRING) : $newSuperior; $newSuperior = ($newSuperior !== null) ? $newSuperior->getValue() : null; return new self($entry->getValue(), $newRdn->getValue(), $deleteOldRdn->getValue(), $newSuperior); } /** * @return SequenceType */ public function toAsn1(): AbstractType { /** @var \FreeDSx\Asn1\Type\SequenceType $asn1 */ $asn1 = Asn1::application(self::APP_TAG, Asn1::sequence( Asn1::octetString($this->dn->toString()), // @todo Make a RDN type. Future validation purposes? Asn1::octetString($this->newRdn->toString()), Asn1::boolean($this->deleteOldRdn) )); if ($this->newParentDn !== null) { $asn1->addChild(Asn1::context(0, Asn1::octetString($this->newParentDn->toString()))); } return $asn1; } }