Migrating to the Modern Layout
The Piece of Cake 2 fork supports two application layouts:
- Legacy layout: the traditional CakePHP 2.x layout with an
app/directory. - Modern layout: a CakePHP 5.x-style layout with
config/,src/,templates/,tests/and so on at the project root. The pieceofcake2/app skeleton uses it.
Both layouts work with the same framework version; you can stay on the legacy layout, or move to the modern one gradually.
Legacy and modern layouts
your-project/
├── app/
│ ├── Config/ (uppercase, nested)
│ ├── Controller/
│ ├── Model/
│ ├── View/ (templates + helpers mixed)
│ ├── Test/
│ ├── Plugin/
│ ├── Vendor/
│ └── tmp/
│ └── logs/
├── vendors/
└── ...2
3
4
5
6
7
8
9
10
11
12
13
your-project/
├── bin/
│ └── cake
├── config/ (lowercase, top-level)
├── src/ (all PHP code)
│ ├── Controller/
│ ├── Model/
│ └── View/ (Helper classes only)
├── templates/ (all .ctp files, separated)
├── resources/
│ └── locales/
├── tests/ (lowercase, top-level)
├── plugins/ (Composer-managed)
├── vendor/ (standard Composer)
├── logs/ (separated from tmp/)
├── tmp/
└── webroot/2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
File migration map
| From (legacy) | To (modern) |
|---|---|
app/Config/* | config/* |
app/Controller/* | src/Controller/* |
app/Model/* | src/Model/* |
app/View/**/*.ctp | templates/**/*.ctp |
app/View/Helper/* | src/View/Helper/* |
app/Console/* | src/Console/* |
app/Console/cake | bin/cake |
app/Lib/* | src/Lib/* |
app/Locale/* | resources/locales/* |
app/Test/* | tests/* |
app/Plugin/* | plugins/* (use Composer) |
app/Vendor/* | vendor/* (use Composer) |
app/tmp/logs/* | logs/* |
app/tmp/* | tmp/* |
app/webroot/* | webroot/* |
Inside tests/, the modern layout uses tests/TestCase/ and tests/Fixture/ instead of Test/Case/ and Test/Fixture/. The test suite and fixture loader detect both.
How the framework finds the layout
The path constants are defined in the application's config/define.php and the framework's own config/define.php. When a constant is not defined by the application, the framework detects the layout:
CONFIGisROOT/config/if that directory exists, otherwiseROOT/APP_DIR/Config/.TMPisROOT/tmp/if it exists, otherwiseAPP/tmp/.LOGSisROOT/logs/whenROOT/tmp/exists, otherwiseTMP/logs/.TESTSisROOT/tests/if it exists, otherwiseAPP/Test/.- Templates are also looked up in
ROOT/templates/, and locales inROOT/resources/locales/.
The modern skeleton's config/define.php sets, among others:
define('ROOT', dirname(__DIR__));
define('APP_DIR', 'src'); // instead of 'app'
define('WEBROOT_DIR', 'webroot');
define('WWW_ROOT', ROOT . DS . WEBROOT_DIR . DS);
define('VENDORS', ROOT . DS . 'vendor' . DS);2
3
4
5
webroot/index.php, webroot/test.php and bin/cake load this file. Your existing application code (App::uses(), controllers, models, views) works without modification in either layout.
Gradual migration to CakePHP 5
Moving from CakePHP 2.x to 5.x in one step means changing code, folder structure and APIs at the same time. The modern layout lets you split this into smaller steps:
Step 1: CakePHP 2.x with traditional structure
↓ (modernize folder structure only)
Step 2: CakePHP 2.x with CakePHP 5.x-style structure ← you can stop here
↓ (upgrade code only)
Step 3: CakePHP 5.x with CakePHP 5.x-style structure2
3
4
5
- Smaller, manageable changes: folder restructuring is separate from code changes.
- Each step can be tested before moving on.
- You can stay on Step 2 indefinitely.
- Smaller changes are easier for teams to review.
Step 2: restructure on CakePHP 2.x
Update
composer.json:json{ "require": { "php": ">=8.0", "pieceofcake2/cakephp": "^2.12" }, "autoload": { "classmap": ["src/"] }, "config": { "vendor-dir": "vendor/", "sort-packages": true, "allow-plugins": { "composer/installers": true } }, "extra": { "installer-paths": { "plugins/{$name}/": ["type:cakephp-plugin"] } } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21If your plugins were installed into
app/Plugin/, theinstaller-pathssetting now points toplugins/. Remove the plugins fromapp/Plugin/and runcomposer installto install them intoplugins/.Update the bootstrap files: copy
config/define.php,webroot/index.php,webroot/test.phpandbin/cakefrom pieceofcake2/app.Move files according to the migration map. This can be done gradually, for example in this order:
- Configuration:
app/Config/*→config/* - PHP code:
app/Controller/*,app/Model/*→src/ - Templates:
app/View/**/*.ctp→templates/ - Tests:
app/Test/*→tests/ - Dependencies: use Composer for plugins and vendors
- Configuration:
Verify that the application still works.
Optionally rely on Composer autoloading: with
"classmap": ["src/"]and aftercomposer dump-autoload, you can removeApp::uses()calls from your controllers, models, helpers and shells.php// Before App::uses('AppController', 'Controller'); class UsersController extends AppController { // ... } // After (with Composer autoload) class UsersController extends AppController { // ... }1
2
3
4
5
6
7
8
9
10
11
12
13
WARNING
Run composer dump-autoload every time you create a new class file. The classmap must be regenerated before new classes can be found. Plugins that don't support Composer autoloading still need App::uses() or CakePlugin::load().
Step 3: upgrade to CakePHP 5
With the folder structure already in place, the upgrade to CakePHP 5.x is limited to code changes: require CakePHP 5.x in composer.json, update code for the API changes, and fix compatibility issues. See the CakePHP 5.x Migration Guide.
