Tự tạo php console app Artisan giống Laravel

21
Phung Thế Hoang viết gần 6 năm trước

Nếu ai đã từng dùng Laravel thì chắc hẳn cái tên Artisan sẽ không còn xa lạ. Thực ra các PHP Framework lớn khác như CakePHP, Yii cũng có 1 công cụ console tương tự. Nhưng với với công cụ console Artisan của Laravel thì đúng như tên gọi của nó, nó quả thật là một nghệ nhân, nó giúp chúng ta xử lý các công việc mang tính chất thủ công bầng việc tự động hóa chúng. Nếu ai chưa biết Artisan là gì thì có thể tham khảo ở một bài viết khá chi tiết về Artisan ở đây.

Don't reinvent the wheel

Trong bài viêt này chúng ta sẽ cùng nghịch ngợm một chút để xây dựng 1 php console app giống Artisan nhưng ở mức độ đơn giản. Tât nhiên là chúng ta sẽ không xây dựng từ zero, mà chúng ta sẽ sử dụng 1 component của framework Symfony đó là Console Component. Việc gì phải đi phát minh lại cái bánh xe nhỉ??? vì trên thực tế thì Laravel Artisan cũng được xây dựng dựa trên Console Component này mà.

Xây dựng cấu trúc project

Chúng ta sẽ tạo project có tên là bất cứ cái gì chúng ta muốn, ở đây mình đặt là php-console-app. Bến trong sẽ tạo tiếp file composer.json và copy paste nội dung sau vào:

{
    "require": {
        "symfony/console": "^3.4"
    }
}

và sau đó chạy lệnh composer install để cài đặt component này và các dependency khác. Sau khi chạy xong thì trong thư mục sẽ xuất hiện thêm folder vendor và file composer.lock. Sau đó chúng ta sẽ tạo thêm thư mục bin và bên trong sẽ tạo thêm 1 file có tên là artisan (note: file này không có đuôi đâu nhé) và tạo thêm thư mục src và thư mục Command bên trong (tham khảo hình bên dưới). Thư mục Command là nơi sẽ chứa tất cả các command của chúng ta. Nhìn cấu trúc thư mục có vẻ giống CakePHP nhỉ (chắc do làm con Jukukoushi lâu quá :D).
alt text
Công việc tiếp theo là mở file artisan lên và copy paste nội dung sau vào:

#!/usr/bin/env php
<?php
    require dirname(__DIR__) . '/vendor/autoload.php';

    use Symfony\Component\Console\Application;

    $application = new Application();

    $application->run();`

Dòng đầu tiên #!/usr/bin/env php sẽ nói cho hệ thống biết đây là file môi trường của PHP và nó nên được thực thi bằng trình thông dịch của PHP. Dòng thứ 3 dùng cho việc autoload các class trong thư mục vendor, còn các dòng sau khá là dễ hiểu. Oke bây giờ chúng ta có thể mớ console lên và chạy lệnh sau:

php bin/artisan

Khi chạy xong thì ở console sẽ xuất hiện thông báo như thế này:
alt text
Xin chúc mừng, nhưng chúng ta mới chỉ xây dựng xong cấu trúc project thôi :D. Chú ý là Console Component đã cung cấp sẵn cho chúng ta sẵn 2 command rồi đó là helplist.

Tạo Command đầu tiên

Trước khi bắt tay vào tạo chúng ta cùng tìm hiểu qua cấu trúc của 1 command trong Laravel Artisan. Ví dụ 1 command trong Laravel sẽ có dạng như sau:

php artisan app:name argument --option

  • php là tên file thực thi của PHP
  • artisan là tên của console app
  • app:name là tên của command sẽ được run (Nếu chúng ta muốn nhóm các command có liên quan đến nhau thì sẽ đặt tên theo kiểu ten_chuc_nang:ten_command)
  • argument là tham số của app:name command (có thể có hoặc không)
  • option cũng có thể có hoặc không

Oke bây giờ chúng ta sẽ tạo 1 file GreetCommand.php bên trong thư mục src/Command và copy paste nội dụng sau đây:

<?php

namespace App\Command;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class GreetCommand extends Command
{
    protected $commandName = 'app:greet';
    protected $commandDescription = 'Greets Someone';

    protected $commandArgumentName = 'name';
    protected $commandArgumentDescription = 'Who do you want to greet?';

    protected $commandOptionName = 'cap'; // should be specified like "app:greet John --cap"
    protected $commandOptionDescription = 'If set, it will greet in uppercase letters';    

    protected function configure()
    {
        $this->setName($this->commandName)
            ->setDescription($this->commandDescription)
            ->addArgument($this->commandArgumentName, InputArgument::OPTIONAL, $this->commandArgumentDescription)
            ->addOption($this->commandOptionName, null, InputOption::VALUE_NONE, $this->commandOptionDescription);
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $name = $input->getArgument($this->commandArgumentName);
        $text = ($name) ? 'Hello ' . $name : 'Hello';

        if ($input->getOption($this->commandOptionName)) {
            $text = strtoupper($text);
        }

        $output->writeln($text);
    }
}

Code đọc khá dễ hiểu, command chỉ đơn giản là in ra một cái tên và nếu có thêm option --cap thì sẽ in ra tên viết hoa. Nhưng để sử dụng được command này thì chúng ta sẽ phải khai báo nó với ứng dụng bằng cách thêm dòng $application->add(new GreetCommand()); trong file artisan:

#!/usr/bin/env php

<?php

require dirname(__DIR__) . '/vendor/autoload.php';

use Symfony\Component\Console\Application;
use App\Command\GreetCommand;

$application = new Application();

# add our commands
$application->add(new GreetCommand());

$application->run();

Chúng ta thử chạy lại câu lệnh php bin/artisan list để liệt kê các command available thì kiểu gì cũng sẽ gặp lỗi sau:
alt text
Ta thấy nó báo lỗi dòng 13 vì không tìm thấy class App\Command\GreetCommand;. Đơn giản là vì chúng ra đã khai báo autoload cho các class trong thư mục src đâu. Để khắc phục chúng ta sẽ thêm dòng sau vào trong file composer.json

"autoload": {
    "psr-4": {
        "App\\": "src"
    },
    "classmap": ["src"]
}

File composer.json sau khi thêm:

{
    "require": {
        "symfony/console": "^3.4"
    },
    "autoload": {
        "psr-4": {
            "App\\": "src"
        },
        "classmap": ["src"]
    }
}

Sau khi thêm xong thì chạy lệnh composer dump -o. Sau khi chạy xong thì lúc này tất cả các class trong thư mục src sẽ được load theo chuẩn PSR4. Oke chúng ta chạy lại lệnh php bin/artisan list để xem kết quả thế nào:

alt text
Chúng ta thấy app:greet command đã được list ra. Thử chạy lệnh php bin/artisan app:greet --help xem sao:
alt text
Và cuối cùng chúng ta chạy 2 lệnh php bin/artisan app:greet someonephp bin/artisan app:greet someone --cap để tận hưởng kết quả thôi :D
alt text

Nguồn tham khảo

Bình luận


White
{{ comment.user.name }}
Hay Bỏ hay
{{ comment.like_count}}
White

Phung Thế Hoang

53 bài viết.
1 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}

  Cùng một tác giả


{{like_count}}

kipalog

{{ comment_count }}

Bình luận


White
{{userFollowed ? 'Following' : 'Follow'}}
53 bài viết.
1 người follow

 Đầu mục bài viết

 Cùng một tác giả