From a752ff9ba5b8173ac262270f4adc7096fc632002 Mon Sep 17 00:00:00 2001 From: Yisroel Baum Date: Thu, 23 Apr 2026 20:44:14 +0300 Subject: [PATCH 1/4] add start and end date and test for null entries --- app/Plan/UseCases/CreatePlan.php | 8 ++++ app/Plan/UseCases/CreatePlanRequest.php | 2 + tests/Unit/Plan/UseCases/CreatePlanTest.php | 46 +++++++++++++++++++++ 3 files changed, 56 insertions(+) diff --git a/app/Plan/UseCases/CreatePlan.php b/app/Plan/UseCases/CreatePlan.php index 0d0124c..7bad774 100644 --- a/app/Plan/UseCases/CreatePlan.php +++ b/app/Plan/UseCases/CreatePlan.php @@ -42,6 +42,14 @@ class CreatePlan throw new BadRequestException('name is required'); } + if ($request->dateStart === null) { + throw new BadRequestException('date start is required'); + } + + if ($request->dateEnd === null) { + throw new BadRequestException('date end is required'); + } + $userId = $request->userId; $user = $this->userRepo->find($userId); if ($user === null) { diff --git a/app/Plan/UseCases/CreatePlanRequest.php b/app/Plan/UseCases/CreatePlanRequest.php index d9e0669..300a7a9 100644 --- a/app/Plan/UseCases/CreatePlanRequest.php +++ b/app/Plan/UseCases/CreatePlanRequest.php @@ -8,5 +8,7 @@ class CreatePlanRequest public ?int $userId, public ?int $textId, public ?string $name, + public ?string $dateStart, + public ?string $dateEnd, ) {} } diff --git a/tests/Unit/Plan/UseCases/CreatePlanTest.php b/tests/Unit/Plan/UseCases/CreatePlanTest.php index cccc4ea..0cdad79 100644 --- a/tests/Unit/Plan/UseCases/CreatePlanTest.php +++ b/tests/Unit/Plan/UseCases/CreatePlanTest.php @@ -59,6 +59,8 @@ class CreatePlanTest extends TestCase userId: 0, name: 'testPlan', textId: 0, + dateStart: '2025-01-01', + dateEnd: '2025-01-01', )); $this->assertEquals('testPlan', $plan->getName()); } @@ -69,6 +71,8 @@ class CreatePlanTest extends TestCase userId: 0, name: 'testPlan', textId: 0, + dateStart: '2025-01-01', + dateEnd: '2025-01-01', )); $this->assertInstanceOf(User::class, $plan->getUser()); } @@ -81,6 +85,8 @@ class CreatePlanTest extends TestCase userId: 1, name: 'testPlan', textId: 0, + dateStart: '2025-01-01', + dateEnd: '2025-01-01', )); } @@ -92,6 +98,8 @@ class CreatePlanTest extends TestCase userId: 0, name: 'testPlan', textId: 1, + dateStart: '2025-01-01', + dateEnd: '2025-01-01', )); } @@ -107,6 +115,8 @@ class CreatePlanTest extends TestCase userId: 0, name: 'testPlan', textId: 0, + dateStart: '2025-01-01', + dateEnd: '2025-01-01', )); $this->assertNotNull($this->scheduledNodeRepo->find(0)); } @@ -128,6 +138,8 @@ class CreatePlanTest extends TestCase userId: 0, name: 'testPlan', textId: 0, + dateStart: '2025-01-01', + dateEnd: '2025-01-01', )); $this->assertEquals( 1, @@ -144,6 +156,8 @@ class CreatePlanTest extends TestCase userId: null, name: 'testPlan', textId: 0, + dateStart: '2025-01-01', + dateEnd: '2025-01-01', )); } @@ -156,6 +170,8 @@ class CreatePlanTest extends TestCase userId: 0, name: 'testPlan', textId: null, + dateStart: '2025-01-01', + dateEnd: '2025-01-01', )); } @@ -168,6 +184,36 @@ class CreatePlanTest extends TestCase userId: 0, name: null, textId: 0, + dateStart: '2025-01-01', + dateEnd: '2025-01-01', + )); + } + + public function test_throws_if_date_start_is_null(): void + { + $this->expectException(BadRequestException::class); + $this->expectExceptionMessage('date start is required'); + + $this->useCase->execute(new CreatePlanRequest( + userId: 0, + name: 'test', + textId: 0, + dateStart: null, + dateEnd: '2025-01-01', + )); + } + + public function test_throws_if_date_end_is_null(): void + { + $this->expectException(BadRequestException::class); + $this->expectExceptionMessage('date end is required'); + + $this->useCase->execute(new CreatePlanRequest( + userId: 0, + name: 'test', + textId: 0, + dateStart: '2025-01-01', + dateEnd: null, )); } } From 858f2e075f3e68dc49c161be2b703933eafde8cb Mon Sep 17 00:00:00 2001 From: Yisroel Baum Date: Thu, 23 Apr 2026 20:50:26 +0300 Subject: [PATCH 2/4] test for date end being before date start --- app/Plan/UseCases/CreatePlan.php | 7 +++++++ tests/Unit/Plan/UseCases/CreatePlanTest.php | 14 ++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/app/Plan/UseCases/CreatePlan.php b/app/Plan/UseCases/CreatePlan.php index 7bad774..0be80cb 100644 --- a/app/Plan/UseCases/CreatePlan.php +++ b/app/Plan/UseCases/CreatePlan.php @@ -50,6 +50,13 @@ class CreatePlan throw new BadRequestException('date end is required'); } + $startDate = new DateTimeImmutable($request->dateStart); + $endDate = new DateTimeImmutable($request->dateEnd); + + if ($endDate < $startDate) { + throw new BadRequestException('date end cannot be before date start'); + } + $userId = $request->userId; $user = $this->userRepo->find($userId); if ($user === null) { diff --git a/tests/Unit/Plan/UseCases/CreatePlanTest.php b/tests/Unit/Plan/UseCases/CreatePlanTest.php index 0cdad79..89ba509 100644 --- a/tests/Unit/Plan/UseCases/CreatePlanTest.php +++ b/tests/Unit/Plan/UseCases/CreatePlanTest.php @@ -216,4 +216,18 @@ class CreatePlanTest extends TestCase dateEnd: null, )); } + + public function test_throws_if_date_end_is_before_date_start(): void + { + $this->expectException(BadRequestException::class); + $this->expectExceptionMessage('date end cannot be before date start'); + + $this->useCase->execute(new CreatePlanRequest( + userId: 0, + name: 'test', + textId: 0, + dateStart: '2025-01-02', + dateEnd: '2025-01-01', + )); + } } From 358694e7e3339f610703bcf1e34eceae0e46f79e Mon Sep 17 00:00:00 2001 From: Yisroel Baum Date: Thu, 23 Apr 2026 20:54:08 +0300 Subject: [PATCH 3/4] nodes are scheduled on different days according to dates provided --- app/Plan/UseCases/CreatePlan.php | 15 ++++++-- app/ScheduledNode/ScheduledNode.php | 5 +++ tests/Unit/Plan/UseCases/CreatePlanTest.php | 40 +++++++++++++++++++++ 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/app/Plan/UseCases/CreatePlan.php b/app/Plan/UseCases/CreatePlan.php index 0be80cb..64c7bda 100644 --- a/app/Plan/UseCases/CreatePlan.php +++ b/app/Plan/UseCases/CreatePlan.php @@ -74,10 +74,21 @@ class CreatePlan name: $request->name, user: $user, )); - foreach ($nodesOfText as $node) { + + $dates = []; + $currentDate = $startDate; + while ($currentDate <= $endDate) { + $dates[] = $currentDate; + $currentDate = $currentDate->modify('+1 day'); + } + + foreach ($nodesOfText as $index => $node) { + $dateIndex = $index % count($dates); + $scheduledDate = $dates[$dateIndex]; + $this->createScheduledNode->execute( new CreateScheduledNodeRequest( - date: '2025-01-01', // TODO: this should be cycling over some list of dates + date: $scheduledDate->format('Y-m-d'), planId: $plan->getId(), ) ); diff --git a/app/ScheduledNode/ScheduledNode.php b/app/ScheduledNode/ScheduledNode.php index ce6ed05..7d479db 100644 --- a/app/ScheduledNode/ScheduledNode.php +++ b/app/ScheduledNode/ScheduledNode.php @@ -22,4 +22,9 @@ class ScheduledNode { return $this->plan; } + + public function getDate(): DateTimeImmutable + { + return $this->date; + } } diff --git a/tests/Unit/Plan/UseCases/CreatePlanTest.php b/tests/Unit/Plan/UseCases/CreatePlanTest.php index 89ba509..d6f686d 100644 --- a/tests/Unit/Plan/UseCases/CreatePlanTest.php +++ b/tests/Unit/Plan/UseCases/CreatePlanTest.php @@ -11,6 +11,7 @@ use App\Text\CreateTextDto; use App\User\UseCases\CreateUserDto; use App\User\User; use App\ValueObjects\EmailAddress; +use DateTimeImmutable; use DomainException; use Tests\Fakes\FakeNodeRepository; use Tests\Fakes\FakePlanRepository; @@ -230,4 +231,43 @@ class CreatePlanTest extends TestCase dateEnd: '2025-01-01', )); } + + public function test_scheduled_nodes_are_scheduled_on_different_days(): void + { + $text = $this->textRepo->find(0); + $rootNode = $this->nodeRepo->create(new CreateNodeDto( + text: $text, + title: 'root node', + parentNode: null, + )); + $this->nodeRepo->create(new CreateNodeDto( + text: $text, + title: 'child 1', + parentNode: $rootNode, + )); + $this->nodeRepo->create(new CreateNodeDto( + text: $text, + title: 'child 2', + parentNode: $rootNode, + )); + $plan = $this->useCase->execute(new CreatePlanRequest( + userId: 0, + name: 'testPlan', + textId: 0, + dateStart: '2025-01-01', + dateEnd: '2025-01-02', + )); + $childOne = $this->scheduledNodeRepo->find(0); + $childTwo = $this->scheduledNodeRepo->find(1); + $this->assertNotNull($childOne); + $this->assertNotNull($childTwo); + $this->assertEquals( + new DateTimeImmutable('2025-01-01'), + $childOne->getDate() + ); + $this->assertEquals( + new DateTimeImmutable('2025-01-02'), + $childTwo->getDate() + ); + } } From 49663d70d9d850e95cda143fd681c6c2827489d3 Mon Sep 17 00:00:00 2001 From: Yisroel Baum Date: Thu, 23 Apr 2026 21:06:22 +0300 Subject: [PATCH 4/4] distribute scheduled nodes evenly by filling days sequentially --- app/Plan/UseCases/CreatePlan.php | 3 +- tests/Unit/Plan/UseCases/CreatePlanTest.php | 50 +++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/app/Plan/UseCases/CreatePlan.php b/app/Plan/UseCases/CreatePlan.php index 64c7bda..9841b33 100644 --- a/app/Plan/UseCases/CreatePlan.php +++ b/app/Plan/UseCases/CreatePlan.php @@ -82,8 +82,9 @@ class CreatePlan $currentDate = $currentDate->modify('+1 day'); } + $nodesPerDay = (int) ceil(count($nodesOfText) / count($dates)); foreach ($nodesOfText as $index => $node) { - $dateIndex = $index % count($dates); + $dateIndex = (int) floor($index / $nodesPerDay); $scheduledDate = $dates[$dateIndex]; $this->createScheduledNode->execute( diff --git a/tests/Unit/Plan/UseCases/CreatePlanTest.php b/tests/Unit/Plan/UseCases/CreatePlanTest.php index d6f686d..667e72c 100644 --- a/tests/Unit/Plan/UseCases/CreatePlanTest.php +++ b/tests/Unit/Plan/UseCases/CreatePlanTest.php @@ -270,4 +270,54 @@ class CreatePlanTest extends TestCase $childTwo->getDate() ); } + + public function test_more_scheduled_nodes_than_days(): void + { + $text = $this->textRepo->find(0); + $rootNode = $this->nodeRepo->create(new CreateNodeDto( + text: $text, + title: 'root node', + parentNode: null, + )); + $this->nodeRepo->create(new CreateNodeDto( + text: $text, + title: 'child 1', + parentNode: $rootNode, + )); + $this->nodeRepo->create(new CreateNodeDto( + text: $text, + title: 'child 2', + parentNode: $rootNode, + )); + $this->nodeRepo->create(new CreateNodeDto( + text: $text, + title: 'child 3', + parentNode: $rootNode, + )); + $plan = $this->useCase->execute(new CreatePlanRequest( + userId: 0, + name: 'testPlan', + textId: 0, + dateStart: '2025-01-01', + dateEnd: '2025-01-02', + )); + $childOne = $this->scheduledNodeRepo->find(0); + $childTwo = $this->scheduledNodeRepo->find(1); + $childThree = $this->scheduledNodeRepo->find(2); + $this->assertNotNull($childOne); + $this->assertNotNull($childTwo); + $this->assertNotNull($childThree); + $this->assertEquals( + new DateTimeImmutable('2025-01-01'), + $childOne->getDate() + ); + $this->assertEquals( + new DateTimeImmutable('2025-01-01'), + $childTwo->getDate() + ); + $this->assertEquals( + new DateTimeImmutable('2025-01-02'), + $childThree->getDate() + ); + } }