12/08/2018, 15:55
Counter Cache trong Laravel
1. Vấn đề Input : Cho 2 bảng: Products (id, name, comment_count,..) và Comments (id, product_id, content,..) có quan hệ 1-N. Output : Tự động tăng hoặc giảm Products.comment_count khi tạo hoặc xóa comment. 2. Thực hiện Cách 1 : Cách đơn giản nhất là khi nào khi nào comment mới ...
1. Vấn đề
Input:
- Cho 2 bảng: Products (id, name, comment_count,..) và Comments (id, product_id, content,..) có quan hệ 1-N.
Output:
- Tự động tăng hoặc giảm Products.comment_count khi tạo hoặc xóa comment.
2. Thực hiện
- Cách 1:
- Cách đơn giản nhất là khi nào khi nào comment mới được tạo ta sẽ thực hiện tăng comment_count lên 1 đơn vị, khi nào comment bị xóa ta sẽ giảm comment_count đi 1 đơn vị:
- Ở đây mình dùng trong Laravel, nên mình sẽ dùng migrate để tạo bảng
Schema::create('products', function (Blueprint $table) { $table->increments('id'); $table->string('name'); $table->integer('comments_count')->default(0); // This is the counter that you have to add $table->timestamps(); });
Schema::create('comments', function (Blueprint $table) { $table->increments('id'); $table->integer('product_id'); $table->string('content'); $table->timestamps(); });
- Chạy lệnh sau để tạo bảng: php artisan migrate
- Tiếp theo ta cần tạo giữa bảng comments và products trong model Comment:
public function product() { return $this->belongsTo('AppProduct'); }
- Đến đây thì xong rồi, ta chỉ cần thêm đoạn tăng giảm comment_count trong controller CommentController hoặc CommentService khi xóa hoặc tạo comment mới:
public function store(Request $request) { $data = $request->only(`content`, `product_id`); $comment = Comment::create($data); if ($comment) { $comment->product->increament("comment_count"); } ... }
- Và xóa comment:
public function delete($id) { $comment = Comment::find($id); if ($comment) { $comment->product->decreament("comment_count"); } ... }
- Hoặc nếu bạn không muốn viết xử lý tăng comment_count trong controller hay service, bạn có thể bắt sự kiện created, deleted để tự động tăng comment_count:
protected static function boot() { static::created(function ($comment) { $comment->product->increment('comment_count'); }); static::deleted(function ($comment) { $comment->product->decrement('comment_count'); }); }
- Hàm này được viết trong model Comment
- Cách trên có vẻ khá dễ và được ae sử dụng khá nhiều đúng không, Ở mình muốn giới thiệu đến 1 cách khác còn dễ hơn nữa:
- Cách 2:
-
Sử dụng package Counter Cache for Laravel:
-
Thêm vào dòng sau vào composer.js:
"kanazaca/counter-cache": "1.0.*"
-
Sau đó chạy lệnh composer install để cài đặt package
-
Thêm providers vào file config/app.php:
'providers' => array( // ... kanazacaCounterCacheCounterCacheServiceProvider::class, )
-
Đến đây, thay vì làm như cách 1, ta chỉ cần include package vào model Comment và khai báo đúng chuẩn là xong, việc tăng giảm comment_count để package lo:
namespace App; use IlluminateDatabaseEloquentModel; use kanazacaCounterCacheCounterCache; class Comments extends Model { use CounterCache; // you can have more than one counter public $counterCacheOptions = [ 'product' => [ 'field' => 'comment_count', 'foreignKey' => 'product_id', ] ]; public function product() { return $this->belongsTo('AppProduct'); } }
-
Nếu bạn muốn filter trước khi tăng count bạn có thể làm như sau:
public $counterCacheOptions = [ 'product' => [ 'field' => 'comment_count', 'foreignKey' => 'product_id', 'filter' => 'CommentValidatedFilter' ] ]; // you can have more than one counter // this code will be executed before the counting (save and update method) public function CommentValidatedFilter() { if ($this->validated) { return true; } return false; }
-