Commit 940e0dff authored by donquixote's avatar donquixote Committed by webchick
Browse files

Issue #2083547 by donquixote: Implement PSR-4 for module-provided class files.

This affects class loading, plugin discovery and test discovery.

PSR-0 is still supported, and no module class files are moved yet.
parent 4f18d622
......@@ -26,10 +26,10 @@
"zendframework/zend-feed": "2.2.*"
},
"autoload": {
"psr-0": {
"Drupal\\Core": "core/lib/",
"Drupal\\Component": "core/lib/",
"Drupal\\Driver": "drivers/lib/"
"psr-4": {
"Drupal\\Core\\": "core/lib/Drupal/Core",
"Drupal\\Component\\": "core/lib/Drupal/Component",
"Drupal\\Driver\\": "drivers/lib/Drupal/Driver"
},
"files": [
"core/lib/Drupal.php"
......
......@@ -2124,7 +2124,10 @@ function drupal_classloader($class_loader = NULL) {
*/
function drupal_classloader_register($name, $path) {
$loader = drupal_classloader();
$loader->add('Drupal\\' . $name, DRUPAL_ROOT . '/' . $path . '/lib');
$loader->addPsr4('Drupal\\' . $name . '\\', array(
DRUPAL_ROOT . '/' . $path . '/lib/Drupal/' . $name,
DRUPAL_ROOT . '/' . $path . '/src',
));
}
/**
......
......@@ -99,7 +99,6 @@ public function getDefinitions() {
// Search for classes within all PSR-0 namespace locations.
foreach ($this->getPluginNamespaces() as $namespace => $dirs) {
foreach ($dirs as $dir) {
$dir .= DIRECTORY_SEPARATOR . str_replace('\\', DIRECTORY_SEPARATOR, $namespace);
if (file_exists($dir)) {
$iterator = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($dir, \RecursiveDirectoryIterator::SKIP_DOTS)
......
......@@ -218,7 +218,7 @@ public function discoverServiceProviders() {
$this->moduleList = isset($extensions['module']) ? $extensions['module'] : array();
}
$module_filenames = $this->getModuleFileNames();
$this->registerNamespaces($this->getModuleNamespaces($module_filenames));
$this->registerNamespacesPsr4($this->getModuleNamespacesPsr4($module_filenames));
// Load each module's serviceProvider class.
foreach ($this->moduleList as $module => $weight) {
......@@ -408,8 +408,8 @@ protected function initializeContainer() {
// All namespaces must be registered before we attempt to use any service
// from the container.
$container_modules = $this->container->getParameter('container.modules');
$namespaces_before = $this->classLoader->getPrefixes();
$this->registerNamespaces($this->container->getParameter('container.namespaces'));
$namespaces_before = $this->classLoader->getPrefixesPsr4();
$this->registerNamespacesPsr4($this->container->getParameter('container.namespaces'));
// If 'container.modules' is wrong, the container must be rebuilt.
if (!isset($this->moduleList)) {
......@@ -422,9 +422,9 @@ protected function initializeContainer() {
// registerNamespaces() performs a merge rather than replace, so to
// effectively remove erroneous registrations, we must replace them with
// empty arrays.
$namespaces_after = $this->classLoader->getPrefixes();
$namespaces_after = $this->classLoader->getPrefixesPsr4();
$namespaces_before += array_fill_keys(array_diff(array_keys($namespaces_after), array_keys($namespaces_before)), array());
$this->registerNamespaces($namespaces_before);
$this->registerNamespacesPsr4($namespaces_before);
}
}
......@@ -500,14 +500,15 @@ protected function buildContainer() {
$container->setParameter('container.modules', $this->getModulesParameter());
// Get a list of namespaces and put it onto the container.
$namespaces = $this->getModuleNamespaces($this->getModuleFileNames());
$namespaces = $this->getModuleNamespacesPsr4($this->getModuleFileNames());
// Add all components in \Drupal\Core and \Drupal\Component that have a
// Plugin directory.
foreach (array('Core', 'Component') as $parent_directory) {
$path = DRUPAL_ROOT . '/core/lib/Drupal/' . $parent_directory;
$parent_namespace = 'Drupal\\' . $parent_directory;
foreach (new \DirectoryIterator($path) as $component) {
if (!$component->isDot() && $component->isDir() && is_dir($component->getPathname() . '/Plugin')) {
$namespaces['Drupal\\' . $parent_directory . '\\' . $component->getFilename()] = DRUPAL_ROOT . '/core/lib';
$namespaces[$parent_namespace . '\\' . $component->getFilename()] = $path . '/' . $component->getFilename();
}
}
}
......@@ -696,6 +697,28 @@ protected function getModuleFileNames() {
return $filenames;
}
/**
* Gets the PSR-4 base directories for module namespaces.
*
* @param array $module_file_names
* Array where each key is a module name, and each value is a path to the
* respective *.module or *.profile file.
*
* @return array
* Array where each key is a module namespace like 'Drupal\system', and each
* value is an array of PSR-4 base directories associated with the module
* namespace.
*/
protected function getModuleNamespacesPsr4($module_file_names) {
$namespaces = array();
foreach ($module_file_names as $module => $filename) {
// @todo Remove lib/Drupal/$module, once the switch to PSR-4 is complete.
$namespaces["Drupal\\$module"][] = DRUPAL_ROOT . '/' . dirname($filename) . '/lib/Drupal/' . $module;
$namespaces["Drupal\\$module"][] = DRUPAL_ROOT . '/' . dirname($filename) . '/src';
}
return $namespaces;
}
/**
* Gets the PSR-0 base directories for module namespaces.
*
......@@ -715,6 +738,20 @@ protected function getModuleNamespaces($module_file_names) {
return $namespaces;
}
/**
* Registers a list of namespaces with PSR-4 directories for class loading.
*
* @param array $namespaces
* Array where each key is a namespace like 'Drupal\system', and each value
* is either a PSR-4 base directory, or an array of PSR-4 base directories
* associated with this namespace.
*/
protected function registerNamespacesPsr4(array $namespaces = array()) {
foreach ($namespaces as $prefix => $paths) {
$this->classLoader->addPsr4($prefix . '\\', $paths);
}
}
/**
* Registers a list of namespaces with PSR-0 directories for class loading.
*
......
......@@ -16,17 +16,23 @@
class AnnotatedClassDiscovery extends ComponentAnnotatedClassDiscovery {
/**
* The subdirectory within a namespace to look for plugins.
* A suffix to append to each PSR-4 directory associated with a base
* namespace, to form the directories where plugins are found.
*
* If the plugins are in the top level of the namespace and not within a
* subdirectory, set this to an empty string.
* @var string
*/
protected $directorySuffix = '';
/**
* A suffix to append to each base namespace, to obtain the namespaces where
* plugins are found.
*
* @var string
*/
protected $subdir = '';
protected $namespaceSuffix = '';
/**
* An object containing the namespaces to look for plugin implementations.
* A list of base namespaces with their PSR-4 directories.
*
* @var \Traversable
*/
......@@ -48,7 +54,13 @@ class AnnotatedClassDiscovery extends ComponentAnnotatedClassDiscovery {
*/
function __construct($subdir, \Traversable $root_namespaces, $plugin_definition_annotation_name = 'Drupal\Component\Annotation\Plugin') {
if ($subdir) {
$this->subdir = str_replace('/', '\\', $subdir);
// Prepend a directory separator to $subdir,
// if it does not already have one.
if ('/' !== $subdir[0]) {
$subdir = '/' . $subdir;
}
$this->directorySuffix = $subdir;
$this->namespaceSuffix = str_replace('/', '\\', $subdir);
}
$this->rootNamespacesIterator = $root_namespaces;
$plugin_namespaces = array();
......@@ -104,11 +116,28 @@ protected function getProviderFromNamespace($namespace) {
*/
protected function getPluginNamespaces() {
$plugin_namespaces = array();
foreach ($this->rootNamespacesIterator as $namespace => $dir) {
if ($this->subdir) {
$namespace .= "\\{$this->subdir}";
if ($this->namespaceSuffix) {
foreach ($this->rootNamespacesIterator as $namespace => $dirs) {
// Append the namespace suffix to the base namespace, to obtain the
// plugin namespace. E.g. 'Drupal\Views' may become
// 'Drupal\Views\Plugin\Block'.
$namespace .= $this->namespaceSuffix;
foreach ((array) $dirs as $dir) {
// Append the directory suffix to the PSR-4 base directory, to obtain
// the directory where plugins are found.
// E.g. DRUPAL_ROOT . '/core/modules/views/src' may become
// DRUPAL_ROOT . '/core/modules/views/src/Plugin/Block'.
$plugin_namespaces[$namespace][] = $dir . $this->directorySuffix;
}
}
}
else {
// Both the namespace suffix and the directory suffix are empty,
// so the plugin namespaces and directories are the same as the base
// directories.
foreach ($this->rootNamespacesIterator as $namespace => $dirs) {
$plugin_namespaces[$namespace] = (array) $dirs;
}
$plugin_namespaces[$namespace] = array($dir);
}
return $plugin_namespaces;
......
......@@ -40,7 +40,7 @@ public function setUp() {
parent::setUp();
$migration = entity_load('migration', 'd6_action_settings');
$dumps = array(
drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6ActionSettings.php',
dirname(__DIR__) . '/Dump/Drupal6ActionSettings.php',
);
$this->prepare($migration, $dumps);
$executable = new MigrateExecutable($migration, $this);
......
......@@ -40,7 +40,7 @@ public function setUp() {
parent::setUp();
$migration = entity_load('migration', 'd6_aggregator_settings');
$dumps = array(
drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6AggregatorSettings.php',
dirname(__DIR__) . '/Dump/Drupal6AggregatorSettings.php',
);
$this->prepare($migration, $dumps);
$executable = new MigrateExecutable($migration, $this);
......
......@@ -41,7 +41,7 @@ public function setUp() {
parent::setUp();
$migration = entity_load('migration', 'd6_book_settings');
$dumps = array(
drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6BookSettings.php',
dirname(__DIR__) . '/Dump/Drupal6BookSettings.php',
);
$this->prepare($migration, $dumps);
$executable = new MigrateExecutable($migration, new MigrateMessage());
......
......@@ -41,7 +41,7 @@ public function setUp() {
parent::setUp();
$migration = entity_load('migration', 'd6_contact_settings');
$dumps = array(
drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6ContactSettings.php',
dirname(__DIR__) . '/Dump/Drupal6ContactSettings.php',
);
$this->prepare($migration, $dumps);
$executable = new MigrateExecutable($migration, new MigrateMessage());
......
......@@ -41,7 +41,7 @@ public function setUp() {
parent::setUp();
$migration = entity_load('migration', 'd6_dblog_settings');
$dumps = array(
drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6DblogSettings.php',
dirname(__DIR__) . '/Dump/Drupal6DblogSettings.php',
);
$this->prepare($migration, $dumps);
$executable = new MigrateExecutable($migration, new MigrateMessage());
......
......@@ -33,7 +33,7 @@ public function setUp() {
parent::setUp();
$migration = entity_load('migration', 'd6_field_settings');
$dumps = array(
drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6FieldSettings.php',
dirname(__DIR__) . '/Dump/Drupal6FieldSettings.php',
);
$this->prepare($migration, $dumps);
$executable = new MigrateExecutable($migration, $this);
......
......@@ -41,7 +41,7 @@ public function setUp() {
parent::setUp();
$migration = entity_load('migration', 'd6_file_settings');
$dumps = array(
drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6FileSettings.php',
dirname(__DIR__) . '/Dump/Drupal6FileSettings.php',
);
$this->prepare($migration, $dumps);
$executable = new MigrateExecutable($migration, new MigrateMessage());
......
......@@ -40,7 +40,7 @@ public function setUp() {
parent::setUp();
$migration = entity_load('migration', 'd6_forum_settings');
$dumps = array(
drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6ForumSettings.php',
dirname(__DIR__) . '/Dump/Drupal6ForumSettings.php',
);
$this->prepare($migration, $dumps);
$executable = new MigrateExecutable($migration, $this);
......
......@@ -40,7 +40,7 @@ public function setUp() {
parent::setUp();
$migration = entity_load('migration', 'd6_locale_settings');
$dumps = array(
drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6LocaleSettings.php',
dirname(__DIR__) . '/Dump/Drupal6LocaleSettings.php',
);
$this->prepare($migration, $dumps);
$executable = new MigrateExecutable($migration, $this);
......
......@@ -40,7 +40,7 @@ public function setUp() {
parent::setUp();
$migration = entity_load('migration', 'd6_menu_settings');
$dumps = array(
drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6MenuSettings.php',
dirname(__DIR__) . '/Dump/Drupal6MenuSettings.php',
);
$this->prepare($migration, $dumps);
$executable = new MigrateExecutable($migration, $this);
......
......@@ -41,7 +41,7 @@ public function setUp() {
parent::setUp();
$migration = entity_load('migration', 'd6_node_settings');
$dumps = array(
drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6NodeSettings.php',
dirname(__DIR__) . '/Dump/Drupal6NodeSettings.php',
);
$this->prepare($migration, $dumps);
$executable = new MigrateExecutable($migration, new MigrateMessage);
......
......@@ -41,7 +41,7 @@ protected function setUp() {
parent::setUp();
$migration = entity_load('migration', 'd6_search_settings');
$dumps = array(
drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SearchSettings.php',
dirname(__DIR__) . '/Dump/Drupal6SearchSettings.php',
);
$this->prepare($migration, $dumps);
$executable = new MigrateExecutable($migration, new MigrateMessage());
......
......@@ -41,7 +41,7 @@ protected function setUp() {
parent::setUp();
$migration = entity_load('migration', 'd6_simpletest_settings');
$dumps = array(
drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SimpletestSettings.php',
dirname(__DIR__) . '/Dump/Drupal6SimpletestSettings.php',
);
$this->prepare($migration, $dumps);
$executable = new MigrateExecutable($migration, new MigrateMessage());
......
......@@ -41,7 +41,7 @@ protected function setUp() {
parent::setUp();
$migration = entity_load('migration', 'd6_statistics_settings');
$dumps = array(
drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6StatisticsSettings.php',
dirname(__DIR__) . '/Dump/Drupal6StatisticsSettings.php',
);
$this->prepare($migration, $dumps);
$executable = new MigrateExecutable($migration, new MigrateMessage());
......
......@@ -40,7 +40,7 @@ protected function setUp() {
parent::setUp();
$migration = entity_load('migration', 'd6_syslog_settings');
$dumps = array(
drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SyslogSettings.php',
dirname(__DIR__) . '/Dump/Drupal6SyslogSettings.php',
);
$this->prepare($migration, $dumps);
$executable = new MigrateExecutable($migration, $this);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment