Prefixed actions - markstory/cakephp GitHub Wiki

Prefixed actions have historically been implemented as prefixes to method names. I feel this has a few drawbacks:

  • Action names must be munged and combined with prefixes to create callable methods names.
  • Prefixed actions have special code to protect them from direct URL access.
  • Prefixes have special code to handle them when generating urls.
  • Prefixes require 2 parameters in calls to Router::connect().
  • Prefixed actions are in the same class as the non-prefixed actions. This creates enormous classes that are generally handling multiple aspects of an application. Having both the admin and non-admin actions in the same class increases the risk of accidentally making mistakes related to privilege escalation. By using components, traits, and inheritance code reuse (the main benefit of having prefixes in the same class) could be achieved.

Proposed solution

Prefixes directly map to separate namespaces inside a plugin/app. A routing key would be used to indicate the prefix. Possible options are _prefix, _ns, _namespace, prefix, namespace.

<?php
// Route connection (using `prefix`)
Router::connect('/admin/:controller/:action/*', array('prefix' => 'admin'));

// generate a url
Router::url(['controller' => 'posts', 'action' => 'index', 'prefix' => 'admin']);

// The above resolves to.
App\Controller\Admin\PostsController::index()

Prefixes are Inflector::camelize() d before being combined into a namespace. This allows for multi-word prefixes. Prefixes in plugins would work in a similar way:

<?php
// Route connection (using `prefix`)
Router::connect(
  '/admin/contacts/:controller/:action/*',
  ['prefix' => 'admin', 'plugin' => 'contacts']
);

// generate a url
Router::url([
  'plugin' => 'contacts',
  'controller' => 'users',
  'action' => 'index',
  'prefix' => 'admin'
]);

// The above resolves to.
Contacts\Controller\Admin\UsersController::index()

The prefix key could be set to false to force a route to generate as a non-prefixed method. The Routing.prefixes Configure var would still be available to declaratively configure which prefixes are going to be connected by the default routes.

View files

All view files would be located in paths similar to the controllers. So if your controller was App\Controller\Admin\ContactsController the view files would be in App/View/Admin/Contacts/ by convention. Of course you can change this using Controller::$viewPath. Prefix controllers with alternate formats would follow the convention of App/View/Admin/Contacts/{xml,json}/.

Support for legacy prefixes

...