*/ private array $sortOrdersById = []; public function create(CreateElementDto $dto): Element { $id = count($this->elementsById) + 1; $element = new Element( id: $id, title: $dto->title, description: $dto->description, iconImageUrl: $dto->iconImageUrl, richText: $dto->richText, shortPdfPath: $dto->shortPdfPath, longPdfPath: $dto->longPdfPath, youtubeUrl: $dto->youtubeUrl, set: $dto->set, parentElement: $dto->parentElement, ); $this->elementsById[$id] = $element; $this->sortOrdersById[$id] = $this->nextSortOrder( $dto->parentElement, ); return $element; } public function update(Element $element): Element { $updatedElement = $this->cloneElement($element); $this->elementsById[$updatedElement->getId()] = $updatedElement; return $this->cloneElement($updatedElement); } public function delete(Element $element): void { unset($this->elementsById[$element->getId()]); unset($this->sortOrdersById[$element->getId()]); } public function find(int $id): ?Element { if (! isset($this->elementsById[$id])) { return null; } return $this->cloneElement($this->elementsById[$id]); } public function findRootBySet(DomainSet $set): ?Element { foreach ($this->elementsById as $element) { if ( $element->getSet()->getId() === $set->getId() && $element->getParentElement() === null ) { return $this->cloneElement($element); } } return null; } /** * @return Element[] */ public function findBySet(DomainSet $set): array { $elements = []; foreach ($this->elementsById as $element) { if ($element->getSet()->getId() === $set->getId()) { $elements[] = $this->cloneElement($element); } } return $elements; } /** * @return Element[] */ public function findByParentElement(Element $parentElement): array { $elements = []; foreach ($this->elementsById as $element) { $currentParentElement = $element->getParentElement(); if ( $currentParentElement !== null && $currentParentElement->getId() === $parentElement->getId() ) { $elements[] = $this->cloneElement($element); } } usort($elements, function ( Element $firstElement, Element $secondElement, ): int { $firstSortOrder = $this->sortOrdersById[ $firstElement->getId() ] ?? $firstElement->getId(); $secondSortOrder = $this->sortOrdersById[ $secondElement->getId() ] ?? $secondElement->getId(); if ($firstSortOrder === $secondSortOrder) { return $firstElement->getId() <=> $secondElement->getId(); } return $firstSortOrder <=> $secondSortOrder; }); return $elements; } /** * @param int[] $childElementIds * @return Element[] */ public function reorderChildren( Element $parentElement, array $childElementIds, ): array { $sortOrder = 1; foreach ($childElementIds as $childElementId) { $this->sortOrdersById[$childElementId] = $sortOrder; $sortOrder++; } return $this->findByParentElement($parentElement); } private function cloneElement(Element $element): Element { $parentElement = $element->getParentElement(); if ($parentElement !== null) { $parentElement = $this->cloneElement($parentElement); } return new Element( id: $element->getId(), title: $element->getTitle(), description: $element->getDescription(), iconImageUrl: $element->getIconImageUrl(), richText: $element->getRichText(), shortPdfPath: $element->getShortPdfPath(), longPdfPath: $element->getLongPdfPath(), youtubeUrl: $element->getYoutubeUrl(), set: $element->getSet(), parentElement: $parentElement, ); } private function nextSortOrder(?Element $parentElement): int { $parentElementId = $parentElement?->getId(); $nextSortOrder = 1; foreach ($this->elementsById as $element) { $currentParentElement = $element->getParentElement(); $currentParentElementId = $currentParentElement?->getId(); if ($currentParentElementId !== $parentElementId) { continue; } $currentSortOrder = $this->sortOrdersById[$element->getId()] ?? 0; if ($currentSortOrder >= $nextSortOrder) { $nextSortOrder = $currentSortOrder + 1; } } return $nextSortOrder; } }