Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
Y
yii2
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
PSDI Army
yii2
Commits
252b6c9e
Commit
252b6c9e
authored
Dec 22, 2013
by
Qiang Xue
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fixes #797: Added support for validating multiple columns by `UniqueValidator` and `ExistValidator`
parent
604d6671
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
172 additions
and
13 deletions
+172
-13
CHANGELOG.md
framework/CHANGELOG.md
+1
-0
ExistValidator.php
framework/yii/validators/ExistValidator.php
+45
-9
UniqueValidator.php
framework/yii/validators/UniqueValidator.php
+37
-4
ExistValidatorTest.php
tests/unit/framework/validators/ExistValidatorTest.php
+42
-0
UniqueValidatorTest.php
tests/unit/framework/validators/UniqueValidatorTest.php
+47
-0
No files found.
framework/CHANGELOG.md
View file @
252b6c9e
...
...
@@ -16,6 +16,7 @@ Yii Framework 2 Change Log
-
Bug: Fixed incorrect event name for
`yii\jui\Spinner`
(samdark)
-
Bug: Json::encode() did not handle objects that implement JsonSerializable interface correctly (cebe)
-
Bug: Fixed issue with tabular input on ActiveField::radio() and ActiveField::checkbox() (jom)
-
Enh #797: Added support for validating multiple columns by
`UniqueValidator`
and
`ExistValidator`
(qiangxue)
-
Enh #1293: Replaced Console::showProgress() with a better approach. See Console::startProgress() for details (cebe)
-
Enh #1406: DB Schema support for Oracle Database (p0larbeer, qiangxue)
-
Enh #1437: Added ListView::viewParams (qiangxue)
...
...
framework/yii/validators/ExistValidator.php
View file @
252b6c9e
...
...
@@ -30,10 +30,25 @@ class ExistValidator extends Validator
*/
public
$className
;
/**
* @var string
the yii\db\
ActiveRecord class attribute name that should be
* @var string
|array the
ActiveRecord class attribute name that should be
* used to look for the attribute value being validated. Defaults to null,
* meaning using the name of the attribute being validated.
* @see className
* meaning using the name of the attribute being validated. Use a string
* to specify the attribute that is different from the attribute being validated
* (often used together with [[className]]). Use an array to validate the existence about
* multiple columns. For example,
*
* ```php
* // a1 needs to exist
* array('a1', 'exist')
* // a1 needs to exist, but its value will use a2 to check for the existence
* array('a1', 'exist', 'attributeName' => 'a2')
* // a1 and a2 need to exist together, and they both will receive error message
* array('a1, a2', 'exist', 'attributeName' => array('a1', 'a2'))
* // a1 and a2 need to exist together, only a1 will receive error message
* array('a1', 'exist', 'attributeName' => array('a1', 'a2'))
* // a1 and a2 need to exist together, a2 will take value 10, only a1 will receive error message
* array('a1', 'exist', 'attributeName' => array('a1', 'a2' => 10))
* ```
*/
public
$attributeName
;
...
...
@@ -64,9 +79,7 @@ class ExistValidator extends Validator
/** @var \yii\db\ActiveRecordInterface $className */
$className
=
$this
->
className
===
null
?
get_class
(
$object
)
:
$this
->
className
;
$attributeName
=
$this
->
attributeName
===
null
?
$attribute
:
$this
->
attributeName
;
$query
=
$className
::
find
();
$query
->
where
([
$attributeName
=>
$value
]);
if
(
!
$query
->
exists
())
{
if
(
!
$this
->
exists
(
$className
,
$attributeName
,
$object
,
$value
))
{
$this
->
addError
(
$object
,
$attribute
,
$this
->
message
);
}
}
...
...
@@ -85,10 +98,33 @@ class ExistValidator extends Validator
if
(
$this
->
attributeName
===
null
)
{
throw
new
InvalidConfigException
(
'The "attributeName" property must be set.'
);
}
return
$this
->
exists
(
$this
->
className
,
$this
->
attributeName
,
null
,
$value
)
?
null
:
[
$this
->
message
,
[]];
}
/**
* Performs existence check.
* @param string $className the AR class name to be checked against
* @param string|array $attributeName the attribute(s) to be checked
* @param \yii\db\ActiveRecordInterface $object the object whose value is being validated
* @param mixed $value the attribute value currently being validated
* @return boolean whether the data being validated exists in the database already
*/
protected
function
exists
(
$className
,
$attributeName
,
$object
,
$value
)
{
/** @var \yii\db\ActiveRecordInterface $className */
$className
=
$this
->
className
;
$query
=
$className
::
find
();
$query
->
where
([
$this
->
attributeName
=>
$value
]);
return
$query
->
exists
()
?
null
:
[
$this
->
message
,
[]];
if
(
is_array
(
$attributeName
))
{
$params
=
[];
foreach
(
$attributeName
as
$k
=>
$v
)
{
if
(
is_integer
(
$k
))
{
$params
[
$v
]
=
$this
->
className
===
null
&&
$object
!==
null
?
$object
->
$v
:
$value
;
}
else
{
$params
[
$k
]
=
$v
;
}
}
}
else
{
$params
=
[
$attributeName
=>
$value
];
}
return
$query
->
where
(
$params
)
->
exists
();
}
}
framework/yii/validators/UniqueValidator.php
View file @
252b6c9e
...
...
@@ -26,9 +26,25 @@ class UniqueValidator extends Validator
*/
public
$className
;
/**
* @var string the ActiveRecord class attribute name that should be
* @var string
|array
the ActiveRecord class attribute name that should be
* used to look for the attribute value being validated. Defaults to null,
* meaning using the name of the attribute being validated.
* meaning using the name of the attribute being validated. Use a string
* to specify the attribute that is different from the attribute being validated
* (often used together with [[className]]). Use an array to validate uniqueness about
* multiple columns. For example,
*
* ```php
* // a1 needs to be unique
* array('a1', 'unique')
* // a1 needs to be unique, but its value will use a2 to check for the uniqueness
* array('a1', 'unique', 'attributeName' => 'a2')
* // a1 and a2 need to unique together, and they both will receive error message
* array('a1, a2', 'unique', 'attributeName' => array('a1', 'a2'))
* // a1 and a2 need to unique together, only a1 will receive error message
* array('a1', 'unique', 'attributeName' => array('a1', 'a2'))
* // a1 and a2 need to unique together, a2 will take value 10, only a1 will receive error message
* array('a1', 'unique', 'attributeName' => array('a1', 'a2' => 10))
* ```
*/
public
$attributeName
;
...
...
@@ -60,7 +76,20 @@ class UniqueValidator extends Validator
$attributeName
=
$this
->
attributeName
===
null
?
$attribute
:
$this
->
attributeName
;
$query
=
$className
::
find
();
$query
->
where
([
$attributeName
=>
$value
]);
if
(
is_array
(
$attributeName
))
{
$params
=
[];
foreach
(
$attributeName
as
$k
=>
$v
)
{
if
(
is_integer
(
$k
))
{
$params
[
$v
]
=
$this
->
className
===
null
?
$object
->
$v
:
$value
;
}
else
{
$params
[
$k
]
=
$v
;
}
}
}
else
{
$params
=
[
$attributeName
=>
$value
];
}
$query
->
where
(
$params
);
if
(
!
$object
instanceof
ActiveRecordInterface
||
$object
->
getIsNewRecord
())
{
// if current $object isn't in the database yet then it's OK just to call exists()
...
...
@@ -71,7 +100,11 @@ class UniqueValidator extends Validator
$objects
=
$query
->
limit
(
2
)
->
all
();
$n
=
count
(
$objects
);
if
(
$n
===
1
)
{
if
(
in_array
(
$attributeName
,
$className
::
primaryKey
()))
{
$keys
=
array_keys
(
$params
);
$pks
=
$className
::
primaryKey
();
sort
(
$keys
);
sort
(
$pks
);
if
(
$keys
===
$pks
)
{
// primary key is modified and not unique
$exists
=
$object
->
getOldPrimaryKey
()
!=
$object
->
getPrimaryKey
();
}
else
{
...
...
tests/unit/framework/validators/ExistValidatorTest.php
View file @
252b6c9e
...
...
@@ -7,6 +7,8 @@ use Yii;
use
yii\base\Exception
;
use
yii\validators\ExistValidator
;
use
yiiunit\data\ar\ActiveRecord
;
use
yiiunit\data\ar\Order
;
use
yiiunit\data\ar\OrderItem
;
use
yiiunit\data\validators\models\ValidatorTestMainModel
;
use
yiiunit\data\validators\models\ValidatorTestRefModel
;
use
yiiunit\framework\db\DatabaseTestCase
;
...
...
@@ -92,4 +94,44 @@ class ExistValidatorTest extends DatabaseTestCase
$val
->
validateAttribute
(
$m
,
'test_val'
);
$this
->
assertTrue
(
$m
->
hasErrors
(
'test_val'
));
}
public
function
testValidateCompositeKeys
()
{
$val
=
new
ExistValidator
([
'className'
=>
OrderItem
::
className
(),
'attributeName'
=>
[
'order_id'
,
'item_id'
],
]);
// validate old record
$m
=
OrderItem
::
find
([
'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'
=>
10
,
'item_id'
=>
2
]);
$val
->
validateAttribute
(
$m
,
'order_id'
);
$this
->
assertTrue
(
$m
->
hasErrors
(
'order_id'
));
$val
=
new
ExistValidator
([
'className'
=>
OrderItem
::
className
(),
'attributeName'
=>
[
'order_id'
,
'item_id'
=>
2
],
]);
// validate old record
$m
=
Order
::
find
(
1
);
$val
->
validateAttribute
(
$m
,
'id'
);
$this
->
assertFalse
(
$m
->
hasErrors
(
'id'
));
$m
=
Order
::
find
(
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'
));
}
}
tests/unit/framework/validators/UniqueValidatorTest.php
View file @
252b6c9e
...
...
@@ -6,6 +6,8 @@ namespace yiiunit\framework\validators;
use
yii\validators\UniqueValidator
;
use
Yii
;
use
yiiunit\data\ar\ActiveRecord
;
use
yiiunit\data\ar\Order
;
use
yiiunit\data\ar\OrderItem
;
use
yiiunit\data\validators\models\FakedValidationModel
;
use
yiiunit\data\validators\models\ValidatorTestMainModel
;
use
yiiunit\data\validators\models\ValidatorTestRefModel
;
...
...
@@ -85,4 +87,49 @@ class UniqueValidatorTest extends DatabaseTestCase
$m
=
new
ValidatorTestMainModel
();
$val
->
validateAttribute
(
$m
,
'testMainVal'
);
}
public
function
testValidateCompositeKeys
()
{
$val
=
new
UniqueValidator
([
'className'
=>
OrderItem
::
className
(),
'attributeName'
=>
[
'order_id'
,
'item_id'
],
]);
// validate old record
$m
=
OrderItem
::
find
([
'order_id'
=>
1
,
'item_id'
=>
2
]);
$val
->
validateAttribute
(
$m
,
'order_id'
);
$this
->
assertFalse
(
$m
->
hasErrors
(
'order_id'
));
$m
->
item_id
=
1
;
$val
->
validateAttribute
(
$m
,
'order_id'
);
$this
->
assertTrue
(
$m
->
hasErrors
(
'order_id'
));
// validate new record
$m
=
new
OrderItem
([
'order_id'
=>
1
,
'item_id'
=>
2
]);
$val
->
validateAttribute
(
$m
,
'order_id'
);
$this
->
assertTrue
(
$m
->
hasErrors
(
'order_id'
));
$m
=
new
OrderItem
([
'order_id'
=>
10
,
'item_id'
=>
2
]);
$val
->
validateAttribute
(
$m
,
'order_id'
);
$this
->
assertFalse
(
$m
->
hasErrors
(
'order_id'
));
$val
=
new
UniqueValidator
([
'className'
=>
OrderItem
::
className
(),
'attributeName'
=>
[
'order_id'
,
'item_id'
=>
2
],
]);
// validate old record
$m
=
Order
::
find
(
1
);
$val
->
validateAttribute
(
$m
,
'id'
);
$this
->
assertFalse
(
$m
->
hasErrors
(
'id'
));
$m
->
id
=
2
;
$val
->
validateAttribute
(
$m
,
'id'
);
$this
->
assertFalse
(
$m
->
hasErrors
(
'id'
));
$m
->
id
=
3
;
$val
->
validateAttribute
(
$m
,
'id'
);
$this
->
assertTrue
(
$m
->
hasErrors
(
'id'
));
$m
=
new
Order
([
'id'
=>
1
]);
$val
->
validateAttribute
(
$m
,
'id'
);
$this
->
assertTrue
(
$m
->
hasErrors
(
'id'
));
$m
=
new
Order
([
'id'
=>
10
]);
$val
->
validateAttribute
(
$m
,
'id'
);
$this
->
assertFalse
(
$m
->
hasErrors
(
'id'
));
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment