diff --git a/core/core.services.yml b/core/core.services.yml index 26bbe97..9c76558 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -1250,26 +1250,10 @@ services: class: Drupal\Core\StreamWrapper\ThemeStream tags: - { name: stream_wrapper, scheme: theme } - stream_wrapper.active_theme: - class: Drupal\Core\StreamWrapper\ActiveThemeStream - tags: - - { name: stream_wrapper, scheme: active-theme } - stream_wrapper.admin_theme: - class: Drupal\Core\StreamWrapper\AdminThemeStream - tags: - - { name: stream_wrapper, scheme: admin-theme } - stream_wrapper.default_theme: - class: Drupal\Core\StreamWrapper\DefaultThemeStream - tags: - - { name: stream_wrapper, scheme: default-theme } stream_wrapper.profile: class: Drupal\Core\StreamWrapper\ProfileStream tags: - { name: stream_wrapper, scheme: profile } - stream_wrapper.installed_profile: - class: Drupal\Core\StreamWrapper\InstalledProfileStream - tags: - - { name: stream_wrapper, scheme: installed-profile } kernel_destruct_subscriber: class: Drupal\Core\EventSubscriber\KernelDestructionSubscriber tags: diff --git a/core/lib/Drupal/Core/StreamWrapper/ActiveThemeStream.php b/core/lib/Drupal/Core/StreamWrapper/ActiveThemeStream.php deleted file mode 100644 index 72c4ece..0000000 --- a/core/lib/Drupal/Core/StreamWrapper/ActiveThemeStream.php +++ /dev/null @@ -1,59 +0,0 @@ -themeNegotiator = \Drupal::service('theme.negotiator'); - $this->routeMatch = \Drupal::service('current_route_match'); - } - - /** - * {@inheritdoc} - */ - protected function getOwnerName() { - return $this->themeNegotiator->determineActiveTheme($this->routeMatch); - } - - /** - * {@inheritdoc} - */ - public function getName() { - return t('Active theme files'); - } - - /** - * {@inheritdoc} - */ - public function getDescription() { - return t('Local active theme files.'); - } - -} diff --git a/core/lib/Drupal/Core/StreamWrapper/AdminThemeStream.php b/core/lib/Drupal/Core/StreamWrapper/AdminThemeStream.php deleted file mode 100644 index 80bfe0d..0000000 --- a/core/lib/Drupal/Core/StreamWrapper/AdminThemeStream.php +++ /dev/null @@ -1,51 +0,0 @@ -configFactory = \Drupal::configFactory(); - } - - /** - * {@inheritdoc} - */ - protected function getOwnerName() { - return $this->configFactory->get('system.theme')->get('admin'); - } - - /** - * {@inheritdoc} - */ - public function getName() { - return t('Admin theme files'); - } - - /** - * {@inheritdoc} - */ - public function getDescription() { - return t('Local admin theme files.'); - } - -} diff --git a/core/lib/Drupal/Core/StreamWrapper/DefaultThemeStream.php b/core/lib/Drupal/Core/StreamWrapper/DefaultThemeStream.php deleted file mode 100644 index 4a4d7d5..0000000 --- a/core/lib/Drupal/Core/StreamWrapper/DefaultThemeStream.php +++ /dev/null @@ -1,51 +0,0 @@ -themeHandler = \Drupal::service('theme_handler'); - } - - /** - * {@inheritdoc} - */ - protected function getOwnerName() { - return $this->themeHandler->getDefault(); - } - - /** - * {@inheritdoc} - */ - public function getName() { - return t('Default theme files'); - } - - /** - * {@inheritdoc} - */ - public function getDescription() { - return t('Local default theme files.'); - } - -} diff --git a/core/lib/Drupal/Core/StreamWrapper/SystemStream.php b/core/lib/Drupal/Core/StreamWrapper/ExtensionStreamBase.php similarity index 56% rename from core/lib/Drupal/Core/StreamWrapper/SystemStream.php rename to core/lib/Drupal/Core/StreamWrapper/ExtensionStreamBase.php index bf064d2..f717c14 100644 --- a/core/lib/Drupal/Core/StreamWrapper/SystemStream.php +++ b/core/lib/Drupal/Core/StreamWrapper/ExtensionStreamBase.php @@ -2,33 +2,32 @@ /** * @file - * Contains \Drupal\Core\StreamWrapper\SystemStream. + * Contains \Drupal\Core\StreamWrapper\ExtensionStreamBase. */ namespace Drupal\Core\StreamWrapper; +use Drupal\Core\StringTranslation\StringTranslationTrait; + /** * Defines a base stream wrapper implementation. * - * SystemStream is a read-only Drupal stream wrapper base class for system files - * located in modules, themes and profiles. + * ExtensionStreamBase is a read-only Drupal stream wrapper base class for + * system files located in extensions: modules, themes and installed profile. */ -abstract class SystemStream extends LocalReadOnlyStream { +abstract class ExtensionStreamBase extends LocalReadOnlyStream { + + // @todo Move this in \Drupal\Core\StreamWrapper\LocalStream in Drupal 9.0.x. + use StringTranslationTrait; + /** - * The request object. + * The current request object. * * @var \Symfony\Component\HttpFoundation\Request */ protected $request; /** - * Constructs a new system stream. - */ - public function __construct() { - $this->request = \Drupal::service('request_stack')->getCurrentRequest(); - } - - /** * {@inheritdoc} */ public static function getType() { @@ -47,12 +46,13 @@ public static function getType() { * The extension name. * * @throws \InvalidArgumentException + * In case of a malformed uri. */ protected function getOwnerName() { $uri_parts = explode('://', $this->uri, 2); if (count($uri_parts) === 1) { // The delimiter ('://') was not found in $uri, malformed $uri passed. - throw new \InvalidArgumentException(sprintf('Malformed uri parameter passed: %s', $this->uri)); + throw new \InvalidArgumentException("Malformed uri parameter passed: {$this->uri}"); } // Remove the trailing filename from the path. @@ -64,20 +64,22 @@ protected function getOwnerName() { * {@inheritdoc} */ protected function getTarget($uri = NULL) { - return rtrim(strstr(parent::getTarget($uri), '/') ?: '', '/'); + if ($target = strstr(parent::getTarget($uri), '/')) { + return trim($target, '/'); + } + return ''; } /** * {@inheritdoc} - * - * @throws \InvalidArgumentException */ public function getExternalUrl() { $dir = $this->getDirectoryPath(); if (empty($dir)) { - throw new \InvalidArgumentException(sprintf('Extension directory for %s does not exist.', $this->uri)); + throw new \InvalidArgumentException("Extension directory for {$this->uri} does not exist."); } - return $this->request->getUriForPath(base_path() . $dir . $this->getTarget()); + $path = rtrim(base_path() . $dir . '/' . $this->getTarget(), '/'); + return $this->getRequest()->getUriForPath($path); } /** @@ -87,7 +89,6 @@ public function dirname($uri = NULL) { if (!isset($uri)) { $uri = $this->uri; } - list($scheme) = explode('://', $uri, 2); $target = $this->getTarget($uri); $dirname = dirname($target); @@ -95,7 +96,22 @@ public function dirname($uri = NULL) { $dirname = ''; } - return rtrim($scheme . '://' . $this->getOwnerName() . $dirname, '/'); + list($scheme) = explode('://', $uri, 2); + + return rtrim($scheme . '://' . $this->getOwnerName() . '/' . $dirname, '/'); + } + + /** + * Returns the current request object. + * + * @return \Symfony\Component\HttpFoundation\Request + * The current request object. + */ + protected function getRequest() { + if (!isset($this->request)) { + $this->request = \Drupal::service('request_stack')->getCurrentRequest(); + } + return $this->request; } } diff --git a/core/lib/Drupal/Core/StreamWrapper/InstalledProfileStream.php b/core/lib/Drupal/Core/StreamWrapper/InstalledProfileStream.php deleted file mode 100644 index 88a3c47..0000000 --- a/core/lib/Drupal/Core/StreamWrapper/InstalledProfileStream.php +++ /dev/null @@ -1,44 +0,0 @@ -getOwnerName())); - } - -} diff --git a/core/lib/Drupal/Core/StreamWrapper/LocalStream.php b/core/lib/Drupal/Core/StreamWrapper/LocalStream.php index db51eda..f49ec6b 100644 --- a/core/lib/Drupal/Core/StreamWrapper/LocalStream.php +++ b/core/lib/Drupal/Core/StreamWrapper/LocalStream.php @@ -15,10 +15,13 @@ * "sites/default/files/example.txt" and then PHP filesystem functions are * invoked. * - * Drupal\Core\StreamWrapper\LocalStream implementations need to implement at least the - * getDirectoryPath() and getExternalUrl() methods. + * \Drupal\Core\StreamWrapper\LocalStream implementations need to implement at + * least the getDirectoryPath() and getExternalUrl() methods. */ abstract class LocalStream implements StreamWrapperInterface { + + use LocalStreamTrait; + /** * Stream context resource. * @@ -52,8 +55,6 @@ public static function getType() { /** * Gets the path that the wrapper is responsible for. * - * @todo Review this method name in D8 per https://www.drupal.org/node/701358. - * * @return string * String specifying the path. */ @@ -74,39 +75,6 @@ function getUri() { } /** - * Returns the local writable target of the resource within the stream. - * - * This function should be used in place of calls to realpath() or similar - * functions when attempting to determine the location of a file. While - * functions like realpath() may return the location of a read-only file, this - * method may return a URI or path suitable for writing that is completely - * separate from the URI used for reading. - * - * @param string $uri - * Optional URI. - * - * @return string - * Returns a string representing a location suitable for writing of a file. - * - * @throws \InvalidArgumentException - * If a malformed $uri parameter is passed in. - */ - protected function getTarget($uri = NULL) { - if (!isset($uri)) { - $uri = $this->uri; - } - - $uri_parts = explode('://', $uri, 2); - if (count($uri_parts) === 1) { - // The delimiter ('://') was not found in $uri, malformed $uri passed. - throw new \InvalidArgumentException(sprintf('Malformed uri parameter passed: %s', $uri)); - } - - // Remove erroneous leading or trailing forward-slashes and backslashes. - return trim($uri_parts[1], '\/'); - } - - /** * {@inheritdoc} */ public function realpath() { @@ -148,6 +116,13 @@ protected function getLocalPath($uri = NULL) { $realpath = realpath(dirname($path)) . '/' . drupal_basename($path); } $directory = realpath($this->getDirectoryPath()); + + // Windows accepts either backslash ('\') or slash (UNIX-style '/') as + // directory separator. We'll switch to slash, if the previous realpath() + // ran on Windows platform. + //$realpath = str_replace(DIRECTORY_SEPARATOR, '/', $realpath); + //$directory = str_replace(DIRECTORY_SEPARATOR, '/', $directory); + if (!$realpath || !$directory || strpos($realpath, $directory) !== 0) { return FALSE; } @@ -406,33 +381,6 @@ public function rename($from_uri, $to_uri) { } /** - * Gets the name of the directory from a given path. - * - * This method is usually accessed through drupal_dirname(), which wraps - * around the PHP dirname() function because it does not support stream - * wrappers. - * - * @param string $uri - * A URI or path. - * - * @return string - * A string containing the directory name. - * - * @see drupal_dirname() - */ - public function dirname($uri = NULL) { - list($scheme) = explode('://', $uri, 2); - $target = $this->getTarget($uri); - $dirname = dirname($target); - - if ($dirname == '.') { - $dirname = ''; - } - - return $scheme . '://' . $dirname; - } - - /** * Support for mkdir(). * * @param string $uri diff --git a/core/lib/Drupal/Core/StreamWrapper/LocalStreamTrait.php b/core/lib/Drupal/Core/StreamWrapper/LocalStreamTrait.php new file mode 100644 index 0000000..19d3860 --- /dev/null +++ b/core/lib/Drupal/Core/StreamWrapper/LocalStreamTrait.php @@ -0,0 +1,73 @@ +uri; + } + + list($scheme) = explode('://', $uri, 2); + $target = $this->getTarget($uri); + $dirname = dirname($target); + + return $dirname !== '.' ? "$scheme://$dirname" : "$scheme://"; + } + + /** + * Returns the local writable target of the resource within the stream. + * + * This function should be used in place of calls to realpath() or similar + * functions when attempting to determine the location of a file. While + * functions like realpath() may return the location of a read-only file, this + * method may return a URI or path suitable for writing that is completely + * separate from the URI used for reading. + * + * @param string $uri + * Optional URI. + * + * @return string + * Returns a string representing a location suitable for writing of a file. + * + * @throws \InvalidArgumentException + * If a malformed $uri parameter is passed in. + */ + protected function getTarget($uri = NULL) { + if (!isset($uri)) { + $uri = $this->uri; + } + + $uri_parts = explode('://', $uri, 2); + if (count($uri_parts) === 1) { + // The delimiter ('://') was not found in $uri, malformed $uri passed. + throw new \InvalidArgumentException("Malformed uri parameter passed: $uri"); + } + + // Remove erroneous leading or trailing forward-slashes and backslashes. + return trim($uri_parts[1], '\/'); + } + + +} \ No newline at end of file diff --git a/core/lib/Drupal/Core/StreamWrapper/ModuleStream.php b/core/lib/Drupal/Core/StreamWrapper/ModuleStream.php index 3424c56..157b876 100644 --- a/core/lib/Drupal/Core/StreamWrapper/ModuleStream.php +++ b/core/lib/Drupal/Core/StreamWrapper/ModuleStream.php @@ -7,62 +7,62 @@ namespace Drupal\Core\StreamWrapper; -use Drupal\Core\Extension\ModuleHandlerInterface; -use Symfony\Component\HttpFoundation\RequestStack; - /** * Defines the read-only module:// stream wrapper for module files. */ -class ModuleStream extends SystemStream { +class ModuleStream extends ExtensionStreamBase { /** - * Wraps the ModuleHandler service. + * The module handler service. * * @var \Drupal\Core\Extension\ModuleHandlerInterface */ protected $moduleHandler; /** - * Constructs a ModuleStream wrapper object. - */ - public function __construct() { - parent::__construct(); - $this->moduleHandler = \Drupal::moduleHandler(); - } - - /** * {@inheritdoc} */ protected function getOwnerName() { $name = parent::getOwnerName(); - if ($this->moduleHandler->moduleExists($name)) { - return $name; - } - else { + if (!$this->getModuleHandler()->moduleExists($name)) { // The module does not exist or is not installed. - throw new \InvalidArgumentException(sprintf('Module %s does not exist or is not installed', $name)); + throw new \InvalidArgumentException("Module $name does not exist or is not installed"); } + return $name; } /** * {@inheritdoc} */ protected function getDirectoryPath() { - return $this->moduleHandler->getModule($this->getOwnerName())->getPath(); + return $this->getModuleHandler()->getModule($this->getOwnerName())->getPath(); } /** * {@inheritdoc} */ public function getName() { - return t('Module files'); + return $this->t('Module files'); } /** * {@inheritdoc} */ public function getDescription() { - return t('Local module files.'); + return $this->t('Local files stored under module directory.'); + } + + /** + * Returns the module handler service. + * + * @return \Drupal\Core\Extension\ModuleHandlerInterface + * The module handler service. + */ + protected function getModuleHandler() { + if (!isset($this->moduleHandler)) { + $this->moduleHandler = \Drupal::moduleHandler(); + } + return $this->moduleHandler; } } diff --git a/core/lib/Drupal/Core/StreamWrapper/ProfileStream.php b/core/lib/Drupal/Core/StreamWrapper/ProfileStream.php index 539ffc5..2569ee6 100644 --- a/core/lib/Drupal/Core/StreamWrapper/ProfileStream.php +++ b/core/lib/Drupal/Core/StreamWrapper/ProfileStream.php @@ -8,44 +8,38 @@ namespace Drupal\Core\StreamWrapper; /** - * Defines the read-only profile:// stream wrapper for profile files. + * Defines the read-only profile:// stream wrapper for installed profile files. */ -class ProfileStream extends SystemStream { +class ProfileStream extends ModuleStream { + + use LocalStreamTrait; /** * {@inheritdoc} */ protected function getOwnerName() { - $name = parent::getOwnerName(); - - if (!is_null(drupal_get_filename('profile', $name))) { - return $name; - } - else { - // The profile does not exist. - throw new \InvalidArgumentException(sprintf('Profile %s does not exist', $name)); - } + return drupal_get_profile(); } /** * {@inheritdoc} */ - protected function getDirectoryPath() { - return dirname(drupal_get_filename('profile', $this->getOwnerName())); + public function getName() { + return $this->t('Installed profile files'); } /** * {@inheritdoc} */ - public function getName() { - return t('Profile files'); + public function getDescription() { + return $this->t('Local files stored under installed profile directory.'); } /** * {@inheritdoc} */ - public function getDescription() { - return t('Local profile files.'); + protected function getDirectoryPath() { + return drupal_get_path('profile', $this->getOwnerName()); } } diff --git a/core/lib/Drupal/Core/StreamWrapper/SystemStreamBase.php b/core/lib/Drupal/Core/StreamWrapper/SystemStreamBase.php deleted file mode 100644 index 198bec8..0000000 --- a/core/lib/Drupal/Core/StreamWrapper/SystemStreamBase.php +++ /dev/null @@ -1,55 +0,0 @@ -uri; - } - - list($scheme) = explode('://', $uri, 2); - $target = $this->getTarget($uri); - - $dirname = dirname($target); - - if ($dirname === '.' || $dirname === '\\') { - $dirname = ''; - } - - return "$scheme://" . trim($dirname, '/'); - } - - /** - * {@inheritdoc} - */ - protected function getTarget($uri = NULL) { - if (!isset($uri)) { - $uri = $this->uri; - } - - $uri_parts = explode('://', $uri, 2); - if (count($uri_parts) === 1) { - // The delimiter ('://') was not found in $uri, malformed $uri passed. - throw new \InvalidArgumentException(sprintf('Malformed uri parameter passed: %s', $uri)); - } - - $target = trim($uri_parts[1], '\/'); - - return !empty($target) ? "/$target" : ''; - } - -} diff --git a/core/lib/Drupal/Core/StreamWrapper/ThemeStream.php b/core/lib/Drupal/Core/StreamWrapper/ThemeStream.php index d39015f..bf100ac 100644 --- a/core/lib/Drupal/Core/StreamWrapper/ThemeStream.php +++ b/core/lib/Drupal/Core/StreamWrapper/ThemeStream.php @@ -10,7 +10,7 @@ /** * Defines the read-only theme:// stream wrapper for theme files. */ -class ThemeStream extends SystemStream { +class ThemeStream extends ExtensionStreamBase { /** * The theme handler service. @@ -20,48 +20,49 @@ class ThemeStream extends SystemStream { protected $themeHandler; /** - * Constructs a new ThemeStream object. - */ - public function __construct() { - parent::__construct(); - $this->themeHandler = \Drupal::service('theme_handler'); - } - - /** * {@inheritdoc} */ protected function getOwnerName() { $name = parent::getOwnerName(); - - // Return name only for installed themes. - if ($this->themeHandler->themeExists($name)) { - return $name; - } - else { + if (!$this->getThemeHandler()->themeExists($name)) { // The theme does not exist or is not installed. - throw new \InvalidArgumentException(sprintf('Theme %s does not exist or is not installed', $name)); + throw new \InvalidArgumentException("Theme $name does not exist or is not installed"); } + return $name; } /** * {@inheritdoc} */ protected function getDirectoryPath() { - return $this->themeHandler->getTheme($this->getOwnerName())->getPath(); + return $this->getThemeHandler()->getTheme($this->getOwnerName())->getPath(); } /** * {@inheritdoc} */ public function getName() { - return t('Theme files'); + return $this->t('Theme files'); } /** * {@inheritdoc} */ public function getDescription() { - return t('Local theme files.'); + return $this->t('Local files stored under theme directory.'); + } + + /** + * Returns the theme handler service. + * + * @return \Drupal\Core\Extension\ThemeHandlerInterface + * The theme handler service. + */ + protected function getThemeHandler() { + if (!isset($this->themeHandler)) { + $this->themeHandler = \Drupal::service('theme_handler'); + } + return $this->themeHandler; } } diff --git a/core/lib/Drupal/Core/StreamWrapper/ThemeStreamBase.php b/core/lib/Drupal/Core/StreamWrapper/ThemeStreamBase.php deleted file mode 100644 index cffd3d0..0000000 --- a/core/lib/Drupal/Core/StreamWrapper/ThemeStreamBase.php +++ /dev/null @@ -1,23 +0,0 @@ -getOwnerName())); - } - -} diff --git a/core/modules/system/src/Tests/File/SystemStreamTest.php b/core/modules/system/src/Tests/File/SystemStreamTest.php deleted file mode 100644 index 4bb8b0e..0000000 --- a/core/modules/system/src/Tests/File/SystemStreamTest.php +++ /dev/null @@ -1,483 +0,0 @@ -streamWrapperManager = $this->container->get('stream_wrapper_manager'); - - /** @var \Drupal\Core\State\StateInterface $state */ - $state = $this->container->get('state'); - // Add 'minimal' profile to 'system.module.files' state to allow - // drupal_get_profile() to get the profile from state. drupal_get_profile() - // resolves only the current profile but reads also profiles from states. - // @see drupal_get_profile() - $system_module_files = $state->get('system.module.files', []); - $system_module_files += ['minimal' => 'core/profiles/minimal/minimal.info.yml']; - $state->set('system.module.files', $system_module_files); - // Add default profile for the purposes of this test. - new Settings(Settings::getAll() + ['install_profile' => 'minimal']); - } - - /** - * Test Invalid stream uri. - */ - public function testInvalidStreamUriException() { - $bad_uris = [ - 'invalid/uri', - 'invalid_uri', - 'module/invalid/uri', - 'module/invalid_uri', - 'module:invalid_uri', - 'module::/invalid/uri', - 'module::/invalid_uri', - 'module//:invalid/uri', - 'module//invalid_uri', - 'module//invalid/uri', - ]; - - $instance = $this->streamWrapperManager->getViaScheme('module'); - - foreach ($bad_uris as $bad_uri) { - try { - $instance->dirname($bad_uri); - $this->fail(SafeMarkup::format('Invalid uri %uri not detected.', ['%uri' => $bad_uri])); - } - catch (\InvalidArgumentException $e) { - if ($e->getMessage() == 'Malformed uri parameter passed: ' . $bad_uri) { - $this->pass(SafeMarkup::format('Throw exception on invalid uri %uri supplied.', ['%uri' => $bad_uri])); - } - else { - throw new \InvalidArgumentException($e); - } - } - } - } - - /** - * Test the Module stream wrapper functions. - */ - public function testModuleStream() { - // Generate a module stream wrapper instance. - $instance = $this->streamWrapperManager->getViaScheme('module'); - - // Test dirname(). - $data = $this->moduleStreamTestCasesProvider('dirname'); - $this->runTestOnInstanceMethod($instance, 'dirname', $data); - - // Test realpath(). - $data = $this->moduleStreamTestCasesProvider('realpath'); - $this->runTestOnInstanceMethod($instance, 'realpath', $data); - - // Test getExternalUrl(). - $data = $this->moduleStreamTestCasesProvider('getExternalUrl'); - $this->runTestOnInstanceMethod($instance, 'getExternalUrl', $data); - } - - /** - * Provides test cases for testModuleStream(). - * - * @param string $method - * The method to be tested. - * - * @return array - * Associative array with test cases as values, keyed by uri. - */ - protected function moduleStreamTestCasesProvider($method) { - $uris = [ - 'module://system', - 'module://system/css/system.admin.css', - 'module://file_test/file_test.dummy.inc', - 'module://file_test/src/file_test.dummy.inc', - 'module://ckeditor/ckeditor.info.yml', - 'module://foo_bar/foo.bar.js', - ]; - switch ($method) { - case 'dirname': - return array_combine($uris, [ - 'module://system', - 'module://system/css', - 'module://file_test', - 'module://file_test/src', - new \InvalidArgumentException('Module ckeditor does not exist or is not installed'), - new \InvalidArgumentException('Module foo_bar does not exist or is not installed'), - ]); - case 'realpath': - return array_combine($uris, [ - DRUPAL_ROOT . '/core/modules/system', - DRUPAL_ROOT . '/core/modules/system/css/system.admin.css', - DRUPAL_ROOT . '/core/modules/file/tests/file_test/file_test.dummy.inc', - DRUPAL_ROOT . '/core/modules/file/tests/file_test/src/file_test.dummy.inc', - new \InvalidArgumentException('Module ckeditor does not exist or is not installed'), - new \InvalidArgumentException('Module foo_bar does not exist or is not installed'), - ]); - case 'getExternalUrl': - $base_url = \Drupal::request()->getUriForPath(base_path()); - return array_combine($uris, [ - $base_url . 'core/modules/system', - $base_url . 'core/modules/system/css/system.admin.css', - $base_url . 'core/modules/file/tests/file_test/file_test.dummy.inc', - $base_url . 'core/modules/file/tests/file_test/src/file_test.dummy.inc', - new \InvalidArgumentException('Module ckeditor does not exist or is not installed'), - new \InvalidArgumentException('Module foo_bar does not exist or is not installed'), - ]); - } - } - - /** - * Test the Profile stream wrapper functions. - */ - public function testProfileStream() { - // Generate a profile stream wrapper instance. - $instance = $this->streamWrapperManager->getViaScheme('profile'); - - // Test dirname(). - $data = $this->profileStreamTestCasesProvider('dirname'); - $this->runTestOnInstanceMethod($instance, 'dirname', $data); - - // Test realpath(). - $data = $this->profileStreamTestCasesProvider('realpath'); - $this->runTestOnInstanceMethod($instance, 'realpath', $data); - - // Test getExternalUrl(). - $data = $this->profileStreamTestCasesProvider('getExternalUrl'); - $this->runTestOnInstanceMethod($instance, 'getExternalUrl', $data); - } - - /** - * Provides test cases for testProfileStream(). - * - * @param string $method - * The method to be tested. - * - * @return array - * Associative array with test cases as values, keyed by uri. - */ - protected function profileStreamTestCasesProvider($method) { - $uris = [ - 'profile://minimal', - 'profile://minimal/config/install/block.block.stark_login.yml', - 'profile://minimal/config/install/node.type.article.yml', - 'profile://foo_bar/', - ]; - - switch ($method) { - case 'dirname': - return array_combine($uris, [ - 'profile://minimal', - 'profile://minimal/config/install', - 'profile://minimal/config/install', - new \InvalidArgumentException('Profile foo_bar does not exist'), - ]); - case 'realpath': - return array_combine($uris, [ - DRUPAL_ROOT . '/core/profiles/minimal', - DRUPAL_ROOT . '/core/profiles/minimal/config/install/block.block.stark_login.yml', - DRUPAL_ROOT . '/core/profiles/minimal/config/install/node.type.article.yml', - new \InvalidArgumentException('Profile foo_bar does not exist'), - ]); - case 'getExternalUrl': - $base_url = \Drupal::request()->getUriForPath(base_path()); - return array_combine($uris, [ - $base_url . 'core/profiles/minimal', - $base_url . 'core/profiles/minimal/config/install/block.block.stark_login.yml', - $base_url . 'core/profiles/minimal/config/install/node.type.article.yml', - new \InvalidArgumentException('Profile foo_bar does not exist'), - ]); - } - } - - /** - * Test the installed profile stream wrapper functions. - */ - public function testInstalledProfileStream() { - // Generate a profile stream wrapper instance. - $instance = $this->streamWrapperManager->getViaScheme('installed-profile'); - - // Test dirname(). - $data = $this->installedProfileStreamTestCasesProvider('dirname'); - $this->runTestOnInstanceMethod($instance, 'dirname', $data); - - // Test realpath(). - $data = $this->installedProfileStreamTestCasesProvider('realpath'); - $this->runTestOnInstanceMethod($instance, 'realpath', $data); - - // Test getExternalUrl(). - $data = $this->installedProfileStreamTestCasesProvider('getExternalUrl'); - $this->runTestOnInstanceMethod($instance, 'getExternalUrl', $data); - } - - /** - * Provides test cases for testProfileStream(). - * - * @param string $method - * The method to be tested. - * - * @return array - * Associative array with test cases as values, keyed by uri. - */ - protected function installedProfileStreamTestCasesProvider($method) { - $uris = [ - 'installed-profile://', - 'installed-profile://config/install/block.block.stark_login.yml', - 'installed-profile://config/install/node.type.article.yml', - 'installed-profile://minimal.info.yml', - ]; - - switch ($method) { - case 'dirname': - return array_combine($uris, [ - 'installed-profile://', - 'installed-profile://config/install', - 'installed-profile://config/install', - 'installed-profile://', - ]); - case 'realpath': - return array_combine($uris, [ - DRUPAL_ROOT . '/core/profiles/minimal', - DRUPAL_ROOT . '/core/profiles/minimal/config/install/block.block.stark_login.yml', - DRUPAL_ROOT . '/core/profiles/minimal/config/install/node.type.article.yml', - DRUPAL_ROOT . '/core/profiles/minimal/minimal.info.yml', - ]); - case 'getExternalUrl': - $base_url = \Drupal::request()->getUriForPath(base_path()); - return array_combine($uris, [ - $base_url . 'core/profiles/minimal', - $base_url . 'core/profiles/minimal/config/install/block.block.stark_login.yml', - $base_url . 'core/profiles/minimal/config/install/node.type.article.yml', - $base_url . 'core/profiles/minimal/minimal.info.yml', - ]); - } - } - - /** - * Test the Theme stream wrapper functions. - */ - public function testThemeStream() { - /** @var \Drupal\Core\Extension\ThemeInstallerInterface $theme_installer */ - $theme_installer = $this->container->get('theme_installer'); - // Install Bartik and Seven themes. - $theme_installer->install(['bartik', 'seven']); - - // Generate a theme stream wrapper instance. - $instance = $this->streamWrapperManager->getViaScheme('theme'); - - // Test dirname(). - $data = $this->themeStreamTestCasesProvider('dirname'); - $this->runTestOnInstanceMethod($instance, 'dirname', $data); - - // Test realpath(). - $data = $this->themeStreamTestCasesProvider('realpath'); - $this->runTestOnInstanceMethod($instance, 'realpath', $data); - - // Test getExternalUrl(). - $data = $this->themeStreamTestCasesProvider('getExternalUrl'); - $this->runTestOnInstanceMethod($instance, 'getExternalUrl', $data); - } - - /** - * Provides test cases for testThemeStream(). - * - * @param string $method - * The method to be tested. - * - * @return array - * Associative array with test cases as values, keyed by uri. - */ - protected function themeStreamTestCasesProvider($method) { - $uris = [ - 'theme://seven', - 'theme://seven/style.css', - 'theme://bartik/color/preview.js', - 'theme://fifteen/screenshot.png', - 'theme://stark/stark.info.yml', - ]; - - switch ($method) { - case 'dirname': - return array_combine($uris, [ - 'theme://seven', - 'theme://seven', - 'theme://bartik/color', - new \InvalidArgumentException('Theme fifteen does not exist or is not installed'), - new \InvalidArgumentException('Theme stark does not exist or is not installed'), - ]); - case 'realpath': - return array_combine($uris, [ - DRUPAL_ROOT . '/core/themes/seven', - DRUPAL_ROOT . '/core/themes/seven/style.css', - DRUPAL_ROOT . '/core/themes/bartik/color/preview.js', - new \InvalidArgumentException('Theme fifteen does not exist or is not installed'), - new \InvalidArgumentException('Theme stark does not exist or is not installed'), - ]); - case 'getExternalUrl': - $base_url = \Drupal::request()->getUriForPath(base_path()); - return array_combine($uris, [ - $base_url . 'core/themes/seven', - $base_url . 'core/themes/seven/style.css', - $base_url . 'core/themes/bartik/color/preview.js', - new \InvalidArgumentException('Theme fifteen does not exist or is not installed'), - new \InvalidArgumentException('Theme stark does not exist or is not installed'), - ]); - } - } - - /** - * Test the pseudo theme stream wrapper functions. - */ - public function testPseudoThemeStreams() { - /** @var \Drupal\Core\Config\ConfigFactoryInterface $config_factory */ - $config_factory = $this->container->get('config.factory'); - /** @var \Drupal\Core\Extension\ThemeInstallerInterface $theme_installer */ - $theme_installer = $this->container->get('theme_installer'); - - // Install Bartik theme. - $theme_installer->install(['bartik']); - // Set default and admin theme to Bartik. - $config_factory->getEditable('system.theme') - ->set('default', 'bartik') - ->set('admin', 'bartik') - ->save(); - - foreach (['active', 'default', 'admin'] as $scheme) { - $scheme .= '-theme'; - - // Generate a theme stream wrapper instance. - $instance = $this->streamWrapperManager->getViaScheme($scheme); - - // Test dirname(). - $data = $this->pseudoThemeStreamTestCasesProvider('dirname', $scheme); - $this->runTestOnInstanceMethod($instance, 'dirname', $data); - - // Test realpath(). - $data = $this->pseudoThemeStreamTestCasesProvider('realpath', $scheme); - $this->runTestOnInstanceMethod($instance, 'realpath', $data); - - // Test getExternalUrl(). - $data = $this->pseudoThemeStreamTestCasesProvider('getExternalUrl', $scheme); - $this->runTestOnInstanceMethod($instance, 'getExternalUrl', $data); - } - } - - /** - * Provides test cases for testPseudoThemeStreams(). - * - * @param string $method - * The method to be tested. - * @param string $scheme - * The scheme to be tested. - * - * @return array - * Associative array with test cases as values, keyed by uri. - */ - protected function pseudoThemeStreamTestCasesProvider($method, $scheme) { - $uris = [ - "$scheme://", - "$scheme://logo.png", - "$scheme://color/preview.js", - ]; - - switch ($method) { - case 'dirname': - return array_combine($uris, [ - "$scheme://", - "$scheme://", - "$scheme://color", - ]); - case 'realpath': - return array_combine($uris, [ - DRUPAL_ROOT . '/core/themes/bartik', - DRUPAL_ROOT . '/core/themes/bartik/logo.png', - DRUPAL_ROOT . '/core/themes/bartik/color/preview.js', - ]); - case 'getExternalUrl': - $base_url = \Drupal::request()->getUriForPath(base_path()); - return array_combine($uris, [ - $base_url . 'core/themes/bartik', - $base_url . 'core/themes/bartik/logo.png', - $base_url . 'core/themes/bartik/color/preview.js', - ]); - } - } - - /** - * Helper method to run specific tests on each StreamWrapper method. - * - * @param \Drupal\Core\StreamWrapper\StreamWrapperInterface $instance - * The stream wrapper instance to carry out the test on. - * @param string $method - * The SystemStream method to be tested. - * @param array $data - * An array of data to be used for the test, containing the following info: - * - The expected result. - * - The test result message. - */ - private function runTestOnInstanceMethod(StreamWrapperInterface $instance, $method, array $data) { - foreach ($data as $uri => $case) { - $instance->setUri($uri); - if ($case instanceof \InvalidArgumentException) { - /** @var \InvalidArgumentException $case */ - $message = sprintf('Exception thrown: \InvalidArgumentException("%s").', $case->getMessage()); - try { - $instance->$method(); - $this->fail($message); - } - catch (\InvalidArgumentException $e) { - $this->assertIdentical($e->getMessage(), $case->getMessage(), $message); - } - } - elseif (is_string($case)) { - $this->assertEqual($instance->$method(), $case); - } - } - } - - /** - * {@inheritdoc} - */ - public function errorHandler($severity, $message, $file = NULL, $line = NULL) { - // When dealing with an unknown module/profile, drupal_get_filename() - // triggers an error. We want to mute this error because we catch this as - // exception. - // @see drupal_get_filename() - if ($severity != E_USER_WARNING || strpos($message, 'The following module is missing from the file system: ') !== 0) { - parent::errorHandler($severity, $message, $file, $line); - } - } - -} diff --git a/core/modules/system/tests/src/Kernel/File/ExtensionStreamTest.php b/core/modules/system/tests/src/Kernel/File/ExtensionStreamTest.php new file mode 100644 index 0000000..b369f1d --- /dev/null +++ b/core/modules/system/tests/src/Kernel/File/ExtensionStreamTest.php @@ -0,0 +1,218 @@ +container->get('stream_wrapper_manager'); + // Get stream wrapper instances. + foreach (['module', 'theme', 'profile'] as $scheme) { + $this->streamWrappers[$scheme] = $stream_wrapper_manager->getViaScheme($scheme); + } + + /** @var \Drupal\Core\State\StateInterface $state */ + $state = $this->container->get('state'); + // Add 'minimal' profile to 'system.module.files' state to allow + // drupal_get_profile() to get the profile from state. drupal_get_profile() + // resolves only the current profile but reads also profiles from states. + // @see drupal_get_profile() + $system_module_files = $state->get('system.module.files', []); + $system_module_files += ['minimal' => 'core/profiles/minimal/minimal.info.yml']; + $state->set('system.module.files', $system_module_files); + // Add default profile for the purposes of this test. + new Settings(Settings::getAll() + ['install_profile' => 'minimal']); + + /** @var \Drupal\Core\Extension\ThemeInstallerInterface $theme_installer */ + $theme_installer = $this->container->get('theme_installer'); + // Install Bartik and Seven themes. + $theme_installer->install(['bartik', 'seven']); + } + + /** + * Test Invalid stream uri. + */ + public function testInvalidStreamUriException() { + $bad_uris = [ + 'invalid/uri', + 'invalid_uri', + 'module/invalid/uri', + 'module/invalid_uri', + 'module:invalid_uri', + 'module::/invalid/uri', + 'module::/invalid_uri', + 'module//:invalid/uri', + 'module//invalid_uri', + 'module//invalid/uri', + ]; + + foreach ($bad_uris as $bad_uri) { + try { + $this->streamWrappers['module']->dirname($bad_uri); + $this->fail(new FormattableMarkup('Invalid uri %uri not detected.', ['%uri' => $bad_uri])); + + } + catch (\InvalidArgumentException $e) { + if ($e->getMessage() == 'Malformed uri parameter passed: ' . $bad_uri) { + $this->assertTrue(TRUE, new FormattableMarkup('Throw exception on invalid uri %uri supplied.', ['%uri' => $bad_uri])); + } + else { + throw new \InvalidArgumentException($e); + } + } + } + } + + /** + * Test the extension stream wrapper methods. + */ + public function testStreamWrapperMethods() { + foreach ($this->streamTestCasesProvider() as $uri => $expectation) { + foreach ($expectation as $method => $expected) { + list($scheme, ) = explode('://', $uri); + $this->streamWrappers[$scheme]->setUri($uri); + if ($expected instanceof \InvalidArgumentException) { + /** @var \InvalidArgumentException $expected */ + $message = sprintf('Exception thrown: \InvalidArgumentException("%s").', $expected->getMessage()); + try { + $this->streamWrappers[$scheme]->$method(); + $this->fail($message); + } + catch (\InvalidArgumentException $e) { + $this->assertSame($expected->getMessage(), $e->getMessage(), $message); + } + } + elseif (is_string($expected)) { + $this->assertSame($expected, $this->streamWrappers[$scheme]->$method()); + } + } + } + } + + /** + * Provides test cases for testThemeStream(). + * + * @return array + * Associative array with test cases as values, keyed by uri. + */ + protected function streamTestCasesProvider() { + $base_url = $this->container->get('request_stack')->getCurrentRequest()->getUriForPath(base_path()); + return [ + + // Cases for module:// stream wrapper. + 'module://system' => [ + 'dirname' => 'module://system', + 'realpath' => DRUPAL_ROOT . '/core/modules/system', + 'getExternalUrl' => $base_url . 'core/modules/system', + ], + 'module://system/css/system.admin.css' => [ + 'dirname' => 'module://system/css', + 'realpath' => DRUPAL_ROOT . '/core/modules/system/css/system.admin.css', + 'getExternalUrl' => $base_url . 'core/modules/system/css/system.admin.css', + ], + 'module://file_test/file_test.dummy.inc' => [ + 'dirname' => 'module://file_test', + 'realpath' => DRUPAL_ROOT . '/core/modules/file/tests/file_test/file_test.dummy.inc', + 'getExternalUrl' => $base_url . 'core/modules/file/tests/file_test/file_test.dummy.inc', + ], + 'module://file_test/src/file_test.dummy.inc' => [ + 'dirname' => 'module://file_test/src', + 'realpath' => DRUPAL_ROOT . '/core/modules/file/tests/file_test/src/file_test.dummy.inc', + 'getExternalUrl' => $base_url . 'core/modules/file/tests/file_test/src/file_test.dummy.inc', + ], + 'module://ckeditor/ckeditor.info.yml' => [ + 'dirname' => new \InvalidArgumentException('Module ckeditor does not exist or is not installed'), + 'realpath' => new \InvalidArgumentException('Module ckeditor does not exist or is not installed'), + 'getExternalUrl' => new \InvalidArgumentException('Module ckeditor does not exist or is not installed'), + ], + 'module://foo_bar/foo.bar.js' => [ + 'dirname' => new \InvalidArgumentException('Module foo_bar does not exist or is not installed'), + 'realpath' => new \InvalidArgumentException('Module foo_bar does not exist or is not installed'), + 'getExternalUrl' => new \InvalidArgumentException('Module foo_bar does not exist or is not installed'), + ], + + // Cases for theme:// stream wrapper. + 'theme://seven' => [ + 'dirname' => 'theme://seven', + 'realpath' => DRUPAL_ROOT . '/core/themes/seven', + 'getExternalUrl' => $base_url . 'core/themes/seven', + ], + 'theme://seven/style.css' => [ + 'dirname' => 'theme://seven', + 'realpath' => DRUPAL_ROOT . '/core/themes/seven/style.css', + 'getExternalUrl' => $base_url . 'core/themes/seven/style.css', + ], + 'theme://bartik/color/preview.js' => [ + 'dirname' => 'theme://bartik/color', + 'realpath' => DRUPAL_ROOT . '/core/themes/bartik/color/preview.js', + 'getExternalUrl' => $base_url . 'core/themes/bartik/color/preview.js', + ], + 'theme://fifteen/screenshot.png' => [ + 'dirname' => new \InvalidArgumentException('Theme fifteen does not exist or is not installed'), + 'realpath' => new \InvalidArgumentException('Theme fifteen does not exist or is not installed'), + 'getExternalUrl' => new \InvalidArgumentException('Theme fifteen does not exist or is not installed'), + ], + 'theme://stark/stark.info.yml' => [ + 'dirname' => new \InvalidArgumentException('Theme stark does not exist or is not installed'), + 'realpath' => new \InvalidArgumentException('Theme stark does not exist or is not installed'), + 'getExternalUrl' => new \InvalidArgumentException('Theme stark does not exist or is not installed'), + ], + + // Cases for profile:// stream wrapper. + 'profile://' => [ + 'dirname' => 'profile://', + 'realpath' => DRUPAL_ROOT . '/core/profiles/minimal', + 'getExternalUrl' => $base_url . 'core/profiles/minimal', + ], + 'profile://config/install/block.block.stark_login.yml' => [ + 'dirname' => 'profile://config/install', + 'realpath' => DRUPAL_ROOT . '/core/profiles/minimal/config/install/block.block.stark_login.yml', + 'getExternalUrl' => $base_url . 'core/profiles/minimal/config/install/block.block.stark_login.yml', + ], + 'profile://config/install/node.type.article.yml' => [ + 'dirname' => 'profile://config/install', + 'realpath' => DRUPAL_ROOT . '/core/profiles/minimal/config/install/node.type.article.yml', + 'getExternalUrl' => $base_url . 'core/profiles/minimal/config/install/node.type.article.yml', + ], + 'profile://minimal.info.yml' => [ + 'dirname' => 'profile://', + 'realpath' => DRUPAL_ROOT . '/core/profiles/minimal/minimal.info.yml', + 'getExternalUrl' => $base_url . 'core/profiles/minimal/minimal.info.yml', + ], + ]; + } + +} diff --git a/core/modules/user/src/Entity/User.php b/core/modules/user/src/Entity/User.php index 1dcdefb..521fd34 100644 --- a/core/modules/user/src/Entity/User.php +++ b/core/modules/user/src/Entity/User.php @@ -573,4 +573,8 @@ public static function getAllowedConfigurableLanguageCodes() { return array_keys(\Drupal::languageManager()->getLanguages(LanguageInterface::STATE_CONFIGURABLE)); } + //public function getCacheTags() { + // return ['session'] + parent::getCacheContexts(); // TODO: Change the autogenerated stub + //} + } diff --git a/core/modules/user/src/UserStorage.php b/core/modules/user/src/UserStorage.php index d6a42f4..0dd35aa 100644 --- a/core/modules/user/src/UserStorage.php +++ b/core/modules/user/src/UserStorage.php @@ -7,6 +7,7 @@ namespace Drupal\user; +use Drupal\Core\Cache\Cache; use Drupal\Core\Database\Connection; use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Entity\ContentEntityInterface; @@ -16,6 +17,7 @@ use Drupal\Core\Password\PasswordInterface; use Drupal\Core\Session\AccountInterface; use Drupal\Core\Language\LanguageManagerInterface; +use Drupal\user\Entity\User; use Symfony\Component\DependencyInjection\ContainerInterface; /**