diff --git a/src/app/Packages/Domains/Interface/UserRepositroyInterface.php b/src/app/Packages/Domains/Interface/UserRepositroyInterface.php index cad8f5e..5c9af12 100644 --- a/src/app/Packages/Domains/Interface/UserRepositroyInterface.php +++ b/src/app/Packages/Domains/Interface/UserRepositroyInterface.php @@ -12,4 +12,6 @@ public function createUser(UserEntity $entity): UserDto; public function findById(int $id): ?UserDto; public function updateUser(UserEntity $entity): UserDto; + + public function deleteUser(int $id): void; } \ No newline at end of file diff --git a/src/app/Packages/Domains/Tests/UserRepositoryTest.php b/src/app/Packages/Domains/Tests/UserRepositoryTest.php index 9262cfd..96c3be0 100644 --- a/src/app/Packages/Domains/Tests/UserRepositoryTest.php +++ b/src/app/Packages/Domains/Tests/UserRepositoryTest.php @@ -121,4 +121,21 @@ public function test_updateUser_throws_exception_when_user_not_found(): void $this->repository()->updateUser($entity); } + + public function test_deleteUser_removes_user_when_exists(): void + { + $user = $this->seedUser(); + + $this->repository()->deleteUser($user->id); + + $this->assertDatabaseMissing('users', ['id' => $user->id]); + } + + public function test_deleteUser_throws_exception_when_user_not_found(): void + { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('User not found.'); + + $this->repository()->deleteUser(999999); + } } \ No newline at end of file diff --git a/src/app/Packages/Domains/UserRepository.php b/src/app/Packages/Domains/UserRepository.php index 87166cd..8794058 100644 --- a/src/app/Packages/Domains/UserRepository.php +++ b/src/app/Packages/Domains/UserRepository.php @@ -66,4 +66,15 @@ public function updateUser(UserEntity $entity): UserDto return UserDtoFactory::build($user->toArray()); } + + public function deleteUser(int $id): void + { + $user = $this->userModel->find($id); + + if ($user === null) { + throw new Exception('User not found.'); + } + + $user->delete(); + } } \ No newline at end of file diff --git a/src/app/Packages/Features/CommandUseCases/UseCase/User/DeleteUserUseCase.php b/src/app/Packages/Features/CommandUseCases/UseCase/User/DeleteUserUseCase.php new file mode 100644 index 0000000..d13b437 --- /dev/null +++ b/src/app/Packages/Features/CommandUseCases/UseCase/User/DeleteUserUseCase.php @@ -0,0 +1,17 @@ +userRepository->deleteUser($id); + } +} diff --git a/src/app/Packages/Features/Controller/UserController.php b/src/app/Packages/Features/Controller/UserController.php index 9917562..49589f8 100644 --- a/src/app/Packages/Features/Controller/UserController.php +++ b/src/app/Packages/Features/Controller/UserController.php @@ -5,6 +5,7 @@ use App\Http\Controllers\Controller; use App\Packages\Features\QueryUseCases\Factory\ViewModel\UserViewModelFactory; use App\Packages\Features\CommandUseCases\UseCase\User\CreateUserUseCase; +use App\Packages\Features\CommandUseCases\UseCase\User\DeleteUserUseCase; use App\Packages\Features\CommandUseCases\UseCase\User\UpdateUserUseCase; use App\Packages\Features\CommandUseCases\UseCommand\User\CreateUserCommand; use App\Packages\Features\CommandUseCases\UseCommand\User\UpdateUserCommand; @@ -81,6 +82,36 @@ public function updateUser( } } + public function deleteUser( + Request $request, + DeleteUserUseCase $useCase, + ): JsonResponse { + try { + $useCase->handle((int) $request->route('id')); + + return response()->json([ + 'status' => 'success', + ], 200); + } catch (\Exception $exception) { + if ($exception->getMessage() === 'User not found.') { + return response()->json([ + 'status' => 'error', + 'message' => 'User not found.', + ], 404); + } + + Log::error('Failed to delete user', [ + 'message' => $exception->getMessage(), + 'trace' => $exception->getTraceAsString(), + ]); + + return response()->json([ + 'status' => 'error', + 'message' => 'Internal Server Error', + ], 500); + } + } + public function createUser( Request $request, CreateUserUseCase $useCase, diff --git a/src/app/Packages/Features/Tests/CommandUseCases/DeleteUserUseCaseTest.php b/src/app/Packages/Features/Tests/CommandUseCases/DeleteUserUseCaseTest.php new file mode 100644 index 0000000..e052074 --- /dev/null +++ b/src/app/Packages/Features/Tests/CommandUseCases/DeleteUserUseCaseTest.php @@ -0,0 +1,45 @@ +shouldReceive('deleteUser') + ->once() + ->with(1); + + (new DeleteUserUseCase($repository))->handle(1); + } + + public function test_handle_propagates_exception_when_user_not_found(): void + { + /** @var UserRepositroyInterface|MockInterface $repository */ + $repository = Mockery::mock(UserRepositroyInterface::class); + $repository->shouldReceive('deleteUser') + ->once() + ->with(999999) + ->andThrow(new \Exception('User not found.')); + + $this->expectException(\Exception::class); + $this->expectExceptionMessage('User not found.'); + + (new DeleteUserUseCase($repository))->handle(999999); + } +} diff --git a/src/app/Packages/Features/Tests/DeleteUserTest.php b/src/app/Packages/Features/Tests/DeleteUserTest.php new file mode 100644 index 0000000..7b78711 --- /dev/null +++ b/src/app/Packages/Features/Tests/DeleteUserTest.php @@ -0,0 +1,70 @@ +truncate(); + } + + protected function tearDown(): void + { + $this->truncate(); + parent::tearDown(); + } + + private function truncate(): void + { + if (env('APP_ENV') === 'testing') { + DB::connection('mysql')->statement('SET FOREIGN_KEY_CHECKS=0;'); + User::truncate(); + DB::connection('mysql')->statement('SET FOREIGN_KEY_CHECKS=1;'); + } + } + + private function seedUser(array $overrides = []): User + { + $faker = FakerFactory::create(); + + return User::create(array_merge([ + 'first_name' => $faker->firstName(), + 'last_name' => $faker->lastName(), + 'email' => $faker->unique()->safeEmail(), + 'password' => bcrypt('password'), + 'age_range' => 'teens', + 'subscription_tier' => 'free', + 'subscription_expires_at' => null, + ], $overrides)); + } + + public function test_delete_user_returns_200_when_user_exists(): void + { + $user = $this->seedUser(); + + $response = $this->deleteJson("/api/v1/users/{$user->id}"); + + $response->assertStatus(200) + ->assertJsonFragment(['status' => 'success']); + + $this->assertDatabaseMissing('users', ['id' => $user->id]); + } + + public function test_delete_user_returns_404_when_user_not_found(): void + { + $response = $this->deleteJson('/api/v1/users/999999'); + + $response->assertStatus(404) + ->assertJsonFragment([ + 'status' => 'error', + 'message' => 'User not found.', + ]); + } +} diff --git a/src/routes/api.php b/src/routes/api.php index a3d59bd..d39dc95 100644 --- a/src/routes/api.php +++ b/src/routes/api.php @@ -12,5 +12,6 @@ Route::get('/users/{id}', [UserController::class, 'getUserById']); Route::patch('/users/{id}', [UserController::class, 'updateUser']); + Route::delete('/users/{id}', [UserController::class, 'deleteUser']); Route::post('/user/create', [UserController::class, 'createUser']); }); \ No newline at end of file