【问题标题】:Symfony2 REST API, always returns false validating the formSymfony2 REST API,总是返回 false 验证表单
【发布时间】:2014-09-17 22:34:47
【问题描述】:

我正在关注Web API REST with Symfony2 使用 Fosrestbundle 和 JMS Serializer 在 symfony2 中构建 REST API,对于 GET 路由可以完美运行,但不能使用 POST,因为当我验证表单时总是返回 false,甚至我也遵循了流程函数和最后一步在 $form->isValid() 中返回 true,所以我很困惑。

甚至不考虑validations.yml文件,所以代码很多但希望你能帮助我,因为这两天我一直在试图找出问题

config.yml

imports:
    - { resource: parameters.yml }
    - { resource: security.yml }
    - { resource: doctrine_extensions.yml }

framework:
    validation:      { enable_annotations: true }

orm:
    auto_generate_proxy_classes: "%kernel.debug%"
    auto_mapping: true

sensio_framework_extra:
    view: { annotations: false }
    router: { annotations: true }
    request: { converters: true }

fos_rest:
    param_fetcher_listener: true
    view:
        view_response_listener: 'force'
        formats:
            json: true
            xml:  true
        templating_formats:
            html: true
    format_listener:
        rules:
            - { path: ^/api, priorities: ['json', 'xml'], fallback_format: json, prefer_extension: false }
            - { path: ^/, priorities: ['html', '*/*'], fallback_format: html, prefer_extension: false }
    exception:
        codes:
            'Symfony\Component\Routing\Exception\ResourceNotFoundException': 404
            'Doctrine\ORM\OptimisticLockException': HTTP_CONFLICT
        messages:
            'Symfony\Component\Routing\Exception\ResourceNotFoundException': true
    allowed_methods_listener: true
    access_denied_listener:
        json: true
    body_listener: true
    disable_csrf_role: ROLE_API

validations.yml

# src/Acme/MyBundle/Resources/config/validation.yml
Acme\MyBundle\Entity\Vendor:
    properties:
        name:
            - NotBlank: ~
            - NotNull: ~
            - Length:
                min: 2
                max: 50
                minMessage: "Your name must be at least {{ limit }} characters length"
                maxMessage: "Your name cannot be longer than {{ limit }} characters length"
        email:
            - Email:
                message: "The email {{ value }} is not a valid email"
                checkMX: true

        password:
            - NotBlank: ~
            - NotNull: ~

供应商实体

<?php

namespace Acme\MyBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Acme\MyBundle\Model\VendorInterface;

use Gedmo\Mapping\Annotation as Gedmo;

use JMS\Serializer\Annotation\ExclusionPolicy;
use JMS\Serializer\Annotation\Exclude;
use JMS\Serializer\Annotation\Expose;
use JMS\Serializer;

/**
 * Vendor
 *
 * @ORM\Table(name="vendors")
 * @ORM\Entity()
 * @ExclusionPolicy("all")
 */
class Vendor implements VendorInterface
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     * @Expose
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=50)
     * @Expose
     */
    private $name;

    /**
     * @var string
     *
     * @ORM\Column(name="email", type="string", length=50)
     * @Expose
     */
    private $email;

    /**
     * @var string
     *
     * @ORM\Column(name="password", type="string", length=255)
     */
    private $password;

    /**
     * @var string
     *
     * @ORM\Column(name="description", type="string", length=200)
     */
    private $description;

    /**
     * @var string
     *
     * @ORM\Column(name="picture", type="string", length=50)
     * @Expose
     */
    private $picture;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="created_at", type="datetime")
     * @Gedmo\Timestampable(on="create")
     * @Expose
     */
    private $createdAt;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="updated_at", type="datetime")
     * @Gedmo\Timestampable(on="create")
     * @Expose
     */
    private $updatedAt;


    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set name
     *
     * @param string $name
     * @return Vendor
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

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

    /**
     * Set email
     *
     * @param string $email
     * @return Vendor
     */
    public function setEmail($email)
    {
        $this->email = $email;

        return $this;
    }

    /**
     * Get email
     *
     * @return string 
     */
    public function getEmail()
    {
        return $this->email;
    }

    /**
     * Set password
     *
     * @param string $password
     * @return Vendor
     */
    public function setPassword($password)
    {
        $this->password = $password;

        return $this;
    }

    /**
     * Get password
     *
     * @return string 
     */
    public function getPassword()
    {
        return $this->password;
    }

    /**
     * Set description
     *
     * @param string $description
     * @return Vendor
     */
    public function setDescription($description)
    {
        $this->description = $description;

        return $this;
    }

    /**
     * Get description
     *
     * @return string 
     */
    public function getDescription()
    {
        return $this->description;
    }

    /**
     * Set picture
     *
     * @param string $picture
     * @return Vendor
     */
    public function setPicture($picture)
    {
        $this->picture = $picture;

        return $this;
    }

    /**
     * Get picture
     *
     * @return string 
     */
    public function getPicture()
    {
        return $this->picture;
    }

    /**
     * Set createdAt
     *
     * @param \DateTime $createdAt
     * @return Vendor
     */
    public function setCreatedAt($createdAt)
    {
        $this->createdAt = $createdAt;

        return $this;
    }

    /**
     * Get createdAt
     *
     * @return \DateTime 
     */
    public function getCreatedAt()
    {
        return $this->createdAt;
    }

    /**
     * Set updatedAt
     *
     * @param \DateTime $updatedAt
     * @return Vendor
     */
    public function setUpdatedAt($updatedAt)
    {
        $this->updatedAt = $updatedAt;

        return $this;
    }

    /**
     * Get updatedAt
     *
     * @return \DateTime 
     */
    public function getUpdatedAt()
    {
        return $this->updatedAt;
    }
}

VendorController.php

<?php

namespace Acme\MyBundle\Controller;

.....


class VendorController extends FOSRestController
{
    public function postVendorAction(Request $request)
    {
        try {
            $form = new VendorType();
            $newVendor = $this->container->get('acme_mybundle.vendor.handler')->post(
                $request->request->all()
            );

            $routeOptions = array(
                'id' => $newVendor->getId(),
                '_format' => $request->get('_format')
            );

            return $this->routeRedirectView('api_get_vendor', $routeOptions, Codes::HTTP_CREATED);


        } catch (InvalidFormException $exception) {
            return $exception->getForm();
        }
    }

    protected function getOr404($id)
    {
        if (!($vendor = $this->container->get('acme_mybundle.vendor.handler')->get($id))) {
            throw new NotFoundHttpException(sprintf('The resource \'%s\' was not found.',$id));
        }

        return $vendor;
    }
}

VendorType.php

namespace Acme\MyBundle\Form;

...

class VendorType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name')
            ->add('email')
            ->add('password')
        ;
    }

    /**
     * @param OptionsResolverInterface $resolver
     */
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Acme\MyBundle\Entity\Vendor',
        ));
    }

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

VendiorHandler.php

    <?php

namespace Acme\MyBundle\Handler;

....

class VendorHandler implements VendorHandlerInterface
{
    private $om;
    private $entityClass;
    private $repository;
    private $formFactory;

    public function __construct(ObjectManager $om, $entityClass, FormFactoryInterface $formFactory)
    {

        $this->om = $om;
        $this->entityClass = $entityClass;
        $this->repository = $this->om->getRepository($this->entityClass);
        $this->formFactory = $formFactory;
    }

    /**
     * Create a new Vendor.
     *
     * @param array $parameters
     *
     * @return VendorInterface
     */
    public function post(array $parameters)
    {
        //die(var_dump("post handler"));

        $vendor = $this->createVendor();

        return $this->processForm($vendor, $parameters, 'POST');
    }


    /**
     * Processes the form.
     *
     * @param VendorInterface $vendor
     * @param array         $parameters
     * @param String        $method
     *
     * @return VendorInterface
     *
     * @throws \Acme\MyBundle\Exception\InvalidFormException
     */
    private function processForm(VendorInterface $vendor, array $parameters, $method = "PUT")
    {
        $form = $this->formFactory->create(new VendorType(), $vendor, array('method' => $method)); 

        $form->submit($parameters, 'PATCH' !== $method);

        if (!$form->isValid()) {
            $vendor = $form->getData();
            $this->om->persist($vendor);
            $this->om->flush($vendor);

            return $vendor;
        }

        throw new InvalidFormException('Invalid submitted data', $form);
    }

    private function createVendor()
    {
        return new $this->entityClass();
    }

}

【问题讨论】:

    标签: rest symfony fosrestbundle


    【解决方案1】:

    似乎有两种简单的方法可以为您的实体设置约束。

    validation.yml

    在您的Bundle 中创建一个yml 文件:

    # src/Acme/BlogBundle/Resources/config/validation.yml
    Acme\BlogBundle\Entity\Author:
        properties:
            name:
                - NotBlank: ~
    

    要使其自动运行,文件必须具有相同的名称并且位于该确切路径中,这一点很重要。然后,您启用了验证并禁用了注释。

    # app/config/config.yml
    framework:
        validation:      { enabled: true, enable_annotations: false }
    

    注释

    您不需要任何特殊文件。只需沿 Entity 的属性指定约束:

    // src/Acme/BlogBundle/Entity/Author.php
    use Symfony\Component\Validator\Constraints as Assert;
    
    class Author
    {
        /**
         * @Assert\NotBlank()
         */
        public $name;
    }
    

    记得启用注解:

    # app/config/config.yml
    framework:
        validation:      { enable_annotations: true }
    

    问题

    如果您想同时使用 validation.yml 和注释,或者您想为验证文件使用不同的名称或路径,那么您必须手动加载它们。

    查看此内容以获取更多信息:https://stackoverflow.com/a/24210501

    【讨论】:

    • 我正在使用注释.. 但请稍等一下刚刚发生了一些奇怪的事情。
    • 我已经更新了我的答案。如果你想同时使用注解和文件,你必须手动加载它。
    • 我真的不知道发生了什么......现在验证工作完美地清除了两次缓存,现在我还有另一个关于保护我的 API 的问题/问题stackoverflow.com/questions/25904542/…
    猜你喜欢
    • 2022-01-16
    • 1970-01-01
    • 2016-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-09
    • 1970-01-01
    相关资源
    最近更新 更多