# Handling Irregular Plural Table Names in CakePHP

> Handling Irregular Plural Table Names in CakePHP

- URL: https://www.codethepixel.com/handling-irregular-plural-table-names-in-cakephp
- Author: Asyraf Wahi Anuar (https://www.codethepixel.com/author/asyraf-wahi-anuar)
- Published: 2025-07-17
- Category: CakePHP
- Tested with: CakePHP, PHP
- Tags: CakePHP, Tutorial
- Reading time: 4 min

CakePHP follows the principle of "convention over configuration", which means it minimizes the amount of code and configuration you need by assuming logical, consistent naming conventions. One key convention is that database table names should be in the plural form. In CakePHP, database table naming follows a convention where plural table names (e.g., users) map to singular entity classes (e.g., User), and corresponding table classes (e.g., UsersTable).

For example:

| **Element** | **Name** |
| --- | --- |
| Table (DB) | Users |
| Model Class | User |
| Table Class | UsersTable |
| Controller | UsersController |
| Entity Class | User |

This convention helps CakePHP automatically determine the relationships between:

- Tables in the database
- Their corresponding Table classes (for database logic)
- Entity classes (representing single records)

By following the plural naming convention (e.g., users, articles, comments), you let CakePHP "just work" without needing to explicitly define table names or override defaults. However, what happens when you encounter irregular plural words like teeth or children? These don’t follow standard pluralization rules and can confuse the framework. Some English words have irregular plurals, such as:

| **Singular** | **Plural** |
| --- | --- |
| Tooth | Teeth |
| Child | Children |
| Person | People |

This tutorial will walk you through how to properly set up a table like teeth in CakePHP so it maps cleanly to a Tooth entity by following best practices.

## Step 1: Create the Table

Create a table in your database called teeth:

```html
CREATE TABLE teeth (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100),
    created DATETIME,
    modified DATETIME
);
```

## Step 2: Create the Table and Entity Classes

TeethTable.php  
Create the TeethTable class under src/Model/Table/.

```html
// src/Model/Table/TeethTable.php
namespace App\Model\Table;

use Cake\ORM\Table;

class TeethTable extends Table
{
    public function initialize(array $config): void
    {
        parent::initialize($config);

        // Explicitly set the table and entity class
        $this->setTable('teeth');
        $this->setEntityClass('App\Model\Entity\Tooth');
    }
}
```

Tooth.php  
Create the Tooth entity class under src/Model/Entity/.

```html
// src/Model/Entity/Tooth.php
namespace App\Model\Entity;

use Cake\ORM\Entity;

class Tooth extends Entity
{
    protected array $_accessible = [
        '*' => true,
        'id' => false,
    ];
}
```

## Optional: Define Inflector Rules

CakePHP uses Inflector to guess plural/singular forms. By default, it doesn't know "tooth" ↔ "teeth". You can define it manually in config/bootstrap.php:

`bootstrap.php`

```html
use Cake\Utility\Inflector;

Inflector::rules('plural', ['irregular' => ['tooth' => 'teeth']]);
Inflector::rules('singular', ['irregular' => ['teeth' => 'tooth']]);
```

This allows you to skip setTable() and setEntityClass() in TeethTable.php because CakePHP will now guess correctly.

## Usage Example

In your controller or elsewhere, you can now do:

```html
// In a controller
$tooth = $this->Teeth->newEmptyEntity();
$tooth->name = 'Upper Right Molar';
$this->Teeth->save($tooth);
```

CakePHP will know that:

- You’re inserting into the teeth table
- Each row is represented by a Tooth entity

| Element | Name |
| --- | --- |
| Table (DB) | teeth |
| Table Class | TeethTable |
| Entity Class | Tooth |
| Optional Inflection | tooth ↔ teeth |

This pattern keeps your domain language meaningful and your code clean, no weird names like teeths required.

While you can name your table teeths to “trick” CakePHP into guessing correctly, it's not semantically correct and may cause confusion later. Use Inflector::rules() or manual mapping for the best results.

That all, happy coding :)
