PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0

Monday, January 10, 2022

[FIXED] Validating Translated Entities in CakePHP 3

 January 10, 2022     cakephp, cakephp-3.0, php     No comments   

Issue

I'm having some difficulties validating a I18N field in CakePHP3.

The translate behavior is setup like this:

$this->addBehavior('Translate', [
    'fields' => ['name', 'body', 'slug'],
    'validator' => 'default'
]);

Like advertised here: https://book.cakephp.org/3.0/en/orm/behaviors/translate.html#validating-translated-entities

The core validation is working properly. I have a validation rule in validationDefault function that checks if name is not empty and it works fine. Though, I also would like to add some application rules on top of this validation. The "name" field should have a unique value. I don't want to allow multiple entities with the same translated name.

This piece of code apparently doesn't work. CakePHP docs also are quite silent about this matter.

public function buildRules(RulesChecker $rules) {
    // prevent duplicate creation
    $rules->add($rules->isUnique(['name']));
    return $rules;
} 

Is this actually possible? Thanks


Solution

What you are doing there is creating a rule for the name field on the main model, this won't affect translations. There is no built-in functionality for that, the behavior only assists with validation rules by making use of the validationTranslated() method in case it exists on your model class, it won't help with application rules.

You'd have to create a custom application rule that checks the translation table, by matching against the field, locale, model and content fields, something along the lines of this:

$rules->add(
    function (EntityInterface $entity) {
        $behavior = $this->behaviors()->get('Translate');
        $association = $this->association($behavior->getConfig('translationTable'));

        $result = true;
        foreach ($entity->get('_translations') as $locale => $translation) {
            $conditions = [
                $association->aliasField('field') => 'name',
                $association->aliasField('locale') => $locale,
                $association->aliasField('content') => $translation->get('name')
            ];

            if ($association->exists($conditions)) {
                $translation->setErrors([
                    'name' => [
                        'uniqueTranslation' => __d('cake', 'This value is already in use')
                    ]
                ]);

                $result = false;
            }
        }

        return $result;
    }
);

Note that this uses the association object rather then the target table, this will ensure that further conditions like the model name are being applied automatically.

Also this requires to set the errors on the entity manually, as they are nested, which isn't supported by the rules checker, currently it can only set errors on the first level entity (see the errorField option).

It should also be noted that it would be possible to modify the rules checker for the translation table association (via the Model.buildRules event), however this would result in the errors being set on new entities that will be put in a separate property (_i18n by default) on the main entity, where the form helper won't find the error, so one would then have to read the error manually, which is a little annoying.

See also

  • Cookbook > Database Access & ORM > Validation > Applying Application Rules


Answered By - ndm
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Newer Post Older Post Home

0 Comments:

Post a Comment

Note: Only a member of this blog may post a comment.

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
Comments
Atom
Comments

Copyright © PHPFixing