2016-07-28 4 views
1

Мне нужно реализовать API с помощью метода PUT, и я хотел бы использовать ParamConverter в моем контроллере для поиска существующего объекта сущности, или если объект объекта не существует, для создания нового.Symfony 2: Как использовать ParamConverter с помощью метода PUT для создания или создания объекта объекта

Однако стандартный Symfony ParamConverter возвращает исключение, если он не находит объект сущности в репозитории.

У вас есть идеи сделать это красивым и чистым способом? Спасибо.

Вот пример того, что я хотел бы сделать (я использую 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(); 
    } 
} 

ответ

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

Я хотел бы написать динамический преобразователь пар таким образом:

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

+0

Прохладный, спасибо. Мне нравится этот общий ParamConverter. Таким образом, я могу использовать его с другими объектами ;-) –

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 и надеюсь, что это поможет.

+0

Спасибо за помощь :-) –