Symfony2动态路由-缓存问题

19
我正在尝试创建动态路由,因为我创建了一个CMS,每个创建的页面都可以关联到一个路由。我正在使用来自此链接的示例 - http://php-and-symfony.matthiasnoback.nl/2012/01/symfony2-dynamically-add-routes/,一切正常,但是路由被缓存,因此除非清除缓存,否则下一个路由将无法工作。在这个阶段,是否可能仅删除路由缓存,或者是否有其他替代方案?我不想在每个页面加载时都删除整个缓存目录,因为那没有意义。以下是示例代码:
namespace Acme\RoutingBundle\Routing;

use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\Config\Loader\LoaderResolver;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;

class ExtraLoader implements LoaderInterface
{
private $loaded = false;

public function load($resource, $type = null)
{
    if (true === $this->loaded) {
        throw new \RuntimeException('Do not add this loader twice');
    }

    $routes = new RouteCollection();

    $pattern = '/extra';
    $defaults = array(
        '_controller' => 'AcmeRoutingBundle:Demo:extraRoute',
    );

    $route = new Route($pattern, $defaults);
    $routes->add('extraRoute', $route);

    return $routes;
}

public function supports($resource, $type = null)
{
    return 'extra' === $type;
}

public function getResolver()
{
}

public function setResolver(LoaderResolver $resolver)
{
    // irrelevant to us, since we don't need a resolver
}
}

然后我为ExtraLoader制作了一个服务:
<!-- in /src/Acme/RoutingBundle/Resources/config/services.xml -->
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/dic/services       http://symfony.com/schema/dic/services/services-1.0.xsd">

    <services>
        <service id="acme.routing_loader" class="Acme\RoutingBundle\Routing\ExtraLoader">
            <tag name="routing.loader"></tag>
        </service>
    </services>
</container>

我们所需要的最后一件事情,就是在/app/config/routing.yml中增加几行额外的代码。
AcmeRoutingBundle:
    resource: .
    type: extra

1+ 对于有趣的问题 - Markus Kottländer
4个回答

1
这样做非常低效,因为每次新建路由都需要清除缓存,这样你就会被无用的清除缓存所限制。另一种选择是在控制器中创建一个接受动态页面的新方法,并在twig中显示动态内容。
你可以创建一个渲染动态页面的服务,这将简化事情。

1
你是否看过symfony-cmf项目中的DynamicRouter?我认为这符合你的需求,而且正是为你的用例而创建的。
你当前的实现存在一些问题,你应该知道。首先,你必须清除路由缓存,每次创建/编辑/删除路由。这会导致竞态条件和不必要的内存峰值。
Symfony的默认实现是处理静态路由,而不是动态路由。

0

我进行了一些研究和尝试,发现您可以删除以下文件:

对于开发人员:

/app/cache/dev/appDevUrlGenerator.php
/app/cache/dev/appDevUrlGenerator.php.meta
/app/cache/dev/appDevUrlMatcher.php
/app/cache/dev/appDevUrlMatcher.php.meta

针对生产环境:

/app/cache/prod/appProdUrlGenerator.php
/app/cache/prod/appProdUrlMatcher.php

这只有一个小缺陷。我正在使用当前路由来确定菜单项是否处于活动状态:

{% set currentPath = path(app.request.attributes.get('_route'), app.request.attributes.get('_route_params')) %}

...

<li{% if currentPath == path('mybundle_default_index') %} class="active"{% endif %}>

在这种情况下,app.request.attributes.get('_route') 仍然被缓存为可能不再存在的路由。我还不知道这是否只涉及到了 Twig 缓存或其他部分。
此外,我不明白为什么每次页面加载都必须删除整个缓存?只有在添加新路由时才需要清除缓存。

0

我已经在我的CMS中解决了这个问题。

起初,我覆盖了基本的Router类:

parameters:
    router.class: Name\Of\Your\Router

并将其扩展:

use Symfony\Bundle\FrameworkBundle\Routing\Router as BaseRouter;

class Router extends BaseRouter
{
    public function clearCache($cache_dir, $environment, $warm_up)
    {
        $cache_dir  .= '/'. $environment;
        $environment = ucfirst($environment);

        @unlink($cache_dir .'/app'. $environment .'UrlMatcher.php');
        @unlink($cache_dir .'/app'. $environment .'UrlGenerator.php');

        if ($warm_up) {
            $this->matcher   = null;
            $this->generator = null;

            $this->warmUp($cache_dir);
        }
    }
}

其次,我创建了一个名为CacheService的服务:
cache_service:
    class: Name\Of\Your\CacheService
    arguments:
        - @router
        - %kernel.environment%
        - %kernel.root_dir%/cache

并添加了以下方法:

public function clearCache($environment = null)
{
    if (null === $environment) {
        $environment = $this->environment;
    }

    $this->router->clearCache($this->cache_dir, $environment, $this->environment == $environment);
}

现在,当我需要清除当前或特定环境的缓存时,我就可以调用这个方法。


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