Bạn có chắc chắn muốn xóa bài viết này không ?
Bạn có chắc chắn muốn xóa bình luận này không ?
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.
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à.
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).
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:
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à help
và list
.
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 PHPartisan
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ôngOke 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:
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:
Chúng ta thấy app:greet command
đã được list ra. Thử chạy lệnh php bin/artisan app:greet --help
xem sao:
Và cuối cùng chúng ta chạy 2 lệnh php bin/artisan app:greet someone
và php bin/artisan app:greet someone --cap
để tận hưởng kết quả thôi :D