diff --git a/CmfRoutingBundle.php b/CmfRoutingBundle.php index 72612e2c..fcce4960 100644 --- a/CmfRoutingBundle.php +++ b/CmfRoutingBundle.php @@ -3,6 +3,7 @@ namespace Symfony\Cmf\Bundle\RoutingBundle; use Doctrine\Bundle\PHPCRBundle\DependencyInjection\Compiler\DoctrinePhpcrMappingsPass; +use Symfony\Cmf\Bundle\CoreBundle\DependencyInjection\Compiler\DoctrineOrmMappingsPass; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\HttpKernel\Bundle\Bundle; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -33,10 +34,39 @@ public function build(ContainerBuilder $container) realpath(__DIR__ . '/Resources/config/doctrine-model') => 'Symfony\Cmf\Bundle\RoutingBundle\Model', realpath(__DIR__ . '/Resources/config/doctrine-phpcr') => 'Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr', ), - array('cmf_routing.manager_name') + array('cmf_routing.dynamic.persistence.phpcr.manager_name'), + 'cmf_routing.backend_type_phpcr' ) ); } + + if (class_exists('Symfony\Cmf\Bundle\CoreBundle\DependencyInjection\Compiler\DoctrineOrmMappingsPass')) { + $container->addCompilerPass($this->buildBaseOrmCompilerPass()); + $container->addCompilerPass( + DoctrineOrmMappingsPass::createXmlMappingDriver( + array( + realpath(__DIR__ . '/Resources/config/doctrine-model') => 'Symfony\Cmf\Bundle\RoutingBundle\Model', + realpath(__DIR__ . '/Resources/config/doctrine-orm') => 'Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Orm', + ), + array('cmf_routing.dynamic.persistence.orm.manager_name'), + 'cmf_routing.backend_type_orm' + ) + ); + } + } + + private function buildBaseOrmCompilerPass() + { + $arguments = array(array(realpath(__DIR__ . '/Resources/config/doctrine-base')), '.orm.xml'); + $locator = new Definition('Doctrine\Common\Persistence\Mapping\Driver\DefaultFileLocator', $arguments); + $driver = new Definition('Doctrine\ORM\Mapping\Driver\XmlDriver', array($locator)); + + return new DoctrineOrmMappingsPass( + $driver, + array('Symfony\Component\Routing'), + array('cmf_routing.dynamic.persistence.orm.manager_name'), + 'cmf_routing.backend_type_orm' + ); } /** @@ -55,7 +85,7 @@ private function buildBasePhpcrCompilerPass() return new DoctrinePhpcrMappingsPass( $driver, array('Symfony\Component\Routing'), - array('cmf_routing.manager_name'), + array('cmf_routing.dynamic.persistence.phpcr.manager_name'), 'cmf_routing.backend_type_phpcr' ); } diff --git a/DependencyInjection/CmfRoutingExtension.php b/DependencyInjection/CmfRoutingExtension.php index 5a1ed2c9..9bd43515 100644 --- a/DependencyInjection/CmfRoutingExtension.php +++ b/DependencyInjection/CmfRoutingExtension.php @@ -93,6 +93,12 @@ private function setupDynamicRouter(array $config, ContainerBuilder $container, $hasProvider = true; $hasContentRepository = true; } + + if (!empty($config['persistence']['orm']['enabled'])) { + $this->loadOrmProvider($config['persistence']['orm'], $loader, $container); + $hasProvider = true; + } + if (isset($config['route_provider_service_id'])) { $container->setAlias('cmf_routing.route_provider', $config['route_provider_service_id']); $hasProvider = true; @@ -142,10 +148,10 @@ public function loadPhpcrProvider($config, XmlFileLoader $loader, ContainerBuild $container->setParameter($this->getAlias() . '.backend_type_phpcr', true); - $container->setParameter($this->getAlias() . '.persistence.phpcr.route_basepath', $config['route_basepath']); - $container->setParameter($this->getAlias() . '.persistence.phpcr.content_basepath', $config['content_basepath']); + $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() . '.manager_name', $config['manager_name']); + $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'); @@ -171,6 +177,13 @@ public function loadSonataPhpcrAdmin($config, XmlFileLoader $loader, ContainerBu $loader->load('admin-phpcr.xml'); } + public function loadOrmProvider($config, XmlFileLoader $loader, ContainerBuilder $container) + { + $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'); + } + /** * Returns the base path for the XSD files. * diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index cb89a4ea..d7d4a4e1 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -72,6 +72,12 @@ public function getConfigTreeBuilder() ->end() ->end() ->end() + ->arrayNode('orm') + ->children() + ->scalarNode('enabled')->defaultNull()->end() + ->scalarNode('manager_name')->defaultNull()->end() + ->end() + ->end() ->end() ->end() ->scalarNode('uri_filter_regexp')->defaultValue('')->end() diff --git a/Doctrine/DoctrineProvider.php b/Doctrine/DoctrineProvider.php index 368f5d5d..e2f705a5 100644 --- a/Doctrine/DoctrineProvider.php +++ b/Doctrine/DoctrineProvider.php @@ -40,6 +40,7 @@ abstract class DoctrineProvider public function __construct(ManagerRegistry $managerRegistry, $className = null) { $this->managerRegistry = $managerRegistry; + $this->className = $className; } /** diff --git a/Doctrine/Orm/ContentRepository.php b/Doctrine/Orm/ContentRepository.php new file mode 100644 index 00000000..4d7d087c --- /dev/null +++ b/Doctrine/Orm/ContentRepository.php @@ -0,0 +1,61 @@ +getModelAndId($id); + + return $this->getObjectManager()->getRepository($model)->find($modelId); + } + + /** + * {@inheritDoc} + */ + public function getContentId($content) + { + if (! is_object($content)) { + return null; + } + + try { + $meta = $this->getObjectManager()->getClassMetadata(get_class($content)); + $ids = $meta->getIdentifierValues($content); + if (0 !== count($ids)) { + throw new \Exception('Multi identifier values not supported in ' . get_class($content)); + } + + return implode(':', array( + get_class($content), + reset($ids) + )); + } catch (\Exception $e) { + return null; + } + } +} diff --git a/Doctrine/Orm/Route.php b/Doctrine/Orm/Route.php new file mode 100644 index 00000000..114fc8f4 --- /dev/null +++ b/Doctrine/Orm/Route.php @@ -0,0 +1,22 @@ +NOT not a doctrine repository but just the route + * provider for the NestedMatcher. (you could of course implement this + * interface in a repository class, if you need that) + * + * @author david.buchmann@liip.ch + */ +class RouteProvider extends DoctrineProvider implements RouteProviderInterface +{ + protected function getCandidates($url) + { + $candidates = array(); + if ('/' !== $url) { + if (preg_match('/(.+)\.[a-z]+$/i', $url, $matches)) { + $candidates[] = $url; + $url = $matches[1]; + } + + $part = $url; + while (false !== ($pos = strrpos($part, '/'))) { + $candidates[] = $part; + $part = substr($url, 0, $pos); + } + } + + $candidates[] = '/'; + + return $candidates; + } + + /** + * {@inheritDoc} + */ + public function getRouteByName($name, $parameters = array()) + { + $route = $this->getRoutesRepository()->findBy(array('name' => $name)); + if (!$route) { + throw new RouteNotFoundException("No route found for name '$name'"); + } + + return $route; + } + + public function getRoutesByNames($names, $parameters = array()) + { + } + + public function getRouteCollectionForRequest(Request $request) + { + $url = $request->getPathInfo(); + + $candidates = $this->getCandidates($url); + + $collection = new RouteCollection(); + + if (empty($candidates)) { + return $collection; + } + + try { + $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]); + } + // SYMFONY 2.1 COMPATIBILITY: tweak route name + $key = trim(preg_replace('/[^a-z0-9A-Z_.]/', '_', $key), '_'); + $collection->add($key, $route); + } + } catch (RepositoryException $e) { + // TODO: how to determine whether this is a relevant exception or not? + // for example, getting /my//test (note the double /) is just an invalid path + // and means another router might handle this. + // but if the PHPCR backend is down for example, we want to alert the user + } + + return $collection; + } + + protected function getRoutesRepository() + { + return $this->getObjectManager()->getRepository($this->className); + } +} diff --git a/Resources/config/admin-phpcr.xml b/Resources/config/admin-phpcr.xml index daab38c9..2e9aa97c 100644 --- a/Resources/config/admin-phpcr.xml +++ b/Resources/config/admin-phpcr.xml @@ -25,11 +25,11 @@ - %cmf_routing.persistence.phpcr.content_basepath% + %cmf_routing.dynamic.persistence.phpcr.content_basepath% - %cmf_routing.persistence.phpcr.route_basepath% + %cmf_routing.dynamic.persistence.phpcr.route_basepath% @@ -47,7 +47,7 @@ - %cmf_routing.persistence.phpcr.route_basepath% + %cmf_routing.dynamic.persistence.phpcr.route_basepath% diff --git a/Resources/config/doctrine-base/Symfony.Component.Routing.Route.orm.xml b/Resources/config/doctrine-base/Symfony.Component.Routing.Route.orm.xml new file mode 100644 index 00000000..29192202 --- /dev/null +++ b/Resources/config/doctrine-base/Symfony.Component.Routing.Route.orm.xml @@ -0,0 +1,12 @@ + + + + + + + + + + diff --git a/Resources/config/doctrine-model/Route.orm.xml b/Resources/config/doctrine-model/Route.orm.xml new file mode 100644 index 00000000..d815a646 --- /dev/null +++ b/Resources/config/doctrine-model/Route.orm.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + diff --git a/Resources/config/doctrine-orm/Route.orm.xml b/Resources/config/doctrine-orm/Route.orm.xml new file mode 100644 index 00000000..039081d3 --- /dev/null +++ b/Resources/config/doctrine-orm/Route.orm.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + diff --git a/Resources/config/provider-phpcr.xml b/Resources/config/provider-phpcr.xml index 2dd23b5a..59a60c7d 100644 --- a/Resources/config/provider-phpcr.xml +++ b/Resources/config/provider-phpcr.xml @@ -15,23 +15,23 @@ %cmf_routing.route_model_class% - %cmf_routing.manager_name% - %cmf_routing.persistence.phpcr.route_basepath% + %cmf_routing.dynamic.persistence.phpcr.manager_name% + %cmf_routing.dynamic.persistence.phpcr.route_basepath% - %cmf_routing.manager_name% + %cmf_routing.dynamic.persistence.phpcr.manager_name% - %cmf_routing.persistence.phpcr.route_basepath% + %cmf_routing.dynamic.persistence.phpcr.route_basepath% - %cmf_routing.persistence.phpcr.route_basepath% + %cmf_routing.dynamic.persistence.phpcr.route_basepath% %cmf_routing.locales% @@ -40,7 +40,7 @@ - %cmf_routing.persistence.phpcr.route_basepath% + %cmf_routing.dynamic.persistence.phpcr.route_basepath% diff --git a/Resources/config/provider_orm.xml b/Resources/config/provider_orm.xml new file mode 100644 index 00000000..4e8fc709 --- /dev/null +++ b/Resources/config/provider_orm.xml @@ -0,0 +1,24 @@ + + + + + Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Orm\Route + Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Orm\RouteProvider + Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Orm\ContentRepository + + + + + + + + + + + %cmf_routing.route_entity_class% + %cmf_routing.dynamic.persistence.orm.manager_name% + + +