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\Response; 13 14use FreeDSx\Asn1\Asn1; 15use FreeDSx\Asn1\Type\AbstractType; 16use FreeDSx\Asn1\Type\OctetStringType; 17use FreeDSx\Asn1\Type\SequenceType; 18use FreeDSx\Ldap\Entry\Attribute; 19use FreeDSx\Ldap\Entry\Dn; 20use FreeDSx\Ldap\Entry\Entry; 21use FreeDSx\Ldap\Exception\ProtocolException; 22 23/** 24 * A search result entry. RFC 4511, 4.5.2. 25 * 26 * SearchResultEntry ::= [APPLICATION 4] SEQUENCE { 27 * objectName LDAPDN, 28 * attributes PartialAttributeList } 29 * 30 * PartialAttributeList ::= SEQUENCE OF 31 * partialAttribute PartialAttribute 32 * 33 * @author Chad Sikorra <Chad.Sikorra@gmail.com> 34 */ 35class SearchResultEntry implements ResponseInterface 36{ 37 protected const TAG_NUMBER = 4; 38 39 /** 40 * @var Entry 41 */ 42 protected $entry; 43 44 /** 45 * @param Entry $entry 46 */ 47 public function __construct(Entry $entry) 48 { 49 $this->entry = $entry; 50 } 51 52 /** 53 * @return Entry 54 */ 55 public function getEntry(): Entry 56 { 57 return $this->entry; 58 } 59 60 /** 61 * {@inheritDoc} 62 * @return self 63 */ 64 public static function fromAsn1(AbstractType $type) 65 { 66 $attributes = []; 67 $dn = $type->getChild(0); 68 if ($dn === null) { 69 throw new ProtocolException('The search result entry is malformed.'); 70 } 71 72 $partialAttributes = $type->getChild(1); 73 if ($partialAttributes !== null) { 74 foreach ($partialAttributes as $partialAttribute) { 75 $values = []; 76 /** @var SequenceType|null $attrValues */ 77 $attrValues = $partialAttribute->getChild(1); 78 if ($attrValues !== null) { 79 foreach ($attrValues->getChildren() as $attrValue) { 80 /** @var OctetStringType $attrValue */ 81 $values[] = $attrValue->getValue(); 82 } 83 } 84 85 $attributes[] = new Attribute($partialAttribute->getChild(0)->getValue(), ...$values); 86 } 87 } 88 89 return new self(new Entry( 90 new Dn($dn->getValue()), 91 ...$attributes 92 )); 93 } 94 95 /** 96 * @return SequenceType 97 */ 98 public function toAsn1(): AbstractType 99 { 100 /** @var SequenceType $asn1 */ 101 $asn1 = Asn1::application(self::TAG_NUMBER, Asn1::sequence()); 102 103 $partialAttributes = Asn1::sequenceOf(); 104 foreach ($this->entry->getAttributes() as $attribute) { 105 $partialAttributes->addChild(Asn1::sequence( 106 Asn1::octetString($attribute->getDescription()), 107 Asn1::setOf(...array_map(function ($v) { 108 return Asn1::octetString($v); 109 }, $attribute->getValues())) 110 )); 111 } 112 $asn1->addChild(Asn1::octetString($this->entry->getDn()->toString())); 113 $asn1->addChild($partialAttributes); 114 115 return $asn1; 116 } 117} 118