Sử dụng Queue để Upload file lên Google Drive
Bài đăng này đã không được cập nhật trong 5 năm
Giới thiệu
Chào mọi người, như mọi người đều biết đến Queue ở trong môn học Cấu trúc dữ liệu và giải thuật. Bài viết hôm nay mình xin chia sẻ đến với moị người việc áp dụng Queue ở trong Laravel và cụ thể là với công việc lưu trữ file trên Google Drive.
Chuẩn bị
-
Cài đặt Project Laravel (ở thời điểm mình viết bài là Laravel 5.7):
composer create-project --prefer-dist laravel/laravel google-drive-demo
-
Cài đặt pakage để tương tác với Google Drive - Flysystem Google Drive :
composer require nao-pon/flysystem-google-drive:~1.1
(For Google Drive API V3)composer require nao-pon/flysystem-google-drive:~1.0.0
(For Google Drive API V2)Ở đây mình sẽ dùng với Google Drive API v3
Bắt đầu
1. Tạo Adapter và Service Provider của Google Drive
- Tạo 2 file GoogleDriveAdapter.php và GoogleDriveServiceProvider.php trong thư mục app/Providers:
GoogleDriveAdaper.php:
<?php
namespace App\Providers;
class GoogleDriveAdapter extends \Hypweb\Flysystem\GoogleDrive\GoogleDriveAdapter
{
public function getService()
{
return $this->service;
}
}
GoogleDriveServiceProvider.php:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class GoogleDriveServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* @return void
*/
public function boot()
{
\Storage::extend('google', function ($app, $config) {
$client = new \Google_Client();
$client->setClientId($config['clientId']);
$client->setClientSecret($config['clientSecret']);
$client->refreshToken($config['refreshToken']);
$service = new \Google_Service_Drive($client);
$options = [];
if (isset($config['teamDriveId'])) {
$options['teamDriveId'] = $config['teamDriveId'];
}
$adapter = new GoogleDriveAdapter($service, $config['folderId'], $options);
return new \League\Flysystem\Filesystem($adapter);
});
}
/**
* Register the application services.
*
* @return void
*/
public function register()
{
//
}
}
- Khai báo
GoogleDriveServiceProvider
vàoproviders
trongconfig/app.php
:
'providers' => [
/*
* Laravel Framework Service Providers...
*/
...
/*
* Package Service Providers...
*/
...
/*
* Application Service Providers...
*/
App\Providers\GoogleDriveServiceProvider::class,
],
- Vì ở đây ta coi Google Drive như là 1 disk nên ta khai báo
google
disk vào trongconfig/filesystems.php
:
<?php
return [
'default' => env('FILESYSTEM_DRIVER', 'cloud'),
'cloud' => env('FILESYSTEM_CLOUD', 'google'),
'disks' => [
/*...*/
'google' => [
'driver' => 'google',
'clientId' => env('GOOGLE_DRIVE_CLIENT_ID'),
'clientSecret' => env('GOOGLE_DRIVE_CLIENT_SECRET'),
'refreshToken' => env('GOOGLE_DRIVE_REFRESH_TOKEN'),
'folderId' => env('GOOGLE_DRIVE_FOLDER_ID'),
],
],
];
2. Lấy Google Drive API Key
a. Client ID & Secret:
- Truy cập vào Google Console và tạo 1 App: https://console.developers.google.com
- Ở đây mình đã tạo xong app google-drive-demo, vào Library tìm Google Drive API và enable:
- Sau đó, vào Credentials, tạo OAuth client ID:
Tại phần này chúng ta nhớ để trong phần Authorized redirect URIs là
https://developers.google.com/oauthplayground
. Sau khi tạo xong, chúng ta sẽ cóclient ID
vàclient secret
b. Refresh Token:
- Truy cập vào đường dẫn: https://developers.google.com/oauthplayground, ở góc bên phải phần cài đặt ta dán client ID và client secret:
- Sau đó, ở bên trái, tìm và chọn Google Drive API V3, chọn dòng đầu tiên:
- Tiếp tục ta làm theo các bước như hình bên dưới:
Cuối cùng ta lấy được Refresh token.
c. Lấy ID thư mục lưu trữ (Root):
- Truy cập vào Google Drive của mình và tạo một thư mục, ở đây mình sẽ tạo thư mục và lấy tên là Demo, đây là thư mục mà chúng ta sẽ tương tác, ID chính là phần cuối trong URL như hình:
Sau khi lấy được tất cả các thông tin trên, chúng ta paste vào file .env :
FILESYSTEM_CLOUD = google
GOOGLE_DRIVE_CLIENT_ID = ***
GOOGLE_DRIVE_CLIENT_SECRET = ***
GOOGLE_DRIVE_REFRESH_TOKEN = ***
GOOGLE_DRIVE_FOLDER_ID = ***
Xong, bây giờ chúng ta có thể truy cập Google Drive như một disk của Storage rồi.
3. Tạo file
- Đầu tiên chúng ta tạo file
demo.blade.php
trongresources/views
để Upload File:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Google Drive Demo</title>
</head>
<body>
<form action="{{ route('post.file') }}" method="POST">
<input type="file" name="file">
<br><br>
<button type="submit">Upload</button>
</form>
</body>
</html>
- Tạo
DemoController.php
:php artisan make:controller DemoController
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class DemoController extends Controller
{
public function store(Request $request)
{
$name = $request->file->getClientOriginalName();
$request->file->storeAs('/', $name, 'google');
return 'File was saved to Google Drive';
}
}
- File
web.php
:
<?php
Route::get('/', function () {
return view('demo');
});
Route::post('/', 'DemoController@store')->name('post.file');
Bây giờ chúng ta thử Upload 1 file lên thử xem. Ổn, file đã được upload lên Google Drive, tuy nhiên ta có thể thấy rằng thời gian chờ đợi upload khoảng gần 3s cho 1 file ~2Mb. Do đó, việc sử dụng Queue Job ở đây để thực hiện việc upload file là một cách để giải quyết vấn đề trên.
4. Tạo Queue Job
- Để chạy queue job trong Laravel đã hỗ trợ kha khá driver, nhưng ở đây để đơn giản mình sẽ sử dụng database để lưu lại Job:
- Tạo table jobs:
php artisan queue:table
php artisan migrate
- Ở file
.env
chúng ta sửaQUEUE_CONNECTION=database
- Tạo Job:
php artisan make:job PutFile
, một filePutFile.php
được tạo ở trongapp/Jobs/
, sửa lại nội dung như sau:
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Support\Facades\Storage;
class PutFile implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $name;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct($name)
{
$this->name = $name;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
$filePut = Storage::disk('public')->get('/' . $this->name);
Storage::cloud()->put('/' . $this->name, $filePut);
Storage::disk('public')->delete('/' . $this->name);
}
}
- Sửa lại file
DemoController.php
:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Jobs\PutFile;
class DemoController extends Controller
{
public function store(Request $request)
{
$name = $request->file->getClientOriginalName();
$request->file->storeAs('/', $name, 'public');
PutFile::dispatch($name);
return 'File was saved to Google Drive';
}
}
Xong! Bây giờ chúng ta mở Terminal và chạy php artisan queue:work
. Upload lại thử file và quan sát Job đã được đẩy vào trong hàng đợi và bạn sẽ thấy web được load nhanh hơn.
Giải thích 1 chút: Do Job không cho phép truyền trực tiếp đối tượng $request->file
nên ở đây mình upload file lên disk local là public, sau đó ở trong Job mình mới lấy ra file ở local upload lên Google Drive, và cuối cùng là xóa file ở disk local đi.
Kết luận
Trong bài viết này, mình đã chia sẻ đến mọi người cách để lưu trữ file trên Google Drive kết hợp dùng Queue Job. Bài viết này mình mới chỉ dừng ở mức demo rất đơn giản, hi vọng sẽ giúp ích 1 phần nào đó cho các bạn. Ngoài việc lưu trữ file các bạn có thể tìm hiểu nhiều hơn với các thao tác xóa file, hay các thao tác với thư mục,...tại đây. Ngoài ra các bạn cũng có thể thao tác với các Cloud khác như Amazone S3, Azure, Dropbox, ...
Tham khảo
Laravel & Google Drive Storage
All rights reserved