Search code examples
validationcakephpuniquecakephp-3.0

CakePHP 3 validation validateUnique error


I've created a validator and I'm trying to make it check if a field is unique, I think I have the rules OK, but it throws a fatal error:

Fatal error: Using $this when not in object context in route/app/vendor/cakephp/cakephp/src/ORM/Table.php on line 2113

Also strict standards tell me this:

Non-static method Cake\ORM\Table::validateUnique() should not be called statically [CORE/src/Validation/ValidationRule.php, line 140]

Is this a bug in Cake 3? I'm using just the core methods...

My cake version is 3.0.1

The validator code:

<?php namespace App\Model\Validation;

use Cake\Validation\Validator;

class SiteValidator extends Validator
{
    public function __construct()
    {
        parent::__construct();
        $this->provider('table', 'Cake\ORM\Table');

        $this
        ->add('id', 'valid', ['rule' => 'numeric'])
        ->allowEmpty('id', 'create')
        ->requirePresence('subdomain', 'create')
        ->notEmpty('subdomain')
        ->add('subdomain', 'validFormat', [
              'rule' => 'alphanumeric',
              'message' => 'El subdominio solo puede contener números y letras sin tildes.',
              ])
        ->add('subdomain', [
              'unique' => ['rule' => 'validateUnique', 'provider' => 'table']
              ])
        ->requirePresence('name', 'create')
        ->notEmpty('name')
        ->add('profile_count', 'valid', ['rule' => 'numeric'])
        ->requirePresence('profile_count', 'create')
        ->notEmpty('profile_count');
    }
}

The call:

use App\Model\Validation\SiteValidator;

....
$validator = new SiteValidator();
$validator->errors( $this->request->data )

Solution

  • You are defining the table provider as a class name, so that's the expected behavior, the validator will call validateUnique() statically in that case.

    See Cookbook > Validation > Adding Validation Providers

    You'll have to pass an actual table class instance in order to use the tables validation methods:

    $sitesTable = TableRegistry::get('Sites');
    $validator->provider('table', $sitesTable);
    

    or, which may be the better choice, define a validator on your table class and use the validate option with newEntity()/newEntities()/patchEntity()/patchEntities().

    $sitesTable->validator('site', $validator);
    $entity = $sitesTable->newEntity($this->request->data, [
        'validate' => 'site'
    ]);
    

    See also