簡體   English   中英

Symfony2:動態路由參數

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM