防止Php/Symfony进行类型转换';正确';价值
我有一个Symfony(4.3)表单和一些验证规则 在我的防止Php/Symfony进行类型转换';正确';价值,php,symfony,casting,Php,Symfony,Casting,我有一个Symfony(4.3)表单和一些验证规则 在我的App\Entity\Objectif类中: /** * @ORM\Column(type="float", options={"default" : 0}) * @Assert\Type("float") */ private $budget; public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add
App\Entity\Objectif
类中:
/**
* @ORM\Column(type="float", options={"default" : 0})
* @Assert\Type("float")
*/
private $budget;
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('budget')
->add('userQuantity')
/* some other parameters */
;
}
public function generateMenu(Request $request)
{
$form = $this->createForm(ObjectifType::class);
$data = json_decode($request->getContent(),true);
$form->submit($data);
if ($form->isValid()) {
/* do some stuff with data */
} else {
return $this->json('some error message');
}
}
在我的App\Form\ObjectifType
类中:
/**
* @ORM\Column(type="float", options={"default" : 0})
* @Assert\Type("float")
*/
private $budget;
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('budget')
->add('userQuantity')
/* some other parameters */
;
}
public function generateMenu(Request $request)
{
$form = $this->createForm(ObjectifType::class);
$data = json_decode($request->getContent(),true);
$form->submit($data);
if ($form->isValid()) {
/* do some stuff with data */
} else {
return $this->json('some error message');
}
}
在我的App\Controller\ObjectifController
类中:
/**
* @ORM\Column(type="float", options={"default" : 0})
* @Assert\Type("float")
*/
private $budget;
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('budget')
->add('userQuantity')
/* some other parameters */
;
}
public function generateMenu(Request $request)
{
$form = $this->createForm(ObjectifType::class);
$data = json_decode($request->getContent(),true);
$form->submit($data);
if ($form->isValid()) {
/* do some stuff with data */
} else {
return $this->json('some error message');
}
}
我的Symfony应用程序是一个API,因此我从前端接收Json格式的数据
我的目标是确保最终用户作为$budget
发送的值为浮动类型
问题:验证过程不适用于值“true”
如果最终用户以$budget
的形式发送字符串,则该过程将正常工作,验证将失败
如果最终用户将值“true”作为$budget
发送,则该值将隐式类型转换为“1”,因此验证成功,但不会发生这种情况
在这种情况下,如何强制PHP或Symfony不隐式地将“true”转换为“1”
多谢各位
测试(可选读数) 出于测试目的,我在我的
App\Entity\Objectif
类中放置了一个Callbak验证器(),其唯一目的是在验证表单时输出$budget
属性的类型:
// App\Entity\Objectif.php
/**
* @Assert\Callback
*/
public function validate(ExecutionContextInterface $context, $payload)
{
dump('Actual value is : ' . $this->budget);
if (!is_float($this->budget)) {
dump('Value is NOT FLOAT');
$context->buildViolation('This is not a float type.')
->atPath('budget')
->addViolation();
exit;
} else {
dump('Value is FLOAT');
exit;
}
}
如果我使用API测试软件发送'true'作为'budget'键(默认值):
我总是得到这些输出:
Objectif.php on line 193:
"Actual value is : 1"
Objectif.php on line 202:
"Value is FLOAT"
我怀疑这是一个Symfony问题,因为当我使用PHP CLI时:
php > var_dump(is_float(true));
bool(false)
我得到了正确的结果
顺便说一句,“false”值会自动转换为“null”,这与我的验证目的无关,但我找不到是否必要。如果不进一步调查,我无法告诉您表单组件更改为1的位置和原因,但您可以在提交表单之前使用DataTransferObject并根据该值进行验证
class ObjectifDto
{
/**
* @Assert\Type("float")
* @var float
*/
public $budget;
public static function fromRequestData($data): self
{
$objectifDto= new self();
$objectifDto->budget = $data['budget'] ?? 0;
return $objectifDto;
}
}
在控制器中:
public function generateMenu(Request $request, ValidatorInterface $validator)
{
$data = json_decode($request->getContent(),true);
$dto = ObjectifDto::fromRequestData($data);
$errors = $validator->validate($dto);
//return errors or go on with the form or persist manually
}
在没有进一步调查的情况下,我无法告诉您表单组件更改为1的位置和原因,但您可以在提交表单之前使用DataTransferObject并根据其进行验证
class ObjectifDto
{
/**
* @Assert\Type("float")
* @var float
*/
public $budget;
public static function fromRequestData($data): self
{
$objectifDto= new self();
$objectifDto->budget = $data['budget'] ?? 0;
return $objectifDto;
}
}
在控制器中:
public function generateMenu(Request $request, ValidatorInterface $validator)
{
$data = json_decode($request->getContent(),true);
$dto = ObjectifDto::fromRequestData($data);
$errors = $validator->validate($dto);
//return errors or go on with the form or persist manually
}
因此,经过一些研究,我发现实现
FormInterface
的类的submit()
方法确实将每个标量值(即整型、浮点型、字符串或布尔型)强制转换为字符串(将“false”值转换为“null”):
这与验证过程无关(在我的例子中,验证过程是正确设置的)
这解释了为什么我将“true”值转换为“1”
有人知道为什么symfony的代码是这样设计的吗?我不明白。
我试图通过使用更常规的handleRequest()
方法来摆脱控制器中的submit()
方法。但它根本不会改变任何东西,因为handleRequest
在内部调用submit()
(请参阅HttpFoundationRequestHandler类中的handleRequest()
)。所以“true”仍然被铸造为“1”
因此,我最终使用了Chris的解决方案(参见上文)。它工作得很好。所有的功劳都归于他:
public function generateMenu(
Request $request,
ValidatorInterface $validator
)
{
$data = json_decode(
strip_tags($request->getContent()),
true);
$dto = ObjectifDto::fromRequestData($data);
$errors = $validator->validate($dto);
if (count($errors) > 0) {
$data = [];
$data['code status'] = 400;
foreach ($errors as $error) {
$data['errors'][$error->getPropertyPath()] = $error->getMessage();
}
return $this->json($data, 400);
}
// everything is fine. keep going
}
我认为不使用Symfony的表单验证过程是一个好习惯,至少在处理API和JSON时是这样
我觉得“raw”(可以这么说)与DataTransfertObject相结合,提供了更多的控制。
最重要的是,无论出于何种原因,它都不会自动转换您的值(这将彻底破坏您的验证过程).因此,经过一些研究,我发现实现
FormInterface
的类的submit()
方法确实转换了每个标量值(即整数、浮点、字符串或布尔值)要设置字符串(将“false”值设置为“null”):
这与验证过程无关(在我的例子中,验证过程是正确设置的)
这解释了为什么我将“true”值转换为“1”
有人知道为什么symfony的代码是这样设计的吗?我不明白。
我试图通过使用更常规的handleRequest()
方法来摆脱控制器中的submit()
方法。但它根本不会改变任何东西,因为handleRequest
在内部调用submit()
(请参阅HttpFoundationRequestHandler类中的handleRequest()
)。所以“true”仍然被铸造为“1”
因此,我最终使用了Chris的解决方案(参见上文)。它工作得很好。所有的功劳都归于他:
public function generateMenu(
Request $request,
ValidatorInterface $validator
)
{
$data = json_decode(
strip_tags($request->getContent()),
true);
$dto = ObjectifDto::fromRequestData($data);
$errors = $validator->validate($dto);
if (count($errors) > 0) {
$data = [];
$data['code status'] = 400;
foreach ($errors as $error) {
$data['errors'][$error->getPropertyPath()] = $error->getMessage();
}
return $this->json($data, 400);
}
// everything is fine. keep going
}
我认为不使用Symfony的表单验证过程是一个好习惯,至少在处理API和JSON时是这样
我觉得“raw”(可以这么说)与DataTransfertObject相结合,提供了更多的控制。
最重要的是,它不会出于任何原因自动广播您的值(这将彻底破坏您的验证过程).谢谢@Chris。我会尝试你的建议并给出反馈。谢谢你@Chris。我会尝试你的建议并给出反馈。