2

I'd like to include action hooks similar to those found in Wordpress. I've read the chapter on writing plugins, but I'd to be able to maintain them without altering the code in the parent app.

Is there any baked-in support for this?

If not, is there a good way to do it? I have some ideas but I'm worried I'm going to be reinventing the wheel.

emersonthis
  • 32,822
  • 59
  • 210
  • 375

2 Answers2

4

Yes there is.

CakePHP Event System

It works a lot like WordPress's hooks, but only better.

You can register callbacks in different places, but easy way is to do this in the bootstrap.php of the plugin.

When the application loads the plugin it can tell CakePHP to bootstrap it. This is done with this command.

CakePlugin::loadAll(array(array('bootstrap'=>true,'routes'=>true)));
Reactgular
  • 52,335
  • 19
  • 158
  • 208
  • I'm having a little trouble with registering the listeners. If I understand you correctly, I should place code similar to the book's example (http://book.cakephp.org/2.0/en/core-libraries/events.html#registering-listeners) in my plugin's bootstrap.php file and then place the code you provided in the parent app's bootstrap.php file. Is that correct? – emersonthis Jun 04 '13 at 16:47
  • Yes, remove `routes` if you don't have routes for your plugin. http://book.cakephp.org/2.0/en/plugins.html – Reactgular Jun 04 '13 at 16:49
  • Thanks for your help. I get `Error: Using $this when not in object context` from the last line (`$this->Model->getEventManager()->attach()`) in the example code. How should this work from in the plugin's bootstrap.php file? – emersonthis Jun 04 '13 at 17:19
  • @Emerson there are two event managers. One attached to an object (controllers, models, etc.) and the global one. It takes some getting use to but worth learning. To access the global read this. http://book.cakephp.org/2.0/en/core-libraries/events.html#the-global-event-manager – Reactgular Jun 04 '13 at 17:49
  • This is more interesting info. But I'm still stuck. When you originally advocated putting it in the plugin's bootstrap.php file, which EventManager where you envisioning? If I don't use the global, and I want to call a specific controller action in response to an event, where do you recommend I put that `attach()`? Inside that controller? – emersonthis Jun 04 '13 at 19:11
  • Events shouldn't talk to controllers. You should put your business logic into the models, and then you can easily access that model from the event listener. `$model = ClassRegistry::init("Myplugin.Document");`. – Reactgular Jun 04 '13 at 19:24
  • @Emerson if everything is in the models, then you aren't dependant upon the controllers. This is called the `fat model pattern`. http://stackoverflow.com/questions/467113/fat-models-skinny-controllers-and-the-mvc-design-pattern – Reactgular Jun 04 '13 at 19:25
  • This is starting to make my head hurt. Right now I think I have about 3 or 4 different ways to do this, all of which I understand 75%. I would love a single implementation that will work. Basically, I need to match a specific code snippet (there are several variations in the book) with location where it will actually work. – emersonthis Jun 04 '13 at 19:31
  • For example: "the use the global EventManager like so: ____ and put it in the MyPluginAppModel (or wherever). The problem I have is that the Event system is very tricky and sparsely documented. And there are various implementations with differing syntax that only works in specific contexts. Everyone keeps saying things like "it doesn't matter where you register your event listener..." which I understand to be true, but that doesn't help me get it to actually work. So I keep chasing my tail. – emersonthis Jun 04 '13 at 19:34
  • Slow down, take a break, and then post new questions on stackoverflow that are specific. You need to learn it before you implement it. – Reactgular Jun 04 '13 at 19:36
  • Fair enough. I have posted a more focused question: http://stackoverflow.com/questions/16923246/where-to-register-event-listeners . But the advice you've given me here has been more constructive so far. – emersonthis Jun 04 '13 at 19:39
2

I'm not sure what you're trying to acomplish, but you could do something like this:

Your controller(s) beforeFilter() method is a good place to create certains hooks:

public function beforeFilter() {
    parent::beforeFilter();  // don't forget to call parent code
    $myHandler->doSomethingInteresting( $this->name, $this->action );
}

where $this->name will give you the name of the controller being called, and $this->action will give you the name of the current action.

I hope it helps a little.

ilbesculpi
  • 328
  • 3
  • 15
  • True, but if you want to hook into a Model from the application when it saves data. There is no telling when that hook will be fired. Your controller may not be the current activity. – Reactgular Jun 04 '13 at 15:44