我有一个包含三个字段的简单实体:自动生成的ID,字符串和整数。我已经为后两个设置了约束,并且对应于整数字段的约束完美地起作用。如果我发送的数据不在范围内,或者我应该发送除整数之外的任何内容,则会返回错误。
然而,字符串字段不会发生这种情况。如果我发送一个整数,表单验证正确。为什么会这样?
我用于测试的代码是:
<?php
namespace AppBundle\Controller;
use AppBundle\Entity\FooBar;
use AppBundle\Form\FooBarType;
use FOS\RestBundle\Controller\FOSRestController;
use FOS\RestBundle\Request\ParamFetcher;
use FOS\RestBundle\View\View;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class FooController extends FOSRestController
{
public function getFooAction()
{
$view = new View();
$data = array(
'foo' => 'bar'
);
$view->setStatusCode(Response::HTTP_OK);
$view->setData($data);
return $view;
}
public function postFooAction(Request $request)
{
$foobar = new FooBar();
$form = $this->createForm(FooBarType::class, $foobar);
$data = json_decode($request->getContent(), true);
$form->submit($data);
if ($form->isValid()) {
//$foobar = $form->getData();
$response = new Response('All good');
$response->setStatusCode(Response::HTTP_OK);
return $response;
}
return View::create($form, Response::HTTP_BAD_REQUEST);
}
}
FooController.php
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class FooBarType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('fieldOne')
->add('fieldTwo')
;
}
}
FooBarType.php
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* FooBar
*
* @ORM\Table(name="foo_bar")
* @ORM\Entity(repositoryClass="AppBundle\Repository\FooBarRepository")
*/
class FooBar
{
/**
* @var int
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @Assert\Type("string")
* @ORM\Column(name="field_one", type="string", length=255)
*/
private $fieldOne;
/**
* @var int
*
* @Assert\Range(
* min = 1,
* max = 10,
* minMessage = "You must be at least {{ limit }}cm tall to enter",
* maxMessage = "You cannot be taller than {{ limit }}cm to enter"
* )
* @ORM\Column(name="field_two", type="int")
*/
private $fieldTwo;
/**
* Get id
*
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* Set fieldOne
*
* @param string $fieldOne
*
* @return FooBar
*/
public function setFieldOne($fieldOne)
{
$this->fieldOne = $fieldOne;
return $this;
}
/**
* Get fieldOne
*
* @return string
*/
public function getFieldOne()
{
return $this->fieldOne;
}
/**
* Set fieldTwo
*
* @param int $fieldTwo
*
* @return FooBar
*/
public function setFieldTwo($fieldTwo)
{
$this->fieldTwo = $fieldTwo;
return $this;
}
/**
* Get fieldOne
*
* @return string
*/
public function getFieldTwo()
{
return $this->fieldTwo;
}
}
FooBar实体
{{1}}
答案 0 :(得分:2)
在此处对表单提交方法进行类型转换时会出现此问题:Symfony\Component\Form\Form::submit()
if (false === $submittedData) {
$submittedData = null;
} elseif (is_scalar($submittedData)) {
$submittedData = (string) $submittedData;
}
原因是保持与标准HTTP请求的兼容性,始终将值作为字符串提交,并允许Symfony的Form\Types将值转换为所需类型。
请记住,父表单是复合表单,每个字段都是子表单元素,这会导致执行类型转换。
例如:
$builder->add('a', Form\TextType::class, [
'constraints' => [
new Assert\Type(['type' => 'string'])
]
]);
$form = $builder->getForm();
$form->submit(['a' => 1]);
dump($form->getData);
dump($form->isValid());
结果:
array:1 [▼
"a" => "1"
]
true
在这种情况下,TextType
不会将值转换为任何值,但提交已经将值转换为字符串。
但是,如果使用new Assert\Type(['type' => 'int'])
约束,并且字段类型不是Form\IntegerType
,则验证失败。
而Range约束仅测试满足min和max的数值,这也适用于数字字符串。
$min = 1;
$max = 10;
$a = "5";
var_dump($a < $max && $a > $min); //true
Versus:https://3v4l.org/8D3N0
$min = 1;
$max = 10;
$a = "c";
var_dump($a < $max && $a > $min); //false
要解决此问题,您可以创建自己的constraint expression,假设您不需要数字值。
class FooBar
{
//...
/**
* @var string
*
* @Assert\Type("string")
* @Assert\Expression("this.isNotNumeric()")
* @ORM\Column(name="field_one", type="string", length=255)
*/
private $fieldOne;
/**
* @return bool
*/
public function isNotNumeric()
{
return !is_numeric($this->fieldOne);
}
}