Solved thread

This post is marked as solved. If you think the information contained on this thread must be part of the official documentation, please contribute submitting a pull request to its repository.

Model uniqueness validation doesn't work on update

I have a Uniqueness validator on a text field in my model. When I try to insert a new record with the same text as a previous record, the validations works and the new record does not get inserted. However, when I update an existing record with a text that is not unique, the validation does not seem to execute since the record gets updated with the non-unique text.

Am I doing something wrong here?

Sample code to reproduce:

<?php

$di = new Phalcon\DI\FactoryDefault();

$di->setShared('db', function () {
    return new \Phalcon\Db\Adapter\PDO\Sqlite(array(
        'dbname'   => ':memory:'
    ));
});

class Test extends \Phalcon\Mvc\Model
{
    public $mappedPrimaryKey;
    public $mappedData;

    public function columnMap()
    {
        // Keys are the real names in the table and
        // the values their names in the application
        //
        return array(
            "primaryKey"    => "mappedPrimaryKey",  
            "data"          => "mappedData"
        );
    }

    public function validation()
    {
        $validator = new Phalcon\Validation();          

            $validator->add( "mappedData",
                new Phalcon\Validation\Validator\Uniqueness( array(
                    "message" => "Data must be unique"
         )));

        return $this->validate( $validator );
    }
}

use \Phalcon\Db\Column as Column;

$di['db']->createTable(
    'test',
    null,
    [
       'columns' => [
            new Column(
                'primaryKey',
                [
                    'type'          => Column::TYPE_INTEGER,
                    'notNull'       => true,
                    'autoIncrement' => true,
                    'primary'       => true,
                ]
            ),
            new Column(
                'data',
                [
                    'type'    => Column::TYPE_TEXT,
                    'notNull' => true,
                ]
            )
        ]
    ]
);

$testObject1 = new Test;
$testObject1->mappedPrimaryKey = 1;
$testObject1->mappedData = "Object 1";

$testObject1->save();

$testObject2 = new Test;
$testObject2->mappedPrimaryKey = 2;
$testObject2->mappedData = "Object 2";

$testObject2->save();

$allRecords = Test::find();
foreach ( $allRecords as $record )
{
    echo $record->mappedPrimaryKey . ": " . $record->mappedData . "\n";
}
echo "\n";

$result = Test::findFirst( "mappedPrimaryKey = 1" );
$result->mappedData = "Object 2";   // Not unique
$result->save();

$allRecords = Test::find();
foreach ( $allRecords as $record )
{
    echo $record->mappedPrimaryKey . ": " . $record->mappedData . "\n";
}

echo "\nPhalcon Version: ", Phalcon\Version::get(), "\n";

My output:

1: Object 1
2: Object 2

1: Object 2
2: Object 2

Phalcon Version: 3.4.0

I also have problems with the ORM to insert records. :/



226
edited 15d ago

I checked the query log and this is the statement generated by the validation for an UPDATE (SQL variables in brackets):

SELECT COUNT(*) AS "rowcount" FROM "test" WHERE "test"."data" = :0 AND "test"."primaryKey" <> :1 [Object 2, ]

The primary key variable is missing (should be 1). It seems that the statement after AND always evaluates to false because of this and no rows are returned. What can be the cause of this?

How your database looks like? Provide schema best, not what is in creatTable, also why you even set primaryKey if you have autoincrement? Try to remove all $testObject1->mappedPrimaryKey setting.



226

How your database looks like? Provide schema best, not what is in creatTable, also why you even set primaryKey if you have autoincrement? Try to remove all $testObject1->mappedPrimaryKey setting.

Hi Wojciech, thanks for your reply.

Here's the output of the sqlite .schema command:

sqlite> .schema test
CREATE TABLE IF NOT EXISTS "test" (
    `primaryKey` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
    `data` TEXT NOT NULL
);

You're right about setting the primary key, I had another issue when I was letting autoincrement do it's job but can't remember what. Anyway, I removed the lines where I set the primary key but this did not change anything.

edited 14d ago

https://github.com/phalcon/cphalcon/blob/master/phalcon/validation/validator/uniqueness.zep#L293

Here you can fidn a code which gets primary key value. You can try test it yourself and post here results, don't have really idea why it's not added correctly.

Maybe it's actually more about SQLite adapter in phalcon, not Uniqueness validator itself? I don't know really. There are many tests in project for this.



226
Accepted
answer

I believe I found the issue, bug report filed: [https://github.com/phalcon/cphalcon/issues/13398]