如何在Symfony中使用多个路由和多个param转换器

时间:2018-05-18 16:17:29

标签: symfony routes

是否可以将 ParamConverter 与不同的类一起使用,具体取决于被调用的路由? 我们假设我有一个父类Food,有两个孩子Fruit班级和Vegetable班级。

我希望能够做到这样的事情:

    /**
     *
     * @Route("fruit/{id}", name="fruit_show")
     * @ParamConverter("food", class="AppBundle:Fruit")
     * @Route("vegetable/{id}", name="vegetable_show")
     * @ParamConverter("food", class="AppBundle:Vegetable")
     */
     public function showAction(Food $food)
     { ... }

2 个答案:

答案 0 :(得分:4)

似乎无法完全按照自己的意愿行事。但是有可能通过两个简单的包装器动作来获得所需的东西。您甚至不需要明确的@ParamConverter注释。 E.g。

/**
 *
 * @Route("fruit/{id}", name="fruit_show")
 */
 public function showFruitAction(Fruit $fruit)
 { 
    return $this->showAction($fruit)
 }

/**
 *
 * @Route("vegetable/{id}", name="vegetable_show")
 */
 public function showVegetableAction(Food $food)
 { 
    return $this->showAction($vegetable)
 }


public function showAction (Food $food)
{ ... }

答案 1 :(得分:2)

我在这里发现的问题是ParamConverter使用注释中的最后一项。如果它与fruit_show路由匹配,则$ food变量是AppBundle:Vegetable类的实例。如果它与vegetable_show路线匹配,则相同。

class FoodController
{
    /**
     * @Route("/items/fruits/{id}", methods={"GET"}, name="fruits_show")
     * @ParamConverter("food", class="AppBundle:Fruit")
     * @Route("/items/vegetables/{id}", methods={"GET"}, name="vegetables_show")
     * @ParamConverter("food", class="AppBundle:Vegetable")
     */
    public function foodAction(Request $request, $food)
    {
        //
    }
}
  

您可以使用的一种解决方法是编写自己的ParamConverter:

use Doctrine\ORM\EntityManagerInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter\ParamConverterInterface;
use Symfony\Component\HttpFoundation\Request;

class FoodConverter implements ParamConverterInterface
{
    protected $entityManager;

    public function __construct(EntityManagerInterface $entityManager)
    {
        $this->entityManager = $entityManager;
    }

    public function apply(Request $request, ParamConverter $configuration)
    {
        $id = $request->get('id');
        $route = $request->get('_route');
        $class = $configuration->getOptions()[$route];

        $request->attributes->set($configuration->getName(), $this->entityManager->getRepository($class)->findOneById($id));

        return true;
    }

    public function supports(ParamConverter $configuration)
    {
        return $configuration->getName() === 'food';
    }
}

将其添加到您的服务中:

services:
    food_converter:
        class: App\SupportClasses\FoodConverter
        arguments: ['@doctrine.orm.entity_manager']
        tags:
            - {name: request.param_converter, priority: -2, converter: food_converter}

像这样使用它:

class FoodController
{

    /**
     * @Route("/items/fruits/{id}", methods={"GET"}, name="fruits_show")
     * @Route("/items/vegetables/{id}", methods={"GET"}, name="vegetables_show")
     * @ParamConverter("food", converter = "food_converter" class="App:Food", options={"fruits_show" = "App:Fruit", "vegetables_show" = "App:Vegetable"})
     */
    public function foodAction(Request $request, $food)
    {
        var_dump($food);
        exit();
    }
}