diff --git a/core/modules/language/language.services.yml b/core/modules/language/language.services.yml index 052fdc0301be48acf10ffe734aef003e57535ba0..576f4f8c326d0cf41d31e0ef26e962a32bba91f8 100644 --- a/core/modules/language/language.services.yml +++ b/core/modules/language/language.services.yml @@ -3,4 +3,4 @@ services: class: Drupal\language\HttpKernel\PathProcessorLanguage tags: - { name: path_processor_inbound, priority: 300 } - arguments: ['@module_handler'] + arguments: ['@config.factory'] diff --git a/core/modules/language/lib/Drupal/language/HttpKernel/PathProcessorLanguage.php b/core/modules/language/lib/Drupal/language/HttpKernel/PathProcessorLanguage.php index ad16ac6802199b0ee6765fc77ef9954be2fa1e98..006b31357d58b7d564bae6986348e8ba9177aeac 100644 --- a/core/modules/language/lib/Drupal/language/HttpKernel/PathProcessorLanguage.php +++ b/core/modules/language/lib/Drupal/language/HttpKernel/PathProcessorLanguage.php @@ -7,7 +7,7 @@ namespace Drupal\language\HttpKernel; -use Drupal\Core\Extension\ModuleHandlerInterface; +use Drupal\Core\Config\ConfigFactory; use Drupal\Core\PathProcessor\InboundPathProcessorInterface; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpFoundation\Request; @@ -17,20 +17,55 @@ */ class PathProcessorLanguage implements InboundPathProcessorInterface { - protected $moduleHandler; + /** + * A config factory for retrieving required config settings. + * + * @var \Drupal\Core\Config\ConfigFactory + */ + protected $config; + + /** + * An array of enabled languages. + * + * @var array + */ + protected $languages; - public function __construct(ModuleHandlerInterface $module_handler) { - $this->moduleHandler = $module_handler; + /** + * Constructs a PathProcessorLanguage object. + * + * @param \Drupal\Core\Config\ConfigFactory $config + * A config factory object for retrieving configuration settings. + * + * @param array $languages + * An array of languages, keyed by language code, representing the languages + * currently enabled on the site. + */ + public function __construct(ConfigFactory $config, array $languages = array()) { + $this->config = $config; + if (empty($languages)) { + $languages = language_list(); + } + $this->languages = $languages; } /** * 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); + if (!empty($path)) { + $args = explode('/', $path); + $prefix = array_shift($args); + + // Search prefix within enabled languages. + $prefixes = $this->config->get('language.negotiation')->get('url.prefixes'); + foreach ($this->languages as $language) { + if (isset($prefixes[$language->langcode]) && $prefixes[$language->langcode] == $prefix) { + // Rebuild $path with the language removed. + return implode('/', $args); + } + } + } return $path; } diff --git a/core/modules/system/lib/Drupal/system/Tests/PathProcessor/PathProcessorFixtures.php b/core/modules/system/lib/Drupal/system/Tests/PathProcessor/PathProcessorFixtures.php deleted file mode 100644 index dbc987dbccedbcf20540a4a2cff71b52976f845b..0000000000000000000000000000000000000000 --- a/core/modules/system/lib/Drupal/system/Tests/PathProcessor/PathProcessorFixtures.php +++ /dev/null @@ -1,27 +0,0 @@ -fixtures = new PathProcessorFixtures(); + + // Set up some languages to be used by the language-based path processor. + $languages = array(); + foreach (array('en' => 'English', 'fr' => 'French') as $langcode => $language_name) { + $language = new \stdClass(); + $language->langcode = $langcode; + $language->name = $language_name; + $languages[$langcode] = $language; + } + $this->languages = $languages; + } /** @@ -42,32 +50,43 @@ public function setUp() { */ function testProcessInbound() { - // Ensure all tables needed for these tests are created. - $connection = Database::getConnection(); - $this->fixtures->createTables($connection); + // Create an alias manager stub. + $alias_manager = $this->getMockBuilder('Drupal\Core\Path\AliasManager') + ->disableOriginalConstructor() + ->getMock(); + + $system_path_map = array( + // Set up one proper alias that can be resolved to a system path. + array('foo', NULL, 'user/1'), + // Passing in anything else should return the same string. + array('fr/foo', NULL, 'fr/foo'), + array('fr', NULL, 'fr'), + array('user', NULL, 'user'), + ); - // Create dependecies needed by various path processors. - $whitelist = new AliasWhitelist('path_alias_whitelist', 'cache', $this->container->get('keyvalue'), $connection); - $alias_manager = new AliasManager($connection, $whitelist, $this->container->get('language_manager')); - $module_handler = $this->container->get('module_handler'); + $alias_manager->expects($this->any()) + ->method('getSystemPath') + ->will($this->returnValueMap($system_path_map)); + + // Create a stub config factory with all config settings that will be checked + // during this test. + $language_prefixes = array_keys($this->languages); + $config_factory_stub = $this->getConfigFactoryStub( + array( + 'system.site' => array( + 'page.front' => 'user' + ), + 'language.negotiation' => array( + 'url.prefixes' => array_combine($language_prefixes, $language_prefixes) + ) + ) + ); // 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); + $front_processor = new PathProcessorFront($config_factory_stub); + $language_processor = new PathProcessorLanguage($config_factory_stub, $this->languages); // First, test the processor manager with the processors in the incorrect // order. The alias processor will run before the language processor, meaning @@ -89,13 +108,13 @@ function testProcessInbound() { $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'); + $this->assertEquals('', $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'); + $this->assertEquals('foo', $processed, '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. @@ -114,13 +133,12 @@ function testProcessInbound() { $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.'); + $this->assertEquals('user', $processed, '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.'); + $this->assertEquals('user/1', $processed, 'Processing in the correct order resolves the system path from an alias.'); } - } diff --git a/core/tests/Drupal/Tests/UnitTestCase.php b/core/tests/Drupal/Tests/UnitTestCase.php index b9a7b504a7804db123fefb7517f8aac9c343985a..c03d125b69559a1cfbcec7452ad1b2a28d5e55b0 100644 --- a/core/tests/Drupal/Tests/UnitTestCase.php +++ b/core/tests/Drupal/Tests/UnitTestCase.php @@ -58,4 +58,46 @@ public static function randomName($length = 8) { } return $str; } + + /** + * Returns a stub config factory that behaves according to the passed in array. + * + * Use this to generate a config factory that will return the desired values + * for the given config names. + * + * @param array $configs + * An associative array of configuration settings whose keys are configuration + * object names and whose values are key => value arrays for the configuration + * object in question. + * + * @return \PHPUnit_Framework_MockObject_MockBuilder + * A MockBuilder object for the ConfigFactory with the desired return values. + */ + public function getConfigFactoryStub($configs) { + $config_map = array(); + // Construct the desired configuration object stubs, each with its own + // desired return map. + foreach ($configs as $config_name => $config_values) { + $config_object = $this->getMockBuilder('Drupal\Core\Config\Config') + ->disableOriginalConstructor() + ->getMock(); + $map = array(); + foreach ($config_values as $key => $value) { + $map[] = array($key, $value); + } + $config_object->expects($this->any()) + ->method('get') + ->will($this->returnValueMap($map)); + $config_map[] = array($config_name, $config_object); + } + // Construct a config factory with the array of configuration object stubs + // as its return map. + $config_factory = $this->getMockBuilder('Drupal\Core\Config\ConfigFactory') + ->disableOriginalConstructor() + ->getMock(); + $config_factory->expects($this->any()) + ->method('get') + ->will($this->returnValueMap($config_map)); + return $config_factory; + } }