jlorente / yii2-command-handler
一个为 Yii2 框架提供命令设计模式的扩展。用于在主进程中创建命令并在其他进程(如 crons、控制台控制器等)中执行这些命令。
README
一个为 Yii2 框架提供 命令设计模式 的扩展。用于在主进程中创建命令并在其他进程(如 crons、控制台控制器等)中执行这些命令。
安装
要安装,运行以下命令之一:
$ php composer.phar require jlorente/yii2-command-handler "*"
或者添加
... "require": { // ... other configurations ... "jlorente/yii2-command-handler": "*" }
到您的 composer.json
文件的 require
部分,然后从您的项目目录中运行以下命令。
$ composer update $ ./yii migrate --migrationPath=@app/vendor/jlorente/yii2-command-handler/src/migrations
最后一个命令将创建处理命令列表所需的表。
基本用法
首先,您必须将模块包含到您的控制台应用程序中,以便执行命令队列处理器。
./console/config/main.php
// ... other configurations ... "modules" => [ // ... other modules ... "command" => [ "class" => "jlorente\command\Module" ] ]
现在您可以开始创建自己的命令了。
示例
假设我们想在管理员点击按钮时向一组用户发送多封电子邮件。这个过程可能很繁琐,并且随着组内用户数量的增加,所需时间也会增加,因此我们的管理员将不得不等待整个过程完成才能继续在网站上导航。
在这里,我们可以创建一个命令,并通过仅编写几行代码将进程委托给另一个非锁定进程。
接收器
首先,Group 类必须实现 \jlorente\command\base\Receiver 接口,并实现向所有组用户发送电子邮件的方法。
namespace common\models; use yii\db\ActiveRecord; use jlorente\command\base\Receiver; class Group extends ActiveRecord implements Receiver { public function sendEmailToUsers() { //Implementation of the send email to group users method goes here. } }
命令
现在我们必须创建将执行此方法的命令。请注意,命令必须实现 \jlorente\command\base\CommandInterface 或扩展其提供的一个子类(例如,\jlorente\command\base\Command 用于扩展自 \yii\base\Model 的类,\jlorente\command\db\Command 用于实现 \yii\db\ActiveRecordInterface 的类)。
//In our example we will extend the \jlorente\command\db\Command because Group extends from \yii\db\ActiveRecord namespace common\models\commands; use jlorente\command\db\Command; class GroupSendEmailCommand extends Command { /** * @inheritdoc */ public function run() { $this->getReciver()->sendEmailToUsers(); } }
命令映射器
现在我们将创建一个控制器操作,它接收用户点击事件,创建并放置命令到命令列表中。
namespace frontend\controllers; use yii\web\Controller; use yii\web\NotFoundHttpException; use common\models\commands\GroupSendEmailCommand; use jlorente\command\db\CommandMapper; class GroupController extends Controller { public function actionSendEmail($groupId) { $group = Group::findOne($groupId); if ($group === null) { throw new NotFoundHttpException(); } $command = new GroupSendEmailCommand(); $command->setReceiver($group); CommandMapper::map($command); //Enqueues the command } }
控制台控制器
控制台控制器将处理命令列表,并以队列模式执行其中的命令。您可以使用以下 shell 命令运行控制台控制器。
$ ./yii <moduleId>/command-processor/run <int>
其中 <moduleId>
是您在配置文件中模块配置中使用的名称,<int>
是一个可选参数,用于限制在执行中处理的映射器数量。
您可能希望将操作执行放在 cronjob 或类似任务中,每分钟或您希望的时间间隔运行。
/etc/crontab
*/1 * * * * <PathToProject>/yii <moduleId>/command-processor/run
高级用法
行为
除了包之外,还有一个可以附加到您的模型上的行为,它可以创建和映射命令。继续上一个示例,我们将在组更改其状态属性时发送电子邮件到用户组,而不是在控制器操作中创建和映射命令。
namespace common\models; use yii\db\ActiveRecord; use jlorente\command\base\Receiver; use jlorente\command\behaviors\CommandGeneratorBehavior; use common\models\commands\GroupSendEmailCommand; class Group extends ActiveRecord implements Receiver { public function sendEmailToUsers() { //Implementation of the send email to group users method goes here. } public function behaviors() { return array_merge(parent::behaviors(), [ // ... other behaviors ... [ 'class' => CommandGeneratorBehavior::className(), 'commands' => [ self::EVENT_BEFORE_SAVE => GroupSendEmailCommand::className(), ], 'condition' => function ($model) { return $model->isAttributeChanged('state'); } ] ]); } }
通过这样做,每当状态属性更改时,GroupSendEmailCommand 将被排队。有关更多配置参数,请参阅 CommandGeneratorBehavior 类的文档。
命令处理器
可能您想自己运行命令队列处理器,而不是使用提供的控制台控制器。
您可以通过实例化和运行 CommandProcessor 类来实现这一点。
use jlorente\command\base\CommandProcessor; $processor = new CommandProcessor(); $processor->run();
您可以通过在队列和堆栈模式之间选择来设置命令处理器执行命令的方式。默认情况下,命令处理器将以队列模式处理执行。
$processor->setMode(CommandProcessor::MODE_QUEUE)
run 方法还接受两个参数。第一个是一个整数,它将限制要处理的命令数量,第二个是一个布尔值,它表示是否需要将错误的命令恢复到队列中以再次处理。默认情况下,处理器将尝试处理列表中的所有命令,并将错误的命令恢复。
$processor->run(10, false); //This will limit the commands to 10 and won't restore the erroneous ones.
进一步考虑
之前我说过,ActiveRecord 接收器必须继承自 \jlorente\command\db\Command。这根本不是真的,这取决于您想要达到的最终行为。ActiveRecord 接收器可以继承自 \jlorente\command\base\Command,但命令接收器将存储命令创建时的状态,而不是执行命令时的状态。从 \jlorente\command\db\Command 继承的命令将始终从数据库中检索 ActiveRecord 对象,而不是使用当命令创建时具有属性的副本。
许可协议
版权所有 © 2015 José Lorente Martín jose.lorente.martin@gmail.com。
根据 MIT 许可协议许可。有关详细信息,请参阅 LICENSE.txt。