2017-12-30 88 views
2

나는 자동 생성 된 ID, 문자열 및 정수의 세 필드가있는 간단한 엔티티가 있습니다. 후자의 두 가지에 대한 제약 조건을 설정했으며 정수 필드에 해당하는 제약 조건이 완벽하게 작동합니다. 범위에없는 정수를 보내거나 정수 이외의 것을 보내야하는 경우 오류가 반환됩니다.문자열의 Symfony 양식 유형 제약 조건 정수 값

그러나 문자열 필드에는 해당되지 않습니다. 정수를 보내면 양식이 올바르게 검증됩니다. 왜 그런 일이 일어나는거야?

내가 테스트를 위해 사용하고있는 코드는 다음과 같습니다

curl -H "Content-Type: application/json" -X POST -d '{"fieldOne": 9000, "fieldTwo": 5}' http://localhost:8000/foos 

FooController.php

<?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); 
    } 

} 

<?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; 
    } 
} 

답변

2

문제는 여기에 양식의 제출 방법의 타입 변환시에 발생 Symfony\Component\Form\Form::submit()

if (false === $submittedData) { 
    $submittedData = null; 
} elseif (is_scalar($submittedData)) { 
    $submittedData = (string) $submittedData; 
} 

이유는 표준 HTTP 요청이 항상 문자열로 허용하는 값을 제출와의 호환성을 유지하는 것입니다 Symfony의 Form\Types을 사용하여 값을 원하는 유형으로 변환합니다.

부모 Form은 복합어이며 각 필드는 자식 폼 요소이므로주의 문자 캐스팅이 수행됩니다. 그래서 예를 들면

:

$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()); 

결과 :이 경우 TextType에서

array:1 [▼ 
    "a" => "1" 
] 

true 

아무것도에 값을 캐스팅하지 않지만, 이미 문자열 값을 캐스트했다 제출합니다.

그러나 new Assert\Type(['type' => 'int']) 제약 조건을 사용하고 필드 유형이 Form\IntegerType이 아닌 경우 유효성 검사에 실패합니다.

반면에 Range 제약 조건은 min 및 max를 충족시키는 숫자 값만 테스트하며 숫자 문자열에서도 작동합니다.

예 : https://3v4l.org/ErQrC

$min = 1; 
$max = 10; 
$a = "5"; 
var_dump($a < $max && $a > $min); //true 

대 : 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); 
    } 
} 
+0

작성해 주신 철저한 설명과 시간에 감사드립니다. – MikelAlejoBR