StructArmed preset for CakePHP 5 application conventions.
Reuses the ideas of StructArmed's built-in MVC preset (layer isolation, thin
entry points, naming, safety rules) but maps them to CakePHP's real layout.
| Layer | CakePHP namespace | Naming |
|---|---|---|
Controller |
<App>\Controller\FooController |
suffix Controller |
Component |
<App>\Controller\Component\FooComponent |
suffix Component |
Table |
<App>\Model\Table\FooTable |
suffix Table |
Entity |
<App>\Model\Entity\Foo |
— |
Behavior |
<App>\Model\Behavior\FooBehavior |
suffix Behavior |
View |
<App>\View\AppView |
— |
Cell |
<App>\View\Cell\FooCell |
suffix Cell |
Helper |
<App>\View\Helper\FooHelper |
suffix Helper |
Command |
<App>\Command\FooCommand |
suffix Command |
Mailer |
<App>\Mailer\FooMailer |
suffix Mailer |
Middleware |
<App>\Middleware\FooMiddleware |
suffix Middleware |
Form |
<App>\Form\FooForm |
suffix Form |
Type |
<App>\Database\Type\FooType |
suffix Type |
Route |
<App>\Routing\Route\FooRoute |
suffix Route |
Widget |
<App>\View\Widget\FooWidget |
suffix Widget |
CacheEngine |
<App>\Cache\Engine\FooEngine |
suffix Engine |
LogEngine |
<App>\Log\Engine\FooLog |
suffix Log |
MailerTransport |
<App>\Mailer\Transport\FooTransport |
suffix Transport |
Event |
<App>\Event\FooListener |
— |
Policy |
<App>\Policy\FooPolicy |
suffix Policy |
Authenticator |
<App>\Authenticator\FooAuthenticator |
suffix Authenticator |
Identifier |
<App>\Identifier\FooIdentifier |
suffix Identifier |
PasswordHasher |
<App>\PasswordHasher\FooPasswordHasher |
suffix PasswordHasher |
UrlChecker |
<App>\UrlChecker\FooUrlChecker |
suffix UrlChecker |
<App> is the root namespace of your application (or plugin), passed to the
constructor (default App).
Templates are not classes — the preset calls skipPathsForRuleset(['templates/'])
so templates/* is still scanned for PSR checks but excluded from layer rules.
Nested layers are never forced into their parent's suffix: a class that resolves
to Component is exempt from the Controller suffix rule even when a broader
host-defined App\Controller\* pattern also matches it (same for Behavior/
Entity vs Table).
Plugins are separate namespaces (Billing\, Inventory\, …). Pass them to the preset
and the same canonical layers, naming, quality and safety rules apply inside the
plugin code:
return Architecture::define()
->withPreset(new CakeAppPreset(
pluginNamespaces: ['Billing', 'Inventory'],
// pluginAppAccess: ['Billing' => ['App\Util']], // grant app kernel access
));Each plugin gets an owner layer (PluginBilling ↔ /^Billing\\.*$/) registered before
the canonical layers, so per-plugin rules can be keyed on it in ruleset(). By
default a plugin may not import the app namespace at all; grant specific app
namespaces per plugin via pluginAppAccess.
composer require --dev crustum/structarmed-cakephp// structarmed.php
use Boundwize\StructArmed\Architecture;
use Crustum\StructArmed\Cake\CakeAppPreset;
return Architecture::define()
->layer('Source', []) // PSR-4 scan paths (needed for the PHPUnit extension)
->withPreset(new CakeAppPreset())
->ruleset([ // your own domain layers, if any
// ...
]);Tune it like the built-in presets:
new CakeAppPreset(
namespace: 'App', // root namespace (no trailing backslash)
controllerMaxComplexity: 3, // default: 5
controllerMaxMethodLength: 15, // default: 20
controllerMaxDependencies: 4, // default: 5
viewMaxComplexity: 2, // default: 3 — View classes should just load helpers
)Skip a rule or a path:
use Crustum\StructArmed\Cake\CakeAppPreset;
return Architecture::define()
->withPreset(new CakeAppPreset())
->skip(CakeAppPreset::CONTROLLER_MAX_DEPENDENCIES); // whole rule
// or: ->skip([CakeAppPreset::ENTITY_MUST... => ['src/Legacy/']]);Rule keys live on the Crustum\StructArmed\Cake\CakeRule enum and are prefixed
with cakephp.. Pass CakeRule::X->value to skip() / replaceRule():
use Crustum\StructArmed\Cake\CakeRule;
return Architecture::define()
->withPreset(new CakeAppPreset())
->skip(CakeRule::CONTROLLER_MAX_DEPENDENCIES->value);- Layer isolation:
cakephp.layer.<from>_not_depend_<to>(TABLE_NOT_DEPEND_CONTROLLER,VIEW_NOT_DEPEND_TABLE,MAILER_NOT_DEPEND_CONTROLLER,TYPE_NOT_DEPEND_TABLE, …) - Naming:
cakephp.<layer>.name_must_end_with_<suffix> - Quality:
<layer>.max_complexity/max_method_length/max_dependencies,<layer>.no_superglobals,<layer>.must_have_return_types - Safety:
cakephp.safety.<layer>_no_<fn|construct>(dd, dump, var_dump, print_r, var_export, die, exit) — derived per layer, not enumerated on the enum
MustBeFinalRule— CakePHP controllers/tables are meant to be extended, not final.MustBeInterfaceRule— no repository interfaces in Cake; Table is the interface.- Doctrine/PDO bans — Cake uses its own ORM;
DateTimeis fine in Model layer.
- PHP 8.2+
Licensed under the MIT License. Redistributions of the source code included in this repository must retain the copyright notice found in each file.