工匠控制台
Introduction
Artisan 是 Laravel 附带的命令行界面。 Artisan 存在于您的应用程序的根部,作为artisan
脚本并提供了许多有用的命令,可以在您构建应用程序时为您提供帮助。要查看所有可用的 Artisan 命令的列表,您可以使用list
命令:
php artisan list
每个命令还包括一个“帮助”屏幕,显示和描述命令的可用参数和选项。要查看帮助屏幕,请在命令名称前加上help
:
php artisan help migrate
Laravel 风帆
如果您正在使用Laravel 风帆 作为您本地的开发环境,请记住使用sail
调用 Artisan 命令的命令行。 Sail 将在您应用程序的 Docker 容器中执行您的 Artisan 命令:
./vendor/bin/sail artisan list
修补匠 (REPL)
Laravel Tinker 是 Laravel 框架的强大 REPL,由PsySH 包裹。
Installation
默认情况下,所有 Laravel 应用程序都包含 Tinker。但是,如果您之前已将 Tinker 从您的应用程序中删除,则可以使用 Composer 安装 Tinker:
composer require laravel/tinker
Note
正在寻找用于与 Laravel 应用程序交互的图形 UI?查看Tinkerwell!
Usage
Tinker 允许您在命令行上与整个 Laravel 应用程序进行交互,包括您的 Eloquent 模型、作业、事件等。要进入 Tinker 环境,请运行tinker
工匠命令:
php artisan tinker
您可以使用发布 Tinker 的配置文件vendor:publish
命令:
php artisan vendor:publish --provider="Laravel\Tinker\TinkerServiceProvider"
Warning
这dispatch
辅助函数和dispatch
上的方法Dispatchable
类依赖垃圾回收将作业放入队列。因此,在使用tinker时,应该使用Bus::dispatch
或者Queue::push
派遣工作。
命令允许列表
Tinker 使用“允许”列表来确定允许在其 shell 中运行哪些 Artisan 命令。默认情况下,您可以运行clear-compiled
,down
,env
,inspire
,migrate
,optimize
, 和up
命令。如果您想允许更多命令,您可以将它们添加到commands
数组在你的tinker.php
配置文件:
'commands' => [
// App\Console\Commands\ExampleCommand::class,
],
不应使用别名的类
通常,当您在 Tinker 中与类交互时,Tinker 会自动为类添加别名。但是,您可能希望永远不要对某些类使用别名。您可以通过在dont_alias
你的数组tinker.php
配置文件:
'dont_alias' => [
App\Models\User::class,
],
编写命令
除了 Artisan 提供的命令之外,您还可以构建自己的自定义命令。命令通常存储在app/Console/Commands
目录;但是,只要您的命令可以被 Composer 加载,您就可以自由选择自己的存储位置。
生成命令
要创建一个新命令,您可以使用make:command
工匠命令。此命令将在app/Console/Commands
目录。如果您的应用程序中不存在此目录,请不要担心 - 它会在您第一次运行时创建make:command
工匠命令:
php artisan make:command SendEmails
命令结构
生成命令后,您应该为signature
和description
类的属性。在上显示您的命令时将使用这些属性list
屏幕。这signature
属性还允许您定义您的命令的输入期望.这handle
执行命令时将调用方法。您可以将您的命令逻辑放在这个方法中。
让我们看一个示例命令。请注意,我们可以通过命令请求我们需要的任何依赖项handle
方法。 Laravel服务容器 将自动注入此方法签名中类型提示的所有依赖项:
<?php
namespace App\Console\Commands;
use App\Models\User;
use App\Support\DripEmailer;
use Illuminate\Console\Command;
class SendEmails extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'mail:send {user}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Send a marketing email to a user';
/**
* Execute the console command.
*/
public function handle(DripEmailer $drip): void
{
$drip->send(User::find($this->argument('user')));
}
}
Note
为了更好地重用代码,最好让您的控制台命令保持简洁,让它们遵从应用程序服务来完成它们的任务。在上面的示例中,请注意我们注入了一个服务类来完成发送电子邮件的“繁重工作”。
关闭命令
基于闭包的命令提供了将控制台命令定义为类的替代方法。就像路由闭包是控制器的替代品一样,将命令闭包视为命令类的替代品。在commands
你的方法app/Console/Kernel.php
文件,Laravel 加载routes/console.php
文件:
/**
* Register the closure based commands for the application.
*/
protected function commands(): void
{
require base_path('routes/console.php');
}
尽管此文件未定义 HTTP 路由,但它定义了基于控制台的入口点(路由)到您的应用程序中。在此文件中,您可以使用以下命令定义所有基于闭包的控制台命令Artisan::command
方法。这command
方法接受两个参数:命令签名 和一个接收命令参数和选项的闭包:
Artisan::command('mail:send {user}', function (string $user) {
$this->info("Sending email to: {$user}!");
});
闭包绑定到底层命令实例,因此您可以完全访问通常可以在完整命令类上访问的所有帮助器方法。
类型提示依赖
除了接收命令的参数和选项之外,命令闭包还可以类型提示您希望从中解决的其他依赖项服务容器:
use App\Models\User;
use App\Support\DripEmailer;
Artisan::command('mail:send {user}', function (DripEmailer $drip, string $user) {
$drip->send(User::find($user));
});
关闭命令说明
在定义基于闭包的命令时,您可以使用purpose
向命令添加描述的方法。运行时将显示此说明php artisan list
或者php artisan help
命令:
Artisan::command('mail:send {user}', function (string $user) {
// ...
})->purpose('Send a marketing email to a user');
可隔离命令
Warning 要使用此功能,您的应用程序必须使用
memcached
,redis
,dynamodb
,database
,file
, 或者array
缓存驱动程序作为应用程序的默认缓存驱动程序。此外,所有服务器都必须与同一个中央缓存服务器通信。
有时您可能希望确保一次只能运行一个命令实例。为此,您可以实现Illuminate\Contracts\Console\Isolatable
命令类上的接口:
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Contracts\Console\Isolatable;
class SendEmails extends Command implements Isolatable
{
// ...
}
当一个命令被标记为Isolatable
, Laravel 会自动添加一个--isolated
命令的选项。当使用该选项调用该命令时,Laravel 将确保该命令没有其他实例已经在运行。 Laravel 通过尝试使用应用程序的默认缓存驱动程序获取原子锁来实现这一点。如果该命令的其他实例正在运行,则该命令将不会执行;但是,该命令仍将以成功退出状态代码退出:
php artisan mail:send 1 --isolated
如果您想指定命令在无法执行时应返回的退出状态代码,您可以通过以下方式提供所需的状态代码isolated
选项:
php artisan mail:send 1 --isolated=12
锁定到期时间
默认情况下,隔离锁在命令完成后过期。或者,如果命令被中断而无法完成,锁将在一小时后到期。但是,您可以通过定义一个isolationLockExpiresAt
命令上的方法:
use DateTimeInterface;
use DateInterval;
/**
* Determine when an isolation lock expires for the command.
*/
public function isolationLockExpiresAt(): DateTimeInterface|DateInterval
{
return now()->addMinutes(5);
}
定义输入期望
编写控制台命令时,通常通过参数或选项收集用户的输入。 Laravel 可以很方便地使用signature
您的命令的属性。这signature
property 允许您在一个单一的、富有表现力的、类似路由的语法中定义命令的名称、参数和选项。
Arguments
所有用户提供的参数和选项都包含在花括号中。在以下示例中,该命令定义了一个必需的参数:user
:
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'mail:send {user}';
您还可以使参数可选或为参数定义默认值:
// Optional argument...
'mail:send {user?}'
// Optional argument with default value...
'mail:send {user=foo}'
Options
选项和参数一样,是用户输入的另一种形式。选项以两个连字符 (--
) 当它们通过命令行提供时。有两种类型的选项:那些接收值的和那些不接收值的。不接收值的选项用作布尔“开关”。让我们看一下此类选项的示例:
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'mail:send {user} {--queue}';
在这个例子中,--queue
可以在调用 Artisan 命令时指定开关。如果--queue
开关被传递,选项的值将是true
.否则,该值将是false
:
php artisan mail:send 1 --queue
有值的选项
接下来,让我们看一下期望值的选项。如果用户必须为选项指定一个值,则应该在选项名称后加上=
符号:
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'mail:send {user} {--queue=}';
在此示例中,用户可以像这样为选项传递一个值。如果调用命令时未指定选项,则其值为null
:
php artisan mail:send 1 --queue=default
您可以通过在选项名称后指定默认值来为选项分配默认值。如果用户没有传递选项值,将使用默认值:
'mail:send {user} {--queue=default}'
选项快捷方式
要在定义选项时分配快捷方式,您可以在选项名称之前指定它并使用|
字符作为分隔符将快捷方式与完整选项名称分开:
'mail:send {user} {--Q|queue}'
在终端上调用命令时,选项快捷方式应以单个连字符为前缀:
php artisan mail:send 1 -Q
输入数组
如果您想定义参数或选项以期望多个输入值,您可以使用*
特点。首先,让我们看一个指定这样一个参数的例子:
'mail:send {user*}'
调用此方法时,user
参数可以按顺序传递到命令行。例如,以下命令将设置值user
到一个数组1
和2
作为其价值观:
php artisan mail:send 1 2
这*
字符可以与可选的参数定义组合以允许参数的零个或多个实例:
'mail:send {user?*}'
选项数组
在定义需要多个输入值的选项时,传递给命令的每个选项值都应以选项名称为前缀:
'mail:send {--id=*}'
这样的命令可以通过传递多个--id
参数:
php artisan mail:send --id=1 --id=2
输入说明
您可以通过使用冒号将参数名称与描述分开来为输入参数和选项分配描述。如果您需要一些额外的空间来定义您的命令,请随意将定义分布在多行中:
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'mail:send
{user : The ID of the user}
{--queue : Whether the job should be queued}';
命令输入输出
检索输入
当您的命令正在执行时,您可能需要访问您的命令接受的参数和选项的值。为此,您可以使用argument
和option
方法。如果参数或选项不存在,null
将返回:
/**
* Execute the console command.
*/
public function handle(): void
{
$userId = $this->argument('user');
}
如果您需要检索所有参数作为array
, 调用arguments
方法:
$arguments = $this->arguments();
可以像使用参数一样轻松地检索选项option
方法。要将所有选项检索为数组,请调用options
方法:
// Retrieve a specific option...
$queueName = $this->option('queue');
// Retrieve all options as an array...
$options = $this->options();
提示输入
除了显示输出之外,您还可以要求用户在执行命令期间提供输入。这ask
方法将提示用户给定的问题,接受他们的输入,然后将用户的输入返回给您的命令:
/**
* Execute the console command.
*/
public function handle(): void
{
$name = $this->ask('What is your name?');
// ...
}
这secret
方法类似于ask
,但是当用户在控制台中键入时,他们将看不到用户的输入。当询问密码等敏感信息时,此方法很有用:
$password = $this->secret('What is the password?');
要求确认
如果您需要询问用户一个简单的“是或否”确认,您可以使用confirm
方法。默认情况下,此方法将返回false
.但是,如果用户输入y
或者yes
响应提示,该方法将返回true
.
if ($this->confirm('Do you wish to continue?')) {
// ...
}
如有必要,您可以指定确认提示应返回true
默认通过true
作为第二个参数confirm
方法:
if ($this->confirm('Do you wish to continue?', true)) {
// ...
}
Auto-Completion
这anticipate
方法可用于为可能的选择提供自动完成。无论自动完成提示如何,用户仍然可以提供任何答案:
$name = $this->anticipate('What is your name?', ['Taylor', 'Dayle']);
或者,您可以将闭包作为第二个参数传递给anticipate
方法。每次用户键入输入字符时都会调用闭包。闭包应该接受一个包含用户到目前为止输入的字符串参数,并返回一个自动完成选项数组:
$name = $this->anticipate('What is your address?', function (string $input) {
// Return auto-completion options...
});
多项选择题
如果您需要在提问时为用户提供一组预定义的选择,您可以使用choice
方法。如果没有选择任何选项,您可以通过将索引作为第三个参数传递给方法来设置要返回的默认值的数组索引:
$name = $this->choice(
'What is your name?',
['Taylor', 'Dayle'],
$defaultIndex
);
除此之外choice
方法接受可选的第四和第五个参数,用于确定选择有效响应的最大尝试次数以及是否允许多项选择:
$name = $this->choice(
'What is your name?',
['Taylor', 'Dayle'],
$defaultIndex,
$maxAttempts = null,
$allowMultipleSelections = false
);
写输出
要将输出发送到控制台,您可以使用line
,info
,comment
,question
,warn
, 和error
方法。这些方法中的每一种都将根据其目的使用适当的 ANSI 颜色。例如,让我们向用户显示一些一般信息。通常,info
方法将在控制台中显示为绿色文本:
/**
* Execute the console command.
*/
public function handle(): void
{
// ...
$this->info('The command was successful!');
}
要显示错误消息,请使用error
方法。错误消息文本通常以红色显示:
$this->error('Something went wrong!');
您可以使用line
显示纯文本、未着色文本的方法:
$this->line('Display this on the screen');
您可以使用newLine
显示空行的方法:
// Write a single blank line...
$this->newLine();
// Write three blank lines...
$this->newLine(3);
Tables
这table
方法可以轻松正确地格式化多行/多列数据。您需要做的就是提供表的列名和数据,Laravel 会
自动为你计算出合适的表格宽度和高度:
use App\Models\User;
$this->table(
['Name', 'Email'],
User::all(['name', 'email'])->toArray()
);
进度条
对于长时间运行的任务,显示一个进度条以告知用户任务的完成情况会很有帮助。使用withProgressBar
方法,Laravel 将显示一个进度条,并在给定的可迭代值上推进每次迭代的进度:
use App\Models\User;
$users = $this->withProgressBar(User::all(), function (User $user) {
$this->performTask($user);
});
有时,您可能需要对进度条的前进方式进行更多手动控制。首先,定义流程将迭代的总步骤数。然后,在处理完每一项后推进进度条:
$users = App\Models\User::all();
$bar = $this->output->createProgressBar(count($users));
$bar->start();
foreach ($users as $user) {
$this->performTask($user);
$bar->advance();
}
$bar->finish();
Note
有关更多高级选项,请查看Symfony 进度条组件文档.
注册命令
您所有的控制台命令都在您的应用程序中注册App\Console\Kernel
类,这是您的应用程序的“控制台内核”。在commands
这个类的方法,你会看到对内核的调用load
方法。这load
方法将扫描app/Console/Commands
目录并自动将它包含的每个命令注册到 Artisan。您甚至可以自由地拨打其他电话load
扫描其他目录以查找 Artisan 命令的方法:
/**
* Register the commands for the application.
*/
protected function commands(): void
{
$this->load(__DIR__.'/Commands');
$this->load(__DIR__.'/../Domain/Orders/Commands');
// ...
}
如有必要,您可以通过将命令的类名添加到$commands
你的财产App\Console\Kernel
班级。如果此属性尚未在您的内核中定义,您应该手动定义它。当 Artisan 启动时,此属性中列出的所有命令都将由服务容器 并在 Artisan 注册:
protected $commands = [
Commands\SendEmails::class
];
以编程方式执行命令
有时您可能希望在 CLI 之外执行 Artisan 命令。例如,您可能希望从路由或控制器执行 Artisan 命令。您可以使用call
上的方法Artisan
facade 来完成这个。这call
方法接受命令的签名名称或类名称作为其第一个参数,以及一个命令参数数组作为第二个参数。将返回退出代码:
use Illuminate\Support\Facades\Artisan;
Route::post('/user/{user}/mail', function (string $user) {
$exitCode = Artisan::call('mail:send', [
'user' => $user, '--queue' => 'default'
]);
// ...
});
或者,您可以将整个 Artisan 命令传递给call
方法作为字符串:
Artisan::call('mail:send 1 --queue=default');
传递数组值
如果您的命令定义了一个接受数组的选项,您可以将一组值传递给该选项:
use Illuminate\Support\Facades\Artisan;
Route::post('/mail', function () {
$exitCode = Artisan::call('mail:send', [
'--id' => [5, 13]
]);
});
传递布尔值
如果您需要指定不接受字符串值的选项的值,例如--force
旗帜在migrate:refresh
命令,你应该通过true
或者false
作为选项的值:
$exitCode = Artisan::call('migrate:refresh', [
'--force' => true,
]);
排队工匠命令
使用queue
上的方法Artisan
facade,您甚至可以将 Artisan 命令排队,以便它们在后台由您的队列工作者.在使用此方法之前,请确保您已配置队列并正在运行队列侦听器:
use Illuminate\Support\Facades\Artisan;
Route::post('/user/{user}/mail', function (string $user) {
Artisan::queue('mail:send', [
'user' => $user, '--queue' => 'default'
]);
// ...
});
使用onConnection
和onQueue
方法,您可以指定 Artisan 命令应该发送到的连接或队列:
Artisan::queue('mail:send', [
'user' => 1, '--queue' => 'default'
])->onConnection('redis')->onQueue('commands');
从其他命令调用命令
有时您可能希望从现有的 Artisan 命令调用其他命令。您可以使用call
方法。这call
方法接受命令名称和命令参数/选项数组:
/**
* Execute the console command.
*/
public function handle(): void
{
$this->call('mail:send', [
'user' => 1, '--queue' => 'default'
]);
// ...
}
如果你想调用另一个控制台命令并抑制它的所有输出,你可以使用callSilently
方法。这callSilently
方法具有与call
方法:
$this->callSilently('mail:send', [
'user' => 1, '--queue' => 'default'
]);
信号处理
您可能知道,操作系统允许将信号发送到正在运行的进程。例如,SIGTERM
信号是操作系统如何要求程序终止。如果你想在你的 Artisan 控制台命令中监听信号并在它们出现时执行代码,你可以使用trap
方法:
/**
* Execute the console command.
*/
public function handle(): void
{
$this->trap(SIGTERM, fn () => $this->shouldKeepRunning = false);
while ($this->shouldKeepRunning) {
// ...
}
}
要一次收听多个信号,您可以向trap
方法:
$this->trap([SIGTERM, SIGQUIT], function (int $signal) {
$this->shouldKeepRunning = false;
dump($signal); // SIGTERM / SIGQUIT
});
存根定制
Artisan 控制台的make
命令用于创建各种类,例如控制器、作业、迁移和测试。这些类是使用“存根”文件生成的,这些文件根据您的输入填充了值。但是,您可能希望对 Artisan 生成的文件进行小的更改。为此,您可以使用stub:publish
命令将最常见的存根发布到您的应用程序,以便您可以自定义它们:
php artisan stub:publish
发布的存根将位于stubs
应用程序根目录中的目录。当您使用 Artisan 生成相应的类时,您对这些存根所做的任何更改都会反映出来make
命令。
Events
Artisan 在运行命令时调度三个事件:Illuminate\Console\Events\ArtisanStarting
,Illuminate\Console\Events\CommandStarting
, 和Illuminate\Console\Events\CommandFinished
.这ArtisanStarting
当 Artisan 开始运行时,事件会立即被调度。接下来,CommandStarting
在命令运行之前立即分派事件。最后,CommandFinished
一旦命令完成执行,事件就会被分派。