1<?php 2 3/** 4 * This file is part of the FreeDSx LDAP package. 5 * 6 * (c) Chad Sikorra <Chad.Sikorra@gmail.com> 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12namespace FreeDSx\Ldap\Operation\Request; 13 14use FreeDSx\Asn1\Asn1; 15use FreeDSx\Asn1\Type\AbstractType; 16use FreeDSx\Asn1\Type\OctetStringType; 17use FreeDSx\Asn1\Type\SequenceType; 18use FreeDSx\Asn1\Type\SetType; 19use FreeDSx\Ldap\Entry\Attribute; 20use FreeDSx\Ldap\Entry\Dn; 21use FreeDSx\Ldap\Entry\Entry; 22use FreeDSx\Ldap\Exception\ProtocolException; 23use function array_map; 24use function count; 25 26/** 27 * A request to add an entry to LDAP. RFC 4511, 4.7. 28 * 29 * AddRequest ::= [APPLICATION 8] SEQUENCE { 30 * entry LDAPDN, 31 * attributes AttributeList } 32 * 33 * AttributeList ::= SEQUENCE OF attribute Attribute 34 * 35 * PartialAttribute ::= SEQUENCE { 36 * type AttributeDescription, 37 * vals SET OF value AttributeValue } 38 * 39 * Attribute ::= PartialAttribute(WITH COMPONENTS { 40 * ..., 41 * vals (SIZE(1..MAX))}) 42 * 43 * AttributeDescription ::= LDAPString 44 * 45 * AttributeValue ::= OCTET STRING 46 * 47 * @author Chad Sikorra <Chad.Sikorra@gmail.com> 48 */ 49class AddRequest implements RequestInterface 50{ 51 protected const APP_TAG = 8; 52 53 /** 54 * @var Entry 55 */ 56 protected $entry; 57 58 /** 59 * @param Entry $entry 60 */ 61 public function __construct(Entry $entry) 62 { 63 $this->entry = $entry; 64 } 65 66 /** 67 * @return Entry 68 */ 69 public function getEntry(): Entry 70 { 71 return $this->entry; 72 } 73 74 /** 75 * @param Entry $entry 76 * @return $this 77 */ 78 public function setEntry(Entry $entry) 79 { 80 $this->entry = $entry; 81 82 return $this; 83 } 84 85 /** 86 * {@inheritDoc} 87 * @return self 88 */ 89 public static function fromAsn1(AbstractType $type) 90 { 91 if (!($type instanceof SequenceType && count($type) === 2)) { 92 throw new ProtocolException('The add request is malformed: %s'); 93 } 94 95 $dn = $type->getChild(0); 96 $attrList = $type->getChild(1); 97 if (!($dn instanceof OctetStringType && $attrList instanceof SequenceType)) { 98 throw new ProtocolException('The add request is malformed.'); 99 } 100 $dn = new Dn($dn->getValue()); 101 102 $attributes = []; 103 foreach ($attrList->getChildren() as $attrListing) { 104 if (!($attrListing instanceof SequenceType && count($attrListing->getChildren()) == 2)) { 105 throw new ProtocolException(sprintf( 106 'Expected a sequence type, but received: %s', 107 get_class($attrListing) 108 )); 109 } 110 111 $attrType = $attrListing->getChild(0); 112 $vals = $attrListing->getChild(1); 113 if (!($attrType instanceof OctetStringType && $vals instanceof SetType)) { 114 throw new ProtocolException('The add request is malformed.'); 115 } 116 117 $attrValues = []; 118 foreach ($vals->getChildren() as $val) { 119 if (!$val instanceof OctetStringType) { 120 throw new ProtocolException('The add request is malformed.'); 121 } 122 $attrValues[] = $val->getValue(); 123 } 124 125 $attributes[] = new Attribute($attrType->getValue(), ...$attrValues); 126 } 127 128 return new self(new Entry($dn, ...$attributes)); 129 } 130 131 /** 132 * {@inheritdoc} 133 */ 134 public function toAsn1(): AbstractType 135 { 136 $attributeList = Asn1::sequenceOf(); 137 138 /** @var Attribute $attribute */ 139 foreach ($this->entry->getAttributes() as $attribute) { 140 $attr = Asn1::sequence(Asn1::octetString($attribute->getDescription())); 141 142 $attrValues = Asn1::setOf(...array_map(function ($value) { 143 return Asn1::octetString($value); 144 }, $attribute->getValues())); 145 146 $attributeList->addChild($attr->addChild($attrValues)); 147 } 148 149 return Asn1::application(self::APP_TAG, Asn1::sequence( 150 Asn1::octetString($this->entry->getDn()->toString()), 151 $attributeList 152 )); 153 } 154} 155