Get it All

For reasons I’m not entirely clear on, CakePHP developers object in general to the practice of including Models into your Componets. I suspect the problem lies in the idea that you might end up with lots and lots of associated Models within the overall framework of a given Controller, leading to bad performance. That makes some sense, but why aren’t there any directions then on how to include the Controller’s Models into the Component, when its actually quite easy to do?

I dunno. But I finally figured it out and I’m passing along the information.

The trick is using the initialize() function. I presume that CakePHP must look at all included Objects to see if this function exists, otherwise I’m not entirely sure how else it becomes a globally recognized function. Perhaps someone more knowledgeable can chime in down there in the comments thingy?

Still, here is some sample code that first includes the Controller into the Component as a reference (taken from this example in the CakePHP Book) and then takes the logical next step of including the Model (in this case, WebPriceView) into the Component as well:

// initialize:	Initializing the Component, importing some needed Objects from the Controller.
public function initialize(&$controller) {
	$this->controller	=& $controller;
	$this->WebPriceView	=& $controller->WebPriceView;

It bears mentioning that this example can be extended well beyond including Models to including helpers and anything else you need from the Controller.

It happens from time to time that we need to associate Models which do not share a common key. An example of this is when I needed to associate pages with templates in a complex join where the PageSettings Model has a primary key of pageid and the PageTemplate Model has a primary key of template_id. We cannot use the primaryKey index of the association array to indicate the relationship, so we need to bypass that index altogether and instead use ‘conditions’ to specify the relationship as follows:

var $hasOne = array('PageTemplate'	=> array('foreignKey' => false,
								       'conditions'	=> array('PageSettings.page_template = PageTemplate.template_id')));

Note also that the ‘conditions’ clause is set using explicit conditions, inasmuch as we are stating that the PageSettings.page_template in the current query should be the same as the PageTemplate.template_id value. I’ve personally been confused in the past, thinking that the ‘PageSettings.page_template’ => ‘PageTemplate.template_id’ formula would naturally be the preferred way of forming the condition in CakePHP. Certainly, that would make sense based on convention, but for reasons I’m not familiar with, this is not how they do it.

I’ve seen many threads on the CakePHP Google Group about how to organize files on a CakePHP installation, but many of those threads are very old and I don’t think they’re always all that relevant. Once a project gets involved, or if the project is aimed at recreating an already-complex structure, it is common to have many files of similar function that it only makes sense you would want to organize into subfolders for expedience – not to mention neatness. Recently, I’ve had cause to start trying to organize files and thought I’d share a few observations. If you find any errors in my logic or ambiguity in the way I explain things, please comment below so I can make the corrections as needed.

Controllers and Models

Probably the most convenient in terms of CakePHP’s ability to flexibly handle subdirectories are Models and Controllers. Here you have the ability to just throw files into subdirectories of the /controllers or /models folders at will and CakePHP will automatically find them at run time with no extra configuration. I have not tested folder depth: I have not see whether /controllers/deep/path works as well as /controllers/path, but certainly a single subdirectory works fine, even with files that were already created in the root directory and later moved.

Views (and Elements, and Layouts, and so on..)

With Views and Elements, subdirectories still work, but in this case the subdirectory path must be specified. If you put an element file inside /views/elements/charts/template_1.ctp, then the path relative to the /elements folder must be specified like so:

<?php echo $this->element('charts/template_1', $args); ?>

So, that’s pretty much all I had to add to the conversation. I hope this relatively simple blog post helps a few of you out there looking for a straight-forward answer to the question, “How do I organize my CakePHP files?”