Cakephp 4.2 | How to override the MVC with the MVC from other plugin?

I have a complex web app, where special plugins are created for user groups. Eg Admin, Editor all have their groups. Each of these groups has its own tasks and customized forms in processing one saved entry, often with a different layout / elements.

It has worked great so far. But now we have one new request from the client, their special customer needs a completely different or customized flow, which is not compatible with the existing MVC structure. This means that in one user group we have to add some functionality from other groups, also change templates, validation, relations.

In this case we do the overriding template via an additional plugin, but how about the override controller and the model?

For example: When we call example.com/editor/articles/add the plugin Editor has its own MVC, for a special customer, the Editor should use the MVC from the SpecialEditor plugin.

How to override the existing MVC?

You can override controller via routes:

// routes.php or Application::routes()
$routes->plugin('Editor', function (RouteBuilder $routes) {
    // Routes connected here are prefixed with '/debug-kit' and
    // have the plugin route element set to 'DebugKit'.
    $routes->connect('/articles/add', ['plugin' => 'SpecialEditor', 'controller' => 'Articles', 'action' => 'add']);
});

Inside the ArticlesController of the SpecialEditor plugin you can load a new model (eg extend original model) and also have the template inside that plugin too.

Also, if you only have to override the controller and not the model, set the modelClass

namespace SpecialEditor\Controller;

class ArticlesController
{
   public $modelClass = "Editor.Articles";
}
1 Like

I’m sorry, but it doesn’t work.

You cannot define routes that conflict with the scope. Scope had plugin = Editor, while route had plugin = SpecialEditor

The question still applies, how to override the controller with another. Is there a similar method as when override a template?

It would be ideal if we could switch plugins for the user but keep the same url.

I have tried this

in the plugin’s src/Plugin.php

public function routes(RouteBuilder $routes): void
{
    parent::routes($routes);
    $params = ['controller' => 'ExportTypes', 'plugin' => 'MyPlugin'];
    $routes->scope('/export-types', $params, function (RouteBuilder $builder) {
        $builder->connect('/', ['action' => 'index']);
    });
   // ....
}

in the app config/routes.php

$routes->prefix('api', function (RouteBuilder $builder) {
    $builder->scope('/export-types', ['plugin' => false, 'controller' => 'ExportTypes'], function (RouteBuilder $builder) {
        $builder->connect('/', ['action' => 'index']);
    });
    $builder->fallbacks();
});

bin/cake routes output:

+--------------------------------+--------------------+----------------------------------------------------------------------------------+
| Route name                     | URI template       | Defaults                                                                         |
+--------------------------------+--------------------+----------------------------------------------------------------------------------+
| api:0.exporttypes:index        | /api/export-types  | {"action":"index","controller":"ExportTypes","plugin":false,"prefix":"Api"}      |
| api:myplugin.exporttypes:index | /api/export-types  | {"action":"index","controller":"ExportTypes","plugin":"MyPlugin","prefix":"Api"} |
+--------------------------------+--------------------+----------------------------------------------------------------------------------+

I used the api prefix since I only use as a rest backend, but should work without it

1 Like