Skip to content

Commit 7e1383d

Browse files
committed
Add modern elements to Structure & Conventions page
Extend conventions.md with Enum, Mailer and Form class conventions so the page reflects current CakePHP 5.x application structure: - Add Enum class example (src/Model/Enum/ArticleStatus) with file path, PSR-4 row, reference table row, file tree entry and SQL column example - Add Form (src/Form/*Form.php) and Mailer (src/Mailer/*Mailer.php) to the src/ directory table and the PSR-4 naming table - Fix Enum docs anchor (#enum-type) and replace misleading created_at column example with is_processed (CakePHP defaults to created/modified)
1 parent 25b5072 commit 7e1383d

1 file changed

Lines changed: 32 additions & 11 deletions

File tree

docs/en/intro/conventions.md

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,10 @@ The `src/` folder is where you'll do most development. Here's what goes in each
5353
| **Command** | Console commands | `*Command.php` - See [Command Objects](../console-commands/commands) |
5454
| **Console** | Installation scripts | Executed by Composer |
5555
| **Controller** | HTTP request handlers | [Controllers](../controllers), [Components](../controllers/components) |
56+
| **Form** | Non-ORM form objects | `*Form.php` - See [Form](../core-libraries/form) |
57+
| **Mailer** | Email sending classes | `*Mailer.php` - See [Email](../core-libraries/email) |
5658
| **Middleware** | Request/response filters | `*Middleware.php` - See [Middleware](../controllers/middleware) |
57-
| **Model** | Data layer | [Tables](../orm/table-objects), [Entities](../orm/entities), [Behaviors](../orm/behaviors) |
59+
| **Model** | Data layer | [Tables](../orm/table-objects), [Entities](../orm/entities), [Behaviors](../orm/behaviors), [Enums](../orm/database-basics#enum-type) |
5860
| **View** | Presentation logic | [Views](../views), [Cells](../views/cells), [Helpers](../views/helpers) |
5961

6062
> [!NOTE]
@@ -146,6 +148,18 @@ class User extends Entity
146148
}
147149
```
148150

151+
```php [✅ Enum Class]
152+
// File: src/Model/Enum/ArticleStatus.php
153+
namespace App\Model\Enum;
154+
155+
enum ArticleStatus: string
156+
{
157+
case Draft = 'draft';
158+
case Published = 'published';
159+
case Archived = 'archived';
160+
}
161+
```
162+
149163
:::
150164

151165
**Rules:**
@@ -154,7 +168,7 @@ class User extends Entity
154168
- `UsersTable`, `MenuLinksTable`, `UserFavoritePagesTable`
155169
- **Entity class:** Singular, CamelCased, no suffix
156170
- `User`, `MenuLink`, `UserFavoritePage`
157-
- **Enum class:** `{Entity}{Column}` - e.g., `UserStatus`, `OrderState`
171+
- **Enum class:** `{Entity}{Column}` in `src/Model/Enum/` - e.g., `ArticleStatus`, `UserRole`
158172
- **Behavior class:** Ends in `Behavior` - `TimestampBehavior`
159173

160174
### Views & Templates
@@ -227,7 +241,7 @@ CREATE TABLE tags_articles;
227241

228242
- **Table names:** Plural, underscored - `users`, `menu_links`
229243
- **Multiple words:** Only pluralize the last word - `user_favorite_pages` (not `users_favorites_pages`)
230-
- **Columns:** Underscored - `first_name`, `created_at`
244+
- **Columns:** Underscored - `first_name`, `is_processed`
231245
- **Foreign keys:** `{singular_table}_id` - `user_id`, `menu_link_id`
232246
- **Junction tables:** Alphabetically sorted plurals - `articles_tags` (not `tags_articles`)
233247

@@ -282,10 +296,13 @@ All files follow **PSR-4 autoloading** - filenames must match class names exactl
282296
| Component | `MyHandyComponent` | `MyHandyComponent.php` | `src/Controller/Component/` |
283297
| Table | `OptionValuesTable` | `OptionValuesTable.php` | `src/Model/Table/` |
284298
| Entity | `OptionValue` | `OptionValue.php` | `src/Model/Entity/` |
299+
| Enum | `ArticleStatus` | `ArticleStatus.php` | `src/Model/Enum/` |
285300
| Behavior | `EspeciallyFunkableBehavior` | `EspeciallyFunkableBehavior.php` | `src/Model/Behavior/` |
286301
| View | `SuperSimpleView` | `SuperSimpleView.php` | `src/View/` |
287302
| Helper | `BestEverHelper` | `BestEverHelper.php` | `src/View/Helper/` |
288303
| Command | `UpdateCacheCommand` | `UpdateCacheCommand.php` | `src/Command/` |
304+
| Mailer | `UserMailer` | `UserMailer.php` | `src/Mailer/` |
305+
| Form | `ContactForm` | `ContactForm.php` | `src/Form/` |
289306

290307
## Complete Example: Articles Feature
291308

@@ -299,6 +316,7 @@ CREATE TABLE articles (
299316
user_id INT,
300317
title VARCHAR(255),
301318
body TEXT,
319+
status VARCHAR(20), -- backed by App\Model\Enum\ArticleStatus
302320
created DATETIME,
303321
modified DATETIME
304322
);
@@ -319,8 +337,10 @@ src/
319337
├── Model/
320338
│ ├── Table/
321339
│ │ └── ArticlesTable.php → class ArticlesTable
322-
│ └── Entity/
323-
│ └── Article.php → class Article
340+
│ ├── Entity/
341+
│ │ └── Article.php → class Article
342+
│ └── Enum/
343+
│ └── ArticleStatus.php → enum ArticleStatus
324344
templates/
325345
└── Articles/
326346
├── index.php → ArticlesController::index()
@@ -346,6 +366,7 @@ URL: `https://example.com/articles/view/5`
346366
| **Database Table** | `articles` | `menu_links` | Plural, underscored |
347367
| **Table Class** | `ArticlesTable` | `MenuLinksTable` | Plural, CamelCased, ends in `Table` |
348368
| **Entity Class** | `Article` | `MenuLink` | Singular, CamelCased |
369+
| **Enum Class** | `ArticleStatus` | `MenuLinkType` | `{Entity}{Column}` in `src/Model/Enum/` |
349370
| **Controller Class** | `ArticlesController` | `MenuLinksController` | Plural, CamelCased, ends in `Controller` |
350371
| **Template Path** | `templates/Articles/` | `templates/MenuLinks/` | Matches controller name |
351372
| **Template File** | `index.php`, `add.php` | `index.php`, `add.php` | Underscored action name |
@@ -359,13 +380,13 @@ URL: `https://example.com/articles/view/5`
359380

360381
::: details Database Convention Summary
361382

362-
| Convention | Description | Example |
363-
|------------|-------------|---------|
383+
| Convention | Description | Example |
384+
|------------|-------------|---------------------------------------------|
364385
| **Foreign Keys** | `{singular_table}_id` for hasMany/belongsTo/hasOne | Users hasMany Articles → `articles.user_id` |
365-
| **Multi-word FKs** | Use singular of full table name | `menu_links` table → `menu_link_id` |
366-
| **Junction Tables** | Alphabetically sorted plurals | `articles_tags` (not `tags_articles`) |
367-
| **Primary Keys** | Auto-increment INT or UUID | UUID auto-generated via `Text::uuid()` |
368-
| **Column Names** | Underscored for multiple words | `first_name`, `created_at` |
386+
| **Multi-word FKs** | Use singular of full table name | `menu_links` table → `menu_link_id` |
387+
| **Junction Tables** | Alphabetically sorted plurals | `articles_tags` (not `tags_articles`) |
388+
| **Primary Keys** | Auto-increment INT or UUID | UUID auto-generated via `Text::uuid()` |
389+
| **Column Names** | Underscored for multiple words | `first_name`, `is_processed` |
369390

370391
> [!WARNING]
371392
> If junction tables have additional data columns, create a dedicated Table and Entity class for them.

0 commit comments

Comments
 (0)