Skip to content
This repository was archived by the owner on Sep 16, 2021. It is now read-only.

[WIP] Support for handling defunct routes #81

Merged
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 43 additions & 2 deletions AutoRoute/Adapter/AdapterInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
namespace Symfony\Cmf\Bundle\RoutingAutoBundle\AutoRoute\Adapter;

use Symfony\Cmf\Component\Routing\RouteObjectInterface;
use Symfony\Cmf\Bundle\RoutingAutoBundle\Model\AutoRouteInterface;
use Symfony\Cmf\Bundle\RoutingAutoBundle\AutoRoute\UrlContext;

/**
* Adapters will (eventually) abstract all database operations
Expand Down Expand Up @@ -42,10 +44,11 @@ public function translateObject($object, $locale);
*
* @param string $path
* @param object $document
* @param string $tag
*
* @return Route new route document
* @return AutoRouteInterface new route document
*/
public function createRoute($path, $document);
public function createRoute($path, $document, $tag);

/**
* Return the canonical name for the given class, this is
Expand All @@ -72,4 +75,42 @@ public function compareRouteContent(RouteObjectInterface $route, $contentObject)
* @return null|Symfony\Cmf\Component\Routing\RouteObjectInterface
*/
public function findRouteForUrl($url);

/**
* Generate a tag which can be used to identify this route from
* other routes as required.
*
* @param UrlContext $urlContext
*/
public function generateAutoRouteTag(UrlContext $urlContext);

/**
* Migrate the descendant path elements from one route to another.
*
* e.g. in an RDBMS with a routes:
*
* /my-blog
* /my-blog/posts/post1
* /my-blog/posts/post2
* /my-new-blog
*
* We want to migrate the children of "my-blog" to "my-new-blog" so that
* we have:
*
* /my-blog
* /my-new-blog
* /my-new-blog/posts/post1
* /my-new-blog/posts/post2
*
* @param AutoRouteInterface $srcAutoRoute
* @param AutoRouteInterface $destAutoRoute
*/
public function migrateAutoRouteChildren(AutoRouteInterface $srcAutoRoute, AutoRouteInterface $destAutoRoute);

/**
* Remove the given auto route
*
* @param AutoRouteInterface $autoRoute
*/
public function removeAutoRoute(AutoRouteInterface $autoRoute);
}
84 changes: 71 additions & 13 deletions AutoRoute/Adapter/PhpcrOdmAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,34 @@
use PHPCR\Util\NodeHelper;
use Symfony\Cmf\Bundle\RoutingAutoBundle\Model\AutoRoute;
use PHPCR\InvalidItemStateException;
use Symfony\Cmf\Bundle\RoutingAutoBundle\Model\AutoRouteInterface;
use Symfony\Cmf\Bundle\RoutingAutoBundle\AutoRoute\UrlContext;

/**
* Abstraction adapter for PHPCR-ODM
* Adapter for PHPCR-ODM
*
* This class will eventually encapsulate all of the PHPCR-ODM
* specific logic to enable support for multiple backends.
* @author Daniel Leech <[email protected]>
*/
class PhpcrOdmAdapter implements AdapterInterface
{
const TAG_NO_MULTILANG = 'no-multilang';

protected $dm;
protected $baseRoutePath;

/**
* @param DocumentManager $dm
* @param string $routeBasePath Route path for all routes
*/
public function __construct(DocumentManager $dm, $routeBasePath)
{
$this->dm = $dm;
$this->baseRoutePath = $routeBasePath;
}

/**
* {@inheritDoc}
*/
public function getLocales($contentDocument)
{
if ($this->dm->isDocumentTranslatable($contentDocument)) {
Expand All @@ -45,6 +55,9 @@ public function getLocales($contentDocument)
return array();
}

/**
* {@inheritDoc}
*/
public function translateObject($contentDocument, $locale)
{
$meta = $this->dm->getMetadataFactory()->getMetadataFor(get_class($contentDocument));
Expand All @@ -53,25 +66,61 @@ public function translateObject($contentDocument, $locale)
return $contentDocument;
}

public function removeDefunctRoute($route, $canonicalRoute)
/**
* {@inheritDoc}
*/
public function generateAutoRouteTag(UrlContext $urlContext)
{
return $urlContext->getLocale() ? : self::TAG_NO_MULTILANG;
}

/**
* {@inheritDoc}
*/
public function removeDefunctRoute($route, $newRoute)
{
$session = $this->dm->getPhpcrSession();
try {
$node = $this->dm->getNodeForDocument($route);
$canonicalNode = $this->dm->getNodeForDocument($canonicalRoute);
$nodeChildren = $node->getNodes();
foreach ($nodeChildren as $nodeChild) {
$session->move($nodeChild->getPath(), $canonicalNode->getPath() . '/' . $nodeChild->getName());
}
$session->removeItem($node->getPath());
$newNode = $this->dm->getNodeForDocument($newRoute);
} catch (InvalidItemStateException $e) {
// nothing ..
}

$session->save();
}

public function createRoute($url, $contentDocument)
/**
* {@inheritDoc}
*/
public function migrateAutoRouteChildren(AutoRouteInterface $srcAutoRoute, AutoRouteInterface $destAutoRoute)
{
$session = $this->dm->getPhpcrSession();
$srcAutoRouteNode = $this->dm->getNodeForDocument($srcAutoRoute);
$destAutoRouteNode = $this->dm->getNodeForDocument($destAutoRoute);

$srcAutoRouteChildren = $srcAutoRouteNode->getNodes();

foreach ($srcAutoRouteChildren as $srcAutoRouteChild) {
$session->move($srcAutoRouteChild->getPath(), $destAutoRouteNode->getPath() . '/' . $srcAutoRouteChild->getName());
}
}

/**
* {@inheritDoc}
*/
public function removeAutoRoute(AutoRouteInterface $autoRoute)
{
$session = $this->dm->getPhpcrSession();
$node = $this->dm->getNodeForDocument($autoRoute);
$session->removeItem($node->getPath());
$session->save();
}

/**
* {@inheritDoc}
*/
public function createRoute($url, $contentDocument, $autoRouteTag)
{
$path = $this->baseRoutePath;
$parentDocument = $this->dm->find(null, $path);
Expand All @@ -95,15 +144,22 @@ public function createRoute($url, $contentDocument)
$headRoute->setContent($contentDocument);
$headRoute->setName($headName);
$headRoute->setParent($document);
$headRoute->setAutoRouteTag($autoRouteTag);

return $headRoute;
}

/**
* {@inheritDoc}
*/
public function getRealClassName($className)
{
return ClassUtils::getRealClass($className);
}

/**
* {@inheritDoc}
*/
public function compareRouteContent(RouteObjectInterface $route, $contentDocument)
{
if ($route->getContent() === $contentDocument) {
Expand All @@ -113,9 +169,12 @@ public function compareRouteContent(RouteObjectInterface $route, $contentDocumen
return false;
}

/**
* {@inheritDoc}
*/
public function getReferringRoutes($contentDocument)
{
return $this->dm->getReferrers($contentDocument, null, null, null, 'Symfony\Cmf\Component\Routing\RouteObjectInterface');
return $this->dm->getReferrers($contentDocument, null, null, null, 'Symfony\Cmf\Bundle\RoutingAutoBundle\Model\AutoRouteInterface');
}

/**
Expand All @@ -132,4 +191,3 @@ private function getPathFromUrl($url)
return $this->baseRoutePath . $url;
}
}

39 changes: 24 additions & 15 deletions AutoRoute/AutoRouteManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class AutoRouteManager
protected $urlGenerator;
protected $defunctRouteHandler;

private $pendingOperationStacks = array();
private $pendingUrlContextStacks = array();

/**
* @param AdapterInterface $adapter Database adapter
Expand All @@ -48,48 +48,57 @@ public function __construct(
/**
* @param object $document
*/
public function buildOperationStack(OperationStack $operationStack)
public function buildUrlContextStack(UrlContextStack $urlContextStack)
{
$this->getUrlContextsForDocument($operationStack);
$this->getUrlContextsForDocument($urlContextStack);

foreach ($operationStack->getUrlContexts() as $urlContext) {
foreach ($urlContextStack->getUrlContexts() as $urlContext) {
$existingRoute = $this->adapter->findRouteForUrl($urlContext->getUrl());

$route = null;

if ($existingRoute) {
$isSameContent = $this->adapter->compareRouteContent($existingRoute, $urlContext->getSubjectObject());

if ($isSameContent) {
continue;
$route = $existingRoute;
} else {
$url = $urlContext->getUrl();
$url = $this->urlGenerator->resolveConflict($url);
$urlContext->setUrl($url);
}
}

$url = $this->urlGenerator->resolveConflict($urlContext->getUrl());
if (!$route) {
$routeTag = $this->adapter->generateAutoRouteTag($urlContext);
$route = $this->adapter->createRoute($urlContext->getUrl(), $urlContext->getSubjectObject(), $routeTag);
}

$newRoute = $this->adapter->createRoute($urlContext->getUrl(), $urlContext->getSubjectObject());
$urlContext->setNewRoute($newRoute);
$urlContext->setRoute($route);
}

$this->pendingOperationStacks[] = $operationStack;
$this->pendingUrlContextStacks[] = $urlContextStack;
}

public function handleDefunctRoutes()
{
while ($operationStack = array_pop($this->pendingOperationStacks)) {
$this->defunctRouteHandler->handleDefunctRoutes($operationStack);
while ($urlContextStack = array_pop($this->pendingUrlContextStacks)) {
$this->defunctRouteHandler->handleDefunctRoutes($urlContextStack);
}
}

private function getUrlContextsForDocument(OperationStack $operationStack)
private function getUrlContextsForDocument(UrlContextStack $urlContextStack)
{
$locales = $this->adapter->getLocales($operationStack->getSubjectObject()) ? : array(null);
$locales = $this->adapter->getLocales($urlContextStack->getSubjectObject()) ? : array(null);

foreach ($locales as $locale) {
if (null !== $locale) {
$this->adapter->translateObject($operationStack->getSubjectObject(), $locale);
$this->adapter->translateObject($urlContextStack->getSubjectObject(), $locale);
}

// create and add url context to stack
$urlContext = $operationStack->createUrlContext($locale);
$urlContext = $urlContextStack->createUrlContext($locale);
$urlContextStack->pushUrlContext($urlContext);

// generate the URL
$url = $this->urlGenerator->generateUrl($urlContext);
Expand Down
66 changes: 0 additions & 66 deletions AutoRoute/DefunctRouteHandler.php

This file was deleted.

Loading