parentElement?->getId(); $model = ElementModel::create([ 'set_id' => $dto->set->getId(), 'title' => $dto->title, 'description' => $dto->description, 'icon_image_url' => $dto->iconImageUrl, 'rich_text' => $dto->richText, 'short_pdf_path' => $dto->shortPdfPath, 'long_pdf_path' => $dto->longPdfPath, 'youtube_url' => $dto->youtubeUrl, 'parent_element_id' => $parentElementId, 'sort_order' => $this->nextSortOrder($dto->set, $parentElementId), ]); return new Element( id: $model->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, ); } public function update(Element $element): Element { $model = ElementModel::find($element->getId()); if ($model === null) { throw new DomainException( "Element with id: {$element->getId()} doesnt exist" ); } $model->set_id = $element->getSet()->getId(); $model->title = $element->getTitle(); $model->description = $element->getDescription(); $model->icon_image_url = $element->getIconImageUrl(); $model->rich_text = $element->getRichText(); $model->short_pdf_path = $element->getShortPdfPath(); $model->long_pdf_path = $element->getLongPdfPath(); $model->youtube_url = $element->getYoutubeUrl(); $model->parent_element_id = $element->getParentElement()?->getId(); $model->save(); return $this->toDomain($model); } public function delete(Element $element): void { $model = ElementModel::find($element->getId()); if ($model === null) { throw new DomainException( "Element with id: {$element->getId()} doesnt exist" ); } $model->delete(); } public function find(int $id): ?Element { $model = ElementModel::find($id); return $model === null ? null : $this->toDomain($model); } public function findRootBySet(DomainSet $set): ?Element { $model = ElementModel::where('set_id', $set->getId()) ->whereNull('parent_element_id') ->orderBy('sort_order') ->orderBy('id') ->first(); return $model === null ? null : $this->toDomain($model); } /** * @return Element[] */ public function findBySet(DomainSet $set): array { $models = ElementModel::where('set_id', $set->getId()) ->orderBy('id') ->get(); $elements = []; foreach ($models as $model) { $elements[] = $this->toDomain($model); } return $elements; } /** * @return Element[] */ public function findByParentElement(Element $parentElement): array { $models = ElementModel::where( 'parent_element_id', $parentElement->getId(), ) ->orderBy('sort_order') ->orderBy('id') ->get(); $elements = []; foreach ($models as $model) { $elements[] = $this->toDomain($model); } return $elements; } /** * @param int[] $childElementIds * @return Element[] */ public function reorderChildren( Element $parentElement, array $childElementIds, ): array { DB::transaction(function () use ($parentElement, $childElementIds) { $sortOrder = 1; foreach ($childElementIds as $childElementId) { ElementModel::where('id', $childElementId) ->where('parent_element_id', $parentElement->getId()) ->update(['sort_order' => $sortOrder]); $sortOrder++; } }); return $this->findByParentElement($parentElement); } private function nextSortOrder( DomainSet $set, ?int $parentElementId, ): int { $query = ElementModel::where('set_id', $set->getId()); if ($parentElementId === null) { $query->whereNull('parent_element_id'); } else { $query->where('parent_element_id', $parentElementId); } $currentMaxSortOrder = $query->max('sort_order'); if ($currentMaxSortOrder === null) { return 1; } return (int) $currentMaxSortOrder + 1; } private function toDomain(ElementModel $model): Element { $set = $this->setRepo->find($model->set_id); if ($set === null) { throw new DomainException( "Set with id: {$model->set_id} doesnt exist" ); } $parentElement = null; if ($model->parent_element_id !== null) { $parentElement = $this->find($model->parent_element_id); if ($parentElement === null) { throw new DomainException( "Element with id: {$model->parent_element_id} doesnt exist" ); } } return new Element( id: $model->id, title: $model->title, description: $model->description, iconImageUrl: $model->icon_image_url, richText: $model->rich_text, shortPdfPath: $model->short_pdf_path, longPdfPath: $model->long_pdf_path, youtubeUrl: $model->youtube_url, set: $set, parentElement: $parentElement, ); } }