*/ final class AdminLevelCollection implements \IteratorAggregate, \Countable { const MAX_LEVEL_DEPTH = 5; /** * @var AdminLevel[] */ private $adminLevels; /** * @param AdminLevel[] $adminLevels */ public function __construct(array $adminLevels = []) { $this->adminLevels = []; foreach ($adminLevels as $adminLevel) { $level = $adminLevel->getLevel(); $this->checkLevel($level); if ($this->has($level)) { throw new InvalidArgument(sprintf('Administrative level %d is defined twice', $level)); } $this->adminLevels[$level] = $adminLevel; } ksort($this->adminLevels, SORT_NUMERIC); } /** * {@inheritdoc} */ public function getIterator(): Traversable { return new \ArrayIterator($this->all()); } /** * {@inheritdoc} */ public function count(): int { return count($this->adminLevels); } /** * @return AdminLevel * * @throws CollectionIsEmpty */ public function first(): AdminLevel { if ([] === $this->adminLevels) { throw new CollectionIsEmpty(); } return reset($this->adminLevels); } /** * @param int $offset * @param int|null $length * * @return AdminLevel[] */ public function slice(int $offset, int $length = null): array { return array_slice($this->adminLevels, $offset, $length, true); } /** * @return bool */ public function has(int $level): bool { return isset($this->adminLevels[$level]); } /** * @return AdminLevel * * @throws \OutOfBoundsException * @throws InvalidArgument */ public function get(int $level): AdminLevel { $this->checkLevel($level); if (!isset($this->adminLevels[$level])) { throw new InvalidArgument(sprintf('Administrative level %d is not set for this address', $level)); } return $this->adminLevels[$level]; } /** * @return AdminLevel[] */ public function all(): array { return $this->adminLevels; } /** * @param int $level * * @throws \OutOfBoundsException */ private function checkLevel(int $level) { if ($level <= 0 || $level > self::MAX_LEVEL_DEPTH) { throw new OutOfBounds(sprintf('Administrative level should be an integer in [1,%d], %d given', self::MAX_LEVEL_DEPTH, $level)); } } }