Expression(表达式)

3.4 版本
维护中的版本

本约束允许你在更加复杂、动态的验证中使用一个 expression 表达式。参考 基本用法,内有例程。参考 Callback (回调)以获得同样的灵活性,可用于不同的约束条件。

Applies to / 适用于 class(类)property/method(属性/方法)
Options / 选项
Class Expression
Validator ExpressionValidator

基本用法 

设想你有一个 BlogPost 类关联了 category 类并且有一个 isTechnicalPost 属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// src/AppBundle/Model/BlogPost.php
namespace AppBundle\Model;
 
use Symfony\Component\Validator\Constraints as Assert;
 
class BlogPost
{
    private $category;
 
    private $isTechnicalPost;
 
    // ...
 
    public function getCategory()
    {
        return $this->category;
    }
 
    public function setIsTechnicalPost($isTechnicalPost)
    {
        $this->isTechnicalPost = $isTechnicalPost;
    }
 
    // ...
}

要验证这个对象,你需要一些特殊条件:

  1. 如果 isTechnicalPost 是 true,那么 category 必须是 php 或者 symfony;
  2. 如果 isTechnicalPost 是 false,那么 category 可以是任何值。

实现这个的一种方式,是使用Expression约束:

1
2
3
4
5
6
# src/AppBundle/Resources/config/validation.yml
AppBundle\Model\BlogPost:
    constraints:
        - Expression:
            expression: "this.getCategory() in ['php', 'symfony'] or !this.isTechnicalPost()"
            message: "If this is a tech post, the category should be either php or symfony!"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// src/AppBundle/Model/BlogPost.php
namespace AppBundle\Model;
 
use Symfony\Component\Validator\Constraints as Assert;
 
/**
 * @Assert\Expression(
 *     "this.getCategory() in ['php', 'symfony'] or !this.isTechnicalPost()",
 *     message="If this is a tech post, the category should be either php or symfony!"
 * )
 */
class BlogPost
{
    // ...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- src/AppBundle/Resources/config/validation.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping http://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">
    <class name="AppBundle\Model\BlogPost">
        <constraint name="Expression">
            <option name="expression">
                this.getCategory() in ['php', 'symfony'] or !this.isTechnicalPost()
            </option>
            <option name="message">
                If this is a tech post, the category should be either php or symfony!
            </option>
        </constraint>
    </class>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// src/AppBundle/Model/BlogPost.php
namespace AppBundle\Model;
 
use Symfony\Component\Validator\Mapping\ClassMetadata;
use Symfony\Component\Validator\Constraints as Assert;
 
class BlogPost
{
    public static function loadValidatorMetadata(ClassMetadata $metadata)
    {
        $metadata->addConstraint(new Assert\Expression(array(
            'expression' => 'this.getCategory() in ["php", "symfony"] or !this.isTechnicalPost()',
            'message' => 'If this is a tech post, the category should be either php or symfony!',
        )));
    }

expression 选项是一个表达式,必须返回true才能令验证通过。要了解更多表达式语法,参考 Expression Syntax一文。

你可以对特定属性施加约束,同时保持基于整个entity的值来进行验证。这在你希望对某个字段附上错误信息时特别有用。在本例的上下文中,value呈现的就是isTechnicalPost的值:

1
2
3
4
5
6
7
8
# src/AppBundle/Resources/config/validation.yml
AppBundle\Model\BlogPost:
    properties:
        isTechnicalPost:
            - Expression:
                expression: "this.getCategory() in ['php', 'symfony'] or value == false"
                message: "If this is a tech post, the category should be either php or symfony!"
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// src/AppBundle/Model/BlogPost.php
namespace AppBundle\Model;
 
use Symfony\Component\Validator\Constraints as Assert;
 
class BlogPost
{
    // ...
 
    /**
     * @Assert\Expression(
     *     "this.getCategory() in ['php', 'symfony'] or value == false",
     *     message="If this is a tech post, the category should be either php or symfony!"
     * )
     */
    private $isTechnicalPost;
 
    // ...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!-- src/AppBundle/Resources/config/validation.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping http://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">
 
    <class name="AppBundle\Model\BlogPost">
        <property name="isTechnicalPost">
            <constraint name="Expression">
                <option name="expression">
                    this.getCategory() in ['php', 'symfony'] or value == false
                </option>
                <option name="message">
                    If this is a tech post, the category should be either php or symfony!
                </option>
            </constraint>
        </property>
    </class>
</constraint-mapping>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// src/AppBundle/Model/BlogPost.php
namespace AppBundle\Model;
 
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Mapping\ClassMetadata;
 
class BlogPost
{
    public static function loadValidatorMetadata(ClassMetadata $metadata)
    {
        $metadata->addPropertyConstraint('isTechnicalPost', new Assert\Expression(array(
            'expression' => 'this.getCategory() in ["php", "symfony"] or value == false',
            'message' => 'If this is a tech post, the category should be either php or symfony!',
        )));
    }
 
    // ...
}

更多表达式信息,以及哪些变量可用,参考下面的 expression 选项细节。

可用选项 

expression 

值类型: string [default option]

将被计算的表达式。如果表达式算出来一个false值 (使用 ==,而不是 ===),那么验证会失败。

要了解更多expression language的语法,参考 The Expression Syntax

  • this: 被验证的对象(比如,一个BlogPost实例);
  • value: 被验证的属性的值 (只在约束直接作用于属性时可用);

message 

值类型: string 默认值: This value is not valid.

payload 

值类型: mixed 默认值: null

例如,你可能希望基于“错误严重性”而使用 多重错误级别 来在前端表达不同的“验证未通过”约束(failed constraints)。

本文,包括例程代码在内,采用的是 Creative Commons BY-SA 3.0 创作共用授权。

登录symfonychina 发表评论或留下问题(我们会尽量回复)