[英]Symfony2: dynamic routing parameter
我转向这个论坛,因为我无法找到解决问题的有效方法。
我已经接管了一个Symfony2应用程序的管理,该应用程序处理公司内部的订单,发票......问题是它上面没有归档功能。 因此,经理要求我将“按年”存档功能添加到应用程序中(根据所选年份显示数据)。
所以,我决定将所有应用程序路由加上/ {year} /,这个参数将与经理想要查看的年份相匹配,并且由于所有文档都已过时,我只需更新Doctrine请求以选择与所选文档匹配的文档年。 到目前为止没有问题。
routes.yml
mes_routes:
resource: "mes_routes.yml"
prefix: /{year}
defaults: {'year': %current_year%}
有了这个,我创建了一个Symfony扩展,它在我的路由定义中默认填充'current_year'var,如果没有提供年份,则为实际年份。
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,当用户显示一个新页面时,它会在会话var中存储先前的路由及其参数(为了显示相同的页面但下一年有不同的年份)
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'路由参数,并且路由器默认提供当前年份。
所以,我的问题是: 如何将所选年份保留在内存中,并将其用作路由参数?
首先,我曾考虑过在应用程序使用switchYearAction()时设置局部var'current_year',但Symfony会返回错误('Frozen variable')
接下来,我曾考虑使用session var来存储所选年份,但我无法访问我的扩展MyAppExtension中的会话。
可能有第三个解决方案,包括更新所有Twig路径和Controller redirect(),但它代表了一些很多行来编辑......
或者也许使用routeEventListener ......但我不知道如何继续。
提前谢谢你。
您可以使用{{ app.session }}
访问Twig中的应用程序会话。 所以这样的事情是可能的:
{{ url('myapp.whatever', {year: app.session.get('current_year')}) }}
由于你有一些关于你当前年份的逻辑(如果它没有设置在会话回落到当前年份等),一个枝条扩展提供了获取当前年份的功能可能是一个更好的方法。 快速,未经测试的例子:
<?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
标记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()}) }}
如果您需要当前年份以外的其他地方,那么从树枝延伸部分中拉出一个可重复使用的物体,并将其与延伸部分和其他地方一起使用。
感谢@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);
}
}
不要忘记在services.yml中注入@router参数
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');
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.