07/09/2018, 17:28

Laravel: tìm hiểu về cache

Laravel cung cấp một API thống nhất cho các caching backend khác nhau. Cấu hình cho cache được đặt trong file config/cache.php. Trong file này bạn có thể chỉ định cache driver nào bạn muốn sử dụng mặc định trong ứng dụng của bạn. Laravel hỗ trợ các hệ thông cache phổ biến như Memcached và Redis. ...



Laravel cung cấp một API thống nhất cho các caching backend khác nhau. Cấu hình cho cache được đặt trong file config/cache.php. Trong file này bạn có thể chỉ định cache driver nào bạn muốn sử dụng mặc định trong ứng dụng của bạn. Laravel hỗ trợ các hệ thông cache phổ biến như Memcached và Redis.
File cấu hình cache cũng chứa các tuỳ chọn khác nhau, đều được ghi chú đầy đủ bên trong file, do đó hãy nhớ đọc qua các tùy chọn này. Mặc định, Laravel được cấu hình để sửa dụng cache driver bằng file , nơi mà các serialized được lưu, các đối tương cached trong filesystem. Với các ứng dụng lớn hơn, bạn nên sử dụng các driver mạnh mẽ hơn như Memcached hay Redis. Bạn thậm chí có thẻ cấu hình để sử dụng nhiều cấu hình cache cho cùng một driver.

Driver Prerequisites

Database

Khi sử dụng cache driver database, bạn sẽ cần thiết lập một bảng để lưu trữ các cache items. Bạn sẽ thấy một ví dụ về khai báo Schema cho bảng dưới đây:

Schema::create('cache', function ($table) {
    $table->string('key')->unique();
    $table->text('value');
    $table->integer('expiration');
});

Memcached
Sử dụng Memcached driver yêu cầu Memcached PECL package phải được cài đặt. Bạn có thể list tất cả Memcached servers của bạn trong file cấu hình config/cache.php:

'memcached' => [
    [
        'host' => '127.0.0.1',
        'port' => 11211,
        'weight' => 100
    ],
],

Bạn cũng có thể thiết lập tùy chọn host tới một đường dẫn UNIX socket. Nếu làm thế này thì port cần được set về 0:

'memcached' => [
    [
        'host' => '/var/run/memcached/memcached.sock',
        'port' => 0,
        'weight' => 100
    ],
],

Redis
Trước khi sử dụng Redis cache với Laravel, bạn cần phải cài đặtpredis/predis package (~1.0) qua Composer hoặc cài đặt PhpRedis PHP extension qua PECL.

Thông tin thêm chi tiết về cấu hình cho Redis, hãy tham khảo Laravel documentation page.


Obtaining A Cache Instance

IlluminateContractsCacheFactory và IlluminateContractsCacheRepository contracts cung cấp truy xuất tới Laravel's cache services. Factory contract cung cấp truy cập tới tất cả các cache drivers được khai báo cho ứng dụng của bạn. Repository contract thường triển khai của cache driver mặc định cho ứng dụng mà bạn chỉ định trong file cấu hình cache.
Tuy nhiên, bạn cũng có thể sử dụng Cache facade, đó là những gì mà chúng ta sẽ sử dụng trong bài này. Cache facade cung cấp cách truy cập thuận tiện và ngắn gọn tới các implement của các Laravel contracts:

<?php

namespace AppHttpControllers;

use IlluminateSupportFacadesCache;

class UserController extends Controller
{
    /**
     * Show a list of all users of the application.
     *
     * @return Response
     */
    public function index()
    {
        $value = Cache::get('key');

        //
    }
}

Accessing Multiple Cache Stores
Sử dụng Cache facade, bạn có thể truy xuất tới nhiều cache store thông quan phương thức store. Giá trị khoá truyền vào phương thức store cần ứng với một trong những store được liệt kê trong mảng cấu hình stores trong file cache của bạn:

$value = Cache::store('file')->get('foo');

Cache::store('redis')->put('bar', 'baz', 10);


Retrieving Items From The Cache

Phương thức get trong Cache facade được sử dụng để lấy các items trong cache. Nếu như item không tồn tại trong cache, giá trị null sẽ được trả về. Nếu muốn, bạn có thể truyền vào tham số thứ hai để phương thức get chỉ định giá trị mặc định nếu như item không tồn tại:

$value = Cache::get('key');

$value = Cache::get('key', 'default');

Bạn thậm chí có thể truyền vào một Closure như một giá trị mặc định. Kết quả của Closure sẽ được trả về nếu item cần lấy không tồn tại trong cache. Truyền vào một Closure cho phép bạn trì hoãn lại việc lấy giá trị mặc định từ trong một database hay từ một dịch vụ bên ngoài:

$value = Cache::get('key', function () {
    return DB::table(...)->get();
});

Checking For Item Existence
Phương thức has có thể được sử dụng để kiểm tra xem một item có tồn tại trong cache hay không:

if (Cache::has('key')) {
    //
}

Incrementing / Decrementing Values
Phương thức increment và decrement có thể được sử dụng để điều chỉnh giá trị của các items số nguyên nằm trong cache. Cả hai hàm này có tuỳ chọn cho phép tham số thứ hai chỉ định giá trị tăng giảm bao nhiêu cho cache item:

Cache::increment('key');
Cache::increment('key', $amount);
Cache::decrement('key');
Cache::decrement('key', $amount);

Retrieve & Store
Đôi khi bạn muốn lấy ra một item trong cache, nhưng cũng muốn lưu giá trị mặc định cho item nếu như nó không tồn tại. Ví dụ, bạn muốn lấy tất cả users nằm trong cache hoặc, nếu chúng không tồn tại, thì sẽ lấy từ database và thêm vào trong cache. Bạn có thể thực hiện việc này bằng cách sử dụng phương thức Cache::remember:

$value = Cache::remember('users', $minutes, function () {
    return DB::table('users')->get();
});

Nếu item không tồn tại trong cache, thì Closure truyền vào trong phương thức remember sẽ được thực thi và kết quả sẽ được lưu lại vào trong cache.
Bạn cũng có thể sử dụng phương thức rememberForever để lấy lại một item từ trong cache hoặc store nó mãi mãi:

$value = Cache::rememberForever('users', function() {
    return DB::table('users')->get();
});

Retrieve & Delete
Nếu bạn muốn lấy ra một item trong cache và xoá đi, bạn có thể sử dụng phương thức pull. Giống như phương thức get, giá trị null sẽ được trả về nếu item không tồn tại trong cache từ trước đó:

$value = Cache::pull('key');


Storing Items In The Cache

Bạn có thể sử dụng phương thức put của Cache facade để lưu items vào trong cache. Khi bạn thêm một item vào trong cache, bạn sẽ cần phải chỉ rõ số phút mà giá trị sẽ được lưu:

Cache::put('key', 'value', $minutes);
```
Thay vì truyền vào số phút cho tới khi item bị hết hạn, bạn cũng có thể truyền vào một đối tượng PHP kiểu  ```DateTime``` để thể hiện thời gian hết hạn của item được cache:
```
$expiresAt = Carbon::now()->addMinutes(10);

Cache::put('key', 'value', $expiresAt);

Store If Not Present
Phương thức add sẽ chỉ thêm item vào cache nếu như nó chưa tồn tại. Phương thức này sẽ trả về true nếu item thực sự được thêm vào cache. Còn ngược lại thì hàm sẽ trả về false:

Cache::add('key', 'value', $minutes);

Storing Items Forever
Phương thức forever có thể được sử dụng để lưu một item trong cache vĩnh viễn. Những giá trị này cần phải được gỡ ra một cách thủ công bằng cách sử dụng phương thức forget:

Cache::forever('key', 'value');


Removing Items From The Cache

Bạn có thể bỏ các item từ cache bằng cách sử dụng phương thức forget:

Cache::forget('key');

Bạn có thể xoá toàn bộ cache bằng cách sử dụng phương thức flush:

Cache::flush();


The Cache Helper

Ngoài ra khi sử dụng Cache facade hoặc cache contract, bạn có thể sử dụng phương thức cache để nhận và lưu dữ liệu từ cache. Khi phương thức cache được gọi một mình, tham số string, nó sẽ trả về giá trị của key:

$value = cache('key');

Nếu bạn cung cấp một mảng của key / value và thời gian hết hạn của hàm, nó sẽ lưu giá trị vào cache với thời gian chỉ định:

cache(['key' => 'value'], $minutes);

cache(['key' => 'value'], Carbon::now()->addSeconds(10));



Storing Tagged Cache Items

Cache tag cho phép bạn tag các item liên quan tới nhau trong cache và sau đó flush hết các giá trị cache mà có chung một tag. Bạn có thể truy xuất vào một cache được tag bằng cách truyền vào một mảng các tên tag. Ví dụ, hãy truy cập một tagged cache và put giá trị vào cache:

Cache::tags(['people', 'artists'])->put('John', $john, $minutes);

Cache::tags(['people', 'authors'])->put('Anne', $anne, $minutes);


Accessing Tagged Cache Items

Để lấy một cache item được tag, truyền vào list tương tự các tag trong phương thức tags và sau đó gọi phương thức get với key bạn muốn nhận:

$john = Cache::tags(['people', 'artists'])->get('John');

$anne = Cache::tags(['people', 'authors'])->get('Anne');


Removing Tagged Cache Items

Bạn có thể flush tất cả các item có chung một tag hoặc danh sách các tag. Ví dụ, mã lệnh sau sẽ xoá tất cả các cache được tag với giá trị là people, authors, hoặc cả hai. Vì vậy, cả Anne và John sẽ bị xóa khỏi cache:

Cache::tags(['people', 'authors'])->flush();

Ngược lại, câu lệnh này sẽ chỉ xoá các cache có tag là authors, vì vậy Anne sẽ bị xoá, còn John thì không:

Cache::tags('authors')->flush();



Writing The Driver

Để viết một tùy biến cache driver, đầu tiên chúng ta cần thực thi IlluminateContractsCacheStore contract contract. Vì vậy, MongoDB cache thực thi sẽ giống như sau:

<?php

namespace AppExtensions;

use IlluminateContractsCacheStore;

class MongoStore implements Store
{
    public function get($key) {}
    public function many(array $keys);
    public function put($key, $value, $minutes) {}
    public function putMany(array $values, $minutes);
    public function increment($key, $value = 1) {}
    public function decrement($key, $value = 1) {}
    public function forever($key, $value) {}
    public function forget($key) {}
    public function flush() {}
    public function getPrefix() {}
}

Chúng ta chỉ cần thực thi mỗi phương thức khi sử dụng kết nối MongoDB. Một ví dụ: làm thế nào để thực thi các phương thức đó, để ý trong IlluminateCacheMemcachedStore. Khi chúng ta đã triển khai, chúng ta có thể hoàn tất đăng ký custom driver của mình.

Cache::extend('mongo', function ($app) {
    return Cache::repository(new MongoStore);
});


Registering The Driver

Để đăng ký custom cache driver với Laravel, chúng ta sử dụng phương thức extend trong Cache facade. Gọi Cache::extend có thể được thực hiện trong phương thức boot của AppProvidersAppServiceProvider mặc định, hoặc bạn có thể tạo tùy biến service provider để mở rộng - đừng quên đăng ký provider trong mảng provider config/app.php:

<?php

namespace AppProviders;

use AppExtensionsMongoStore;
use IlluminateSupportFacadesCache;
use IlluminateSupportServiceProvider;

class CacheServiceProvider extends ServiceProvider
{
    /**
     * Perform post-registration booting of services.
     *
     * @return void
     */
    public function boot()
    {
        Cache::extend('mongo', function ($app) {
            return Cache::repository(new MongoStore);
        });
    }

    /**
     * Register bindings in the container.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

Tham số đầu tiên truyền vào phương thức extend là tên của driver. Nó tương ứng với driver của bạn lựa chọn trong file cấu hình config/cache.php. Tham số thứ hai là một Closure nên trả về một IlluminateCacheRepository instance. Closure sẽ truyền vào một $app instance, nó là instance của service container.

Khi mở rộng của bạn được đăng ký, đơn giản chỉ cần cập nhật file cấu hình config/cache.php driver giống với tên của extension của bạn.



Để thực thi code mỗi khi có một thao tác làm việc với cache xảy ra, bạn có thể lắng nghe các events được bắn vào từ cache. Về cơ bản, bạn nên đặt những phần này vào trong EventServiceProvider:

/**
 * The event listener mappings for the application.
 *
 * @var array
 */
protected $listen = [
    'IlluminateCacheEventsCacheHit' => [
        'AppListenersLogCacheHit',
    ],

    'IlluminateCacheEventsCacheMissed' => [
        'AppListenersLogCacheMissed',
    ],

    'IlluminateCacheEventsKeyForgotten' => [
        'AppListenersLogKeyForgotten',
    ],

    'IlluminateCacheEventsKeyWritten' => [
        'AppListenersLogKeyWritten',
    ],
];
0