Problem/Motivation

See #2229865: [meta] Modernize File/StreamWrapper API, we need to move file scheme functions out of file.inc. StreamWrapperManager is a good place for them, but some were already moved to FileSystem earlier.

Proposed resolution

Deprecate both the remaining undeprecated functions in file.inc and those that were already moved to FileSystem in favor of methods on StreamWrapperManager:

StreamWrapperManager is be a good place for them, as it is already injected into FileSystem and closely related to that stuff.

See #126 there for example:

Hm, on closer investigation, I don't think any of these additional methods belong into this new service.

* file_uri_target() is the counter-part to file_uri_scheme(), which is already on file_system
* file_stream_wrapper_uri_normalize() is also very related to these, they're all about (stream wrapper) URI's, not file URLs.
* file_valid_uri() is again about stream wrapper URI's and as a small wrapper around two functions/methods that were already moved to file_system.
* file_build_uri() also is about creating stream wrapper URIs and is tightly connected to these other functions.

FileSystem is getting quite big with that other issue, so maybe these methods could be on the stream wrapper manager, but then we'd also need to move some existing methods from FileSystem to that to avoid a cross-dependency.

Remaining tasks

Make method names more consistent.

The following change records need updating on commit:

User interface changes

None

API changes

The following functions have been deprecated:

Old function/method New method
FileSystem::uriScheme()
file_uri_scheme()
StreamWrapperManager::getScheme()
file_uri_target() StreamWrapperManager::getTarget()
FileSystem::validScheme()
file_stream_wrapper_valid_scheme()
\Drupal::service('stream_wrapper_manager')->isValidScheme()
file_stream_wrapper_uri_normalize() \Drupal::service('stream_wrapper_manager')->normalizeUri()
file_valid_uri() \Drupal::service('stream_wrapper_manager')->isValidUri()

The above table indicates which methods should now be accessed through the service and which are now static methods on the StreamWrapperManager class.

Data model changes

None

Release notes snippet

Several stream wrapper methods have been deprecated in file.inc and the FileSystem service, and are now methods on StreamWrapperManager.

CommentFileSizeAuthor
#84 3034072-84-interdiff.txt17.99 KBkim.pepper
#84 3034072-84.patch86.27 KBkim.pepper
#80 3034072-80-interdiff.txt16.64 KBkim.pepper
#80 3034072-80.patch86.37 KBkim.pepper
#78 3034072-78-interdiff.txt1.01 KBkim.pepper
#78 3034072-78.patch83.17 KBkim.pepper
#76 3034072-76-interdiff.txt7.12 KBkim.pepper
#76 3034072-76.patch83.16 KBkim.pepper
#73 3034072-73-interdiff.txt2.92 KBkim.pepper
#73 3034072-73.patch81.77 KBkim.pepper
#71 3034072-71-interdiff.txt39 KBkim.pepper
#71 3034072-71.patch84.16 KBkim.pepper
#67 3034072-67-interdiff.txt3.99 KBkim.pepper
#67 3034072-67.patch81.87 KBkim.pepper
#65 3034072-65.patch81.76 KBkim.pepper
#55 3034072-55.patch81.65 KBkim.pepper
#52 3034072-52.patch81.69 KBberdir
#50 3034072-50.patch82 KBkim.pepper
#50 3034072-50-interdiff.txt8.84 KBkim.pepper
#47 3034072-47.patch81.73 KBkim.pepper
#47 3034072-47-interdiff.txt7.41 KBkim.pepper
#45 3034072-45.patch81.74 KBkim.pepper
#45 3034072-45-interdiff.txt7.42 KBkim.pepper
#43 3034072-43.patch80.93 KBkim.pepper
#43 3034072-43-interdiff.txt841 byteskim.pepper
#41 3034072-41.patch80.93 KBkim.pepper
#41 3034072-41-interdiff.txt8.47 KBkim.pepper
#39 3034072-39.patch80.18 KBkim.pepper
#39 3034072-39-interdiff.txt7.48 KBkim.pepper
#37 3034072-37.patch77.81 KBkim.pepper
#37 3034072-37-interdiff.txt661 byteskim.pepper
#36 3034072-36.patch77.81 KBkim.pepper
#36 3034072-36-interdiff.txt36.23 KBkim.pepper
#33 3034072-33.patch78.96 KBberdir
#21 3034072-21-interdiff.txt5.5 KBberdir
#21 3034072-21.patch78.91 KBberdir
#19 3034072-19-interdiff.txt734 bytesberdir
#19 3034072-19.patch76.88 KBberdir
#16 3034072-16.patch76.88 KBkim.pepper
#16 3034072-16-interdiff.txt6.44 KBkim.pepper
#14 3034072-14.patch72.75 KBkim.pepper
#14 3034072-14-interdiff.txt1.33 KBkim.pepper
#11 3034072-11.patch72.09 KBkim.pepper
#11 3034072-11-interdiff.txt1.74 KBkim.pepper
#8 3034072-8.patch70.68 KBkim.pepper
#8 3034072-8-interdiff.txt594 byteskim.pepper
#7 3034072-7.patch70.1 KBkim.pepper
#7 3034072-7-interdiff.txt8.63 KBkim.pepper
#5 3034072-5.patch62.42 KBkim.pepper
#5 3034072-5-interdiff.txt2.36 KBkim.pepper
#3 file-uri-scheme-functions-3034072-2.patch62.42 KBberdir

Comments

Berdir created an issue. See original summary.

berdir’s picture

Assigned: Unassigned » berdir
berdir’s picture

Status: Active » Needs review
StatusFileSize
new62.42 KB

Some DI injections left and some unit tests are doing fun things but this deals with most things. I think this makes a lot of sense as an API, multiple places that used these functions already had the stream wrapper manager injected, so that shows IMHO that it makes sense to have them there.

Two are left that I'm not sure: file_default_scheme(), which is a simple wrapper around \Drupal::config() and file_build_uri(), which uses that. StreamWrapperManager is too deep for config, so we can't move that there. But FileSystem uses them in prepareDestination, which only works because nothing that's low-level enough calls that.

Status: Needs review » Needs work

The last submitted patch, 3: file-uri-scheme-functions-3034072-2.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

kim.pepper’s picture

Status: Needs work » Needs review
Issue tags: +Kill includes
StatusFileSize
new2.36 KB
new62.42 KB

Re-roll of #3 plus some code sniff fixes.

Status: Needs review » Needs work

The last submitted patch, 5: 3034072-5.patch, failed testing. View results

kim.pepper’s picture

Status: Needs work » Needs review
StatusFileSize
new8.63 KB
new70.1 KB

Fixes some more usages of deprecated methods. Created \Drupal\KernelTests\Core\StreamWrapper\StreamWrapperManagerTest and moved the FileSystemTest method there.

kim.pepper’s picture

StatusFileSize
new594 bytes
new70.68 KB

Oops. Forgot to update the service definition.

The last submitted patch, 7: 3034072-7.patch, failed testing. View results

Status: Needs review » Needs work

The last submitted patch, 8: 3034072-8.patch, failed testing. View results

kim.pepper’s picture

Status: Needs work » Needs review
StatusFileSize
new1.74 KB
new72.09 KB

Need to handle the child classes constructor too.

Status: Needs review » Needs work

The last submitted patch, 11: 3034072-11.patch, failed testing. View results

berdir’s picture

+++ b/core/tests/Drupal/KernelTests/Core/StreamWrapper/StreamWrapperManagerTest.php
@@ -0,0 +1,62 @@
+  protected function setUp() {
+    parent::setUp();
+    $this->streamWrapperManager = $this->container->get('stream_wrapper_manager');

still not 100% official, but I prefer using \Drupal::service(), I just don't see a benefit of using $this->container :)

in this case it's also a bit overkill to have that property and setup method for one method, but I guess the goal is to have more test methods here.

kim.pepper’s picture

Status: Needs work » Needs review
StatusFileSize
new1.33 KB
new72.75 KB

Fixes ConfigController calling new FileDownloadController() . :-\

Fixes #13.1 Changed to \Drupal::service().

I guess the goal is to have more test methods here.

That was the idea.

Status: Needs review » Needs work

The last submitted patch, 14: 3034072-14.patch, failed testing. View results

kim.pepper’s picture

Status: Needs work » Needs review
StatusFileSize
new6.44 KB
new76.88 KB

Fix a few more fails. Struggling to decipher the large number of remaining fails.

I manually tried to upload and got an error:

The file could not be uploaded because the destination public://2019-03 is invalid.

Any ideas?

Status: Needs review » Needs work

The last submitted patch, 16: 3034072-16.patch, failed testing. View results

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

berdir’s picture

Status: Needs work » Needs review
StatusFileSize
new76.88 KB
new734 bytes

This should fix most of these fails. Was pondering about using isValidUri($destination) there but we need the scheme later on, so I ended up doing a mix of both :)

Status: Needs review » Needs work

The last submitted patch, 19: 3034072-19.patch, failed testing. View results

berdir’s picture

Status: Needs work » Needs review
StatusFileSize
new78.91 KB
new5.5 KB

Some more fixes and test updates.

jibran’s picture

Issue tags: +Needs change record updates

We have to update https://www.drupal.org/node/2418133 after the commit.

kim.pepper’s picture

Status: Needs review » Reviewed & tested by the community
+++ b/core/lib/Drupal/Core/File/FileSystemInterface.php
@@ -242,7 +242,10 @@ public function tempnam($directory, $prefix);
+   *   * @deprecated in Drupal 8.7.0, will be removed before Drupal 9.0.0.

Nit: extra *

RTBC for committer review.

berdir’s picture

Thanks for the RTBC, I think it's a bit early for that though because the CR has not been actually written yet, and there is still the second paragraph of #3 to think about.

We could deal with those two functions elsewhere, but might make sense to have a plan at least.

kim.pepper’s picture

Ah missed #3!

file_default_scheme() seems like overkill for an api method. Why not just call \Drupal::config('system.file')->get('default_scheme') directly? We don't have API methods for other 'system.file' config do we?

file_build_uri() looks like it should be in FileSystem service, but we'd be introducing a dependency on config there. 🤔

berdir’s picture

Yes, I'd be happy to drop file_default_scheme() but it doesn't actually solve anything as file_build_uri() uses it.

kim.pepper’s picture

file_system service is the 'least worse' option as it is already somewhat high-level with dependencies on StreamWrapperManager, Logger, and Settings.

We could possibly move lower-level file system methods to the FileSystem component later?

berdir’s picture

I'd really prefer that the file_system service doesn't depend on configuration, that just seems like a bad idea. Config\DatabaseStorage is full of fileSystem calls, and then that again depending on config and even writing config seems too dangerous, even i it's not the actually the same methods.

There's also file_directory_temp(), see #931794: 'file_temporary_path' variable and file_directory_temp() function should match, maybe a new FileSystemConfiguration service for those, but file_build_uri() is still weird, especially since FileSystem actually calls it already. The thing is that it is only called if $destination is *empty* for copy() or move() which, to be honest, seems extremely weird. I'm considering that we should just deprecate support for that entirely, copying/moving implicitly into the default scheme seems like a *suuper* rare case. Question is whether we could push that still in 8.7, then we wouldn't need a dedicated deprecation for that, we'd just make the argument required from the start.

If we drop that, we can remove the hidden config dependency in FileSystem, same for system_retrieve_file(), and then the only remaining non-test use case of that function is \Drupal\image\Entity\ImageStyle::buildUrl(), meaning, we can possibly deprecate that without a replacement too?

berdir’s picture

kim.pepper’s picture

Sounds like a good plan!

kim.pepper’s picture

I'd really prefer that the file_system service doesn't depend on configuration, that just seems like a bad idea. Config\DatabaseStorage is full of fileSystem calls, and then that again depending on config and even writing config seems too dangerous, even i it's not the actually the same methods.

I think you meant \Drupal\Core\Config\FileStorage?

There's also file_directory_temp(), see #931794: 'file_temporary_path' variable and file_directory_temp() function should match, maybe a new FileSystemConfiguration service for those, but file_build_uri() is still weird, especially since FileSystem actually calls it already. ... I'm considering that we should just deprecate support for that entirely ...

We can do both. Makes sense to have a FileSystemConfiguration service and deprecate those functions.

Created #3039026: Deprecate file_directory_temp() and move to FileSystem service

larowlan’s picture

Status: Reviewed & tested by the community » Needs review
Issue tags: +Needs reroll, +Needs issue summary update

Feels like we still need discussion here? What became of #3? Perhaps issue summary update to clarify what is done and what still needs to be done?

Looks like might need a re-roll too.

berdir’s picture

Issue summary: View changes
StatusFileSize
new78.96 KB

The answer to #3 is #3039026: Deprecate file_directory_temp() and move to FileSystem service and #3038988: Remove support for empty destination in FileSystem::copy(), FileSystem::move() and FileSystem::saveData(), we move those two into a separate service and remove the dependency on file_build_uri() in FileSystem.

Did a reroll, which git apply -3 resolved automatically, lets see if that worked.

Also started working on an issue summary and change record update. Shows that we still have some work to do in regards to making the new methods more consistent. I kept the names from FileSystem, but I think it would make more sense to prefix them with is/get or another verb (isValidScheme()? validateScheme()? getUriScheme()? getScheme()?)

kim.pepper’s picture

but I think it would make more sense to prefix them with is/get or another verb (isValidScheme()? validateScheme()? getUriScheme()? getScheme()?)

Yeah, I agree with that.

kim.pepper’s picture

To be clearer, I like isValidScheme() and getScheme(). :-)

kim.pepper’s picture

StatusFileSize
new36.23 KB
new77.81 KB

Re-rolled #33.

Discussed the naming with @Berdir in slack and replaced validScheme() with isValidScheme() and uriScheme() with getScheme() as per #34.

kim.pepper’s picture

StatusFileSize
new661 bytes
new77.81 KB

Fix incorrect case of isVAlidUri() in file.inc

berdir’s picture

Status: Needs review » Needs work
Issue tags: -Needs reroll
+++ b/core/includes/file.inc
@@ -98,25 +98,27 @@
 function file_uri_scheme($uri) {
-  return \Drupal::service('file_system')->uriScheme($uri);
+  @trigger_error('file_uri_scheme() is deprecated in Drupal 8.0.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface::getScheme(). See https://www.drupal.org/node/3035273.', E_USER_DEPRECATED);
+  return \Drupal::service('stream_wrapper_manager')->getScheme($uri);

The deprecation message here is a bit challenging. file_uri_scheme() *is* deprecated since 8.0.0, but the replacement is changing in 8.8, so we should probably say that? Easiest "fix" might be to just update it to say deprecated in 8.8, so that people know they can't use the stream wrapper manager replacement before that?

Either way, most messages will need to be updated to 8.8 and I think the message needs some updates for the new standard, e.g. it should AFAIK be "drupal:8.8.0" now.

kim.pepper’s picture

Status: Needs work » Needs review
StatusFileSize
new7.48 KB
new80.18 KB

I have updated all deprecation messages to drupal:8.8.0 format.

I also added a number of deprecation tests which were missing.

berdir’s picture

Status: Needs review » Needs work
+++ b/core/tests/Drupal/KernelTests/Core/File/FileSystemDeprecationTest.php
@@ -146,4 +146,39 @@ public function testDeprecatedDrupalTempnam() {
+  /**
+   * @expectedDeprecation file_uri_scheme() is deprecated in drupal:8.0.0 and will be removed before drupal:9.0.0. Use \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface::getScheme() instead. See https://www.drupal.org/node/3035273.
+   */
+  public function testDeprecatedFileUriScheme() {
+    $this->assertNotNull(file_uri_scheme(''));
+  }

We might need to be a bit more specific with those kernel tests.

The problem is that this would still pass if the function would return an incorrect but non-null result. A legacy test has two goals:

a) Assert that the expected deprecation message is thrown.
b) Assert that it still works correctly.

b is only partially tested right now. See for example the copy/move test methods that I updated in that test.

kim.pepper’s picture

Status: Needs work » Needs review
StatusFileSize
new8.47 KB
new80.93 KB

Re: #40 I added proper tests for the deprecated methods.

I also found another usage of file_valid_uri() which I replaced.

Status: Needs review » Needs work

The last submitted patch, 41: 3034072-41.patch, failed testing. View results

kim.pepper’s picture

Status: Needs work » Needs review
StatusFileSize
new841 bytes
new80.93 KB

Oops. Typo with ::isValidUrl() instead of ::isValidUri()

berdir’s picture

+++ b/core/tests/Drupal/KernelTests/Core/File/FileSystemDeprecationTest.php
@@ -147,38 +147,38 @@ public function testDeprecatedDrupalTempnam() {
   /**
-   * @expectedDeprecation file_stream_wrapper_uri_normalize() is deprecated in drupal:8.8.0 and will be removed before drupal:9.0.0. Use \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface::normalizeUri() instead. See https://www.drupal.org/node/3035273.
+   * @expectedDeprecation file_stream_wrapper_uri_normalize() is deprecated in Drupal:8.8.0 and will be removed before Drupal:9.0.0. Use \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface::normalizeUri() instead. See https://www.drupal.org/node/3035273.

why the case change in those messages?

It is "drupal", according to the examples in https://www.drupal.org/project/coding_standards/issues/3024461, also for @deprecated.

kim.pepper’s picture

StatusFileSize
new7.42 KB
new81.74 KB

Fixes for #44

Status: Needs review » Needs work

The last submitted patch, 45: 3034072-45.patch, failed testing. View results

kim.pepper’s picture

Status: Needs work » Needs review
StatusFileSize
new7.41 KB
new81.73 KB

Doh. Update the tests with the correct deprecation messages.

claudiu.cristea’s picture

Status: Needs review » Needs work

Here's a 1st round of review.

The CR branch should be incremented too to 8.8.0.

  1. +++ b/core/includes/file.inc
    @@ -98,25 +98,27 @@
    + * @deprecated in Drupal 8.8.0 and will be removed before Drupal 9.0.0.
    ...
    +  @trigger_error('file_uri_scheme() is deprecated in drupal:8.0.0 and will be removed before drupal:9.0.0. Use \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface::getScheme() instead. See https://www.drupal.org/node/3035273', E_USER_DEPRECATED);
    ...
    + * @deprecated in Drupal 8.8.0 and will be removed before Drupal 9.0.0.
    ...
    +  @trigger_error('file_stream_wrapper_valid_scheme() is deprecated in drupal:8.0.0 and will be removed before drupal:9.0.0. Use \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface::isValidScheme() instead. See https://www.drupal.org/node/3035273', E_USER_DEPRECATED);
    
    @@ -130,15 +132,14 @@ function file_stream_wrapper_valid_scheme($scheme) {
    + * @deprecated in Drupal 8.8.0 and will be removed before Drupal 9.0.0.
    ...
    +  @trigger_error('file_uri_target() is deprecated in drupal:8.8.0 and will be removed before drupal:9.0.0. Use \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface::getUriTarget() instead. See https://www.drupal.org/node/3035273', E_USER_DEPRECATED);
    
    @@ -165,19 +166,15 @@ function file_default_scheme() {
    + * @deprecated in Drupal 8.8.0 and will be removed before Drupal 9.0.0.
    ...
    +  @trigger_error('file_stream_wrapper_uri_normalize() is deprecated in drupal:8.8.0 and will be removed before drupal:9.0.0. Use \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface::normalizeUri() instead. See https://www.drupal.org/node/3035273', E_USER_DEPRECATED);
    
    @@ -415,14 +416,15 @@ function file_htaccess_lines($private = TRUE) {
    + * @deprecated in Drupal 8.8.0 and will be removed before Drupal 9.0.0.
    ...
    +  @trigger_error('file_valid_uri() is deprecated in drupal:8.8.0 and will be removed before drupal:9.0.0. Use \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface::isValidUri() instead. See https://www.drupal.org/node/3035273', E_USER_DEPRECATED);
    

    I see you have used the pattern from #3024461: Adopt consistent deprecation format for core and contrib deprecation messages in trigger_error() but not in @deprecated. Let's be consistent and use the new standard in both.

  2. +++ b/core/includes/file.inc
    @@ -98,25 +98,27 @@
    + *   Use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface::isValidScheme().
    
    @@ -130,15 +132,14 @@ function file_stream_wrapper_valid_scheme($scheme) {
    + *   Use \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface::getUriTarget().
    
    @@ -165,19 +166,15 @@ function file_default_scheme() {
    + *   Use \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface::normalizeUri().
    
    +++ b/core/lib/Drupal/Core/Asset/LibraryDiscoveryParser.php
    @@ -393,10 +408,14 @@ protected function drupalGetPath($type, $name) {
    +   * Wraps \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface::isValidUri().
    ...
    +   *   Use \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface::isValidUri().
    
    +++ b/core/lib/Drupal/Core/File/FileSystemInterface.php
    @@ -259,6 +262,11 @@ public function uriScheme($uri);
    +   *   Use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface::isValidScheme().
    

    Exceeds 80 chars. The "Use" word can be moved one line up.

  3. +++ b/core/lib/Drupal/Core/Asset/CssOptimizer.php
    @@ -16,6 +24,20 @@ class CssOptimizer implements AssetOptimizerInterface {
    +      @trigger_error('CssOptimizer::__construct() adds the $stream_wrapper_manager argument in 8.7.0 and will be required in 9.0.0. See https://www.drupal.org/node/3035273.', E_USER_DEPRECATED);
    
    +++ b/core/lib/Drupal/Core/Asset/LibraryDiscoveryParser.php
    @@ -47,11 +55,18 @@ class LibraryDiscoveryParser {
    +      @trigger_error('LibraryDiscoveryParser::__construct() adds the $stream_wrapper_manager argument in 8.7.0 and will be required in 9.0.0. See https://www.drupal.org/node/3035273.', E_USER_DEPRECATED);
    
    @@ -393,10 +408,14 @@ protected function drupalGetPath($type, $name) {
    +    @trigger_error('fileValidUri() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface::isValidUri(). See https://www.drupal.org/node/3035273.', E_USER_DEPRECATED);
    ...
    diff --git a/core/lib/Drupal/Core/File/FileSystem.php b/core/lib/Drupal/Core/File/FileSystem.php
    
    +++ b/core/lib/Drupal/Core/File/FileSystem.php
    @@ -290,22 +288,16 @@ public function tempnam($directory, $prefix) {
    +    @trigger_error('FileSystem::uriScheme() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface::getScheme(). See https://www.drupal.org/node/3035273.', E_USER_DEPRECATED);
    ...
    +    @trigger_error('FileSystem::validScheme() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface::isValidScheme(). See https://www.drupal.org/node/3035273.', E_USER_DEPRECATED);
    
    +++ b/core/lib/Drupal/Core/File/FileSystemInterface.php
    @@ -242,7 +242,10 @@ public function tempnam($directory, $prefix);
    +   * @deprecated in Drupal 8.7.0, will be removed before Drupal 9.0.0.
    
    @@ -259,6 +262,11 @@ public function uriScheme($uri);
    +   * @deprecated in Drupal 8.0.0, will be removed before Drupal 9.0.0.
    
  4. +++ b/core/lib/Drupal/Core/Asset/CssOptimizer.php
    @@ -16,6 +24,20 @@ class CssOptimizer implements AssetOptimizerInterface {
    +      @trigger_error('CssOptimizer::__construct() adds the $stream_wrapper_manager argument in 8.7.0 and will be required in 9.0.0. See https://www.drupal.org/node/3035273.', E_USER_DEPRECATED);
    
    +++ b/core/lib/Drupal/Core/Asset/LibraryDiscoveryParser.php
    @@ -47,11 +55,18 @@ class LibraryDiscoveryParser {
    +      @trigger_error('LibraryDiscoveryParser::__construct() adds the $stream_wrapper_manager argument in 8.7.0 and will be required in 9.0.0. See https://www.drupal.org/node/3035273.', E_USER_DEPRECATED);
    

    Should we test these too?

berdir’s picture

4. We usually don't test constructor deprecations unless it's something special, I did dozens of these part of my entity manager issues.

kim.pepper’s picture

Status: Needs work » Needs review
StatusFileSize
new8.84 KB
new82 KB

I don't think we should be too pedantic about the deprecation message formatting until that issue is resolved. It's changed multiple times, and I think we're chasing our tail if we keep trying to match the latest format. None the less, I've updated the formatting as per #48.

  1. Fixed
  2. Fixed
  3. Fixed
  4. Left as is.
claudiu.cristea’s picture

Issue tags: +Needs reroll
berdir’s picture

kim.pepper’s picture

Status: Needs review » Reviewed & tested by the community

Given the number of reviewers, contributors and all feedback being addressed, we can safely RTBC.

kim.pepper’s picture

Issue tags: +Needs reroll
kim.pepper’s picture

StatusFileSize
new81.65 KB

Re-roll of #52

kim.pepper’s picture

Issue tags: -Needs reroll
larowlan’s picture

Status: Reviewed & tested by the community » Needs review

Apologies if these questions have been asked before

  1. +++ b/core/lib/Drupal/Core/File/FileSystem.php
    @@ -290,22 +288,16 @@ public function tempnam($directory, $prefix) {
       public function uriScheme($uri) {
    -    if (preg_match('/^([\w\-]+):\/\/|^(data):/', $uri, $matches)) {
    -      // The scheme will always be the last element in the matches array.
    -      return array_pop($matches);
    -    }
    -
    -    return FALSE;
    

    i'm not really sure why this is a service at all - there is no state? Would it fit better on a utility class as a static method. Does that untie some of our circular dependency issues?

  2. +++ b/core/lib/Drupal/Core/StreamWrapper/StreamWrapperManager.php
    @@ -208,4 +208,75 @@ public function registerWrapper($scheme, $class, $type) {
    +  public function getUriTarget($uri) {
    +    // Remove the scheme from the URI and remove erroneous leading or trailing,
    +    // forward-slashes and backslashes.
    +    $target = trim(preg_replace('/^[\w\-]+:\/\/|^data:/', '', $uri), '\/');
    +
    +    // If nothing was replaced, the URI doesn't have a valid scheme.
    +    return $target !== $uri ? $target : FALSE;
    

    same here

  3. +++ b/core/lib/Drupal/Core/StreamWrapper/StreamWrapperManager.php
    @@ -208,4 +208,75 @@ public function registerWrapper($scheme, $class, $type) {
    +    if (preg_match('/^([\w\-]+):\/\/|^(data):/', $uri, $matches)) {
    +      // The scheme will always be the last element in the matches array.
    +      return array_pop($matches);
    +    }
    

    and here

  4. +++ b/core/lib/Drupal/Core/StreamWrapper/StreamWrapperManager.php
    @@ -208,4 +208,75 @@ public function registerWrapper($scheme, $class, $type) {
    +  public function isValidScheme($scheme) {
    +    if (!$scheme) {
    +      return FALSE;
    +    }
    +    return class_exists($this->getClass($scheme));
    

    and here

berdir’s picture

Good question, I'm not sure. Happy to make some of these static, I assume they would still live on StreamWrapperManager? Note that it doens't really change that much. most calls that we have to one of these is then followed by another method call that is not static, typically something like this:

$scheme = $this->streamWrapperManager->getScheme($directory);
if ($this->streamWrapperManager->isValidScheme($scheme)) {

And leaving uriScheme() on FileSystem also doesn't make sense to me when all the other related functions are on StreamWrapperManager, including its companion getUriTarget().

1. and 3. is the same function I think, just old and new location.
2. getUriTarget(), yup, that could be static.
4. This one actually calls $this->getClass(), so no candidate.

So that means we would have 2 methods that could be static, getScheme() and getUriTarget().

alexpott’s picture

There are benefits to making things static in that we'll not be tempted to make these things stateful in the future. I think that means we wouldn't have to inject the stream wrapper manager into ThemeSettingsForm. Another thought is looking at the code makes me wonder if we shouldn't be adding a value object like FileUri that has these methods.

berdir’s picture

I'm not sure how a FileUri value object would work. These are URI's that we're passing around to file_system and php functions, they need a string. And several things, like isValidScheme() need access to the registered stream wrappers and with that the manager.

Maybe a helper class FileUrl (..Validator|Parser|...) with static methods but the only thing we can IMHO move are getScheme() and getUriTarget() and not sure that's worth it.

kim.pepper’s picture

I'm in favour of making dependencies explicit by passing them in. If we split this into two, one the service and another a helper class with static methods, only on of them will be explicit. However, both are still dependencies, and instead of one dependency, we now have two.

+1 for keeping them on the service.

berdir’s picture

Status: Needs review » Reviewed & tested by the community

Setting back to RTBC to get feedback from @alexpott/@larowlan.

jibran’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs reroll
jibran’s picture

Issue tags: -Needs issue summary update

IS has been updated since the tag was added.

kim.pepper’s picture

Status: Needs work » Needs review
Issue tags: -Needs reroll
StatusFileSize
new81.76 KB

Status: Needs review » Needs work

The last submitted patch, 65: 3034072-65.patch, failed testing. View results

kim.pepper’s picture

Status: Needs work » Needs review
StatusFileSize
new81.87 KB
new3.99 KB

Fixed leftover line from merge. Also switched to using assert for typehinting in tests, because I know @dawehner prefers that. ;-)

kim.pepper’s picture

Status: Needs review » Reviewed & tested by the community

Setting back to RTBC as per #62

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

So @Berdir convinced me that my value objects idea was a bad one BUT I agree with @larowlan that we should make getScheme() and getUriTarget() static. Declaring something has no need of state and keeping it that way is valuable.

berdir’s picture

As discussed with @alexpott in slack, we'll heave the methods on the interface/class and just make it static.

kim.pepper’s picture

Status: Needs work » Needs review
StatusFileSize
new84.16 KB
new39 KB

Converted getScheme() and getUriTarget() to static methods.

berdir’s picture

Status: Needs review » Needs work
  1. +++ b/core/includes/file.inc
    @@ -369,7 +369,7 @@ function file_save_htaccess($directory, $private = TRUE, $force_overwrite = FALS
     
    -  if ($stream_wrapper_manager->getScheme($directory)) {
    +  if ($stream_wrapper_manager::getScheme($directory)) {
         $htaccess_path = $stream_wrapper_manager->normalizeUri($directory . '/.htaccess');
       }
    

    hm, that's an interesting pattern. Not sure, but I'd either keep it as -> or with the classname.
    Rest of the patch is a mix of both. I'd wait for some more feedback on that.

    Discussed a bit on slack and thought about it a bit more. There's a good amount of existing examples in core and it helps to avoid an extra use statement in most cases, so $stream_wrapper_manager:: if it's needed as an object, the classname otherwise seems fine.

  2. +++ b/core/lib/Drupal/Core/Asset/CssOptimizer.php
    @@ -125,7 +126,7 @@ public function loadFile($file, $optimize = NULL, $reset_basepath = TRUE) {
         // Stylesheets are relative one to each other. Start by adding a base path
         // prefix provided by the parent stylesheet (if necessary).
    -    if ($basepath && !$this->streamWrapperManager->getScheme($file)) {
    +    if ($basepath && !StreamWrapperManager::getScheme($file)) {
           $file = $basepath . '/' . $file;
    

    Looks like this was the only usage of this in CssOptimizer, so we can drop the constructor again, yay.

kim.pepper’s picture

Status: Needs work » Needs review
StatusFileSize
new81.77 KB
new2.92 KB
  1. OK great!
  2. Fixed
berdir’s picture

Assigned: berdir » Unassigned
Status: Needs review » Reviewed & tested by the community

Great, back to RTBC as #69 has been addressed.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
  1. +++ b/core/includes/file.inc
    @@ -98,25 +98,29 @@
    +  return \Drupal::service('stream_wrapper_manager')->getScheme($uri);
    
    @@ -130,15 +134,15 @@ function file_stream_wrapper_valid_scheme($scheme) {
    +  return \Drupal::service('stream_wrapper_manager')->getUriTarget($uri);
    

    Unnecessary use of a service.

  2. +++ b/core/modules/color/color.module
    @@ -493,7 +493,7 @@ function color_scheme_form_submit($form, FormStateInterface $form_state) {
    -      $css_optimizer = new CssOptimizer();
    +      $css_optimizer = new CssOptimizer(\Drupal::service('stream_wrapper_manager'));
    

    unnecessary injection

  3. +++ b/core/modules/system/src/FileDownloadController.php
    @@ -13,6 +15,32 @@
    +  public function __construct(StreamWrapperManagerInterface $streamWrapperManager) {
    +    $this->streamWrapperManager = $streamWrapperManager;
    +  }
    

    As we're adding a constructor here we need to cope with a things that don't expect it to be required so we need to enable this to be constructed with out a stream wrapper manager. I.e as if we've added an arg to an existing constructor.

  4. +++ b/core/tests/Drupal/Tests/Core/File/FileSystemTest.php
    @@ -125,32 +129,6 @@ public function providerTestBasename() {
    -  /**
    -   * @covers ::uriScheme
    -   *
    -   * @dataProvider providerTestUriScheme
    -   */
    -  public function testUriScheme($uri, $expected) {
    -    $this->assertSame($expected, $this->fileSystem->uriScheme($uri));
    -  }
    

    This could be converted into a legacy test with an @expected deprecation rather than removed. Otherwise I don;t think we have test coverage of $this->fileSystem->uriScheme()

kim.pepper’s picture

Status: Needs work » Needs review
StatusFileSize
new83.16 KB
new7.12 KB
  1. Fixed
  2. Fixed
  3. Fixed
  4. Fixed
alexpott’s picture

+++ b/core/modules/system/src/FileDownloadController.php
@@ -29,6 +29,10 @@ class FileDownloadController extends ControllerBase {
   public function __construct(StreamWrapperManagerInterface $streamWrapperManager) {

Need a = NULL here.

kim.pepper’s picture

StatusFileSize
new83.17 KB
new1.01 KB

Oops! Thanks!

berdir’s picture

Status: Needs review » Needs work
  1. +++ b/core/lib/Drupal/Core/StreamWrapper/StreamWrapperManager.php
    @@ -100,7 +100,7 @@ public function getViaScheme($scheme) {
        */
       public function getViaUri($uri) {
    -    $scheme = file_uri_scheme($uri);
    +    $scheme = $this->getScheme($uri);
         return $this->getWrapper($scheme, $uri);
       }
    

    this could be a static::getScheme(), not sure if it makes a difference.

  2. +++ b/core/lib/Drupal/Core/StreamWrapper/StreamWrapperManagerInterface.php
    @@ -169,4 +169,81 @@ public function getClass($scheme);
    +   *
    +   * @param $uri
    +   *   The URI to be tested.
    +   *
    +   * @return bool
    +   *   TRUE if the URI is allowed.
    

    nitpick: missing type and description of return seems off, "allowed" for what? should be valid I'd say

  3. +++ b/core/modules/image/image.module
    @@ -471,8 +473,11 @@ function image_field_config_update(FieldConfigInterface $field) {
     
    +  /** @var \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface $stream_wrapper_manager */
    +  $stream_wrapper_manager = \Drupal::service('stream_wrapper_manager');
    +
       // If the upload destination changed, then move the file.
    -  if ($file_new && (file_uri_scheme($file_new->getFileUri()) != $field_storage->getSetting('uri_scheme'))) {
    +  if ($file_new && ($stream_wrapper_manager::getScheme($file_new->getFileUri()) != $field_storage->getSetting('uri_scheme'))) {
         $directory = $field_storage->getSetting('uri_scheme') . '://default_images/';
    

    another one where the static call is the only call, so no service needed?

  4. +++ b/core/modules/image/src/Controller/ImageStyleDownloadController.php
    @@ -48,8 +49,11 @@ class ImageStyleDownloadController extends FileDownloadController {
        */
    -  public function __construct(LockBackendInterface $lock, ImageFactory $image_factory) {
    +  public function __construct(LockBackendInterface $lock, ImageFactory $image_factory, StreamWrapperManagerInterface $stream_wrapper_manager) {
    +    parent::__construct($stream_wrapper_manager);
         $this->lock = $lock;
    

    needs to be = NULL here too, so that subclasses of ImageStyleDownloadController still work as well.

  5. +++ b/core/modules/image/src/Controller/ImageStyleDownloadController.php
    @@ -91,6 +96,9 @@ public function deliver(Request $request, $scheme, ImageStyleInterface $image_st
     
    +    /** @var \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface $stream_wrapper_manager */
    +    $stream_wrapper_manager = \Drupal::service('stream_wrapper_manager');
    +
         // Check that the style is defined, the scheme is valid, and the image
         // derivative token is valid. Sites which require image derivatives to be
         // generated without a token can set the
    @@ -102,7 +110,7 @@ public function deliver(Request $request, $scheme, ImageStyleInterface $image_st
    
    @@ -102,7 +110,7 @@ public function deliver(Request $request, $scheme, ImageStyleInterface $image_st
         // The $target variable for a derivative of a style has
         // styles/<style_name>/... as structure, so we check if the $target variable
         // starts with styles/.
    -    $valid = !empty($image_style) && file_stream_wrapper_valid_scheme($scheme);
    +    $valid = !empty($image_style) && $stream_wrapper_manager->isValidScheme($scheme);
    

    we are injecting the stream wrapper manager here, so can use $this->streamWrapperManager

  6. +++ b/core/modules/image/src/Entity/ImageStyle.php
    @@ -505,16 +510,12 @@ protected function addExtension($path) {
       protected function fileUriScheme($uri) {
    -    return file_uri_scheme($uri);
    +    return StreamWrapperManager::getScheme($uri);
       }
    
    @@ -525,17 +526,13 @@ protected function fileUriScheme($uri) {
        */
       protected function fileUriTarget($uri) {
    -    return file_uri_target($uri);
    +    return StreamWrapperManager::getUriTarget($uri);
       }
    

    now that these two methods are static, can we just call them directly in the unit test? looks like that duplicates the real implementation? Then we can add a @trigger_error() to these too.

  7. +++ b/core/modules/image/tests/src/Functional/ImageFieldDisplayTest.php
    @@ -451,7 +451,11 @@ public function testImageFieldDefaultImage() {
    +
    +    /** @var \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface $stream_wrapper_manager */
    +    $stream_wrapper_manager = \Drupal::service('stream_wrapper_manager');
    +
    +    $this->assertEqual('private', $stream_wrapper_manager->getScheme($file->getFileUri()), 'Default image uses private:// scheme.');
         $this->assertTrue($file->isPermanent(), 'The default image status is permanent.');
    

    another static call?

  8. +++ b/core/modules/image/tests/src/Functional/ImageStylesPathAndUrlTest.php
    @@ -184,12 +184,15 @@ public function doImageStyleUrlAndPathTests($scheme, $clean_url = TRUE, $extra_s
     
    +    /** @var \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface $stream_wrapper_manager */
    +    $stream_wrapper_manager = \Drupal::service('stream_wrapper_manager');
    +
         // Check that the generated URL is the same when we pass in a relative path
         // rather than a URI. We need to temporarily switch the default scheme to
         // match the desired scheme before testing this, then switch it back to the
         // "temporary" scheme used throughout this test afterwards.
         $this->config('system.file')->set('default_scheme', $scheme)->save();
    -    $relative_path = file_uri_target($original_uri);
    +    $relative_path = $stream_wrapper_manager::getUriTarget($original_uri);
    

    doesn't seem to use the service elsewhere?

  9. +++ b/core/modules/image/tests/src/Kernel/ImageStyleCustomStreamWrappersTest.php
    @@ -75,7 +75,7 @@ public function register(ContainerBuilder $container) {
       public function testCustomStreamWrappers($source_scheme, $expected_scheme) {
         $derivative_uri = $this->imageStyle->buildUri("$source_scheme://some/path/image.png");
    -    $derivative_scheme = $this->fileSystem->uriScheme($derivative_uri);
    +    $derivative_scheme = \Drupal::service('stream_wrapper_manager')->getScheme($derivative_uri);
     
    

    same.

  10. +++ b/core/modules/locale/locale.translation.inc
    @@ -376,7 +376,9 @@ function locale_cron_fill_queue() {
     function _locale_translation_file_is_remote($uri) {
    -  $scheme = file_uri_scheme($uri);
    +  /** @var \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface $stream_wrapper_manager */
    +  $stream_wrapper_manager = \Drupal::service('stream_wrapper_manager');
    +  $scheme = $stream_wrapper_manager->getScheme($uri);
    

    same.

  11. +++ b/core/modules/system/src/Form/ThemeSettingsForm.php
    @@ -295,8 +296,9 @@ public function buildForm(array $form, FormStateInterface $form_state, $theme =
    +
    +        if (StreamWrapperManager::getScheme($original_path) == 'public') {
    +          $friendly_path = StreamWrapperManager::getUriTarget($original_path);
               $element['#default_value'] = $friendly_path;
             }
    

    seeing them next to each other made me realize that one has Uri and the other doesn't, seems a bit inconsistent but not sure if that's an issue and which way we should make them consistent.

  12. +++ b/core/modules/user/tests/src/Functional/UserPictureTest.php
    @@ -63,9 +63,12 @@ public function testCreateDeletePicture() {
     
    +    /** @var \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface $stream_wrapper_manager */
    +    $stream_wrapper_manager = \Drupal::service('stream_wrapper_manager');
    +
         // Verify that the image is displayed on the user account page.
         $this->drupalGet('user');
    -    $this->assertRaw(file_uri_target($file->getFileUri()), 'User picture found on user account page.');
    +    $this->assertRaw($stream_wrapper_manager::getUriTarget($file->getFileUri()), 'User picture found on user account page.');
     
    
    @@ -135,8 +138,11 @@ public function testPictureOnNodeComment() {
           ->save();
     
    +    /** @var \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface $stream_wrapper_manager */
    +    $stream_wrapper_manager = \Drupal::service('stream_wrapper_manager');
    +
         $this->drupalGet('node/' . $node->id());
    -    $this->assertNoRaw(file_uri_target($file->getFileUri()), 'User picture not found on node and comment.');
    +    $this->assertNoRaw($stream_wrapper_manager::getUriTarget($file->getFileUri()), 'User picture not found on node and comment.');
       }
    

    more static only calls.

kim.pepper’s picture

Status: Needs work » Needs review
StatusFileSize
new86.37 KB
new16.64 KB

Thanks for the thorough review @Berdir!

  1. Fixed
  2. Fixed
  3. Fixed
  4. Fixed
  5. Fixed
  6. Fixed
  7. Fixed
  8. Fixed
  9. Fixed
  10. Fixed
  11. Makes me think we need to treat URIs as first class citizens and make a value object for them. (Or use a 3rd party lib like https://uri.thephpleague.com/) But I don't mind changing getScheme() to getUriScheme()
  12. Fixed
berdir’s picture

Status: Needs review » Reviewed & tested by the community

Looks good to me now, nice cleanup in that interdiff.

@alexpottt might have some thoughts on that method name in #79.11, I think otherwise it is ready.

alexpott’s picture

Re the names getScheme() and getTargetUri() - looking at the PHP doc for inspiration - https://www.php.net/manual/en/intro.stream.php it says:

A stream is referenced as: scheme://target

  • scheme(string) - The name of the wrapper to be used. Examples include: file, http, https, ftp, ftps, compress.zlib, compress.bz2, and php. See Supported Protocols and Wrappers for a list of PHP built-in wrappers. If no wrapper is specified, the function default is used (typically file://).
  • target - Depends on the wrapper used. For filesystem related streams this is typically a path and filename of the desired file. For network related streams this is typically a hostname, often with a path appended. Again, see Supported Protocols and Wrappers for a description of targets for built-in streams.

So I think the methods should be getScheme() and getTarget() because together they represent a URI but individually neither are a URI.

berdir’s picture

Status: Reviewed & tested by the community » Needs work

Works for me, thanks.

kim.pepper’s picture

Status: Needs work » Needs review
StatusFileSize
new86.27 KB
new17.99 KB

re: #82 renamed getUriTarget() to getTarget().

kim.pepper’s picture

Status: Needs review » Reviewed & tested by the community

I think it's safe to put this back to rtbc

jibran’s picture

Yeah, #82 is addressed so RTBC +1

alexpott’s picture

Issue summary: View changes
Status: Reviewed & tested by the community » Needs work

The CR needs updating to match the final state of the patch.
The API changes section of the issue summary needs filling out
The release notes section needs completing.
Also we should list the CRs that need updating in the issue summary - atm from the comments I can find https://www.drupal.org/node/2418133

kim.pepper’s picture

Issue summary: View changes
kim.pepper’s picture

Issue summary: View changes
Status: Needs work » Reviewed & tested by the community

I've updated the IS and CR. I couldn't find any other CRs that needs updating other than the one you listed. I put that in the IS.

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

I rerolled the patch to fix the conflict in core/tests/Drupal/Tests/Core/File/FileSystemTest.php and ran the test locally. All good - it was a conflict with the getMock() patch.

Committed e08ec13 and pushed to 8.8.x. Thanks!

Time to update that CR.

  • alexpott committed e08ec13 on 8.8.x
    Issue #3034072 by kim.pepper, Berdir, alexpott, jibran, larowlan,...
alexpott’s picture

Issue tags: +8.8.0 release notes
jibran’s picture

https://www.drupal.org/node/2418133 still needs the update.

kim.pepper’s picture

Woop! \m/

Updated the related CR.

mondrake’s picture

FTR, the change of Drupal\system\FileDownloadController constructor's signature can lead to an error like

Call to a member function isValidScheme() on null

in modules that extend the base class without calling the parent constructor.

See for example #3059071: Call to a member function isValidScheme() on null for Textimage.

berdir’s picture

Fun :-/ I'd suggest you open a follow-up, we can do the same thing we did before in other places, add a private getFileSystem() method that does another @trigger_error() and falls back to Drupal::service() if it's not set.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

xjm’s picture

Issue tags: -8.8.0 release notes

Based on discussion with @larowlan and @pameeela, this issue isn't more disruptive than any typical deprecation, so it probably doesn't need to be listed in the release notes (unless there's something more disruptive for some edgecase than what's called out in the CR).