我正在努力实现的目标正在创建一个高度模块化的应用程序。我正在尝试创建一个cron脚本,它解决了所有需要在所有子模块中触发的cron脚本。我真正想要做的是创建一个事件,比如说runCron
从CController
被触发,然后在从onRunCron
子模块中引发它时挂钩方法。概述我正在尝试做的事情:
Application
|- CronController.php - Raise the event 'RunCron', not knowing which modules will fire after this.
|- Modules
|- Nodes
|- Observe the event 'onRunCron' and run own cron script
|- Users
|- Observe the event 'onRunCron' and run own cron script
根据Yii的事件系统,我认为我需要做什么是创建事件并在应用程序级别提升它(这仍然是我正在尝试做的事情)但是然后;我还需要在控制器中的应用程序级别上分配子模块的回调。这是我不想要的,因为当添加/删除子模块时,需要调整应用程序,这根本不是模块化的。
有人可以列出设置此类事件的基本知识并使其尽可能模块化吗?因为我认为我完全错误地看待这个。
编辑(解决方案):
感谢acorncom's answer我设法制定了以下系统。
application.components.CronSingleton
<?php
class CronSingleton extends CApplicationComponent {
/**
* Make sure we "touch" the modules, so they are initialised and are able to attach their listeners.
*/
public function touchModules () {
$modules = Yii::app()->getModules();
if (!empty($modules)) {
foreach ($modules as $name => $module) {
Yii::app()->getModule($name);
}
}
}
/**
* This method should be run to run the cron. It will commense all the procedures in cronjobs
*/
public function execCron($caller) {
$this->touchModules();
$this->onStartCron(new CEvent($caller));
$this->onRunCron(new CEvent($caller));
$this->onExitCron(new CEvent($caller));
}
/**
* Raise an event when starting cron, all modules should add their listeners to this event if they would like to fire something before running the cron.
*/
public function onStartCron ($event) {
$this->raiseEvent('onStartCron', $event);
}
/**
* Raise an event when running cron, all modules should add their listeners to this event to execute during cron run. Mosty this event should be used.
*/
public function onRunCron ($event) {
$this->raiseEvent('onRunCron', $event);
}
/**
* Raise an event when cron exits, all modules should add their listeners to this event when cron exits.
*/
public function onExitCron ($event) {
$this->raiseEvent('onExitCron', $event);
}
}
?>
application.controllers.CronController
<?php
class CronController extends Controller
{
public $layout='//layouts/bare';
public function actionIndex($k) {
Yii::app()->cron->onStartCron = array($this, 'startcron');
Yii::app()->cron->onRunCron = array($this, 'runcron');
Yii::app()->cron->onExitCron = array($this, 'exitcron');
Yii::app()->cron->execCron($this);
}
public function startcron(){
var_dump('CronController - Starting cron');
}
public function runcron(){
var_dump('CronController - Run cron');
}
public function exitcron(){
var_dump('CronController - Ending cron');
}
}
?>
application.modules.admin.AdminModule
<?php
class AdminModule extends CWebModule
{
public function init()
{
// this method is called when the module is being created
// you may place code here to customize the module or the application
// import the module-level models and components
$this->setImport(array(
'admin.models.*',
'admin.components.*',
));
Yii::app()->cron->onRunCron = array($this, 'runCron');
}
public function runCron($event) {
var_dump('AdminModule - Run cron');
}
public function beforeControllerAction($controller, $action)
{
if(parent::beforeControllerAction($controller, $action))
{
// this method is called before any module controller action is performed
// you may place customized code here
return true;
}
else
return false;
}
}
?>
这个“概念验证”设置设法打印出以下结果,正是我想要它做的:
string(30) "CronController - Starting cron"
string(25) "CronController - Run cron"
string(22) "AdminModule - Run cron"
string(28) "CronController - Ending cron"
答案 0 :(得分:1)
我认为你会想做类似下面的事情(注意:这还没有经过测试,但它应该在概念上有效)。
为您的cron系统创建一个CApplicationComponent。将它作为应用程序组件(在config / main.php文件中注册)使其可以从app / modules / sub modules / controllers等的任何位置访问
让您的cron组件处理事件/触发事件的注册。有关其工作原理的详细信息,请参阅Yii事件页面。注意:如果需要传递有关事件的其他参数,则可以创建自己的自定义事件,这些事件是主CEvent类的子类。
让您的模块在初始化时使用您的cron组件注册为事件处理程序。
让您的控制器触发事件到您的cron组件。
一个潜在的问题。我不确定模块或组件是否首先注册(我相信组件应该是,但它值得测试)。如果您的cron组件在尝试使用您的cron组件注册事件的模块之后加载,那么您可能需要预加载您的cron组件。如果不起作用,还可以尝试其他一些黑客(回来再询问更多细节)。
哦,让我们知道它是怎么回事!
答案 1 :(得分:0)
您是否在yii网站上查看了有关活动的wiki?我认为这是一个好的开始,如果你还有一些问题我们可以帮助你!