Artisan Console trong Laravel


Artisan là tên của giao diện gõ lệnh đính kèm trong Laravel. Nó cung cấp một danh sách các câu lệnh hữu ích để sử dụng trong quá trình phát triển ứng dụng.

Giới thiệu

Artisan được phát triển dựa trên component Symfony Console khá mạnh mẽ. Để xem danh sách các câu lệnh được cung cấp, bạn sử dụng câu lệnh sau:

php artisan list

Mỗi câu lệnh đều có kèm theo một màn hình “help” để hiển thị và những đối số tùy chọn kèm theo. Để xem nó, đơn giản sử dụng lệnh sau:

php artisan help migrate

Tạo lệnh

Ngoài việc sử dụng các lệnh được Laravel cung cấp sẵn, bạn cũng có thể tạo câu lệnh riêng phục vụ cho những nhu cầu của ứng dụng. Các bạn có thể tự tạo bằng tay, class mới tạo sẽ được kế thừa từ thư viện Illuminate\Console\Command, nhưng mình khuyên các bạn những gì có thể dùng lệnh để tạo thì nên dùng lệnh, để có đầy đủ “đồ chơi” để nó hoạt động. Sau khi tạo, thì file được lưu trữ trong thư mục “app/Console/Commands“. Tuy nhiên bạn có thể thay đổi vị trí lưu, nhưng như mình đã nói cái gì mặc định thì cứ sử dụng. Khi nào trình chúng ta đạt tới mức có thể “nắm Laravel trong tay” thì các bạn cứ tùy thích Custom.

Để tạo một câu lệnh mới, ta chạy lệnh sau:

php artisan make:command AddNewUser

Cấu trúc câu lệnh

Khi câu lệnh được tạo, cần cập nhật $signature và $description trong class, vì chúng là cái giúp ta hiểu và chạy được câu lệnh.

Phương thức “handle” sẽ được gọi khi câu lệnh được thực thi. Bạn có thể viết logic tùy ý. Cùng xem ví dụ bên dưới để hiểu rõ hơn nhá.

Bạn có thể inject bất cứ dependencies nào mà chúng ta cần để xử lý công việc trong hàm khởi tạo “__construct()”.

<?php

namespace App\Console\Commands;

use App\Models\User;
use Illuminate\Console\Command;

class AddNewUser extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'datnquit:add-new-user {number}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Add some user';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
        // Inject Dependancies here!
    }

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        for ($i = 0; $i < $this->argument('number'); $i++) {
            User::create([
                'name' => 'Dat ' . $i,
                'email' => 'datnquit'.$i.'@gmail.com',
                'password' => bcrypt('123456'),
            ]);
        }
        return 0;
    }
}

Khai báo yêu cầu dữ liệu đầu vào

Khi tạo lệnh, chúng ta lấy dữ liệu đầu vào thông qua các options. Laravel làm cho việc này trở nên tiện lợi hơn khi khi báo yêu cầu dữ liệu đầu vào ngay trên thuộc tính “$signature”.

Arguments

Tất cả các đối số và tùy chọn nhận được từ người dùng sẽ phải nằm trong cặp dấu ngoặc nhọn. Ở ví dụ dưới đây, câu lệnh khi báo một đối số bắt buộc:

/**
 * The name and signature of the console command.
 *
 * @var string
 */
protected $signature = 'datnquit:add-new-user {number}';

Bạn cũng có thể đặt đối số này là tùy chọn (có cũng được không cũng được) và cài đặt giá trị mặc định:

// Optional argument...
datnquit:add-new-user {number?}

// Optional argument with default value...
datnquit:add-new-user {number=1}

Options

Tương tự như Arguments, cũng là nhập dữ liệu từ người sử dụng nhưng chúng có tiền tố (–) khi được tạo. Chúng ta khai báo như sau:

protected $signature = 'datnquit:add-new-user {number=1} {--email}';

Tùy chọn “–email” có thể được chỉ định khi thực hiện gọi câu lệnh. Nếu như “–email” được gọi, thì giá trị của tùy chọn này là “True”, ngược lại là “False”:

php artisan datnquit:add-new-user 1 --email

Truyền dữ liệu vào Options
Bạn cũng có thể tùy chỉnh giá trị của Options, ta khai báo như sau:

protected $signature = 'datnquit:add-new-user {number=1} {--email=}';

Người dùng có thể truyền giá trị vào như sau:

php artisan datnquit:add-new-user 1 --email=datnquit@gmail.com

Bạn cũng có thể gán giá trị mặc định cho Options:

datnquit:add-new-user {number=1} {--email=datnquit@gmail.com}

Options Shortcuts
Thiết lập shortcut cho tùy chọn ta khai báo như sau:

datnquit:add-new-user {number=1} {--E|email}

Ta có thể dử dụng –E hoặc –email đều được.

Input Arrays

Nếu bạn muốn Arguments hay Options của dữ liệu đầu vào là một mảng, ta sử dụng (*):

datnquit:add-new-user {number*}
php artisan datnquit:add-new-user 1 2 

datnquit:add-new-user {--email=*}
php artisan datnquit:add-new-user --email=datnquit@gmail.com --email=a@gamil.com

Input Descriptions

Bạn có thể mô tả cho Arguments và Options bằng cách sử dụng (:):

/**
 * The name and signature of the console command.
 *
 * @var string
 */
protected $signature = 'datnquit:add-new-user
                        {number : Number new user}
                        {--email= : Email default}';

Command I/O

Nhận dữ liệu đầu vào

Khi câu lệnh được thực thi, chúng ta cần lấy những giá trị của các đối số và options được nhận từ câu lệnh để xử lý gì đó. Để sử dụng được điều này, bạn cần sử dụng tới phương thức “argument” và “option”:

/**
 * Execute the console command.
 *
 * @return int
 */
public function handle()
{
    $userId = $this->argument('number');

}

Nếu đối số truyền vào dưới dạng Array, bạn sử dụng “arguments”:

$arguments = $this->arguments();
// php artisan datnquit:add-new-user 3 4
// Giá trị của $arguments
// [
//   "command" => "datnquit:add-new-user"
//   "number" => [
//     0 => "3"
//     1 => "4"
//   ]
// ]

Các tùy chọn nhận dữ liệu thông qua phương thức “option”. Sử dụng option tương tự argument:

// Retrieve a specific option...
$queueName = $this->option('email');

// Retrieve all options...
$options = $this->option();

// php artisan datnquit:add-new-user --email=datnquit@gmail.com --email=laravel@gmail.com
// Giá trị của $options['email']
// [
//     0 => "datnquit@gmail.com"
//     1 => "laravel@gmail.com"
// ]

Nếu đối số hay tùy chọn không tồn lại, giá trị nhận được sẽ là null

Yêu cầu nhập dữ liệu

Ngoài việc hiển thị, bạn cũng có thể yêu cầu người dùng nhập dữ liệu vào trong quá trình thực thi câu lệnh. Phương thức “ask” sẽ yêu cầu người dùng nhập dữ liệu với câu hỏi được đưa ra, nhận dữ liệu và truyền dẽ liệu nhập từ người dùng vào trong câu lệnh:

/**
 * Execute the console command.
 *
 * @return mixed
 */
public function handle()
{
    $name = $this->ask('What is your name?');
    // What is your name?:
    //  > enter your name
}

Phương thức “secret” cũng tương tự ask, nhưng dữ liệu mà người dùng nhập khi gõ bàn phím sẽ không được hiển thị lên. Phương thức này dùng nhiều khi yêu cầu người dùng nhập mật khẩu:

$password = $this->secret('What is the password?');

Yêu cầu xác nhận

Nếu bạn đơn giản chỉ cần xác nhận từ người dùng, bạn có thể sử dụng phương thức “confirm”. Mặc định thì phương thức này trả lại giá trị False. Tuy nhiên nếu người dùng nhập vào “y” sẽ trả về “true”.

if ($this->confirm('Do you wish to continue?')) {
        //
  }

Nếu muốn mặc định trả về true, ta làm như sau:

if ($this->confirm('Do you wish to continue?', true)) {
    //
}

Tự chọn giá trị

Phương thức “anticipate” có thể sử dụng để cung cấp tự động hoàn thành câu lệnh với một danh sách các gợi ý có thể. Người dùng vẫn có thể nhập giá trị riêng không liên quan đến gợi ý được đưa ra:

    $name = $this->anticipate('What is your name?', ['Quang', 'Dat']);

Thật ra cái này mình giới thiệu vậy thôi chứ mình cũng không thấy khác “ask” luôn, cái tham số thứ 2 truyền vào array mà mình ko thấy tác dụng như nào cả, tham số thức 3 có thể truyền giá trị mặc định vào:

    $name = $this->anticipate('What is your name?', ['Nguyen', 'Quang'], 'Dat');

Đưa ra sự lựa chọn

Nếu bạn cần đưa ra một danh sách các sự lựa chọn, bạn có thể dùng “choice”. Người dùng sẽ nhập vào index của câu trả lời, và giá trị này sẽ được trả lại cho bạn. Bạn có thể chọn giá trị mặc định nếu như người dùng không lựa chọn gì:

$name = $this->choice('What is your name?', ['Nguyen', 'Quang'], 'Dat');

Hiển thị thông tin

Để hiển thị nội dung ra màn hình console, sử dụng các phương thức “line, info, comment, question, error”. Mỗi phương thức sẽ sử dụng màu ANSI tương ứng.
Thông tin màu tương ứng
Color of message

Lưu ý: Chỉ hiển thị ở dạng String

Giao diện table

Phương thức table sẽ giúp cho việc chỉnh hiển thị các dữ liệu kiểu dòng / cột. Chỉ cần truyền vào headers và các dòng nội dung vào trong phương thức. Chiều rộng vào chiều cao sẽ được tự động tính toán căn chỉnh dựa trên dữ liệu đầu vào:

$headers = ['Name', 'Email'];

$users = User::all(['name', 'email'])->toArray();

$this->table($headers, $users);

Thanh tiến trình

Với các tác vụ chạy lâu, thì việc sử dụng một thanh tiến trình khá là hữu ích. Sử dụng output, chúng ta có thể khởi tạo, chạy tiến trình và dừng thanh tiến trình. Bạn có thể khai báo số lượng steps khi bắt đầu tiến trình và thực hiện chạy:

$users = User::all();

$bar = $this->output->createProgressBar(count($users));

foreach ($users as $user) {
    $this->performTask($user);

    $bar->advance();
}

$bar->finish();

Tham khảo tài liệu về Symfony Progress Bar để cập nhật thêm các tuỳ chọn khác.

Đăng ký Commands

Khi mà câu lệnh hoàn thành, bạn cần phải đăng kí với Artisan để câu lệnh có thể sử dụng được. Việc này sẽ thông qua file “app/Console/Kernel.php

protected $commands = [
    AddNewUser::class,
];

Gọi câu lệnh trên mã nguồn

Đôi lúc bạn muốn thực thi một câu lệnh Artisan nằm ngoài CLI. Ví dụ, bạn muốn gọi một câu lệnh Artisan từ một route hay controller. Bạn có thể sử dụng call trong Artisan facade để thực hiện việc này. Phương thức call nhận tên của câu lệnh vào trong đối số đầu tiên, và một mảng danh sách các tham số thực thi câu lệnh ở đối số thứ hai. Mã kết quả thực thi sẽ được trả lại:

Route::get('/foo', function () {
        $exitCode = Artisan::call('datnquit:add-new-user', [
            'user' => 1, '--email' => 'datnquit@gmail.com'
        ]);

        // passing array example
        // 'user' => [5, 13]
    });

Khi sử dụng queue trên Artisan facade, thì bạn của thể thực hiện câu lệnh trên hàng đợi và chúng sẽ được thực hiện ở background bởi queue workers trong ứng dụng của bạn:

Route::get('/foo', function () {
    Artisan::queue('datnquit:add-new-user', [
        'user' => 1, '--email' => 'datnquit@gmail.com'
    ]);

    //
});

Thực thi câu lệnh trong một câu lệnh khác

Đôi lúc bạn muốn thực thi gọi câu lệnh từ một câu lệnh Artisan khác. Bạn có thể sử dụng phương thức call với tên câu lệnh và danh sách các tham số truyền vào:

/**
 * Execute the console command.
 *
 * @return mixed
 */
public function handle()
{
    $this->call('datnquit:add-new-user', [
        'user' => 1, '--email' => 'datnquit@gmail.com'
    ]);

    //
}

Nếu bạn muốn thực thi một câu lệnh và chặn không muốn hiển thị nội dung của nó ra ngoài, bạn có thể dùng callSilent. Phương thức này sử dụng tương tự call:

$this->callSilent('datnquit:add-new-user', [
        'user' => 1, '--email' => 'datnquit@gmail.com'
    ]);

Ngoài ra Artisan Console còn hổ trợ một số tính năng như Signal Handling, Stub Customization, Events. Nhưng thật sự nó chưa cần thiết để tìm hiểu nhưng không có nghĩa là nó không có ích chỉ là bây giờ chưa thật sự dùng đến thôi.

Kết luận

Dưới đây mình đã giới thiệu về khái niệm Artisan cũng như cách xử dụng nó. Nếu có bất kì thắc mắc gì hãy để lại comment ở phía dưới nhé.
Nguồn tham khảo:

Rất mong được sự ủng hộ của mọi người để mình có động lực ra những bài viết tiếp theo.
{\__/}
( ~.~ )
/ > ♥️ I LOVE YOU 3000

JUST DO IT!


Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint policy. If reproduced, please indicate source Nguyễn Quang Đạt !
Comments
  TOC