REST API。 IntegerType和ChoiceType字段在CustomFormType中返回“空”值

时间:2019-05-31 21:03:05

标签: rest symfony

我正在用来自FOS的Symfony和RestBundle编写Restful API。我也在使用mongodb和学说。 我创建了Document,FormType和RestRoute,当我通过Postman指向端点时,发生了一些魔术。

文档:

<?php

declare(strict_types=1);

namespace App\Document;

use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
use Symfony\Component\Validator\Constraints as Assert;

class SomeObject
{
    /**
     * @MongoDB\Id()
     *
     * @var string $id
     */
    private $id;

    /**
     * @MongoDB\Field(type="string", name="name")
     * @MongoDB\UniqueIndex()
     * @Assert\NotBlank(
     *     message="Field: name. This value should not be blank."
     * )
     * @Assert\Length(
     *     max="30"
     * )
     *
     * @var string $name
     */
    private $name;

    /**
     * @MongoDB\Field(type="integer", name="minimum")
     * @Assert\NotBlank(
     *     message="Field: minimum. This value should not be blank."
     * )
     * @Assert\GreaterThanOrEqual(1)
     *
     * @var int $minimum
     */
    private $minimum;

    /**
     * @MongoDB\Field(type="decimal", name="price")
     * @Assert\NotNull(
     *     message="Field: price. This value should not be null."
     * )
     *
     * @var float $price
     */
    private $price;

    /**
     * @MongoDB\Field(type="float", name="percent")
     * @Assert\NotNull(
     *     message="Field: percent. This value should not be null."
     * )
     *
     * @var float $percent
     */
    private $percent;

    /**
     * @MongoDB\Field(type="integer", name="level")
     * @Assert\NotBlank(
     *     message="Field: level. This value should not be blank."
     * )
     * @Assert\GreaterThanOrEqual(1)
     * @Assert\Range(
     *     min="1",
     *     max="4"
     * )
     *
     * @var int $level
     */
    private $level;

    /**
     * @MongoDB\Field(type="integer", name="active")
     * @Assert\NotNull(
     *     message="Field: active. This value should not be null."
     * )
     *
     * @var int $active
     */
    private $active;


    /**
     * SomeObject constructor.
     */
    public function __construct()
    {
        //nothing to do here...
    }

    /**
     * @return string
     */
    public function getName(): string
    {
        return (string)$this->name;
    }

    /**
     * @param string $name
     * @return SomeObject
     */
    public function setName(string $name): self
    {
        $this->name = $name;
        return $this;
    }

    /**
     * @return int
     */
    public function getMinimum(): int
    {
        return $this->minimum ?? 1;
    }

    /**
     * @param int $minimum
     * @return SomeObject
     */
    public function setMinimum(int $minimum): self
    {
        $minimum = abs($minimum);

        if (empty($minimum)) {
            $minimum = 1;
        }

        $this->minimum = $minimum;
        return $this;
    }

    /**
     * @return float
     */
    public function getPrice(): float
    {
        return (float)$this->price;
    }

    /**
     * @param float $price
     * @return SomeObject
     */
    public function setPrice(float $price): self
    {
        $this->price = abs($price);
        return $this;
    }

    /**
     * @return float
     */
    public function getPercent(): float
    {
        return (float)$this->percent;
    }

    /**
     * @param float $percent
     * @return SomeObject
     */
    public function setPercent(float $percent): self
    {
        $this->percent = abs($percent);
        return $this;
    }

    /**
     * @return int
     */
    public function getLevel(): int
    {
        return $this->level ?? 1;
    }

    /**
     * @param int $level
     * @return SomeObject
     */
    public function setLevel(int $level): self
    {
        $level = abs($level);

        if (empty($level)) {
            $level = 1;
        }

        if ($level > 4) {
            $level = 4;
        }

        $this->level = $level;
        return $this;
    }

    /**
     * @return int
     */
    public function getActive(): int
    {
        return $this->active ?? 1;
    }

    /**
     * @param int $active
     * @return SomeObject
     */
    public function setActive(int $active): self
    {
        $this->active = (int)(bool)$active;
        return $this;
    }
}

FormType:

<?php

declare(strict_types=1);

namespace App\Form;

use App\Document\SomeObject;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\MoneyType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;


/**
 * Class SomeObjectType
 * @package App\Form
 */
class SomeObjectType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add(
                'name',
                TextType::class
            )
            ->add(
                'minimum',
                IntegerType::class
            )
            ->add(
                'price',
                MoneyType::class,
                [
                    'scale' => 8,
                ])
            ->add(
                'percent',
                NumberType::class,
                [
                    'scale' => 2,
                ])
            ->add(
                'level',
                IntegerType::class
            )
            ->add(
                'active',
                ChoiceType::class,
                [
                    'choices' => [
                        'No' => 0,
                        'Yes' => 1,
                    ],
                ]);
    }

    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => SomeObject::class,
            'csrf_protection' => false,
        ]);
    }

    /**
     * @return string
     */
    public function getName()
    {
        return 'someObject';
    }
}

Controller (BaseController扩展了AbstractFOSRestController)

<?php

declare(strict_types=1);

namespace App\Controller\Api;

use App\Document\SomeObject;
use App\Document\User;
use App\Form\SomeObjectType;
use App\Service\ApiResponse;
use App\Service\Manager\SomeObjectManager;
use App\Service\MongoHelper;
use Doctrine\ODM\MongoDB\DocumentManager;
use Exception;
use FOS\RestBundle\Controller\Annotations as Rest;
use FOS\RestBundle\View\View;
use Symfony\Component\Form\Form;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;


/**
 * Class SomeObjectController
 * @package App\Controller\Api
 *
 * @Rest\Route("objects")
 */
final class SomeObjectController extends BaseController
{
    /** @var SomeObjectManager $someObjectManager */
    private $someObjectManager;

    /**
     * SomeObjectController constructor.
     * @param DocumentManager $dm
     * @param RequestStack $requestStack
     * @param UrlGeneratorInterface $router
     * @param ApiResponse $apiResponse
     * @param MongoHelper $mongoHelper
     */
    public function __construct(DocumentManager $dm, RequestStack $requestStack, UrlGeneratorInterface $router, ApiResponse $apiResponse, MongoHelper $mongoHelper, SomeObjectManager $someObjectManagerr)
    {
        parent::__construct($dm, $requestStack, $router, $apiResponse, $mongoHelper);

        $this->someObjectManager = $someObjectManager;
    }

    /**
     * @Rest\Post("/", name="post_someObject")
     *
     * @param Request $request
     * @return View
     */
    public function postSomeObjectAction(Request $request): View
    {
        /** @var User $admin */
        $admin = $this->getUser();

        //!todo: change to Symfony roles
        if (!$admin->getIsAdmin()) {
            $this->apiResponse->setMessage('User needs to have Admin privileges.');
            $this->status = Response::HTTP_UNAUTHORIZED;
        }

        if ($this->apiResponse->getStatus()) {
            /** @var SomeObject $someObject */
            $someObject = new SomeObject();

            /** @var Form $form */
            $form = $this->createForm(SomeObjectType::class, $someObject);
            $form->handleRequest($request);

            dd($form->getData());

            if ($form->isSubmitted() && $form->isValid()) {
                $data = $form->getData();

                try {
                    $this->documentManager->persist($data);
                    $this->documentManager->flush();

                    $this->apiResponse->setMessage('Object created.', false);
                    $this->apiResponse->setDataCreated($someObject->getId());
                    $this->status = Response::HTTP_CREATED;
                } catch (Exception $e) {
                    $this->apiResponse->setMessage($e->getMessage());
                    $this->status = Response::HTTP_CONFLICT;
                }
            } else {
                $this->getErrors($form);
            }
        }

        return $this->getResponse();
    }
}

JSON:

{
    "someObject": {
        "name": "Test Name",
        "minimum": 1,
        "price": 1,
        "percent": 1,
        "level": 1,
        "active": 1
    }
}

每次都会得到这个

SomeObject {#831
  -id: null
  -name: "Test Name"
  -minimum: null
  -price: 1.0
  -percent: 1.0
  -level: null
  -active: null
}

但是,如果我更改JSON例如。与此(不同于1)

{
    "someObject": {
        "name": "Test Name",
        "minimum": 2,
        "price": 1,
        "percent": 1,
        "level": 5,
        "active": 0
    }
}

我会得到:

SomeObject {#831
  -id: null
  -name: "Test Name"
  -minimum: 2
  -price: 1.0
  -percent: 1.0
  -level: 4
  -active: 0
}

如果我将IntegerType更改为NumberType,则第一个指向测试将返回正确的值。但是ChoiceType呢?

为什么在我的示例中IntegerType和ChoiceType返回null?我在做什么错了?

0 个答案:

没有答案