diff --git a/docs/en/intro.md b/docs/en/intro.md index e5f70c3a94..910cd8306b 100644 --- a/docs/en/intro.md +++ b/docs/en/intro.md @@ -160,5 +160,4 @@ The next obvious steps are to [download CakePHP](installation), read the ## Additional Reading - [Where to Get Help](intro/where-to-get-help) -- [CakePHP Conventions](intro/conventions) -- [CakePHP Folder Structure](intro/cakephp-folder-structure) +- [Structure & Conventions](intro/conventions) diff --git a/docs/en/intro/cakephp-folder-structure.md b/docs/en/intro/cakephp-folder-structure.md deleted file mode 100644 index a7ad0d7221..0000000000 --- a/docs/en/intro/cakephp-folder-structure.md +++ /dev/null @@ -1,74 +0,0 @@ -# CakePHP Folder Structure - -After you've downloaded the CakePHP application skeleton, there are a few top -level folders you should see: - -- `bin/` holds the Cake console executables so you can execute e.g. `bin/cake bake all`. - -- `config/` holds the [Configuration](../development/configuration) files. - Database connection details, bootstrapping, core configuration files - and more should be stored here. - -- `plugins/` is where the [Plugins](../plugins) your application uses are stored. - -- `logs/` contains your log files, can be adjusted via [Log Configuration](../core-libraries/logging.md#logging-configuration). - -- `src/` will be where your application's source files like Controllers, Models, Commands etc. will be placed. - -- `templates/` has presentational files placed here: - elements, error pages, layouts, and view template files. - -- `resources/` is primarily used for the `locales/` subfolder storing language files for static internationalization. - -- `tests/` will be where you put the test cases for your application. - -- `tmp/` is where CakePHP stores temporary data. The actual data it - stores depends on how you have CakePHP configured, but this folder - is usually used to store translation messages, model descriptions and sometimes - session information. - -- `vendor/` is where CakePHP and other application dependencies will - be installed by [Composer](https://getcomposer.org). **Editing these files is not - advised, as Composer will overwrite your changes next time you update.** - -- `webroot/` is the public document root of your application. It - contains all the files you want to be publicly reachable. - -Make sure that the `tmp/` and `logs/` folders exist and are writable, -otherwise the performance of your application will be severely -impacted. In debug mode, CakePHP will warn you if these directories are not -writable. - -## The src Folder - -CakePHP's `src/` folder is where you will do most of your application -development. Let's look a little closer at the folders inside. - -### Command - -Contains your application's console commands. See -[Command Objects](../console-commands/commands) to learn more. - -> [!NOTE] -> The folder `Command/` is not present by default. -> It will be auto generated when you create your first command using bake. - -### Console - -Contains the installation script executed by Composer. - -### Controller - -Contains your application's [Controllers](../controllers) and their components. - -### Middleware - -Stores any [Middleware](../controllers/middleware) for your application. - -### Model - -Contains your application's [Tables](../orm/table-objects.md), [Entities](../orm/entities.md) and [Behaviors](../orm/behaviors.md). - -### View - -Presentational classes are placed here: [Views](../views.md), [Cells](../views/cells.md), [Helpers](../views/helpers.md). diff --git a/docs/en/intro/conventions.md b/docs/en/intro/conventions.md index f845b969c0..408f097b75 100644 --- a/docs/en/intro/conventions.md +++ b/docs/en/intro/conventions.md @@ -1,296 +1,374 @@ -# CakePHP Conventions +# Structure & Conventions -We are big fans of convention over configuration. While it takes a bit of time -to learn CakePHP's conventions, you save time in the long run. By following -conventions, you get free functionality, and you liberate yourself from the -maintenance nightmare of tracking config files. Conventions also make for a very -uniform development experience, allowing other developers to jump in and help. +CakePHP embraces **convention over configuration**. By following conventions, you get free functionality without tracking config files, and create a uniform codebase that other developers can quickly understand. This guide covers both where files go and how to name them. -## Controller Conventions +> [!TIP] +> Following these conventions means CakePHP automatically wires up your application - controllers find their models, views find their templates, and URLs map to actions without any configuration. -Controller class names are plural, CamelCased, and end in `Controller`. -`UsersController` and `MenuLinksController` are both examples of -conventional controller names. +## Application Folder Structure -Public methods on Controllers are often exposed as 'actions' accessible through -a web browser. They are camelBacked. For example the `/users/view-me` maps to the `viewMe()` method -of the `UsersController` out of the box (if one uses default dashed inflection in routing). -Protected or private methods cannot be accessed with routing. +After downloading the CakePHP application skeleton, you'll see these top-level folders: -For inflection of acronyms it is useful to treat them as words, so `CMS` would be `Cms`. +**Essential Folders:** -### URL Considerations for Controller Names +- `src/` - Your application's source code (Controllers, Models, Commands, etc.) +- `templates/` - View template files, elements, layouts, and error pages +- `config/` - [Configuration](../development/configuration) files for database, routes, and application settings +- `webroot/` - Public document root containing publicly accessible files -As you've just seen, single word controllers map to a simple lower case URL -path. For example, `UsersController` (which would be defined in the file name -**UsersController.php**) is accessed from `https://example.com/users`. +::: details Other Application Folders -While you can route multiple word controllers in any way you like, the -convention is that your URLs are lowercase and dashed using the `DashedRoute` -class, therefore `/menu-links/view-all` is the correct form to access -the `MenuLinksController::viewAll()` action. +**Development & Testing:** -When you create links using `this->Html->link()`, you can use the following -conventions for the url array: +- `tests/` - Your application's test cases +- `bin/` - Cake console executables (`bin/cake bake all`, etc.) -``` php -$this->Html->link('link-title', [ - 'prefix' => 'MyPrefix' // CamelCased - 'plugin' => 'MyPlugin', // CamelCased - 'controller' => 'ControllerName', // CamelCased - 'action' => 'actionName', // camelBacked -] +**Runtime & Dependencies:** + +- `tmp/` - Temporary data (cache, sessions, logs). Must be writable! +- `logs/` - Application log files. Must be writable! +- `vendor/` - Dependencies installed by [Composer](https://getcomposer.org). **Don't edit - Composer will overwrite changes!** + +**Extensions & Localization:** + +- `plugins/` - [Plugins](../plugins) used by your application +- `resources/` - Contains `locales/` subfolder for internationalization files + +::: + +> [!WARNING] +> Make sure `tmp/` and `logs/` folders are writable! Poor performance or errors will occur otherwise. CakePHP warns you in debug mode if they're not writable. + +## The src/ Directory + +The `src/` folder is where you'll do most development. Here's what goes in each subfolder: + +| Folder | Contains | Naming Convention | +|--------|----------|-------------------| +| **Command** | Console commands | `*Command.php` - See [Command Objects](../console-commands/commands) | +| **Console** | Installation scripts | Executed by Composer | +| **Controller** | HTTP request handlers | [Controllers](../controllers), [Components](../controllers/components) | +| **Middleware** | Request/response filters | `*Middleware.php` - See [Middleware](../controllers/middleware) | +| **Model** | Data layer | [Tables](../orm/table-objects), [Entities](../orm/entities), [Behaviors](../orm/behaviors) | +| **View** | Presentation logic | [Views](../views), [Cells](../views/cells), [Helpers](../views/helpers) | + +> [!NOTE] +> The `Command/` folder isn't present by default - it's auto-generated when you create your first command using bake. + +## Naming Conventions + +### Controllers + +::: code-group + +```php [✅ Correct] +// File: src/Controller/UsersController.php +namespace App\Controller; + +class UsersController extends AppController +{ + // URL: /users/view-me + public function viewMe() + { + // camelBacked method names + } +} ``` -For more information on CakePHP URLs and parameter handling, see -[Routes Configuration](../development/routing#routes-configuration). +```php [❌ Incorrect] +// Wrong: singular, lowercase, no suffix +class user extends AppController +{ + // Wrong: underscores instead of camelCase + public function view_me() + { + } +} +``` - +::: -## File and Class Name Conventions +**Rules:** -In general, filenames match the class names, and follow the PSR-4 standard for -autoloading. The following are some examples of class names and their filenames: - -- The Controller class `LatestArticlesController` would be found in a file - named **LatestArticlesController.php** -- The Component class `MyHandyComponent` would be found in a file named - **MyHandyComponent.php** -- The Table class `OptionValuesTable` would be found in a file named - **OptionValuesTable.php**. -- The Entity class `OptionValue` would be found in a file named - **OptionValue.php**. -- The Behavior class `EspeciallyFunkableBehavior` would be found in a file - named **EspeciallyFunkableBehavior.php** -- The View class `SuperSimpleView` would be found in a file named - **SuperSimpleView.php** -- The Helper class `BestEverHelper` would be found in a file named - **BestEverHelper.php** - -Each file would be located in the appropriate folder/namespace in your app -folder. +- **Class names:** Plural, CamelCased, end in `Controller` + - `UsersController`, `MenuLinksController` +- **File names:** Match class name exactly - `UsersController.php` +- **Location:** `src/Controller/UsersController.php` +- **Actions:** camelBacked public methods - `viewMe()`, `editProfile()` +- **URLs:** Lowercase with dashes - `/users/view-me` maps to `viewMe()` - +> [!WARNING] +> Only **public** methods are accessible through routing. Protected and private methods cannot be accessed via URLs, providing automatic security for internal helper methods. -## Database Conventions +> [!TIP] +> **Acronyms:** Treat them as words. `CMS` becomes `CmsController`, not `CMSController` -Table names corresponding to CakePHP models are plural and underscored. For -example `users`, `menu_links`, and `user_favorite_pages` -respectively. Table name whose name contains multiple words should only -pluralize the last word, for example, `menu_links`. +> [!NOTE] +> CakePHP uses the `DashedRoute` class by convention to automatically convert camelCase action names to dashed URLs. See [Routes Configuration](../development/routing#routes-configuration) for details. -Column names with two or more words are underscored, for example, `first_name`. +**URL Arrays:** -Foreign keys in hasMany, belongsTo/hasOne relationships are recognized by -default as the (singular) name of the related table followed by `_id`. So if -Users hasMany Articles, the `articles` table will refer to the `users` -table via a `user_id` foreign key. For a table like `menu_links` -whose name contains multiple words, the foreign key would be -`menu_link_id`. +```php +$this->Html->link('title', [ + 'prefix' => 'MyPrefix', // CamelCased + 'plugin' => 'MyPlugin', // CamelCased + 'controller' => 'Users', // CamelCased + 'action' => 'viewProfile' // camelBacked +]); +``` + +### Models (Tables & Entities) + +::: code-group + +```php [✅ Table Class] +// File: src/Model/Table/UsersTable.php +namespace App\Model\Table; + +class UsersTable extends Table +{ + // Plural, CamelCased, ends in "Table" +} +``` -Join (or "junction") tables are used in BelongsToMany relationships between -models. These should be named for the tables they connect. The names should be -pluralized and sorted alphabetically: `articles_tags`, not `tags_articles` -or `article_tags`. *The bake command will not work if this convention is not -followed.* If the junction table holds any data other than the linking foreign -keys, you should create a concrete entity/table class for the table. +```php [✅ Entity Class] +// File: src/Model/Entity/User.php +namespace App\Model\Entity; -In addition to using an auto-incrementing integer as primary keys, you can also -use UUID columns. CakePHP will create UUID values automatically using -(`Cake\Utility\Text::uuid()`) whenever you save new records using -the `Table::save()` method. +class User extends Entity +{ + // Singular, CamelCased, no suffix +} +``` -## Model Conventions +::: -Table class names are plural, CamelCased and end in `Table`. `UsersTable`, -`MenuLinksTable`, and `UserFavoritePagesTable` are all examples of -table class names matching the `users`, `menu_links` and -`user_favorite_pages` tables respectively. +**Rules:** -Entity class names are singular CamelCased and have no suffix. `User`, -`MenuLink`, and `UserFavoritePage` are all examples of entity names -matching the `users`, `menu_links` and `user_favorite_pages` -tables respectively. +- **Table class:** Plural, CamelCased, ends in `Table` + - `UsersTable`, `MenuLinksTable`, `UserFavoritePagesTable` +- **Entity class:** Singular, CamelCased, no suffix + - `User`, `MenuLink`, `UserFavoritePage` +- **Enum class:** `{Entity}{Column}` - e.g., `UserStatus`, `OrderState` +- **Behavior class:** Ends in `Behavior` - `TimestampBehavior` -Enum class names should use a `{Entity}{Column}` convention, and enum cases -should use CamelCased names. +### Views & Templates -## View Conventions +::: code-group -View template files are named after the controller functions they display, in an -underscored form. The `viewAll()` function of the `ArticlesController` class -will look for a view template in **templates/Articles/view_all.php**. +```php [✅ Template Files] +// Controller method: ArticlesController::viewAll() +templates/Articles/view_all.php -The basic pattern is -**templates/Controller/underscored_function_name.php**. +// Controller method: MenuLinksController::editItem() +templates/MenuLinks/edit_item.php +``` + +```php [✅ View Classes] +// File: src/View/ArticlesView.php +class ArticlesView extends View +{ +} +``` + +::: + +**Rules:** + +- **Template files:** `templates/{Controller}/{underscored_action}.php` + - Method `viewAll()` → `templates/Articles/view_all.php` +- **View classes:** CamelCased, end in `View` - `ArticlesView.php` +- **Helpers:** CamelCased, end in `Helper` - `BestEverHelper.php` +- **Cells:** CamelCased, end in `Cell` - `InboxCell.php` > [!NOTE] -> By default CakePHP uses English inflections. If you have database -> tables/columns that use another language, you will need to add inflection -> rules (from singular to plural and vice-versa). You can use -> `Cake\Utility\Inflector` to define your custom inflection -> rules. See the documentation about [Inflector](../core-libraries/inflector) for more -> information. +> CakePHP uses English inflections by default. For other languages, use `Cake\Utility\Inflector` to define custom rules. See [Inflector](../core-libraries/inflector) documentation. -## Plugins Conventions +### Database Tables -It is useful to prefix a CakePHP plugin with "cakephp-" in the package name. -This makes the name semantically related on the framework it depends on. +::: code-group -Do **not** use the CakePHP namespace (cakephp) as vendor name as this is -reserved to CakePHP owned plugins. The convention is to use lowercase letters -and dashes as separator: +```sql [✅ Correct Table Names] +-- Plural, underscored +CREATE TABLE users; +CREATE TABLE menu_links; +CREATE TABLE user_favorite_pages; -``` text -// Bad -cakephp/foo-bar +-- Foreign keys: {singular_table}_id +ALTER TABLE articles ADD user_id INT; +ALTER TABLE photos ADD menu_link_id INT; -// Good -your-name/cakephp-foo-bar +-- Junction tables: alphabetically sorted plurals +CREATE TABLE articles_tags; ``` -See [awesome list recommendations](https://github.com/FriendsOfCake/awesome-cakephp/blob/master/CONTRIBUTING.md#tips-for-creating-cakephp-plugins) -for details. - -## Summarized - -By naming the pieces of your application using CakePHP conventions, you gain -functionality without the hassle and maintenance tethers of configuration. -Here's a final example that ties the conventions together: - -- Database table: "articles", "menu_links" -- Table class: `ArticlesTable`, found at **src/Model/Table/ArticlesTable.php** -- Entity class: `Article`, found at **src/Model/Entity/Article.php** -- Controller class: `ArticlesController`, found at - **src/Controller/ArticlesController.php** -- View template, found at **templates/Articles/index.php** - -Using these conventions, CakePHP knows that a request to -`https://example.com/articles` maps to a call on the `index()` method of the -`ArticlesController`, where the `Articles` model is automatically available. -None of these relationships have been configured by any means other than by -creating classes and files that you'd need to create anyway. - -
| Example | -articles | -menu_links | -- |
| Database Table | -articles | -menu_links | -Table names corresponding to CakePHP models are plural and underscored. | -
| File | -ArticlesController.php | -MenuLinksController.php | -- |
| Table | -ArticlesTable.php | -MenuLinksTable.php | -Table class names are plural, CamelCased and end in Table | -
| Entity | -Article.php | -MenuLink.php | -Entity class names are singular, CamelCased: Article and MenuLink | -
| Class | -ArticlesController | -MenuLinksController | -- |
| Controller | -ArticlesController | -MenuLinksController | -Plural, CamelCased, end in Controller | -
| Templates | -Articles/index.php Articles/add.php Articles/get_list.php | -MenuLinks/index.php MenuLinks/add.php MenuLinks/get_list.php | -View template files are named after the controller functions they display, in an underscored form | -
| Behavior | -ArticlesBehavior.php | -MenuLinksBehavior.php | -- |
| View | -ArticlesView.php | -MenuLinksView.php | -- |
| Helper | -ArticlesHelper.php | -MenuLinksHelper.php | -- |
| Component | -ArticlesComponent.php | -MenuLinksComponent.php | -- |
| Plugin | -Bad: cakephp/articles Good: you/cakephp-articles | -cakephp/menu-links you/cakephp-menu-links | -Useful to prefix a CakePHP plugin with "cakephp-" in the package name. Do not use the CakePHP namespace (cakephp) as vendor name as this is reserved to CakePHP owned plugins. The convention is to use lowercase letters and dashes as separator. | -
| Each file would be located in the appropriate folder/namespace in your app folder. | -|||
Foreign keys -hasMany belongsTo/ hasOne BelongsToMany |
-Relationships are recognized by default as the (singular) name of the related table followed by _id. Users hasMany Articles, articles table will refer to the users table via a user_id foreign key. |
-
| Multiple Words | -menu_links whose name contains multiple words, the foreign key would be menu_link_id. |
-
| Auto Increment | -In addition to using an auto-incrementing integer as primary keys, you can also use UUID columns. CakePHP will create UUID values automatically using (Cake\Utility\Text::uuid()) whenever you save new records using the Table::save() method. |
-
| Join tables | -Should be named after the model tables they will join or the bake command won't work, arranged in alphabetical order (articles_tags rather than tags_articles). Additional columns on the junction table you should create a separate entity/table class for that table. |
-