Symfony 2:如何使用ParamConverter和PUT方法来获取或创建实体对象

时间:2016-07-28 14:34:55

标签: api symfony entity put

我需要使用PUT方法实现API,并且我想在我的Controller中使用ParamConverter来查找现有的实体对象,或者如果实体对象不存在,则创建一个新的实体对象。

但是,如果标准Symfony ParamConverter在存储库中找不到实体对象,则会返回异常。

你有什么想法以干净利落的方式做到这一点吗? THX。

这是我想做的一个例子(我使用FOS REST Bundle来处理PUT请求):

/**
 * @param Request $request
 * @return View
 *
 * @ParamConverter("video")
 *
 */
public function putVideosAction(Request $request, Video $video)
{
    try {
        return $this->getHandlerVideos()->put($video, $request->request->all());
    } catch (InvalidFormException $e) {
        return $e->getForm();
    }
}

2 个答案:

答案 0 :(得分:4)

这是一个解决方案。请告诉我你的想法。

在你的控制器中,我会这样做:

/**
 * @param Request $request
 * @return View
 *
 * @Rest\Put()
 * @Rest\View()
 *
 * @ParamConverter("video", converter="app_get_or_create_entity_converter", options={"repository_method" = "findOneById"})
 */
public function putVideosAction(Request $request, Video $video)
{
    try {
        $video = $this->getHandlerVideos()->put($video, $request->request->all());
        return $video;
    } catch (InvalidFormException $e) {
        return $e->getForm();
    }
}

我会写一个动态的param转换器:

    class GetOrCreateEntityConverter implements \Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter\ParamConverterInterface
{
    /**
     * @var EntityManagerInterface
     */
    protected $entityManager;

    /**
     * @var ManagerRegistry $registry Manager registry
     */
    private $registry;

    /**
     * @param ManagerRegistry $registry
     * @param EntityManagerInterface $entityManager
     */
    public function __construct(ManagerRegistry $registry, EntityManagerInterface $entityManager)
    {
        $this->registry = $registry;
        $this->entityManager = $entityManager;
    }

    public function supports(ParamConverter $configuration)
    {
        if ('app_get_or_create_entity_converter' !== $configuration->getConverter()) {
            return false;
        }

        return true;
    }

    /**
     * {@inheritdoc}
     *
     * Applies converting
     *
     * @throws \InvalidArgumentException When route attributes are missing
     * @throws NotFoundHttpException     When object not found
     */
    public function apply(Request $request, ParamConverter $configuration)
    {
        $name    = $configuration->getName();
        $options = $configuration->getOptions();
        $class   = $configuration->getClass();
        $repository = $this->entityManager->getRepository($class);

        $repositoryMethod = $options['repository_method'];

        if (!is_callable([$repository, $repositoryMethod])) {
            throw new \BadMethodCallException($repositoryMethod . ' function does not exist.', 405);
        }

        $entity = $repository->$repositoryMethod($id);

        if (null === $entity) {
            $entity = new $class;
        }

        $request->attributes->set($name, $entity);
    }
}

如果您问我为什么要在表格中找回表格,请转到https://github.com/liuggio/symfony2-rest-api-the-best-2013-way/blob/master/src/Acme/BlogBundle/Controller/PageController.php

答案 1 :(得分:4)

您必须创建自己的自定义paramConverter。

首先,这是您想要在控制器中编写的内容:

/**
 * @ParamConverter("video", class = "MyBundle:Video", converter = "my_param_converter")
 * @param Request $request
 * @param Video $video
 * @return \Symfony\Component\HttpFoundation\Response
 */
public function putVideosAction(Request $request, Video $video)
{
    // your code..
}

现在让我们写下my_param_converter

use Doctrine\Common\Persistence\ManagerRegistry;
use Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter\ParamConverterInterface;
// ...

class MyParamConverter implements ParamConverterInterface
{
    private $registry;

    /**
     * @param ManagerRegistry $registry
     */
    public function __construct(ManagerRegistry $registry = null)
    {
        $this->registry = $registry;
    }

    /**
     * Check if object supported by our paramConverter
     *
     * @param ParamConverter $configuration
     */
    public function supports(ParamConverter $configuration)
    {
        // In this case we can do nothing and just return
        if (null === $this->registry || !count($this->registry->getManagers())) {
            return false;
        }

        // Check if the class is set in configuration
        if(null === $configuration->getClass()) {
            return false;
        }

        // Get actual entity manager for class
        $em = $this->registry->getManagerForClass($configuration->getClass());

        // Check what you need to check...

        return true;
    }

    public function apply(Request $request, ParamConverter $configuration)
    {
        $videoId = $request->attributes->get('video');

        if(null === videoId) {
            throw new \InvalidArgumentException('Route attribute is missing');
        }

        // Get actual entity manager for class
        $em = $this->registry->getManagerForClass($configuration->getClass());

        $repository = $em->getRepository($configuration->getClass());

        // Try to find the video
        $video = $$repository->findOneById($videoId);

        if($video === null || !($video instanceof Video)) {
            // Here you can create your new video object
        }

        // Map video to the route's parameter
        $request->attributes->set($configuration->getName(), $video);
    }
}

新的paramConverter写完后,将其声明为服务:

services:
    app.param_converter.my_param_converter:
        class: YourBundle\Path\To\MyParamConverter
        tags:
            - { name: request.param_converter, converter: my_param_converter }
        arguments:
            - @?doctrine 

在这里你完成了!

我的回答很大程度上受到了article的启发,希望很有帮助。