summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcatch2013-02-21 10:17:55 (GMT)
committercatch2013-02-21 10:17:55 (GMT)
commit4ab57bed547f41d045d78bba1cb8d9f08fbbbf1b (patch)
tree9b1cd5c8a26d3a5e6d4e61b101400caca0194b66
parent98294873f591b1867e38a19141e9261386b7ebcc (diff)
Issue #1910318 by katbailey: Make path resolution the responsibility of a series of PathProcessor classes, rather than one PathSubscriber class.
-rw-r--r--core/lib/Drupal/Core/CoreBundle.php27
-rw-r--r--core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterPathProcessorsPass.php35
-rw-r--r--core/lib/Drupal/Core/EventSubscriber/PathSubscriber.php89
-rw-r--r--core/lib/Drupal/Core/PathProcessor/InboundPathProcessorInterface.php28
-rw-r--r--core/lib/Drupal/Core/PathProcessor/PathProcessorAlias.php43
-rw-r--r--core/lib/Drupal/Core/PathProcessor/PathProcessorDecode.php35
-rw-r--r--core/lib/Drupal/Core/PathProcessor/PathProcessorFront.php48
-rw-r--r--core/lib/Drupal/Core/PathProcessor/PathProcessorManager.php92
-rw-r--r--core/modules/language/language.negotiation.inc4
-rw-r--r--core/modules/language/lib/Drupal/language/HttpKernel/PathProcessorLanguage.php37
-rw-r--r--core/modules/language/lib/Drupal/language/LanguageBundle.php29
-rw-r--r--core/modules/system/lib/Drupal/system/Tests/Path/AliasTest.php16
-rw-r--r--core/modules/system/lib/Drupal/system/Tests/Path/PathUnitTestBase.php28
-rw-r--r--core/modules/system/lib/Drupal/system/Tests/Path/UrlAliasFixtures.php6
-rw-r--r--core/modules/system/lib/Drupal/system/Tests/PathProcessor/PathProcessorFixtures.php27
-rw-r--r--core/modules/system/lib/Drupal/system/Tests/PathProcessor/PathProcessorTest.php124
16 files changed, 568 insertions, 100 deletions
diff --git a/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php
index 2ebe38f..c6c2a60 100644
--- a/core/lib/Drupal/Core/CoreBundle.php
+++ b/core/lib/Drupal/Core/CoreBundle.php
@@ -10,6 +10,7 @@ namespace Drupal\Core;
use Drupal\Core\DependencyInjection\Compiler\RegisterKernelListenersPass;
use Drupal\Core\DependencyInjection\Compiler\RegisterAccessChecksPass;
use Drupal\Core\DependencyInjection\Compiler\RegisterMatchersPass;
+use Drupal\Core\DependencyInjection\Compiler\RegisterPathProcessorsPass;
use Drupal\Core\DependencyInjection\Compiler\RegisterRouteFiltersPass;
use Drupal\Core\DependencyInjection\Compiler\RegisterRouteEnhancersPass;
use Drupal\Core\DependencyInjection\Compiler\RegisterParamConvertersPass;
@@ -245,6 +246,7 @@ class CoreBundle extends Bundle {
->addTag('event_subscriber');
$container->register('path_subscriber', 'Drupal\Core\EventSubscriber\PathSubscriber')
->addArgument(new Reference('path.alias_manager.cached'))
+ ->addArgument(new Reference('path_processor_manager'))
->addTag('event_subscriber');
$container->register('legacy_request_subscriber', 'Drupal\Core\EventSubscriber\LegacyRequestSubscriber')
->addTag('event_subscriber');
@@ -270,6 +272,8 @@ class CoreBundle extends Bundle {
->addTag('event_subscriber')
->addArgument(array(new Reference('exception_controller'), 'execute'));
+ $this->registerPathProcessors($container);
+
$container
->register('transliteration', 'Drupal\Core\Transliteration\PHPTransliteration');
@@ -375,4 +379,27 @@ class CoreBundle extends Bundle {
// @see http://drupal.org/node/1804998
->addMethodCall('addExtension', array(new Definition('Twig_Extension_Debug')));
}
+
+ /**
+ * Register services related to path processing.
+ */
+ protected function registerPathProcessors(ContainerBuilder $container) {
+ // Register the path processor manager service.
+ $container->register('path_processor_manager', 'Drupal\Core\PathProcessor\PathProcessorManager');
+ // Register the processor that urldecodes the path.
+ $container->register('path_processor_decode', 'Drupal\Core\PathProcessor\PathProcessorDecode')
+ ->addTag('path_processor_inbound', array('priority' => 1000));
+ // Register the processor that resolves the front page.
+ $container->register('path_processor_front', 'Drupal\Core\PathProcessor\PathProcessorFront')
+ ->addArgument(new Reference('config.factory'))
+ ->addTag('path_processor_inbound', array('priority' => 200));
+ // Register the alias path processor.
+ $container->register('path_processor_alias', 'Drupal\Core\PathProcessor\PathProcessorAlias')
+ ->addArgument(new Reference('path.alias_manager'))
+ ->addTag('path_processor_inbound', array('priority' => 100));
+
+ // Add the compiler pass that will process the tagged services.
+ $container->addCompilerPass(new RegisterPathProcessorsPass());
+ }
+
}
diff --git a/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterPathProcessorsPass.php b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterPathProcessorsPass.php
new file mode 100644
index 0000000..6e298da
--- /dev/null
+++ b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterPathProcessorsPass.php
@@ -0,0 +1,35 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\DependencyInjection\Compiler\RegisterPathProcessorsPass.
+ */
+
+namespace Drupal\Core\DependencyInjection\Compiler;
+
+use Symfony\Component\DependencyInjection\Reference;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
+
+/**
+ * Adds services to the 'path_processor_manager service.
+ */
+class RegisterPathProcessorsPass implements CompilerPassInterface {
+
+ /**
+ * Adds services tagged 'path_processor_inbound' to the path processor manager.
+ *
+ * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
+ * The container to process.
+ */
+ public function process(ContainerBuilder $container) {
+ if (!$container->hasDefinition('path_processor_manager')) {
+ return;
+ }
+ $manager = $container->getDefinition('path_processor_manager');
+ foreach ($container->findTaggedServiceIds('path_processor_inbound') as $id => $attributes) {
+ $priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0;
+ $manager->addMethodCall('addInbound', array(new Reference($id), $priority));
+ }
+ }
+}
diff --git a/core/lib/Drupal/Core/EventSubscriber/PathSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/PathSubscriber.php
index 6e5b7a9..5915d4b 100644
--- a/core/lib/Drupal/Core/EventSubscriber/PathSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/PathSubscriber.php
@@ -8,6 +8,7 @@
namespace Drupal\Core\EventSubscriber;
use Drupal\Core\CacheDecorator\AliasManagerCacheDecorator;
+use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
@@ -20,24 +21,24 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class PathSubscriber extends PathListenerBase implements EventSubscriberInterface {
protected $aliasManager;
+ protected $pathProcessor;
- public function __construct(AliasManagerCacheDecorator $alias_manager) {
+ public function __construct(AliasManagerCacheDecorator $alias_manager, InboundPathProcessorInterface $path_processor) {
$this->aliasManager = $alias_manager;
+ $this->pathProcessor = $path_processor;
}
/**
- * Resolve the system path.
+ * Converts the request path to a system path.
*
* @param Symfony\Component\HttpKernel\Event\GetResponseEvent $event
* The Event to process.
*/
- public function onKernelRequestPathResolve(GetResponseEvent $event) {
+ public function onKernelRequestConvertPath(GetResponseEvent $event) {
$request = $event->getRequest();
- $path = $this->extractPath($request);
- $path = $this->aliasManager->getSystemPath($path);
- $this->setPath($request, $path);
- // If this is the master request, set the cache key for the caching of all
- // system paths looked up during the request.
+ $path = trim($request->getPathInfo(), '/');
+ $path = $this->pathProcessor->processInbound($path, $request);
+ $request->attributes->set('system_path', $path);
if ($event->getRequestType() == HttpKernelInterface::MASTER_REQUEST) {
$this->aliasManager->setCacheKey($path);
}
@@ -51,84 +52,14 @@ class PathSubscriber extends PathListenerBase implements EventSubscriberInterfac
}
/**
- * Resolve the front-page default path.
- *
- * @todo The path system should be objectified to remove the function calls in
- * this method.
- *
- * @param Symfony\Component\HttpKernel\Event\GetResponseEvent $event
- * The Event to process.
- */
- public function onKernelRequestFrontPageResolve(GetResponseEvent $event) {
- $request = $event->getRequest();
- $path = $this->extractPath($request);
-
- if (empty($path)) {
- // @todo Temporary hack. Fix when configuration is injectable.
- $path = config('system.site')->get('page.front');
- if (empty($path)) {
- $path = 'user';
- }
- }
-
- $this->setPath($request, $path);
- }
-
- /**
- * Decode language information embedded in the request path.
- *
- * @param Symfony\Component\HttpKernel\Event\GetResponseEvent $event
- * The Event to process.
- */
- public function onKernelRequestLanguageResolve(GetResponseEvent $event) {
- // We need to act only on the master request, otherwise subrequests will
- // inherit the main request path and an infinite loop will be started.
- if ($event->getRequestType() == HttpKernelInterface::MASTER_REQUEST) {
- $path = _language_resolved_path();
- if ($path !== NULL) {
- $this->setPath($event->getRequest(), $path);
- }
- }
- }
-
- /**
- * Decodes the path of the request.
- *
- * Parameters in the URL sometimes represent code-meaningful strings. It is
- * therefore useful to always urldecode() those values so that individual
- * controllers need not concern themselves with it. This is Drupal-specific
- * logic and may not be familiar for developers used to other Symfony-family
- * projects.
- *
- * @todo Revisit whether or not this logic is appropriate for here or if
- * controllers should be required to implement this logic themselves. If we
- * decide to keep this code, remove this TODO.
- *
- * @param Symfony\Component\HttpKernel\Event\GetResponseEvent $event
- * The Event to process.
- */
- public function onKernelRequestDecodePath(GetResponseEvent $event) {
- $request = $event->getRequest();
- $path = $this->extractPath($request);
-
- $path = urldecode($path);
-
- $this->setPath($request, $path);
- }
-
- /**
* Registers the methods in this class that should be listeners.
*
* @return array
* An array of event listener definitions.
*/
static function getSubscribedEvents() {
- $events[KernelEvents::REQUEST][] = array('onKernelRequestDecodePath', 200);
- $events[KernelEvents::REQUEST][] = array('onKernelRequestLanguageResolve', 150);
- $events[KernelEvents::REQUEST][] = array('onKernelRequestFrontPageResolve', 101);
- $events[KernelEvents::REQUEST][] = array('onKernelRequestPathResolve', 100);
+ $events[KernelEvents::REQUEST][] = array('onKernelRequestConvertPath', 200);
$events[KernelEvents::TERMINATE][] = array('onKernelTerminate', 200);
-
return $events;
}
}
diff --git a/core/lib/Drupal/Core/PathProcessor/InboundPathProcessorInterface.php b/core/lib/Drupal/Core/PathProcessor/InboundPathProcessorInterface.php
new file mode 100644
index 0000000..946b29c
--- /dev/null
+++ b/core/lib/Drupal/Core/PathProcessor/InboundPathProcessorInterface.php
@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\PathProcessor\InboundPathProcessorInterface.
+ */
+
+namespace Drupal\Core\PathProcessor;
+
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Defines an interface for classes that process the inbound path.
+ */
+interface InboundPathProcessorInterface {
+
+ /**
+ * Processes the inbound path.
+ *
+ * @param string $path
+ * The path to process.
+ *
+ * @param \Symfony\Component\HttpFoundation\Request $request
+ * The HttpRequest object representing the current request.
+ */
+ public function processInbound($path, Request $request);
+
+}
diff --git a/core/lib/Drupal/Core/PathProcessor/PathProcessorAlias.php b/core/lib/Drupal/Core/PathProcessor/PathProcessorAlias.php
new file mode 100644
index 0000000..7020710
--- /dev/null
+++ b/core/lib/Drupal/Core/PathProcessor/PathProcessorAlias.php
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\PathProcessor\PathProcessorAlias.
+ */
+
+namespace Drupal\Core\PathProcessor;
+
+use Drupal\Core\Path\AliasManagerInterface;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Processes the inbound path using path alias lookups.
+ */
+class PathProcessorAlias implements InboundPathProcessorInterface {
+
+ /**
+ * An alias manager for looking up the system path.
+ *
+ * @var \Drupal\Core\Path\AliasManagerInterface
+ */
+ protected $aliasManager;
+
+ /**
+ * Constructs a PathProcessorAlias object.
+ *
+ * @param \Drupal\Core\Path\AliasManagerInterface $alias_manager
+ * An alias manager for looking up the system path.
+ */
+ public function __construct(AliasManagerInterface $alias_manager) {
+ $this->aliasManager = $alias_manager;
+ }
+
+ /**
+ * Implements Drupal\Core\PathProcessor\InboundPathProcessorInterface::processInbound().
+ */
+ public function processInbound($path, Request $request) {
+ $path = $this->aliasManager->getSystemPath($path);
+ return $path;
+ }
+
+}
diff --git a/core/lib/Drupal/Core/PathProcessor/PathProcessorDecode.php b/core/lib/Drupal/Core/PathProcessor/PathProcessorDecode.php
new file mode 100644
index 0000000..0674cda
--- /dev/null
+++ b/core/lib/Drupal/Core/PathProcessor/PathProcessorDecode.php
@@ -0,0 +1,35 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\PathProcessor\PathProcessorDecode.
+ */
+
+namespace Drupal\Core\PathProcessor;
+
+use Drupal\Core\Config\ConfigFactory;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Processes the inbound path by urldecoding it.
+ *
+ * Parameters in the URL sometimes represent code-meaningful strings. It is
+ * therefore useful to always urldecode() those values so that individual
+ * controllers need not concern themselves with it. This is Drupal-specific
+ * logic and may not be familiar for developers used to other Symfony-family
+ * projects.
+ *
+ * @todo Revisit whether or not this logic is appropriate for here or if
+ * controllers should be required to implement this logic themselves. If we
+ * decide to keep this code, remove this TODO.
+ */
+class PathProcessorDecode implements InboundPathProcessorInterface {
+
+ /**
+ * Implements Drupal\Core\PathProcessor\InboundPathProcessorInterface::processInbound().
+ */
+ public function processInbound($path, Request $request) {
+ return urldecode($path);
+ }
+
+}
diff --git a/core/lib/Drupal/Core/PathProcessor/PathProcessorFront.php b/core/lib/Drupal/Core/PathProcessor/PathProcessorFront.php
new file mode 100644
index 0000000..872885a
--- /dev/null
+++ b/core/lib/Drupal/Core/PathProcessor/PathProcessorFront.php
@@ -0,0 +1,48 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\PathProcessor\PathProcessorFront.
+ */
+
+namespace Drupal\Core\PathProcessor;
+
+use Drupal\Core\Config\ConfigFactory;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Processes the inbound path by resolving it to the front page if empty.
+ */
+class PathProcessorFront implements InboundPathProcessorInterface {
+
+ /**
+ * A config factory for retrieving required config settings.
+ *
+ * @var \Drupal\Core\Config\ConfigFactory
+ */
+ protected $config;
+
+ /**
+ * Constructs a PathProcessorFront object.
+ *
+ * @param Drupal\Core\Config\ConfigFactory $config
+ * A config factory for retrieving the site front page configuration.
+ */
+ public function __construct(ConfigFactory $config) {
+ $this->config = $config;
+ }
+
+ /**
+ * Implements Drupal\Core\PathProcessor\InboundPathProcessorInterface::processInbound().
+ */
+ public function processInbound($path, Request $request) {
+ if (empty($path)) {
+ $path = $this->config->get('system.site')->get('page.front');
+ if (empty($path)) {
+ $path = 'user';
+ }
+ }
+ return $path;
+ }
+
+}
diff --git a/core/lib/Drupal/Core/PathProcessor/PathProcessorManager.php b/core/lib/Drupal/Core/PathProcessor/PathProcessorManager.php
new file mode 100644
index 0000000..1d0adff
--- /dev/null
+++ b/core/lib/Drupal/Core/PathProcessor/PathProcessorManager.php
@@ -0,0 +1,92 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\PathProcessor\PathProcessorManager.
+ */
+
+namespace Drupal\Core\PathProcessor;
+
+use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Path processor manager.
+ *
+ * Holds an array of path processor objects and uses them to sequentially process
+ * a path, in order of processor priority.
+ */
+class PathProcessorManager implements InboundPathProcessorInterface {
+
+ /**
+ * Holds the array of processors to cycle through.
+ *
+ * @var array
+ * An array whose keys are priorities and whose values are arrays of path
+ * processor objects.
+ */
+ protected $inboundProcessors = array();
+
+ /**
+ * Holds the array of processors, sorted by priority.
+ *
+ * @var array
+ * An array of path processor objects.
+ */
+ protected $sortedInbound = array();
+
+ /**
+ * Adds an inbound processor object to the $inboundProcessors property.
+ *
+ * @param \Drupal\Core\PathProcessor\InboundPathProcessorInterface $processor
+ * The processor object to add.
+ *
+ * @param int $priority
+ * The priority of the processor being added.
+ */
+ public function addInbound(InboundPathProcessorInterface $processor, $priority = 0) {
+ $this->inboundProcessors[$priority][] = $processor;
+ $this->sortedInbound = array();
+ }
+
+ /**
+ * Implements Drupal\Core\PathProcessor\InboundPathProcessorInterface::processInbound().
+ */
+ public function processInbound($path, Request $request) {
+ $processors = $this->getInbound();
+ foreach ($processors as $processor) {
+ $path = $processor->processInbound($path, $request);
+ }
+ return $path;
+ }
+
+ /**
+ * Returns the sorted array of inbound processors.
+ *
+ * @return array
+ * An array of processor objects.
+ */
+ protected function getInbound() {
+ if (empty($this->sortedInbound)) {
+ $this->sortedInbound = $this->sortProcessors('inboundProcessors');
+ }
+
+ return $this->sortedInbound;
+ }
+
+ /**
+ * Sorts the processors according to priority.
+ *
+ * @param string $type
+ * The processor type to sort, e.g. 'inboundProcessors'.
+ */
+ protected function sortProcessors($type) {
+ $sorted = array();
+ krsort($this->{$type});
+
+ foreach ($this->{$type} as $processors) {
+ $sorted = array_merge($sorted, $processors);
+ }
+ return $sorted;
+ }
+}
diff --git a/core/modules/language/language.negotiation.inc b/core/modules/language/language.negotiation.inc
index 9521247..6565c6d 100644
--- a/core/modules/language/language.negotiation.inc
+++ b/core/modules/language/language.negotiation.inc
@@ -282,11 +282,7 @@ function language_from_url($languages, Request $request = NULL) {
case LANGUAGE_NEGOTIATION_URL_PREFIX:
$request_path = urldecode(trim($request->getPathInfo(), '/'));
-
list($language, $path) = language_url_split_prefix($request_path, $languages);
- // Store the correct system path, i.e., the request path without the
- // language prefix.
- _language_resolved_path($path);
if ($language !== FALSE) {
$language_url = $language->langcode;
diff --git a/core/modules/language/lib/Drupal/language/HttpKernel/PathProcessorLanguage.php b/core/modules/language/lib/Drupal/language/HttpKernel/PathProcessorLanguage.php
new file mode 100644
index 0000000..ad16ac6
--- /dev/null
+++ b/core/modules/language/lib/Drupal/language/HttpKernel/PathProcessorLanguage.php
@@ -0,0 +1,37 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\language\HttpKernel\PathProcessorLanguage.
+ */
+
+namespace Drupal\language\HttpKernel;
+
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Processes the inbound path using path alias lookups.
+ */
+class PathProcessorLanguage implements InboundPathProcessorInterface {
+
+ protected $moduleHandler;
+
+ public function __construct(ModuleHandlerInterface $module_handler) {
+ $this->moduleHandler = $module_handler;
+ }
+
+ /**
+ * Implements Drupal\Core\PathProcessor\InboundPathProcessorInterface::processInbound().
+ */
+ public function processInbound($path, Request $request) {
+ include_once DRUPAL_ROOT . '/core/includes/language.inc';
+ $this->moduleHandler->loadInclude('language', 'inc', 'language.negotiation');
+ $languages = language_list();
+ list($language, $path) = language_url_split_prefix($path, $languages);
+ return $path;
+ }
+
+}
diff --git a/core/modules/language/lib/Drupal/language/LanguageBundle.php b/core/modules/language/lib/Drupal/language/LanguageBundle.php
new file mode 100644
index 0000000..1e788aa
--- /dev/null
+++ b/core/modules/language/lib/Drupal/language/LanguageBundle.php
@@ -0,0 +1,29 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\language\LanguageBundle.
+ */
+
+namespace Drupal\language;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\HttpKernel\Bundle\Bundle;
+use Symfony\Component\DependencyInjection\Reference;
+
+/**
+ * language dependency injection container.
+ */
+class LanguageBundle extends Bundle {
+
+ /**
+ * Overrides Symfony\Component\HttpKernel\Bundle\Bundle::build().
+ */
+ public function build(ContainerBuilder $container) {
+ // Register the language-based path processor.
+ $container->register('path_processor_language', 'Drupal\language\HttpKernel\PathProcessorLanguage')
+ ->addArgument(new Reference('module_handler'))
+ ->addTag('path_processor_inbound', array('priority' => 300));
+ }
+
+}
diff --git a/core/modules/system/lib/Drupal/system/Tests/Path/AliasTest.php b/core/modules/system/lib/Drupal/system/Tests/Path/AliasTest.php
index 275e1c4..5dc3158 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Path/AliasTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Path/AliasTest.php
@@ -2,7 +2,7 @@
/**
* @file
- * Definition of Drupal\system\Tests\Path\CrudTest.
+ * Contains Drupal\system\Tests\Path\AliasTest.
*/
namespace Drupal\system\Tests\Path;
@@ -15,7 +15,7 @@ use Drupal\Core\Path\AliasManager;
/**
* Tests path alias CRUD and lookup functionality.
*/
-class AliasTest extends DrupalUnitTestBase {
+class AliasTest extends PathUnitTestBase {
public static function getInfo() {
return array(
@@ -25,18 +25,6 @@ class AliasTest extends DrupalUnitTestBase {
);
}
- public function setUp() {
- parent::setUp();
- $this->fixtures = new UrlAliasFixtures();
- }
-
- public function tearDown() {
- $this->fixtures->dropTables(Database::getConnection());
-
- parent::tearDown();
- }
-
-
function testCRUD() {
//Prepare database table.
$connection = Database::getConnection();
diff --git a/core/modules/system/lib/Drupal/system/Tests/Path/PathUnitTestBase.php b/core/modules/system/lib/Drupal/system/Tests/Path/PathUnitTestBase.php
new file mode 100644
index 0000000..c24506d
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Tests/Path/PathUnitTestBase.php
@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\system\Tests\Path\PathUnitTestBase.
+ */
+
+namespace Drupal\system\Tests\Path;
+
+use Drupal\simpletest\DrupalUnitTestBase;
+use Drupal\Core\Database\Database;
+
+/**
+ * Defines a base class for path unit testing.
+ */
+class PathUnitTestBase extends DrupalUnitTestBase {
+
+ public function setUp() {
+ parent::setUp();
+ $this->fixtures = new UrlAliasFixtures();
+ }
+
+ public function tearDown() {
+ $this->fixtures->dropTables(Database::getConnection());
+
+ parent::tearDown();
+ }
+}
diff --git a/core/modules/system/lib/Drupal/system/Tests/Path/UrlAliasFixtures.php b/core/modules/system/lib/Drupal/system/Tests/Path/UrlAliasFixtures.php
index 6fb02da..a51e3bf 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Path/UrlAliasFixtures.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Path/UrlAliasFixtures.php
@@ -16,7 +16,7 @@ class UrlAliasFixtures {
* The connection to use to create the tables.
*/
public function createTables(Connection $connection) {
- $tables = $this->urlAliasTableDefinition();
+ $tables = $this->tableDefinition();
$schema = $connection->schema();
foreach ($tables as $name => $table) {
@@ -32,7 +32,7 @@ class UrlAliasFixtures {
* The connection to use to drop the tables.
*/
public function dropTables(Connection $connection) {
- $tables = $this->urlAliasTableDefinition();
+ $tables = $this->tableDefinition();
$schema = $connection->schema();
foreach ($tables as $name => $table) {
@@ -77,7 +77,7 @@ class UrlAliasFixtures {
* @return array
* Table definitions.
*/
- public function urlAliasTableDefinition() {
+ public function tableDefinition() {
$tables = array();
module_load_install('system');
diff --git a/core/modules/system/lib/Drupal/system/Tests/PathProcessor/PathProcessorFixtures.php b/core/modules/system/lib/Drupal/system/Tests/PathProcessor/PathProcessorFixtures.php
new file mode 100644
index 0000000..dbc987d
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Tests/PathProcessor/PathProcessorFixtures.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace Drupal\system\Tests\PathProcessor;
+
+use Drupal\Core\Database\Connection;
+use Drupal\system\Tests\Path\UrlAliasFixtures;
+
+/**
+ * Utility methods to provide necessary database tables for tests.
+ */
+class PathProcessorFixtures extends UrlAliasFixtures {
+
+ /**
+ * Overrides Drupal\system\Tests\Path\UrlAliasFixtures::tableDefinition() .
+ */
+ public function tableDefinition() {
+ // In addition to the tables added by the parent method, we also need the
+ // language and variable tables for the path processor tests.
+ $tables = parent::tableDefinition();
+ $schema = system_schema();
+ $tables['variable'] = $schema['variable'];
+ module_load_install('language');
+ $schema = language_schema();
+ $tables['language'] = $schema['language'];
+ return $tables;
+ }
+}
diff --git a/core/modules/system/lib/Drupal/system/Tests/PathProcessor/PathProcessorTest.php b/core/modules/system/lib/Drupal/system/Tests/PathProcessor/PathProcessorTest.php
new file mode 100644
index 0000000..5b10c2a
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Tests/PathProcessor/PathProcessorTest.php
@@ -0,0 +1,124 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\system\Tests\PathProcessor\PathProcessorTest.
+ */
+
+namespace Drupal\system\Tests\PathProcessor;
+
+use Drupal\system\Tests\Path\PathUnitTestBase;
+use Drupal\Core\Database\Database;
+use Drupal\Core\Path\Path;
+use Drupal\Core\Path\AliasManager;
+use Drupal\Core\PathProcessor\PathProcessorAlias;
+use Drupal\Core\PathProcessor\PathProcessorDecode;
+use Drupal\Core\PathProcessor\PathProcessorFront;
+use Drupal\Core\PathProcessor\PathProcessorManager;
+use Drupal\language\HttpKernel\PathProcessorLanguage;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Tests path processor functionality.
+ */
+class PathProcessorTest extends PathUnitTestBase {
+
+ public static function getInfo() {
+ return array(
+ 'name' => t('Path Processor Unit Tests'),
+ 'description' => t('Tests processing of the inbound path.'),
+ 'group' => t('Path API'),
+ );
+ }
+
+ public function setUp() {
+ parent::setUp();
+ $this->fixtures = new PathProcessorFixtures();
+ }
+
+ /**
+ * Tests resolving the inbound path to the system path.
+ */
+ function testProcessInbound() {
+
+ // Ensure all tables needed for these tests are created.
+ $connection = Database::getConnection();
+ $this->fixtures->createTables($connection);
+
+ // Create dependecies needed by various path processors.
+ $alias_manager = new AliasManager($connection, $this->container->get('state'), $this->container->get('language_manager'));
+ $module_handler = $this->container->get('module_handler');
+
+ // Create the processors.
+ $alias_processor = new PathProcessorAlias($alias_manager);
+ $decode_processor = new PathProcessorDecode();
+ $front_processor = new PathProcessorFront($this->container->get('config.factory'));
+ $language_processor = new PathProcessorLanguage($module_handler);
+
+ // Add a url alias for testing the alias-based processor.
+ $path_crud = new Path($connection, $alias_manager);
+ $path_crud->save('user/1', 'foo');
+
+ // Add a language for testing the language-based processor.
+ $module_handler->setModuleList(array('language' => 'core/modules/language/language.module'));
+ $module_handler->load('language');
+ $language = new \stdClass();
+ $language->langcode = 'fr';
+ $language->name = 'French';
+ language_save($language);
+
+ // First, test the processor manager with the processors in the incorrect
+ // order. The alias processor will run before the language processor, meaning
+ // aliases will not be found.
+ $priorities = array(
+ 1000 => $alias_processor,
+ 500 => $decode_processor,
+ 300 => $front_processor,
+ 200 => $language_processor,
+ );
+
+ // Create the processor manager and add the processors.
+ $processor_manager = new PathProcessorManager();
+ foreach ($priorities as $priority => $processor) {
+ $processor_manager->addInbound($processor, $priority);
+ }
+
+ // Test resolving the French homepage using the incorrect processor order.
+ $test_path = 'fr';
+ $request = Request::create($test_path);
+ $processed = $processor_manager->processInbound($test_path, $request);
+ $this->assertEqual($processed, '', 'Processing in the incorrect order fails to resolve the system path from the empty path');
+
+ // Test resolving an existing alias using the incorrect processor order.
+ $test_path = 'fr/foo';
+ $request = Request::create($test_path);
+ $processed = $processor_manager->processInbound($test_path, $request);
+ $this->assertEqual($processed, 'foo', 'Processing in the incorrect order fails to resolve the system path from an alias');
+
+ // Now create a new processor manager and add the processors, this time in
+ // the correct order.
+ $processor_manager = new PathProcessorManager();
+ $priorities = array(
+ 1000 => $decode_processor,
+ 500 => $language_processor,
+ 300 => $front_processor,
+ 200 => $alias_processor,
+ );
+ foreach ($priorities as $priority => $processor) {
+ $processor_manager->addInbound($processor, $priority);
+ }
+
+ // Test resolving the French homepage using the correct processor order.
+ $test_path = 'fr';
+ $request = Request::create($test_path);
+ $processed = $processor_manager->processInbound($test_path, $request);
+ $this->assertEqual($processed, 'user', 'Processing in the correct order resolves the system path from the empty path.');
+
+ // Test resolving an existing alias using the correct processor order.
+ $test_path = 'fr/foo';
+ $request = Request::create($test_path);
+ $processed = $processor_manager->processInbound($test_path, $request);
+ $this->assertEqual($processed, 'user/1', 'Processing in the correct order resolves the system path from an alias.');
+ }
+
+}