Organizing your code with folders

Published on November 22, 2007 and tagged with cakephp  configuration

If you have, for example, a lot of model classes and you wanted to organize them with folders, you had to add the path for each folder to the $modelPaths array in /app/config/bootstrap.php like:

$modelPaths = array('/path_to_model_folder_A/', '/path_to_model_folder_B/');

Thanks to some recent changes in the development branch this is no longer necessary. You can now create as many folders as you want within the “/app/models” folder, and CakePHP will automatically find the models in those folders. So you could have a structure like:

/app
    /models
        /A
        /B
            /C
            /D

A model can now be in the “models” folder as usual, or it could be in one of the other folders (A, B, C, or D). It doesn’t matter. And in your code you do not have to care about in which folder a model is stored, you use your models as usual.

What I described for models also works for controllers, components, and helpers (and probably behaviors, but I didn’t test it with them).

27 comments baked

  • Tarique Sani November 23, 2007 at 08:29

    Wonderful – being lazy here – but does putting controllers inside a folder affect the URL?

    If it does that would be indeed doubly wonderful

  • cakebaker November 23, 2007 at 09:24

    @Tarique: No, it doesn’t affect the URL.

  • Nils Hitze November 23, 2007 at 12:54

    This will definitly help, thanks for the tip.

  • Nik Chankov November 23, 2007 at 14:32

    Nice approach, now I have hudge project and I was wondering how to separate everything without building tons of pluings.

  • Chad Weaber November 25, 2007 at 08:25

    good tip. I just wish modelPaths worked in app controller :/

  • Zonium November 25, 2007 at 14:03

    Being able to put models, controllers, etc. into folders and have them loaded auto/dynamically will help us better organize our code. We can’t afford to have a large amount of controllers (or models) in the same folder.

    ( In fact, before this feature becomes available in 1.2 I have used this similar approach for some projects
    http://bakery.cakephp.org/articles/view/flexible-controller-and-modelpaths )

    However, I still feel that the current cake’s app structure – separating Model, View, Controller at the application level no mater how big your application is – is not the best organization method in many cases.

    We often want to organize our application into smaller ones (think sub-applications or features), each has its own MVC structure for the sake of easy development , delegation and maintenance. Usually one such sub-application has some of its own set of logic, data and related resources such as images, swf and fla files, css and js etc.
    js and fla files may contain a large amount of code to maintain in development environment (take flash based shopping cart as an example).

    When we develop a new feature or update an existing one we have to touch multiple pieces of code, both back-end and front-end. Having to find /remember all related files which reside in multiple locations is not fun and even significantly slows down the development process (we’re targeting rapid development, aren’t we?)

    Our front-end developers often complaint about having to put all their code and supporting resources in predefined places in webroot. To make some simple change for a SINGLE feature of the site they have to look into different places (views, js, css, img etc.), and because these places are shared by the WHOLE application, there are ton of files (that do not belong to the feature) that the developers have to search through. Yes, they can put them in sub-folders but these folders are still not in the same umbrella representing the feature.

    We really want to place front-end stuff closer to, or in the same place as back-end stuff which includes related Models and Controllers, to save our time.
    We’ve got to find our own way to more or less accomplish this, but we wish the fragmentation issue in Cake’s app structure is noted and solved.

  • Vladimir Luchaninov November 25, 2007 at 16:44

    @Zonium: use .htaccess and mod_rewrite

  • cakebaker November 26, 2007 at 18:25

    @all: Thanks for your comments.

    @Zonium: Sounds like you are looking for plugins, as each plugin has its own MVC structure. I am not sure whether they have their own webroot now (a corresponding ticket, https://trac.cakephp.org/ticket/1897, is still open), you may have to ask one of the devs. It is possible it has been added in the meantime.

  • titang November 27, 2007 at 12:33

    This is a great feature. Does this work for the “elements” folder? I work on a project with more than 60 elements in “elements” folder. i planned to organize it by using folder, but i was discouraged to rename all the references in the project…

  • cakebaker November 27, 2007 at 18:33

    @titang: No, it doesn’t work for the “elements” folder, you still have to specify in which folder an element is located.

  • Zonium November 27, 2007 at 23:27

    @cakebaker:
    I have used plugins, I know plugins enable implementation of separate MVC packages. However, there is paradox: while the plugins in cakePhp are meant for self contained sub-applications (sharing models with the main application is not expected), all front-end stuff (js, css, img) are tied to the main app (they got to be in the main app’s webroot).

    There were some requests to increase the flexibility of plugins
    http://groups.google.com/group/cake-php/browse_thread/thread/8526219c24ce3a8b/0d8ff47ad5e89faf?lnk=gst&q=plugins+gwoo#0d8ff47ad5e89faf

    and some positive responses:

    http://groups.google.com/group/cake-php/msg/17895d05b0a65397

  • DarkRyder November 28, 2007 at 11:35

    Although I needed no modification by adding $modelPaths as suggested, or in this case $controllerPaths, sub folders worked fine and correctly found the file.

    However the class declaration “class Comment/commentController”

    has led to this error:

    Parse error: syntax error, unexpected ‘/’, expecting ‘{‘ in [omitted path to app]/app/controllers/comment/comment_controller.php on line 2

    When using the bootstrap method doesn’t find the controller in the sub folder.

  • cakebaker November 28, 2007 at 18:13

    @Zonium: Yes, it seems plugins are a bit restricted.

    @DarkRyder: Why do you want to create a “Comment/commentController”? If you use subfolders then the controllers are named as usual, in this case it would be “CommentController”.

    HTH

  • Dieter December 01, 2007 at 22:56
  • Brandon P December 02, 2007 at 20:04

    @Dieter:
    Great read! It’s nice to see people discussing these kinds of issues which test the limits of cake!

    You mentioned naming conflicts in one of your replies and I agree this is a serious hindrance of cakephp’s extensibility. Even within it’s own code base there are serious conflicts. For example, just one I ran into:

    Controller Model vs. Component
    ————————-
    EmailsController
    var $uses = array(‘Email’);
    var $components = array(‘Email’);
    Question: What does $this->Email reference to in the EmailsController?

    IMO, there needs to be a better way to (generically) namespace parts of the cake core and 3rd party classes. Vendor apps, plugins, etc would catapult the framework to a whole new level.

  • cakebaker December 03, 2007 at 18:17

    @Brandon: I agree with you that this is a problem. Any idea how this could be solved (without waiting for support of namespaces in PHP)?

  • brandon December 03, 2007 at 23:41

    @cakebaker
    I think the problem can be solved in 2 parts:

    1. There is a need for more strict assignment conventions of components and helpers. It would also help remove much of the ambiguity when reading code:

    $this->component->Email->send();
    $this->helper->Form->create();

    One could even take it as far to make a static/ad-hoc class to load these classes dynamically and store them as singletons (those that don’t need to be injected into cakes runtime process … ie. for callbacks).

    2. Assignments of components and helpers should work in similarity to how models are constructed. A person should be able to “plug-n-play” different components that share the same basic functionality. For example:

    var $components = array(‘Acl’ => array(‘className’ => ‘MyAclComponent’));

    This way if you decide to switch the Acl component out you aren’t left with having to search & replace all “$this->Acl” with “$this->MyAcl”.

    I think there should be more of a movement into making abstract API’s so there can be multiple classes that are 100% interchangeable. A good example would be a jQueryAjaxHelper that uses jQuery (instead of prototype) for Ajax.

    Btw, here are a few more examples of possible conflicts:

    Helper vs. Controller::set()
    —–
    var $helpers = array(‘List’);
    $this->set(‘List’, array(1, 2, 3)):
    Question: What does in the view print out?

    Model vs. Core Lib. Class
    —–
    Model: Folder (references folders table)
    Question: What happens when you do uses(‘folder’)? Can you even USE the Folder class in the core?

  • cakebaker December 04, 2007 at 20:37

    @brandon: Thanks for your answer!

    1) Yes, that’s a possible solution, even though it looks a bit ugly ;-) Another solution could be to forget the current concepts “helper” and “component” and to rethink it completely.

    2) I agree with you. Such abstract API’s would also help with testing, and the framework could provide mock implementations of core stuff for testing.

  • brandon December 05, 2007 at 00:54

    @cakebaker

    Beauty is in the eye of the beholder :) I see the code and my brain goes “ah, thats a component because it says component”. But I agree with you that the concepts of both helpers and components need to be refined. Actually, IMO, you can add behaviors to that list too :)

    Why behaviors? Again, mainly because of naming conflicts. If you have two behaviors that have a semantically equivalent method names (which is legal in PHP) :

    Behavior1::test();
    Behavior2::test();
    Model … $actsAs = array(‘Behavior1′, ‘Behavior2′);
    Question: Which behavior does $this->Model->test() refer to?

    Not sure if this issue has been looked into or fixed but you can imagine how this would be a major conflict! I have already ran into the problem where you can’t have method names that match Model’s methods: read(), create(), etc.

    2. Glad you agree! I think more time should be invested into making 3rd party classes/packages work WITH cake (not along side it). The argument could be made that any class within cake can be extended — but you get into situations where sloppy programming can overwrite dependent code. I’d personally like to see cake branch off a PHP5 version and take advantage of these concepts and practices.

    Also, thanks for bringing up testing. That would be so great because then new classes/packages could be run against the core tests (there is no need for developers to create redundant tests).

  • cakebaker December 06, 2007 at 18:49

    @brandon: Thanks for your answer!

    Yes, you can also add behaviors to that list. I always forget them, as I don’t use them very often ;-)

    2) Hm, I don’t understand what you mean with “making 3rd party classes/packages work with cake”. Usually, you don’t have any control about 3rd party classes and you cannot change them (well, you could change them, but if there is an update you have to re-apply your changes).

    I would like to see a PHP5-only version of Cake, too. Unfortunately, PHP4 is still widespread…

  • Tim Daldini December 27, 2007 at 02:14

    Not sure if this is what Dieter or Zonium is also saying but I think it would be useful to group certain classes, (especially views and controllers) together…maybe even in the same directory.

    Sometimes I think it would be cool if controllers could be split up in that way that each action represents a file and these files could be grouped with corresponding views or something.

    But then again, that really resembles the ASP.NET codebehind concept…oh well.

  • cakebaker December 27, 2007 at 18:57

    @Tim: Yes, sometimes it would be really useful if you could group certain classes together. At least to a certain degree you can do that with plug-ins or by setting additional view paths, but it is not very handy in my opinion.

  • Robby January 04, 2008 at 02:22

    I tried doing this with controllers, and it worked nicely (be interesting to see what happens with name conflicts) – but its not working with views. Is it supposed to with views?

  • Pravin Gundawar January 04, 2008 at 11:34

    Similarly how can we use multiple databases as we can organize models and controllers

  • cakebaker January 04, 2008 at 18:33

    @Robby: No, this doesn’t work with views.

    @Pravin: You can define multiple database connections in app/config/database.php and then in your model you specify with the variable $useDbConfig which connection should be used by the respective model.

  • Peter Lombardo February 05, 2008 at 23:29

    It’s a nice feature although a bit confusing. Usually there are many views to a single controller so grouping of views would seem higher priority if argued by pure number of files.

    We’re grouping controllers as mentioned above and in those controllers we have to specifically set $this->viewPath for cake to find the correct view which is also stored in a subdirectory below views.

    Maybe this is the planned process or is it just that the auto-find for views hasn’t been completed yet?

  • cakebaker February 06, 2008 at 18:23

    @Peter: I think that’s the planned process. And as you already group the views by controller I don’t see the need for a more flexible way to organize views. But as I don’t know what features are planned, it is possible that such a feature will be implemented in the future. We will see :)

Bake a comment




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

© daniel hofstetter. Licensed under a Creative Commons License