2016-07-10 141 views
1

我转向这个论坛,因为我无法找到有效的解决方案来解决我的问题。Symfony2:动态路由参数

我已经接管了Symfony2应用程序的管理,该应用程序处理公司内部的订单,发票......问题是没有归档功能。所以,经理要求我在应用程序中添加逐年存档功能(仅根据所选年份显示数据)。

因此,我决定以/ {year} /为参数来匹配管理员希望查看的年份的所有应用程序路由前缀,因为所有文档都过时了,所以我只需更新用于选择这些文档的请求符合所选年份。到目前为止没有问题。

routes.yml

mes_routes: 
    resource: "mes_routes.yml" 
    prefix: /{year} 
    defaults: {'year': %current_year%} 

有了这个,我创建了一个Symfony的扩展,如果没有提供一年默认填充“CURRENT_YEAR”变种在我的路线定义,与实际的一年。

MyAppExtension.php

class MyAppExtension extends Extension 
{ 
    public function load(array $configs, ContainerBuilder $container) 
    { 
     $configuration = new Configuration(); 
     $config = $this->processConfiguration($configuration, $configs); 

     $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); 
     $loader->load('services.yml'); 

     // Fill parameter with the current year 
     $container->setParameter('current_year', date("Y")); 
    } 
} 

接下来,我已经创建了一个存储了之前的路线,它的一个变种会话里面的参数,当用户显示一个新的页面RouteListener(以显示相同网页,但与未来不同的年份)

LastRouteListener.php

class LastRouteListener 
{ 
    public function onKernelRequest(GetResponseEvent $event) 
    { 
     // Don't store subrequests 
     if ($event->getRequestType() !== HttpKernel::MASTER_REQUEST) { 
      return; 
     } 

     $request = $event->getRequest(); 
     $session = $request->getSession(); 

     $routeName = $request->get('_route'); 
     $routeParams = $request->get('_route_params'); 
     if ($routeName[0] == "_") { 
      return; 
     } 
     $routeData = ['name' => $routeName, 'params' => $routeParams]; 

     // Don't store the same route twice 
     $thisRoute = $session->get('this_route', []); 
     if ($thisRoute == $routeData) { 
      return; 
     } 
     $session->set('last_route', $thisRoute); 
     $session->set('this_route', $routeData); 
    } 
} 

services.yml

myapp.last_route_event_listener: 
    class: MyApp\EventListener\LastRouteListener 
    tags: 
     - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest, priority: 30 } 

最后,我添加了一个新的控制器,通过在应用程序导航栏的下拉菜单,显示用户正在浏览当前页面,但有不同的年

ArchiveController.php

class ArchiveController extends Controller 
{ 
    public function switchYearAction(Request $request, $year) 
    { 
     $session = $request->getSession(); 
     $lastRoute = $session->get('last_route'); 
     $route = $lastRoute["name"]; 
     $routeParams = $lastRoute["params"]; 

     if (array_key_exists("year", $routeParams)) { 
      $routeParams["year"] = $year; 
      $session->set("current_year", $year); 
     } 

     return $this->redirect($this->generateUrl($route, $routeParams)); 
    } 
} 

来到这里,一切工作。如果用户选择了其他日期,应用程序将显示相同的页面,但选择新的日期。

但是,这是我的问题,如果从前一年,用户点击页面中的链接,我们回到实际的年份。很正常,因为应用程序中的Twig路径不能填充'year'路由参数,并且路由器默认提供当前年份。

所以,我的问题是:如何保持选定的年份在内存中,并将其用作路由参数?

首先,我曾想过设置局部变量“CURRENT_YEAR”当应用程序使用的switchYearAction(),但Symfony的返回一个错误(“冻结变量”)

接下来,我曾想过使用session var来存储选定的年份,但我无法访问我的扩展MyAppExtension中的会话。

可能有其中包括在更新所有的树枝路径和控制器重定向(),但它代表了一些多线编辑第三种解决方案...

或者,也许有routeEventListener ...但我不不知道如何继续。

非常感谢您。

回答

0

感谢@chrisguitarguy给出的答案:https://stackoverflow.com/a/13495302/1031898我找到了解决我的问题的方法。

实际上,我可以使用我的routeListener来完成这项工作。 我只需要实现路由器接口。

LastRouteListener.php(更新)

class LastRouteListener 
{ 
    private $router; 

    public function __construct(RouterInterface $router) 
    { 
     $this->router = $router; 
    } 

    public function onKernelRequest(GetResponseEvent $event) 
    { 
     // Don't store subrequests 
     if ($event->getRequestType() !== HttpKernel::MASTER_REQUEST) { 
      return; 
     } 

     $request = $event->getRequest(); 
     $session = $request->getSession(); 
     $context = $this->router->getContext(); 

     // If current_year exists in session, replace route parameter with it 
     if ($session->has('current_year')) { 
      $context->setParameter('year', $session->get('current_year')); 
     } 
     // Else, we set the current year by default 
     else { 
      $context->setParameter('year', date('Y')); 
     } 

     $routeName = $request->get('_route'); 
     $routeParams = $request->get('_route_params'); 
     if ($routeName[0] == "_") { 
      return; 
     } 
     $routeData = ['name' => $routeName, 'params' => $routeParams]; 

     // On ne sauvegarde pas la même route plusieurs fois 
     $thisRoute = $session->get('this_route', []); 
     if ($thisRoute == $routeData) { 
      return; 
     } 
     $session->set('last_route', $thisRoute); 
     $session->set('this_route', $routeData); 
    } 
} 

不要忘记注入@router论点services.yml

myapp.last_route_event_listener: 
    class: MyApp\EventListener\LastRouteListener 
    tags: 
     - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest, priority: 30 } 
    arguments: ['@router'] 

然后,没有必要使用 'CURRENT_YEAR'路由配置中的默认参数了。

routes.yml

mes_routes: 
    resource: "mes_routes.yml" 
    prefix: /{year} 

MyAppExtension.php

class MyAppExtension extends Extension 
{ 
    public function load(array $configs, ContainerBuilder $container) 
    { 
     $configuration = new Configuration(); 
     $config = $this->processConfiguration($configuration, $configs); 

     $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); 
     $loader->load('services.yml'); 
} 

}

0

您可以使用{{ app.session }}访问Twig中的应用程序会话。因此,像这样的可能:

{{ url('myapp.whatever', {year: app.session.get('current_year')}) }} 

既然你有一点逻辑的在你当年的东西(如果它没有在会议上退回到本年度,等设置),一个twig extension提供了一个funtion到今年的取件可能是更好的方式。快速,未经测试的例子:

<?php 
use Symfony\Component\HttpFoundation\Session\SessionInterface; 

class CurrentYearExtension extends \Twig_Extension 
{ 
    private $session; 
    private $defaultYear; 

    public function __construct(SessionInterface $session, $defaultYear) 
    { 
     $this->session = $session; 
     $this->defaultYear = $defaultYear; 
    } 

    public function getFunctions() 
    { 
     return [ 
      new \Twig_SimpleFunction('current_year', [$this, 'currentYear']), 
     ]; 
    } 

    public function currentYear() 
    { 
     return $this->session->get('current_year') ?: $this->defaultYear; 
    } 
} 

然后把它添加到您的容器中,用twig.extension标签标记它。

<service id="myapp.currentyear_extension" class="CurrentYearExtension" public="false"> 
    <argument type="service" id="session" /> 
    <argument>%current_year%</argument> 
    <tag name="twig.extension" /> 
</service> 

而且用它在你的行进路线生成:

{{ url('myapp.whatever', {year: current_year()}) }} 

如果您需要当年比其他地方树枝,然后拉一个可重用的对象了树枝延伸和使用都与延伸和其他地方。

+0

谢谢您的回答。但是不得不编辑所有Twig路径和所有重定向URL的问题仍然存在于您的解决方案中。 我正在寻找类似于可拦截路由调用的路由事件监听器,并自动将current_year var与会话var或缺省情况下与当前年份一起填充。 –

+0

看到这个答案@BenjaminLemoine http://stackoverflow.com/a/13495302/1031898应该是你想要的。 – chrisguitarguy

+0

太棒了!这个答案正是我需要的。谢谢 ! 我会在此主题上发布我的更新代码。 –