我要做的就是:
在 yml 中定义约束
使用它来验证数组
说,一个产品数组:
$product['name'] = 'A book';
$product['date'] = '2012-09';
$product['price'] = '21.5';
怎么做?
我要做的就是:
在 yml 中定义约束
使用它来验证数组
说,一个产品数组:
$product['name'] = 'A book';
$product['date'] = '2012-09';
$product['price'] = '21.5';
怎么做?
首先,您需要知道 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."
}
}
希望这可以帮助。
验证数组的方法很简单,我在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 中你可以创建你的模型并定义与之相关的验证。
在您的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));
}
}
}
?>