createSet('Bible'); $repository = app(ElementRepository::class); $bookLevel = $this->createLevel($set, 'book'); $portionLevel = $this->createLevel($set, 'portion'); $genesisBook = $repository->create(new CreateElementDto( name: 'Genesis', level: $bookLevel, parentElement: null, )); $exodusBook = $repository->create(new CreateElementDto( name: 'Exodus', level: $bookLevel, parentElement: null, )); $genesisPortion = $repository->create(new CreateElementDto( name: 'Genesis', level: $portionLevel, parentElement: $genesisBook, )); $noahPortion = $repository->create(new CreateElementDto( name: 'Noah', level: $portionLevel, parentElement: $genesisBook, )); $this->assertSame(1, $genesisBook->getPosition()); $this->assertSame(2, $exodusBook->getPosition()); $this->assertSame(1, $genesisPortion->getPosition()); $this->assertSame(2, $noahPortion->getPosition()); $this->assertDatabaseHas('elements', [ 'id' => $genesisPortion->getId(), 'set_level_id' => $portionLevel->getId(), 'name' => 'Genesis', 'parent_element_id' => $genesisBook->getId(), 'position' => 1, ]); $foundElement = $repository->find($noahPortion->getId()); $this->assertNotNull($foundElement); $this->assertSame('Noah', $foundElement->getName()); $this->assertSame('portion', $foundElement->getKind()); $this->assertSame( $portionLevel->getId(), $foundElement->getLevel()->getId(), ); $this->assertSame($set->getId(), $foundElement->getSet()->getId()); $this->assertSame( $genesisBook->getId(), $foundElement->getParentElement()?->getId(), ); } public function testItRejectsAParentFromAnotherSet(): void { $bible = $this->createSet('Bible'); $course = $this->createSet('Course'); $repository = app(ElementRepository::class); $bookLevel = $this->createLevel($bible, 'book'); $moduleLevel = $this->createLevel($course, 'module'); $book = $repository->create(new CreateElementDto( name: 'Genesis', level: $bookLevel, parentElement: null, )); $this->expectException(DomainException::class); $this->expectExceptionMessage( 'parent element must belong to the same set', ); $repository->create(new CreateElementDto( name: 'Invalid lesson', level: $moduleLevel, parentElement: $book, )); } public function testItRejectsARootOutsideTheFirstLevel(): void { $set = $this->createSet('Bible'); $this->createLevel($set, 'book'); $portionLevel = $this->createLevel($set, 'portion'); $this->expectException(DomainException::class); $this->expectExceptionMessage( 'root element must use the first set level', ); app(ElementRepository::class)->create(new CreateElementDto( name: 'Creation', level: $portionLevel, parentElement: null, )); } public function testItRejectsAChildOutsideTheNextLevel(): void { $set = $this->createSet('Bible'); $bookLevel = $this->createLevel($set, 'book'); $this->createLevel($set, 'portion'); $chapterLevel = $this->createLevel($set, 'chapter'); $repository = app(ElementRepository::class); $book = $repository->create(new CreateElementDto( name: 'Genesis', level: $bookLevel, parentElement: null, )); $this->expectException(DomainException::class); $this->expectExceptionMessage( 'child element must use the next set level', ); $repository->create(new CreateElementDto( name: 'Chapter 1', level: $chapterLevel, parentElement: $book, )); } public function testItListsOrderedElementsWithinTheirTreeScope(): void { $bible = $this->createSet('Bible'); $course = $this->createSet('Course'); $repository = app(ElementRepository::class); $bookLevel = $this->createLevel($bible, 'book'); $portionLevel = $this->createLevel($bible, 'portion'); $moduleLevel = $this->createLevel($course, 'module'); $genesisBook = $repository->create(new CreateElementDto( name: 'Genesis', level: $bookLevel, parentElement: null, )); $exodusBook = $repository->create(new CreateElementDto( name: 'Exodus', level: $bookLevel, parentElement: null, )); $repository->create(new CreateElementDto( name: 'Module 1', level: $moduleLevel, parentElement: null, )); $repository->create(new CreateElementDto( name: 'Genesis', level: $portionLevel, parentElement: $genesisBook, )); $repository->create(new CreateElementDto( name: 'Noah', level: $portionLevel, parentElement: $genesisBook, )); $repository->create(new CreateElementDto( name: 'Shemot', level: $portionLevel, parentElement: $exodusBook, )); $topLevelElements = $repository->findTopLevelBySet($bible); $childElements = $repository->findByParentElement($genesisBook); $this->assertSame( ['Genesis', 'Exodus'], array_map(function ($element): string { return $element->getName(); }, $topLevelElements), ); $this->assertSame( ['Genesis', 'Noah'], array_map(function ($element): string { return $element->getName(); }, $childElements), ); } public function testItListsEveryElementForASet(): void { $bible = $this->createSet('Bible'); $course = $this->createSet('Course'); $repository = app(ElementRepository::class); $bookLevel = $this->createLevel($bible, 'book'); $portionLevel = $this->createLevel($bible, 'portion'); $moduleLevel = $this->createLevel($course, 'module'); $genesis = $repository->create(new CreateElementDto( name: 'Genesis', level: $bookLevel, parentElement: null, )); $repository->create(new CreateElementDto( name: 'Creation', level: $portionLevel, parentElement: $genesis, )); $repository->create(new CreateElementDto( name: 'Foundations', level: $moduleLevel, parentElement: null, )); $elements = $repository->findBySet($bible); $this->assertSame( ['Genesis', 'Creation'], array_map(function ($element): string { return $element->getName(); }, $elements), ); $this->assertNull($elements[0]->getParentElement()); $this->assertSame( $genesis->getId(), $elements[1]->getParentElement()?->getId(), ); } private function createSet(string $name): Set { $creator = app(UserRepository::class)->create(new CreateUserDto( email: new EmailAddress(strtolower($name) . '@example.com'), passwordHash: 'hashed-password', )); return app(SetRepository::class)->create(new CreateSetDto( name: $name, creator: $creator, )); } private function createLevel(Set $set, string $kind): SetLevel { return app(SetLevelRepository::class)->create(new CreateSetLevelDto( set: $set, kind: $kind, )); } }