Symfony @ParamConverter:如果占位符不包含点,则排除使用

4

我有这个控制器:

/**
 * {@inheritdoc}
 *
 * @Route("entity/{domain_host}")
 * @ParamConverter("entity", class="AppBundle:Entity", options={
 *     "repository_method" = "findOneByDomainHost",
 *     "mapping": {"domain_host": "domainHost"},
 *     "map_method_signature" = true
 * })
 */
class EntityController extends Controller
{
...
}

这样,一个URL如http://example.com/entity/another-example.com会被匹配并对应的another-example.com实体会被解析并传递给控制器。

现在,这个实体也有一个ID。

我想拦截一个URL如http://example.com/entity/12345并将其重定向到http://example.com/entity/another-example.com

为了做到这一点,我在EntityController中创建了另一个方法:

/**
 * {@inheritdoc}
 *
 * @Route("entity/{domain_host}")
 * @ParamConverter("store", class="AppBundle:Entity", options={
 *     "repository_method" = "findOneByDomainHost",
 *     "mapping": {"domain_host": "domainHost"},
 *     "map_method_signature" = true
 * })
 */
class EntityController extends Controller
{
    public function redirectIdToDomainAction(Request $request)
    {
        die(dump($request));
        // Following will be the redirect logic
    }
}

在我的 routing.yml 文件的顶部:

entity_id_to_domain:
    path: /entity/{id}
    defaults: { _controller: AppBundle:Entity:redirectIdToDomain }
    requirements:
        id: ^[^.]*$
    methods: [GET]

实际上,如果占位符不包含句点(句点是区分标志),则调用redirectIdToDomain操作:如果占位符有句点,传递一个域,如果没有句点,则占位符可能表示一个通过uts ID的实体,我必须进行重定向。

问题在于,控制器类EntityController使用了@ParamConverter,因此占位符始终被解释为域,结果是我得到了一个AppBundle:Entity object not found.的异常。

那么,是否有一种方法只在占位符有句点时应用@ParamConverter?或者,我可以使用哪些其他方法来使redirectToIdAction正常工作而不抛出Not found异常?


更好地实现重定向监听器和/或自定义参数转换器 - Matteo
1
为什么不将ParamConverter放在只有它需要的一个操作上,而不是整个类上,或者将重定向操作移动到该操作之外呢? - Gerry
1
“paramconverter”被更多的操作(约7个)所需。我考虑过将重定向操作移出类的可能性,但我希望还有其他选择,所以在这里问了一下...我打算创建另一个控制器,然后在其中放置重定向操作,而不是创建自定义参数转换器... - Aerendir
1个回答

1

自定义ParamConverter可能会起作用,但如果您不想创建一个,您将不得不为ID和域名使用不同的路由。

解决方案1

由于您的路由是在整个类上完成而不是在操作本身上完成的,我担心您将不得不将重定向操作移动到另一个控制器类中。

之后,您可以使用要求有选择地匹配ID和域名。

/**
 *@Route(
    "entity/{domain_host}",
     name="entity_domain",
     requirements={"domain_host": "^(?=.*[\w])(?=.*[.]).+$"}
 *)
 *@ParamConverter(...)
 */
someActionOnDomainAction()
{
//...
}


/**
 *@Route(
    "entity/{id}",
     name="entity_domain",
     requirements={"id": "^[\d]$"}
 *)
 */
redirectIdToDomainAction()
{
//...
}

解决方案2

或者,您可以将存储库方法findOneByDomainHost()更改为类似于findOneByDomainHostOrID()的内容,并使其匹配域名和数字ID。

这样,您就可以摆脱Object Not Found错误,并始终获取实体的域名,在同一控制器操作中执行重定向。

以下是一个示例:

/**
 * Class EntityController
 *
 * @Route("/entity/{domain_host}", name="domain_host")
 * @ParamConverter("domain_host", class="AppBundle:Entity", options={
 *     "repository_method" = "findOneByHostOrID"
 * })
 */
class EntityController extends Controller
{
    /**
     * @Route("/", name="show_domain_host")
     * @param Entity $domain_host
     */
    public function domain_hostAction(Entity $domain_host, Request $request)
    {
        $id = $domain_host->getId();
        $host = $domain_host->getHost();

        // Get the unconverted route parameter.
        $parameter = $request->attributes->get('_route_params')['domain_host'];

        if ($parameter == $domain_host->getId()){
            // If the route parameter matches the ID,
            // redirect to the same route using the domain host.
            $url = $this->generateUrl('show_mail', ['mail' => $lib]);
            return $this->redirect($url, 301);
        }

        return new Response("<html><body>$id $host</body></html>");
    }
}

而仓库类:

class EntityRepository extends EntityRepository
{
    public function findOneByHostOrID($domain_host)
    {
        if (preg_match("[\\d]",$domain_host)) {
            return $this->findOneById($domain_host);
        } else {
            return $this->findOneByHost($domain_host);
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接