Dessert #10 - Default Models, Components & Helpers
Posted on 17/9/06 by Felix Geisendörfer
Deprecated post
The authors of this post have marked it as deprecated. This means the information displayed is most likely outdated, inaccurate, boring or a combination of all three.
Policy: We never delete deprecated posts, but they are not listed in our categories or show up in the search anymore.
Comments: You can continue to leave comments on this post, but please consult Google or our search first if you want to get an answer ; ).
Important: It appears that this method is and has not been needed at all at least for a while. This was one of the first little AppController hacks I used when I started CakePHP in november/december last year and apparently at some point there was an improvement in the Controller class making it unnessarry. I wish those *little* features would be posted somewhere regulary, similar to nate's postings about 1.2.
We all know the problem, there are always Models, Components or Helpers that we need for about 99% of all our actions/views and therefor would fit beautifully in our AppController. The only problem is, as soon as we define them via "var $uses = array('...');" (etc.), we cannot easily add more items in our derived controllers without having to repeat the entire list.
Today I actually felt like writing little piece of code to finally DRY the probem. The basic idea is to not add the items to the AppController by using the "var" command, but rather by overwriting it's __construct() function and adding them there. I already used this technic before, but this time I added a little algorithm to it that would automate the array_merging:
{
/**
* Default Models, Components and Helpers
*/
$default['uses'] = array('Config', 'Menu', 'MenuEntry', 'User', 'Group');
$default['components'] = array('RequestHandler', 'Themes', 'Header', 'MenuManager', 'SimpleAcl', 'SimpleAuth');
$default['helpers'] = array('Html', 'Lugsteinhof', 'Lists', 'Accessibility', 'Javascript', 'Form', 'Time');
foreach ($default as $type => $items)
{
if (empty($this->{$type}))
$this->{$type} = array();
$this->{$type} = array_merge($this->{$type}, $items);
}
parent::__construct();
}
Let me know if you find this approach useful or what kind of technic you are using to solve this problem.
--Felix Geisendörfer aka the_undefined
You can skip to the end and add a comment.
Ad7,
I don't know how CakePHP *could* take care of this. Is there any way to access the default property values of inherited classes? If yes it's totally unknown to me. I couldn't find anything relevant in line 261 of the latest release of the 1.1.x branch which I assume you referr to?
But I agree with the disadvantage you brought up of having to specify var $uses for every Controller. However, this could be easily fixed by using a beforeFilter that uses the Inflector to determine the name of the default Model based on the Controller->name if Controller->uses is not overwritten. But it didn't bother me that much so far.
The reason why I don't create the instances of the classes myself is because I want to leverage as much CakePHP power as possible. When I create instances of Components myself I might also have to run startup() on all of them manually which doesn't seem very DRY to me.
I use a beforeFilter function to achieve this. Which allows me the option of completely overriding it in a specific Controller if I wanted to for some reason, and keeps the array at arm's length. I don't make any effort to avoid duplicate entries, but such a check would be trivial to add.
function add_helpers ()
{
array_push($this->helpers, 'numalist');
array_push($this->helpers, 'numasettings');
array_push($this->helpers, 'numatime');
array_push($this->helpers, 'text');
array_push($this->helpers, 'javascript');
array_push($this->helpers, 'form');
array_push($this->helpers, 'rss');
array_push($this->helpers, 'xml');
array_push($this->helpers, 'datepicker');
}
Hi Felix,
Ooops the line numbers are rather different between 1.2 and 1.1.7 ;). Have a look at this:
https://trac.cakephp.org/browser/branches/1.1.x.x/cake/libs/controller/controller.php#L234
In the controller constructor, lines 234 through 240, the values for the fields components, helpers and uses are merged such that anything defined in app_controller is added to the field values for the child controller. This introduces a minor problem if you want the possibility to declare something in app_controller but remove it for one controller; you can't as it's included as soon as the controller is instanciated - but that's a rather minor problem.
Cheers,
AD7six
AD7six: Wow, that sure looks like a sweet workaround. I'm wondering when this has made it into the core, I know that when I started doing this kind of stuff in the __constructor() I did it because there was a real problem. I'll check it out tomorrow and eventually put a warning sign "This dessert is spoiled" on it ; ). That's what I love about blogging, I learn tons of new stuff through sharing what I know - it's great! Again, thanks for pointing it out.
I added this into the core several months ago working with gwoo. It might have actually been added pre-1.0.
Nate: I'm pretty sure that it has been at least that long ago since I started using workaround like this ; ), but ok after the test I'll put a comment on this post.
Hi all!
As a fresh debuggable.com user i just wanted to say hi to everyone else who uses this forum ;-)
lypeAlicleCip: Hiho, welcome aboard : )
Though this is no forum, but a blog. :]
Greetings,
What is the best VPS web hosting company?
I'm want to build a web site for my new business.
appreciate your feedback,
-Steve
This post is too old. We do not allow comments here anymore in order to fight spam. If you have real feedback or questions for the post, please contact us.
Hi Felix,
Cake already takes care of such inheritance, at least in my experience (controller line 261). The only time I have found this not to be true is with components and helpers defined in plugin-appcontrollers, which aren't taken into account automatically. It's therefore not necessary to repeat values defined in the app controller for uses/components/helpers in child controllers. Aditionally, regarding the uses array, doesn't that risk your controller not having the default model if the $uses value is not set? Or do you always set $uses for all of your controllers?
For example rather than add MiLog to the uses array (which is a model I use primarily for debugging) I just added this to the app_controller constructor.
function __construct () {
parent::__construct();
$this->MiLog = new MiLog();
}
In any event it's good to read and contrast how other's are coding ;)
Cheers,
AD7six