Compare commits

..

No commits in common. "6d8f9314321990ece4a1de787abcc417c931920d" and "189493b045ebbadba0bea4a019a1e3a5aebaeb74" have entirely different histories.

22 changed files with 52 additions and 318 deletions

View file

@ -1,5 +0,0 @@
<?php
namespace App\Exceptions;
class BadRequestException extends \RuntimeException {}

View file

@ -2,7 +2,6 @@
namespace App\Node; namespace App\Node;
use App\Exceptions\BadRequestException;
use App\Node\UseCases\BulkCreateNodesRequest; use App\Node\UseCases\BulkCreateNodesRequest;
use App\Node\NodeRepository; use App\Node\NodeRepository;
use App\Node\UseCases\BulkCreateNodes; use App\Node\UseCases\BulkCreateNodes;
@ -48,10 +47,17 @@ class NodeController
CreateNode $createNodeUseCase, CreateNode $createNodeUseCase,
): Response { ): Response {
$data = json_decode((string) $request->getBody(), true) ?? []; $data = json_decode((string) $request->getBody(), true) ?? [];
$title = $data['title'] ?? '';
$textId = isset($data['textId']) ? (int) $data['textId'] : null; if (empty($title)) {
$title = $data['title'] ?? null; $response->getBody()->write(json_encode(['error' => 'Title is required']));
$parentNodeId = isset($data['parentNodeId']) ? (int) $data['parentNodeId'] : null; return $response->withStatus(400)->withHeader('Content-Type', 'application/json');
}
$textId = (int) ($data['textId'] ?? 0);
$parentNodeId = isset($data['parentNodeId']) && $data['parentNodeId'] !== null
? (int) $data['parentNodeId']
: null;
try { try {
$node = $createNodeUseCase->execute(new CreateNodeRequest( $node = $createNodeUseCase->execute(new CreateNodeRequest(
@ -59,9 +65,6 @@ class NodeController
title: $title, title: $title,
parentNodeId: $parentNodeId, parentNodeId: $parentNodeId,
)); ));
} catch (BadRequestException $e) {
$response->getBody()->write(json_encode(['error' => $e->getMessage()]));
return $response->withStatus(400)->withHeader('Content-Type', 'application/json');
} catch (DomainException $e) { } catch (DomainException $e) {
$response->getBody()->write(json_encode(['error' => $e->getMessage()])); $response->getBody()->write(json_encode(['error' => $e->getMessage()]));
return $response->withStatus(404)->withHeader('Content-Type', 'application/json'); return $response->withStatus(404)->withHeader('Content-Type', 'application/json');
@ -82,10 +85,25 @@ class NodeController
): Response { ): Response {
$data = json_decode((string) $request->getBody(), true) ?? []; $data = json_decode((string) $request->getBody(), true) ?? [];
$textId = isset($data['textId']) ? (int) $data['textId'] : null; $titlePrefix = trim($data['titlePrefix'] ?? '');
$parentNodeId = isset($data['parentNodeId']) ? (int) $data['parentNodeId'] : null; if ($titlePrefix === '') {
$titlePrefix = isset($data['titlePrefix']) ? (string) $data['titlePrefix'] : null; $response->getBody()->write(json_encode(['error' => 'Title prefix is required']));
$count = isset($data['count']) ? (int) $data['count'] : null; return $response->withStatus(400)->withHeader('Content-Type', 'application/json');
}
$count = isset($data['count']) ? (int) $data['count'] : 0;
if ($count < 1) {
$response->getBody()->write(json_encode(['error' => 'Count must be at least 1']));
return $response->withStatus(400)->withHeader('Content-Type', 'application/json');
}
if (!isset($data['parentNodeId']) || $data['parentNodeId'] === null) {
$response->getBody()->write(json_encode(['error' => 'parentNodeId is required']));
return $response->withStatus(400)->withHeader('Content-Type', 'application/json');
}
$textId = (int) ($data['textId'] ?? 0);
$parentNodeId = (int) $data['parentNodeId'];
try { try {
$nodes = $bulkCreateNodesUseCase->execute(new BulkCreateNodesRequest( $nodes = $bulkCreateNodesUseCase->execute(new BulkCreateNodesRequest(
@ -94,9 +112,6 @@ class NodeController
titlePrefix: $titlePrefix, titlePrefix: $titlePrefix,
count: $count, count: $count,
)); ));
} catch (BadRequestException $e) {
$response->getBody()->write(json_encode(['error' => $e->getMessage()]));
return $response->withStatus(400)->withHeader('Content-Type', 'application/json');
} catch (DomainException $e) { } catch (DomainException $e) {
$response->getBody()->write(json_encode(['error' => $e->getMessage()])); $response->getBody()->write(json_encode(['error' => $e->getMessage()]));
return $response->withStatus(404)->withHeader('Content-Type', 'application/json'); return $response->withStatus(404)->withHeader('Content-Type', 'application/json');

View file

@ -2,7 +2,6 @@
namespace App\Node\UseCases; namespace App\Node\UseCases;
use App\Exceptions\BadRequestException;
use App\Node\CreateNodeDto; use App\Node\CreateNodeDto;
use App\Node\Node; use App\Node\Node;
use App\Node\NodeRepository; use App\Node\NodeRepository;
@ -18,31 +17,10 @@ class BulkCreateNodes
/** /**
* @return Node[] * @return Node[]
* @throws BadRequestException
* @throws DomainException * @throws DomainException
*/ */
public function execute(BulkCreateNodesRequest $request): array public function execute(BulkCreateNodesRequest $request): array
{ {
if ($request->textId === null) {
throw new BadRequestException('textId is required');
}
if ($request->parentNodeId === null) {
throw new BadRequestException('parentNodeId is required');
}
if ($request->titlePrefix === null) {
throw new BadRequestException('titlePrefix is required');
}
if ($request->count === null) {
throw new BadRequestException('count is required');
}
if ($request->count < 1) {
throw new BadRequestException('count must be at least 1');
}
$text = $this->textRepo->find($request->textId); $text = $this->textRepo->find($request->textId);
if ($text === null) { if ($text === null) {
throw new DomainException("Text with id: {$request->textId} doesnt exist"); throw new DomainException("Text with id: {$request->textId} doesnt exist");

View file

@ -5,9 +5,9 @@ namespace App\Node\UseCases;
class BulkCreateNodesRequest class BulkCreateNodesRequest
{ {
public function __construct( public function __construct(
public ?int $textId, public int $textId,
public ?int $parentNodeId, public int $parentNodeId,
public ?string $titlePrefix, public string $titlePrefix,
public ?int $count, public int $count,
) {} ) {}
} }

View file

@ -2,7 +2,6 @@
namespace App\Node\UseCases; namespace App\Node\UseCases;
use App\Exceptions\BadRequestException;
use App\Node\Node; use App\Node\Node;
use App\Node\CreateNodeDto; use App\Node\CreateNodeDto;
use App\Node\NodeRepository; use App\Node\NodeRepository;
@ -17,19 +16,10 @@ class CreateNode
) {} ) {}
/** /**
* @throws BadRequestException
* @throws DomainException * @throws DomainException
*/ */
public function execute(CreateNodeRequest $request): Node public function execute(CreateNodeRequest $request): Node
{ {
if ($request->textId === null) {
throw new BadRequestException('textId is required');
}
if ($request->title === null) {
throw new BadRequestException('title is required');
}
$textId = $request->textId; $textId = $request->textId;
$text = $this->textRepo->find($textId); $text = $this->textRepo->find($textId);
if ($text === null) { if ($text === null) {

View file

@ -5,8 +5,8 @@ namespace App\Node\UseCases;
class CreateNodeRequest class CreateNodeRequest
{ {
public function __construct( public function __construct(
public ?int $textId, public int $textId,
public ?string $title, public string $title,
public ?int $parentNodeId, public ?int $parentNodeId,
) {} ) {}
} }

View file

@ -2,7 +2,6 @@
namespace App\Plan\UseCases; namespace App\Plan\UseCases;
use App\Exceptions\BadRequestException;
use App\Node\NodeRepository; use App\Node\NodeRepository;
use App\Plan\CreatePlanDto; use App\Plan\CreatePlanDto;
use App\Plan\Plan; use App\Plan\Plan;
@ -25,23 +24,10 @@ class CreatePlan
) {} ) {}
/** /**
* @throws BadRequestException
* @throws DomainException * @throws DomainException
*/ */
public function execute(CreatePlanRequest $request): Plan public function execute(CreatePlanRequest $request): Plan
{ {
if ($request->userId === null) {
throw new BadRequestException('userId is required');
}
if ($request->textId === null) {
throw new BadRequestException('textId is required');
}
if ($request->name === null) {
throw new BadRequestException('name is required');
}
$userId = $request->userId; $userId = $request->userId;
$user = $this->userRepo->find($userId); $user = $this->userRepo->find($userId);
if ($user === null) { if ($user === null) {

View file

@ -5,8 +5,8 @@ namespace App\Plan\UseCases;
class CreatePlanRequest class CreatePlanRequest
{ {
public function __construct( public function __construct(
public ?int $userId, public int $userId,
public ?int $textId, public int $textId,
public ?string $name, public string $name,
) {} ) {}
} }

View file

@ -2,7 +2,6 @@
namespace App\ScheduledNode\UseCases; namespace App\ScheduledNode\UseCases;
use App\Exceptions\BadRequestException;
use App\Plan\PlanRepository; use App\Plan\PlanRepository;
use App\ScheduledNode\ScheduledNode; use App\ScheduledNode\ScheduledNode;
use App\ScheduledNode\CreateScheduledNodeDto; use App\ScheduledNode\CreateScheduledNodeDto;
@ -16,21 +15,9 @@ class CreateScheduledNode
private PlanRepository $planRepo, private PlanRepository $planRepo,
) {} ) {}
/**
* @throws BadRequestException
* @throws DomainException
*/
public function execute( public function execute(
CreateScheduledNodeRequest $request CreateScheduledNodeRequest $request
): ScheduledNode { ): ScheduledNode {
if ($request->date === null) {
throw new BadRequestException('date is required');
}
if ($request->planId === null) {
throw new BadRequestException('planId is required');
}
$id = $request->planId; $id = $request->planId;
$plan = $this->planRepo->find($id); $plan = $this->planRepo->find($id);
if ($plan === null) { if ($plan === null) {

View file

@ -7,7 +7,7 @@ use DateTimeImmutable;
class CreateScheduledNodeRequest class CreateScheduledNodeRequest
{ {
public function __construct( public function __construct(
public ?DateTimeImmutable $date, public DateTimeImmutable $date,
public ?int $planId, public int $planId,
) {} ) {}
} }

View file

@ -2,7 +2,6 @@
namespace App\Text; namespace App\Text;
use App\Exceptions\BadRequestException;
use App\Text\TextRepository; use App\Text\TextRepository;
use App\Text\UseCases\CreateText; use App\Text\UseCases\CreateText;
use App\Text\UseCases\CreateTextRequest; use App\Text\UseCases\CreateTextRequest;
@ -51,21 +50,21 @@ class TextController
CreateText $createTextUseCase, CreateText $createTextUseCase,
): Response { ): Response {
$data = $request->getParsedBody(); $data = $request->getParsedBody();
$name = $data['name'] ?? null; $name = $data['name'] ?? '';
try { if (!empty($name)) {
$text = $createTextUseCase->execute(new CreateTextRequest( $text = $createTextUseCase->execute(new CreateTextRequest(
name: $name, name: $name,
)); ));
} catch (BadRequestException $e) {
$response->getBody()->write(json_encode(['error' => $e->getMessage()])); $response->getBody()->write(json_encode([
return $response->withStatus(400)->withHeader('Content-Type', 'application/json'); 'id' => $text->getId(),
'name' => $text->getName(),
]));
return $response->withHeader('Content-Type', 'application/json');
} }
$response->getBody()->write(json_encode([ $response->getBody()->write(json_encode(['error' => 'Name is required']));
'id' => $text->getId(), return $response->withStatus(400);
'name' => $text->getName(),
]));
return $response->withHeader('Content-Type', 'application/json');
} }
} }

View file

@ -2,7 +2,6 @@
namespace App\Text\UseCases; namespace App\Text\UseCases;
use App\Exceptions\BadRequestException;
use App\Text\Text; use App\Text\Text;
use App\Text\CreateTextDto; use App\Text\CreateTextDto;
use App\Text\TextRepository; use App\Text\TextRepository;
@ -16,15 +15,8 @@ class CreateText
private NodeRepository $nodeRepo, private NodeRepository $nodeRepo,
) {} ) {}
/**
* @throws BadRequestException
*/
public function execute(CreateTextRequest $request): Text public function execute(CreateTextRequest $request): Text
{ {
if ($request->name === null) {
throw new BadRequestException('name is required');
}
$text = $this->textRepo->create(new CreateTextDto( $text = $this->textRepo->create(new CreateTextDto(
name: $request->name, name: $request->name,
)); ));

View file

@ -5,6 +5,6 @@ namespace App\Text\UseCases;
class CreateTextRequest class CreateTextRequest
{ {
public function __construct( public function __construct(
public ?string $name, public string $name,
) {} ) {}
} }

View file

@ -2,7 +2,6 @@
namespace App\User\UseCases; namespace App\User\UseCases;
use App\Exceptions\BadRequestException;
use App\User\UserRepository; use App\User\UserRepository;
use App\ValueObjects\EmailAddress; use App\ValueObjects\EmailAddress;
@ -12,15 +11,8 @@ class CreateUser
private UserRepository $userRepo, private UserRepository $userRepo,
) {} ) {}
/**
* @throws BadRequestException
*/
public function execute(CreateUserRequest $dto): void public function execute(CreateUserRequest $dto): void
{ {
if ($dto->email === null) {
throw new BadRequestException('email is required');
}
$this->userRepo->create(new CreateUserDto( $this->userRepo->create(new CreateUserDto(
email: new EmailAddress($dto->email), email: new EmailAddress($dto->email),
)); ));

View file

@ -5,6 +5,6 @@ namespace App\User\UseCases;
class CreateUserRequest class CreateUserRequest
{ {
public function __construct( public function __construct(
public ?string $email, public string $email,
) {} ) {}
} }

View file

@ -2,7 +2,6 @@
namespace Tests\Unit\Node\UseCases; namespace Tests\Unit\Node\UseCases;
use App\Exceptions\BadRequestException;
use App\Node\CreateNodeDto; use App\Node\CreateNodeDto;
use App\Node\Node; use App\Node\Node;
use App\Node\UseCases\BulkCreateNodes; use App\Node\UseCases\BulkCreateNodes;
@ -132,69 +131,4 @@ class BulkCreateNodesTest extends TestCase
count: 5, count: 5,
)); ));
} }
public function test_throws_if_text_id_is_null(): void
{
$this->expectException(BadRequestException::class);
$this->expectExceptionMessage('textId is required');
$this->useCase->execute(new BulkCreateNodesRequest(
textId: null,
parentNodeId: $this->parentNode->getId(),
titlePrefix: 'Page',
count: 5,
));
}
public function test_throws_if_parent_node_id_is_null(): void
{
$this->expectException(BadRequestException::class);
$this->expectExceptionMessage('parentNodeId is required');
$this->useCase->execute(new BulkCreateNodesRequest(
textId: 0,
parentNodeId: null,
titlePrefix: 'Page',
count: 5,
));
}
public function test_throws_if_title_prefix_is_null(): void
{
$this->expectException(BadRequestException::class);
$this->expectExceptionMessage('titlePrefix is required');
$this->useCase->execute(new BulkCreateNodesRequest(
textId: 0,
parentNodeId: $this->parentNode->getId(),
titlePrefix: null,
count: 5,
));
}
public function test_throws_if_count_is_null(): void
{
$this->expectException(BadRequestException::class);
$this->expectExceptionMessage('count is required');
$this->useCase->execute(new BulkCreateNodesRequest(
textId: 0,
parentNodeId: $this->parentNode->getId(),
titlePrefix: 'Page',
count: null,
));
}
public function test_throws_if_count_is_less_than_one(): void
{
$this->expectException(BadRequestException::class);
$this->expectExceptionMessage('count must be at least 1');
$this->useCase->execute(new BulkCreateNodesRequest(
textId: 0,
parentNodeId: $this->parentNode->getId(),
titlePrefix: 'Page',
count: 0,
));
}
} }

View file

@ -2,7 +2,6 @@
namespace Tests\Unit\Node\UseCases; namespace Tests\Unit\Node\UseCases;
use App\Exceptions\BadRequestException;
use App\Node\Node; use App\Node\Node;
use App\Node\NodeRepository; use App\Node\NodeRepository;
use App\Node\UseCases\CreateNode; use App\Node\UseCases\CreateNode;
@ -112,28 +111,4 @@ class CreateNodeTest extends TestCase
parentNodeId: null, parentNodeId: null,
)); ));
} }
public function test_throws_if_text_id_is_null(): void
{
$this->expectException(BadRequestException::class);
$this->expectExceptionMessage('textId is required');
$this->useCase->execute(new CreateNodeRequest(
textId: null,
title: 'test',
parentNodeId: null,
));
}
public function test_throws_if_title_is_null(): void
{
$this->expectException(BadRequestException::class);
$this->expectExceptionMessage('title is required');
$this->useCase->execute(new CreateNodeRequest(
textId: 0,
title: null,
parentNodeId: null,
));
}
} }

View file

@ -2,7 +2,6 @@
namespace Tests\Unit\Plan\UseCases; namespace Tests\Unit\Plan\UseCases;
use App\Exceptions\BadRequestException;
use App\Node\CreateNodeDto; use App\Node\CreateNodeDto;
use App\Plan\UseCases\CreatePlan; use App\Plan\UseCases\CreatePlan;
use App\Plan\UseCases\CreatePlanRequest; use App\Plan\UseCases\CreatePlanRequest;
@ -126,40 +125,4 @@ class CreatePlanTest extends TestCase
$this->scheduledNodeRepo->getNumberOfTimesCreateCalled() $this->scheduledNodeRepo->getNumberOfTimesCreateCalled()
); );
} }
public function test_throws_if_user_id_is_null(): void
{
$this->expectException(BadRequestException::class);
$this->expectExceptionMessage('userId is required');
$this->useCase->execute(new CreatePlanRequest(
userId: null,
name: 'testPlan',
textId: 0,
));
}
public function test_throws_if_text_id_is_null(): void
{
$this->expectException(BadRequestException::class);
$this->expectExceptionMessage('textId is required');
$this->useCase->execute(new CreatePlanRequest(
userId: 0,
name: 'testPlan',
textId: null,
));
}
public function test_throws_if_name_is_null(): void
{
$this->expectException(BadRequestException::class);
$this->expectExceptionMessage('name is required');
$this->useCase->execute(new CreatePlanRequest(
userId: 0,
name: null,
textId: 0,
));
}
} }

View file

@ -2,7 +2,6 @@
namespace Tests\Unit\ScheduledNode\UseCases; namespace Tests\Unit\ScheduledNode\UseCases;
use App\Exceptions\BadRequestException;
use App\Plan\CreatePlanDto; use App\Plan\CreatePlanDto;
use App\Plan\Plan; use App\Plan\Plan;
use App\ScheduledNode\ScheduledNode; use App\ScheduledNode\ScheduledNode;
@ -76,30 +75,4 @@ class CreateScheduledNodeTest extends TestCase
) )
); );
} }
public function test_throws_if_date_is_null(): void
{
$this->expectException(BadRequestException::class);
$this->expectExceptionMessage('date is required');
$this->useCase->execute(
new CreateScheduledNodeRequest(
date: null,
planId: 0,
)
);
}
public function test_throws_if_plan_id_is_null(): void
{
$this->expectException(BadRequestException::class);
$this->expectExceptionMessage('planId is required');
$this->useCase->execute(
new CreateScheduledNodeRequest(
date: new DateTimeImmutable('now'),
planId: null,
)
);
}
} }

View file

@ -2,7 +2,6 @@
namespace Tests\Unit\Text\UseCases; namespace Tests\Unit\Text\UseCases;
use App\Exceptions\BadRequestException;
use App\Text\Text; use App\Text\Text;
use App\Text\TextRepository; use App\Text\TextRepository;
use App\Text\UseCases\CreateText; use App\Text\UseCases\CreateText;
@ -52,14 +51,4 @@ class CreateTextTest extends TestCase
$this->assertEquals('my text', $rootNode->getTitle()); $this->assertEquals('my text', $rootNode->getTitle());
$this->assertNull($rootNode->getParentNode()); $this->assertNull($rootNode->getParentNode());
} }
public function test_throws_if_name_is_null(): void
{
$this->expectException(BadRequestException::class);
$this->expectExceptionMessage('name is required');
$this->useCase->execute(new CreateTextRequest(
name: null,
));
}
} }

View file

@ -2,7 +2,6 @@
namespace Tests\Unit\User\UseCases; namespace Tests\Unit\User\UseCases;
use App\Exceptions\BadRequestException;
use App\User\User; use App\User\User;
use App\User\UseCases\CreateUser; use App\User\UseCases\CreateUser;
use App\User\UseCases\CreateUserRequest; use App\User\UseCases\CreateUserRequest;
@ -22,17 +21,4 @@ class CreateUserTest extends TestCase
$this->assertInstanceOf(User::class, $user); $this->assertInstanceOf(User::class, $user);
$this->assertEquals('test@test.com', $user->getEmail()); $this->assertEquals('test@test.com', $user->getEmail());
} }
public function test_throws_if_email_is_null(): void
{
$userRepo = new FakeUserRepository();
$useCase = new CreateUser($userRepo);
$this->expectException(BadRequestException::class);
$this->expectExceptionMessage('email is required');
$useCase->execute(new CreateUserRequest(
email: null,
));
}
} }

View file

@ -84,24 +84,4 @@ class TextControllerTest extends TestCase
$response->getBody() $response->getBody()
); );
} }
public function test_create_text_returns_400_when_name_missing(): void
{
$request = new ServerRequestFactory()
->createServerRequest('POST', 'http://localhost/texts')
->withParsedBody([]);
$response = $this->controller->createText(
$request,
new Response(),
new CreateText(
$this->textRepo,
new FakeNodeRepository(),
),
);
$this->assertEquals(400, $response->getStatusCode());
$body = json_decode($response->getBody(), true);
$this->assertArrayHasKey('error', $body);
}
} }