Symfony数据校验方法实例分析


Posted in PHP onJanuary 26, 2015

本文实例讲述了Symfony数据校验方法。分享给大家供大家参考。具体分析如下:

校验在web应用程序中是一个常见的任务。数据输入到表单需要被校验。数据在被写入数据库之前或者传入一个webservice时也需要被校验。

Symfony2 配备了一个Validator 组件,它让校验工作变得简单易懂。该组件是基于JSR303 Bean校验规范。一个Java规范用在PHP中。

基本验证

理解校验的最好方法是看它的表现。首先,假设你已经创建了一个用于你应用程序某个地方的PHP对象。

//src/Acme/BlogBundle/Entity/Author.php

namespace Acme\BlogBundle\Entity;
class Author

{

    public $name;

}

到现在为止,它只是个服务于你应用程序的某些目的的普通的类。而校验的目的就是要告诉你对象的数据是否合法。为了这个目的,你需要配置一个对象必须遵守规则或者约束列表来让自己的数据合法。这些规则可以被描述成多种不同的格式的(比如,YAML,XML,类声明或者PHP)。比如,我们保证属性$name不能为空,来添加下面的规则:

YAML格式:

# src/Acme/BlogBundle/Resources/config/validation.yml

Acme\BlogBundle\Entity\Author:

    properties:

         name:

            - NotBlank: ~

类声明格式:
// src/Acme/BlogBundle/Entity/Author.php

use Symfony\Component\Validator\Constraints as Assert;
class Author

{

   /**

    * @Assert\NotBlank()

    */

    public $name;

}

XML格式:

<!-- src/Acme/BlogBundle/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="Acme\BlogBundle\Entity\Author">

        <property name="name">

            <constraint name="NotBlank" />

        </property>

    </class>

</constraint-mapping>

PHP代码格式:

// src/Acme/BlogBundle/Entity/Author.php
use Symfony\Component\Validator\Mapping\ClassMetadata;

use Symfony\Component\Validator\Constraints\NotBlank;
class Author

{

   public $name;

   

   public static function loadValidatorMetadata(ClassMetadata $metadata)

   {

       $metadata->addPropertyConstraint('name', new NotBlank());

   }

}

Protected和private属性以及getter方法也都可以被校验。

使用validator服务:

接下来,使用validator服务的validate方法来真正的校验Author对象。 validator的工作很简单:读取一个类的约束规则来校验一个对象的数据是否符合这些规则约束。如果校验失败,一个错误数组将被返回。现在我们在一个controller中来执行它:

use Symfony\Component\HttpFoundation\Response;

use Acme\BlogBundle\Entity\Author;

//...
public function indexAction()

{

   $author = new Author();

   //... 对$auother对象做些什么

   

   $validator = $this->get('validator');

   $errors = $validator->validate($author);
   if(count($errors) >0){

     return new Response(print_r($errors, true));

   }else{

     return new Response('The author is valid! Yes!');

   }

}

如果$name 属性为空,你将看到下面的错误信息:

Acme\BlogBundle\Author.name:
     This value should not be blank

如果你为$name属性插入一个值,那么你会获得快乐的成功信息。

大多数时候,你不需要直接跟validator服务交流或者根本不需要担心打印出错误来。

大多数情况下,你将在处理提交表单数据时间接使用校验。

你也可以传递一个错误信息集合到一个模版:

if(count($errors)>0){

   return $this->render('AcmeBlogBundle:Author:validate.html.twig',array(

        'errors' => $errors,

   ));

}else{

  //...

}

在模版中,你可以根据需要精确的输出错误列表:

Twig格式:

{# src/Acme/BlogBundle/Resources/views/Author/validate.html.twig #}

<h3>The author has the following errros</h3>

<ul>

{% for error in errors %}

    <li>{{ error.message }}</li>

{% endfor %}

</ul>

校验和表单

validator服务可以被用于任何时候校验任何对象。 事实上,你将经常在处理表单时间接使用validator。Symfony的表单类库间接使用validator服务来在数据被提交和绑定后校验底层对象。对象违反约束信息将被转化到FieldError对象,该对象可以很容易的被展示在你的表单中。在一个controller中的传统表单提交流程如下:

use Acme\BlogBundle\Entity\Author;

use Acme\BlogBundle\Form\AuthorType;

use Acme\Component\HttpFoundation\Request;

//...
public function updateAction(Request $request)

{

    $author = new Acme\BlogBundle\Entity\Author();

    $form = $this->createForm(new AuthorType(),$author);
    if($request->getMethod() =='POST'){

       $form->bindRequest($request);

 

       if($form->isvalid()){

          //对$author做一些操作

          return $this->redirect($this->generateUrl('...'));

       }

     }
     return $this->render('BlogBundle:Author:form.html.twig',array(

         'form' => $form->createView(),

     ));

}

配置:

Symfony2 的validator默认情况下是可用的。但是如果你使用了生命方法来指定你的约束,那么你需要显式的开启声明功能:

YAML格式:

# app/config/config.yml

framework:

   validation: {enable_annotations: true }

XML格式:
<!-- app/config/config.xml -->

<framework:config>

   <framework:validation enable-annotations="true" />

</framework:config>

PHP代码格式:
// app/config/config.php

$contianer->loadFromExtension('framework',array('validation'=> array(

     'enable_annotations'=>true,

)));

约束规则

Validator是设计了用来按照约束规则校验对象的。为了校验一个对象,只需要映射一个或者多个约束到它要校验的类然后把它传递给validator服务即可。

本质上,一个约束就是一个简单的PHP对象,它可以生成一个决断语句。 在现实生活中,一个约束可以是"蛋糕不能烤焦了" 这样的规则约束。在Symfony2中,约束都差不多:他们决断某个条件是否成立。给定一个值,约束会告诉你这个值是否遵守了你的约束规则。

Symfony2 支持的约束规则

首先是基础约束规则:使用他们来决断非常基本的事,比如你对象属性的值或者方法的返回值。

NotBlank,Blank,NotNull,Null,True,False,Type

字符串约束:Email,MinLength,MaxLength,Url,Regex,Ip等

数字约束:Max,Min

日期约束:Date,DateTime和Time

集合约束:Choice,Collection,UniqueEntity,Language,Locale和Country等。

文件约束:File,Image

其它约束:Callback,All,Valid

你也可以创建自己的自定义约束。

约束配置:

一些约束,比如NotBlank,很简单,但是其它的比如Choice约束,有许多配置项需要设置。假设Author类有另外一个属性,gener可以被设置为”male"或者"female":

YAML格式:

# src/Acme/BlogBundle/Resources/config/validation.yml

Acme\BlogBundle\Entity\Author:

    properties:

         gener:

            - Choice: { choices: [male, female], message: Choos a valid gender. }

类声明格式:
// src/Acme/BlogBundle/Entity/Author.php

use Symfony\Component\Validator\Constraints as Assert;
class Author

{

   /**

    * @Assert\Choice(

    *     choices = {"male","female"},

    *     message = "Choose a valid gender."

    * )

    */

    public $gender;

}

XML格式:

<!-- src/Acme/BlogBundle/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="Acme\BlogBundle\Entity\Author">

        <property name="gender">

            <constraint name="Choice">

                <option name="choices">

                    <value>male</value>

                    <value>female</value>

                </option>

                <option name="message">Choose a valid gender.</option>

            </constraint>

        </property>

    </class>

</constraint-mapping>

PHP代码格式:

// src/Acme/BlogBundle/Entity/Author.php

use Symfony\Component\Validator\Mapping\ClassMetadata;

use Symfony\Component\Validator\Constraints\NotBlank;
class Author

{

    public $gender;
    public static function loadValidatorMetadata(ClassMetadata $metadata)

    {

        $metadata->addPropertyConstraint('gender', new Choice(array(

            'choices' => array('male', 'female'),

            'message' => 'Choose a valid gender.',

        )));

    }

}

一个约束的选项通常都是通过一个数组来传递的。有些约束也允许你传递一个值。"default"在数组中是可选的。在Choice约束时,choices选项就可以通过这种方式指定。

YAML格式:

# src/Acme/BlogBundle/Resources/config/validation.yml

Acme\BlogBundle\Entity\Author:

    properties:

        gender:

            - Choice: [male, female]

类声明格式:
// src/Acme/BlogBundle/Entity/Author.php

use Symfony\Component\Validator\Constraints as Assert;
class Author

{

    /**

     * @Assert\Choice({"male", "female"})

     */

    protected $gender;

}

XML格式:

<!-- src/Acme/BlogBundle/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="Acme\BlogBundle\Entity\Author">

        <property name="gender">

            <constraint name="Choice">

                <value>male</value>

                <value>female</value>

            </constraint>

        </property>

    </class>

</constraint-mapping>

PHP格式:

// src/Acme/BlogBundle/Entity/Author.php

use Symfony\Component\Validator\Mapping\ClassMetadata;

use Symfony\Component\Validator\Constraints\Choice;
class Author

{

    protected $gender;
    public static function loadValidatorMetadata(ClassMetadata $metadata)

    {

        $metadata->addPropertyConstraint('gender', new Choice(array('male', 'female')));

    }

}

约束目标

约束可以被用于一个类的属性或者一个公共的getter方法。属性约束最常用也最简单,而公共的getter方法约束则允许你指定一个复杂的约束规则。

属性约束:

校验类的属性石一个最常规的校验技术。Symfony2允许你校验private,protected或者public属性。下面代码显示如何配置Author对象的$firstName属性至少有3个字符:

YAML格式:

# src/Acme/BlogBundle/Resources/config/validation.yml

Acme\BlogBundle\Entity\Author:

    properties:

        firstName:

            - NotBlank: ~

            - MinLength: 3

类声明格式:
// Acme/BlogBundle/Entity/Author.php

use Symfony\Component\Validator\Constraints as Assert;
class Author

{

    /**

     * @Assert\NotBlank()

     * @Assert\MinLength(3)

     */

    private $firstName;

}

XML格式:

<!-- src/Acme/BlogBundle/Resources/config/validation.xml -->

<class name="Acme\BlogBundle\Entity\Author">

    <property name="firstName">

        <constraint name="NotBlank" />

        <constraint name="MinLength">3</constraint>

    </property>

</class>

PHP代码格式:

// src/Acme/BlogBundle/Entity/Author.php

use Symfony\Component\Validator\Mapping\ClassMetadata;

use Symfony\Component\Validator\Constraints\NotBlank;

use Symfony\Component\Validator\Constraints\MinLength;
class Author

{

    private $firstName;
    public static function loadValidatorMetadata(ClassMetadata $metadata)

    {

        $metadata->addPropertyConstraint('firstName', new NotBlank());

        $metadata->addPropertyConstraint('firstName', new MinLength(3));

    }

}

Getters

约束也可以应用于一个方法的返回值。Symfony2 允许你添加一个约束到任何"get"或者 "is"开头的public方法。该技术的好处是允许你动态的校验你的对象。比如,假设你想确认密码字段不匹配用户的first name(因为安全原因)。你可以通过创建一个idPasswordLegal 方法,然后决断这个方法必须返回true:

YAML格式:

# src/Acme/BlogBundle/Resources/config/validation.yml

Acme\BlogBundle\Entity\Author:

    getters:

        passwordLegal:

            - "True": { message: "The password cannot match your first name" }

类声明格式:
// src/Acme/BlogBundle/Entity/Author.php

use Symfony\Component\Validator\Constraints as Assert;
class Author

{

    /**

     * @Assert\True(message = "The password cannot match your first name")

     */

    public function isPasswordLegal()

    {

        // return true or false

    }

}

XML格式:

<!-- src/Acme/BlogBundle/Resources/config/validation.xml -->

<class name="Acme\BlogBundle\Entity\Author">

    <getter property="passwordLegal">

        <constraint name="True">

            <option name="message">The password cannot match your first name</option>

        </constraint>

    </getter>

</class>

PHP代码格式:

// src/Acme/BlogBundle/Entity/Author.php

use Symfony\Component\Validator\Mapping\ClassMetadata;

use Symfony\Component\Validator\Constraints\True;
class Author

{

    public static function loadValidatorMetadata(ClassMetadata $metadata)

    {

        $metadata->addGetterConstraint('passwordLegal', new True(array(

            'message' => 'The password cannot match your first name',

        )));

    }

}

现在我们创建一个isPasswordLegal()方法,并且包含你需要逻辑:

public function isPasswordLegal()

{

   return ($this->firstName != $this->password);

}

眼尖的人可能会注意到getter的前缀("get"或者"is")在映射时被忽略了。这允许你在不改变校验规则的前提下,把一个约束移动到一个具有同名属性上,反之亦然。

类:

一些约束应用到整个类被校验上面。比如,Callback约束是一个通用约束,它可以应用到类自身。当类被校验时,被约束描述的方法只是被执行这样每一个可以提供更个性化的校验。

校验分组

到目前为止,你已经能够添加约束到类并询问是否该类传入所有定义的约束规则。一些情况下,你只需要使用该类的其中某些规则来校验一个对象。要做到这些,你可以组织每一个约束到一个或者多个校验组中,然后应用使用其中一组校验。比如,假设你有一个User类,它会在用户注册和用户更新他们的联系信息时使用。

YAML格式:

# src/Acme/BlogBundle/Resources/config/validation.yml

Acme\BlogBundle\Entity\User:

    properties:

        email:

            - Email: { groups: [registration] }

        password:

            - NotBlank: { groups: [registration] }

            - MinLength: { limit: 7, groups: [registration] }

        city:

            - MinLength: 2

类声明格式:

// src/Acme/BlogBundle/Entity/User.php

namespace Acme\BlogBundle\Entity;
use Symfony\Component\Security\Core\User\UserInterface;

use Symfony\Component\Validator\Constraints as Assert;
class User implements UserInterface

{

    /**

    * @Assert\Email(groups={"registration"})

    */

    private $email;
    /**

    * @Assert\NotBlank(groups={"registration"})

    * @Assert\MinLength(limit=7, groups={"registration"})

    */

    private $password;
    /**

    * @Assert\MinLength(2)

    */

    private $city;

}

XML格式:

<!-- src/Acme/BlogBundle/Resources/config/validation.xml -->

<class name="Acme\BlogBundle\Entity\User">

    <property name="email">

        <constraint name="Email">

            <option name="groups">

                <value>registration</value>

            </option>

        </constraint>

    </property>

    <property name="password">

        <constraint name="NotBlank">

            <option name="groups">

                <value>registration</value>

            </option>

        </constraint>

        <constraint name="MinLength">

            <option name="limit">7</option>

            <option name="groups">

                <value>registration</value>

            </option>

        </constraint>

    </property>

    <property name="city">

        <constraint name="MinLength">7</constraint>

    </property>

</class>

PHP代码格式:

// src/Acme/BlogBundle/Entity/User.php

namespace Acme\BlogBundle\Entity;
use Symfony\Component\Validator\Mapping\ClassMetadata;

use Symfony\Component\Validator\Constraints\Email;

use Symfony\Component\Validator\Constraints\NotBlank;

use Symfony\Component\Validator\Constraints\MinLength;
class User

{

    public static function loadValidatorMetadata(ClassMetadata $metadata)

    {

        $metadata->addPropertyConstraint('email', new Email(array(

            'groups' => array('registration')

        )));
        $metadata->addPropertyConstraint('password', new NotBlank(array(

            'groups' => array('registration')

        )));

        $metadata->addPropertyConstraint('password', new MinLength(array(

            'limit'  => 7,

            'groups' => array('registration')

        )));
        $metadata->addPropertyConstraint('city', new MinLength(3));

    }

}

这里我们配置了两个校验组:
      default默认组: 包括所有没有分配到任何组的约束规则
      registration: 只包含了email和password字段的校验规则

告诉validator使用指定的校验组,传一个或者多个组名作为validate()方法的第二个参数即可:

$errors = $validator->validate($author,array('registration'));

值和数组校验

到目前为止,我们已经看了如何校验整个对象。但是有时候,我们可能想值校验一个单独的值,比如校验一个字符串是不是一个合法的email地址。这非常简单,在Controller类中进行如下:

// 在controller类前引用相应的校验命名空间

use Symfony\Component\Validator\Constraints\Email;
public function addEmailAction($email)

{

    $emailConstraint = new Email();

    // 所有的校验选项(options)都可以这样设置

    $emailConstraint->message = 'Invalid email address';
    // 使用validator来校验一个值

    $errorList = $this->get('validator')->validateValue($email, $emailConstraint);
    if (count($errorList) == 0) {

        // 这是一个合法的email地址,可以做些什么

    } else {

        // 这是一个非法的email地址

        $errorMessage = $errorList[0]->getMessage()
        // 做一些错误处理

    }
    // ...

}

通过调用validator的validateValue方法,你可以传入一个原始值和一个你要使用的校验对象。该方法会返回一个ConstraintViolationList对象,它扮演的只是一个错误信息数组的角色。集合中的每一个错误是一个ConstraintViolation对象,使用对象的getMessage方法可以获取错误信息。

总结:

Symfony2 的validator是一个强大的工具,它可以被用来保证任何对象数据的合法性。它的强大来源于约束规则,你可以把它们应用于你对象的属性和getter方法。其实,你大多数情况下都是在使用表单时,间接的应用了校验框架,记住它可以被应用于任何地方校验任何对象。

希望本文所述对大家的Symfony框架程序设计有所帮助。

PHP 相关文章推荐
在VS2008中编译MYSQL5.1.48的方法
Jul 03 PHP
PHP合并数组+与array_merge的区别分析
Aug 01 PHP
通过5个php实例细致说明传值与传引用的区别
Aug 08 PHP
如何使用“PHP” 彩蛋进行敏感信息获取
Aug 07 PHP
Linux系统下php获得系统分区信息的方法
Mar 30 PHP
Thinkphp关闭缓存的方法
Jun 26 PHP
php图形jpgraph操作实例分析
Feb 22 PHP
PHP+JQUERY操作JSON实例
Mar 23 PHP
PHP中Laravel 关联查询返回错误id的解决方法
Apr 01 PHP
PHP异常处理定义与使用方法分析
Jul 25 PHP
PHP实现类似于C语言的文件读取及解析功能
Sep 01 PHP
laravel手动创建数组分页的实现代码
Jun 07 PHP
symfony表单与页面实现技巧
Jan 26 #PHP
php使用cookie保存登录用户名的方法
Jan 26 #PHP
Symfony页面的基本创建实例详解
Jan 26 #PHP
PHP中使用imagick生成PSD文件缩略图教程
Jan 26 #PHP
PHP中使用imagick实现把PDF转成图片
Jan 26 #PHP
PHP中使用Imagick操作PSD文件实例
Jan 26 #PHP
PHP实现将浏览历史页面网址保存到cookie的方法
Jan 26 #PHP
You might like
解决控件遮挡问题:关于有窗口元素和无窗口元素
2007/01/28 PHP
用php简单实现加减乘除计算器
2014/01/06 PHP
php生成随机数的三种方法
2014/09/10 PHP
Laravel中如何增加自定义全局函数详解
2017/05/09 PHP
php 字符串中是否包含指定字符串的多种方法
2018/04/12 PHP
php支付宝APP支付功能
2020/07/29 PHP
laravel 自定义常量的两种方案
2019/10/14 PHP
PHP与Web页面的交互示例详解一
2020/08/04 PHP
jquery validation插件表单验证的一个例子
2010/03/03 Javascript
javascript中自定义对象的属性方法分享
2013/07/12 Javascript
用js读、写、删除Cookie代码续篇
2014/12/03 Javascript
js实现格式化金额,字符,时间的方法
2015/02/26 Javascript
javascript中Date format(js日期格式化)方法小结
2015/12/17 Javascript
jQuery动态改变多行文本框高度的方法
2016/09/07 Javascript
JavaScript 实现的checkbox经典实例分享
2016/10/16 Javascript
JQuery validate 验证一个单独的表单元素实例
2017/02/17 Javascript
微信小程序 下拉菜单的实现
2017/04/06 Javascript
JS中使用media实现响应式布局
2017/08/04 Javascript
node.js读取Excel数据(下载图片)的方法示例
2018/08/02 Javascript
使用Nuxt.js改造已有项目的方法
2018/08/07 Javascript
JS选取DOM元素常见操作方法实例分析
2018/12/10 Javascript
vue样式穿透 ::v-deep的具体使用
2020/06/04 Javascript
js实现小球在页面规定的区域运动
2020/06/16 Javascript
使用Vue-cli 中为单独页面设置背景图片铺满全屏
2020/07/17 Javascript
python实现类似ftp传输文件的网络程序示例
2014/04/08 Python
在Django的模型中添加自定义方法的示例
2015/07/21 Python
解决python使用open打开文件中文乱码的问题
2017/12/29 Python
Python中实现最小二乘法思路及实现代码
2018/01/04 Python
几种实用的pythonic语法实例代码
2018/02/24 Python
python操作excel的方法(xlsxwriter包的使用)
2018/06/11 Python
Python日志器使用方法及原理解析
2020/09/27 Python
如何提高JDBC的性能
2013/04/30 面试题
英语生日邀请函
2014/01/23 职场文书
寒假家长评语大全
2014/04/16 职场文书
小学生倡议书范文
2014/05/13 职场文书
欢迎领导标语
2014/06/27 职场文书