Subdirectories for Models, Entities, Controllers, Views

After a long sojourn with Yii2, I’m looking into coming back to CakePHP. The web site that I’m attempting to build in Cake will have a very large number of models/entities/controllers/views. In Yii2, it was possible to set subdirectories for collections of each type to avoid having to scroll through enormous numbers of files. Note that this had nothing whatsoever to do with routing prefixes. I am not at all interested in creating routing prefixes. What I am interested in is creating a workable organizational structure.

My tables tend to fall into easily identifiable groupings that I was able to use in Yii2 to create organizational subdirectories. For instance, in my entities (not related to the formal Entities as used in Cake) subdirectories, I had files relating to the following tables: entities, entities_entity_categories, entities_entity_roles, entities_entity_sources, entity_categories, entity_roles, entity_sources, entity_types. (The joys of fully normalized databases!) My HealthCare grouping has an even larger number of tables, as do my HomeAutomation, HerbalMedicine, and on and on and on. Putting all the related files for controllers in one ginormous Controllers directory, for instance, would very quickly become completely unworkable. Just finding a relevant file in such a directory becomes a mind-boggling struggle.

How can I create a workable organizational structure in Cake? Subdirectories seem like the best, most direct approach, but if there’s another way, I’d love the advice.

1 Like

My opinion is don’t over normalise, it’s just messy and we have enough hard drive space - as in a lot of one-to-one relations, I just make/keep as one table.

I don’t think sub directories would work… Maybe look into separating the app into separate plugins / vendor libraries.

Trying to put all of this into a single table would be a nightmare of incredibly monumental proportions. I can’t even imagine where I would begin to do that, but I know that my grandchildren would be long dead of old age before such a thing could be accomplished. You are recommending that we totally discard all the best and professional practices that we’ve developed over the past decades?! As to separating the app into plugins/vendor libraries, that sounds like a very excellent way — to run madly back to the sanity of Yii2 where such things are easy to do. I can’t even imagine how that would look with all the many-to-many relations involved. It sounds like to me that CakePHP has become a toy best suited for the the very trivial things that a second-grader might undertake, not for a professional system. I’m sincerely hoping that there is some more reasonable solution within Cake. Otherwise, I’m just wasting my time on it.

I think you have misunderstood my point. Of course I didn’t say to put everything into one table. Some tables yes, can be put together, others not. Don’t be extreme in or blindly follow methodology, it is about balance and the situation.

It seems like you’re here just to bash CakePHP. Whatever framework you use, you have to architect your software well. If it is monolithic you can run into maintainability problems. So people may break it up into microservices with a REST API or plugins. For example we have broken up our app into a main business logic app with the users and customers into separate REST API services.

simplifying Cake uses 1 controller - 1 table - 1 entity for each ‘resource’ so basically when you have 50 tables you would end up with around 50 controllers (some tables can be join tables which you don’t need controller for).

while i’m 90% sure you could split entities/tables/controllers into sub directories ie. table has setEntity, each relationship can be used as alias to table class using className and controllers can be pointed at routes BUT i would advise against it, it will be hard to setup with low (IMHO) repay.

for larger projects i would advise you to use good IDE instead of rearranging file structure.

Having done Web development for close to 25 years and currently being a PhpStorm user, but having used NetBeans, Eclipse, Dreamweaver and just about every other IDE in the past, I’m totally at a loss to imagine what you mean by “for larger projects i would advise you to use good IDE.” Regardless of the crutches (necessary though they may be), I have always found that good, logical organizational structure, tailored to the project at hand, is a vital necessity to anything more than trivial development. I am astounded to come back to CakePHP and find that it imposes such a horrible, inexplicable straitjacket on developers. I can only hope that the Cake developers will literally drop everything and commit themselves to bringing Cake up to speed with Yii2, Laravel, Symfony and countless other frameworks.

Contrary to what another person has said, I didn’t come here to bash Cake. I don’t have that time to waste. I committed myself to learning Cake because I thought it had something to offer. I fully realize that how you achieve results may prove elusive and hard to track down. I was totally convinced that Cake must have some way to be flexible about something as simple the location of files, something that is built into every other major player in the PHP frameworks field for the express purpose of organization. I am truly sorry that I have wasted so much time trying to learn something that is stuck back in the 90s in terms of development.

Larry E. Lutz

can you give some example how do you structure your projects? cake devs are very open about good ideas so if you think it would enhance Cake for bigger projects just give them a call on github.

maybe there is some simple way that i just need to think of (as i said im 90% sure its possible) just not sure what you expect

the largest project ive worked up to now was around 50 tables and using PHPStorm omnisearch i never had any problem with cake default structure, i just create file and forget where is it

Create-and-forget works fine — until you have to come back to it a year from when you last touched it and try to update it. With Yii2, Laravel, and Symfony, I’ve taken two basic approaches. The actual names may vary depending on the framework, but the structure remains. They are:

Object-centered approach

Within the Models, Controllers, and Views directories, there are subdirectories for specific groupings of tables. (Yes, it remains that there is one model and controller per table, but those models and controllers, with their views, are organized into a hierarchy.) Right now, my structure — very abbreviated for the purposes of illustration, with pivot/join tables left out for brevity — would look something like:

Entities Subdirectory

Entities

EntityCategories (lookup table)

EntityRoles (lookup table)

EntitySources

EntityTypes (lookup table)

EntityLocations

EntityPhones

HealthCare Subdirectory

HealthCareProviders (belongs to Entities)

HealthCareProviderTypes (lookup table)

HealthCareAllergies

HealthCareAppointments

HealthCareDiagnoses

HealthCareImmunizations

HealthCareImmunizationTypes (Lookup table)

HealthCareMedications

HealthCareTests

HealthCareTestPanels (Lookup table)

HealthCareTestPanelTests

HealthCareTestResults

HealthCareTestResultRatings (lookup table)

HealthCareTreatmentCenters (belongs to Entities)

I could go on for about 15 more subdirectories, but this should give you the idea. These same subdirectories repeat under the directories for Models, for Controllers, and for Views. Sure, you could dump all this in one directory and use search within PhpStorm — as long as you can remember the name to search for. If you carefully name each class, as I have done in my example above, it’s fairly simple, but if you have to pick up behind someone else, you’re lost.

Module Approach

With this approach, a “module” is created for each of the subdirectory topics like I listed above. So for instance, there would be an Entities module that has directories within for its models, controllers, and views. The module, in effect, becomes an “applet” — but, it is very much a participating member of the entire webapp. So, for instance, there is no problem with the HealthCareProviders model reaching across to form a belongs-to relationship with Entities within the Entities module. It may be that this approach can be achieved by Cake’s concept of plugins, but the absolute paucity of documentation gives little to no guidance or support for going to that direction. I’m also not sure if the inter-plugin relationships in Cake would work all that well.

In my experience, the development process begins with the object-centered approach and ends up modular. The issue is that the major, mature frameworks allow both.

I guess one of the things that really perturbs me is the immaturity of Cake’s documentation and flexibility for the many approaches that developers take. When I compare at Yii2 and Laravel, I can really see that Yii is an older much more mature framework. Laravel is much newer, and its relative immaturity really shows. (Having to specify the route for every controller action? Yikes! Thank God they finally created resource routing that diminishes that somewhat, but compare that to Yii where you never have to specify routes. The framework figures it all out.) CakePHP is as old if not older than Yii, yet lacks the maturity, flexibility, and documentation that Yii has.

Speaking of documentation, you want to bake a model in Cake? It’s no where as easy as Gii in Yii where you can just do it all in a GUI, but you do have Bake. Take a look at the instructions for baking a model. If you follow the instructions, you just enter cake bake with the appropriate allowance for directories. Just cake bake , nothing else. I figured out that you must have to enter something like the table name, the model name, but what? It’s nowhere in the documentation, at least that I could find. Procedures for developing a plugin? Forget it. It’s time for CakePHP to grow up and have the maturity that it should.

Larry E. Lutz

Object-centered approach

this one is the one i said its possible but a lot of configuration ie.

for controllers and views - prefix: in routes.php
$routes->connect('/', ['controller' => 'Pages', 'action' => 'display', 'home', 'prefix' => 'Pages']);
for entities and tables: in AppController.php

initialize() {
TableRegistry::config('One', [
            'className' => 'App\Model\Table\Pages\OneTable'
        ]);
        TableRegistry::config('Two', [
            'className' => 'App\Model\Table\Two\TwoTable'
        ]);
}

in Pages/OneTable.php

initialize() {
    ...
   $this->setEntityClass('App\Model\Entity\Pages\One');
}

in Two/TwoTable.php

initialize() {
       ...
       $this->setEntityClass('App\Model\Entity\Two\Two');

        $this->belongsTo('One', [
            'className' => 'App\Model\Table\Pages\OneTable'
        ]);
}

Module Approach

there isnt much of documentation because its not much to tell you just bin/cake bake plugin one then everything else you do by adding its prefix to command ie. bin/cake bake model one.patients or bin/cake bake controller one.insurance and you can treat it as separate app - same structure etc. to use other plugins you just add pluginName. ie $this->loadModel('HealthCare.patients');

CakePHP is as old if not older than Yii, yet lacks the maturity, flexibility, and documentation that Yii has.

while i did some have problems with cake documentation in past, at this moment there is very little i cant find in it and even at those times there is always api documentation which complements book.

It’s no where as easy as Gii

i dont know how easy its in Gii but i always have open terminal for composer/tests/etc and switching to GUI to add table doesnt sound easier than bin/cake bake model tableName

I figured out that you must have to enter something like the table name, the model name, but what? It’s nowhere in the documentation,

have you tried bin/cake bake model --help ? https://book.cakephp.org/3.0/en/bake/usage.html

1 Like

I realise it’s been 3 years and the OP is very likely to have moved on, but I just found this using search, and someone else may as well.

Using OP’s hierarchy as an example and omitting a lot of irrelevant code, here’s how I’d organise models into subdirectories:

<?php

namespace App\Model\Table\HealthCare;

class ProvidersTable extends Table
{

    public function initialize(array $config): void
    {
        parent::initialize($config);

        $this->setTable('healthcareproviders');
        $this->setAlias('HealthCareProviders');

        $this->hasMany('HealthCareAppointments', [
            'className' => 'App\Model\Table\HealthCare\AppointmentsTable',
            'foreignKey' => 'appointment_id',
            'joinType' => 'INNER',
        ]);

So essentially, moving table classes into corresponding subdirectories and then linking them with each other by providing className value for each association - because the framework won’t find these classes otherwise.

This is the approach I’m using right now with CakePHP 4. Please let me know if you have any feedback or if you think there’s a better way.

1 Like

Hi @alex

Following up as well much later after your post: I like your approach and am using v4.4.3 but struggling since the controller won’t find the table in a subfolder. How does your ProvidersController know to look in folder App\Model\Table\HealthCare instead of App\Model\Table?

Thanks for your hint!