18

我正在尝试创建动态路由,因为我创建了一个 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
4

4 回答 4

1

你看过DynamicRouter这个symfony-cmf项目吗?我认为这符合您的需求,并且正是为您的用例创建的。

您当前的实现有一些您应该知道的真正问题。首先,您必须为您创建/编辑/删除的每个路由清除路由缓存。这会无缘无故地导致竞争条件和内存峰值。

symfony 的默认实现是处理静态路由,而不是动态路由。

于 2018-01-11T21:37:22.660 回答
1

这是非常低效的,因为每条新路由都必须清除缓存,因此您将被 hdd/ssd 绑定到无用的清除缓存。另一种方法是在控制器中创建一个新方法,该方法接受 GET 上的动态页面并在 twig 中显示动态内容。

您可以创建一个服务来呈现动态页面,这将简化事情。

于 2016-04-13T11:49:44.513 回答
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'),仍然缓存为可能不再存在的路由。我还不知道这是否也只涉及树枝缓存或其他部分。

另外我不明白为什么你必须在每次页面加载时删除整个缓存?您只需在添加新路由时清除缓存。

于 2014-11-08T16:23:21.227 回答
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);
}

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

于 2016-03-24T21:45:44.627 回答