Question

What I'm trying to achieve is creating an application that is highly modular. I'm trying to create a cron script which addresses all the cron scripts that need to be fired in all the sub-modules. What I would actually would like to do, is create an event, say runCron that gets fired from a CController and then hook into that when it get's raised from within the sub modules with onRunCron methods. Outlining what I'm trying to do:

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

What I think I will need to do according to Yii's event system, is create the event and raise it at an application-level (that is still what I'm trying to do) but then; I also need to assign the callbacks from the submodules on an application-level in the controller. Which I do not want, since when a submodule gets added / deleted, the application needs to be adjusted, which does not sound modular at all.

Could someone line out the basics of setting up a event like this and making it as modular as possible? Since I think I'm looking at this completely the wrong way.

Edit (solution):

Thanks to acorncom's answer I've managed to work out the following system.

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;
    }
}
?>

This "proof of concept" setup manages to print out the following result, exactly what I wanted it to do:

string(30) "CronController - Starting cron"
string(25) "CronController - Run cron"
string(22) "AdminModule - Run cron"
string(28) "CronController - Ending cron"
Était-ce utile?

La solution

I think you'll want to do something like the following (note: this hasn't been tested, but it should work conceptually).

  1. Create a CApplicationComponent for your cron system. Having it be an application component (registered in your config/main.php file) makes it accessible from anywhere in your app / modules / sub modules / controllers, etc

  2. Have your cron component handle the registration of events / firing of events. Refer to the Yii events page for more info on the details of how this works. Note: you can create your own custom events that subclass the main CEvent class if you need to pass in additional parameters about your events.

  3. Have your modules register as event handlers with your cron component as they initialize.

  4. Have your controller fire off an event to your cron component.

One potential gotcha. I'm not sure whether modules or components are registered first (I believe components should be, but it's worth testing). If your cron component is loading after the modules that are trying to register events with your cron component, then you may want to preload your cron component. There are a few other hacks you can try if that doesn't work (come back and ask for more details).

Oh, and let us know how it goes!

Autres conseils

Have you checked the wikis on yii's website about events? I think it's a good place to start, then if you still have some questions we could help you!

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top