7

我要做的就是:

  1. 在 yml 中定义约束

  2. 使用它来验证数组

说,一个产品数组:

$product['name'] = 'A book';
$product['date'] = '2012-09';
$product['price'] = '21.5';

怎么做?

4

3 回答 3

4

首先,您需要知道 Symfony2 验证器还没有准备好轻易做到这一点。我花了一些时间和一些 Symfony2 源代码阅读来为您的案例找到一个可行的解决方案,而我的解决方案并不是那么自然。

我创建了一个包含验证器、数组和 yaml 配置文件的类,这样你就可以做你期望的事情。此类YamlFileLoader从 Symfony 扩展以访问受保护的parseNodes方法:这并不漂亮,但这是我发现将自定义 Yaml 配置文件转换为Constraint对象数组的唯一方法。

所以我们在这里。我给你我的代码,你需要根据自己的上下文替换一些命名空间。

首先,为我们的演示创建一个控制器:

    public function indexAction()
    {

        // We create a sample validation file for the demo
        $demo = <<< EOT
name:
    - NotBlank: ~
    - MinLength: { limit: 3 }
    - MaxLength: { limit: 10 }
date:
    - NotBlank: ~
    - Regex: "/^[0-9]{4}\-[0-9]{2}$/"
price:
    - Min: 0

EOT;
        file_put_contents("/tmp/test.yml", $demo);

        // We create your array to validate
        $product = array ();
        $product['name'] = 'A book';
        $product['date'] = '2012-09';
        $product['price'] = '21.5';

        $validator = $this->get('validator');
        $service = new \Fuz\TestsBundle\Services\ArrayValidator($validator, $product, "/tmp/test.yml");
        $errors = $service->validate();

        echo '<pre>';
        var_dump($errors);
        die();

        return $this->render('FuzTestsBundle:Default:index.html.twig');
    }

然后创建一个名为 ArrayValidator.php 的类。再次,照顾命名空间。

<?php

namespace Fuz\TestsBundle\Services;

use Symfony\Component\Validator\ValidatorInterface;
use Symfony\Component\Yaml\Parser;
use Symfony\Component\Validator\Mapping\Loader\YamlFileLoader;

/**
 * This class inherits from YamlFileLoader because we need to call the
 * parseNodes() protected method.
 */
class ArrayValidator extends YamlFileLoader
{

    /* the @validator service */
    private $validator;

    /* The array to check */
    private $array;

    /* The file that contains your validation rules */
    private $validationFile;

    public function __construct(ValidatorInterface $validator, array $array = array(), $validationFile)
    {
        $this->validator = $validator;
        $this->array = $array;
        $this->validationFile = $validationFile;
    }

    /* The method that does what you want */
    public function validate()
    {
        $yaml = file_get_contents($this->validationFile);

        // We parse the yaml validation file
        $parser = new Parser();
        $parsedYaml = $parser->parse($yaml);

        // We transform this validation array to a Constraint array
        $arrayConstraints = $this->parseNodes($parsedYaml);

        // For each elements of the array, we execute the validation
        $errors = array();
        foreach ($this->array as $key => $value)
        {
            $errors[$key] = array();

            // If the array key (eg: price) has validation rules, we check the value
            if (isset($arrayConstraints[$key]))
            {
                foreach ($arrayConstraints[$key] as $constraint)
                {
                    // If there is constraint violations, we list messages
                    $violationList = $this->validator->validateValue($value, $constraint);
                    if (count($violationList) > 0)
                    {
                        foreach ($violationList as $violation)
                        {
                            $errors[$key][] = $violation->getMessage();
                        }
                    }
                }
            }
        }

        return $errors;
    }

}

最后,使用 $product 数组中的不同值对其进行测试。

默认 :

        $product = array ();
        $product['name'] = 'A book';
        $product['date'] = '2012-09';
        $product['price'] = '21.5';

将显示:

array(3) {
  ["name"]=>
  array(0) {
  }
  ["date"]=>
  array(0) {
  }
  ["price"]=>
  array(0) {
  }
}

如果我们将值更改为:

    $product = array ();
    $product['name'] = 'A very interesting book';
    $product['date'] = '2012-09-03';
    $product['price'] = '-21.5';

你会得到 :

array(3) {
  ["name"]=>
  array(1) {
    [0]=>
    string(61) "This value is too long. It should have 10 characters or less."
  }
  ["date"]=>
  array(1) {
    [0]=>
    string(24) "This value is not valid."
  }
  ["price"]=>
  array(1) {
    [0]=>
    string(31) "This value should be 0 or more."
  }
}

希望这可以帮助。

于 2012-09-30T13:27:07.257 回答
1

验证数组的方法很简单,我在silex 文档中学到了

use Symfony\Component\Validator\Constraints as Assert;

...
...

$constraint = new Assert\Collection(array(
    'Name' => new Assert\MinLength(10),
    'author' => new Assert\Collection(array(
        'first_name' => array(new Assert\NotBlank(), new Assert\MinLength(10)),
        'last_name'  => new Assert\MinLength(10),
    )),
));
$errors = $this->get('validator')->validateValue($book, $constraint);

或者您可以直接创建带有约束的表单

$form = $this->get('form.factory')->createBuilder('form',array(),array(
    'csrf_protection'       => false,
    'validation_constraint' => new Assert\Collection(array(
        'name'       => new Assert\NotBlank(array(
            'message' => 'Can\'t be null'
        )),
        'email'      => new Assert\Email(array(
            'message' => 'Invalid email'
        )),
    ))
))
->add('name', 'text')
->add('email', 'email')
->getForm();

}

此代码可以解决您的第二点,但对于第一点,我建议您编写一个自定义类,将您的 yaml 定义转换为具有实例化验证约束对象的有效约束数组,或者直接给出一个表单!

我不知道在 symfony2 中准备好做这件事的类。

我在其他没有好的数据模型的项目中做过,但是在 symfony 中你可以创建你的模型并定义与之相关的验证。

于 2012-09-28T17:51:26.537 回答
-1

在您的validation.yml 中:

Acme\DemoBundle\Entity\AcmeEntity:
    properties:
        price:
            - NotBlank: ~
            - Acme\DemoBundle\Validator\Constraints\ContainsAlphanumeric: ~

和您的 ContainsAlphanumeric:

<?php
    namespace Acme\DemoBundle\Validator\Constraints;
    use Symfony\Component\Validator\Constraint;
    use Symfony\Component\Validator\ConstraintValidator;

    class ContainsAlphanumericValidator extends ConstraintValidator
    {
        public function validate($value, Constraint $constraint)
        {
            if (!preg_match('/^[a-zA-Za0-9]+$/', $value, $matches)) {
                $this->context->addViolation($constraint->message, array('%string%' => $value));
            }
        }
    }
?>
于 2012-09-25T21:26:07.333 回答