- vừa được xem lúc

Handle for multiple timezone in Laravel

0 0 5

Người đăng: Nguyen Ngoc

Theo Viblo Asia

Giả dụ bạn đang làm một dự án mà ứng dụng của họ được sử dụng ở nhiều quốc gia, vậy thì mỗi nơi khác nhau lại có một múi giờ riêng (VD như Việt Nam và Nhật Bản múi giờ chênh lệch nhau 2h) dẫn đến việc lưu timestamp trong DB sẽ bị conflict và sẽ có lúc hiển thị time sai.

Vậy cách giải quyết vấn đề này là gì? Thì trong bài viết hôm nay mình xin hướng dẫn các bạn set multiple timezone trong project laravel nha! cumming nạ ???

1. Giới thiệu

Như mọi người cũng biết Laravel cũng cấp cho chúng ta folder config - dùng để chứa các file cấu hình cho Laravel. Và mặc định khi bạn create 1 project Laravel timezone default sẽ được set mặc định trong file config/app.php và mình có thể thay đổi nó thành bất kỳ múi giờ nào bạn mong muốn ạ.

 /* |-------------------------------------------------------------------------- | Application Timezone |-------------------------------------------------------------------------- | | Here you may specify the default timezone for your application, which | will be used by the PHP date and date-time functions. We have gone | ahead and set this to a sensible default for you out of the box. | */ 'timezone' => 'UTC',

Tuy nhiên lại quay lại bài toán ở trên, vậy nếu mình muốn sử dụng nhiều timezone khác nhau thì sao? làm cách nào? Thì bây giờ chúng mình cùng đọc tiếp phần 2 của mình nhé!

2. Các bước thực hiện

1. Create project

Bước đầu tiên mình sẽ tạo 1 project Laravel bằng cách run comman sau:

composer create-project laravel/laravel multi-timezone

Trong ví dụ demo này mình bỏ qua các bước setup và seed data, mình sử dụng luôn table có sẵn users. Sau khi create xong project mình tìm đến file config/app.php và tìm đến 'timezone' để set timezone mặc định chúng ta sẽ sử dụng nè. VD ở đây mình sẽ set timezone mặc định là Tokyo

'timezone' => env('TIMEZONE', 'Asia/Tokyo'),

Bước tiếp theo chúng ta sẽ create TimeZoneMiddleware và cấu hình cho nó nhé!

2. Create TimeZoneMiddleware

Run comman: php artisan make:middleware TimeZoneMiddleware

Sau khi câu lệnh chạy xong, mình sẽ đi đăng ký middleware trong app/Http/Kernel.php tại thuộc tính $routeMiddleware để gán middleware đó cho một route cụ thể.

 protected $routeMiddleware = [ \\ other middlewares 'timezone' => \App\Http\Middleware\TimeZoneMiddleware::class, ];

PHP cung cấp cho chúng ta hàm date_default_timezone_set() và dùng để set giá trị timezone cho hệ thống, sau khi set thì tất cả các hàm xử lí thời gian sẽ sử dụng timezone này. Sau khi cấu hình cho TimeZoneMiddleware thì mình có một file app/Http/Middleware/TimeZoneMiddleware.php như sau:

<?php namespace App\Http\Middleware; use Closure; class TimeZoneMiddleware
{ /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle($request, Closure $next) { $timezone = ($request->hasHeader('X-Timezone')) ? $request->header('X-Timezone') : config('app.timezone'); date_default_timezone_set($timezone); return $next($request); }
}

Ở đây mình sẽ thực hiện kiểm tra header request truyền lên. Và nếu k gửi lên X-Timezone thì mình set nó sử dụng giá trị mặc định trong file config/app.php. Ting ting vậy là mình đã đi được nửa chặng đường rồi đó ạ hí hí.

3. SetAttribute and GetAttribute in BaseModel

Giờ đây các bạn có thể hình dung cách mình giải quyết bài toán trên đó là trong database của chúng ta mình chỉ lưu trữ dữ liệu timestamp ở một dạng mặc định. Từ đó dựa vào timezone truyền lên mà chúng ta có thể set và get dữ liệu ra đúng như mình mong muốn.

Laravel đã cung cấp Eloquent: Mutators khá hay - đó là khi bạn set hoặc get một attributes nào đó đã được định nghĩa thì mỗi lần ta call đến attributes đó đều auto chạy vào function setAttribute/getAttribute. Để biết thêm chi tiết các bạn đọc ở đây nhé! Ở đây mình có tạo 1 BaseModel và model User được extend từ đây, trong này có viết 2 function setAttribute and getAttribute như sau:

<?php namespace App\Models; use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Database\Eloquent\Model; class BaseModel extends Model
{ /** * Set a given attribute on the model. * * @param string $key * @param mixed $value * @return mixed */ public function setAttribute($key, $value) { $array = [ 'created_at', 'updated_at', ]; if (in_array($key, $array)) { $timezone = new \DateTime('now'); if (!($value instanceof Carbon)) { $value = Carbon::parse($value); } return $this->attributes[$key] = Carbon::createFromFormat('Y-m-d H:i:s', $value, $timezone->getTimezone()) ->setTimezone(config('app.timezone')); } return parent::setAttribute($key, $value); } /** * Get an attribute from the model. * * @param string $key * @return mixed */ public function getAttribute($key) { $array = [ 'created_at', 'updated_at', ]; if (in_array($key, $array)) { $timezone = new \DateTime('now'); $value = $this->getAttributeValue($key); if (!($value instanceof Carbon)) { $value = Carbon::parse($value); } return Carbon::createFromFormat('Y-m-d H:i:s', $value, config('app.timezone')) ->setTimezone($timezone->getTimezone()); } return parent::getAttribute($key); }
}

Nhìn tên function chúng ta cũng lờ mờ đoán ra ý nghĩa của chúng đúng k ạ, Tuy nhiên mình vẫn sẽ giải thích qua một chút nhé:

  • function setAttribute(): sẽ được gọi đến khi bạn create/update 1 record có thao tác với attributes đã được định nghĩa trong function.
  • function getAttribute(): sẽ được gọi đến khi bạn get records có thao tác với attributes đã được định nghĩa trong function.

Và giờ đây muốn sử dụng chúng ta chỉ cần thêm middleware đó vào trc mỗi API cần dùng và truyền lên Headers X-Token là uki nạ: VD

Route::group(['prefix' => 'v1', 'namespace' => 'Api\V1', 'middleware' => ['timezone']], function () { Route::resource('users', 'UsersController');
});

Sau khi cấu hình xong tất cả, bây giờ mỗi lần bạn create/update mặc định created_at or updated_at sẽ mặc định chuyển và lưu time theo múi giờ Tokyo, thật tiện lợi phải không ạ.

3. Kết luận

Bài viết này mình đã chia sẻ với mọi người về cách config khi làm việc với dự án nhiều timezone bằng việc đưa bài toán về dạng lưu một dạng timezone mặc định trong database. Rất vui được khi được mọi người đọc bài và ủng hộ ạ ❤️

Bình luận

Bài viết tương tự

- vừa được xem lúc

Tìm hiểu về Resource Controller trong Laravel

Giới thiệu. Trong laravel, việc sử dụng các route post, get, group để gọi đến 1 action của Controller đã là quá quen đối với các bạn sử dụng framework này.

0 0 335

- vừa được xem lúc

Phân quyền đơn giản với package Laravel permission

Như các bạn đã biết, phân quyền trong một ứng dụng là một phần không thể thiếu trong việc phát triển phần mềm, dù đó là ứng dụng web hay là mobile. Vậy nên, hôm nay mình sẽ giới thiệu một package có thể giúp các bạn phân quyền nhanh và đơn giản trong một website được viết bằng PHP với framework là L

0 0 421

- vừa được xem lúc

Sử dụng Swagger để xây dựng API documentation

Giới thiệu về Swagger. RESTful API là một tiêu chuẩn dùng trong việc thiết kế API cho các ứng dụng web (thiết kế Web services) để tiện cho việc quản lý các resource.

0 0 1k

- vừa được xem lúc

Ví dụ CRUD với Laravel và Vuejs.

1. Cài đặt Laravel. composer create-project --prefer-dist laravel/laravel vuelaravelcrud. .

0 0 141

- vừa được xem lúc

Một số tips khi dùng laravel (Part 1)

1. Show database query in raw SQL format. DB::enableQueryLog(); // Bật tính năng query logging. DB::table('users')->get(); // Chạy truy vấn bạn muốn ghi log.

0 0 69

- vừa được xem lúc

Inertiajs - Xây dựng Single Page App không cần API

Tiêu đề là mình lấy từ trang chủ của https://inertiajs.com/ chứ không phải mình tự nghĩ ra đâu nhé :v. Lâu lâu rồi chưa động tới Laravel (dự án cuối cùng mình code là ở ver 5.8), thế nên một ngày đẹp trời lượn vào đọc docs ver 8.

0 0 227