如何在Symfony2中为多重实体基于slug的路由实现一个很好的解决方案

时间:2014-11-30 17:30:16

标签: symfony routing translation slug

我想创建一个简单的包来处理带有翻译slugs的网站中的一些多语言页面。

基于translatablesluggablei18nrouting

  1. 实现了一个实体(页面),其中包含标题,内容,段塞字段+语言环境属性,如文档所述
  2. 创建了一个新的页面设置其标题和内容,然后将其翻译为$page->setTranslatableLocale('de');并再次使用德语值设置这些字段,以便表格中的数据看起来很好,它们都在那里
  3. 使用类型提示签名实现控制器:public function showAction(Page $page)
  4. 在模板中生成了一些网址:{{ path("page_show", {"slug": "test", "_locale": "en"}) }}{{ path("page_show", {"slug": "test-de", "_locale": "de"}) }},路由生成正常,看起来正确(/ en / test和/ de / test-de)
  5. 点击它们:
  6. 只有“en”翻译有效,“de”翻译失败:

      

    找不到MyBundle \ Entity \ Page对象。

    如何在检索页面时告诉Symfony或Doctrine或其他任何包使用当前语言环境?我是否必须创建ParamConverter然后将自定义DQL手动放入其中? 谢谢!

3 个答案:

答案 0 :(得分:1)

刚刚找到另一个我认为更好的解决方案,我将使用那个!

实现了一个存储库方法,并在控制器的注释中使用它:

  

@ParamConverter(“page”,class =“MyBundle:Page”,options = {“repository_method”=“findTranslatedOneBy”})

public function findTranslatedOneBy(array $criteria, array $orderBy = null)
{
    $page = $this->findOneBy($criteria, $orderBy);

    if (!is_null($page)) {
        return $page;
    }

    $qb = $this->getEntityManager()
        ->getRepository('Gedmo\Translatable\Entity\Translation')
        ->createQueryBuilder('t');

    $i = 0;
    foreach ($criteria as $name => $value) {
        $qb->orWhere('t.field = :n'. $i .' AND t.content = :v'. $i);
        $qb->setParameter('n'. $i, $name);
        $qb->setParameter('v'. $i, $value);
        $i++;
    }

    /** @var \Gedmo\Translatable\Entity\Translation[] $trs */
    $trs = $qb->groupBy('t.locale', 't.foreignKey')->getQuery()->getResult();

    return count($trs) == count($criteria) ? $this->find($trs[0]->getForeignKey()) : null;
}

它有一个缺点,就是没有针对相同翻译价值的保护......

答案 1 :(得分:0)

我找到了一个解决方案,我不确定最好,但有效。

实施了PageParamConverter:

class PageParamConverter extends DoctrineParamConverter
{
const PAGE_CLASS = 'MyBundle:Page';

public function apply(Request $request, ParamConverter $configuration)
{
    try {
        return parent::apply($request, $configuration);
    } catch (NotFoundHttpException $e) {
        $slug = $request->get('slug');
        $name = $configuration->getName();
        $class = $configuration->getClass();
        $em = $this->registry->getManagerForClass($class);

        /** @var \Gedmo\Translatable\Entity\Translation $tr */
        $tr = $em->getRepository('Gedmo\Translatable\Entity\Translation')
            ->findOneBy(['content' => $slug, 'field' => 'slug']);

        if (is_null($tr)) {
            throw new NotFoundHttpException(sprintf('%s object not found.', $class));
        }

        $page = $em->find($class, $tr->getForeignKey());

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

    return true;
}

public function supports(ParamConverter $configuration)
{
    $name = $configuration->getName();
    $class = $configuration->getClass();

    return parent::supports($configuration) && $class == self::PAGE_CLASS;
}
}

答案 2 :(得分:0)

TranslationWalker很好地在活动的语言环境中获取了实体:

class PagesRepository extends \Doctrine\ORM\EntityRepository
{
    public function findTranslatedBySlug(string $slug)
    {
        $queryBuilder = $this->createQueryBuilder("p");

        $queryBuilder
            ->where("p.slug = :slug")
            ->setParameter('slug', $slug)
        ;

        $query = $queryBuilder->getQuery();

        $query->setHint(
            Query::HINT_CUSTOM_OUTPUT_WALKER,
            'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker'
        );

        return $query->getSingleResult();
    }
}

在控制器中

 /**
 * @Entity("page", expr="repository.findTranslatedBySlug(slug)")
 * @param         $page
 *
 * @return Response
 */
public function slug(Pages $page)
{
// thanks to @Entity annotation (Sensio\Bundle\FrameworkExtraBundle\Configuration\Entity) 
// Pages entity is automatically retrieved by slug

    return $this->render('content/index.html.twig', [
        'page' => $page
    ]);
}