2013-02-25 16 views
13

Ich versuche, dynamische Routen zu erstellen, da ich ein CMS erstellt habe, bei dem jede erstellte Seite einer Route zugeordnet werden kann. Ich benutze das Beispiel von diesem Link - http://php-and-symfony.matthiasnoback.nl/2012/01/symfony2-dynamically-add-routes/ und alles funktioniert gut, aber das Routing ist im Cache, daher wird eine Route funktionieren, aber dann die nächste wird nicht, wenn ich den Cache löschen. Ist es möglich, nur den Routing-Cache zu diesem Zeitpunkt zu entfernen, oder gibt es eine andere Alternative? Ich möchte nicht das gesamte Cache-Verzeichnis bei jedem Laden der Seite entfernen, da dies keinen Sinn ergibt. Hier ist der Beispielcode:Symfony2 dynamisches Routing - Caching Problem

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 
} 
} 

Dann habe ich einen Dienst für die ExtraLoader gemacht:

<!-- 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> 

Das letzte, was wir brauchen, ist ein paar zusätzliche Zeilen in/app/config/Routing. yml:

AcmeRoutingBundle: 
    resource: . 
    type: extra 
+0

1+ für interessante Frage –

Antwort

0

ich recherchiert und versucht, ein bisschen aus und ich fand heraus, dass Sie nur die folgenden Dateien löschen:

für Entwickler:

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

für prod:

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

Es gibt nur einen Minior Kehrseite der Medaille. Ich verwende die aktuelle Route zu bestimmen, ob ein Menüpunkt aktiv ist oder nicht:

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

... 

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

In diesem Fall app.request.attributes.get('_route') noch als Weg zwischengespeichert wird, die nicht mehr existieren könnte. Ich weiß noch nicht, ob das nur den Zweigcache oder andere Teile betrifft.

Auch ich verstehe nicht, warum Sie den gesamten Cache bei jedem Laden der Seite löschen müssten? Sie müssen den Cache nur löschen, wenn neue Routen hinzugefügt werden.

0

Ich habe dieses Problem in meinem eigenen CMS gelöst.

Zunächst überwog ich die Basis Router Klasse:

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

und es erweitert:

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); 
     } 
    } 
} 

Zweitens habe ich einen Dienst CacheService:

cache_service: 
    class: Name\Of\Your\CacheService 
    arguments: 
     - @router 
     - %kernel.environment% 
     - %kernel.root_dir%/cache 

und addierten die folgenden Verfahren :

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

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

So jetzt kann ich diese Methode aufrufen, wenn ich Cache für aktuelle oder spezifische Umgebung löschen muss.

0

Dies ist ziemlich ineffizient, weil Sie mit jeder neuen Route den Cache löschen müssen, so dass Sie durch die Verwendung von HDD/SSD mit nutzlosem Cache gebunden sind. Die Alternative besteht darin, eine neue Methode im Controller zu erstellen, die eine dynamische Seite in GET akzeptiert und den dynamischen Inhalt in Zweig anzeigt.

Sie können einen Dienst erstellen, um die dynamischen Seiten zu rendern, was die Dinge vereinfachen wird.

0

Haben Sie sich die DynamicRouter aus dem Projekt symfony-cmf angesehen? Ich denke, das passt zu Ihren Bedürfnissen und ist genau auf Ihren Anwendungsfall zugeschnitten.

Ihre aktuelle Implementierung hat einige wirklich Probleme, über die Sie wissen sollten. Zunächst müssen Sie den Routing-Cache für jede Route löschen, die Sie erstellen/bearbeiten/löschen. Dies führt ohne Grund zu Wettlaufbedingungen und Speicherspitzen.

Die Standardimplementierung von Symfony ist statische Routen, nicht dynamische Routen.