mirror of
https://github.com/yiisoft/yii2.git
synced 2025-08-26 06:15:19 +08:00
Fixes #14254: add an option to specify whether validator is forced to always use master DB for yii\validators\UniqueValidator
and yii\validators\ExistValidator
This commit is contained in:

committed by
Alexander Makarov

parent
41cf14e515
commit
63ffae028e
@ -12,6 +12,7 @@ use yii\base\InvalidConfigException;
|
||||
use yii\base\Model;
|
||||
use yii\db\ActiveQuery;
|
||||
use yii\db\ActiveRecord;
|
||||
use yii\db\QueryInterface;
|
||||
|
||||
/**
|
||||
* ExistValidator validates that the attribute value exists in a table.
|
||||
@ -79,6 +80,12 @@ class ExistValidator extends Validator
|
||||
*/
|
||||
public $targetAttributeJunction = 'and';
|
||||
|
||||
/**
|
||||
* @var bool whether this validator is forced to always use master DB
|
||||
* @since 2.0.14
|
||||
*/
|
||||
public $forceMasterDb = true;
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
@ -105,12 +112,25 @@ class ExistValidator extends Validator
|
||||
|
||||
/**
|
||||
* Validates existence of the current attribute based on relation name
|
||||
* @param \yii\base\Model $model the data model to be validated
|
||||
* @param \yii\db\ActiveRecord $model the data model to be validated
|
||||
* @param string $attribute the name of the attribute to be validated.
|
||||
*/
|
||||
private function checkTargetRelationExistence($model, $attribute)
|
||||
{
|
||||
if (!$model->{'get' . ucfirst($this->targetRelation)}()->exists()) {
|
||||
$exists = false;
|
||||
/** @var ActiveQuery $relationQuery */
|
||||
$relationQuery = $model->{'get' . ucfirst($this->targetRelation)}();
|
||||
|
||||
if ($this->forceMasterDb) {
|
||||
$model::getDb()->useMaster(function() use ($relationQuery, &$exists) {
|
||||
$exists = $relationQuery->exists();
|
||||
});
|
||||
} else {
|
||||
$relationQuery->exists();
|
||||
}
|
||||
|
||||
|
||||
if (!$exists) {
|
||||
$this->addError($model, $attribute, $this->message);
|
||||
}
|
||||
}
|
||||
@ -142,11 +162,7 @@ class ExistValidator extends Validator
|
||||
$targetClass = $this->targetClass === null ? get_class($model) : $this->targetClass;
|
||||
$query = $this->createQuery($targetClass, $conditions);
|
||||
|
||||
if (is_array($model->$attribute)) {
|
||||
if ($query->count("DISTINCT [[$targetAttribute]]") != count($model->$attribute)) {
|
||||
$this->addError($model, $attribute, $this->message);
|
||||
}
|
||||
} elseif (!$query->exists()) {
|
||||
if (!$this->valueExists($targetClass, $query, $model->$attribute)) {
|
||||
$this->addError($model, $attribute, $this->message);
|
||||
}
|
||||
}
|
||||
@ -210,17 +226,53 @@ class ExistValidator extends Validator
|
||||
throw new InvalidConfigException('The "targetAttribute" property must be configured as a string.');
|
||||
}
|
||||
|
||||
$query = $this->createQuery($this->targetClass, [$this->targetAttribute => $value]);
|
||||
|
||||
if (is_array($value)) {
|
||||
if (!$this->allowArray) {
|
||||
return [$this->message, []];
|
||||
}
|
||||
|
||||
return $query->count("DISTINCT [[$this->targetAttribute]]") == count($value) ? null : [$this->message, []];
|
||||
if (is_array($value) && !$this->allowArray) {
|
||||
return [$this->message, []];
|
||||
}
|
||||
|
||||
return $query->exists() ? null : [$this->message, []];
|
||||
$query = $this->createQuery($this->targetClass, [$this->targetAttribute => $value]);
|
||||
|
||||
return $this->valueExists($this->targetClass, $query, $value) ? null : [$this->message, []];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether value exists in target table
|
||||
*
|
||||
* @param string $targetClass
|
||||
* @param QueryInterface $query
|
||||
* @param mixed $value the value want to be checked
|
||||
* @return boolean
|
||||
*/
|
||||
private function valueExists($targetClass, $query, $value)
|
||||
{
|
||||
$db = $targetClass::getDb();
|
||||
$exists = false;
|
||||
|
||||
if ($this->forceMasterDb) {
|
||||
$db->useMaster(function ($db) use ($query, $value, &$exists) {
|
||||
$exists = $this->queryValueExists($query, $value);
|
||||
});
|
||||
} else {
|
||||
$exists = $this->queryValueExists($query, $value);
|
||||
}
|
||||
|
||||
return $exists;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Run query to check if value exists
|
||||
*
|
||||
* @param QueryInterface $query
|
||||
* @param mixed $value the value to be checked
|
||||
* @return bool
|
||||
*/
|
||||
private function queryValueExists($query, $value)
|
||||
{
|
||||
if (is_array($value)) {
|
||||
return $query->count("DISTINCT [[$this->targetAttribute]]") == count($value) ;
|
||||
}
|
||||
return $query->exists();
|
||||
}
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user