3

我对 Symfony2 还是很陌生,并且无法解决以下问题。

我在控制器中有一个主浏览操作,其中定义了以下路由(在控制器中):

/**
 * @Route("/browse")
 * @Route("/browse/{page}")
 * @Route("/browse/c/{category}/{categoryName}")
 * @Route("/browse/c/{category}/{categoryName}/{page}")
 * @Route("/browse/c/{category}/b/{brand}/{page}")
 * @Route("/browse/b/{brand}")
 * @Route("/browse/b/{brand}/{page}")
 * @Template()
 */
public function browseAction($category = 0, $page = 1, $brand = 0) {

上述路由没有问题。

问题是从树枝视图或视图助手生成 url。

我希望能够在视图助手中执行以下操作:

{{ url('browse', {'brand': '123'}) }}

这适用于 routing.yml 中的以下内容:

browse:
  pattern: /browse/b/{brand}
  defaults: { _controller: MyCoreBundle:Browse:browse } 

然后我尝试了:

browse:
  pattern: /browse/b/{brand}
  pattern: /browse/c/{category}/b/{brand}
  defaults: { _controller: MyCoreBundle:Browse:browse } 

但似乎只有最后一种模式适用,并且尝试使用以下模式会引发错误:

{{ url('browse', {'brand': '123'}) }}

我意识到我可以在 routing.yml 中创建多个具有唯一名称的单独路由。但这意味着根据将要使用的变量,我需要指定一个不同的路由名称,这会很快变得非常混乱。

我也试过:

browse:
  pattern: /browse/c/{category}/b/{brand}/{page}
  defaults: { _controller: MyCoreBundle:Browse:browse } 

和:

{{ url('browse', {'brand': '123', 'category':'', 'page': '1'}) }}

但这引发了一个错误,说类别的格式不正确..

我在这里错过了什么吗?有人可以指出我正确的方向吗?我是否可能需要创建一个可以获取所有变量并根据输入构造 URL 的树枝扩展?

4

3 回答 3

3

我最终创建了一个树枝扩展。它冗长,涉及传递 route_params 和 query_params 但它有效。

所以在我的控制器中,我需要获取路由和查询参数:

$routeParams = $this->get('request')->attributes->get('_route_params');
$queryParams = $this->get('request')->query->all();

然后通过查看:

return array('products' => $products,  'mfdFacets' => $mfdFacets, 'routeParams' => $routeParams, 'queryParams' => $queryParams);

然后在我的 browse.html.twig 中调用视图助手并传递路由和查询参数:

{% render controller("MyCoreBundle:Helper:menumfd", {'mfdFacets': mfdFacets, 'routeParams': routeParams, 'queryParams': queryParams }) %}

然后在辅助控制器中:

   /**
     * @Route("/helper/menu/module/mfd")
     * @Template()
     */
    public function menumfdAction($mfdFacets, $routeParams, $queryParams) {
    $manufacturers = $this->get("my.manufacturers")->makeNamedArray($mfdFacets);
    return array('manufacturers' => $manufacturers, 'routeParams' => $routeParams, 'queryParams' => $queryParams);
    }

然后在助手视图中:

<ul>
{% for mfd in manufacturers %}

    <li><a href="{{ mybrowseroute("brand", mfd.id, "brandName", mfd.name, routeParams, queryParams) }}">{{ mfd.name | raw }} ({{ mfd.count }})</a></li>

{% endfor %}
</ul>

然后是 Twig 扩展(服务?)类:

<?

namespace My\Bundle\ServiceBundle\Twig\Extension;

use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\HttpFoundation\Request;

class MyRouterExtension extends \Twig_Extension {

    protected $container;

    public function __construct(Container $container) {
    $this->container = $container;
    }

    public function getFunctions() {
    return array(
        'mybrowseroute' => new \Twig_Function_Method($this, 'myBrowseRoute')
    );
    }

    public function myBrowseRoute($label, $value, $label2, $value2, $routeParams, $queryParams) {


    #print_r($routeParams);
    $route_array = array("category", "categoryName", "brand", "brandName");

    ## Value 1
    if (array_key_exists($label, $routeParams)) {
        $routeParams["$label"] = $value;
    } else {
        if (in_array($label, $route_array)) {
            $routeParams["$label"] = $value;
        }
    }
    if (array_key_exists($label, $queryParams)) {
        $queryParams["$label"] = $value;
    } else {
        if (!array_key_exists($label, $route_array) && !array_key_exists($label, $routeParams)) {
            $queryParams["$label"] = $value;
        }
    }

    ## Value 2
    if (array_key_exists($label, $routeParams)) {
        $routeParams["$label2"] = $value2;
    } else {
        if (in_array($label, $route_array)) {
            $routeParams["$label2"] = $value2;
        }
    }
    if (array_key_exists($label2, $queryParams)) {
        $queryParams["$label2"] = $value2;
    } else {
        if (!array_key_exists($label2, $route_array) && !array_key_exists($label2, $routeParams)) {
            $queryParams["$label2"] = $value2;
        }
    }

    ## Generate URL string

    $base_route = $this->container->get('router')->generate("browse");
    $routeString = $base_route;


    if (array_key_exists("category", $routeParams)) {
        $routeString .= "/c/" . $routeParams["category"];
    }
    if (array_key_exists("categoryName", $routeParams)) {
        $routeString .= "/" . urlencode($routeParams["categoryName"]);
    }
    if (array_key_exists("brand", $routeParams)) {
        $routeString .= "/b/" . $routeParams["brand"];
    }
    if (array_key_exists("brandName", $routeParams)) {
        $routeString .= "/" . urlencode($routeParams["brandName"]);
    }

    # Page
    $routeString .= '/1';

    $i = 1;
    foreach($queryParams as $qLabel => $qValue){
        if($i == 1){
            $routeString .= "?$qLabel=$qValue";
        } else {
            $routeString .= "&$qLabel=$qValue";
        }
        $i++;
    }

    return $routeString;
    }

    public function getName() {
    return 'my_router';
    }

}

在 routing.yml 中需要以下内容:

browse:
      pattern: /browse
      defaults: { _controller: MyCoreBundle:Browse:browse } 

在 services.yml 中:

services:
    my.router:
    class: My\Bundle\ServiceBundle\Twig\Extension\MyRouterExtension
    arguments: ['@service_container']
    tags:
        - { name: twig.extension }

如果您只想在视图助手中传递 1 个键值对,您可以使用:

<li><a href="{{ mybrowseroute("brand", mfd.id, '', '', routeParams, queryParams) }}">{{ mfd.name | raw }} ({{ mfd.count }})</a></li>
于 2013-04-27T15:56:29.893 回答
1

调试路由,您将看到每个路由注释都有一个唯一的名称

php app/console router:debug

您可以在注解中使用 name 参数设置单个名称。看看文档

@Route("/browse/{page}", name="browse_with_page") 

为您的案例创建专用的树枝扩展可能是另一种解决方案。或者,也许这篇博客文章和提到的可能很有趣。

编辑:您可以最小化您的路线,因为页面参数可以是可选的。

@Route("/browse/c/{category}/{categoryName}")
@Route("/browse/c/{category}/{categoryName}/{page}")

是相同的并且可以被称为两种方式。

@Route("/browse/c/{category}/{categoryName}/{page}", defaults={"page" = 1})

在控制台上测试它,相同的路由应该匹配。

php app:console router:match /browse/c/1/foobar
php app:console router:match /browse/c/1/foobar/2
于 2013-04-27T08:14:39.200 回答
-2

首先,这不是动态路由。这是具有多种模式的静态路由。有明显的区别。

其次,您需要为每个模式创建一个专门定义的路由,每个模式都有唯一的名称。但是,您可以将 page 参数默认为 1 以使其成为可选参数,从而减少定义的模式数量。

第三,当您需要在 twig 中生成这些链接时,只需使用上面定义的唯一名称,以及所需的参数。

最后,在您的最后一个示例中,类别是必需的参数,您将向其传递一个空白值。这将创建“/browse/c//b/123/1”,这是 Symfony2 处理的无效路由。

于 2013-09-23T01:22:23.500 回答