How to create an instance of a controller

Published on and tagged with cakephp  controller

Usually you do not have to care about the instantiation of controllers, it is done automatically for you by CakePHP. Though, in some cases it might be necessary to do it manually, at least I saw some people who tried it and failed. So, how do you do it?

The obvious way is to use the following approach:

$myController = new ExampleController();
$myController->test();

If you are “lucky” and you do not use components or models in the called method, then the snippet above works fine. In the other case, you will get a “Call to a member function on a non-object” error.

The reason for this error is that the models and components used by the controller are not constructed when you create a new instance of the controller. For this purpose you have to call the constructClasses() method before you use any controller methods. We can now rewrite the example from above to:

$myController = new ExampleController();
$myController->constructClasses();
$myController->test();

This probably works in most cases. I say “probably”, because if the used components use callback methods like initialize() or startUp(), then you have to call those callbacks yourself. The same is true if you want to use the beforeFilter() and afterFilter() callbacks in your controller.

Here an example with calling the initialize() callback method of the components (“Component” is misnamed, it is in fact a container which contains all components a controller uses):

$myController = new ExampleController();
$myController->constructClasses();
$myController->Component->initialize($myController);
$myController->test();

This is a bit ugly, because you have to know implementation details of the controller you shouldn’t have to know…

Anyway, if you are interested in the complete instantiation and initialization process of a controller, have a look at Dispatcher::dispatch() and Dispatcher::_invoke().

This leads us to an alternative to the instantiation of a controller: to use a controller method indirectly by using Dispatcher::dispatch(). The example would then look like:

$dispatcher = new Dispatcher();
$dispatcher->dispatch('/example/test');

It depends on your specific use case whether this is a possible alternative, as with this approach you no longer have direct access to the respective controller.

Anyway, happy baking!

13 comments baked

  • Rui Cruz

    As I read your article I was wondering in what kind of situations one would need to do this.

    Do you mind giving some concrete examples?

  • Jonah

    I would not recommend doing this. CakePHP is not made to do it, and it does not make sense. And I cannot think of any reasons that you would need to do that.

    Thanks for the FYI tho

  • cakebaker

    @Rui: Thanks for your comment!

    In one case I have seen that someone tried to use a controller from a shell script. Though, I’m not sure what exactly he tried to accomplish.

    Another possible case I could imagine is testing, when you want to have your controller in a certain state.

  • Mark Story

    Daniel, you forgot about Component->init($controller) That is the callback that actually loads the components, which is necessary, as without it the rest of Component’s methods do nothing.

    Jonah: As for why you would need to do this, biggest use is in testing. Testing controllers like a model (by directly running their methods) is the most powerful and flexible way to test controllers.

  • http-repsah.pip.verisignlabs.com-

    I was the one, it might make little sense to you and I might be totally wrong at doing it, but rather that writing a complete different application to handle certain situations I’d rather find a way to access my controllers through a script run by crontab, which I found and I keep using with satisfactory results.

  • cakebaker

    @Mark, Repsah: Thanks for your comments!

    @Mark: No, I didn’t forgot the init() callback. At least in the current version (rev. 7897) from the repository the init() callback is automatically called if you use Controller::constructClasses(), see https://trac.cakephp.org/browser/branches/1.2.x.x/cake/libs/controller/controller.php#L413.

  • Pages tagged "how-to"

    [...] bookmarks tagged how-toBusiness Checks How to create an instance of a controller – cakeba… saved by 1 others     narutoboi92 bookmarked on 11/28/08 | [...]

  • Mark Story

    Daniel: must have missed it hiding way up at the top ;) my bad.

  • Martin Westin

    @Rui & @cakebaker:
    Thought I’d chime in since I call controllers from a shell (cron job).

    The cron is an “hourly update” type of cron for aggregating reporting data, send scheduled messages (email, sms…) or performing other timed actions. The reason for calling controllers is that the shell should call all plugins which in turn will decide what needs to be done for that plugin.

    Since each plugin has a PluginnameController and that the call is an “external” request, a controller call seems quite sensibile. The alternative would be some kind of PluginnameModel (which would not really be much of a model) or load a custom shell task located somewhere in the plugin, which would take care of any periodical stuff needed.

    OK, I just thought I’d provide an example of when calling a controller might be used.

  • cakebaker

    @Martin: Thanks for sharing your use case!

  • Fred

    You can also do:

    $myController = new ExampleController();
    $myController->constructClasses();
    $myController->startupProcess();
    $myController->test();

  • cakebaker

    @Fred: Yes, you are right, this is the way you do it in CakePHP 1.3.x (previous versions don’t contain a startupProcess() method). Thanks for mentioning it!

  • Siyan

    Hi,

    Thanks a lot ………. this is just like cherry on cake for me thanks ,,,,

Bake a comment




(for code please use <code>...</code> [no escaping necessary])

© daniel hofstetter. Licensed under a Creative Commons License