*/ private array $elements = []; public function create(CreateElementDto $dto): Element { $this->validateParentSet($dto); $id = count($this->elements) + 1; $element = new Element( id: $id, name: $dto->name, kind: $dto->kind, set: $dto->set, parentElement: $dto->parentElement, position: $this->nextPosition($dto), ); $this->elements[$id] = $element; return $this->copy($element); } public function find(int $id): ?Element { $element = $this->elements[$id] ?? null; return $element === null ? null : $this->copy($element); } public function findTopLevelBySet(Set $set): array { $elements = array_filter( $this->elements, function (Element $element) use ($set): bool { return $element->getSet()->getId() === $set->getId() && $element->getParentElement() === null; }, ); return $this->orderedCopies($elements); } public function findByParentElement(Element $parentElement): array { $elements = array_filter( $this->elements, function (Element $element) use ($parentElement): bool { return $element->getSet()->getId() === $parentElement->getSet()->getId() && $element->getParentElement()?->getId() === $parentElement->getId(); }, ); return $this->orderedCopies($elements); } /** * @throws DomainException */ private function validateParentSet(CreateElementDto $dto): void { $parentElement = $dto->parentElement; if ($parentElement === null) { return; } if ($parentElement->getSet()->getId() !== $dto->set->getId()) { throw new DomainException( 'parent element must belong to the same set', ); } } private function nextPosition(CreateElementDto $dto): int { $requestedParentId = $dto->parentElement?->getId(); $maximumPosition = 0; foreach ($this->elements as $element) { if ($element->getSet()->getId() !== $dto->set->getId()) { continue; } $elementParentId = $element->getParentElement()?->getId(); if ($elementParentId !== $requestedParentId) { continue; } $maximumPosition = max( $maximumPosition, $element->getPosition(), ); } return $maximumPosition + 1; } /** * @param array $elements * @return list */ private function orderedCopies(array $elements): array { usort($elements, function (Element $first, Element $second): int { $positionComparison = $first->getPosition() <=> $second->getPosition(); if ($positionComparison !== 0) { return $positionComparison; } return $first->getId() <=> $second->getId(); }); return array_map(function (Element $element): Element { return $this->copy($element); }, $elements); } private function copy(Element $element): Element { $parentElement = $element->getParentElement(); return new Element( id: $element->getId(), name: $element->getName(), kind: $element->getKind(), set: $element->getSet(), parentElement: $parentElement === null ? null : $this->copy($parentElement), position: $element->getPosition(), ); } }