Skip to content

Commit 687c993

Browse files
committed
Update Book Repository Pattern
Add Unit Test for BookService.php
1 parent 2e7e726 commit 687c993

File tree

9 files changed

+530
-187
lines changed

9 files changed

+530
-187
lines changed

app/Exceptions/BookNotDeletedException.php

Lines changed: 0 additions & 19 deletions
This file was deleted.

app/Http/Controllers/BookController.php

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace App\Http\Controllers;
44

5+
use App\Exceptions\BookNotFoundException;
6+
use App\Exceptions\PublisherNotFoundException;
57
use App\Http\Requests\StoreBookRequest;
68
use App\Http\Requests\UpdateBookRequest;
79
use App\Http\Resources\BookResource;
@@ -23,45 +25,47 @@ public function __construct(
2325
*/
2426
public function index()
2527
{
26-
$books = $this->bookService->all();
27-
return BookResource::collection($books);
28+
$books = $this->bookService->getAllBooks();
29+
return new BookResourceCollection($books);
2830
}
2931

3032
/**
3133
* Store a newly created resource in storage.
3234
*
3335
* @param StoreBookRequest $request
34-
* @return BookResource
36+
* @return JsonResponse
3537
*/
36-
public function store(StoreBookRequest $request): BookResource
38+
public function store(StoreBookRequest $request): JsonResponse
3739
{
38-
$book = $this->bookService->create($request->validated());
39-
return new BookResource($book);
40+
$book = $this->bookService->createBook($request->validated());
41+
return response()->json(new BookResource($book), 201);
4042
}
4143

4244
/**
4345
* Display the specified resource.
4446
*
4547
* @param int $id
46-
* @return BookResource
48+
* @return JsonResponse
49+
* @throws BookNotFoundException
4750
*/
48-
public function show(int $id): BookResource
51+
public function show(int $id): JsonResponse
4952
{
50-
$book = $this->bookService->show($id);
51-
return new BookResource($book);
53+
$book = $this->bookService->findBookById($id);
54+
return response()->json(new BookResource($book));
5255
}
5356

5457
/**
5558
* Update the specified resource in storage.
5659
*
5760
* @param UpdateBookRequest $request
5861
* @param int $id
59-
* @return BookResource
62+
* @return JsonResponse
63+
* @throws PublisherNotFoundException
6064
*/
61-
public function update(UpdateBookRequest $request, int $id): BookResource
65+
public function update(UpdateBookRequest $request, int $id): JsonResponse
6266
{
63-
$book = $this->bookService->update($id, $request->validated());
64-
return new BookResource($book);
67+
$book = $this->bookService->updateBook($id, $request->validated());
68+
return response()->json(new BookResource($book), JsonResponse::HTTP_OK);
6569
}
6670

6771
/**
@@ -72,6 +76,7 @@ public function update(UpdateBookRequest $request, int $id): BookResource
7276
*/
7377
public function destroy(int $id): bool|JsonResponse
7478
{
75-
return $this->bookService->delete($id);
79+
$this->bookService->deleteBook($id);
80+
return response()->json(null, JsonResponse::HTTP_NO_CONTENT);
7681
}
7782
}

app/Http/Resources/BookResourceCollection.php

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,15 @@ class BookResourceCollection extends ResourceCollection
1515
*/
1616
public function toArray(Request $request): array
1717
{
18-
return $this->collection->map(
19-
function ($item) use ($request) {
20-
return $item instanceof BookResource ? $item->toArray($request) : [];
21-
}
22-
)->all();
18+
return [
19+
'data' => $this->collection->map(
20+
function ($item) use ($request) {
21+
return $item instanceof BookResource ? $item->toArray($request) : [];
22+
}
23+
)->all(),
24+
'meta' => [
25+
'total' => $this->collection->count(),
26+
],
27+
];
2328
}
2429
}

app/Interfaces/BookRepositoryInterface.php

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,37 +4,36 @@
44

55
use App\Models\Book;
66
use Illuminate\Database\Eloquent\Collection;
7-
use Illuminate\Http\JsonResponse;
87

98
interface BookRepositoryInterface
109
{
1110
/**
1211
* @return Collection<int, Book>
1312
*/
14-
public function all(): Collection;
13+
public function getAllBooks(): Collection;
1514

1615
/**
17-
* @param array<string, mixed> $data
16+
* @param int $id
1817
* @return Book
1918
*/
20-
public function create(array $data): Book;
19+
public function findBookById(int $id): ?Book;
2120

2221
/**
23-
* @param int $id
22+
* @param array<string, mixed> $data
2423
* @return Book
2524
*/
26-
public function show(int $id): Book;
25+
public function createBook(array $data): Book;
2726

2827
/**
29-
* @param array<string, mixed> $data
3028
* @param int $id
29+
* @param array<string, mixed> $data
3130
* @return Book
3231
*/
33-
public function update(array $data, int $id): Book;
32+
public function updateBook(int $id, array $data): Book;
3433

3534
/**
3635
* @param int $id
37-
* @return JsonResponse
36+
* @return bool|null
3837
*/
39-
public function delete(int $id): JsonResponse;
38+
public function deleteBookById(int $id): ?bool;
4039
}

app/Providers/AppServiceProvider.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ public function register(): void
1919
{
2020
$this->app->bind(BookRepositoryInterface::class, BookRepository::class);
2121
$this->app->bind(BookService::class, function ($app) {
22-
return new BookService($app->make(BookRepositoryInterface::class));
22+
return new BookService(
23+
$app->make(BookRepositoryInterface::class),
24+
$app->make(PublisherRepositoryInterface::class),
25+
);
2326
});
2427

2528
$this->app->bind(PublisherRepositoryInterface::class, PublisherRepository::class);

app/Repositories/BookRepository.php

Lines changed: 17 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,79 +7,66 @@
77
use App\Interfaces\BookRepositoryInterface;
88
use App\Models\Book;
99
use Illuminate\Database\Eloquent\Collection;
10-
use Illuminate\Http\JsonResponse;
1110

1211
class BookRepository implements BookRepositoryInterface
1312
{
1413
/**
1514
* @return Collection<int, Book>
1615
*/
17-
public function all(): Collection
16+
public function getAllBooks(): Collection
1817
{
1918
$books = Book::with('publisher')->get()->all();
2019
return Collection::make($books);
2120
}
2221

2322
/**
24-
* @param array<string, string> $data
25-
* @return Book
23+
* @param int $id
24+
* @return Book|null
2625
*/
27-
public function create(array $data): Book
26+
public function findBookById(int $id): ?Book
2827
{
29-
return Book::create($data);
28+
return Book::find($id) ?? null;
3029
}
3130

3231
/**
3332
* @param array<string, string> $data
34-
* @param int $id
3533
* @return Book
3634
*/
37-
public function update(array $data, int $id): Book
35+
public function createBook(array $data): Book
3836
{
39-
$book = Book::find($id);
40-
41-
if (!$book) {
42-
throw new BookNotFoundException();
43-
}
44-
45-
if ($book->update($data) && !empty($data['publisher_id'])) {
46-
$book->load('publisher');
47-
}
48-
49-
return $book;
37+
return Book::create($data);
5038
}
5139

5240
/**
5341
* @param int $id
42+
* @param array<string, string> $data
5443
* @return Book
55-
* @throws BookNotFoundException
5644
*/
57-
public function show(int $id): Book
45+
public function updateBook(int $id, array $data): Book
5846
{
59-
$book = Book::find($id);
47+
$book = $this->findBookById($id);
6048

6149
if (!$book) {
6250
throw new BookNotFoundException();
6351
}
6452

65-
$book->load('publisher');
53+
$book->update($data);
6654

6755
return $book;
6856
}
6957

7058
/**
7159
* @param int $id
72-
* @return JsonResponse
73-
* @throws BookNotDeletedException
60+
* @return bool|null
7461
*/
75-
public function delete(int $id): JsonResponse
62+
public function deleteBookById(int $id): ?bool
7663
{
77-
$book = Book::find($id);
64+
$book = $this->findBookById($id);
7865

79-
if (!$book || !$book->delete()) {
80-
throw new BookNotDeletedException();
66+
if (!$book) {
67+
return false;
8168
}
8269

83-
return response()->json(null, JsonResponse::HTTP_NO_CONTENT);
70+
return $book->delete();
8471
}
8572
}

app/Services/BookService.php

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,61 +2,99 @@
22

33
namespace App\Services;
44

5+
use App\Exceptions\BookNotFoundException;
6+
use App\Exceptions\PublisherNotFoundException;
57
use App\Interfaces\BookRepositoryInterface;
8+
use App\Interfaces\PublisherRepositoryInterface;
69
use App\Models\Book;
710
use Illuminate\Database\Eloquent\Collection;
8-
use Illuminate\Http\JsonResponse;
11+
use InvalidArgumentException;
912

1013
class BookService
1114
{
1215
public function __construct(
13-
protected BookRepositoryInterface $bookRepository
16+
protected BookRepositoryInterface $bookRepository,
17+
protected PublisherRepositoryInterface $publisherRepository,
1418
)
1519
{
1620
}
1721

1822
/**
1923
* @return Collection<int, Book>
2024
*/
21-
public function all(): Collection
25+
public function getAllBooks(): Collection
2226
{
23-
return $this->bookRepository->all();
27+
return $this->bookRepository->getAllBooks();
2428
}
2529

2630
/**
27-
* @param array<string, mixed> $data
28-
* @return Book
31+
* @param int $id
32+
* @return Book|null
33+
* @throws BookNotFoundException
2934
*/
30-
public function create(array $data): Book
35+
public function findBookById(int $id): ?Book
3136
{
32-
return $this->bookRepository->create($data);
37+
$book = $this->bookRepository->findBookById($id);
38+
39+
if (!$book) {
40+
throw new BookNotFoundException();
41+
}
42+
43+
if (isset($book->publisher_id)) {
44+
$book->load('publisher');
45+
}
46+
47+
return $book;
3348
}
3449

3550
/**
36-
* @param int $id
3751
* @param array<string, mixed> $data
3852
* @return Book
53+
* @throws PublisherNotFoundException
3954
*/
40-
public function update(int $id, array $data): Book
55+
public function createBook(array $data): Book
4156
{
42-
return $this->bookRepository->update($data, $id);
57+
if (isset($data['publisher_id'])) {
58+
if (!is_int($data['publisher_id'])) {
59+
throw new InvalidArgumentException('The publisher_id must be an integer.');
60+
}
61+
62+
$publisher = $this->publisherRepository->findPublisherById($data['publisher_id']);
63+
if (!$publisher) {
64+
throw new PublisherNotFoundException();
65+
}
66+
}
67+
return $this->bookRepository->createBook($data);
4368
}
4469

4570
/**
4671
* @param int $id
72+
* @param array<string, mixed> $data
4773
* @return Book
74+
* @throws PublisherNotFoundException
4875
*/
49-
public function show(int $id): Book
76+
public function updateBook(int $id, array $data): Book
5077
{
51-
return $this->bookRepository->show($id);
78+
if (isset($data['publisher_id'])) {
79+
if (!is_int($data['publisher_id'])) {
80+
throw new InvalidArgumentException('The publisher_id must be an integer.');
81+
}
82+
83+
$publisher = $this->publisherRepository->findPublisherById($data['publisher_id']);
84+
if (!$publisher) {
85+
throw new PublisherNotFoundException();
86+
}
87+
}
88+
89+
return $this->bookRepository->updateBook($id, $data);
5290
}
5391

5492
/**
5593
* @param int $id
56-
* @return JsonResponse
94+
* @return bool|null
5795
*/
58-
public function delete(int $id): JsonResponse
96+
public function deleteBook(int $id): ?bool
5997
{
60-
return $this->bookRepository->delete($id);
98+
return $this->bookRepository->deleteBookById($id);
6199
}
62100
}

0 commit comments

Comments
 (0)