Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Validation

Form data cannot be saved blindly: a title may be empty and an email may be a random set of letters. CakePHP checks data in two stages. Validation looks at the format of submitted values. Application rules check what needs the database: whether a value is taken, whether a related record exists.

Where the rules are

Both sets are in the table class, src/Model/Table/ArticlesTable.php. The bake model command creates their drafts from the table columns, and after that they are edited by hand.

Validation

// src/Model/Table/ArticlesTable.php
use Cake\Validation\Validator;
 
public function validationDefault(Validator $validator): Validator
{
    $validator
        ->notEmptyString('title', 'Enter a title.');
 
    return $validator;
}

There is one rule: the title must not be empty. The second argument is the error message.

When it runs

Validation runs inside patchEntity() and newEntity():

$article = $this->Articles->newEntity(['title' => '']);
 
debug($article->getErrors());

debug() shows an array with the title key and the text "Enter a title." Errors are stored in the entity itself, and save() does not save such an entity and returns false.

Several rules

$validator
    ->requirePresence('title', 'create')
    ->notEmptyString('title', 'Enter a title.')
    ->minLength('title', 5, 'The title must be at least 5 characters long.')
    ->maxLength('title', 255);
 
$validator
    ->notEmptyString('body', 'Enter the text.')
    ->boolean('published');

Rules for one field are chained. requirePresence('title', 'create') requires the field to be present in the data when a record is created.

Frequent rules

MethodWhat it checks
notEmptyString('field')The value is not empty
allowEmptyString('field')The value may be empty
minLength(), maxLength()String length
email('field')An email address
integer('field'), decimal('field')A number
inList('field', ['a', 'b'])One of the values
date('field')A date
sameAs('password_confirm', 'password')Equality with another field

Application rules

use Cake\ORM\RulesChecker;
 
public function buildRules(RulesChecker $rules): RulesChecker
{
    $rules->add($rules->isUnique(['title'], 'An article with this title already exists.'));
 
    return $rules;
}

isUnique() looks into the database and does not allow saving a second article with the same title. Application rules run later than validation, when save() is called. Another ready-made rule is existsIn(['article_id'], 'Articles'): the related record must exist.

A custom rule

$validator->add('title', 'noShouting', [
    'rule' => fn (string $value) => $value !== mb_strtoupper($value),
    'message' => 'Do not write the title in capital letters only.',
]);

The function receives the field value and returns true when it is acceptable. noShouting is an arbitrary rule name.

Common mistake

Validation checks only data that came through patchEntity() or newEntity(). A value set in code, $article->title = '', bypasses it. Rules that data integrity depends on, such as uniqueness or the existence of a related record, belong in buildRules(): they check the entity on every save.

Thanks for reading!

Donate to the site — we work hard for you.