2016-07-28 83 views
1

我需要使用PUT方法實現API,並且我想在我的Controller中使用ParamConverter來查找現有的實體對象,或者如果實體對象不存在,則創建一個新對象。Symfony 2:如何使用ParamConverter和PUT方法獲取或創建實體對象

但是,如果標準Symfony ParamConverter未在存儲庫中找到實體對象,則會返回一個異常。

你有什麼想法,以一個很好和乾淨的方式做到這一點?謝謝。

這裏是我想要做什麼的例子(我用FOS REST捆綁處理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(); 
    } 
} 

我會寫一個動態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); 
    } 
} 

如果你問我爲什麼在catch返回一個表格,請去看看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

謝謝你的幫助:-) –

相關問題