Viblo CTF
+5

Artisan Console trong Laravel

Xin chào các bạn. Hôm nay mình sẽ giới thiệu với các bạn Artisan là gì,cách viết câu lệnh và các sử dụng Command.

Artisan Console

Giới thiệu

Artisan là tên của giao diện màn hình 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 sản phẩm. 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 có thể sử dụng câu lệnh list:


    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à mô tả những đối số và tuỳ chọn có thể sử dụng. Để xem màn hình help, đơn giản chỉ cần gõ tên câu lệnh kèm theo từ khoá help:

    php artisan help migrate

Viết câu lệnh

Ngoài việc sử dụng các câu lệnh được cung cấp sẵn, ban cũng có thể tạo câu lệnh riêng để sử dụng cho ứng dụng của bạn. Bạn có thể lưu trữ các câu lệnh riêng đó trong thư mục app/Console/Commands; tuy nhiên, bạn hoàn toàn thoải mái trong việc chọn vị trí lưu đặt mã nguồn các câu lệnh với điều kiện là phải khai báo tự động khởi tạo trong cấu hình của composer.json.

Để tạo một câu lệnh mới, bạn có thể sử dụng câu lệnh make:console, nó sẽ tạo ra các khung mã nguồn cơ bản để giúp bạn bắt đầu một cách dễ dàng hơn:

    php artisan make:console SendEmails

Câu lệnh trên sẽ tạo một class tại app/Console/Commands/SendEmails.php. Khi tạo một câu lệnh, tuỳ chọn --command có thể được gán giá trị trên màn hình terminal:

    php artisan make:console SendEmails --command=emails:send

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

Khi mà câu lệnh được tạo ra, bạn nên điền vào thông tin của hai thuộc tính signaturedescription trong class, vì chúng sẽ được dùng để hiển thị khi mà câu lệnh list được thực thi.

Phương thức handle sẽ được gọi khi mà câu lệnh được thực thi. Bạn có thể viết logic tuỳ ý trong phương thức này. Nào, hãy cùng nhau xe một ví dụ về câu lệnh.

Chú ý là chúng ta có thể inject bất cứ dependencies nào mà chúng ta cần vào trong hàm khởi tạo của câu lệnh. Laravel service container sẽ tự động inject tất cả các dependencies được đánh dầu trong hàm khởi tạo. Để mã nguồn tái sử dụng tốt hơn, khuyến khích các bạn xử lý câu lệnh một cách gọn nhẹ và chuyển giao cho application services để thực hiện công việc.

    <?php

    namespace App\Console\Commands;

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

    class SendEmails extends Command
    {
        /**
         * The name and signature of the console command.
         *
         * @var string
         */
        protected $signature = 'email:send {user}';

        /**
         * The console command description.
         *
         * @var string
         */
        protected $description = 'Send drip e-mails to a user';

        /**
         * The drip e-mail service.
         *
         * @var DripEmailer
         */
        protected $drip;

        /**
         * Create a new command instance.
         *
         * @param  DripEmailer  $drip
         * @return void
         */
        public function __construct(DripEmailer $drip)
        {
            parent::__construct();

            $this->drip = $drip;
        }

        /**
         * Execute the console command.
         *
         * @return mixed
         */
        public function handle()
        {
            $this->drip->send(User::find($this->argument('user')));
        }
    }

Command I/O

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

Thông thường chúng ta sẽ nhận dữ liệu đầu vào từ người sử dụng thông qua các đối số và tuỳ chọn khi thực hiện viết các câu lệnh console. Laravel làm cho việc này trở nên tiện hơn khi khai báo yêu cầu dữ liệu đầu vào sử dụng thuộc tính signature trong câu lệnh. Thuộc tính signature cho phép bạn khai báo tên, đối số, và các tuỳ chọn cho câu lệnh dưới dạng một giá trị, một biểu thức hay cú pháp tương tự khai báo route.

Tất cả các đối số và tuỳ 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 khai báo một đối số cần thiết: user:

    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'email:send {user}';

Bạn cũng có thể đặt đối số này là tuỳ chọn và cài đặt giá trị mặc định:

    // Optional argument...
    email:send {user?}

    // Optional argument with default value...
    email:send {user=foo}

Tuỳ chọn, như đối số, cũng là một kiểu nhập vào từ người sử dụng nhưng chúng có tiền tố là hai dấu gạch ngang (--) khi được viết. Chúng ta có thể khai báo tuỳ chọn trong signature như sau:

    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'email:send {user} {--queue}';

Ở ví dụ này, tuỳ chọn --queue có thể được chỉ định khi thực hiện gọi câu lệnh. Nếu như --queue được gọi, thì giá trị của tuỳ chọn này sẽ là true. Ngược lại, giá trị sẽ là false:

    php artisan email:send 1 --queue

Bạn cũng có thể điều chỉnh sao cho tuỳ chọn phải được gán với một giá trị bởi người dùng thông qua việc sử dụng kí hiệu = để cho biết là cần yêu cầu có dữ liệu nhập vào:

    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'email:send {user} {--queue=}';

Trong ví dụ này, người sử dụng có thể truyền vào một giá trị cho tuỳ chọn:

    php artisan email:send 1 --queue=default

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

    email:send {user} {--queue=default}

Để thiết lập một shortcut khi khai báo tuỳ chọn, bạn có thể thêm vào tên của shortcut ngay trước tên của tuỳ chọn và dùng dấu | để ngăn cách:

    email:send {user} {--Q|queue}

Nếu bạn muốn đối số hay tuỳ chọn của dữ liệu đầu vào là một mảng, sử dụng dấu *:

    email:send {user*}

    email:send {user} {--id=*}

Mô tả dữ liệu đầu vào

Bạn có thể gán nội dung mô tả cho các đối số và tuỳ chọn bằng việc sử dụng dấu : để ngăn cách:

    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'email:send
                            {user : The ID of the user}
                            {--queue= : Whether the job should be queued}';

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

Khi câu lệnh được thực thi, rõ ràng là chúng ta cần lấy được giá trị của các đối số và tuỳ chọn được nhận vào câu lệnh. Để làm được điều này, bạn cần sử dụng tới phương thức argumentoption:

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

        //
    }

Nếu bạn cần lấy tất cả đối số truyền vào dưới dạng một array, sử dụng argument mà không truyền vào tham số nào:

    $arguments = $this->argument();

Tuỳ chọn có thể nhận thông qua phương thức option. Bạn sử dụng phương thức option một cách tương tự với argument:

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

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

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

Hỏi 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 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?');
    }

Phương thức secret tương tự như 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 rất hữu ích khi yêu cầu các thông tin nhạy cảm như 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 một xác nhận từ người sử 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 thì phương thức sẽ trả về true.

    if ($this->confirm('Do you wish to continue? [y|N]')) {
        //
    }

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

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 sự gợi ý có thể. Người dùng vẫn có thể đưa ra câu trả lời riêng không liên quan tới các gợi ý được đưa ra:

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

Nếu như 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ẽ chọn đáp án bằng cách 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ể thiệt lập giá trị chọn lựa mặc định nếu như mà người dùng không chọn gì:

    $name = $this->choice('What is your name?', ['Taylor', 'Dayle'], $default);

Hiển thị nội dung

Để hiển thị nội dung ra màn hình, sử dụng các phương thức sau line, info, comment, questionerror. Mỗi phương thức sẽ sử dụng màu ANSI tương ứng với mục đích của nó.

Để hiển thị thông tin cho người dùng, sử dụng info. Về cơ bản, nó sẽ hiển thị chữ màu xanh lá cây.

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        $this->info('Display this on the screen');
    }

Để hiển thị nội dung về lỗi, sử dụng error. Các nội dung lỗi sẽ được hiển thị bằng màu đỏ.

    $this->error('Something went wrong!');

Nếu bạn muốn hiển thị nội dung đơn thuẩn, sử dụng line. Phương thức này không sử dụng bất cứ màu đặc trưng nào:

    $this->line('Display this on the screen');

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 = App\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 = App\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í câu lệnh

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.

Trong file này, bạn có thể thấy một danh sách câu lệnh trong thuộc tính commands. Để đăng kí, đơn giản chỉ cần thêm tên class của câu lệnh vào trong danh sách. Khi Artisan khởi tạo, tất cả các câu lệnh trong danh sách này sẽ được duyệt bởi service container và sẽ được đăng kí vào Artisan:

    protected $commands = [
        Commands\SendEmails::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('email:send', [
            'user' => 1, '--queue' => 'default'
        ]);

        //
    });

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('email:send', [
            'user' => 1, '--queue' => 'default'
        ]);

        //
    });

Nếu bạn cần chỉ rõ giá trị của tuỳ chọn không nhận kiểu string, ví dụ --force trong câu lệnh migrate:refresh, bạn có thể truyền vào giá trị boolean true hay false:

    $exitCode = Artisan::call('migrate:refresh', [
        '--force' => true,
    ]);

Thực thi câu lệnh 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('email:send', [
            'user' => 1, '--queue' => 'default'
        ]);

        //
    }

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('email:send', [
        'user' => 1, '--queue' => 'default'
    ]);

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é.

Thao Khảo

https://laravel.com/docs/5.7/artisan


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.