enforce element parent scope

This commit is contained in:
Yisroel Baum 2026-08-08 22:22:25 +03:00
parent eccfed2350
commit 588a3ecb40
Signed by: yisroelbaum
GPG key ID: 0FA60884F75520A9
3 changed files with 43 additions and 0 deletions

View file

@ -2,8 +2,13 @@
namespace App\Element; namespace App\Element;
use DomainException;
interface ElementRepository interface ElementRepository
{ {
/**
* @throws DomainException
*/
public function create(CreateElementDto $dto): Element; public function create(CreateElementDto $dto): Element;
public function find(int $id): ?Element; public function find(int $id): ?Element;

View file

@ -4,6 +4,7 @@ namespace App\Element;
use App\Set\Set; use App\Set\Set;
use App\Set\SetRepository; use App\Set\SetRepository;
use DomainException;
use RuntimeException; use RuntimeException;
class EloquentElementRepository implements ElementRepository class EloquentElementRepository implements ElementRepository
@ -14,6 +15,7 @@ class EloquentElementRepository implements ElementRepository
public function create(CreateElementDto $dto): Element public function create(CreateElementDto $dto): Element
{ {
$this->validateParentSet($dto);
$position = $this->nextPosition( $position = $this->nextPosition(
$dto->set, $dto->set,
$dto->parentElement, $dto->parentElement,
@ -43,6 +45,23 @@ class EloquentElementRepository implements ElementRepository
return $model === null ? null : $this->toDomain($model); return $model === null ? null : $this->toDomain($model);
} }
/**
* @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( private function nextPosition(
Set $set, Set $set,
?Element $parentElement, ?Element $parentElement,

View file

@ -5,6 +5,7 @@ namespace Tests\Fakes;
use App\Element\CreateElementDto; use App\Element\CreateElementDto;
use App\Element\Element; use App\Element\Element;
use App\Element\ElementRepository; use App\Element\ElementRepository;
use DomainException;
class FakeElementRepository implements ElementRepository class FakeElementRepository implements ElementRepository
{ {
@ -15,6 +16,7 @@ class FakeElementRepository implements ElementRepository
public function create(CreateElementDto $dto): Element public function create(CreateElementDto $dto): Element
{ {
$this->validateParentSet($dto);
$id = count($this->elements) + 1; $id = count($this->elements) + 1;
$element = new Element( $element = new Element(
id: $id, id: $id,
@ -36,6 +38,23 @@ class FakeElementRepository implements ElementRepository
return $element === null ? null : $this->copy($element); return $element === null ? null : $this->copy($element);
} }
/**
* @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 private function nextPosition(CreateElementDto $dto): int
{ {
$requestedParentId = $dto->parentElement?->getId(); $requestedParentId = $dto->parentElement?->getId();