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

Commit b4a79bb

Browse files
committed
Merge pull request #5 from symfony-cmf/dev
Fixes some bugs
2 parents 9609328 + 32af460 commit b4a79bb

21 files changed

+670
-84
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace Symfony\Cmf\Bundle\RoutingAutoBundle\AutoRoute\Exception;
4+
5+
/**
6+
* @author Daniel Leech <[email protected]>
7+
*/
8+
class CannotModifyClosedRouteStackException extends \RuntimeException
9+
{
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace Symfony\Cmf\Bundle\RoutingAutoBundle\AutoRoute\Exception;
4+
5+
/**
6+
* @author Daniel Leech <[email protected]>
7+
*/
8+
class InvalidPathElementException extends \RuntimeException
9+
{
10+
}

AutoRoute/PathNotExists/ThrowException.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public function init(array $options)
2323

2424
public function execute(RouteStack $routeStack)
2525
{
26-
throw new CouldNotFindRouteException($routeStack->getFullPath());
26+
throw new CouldNotFindRouteException('/'.$routeStack->getFullPath());
2727
}
2828
}
2929

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
namespace Symfony\Cmf\Bundle\RoutingAutoBundle\AutoRoute\PathProvider;
4+
5+
use Symfony\Cmf\Bundle\RoutingAutoBundle\AutoRoute\PathProviderInterface;
6+
use Symfony\Cmf\Bundle\RoutingAutoBundle\AutoRoute\Exception\MissingOptionException;
7+
use Symfony\Cmf\Bundle\RoutingAutoBundle\AutoRoute\RouteStack;
8+
use Symfony\Cmf\Bundle\CoreBundle\Slugifier\SlugifierInterface;
9+
10+
/**
11+
* Provides path elements by determining them from
12+
* a DateTime object provided by a designated method on
13+
* the content object..
14+
*
15+
* @author Daniel Leech <[email protected]>
16+
*/
17+
class ContentDateTimeProvider extends ContentMethodProvider
18+
{
19+
protected $dateFormat;
20+
21+
public function init(array $options)
22+
{
23+
parent::init($options);
24+
25+
$options = array_merge(array(
26+
'date_format' => 'Y-m-d'
27+
), $options);
28+
29+
$this->dateFormat = $options['date_format'];
30+
}
31+
32+
public function providePath(RouteStack $routeStack)
33+
{
34+
$object = $routeStack->getContext()->getContent();
35+
$method = $this->method;
36+
37+
if (!method_exists($object, $method)) {
38+
throw new \BadMethodCallException(sprintf('Method "%s" does not exist on class "%s"', $method, get_class($object)));
39+
}
40+
41+
$date = $object->$method();
42+
43+
if (!$date instanceof \DateTime) {
44+
throw new \RuntimeException(sprintf('Method %s:%s must return an instance of DateTime.'));
45+
}
46+
47+
$string = $date->format($this->dateFormat);
48+
$pathElements = $this->normalizePathElements($string);
49+
50+
$routeStack->addPathElements($pathElements);
51+
}
52+
}

AutoRoute/PathProvider/FromObjectMethodProvider.php renamed to AutoRoute/PathProvider/ContentMethodProvider.php

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,22 @@
88
use Symfony\Cmf\Bundle\CoreBundle\Slugifier\SlugifierInterface;
99

1010
/**
11+
* Provides path elements by determining them from
12+
* the return value of a method on the Content object.
13+
*
14+
* The path elements returned by the designated method can
15+
* either be a string of path elements delimited by the path
16+
* separator "/" or an array of path elements:
17+
*
18+
* - a/full/path
19+
* - array('a', 'full', 'path')
20+
*
21+
* Each element will be automatically slugified unless the
22+
* slugify option is explicitly set to false.
23+
*
1124
* @author Daniel Leech <[email protected]>
1225
*/
13-
class FromObjectMethodProvider implements PathProviderInterface
26+
class ContentMethodProvider implements PathProviderInterface
1427
{
1528
protected $method;
1629
protected $slugifier;
@@ -46,6 +59,15 @@ public function providePath(RouteStack $routeStack)
4659

4760
$pathElements = $object->$method();
4861

62+
$pathElements = $this->normalizePathElements($pathElements);
63+
64+
65+
// @todo: Validate the validator service.
66+
$routeStack->addPathElements($pathElements);
67+
}
68+
69+
protected function normalizePathElements($pathElements)
70+
{
4971
if (is_string($pathElements)) {
5072
if (substr($pathElements, 0, 1) == '/') {
5173
throw new \RuntimeException('Path must not be absolute.');
@@ -70,7 +92,6 @@ public function providePath(RouteStack $routeStack)
7092
});
7193
}
7294

73-
// @todo: Validate the validator service.
74-
$routeStack->addPathElements($pathElements);
95+
return $pathElements;
7596
}
7697
}
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
<?php
2+
3+
namespace Symfony\Cmf\Bundle\RoutingAutoBundle\AutoRoute\PathProvider;
4+
5+
use Symfony\Cmf\Bundle\RoutingAutoBundle\AutoRoute\PathProviderInterface;
6+
use Symfony\Cmf\Bundle\RoutingAutoBundle\AutoRoute\Exception\MissingOptionException;
7+
use Symfony\Cmf\Bundle\RoutingAutoBundle\AutoRoute\Exception\CouldNotFindRouteException;
8+
use Symfony\Cmf\Bundle\RoutingAutoBundle\AutoRoute\RouteStack;
9+
use Symfony\Cmf\Bundle\CoreBundle\Slugifier\SlugifierInterface;
10+
use Doctrine\ODM\PHPCR\DocumentManager;
11+
use Symfony\Cmf\Bundle\RoutingExtraBundle\Document\Route;
12+
use Doctrine\Common\Collections\ArrayCollection;
13+
14+
/**
15+
* Provides path elements by determining them from
16+
* the existing routes of a PHPCR-ODM document returned
17+
* by a designated method on the Content document.
18+
*
19+
* @author Daniel Leech <[email protected]>
20+
*/
21+
class ContentObjectProvider implements PathProviderInterface
22+
{
23+
protected $method;
24+
protected $dm;
25+
26+
public function __construct(DocumentManager $dm)
27+
{
28+
$this->dm = $dm;
29+
}
30+
31+
public function init(array $options)
32+
{
33+
if (!isset($options['method'])) {
34+
throw new MissingOptionException(__CLASS__, 'method');
35+
}
36+
37+
$this->method = $options['method'];
38+
}
39+
40+
public function providePath(RouteStack $routeStack)
41+
{
42+
$context = $routeStack->getContext();
43+
44+
if (count($context->getRouteStacks()) > 0) {
45+
throw new \RuntimeException(
46+
'ContentObjectProvider must belong to the first builder unit - adding '.
47+
'the full route path of an existing object would not make any sense otherwise.'
48+
);
49+
}
50+
51+
$contentObject = $context->getContent();
52+
$method = $this->method;
53+
54+
if (!method_exists($contentObject, $method)) {
55+
throw new \BadMethodCallException(sprintf('Method "%s" does not exist on class "%s"', $method, get_class($contentObject)));
56+
}
57+
58+
$object = $contentObject->$method();
59+
60+
$routeFilter = function ($referrer) use ($object) {
61+
if ($referrer instanceof Route && $referrer->getRouteContent() === $object) {
62+
return true;
63+
}
64+
65+
return false;
66+
};
67+
68+
$referringRoutes = new ArrayCollection;
69+
70+
if ($this->documentIsPersisted($object)) {
71+
// check to see existing routes
72+
$referrers = $this->dm->getReferrers($object);
73+
$referringRoutes = $referrers->filter($routeFilter);
74+
}
75+
76+
// Now check to see if there are any scheduled routes
77+
// I think this should be handled by the ODM ...
78+
79+
$uow = $this->dm->getUnitOfWork();
80+
$scheduledInserts = $uow->getScheduledInserts();
81+
$scheduledRoutes = array_filter($scheduledInserts, $routeFilter);
82+
$routes = array_merge($referringRoutes->toArray(), array_values($scheduledRoutes));
83+
84+
if (count($routes) > 1) {
85+
throw new \RuntimeException(
86+
'Multiple referring routes (i.e. translations) not supported yet.'
87+
);
88+
}
89+
90+
if (empty($routes)) {
91+
throw new CouldNotFindRouteException(sprintf(
92+
'Could not find route for object "%s" provided by %s:%s',
93+
get_class($object),
94+
get_class($contentObject),
95+
$method
96+
));
97+
}
98+
99+
$route = current($routes);
100+
$id = $route->getId();
101+
102+
// get rid of the first path separator (We do have one right ...)
103+
$id = substr($id, 1);
104+
105+
$pathElements = explode('/', $id);
106+
$routeStack->addPathElements($pathElements);
107+
}
108+
109+
protected function documentIsPersisted($document)
110+
{
111+
$metadata = $this->dm->getClassMetadata(get_class($document));
112+
$id = $metadata->getIdentifierValue($document);
113+
$phpcrSession = $this->dm->getPhpcrSession();
114+
return $phpcrSession->nodeExists($id);
115+
}
116+
}

AutoRoute/RoutePatcher/GenericPatcher.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,13 @@ public function patch(RouteStack $routeStack)
2525
$paths = $routeStack->getFullPaths();
2626

2727
foreach ($paths as $path) {
28-
$doc = $this->dm->find(null, $path);
28+
$absPath = '/'.$path;
29+
$doc = $this->dm->find(null, $absPath);
2930

3031
if (null === $doc) {
3132
$doc = new Generic;
3233
$meta = $this->dm->getClassMetadata(get_class($doc));
33-
$meta->setIdentifierValue($doc, $path);
34+
$meta->setIdentifierValue($doc, $absPath);
3435
}
3536

3637
$routeStack->addRoute($doc);

AutoRoute/RouteStack.php

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class RouteStack
1313
protected $pathElements;
1414
protected $routes = array();
1515
protected $context;
16+
protected $existingRoute;
1617

1718
protected $closed = false;
1819

@@ -44,10 +45,20 @@ public function addPathElements(array $pathElements)
4445
public function addPathElement($pathElement)
4546
{
4647
if (!$pathElement) {
47-
throw new \RuntimeException('Empty path element passed to addPAthElement');
48+
throw new Exception\InvalidPathElementException('Empty path element passed to addPAthElement');
4849
}
50+
51+
if (false !== strpos($pathElement, '/')) {
52+
throw new Exception\InvalidPathElementException(sprintf(
53+
'Path elements must not contain the path separator "/", given "%s"',
54+
$pathElement
55+
));
56+
}
57+
4958
if (true === $this->closed) {
50-
throw new \RuntimeException('Cannot add path elements to a closed route stack.');
59+
throw new Exception\CannotModifyClosedRouteStackException(
60+
'Cannot add path elements to a closed route stack.'
61+
);
5162
}
5263

5364
$this->pathElements[] = $pathElement;
@@ -105,7 +116,7 @@ public function getFullPaths()
105116
$paths = $this->getPaths();
106117

107118
array_walk($paths, function (&$path) use ($parentPath) {
108-
$path = $parentPath.'/'.$path;
119+
$path = $parentPath ? $parentPath.'/'.$path : $path;
109120
});
110121

111122
return $paths;
@@ -179,6 +190,13 @@ public function addRoute($route)
179190
$this->routes[] = $route;
180191
}
181192

193+
public function addRoutes($routes)
194+
{
195+
foreach ($routes as $route) {
196+
$this->addRoute($route);
197+
}
198+
}
199+
182200
/**
183201
* Close the stack. Closing a stack will check to see if
184202
* the number of path elements matches the number of routes and

AutoRoute/RouteStack/Builder.php

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
namespace Symfony\Cmf\Bundle\RoutingAutoBundle\AutoRoute\RouteStack;
44

5-
use PHPCR\SessionInterface as PhpcrSession;
65
use Symfony\Cmf\Bundle\RoutingAutoBundle\AutoRoute\BuilderContext;
76
use Symfony\Cmf\Bundle\RoutingAutoBundle\AutoRoute\RouteStack;
7+
use Doctrine\ODM\PHPCR\DocumentManager;
88

99
/**
1010
* This class is responsible for building and closing
@@ -14,20 +14,22 @@
1414
*/
1515
class Builder
1616
{
17-
protected $phpcrSession;
17+
protected $dm;
1818

19-
public function __construct(PhpcrSession $phpcrSession)
19+
public function __construct(DocumentManager $dm)
2020
{
21-
$this->phpcrSession = $phpcrSession;
21+
$this->dm = $dm;
2222
}
2323

2424
public function build(RouteStack $routeStack, BuilderUnitInterface $rsbu)
2525
{
2626
$rsbu->pathAction($routeStack);
27+
$fullPath = $routeStack->getFullPath();
28+
$absPath = '/'.$fullPath;
2729

28-
$exists = $this->phpcrSession->nodeExists('/'.$routeStack->getFullPath());
30+
$existingRoute = $this->dm->find(null, $absPath);
2931

30-
if ($exists) {
32+
if ($existingRoute) {
3133
$rsbu->existsAction($routeStack);
3234
} else {
3335
$rsbu->notExistsAction($routeStack);

Resources/config/auto_route.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
</service>
4444

4545
<service id="symfony_cmf_routing_auto.route_stack_builder" class="%symfony_cmf_routing_auto.route_stack_builder_class%">
46-
<argument type="service" id="doctrine_phpcr.default_session"/>
46+
<argument type="service" id="doctrine_phpcr.odm.default_document_manager"/>
4747
</service>
4848

4949
<service id="symfony_cmf_routing_auto.route_patcher" class="%symfony_cmf_routing_auto.route_patcher_class%">

0 commit comments

Comments
 (0)