Sử dụng Service Layer và Repository trong Laravel
Bài đăng này đã không được cập nhật trong 2 năm
Giới thiệu
Repository
thường là nơi các bạn viết các câu truy vấn database. Trong một ứng dụng, ta thường phải xử lý dữ liệu trước khi lưu vào database hoặc trước khi trả về. Thông thường ta viết luôn các đoạn xử lý đó ở trong controller
dẫn đến tình trạng controller bị phình to ra và rất khó đọc nếu ta có quá nhiều đoạn xử lý logic đó. Ta có một giải pháp đó là xử dụng Service Layer
.
"Service Layer" nằm ở giữa phần UI và phần backend lưu dữ liệu. Nó phụ trách việc biến đổi và thông dịch dữ liệu giữa 2 tầng với nhau
về cơ bản thì, Service Layer nằm ở giữa tầng trình diễn và tầng dữ liệu. Vậy nên, đây là nơi bạn viết logic của ứng dụng. Trong bài này, ứng dụng của chúng ta sẽ có 5 tầng:
UI > Controller > Service > Repository > Model/Database
Bắt đầu
Chúng ta sẽ cùng nhau xây dựng một ứng dụng CRUD post
sử dụng cả Service Layer và Repository.
Chúng ta có 2 model là Post
và Tag
được định nghĩa như sau
Post Model
định nghĩa các trường có thể fillable
<?php
namespace App;
use App\Tag;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
protected $filable = [
'title',
'content',
];
public function tags()
{
return $this->belongsToMany(Tag::class);
}
}
Tag Model
<?php
namespace App;
use App\Post;
use Illuminate\Database\Eloquent\Model;
class Tag extends Model
{
protected $filable = [
'name',
];
public function posts()
{
return $this->belongsToMany(Post::class);
}
}
PostRepositoty
<?php
namespace App\Repositories;
use App\Post;
class PostRepository
{
protected $post;
public function __construct(Post $post)
{
$this->post = $post;
}
public function create($attributes)
{
return $this->post->create($attributes);
}
}
TagRepository
<?php
namespace App\Repositories;
use App\Tag;
class TagRepository
{
protected $tag;
public function __construct(Tag $tag)
{
$this->tag = $tag;
}
public function insert(array $values)
{
return $this->tag->insert($values);
}
public function findByName(array $names)
{
return $this->tag->whereIn('name', $names)->get();
}
}
PostService
Giả sử, khi tạo 1 post mới ta sẽ cho phép người dùng nhập tag cho post, dữ liệu truyền sang serve là biến names
có dạng là array
. Chúng ta sẽ phải kiểm tra xem tag đã có trong csdl chưa và chỉ lưu vào những tag mới.
<?php
namespace App\Services;
use Illuminate\Http\Request;
use App\Repositories\TagRepository;
use App\Repositories\PostRepository;
class PostService
{
public function __construct(PostRepository $postRepository, TagRepository $tagRepository)
{
$this->postRepository = $postRepository;
$this->tagRepository = $tagRepository;
}
public function create(Request $request)
{
$attributes = $request->except('names');
$names = $request->names;
$count = count($names);
$tags = $this->tagRepository->findByName($names); // lấy các tag dựa vào name
$duplicateNames = [];
for ($i = 0; $i < $count; $i++) { // lấy các tag đã tồn tại trong csdl
foreach ($tags as $tag) {
if ($names[$i] === $tag->name) {
array_push($duplicateNames, $names[$i]);
}
}
}
$newNames = array_diff($names, $duplicateNames); // loại bỏ các tag đã tồn tại
$this->tagRepository->insert($newNames); // lưu các tag mới vào csdl
$post = $this->postRepository->create($attributes); // lưu post
$tagIds = $this->tagRepository->findByName($names)->pluck('ids')->toArray();
$post->sync($tagIds); // cập nhật tag cho post
return $post;
}
}
PostController
khi đã đẩy phần xử lý logic ở trong PostService
thì controller
của bạn sẽ cực kì thon gọn.
<?php
namespace App\Http\Controllers;
use App\Services\PostService;
use App\Http\Requests\PostRequest;
class PostController
{
protected $postservice;
public function __construct(PostService $postservice)
{
$this->postService = $postService;
}
public function create(PostRequest $request)
{
$this->postService->create($request);
return back()->with(['status' => 'Post created successfully']);
}
}
Tài liệu tham khảo
https://m.dotdev.co/design-pattern-service-layer-with-laravel-5-740ff0a7b65f https://medium.com/@smayzes/how-do-you-work-in-laravel-5a763fe5c5a0
All rights reserved