Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

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

BehaviorWhat it does
TimestampFills created and modified
CounterCacheKeeps the number of related records in a column of the parent
TranslateTranslations of fields into several languages
TreeNested 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:

MethodWhen 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.

Thanks for reading!

Donate to the site — we work hard for you.