thettler / laravel-console-toolkit
此包提供了一些有用的控制台功能,例如参数和选项的属性语法、验证、自动询问和类型转换。
Requires
- php: ^8.1
- illuminate/contracts: ^9.0|^10.0
- spatie/laravel-package-tools: ^1.9.2
- symfony/console: ^6.0
Requires (Dev)
- laravel/sail: ^1.13
- nunomaduro/collision: ^v6.1.0
- nunomaduro/larastan: ^2.0
- orchestra/testbench: ^7.0|^8.0
- pestphp/pest: ^1.21
- pestphp/pest-plugin-laravel: ^1.4
- phpstan/extension-installer: ^1.1
- phpstan/phpstan-deprecation-rules: ^1.0
- phpstan/phpstan-phpunit: ^1.0
- phpunit/phpunit: ^9.5
- spatie/laravel-ray: ^1.26
This package is auto-updated.
Last update: 2024-09-09 02:15:18 UTC
README
此包使编写可维护且易于表达的Artisan命令更加容易,具有参数/选项类型转换、验证和autoAsk。此外,它允许您使用简单的属性和属性定义您的参数/选项,以获得更好的IDE支持和静态分析。所有这些只需一个特性即可完成。
🤯 特性
所有功能
💜 支持我
访问我的博客https://bitbench.dev或关注我的社交媒体Twitter @bitbench Instagram @bitbench.dev
📦 安装
您可以通过composer安装此包
composer require thettler/laravel-console-toolkit
🔧 使用方法
🗯️ 在您使用此包之前,您应该已经了解Artisan命令。您可以在这里了解有关它们的更多信息。
基本命令
要使用工具包,您只需在您的命令中添加UsesConsoleToolkit特性。
然后将Thettler\LaravelConsoleToolkit\Attributes\ArtisanCommand添加到类中,以指定名称以及其他诸如描述、帮助等事项。
ArtisanCommand需要设置name参数。这将作为您可以通过命令行调用的命令的名称。
<?php namespace App\Console\Commands; use Illuminate\Console\Command; use Thettler\LaravelConsoleToolkit\Concerns\UsesConsoleToolkit; #[ArtisanCommand( name: 'basic', )] class BasicCommand extends Command { use UsesConsoleToolkit; public function handle() { } }
可以这样调用它
php artisan basic
传统语法
<?php namespace App\Console\Commands; use Illuminate\Console\Command; class BasicCommand extends Command { protected $signature = 'basic'; public function handle() { } }
描述、帮助和隐藏命令
如果您想添加描述、帮助注释或将命令标记为隐藏,您可以在ArtisanCommand属性中指定此操作
#[ArtisanCommand( name: 'basic', description: 'Some useful description.', help: 'Some helpful text.', hidden: true )] class BasicCommand extends Command { use UsesConsoleToolkit; ... }
我喜欢使用命名参数,以便更易读。
传统语法
... class BasicCommand extends Command { protected $signature = 'basic'; protected $description = 'Some useful description.'; protected $help = 'Some helpful text.'; protected $hidden = true; ... }
定义输入预期
添加参数或选项的基本工作流程始终是添加一个属性,并用属性对其进行装饰。#[Option]如果您想有一个选项,以及#[Argument]如果您想有一个参数。属性将通过命令行中的值进行填充,因此您可以在handle()方法中像使用任何普通属性一样使用它。
有关更多详细信息,请参阅以下部分。⬇️
❗ 属性仅在
handle()方法内部填充。请注意这一点。
参数
要定义参数,您创建一个属性,并将Argument属性添加到它。属性将通过命令行中的值进行填充,因此您可以在handle()方法中像使用任何普通属性一样使用它。
... use \Thettler\LaravelConsoleToolkit\Attributes\Argument; #[ArtisanCommand( name: 'basic', )] class BasicCommand extends Command { use UsesConsoleToolkit; #[Argument] protected string $myArgument; public function handle() { $this->line($this->myArgument); } }
可以这样调用它
php artisan basic myValue # Output: # myValue
传统语法
class BasicCommand extends Command { protected $signature = 'basic {myArgument}'; public function handle() { $this->line($this->argument('myArgument')); } }
数组参数
您还可以在参数中使用数组,只需将属性的类型提示为array即可。
#[ArtisanCommand( name: 'basic', )] class BasicCommand extends Command { use UsesConsoleToolkit; #[Argument] protected array $myArray; public function handle() { $this->line(implode(', ', $this->myArray)); } }
可以这样调用它
php artisan basic Item1 Item2 Item3 # Output # Item1, Item2, Item3
传统语法
class BasicCommand extends Command { protected $signature = 'basic {myArgument*}'; public function handle() { $this->line($this->argument('myArgument')); } }
可选参数
当然,您也可以使用可选参数。为了实现这一点,您只需使属性为可空的。
ℹ️ 这也适用于
array,但属性将不为空,而是一个空数组
#[ArtisanCommand( name: 'basic', )] class BasicCommand extends Command { use UsesConsoleToolkit; #[Argument] protected ?string $myArgument; ... }
传统语法
class BasicCommand extends Command { protected $signature = 'basic {myArgument?}'; ... }
如果您的参数应该有一个默认值,您可以将一个值分配给属性,该值将用作默认值。
#[ArtisanCommand( name: 'basic', )] class BasicCommand extends Command { use UsesConsoleToolkit; #[Argument] protected string $myArgument = 'default'; ... }
传统语法
class BasicCommand extends Command { protected $signature = 'basic {myArgument=default}'; ... }
参数描述
您可以在Argument属性上设置参数的描述。
#[ArtisanCommand( name: 'basic', )] class BasicCommand extends Command { use UsesConsoleToolkit; #[Argument( description: 'Argument Description' )] protected string $myArgument; ... }
传统语法
... class BasicCommand extends Command { protected $signature = 'basic {myArgument: Argument Description}'; ... }
❗❗ 如果您有多个参数,类中的顺序也将是命令行上的顺序
选项
要在命令中使用选项,您需要使用 Options 属性。如果您设置了 boolean 类型的类型提示,那么如果未设置选项,则它将为 false,如果设置了选项,则它将为 true。
use \Thettler\LaravelConsoleToolkit\Attributes\Option; #[ArtisanCommand( name: 'basic', )] class BasicCommand extends Command { use UsesConsoleToolkit; #[Option] protected bool $myOption; public function handle() { dump($this->myOption); } }
可以这样调用它
php artisan basic --myOption # Output # true
php artisan basic # Output # false
传统语法
class BasicCommand extends Command { protected $signature = 'basic {--myOption}'; public function handle() { dump($this->option('myOption')); } }
值选项
如果您使用不同于 bool 的类型提示来指定属性,则可以给选项添加一个值。这将自动将其转换为具有值的选项。如果您的类型提示不是可空的,则选项将具有必需的值。这意味着选项只能与值一起使用。
❌ 不起作用 --myoption ✅ 工作正常 --myoption=myvalue
如果要让值可选,只需使类型可空或将值分配给属性即可。
#[ArtisanCommand( name: 'basic', )] class BasicCommand extends Command { use UsesConsoleToolkit; #[Option] protected string $requiredValue; // if the option is used the User must specify a value #[Option] protected ?string $optionalValue; // The value is optional #[Option] protected string $defaultValue = 'default'; // The option has a default value #[Option] protected array $array; // an Array Option #[Option] protected array $defaultArray = ['default1', 'default2']; // an Array Option with default ... }
可以这样调用它
php artisan basic --requiredValue=someValue --optionalValue --array=Item1 --array=Item2
传统语法
class BasicCommand extends Command { // requiredValue is not possible // defaultArray is not possible protected $signature = 'basic {--optionalValue=} {--defaultValue=default} {--array=*}'; ... }
选项描述
您可以在 Option 属性上设置选项的描述。
#[ArtisanCommand( name: 'basic', )] class BasicCommand extends Command { use UsesConsoleToolkit; #[Option( description: 'Option Description' )] protected bool $option; ... }
传统语法
class BasicCommand extends Command { protected $signature = 'basic {--option: Option Description}'; }
选项快捷键
您可以在 Option 属性上设置选项的快捷键。
⚠️ 注意:快捷键只能有一个字符长。
#[ArtisanCommand( name: 'basic', )] class BasicCommand extends Command { use UsesConsoleToolkit; #[Option( shortcut: 'Q' )] protected bool $option; ... }
可以这样调用它
php artisan basic -Q
传统语法
class BasicCommand extends Command { protected $signature = 'basic {--Q|option}'; }
可取消选项
您可以通过向 Option 属性中添加可取消参数来使选项可取消。现在该选项接受标志(例如,--yell)或其否定(例如,--no-yell)。
#[ArtisanCommand( name: 'basic', )] class BasicCommand extends Command { use UsesConsoleToolkit; #[Option( negatable: true )] protected bool $yell; public function handle(){ dump($this->yell); // true if called with --yell dump($this->yell); // false if called with --no-yell } }
可以这样调用它
php artisan basic --yell php artisan basic --no-yell
枚举类型
您还可以将 Arguments 或 Options 类型化为枚举。包会自动将命令行输入转换为类型化的枚举。如果您使用 BackedEnums,则使用 case 的值;如果您有一个非 backed 枚举,则使用 case 的名称。
enum Enum { case A; case B; case C; } enum IntEnum: int { case A = 1; case B = 2; case C = 3; } enum StringEnum: string { case A = 'String A'; case B = 'String B'; case C = 'String C'; }
#[Argument] protected Enum $argEnum; #[Argument] protected StringEnum $argStringEnum; #[Argument] protected IntEnum $argIntEnum; #[Option] protected Enum $enum; #[Option] protected StringEnum $stringEnum; #[Option] protected IntEnum $intEnum;
php artisan enum B "String B" 2 --enum=B --stringEnum="String B" --intEnum=2
输入别名
默认情况下,用于命令行的输入名称将与属性名称相同。您可以使用 Option 或 Argument 属性上的 as 参数来更改此名称。这可能在您有冲突的属性名称或希望为您的命令提供更丰富的 API 时很有用。
⚠️ 如果您使用
->option()语法,则需要指定别名名称以获取选项。
#[ArtisanCommand( name: 'basic', )] class BasicCommand extends Command { use UsesConsoleToolkit; #[Argument( as: 'alternativeArgument' )] protected string $myArgument; #[Option( as: 'alternativeName' )] protected bool $myOption; public function handle(){ dump($this->myArgument); dump($this->myOption); } }
可以这样调用它
php artisan basic something --alternativeName
特殊默认值
如果您想要使用一些具有类型转换的默认对象,您可以使用命令上的 configureDefauls() 方法来设置默认值。
#[ArtisanCommand( name: 'basic', )] class BasicCommand extends Command { use UsesConsoleToolkit; #[Argument] protected BandModel $band; public function configureDefaults(): void { $this->band = BandModel::find('2'); } public function handle(){ dump($this->band); // The Band with id 2 } }
类型转换
可以在 Arguments 和 Options 上指定类型转换。您可以选择提供用于转换的类字符串或转换器的实例。这有助于通过构造函数配置转换器。
模型转换
工具包提供开箱即用的 eloquent 模型转换。因此,如果您将类型提示为 eloquent 模型,则工具包会尝试将控制台输入与模型的主键匹配,并从数据库中检索它。
#[Argument] protected BandModel $band; public function handle(){ $this->band // Well be an instance of BandModel }
如果您想更改用于将输入与数据库匹配的列、加载关系或仅选择特定列,您可以使用如下所示的手动转换。
#[Argument( cast: new \Thettler\LaravelConsoleToolkit\Casts\ModelCaster( findBy: 'name', select: ['id', 'name'] with: ['songs'] ) )] protected BandModel $band; public function handle(){ $this->band // Will be an instance of BandModel }
枚举转换
枚举转换将自动将每个类型化的枚举转换为该枚举。但您也可以手动指定它。
#[Argument( cast: \Thettler\LaravelConsoleToolkit\Casts\EnumCaster::class )] protected Enum $argEnum; #[Option( cast: new \Thettler\LaravelConsoleToolkit\Casts\EnumCaster(Enum::class) )] protected Enum $enum;
数组转换
如果您有一个数组并且希望将其所有值转换为特定类型,您可以使用 ArrayCaster。它期望一个转换器和特定类型。
#[Argument( cast: new \Thettler\LaravelConsoleToolkit\Casts\ArrayCaster( caster: \Thettler\LaravelConsoleToolkit\Casts\EnumCaster::class, type: StringEnum::class ) )] protected array $enumArray; #[Option( cast: new \Thettler\LaravelConsoleToolkit\Casts\ArrayCaster( caster: \Thettler\LaravelConsoleToolkit\Casts\EnumCaster::class, type: StringEnum::class ) )] protected array $enumArray2;
自定义转换
您还可以定义自己的转换。为此,您需要创建一个实现 Caster 接口的类。
让我们看看一个小小的 UserCast,它允许您在命令行上简单地使用用户模型的 id,并自动从数据库中检索正确的用户。
<?php class UserCast implements Caster { /** * This method deals with the conversion from the default value to a value the console understand so only * basic return types are allowed * * @param mixed $value The default value if one is present * @param string $type The type is a string representation of the type of the property * @param \ReflectionProperty $property The property reflection itself for more control * @return int|float|array|string|bool|null */ public function from(mixed $value, string $type, \ReflectionProperty $property): int|float|array|string|bool|null { if ($value instanceof Band){ return $value->getKey(); } throw new Exception(self::class . ' can only be used with type '. Band::class) } /** * This method deals with the conversion from console input to property value * * @param mixed $value The Value from the command line * @param class-string<Band> $type The type is a string representation of the type of the property * @param \ReflectionProperty $property The property reflection itself for more control * @return mixed */ public function to(mixed $value, string $type, \ReflectionProperty $property) { return $type::find($value); } }
现在您可以在属性上本地使用此转换,或者在 AppServiceProvider 中注册它以进行自动转换,如下所示:
/** Uses the UserCaster everytime the User class is typehint on an Argument or Option */ \Thettler\LaravelConsoleToolkit\ConsoleToolkit::addCast(UserCaster::class, User::class); /** Uses the UserCaster everytime the User or MasterUser class is typehint on an Argument or Option */ \Thettler\LaravelConsoleToolkit\ConsoleToolkit::addCast(UserCaster::class, [User::class, MasterUser::class]); /** Uses the UserCaster everytime the callable returns true */ \Thettler\LaravelConsoleToolkit\ConsoleToolkit::addCast( UserCaster::class, fn (mixed $value, ReflectionProperty $property): bool => is_subclass_of($property->getType()->getName(), User::class); );
验证
您还可以使用正常的 Laravel 验证规则来验证输入。
#[Argument( validation: ['max:5'] )] protected string $validated;
如果您需要自定义消息,则需要使用验证对象。
#[Argument( validation: new \Thettler\LaravelConsoleToolkit\Transfers\Validation( rules: ['max:5'] messages: [ 'max' => 'This is way to much!' ] ) )] protected string $validated;
自动询问
默认情况下,自动询问是启用的。每次调用命令时,如果输入验证失败或需要但未指定,命令会自动提示用户输入(新的)值。如果类型是枚举,则会提供所有枚举值的选项供用户选择。
如果您想禁用此行为,可以在本地进行
#[Argument( autoAsk: false )] protected string $dontAsk;
或者在您的AppServiceProvider中全局进行
\Thettler\LaravelConsoleToolkit\ConsoleToolkit::enableAutoAsk(false);
🤖 测试
composer test
📖 更新日志
请参阅更新日志获取有关最近更改的更多信息。
👼 贡献
请参阅贡献指南获取详细信息。
🔒 安全漏洞
请查阅我们的安全策略了解如何报告安全漏洞。
©️ 致谢
📚 许可证
MIT许可证(MIT)。请参阅许可证文件获取更多信息。
