* * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FreeDSx\Ldap\Entry; use ArrayIterator; use Countable; use IteratorAggregate; use Traversable; use function count; use function is_array; /** * Represents an Entry in LDAP. * * @author Chad Sikorra */ class Entry implements IteratorAggregate, Countable { /** * @var Attribute[] */ protected $attributes; /** * @var Dn */ protected $dn; /** * @var Changes */ protected $changes; /** * @param string|Dn $dn * @param Attribute ...$attributes */ public function __construct($dn, Attribute ...$attributes) { $this->dn = $dn instanceof Dn ? $dn : new Dn($dn); $this->attributes = $attributes; $this->changes = new Changes(); } /** * Add an attribute and its values. * * @param string|Attribute $attribute * @param string ...$values * @return $this */ public function add($attribute, ...$values) { $attribute = $attribute instanceof Attribute ? $attribute : new Attribute($attribute, ...$values); if (($exists = $this->get($attribute, true)) !== null) { $exists->add(...$attribute->getValues()); } else { $this->attributes[] = $attribute; } $this->changes->add(Change::add(clone $attribute)); return $this; } /** * Remove an attribute's value(s). * * @param string|Attribute $attribute * @param mixed|string ...$values * @return $this */ public function remove($attribute, ...$values) { $attribute = $attribute instanceof Attribute ? $attribute : new Attribute($attribute, ...$values); if (count($attribute->getValues()) !== 0) { if (($exists = $this->get($attribute, true)) !== null) { $exists->remove(...$attribute->getValues()); } $this->changes->add(Change::delete(clone $attribute)); } return $this; } /** * Reset an attribute, which removes any values it may have. * * @param string|Attribute ...$attributes * @return $this */ public function reset(...$attributes) { foreach ($attributes as $attribute) { $attribute = $attribute instanceof Attribute ? $attribute : new Attribute($attribute); foreach ($this->attributes as $i => $attr) { if ($attr->equals($attribute, true)) { unset($this->attributes[$i]); break; } } $this->changes()->add(Change::reset(clone $attribute)); } return $this; } /** * Set an attribute on the entry, replacing any value(s) that may exist on it. * * @param string|Attribute $attribute * @param mixed ...$values * @return $this */ public function set($attribute, ...$values) { $attribute = $attribute instanceof Attribute ? $attribute : new Attribute($attribute, ...$values); $exists = false; foreach ($this->attributes as $i => $attr) { if ($attr->equals($attribute, true)) { $exists = true; $this->attributes[$i] = $attribute; break; } } if (!$exists) { $this->attributes[] = $attribute; } $this->changes->add(Change::replace(clone $attribute)); return $this; } /** * Get a specific attribute by name (or Attribute object). * * @param string|Attribute $attribute * @param bool $strict If set to true, then options on the attribute must also match. * @return null|Attribute */ public function get($attribute, bool $strict = false): ?Attribute { $attribute = $attribute instanceof Attribute ? $attribute : new Attribute($attribute); foreach ($this->attributes as $attr) { if ($attr->equals($attribute, $strict)) { return $attr; } } return null; } /** * Check if a specific attribute exists on the entry. * * @param string|Attribute $attribute * @param bool $strict * @return bool */ public function has($attribute, bool $strict = false): bool { $attribute = $attribute instanceof Attribute ? $attribute : new Attribute($attribute); return (bool) $this->get($attribute, $strict); } /** * @return Attribute[] */ public function getAttributes(): array { return $this->attributes; } /** * @return Dn */ public function getDn(): Dn { return $this->dn; } /** * Get the changes accumulated for this entry. * * @return Changes */ public function changes(): Changes { return $this->changes; } /** * Get the entry representation as an associative array. * * @return array */ public function toArray(): array { $attributes = []; foreach ($this->attributes as $attribute) { $attributes[$attribute->getDescription()] = $attribute->getValues(); } return $attributes; } /** * @inheritDoc * @psalm-return \ArrayIterator */ public function getIterator(): Traversable { return new ArrayIterator($this->attributes); } /** * @return int * @psalm-return 0|positive-int */ public function count(): int { return count($this->attributes); } public function __toString(): string { return $this->dn->toString(); } public function __get(string $name): ?Attribute { return $this->get($name); } /** * @param string[]|string $value */ public function __set(string $name, $value): void { $this->set($name, ...(is_array($value) ? $value : [$value])); } public function __isset(string $name): bool { return $this->has($name); } public function __unset(string $name): void { $this->reset($name); } /** * An alias of fromArray(). * * @param string $dn * @param array $attributes * @return Entry */ public static function create(string $dn, array $attributes = []): Entry { return self::fromArray($dn, $attributes); } /** * Construct an entry from an associative array. * * @param string $dn * @param array $attributes * @return Entry */ public static function fromArray(string $dn, array $attributes = []): Entry { /** @var Attribute[] $entryAttr */ $entryAttr = []; foreach ($attributes as $attribute => $value) { $entryAttr[] = new Attribute($attribute, ...(is_array($value) ? $value : [$value])); } return new self($dn, ...$entryAttr); } }