我需要使用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();
}
}
答案 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的启发,希望很有帮助。