Cphalcon: [BUG] Uniqueness validator incorrectly fails validation on update

Created on 6 Nov 2013  Â·  15Comments  Â·  Source: phalcon/cphalcon

With the following model $id is the primary key and $name must be unique within $project_id

use Phalcon\Mvc\Model\Validator\Uniqueness;

class Tags extends \Phalcon\Mvc\Model {
  public $id;
  public $project_id;
  public $name;

  public function initialize() {
    $this->setSource('table_tags');
  }

  public function validation()
  {
    $this->validate(new Uniqueness([
      'field' => ['project_id', 'name'],
      'message' => 'The tag already exists in selected project'
    ]));

    return ($this->validationHasFailed() != true);
  }
}

Lets say I have the following data:

$data = array(
    'id' => 1,
    'project_id' => 1,
    'name' => 'Some tag',
);

It works fine when creating a new record with Tags::save(), but then Tags::update() is failing the validation. There might be something I'm missing here or the Uniqueness validation is not excluding current $id from the check.

Tested on:
Phalcon 1.3.0 and 1.2.4
PHP 5.4.18 and 5.5.5
Windows 7

Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.

bug medium

Most helpful comment

The bug seems to be back with version 2.1.0.RC1.
I rolled back to a previous version 2.0.8 released on Sep 26 2015 16:25:52 which works fine.

All 15 comments

Currently using the following workaround:
https://gist.github.com/WooDzu/7352767

I test it ok, Would you please submit code, reproduce this error? :

        $account = Accounts::findFirst();
        $account->phone = $account->phone;
        $account->email = $account->email;
        $account->id = $account->id;
        if ($account->update() == false) {
            echo 'fail';
        } else {
            echo 'success';
        }

Your example should actually reproduce the case assuming phone and email have set Uniqueness validator.

If you do $account->validation() before update() it will give false.

EDIT: Actually $account->validation() also fails if Uniqueness is set with a single field like the one from Phalcon testsuite:


// unit-tests/models/Subscriptorers.php
class Subscriptores extends Phalcon\Mvc\Model
....
$this->validate(new UniquenessValidator(array(
   'field' => 'email'
)));
....

// test
$test = Subscriptores::findFirst();
$valid = $test->validation(); // <-- FALSE

Due to

PHALCON_CALL_METHOD(&operation_made, record, "getoperationmade");
if (PHALCON_IS_LONG(operation_made, 2)) {

in phalcon source code you must set model in update operation mode "2" then validation will check unique key.
Set:

$this->_operationMade=2;

during validation to resolve this problem.

@niden This is a horrible bug. Is it solved in version 2.0?

This bug is open for months. Any news??

I come up with the following validator:

class UniquenessValidator extends \Phalcon\Mvc\Model\Validator
{
    public function validate($record)
    {

        $message = $this->getOption('message') ?: 'مقدار وارد شده تکراری است.';
        $field = $this->getOption('field');
        if (isset($record->id)) {
            $query = $record->query()->where("$field=:value: and id!=:id:")->bind([
                'value' => $record->$field,
                'id' => $record->id
            ]);
        }
        else {
            $query = $record->query()->where("$field=:value:")->bind([
                'value' => $record->$field,
            ]);

        }
        $count = count($query->execute());
        if ($count == 0) {
            return true;
        }
        $this->appendMessage($message, $field);
        return false;
    }
}

This is a terrible bug :cactus:

Can you confirm whether this is still happening in Phalcon 2?

I test my code just now, This bug has been fixed in Phalcon 2. :smile:
Thank you!

Nice

I'm still experiencing this problem。
It works fine when creating a new record with Model::create(), but then Model::update() is failing the validation.

Tested on:
Phalcon 2.0.10
PHP 5.6.10
Ubuntu 14.04.1 LTS 32bit

Here is my code:
use Phalcon\Mvc\Model\Validator\Uniqueness as UniquenessValidator;
class NoteGroup extends \Phalcon\Mvc\Model
{

public $groupId;
public $groupName;
public $userId;
public $createTime;
public $modifiedTime;

public function getSource()
{
    return 'note_group';
}

public function initialize()
{
    $this->keepSnapshots(true);
    $this->useDynamicUpdate(true);
}

public function validation(){
    $this->validate(new UniquenessValidator([
        "field" => ['groupName','userId'],
        "message" => 'The groupName already exists'
    ]));
    if ($this->validationHasFailed() == true) {
        return false;
    }
    return true;
}

public function columnMap()
{
    return array(
        'group_id' => 'groupId',
        'group_name' => 'groupName',
        'user_id' => 'userId',
        'create_time' => 'createTime',
        'modified_time' => 'modifiedTime'
    );
}

}
?>

Controller:

        $noteGroup    = new NoteGroup();
        $noteGroup->groupName  = $groupName;
        $noteGroup->userId     = $userId;
        $test =  $noteGroup->create();  // <-- FALSE

But,

        $noteGroup = NoteGroup::findFirst([
            'groupId = :groupId: AND userId = :userId:',
            'bind' => [
                'groupId' => $groupId,
                'userId'  => $userId
            ]
        ]);
        if (false !== $noteGroup) {
            $noteGroup->groupName  = $groupName;
            $validate = $noteGroup->validation();  // <-- FALSE
            $test     = $noteGroup->update();      // <-- TRUE
        }     

The bug seems to be back with version 2.1.0.RC1.
I rolled back to a previous version 2.0.8 released on Sep 26 2015 16:25:52 which works fine.

Yes,This bug has been rolled back.

create please separated issue with script to reproduce

Was this page helpful?
0 / 5 - 0 ratings

Related issues

TimurFlush picture TimurFlush  Â·  3Comments

borisdelev picture borisdelev  Â·  3Comments

abcpremium picture abcpremium  Â·  3Comments

ismail0234 picture ismail0234  Â·  3Comments

Yakovlev-Melarn picture Yakovlev-Melarn  Â·  3Comments