构建基于事件的应用程序范围的cron组件

时间:2013-02-26 11:13:40

标签: module yii yii-events

我正在努力实现的目标正在创建一个高度模块化的应用程序。我正在尝试创建一个cron脚本,它解决了所有需要在所有子模块中触发的cron脚本。我真正想要做的是创建一个事件,比如说runCronCController被触发,然后在从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"

2 个答案:

答案 0 :(得分:1)

我认为你会想做类似下面的事情(注意:这还没有经过测试,但它应该在概念上有效)。

  1. 为您的cron系统创建一个CApplicationComponent。将它作为应用程序组件(在config / main.php文件中注册)使其可以从app / modules / sub modules / controllers等的任何位置访问

  2. 让您的cron组件处理事件/触发事件的注册。有关其工作原理的详细信息,请参阅Yii事件页面。注意:如果需要传递有关事件的其他参数,则可以创建自己的自定义事件,这些事件是主CEvent类的子类。

  3. 让您的模块在初始化时使用您的cron组件注册为事件处理程序。

  4. 让您的控制器触发事件​​到您的cron组件。

  5. 一个潜在的问题。我不确定模块或组件是否首先注册(我相信组件应该是,但它值得测试)。如果您的cron组件在尝试使用您的cron组件注册事件的模块之后加载,那么您可能需要预加载您的cron组件。如果不起作用,还可以尝试其他一些黑客(回来再询问更多细节)。

    哦,让我们知道它是怎么回事!

答案 1 :(得分:0)

您是否在yii网站上查看了有关活动的wiki?我认为这是一个好的开始,如果你还有一些问题我们可以帮助你!