この記事では、Symfony データ検証方法を例とともに分析します。興味のある方は参照してください。検証は Web アプリケーションの一般的なタスクです。フォームに入力されたデータは検証される必要があります。データは、データベースに書き込まれる前、または Web サービスに渡されるときにも検証する必要があります。
Symfony2 には Validator コンポーネントが搭載されており、検証作業をシンプルかつ理解しやすくしています。このコンポーネントは、JSR303 Bean 検証仕様に基づいています。 PHP で使用するための Java 仕様。
コードは次のとおりです:
//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 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">
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()); } }
保護されたプライベート属性とゲッターメソッドも検証できます。
コードは次のとおりです:
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 属性が空の場合、次のエラー メッセージが表示されます:
AcmeBlogBundleAuthor.name:
この値は使用できません空白にしてください
$name 属性の値を挿入すると、成功を示すメッセージが表示されます。
ほとんどの場合、バリデーターサービスと直接通信する必要はなく、印刷エラーについて心配する必要もまったくありません。
コードは次のとおりです:
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 #} The author has the following errros {% for error in errors %} {{ error.message }} {% endfor %}
チェックサムフォーム
validatorサービスを使用すると、いつでも任意のオブジェクトを検証できます。 実際、フォームを処理するときに間接的にバリデーターを使用することがよくあります。 Symfony のフォーム ライブラリは、データが送信されてバインドされた後、間接的にバリデーター サービスを使用して、基礎となるオブジェクトを検証します。オブジェクト制約違反情報は FieldError オブジェクトに変換され、フォームに簡単に表示できます。コントローラーでの従来のフォーム送信プロセスは次のとおりです:
コードは次のとおりです:
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(), )); }
設定:
コードは次のとおりです:
# app/config/config.yml framework: validation: {enable_annotations: true }
XML 形式:
コードは次のとおりです:
PHP コード形式:
// app/config/config.php $contianer->loadFromExtension('framework',array('validation'=> array( 'enable_annotations'=>true, )));
数値制約: Max、Min
日付制約: Date、DateTime、Timeコレクション制約: Choice、Collection、UniqueEntity、Language、Locale、 Country など。
ファイル制約:File、Image
その他の制約:Callback、All、Valid
独自のカスタム制約を作成することもできます。
制約の設定:
コードは次のとおりです:
# 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 形式:
コードは次のとおりです:
<?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">
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格式:
代码如下:
<?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"> male female
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格式:
代码如下:
3
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格式:
代码如下:
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格式:
代码如下:
7
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 中国語 Web サイトの他の関連記事を参照してください。