destroyApplication(); ActiveRecord::$db = $this->getConnection(); } public function testValidateValueExpectedException(): void { try { $val = new ExistValidator(); $val->validate('ref'); $this->fail('Exception should have been thrown at this time'); } catch (Exception $e) { $this->assertInstanceOf('yii\base\InvalidConfigException', $e); $this->assertEquals('The "targetClass" property must be set.', $e->getMessage()); } // combine to save the time creating a new db-fixture set (likely ~5 sec) try { $val = new ExistValidator(['targetClass' => ValidatorTestMainModel::class]); $val->validate('ref'); $this->fail('Exception should have been thrown at this time'); } catch (Exception $e) { $this->assertInstanceOf('yii\base\InvalidConfigException', $e); $this->assertEquals('The "targetAttribute" property must be configured as a string.', $e->getMessage()); } } public function testValidateValue(): void { $val = new ExistValidator(['targetClass' => ValidatorTestRefModel::class, 'targetAttribute' => 'id']); $this->assertTrue($val->validate(2)); $this->assertTrue($val->validate(5)); $this->assertFalse($val->validate(99)); $this->assertFalse($val->validate(['1'])); } public function testValidateAttribute(): void { // existing value on different table $val = new ExistValidator(['targetClass' => ValidatorTestMainModel::class, 'targetAttribute' => 'id']); $m = ValidatorTestRefModel::findOne(['id' => 1]); $val->validateAttribute($m, 'ref'); $this->assertFalse($m->hasErrors()); // non-existing value on different table $val = new ExistValidator(['targetClass' => ValidatorTestMainModel::class, 'targetAttribute' => 'id']); $m = ValidatorTestRefModel::findOne(['id' => 6]); $val->validateAttribute($m, 'ref'); $this->assertTrue($m->hasErrors('ref')); // existing value on same table $val = new ExistValidator(['targetAttribute' => 'ref']); $m = ValidatorTestRefModel::findOne(['id' => 2]); $val->validateAttribute($m, 'test_val'); $this->assertFalse($m->hasErrors()); // non-existing value on same table $val = new ExistValidator(['targetAttribute' => 'ref']); $m = ValidatorTestRefModel::findOne(['id' => 5]); $val->validateAttribute($m, 'test_val_fail'); $this->assertTrue($m->hasErrors('test_val_fail')); // check for given value (true) $val = new ExistValidator(); $m = ValidatorTestRefModel::findOne(['id' => 3]); $val->validateAttribute($m, 'ref'); $this->assertFalse($m->hasErrors()); // check for given defaults (false) $val = new ExistValidator(); $m = ValidatorTestRefModel::findOne(['id' => 4]); $m->a_field = 'some new value'; $val->validateAttribute($m, 'a_field'); $this->assertTrue($m->hasErrors('a_field')); // existing array $val = new ExistValidator(['targetAttribute' => 'ref']); $val->allowArray = true; $m = new ValidatorTestRefModel(); $m->test_val = [2, 3, 4, 5]; $val->validateAttribute($m, 'test_val'); $this->assertFalse($m->hasErrors('test_val')); // existing non-unique array $val = new ExistValidator(['targetAttribute' => 'ref']); $val->allowArray = true; $m = new ValidatorTestRefModel(); $m->test_val = [2, 2, 3, 3, 4, 4, 5, 5]; $val->validateAttribute($m, 'test_val'); $this->assertFalse($m->hasErrors('test_val')); // non-existing array $val = new ExistValidator(['targetAttribute' => 'ref']); $val->allowArray = true; $m = new ValidatorTestRefModel(); $m->test_val = [95, 96, 97, 98]; $val->validateAttribute($m, 'test_val'); $this->assertTrue($m->hasErrors('test_val')); // partial-existing array $val = new ExistValidator(['targetAttribute' => 'ref']); $val->allowArray = true; $m = new ValidatorTestRefModel(); $m->test_val = [2, 97, 3, 98]; $val->validateAttribute($m, 'test_val'); $this->assertTrue($m->hasErrors('test_val')); // existing array (allowArray = false) $val = new ExistValidator(['targetAttribute' => 'ref']); $val->allowArray = false; $m = new ValidatorTestRefModel(); $m->test_val = [2, 3, 4, 5]; $val->validateAttribute($m, 'test_val'); $this->assertTrue($m->hasErrors('test_val')); // non-existing array (allowArray = false) $val = new ExistValidator(['targetAttribute' => 'ref']); $val->allowArray = false; $m = new ValidatorTestRefModel(); $m->test_val = [95, 96, 97, 98]; $val->validateAttribute($m, 'test_val'); $this->assertTrue($m->hasErrors('test_val')); } public function testValidateCompositeKeys(): void { $val = new ExistValidator([ 'targetClass' => OrderItem::class, 'targetAttribute' => ['order_id', 'item_id'], ]); // validate old record $m = OrderItem::findOne(['order_id' => 1, 'item_id' => 2]); $val->validateAttribute($m, 'order_id'); $this->assertFalse($m->hasErrors('order_id')); // validate new record $m = new OrderItem(['order_id' => 1, 'item_id' => 2]); $val->validateAttribute($m, 'order_id'); $this->assertFalse($m->hasErrors('order_id')); $m = new OrderItem(['order_id' => 2, 'item_id' => 5]); $val->validateAttribute($m, 'order_id'); $this->assertFalse($m->hasErrors('order_id')); $m = new OrderItem(['order_id' => 10, 'item_id' => 2]); $val->validateAttribute($m, 'order_id'); $this->assertTrue($m->hasErrors('order_id')); $val = new ExistValidator([ 'targetClass' => OrderItem::class, 'targetAttribute' => ['id' => 'order_id'], ]); // validate old record $m = Order::findOne(1); $val->validateAttribute($m, 'id'); $this->assertFalse($m->hasErrors('id')); $m = Order::findOne(1); $m->id = 10; $val->validateAttribute($m, 'id'); $this->assertTrue($m->hasErrors('id')); $m = new Order(['id' => 1]); $val->validateAttribute($m, 'id'); $this->assertFalse($m->hasErrors('id')); $m = new Order(['id' => 10]); $val->validateAttribute($m, 'id'); $this->assertTrue($m->hasErrors('id')); } /** * @see https://github.com/yiisoft/yii2/issues/14150 */ public function testTargetTableWithAlias(): void { $oldTableName = OrderItem::$tableName; OrderItem::$tableName = '{{%order_item}}'; $val = new ExistValidator([ 'targetClass' => OrderItem::class, 'targetAttribute' => ['id' => 'order_id'], ]); $m = new Order(['id' => 1]); $val->validateAttribute($m, 'id'); $this->assertFalse($m->hasErrors('id')); OrderItem::$tableName = $oldTableName; } /** * Test expresssion in targetAttribute. * @see https://github.com/yiisoft/yii2/issues/14304 */ public function testExpresionInAttributeColumnName(): void { $val = new ExistValidator([ 'targetClass' => OrderItem::class, 'targetAttribute' => ['id' => 'COALESCE([[order_id]], 0)'], ]); $m = new Order(['id' => 1]); $val->validateAttribute($m, 'id'); $this->assertFalse($m->hasErrors('id')); } public function testTargetRelation(): void { $val = new ExistValidator(['targetRelation' => 'references']); $m = ValidatorTestMainModel::findOne(2); $val->validateAttribute($m, 'id'); $this->assertFalse($m->hasErrors('id')); $m = ValidatorTestMainModel::findOne(1); $val->validateAttribute($m, 'id'); $this->assertTrue($m->hasErrors('id')); } public function testTargetRelationWithFilter(): void { $val = new ExistValidator(['targetRelation' => 'references', 'filter' => function ($query): void { $query->andWhere(['a_field' => 'ref_to_2']); }]); $m = ValidatorTestMainModel::findOne(2); $val->validateAttribute($m, 'id'); $this->assertFalse($m->hasErrors('id')); $val = new ExistValidator(['targetRelation' => 'references', 'filter' => function ($query): void { $query->andWhere(['a_field' => 'ref_to_3']); }]); $m = ValidatorTestMainModel::findOne(2); $val->validateAttribute($m, 'id'); $this->assertTrue($m->hasErrors('id')); } public function testForceMaster(): void { $connection = $this->getConnectionWithInvalidSlave(); ActiveRecord::$db = $connection; $model = null; $connection->useMaster(function() use (&$model): void { $model = ValidatorTestMainModel::findOne(2); }); $validator = new ExistValidator([ 'forceMasterDb' => true, 'targetRelation' => 'references', ]); $validator->validateAttribute($model, 'id'); $this->expectException('\yii\base\InvalidConfigException'); $validator = new ExistValidator([ 'forceMasterDb' => false, 'targetRelation' => 'references', ]); $validator->validateAttribute($model, 'id'); ActiveRecord::$db = $this->getConnection(); } public function testSecondTargetAttributeWithError(): void { $validator = new ExistValidator(['targetAttribute' => ['email', 'name']]); $customer = new Customer(); $customer->email = 'user11111@example.com'; $customer->name = 'user11111'; $validator->validateAttribute($customer, 'email'); $this->assertTrue($customer->hasErrors('email')); $customer->clearErrors(); $customer->addError('name', 'error'); $validator->validateAttribute($customer, 'email'); $this->assertFalse($customer->hasErrors('email')); // validator should be skipped $validator = new ExistValidator([ 'targetAttribute' => ['email', 'name'], 'skipOnError' => false, ]); $customer->clearErrors(); $customer->addError('name', 'error'); $validator->validateAttribute($customer, 'email'); $this->assertTrue($customer->hasErrors('email')); // validator should not be skipped } }