Skip to content

Unique validation rule needs to check if target attribute has previous validation errors #19407

@xcopy

Description

@xcopy

What steps will reproduce the problem?

  1. Create a claim table
$this->createTable('{{%claim}}', [
    'id' => $this->primaryKey(),
    'event_date' => $this->date()->notNull(),
]);
  1. Create a medication table
$this->createTable('{{%medication}}', [
    'id' => $this->primaryKey(),
    'name' => $this->string()->notNull()->unique(),
]);
  1. Create a junction table claim_medication
$this->createTable('{{%claim_medication}}', [
    'id' => $this->primaryKey(),
    'claim_id' => $this->integer()->notNull(),
    'medication_id' => $this->integer()->notNull(),
]);

$this->addForeignKey(
    'fk-claim_medication-claim_id',
    'claim_medication',
    'claim_id',
    'claim',
    'id'
);

$this->addForeignKey(
    'fk-claim_medication-medication_id',
    'claim_medication',
    'medication_id',
    'medication',
    'id'
);

// IMPORTANT: unique index on two columns
$this->createIndex(
    'idx-claim_medication-unique',
    'claim_medication',
    ['claim_id', 'medication_id'],
    true
);

Generated rules in the ClaimMedication model:

public function rules()
{
    return [
        [['claim_id', 'medication_id'], 'required'],
        [['claim_id', 'medication_id'], 'default', 'value' => null],
        [['claim_id', 'medication_id'], 'integer'],
        [['strength', 'quantity', 'duration'], 'string', 'max' => 255],
        [['claim_id', 'medication_id'], 'unique', 'targetAttribute' => ['claim_id', 'medication_id']],
        [['claim_id'], 'exist', 'skipOnError' => true, 'targetClass' => Claim::className(), 'targetAttribute' => ['claim_id' => 'id']],
        [['medication_id'], 'exist', 'skipOnError' => true, 'targetClass' => Medication::className(), 'targetAttribute' => ['medication_id' => 'id']],
    ];
}
  1. Try to create a new ClaimMedication model
$model = new app\models\ClaimMedication();

// case 1
$model->claim_id = 1;
$model->medication_id = null;
$model->save(); // all good, just one error: "Medication ID cannot be blank."

// case 2
$model->claim_id = 1;
$model->medication_id = 1;
$model->save(); // all good, no errors

// case 3
$model->claim_id = 1;
$model->medication_id = ''; // an empty string
$model->save(); // not good

What is the expected result?

Still expecting a single error on case 3: Medication ID cannot be blank.

What do you get instead?

Database exception on case 3 (i.e. unique rule in action):

yii\db\Exception with message 'SQLSTATE[22P02]: Invalid text representation: 7 ERROR:  invalid input syntax for type integer: ""
The SQL being executed was: SELECT EXISTS(SELECT * FROM "claim_medication" WHERE ("claim_medication"."claim_id"=1) AND ("claim_medication"."medication_id"=''))'

Additional info

Q A
Yii version 2.0.46-dev
PHP version 7.4.29
Operating system Ubuntu 20.04

IMPORTANT: If I swap the order of the rules required & default, then everything works as expected. But this change may affect of other models. The problem occurs precisely when there is more than one attribute in the rule unique.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions