How to organize my system

I’m trying to figure out the best way of organizing the code of a system I’m working on, and I can’t really figure out how to best do it. The scenario is as following:

The system is very big. It uses a lot of functions defined in the database. I want to keep controllers thin, but at the same time I want to keep models manageable.
Since there’s one model per table and the system is so big, some models have lots of functions.
I want to be able to have a good overview of the logic in the models just like in the controllers, and functions lean to potentially reusing them and also keep the structure of the functions somewhat similar. Behaviors are for reusing logic in the model.

So far, I’ve put the db function calls in components, since they are not based on tables and are not using ORM, even though components are supposed to be for sharing code between controllers.
I’m also using many controllers, and have private functions in them to be able to have both thin controllers and thin models, and have buisness logic overview. But it seems like controller functions shouldn’t call other controller functions.

I think Visual Studio C# has Handlers for what I’m looking for…

What would be the best approach for this in CakePHP?

1 Like

Controllers should not be calling functions in other controllers, that’s right. If you need to share functions between a few controllers, that’s a good thing to put in a component. If you need to share a function with all (or even most) controllers, it would generally go in your AppController.

It’s not clear what kinds of “db function calls” you’ve put in components, so no good suggestion on that front at this time.

Not familiar with C# Handlers. Are they anything like Cake’s Events System?

Ok, but this is controllers calling private functions in themselves.

The db functions are functions defined in the db layer, and called similar to this:
$q = “SELECT * FROM web.get_data_for_stuff($id)”;
return ConnectionManager::get(‘default’)->execute($q)->fetchAll(‘assoc’);

Handlers in C# seems to be a way of off-loading logic from the controllers/models almost like an extra layer, and not similar to Cake’s Events System.

Controllers can certainly call private functions in themselves. Just not cross-controller calls.

Seems that you could put your DB functions into custom finders?

Alright, private functions are ok then.
Custom finders are still table based, but these are… schema based I guess.

Not clear on what the distinction is between “table based” and “schema based”. Do you mean it returns data from multiple tables combined? Because “table” finders can use contain to do that too. Without further details, I feel like I’d decide on a table that’s “driving” the results more than the rest, and put the finder there.

A db function could use multiple separated queries from different table(s), and also use programmatic logic between them etc.

Still not seeing why it can’t be put in a custom finder for one of the tables involved.

Sure you could, but then you’ll have to know what’s in them to find them easily. But the big issue for me is how to offload logic from both controllers and models without using something like handles. I guess more controllers with private functions is the way to go in CakePHP…

Every situation is unique, so the right answer is generally going to be whatever works well for you. Do keep in mind that CakePHP is just PHP. My projects typically have some additional folders under src, like Libraries or Modules or the like. Nothing stopping you from having a Handlers folder there. Just make sure the namespace is correct, and you can use that sort of structure to pull out common functionality that doesn’t really fit anywhere else.

Ok, I’ll try that!

How would a handler look like you think? I’m having trouble with loading the model in it. So far I’ve tried this:

New file/folder - src\Handler\NewControllerHandler.php
Code at the top of the controller using it: use App\Handler;

Declare the new Handler file with class like this:

namespace App\Handler;

use Cake\ORM\Table;

class NewControllerHandler {
    public static function doStuff(int i): bool {
        //load model here to use its methods     
        $i++;
        $this->myModel->updateValue($i);

        return true;
    }
}

I tried $this->MyModel = TableRegistry::get(‘MyModel’);, but get() is deprecated. Not sure how to do this…

Check the documentation for the get function, it tells you what to replace that call with. Functions don’t generally go away when they’re deprecated, they just move to a different spot.

I find Traits to be a great way of sharing code between classes that would be boilerplate in most cases otherwise.

See https://www.php.net/manual/en/language.oop5.traits.php for more details…