Behaviors
A behavior is a ready-made piece of logic attached to a table class with one line. It runs by itself when records are saved or found. This way shared code, such as timestamps or building an address from a title, is written once and used in any table.
Attaching
Behaviors are attached in the initialize() method of the table class:
// src/Model/Table/ArticlesTable.php
public function initialize(array $config): void
{
parent::initialize($config);
$this->addBehavior('Timestamp');
}Timestamp fills the created column when a record is created and modified on every save. Save an article through the form and look into the database: both dates are set although the code never mentions them.
Built-in behaviors
| Behavior | What it does |
|---|---|
Timestamp | Fills created and modified |
CounterCache | Keeps the number of related records in a column of the parent |
Translate | Translations of fields into several languages |
Tree | Nested categories |
Behavior settings
Settings are passed as the second argument:
// src/Model/Table/CommentsTable.php
$this->belongsTo('Articles');
$this->addBehavior('CounterCache', [
'Articles' => ['comment_count'],
]);Now when a comment is added or deleted, the comment_count column of the articles table is updated with their number. The column has to be created with a migration beforehand.
A custom behavior
Your own behaviors live in the src/Model/Behavior folder. Let us create a behavior that turns a title into an article address, a slug:
bin/cake bake behavior Sluggable// src/Model/Behavior/SluggableBehavior.php
namespace App\Model\Behavior;
use ArrayObject;
use Cake\Datasource\EntityInterface;
use Cake\Event\EventInterface;
use Cake\ORM\Behavior;
use Cake\Utility\Text;
class SluggableBehavior extends Behavior
{
public function beforeSave(EventInterface $event, EntityInterface $entity, ArrayObject $options): void
{
if ($entity->isNew() && !$entity->slug) {
$entity->slug = Text::slug(mb_strtolower($entity->title));
}
}
}The beforeSave() method is called before every save. For a new record without a slug it turns the title "Hello World" into hello-world.
Using it
Add a slug column to the table with a migration and attach the behavior:
// src/Model/Table/ArticlesTable.php
$this->addBehavior('Sluggable');Create an article through the form and the slug column is filled in automatically. The same behavior can be attached to any table that has the title and slug columns.
Table events
A behavior can react to several events:
| Method | When it is called |
|---|---|
beforeMarshal() | Before form data is moved into an entity |
beforeSave() | Before saving |
afterSave() | After saving |
beforeDelete() | Before deleting |
beforeFind() | Before a query runs |
The same methods can be written directly in the table class when only that table needs the logic.
Common mistake
Timestamp looks for columns named created and modified. If they are called created_at and updated_at, as in other frameworks, the behavior silently fills nothing. Name columns by the CakePHP conventions.