From d81035a25f8eb164aebbcaaae719dbf36f9ae5cd Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Sun, 26 Jan 2014 21:48:14 +0100 Subject: [PATCH 01/12] port features from simple cms into routing bundle to simplify things --- DependencyInjection/CmfRoutingExtension.php | 1 + DependencyInjection/Configuration.php | 1 + Doctrine/Orm/RouteProvider.php | 2 +- Doctrine/Phpcr/IdPrefixListener.php | 42 ++-- Doctrine/Phpcr/LocaleListener.php | 60 ++++-- Doctrine/Phpcr/LocaleRouteProvider.php | 123 ++++++++++++ Doctrine/Phpcr/Route.php | 28 ++- Doctrine/Phpcr/RouteProvider.php | 127 +++++++++--- Model/Route.php | 32 ++- Resources/config/provider-phpcr.xml | 8 +- Resources/config/schema/routing-1.0.xsd | 1 + .../Doctrine/Phpcr/RouteProviderTest.php | 4 +- Tests/Resources/Fixtures/config/config.php | 1 + Tests/Resources/Fixtures/config/config.xml | 5 +- Tests/Resources/Fixtures/config/config.yml | 1 + Tests/Resources/Fixtures/config/config4.xml | 1 + .../DependencyInjection/ConfigurationTest.php | 1 + .../Doctrine/Phpcr/IdPrefixListenerTest.php | 100 +++++++++- .../Doctrine/Phpcr/LocaleListenerTest.php | 154 ++++++++++++--- .../Unit/Doctrine/Phpcr/RouteProviderTest.php | 187 ++++++++++++------ Tests/Unit/Doctrine/Phpcr/RouteTest.php | 2 +- 21 files changed, 712 insertions(+), 169 deletions(-) create mode 100644 Doctrine/Phpcr/LocaleRouteProvider.php diff --git a/DependencyInjection/CmfRoutingExtension.php b/DependencyInjection/CmfRoutingExtension.php index 65e6ebdd..ead97c90 100644 --- a/DependencyInjection/CmfRoutingExtension.php +++ b/DependencyInjection/CmfRoutingExtension.php @@ -99,6 +99,7 @@ private function setupDynamicRouter(array $config, ContainerBuilder $container, $locales = $config['locales']; $container->setParameter($this->getAlias() . '.dynamic.locales', $locales); } + $container->setParameter($this->getAlias() . '.dynamic.auto_locale_pattern', $config['auto_locale_pattern']); $loader->load('routing-dynamic.xml'); diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 3d1dd75c..568dc2a1 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -122,6 +122,7 @@ public function getConfigTreeBuilder() ->arrayNode('locales') ->prototype('scalar')->end() ->end() + ->booleanNode('auto_locale_pattern')->defaultValue(false)->end() ->end() ->end() ->end() diff --git a/Doctrine/Orm/RouteProvider.php b/Doctrine/Orm/RouteProvider.php index 912ff707..64f77b6a 100644 --- a/Doctrine/Orm/RouteProvider.php +++ b/Doctrine/Orm/RouteProvider.php @@ -90,7 +90,7 @@ public function getRoutesByNames($names = null) $routes = array(); foreach ($names as $name) { try { - $routes[] = $this->getRouteByName($name, $parameters); + $routes[] = $this->getRouteByName($name); } catch (RouteNotFoundException $e) { // not found } diff --git a/Doctrine/Phpcr/IdPrefixListener.php b/Doctrine/Phpcr/IdPrefixListener.php index b2d7dd4a..45a7047b 100644 --- a/Doctrine/Phpcr/IdPrefixListener.php +++ b/Doctrine/Phpcr/IdPrefixListener.php @@ -15,30 +15,38 @@ use Doctrine\Common\Persistence\Event\LifecycleEventArgs; /** - * Doctrine PHPCR-ODM listener to set the idPrefix on routes + * Doctrine PHPCR-ODM listener to tell routes what part of their id is the URL. + * + * This listener knows about the RouteProvider and uses its prefixes to + * identify routes that could need the prefix. In case prefixes overlap, the + * order matters as the first matching prefix is taken. * * @author David Buchmann */ class IdPrefixListener { /** - * The prefix to add to the url to create the repository path + * Used to ask for the possible prefixes to remove from the repository ID + * to create the URL. * - * @var string + * @var RouteProvider */ - protected $idPrefix = ''; + protected $provider; - public function __construct($prefix) + /** + * @param RouteProvider $provider + */ + public function __construct(RouteProvider $provider) { - $this->idPrefix = $prefix; + $this->provider = $provider; } /** - * @param $prefix + * @return array */ - public function setPrefix($prefix) + protected function getPrefixes() { - $this->idPrefix = $prefix; + return $this->provider->getPrefixes(); } public function postLoad(LifecycleEventArgs $args) @@ -51,16 +59,24 @@ public function postPersist(LifecycleEventArgs $args) $this->updateId($args); } + public function postMove(LifecycleEventArgs $args) + { + $this->updateId($args); + } + protected function updateId(LifecycleEventArgs $args) { $doc = $args->getObject(); // only update route objects and only if the prefix can match, to allow // for more than one listener and more than one route root - if (($doc instanceof PrefixInterface) - && ! strncmp($this->idPrefix, $doc->getId(), strlen($this->idPrefix)) - ) { - $doc->setPrefix($this->idPrefix); + if ($doc instanceof PrefixInterface) { + foreach ($this->getPrefixes() as $prefix) { + if (! strncmp($prefix, $doc->getId(), strlen($prefix))) { + $doc->setPrefix($prefix); + break; + } + } } } } diff --git a/Doctrine/Phpcr/LocaleListener.php b/Doctrine/Phpcr/LocaleListener.php index bea164ed..daff2b56 100644 --- a/Doctrine/Phpcr/LocaleListener.php +++ b/Doctrine/Phpcr/LocaleListener.php @@ -29,11 +29,12 @@ class LocaleListener { /** - * The prefix to add to the url to create the repository path + * Used to ask for the possible prefixes to determine the possible locale + * segment of the id. * - * @var string + * @var RouteProvider */ - protected $idPrefix = ''; + protected $provider; /** * List of possible locales to detect on URL after idPrefix @@ -42,20 +43,24 @@ class LocaleListener */ protected $locales; - public function __construct($prefix, array $locales) - { - $this->idPrefix = $prefix; - $this->locales = $locales; - } + /** + * If set, call Route::setAddLocalePattern. + * @var boolean + */ + protected $addLocalePattern; /** - * The repository path prefix where routes handled by this listener are located. - * - * @param $prefix + * @param RouteProvider $provider To get prefixes from. + * @param array $locales Locales that should be detected. + * @param bool $addLocalePattern Whether to make route prepend the + * locale pattern if it does not have + * one of the allowed locals in its id. */ - public function setPrefix($prefix) + public function __construct(RouteProvider $provider, array $locales, $addLocalePattern = false) { - $this->idPrefix = $prefix; + $this->provider = $provider; + $this->locales = $locales; + $this->addLocalePattern = $addLocalePattern; } /** @@ -68,6 +73,17 @@ public function setLocales(array $locales) $this->locales = $locales; } + /** + * Whether to make the route prepend the locale pattern if it does not + * have one of the allowed locals in its id. + * + * @param boolean $addLocalePattern + */ + public function setAddLocalePattern($addLocalePattern) + { + $this->addLocalePattern = $addLocalePattern; + } + /** * Update locale after loading a route. * @@ -110,6 +126,14 @@ public function postMove(MoveEventArgs $args) $this->updateLocale($doc, $args->getTargetPath(), true); } + /** + * @return array + */ + protected function getPrefixes() + { + return $this->provider->getPrefixes(); + } + /** * Update the locale of a route if $id starts with the prefix and has a * valid locale right after. @@ -126,17 +150,19 @@ protected function updateLocale(Route $doc, $id, $force = false) // only update route objects and only if the prefix can match, to allow // for more than one listener and more than one route root - if (! preg_match('#' . $this->idPrefix . '/([^/]+)(/|$)#', $id, $matches)) { + if (! preg_match('#(' . implode('|', $this->getPrefixes()) . ')/([^/]+)(/|$)#', $id, $matches)) { return; } - if (in_array($matches[1], $this->locales)) { + if (in_array($locale = $matches[2], $this->locales)) { if ($force || ! $doc->getDefault('_locale')) { - $doc->setDefault('_locale', $matches[1]); + $doc->setDefault('_locale', $locale); } if ($force || ! $doc->getRequirement('_locale')) { - $doc->setRequirement('_locale', $matches[1]); + $doc->setRequirement('_locale', $locale); } + } elseif ($this->addLocalePattern) { + $doc->setAddLocalePattern(true); } } } diff --git a/Doctrine/Phpcr/LocaleRouteProvider.php b/Doctrine/Phpcr/LocaleRouteProvider.php new file mode 100644 index 00000000..f027028a --- /dev/null +++ b/Doctrine/Phpcr/LocaleRouteProvider.php @@ -0,0 +1,123 @@ + + */ +class LocaleRouteProvider extends RouteProvider +{ + /** + * The allowed locales. + * + * @var array + */ + protected $locales = array(); + + /** + * The detected locale in this request. + * + * @var string + */ + private $locale; + + /** + * Set the allowed locales. + * + * @param array $locales + */ + public function setLocales(array $locales = array()) + { + $this->locales = $locales; + } + + /** + * {@inheritDoc} + * + * Additionally checks if $url starts with a locale, and if so proposes + * additional candidates without the locale. + */ + protected function getCandidates($url) + { + $directCandidates = parent::getCandidates($url); + + $dirs = explode('/', ltrim($url, '/')); + if (isset($dirs[0]) && in_array($dirs[0], $this->locales)) { + $this->locale = $dirs[0]; + array_shift($dirs); + $url = '/'.implode('/', $dirs); + + // the normal listener "waits" until the routing completes + // as the locale could be defined inside the route + $this->getObjectManager()->getLocaleChooserStrategy()->setLocale($this->locale); + + return array_merge($directCandidates, parent::getCandidates($url)); + } + + return $directCandidates; + } + + protected function configureLocale($route) + { + crap. that if is about simple cms + if ($this->getObjectManager()->isDocumentTranslatable($route)) { + // add locale requirement + if (!$route->getRequirement('_locale')) { + $locales = $this->getObjectManager()->getLocalesFor($route, true); + $route->setRequirement('_locale', implode('|', $locales)); + } + } + } + + /** + * {@inheritDoc} + */ + public function getRouteCollectionForRequest(Request $request) + { + $collection = parent::getRouteCollectionForRequest($request); + foreach ($collection as $route) { + $this->configureLocale($route); + } + + return $collection; + } + + /** + * {@inheritDoc} + */ + public function getRouteByName($name, $parameters = array()) + { + $route = parent::getRouteByName($name, $parameters); + $this->configureLocale($route); + + return $route; + } + + /** + * {@inheritDoc} + */ + public function getRoutesByNames($names = null) + { + $collection = parent::getRoutesByNames($names); + foreach ($collection as $route) { + $this->configureLocale($route); + } + + return $collection; + } +} diff --git a/Doctrine/Phpcr/Route.php b/Doctrine/Phpcr/Route.php index 44eec064..7706ed73 100644 --- a/Doctrine/Phpcr/Route.php +++ b/Doctrine/Phpcr/Route.php @@ -12,6 +12,7 @@ namespace Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr; +use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ODM\PHPCR\Document\Generic; use Doctrine\ODM\PHPCR\Exception\InvalidArgumentException; @@ -65,18 +66,18 @@ class Route extends RouteModel implements PrefixInterface, ChildInterface protected $idPrefix; /** - * Overwrite to be able to create route without pattern + * PHPCR id can not end on '/', so we need an additional option. * - * @param Boolean $addFormatPattern if to add ".{_format}" to the route pattern - * also implicitly sets a default/require on "_format" to "html" - * @param Boolean $addTrailingSlash whether to add a trailing slash to the route, defaults to not add one + * Additional supported settings are: + * + * * addTrailingSlash: When set, a trailing slash is appended to the route */ - public function __construct($addFormatPattern = false, $addTrailingSlash = false) + public function __construct(array $settings = array()) { - parent::__construct($addFormatPattern); + parent::__construct($settings); - $this->children = array(); - $this->addTrailingSlash = $addTrailingSlash; + $this->children = new ArrayCollection(); + $this->addTrailingSlash = empty($settings['addTrailingSlash']); } public function getAddTrailingSlash() @@ -217,7 +218,14 @@ public function setPrefix($idPrefix) */ public function getStaticPrefix() { - return $this->generateStaticPrefix($this->getId(), $this->idPrefix); + $path = $this->getId(); + $prefix = $this->getPrefix(); + + if ($this->addLocalePattern) { + $path = $prefix . '/{_locale}' . substr($path, strlen($prefix)); + } + + return $this->generateStaticPrefix($path, $prefix); } /** @@ -297,7 +305,7 @@ public function getRouteChildren() /** * Get all children of this route including non-routes. * - * @return array + * @return Collection */ public function getChildren() { diff --git a/Doctrine/Phpcr/RouteProvider.php b/Doctrine/Phpcr/RouteProvider.php index f06b0403..e3934123 100644 --- a/Doctrine/Phpcr/RouteProvider.php +++ b/Doctrine/Phpcr/RouteProvider.php @@ -31,7 +31,7 @@ use Symfony\Cmf\Bundle\RoutingBundle\Doctrine\DoctrineProvider; /** - * Provide routes loaded from PHPCR-ODM + * Loads routes from Doctrine PHPCR-ODM. * * This is NOT not a doctrine repository but just the route * provider for the NestedMatcher. (you could of course implement this @@ -42,18 +42,38 @@ class RouteProvider extends DoctrineProvider implements RouteProviderInterface { /** - * The prefix to add to the url to create the repository path + * Places in the PHPCR tree where routes are located. * - * @var string + * @var array */ - protected $idPrefix = ''; + protected $idPrefixes = array(); /** * @param $prefix */ - public function setPrefix($prefix) + public function setPrefixes($prefixes) { - $this->idPrefix = $prefix; + $this->idPrefixes = $prefixes; + } + + /** + * Append a repository prefix to the possible prefixes. + * + * @param $prefix + */ + public function addPrefix($prefix) + { + $this->idPrefixes[] = $prefix; + } + + /** + * Get all currently configured prefixes where to look for routes. + * + * @return array + */ + public function getPrefixes() + { + return $this->idPrefixes; } /** @@ -97,27 +117,47 @@ public function getRouteCollectionForRequest(Request $request) } /** - * @param $url + * Get id candidates for all configured prefixes. * - * @return array + * @param string $url + * + * @return array PHPCR ids that could load routes that match $url. */ protected function getCandidates($url) + { + $candidates = array(); + foreach ($this->getPrefixes() as $prefix) { + $candidates = array_merge($candidates, $this->getCandidatesFor($prefix, $url)); + } + + return $candidates; + } + + /** + * Get the id candidates for one prefix. + * + * @param string $url + * + * @return array PHPCR ids that could load routes that match $url and are + * child of $prefix. + */ + protected function getCandidatesFor($prefix, $url) { $candidates = array(); if ('/' !== $url) { if (preg_match('/(.+)\.[a-z]+$/i', $url, $matches)) { - $candidates[] = $this->idPrefix . $url; + $candidates[] = $prefix . $url; $url = $matches[1]; } $part = $url; while (false !== ($pos = strrpos($part, '/'))) { - $candidates[] = $this->idPrefix . $part; + $candidates[] = $prefix . $part; $part = substr($url, 0, $pos); } } - $candidates[] = $this->idPrefix; + $candidates[] = $prefix; return $candidates; } @@ -137,8 +177,18 @@ public function getRouteByName($name) ) { $route = null; } - } elseif ('' === $this->idPrefix || 0 === strpos($name, $this->idPrefix)) { + } else { $route = $this->getObjectManager()->find($this->className, $name); + + foreach ($this->getPrefixes() as $prefix) { + // $name is the route document path + if ('' === $prefix || 0 === strpos($name, $prefix)) { + $route = $this->getObjectManager()->find($this->className, $name); + if ($route) { + break; + } + } + } } if (empty($route)) { @@ -153,11 +203,12 @@ public function getRouteByName($name) } /** - * Get list of route names + * Get all the routes in the repository that are under one of the + * configured prefixes. This respects the limit. * * @return array */ - private function getRouteNames() + private function getAllRoutes() { if (0 === $this->routeCollectionLimit) { return array(); @@ -167,8 +218,16 @@ private function getRouteNames() $dm = $this->getObjectManager(); $sql2 = 'SELECT * FROM [nt:unstructured] WHERE [phpcr:classparents] = '.$dm->quote('Symfony\Component\Routing\Route'); - if ('' !== $this->idPrefix) { - $sql2.= ' AND ISDESCENDANTNODE('.$dm->quote($this->idPrefix).')'; + $prefixConstraints = array(); + foreach ($this->getPrefixes() as $prefix) { + if ('' == $prefix) { + $prefixConstraints = array(); + break; + } + $prefixConstraints[] = 'ISDESCENDANTNODE('.$dm->quote($prefix).')'; + } + if ($prefixConstraints) { + $sql2 .= ' AND (' . implode(' OR ', $prefixConstraints) . ')'; } $query = $dm->createPhpcrQuery($sql2, QueryInterface::JCR_SQL2); @@ -176,15 +235,7 @@ private function getRouteNames() $query->setLimit($this->routeCollectionLimit); } - $result = $query->execute(); - - $names = array(); - foreach ($result as $row) { - /** @var $row RowInterface */ - $names[] = $row->getPath(); - } - - return $names; + return $dm->getDocumentsByPhpcrQuery($query); } /** @@ -193,20 +244,34 @@ private function getRouteNames() public function getRoutesByNames($names = null) { if (null === $names) { - $names = $this->getRouteNames(); + return $this->getAllRoutes(); } - if ('' !== $this->idPrefix) { - foreach ($names as $key => $name) { - if (!UUIDHelper::isUUID($name) && 0 !== strpos($name, $this->idPrefix)) { - unset($names[$key]); + $candidates = array(); + foreach ($names as $key => $name) { + if (UUIDHelper::isUUID($name)) { + continue; + } + foreach ($this->getPrefixes() as $prefix) { + if ('' == $prefix) { + $candidates = $names; + break 2; + } + foreach ($names as $key => $name) { + if (0 === strpos($name, $prefix)) { + $candidates[$key] = $name; + } } } } + if (!$candidates) { + return array(); + } + /** @var $dm DocumentManager */ $dm = $this->getObjectManager(); - $collection = $dm->findMany($this->className, $names); + $collection = $dm->findMany($this->className, $candidates); foreach ($collection as $key => $document) { if (!$document instanceof SymfonyRoute) { // we follow the logic of DocumentManager::findMany and do not throw an exception diff --git a/Model/Route.php b/Model/Route.php index 777b3afe..76054da3 100644 --- a/Model/Route.php +++ b/Model/Route.php @@ -54,12 +54,18 @@ class Route extends SymfonyRoute implements RouteObjectInterface protected $variablePattern; /** - * if to add ".{_format}" to the pattern + * Whether to append ".{_format}" to the pattern. * * @var Boolean */ protected $addFormatPattern; + /** + * Whether to prepend "{_locale}" to the pattern. + * @var boolean + */ + protected $addLocalePattern; + /** * Whether this route was changed since being last compiled. * @@ -72,20 +78,26 @@ class Route extends SymfonyRoute implements RouteObjectInterface /** * Overwrite to be able to create route without pattern * - * @param bool $addFormatPattern if to add ".{_format}" to the route pattern - * also implicitly sets a default/require on "_format" to "html" + * Supported settings are: + * + * * addFormatPattern: When set, ".{_format}" is appended to the route pattern. + * Also implicitly sets a default/require on "_format" to "html". + * * addLocalePattern: When set, "/{_locale}" is prepended to the route pattern. + * + * @param array $settings */ - public function __construct($addFormatPattern = false) + public function __construct(array $settings = array()) { $this->setDefaults(array()); $this->setRequirements(array()); $this->setOptions(array()); - $this->addFormatPattern = $addFormatPattern; + $this->addFormatPattern = !empty($settings['addFormatPattern']); if ($this->addFormatPattern) { $this->setDefault('_format', 'html'); $this->setRequirement('_format', 'html'); } + $this->addLocalePattern = !empty($settings['addLocalePattern']); } public function getAddFormatPattern() @@ -98,6 +110,16 @@ public function setAddFormatPattern($addFormatPattern) $this->addFormatPattern = $addFormatPattern; } + public function getAddLocalePattern() + { + return $this->addLocalePattern; + } + + public function setAddLocalePattern($addLocalePattern) + { + $this->addLocalePattern = $addLocalePattern; + } + /** * {@inheritDoc} */ diff --git a/Resources/config/provider-phpcr.xml b/Resources/config/provider-phpcr.xml index f884678e..0e15c786 100644 --- a/Resources/config/provider-phpcr.xml +++ b/Resources/config/provider-phpcr.xml @@ -16,7 +16,7 @@ %cmf_routing.route_model.class% %cmf_routing.dynamic.persistence.phpcr.manager_name% - %cmf_routing.dynamic.persistence.phpcr.route_basepath% + %cmf_routing.dynamic.persistence.phpcr.route_basepath% %cmf_routing.route_collection_limit% @@ -26,14 +26,16 @@ - %cmf_routing.dynamic.persistence.phpcr.route_basepath% + + - %cmf_routing.dynamic.persistence.phpcr.route_basepath% + %cmf_routing.dynamic.locales% + %cmf_routing.dynamic.auto_locale_pattern% diff --git a/Resources/config/schema/routing-1.0.xsd b/Resources/config/schema/routing-1.0.xsd index 1d3a55b4..04ed1524 100644 --- a/Resources/config/schema/routing-1.0.xsd +++ b/Resources/config/schema/routing-1.0.xsd @@ -39,6 +39,7 @@ + diff --git a/Tests/Functional/Doctrine/Phpcr/RouteProviderTest.php b/Tests/Functional/Doctrine/Phpcr/RouteProviderTest.php index 789d2dbc..899a9858 100644 --- a/Tests/Functional/Doctrine/Phpcr/RouteProviderTest.php +++ b/Tests/Functional/Doctrine/Phpcr/RouteProviderTest.php @@ -122,8 +122,8 @@ public function testGetRoutesByNames() } - public function testSetPrefix() + public function testSetPrefixes() { - $this->repository->setPrefix(self::ROUTE_ROOT); + $this->repository->setPrefixes(array(self::ROUTE_ROOT)); } } diff --git a/Tests/Resources/Fixtures/config/config.php b/Tests/Resources/Fixtures/config/config.php index 1ae9b703..9cd9c49d 100644 --- a/Tests/Resources/Fixtures/config/config.php +++ b/Tests/Resources/Fixtures/config/config.php @@ -27,5 +27,6 @@ ), ), 'locales' => array('en', 'fr'), + 'auto_locale_pattern' => true, ), )); diff --git a/Tests/Resources/Fixtures/config/config.xml b/Tests/Resources/Fixtures/config/config.xml index d4b34449..f218d727 100644 --- a/Tests/Resources/Fixtures/config/config.xml +++ b/Tests/Resources/Fixtures/config/config.xml @@ -8,7 +8,10 @@ 100 - + acme_main.some_controller:editableAction cmf_content.controller:indexAction diff --git a/Tests/Resources/Fixtures/config/config.yml b/Tests/Resources/Fixtures/config/config.yml index c3c86684..542ebcd1 100644 --- a/Tests/Resources/Fixtures/config/config.yml +++ b/Tests/Resources/Fixtures/config/config.yml @@ -18,3 +18,4 @@ cmf_routing: content_basepath: /cms/content use_sonata_admin: false locales: [en, fr] + auto_locale_pattern: true diff --git a/Tests/Resources/Fixtures/config/config4.xml b/Tests/Resources/Fixtures/config/config4.xml index 228e5699..79ee8e2a 100644 --- a/Tests/Resources/Fixtures/config/config4.xml +++ b/Tests/Resources/Fixtures/config/config4.xml @@ -7,6 +7,7 @@ uri-filter-regexp=".*" route-provider-service-id="my-provider" content-repository-service-id="my-repo" + auto-locale-pattern="true" > type-controller class-controller diff --git a/Tests/Unit/DependencyInjection/ConfigurationTest.php b/Tests/Unit/DependencyInjection/ConfigurationTest.php index de801719..68a150f7 100644 --- a/Tests/Unit/DependencyInjection/ConfigurationTest.php +++ b/Tests/Unit/DependencyInjection/ConfigurationTest.php @@ -68,6 +68,7 @@ public function testSupportsAllConfigFormats() 'uri_filter_regexp' => '', 'route_filters_by_id' => array(), 'locales' => array('en', 'fr'), + 'auto_locale_pattern' => true, ), ); diff --git a/Tests/Unit/Doctrine/Phpcr/IdPrefixListenerTest.php b/Tests/Unit/Doctrine/Phpcr/IdPrefixListenerTest.php index f0514b55..84675951 100644 --- a/Tests/Unit/Doctrine/Phpcr/IdPrefixListenerTest.php +++ b/Tests/Unit/Doctrine/Phpcr/IdPrefixListenerTest.php @@ -12,16 +12,110 @@ namespace Symfony\Cmf\Bundle\RoutingBundle\Tests\Doctrine\Phpcr; +use Doctrine\Common\Persistence\Event\LifecycleEventArgs; use Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\IdPrefixListener; use Symfony\Cmf\Component\Routing\Test\CmfUnitTestCase; class IdPrefixListenerTest extends CmfUnitTestCase { - public function testConstructor() + protected $provider; + protected $dmMock; + protected $routeMock; + + /** + * @var IdPrefixListener + */ + protected $listener; + + public function setUp() + { + $this->provider = $this->getMockBuilder('Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\RouteProvider') + ->disableOriginalConstructor() + ->getMock() + ; + $this->provider + ->expects($this->any()) + ->method('getPrefixes') + ->will($this->returnValue(array('/cms/routes', '/cms/simple'))) + ; + $this->dmMock = $this->buildMock('Doctrine\ODM\PHPCR\DocumentManager'); + $this->routeMock = $this->buildMock('Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\Route'); + + $this->listener = new IdPrefixListener($this->provider); + } + + public function testNoRoute() + { + $args = new LifecycleEventArgs($this, $this->dmMock); + + $this->listener->postLoad($args); + } + + private function prepareMatch() + { + $this->routeMock + ->expects($this->once()) + ->method('getId') + ->will($this->returnValue('/cms/routes')) + ; + $this->routeMock + ->expects($this->once()) + ->method('setPrefix') + ->with('/cms/routes') + ; + + return new LifecycleEventArgs($this->routeMock, $this->dmMock); + } + + public function testPostLoad() + { + $this->listener->postLoad($this->prepareMatch()); + } + + public function testPostPersist() + { + $this->listener->postPersist($this->prepareMatch()); + } + + public function testPostMove() { - new IdPrefixListener('test'); + $this->listener->postMove($this->prepareMatch()); } - // the rest is covered by functional test + public function testSecond() + { + + $this->routeMock + ->expects($this->exactly(2)) + ->method('getId') + ->will($this->returnValue('/cms/simple/test')) + ; + $this->routeMock + ->expects($this->once()) + ->method('setPrefix') + ->with('/cms/simple') + ; + + $args = new LifecycleEventArgs($this->routeMock, $this->dmMock); + + $this->listener->postLoad($args); + } + + public function testOutside() + { + $this->routeMock + ->expects($this->exactly(2)) + ->method('getId') + ->will($this->returnValue('/outside')) + ; + $this->routeMock + ->expects($this->never()) + ->method('setPrefix') + ; + + $args = new LifecycleEventArgs($this->routeMock, $this->dmMock); + + $this->listener->postLoad($args); + } } diff --git a/Tests/Unit/Doctrine/Phpcr/LocaleListenerTest.php b/Tests/Unit/Doctrine/Phpcr/LocaleListenerTest.php index b0262be2..39089af8 100644 --- a/Tests/Unit/Doctrine/Phpcr/LocaleListenerTest.php +++ b/Tests/Unit/Doctrine/Phpcr/LocaleListenerTest.php @@ -10,7 +10,7 @@ */ -namespace Symfony\Cmf\Bundle\RoutingBundle\Tests\Listener; +namespace Symfony\Cmf\Bundle\RoutingBundle\Tests\Unit\Doctrine\Phpcr; use Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\LocaleListener; use Doctrine\ODM\PHPCR\Event\MoveEventArgs; @@ -24,42 +24,81 @@ class LocaleListenerTest extends CmfUnitTestCase protected $listener; protected $routeMock; protected $dmMock; + protected $provider; public function setUp() { - $this->listener = new LocaleListener('/prefix/path', array('en', 'de')); + $this->provider = $this->buildMock('Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\RouteProvider'); + + $this->provider->expects($this->any()) + ->method('getPrefixes') + ->will($this->returnValue(array('/cms/routes', '/cms/simple'))) + ; + $this->listener = new LocaleListener($this->provider, array('en', 'de')); $this->routeMock = $this->buildMock('Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\Route'); $this->dmMock = $this->buildMock('Doctrine\ODM\PHPCR\DocumentManager'); } - public function testMoved() + public function testNoRoute() { - $moveArgs = new MoveEventArgs( - $this->routeMock, - $this->dmMock, - '/prefix/path/de/my/route', - '/prefix/path/en/my/route' - ); + $args = new LifecycleEventArgs($this, $this->dmMock); + $this->listener->postLoad($args); + $this->listener->postPersist($args); + } + public function testNoPrefixMatch() + { $this->routeMock->expects($this->once()) + ->method('getId') + ->will($this->returnValue('/cms/outside/de/my/route')) + ; + + $this->routeMock->expects($this->never()) ->method('setDefault') - ->with('_locale', 'en') + ; + $this->routeMock->expects($this->never()) + ->method('setRequirement') + ; + + $args = new LifecycleEventArgs($this->routeMock, $this->dmMock); + + $this->listener->postLoad($args); + } + + private function prepareMatch() + { + $this->routeMock->expects($this->once()) + ->method('getId') + ->will($this->returnValue('/cms/routes/de/my/route')) + ; + + $this->routeMock->expects($this->once()) + ->method('setDefault') + ->with('_locale', 'de') ; $this->routeMock->expects($this->once()) ->method('setRequirement') - ->with('_locale', 'en') + ->with('_locale', 'de') ; - $this->listener->postMove($moveArgs); + return new LifecycleEventArgs($this->routeMock, $this->dmMock); } public function testLoad() { - $args = new LifecycleEventArgs($this->routeMock, $this->dmMock); + $this->listener->postLoad($this->prepareMatch()); + } - $this->routeMock->expects($this->any()) + public function testPersist() + { + $this->listener->postPersist($this->prepareMatch()); + } + + public function testSecond() + { + $this->routeMock->expects($this->once()) ->method('getId') - ->will($this->returnValue('/prefix/path/de/my/route')) + ->will($this->returnValue('/cms/simple/de')) ; $this->routeMock->expects($this->once()) @@ -71,35 +110,56 @@ public function testLoad() ->with('_locale', 'de') ; + $args = new LifecycleEventArgs($this->routeMock, $this->dmMock); $this->listener->postLoad($args); } - public function testNolocaleUrl() + public function testMoveNoRoute() { - $args = new LifecycleEventArgs($this->routeMock, $this->dmMock); + $moveArgs = new MoveEventArgs( + $this, + $this->dmMock, + '/cms/routes/de/my/route', + '/cms/routes/en/my/route' + ); - $this->routeMock->expects($this->any()) - ->method('getId') - ->will($this->returnValue('/prefix/path/my/route')) - ; + $this->listener->postMove($moveArgs); + } - $this->routeMock->expects($this->never()) + public function testMoved() + { + $moveArgs = new MoveEventArgs( + $this->routeMock, + $this->dmMock, + '/cms/routes/de/my/route', + '/cms/routes/en/my/route' + ); + + $this->routeMock->expects($this->once()) ->method('setDefault') + ->with('_locale', 'en') ; - $this->routeMock->expects($this->never()) + $this->routeMock->expects($this->once()) ->method('setRequirement') + ->with('_locale', 'en') ; - $this->listener->postLoad($args); + $this->listener->postMove($moveArgs); + } + + public function testSetLocales() + { + $this->listener->setLocales(array('xx')); + $this->assertAttributeEquals(array('xx'), 'locales', $this->listener); } public function testHaslocale() { $args = new LifecycleEventArgs($this->routeMock, $this->dmMock); - $this->routeMock->expects($this->any()) + $this->routeMock->expects($this->once()) ->method('getId') - ->will($this->returnValue('/prefix/path/de/my/route')) + ->will($this->returnValue('/cms/routes/de/my/route')) ; $this->routeMock->expects($this->once()) @@ -123,4 +183,46 @@ public function testHaslocale() $this->listener->postLoad($args); } + + /** + * URL without locale, addLocalePattern not set. + */ + public function testNolocaleUrl() + { + $args = new LifecycleEventArgs($this->routeMock, $this->dmMock); + + $this->routeMock->expects($this->once()) + ->method('getId') + ->will($this->returnValue('/cms/routes/my/route')) + ; + + $this->routeMock->expects($this->never()) + ->method('setDefault') + ; + $this->routeMock->expects($this->never()) + ->method('setRequirement') + ; + + $this->listener->postLoad($args); + } + + /** + * URL without locale, addLocalePattern set. + */ + public function testLocalePattern() + { + $this->routeMock->expects($this->once()) + ->method('getId') + ->will($this->returnValue('/cms/simple/something')) + ; + + $this->routeMock->expects($this->once()) + ->method('setAddLocalePattern') + ->with(true) + ; + + $this->listener->setAddLocalePattern(true); + $args = new LifecycleEventArgs($this->routeMock, $this->dmMock); + $this->listener->postLoad($args); + } } diff --git a/Tests/Unit/Doctrine/Phpcr/RouteProviderTest.php b/Tests/Unit/Doctrine/Phpcr/RouteProviderTest.php index 2247fb19..227cd061 100644 --- a/Tests/Unit/Doctrine/Phpcr/RouteProviderTest.php +++ b/Tests/Unit/Doctrine/Phpcr/RouteProviderTest.php @@ -10,10 +10,14 @@ */ -namespace Symfony\Cmf\Bundle\RoutingBundle\Tests\Doctrine\Phpcr; +namespace Symfony\Cmf\Bundle\RoutingBundle\Tests\Unit\Doctrine\Phpcr; use PHPCR\Util\UUIDHelper; +use PHPCR\Query\QueryInterface; +use Doctrine\Common\Collections\ArrayCollection; use Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\RouteProvider; +use Symfony\Component\Routing\Route; +use Symfony\Component\Routing\RouteCollection; class RouteProviderTest extends \PHPUnit_Framework_Testcase { @@ -32,9 +36,23 @@ public function setUp() $this->route2 = $this->getMockBuilder('Symfony\Component\Routing\Route') ->disableOriginalConstructor() ->getMock(); - $this->objectManager = $this->getMock('Doctrine\Common\Persistence\ObjectManager'); - $this->objectManager2 = $this->getMock('Doctrine\Common\Persistence\ObjectManager'); + $this->objectManager = $this + ->getMockBuilder('Doctrine\ODM\PHPCR\DocumentManager') + ->disableOriginalConstructor() + ->getMock() + ; + $this->objectManager2 = $this + ->getMockBuilder('Doctrine\ODM\PHPCR\DocumentManager') + ->disableOriginalConstructor() + ->getMock() + ; $this->managerRegistry = $this->getMock('Doctrine\Common\Persistence\ManagerRegistry'); + + $this->managerRegistry + ->expects($this->any()) + ->method('getManager') + ->will($this->returnValue($this->objectManager)) + ; } public function testGetRouteCollectionForRequest() @@ -44,7 +62,6 @@ public function testGetRouteCollectionForRequest() public function testGetRouteByName() { - $this->route ->expects($this->any()) ->method('getPath') @@ -58,16 +75,10 @@ public function testGetRouteByName() ->will($this->returnValue($this->route)) ; - $this->managerRegistry - ->expects($this->any()) - ->method('getManager') - ->will($this->returnValue($this->objectManager)) - ; - $routeProvider = new RouteProvider($this->managerRegistry); $routeProvider->setManagerName('default'); - $routeProvider->setPrefix('/cms/routes/'); + $routeProvider->setPrefixes(array('/cms/routes/')); $foundRoute = $routeProvider->getRouteByName('/cms/routes/test-route'); $this->assertInstanceOf('Symfony\Component\Routing\Route', $foundRoute); @@ -137,15 +148,9 @@ public function testGetRouteByNameNotFound() ->will($this->returnValue(null)) ; - $this->managerRegistry - ->expects($this->any()) - ->method('getManager') - ->will($this->returnValue($this->objectManager)) - ; - $routeProvider = new RouteProvider($this->managerRegistry); $routeProvider->setManagerName('default'); - $routeProvider->setPrefix('/cms/routes/'); + $routeProvider->setPrefixes(array('/cms/routes/')); $routeProvider->getRouteByName('/cms/routes/test-route'); } @@ -161,15 +166,9 @@ public function testGetRouteByNameNoRoute() ->will($this->returnValue($this)) ; - $this->managerRegistry - ->expects($this->any()) - ->method('getManager') - ->will($this->returnValue($this->objectManager)) - ; - $routeProvider = new RouteProvider($this->managerRegistry); $routeProvider->setManagerName('default'); - $routeProvider->setPrefix('/cms/routes/'); + $routeProvider->setPrefixes(array('/cms/routes/')); $routeProvider->getRouteByName('/cms/routes/test-route'); } @@ -183,16 +182,10 @@ public function testGetRouteByNameInvalidRoute() ->method('find') ; - $this->managerRegistry - ->expects($this->any()) - ->method('getManager') - ->will($this->returnValue($this->objectManager)) - ; - $routeProvider = new RouteProvider($this->managerRegistry); $routeProvider->setManagerName('default'); - $routeProvider->setPrefix('/cms/routes'); + $routeProvider->setPrefixes(array('/cms/routes')); $routeProvider->getRouteByName('invalid_route'); } @@ -213,16 +206,10 @@ public function testGetRouteByNameIdPrefixEmptyString() ->will($this->returnValue($this->route)) ; - $this->managerRegistry - ->expects($this->any()) - ->method('getManager') - ->will($this->returnValue($this->objectManager)) - ; - $routeProvider = new RouteProvider($this->managerRegistry); $routeProvider->setManagerName('default'); - $routeProvider->setPrefix(''); + $routeProvider->setPrefixes(array('')); $foundRoute = $routeProvider->getRouteByName('/cms/routes/test-route'); $this->assertInstanceOf('Symfony\Component\Routing\Route', $foundRoute); @@ -242,15 +229,9 @@ public function testGetRouteByNameNotFoundIdPrefixEmptyString() ->will($this->returnValue(null)) ; - $this->managerRegistry - ->expects($this->any()) - ->method('getManager') - ->will($this->returnValue($this->objectManager)) - ; - $routeProvider = new RouteProvider($this->managerRegistry); $routeProvider->setManagerName('default'); - $routeProvider->setPrefix(''); + $routeProvider->setPrefixes(array('')); $routeProvider->getRouteByName('/cms/routes/test-route'); } @@ -260,28 +241,121 @@ public function testGetRouteByNameNotFoundIdPrefixEmptyString() public function testGetRouteByNameNoRoutePrefixEmptyString() { $this->objectManager - ->expects($this->any()) + ->expects($this->once()) ->method('find') ->with(null, '/cms/routes/test-route') ->will($this->returnValue($this)) ; - $this->managerRegistry - ->expects($this->any()) - ->method('getManager') - ->will($this->returnValue($this->objectManager)) - ; - $routeProvider = new RouteProvider($this->managerRegistry); $routeProvider->setManagerName('default'); - $routeProvider->setPrefix(''); + $routeProvider->setPrefixes(array('')); $routeProvider->getRouteByName('/cms/routes/test-route'); } public function testGetRoutesByNames() { - $this->markTestIncomplete(); + $paths = array( + '/cms/routes/test-route', + '/cms/simple/other-route', + '/cms/routes/not-a-route', + ); + + $collection = new ArrayCollection(); + $collection->set('/cms/routes/test-route', new Route('/test-route')); + $collection->set('/cms/simple/other-route', new Route('/other-route')); + $collection->set('/cms/routes/not-a-route', $this); + + $this->objectManager + ->expects($this->once()) + ->method('findMany') + ->with(null, $paths) + ->will($this->returnValue($collection)) + ; + $paths[] = '/outside/prefix'; + + $routeProvider = new RouteProvider($this->managerRegistry); + $routeProvider->setManagerName('default'); + $routeProvider->setPrefixes(array('/cms/routes', '/cms/simple')); + $routeProvider->setRouteCollectionLimit(1); + + $collection = $routeProvider->getRoutesByNames($paths); + $this->assertCount(2, $collection); + } + + private function doRouteDump($limit) + { + if ($limit === 0) { + $this->objectManager + ->expects($this->never()) + ->method('createPhpcrQuery') + ; + $this->objectManager + ->expects($this->never()) + ->method('getDocumentsByPhpcrQuery') + ; + } else { + $query = $this->getMock('\PHPCR\Query\QueryInterface'); + $sql2 = 'SELECT * FROM [nt:unstructured] WHERE [phpcr:classparents] = "Symfony\Component\Routing\Route" AND (ISDESCENDANTNODE("/cms/routes") OR ISDESCENDANTNODE("/cms/simple"))'; + $this->objectManager + ->expects($this->once()) + ->method('createPhpcrQuery') + ->with($sql2, QueryInterface::JCR_SQL2) + ->will($this->returnValue($query)) + ; + if ($limit) { + $query + ->expects($this->once()) + ->method('setLimit') + ->with($limit) + ; + } else { + $query + ->expects($this->never()) + ->method('setLimit') + ; + } + $this->objectManager + ->expects($this->once()) + ->method('getDocumentsByPhpcrQuery') + ->with($query) + ->will($this->returnValue(new ArrayCollection())) + ; + $this->objectManager + ->expects($this->any()) + ->method('quote') + ->will( + $this->returnCallback( + function ($text) { + return '"' . $text . '"'; + } + ) + ) + ; + } + + $routeProvider = new RouteProvider($this->managerRegistry); + $routeProvider->setManagerName('default'); + $routeProvider->setPrefixes(array('/cms/routes', '/cms/simple')); + $routeProvider->setRouteCollectionLimit($limit); + + $routeProvider->getRoutesByNames(); + } + + public function testDumpRoutesNoLimit() + { + $this->doRouteDump(null); + } + + public function testDumpRoutesLimit() + { + $this->doRouteDump(1); + } + + public function testDumpRoutesDisabled() + { + $this->doRouteDump(0); } /** @@ -318,6 +392,7 @@ public function testChangingDocumentManager() 'default' => $this->objectManager, 'new_manager' => $this->objectManager2 ); + $this->managerRegistry = $this->getMock('Doctrine\Common\Persistence\ManagerRegistry'); $this->managerRegistry ->expects($this->any()) ->method('getManager') @@ -332,7 +407,7 @@ function ($name) use ($objectManagers) { $routeProvider = new RouteProvider($this->managerRegistry); $routeProvider->setManagerName('default'); - $routeProvider->setPrefix('/cms/routes/'); + $routeProvider->setPrefixes(array('/cms/routes/')); $foundRoute = $routeProvider->getRouteByName('/cms/routes/test-route'); $this->assertInstanceOf('Symfony\Component\Routing\Route', $foundRoute); diff --git a/Tests/Unit/Doctrine/Phpcr/RouteTest.php b/Tests/Unit/Doctrine/Phpcr/RouteTest.php index 2022203b..97d53c15 100644 --- a/Tests/Unit/Doctrine/Phpcr/RouteTest.php +++ b/Tests/Unit/Doctrine/Phpcr/RouteTest.php @@ -10,7 +10,7 @@ */ -namespace Symfony\Cmf\Bundle\RoutingBundle\Tests\Doctrine\Phpcr; +namespace Symfony\Cmf\Bundle\RoutingBundle\Tests\Unit\Doctrine\Phpcr; use Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\Route; From 3eef9cde447d47b44f1a12cab341d28146232e9d Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Thu, 30 Jan 2014 08:56:54 +0100 Subject: [PATCH 02/12] convert settings to options --- Doctrine/Phpcr/LocaleListener.php | 2 +- Doctrine/Phpcr/RedirectRoute.php | 25 +++----- Doctrine/Phpcr/Route.php | 37 ++++++------ Model/Route.php | 60 +++++++------------ Resources/config/doctrine-model/Route.orm.xml | 1 - .../config/doctrine-model/Route.phpcr.xml | 1 - .../doctrine-phpcr/RedirectRoute.phpcr.xml | 1 - .../config/doctrine-phpcr/Route.phpcr.xml | 1 - Tests/Functional/Doctrine/Phpcr/RouteTest.php | 8 +-- .../Functional/Routing/DynamicRouterTest.php | 24 ++++---- .../Doctrine/Phpcr/LocaleListenerTest.php | 6 +- 11 files changed, 70 insertions(+), 96 deletions(-) diff --git a/Doctrine/Phpcr/LocaleListener.php b/Doctrine/Phpcr/LocaleListener.php index daff2b56..4b369553 100644 --- a/Doctrine/Phpcr/LocaleListener.php +++ b/Doctrine/Phpcr/LocaleListener.php @@ -162,7 +162,7 @@ protected function updateLocale(Route $doc, $id, $force = false) $doc->setRequirement('_locale', $locale); } } elseif ($this->addLocalePattern) { - $doc->setAddLocalePattern(true); + $doc->setOption('add_locale_pattern', true); } } } diff --git a/Doctrine/Phpcr/RedirectRoute.php b/Doctrine/Phpcr/RedirectRoute.php index 2b1edf52..a6c3ce04 100644 --- a/Doctrine/Phpcr/RedirectRoute.php +++ b/Doctrine/Phpcr/RedirectRoute.php @@ -12,9 +12,10 @@ namespace Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr; -use Symfony\Cmf\Bundle\CoreBundle\Model\ChildInterface; +use Doctrine\Common\Collections\Collection; use Symfony\Cmf\Bundle\RoutingBundle\Model\RedirectRoute as RedirectRouteModel; use Symfony\Cmf\Component\Routing\RouteObjectInterface; +use Symfony\Cmf\Bundle\CoreBundle\Model\ChildInterface; /** * {@inheritDoc} @@ -45,13 +46,6 @@ class RedirectRoute extends RedirectRouteModel implements PrefixInterface, Child */ protected $children; - /** - * if to add "/" to the pattern - * - * @var Boolean - */ - protected $addTrailingSlash; - /** * The part of the PHPCR path that does not belong to the url * @@ -62,18 +56,17 @@ class RedirectRoute extends RedirectRouteModel implements PrefixInterface, Child protected $idPrefix; /** - * Overwrite to be able to create route without pattern + * Overwrite to be able to create route without pattern. + * + * Additional options: * - * @param bool $addFormatPattern if to add ".{_format}" to the route pattern - * also implicitly sets a default/require on "_format" to "html" - * @param bool $addTrailingSlash whether to add a trailing slash to the route, defaults to not add one + * * add_trailing_slash: When set, a trailing slash is appended to the route */ - public function __construct($addFormatPattern = false, $addTrailingSlash = false) + public function __construct(array $options = array()) { - parent::__construct($addFormatPattern); + parent::__construct($options); $this->children = array(); - $this->addTrailingSlash = $addTrailingSlash; } /** @@ -225,7 +218,7 @@ public function generateStaticPrefix($id, $idPrefix) public function getPath() { $pattern = parent::getPath(); - if ($this->addTrailingSlash && '/' !== $pattern[strlen($pattern)-1]) { + if ($this->getOption('add_trailing_slash') && '/' !== $pattern[strlen($pattern)-1]) { $pattern .= '/'; }; diff --git a/Doctrine/Phpcr/Route.php b/Doctrine/Phpcr/Route.php index 7706ed73..e6c2f94f 100644 --- a/Doctrine/Phpcr/Route.php +++ b/Doctrine/Phpcr/Route.php @@ -49,13 +49,6 @@ class Route extends RouteModel implements PrefixInterface, ChildInterface */ protected $children; - /** - * if to add "/" to the pattern - * - * @var Boolean - */ - protected $addTrailingSlash; - /** * The part of the PHPCR path that does not belong to the url * @@ -66,28 +59,34 @@ class Route extends RouteModel implements PrefixInterface, ChildInterface protected $idPrefix; /** - * PHPCR id can not end on '/', so we need an additional option. + * PHPCR id can not end on '/', so we need an additional option for a + * trailing slash. * - * Additional supported settings are: + * Additional supported option is: * - * * addTrailingSlash: When set, a trailing slash is appended to the route + * * add_trailing_slash: When set, a trailing slash is appended to the route */ - public function __construct(array $settings = array()) + public function __construct(array $options= array()) { - parent::__construct($settings); + parent::__construct($options); $this->children = new ArrayCollection(); - $this->addTrailingSlash = empty($settings['addTrailingSlash']); } + /** + * @deprecated use getOption('add_trailing_slash') instead + */ public function getAddTrailingSlash() { - return $this->addTrailingSlash; + return $this->getOption('add_trailing_slash'); } + /** + * @deprecated use setOption('add_trailing_slash', $add) instead + */ public function setAddTrailingSlash($addTrailingSlash) { - $this->addTrailingSlash = $addTrailingSlash; + $this->setOption('add_trailing_slash', $addTrailingSlash); } /** @@ -221,10 +220,6 @@ public function getStaticPrefix() $path = $this->getId(); $prefix = $this->getPrefix(); - if ($this->addLocalePattern) { - $path = $prefix . '/{_locale}' . substr($path, strlen($prefix)); - } - return $this->generateStaticPrefix($path, $prefix); } @@ -256,11 +251,13 @@ public function generateStaticPrefix($id, $idPrefix) /** * {@inheritDoc} + * + * Handle the trailing slash option. */ public function getPath() { $pattern = parent::getPath(); - if ($this->addTrailingSlash && '/' !== $pattern[strlen($pattern)-1]) { + if ($this->getOption('add_trailing_slash') && '/' !== $pattern[strlen($pattern)-1]) { $pattern .= '/'; }; diff --git a/Model/Route.php b/Model/Route.php index 76054da3..73522432 100644 --- a/Model/Route.php +++ b/Model/Route.php @@ -53,19 +53,6 @@ class Route extends SymfonyRoute implements RouteObjectInterface */ protected $variablePattern; - /** - * Whether to append ".{_format}" to the pattern. - * - * @var Boolean - */ - protected $addFormatPattern; - - /** - * Whether to prepend "{_locale}" to the pattern. - * @var boolean - */ - protected $addLocalePattern; - /** * Whether this route was changed since being last compiled. * @@ -78,46 +65,40 @@ class Route extends SymfonyRoute implements RouteObjectInterface /** * Overwrite to be able to create route without pattern * - * Supported settings are: + * Additional supported options are: * - * * addFormatPattern: When set, ".{_format}" is appended to the route pattern. - * Also implicitly sets a default/require on "_format" to "html". - * * addLocalePattern: When set, "/{_locale}" is prepended to the route pattern. + * * add_format_pattern: When set, ".{_format}" is appended to the route pattern. + * Also implicitly sets a default/require on "_format" to "html". + * * add_locale_pattern: When set, "/{_locale}" is prepended to the route pattern. * - * @param array $settings + * @param array $options */ - public function __construct(array $settings = array()) + public function __construct(array $options = array()) { $this->setDefaults(array()); $this->setRequirements(array()); - $this->setOptions(array()); + $this->setOptions($options); - $this->addFormatPattern = !empty($settings['addFormatPattern']); - if ($this->addFormatPattern) { + if ($this->getOption('add_format_pattern')) { $this->setDefault('_format', 'html'); $this->setRequirement('_format', 'html'); } - $this->addLocalePattern = !empty($settings['addLocalePattern']); } + /** + * @deprecated use getOption('add_format_pattern') instead + */ public function getAddFormatPattern() { - return $this->addFormatPattern; + return $this->getOption('add_format_pattern'); } + /** + * @deprecated use setOption('add_format_pattern', $bool) instead + */ public function setAddFormatPattern($addFormatPattern) { - $this->addFormatPattern = $addFormatPattern; - } - - public function getAddLocalePattern() - { - return $this->addLocalePattern; - } - - public function setAddLocalePattern($addLocalePattern) - { - $this->addLocalePattern = $addLocalePattern; + $this->setOption('add_format_pattern', $addFormatPattern); } /** @@ -235,8 +216,13 @@ public function getPattern() */ public function getPath() { - $pattern = $this->getStaticPrefix() . $this->getVariablePattern(); - if ($this->addFormatPattern && !preg_match('/(.+)\.[a-z]+$/i', $pattern, $matches)) { + $pattern = ''; + if ($this->getOption('add_locale_pattern')) { + $pattern .= '/{_locale}'; + } + $pattern .= $this->getStaticPrefix(); + $pattern .= $this->getVariablePattern(); + if ($this->getOption('add_format_pattern') && !preg_match('/(.+)\.[a-z]+$/i', $pattern, $matches)) { $pattern .= '.{_format}'; }; diff --git a/Resources/config/doctrine-model/Route.orm.xml b/Resources/config/doctrine-model/Route.orm.xml index ef3a76d9..cca534fe 100644 --- a/Resources/config/doctrine-model/Route.orm.xml +++ b/Resources/config/doctrine-model/Route.orm.xml @@ -4,7 +4,6 @@ - diff --git a/Resources/config/doctrine-model/Route.phpcr.xml b/Resources/config/doctrine-model/Route.phpcr.xml index 9280b7f1..d007a8da 100644 --- a/Resources/config/doctrine-model/Route.phpcr.xml +++ b/Resources/config/doctrine-model/Route.phpcr.xml @@ -8,7 +8,6 @@ - diff --git a/Resources/config/doctrine-phpcr/RedirectRoute.phpcr.xml b/Resources/config/doctrine-phpcr/RedirectRoute.phpcr.xml index 6a69c312..07f12b07 100644 --- a/Resources/config/doctrine-phpcr/RedirectRoute.phpcr.xml +++ b/Resources/config/doctrine-phpcr/RedirectRoute.phpcr.xml @@ -9,7 +9,6 @@ - diff --git a/Resources/config/doctrine-phpcr/Route.phpcr.xml b/Resources/config/doctrine-phpcr/Route.phpcr.xml index ba49a4dd..c0f8f000 100644 --- a/Resources/config/doctrine-phpcr/Route.phpcr.xml +++ b/Resources/config/doctrine-phpcr/Route.phpcr.xml @@ -10,7 +10,6 @@ - diff --git a/Tests/Functional/Doctrine/Phpcr/RouteTest.php b/Tests/Functional/Doctrine/Phpcr/RouteTest.php index 038a69b3..84c86da9 100644 --- a/Tests/Functional/Doctrine/Phpcr/RouteTest.php +++ b/Tests/Functional/Doctrine/Phpcr/RouteTest.php @@ -29,7 +29,7 @@ public function setUp() public function testPersist() { - $route = new Route; + $route = new Route(); $root = $this->getDm()->find(null, self::ROUTE_ROOT); $route->setContent($root); // this happens to be a referenceable node @@ -68,7 +68,7 @@ public function testPersist() public function testPersistEmptyOptions() { - $route = new Route; + $route = new Route(); $root = $this->getDm()->find(null, self::ROUTE_ROOT); $route->setPosition($root, 'empty'); @@ -129,13 +129,13 @@ public function testInvalidIdPrefix() */ public function testPrefixNonpersisted() { - $route = new Route; + $route = new Route(); $route->getPattern(); } public function testDefaultFormat() { - $route = new Route(true); + $route = new Route(array('add_format_pattern' => true)); $root = $this->getDm()->find(null, self::ROUTE_ROOT); diff --git a/Tests/Functional/Routing/DynamicRouterTest.php b/Tests/Functional/Routing/DynamicRouterTest.php index f2c3dacf..fe333ee6 100644 --- a/Tests/Functional/Routing/DynamicRouterTest.php +++ b/Tests/Functional/Routing/DynamicRouterTest.php @@ -51,35 +51,37 @@ public function setUp() $root = $this->getDm()->find(null, self::ROUTE_ROOT); // do not set a content here, or we need a valid request and so on... - $route = new Route; + $route = new Route(); $route->setPosition($root, 'testroute'); $route->setVariablePattern('/{slug}/{id}'); $route->setDefault('id', '0'); $route->setRequirement('id', '[0-9]+'); $route->setDefault(RouteObjectInterface::CONTROLLER_NAME, 'testController'); - // TODO: what are the options used for? we should test them too if it makes sense + + //TODO options + $this->getDm()->persist($route); - $childroute = new Route; + $childroute = new Route(); $childroute->setPosition($route, 'child'); $childroute->setDefault(RouteObjectInterface::CONTROLLER_NAME, 'testController'); $this->getDm()->persist($childroute); - $formatroute = new Route(true); + $formatroute = new Route(array('add_format_pattern' => true)); $formatroute->setPosition($root, 'format'); $formatroute->setVariablePattern('/{id}'); $formatroute->setRequirement('_format', 'html|json'); $formatroute->setDefault(RouteObjectInterface::CONTROLLER_NAME, 'testController'); $this->getDm()->persist($formatroute); - $format2jsonroute = new Route(true); + $format2jsonroute = new Route(array('add_format_pattern' => true)); $format2jsonroute->setPosition($root, 'format2.json'); $format2jsonroute->setDefault('_format', 'json'); $format2jsonroute->setRequirement('_format', 'json'); $format2jsonroute->setDefault(RouteObjectInterface::CONTROLLER_NAME, 'testJsonController'); $this->getDm()->persist($format2jsonroute); - $format2route = new Route(true); + $format2route = new Route(array('add_format_pattern' => true)); $format2route->setPosition($root, 'format2'); $format2route->setDefault(RouteObjectInterface::CONTROLLER_NAME, 'testController'); $this->getDm()->persist($format2route); @@ -137,7 +139,7 @@ public function testNotAllowed() $root = $this->getDm()->find(null, self::ROUTE_ROOT); // do not set a content here, or we need a valid request and so on... - $route = new Route; + $route = new Route(); $route->setPosition($root, 'notallowed'); $route->setRequirement('_method', 'GET'); $route->setDefault(RouteObjectInterface::CONTROLLER_NAME, 'testController'); @@ -213,15 +215,15 @@ public function testNoMatchingFormat() public function testMatchLocale() { - $route = new Route; + $route = new Route(); $route->setPosition($this->getDm()->find(null, self::ROUTE_ROOT), 'de'); $route->setDefault(RouteObjectInterface::CONTROLLER_NAME, 'testController'); $this->getDm()->persist($route); - $childroute = new Route; + $childroute = new Route(); $childroute->setPosition($route, 'testroute'); $childroute->setDefault(RouteObjectInterface::CONTROLLER_NAME, 'testController'); $this->getDm()->persist($childroute); - $nolocale = new Route; + $nolocale = new Route(); $nolocale->setPosition($this->getDm()->find(null, self::ROUTE_ROOT), 'es'); $nolocale->setDefault(RouteObjectInterface::CONTROLLER_NAME, 'testController'); $this->getDm()->persist($nolocale); @@ -317,7 +319,7 @@ public function testEnhanceTemplateByClass() // put a route for this content $root = $this->getDm()->find(null, self::ROUTE_ROOT); - $route = new Route; + $route = new Route(); $route->setContent($document); $route->setPosition($root, 'templatebyclass'); $this->getDm()->persist($route); diff --git a/Tests/Unit/Doctrine/Phpcr/LocaleListenerTest.php b/Tests/Unit/Doctrine/Phpcr/LocaleListenerTest.php index 39089af8..3ae6dce5 100644 --- a/Tests/Unit/Doctrine/Phpcr/LocaleListenerTest.php +++ b/Tests/Unit/Doctrine/Phpcr/LocaleListenerTest.php @@ -185,7 +185,7 @@ public function testHaslocale() } /** - * URL without locale, addLocalePattern not set. + * URL without locale, add_locale_pattern not set. */ public function testNolocaleUrl() { @@ -217,8 +217,8 @@ public function testLocalePattern() ; $this->routeMock->expects($this->once()) - ->method('setAddLocalePattern') - ->with(true) + ->method('setOption') + ->with('add_locale_pattern', true) ; $this->listener->setAddLocalePattern(true); From 004dced6417e9f3a9c28bfbc8d52139497dcb32b Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Sat, 1 Feb 2014 11:49:19 +0100 Subject: [PATCH 03/12] candidates strategy --- Admin/RouteAdmin.php | 24 +- CHANGELOG.md | 8 +- DependencyInjection/CmfRoutingExtension.php | 56 +- DependencyInjection/Configuration.php | 26 +- Doctrine/DoctrineProvider.php | 5 +- Doctrine/Orm/RouteProvider.php | 93 ++- Doctrine/Phpcr/IdPrefixListener.php | 15 +- Doctrine/Phpcr/LocaleListener.php | 100 ++- Doctrine/Phpcr/LocaleRouteProvider.php | 123 ---- Doctrine/Phpcr/PrefixCandidates.php | 185 ++++++ Doctrine/Phpcr/RouteProvider.php | 169 ++---- Resources/config/admin-phpcr.xml | 12 +- Resources/config/provider-orm.xml | 8 +- Resources/config/provider-phpcr.xml | 22 +- Resources/config/schema/routing-1.0.xsd | 11 + .../translations/CmfRoutingBundle.de.xliff | 4 + .../translations/CmfRoutingBundle.en.xliff | 4 + .../translations/CmfRoutingBundle.fr.xliff | 4 + .../Doctrine/Phpcr/RouteProviderTest.php | 14 +- Tests/Resources/Fixtures/config/config.php | 6 +- Tests/Resources/Fixtures/config/config.xml | 5 +- Tests/Resources/Fixtures/config/config.yml | 5 +- .../DependencyInjection/ConfigurationTest.php | 6 +- Tests/Unit/Doctrine/Orm/RouteProviderTest.php | 272 ++++++++- .../Doctrine/Phpcr/IdPrefixListenerTest.php | 31 +- .../Doctrine/Phpcr/LocaleListenerTest.php | 57 +- .../Doctrine/Phpcr/PrefixCandidatesTest.php | 167 +++++ .../Unit/Doctrine/Phpcr/RouteProviderTest.php | 569 ++++++++++++------ composer.json | 2 +- 29 files changed, 1379 insertions(+), 624 deletions(-) delete mode 100644 Doctrine/Phpcr/LocaleRouteProvider.php create mode 100644 Doctrine/Phpcr/PrefixCandidates.php create mode 100644 Tests/Unit/Doctrine/Phpcr/PrefixCandidatesTest.php diff --git a/Admin/RouteAdmin.php b/Admin/RouteAdmin.php index e664b59b..aa8b297d 100644 --- a/Admin/RouteAdmin.php +++ b/Admin/RouteAdmin.php @@ -66,8 +66,6 @@ protected function configureFormFields(FormMapper $formMapper) array('choice_list' => array(), 'select_root_node' => true, 'root_node' => $this->routeRoot) ) ->add('name', 'text') - ->add('addFormatPattern', null, array('required' => false, 'help' => 'form.help_add_format_pattern')) - ->add('addTrailingSlash', null, array('required' => false, 'help' => 'form.help_add_trailing_slash')) ->end(); if (null === $this->getParentFieldDescription()) { @@ -76,6 +74,7 @@ protected function configureFormFields(FormMapper $formMapper) ->add('variablePattern', 'text', array('required' => false)) ->add('content', 'doctrine_phpcr_odm_tree', array('choice_list' => array(), 'required' => false, 'root_node' => $this->contentRoot)) ->add('defaults', 'sonata_type_immutable_array', array('keys' => $this->configureFieldsForDefaults())) + ->add('options', 'sonata_type_immutable_array', array('keys' => $this->configureFieldsForOptions())) ->end(); } } @@ -110,7 +109,7 @@ public function getExportFormats() protected function configureFieldsForDefaults() { - $defaults = array( + $defaults = array( '_controller' => array('_controller', 'text', array('required' => false)), '_template' => array('_template', 'text', array('required' => false)), 'type' => array('type', 'cmf_routing_route_type', array( @@ -125,7 +124,7 @@ protected function configureFieldsForDefaults() $defaults[$name] = array($name, 'text', array('required' => false)); } } - + //parse variable pattern and add defaults for it - taken from routecompiler /** @var $route Route */ $route = $this->subject; @@ -142,6 +141,23 @@ protected function configureFieldsForDefaults() return $defaults; } + protected function configureFieldsForOptions() + { + $options = array( + 'addFormatPattern' => array('addFormatPattern', 'text', array('required' => false), array('help' => 'form.help_add_format_pattern')), + 'addTrailingSlash' => array('addTrailingSlash', 'text', array('required' => false), array('help' => 'form.help_add_trailing_slash')), + ); + + $dynamicOptions = $this->getSubject()->getOptions(); + foreach ($dynamicOptions as $name => $value) { + if (!isset($options[$name])) { + $options[$name] = array($name, 'text', array('required' => false)); + } + } + + return $options; + } + public function prePersist($object) { $defaults = array_filter($object->getDefaults()); diff --git a/CHANGELOG.md b/CHANGELOG.md index 3773a8c0..0fc896b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ Changelog ========= +* **2014-03-26**: [ORM] Applied the cleanup for the PHPCR provider to the ORM + provider now: If the route matched a pattern with a format extension, the + format extension is no longer set as route a default. + * **2014-03-25**: setParent() and getParent() are now deprecated. Use setParentDocument() and getParentDocument() instead. Moreover, you should now enable the ChildExtension from the CoreBundle. @@ -8,8 +12,8 @@ Changelog * **2014-03-23**: When using PHPCR-ODM, routes can now be generated with their uuid as route name as well, in addition to the repository path. -* **2013-11-28**: [BC BREAK] the alias attribute of the is - renamed to class in the bundle configuration. +* **2013-11-28**: [BC BREAK for xml configuration] the alias attribute of the + is renamed to class in the bundle configuration. 1.1.0 ----- diff --git a/DependencyInjection/CmfRoutingExtension.php b/DependencyInjection/CmfRoutingExtension.php index ead97c90..5179d31a 100644 --- a/DependencyInjection/CmfRoutingExtension.php +++ b/DependencyInjection/CmfRoutingExtension.php @@ -95,11 +95,11 @@ private function setupDynamicRouter(array $config, ContainerBuilder $container, $container->setParameter($this->getAlias() . '.route_collection_limit', $config['route_collection_limit']); $locales = false; - if (isset($config['locales'])) { + if (!empty($config['locales'])) { $locales = $config['locales']; $container->setParameter($this->getAlias() . '.dynamic.locales', $locales); + $container->setParameter($this->getAlias() . '.dynamic.auto_locale_pattern', $config['auto_locale_pattern']); } - $container->setParameter($this->getAlias() . '.dynamic.auto_locale_pattern', $config['auto_locale_pattern']); $loader->load('routing-dynamic.xml'); @@ -110,13 +110,13 @@ private function setupDynamicRouter(array $config, ContainerBuilder $container, } if ($config['persistence']['phpcr']['enabled']) { - $this->loadPhpcrProvider($config['persistence']['phpcr'], $loader, $container, $locales); + $this->loadPhpcrProvider($config['persistence']['phpcr'], $loader, $container, $locales, $config['match_implicit_locale']); $hasProvider = true; $hasContentRepository = true; } if ($config['persistence']['orm']['enabled']) { - $this->loadOrmProvider($config['persistence']['orm'], $loader, $container); + $this->loadOrmProvider($config['persistence']['orm'], $loader, $container, $locales, $config['match_implicit_locale']); $hasProvider = true; } @@ -227,22 +227,41 @@ private function setupDynamicRouter(array $config, ContainerBuilder $container, } } - public function loadPhpcrProvider($config, XmlFileLoader $loader, ContainerBuilder $container, $locales) + public function loadPhpcrProvider($config, XmlFileLoader $loader, ContainerBuilder $container, $locales, $matchImplicitLocale) { $loader->load('provider-phpcr.xml'); $container->setParameter($this->getAlias() . '.backend_type_phpcr', true); - $container->setParameter($this->getAlias() . '.dynamic.persistence.phpcr.route_basepath', $config['route_basepath']); - $container->setParameter($this->getAlias() . '.dynamic.persistence.phpcr.content_basepath', $config['content_basepath']); - - $container->setParameter($this->getAlias() . '.dynamic.persistence.phpcr.manager_name', $config['manager_name']); - - $container->setAlias($this->getAlias() . '.route_provider', $this->getAlias() . '.phpcr_route_provider'); - $container->setAlias($this->getAlias() . '.content_repository', $this->getAlias() . '.phpcr_content_repository'); + $container->setParameter( + $this->getAlias() . '.dynamic.persistence.phpcr.route_basepaths', + $config['route_basepaths'] + ); + $container->setParameter( + $this->getAlias() . '.dynamic.persistence.phpcr.content_basepath', + $config['content_basepath'] + ); + + $container->setParameter( + $this->getAlias() . '.dynamic.persistence.phpcr.manager_name', + $config['manager_name'] + ); + + $container->setAlias( + $this->getAlias() . '.route_provider', + $this->getAlias() . '.phpcr_route_provider' + ); + $container->setAlias( + $this->getAlias() . '.content_repository', + $this->getAlias() . '.phpcr_content_repository' + ); if (!$locales) { $container->removeDefinition($this->getAlias() . '.phpcrodm_route_locale_listener'); + } elseif (!$matchImplicitLocale) { + // remove all but the prefixes configuration from the service definition. + $definition = $container->getDefinition($this->getAlias() . '.phpcr_candidates_prefix'); + $definition->setArguments(array($definition->getArgument(0))); } if ($config['use_sonata_admin']) { @@ -257,14 +276,25 @@ public function loadSonataPhpcrAdmin($config, XmlFileLoader $loader, ContainerBu return; } + $basePath = empty($config['admin_basepath']) ? reset($config['route_basepaths']) : $config['admin_basepath']; + + $container->setParameter($this->getAlias() . '.dynamic.persistence.phpcr.admin_basepath', $basePath); + + $loader->load('admin-phpcr.xml'); } - public function loadOrmProvider($config, XmlFileLoader $loader, ContainerBuilder $container) + public function loadOrmProvider($config, XmlFileLoader $loader, ContainerBuilder $container, $matchImplicitLocale) { $container->setParameter($this->getAlias() . '.dynamic.persistence.orm.manager_name', $config['manager_name']); $container->setParameter($this->getAlias() . '.backend_type_orm', true); $loader->load('provider-orm.xml'); + + if (!$matchImplicitLocale) { + // remove the locales argument from the candidates + $definition = $container->getDefinition($this->getAlias() . '.orm_candidates'); + $definition->setArguments(array()); + } } /** diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 568dc2a1..ac973538 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -77,9 +77,32 @@ public function getConfigTreeBuilder() ->arrayNode('phpcr') ->addDefaultsIfNotSet() ->canBeEnabled() + ->fixXmlConfig('route_basepath') + ->beforeNormalization() + ->ifTrue(function ($v) { + return isset($v['route_basepath']); + }) + ->then(function ($v) { + $base = isset($v['route_basepaths']) ? $v['route_basepaths'] : array(); + if (is_array($v['route_basepath'])) { + // xml configuration + $base += $v['route_basepath']; + } else { + $base[] = $v['route_basepath']; + } + $v['route_basepaths'] = array_unique($base); + unset($v['route_basepath']); + + return $v; + }) + ->end() ->children() ->scalarNode('manager_name')->defaultNull()->end() - ->scalarNode('route_basepath')->defaultValue('/cms/routes')->end() + ->arrayNode('route_basepaths') + ->prototype('scalar')->end() + ->defaultValue(array('/cms/routes')) + ->end() + ->scalarNode('admin_basepath')->end() ->scalarNode('content_basepath')->defaultValue('/cms/content')->end() ->enumNode('use_sonata_admin') ->beforeNormalization() @@ -122,6 +145,7 @@ public function getConfigTreeBuilder() ->arrayNode('locales') ->prototype('scalar')->end() ->end() + ->booleanNode('match_implicit_locale')->defaultValue(true)->end() ->booleanNode('auto_locale_pattern')->defaultValue(false)->end() ->end() ->end() diff --git a/Doctrine/DoctrineProvider.php b/Doctrine/DoctrineProvider.php index 85c7f1ab..72e058ca 100644 --- a/Doctrine/DoctrineProvider.php +++ b/Doctrine/DoctrineProvider.php @@ -73,8 +73,9 @@ public function setManagerName($managerName) } /** - * Set the limit to apply when calling getRoutesByNames() with null. - * Note that setting the limit to null means no limit applied. + * Set the limit to apply when calling getAllRoutes(). + * + * Setting the limit to null means no limit is applied. * * @param integer|null $routeCollectionLimit */ diff --git a/Doctrine/Orm/RouteProvider.php b/Doctrine/Orm/RouteProvider.php index 64f77b6a..2b365e4e 100644 --- a/Doctrine/Orm/RouteProvider.php +++ b/Doctrine/Orm/RouteProvider.php @@ -12,6 +12,9 @@ namespace Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Orm; +use Doctrine\Common\Persistence\ManagerRegistry; +use Doctrine\Common\Persistence\ObjectRepository; +use Symfony\Cmf\Component\Routing\Candidates\CandidatesInterface; use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Exception\RouteNotFoundException; @@ -32,29 +35,34 @@ class RouteProvider extends DoctrineProvider implements RouteProviderInterface { /** - * @param $url - * - * @return array + * @var CandidatesInterface */ - protected function getCandidates($url) + private $candidatesStrategy; + + public function __construct(ManagerRegistry $managerRegistry, CandidatesInterface $candidatesStrategy, $className) { - $candidates = array(); - if ('/' !== $url) { - if (preg_match('/(.+)\.[a-z]+$/i', $url, $matches)) { - $candidates[] = $url; - $url = $matches[1]; - } + parent::__construct($managerRegistry, $className); + $this->candidatesStrategy = $candidatesStrategy; + } - $part = $url; - while (false !== ($pos = strrpos($part, '/'))) { - $candidates[] = $part; - $part = substr($url, 0, $pos); - } - } + /** + * {@inheritDoc} + */ + public function getRouteCollectionForRequest(Request $request) + { + $collection = new RouteCollection(); - $candidates[] = '/'; + $candidates = $this->candidatesStrategy->getCandidates($request); + if (empty($candidates)) { + return $collection; + } + $routes = $this->getRouteRepository()->findByStaticPrefix($candidates, array('position' => 'ASC')); + /** @var $route Route */ + foreach ($routes as $route) { + $collection->add($route->getName(), $route); + } - return $candidates; + return $collection; } /** @@ -62,7 +70,11 @@ protected function getCandidates($url) */ public function getRouteByName($name) { - $route = $this->getRoutesRepository()->findOneBy(array('name' => $name)); + if (!$this->candidatesStrategy->isCandidate($name)) { + throw new RouteNotFoundException(sprintf('Route "%s" is not handled by this route provider', $name)); + } + + $route = $this->getRouteRepository()->findOneBy(array('name' => $name)); if (!$route) { throw new RouteNotFoundException("No route found for name '$name'"); } @@ -76,19 +88,16 @@ public function getRouteByName($name) public function getRoutesByNames($names = null) { if (null === $names) { - $names = array(); if (0 === $this->routeCollectionLimit) { - return $names; - } - if (null !== $this->routeCollectionLimit) { - return $this->getRoutesRepository()->findBy(array(), null, $this->routeCollectionLimit); + return array(); } - return $this->getRoutesRepository()->findAll(); + return $this->getRouteRepository()->findBy(array(), null, $this->routeCollectionLimit); } $routes = array(); foreach ($names as $name) { + // TODO: if we do findByName with multivalue, we need to filter with isCandidate afterwards try { $routes[] = $this->getRouteByName($name); } catch (RouteNotFoundException $e) { @@ -100,39 +109,9 @@ public function getRoutesByNames($names = null) } /** - * {@inheritDoc} - */ - public function getRouteCollectionForRequest(Request $request) - { - $url = $request->getPathInfo(); - - $candidates = $this->getCandidates($url); - - $collection = new RouteCollection(); - - if (empty($candidates)) { - return $collection; - } - - $routes = $this->getRoutesRepository()->findByStaticPrefix($candidates, array('position' => 'ASC')); - foreach ($routes as $key => $route) { - if (preg_match('/.+\.([a-z]+)$/i', $url, $matches)) { - if ($route->getDefault('_format') === $matches[1]) { - continue; - } - - $route->setDefault('_format', $matches[1]); - } - $collection->add($key, $route); - } - - return $collection; - } - - /** - * @return \Doctrine\Common\Persistence\ObjectRepository + * @return ObjectRepository */ - protected function getRoutesRepository() + protected function getRouteRepository() { return $this->getObjectManager()->getRepository($this->className); } diff --git a/Doctrine/Phpcr/IdPrefixListener.php b/Doctrine/Phpcr/IdPrefixListener.php index 45a7047b..75fae3aa 100644 --- a/Doctrine/Phpcr/IdPrefixListener.php +++ b/Doctrine/Phpcr/IdPrefixListener.php @@ -29,16 +29,19 @@ class IdPrefixListener * Used to ask for the possible prefixes to remove from the repository ID * to create the URL. * - * @var RouteProvider + * @var PrefixCandidates */ - protected $provider; + protected $candidates; /** - * @param RouteProvider $provider + * This listener only makes sense together with the PrefixCandidates + * strategy. + * + * @param PrefixCandidates $candidates */ - public function __construct(RouteProvider $provider) + public function __construct(PrefixCandidates $candidates) { - $this->provider = $provider; + $this->candidates = $candidates; } /** @@ -46,7 +49,7 @@ public function __construct(RouteProvider $provider) */ protected function getPrefixes() { - return $this->provider->getPrefixes(); + return $this->candidates->getPrefixes(); } public function postLoad(LifecycleEventArgs $args) diff --git a/Doctrine/Phpcr/LocaleListener.php b/Doctrine/Phpcr/LocaleListener.php index 4b369553..b9907009 100644 --- a/Doctrine/Phpcr/LocaleListener.php +++ b/Doctrine/Phpcr/LocaleListener.php @@ -12,11 +12,11 @@ namespace Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr; +use Doctrine\Common\Persistence\ManagerRegistry; +use Doctrine\ODM\PHPCR\DocumentManager; use Doctrine\ODM\PHPCR\Event\MoveEventArgs; use Doctrine\Common\Persistence\Event\LifecycleEventArgs; -use Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\Route; - /** * Doctrine PHPCR-ODM listener to update the locale on routes based on the URL. * @@ -34,7 +34,7 @@ class LocaleListener * * @var RouteProvider */ - protected $provider; + protected $candidates; /** * List of possible locales to detect on URL after idPrefix @@ -44,23 +44,46 @@ class LocaleListener protected $locales; /** - * If set, call Route::setAddLocalePattern. - * @var boolean + * Whether to enforce the route option add_locale_pattern. + * + * @var bool */ protected $addLocalePattern; /** - * @param RouteProvider $provider To get prefixes from. - * @param array $locales Locales that should be detected. - * @param bool $addLocalePattern Whether to make route prepend the - * locale pattern if it does not have - * one of the allowed locals in its id. + * Whether to update the _locales requirement based on available + * translations of the document. + * + * This is only done for routes that are translated documents at the same + * time, and only if their path does not start with one of the available + * locales. An example are the CmfSimpleCmsBundle Page documents. + * + * @var bool */ - public function __construct(RouteProvider $provider, array $locales, $addLocalePattern = false) - { - $this->provider = $provider; + protected $updateAvailableTranslations; + + /** + * This listener is built to work with the prefix candidates strategy. + * + * @param PrefixCandidates $candidates To get prefixes from. + * @param array $locales Locales that should be detected. + * @param bool $addLocalePattern Whether to enforce the add_locale_pattern + * option if the route does not have one of + * the allowed locales in its id. + * @param bool $updateAvailableTranslations Whether to update the route document with + * its available translations if it does not + * have one of the allowed locales in its id. + */ + public function __construct( + PrefixCandidates $candidates, + array $locales, + $addLocalePattern = false, + $updateAvailableTranslations = false + ) { + $this->candidates = $candidates; $this->locales = $locales; - $this->addLocalePattern = $addLocalePattern; + $this->setAddLocalePattern($addLocalePattern); + $this->setUpdateAvailableTranslations($updateAvailableTranslations); } /** @@ -84,6 +107,11 @@ public function setAddLocalePattern($addLocalePattern) $this->addLocalePattern = $addLocalePattern; } + public function setUpdateAvailableTranslations($update) + { + $this->updateAvailableTranslations = $update; + } + /** * Update locale after loading a route. * @@ -95,7 +123,7 @@ public function postLoad(LifecycleEventArgs $args) if (! $doc instanceof Route) { return; } - $this->updateLocale($doc, $doc->getId()); + $this->updateLocale($doc, $doc->getId(), $args->getObjectManager()); } /** @@ -109,7 +137,7 @@ public function postPersist(LifecycleEventArgs $args) if (! $doc instanceof Route) { return; } - $this->updateLocale($doc, $doc->getId()); + $this->updateLocale($doc, $doc->getId(), $args->getObjectManager()); } /** @@ -123,7 +151,7 @@ public function postMove(MoveEventArgs $args) if (! $doc instanceof Route) { return; } - $this->updateLocale($doc, $args->getTargetPath(), true); + $this->updateLocale($doc, $args->getTargetPath(), $args->getObjectManager(), true); } /** @@ -131,38 +159,50 @@ public function postMove(MoveEventArgs $args) */ protected function getPrefixes() { - return $this->provider->getPrefixes(); + return $this->candidates->getPrefixes(); } /** * Update the locale of a route if $id starts with the prefix and has a * valid locale right after. * - * @param Route $doc The route object - * @param string $id The id (in move case, this is not the current id - * of $route) - * @param boolean $force Whether to update the locale even if the route - * already has a locale. + * @param Route $doc The route object + * @param string $id The id (in move case, this is not the current + * id of $route). + * @param DocumentManager $dm The document manager to get locales from if + * the setAvailableTranslations option is + * enabled. + * @param boolean $force Whether to update the locale even if the + * route already has a locale. */ - protected function updateLocale(Route $doc, $id, $force = false) + protected function updateLocale(Route $doc, $id, DocumentManager $dm, $force = false) { $matches = array(); - // only update route objects and only if the prefix can match, to allow - // for more than one listener and more than one route root + // only update if the prefix matches, to allow for more than one + // listener and more than one route root. if (! preg_match('#(' . implode('|', $this->getPrefixes()) . ')/([^/]+)(/|$)#', $id, $matches)) { return; } if (in_array($locale = $matches[2], $this->locales)) { - if ($force || ! $doc->getDefault('_locale')) { + if ($force || !$doc->getDefault('_locale')) { $doc->setDefault('_locale', $locale); } - if ($force || ! $doc->getRequirement('_locale')) { + if ($force || !$doc->getRequirement('_locale')) { $doc->setRequirement('_locale', $locale); } - } elseif ($this->addLocalePattern) { - $doc->setOption('add_locale_pattern', true); + } else { + if ($this->addLocalePattern) { + $doc->setOption('add_locale_pattern', true); + } + if ($this->updateAvailableTranslations + && $dm->isDocumentTranslatable($doc) + && !$doc->getRequirement('_locale') + ) { + $locales = $dm->getLocalesFor($doc, true); + $doc->setRequirement('_locale', implode('|', $locales)); + } } } } diff --git a/Doctrine/Phpcr/LocaleRouteProvider.php b/Doctrine/Phpcr/LocaleRouteProvider.php deleted file mode 100644 index f027028a..00000000 --- a/Doctrine/Phpcr/LocaleRouteProvider.php +++ /dev/null @@ -1,123 +0,0 @@ - - */ -class LocaleRouteProvider extends RouteProvider -{ - /** - * The allowed locales. - * - * @var array - */ - protected $locales = array(); - - /** - * The detected locale in this request. - * - * @var string - */ - private $locale; - - /** - * Set the allowed locales. - * - * @param array $locales - */ - public function setLocales(array $locales = array()) - { - $this->locales = $locales; - } - - /** - * {@inheritDoc} - * - * Additionally checks if $url starts with a locale, and if so proposes - * additional candidates without the locale. - */ - protected function getCandidates($url) - { - $directCandidates = parent::getCandidates($url); - - $dirs = explode('/', ltrim($url, '/')); - if (isset($dirs[0]) && in_array($dirs[0], $this->locales)) { - $this->locale = $dirs[0]; - array_shift($dirs); - $url = '/'.implode('/', $dirs); - - // the normal listener "waits" until the routing completes - // as the locale could be defined inside the route - $this->getObjectManager()->getLocaleChooserStrategy()->setLocale($this->locale); - - return array_merge($directCandidates, parent::getCandidates($url)); - } - - return $directCandidates; - } - - protected function configureLocale($route) - { - crap. that if is about simple cms - if ($this->getObjectManager()->isDocumentTranslatable($route)) { - // add locale requirement - if (!$route->getRequirement('_locale')) { - $locales = $this->getObjectManager()->getLocalesFor($route, true); - $route->setRequirement('_locale', implode('|', $locales)); - } - } - } - - /** - * {@inheritDoc} - */ - public function getRouteCollectionForRequest(Request $request) - { - $collection = parent::getRouteCollectionForRequest($request); - foreach ($collection as $route) { - $this->configureLocale($route); - } - - return $collection; - } - - /** - * {@inheritDoc} - */ - public function getRouteByName($name, $parameters = array()) - { - $route = parent::getRouteByName($name, $parameters); - $this->configureLocale($route); - - return $route; - } - - /** - * {@inheritDoc} - */ - public function getRoutesByNames($names = null) - { - $collection = parent::getRoutesByNames($names); - foreach ($collection as $route) { - $this->configureLocale($route); - } - - return $collection; - } -} diff --git a/Doctrine/Phpcr/PrefixCandidates.php b/Doctrine/Phpcr/PrefixCandidates.php new file mode 100644 index 00000000..330cc2d8 --- /dev/null +++ b/Doctrine/Phpcr/PrefixCandidates.php @@ -0,0 +1,185 @@ + + */ +class PrefixCandidates extends Candidates +{ + /** + * Places in the PHPCR tree where routes are located. + * + * @var array + */ + protected $idPrefixes = array(); + + /** + * @var string + */ + protected $managerName; + + /** + * @var ManagerRegistry + */ + protected $doctrine; + + /** + * @param array $prefixes The prefixes to use. If one of them is + * an empty string, the whole repository + * is used for routing. + * @param array $locales Allowed locales. + * @param ManagerRegistry $doctrine Used when the URL matches one of the + * $locales. This must be the same + * document manager as the RouteProvider + * is using. + */ + public function __construct(array $prefixes, array $locales = array(), ManagerRegistry $doctrine = null) + { + parent::__construct($locales); + $this->setPrefixes($prefixes); + $this->doctrine = $doctrine; + } + + /** + * {@inheritDoc} + * + * A name is a candidate if it starts with one of the prefixes + */ + public function isCandidate($name) + { + foreach ($this->getPrefixes() as $prefix) { + // $name is the route document path + if ($name === $prefix || 0 === strpos($name, $prefix . '/')) { + return true; + } + } + + return false; + } + + /** + * {@inheritDoc} + * + * @param QueryBuilder $queryBuilder + */ + public function restrictQuery($queryBuilder) + { + $prefixes = $this->getPrefixes(); + if (array_search('', $prefixes) || !count($prefixes)) { + return; + } + + $where = $queryBuilder->andWhere()->orX(); + foreach ($prefixes as $prefix) { + $where->descendant($prefix, $queryBuilder->getPrimaryAlias()); + } + } + + /** + * {@inheritDoc} + */ + public function getCandidates(Request $request) + { + $candidates = array(); + $url = $request->getPathInfo(); + foreach ($this->getPrefixes() as $prefix) { + $candidates = array_unique(array_merge($candidates, $this->getCandidatesFor($url, $prefix))); + } + + $locale = $this->determineLocale($url); + if ($locale) { + $url = substr($url, strlen($locale) + 1); + foreach ($this->getPrefixes() as $prefix) { + $candidates = array_unique(array_merge($candidates, $this->getCandidatesFor($url, $prefix))); + } + } + + return $candidates; + } + + /** + * Set the prefixes handled by this strategy. + * + * @param array $prefixes List of prefixes, possibly including ''. + */ + public function setPrefixes(array $prefixes) + { + $this->idPrefixes = $prefixes; + } + + /** + * Append a prefix to the allowed prefixes. + * + * @param string $prefix A prefix + */ + public function addPrefix($prefix) + { + $this->idPrefixes[] = $prefix; + } + + /** + * Get all currently configured prefixes where to look for routes. + * + * @return array The prefixes. + */ + public function getPrefixes() + { + return $this->idPrefixes; + } + + /** + * Set the doctrine document manager name. + * + * @param string $manager + */ + public function setManagerName($manager) + { + $this->managerName = $manager; + } + + /** + * {@inheritDoc} + * + * The normal phpcr-odm locale listener "waits" until the routing completes + * as the locale is usually defined inside the route. We need to set it + * already in case the route document itself is translated. + * + * For example the CmfSimpleCmsBundle Page documents. + */ + protected function determineLocale($url) + { + $locale = parent::determineLocale($url); + if ($locale && $this->doctrine) { + $this->getDocumentManager()->getLocaleChooserStrategy()->setLocale($locale); + } + + return $locale; + } + + /** + * @return DocumentManager The document manager + */ + protected function getDocumentManager() + { + return $this->doctrine->getManager($this->managerName); + } + +} diff --git a/Doctrine/Phpcr/RouteProvider.php b/Doctrine/Phpcr/RouteProvider.php index e3934123..89358009 100644 --- a/Doctrine/Phpcr/RouteProvider.php +++ b/Doctrine/Phpcr/RouteProvider.php @@ -9,24 +9,22 @@ * file that was distributed with this source code. */ - namespace Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr; -use Doctrine\ODM\PHPCR\DocumentManager; - use PHPCR\Query\QueryInterface; -use PHPCR\RepositoryException; - use PHPCR\Query\RowInterface; - +use PHPCR\RepositoryException; use PHPCR\Util\UUIDHelper; +use Doctrine\Common\Persistence\ManagerRegistry; +use Doctrine\ODM\PHPCR\DocumentManager; + use Symfony\Component\Routing\Route as SymfonyRoute; use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Exception\RouteNotFoundException; - use Symfony\Component\HttpFoundation\Request; use Symfony\Cmf\Component\Routing\RouteProviderInterface; +use Symfony\Cmf\Component\Routing\Candidates\CandidatesInterface; use Symfony\Cmf\Bundle\RoutingBundle\Doctrine\DoctrineProvider; @@ -42,38 +40,14 @@ class RouteProvider extends DoctrineProvider implements RouteProviderInterface { /** - * Places in the PHPCR tree where routes are located. - * - * @var array - */ - protected $idPrefixes = array(); - - /** - * @param $prefix - */ - public function setPrefixes($prefixes) - { - $this->idPrefixes = $prefixes; - } - - /** - * Append a repository prefix to the possible prefixes. - * - * @param $prefix + * @var CandidatesInterface */ - public function addPrefix($prefix) - { - $this->idPrefixes[] = $prefix; - } + private $candidatesStrategy; - /** - * Get all currently configured prefixes where to look for routes. - * - * @return array - */ - public function getPrefixes() + public function __construct(ManagerRegistry $managerRegistry, CandidatesInterface $candidatesStrategy, $className = null) { - return $this->idPrefixes; + parent::__construct($managerRegistry, $className); + $this->candidatesStrategy = $candidatesStrategy; } /** @@ -86,8 +60,7 @@ public function getPrefixes() */ public function getRouteCollectionForRequest(Request $request) { - $url = $request->getPathInfo(); - $candidates = $this->getCandidates($url); + $candidates = $this->candidatesStrategy->getCandidates($request); $collection = new RouteCollection(); @@ -116,52 +89,6 @@ public function getRouteCollectionForRequest(Request $request) return $collection; } - /** - * Get id candidates for all configured prefixes. - * - * @param string $url - * - * @return array PHPCR ids that could load routes that match $url. - */ - protected function getCandidates($url) - { - $candidates = array(); - foreach ($this->getPrefixes() as $prefix) { - $candidates = array_merge($candidates, $this->getCandidatesFor($prefix, $url)); - } - - return $candidates; - } - - /** - * Get the id candidates for one prefix. - * - * @param string $url - * - * @return array PHPCR ids that could load routes that match $url and are - * child of $prefix. - */ - protected function getCandidatesFor($prefix, $url) - { - $candidates = array(); - if ('/' !== $url) { - if (preg_match('/(.+)\.[a-z]+$/i', $url, $matches)) { - $candidates[] = $prefix . $url; - $url = $matches[1]; - } - - $part = $url; - while (false !== ($pos = strrpos($part, '/'))) { - $candidates[] = $prefix . $part; - $part = substr($url, 0, $pos); - } - } - - $candidates[] = $prefix; - - return $candidates; - } - /** * {@inheritDoc} * @@ -172,23 +99,20 @@ public function getRouteByName($name) if (UUIDHelper::isUUID($name)) { $route = $this->getObjectManager()->find($this->className, $name); if ($route - && '' !== $this->idPrefix - && 0 !== strpos($this->getObjectManager()->getUnitOfWork()->getDocumentId($route), $this->idPrefix) + && !$this->candidatesStrategy->isCandidate($this->getObjectManager()->getUnitOfWork()->getDocumentId($route)) ) { - $route = null; + throw new RouteNotFoundException( + sprintf( + 'Route with uuid "%s" and id "%s" is not handled by this route provider', + $name, + $this->getObjectManager()->getUnitOfWork()->getDocumentId($route) + ) + ); } + } elseif (!$this->candidatesStrategy->isCandidate($name)) { + throw new RouteNotFoundException(sprintf('Route name "%s" is not handled by this route provider', $name)); } else { $route = $this->getObjectManager()->find($this->className, $name); - - foreach ($this->getPrefixes() as $prefix) { - // $name is the route document path - if ('' === $prefix || 0 === strpos($name, $prefix)) { - $route = $this->getObjectManager()->find($this->className, $name); - if ($route) { - break; - } - } - } } if (empty($route)) { @@ -216,26 +140,18 @@ private function getAllRoutes() /** @var $dm DocumentManager */ $dm = $this->getObjectManager(); - $sql2 = 'SELECT * FROM [nt:unstructured] WHERE [phpcr:classparents] = '.$dm->quote('Symfony\Component\Routing\Route'); + $qb = $dm->createQueryBuilder(); - $prefixConstraints = array(); - foreach ($this->getPrefixes() as $prefix) { - if ('' == $prefix) { - $prefixConstraints = array(); - break; - } - $prefixConstraints[] = 'ISDESCENDANTNODE('.$dm->quote($prefix).')'; - } - if ($prefixConstraints) { - $sql2 .= ' AND (' . implode(' OR ', $prefixConstraints) . ')'; - } + $qb->from('d')->document('Symfony\Component\Routing\Route', 'd'); - $query = $dm->createPhpcrQuery($sql2, QueryInterface::JCR_SQL2); + $this->candidatesStrategy->restrictQuery($qb); + + $query = $qb->getQuery(); if (null !== $this->routeCollectionLimit) { - $query->setLimit($this->routeCollectionLimit); + $query->setMaxResults($this->routeCollectionLimit); } - return $dm->getDocumentsByPhpcrQuery($query); + return $query->getResult(); } /** @@ -249,19 +165,8 @@ public function getRoutesByNames($names = null) $candidates = array(); foreach ($names as $key => $name) { - if (UUIDHelper::isUUID($name)) { - continue; - } - foreach ($this->getPrefixes() as $prefix) { - if ('' == $prefix) { - $candidates = $names; - break 2; - } - foreach ($names as $key => $name) { - if (0 === strpos($name, $prefix)) { - $candidates[$key] = $name; - } - } + if (UUIDHelper::isUUID($name) || $this->candidatesStrategy->isCandidate($name)) { + $candidates[$key] = $name; } } @@ -271,14 +176,20 @@ public function getRoutesByNames($names = null) /** @var $dm DocumentManager */ $dm = $this->getObjectManager(); - $collection = $dm->findMany($this->className, $candidates); - foreach ($collection as $key => $document) { + $documents = $dm->findMany($this->className, $candidates); + foreach ($documents as $key => $document) { + if (UUIDHelper::isUUID($key) + && !$this->candidatesStrategy->isCandidate($this->getObjectManager()->getUnitOfWork()->getDocumentId($document)) + ) { + // this uuid pointed out of our path. can only determine after fetching the document + unset($documents[$key]); + } if (!$document instanceof SymfonyRoute) { // we follow the logic of DocumentManager::findMany and do not throw an exception - unset($collection[$key]); + unset($documents[$key]); } } - return $collection; + return $documents; } } diff --git a/Resources/config/admin-phpcr.xml b/Resources/config/admin-phpcr.xml index a32c80ef..ac23d55f 100644 --- a/Resources/config/admin-phpcr.xml +++ b/Resources/config/admin-phpcr.xml @@ -29,7 +29,7 @@ - %cmf_routing.dynamic.persistence.phpcr.route_basepath% + %cmf_routing.dynamic.persistence.phpcr.admin_basepath% @@ -47,7 +47,7 @@ - %cmf_routing.dynamic.persistence.phpcr.route_basepath% + %cmf_routing.dynamic.persistence.phpcr.admin_basepath% @@ -55,5 +55,13 @@ + + CmfRoutingBundle + + %cmf_routing.dynamic.persistence.phpcr.admin_basepath% + + + + diff --git a/Resources/config/provider-orm.xml b/Resources/config/provider-orm.xml index 0fcb7c56..572b0e70 100644 --- a/Resources/config/provider-orm.xml +++ b/Resources/config/provider-orm.xml @@ -5,6 +5,7 @@ Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Orm\Route + Symfony\Cmf\Component\Routing\Candidates\Candidates Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Orm\RouteProvider Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Orm\ContentRepository @@ -16,8 +17,13 @@ %cmf_routing.dynamic.persistence.orm.manager_name% + + %cmf_routing.dynamic.locales% + + - + + %cmf_routing.route_entity.class% %cmf_routing.dynamic.persistence.orm.manager_name% %cmf_routing.route_collection_limit% diff --git a/Resources/config/provider-phpcr.xml b/Resources/config/provider-phpcr.xml index 0e15c786..68b133a5 100644 --- a/Resources/config/provider-phpcr.xml +++ b/Resources/config/provider-phpcr.xml @@ -5,6 +5,7 @@ Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\RouteProvider + Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\PrefixCandidates Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\ContentRepository Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\IdPrefixListener Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\LocaleListener @@ -14,26 +15,33 @@ + %cmf_routing.route_model.class% %cmf_routing.dynamic.persistence.phpcr.manager_name% - %cmf_routing.dynamic.persistence.phpcr.route_basepath% %cmf_routing.route_collection_limit% + + %cmf_routing.dynamic.persistence.phpcr.route_basepaths% + %cmf_routing.dynamic.locales% + + %cmf_routing.dynamic.persistence.phpcr.manager_name% + + %cmf_routing.dynamic.persistence.phpcr.manager_name% - + - + %cmf_routing.dynamic.locales% %cmf_routing.dynamic.auto_locale_pattern% @@ -41,13 +49,5 @@ - - CmfRoutingBundle - - %cmf_routing.dynamic.persistence.phpcr.route_basepath% - - - - diff --git a/Resources/config/schema/routing-1.0.xsd b/Resources/config/schema/routing-1.0.xsd index 04ed1524..e4bf1200 100644 --- a/Resources/config/schema/routing-1.0.xsd +++ b/Resources/config/schema/routing-1.0.xsd @@ -40,6 +40,7 @@ + @@ -74,6 +75,10 @@ + + + + @@ -81,6 +86,12 @@ + + + + + + diff --git a/Resources/translations/CmfRoutingBundle.de.xliff b/Resources/translations/CmfRoutingBundle.de.xliff index 8caf9a03..52be18df 100644 --- a/Resources/translations/CmfRoutingBundle.de.xliff +++ b/Resources/translations/CmfRoutingBundle.de.xliff @@ -78,6 +78,10 @@ form.label_defaults Vorgabewerte + + form.label_options + Optionen + form.label_route_name Name diff --git a/Resources/translations/CmfRoutingBundle.en.xliff b/Resources/translations/CmfRoutingBundle.en.xliff index a77a30d8..4a2782c8 100644 --- a/Resources/translations/CmfRoutingBundle.en.xliff +++ b/Resources/translations/CmfRoutingBundle.en.xliff @@ -78,6 +78,10 @@ form.label_defaults Defaults + + form.label_options + Options + form.label_route_name Name diff --git a/Resources/translations/CmfRoutingBundle.fr.xliff b/Resources/translations/CmfRoutingBundle.fr.xliff index 273afa34..25cab981 100644 --- a/Resources/translations/CmfRoutingBundle.fr.xliff +++ b/Resources/translations/CmfRoutingBundle.fr.xliff @@ -78,6 +78,10 @@ form.label_defaults Defauts + + form.label_options + Options + form.label_route_name Nom diff --git a/Tests/Functional/Doctrine/Phpcr/RouteProviderTest.php b/Tests/Functional/Doctrine/Phpcr/RouteProviderTest.php index 899a9858..b5123f54 100644 --- a/Tests/Functional/Doctrine/Phpcr/RouteProviderTest.php +++ b/Tests/Functional/Doctrine/Phpcr/RouteProviderTest.php @@ -20,7 +20,7 @@ use Symfony\Cmf\Bundle\RoutingBundle\Tests\Functional\BaseTestCase; -class RouteRepositoryTest extends BaseTestCase +class RouteProviderTest extends BaseTestCase { const ROUTE_ROOT = '/test/routing'; @@ -65,7 +65,7 @@ public function testGetRouteCollectionForRequest() $routes = $this->repository->getRouteCollectionForRequest(Request::create('/testroute/noroute/child')); $this->assertCount(3, $routes); - $this->assertContainsOnlyInstancesOf('Symfony\\Cmf\\Component\\Routing\\RouteObjectInterface', $routes); + $this->assertContainsOnlyInstancesOf('Symfony\Cmf\Component\Routing\RouteObjectInterface', $routes); $routes = $routes->all(); list($key, $child) = each($routes); @@ -102,7 +102,7 @@ public function testGetRouteCollectionForRequestFormat() public function testGetRouteCollectionForRequestNophpcrUrl() { $collection = $this->repository->getRouteCollectionForRequest(Request::create(':///')); - $this->assertInstanceOf('Symfony\\Component\\Routing\\RouteCollection', $collection); + $this->assertInstanceOf('Symfony\Component\Routing\RouteCollection', $collection); $this->assertCount(0, $collection); } @@ -118,12 +118,6 @@ public function testGetRoutesByNames() $routes = $this->repository->getRoutesByNames($routeNames); $this->assertCount(2, $routes); - $this->assertContainsOnlyInstancesOf('Symfony\\Cmf\\Component\\Routing\\RouteObjectInterface', $routes); - } - - - public function testSetPrefixes() - { - $this->repository->setPrefixes(array(self::ROUTE_ROOT)); + $this->assertContainsOnlyInstancesOf('Symfony\Cmf\Component\Routing\RouteObjectInterface', $routes); } } diff --git a/Tests/Resources/Fixtures/config/config.php b/Tests/Resources/Fixtures/config/config.php index 9cd9c49d..af09e474 100644 --- a/Tests/Resources/Fixtures/config/config.php +++ b/Tests/Resources/Fixtures/config/config.php @@ -21,12 +21,16 @@ ), 'persistence' => array( 'phpcr' => array( - 'route_basepath' => '/cms/routes', + 'route_basepaths' => array( + '/cms/routes', + '/simple', + ), 'content_basepath' => '/cms/content', 'use_sonata_admin' => 'false', ), ), 'locales' => array('en', 'fr'), 'auto_locale_pattern' => true, + 'match_implicit_locale' => true, ), )); diff --git a/Tests/Resources/Fixtures/config/config.xml b/Tests/Resources/Fixtures/config/config.xml index f218d727..90213d8d 100644 --- a/Tests/Resources/Fixtures/config/config.xml +++ b/Tests/Resources/Fixtures/config/config.xml @@ -11,6 +11,7 @@ acme_main.some_controller:editableAction @@ -25,7 +26,9 @@ route-basepath="/cms/routes" content-basepath="/cms/content" use-sonata-admin="false" - /> + > + /simple + en diff --git a/Tests/Resources/Fixtures/config/config.yml b/Tests/Resources/Fixtures/config/config.yml index 542ebcd1..02801b90 100644 --- a/Tests/Resources/Fixtures/config/config.yml +++ b/Tests/Resources/Fixtures/config/config.yml @@ -14,8 +14,11 @@ cmf_routing: Symfony\Cmf\Bundle\ContentBundle\Document\StaticContent: CmfContentBundle:StaticContent:index.html.twig persistence: phpcr: - route_basepath: /cms/routes + route_basepaths: + - /cms/routes + - /simple content_basepath: /cms/content use_sonata_admin: false locales: [en, fr] auto_locale_pattern: true + match_implicit_locale: true diff --git a/Tests/Unit/DependencyInjection/ConfigurationTest.php b/Tests/Unit/DependencyInjection/ConfigurationTest.php index 68a150f7..e6663ae1 100644 --- a/Tests/Unit/DependencyInjection/ConfigurationTest.php +++ b/Tests/Unit/DependencyInjection/ConfigurationTest.php @@ -53,7 +53,10 @@ public function testSupportsAllConfigFormats() 'persistence' => array( 'phpcr' => array( 'enabled' => true, - 'route_basepath' => '/cms/routes', + 'route_basepaths' => array( + '/cms/routes', + '/simple', + ), 'content_basepath' => '/cms/content', 'manager_name' => null, 'use_sonata_admin' => false, @@ -69,6 +72,7 @@ public function testSupportsAllConfigFormats() 'route_filters_by_id' => array(), 'locales' => array('en', 'fr'), 'auto_locale_pattern' => true, + 'match_implicit_locale' => true, ), ); diff --git a/Tests/Unit/Doctrine/Orm/RouteProviderTest.php b/Tests/Unit/Doctrine/Orm/RouteProviderTest.php index 80f4fdf4..56f7ec67 100644 --- a/Tests/Unit/Doctrine/Orm/RouteProviderTest.php +++ b/Tests/Unit/Doctrine/Orm/RouteProviderTest.php @@ -12,62 +12,272 @@ namespace Symfony\Cmf\Bundle\RoutingBundle\Tests\Doctrine\Orm; +use Doctrine\Common\Persistence\ManagerRegistry; +use Doctrine\Common\Persistence\ObjectManager; +use Doctrine\ORM\EntityRepository; +use Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Orm\Route; use Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Orm\RouteProvider; +use Symfony\Cmf\Component\Routing\Candidates\CandidatesInterface; +use Symfony\Cmf\Component\Routing\Test\CmfUnitTestCase; +use Symfony\Component\HttpFoundation\Request; -class RouteProviderTest extends \PHPUnit_Framework_Testcase +class RouteProviderTest extends CmfUnitTestCase { - private $route; - private $managerRegistry; - private $objectManager; - private $objectRepository; + /** + * @var Route|\PHPUnit_Framework_MockObject_MockObject + */ + private $routeMock; - public function setUp() - { - $this->route = $this->getMockBuilder('Symfony\Component\Routing\Route') - ->disableOriginalConstructor() - ->getMock(); - $this->objectManager = $this->getMock('Doctrine\Common\Persistence\ObjectManager'); - $this->managerRegistry = $this->getMock('Doctrine\Common\Persistence\ManagerRegistry'); - $this->objectRepository = $this->getMock('Doctrine\Common\Persistence\ObjectRepository'); - } + /** + * @var Route|\PHPUnit_Framework_MockObject_MockObject + */ + private $route2Mock; - public function testGetRouteByName() + /** + * @var ManagerRegistry|\PHPUnit_Framework_MockObject_MockObject + */ + private $managerRegistryMock; + + /** + * @var ObjectManager|\PHPUnit_Framework_MockObject_MockObject + */ + private $objectManagerMock; + + /** + * @var EntityRepository|\PHPUnit_Framework_MockObject_MockObject + */ + private $objectRepositoryMock; + + /** + * @var CandidatesInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $candidatesMock; + + public function setUp() { - $this->route + $this->routeMock = $this->buildMock('Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Orm\Route'); + $this->route2Mock = $this->buildMock('Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Orm\Route'); + $this->objectManagerMock = $this->getMock('Doctrine\Common\Persistence\ObjectManager'); + $this->managerRegistryMock = $this->getMock('Doctrine\Common\Persistence\ManagerRegistry'); + $this->objectRepositoryMock = $this->getMock('Doctrine\Orm\EntityRepository', array('findByStaticPrefix', 'findOneBy', 'findBy')); + $this->candidatesMock = $this->getMock('Symfony\Cmf\Component\Routing\Candidates\CandidatesInterface'); + $this->candidatesMock ->expects($this->any()) - ->method('getPath') - ->will($this->returnValue('/cms/routes/test-route')); + ->method('isCandidate') + ->will($this->returnValue(true)) + ; - $this->objectManager + $this->managerRegistryMock + ->expects($this->any()) + ->method('getManager') + ->will($this->returnValue($this->objectManagerMock)) + ; + $this->objectManagerMock ->expects($this->any()) ->method('getRepository') - ->will($this->returnValue($this->objectRepository)) + ->with('Route') + ->will($this->returnValue($this->objectRepositoryMock)) + ; + } + + public function testGetRouteCollectionForRequest() + { + $request = Request::create('/my/path'); + $candidates = array('/my/path', '/my', '/'); + + $this->candidatesMock + ->expects($this->once()) + ->method('getCandidates') + ->with($request) + ->will($this->returnValue($candidates)) ; - $this->objectRepository + $this->routeMock + ->expects($this->once()) + ->method('getName') + ->will($this->returnValue('/my/path')) + ; + $this->route2Mock + ->expects($this->once()) + ->method('getName') + ->will($this->returnValue('/my')) + ; + $objects = array( + $this->routeMock, + $this->route2Mock, + ); + + $this->objectRepositoryMock + ->expects($this->once()) + ->method('findByStaticPrefix') + ->with($candidates, array('position' => 'ASC')) + ->will($this->returnValue($objects)) + ; + + $routeProvider = new RouteProvider($this->managerRegistryMock, $this->candidatesMock, 'Route'); + $collection = $routeProvider->getRouteCollectionForRequest($request); + $this->assertInstanceOf('Symfony\Component\Routing\RouteCollection', $collection); + $this->assertCount(2, $collection); + } + + public function testGetRouteCollectionForRequestEmpty() + { + $request = Request::create('/my/path'); + + $this->candidatesMock + ->expects($this->once()) + ->method('getCandidates') + ->with($request) + ->will($this->returnValue(array())) + ; + + $this->objectRepositoryMock + ->expects($this->never()) + ->method('findByStaticPrefix') + ; + + $routeProvider = new RouteProvider($this->managerRegistryMock, $this->candidatesMock, 'Route'); + $collection = $routeProvider->getRouteCollectionForRequest($request); + $this->assertInstanceOf('Symfony\Component\Routing\RouteCollection', $collection); + $this->assertCount(0, $collection); + } + + public function testGetRouteByName() + { + $this->objectRepositoryMock ->expects($this->any()) ->method('findOneBy') - ->with(array('name' => '/cms/routes/test-route')) - ->will($this->returnValue($this->route)) + ->with(array('name' => '/test-route')) + ->will($this->returnValue($this->routeMock)) ; - $this->managerRegistry + $routeProvider = new RouteProvider($this->managerRegistryMock, $this->candidatesMock, 'Route'); + $routeProvider->setManagerName('default'); + + $foundRoute = $routeProvider->getRouteByName('/test-route'); + + $this->assertSame($this->routeMock, $foundRoute); + } + + /** + * @expectedException \Symfony\Component\Routing\Exception\RouteNotFoundException + */ + public function testGetRouteByNameNotFound() + { + $this->objectRepositoryMock ->expects($this->any()) - ->method('getManager') - ->will($this->returnValue($this->objectManager)) + ->method('findOneBy') + ->with(array('name' => '/test-route')) + ->will($this->returnValue(null)) ; - $routeProvider = new RouteProvider($this->managerRegistry); + $routeProvider = new RouteProvider($this->managerRegistryMock, $this->candidatesMock, 'Route'); $routeProvider->setManagerName('default'); - $foundRoute = $routeProvider->getRouteByName('/cms/routes/test-route'); + $routeProvider->getRouteByName('/test-route'); + } + + /** + * @expectedException \Symfony\Component\Routing\Exception\RouteNotFoundException + */ + public function testGetRouteByNameNotCandidate() + { + $this->objectRepositoryMock + ->expects($this->never()) + ->method('findOneBy') + ; + $candidatesMock = $this->getMock('Symfony\Cmf\Component\Routing\Candidates\CandidatesInterface'); + $candidatesMock + ->expects($this->once()) + ->method('isCandidate') + ->with('/test-route') + ->will($this->returnValue(false)) + ; + + $routeProvider = new RouteProvider($this->managerRegistryMock, $candidatesMock, 'Route'); + $routeProvider->setManagerName('default'); - $this->assertInstanceOf('Symfony\Component\Routing\Route', $foundRoute); - $this->assertEquals('/cms/routes/test-route', $foundRoute->getPath()); + $routeProvider->getRouteByName('/test-route'); } public function testGetRoutesByNames() { - $this->markTestIncomplete(); + $paths = array( + '/test-route', + '/other-route', + ); + + $this->objectRepositoryMock + ->expects($this->at(0)) + ->method('findOneBy') + ->with(array('name' => $paths[0])) + ->will($this->returnValue($this->routeMock)) + ; + $this->objectRepositoryMock + ->expects($this->at(1)) + ->method('findOneBy') + ->with(array('name' => $paths[1])) + ->will($this->returnValue($this->routeMock)) + ; + + $paths[] = '/no-candidate'; + + $candidatesMock = $this->getMock('Symfony\Cmf\Component\Routing\Candidates\CandidatesInterface'); + $candidatesMock + ->expects($this->at(0)) + ->method('isCandidate') + ->with($paths[0]) + ->will($this->returnValue(true)) + ; + $candidatesMock + ->expects($this->at(1)) + ->method('isCandidate') + ->with($paths[1]) + ->will($this->returnValue(true)) + ; + $candidatesMock + ->expects($this->at(2)) + ->method('isCandidate') + ->with($paths[2]) + ->will($this->returnValue(false)) + ; + + $routeProvider = new RouteProvider($this->managerRegistryMock, $candidatesMock, 'Route'); + $routeProvider->setManagerName('default'); + + $routes = $routeProvider->getRoutesByNames($paths); + $this->assertCount(2, $routes); + } + + public function testGetAllRoutesDisabled() + { + $this->objectRepositoryMock + ->expects($this->never()) + ->method('findBy') + ; + + $routeProvider = new RouteProvider($this->managerRegistryMock, $this->candidatesMock, 'Route'); + $routeProvider->setRouteCollectionLimit(0); + $routeProvider->setManagerName('default'); + + $routes = $routeProvider->getRoutesByNames(null); + $this->assertCount(0, $routes); + } + + public function testGetAllRoutes() + { + $this->objectRepositoryMock + ->expects($this->once()) + ->method('findBy') + ->with(array(), null, 42) + ->will($this->returnValue(array($this->routeMock))) + ; + + $routeProvider = new RouteProvider($this->managerRegistryMock, $this->candidatesMock, 'Route'); + $routeProvider->setManagerName('default'); + $routeProvider->setRouteCollectionLimit(42); + + $routes = $routeProvider->getRoutesByNames(null); + $this->assertCount(1, $routes); } } diff --git a/Tests/Unit/Doctrine/Phpcr/IdPrefixListenerTest.php b/Tests/Unit/Doctrine/Phpcr/IdPrefixListenerTest.php index 84675951..187dd945 100644 --- a/Tests/Unit/Doctrine/Phpcr/IdPrefixListenerTest.php +++ b/Tests/Unit/Doctrine/Phpcr/IdPrefixListenerTest.php @@ -13,28 +13,39 @@ namespace Symfony\Cmf\Bundle\RoutingBundle\Tests\Doctrine\Phpcr; use Doctrine\Common\Persistence\Event\LifecycleEventArgs; +use Doctrine\ODM\PHPCR\DocumentManager; use Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\IdPrefixListener; +use Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\Route; +use Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\PrefixCandidates; use Symfony\Cmf\Component\Routing\Test\CmfUnitTestCase; class IdPrefixListenerTest extends CmfUnitTestCase { - protected $provider; - protected $dmMock; - protected $routeMock; - /** * @var IdPrefixListener */ protected $listener; + /** + * @var PrefixCandidates|\PHPUnit_Framework_MockObject_MockObject + */ + protected $candidatesMock; + + /** + * @var DocumentManager|\PHPUnit_Framework_MockObject_MockObject + */ + protected $dmMock; + + /** + * @var Route|\PHPUnit_Framework_MockObject_MockObject + */ + protected $routeMock; + public function setUp() { - $this->provider = $this->getMockBuilder('Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\RouteProvider') - ->disableOriginalConstructor() - ->getMock() - ; - $this->provider + $this->candidatesMock = $this->buildMock('Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\PrefixCandidates'); + $this->candidatesMock ->expects($this->any()) ->method('getPrefixes') ->will($this->returnValue(array('/cms/routes', '/cms/simple'))) @@ -42,7 +53,7 @@ public function setUp() $this->dmMock = $this->buildMock('Doctrine\ODM\PHPCR\DocumentManager'); $this->routeMock = $this->buildMock('Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\Route'); - $this->listener = new IdPrefixListener($this->provider); + $this->listener = new IdPrefixListener($this->candidatesMock); } public function testNoRoute() diff --git a/Tests/Unit/Doctrine/Phpcr/LocaleListenerTest.php b/Tests/Unit/Doctrine/Phpcr/LocaleListenerTest.php index 3ae6dce5..aa8a731f 100644 --- a/Tests/Unit/Doctrine/Phpcr/LocaleListenerTest.php +++ b/Tests/Unit/Doctrine/Phpcr/LocaleListenerTest.php @@ -12,29 +12,44 @@ namespace Symfony\Cmf\Bundle\RoutingBundle\Tests\Unit\Doctrine\Phpcr; +use Doctrine\ODM\PHPCR\DocumentManager; use Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\LocaleListener; use Doctrine\ODM\PHPCR\Event\MoveEventArgs; use Doctrine\Common\Persistence\Event\LifecycleEventArgs; +use Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\Route; +use Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\PrefixCandidates; use Symfony\Cmf\Component\Routing\Test\CmfUnitTestCase; class LocaleListenerTest extends CmfUnitTestCase { /** @var LocaleListener */ protected $listener; - protected $routeMock; + + /** + * @var PrefixCandidates|\PHPUnit_Framework_MockObject_MockObject + */ + protected $candidatesMock; + + /** + * @var DocumentManager|\PHPUnit_Framework_MockObject_MockObject + */ protected $dmMock; - protected $provider; + + /** + * @var Route|\PHPUnit_Framework_MockObject_MockObject + */ + protected $routeMock; public function setUp() { - $this->provider = $this->buildMock('Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\RouteProvider'); + $this->candidatesMock = $this->buildMock('Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\PrefixCandidates'); - $this->provider->expects($this->any()) + $this->candidatesMock->expects($this->any()) ->method('getPrefixes') ->will($this->returnValue(array('/cms/routes', '/cms/simple'))) ; - $this->listener = new LocaleListener($this->provider, array('en', 'de')); + $this->listener = new LocaleListener($this->candidatesMock, array('en', 'de')); $this->routeMock = $this->buildMock('Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\Route'); $this->dmMock = $this->buildMock('Doctrine\ODM\PHPCR\DocumentManager'); } @@ -185,7 +200,7 @@ public function testHaslocale() } /** - * URL without locale, add_locale_pattern not set. + * URL without locale, addLocalePattern not set. */ public function testNolocaleUrl() { @@ -225,4 +240,34 @@ public function testLocalePattern() $args = new LifecycleEventArgs($this->routeMock, $this->dmMock); $this->listener->postLoad($args); } + + /** + * URL without locale, set available translations + */ + public function testAvailableTranslations() + { + $this->routeMock->expects($this->once()) + ->method('getId') + ->will($this->returnValue('/cms/simple/something')) + ; + + $this->dmMock->expects($this->once()) + ->method('isDocumentTranslatable') + ->with($this->routeMock) + ->will($this->returnValue(true)) + ; + $this->dmMock->expects($this->once()) + ->method('getLocalesFor') + ->with($this->routeMock, true) + ->will($this->returnValue(array('en', 'de', 'fr'))) + ; + $this->routeMock->expects($this->once()) + ->method('setRequirement') + ->with('_locale', 'en|de|fr') + ; + + $this->listener->setUpdateAvailableTranslations(true); + $args = new LifecycleEventArgs($this->routeMock, $this->dmMock); + $this->listener->postLoad($args); + } } diff --git a/Tests/Unit/Doctrine/Phpcr/PrefixCandidatesTest.php b/Tests/Unit/Doctrine/Phpcr/PrefixCandidatesTest.php new file mode 100644 index 00000000..6a48a906 --- /dev/null +++ b/Tests/Unit/Doctrine/Phpcr/PrefixCandidatesTest.php @@ -0,0 +1,167 @@ +assertEquals(array('/routes'), $candidates->getPrefixes()); + $candidates->addPrefix('/simple'); + $this->assertEquals(array('/routes', '/simple'), $candidates->getPrefixes()); + $candidates->setPrefixes(array('/other')); + $this->assertEquals(array('/other'), $candidates->getPrefixes()); + } + + public function testGetCandidates() + { + $request = Request::create('/my/path.html'); + + $candidates = new PrefixCandidates(array('/routes', '/simple')); + $paths = $candidates->getCandidates($request); + + $this->assertEquals( + array( + '/routes/my/path.html', + '/routes/my/path', + '/routes/my', + '/routes', + '/simple/my/path.html', + '/simple/my/path', + '/simple/my', + '/simple', + ), + $paths + ); + } + + public function testGetCandidatesLocales() + { + $request = Request::create('/de/path.html'); + + $candidates = new PrefixCandidates(array('/routes', '/simple'), array('de', 'fr')); + $paths = $candidates->getCandidates($request); + + $this->assertEquals( + array( + '/routes/de/path.html', + '/routes/de/path', + '/routes/de', + '/routes', + '/simple/de/path.html', + '/simple/de/path', + '/simple/de', + '/simple', + '/routes/path.html', + '/routes/path', + '/simple/path.html', + '/simple/path', + ), + $paths + ); + } + + public function testGetCandidatesLocalesDm() + { + $request = Request::create('/de/path.html'); + + $dmMock = $this->buildMock('Doctrine\ODM\PHPCR\DocumentManager'); + $managerRegistryMock = $this->getMock('Doctrine\Common\Persistence\ManagerRegistry'); + $managerRegistryMock + ->expects($this->any()) + ->method('getManager') + ->will($this->returnValue($dmMock)) + ; + $localeMock = $this->buildMock('Doctrine\ODM\PHPCR\Translation\LocaleChooser\LocaleChooserInterface'); + $localeMock + ->expects($this->once()) + ->method('setLocale') + ->with('de') + ; + $dmMock + ->expects($this->once()) + ->method('getLocaleChooserStrategy') + ->will($this->returnValue($localeMock)) + ; + + $candidates = new PrefixCandidates(array('/simple'), array('de', 'fr'), $managerRegistryMock); + $candidates->getCandidates($request); + } + + public function testGetCandidatesLocalesDmNoLocale() + { + $request = Request::create('/it/path.html'); + $managerRegistryMock = $this->getMock('Doctrine\Common\Persistence\ManagerRegistry'); + $managerRegistryMock + ->expects($this->never()) + ->method('getManager') + ; + + $candidates = new PrefixCandidates(array('/simple'), array('de', 'fr'), $managerRegistryMock); + $candidates->getCandidates($request); + } + + public function testIsCandidate() + { + $candidates = new PrefixCandidates(array('/routes')); + $this->assertTrue($candidates->isCandidate('/routes')); + $this->assertTrue($candidates->isCandidate('/routes/my/path')); + $this->assertFalse($candidates->isCandidate('/other/my/path')); + $this->assertFalse($candidates->isCandidate('/route')); + $this->assertFalse($candidates->isCandidate('/routesnotsame')); + } + + public function testRestrictQuery() + { + $orX = $this->getMock('Doctrine\ODM\PHPCR\Query\Builder\QueryBuilder', array('descendant')); + $orX->expects($this->once()) + ->method('descendant') + ->with('/routes', 'd') + ; + $andWhere = $this->getMock('Doctrine\ODM\PHPCR\Query\Builder\QueryBuilder', array('orX')); + $andWhere->expects($this->once()) + ->method('orX') + ->will($this->returnValue($orX)) + ; + $qb = $this->getMock('Doctrine\ODM\PHPCR\Query\Builder\QueryBuilder', array('andWhere', 'getPrimaryAlias')); + $qb->expects($this->once()) + ->method('andWhere') + ->will($this->returnValue($andWhere)) + ; + $qb->expects($this->once()) + ->method('getPrimaryAlias') + ->will($this->returnValue('d')) + ; + + $candidates = new PrefixCandidates(array('/routes')); + $candidates->restrictQuery($qb); + } + + public function testRestrictQueryGlobal() + { + $qb = $this->getMock('Doctrine\ODM\PHPCR\Query\Builder\QueryBuilder', array('andWhere')); + $qb->expects($this->never()) + ->method('andWhere') + ; + + $candidates = new PrefixCandidates(array('/routes', '', '/other')); + $candidates->restrictQuery($qb); + } +} diff --git a/Tests/Unit/Doctrine/Phpcr/RouteProviderTest.php b/Tests/Unit/Doctrine/Phpcr/RouteProviderTest.php index 227cd061..b6a9125c 100644 --- a/Tests/Unit/Doctrine/Phpcr/RouteProviderTest.php +++ b/Tests/Unit/Doctrine/Phpcr/RouteProviderTest.php @@ -9,76 +9,139 @@ * file that was distributed with this source code. */ - namespace Symfony\Cmf\Bundle\RoutingBundle\Tests\Unit\Doctrine\Phpcr; use PHPCR\Util\UUIDHelper; use PHPCR\Query\QueryInterface; use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Persistence\ManagerRegistry; +use Doctrine\ODM\PHPCR\DocumentManager; use Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\RouteProvider; +use Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\PrefixCandidates; +use Symfony\Cmf\Component\Routing\Test\CmfUnitTestCase; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Route; use Symfony\Component\Routing\RouteCollection; -class RouteProviderTest extends \PHPUnit_Framework_Testcase +class RouteProviderTest extends CmfUnitTestCase { - private $route; - private $route2; - private $objectManager; - private $objectManager2; - private $managerRegistry; + /** + * @var ManagerRegistry|\PHPUnit_Framework_MockObject_MockObject + */ + private $managerRegistryMock; + + /** + * @var PrefixCandidates|\PHPUnit_Framework_MockObject_MockObject + */ + protected $candidatesMock; + + /** + * @var DocumentManager|\PHPUnit_Framework_MockObject_MockObject + */ + protected $dmMock; + /** + * @var DocumentManager|\PHPUnit_Framework_MockObject_MockObject + */ + protected $dm2Mock; + + /** + * @var Route|\PHPUnit_Framework_MockObject_MockObject + */ + protected $routeMock; + /** + * @var Route|\PHPUnit_Framework_MockObject_MockObject + */ + protected $route2Mock; public function setUp() { - $this->route = $this->getMockBuilder('Symfony\Component\Routing\Route') - ->disableOriginalConstructor() - ->getMock() - ; - $this->route2 = $this->getMockBuilder('Symfony\Component\Routing\Route') - ->disableOriginalConstructor() - ->getMock(); - $this->objectManager = $this - ->getMockBuilder('Doctrine\ODM\PHPCR\DocumentManager') - ->disableOriginalConstructor() - ->getMock() - ; - $this->objectManager2 = $this - ->getMockBuilder('Doctrine\ODM\PHPCR\DocumentManager') - ->disableOriginalConstructor() - ->getMock() - ; - $this->managerRegistry = $this->getMock('Doctrine\Common\Persistence\ManagerRegistry'); - - $this->managerRegistry + $this->routeMock = $this->buildMock('Symfony\Component\Routing\Route'); + $this->route2Mock = $this->buildMock('Symfony\Component\Routing\Route'); + $this->dmMock = $this->buildMock('Doctrine\ODM\PHPCR\DocumentManager'); + $this->dm2Mock = $this->buildMock('Doctrine\ODM\PHPCR\DocumentManager'); + $this->managerRegistryMock = $this->getMock('Doctrine\Common\Persistence\ManagerRegistry'); + + $this->managerRegistryMock ->expects($this->any()) ->method('getManager') - ->will($this->returnValue($this->objectManager)) + ->will($this->returnValue($this->dmMock)) ; + + $this->candidatesMock = $this->buildMock('Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\PrefixCandidates'); } public function testGetRouteCollectionForRequest() { - $this->markTestIncomplete(); + $request = Request::create('/my/path'); + $candidates = array('/prefix/my/path', '/prefix/my'); + + $this->candidatesMock + ->expects($this->once()) + ->method('getCandidates') + ->with($request) + ->will($this->returnValue($candidates)) + ; + + $objects = array( + new Route('/my'), + $this, + ); + + $this->dmMock + ->expects($this->once()) + ->method('findMany') + ->with(null, $candidates) + ->will($this->returnValue($objects)) + ; + + $routeProvider = new RouteProvider($this->managerRegistryMock, $this->candidatesMock); + $collection = $routeProvider->getRouteCollectionForRequest($request); + $this->assertInstanceOf('Symfony\Component\Routing\RouteCollection', $collection); + $this->assertCount(1, $collection); + } + + public function testGetRouteCollectionForRequestEmpty() + { + $request = Request::create('/my/path'); + + $this->candidatesMock + ->expects($this->once()) + ->method('getCandidates') + ->with($request) + ->will($this->returnValue(array())) + ; + + $routeProvider = new RouteProvider($this->managerRegistryMock, $this->candidatesMock); + $collection = $routeProvider->getRouteCollectionForRequest($request); + $this->assertInstanceOf('Symfony\Component\Routing\RouteCollection', $collection); + $this->assertCount(0, $collection); } public function testGetRouteByName() { - $this->route + $this->routeMock ->expects($this->any()) ->method('getPath') ->will($this->returnValue('/cms/routes/test-route')) ; - $this->objectManager + $this->dmMock ->expects($this->any()) ->method('find') ->with(null, '/cms/routes/test-route') - ->will($this->returnValue($this->route)) + ->will($this->returnValue($this->routeMock)) + ; + + $this->candidatesMock + ->expects($this->once()) + ->method('isCandidate') + ->with('/cms/routes/test-route') + ->will($this->returnValue(true)) ; - $routeProvider = new RouteProvider($this->managerRegistry); + $routeProvider = new RouteProvider($this->managerRegistryMock, $this->candidatesMock); $routeProvider->setManagerName('default'); - $routeProvider->setPrefixes(array('/cms/routes/')); $foundRoute = $routeProvider->getRouteByName('/cms/routes/test-route'); $this->assertInstanceOf('Symfony\Component\Routing\Route', $foundRoute); @@ -88,28 +151,20 @@ public function testGetRouteByName() public function testGetRouteByNameUuid() { $uuid = UUIDHelper::generateUUID(); - $this->route + $this->routeMock ->expects($this->any()) ->method('getPath') ->will($this->returnValue('/cms/routes/test-route')) ; - $objectManager = $this - ->getMockBuilder('Doctrine\ODM\PHPCR\DocumentManager') - ->disableOriginalConstructor() - ->getMock() - ; - $uow = $this - ->getMockBuilder('Doctrine\ODM\PHPCR\UnitOfWork') - ->disableOriginalConstructor() - ->getMock() - ; - $objectManager + + $uow = $this->buildMock('Doctrine\ODM\PHPCR\UnitOfWork'); + $this->dmMock ->expects($this->any()) ->method('find') ->with(null, $uuid) - ->will($this->returnValue($this->route)) + ->will($this->returnValue($this->routeMock)) ; - $objectManager + $this->dmMock ->expects($this->any()) ->method('getUnitOfWork') ->will($this->returnValue($uow)) @@ -117,19 +172,20 @@ public function testGetRouteByNameUuid() $uow ->expects($this->any()) ->method('getDocumentId') + ->with($this->routeMock) ->will($this->returnValue('/cms/routes/test-route')) ; - $this->managerRegistry - ->expects($this->any()) - ->method('getManager') - ->will($this->returnValue($objectManager)) + $this->candidatesMock + ->expects($this->once()) + ->method('isCandidate') + ->with('/cms/routes/test-route') + ->will($this->returnValue(true)) ; - $routeProvider = new RouteProvider($this->managerRegistry); + $routeProvider = new RouteProvider($this->managerRegistryMock, $this->candidatesMock); $routeProvider->setManagerName('default'); - $routeProvider->setPrefix('/cms/routes/'); $foundRoute = $routeProvider->getRouteByName($uuid); $this->assertInstanceOf('Symfony\Component\Routing\Route', $foundRoute); @@ -139,118 +195,132 @@ public function testGetRouteByNameUuid() /** * @expectedException \Symfony\Component\Routing\Exception\RouteNotFoundException */ - public function testGetRouteByNameNotFound() + public function testGetRouteByNameUuidNotFound() { - $this->objectManager + $uuid = UUIDHelper::generateUUID(); + + $this->dmMock ->expects($this->any()) ->method('find') - ->with(null, '/cms/routes/test-route') + ->with(null, $uuid) ->will($this->returnValue(null)) ; - $routeProvider = new RouteProvider($this->managerRegistry); + $routeProvider = new RouteProvider($this->managerRegistryMock, $this->candidatesMock); $routeProvider->setManagerName('default'); - $routeProvider->setPrefixes(array('/cms/routes/')); - $routeProvider->getRouteByName('/cms/routes/test-route'); + + $routeProvider->getRouteByName($uuid); } /** * @expectedException \Symfony\Component\Routing\Exception\RouteNotFoundException */ - public function testGetRouteByNameNoRoute() + public function testGetRouteByNameUuidNotCandidate() { - $this->objectManager + $uuid = UUIDHelper::generateUUID(); + $this->routeMock + ->expects($this->any()) + ->method('getPath') + ->will($this->returnValue('/cms/routes/test-route')) + ; + + $uow = $this->buildMock('Doctrine\ODM\PHPCR\UnitOfWork'); + $this->dmMock ->expects($this->any()) ->method('find') - ->with(null, '/cms/routes/test-route') - ->will($this->returnValue($this)) + ->with(null, $uuid) + ->will($this->returnValue($this->routeMock)) + ; + $this->dmMock + ->expects($this->any()) + ->method('getUnitOfWork') + ->will($this->returnValue($uow)) + ; + $uow + ->expects($this->any()) + ->method('getDocumentId') + ->will($this->returnValue('/cms/routes/test-route')) + ; + + $this->candidatesMock + ->expects($this->once()) + ->method('isCandidate') + ->with('/cms/routes/test-route') + ->will($this->returnValue(false)) ; - $routeProvider = new RouteProvider($this->managerRegistry); + $routeProvider = new RouteProvider($this->managerRegistryMock, $this->candidatesMock); $routeProvider->setManagerName('default'); - $routeProvider->setPrefixes(array('/cms/routes/')); - $routeProvider->getRouteByName('/cms/routes/test-route'); + + $routeProvider->getRouteByName($uuid); } /** - * @expectedException \Symfony\Component\Routing\Exception\RouteNotFoundException + * @expectedException \Symfony\Component\Routing\Exception\RouteNotFoundException */ - public function testGetRouteByNameInvalidRoute() + public function testGetRouteByNameNotCandidate() { - $this->objectManager + $this->dmMock ->expects($this->never()) ->method('find') ; - $routeProvider = new RouteProvider($this->managerRegistry); - $routeProvider->setManagerName('default'); - - $routeProvider->setPrefixes(array('/cms/routes')); - - $routeProvider->getRouteByName('invalid_route'); - } - - public function testGetRouteByNameIdPrefixEmptyString() - { - - $this->route - ->expects($this->any()) - ->method('getPath') - ->will($this->returnValue('/cms/routes/test-route')) - ; - - $this->objectManager - ->expects($this->any()) - ->method('find') - ->with(null, '/cms/routes/test-route') - ->will($this->returnValue($this->route)) + $this->candidatesMock + ->expects($this->once()) + ->method('isCandidate') + ->with('/cms/routes/test-route') + ->will($this->returnValue(false)) ; - $routeProvider = new RouteProvider($this->managerRegistry); + $routeProvider = new RouteProvider($this->managerRegistryMock, $this->candidatesMock); $routeProvider->setManagerName('default'); - - $routeProvider->setPrefixes(array('')); - $foundRoute = $routeProvider->getRouteByName('/cms/routes/test-route'); - - $this->assertInstanceOf('Symfony\Component\Routing\Route', $foundRoute); - $this->assertEquals('/cms/routes/test-route', $foundRoute->getPath()); + $routeProvider->getRouteByName('/cms/routes/test-route'); } - /** * @expectedException \Symfony\Component\Routing\Exception\RouteNotFoundException */ - public function testGetRouteByNameNotFoundIdPrefixEmptyString() + public function testGetRouteByNameNotFound() { - $this->objectManager + $this->dmMock ->expects($this->any()) ->method('find') ->with(null, '/cms/routes/test-route') ->will($this->returnValue(null)) ; - $routeProvider = new RouteProvider($this->managerRegistry); + $this->candidatesMock + ->expects($this->once()) + ->method('isCandidate') + ->with('/cms/routes/test-route') + ->will($this->returnValue(true)) + ; + + $routeProvider = new RouteProvider($this->managerRegistryMock, $this->candidatesMock); $routeProvider->setManagerName('default'); - $routeProvider->setPrefixes(array('')); $routeProvider->getRouteByName('/cms/routes/test-route'); } /** * @expectedException \Symfony\Component\Routing\Exception\RouteNotFoundException */ - public function testGetRouteByNameNoRoutePrefixEmptyString() + public function testGetRouteByNameNoRoute() { - $this->objectManager - ->expects($this->once()) + $this->dmMock + ->expects($this->any()) ->method('find') ->with(null, '/cms/routes/test-route') ->will($this->returnValue($this)) ; + $this->candidatesMock + ->expects($this->once()) + ->method('isCandidate') + ->with('/cms/routes/test-route') + ->will($this->returnValue(true)) + ; - $routeProvider = new RouteProvider($this->managerRegistry); + $routeProvider = new RouteProvider($this->managerRegistryMock, $this->candidatesMock); $routeProvider->setManagerName('default'); - $routeProvider->setPrefixes(array('')); - $routeProvider->getRouteByName('/cms/routes/test-route'); } @@ -262,82 +332,202 @@ public function testGetRoutesByNames() '/cms/routes/not-a-route', ); - $collection = new ArrayCollection(); - $collection->set('/cms/routes/test-route', new Route('/test-route')); - $collection->set('/cms/simple/other-route', new Route('/other-route')); - $collection->set('/cms/routes/not-a-route', $this); + $routes = new ArrayCollection(); + $routes->set('/cms/routes/test-route', new Route('/test-route')); + $routes->set('/cms/simple/other-route', new Route('/other-route')); + $routes->set('/cms/routes/not-a-route', $this); - $this->objectManager + $this->dmMock ->expects($this->once()) ->method('findMany') ->with(null, $paths) - ->will($this->returnValue($collection)) + ->will($this->returnValue($routes)) + ; + + $this->candidatesMock + ->expects($this->at(0)) + ->method('isCandidate') + ->with('/cms/routes/test-route') + ->will($this->returnValue(true)) ; + $this->candidatesMock + ->expects($this->at(1)) + ->method('isCandidate') + ->with('/cms/simple/other-route') + ->will($this->returnValue(true)) + ; + $this->candidatesMock + ->expects($this->at(2)) + ->method('isCandidate') + ->with('/cms/routes/not-a-route') + ->will($this->returnValue(true)) + ; + $this->candidatesMock + ->expects($this->at(3)) + ->method('isCandidate') + ->with('/outside/prefix') + ->will($this->returnValue(false)) + ; + $paths[] = '/outside/prefix'; - $routeProvider = new RouteProvider($this->managerRegistry); + $routeProvider = new RouteProvider($this->managerRegistryMock, $this->candidatesMock); $routeProvider->setManagerName('default'); - $routeProvider->setPrefixes(array('/cms/routes', '/cms/simple')); - $routeProvider->setRouteCollectionLimit(1); - $collection = $routeProvider->getRoutesByNames($paths); - $this->assertCount(2, $collection); + $routes = $routeProvider->getRoutesByNames($paths); + $this->assertCount(2, $routes); + } + + public function testGetRoutesByNamesNotCandidates() + { + $paths = array( + '/cms/routes/test-route', + '/cms/simple/other-route', + '/cms/routes/not-a-route', + ); + + $this->dmMock + ->expects($this->never()) + ->method('findMany') + ; + + $this->candidatesMock + ->expects($this->at(0)) + ->method('isCandidate') + ->with('/cms/routes/test-route') + ->will($this->returnValue(false)) + ; + $this->candidatesMock + ->expects($this->at(1)) + ->method('isCandidate') + ->with('/cms/simple/other-route') + ->will($this->returnValue(false)) + ; + $this->candidatesMock + ->expects($this->at(2)) + ->method('isCandidate') + ->with('/cms/routes/not-a-route') + ->will($this->returnValue(false)) + ; + + $routeProvider = new RouteProvider($this->managerRegistryMock, $this->candidatesMock); + $routeProvider->setManagerName('default'); + + $routes = $routeProvider->getRoutesByNames($paths); + $this->assertCount(0, $routes); + } + + public function testGetRoutesByNamesUuid() + { + $uuid1 = UUIDHelper::generateUUID(); + $uuid2 = UUIDHelper::generateUUID(); + $paths = array( + $uuid1, + $uuid2, + ); + + $route1 = new Route('/test-route'); + $route2 = new Route('/other-route'); + + $routes = new ArrayCollection(); + $routes->set($uuid1, $route1); + $routes->set($uuid2, $route2); + + $this->dmMock + ->expects($this->once()) + ->method('findMany') + ->with(null, $paths) + ->will($this->returnValue($routes)) + ; + + $uow = $this->buildMock('Doctrine\ODM\PHPCR\UnitOfWork'); + + $this->dmMock + ->expects($this->any()) + ->method('getUnitOfWork') + ->will($this->returnValue($uow)) + ; + $uow + ->expects($this->at(0)) + ->method('getDocumentId') + ->with($route1) + ->will($this->returnValue('/cms/routes/test-route')) + ; + $uow + ->expects($this->at(1)) + ->method('getDocumentId') + ->with($route2) + ->will($this->returnValue('/cms/routes/other-route')) + ; + + $this->candidatesMock + ->expects($this->at(0)) + ->method('isCandidate') + ->with('/cms/routes/test-route') + ->will($this->returnValue(true)) + ; + $this->candidatesMock + ->expects($this->at(1)) + ->method('isCandidate') + ->with('/cms/routes/other-route') + ->will($this->returnValue(false)) + ; + + $routeProvider = new RouteProvider($this->managerRegistryMock, $this->candidatesMock); + $routeProvider->setManagerName('default'); + + $routes = $routeProvider->getRoutesByNames($paths); + $this->assertCount(1, $routes); } private function doRouteDump($limit) { - if ($limit === 0) { - $this->objectManager - ->expects($this->never()) - ->method('createPhpcrQuery') - ; - $this->objectManager - ->expects($this->never()) - ->method('getDocumentsByPhpcrQuery') - ; - } else { - $query = $this->getMock('\PHPCR\Query\QueryInterface'); - $sql2 = 'SELECT * FROM [nt:unstructured] WHERE [phpcr:classparents] = "Symfony\Component\Routing\Route" AND (ISDESCENDANTNODE("/cms/routes") OR ISDESCENDANTNODE("/cms/simple"))'; - $this->objectManager - ->expects($this->once()) - ->method('createPhpcrQuery') - ->with($sql2, QueryInterface::JCR_SQL2) - ->will($this->returnValue($query)) - ; - if ($limit) { - $query - ->expects($this->once()) - ->method('setLimit') - ->with($limit) - ; - } else { - $query - ->expects($this->never()) - ->method('setLimit') - ; - } - $this->objectManager + $from = $this->getMock('Doctrine\ODM\PHPCR\Query\Builder\QueryBuilder', array('document')); + $from->expects($this->once()) + ->method('document') + ->with('Symfony\Component\Routing\Route', 'd') + ; + + $query = $this->buildMock('Doctrine\ODM\PHPCR\Query\Query'); + $query->expects($this->once())->method('getResult'); + if ($limit) { + $query ->expects($this->once()) - ->method('getDocumentsByPhpcrQuery') - ->with($query) - ->will($this->returnValue(new ArrayCollection())) + ->method('setMaxResults') + ->with($limit) ; - $this->objectManager - ->expects($this->any()) - ->method('quote') - ->will( - $this->returnCallback( - function ($text) { - return '"' . $text . '"'; - } - ) - ) + } else { + $query + ->expects($this->never()) + ->method('setMaxResults') ; } - $routeProvider = new RouteProvider($this->managerRegistry); + $queryBuilder = $this->getMock('Doctrine\ODM\PHPCR\Query\Builder\QueryBuilder', array('from', 'getQuery')); + $queryBuilder->expects($this->once()) + ->method('from') + ->with('d') + ->will($this->returnValue($from)) + ; + $queryBuilder->expects($this->once()) + ->method('getQuery') + ->will($this->returnValue($query)) + ; + + $this->dmMock + ->expects($this->once()) + ->method('createQueryBuilder') + ->will($this->returnValue($queryBuilder)) + ; + + $this->candidatesMock + ->expects($this->once()) + ->method('restrictQuery') + ->with($queryBuilder) + ; + + $routeProvider = new RouteProvider($this->managerRegistryMock, $this->candidatesMock); $routeProvider->setManagerName('default'); - $routeProvider->setPrefixes(array('/cms/routes', '/cms/simple')); $routeProvider->setRouteCollectionLimit($limit); $routeProvider->getRoutesByNames(); @@ -355,7 +545,19 @@ public function testDumpRoutesLimit() public function testDumpRoutesDisabled() { - $this->doRouteDump(0); + $this->dmMock + ->expects($this->never()) + ->method('createPhpcrQuery') + ; + $this->dmMock + ->expects($this->never()) + ->method('getDocumentsByPhpcrQuery') + ; + $routeProvider = new RouteProvider($this->managerRegistryMock, $this->candidatesMock); + $routeProvider->setManagerName('default'); + $routeProvider->setRouteCollectionLimit(0); + + $this->assertEquals(array(), $routeProvider->getRoutesByNames()); } /** @@ -364,36 +566,36 @@ public function testDumpRoutesDisabled() */ public function testChangingDocumentManager() { - $this->route + $this->routeMock ->expects($this->any()) ->method('getPath') ->will($this->returnValue('/cms/routes/test-route')); - $this->route2 + $this->route2Mock ->expects($this->any()) ->method('getPath') ->will($this->returnValue('/cms/routes/new-route')); - $this->objectManager + $this->dmMock ->expects($this->any()) ->method('find') ->with(null, '/cms/routes/test-route') - ->will($this->returnValue($this->route)) + ->will($this->returnValue($this->routeMock)) ; - $this->objectManager2 + $this->dm2Mock ->expects($this->any()) ->method('find') ->with(null, '/cms/routes/test-route') - ->will($this->returnValue($this->route2)) + ->will($this->returnValue($this->route2Mock)) ; $objectManagers = array( - 'default' => $this->objectManager, - 'new_manager' => $this->objectManager2 + 'default' => $this->dmMock, + 'new_manager' => $this->dm2Mock ); - $this->managerRegistry = $this->getMock('Doctrine\Common\Persistence\ManagerRegistry'); - $this->managerRegistry + $this->managerRegistryMock = $this->getMock('Doctrine\Common\Persistence\ManagerRegistry'); + $this->managerRegistryMock ->expects($this->any()) ->method('getManager') ->will( @@ -402,12 +604,17 @@ function ($name) use ($objectManagers) { return $objectManagers[$name]; } ) - ); + ) + ; - $routeProvider = new RouteProvider($this->managerRegistry); + $this->candidatesMock + ->expects($this->any()) + ->method('isCandidate') + ->will($this->returnValue(true)) + ; + $routeProvider = new RouteProvider($this->managerRegistryMock, $this->candidatesMock); $routeProvider->setManagerName('default'); - $routeProvider->setPrefixes(array('/cms/routes/')); $foundRoute = $routeProvider->getRouteByName('/cms/routes/test-route'); $this->assertInstanceOf('Symfony\Component\Routing\Route', $foundRoute); diff --git a/composer.json b/composer.json index 5af886c4..c9c7dd96 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ "prefer-stable": false, "require": { "php": ">=5.3.3", - "symfony-cmf/routing": "~1.2.0", + "symfony-cmf/routing": "dev-candidates as 1.2.0", "symfony/framework-bundle": "~2.2" }, "require-dev": { From 623a6add153fa508facd9c219c73083541f6a1c9 Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Sat, 29 Mar 2014 16:02:04 +0100 Subject: [PATCH 04/12] add changelog and upgrade instructions --- CHANGELOG.md | 9 ++++++ DependencyInjection/CmfRoutingExtension.php | 2 -- Doctrine/Phpcr/Route.php | 2 ++ UPGRADE-1.2.md | 31 +++++++++++++++++++++ 4 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 UPGRADE-1.2.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 0fc896b7..d942f6ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,15 @@ Changelog ========= +* **2014-03-29**: [Multilang] Added some options to support locale matching + without separate routes per locale. See the new configuration options + `match_implicit_locale` and `auto_locale_pattern`. + +* **2014-03-29**: [PHPCR] The route provider can now load Routes from more than + path in PHPCR. The configuration option `route_basepath` is renamed to + `route_basepaths` and accepts a list of base paths. See the changelog of + the SimpleCmsBundle as the main impact is on that side. + * **2014-03-26**: [ORM] Applied the cleanup for the PHPCR provider to the ORM provider now: If the route matched a pattern with a format extension, the format extension is no longer set as route a default. diff --git a/DependencyInjection/CmfRoutingExtension.php b/DependencyInjection/CmfRoutingExtension.php index 5179d31a..1df2b79e 100644 --- a/DependencyInjection/CmfRoutingExtension.php +++ b/DependencyInjection/CmfRoutingExtension.php @@ -277,10 +277,8 @@ public function loadSonataPhpcrAdmin($config, XmlFileLoader $loader, ContainerBu } $basePath = empty($config['admin_basepath']) ? reset($config['route_basepaths']) : $config['admin_basepath']; - $container->setParameter($this->getAlias() . '.dynamic.persistence.phpcr.admin_basepath', $basePath); - $loader->load('admin-phpcr.xml'); } diff --git a/Doctrine/Phpcr/Route.php b/Doctrine/Phpcr/Route.php index e6c2f94f..1c859ece 100644 --- a/Doctrine/Phpcr/Route.php +++ b/Doctrine/Phpcr/Route.php @@ -142,6 +142,8 @@ public function getParentDocument() * Note that this will change the URL this route matches. * * @param string $name the new name + * + * @return self */ public function setName($name) { diff --git a/UPGRADE-1.2.md b/UPGRADE-1.2.md new file mode 100644 index 00000000..3b0425d5 --- /dev/null +++ b/UPGRADE-1.2.md @@ -0,0 +1,31 @@ +UPGRADE FROM 1.1 TO 1.2 +======================= + +Renamed the configuration option `dynamic.persistence.phpcr.route_basepath` to +`dynamic.persistence.phpcr.route_basepaths` and made it a list instead of a +single value. `route_basepath` is supported for BC but deprecated. + +Refactored explicit properties for `addTrailingSlash` and `addFormatPattern` +into Route options. Use setOption/getOption with `add_trailing_slash` resp +`add_format_pattern` to interact with the options. The getters and setters are +kept for BC. If you have stored PHPCR Routes with these options activated, you +need to move the data into the options: + +```php +/** @var $dm \Doctrine\ODM\PHPCR\DocumentManager */ +$query = $dm->createPhpcrQuery("SELECT * FROM nt:base WHERE addFormatPattern = 'true'", QueryInterface::JCR_SQL2) +$routes = $dm->getDocumentsByPhpcrQuery($query); +/** @var $route \Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\Route */ +foreach($routes as $route) { + $route->setOption('add_format_pattern', true); +} + +$query = $dm->createPhpcrQuery("SELECT * FROM nt:base WHERE addTrailingSlash = 'true'", QueryInterface::JCR_SQL2) +$routes = $dm->getDocumentsByPhpcrQuery($query); +/** @var $route \Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\Route */ +foreach($routes as $route) { + $route->setOption('add_trailing_slash', true); +} + +$dm->flush(); +``` From badf1d83f4acd8d1a9e25376394e1751221d468f Mon Sep 17 00:00:00 2001 From: Lukas Kahwe Smith Date: Mon, 31 Mar 2014 21:26:05 +0200 Subject: [PATCH 05/12] fix ORM tests --- Tests/Unit/Doctrine/Orm/RouteProviderTest.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Tests/Unit/Doctrine/Orm/RouteProviderTest.php b/Tests/Unit/Doctrine/Orm/RouteProviderTest.php index 56f7ec67..16dc02f4 100644 --- a/Tests/Unit/Doctrine/Orm/RouteProviderTest.php +++ b/Tests/Unit/Doctrine/Orm/RouteProviderTest.php @@ -59,7 +59,10 @@ public function setUp() $this->route2Mock = $this->buildMock('Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Orm\Route'); $this->objectManagerMock = $this->getMock('Doctrine\Common\Persistence\ObjectManager'); $this->managerRegistryMock = $this->getMock('Doctrine\Common\Persistence\ManagerRegistry'); - $this->objectRepositoryMock = $this->getMock('Doctrine\Orm\EntityRepository', array('findByStaticPrefix', 'findOneBy', 'findBy')); + $this->objectRepositoryMock = $this->getMockBuilder('Doctrine\ORM\EntityRepository') + ->setMethods(array('findByStaticPrefix', 'findOneBy', 'findBy')) + ->disableOriginalConstructor() + ->getMock(); $this->candidatesMock = $this->getMock('Symfony\Cmf\Component\Routing\Candidates\CandidatesInterface'); $this->candidatesMock ->expects($this->any()) From f3c27b8859b64699469a50b95ede9d259f9c688d Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Mon, 31 Mar 2014 22:10:23 +0200 Subject: [PATCH 06/12] cleanup sonata admin --- Admin/RouteAdmin.php | 15 ++++++++----- .../translations/CmfRoutingBundle.de.xliff | 21 +++++++++++++----- .../translations/CmfRoutingBundle.en.xliff | 20 ++++++++++++----- .../translations/CmfRoutingBundle.fr.xliff | 22 +++++++++++++------ 4 files changed, 53 insertions(+), 25 deletions(-) diff --git a/Admin/RouteAdmin.php b/Admin/RouteAdmin.php index aa8b297d..e7c56a9f 100644 --- a/Admin/RouteAdmin.php +++ b/Admin/RouteAdmin.php @@ -71,10 +71,13 @@ protected function configureFormFields(FormMapper $formMapper) if (null === $this->getParentFieldDescription()) { $formMapper ->with('form.group_general') - ->add('variablePattern', 'text', array('required' => false)) - ->add('content', 'doctrine_phpcr_odm_tree', array('choice_list' => array(), 'required' => false, 'root_node' => $this->contentRoot)) - ->add('defaults', 'sonata_type_immutable_array', array('keys' => $this->configureFieldsForDefaults())) - ->add('options', 'sonata_type_immutable_array', array('keys' => $this->configureFieldsForOptions())) + ->add('content', 'doctrine_phpcr_odm_tree', array('choice_list' => array(), 'required' => false, 'root_node' => $this->contentRoot)) + ->end() + ->with('form.group_advanced') + ->add('variablePattern', 'text', array('required' => false), array('help' => 'form.help_variable_pattern')) + ->add('defaults', 'sonata_type_immutable_array', array('keys' => $this->configureFieldsForDefaults())) + ->add('options', 'sonata_type_immutable_array', array('keys' => $this->configureFieldsForOptions()), array('help' => 'form.help_options')) + ->end() ->end(); } } @@ -144,8 +147,8 @@ protected function configureFieldsForDefaults() protected function configureFieldsForOptions() { $options = array( - 'addFormatPattern' => array('addFormatPattern', 'text', array('required' => false), array('help' => 'form.help_add_format_pattern')), - 'addTrailingSlash' => array('addTrailingSlash', 'text', array('required' => false), array('help' => 'form.help_add_trailing_slash')), + 'addFormatPattern' => array('addFormatPattern', 'checkbox', array('required' => false, 'label' => 'form.label_add_format_pattern', 'translation_domain' => $this->translationDomain)), + 'addTrailingSlash' => array('addTrailingSlash', 'checkbox', array('required' => false, 'label' => 'form.label_add_trailing_slash', 'translation_domain' => $this->translationDomain)), ); $dynamicOptions = $this->getSubject()->getOptions(); diff --git a/Resources/translations/CmfRoutingBundle.de.xliff b/Resources/translations/CmfRoutingBundle.de.xliff index 52be18df..618e09a0 100644 --- a/Resources/translations/CmfRoutingBundle.de.xliff +++ b/Resources/translations/CmfRoutingBundle.de.xliff @@ -58,6 +58,10 @@ form.group_general Allgemein + + form.group_advanced + Details + form.label_parent Übergeordnet @@ -70,6 +74,10 @@ form.label_variable_pattern Variablenmuster + + form.help_variable_pattern + Ein Muster im Format {variable}/{mehr}... Die Felder werden dem Controller übergeben falls er sie deklariert. + form.label_content Inhalt @@ -111,12 +119,13 @@ Abschließenden Schrägstrich hinzufügen - form.help_add_format_pattern - Format zu URL hinzufügen: /eine/url.{format}. Wenn nichts angegeben wird ist das Format html. - - - form.help_add_trailing_slash - Die URL hört in diesem Fall mit einem Schrägstrich auf, zum Beispiel /eine/url/. + form.help_options + + + Schrägstrich: Die URL hört in diesem Fall mit einem Schrägstrich auf, zum Beispiel /eine/url/ + ]]> + diff --git a/Resources/translations/CmfRoutingBundle.en.xliff b/Resources/translations/CmfRoutingBundle.en.xliff index 4a2782c8..56ed0ed0 100644 --- a/Resources/translations/CmfRoutingBundle.en.xliff +++ b/Resources/translations/CmfRoutingBundle.en.xliff @@ -58,6 +58,10 @@ form.group_general General + + form.group_advanced + Advanced + form.label_parent Parent @@ -70,6 +74,10 @@ form.label_variable_pattern Variable pattern + + form.help_variable_pattern + A pattern in the format {variable}/{more}... The fields are passed to the controller if it declares them as arguments. + form.label_content Content @@ -111,12 +119,12 @@ Add trailing slash - form.help_add_format_pattern - Append format to route like /your/route.{format}. Default format is html. - - - form.help_add_trailing_slash - Append a trailing slash to route like /your/route/. + form.help_options + + + Slash: Append a trailing slash to route like /your/route/ + ]]> + diff --git a/Resources/translations/CmfRoutingBundle.fr.xliff b/Resources/translations/CmfRoutingBundle.fr.xliff index 25cab981..6ce724fd 100644 --- a/Resources/translations/CmfRoutingBundle.fr.xliff +++ b/Resources/translations/CmfRoutingBundle.fr.xliff @@ -58,6 +58,10 @@ form.group_general Général + + form.group_advanced + Avancé + form.label_parent Parent @@ -70,6 +74,10 @@ form.label_variable_pattern Motif variable + + form.help_variable_pattern + Un motif en format {variable}/{plus}... Les variables sont passé au controlleur s'il les déclare comme arguments. + form.label_content Contenu @@ -110,13 +118,13 @@ form.label_add_trailing_slash Ajouter une barre oblique en fin - - form.help_add_format_pattern - Ajoute le format à la route tel que /your/route.{format}. Le format par défaut est html. - - - form.help_add_trailing_slash - Ajoute un slash à la fin de la route tel que /your/route/. + + form.help_options + + Barre Oblique: Ajoute un slash à la fin de la route tel que /your/route/ + ]]> + From 0b2ce04152ae968d6cfe460f73786e6765d4c2a1 Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Mon, 31 Mar 2014 22:17:22 +0200 Subject: [PATCH 07/12] fix route filter name. via @psytraxx --- Admin/RouteAdmin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Admin/RouteAdmin.php b/Admin/RouteAdmin.php index e7c56a9f..5dc9dd4d 100644 --- a/Admin/RouteAdmin.php +++ b/Admin/RouteAdmin.php @@ -85,7 +85,7 @@ protected function configureFormFields(FormMapper $formMapper) protected function configureDatagridFilters(DatagridMapper $datagridMapper) { $datagridMapper - ->add('name', 'doctrine_phpcr_string'); + ->add('name', 'doctrine_phpcr_nodename'); } public function setRouteRoot($routeRoot) From b6729dbe46861de68c6fcb00ab376775cde33674 Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Mon, 31 Mar 2014 22:20:49 +0200 Subject: [PATCH 08/12] adjust to feedback for configuration --- DependencyInjection/Configuration.php | 20 +++----------------- Resources/config/schema/routing-1.0.xsd | 1 + 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index ac973538..fa929c51 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -78,23 +78,9 @@ public function getConfigTreeBuilder() ->addDefaultsIfNotSet() ->canBeEnabled() ->fixXmlConfig('route_basepath') - ->beforeNormalization() - ->ifTrue(function ($v) { - return isset($v['route_basepath']); - }) - ->then(function ($v) { - $base = isset($v['route_basepaths']) ? $v['route_basepaths'] : array(); - if (is_array($v['route_basepath'])) { - // xml configuration - $base += $v['route_basepath']; - } else { - $base[] = $v['route_basepath']; - } - $v['route_basepaths'] = array_unique($base); - unset($v['route_basepath']); - - return $v; - }) + ->validate() + ->ifTrue(function ($v) { isset($v['route_basepath']) && isset($v['route_basepaths']); }) + ->thenInvalid('Found values for both "route_basepath" and "route_basepaths", use "route_basepaths" instead.') ->end() ->children() ->scalarNode('manager_name')->defaultNull()->end() diff --git a/Resources/config/schema/routing-1.0.xsd b/Resources/config/schema/routing-1.0.xsd index e4bf1200..3c4a1482 100644 --- a/Resources/config/schema/routing-1.0.xsd +++ b/Resources/config/schema/routing-1.0.xsd @@ -81,6 +81,7 @@ + From a1205ec87f71a3d406a5174a6dc6815c564e195c Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Mon, 31 Mar 2014 23:02:17 +0200 Subject: [PATCH 09/12] support candidates limit --- DependencyInjection/CmfRoutingExtension.php | 1 + DependencyInjection/Configuration.php | 1 + Doctrine/Phpcr/PrefixCandidates.php | 5 +++-- Resources/config/provider-orm.xml | 1 + Resources/config/provider-phpcr.xml | 1 + Tests/Unit/DependencyInjection/ConfigurationTest.php | 1 + 6 files changed, 8 insertions(+), 2 deletions(-) diff --git a/DependencyInjection/CmfRoutingExtension.php b/DependencyInjection/CmfRoutingExtension.php index 1df2b79e..2390244d 100644 --- a/DependencyInjection/CmfRoutingExtension.php +++ b/DependencyInjection/CmfRoutingExtension.php @@ -100,6 +100,7 @@ private function setupDynamicRouter(array $config, ContainerBuilder $container, $container->setParameter($this->getAlias() . '.dynamic.locales', $locales); $container->setParameter($this->getAlias() . '.dynamic.auto_locale_pattern', $config['auto_locale_pattern']); } + $container->setParameter($this->getAlias() . '.dynamic.limit_candidates', $config['limit_candidates']); $loader->load('routing-dynamic.xml'); diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index fa929c51..b90c5d93 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -131,6 +131,7 @@ public function getConfigTreeBuilder() ->arrayNode('locales') ->prototype('scalar')->end() ->end() + ->scalarNode('limit_candidates')->defaultValue(20)->end() ->booleanNode('match_implicit_locale')->defaultValue(true)->end() ->booleanNode('auto_locale_pattern')->defaultValue(false)->end() ->end() diff --git a/Doctrine/Phpcr/PrefixCandidates.php b/Doctrine/Phpcr/PrefixCandidates.php index 330cc2d8..bdf56314 100644 --- a/Doctrine/Phpcr/PrefixCandidates.php +++ b/Doctrine/Phpcr/PrefixCandidates.php @@ -50,10 +50,11 @@ class PrefixCandidates extends Candidates * $locales. This must be the same * document manager as the RouteProvider * is using. + * @param int $limit Limit to candidates generated per prefix. */ - public function __construct(array $prefixes, array $locales = array(), ManagerRegistry $doctrine = null) + public function __construct(array $prefixes, array $locales = array(), ManagerRegistry $doctrine = null, $limit = 20) { - parent::__construct($locales); + parent::__construct($locales, $limit); $this->setPrefixes($prefixes); $this->doctrine = $doctrine; } diff --git a/Resources/config/provider-orm.xml b/Resources/config/provider-orm.xml index 572b0e70..e15196b0 100644 --- a/Resources/config/provider-orm.xml +++ b/Resources/config/provider-orm.xml @@ -19,6 +19,7 @@ %cmf_routing.dynamic.locales% + %cmf_routing.dynamic.limit_candidates% diff --git a/Resources/config/provider-phpcr.xml b/Resources/config/provider-phpcr.xml index 68b133a5..298c4f06 100644 --- a/Resources/config/provider-phpcr.xml +++ b/Resources/config/provider-phpcr.xml @@ -25,6 +25,7 @@ %cmf_routing.dynamic.persistence.phpcr.route_basepaths% %cmf_routing.dynamic.locales% + %cmf_routing.dynamic.limit_candidates% %cmf_routing.dynamic.persistence.phpcr.manager_name% diff --git a/Tests/Unit/DependencyInjection/ConfigurationTest.php b/Tests/Unit/DependencyInjection/ConfigurationTest.php index e6663ae1..988b878b 100644 --- a/Tests/Unit/DependencyInjection/ConfigurationTest.php +++ b/Tests/Unit/DependencyInjection/ConfigurationTest.php @@ -71,6 +71,7 @@ public function testSupportsAllConfigFormats() 'uri_filter_regexp' => '', 'route_filters_by_id' => array(), 'locales' => array('en', 'fr'), + 'limit_candidates' => true, 'auto_locale_pattern' => true, 'match_implicit_locale' => true, ), From dbbd077a2cb623d79c60694c0cc1d29381559315 Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Mon, 31 Mar 2014 23:04:50 +0200 Subject: [PATCH 10/12] cleaning up redirect route admin a bit --- Admin/RedirectRouteAdmin.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Admin/RedirectRouteAdmin.php b/Admin/RedirectRouteAdmin.php index c41a32bb..a5b37839 100644 --- a/Admin/RedirectRouteAdmin.php +++ b/Admin/RedirectRouteAdmin.php @@ -9,7 +9,6 @@ * file that was distributed with this source code. */ - namespace Symfony\Cmf\Bundle\RoutingBundle\Admin; use Sonata\AdminBundle\Datagrid\DatagridMapper; @@ -31,7 +30,7 @@ class RedirectRouteAdmin extends Admin protected function configureListFields(ListMapper $listMapper) { $listMapper - ->addIdentifier('id', 'text') + ->addIdentifier('path', 'text') ; } @@ -44,14 +43,15 @@ protected function configureFormFields(FormMapper $formMapper) ->add('routeName', 'text', array('required' => false)) ->add('uri', 'text', array('required' => false)) ->add('routeTarget', 'doctrine_phpcr_odm_tree', array('choice_list' => array(), 'required' => false, 'root_node' => $this->routeRoot)) - ->end(); + ->end() + ; } protected function configureDatagridFilters(DatagridMapper $datagridMapper) { $datagridMapper ->add('name', 'doctrine_phpcr_nodename') - ; + ; } public function setRouteRoot($routeRoot) @@ -69,6 +69,6 @@ public function toString($object) return $object instanceof Route && $object->getId() ? $object->getId() : $this->trans('link_add', array(), 'SonataAdminBundle') - ; + ; } } From 6e546e1357e9a794ec644c97b017186569ff63af Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Mon, 31 Mar 2014 23:26:16 +0200 Subject: [PATCH 11/12] add option for locale pattern --- Admin/RouteAdmin.php | 5 +++-- Resources/translations/CmfRoutingBundle.de.xliff | 5 +++++ Resources/translations/CmfRoutingBundle.en.xliff | 8 +++++++- Resources/translations/CmfRoutingBundle.fr.xliff | 5 +++++ 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/Admin/RouteAdmin.php b/Admin/RouteAdmin.php index 5dc9dd4d..6d5dd49e 100644 --- a/Admin/RouteAdmin.php +++ b/Admin/RouteAdmin.php @@ -147,8 +147,9 @@ protected function configureFieldsForDefaults() protected function configureFieldsForOptions() { $options = array( - 'addFormatPattern' => array('addFormatPattern', 'checkbox', array('required' => false, 'label' => 'form.label_add_format_pattern', 'translation_domain' => $this->translationDomain)), - 'addTrailingSlash' => array('addTrailingSlash', 'checkbox', array('required' => false, 'label' => 'form.label_add_trailing_slash', 'translation_domain' => $this->translationDomain)), + array('add_locale_pattern', 'checkbox', array('required' => false, 'label' => 'form.label_add_locale_pattern', 'translation_domain' => $this->translationDomain)), + array('add_format_pattern', 'checkbox', array('required' => false, 'label' => 'form.label_add_format_pattern', 'translation_domain' => $this->translationDomain)), + array('add_trailing_slash', 'checkbox', array('required' => false, 'label' => 'form.label_add_trailing_slash', 'translation_domain' => $this->translationDomain)), ); $dynamicOptions = $this->getSubject()->getOptions(); diff --git a/Resources/translations/CmfRoutingBundle.de.xliff b/Resources/translations/CmfRoutingBundle.de.xliff index 618e09a0..4cb37376 100644 --- a/Resources/translations/CmfRoutingBundle.de.xliff +++ b/Resources/translations/CmfRoutingBundle.de.xliff @@ -110,6 +110,10 @@ form.label_routes Routen + + form.label_add_locale_pattern + Sprache hinzufügen + form.label_add_format_pattern Formatmuster hinzufügen @@ -122,6 +126,7 @@ form.help_options Schrägstrich: Die URL hört in diesem Fall mit einem Schrägstrich auf, zum Beispiel /eine/url/ ]]> diff --git a/Resources/translations/CmfRoutingBundle.en.xliff b/Resources/translations/CmfRoutingBundle.en.xliff index 56ed0ed0..a565391f 100644 --- a/Resources/translations/CmfRoutingBundle.en.xliff +++ b/Resources/translations/CmfRoutingBundle.en.xliff @@ -110,6 +110,10 @@ form.label_routes Routes + + form.label_add_locale_pattern + Add locale pattern + form.label_add_format_pattern Add format pattern @@ -121,7 +125,9 @@ form.help_options - + + Format: Append format to route like /your/route.{format}. Default format is 'html'
Slash: Append a trailing slash to route like /your/route/ ]]>
diff --git a/Resources/translations/CmfRoutingBundle.fr.xliff b/Resources/translations/CmfRoutingBundle.fr.xliff index 6ce724fd..57ed3fb7 100644 --- a/Resources/translations/CmfRoutingBundle.fr.xliff +++ b/Resources/translations/CmfRoutingBundle.fr.xliff @@ -110,6 +110,10 @@ form.label_routes Routes
+ + form.label_add_locale_pattern + Ajouter le langage + form.label_add_format_pattern Ajouter le motif du format @@ -121,6 +125,7 @@ form.help_options Format: Ajoute le format à la route tel que /your/route.{format}. Le format par défaut est 'html'
Barre Oblique: Ajoute un slash à la fin de la route tel que /your/route/ ]]> From 2c9293e4217c2b80f8f50b5584ef851e42a0b26d Mon Sep 17 00:00:00 2001 From: Lukas Kahwe Smith Date: Tue, 1 Apr 2014 14:27:42 +0200 Subject: [PATCH 12/12] routing component candidates branch has been merged --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index c9c7dd96..5af886c4 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ "prefer-stable": false, "require": { "php": ">=5.3.3", - "symfony-cmf/routing": "dev-candidates as 1.2.0", + "symfony-cmf/routing": "~1.2.0", "symfony/framework-bundle": "~2.2" }, "require-dev": {