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\Entry; 13 14use ArrayIterator; 15use Countable; 16use IteratorAggregate; 17use Traversable; 18use function count; 19use function sort; 20 21/** 22 * Represents a collection of attribute options. 23 * 24 * @author Chad Sikorra <Chad.Sikorra@gmail.com> 25 */ 26class Options implements Countable, IteratorAggregate 27{ 28 /** 29 * @var Option[] 30 */ 31 protected $options; 32 33 /** 34 * @param string|Option ...$options 35 */ 36 public function __construct(...$options) 37 { 38 $this->set(...$options); 39 } 40 41 /** 42 * @param string|Option ...$options 43 * @return $this 44 */ 45 public function add(...$options) 46 { 47 foreach ($options as $option) { 48 $this->options[] = $option instanceof Option ? $option : new Option($option); 49 } 50 51 return $this; 52 } 53 54 /** 55 * @param string|Option ...$options 56 * @return $this 57 */ 58 public function set(...$options) 59 { 60 $this->options = []; 61 foreach ($options as $i => $option) { 62 if ($option instanceof Option) { 63 $this->options[] = $option; 64 } else { 65 $this->options[] = new Option($option); 66 } 67 } 68 69 return $this; 70 } 71 72 /** 73 * @param string|Option $option 74 * @return bool 75 */ 76 public function has($option): bool 77 { 78 $option = $option instanceof Option ? $option : new Option($option); 79 80 foreach ($this->options as $opt) { 81 if ($opt->equals($option)) { 82 return true; 83 } 84 } 85 86 return false; 87 } 88 89 /** 90 * @param string|Option ...$options 91 * @return $this 92 */ 93 public function remove(...$options) 94 { 95 foreach ($options as $option) { 96 $option = $option instanceof Option ? $option : new Option($option); 97 foreach ($this->options as $i => $opt) { 98 if ($opt->equals($option)) { 99 unset($this->options[$i]); 100 } 101 } 102 } 103 104 return $this; 105 } 106 107 /** 108 * Retrieve the first option, if it exists. 109 * 110 * @return Option|null 111 */ 112 public function first(): ?Option 113 { 114 $option = reset($this->options); 115 116 return $option === false ? null : $option; 117 } 118 119 /** 120 * Retrieve the last option, if it exists. 121 * 122 * @return Option|null 123 */ 124 public function last(): ?Option 125 { 126 $option = end($this->options); 127 reset($this->options); 128 129 return $option === false ? null : $option; 130 } 131 132 /** 133 * @param bool $sortedlc Used for comparison, as both case and order of options are irrelevant for options equality. 134 * @return string 135 */ 136 public function toString(bool $sortedlc = false): string 137 { 138 $opts = $this->options; 139 if ($sortedlc) { 140 sort($opts); 141 } 142 143 $options = ''; 144 foreach ($opts as $option) { 145 $options .= ($options === '') ? $option->toString($sortedlc) : ';' . $option->toString($sortedlc); 146 } 147 148 return $options; 149 } 150 151 /** 152 * @return Option[] 153 * @psalm-return array<array-key, Option> 154 */ 155 public function toArray(): array 156 { 157 return $this->options; 158 } 159 160 /** 161 * @return string 162 */ 163 public function __toString() 164 { 165 return $this->toString(); 166 } 167 168 /** 169 * @inheritDoc 170 * @psalm-return ArrayIterator<array-key, Option> 171 */ 172 public function getIterator(): Traversable 173 { 174 return new ArrayIterator($this->options); 175 } 176 177 /** 178 * @inheritDoc 179 * @psalm-return 0|positive-int 180 */ 181 public function count(): int 182 { 183 return count($this->options); 184 } 185} 186