ParamConverter Symfony 中的集合

问题描述

我试图创建一个有效负载,其中一个字段是另一个对象的集合。所以我创造了这样的东西。

use DateTimeInterface;
use JMS\Serializer\Annotation as Serializer;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Constraints\Collection;

class MyPayload
{

    /**
     * @var int
     *
     * @Serializer\Type("int")
     * @Assert\Positive()
     */
    private int $someNumber;

    /**
     * @var DateTimeInterface
     *
     * @Serializer\Type("DateTime<'Y-m-d'>")
     */
    private DateTimeInterface $someDate;

    /**
     * @Assert\Collection(
     *              fields={
     *                  "label"=@Assert\NotBlank(),*                  "someNumber2"=@Assert\Positive(),*              }
     *          )
     */
    private Collection $someCollection;
}



我正在通过邮递员发送类似的内容(some_collection 中的元素数量未知,可以是 1 可以是 10):

{
    "some_number": 123,"some_date": "2021-01-01","some_collection": [
        {
            "label": "test1","some_number2": 10000
        },{
            "label": "test2","some_number2": 15000
        }
    ]
}

我的控制器看起来像这样:

    /**
     * @param MyPayload                  $myPayload
     * @param ConstraintViolationListInterface $validationErrors
     *
     * @return JsonResponse
     * @ParamConverter("myPayload",converter="fos_rest.request_body",*                                    class="App\Request\Payload\MyPayload")
     *
     */
    public function doSomething(
        ContractPayload $myPayload,ConstraintViolationListInterface $validationErrors
    ): JsonResponse {
        try {
            if (count($validationErrors) > 0) {
                throw new ValidationException($validationErrors);
            }
    ...
}

我唯一的回答是:

'contractRate' - This value should be of type array|(Traversable&ArrayAccess).

我一直在寻找解决方案,但找不到任何可行的解决方案,您知道该怎么做才能使其发挥作用吗?

解决方法

您的问题正是在于您传递给函数的类型,您传递的是 ContractPayload 而不是 MyPayload, 突然之间,与 MyPayload 类型上的集合相比,您会遇到序列化的另一个问题。

  • 首先为集合创建一个新类型,它很有用,而不是任何类型的集合

      <?php
    
      namespace App\Request\Payload;
    
    
      use JMS\Serializer\Annotation as Serializer;
      use Symfony\Component\Validator\Constraints as Assert;
    
      class SomeItem
      {
          /**
           * @Assert\NotBlank()
           * @Serializer\Type("string")
           */
          private $label;
    
          /**
           * @Assert\Positive()
           * @Serializer\Type("int")
           */
          private $someNumber2;
    
    
          /**
           * @return string
           */
          public function getLabel():string
          {
              return $this->label;
          }
    
          /**
           * @param string $label
           */
          public function setLabel(string $label)
          {
              $this->label = $label;
          }
    
          /**
           * @return int
           */
          public function getSomeNumber2():int
          {
              return $this->someNumber2;
          }
    
          /**
           * @param mixed $someNumber2
           */
          public function setSomeNumber2(int $someNumber2)
          {
              $this->someNumber2 = $someNumber2;
          }
    
    
    
      }
    
  • 对 MyPayload 稍作改动

    <?php
    
      namespace App\Request\Payload; 
      use DateTimeInterface;
      use JMS\Serializer\Annotation as Serializer;
      use Symfony\Component\Validator\Constraints as Assert;
      use Symfony\Component\Validator\Constraints\Collection;
    
      class MyPayload
      {
    
           /**
           * @var int
           *
           * @Serializer\Type("int")
           * @Assert\Positive()
           */
          private int $someNumber;
    
          /**
           * @var DateTimeInterface
           *
           * @Serializer\Type("DateTime<'Y-m-d'>")
           */
          private DateTimeInterface $someDate;
    
          /**
           * @Serializer\Type("ArrayCollection<App\Request\Payload\SomeItem>")
           */
          private Collection $someCollection;
    
    
    
          public function getSomeNumber():int
          {
              return $this->someNumber;
          }
    
    
          /**
           * @param int $someNumber
           */
          public function setSomeNumber(int $someNumber)
          {
              $this->someNumber = $someNumber;
          }
    
          /**
           * @return DateTimeInterface
           */
          public function getSomeDate():DateTimeInterface
          {
              return $this->someDate;
          }
    
          /**
           * @param DateTimeInterface $someDate
           */
          public function setSomeDate(DateTimeInterface $someDate)
          {
              $this->someDate = $someDate;
          }
    
          /**
           * @return mixed
           */
          public function getSomeCollection():Collection
          {
              return $this->someCollection;
          }
    
    
          // todo implmentation of add remove someItem  ...;)
    
    
    
      }
    
  • 上次更改,控制器 使用 App\Request\Payload\MyPayload; // ..

       /**
       * @param MyPayload                  $myPayload
       * @param ConstraintViolationListInterface $validationErrors
       *
       * @return JsonResponse
       * @ParamConverter("myPayload",converter="fos_rest.request_body",class="App\Request\Payload\MyPayload")
       *
       */
      public function doSomething(MyPayload $myPayload,ConstraintViolationListInterface $validationErrors): JsonResponse {
          try {
              if (count($validationErrors) > 0) {
                  throw new ValidationException($validationErrors);
              }
      ...
    }
    

enter image description here