Laravel Artisan 命令行:创建一个命令

Laravel Artisan 除了自带的命令外,它也支持用户创建自己的命令。下面我们以创建一个 hash 命令为例来讲解如何创建自己的命令。

通过 make:command 创建命令

rtisan 提供了一个 make:command 命令用于创建用户自己的命令。它的使用很简单,接受一个 name 参数,用于指定生成的命令文件名及命令类名,还可指定一个 –command 选项,可用于指定命令名、命令参数及命令选项(会在下面详细讲到),make:command 命令的帮助说明如下:

artisan

首先打开终端,在项目根目录下执行以下命令:

php artisan make:command HashCommand

当看到

php artisan make:command HashCommand
Console command created successfully.

表示命令文件已经创建好了,我们可以在项目的 app/Console/Commands 目录中看到多了一个新生成的 Hash.php 文件,这就是我们的命令源文件。看下它的内容:

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;

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

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Command description';

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

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        //
    }
}

可以看到,HashCommand 类派生自 Illuminate\Console\Command 类,除了构造方法,HashCommand 类中还包含以下属性和方法:

$signature 属性,设置命令名、命令参数、命令选项;
$description 属性,设置命令的描述信息;
handle() 方法,包含实际的命令逻辑代码。
这个时候,我们已经可以执行这个命令了(尽管它还啥事都做不了),那么如何执行它呢?只要在 php artisan 后面带上 $signature 属性指定的命令名即可:

php artisan command:name

下面是php artisan command 的一个完整例子:定时任务同步处理订单异步回调

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use App\Model\TransactionOrder;
use App\Model\Merchants;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ServerException;
use GuzzleHttp\Exception\ClientException;

class SyncStatusToMerchants extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'merchant-order:sync';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Command description';

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

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        $orders = TransactionOrder::where('sync_status', 0)->where('status', TransactionOrder::ORDER_STATUS_COMPLETED)->orderBy('id', 'DESC')->limit(20)->get();
        foreach ($orders as $order)
        {
            $_merchant = Merchants::find($order->merchants_id);
            $_response = $this->doRequest($_merchant->notification_url, [
                'incrementid'   =>$order->increment_id,
                'transaction_id'=>$order->transaction_id_3rd,
                'status'        =>$order->status
            ], $_merchant);

            if (is_array($_response))
            {
                if ($_response['code'] == '00') {
                    $order->sync_status = 1;
                } else {
                    $_order->sync_note  = $_response['msg'];
                }
                $order->save();

                $this->line('order id:' . $order->increment_id . ' status: ' . $order->sync_status . '--' . $order->status . 'response' . $_response['code'] . '-' . $_response['msg']);
            } else {
                $this->error('order id:' . $order->increment_id . ' status: ' . $order->sync_status . '--' . $order->status);
            }
        }
    }

    public function doRequest($url, $data, $_merchant)
    {
        $params = '?incrementid='.$data['incrementid'].'&transaction_id='.$data['transaction_id'].'&status='.$data['status'];
        $sigStr = hash('sha512', $params . $_merchant->email . $_merchant->api_key, false);

        $data['sig'] = $sigStr;
        $_client = new Client();

        try {
            $_result = $_client->post($url, [
                'form_params' => $data
            ]);

            return json_decode($_result->getBody()->getContents(), true);
        } catch (ClientException $e) {
            // do something
            $this->error('1: ' . $e->getMessage());
            return false;
        } catch (ServerException $e) {
            // do something
            $this->error('2: ' . $e->getMessage());
            return false;
        } catch (\Throwable $throwable) {
            // do something
            $this->error('3: ' . $throwable->getMessage());
            return false;
        }
    }
}
artisan

有了上面的命令,我们需要在服务器上开启定时任务。在开启定时任务之前,我们可以把我们的命令交给 Kernel.php来执行。