Problem/Motivation
After the completion of the new Extension system API's in #2208429: Extension System, Part III: ExtensionList, ModuleExtensionList and ProfileExtensionList and #2659940: Extension System, Part III: ThemeExtensionList and ThemeEngineExtensionList, drupal_get_path() has been replaced with the theme, module and profile extension listing services. This issue will deprecate the usage of drupal_get_path() and drupal_get_filename() in core and replace with the relevant extension listing service calls (Module|Profile|Theme)ExtensionList::getPath() and (Module|Profile|Theme)ExtensionList::getPathname() respectively.
Proposed resolution
Replace all dynamic uses drupal_get_path() with (Module|Profile|Theme)ExtensionList::getPath().
Replace all dynamic uses drupal_get_filename() with (Module|Profile|Theme)ExtensionList::getPathname().
Remaining tasks
Reviews
Commit
User interface changes
None
API changes
drupal_get_path() and drupal_get_filename() are deprecated.
\Drupal\Core\Extension\Exception\UnknownExtensionException is now thrown if the extension is not found.
\Drupal\Core\Extension\Exception\UnknownExtensionTypeException is now thrown if the extension type is not found.
The class \Drupal\ckeditor\CKEditorPluginBase gets two new public methods: getModuleList() and getModulePath($module_name). The first method returns the module list service (\Drupal::service('extension.list.module')). The second method the module path for the given module name (\Drupal::service('extension.list.module')->getPath($module_name)).
| Comment | File | Size | Author |
|---|---|---|---|
| #302 | 2347783-302-interdiff.txt | 6.2 KB | berdir |
| #302 | 2347783-302.patch | 177.45 KB | berdir |
Issue fork drupal-2347783
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #1
almaudoh commentedComment #2
tim.plunkettdrupal_get_path() is used for much more than PHP files.
Mostly for CSS and JS.
Comment #3
almaudoh commented@tim.plunkett, this is kinda jumping ahead of #1308152-182: Add stream wrappers to access .json files in extensions. Marking postponed on that one.
Comment #4
midynamics commentedI would agree with almoudoh. Its best to remove drupal_get_path()and replace with module_load_include
Comment #5
Crell commentedWith most code now in classed objects, do we even need module_load_include() anymore? I don't think it has a purpose. (If you have enough procedural code to bother breaking into multiple files then most of it should be in classes anyway.)
Comment #6
tim.plunkettThats a nice thought, but it's post-beta and there are 53 usages of module_load_include in HEAD.
Comment #7
almaudoh commentedRelated issue #697946: Properly deprecate module_load_include() and move it into \Drupal::moduleHandler() service where module_load_include() is replaced with include_once(), file_exists() and drupal_get_path(). So are we going round in loops...
Comment #8
fietserwinIf we don't want to go around in loops with #697946: Properly deprecate module_load_include() and move it into \Drupal::moduleHandler() service, we might change the goal of this issue into striving to replace the other usages of drupal_get_path():
- js files: about 23 usages: replace with module://...?
- css files: about 37 usages: replace with module://...?
- info.yml: 2 usages (and 1 in a comment): replace with $this->moduleHandler()->getModule($moduleName)->getName()
- other .yml: 2 usages: replace with module://...?
- xml files: 4 usages: replace with module://...?
- php files not to be included but to be executed via an HTTP request in tests: 8 usages: can be replaced with module://
In total there are about 181 usages. It seems that many can be replaced with module:// (or theme:// or profile:// or the not yet existing library://) as their usage is in adding css/js resources to a page, and many are in test situations. However, to which degree, do we want to make our tests depend on other functionality like module:// where a small error in the module stream wrapper may lead to 1000's of test failures?
For not test situations: how is the order of loading? I saw some usages of drupal_get_path in the module handler, so that obviously can't be replaced with module://. But how early are the stream wrappers loaded, currently and after turning them into services?
Comment #9
almaudoh commentedAlready raised #2350553: Replace uses of drupal_get_path() for CSS and JS files with module:// theme:// and profile://streamwrappers to replace usages for CSS and JS files which more or less everyone agrees on. So this issue can be rescoped to discuss (and implement) the other use cases.
Comment #10
fietserwinI was not ware of that issue.
Comment #11
almaudoh commentedThere's now a better direction, with a more streamlined extension system for (profiles, module, theme, theme_engines, etc.),
drupal_get_path()will be easily replaced byExtensionList::getPath($extension_name)Comment #17
jibran#2208429: Extension System, Part III: ExtensionList, ModuleExtensionList and ProfileExtensionList is in.
Comment #18
almaudoh commentedRescoping this issue to deprecate
drupal_get_path()and replace withExtensionList::getPath(). The second issue this was postponed on has been fixed for D8 and is just awaiting backport to D7.Comment #19
ioana apetri commentedI created a change record and I deprecate the drupal_get_path() function.
Please review.
Thanks:).
Comment #21
almaudoh commentedYou should actually remove the uses of
drupal_get_path()in the code base as well and replace with\Drupal::service('extension.list.module')->getPath($module_name);Comment #22
harsha012 commentedfixed as per #21
Comment #24
almaudoh commentedSo this is not a simple matter of find and replace. drupal_get_path() is used in so many places in core that it would be difficult to inject the service classes into all the places where it is used. So this patch does the following:
1. Creates a new trait called
ExtensionPathsTraitthat provides wrappers arounddrupal_get_path()for modules and profiles. So using this trait in classes allows the classes to call$this->getModulePath()or$this->getProfilePath()instead of having to inject the dependencies directly. This pattern is used in core in other places e.g. withStringTranslationTrait2. A method
::getModulePath($module_name)is also added toKernelTestBase,BrowserTestBaseandWebTestBasesince so many tests usedrupal_get_path()and it's easier DX to just have a helper method.3. Injection is done in a few places where there's no BC impact.
4. __DIR__ is used in places where there is a fixed relative path the script file and the other file being referenced (e.g. files in the same module)
5. The rest just directly call the service using
\Drupal::service($service_name)->getPath()6. Changes made to
drupal_get_path('theme', ...)were reverted pending when #2659940: Extension System, Part III: ThemeExtensionList and ThemeEngineExtensionList is committed.Comment #26
almaudoh commentedRemoved the
@trigger_errorfromdrupal_get_filename(), since that still has uses in many parts of the codebase.Comment #28
almaudoh commentedAlso removed the
@trigger_errorfromdrupal_get_path(), since we didn't remove all its uses. Just to allow testbot confirm that the changes are sane.Comment #30
almaudoh commentedMade a little blunder there yesterday. Fixed now. Let's see how it goes.
Comment #32
almaudoh commentedFurther work on this requires #2659940: Extension System, Part III: ThemeExtensionList and ThemeEngineExtensionList to be committed.
Comment #34
andypostBlocker commited #2659940: Extension System, Part III: ThemeExtensionList and ThemeEngineExtensionList
Comment #35
andypostComment #36
almaudoh commentedComment #37
wim leers🥳
Comment #38
gumanist commentedComment #39
andypostComment #41
berdirWe only needed to wrap the function because it was a function, to make unit tests happy. Now that it no longer is, we can just call $this->moduleList->getPath() directly.
Not sure if we should keep the protected function getPath(), we might need to, to be extra careful with subclasses.
the common approach is to do the fallback directly in the constructor, possibly with a @trigger_error() if it's missing.
Same here, the the description doesn't make sense anymore
Comment #42
gumanist commentedThanks @Berdir
Comment #44
gumanist commentedMissed trait
Comment #46
almaudoh commentedShould be
return (bool) \Drupal::service('extension.list.theme')->getPath($this->name);Same here
Same here
Same here too
Should be
$extension_path = \Drupal::service('extension.list.profile')->getPath('standard');Comment #47
andypostFix #46 and few other places
I think deprecation of
drupal_get_filename()needs separate issue because this patch is already big enoughRemaining usage (todo)
-
module_load_include()-
\Drupal\Core\Config\ConfigInstaller::drupalGetPath()-
\Drupal\Core\Config\ConfigManager::uninstall()Comment #48
almaudoh commentedI was actually working on a patch, but you beat me to it. So here's a diff off what additional stuff I did, in case you're still working on it.
Comment #49
andypost@almaudoh Thanks for fixes, meanwhile would be great to check #697946: Properly deprecate module_load_include() and move it into \Drupal::moduleHandler() service
ATM I'm workin on followup for
drupal_get_filename()cos it needs separate CR and will help to simplify the patch a bitComment #50
andypostFiled #3017951: Deprecate drupal_get_filename() and replace usage with ExtensionList::getPathname()
Comment #51
andypostLet's see how many fails with #48 interdiff
Comment #52
gumanist commentedUpdated files getPath instead of __DIR__
Comment #53
gumanist commentedoups, status...
Comment #54
gumanist commentedRemoved __DIR__ for other places in locale module
Comment #57
gumanist commentedReplaced with services for batches in update and node modules
Comment #58
gumanist commentedstatus
Comment #60
almaudoh commentedMade some fixes to the tests that are failing. The patch is now huge and would need to be split into three or more pieces.
I suggest:
1. Direct replacements in tests without any dependency injection
2. Replacement in classes or other services which require dependency injection
3. Replacement in functions which don't require dependency injection.
Comment #61
andypostI find strange that
__DIR__replaced with service call, it reverts #2351919: Replace uses of drupal_get_path() with __DIR__ where possibleComment #63
almaudoh commentedNot really, the
__DIR__uses replaced in recent patches were actually introduced in this issues' original patch #24.4, not in #2351919: Replace uses of drupal_get_path() with __DIR__ where possible. In these cases__DIR__cannot be used because what is needed is a relative path (e.g.core/modules/statistics) while__DIR__will return an absolute path (e.g./var/www/html/core/modules/statistics), and calculating the relative path is more expensive than just pulling it from the ModuleExtensionList service. This may be why these particular cases were not changed by the #2351919 patchComment #64
almaudoh commentedFinally found time to fix the AjaxTest. A similar fix was tried in #2808063: LibraryDiscoveryParser::buildByExtension() doesn't validate that extensions exist
Comment #65
almaudoh commentedComment #66
andypostNice summary! Meanwhile ci shows
4 coding standards messagesComment #67
almaudoh commentedFixed coding standard nits.
Comment #69
izus commentedHi,
rerolled #67 to trigger again tests
hope it'll be green this time
Comment #70
izus commentedcorrected the increment error in the file name
Comment #71
andypostThis looks the all of usage of the trait, so I think no reason to implement the trait.
Instead, helpers like ones added to testBase classes makes sense
Comment #72
rodrigoaguileraThis patch needed a reroll for a conflict in
core/modules/system/src/Form/ThemeSettingsForm.php
I want to try to address #71 after the reroll
Comment #74
rodrigoaguileraoops. missing comma
Comment #76
rodrigoaguileraThe patch in #74 was missing the new Trait.
In the patch attached I remove that trait with methods in the CkeditorPluginBase. I also fix the code style issue reported by the CI.
I don't know what is happening with the CI...
Comment #78
rodrigoaguileraForgot the interdiff
Comment #79
rodrigoaguileraOk, It was not a good decision to make DrupalImageCaption extend CKEditorPluginBase. Reverting that.
Comment #81
rodrigoaguileraI forgot one getModulePath
Comment #83
naveenvalechaHere's the updated patch for 8.8.x with the updated deprecated message.
Comment #84
kim.pepperLooking great!
Just a few nitpicks...
Can we create a local variable and typehint?
Can we inject this?
Can we use the *almost* standard format? https://www.drupal.org/project/coding_standards/issues/3024461
Can we create a local variable then do assert($var instanceof ModuleExtensionList)?
assert($extension_list instanceof ModuleExtensionList)
Ditto
Comment #85
kim.pepperFixes for my own feedback in #84 :-)
Comment #87
kim.pepperUpdates services yaml.
Comment #89
kim.pepperFix deprecation message.
Comment #90
subson commentedrerolling the patch against 8.8.x, am not able to take the interdiff between 89 and 90 as the earlier patch was not applying cleanly.
Comment #92
kim.pepperHere's another attempt at a reroll.
I also updated some of the deprecation messages to the standard format, and added a trigger_error where it was missing.
Comment #94
kim.pepperFixes deprecation test.
Comment #95
andypostLooks great!
As I see it missing legacy tests for this functions but adds legacy test for constructor which looks not much useful
Also base test classes using duplicated methods - not sure it fits to trait but this is code duplication
Maybe this function also should trigger error (depending on $type pointing to valid service)?
otoh it will trigger twice if both functions will use it
other tests also add getThemePath (trait?)
Not sure it needed
Could be a trait
Comment #96
andypostNW for message
The message should use new format `drupal:8.8.0` and so on according to https://www.drupal.org/core/deprecation#how-function
Comment #97
kim.pepper#95:
#96 updated deprecation format.
I added the deprecation and realised there were quite a lot of usages that were still in core. I've made an attempt to replace them all, however, not sure what is going to break now.
Comment #98
kim.pepperThis makes me think we haven't got the api right yet!
Comment #99
berdirWent through the patch a bit, not a full review...
I think we can still improve this a bit.
You also need to know the corresponding service name if you do inject it, so maybe it should be something like "Use ExtensionList::getPathname() from the respective service (extension.list.module, extension.list.profile, extension.list.theme)" or so
doesn't feel like we've really resolved this @todo and the one for user below. We apparently still special-case system and user, I think that @todo doesn't mean to just replace it with the equivalent method/service but completely remove it. I'd just keep the @todo for now?
apparently we still need $extension_type below, once..
we've kept such methods before in similar cases and deprecated them as well. kinda overkill, but might be the safer option?
looks like this updates the docs but not the actual implementation? Possibly another one we want to deprecate and use an injected service?
can there be anything else?
I mean we could do something like this, but not sure if that's really better:
$schema_dir = $this->{$type . 'ExtensionList'}->getPathname().
That's basically what drupal_get_path/filename does too with "\Drupal::service("extension.list.$type")", so that would fail hard if called with something non-existing as well.
there might be a reason we didn't inject that yet, module installer is really funky as it does container rebuilds.
missing the deprecation thingy.
Having a dejavu, but I think this test isn't just a legacy test, that still needs to work now for our installer? so maybe instead rename and use the extension list?
looks like a merge leftover... this was removed.
Comment #100
joachim commented> there might be a reason we didn't inject that yet, module installer is really funky as it does container rebuilds.
Sounds like we should open a side issue to add a comment about that there, so it doesn't get accidentally 'fixed' in future.
Comment #101
kim.pepperThanks @Berdir
ExtensionListFactory::getExtensionList($type)DRUPAL_MINIMUM_PHPconstant.Comment #103
kim.pepperRe: #101.6 here's what I was thinking for an extension list factory. I think it makes things a lot cleaner.
Comment #104
kim.pepperHmm. Need to special-case some logic for core in ConfigInstaller.
Comment #105
berdirmaybe include the classname for those methods?
hm, I know we don't do that in unit tests because it pollutes all tests. If we need it then I assume we have to re-add the constant, just with the right value.
Why do we need it now though?
Maybe, but not sure if factory is the right term here? It doesn't actually create them, just allows you to access them through a single dependency?
Can't really think of a good name right now, ExtensionListRepository also doesn't seem that great?
maybe use an assertInstanceOf for these?
I suppose that's exactly why we have the core logic in drupal_get_filename() :)
Comment #106
kim.pepperWe could:
getPathname()(getPath()?) methodgetPathname()on itComment #107
berdirThat sounds interesting, I guess most cases that need to call the same method on these services dynamically is the path stuff?
Comment #108
andypostLast weekend I used to dig Advanced help module and filed #3077074: [Meta] Change mentions from module to extension
Module using module & theme handlers to look for read.me(+ bit more) in active extensions
Then a lot of UI/render require to
- get path to use "finder"
- render extension name - that's where it using proxy
ModuleHandler::getName()Comment #109
kim.pepperHere's an attempt at the idea suggested in #106.
Comment #110
kim.pepperFixed incorrect replacement of
getPathname()instead ofgetPath().Comment #113
joachim commentedNot a full review, but I spotted this:
This @todo shouldn't be getting removed.
Comment #114
kim.pepperFound another place that can use ExtensionPathResolver.
Re #113: restores todo
Comment #116
kim.pepperFix LibraryDiscoveryParserTest fails.
Comment #118
kim.pepperI'm scratching my head over these fails...
Comment #119
volegerIn
BrowserTestBaseUserAgentTestI comparing the values that provaided before and after changes. Sodrupal_get_path('module', 'system')returns path to the directory, but$this->container->get('extension.list.module')->getPathname('system')returns path to the info file.See the results:
Comment #120
volegerSo the main problem is in that test
getPathnamemethod call have to be replaced withgetPathmethod callComment #121
volegerAlso, I'm not sure that
$profile_listhave to be an instance of theextension.list.moduleservice.Comment #122
kim.pepperThanks @voleger 🎉 They are definitely bugs, however I don't think that will fix the fails.
Comment #124
kim.pepperFrom @Berdir slack:
Comment #125
kim.pepperI think I need a picture to get my head around that! 🤯
Comment #126
volegerAt least we fix the UA related test.
There is more issue related to changes introduced by the patch:
There is an incorrect method call introduced in the ConfigInstaller.
getInfoPathmethod call has to be used instead ofgetDirmethod call.Comment #127
kim.pepperI don't think that's true? Looking at how $extension_path is used on the next line indicates it should be a directory.
Comment #128
volegerI debugging the code in the context of the InstallerBase tests, so I'm also confused about that. But the return values of the replaced code is different so that looks incorrect.
Also
Typo here
Checked the return values of the replaced code so in the context of the InstallerBase test here we can get the next values:
$this->drupalGetPath($type, $name)returnscore$this->extensionPathResolver->getDir($type, $name)returns.But if we replace code with
$this->extensionPathResolver->getInfoPath($type, $name)that will returnscoreComment #129
volegerI have an assumption that at some phase we set the dirname path to the extension path property instead of the filename of the info file of that extension. Can be that a reason why we can get the correct value from
getFilenamemethod instead ofgetDirmethod?Comment #130
kim.pepperAha! That was the problem. I tried to remove that code in the ExtensionPathResolver, but it's required for the 'core' type.
Comment #131
volegerOh, that makes sense. And also fixes the installer related tests.
+1 for rtbc
Comment #132
andypost+1 to rtbc but I think @Berdir should set it
Comment #133
berdirI like the path resolver, but I'm not 100% sure that we should use an extensible pattern to inject its depenndencies, that implies an extensibility that doesn't actually exist? There is no use case for contrib to add another etension list?
I guess it's off-topic to fix that here, although we're actually specifically changing ConfigInstaller::getProfileStorages() here.
Why different method names here than on the extension lists? I agree that getPath() vs getPathname() is a bit confusing, but IIRC, that was discussed and explicitly decided to be consistent with https://www.php.net/manual/de/splfileinfo.getpathname.php and https://www.php.net/manual/de/splfileinfo.getpath.php.
The class name is also ExtensionPathResolver.
Also, we don't shorten things like that, so should be getDirectory() if we stick with that.
If it's only called through getDir() then why not implement it there?
I'm a bit confused about our two mocking libraries in core to be honest.. other places use createMock(), this uses prophecy, it's not about consistency either as the call above is createMock() ;)
still confused by this, as mentioned should at least use the same php version?
not really in scope ;)
we certainly don't need these methods on WebTestBsae and I'm also not sure if we should if others need it. Maybe it should be getExtensionPath($type, $name) and use the extension path resolver?
kernel tests have 18 calls to their getModulePath() (and just 2 for getThemePath()), most of them for hardcoded method names that often violate https://www.drupal.org/node/3034299, for example all the ckeditor calls.
And most that aren't their own module is for simpletest files, so something that we need to move out of there anyway.
browser tests do have a bit more calls, and whlie most are also a hardcoded module, most need to relative path for checking http requests/html content, so __DIR__ doesn't work there. Maybe we could just keep a getExtensionPath() method there?
Just thinking about loud, happy to hear counter-arguments on most of these (not WebTestBase, though :))
Comment #134
berdirOn #133.6, I did run the test without that line with run-tests.sh and phpunit directly and it's not needed?
Comment #135
andypostI suppose it is, at least db drivers screams about it
Why extension system should be not extensible?
Comment #136
kim.pepperThanks for the review @Berdir!
getPathname()andgetPath()as this was previously agreed to.getPath()createMock()getThemePath()as it wasn't used. I also replaced a few usages in\Drupal\aggregator\Tests\AggregatorTestBasealthough that is deprecated anyway.Comment #137
berdir> Why extension system should be not extensible?
Because it's not? ExtensionPathResolver has a hardcoded list of allowed types and validates against that.
yeah, these are exactly problematic examples. This isn't about a local path, it's about a URL that is then requested in the test.
WebTestBase is fully deprecated and we shouldn't have any calls to WebTestBase::getModulePath() in this patch anyway?
Comment #138
kim.pepperI've reverted changes to WebTestBase and sub-classes, removing
getModulePath()Comment #139
volegerFound that #105.2 still without answer why we need this change.
Also wondering why we need this change also. Does that mean influence on the library definitions?
Comment #140
kim.pepperThanks @voleger.
DRUPAL_MINIMUM_PHPin the test setup.Comment #142
voleger#140.1 now it is better. Instead of including the whole bootstrap file just defining the required constant. And that is great, let's keep it for the issue related to moving those constant into namespaced class. See #2908079: Move some of the bootstrap.inc PHP-related constants to \Drupal and deprecate the old versions.
#140.2 Does that mean that change introduced in the patch has influence on the caching?
Comment #143
kim.pepperNot sure.
I also re-removed the file docblock as this is now failing code sniffer as we've touched this file.
Comment #144
andypostComment #145
andypostReroll and one more fix
Comment #146
volegerSet retest against the latest changes in core. If green +1 for RTBC
Comment #147
volegerNeeds reroll
Comment #148
andypostReroll + few fixes, also found few new mentions in comments
Comment #149
berdirI think this looks good, I did several reviews and I really like the ExtensionPathResolver service that we added here, it allows us to keep a similar/simple API to get the path of any type of extension and made many of the replacements much easier as we previously needed to inject 3 different services to get the same result.
If #2908079: Move some of the bootstrap.inc PHP-related constants to \Drupal and deprecate the old versions lands first (and it is also RTBC), then we can drop the constant definition here.
Comment #150
alexpott@var \Drupal\Core\Extension\ExtensionList[]
This is a large change and some of this is not related or necessary for the change. Makes reviewing harder.
This should be deprecated - no?
Not sure this should be here.
Don't we need to dance the deprecation dance here?
Can we not assert against the return value. Won't this be
core/modules/systemThis isn't testing drupal_get_filename()
Comment #151
kim.pepperNeeded a re-roll after #2940189: Deprecate system_get_info().
Re #150
Comment #152
kim.pepperRe: #150.5 I think this was accidentally included in a bad reroll. Removed.
Comment #153
alexpottDiscussed with @berdir. The first test is no longer testing anything without a database. And we already have good unit test coverage of both ExtensionList and ExtensionDiscovery.
The second test is also covered by the existing unit test coverage.
Therefore let's not add this test here but still completely remove GetFilenameTest.
Comment #154
kim.pepperI took this to mean remove the entire test class.
Comment #156
berdirYes, exactly that. I always feel bad when I RTBC something and miss things like #150.5 and some of the others, hopefully this one will be better :)
Comment #157
kim.pepperUpdated the title and CR to mention we are also deprecating
drupal_get_filename().Comment #158
kim.pepperUbernit: found an extra character in
getPathnØame()in this comment.Comment #159
larowlanThis is great work here folks, and really highlights some hidden dependencies we were masking with procedural code. Below is a few actual things that might need fixing, and a lot of random ramblings about the coupling.
stray character here that can be fixed on commit
ick, circular dependency? realise it was already there, but just hidden
and here too 😿
It would be good to get a follow up to try and untangle this a bit (and the above).
install storage calls scan on profiles, which calls setProfileDirectoriesFromSettings which gets the profile directories, but then install storage calls set profile? its super-coupled and the static access on both of them indicates something is out right?
Something where we can map out a plan of how we fix this interdependency
wow this really highlights all the places we were kidding ourselves about having modern code 😂
the module installer and the extension list are tightly coupled aren't they (sorry, nothing useful in my review so far, I might be getting delirious)
any reason these don't use ->getModulePath like the ones above and below?
could these be in a trait so a) we can share the code with these two base classes but b) DTT can also use it?
Comment #160
kim.pepperRe: #159
1. Fixed
I left 2-5 for @Berdir to respond to.
6. Created follow up #3087327: [PP-1] DrupalImageCaption should extend CKEditorPluginBase.
7. Moved to a trait.
Also fixed method name in deprecation message.
Comment #161
wim leersEpic work!
🤔 Shouldn't this get a constructor with an optional argument, with the optionality being deprecated in 9.0.0?✅ Hm … upon further investigation, it looks like we almost never do this in plugin base classes.
🤓 Übernit: "drupal" → "Drupal"
🤓 "8.0.0" → "8.8.0"
🤓 "list factory" → "path resolver".Nope,\Drupal\Core\Extension\ExtensionPathResolveris documented asFactory for getting extension lists by type.so leaving unchanged. Oddly named though.🤓 Mismatches.
👎 The first one is correct, the second one should be calling
::getPath().🥳
🤓 "drupal" → "Drupal"
Fixed all those nits,
and back to RTBCah no, I can't, @Berdir still needs to respond to point 2–5. Darn!Comment #162
wim leersJust stumbled upon this in Drupal Slack!
The only reason I did not RTBC #161 is points 2–5 in #159. But those cannot be fixed here. @Berdir will file a follow-up.
So: tagging + RTBC'ing :)
Comment #163
berdir#3087382: Improve circular dependencies between Config/InstallStorage and Extension Discovery
Comment #164
alexpottThe behaviour for when you use type 'core' does not seem to be the same.
What's interesting about this is that we have code like
in core/lib/Drupal/Core/Extension/Extension.php
and
core/lib/Drupal/Core/Theme/ThemeInitialization.php
I think we need to do
in \Drupal\Core\Extension\ExtensionPathResolver::getPathname() and remove the early return from \Drupal\Core\Extension\ExtensionPathResolver::getPath
This results in
which matches drupal_get_path() and drupal_get_filename() behaviour.
Comment #165
kim.pepperGood catch!
Comment #166
kim.pepperI guess this is now drupal 9.1.x 😭
Comment #167
volegerYes, small chances to be replaced before 9.0.0. Here the discussion #3088246: [policy, no patch] How to handle Drupal 8.9.x deprecations
Comment #168
wim leersI think this is actually at committer discretion. This is one of the few remaining procedural APIs. Core committers could decide that if this is important enough, that it ships with
8.8.0-alpha2.Also, given that this allows us to do actual unit testing instead of faking it, bumping this to .
Comment #169
alexpottWe need a reroll here also we've missed the D8.8 ship so I think that means we need to target Drupal 9 now - which will be 9.1 - or we might consider this important enough to do in 8.9 but only deprecate for Drupal 10 - this is a release manager decision.
Comment #170
kim.pepperRe-roll of #164.
I left the deprecation messages at 8.8.0 until we get some direction on the version this should target.
Comment #172
kim.pepperReplaced a couple of uses of deprecated
drupal_get_path()anddrupal_get_filename()introduced in the last 3 months.Comment #174
kim.pepperReplaced use of
$this->libraryDiscoveryParser->setPaths()inLibraryDiscoveryParserTestwhich was removed in earlier patches.Comment #175
kim.pepperTagging for #169
Comment #176
kim.pepperRe-roll against 9.1.x
Comment #178
kim.pepperRemoves a couple of uses of deprecated drupal_get_path that have been added.
Comment #180
aleevasTried to fix failed tests
Comment #182
kim.pepperSorry. Didn't see what #180 was trying to do from that interdiff.
This patch is based off #178 and tries to fix the remaining test fails.
Comment #183
daffie commentedThis patch is for 9.1. Deprecating in 8.8 is no longer possible. Multiple places.
drupal_get_filename().Comment #184
kapilv commented@daffie is correct, I am working on this issue.
Thanks.
Comment #185
anybodyComment #186
aleevasHope I've resolved all issues that was listed in #183
I've also updated the CR
Comment #187
daffie commentedThe testbot returns the following error: "PHP Fatal error: Trait 'Drupal\Tests\ExtensionListTestTrait' not found in /var/www/html/core/tests/Drupal/KernelTests/KernelTestBase.php on line 76"
Comment #188
deepak goyal commentedComment #189
deepak goyal commentedI have applied patch #186 and getting error so I am unassigned myself.
Comment #190
aleevasSorry, In patch was a wrong path to file.
Trying to fix last failure.
Comment #191
daffie commentedComment #192
kim.pepperComment #193
shaktikComment #194
shaktikComment #195
daffie commented@kim.pepper: Thank you for the interdiff. It makes reviewing the differences between the patches from comment #182 and #190 a lot easier.
For #192.1: Good point!
For #192.2: I think it is better to only change "drupal_get_filename()" and create a followup for removing the comment. It is a bit out of scope for this issue.
Comment #196
kim.pepperText should wrap at 80 chars.
Comment #197
saurabh-2k17 commentedComment #198
saurabh-2k17 commentedHi team,
1. @daffie, I have changed drupal_get_filename() as per your suggestion.
2. 183.3 - now the message is changed "drupalGetPath() is deprecated in drupal:9.1.0 and is removed from drupal:10.0.0" this is the current one.
3. @kim.pepper as per your suggestion i have not changed drupal_get_path() comment.
Thanks
Comment #199
saurabh-2k17 commentedComment #200
saurabh-2k17 commentedSorry for the mess forgot to add newly generated files in the patch, here is the correct one.
Comment #202
saurabh-2k17 commentedHi,
Updated patch as last one failed. I have attached interdiff for better understanding.
Thanks
Comment #203
daffie commented@Saurabh_sgh: Thank you for adding the intediff_190-202.txt file.
Whitespace error.
This comment goes over the 80 character limit.
These comments must wrap as close to 80 characters as possible without going over. See: https://www.drupal.org/docs/develop/standards/api-documentation-and-comm....
Comment #204
aleevasWas updated the latest patch accordingly previous warnings.
Comment #205
aleevasSorry for previous patch, was lost one file.
Next try
Comment #206
kim.pepper@aleevas can you please post an interdiff as per https://www.drupal.org/documentation/git/interdiff#git
Comment #207
daffie commentedPutting this back to needs work for the interdiff.txt file. The patch file is 170KB. I am not going to review the whole patch again, trying to figure out what has changed!
Comment #208
mrinalini9 commentedPlease find the interdiff file here.
Comment #209
aleevas@mrinalini9 thank you for help.
@kim.pepper @daffie
sorry for that, I've just forgot to add interdiff to my last comment
Comment #210
daffie commentedComment #211
daffie commented@mrinalini9: Thank you for the interdiff.txt file.
All occurrences of "drupal_get_filename()" and "drupal_get_path()" have been replaced on places where it should be replaced.
Both deprecated function have deprecation testing.
All code changes look good to me.
The IS and the CR are in order.
For me it is RTBC.
Comment #212
shaktikSome more files require deprecation for drupal_get_path().
Comment #213
dww@shaktik:
A) Please don't post screenshots of your editor or CLI. That's not helpful.
B) Did you read the context of the "problems" found? They're all either deprecated wrapper functions or a deprecation test. ;) None of that needs "fixing".
Meanwhile, I started a thorough review on this. Found some stuff. I'll post the review in a bit, but wanted to alert folks that this isn't RTBC and that I'm working on finishing the review.
Thanks,
-Derek
Comment #214
dwwSorry for the novel. :/ Long patches solicit long reviews...
Seems weird to change this comment. It's in the docblock for drupal_get_filename(). That's already marked deprecated. But I don't think we we want to try to introduce "the right way" to get this info like this.
Looks like extension.list.theme_engine is also a thing. Dare we mention it here?
This @trigger_error doesn't match the @deprecated text above. Does that matter?
This is maybe out of scope, but if we're changing this comment anyway, the "
getPath(). /corepart looks like string concatenation, not the end of a sentence. ;) Can we say:"getPath(). The file /core/core.info.yml does not exist..." to break this up?
Above, we @see to the replacement, too. Can we do that here?
@see \Drupal\Core\Extension\ExtensionList::getPath()
Again, the @trigger_error doesn't match @deprecated. Maybe it doesn't matter.
The @trigger_error version: "Use \Drupal\Core... instead." seems better for both...
"module's" ahouls wrap to the previous line now.
Again can/should we @see the replacement, too?
A) "and thus should be built using should use \Drupal..." doesn't parse. s/should use// on the new line.
B) "Defaults to" at least can wrap to the previous line. Maybe more once you remove "should use".
Wrong versions here.
@see the replacement?
I don't think we want |null here. Never seen that for other optional args anywhere in core.
Wrong versions.
getPathname() with parens...
Haven't fully investigated, but can we not use proper DI for this service in this class? \Drupal::service() inside a class is generally frowned upon.
The "yet because..." line can now wrap onto the previous.
Nothing to fix, but... deja vu here. ;) Too bad we have the same comment and code block sprinkled in various spots in core. :/
🤔 is returning 'core/' like this legit? Seems like a bit of a wonky API here. Would need to investigate more to see what's really happening, but on first glance, this seems like it would break for sites running in subdirectories (maybe?)...
Can we not use proper DI here?
A) Wonder if we really want a separate array for validTypes at all. Maybe we just want:
B) Looks like validateType() is only called from getPathname(). Do we need it at all? Maybe we can just test for
!isset($this->extensionLists[$type])directly in getPathname() and throw the exception there?A) s/A/An/
B) "ExtensionLists" is a bit weird. Maybe:
"An associative array of ExtensionList objects keyed by type."
?
I'm having flashbacks to other core bugs where calling dirname() directly breaks in certain cases. We have a filesystem service that handles dirname() for us. Maybe we need to be using that service in this class?
Real DI?
There the whole \Drupal:: vs. container in tests debate, which is still unresolved, but I think the emerging consensus is that \Drupal:: is better in tests. /shrug
Don't need |null
Wrong versions.
Real DI?
More DI.
Since this is about themes, we mean 'extension.list.theme' in this comment.
s/list.module/list.theme/ here, too.
More DI. Maybe for this class, we want the general extension.path.resolver service, and use it for both modules and themes?
Out of scope. :/
Out of scope.
Why not
$this->getModulePath()?Wrong versions.
Aren't these more children of CKEditorPluginBase? Why not
$this->getModulePath()for these?Probably out of scope, but yowzah, that's a really long + complicated line. ;) Can we maybe break this up into multi-line format?
Let's not mix container->get() vs. \Drupal::service() in this patch. Let's have everything use \Drupal:: per previous comment...
Most of this is out of scope. I hate having to say so. I wish we let such cleanups happen naturally, but I know core committers are hyper aware of this, so I figure I should flag it so they don't have to. :/
getPathname()
Probably out of scope.
getPathname()
Since this is like the bazillontyith time this code block appears in the patch, can we put it somewhere shared? ;) Probably not, and probably out of scope (take that, @dww!), but maybe?
A) Wrong versions.
B) This comes up a lot in the patch. It'd be nice to be consistent about "Calling" or not, __METHOD__ or not, () or not, etc.
More container vs. \Drupal:: inconsistency.
Out of scope.
getPathname()
$bazillontyith++ ;)
Why do we care about ExtentionList itself? Previously we assert it's an instance of ModuleExtensionList. Not clear why this one is any different...
👍 I was wondering where this happened. Lots of the tests above use the trait themselves, but now we've finally got it happening in the base class. We should remove the trait from children test classes if it's handled in the base. Sorry, I don't want to go back through the whole patch for this. But basically search for "use ExtensionListTestTrait" and remove it from any test classes since we should have it in the parent classes.
Don't we need
use Drupal\Tests\ExtensionListTestTraitearlier in this file before we can use it?🤔 Is that the right format for these? I don't remember seeing this, but I'm probably wrong.
Out of scope? What's up with this?
Container or \Drupal::?
Thanks/sorry!
-Derek
Comment #215
shaktikComment #216
shaktikComment #217
shaktikHi @dww,
I have applied patch #205 and getting below error, Please find the attached screenshot.
Comment #218
kim.pepperThanks for the exhaustive review @dww!
Overall comments:
Here goes:
Comment #220
dwwThanks for addressing all that! Don't have time to look at the interdiff, but sounds promising. :)
Re: Overall - container + DI: all sounds fine, we can do those in followups.
31: Yes, sorry. I guess I had missed this was Theme.php and doesn't care about modules at all. 😉
34: Oh wow. 😉 Sorry, didn't realize this doesn't extend
CKEditorPluginBase. Whoops. follow-up++42: Follow-up++
49: Sorry I wasn't clear.
BrowserTestBaseis now using theExtensionListTestTraittrait but doesn't have ausestatement about it. Guess they're in the same namespace so it finds it? Didn't notice that the first time, so probably this is fine.50: 👍
51: 👍
Re: test fail: Looks like a random fail? Re-queuing.
Comment #221
kim.pepperDid a quick scan and we already have followup for #3087327: [PP-1] DrupalImageCaption should extend CKEditorPluginBase I guess they all could extend
CKEditorPluginBase?Comment #222
kim.pepperI wonder if the test fail was due to #214.45 and why??
Comment #223
kim.pepperThe ajax test change was introduced in #64 by @almaudoh, then removed, then re-added. I don't think we had an explanation for the change anywhere in the long history of this issue.
Comment #224
alexpottThis injection is no longer used.
How come we're not mentioning the new extension.path.resolver service?
As this is new code let's use scalar typehints and return typehints.
This could be simplified by swapping things around. Eg:
This is used in functional tests - we should not be using $this->container there. It gets out of date.
BrowserTests should avoid $this->container
This should no longer be necessary. It's been converted to \Drupal::MINIMUM_PHP
So as mentioned before $this->container is tricky in browser tests because it gets out of date. I think we should use \Drupal::service() here. Plus we should now have scalar typehints and return typehints.
Comment #225
kim.pepperThanks @alexpott.
Addresses feedback in #224. The AjaxTest fail is still a mystery.
Comment #227
kim.pepperOK. Here's the fix for AjaxTest
Comment #228
dwwRe: #227: Ugh, it really was #214.45 🤦♂️ whoops! 😉 Sorry about that, and thanks for tracking it down.
https://www.drupal.org/node/2940438 could use some edits to mention extension.path.resolver, too.
Do we need a new title here, too?
Thanks!
-Derek
Comment #229
kim.pepperI gave the change record a few teaks to emphasise
Drupal\Core\Extension\ExtensionPathResolverComment #230
dwwNice, thanks. Did a few more little formatting edits. Removing the tag.
Comment #231
alexpottThis is why the Ajax test needs changing... in drupal_get_filename() we catch InvalidArgumentException and covert it to a warning. The new code is not doing this. PHP will continue processing after the warning. I think we need to update the CR with this information. Also I think we need to have a good think about whether this change will break sites that were previously working even though they have missing module code. Also the API changes section of the issue summary doesn't cover this change. In some ways I think we might have to consider deprecating the warning behaviour and only make this part of the change in Drupal 10. Maybe one course of action would be to re-implement this warning functionality in the new extension path resolver service (and deprecate it for Drupal 10) and then use this service in any place where this might matter.
So review points:
Maybe we should document that this will thrown an exception when the extension is not found.
Can use scalar typehints and return typehints.
The exception is not documented with an @throws
Comment #232
kim.pepperAddressed feedback in #231 I'm declaring these methods throw
\Drupal\Core\Extension\Exception\UnknownExtensionExceptionif the extension is not found, which I think is more accurate than\InvalidArgumentExceptionI've updated the API Changes section in the summary and the change record.
Comment #233
alexpottWell there is a bit of #231 that's not addressed
This one is tricky. But I think we need to go through the code and see where this might cause an issue. We know it might in the assert resolver because of #214.45
Comment #234
kim.pepperAdds a deprecation warning if extension type not found, and a legacy test to test the deprecation works.
Comment #235
alexpott@kim.pepper I don't think #234 addresses #233.
The issue is that the code is no longer behaving the same way for:
In HEAD, I think this results in this code in drupal_get_filename()
triggering.
The change in #234 is covering the following code in drupal_get_filename()
Thinking about this situation some more.
Comment #236
kim.pepperI (incorrectly) assumed triggering a deprecation would have the same effect.
I took out throwing an exception in #234 and triggered a deprecation warning?
I had a look through AssetResolver but couldn't workout where it calls
ExtensionPathResolverin order to catch an exception in the right place. 🤔Comment #238
andypostQueued for 9.2, maybe apply for merge requests for this issue?
The patch is ~150kb - it needs rebase time to time
Comment #239
kapilv commentedComment #240
kapilv commentedHear an updated patch.
Comment #241
daffie commentedThe patch fails the testbot.
Comment #242
anmolgoyal74 commentedIn 240, new files were not added to the patch.
Added those and updated CS messages.
Comment #244
cyb_tachyon commentedAdded #3179546: Tag ExtensionList services with extension.list
This will allow us to reduce the amount of repeated code in this patch.
Comment #245
kim.pepperRe: #244 should be a follow up.
Comment #246
kim.pepperWasn't sure what was going on in #242 so did a reroll of #234 replacing some new uses of drupal_get_path().
Comment #247
kim.pepperComment #249
kim.pepperFixes deprecation annotations.
Comment #250
kim.pepperRounding back to the issue raised by @alexpott in #235. I *think* this should restore the original behaviour.
Comment #251
andypostDeprecated in 9.2 please update now(
Comment #252
kim.pepperUpdated deprecation notices to 9.2. Let's hope we don't need to change it to 9.3!
Still puzzled by the AjaxTest fail. Could use some help with that.
Comment #254
alexpottHere's a fix for the AjaxTest - #250 copied the wrong catch...
Comment #255
paulocsWe must also update the CR.
I'll do it.
Comment #256
paulocsCR was updated.
Moving to RTBC as I did not find any place where drupal_get_path() and drupal_get_filename() are called.
Deprecation tests looks good.
Comment #257
mondrakeComment #258
kim.pepperRe-roll of #254
Comment #260
kim.pepperReplace usage in core/modules/migrate_drupal_ui/tests/src/Functional/d7/DoubleSlashTest.php
Comment #262
spokjeI think this is what you were after?
Comment #263
daffie commentedThere is no deprecation message test for this deprecation.
There is no deprecation message test for this deprecation.
Nitpick: This empty line can be removed.
Why
trigger_errorinstead of@trigger_errorlike we do everywhere else.Can we do this on 2 lines for improved readability.
In core we usually do
if (!$this->moduleList) {This change does not belong in this patch. Out of scope.
Why is this test removed?
This change is out of scope for this issue.
Nitpick: This empty does not need to be removed.
This change is out of scope for this issue.
This change can be removed. See: #2908079: Move some of the bootstrap.inc PHP-related constants to \Drupal and deprecate the old versions
Comment #264
daffie commentedThe CR was updated by @kim.pepper on 3 july.
Comment #265
paulocsI'll work on it
Comment #266
paulocsSorry, I will have to unassigned the issue. Tomorrow morning I can work on it and add a patch for it.
Comment #267
paulocsNow I'll work on it.
Comment #268
paulocsAbout 263.1 and 263.1, the patch removes the function drupalGetPath() as it is a protected function and it is not used any more in LibraryDiscoveryParser.php and in ConfigInstaller.php
I didn't addressed 263.4 because I'm not sure if it is on scope of that issue.
I did the rest of the changes suggested on comment #263.
Please review.
Comment #269
daffie commentedFor #263.4: I did a code search and we are using both in core. So, both are good.
Just 1 point left for me:
Can we move these tests over to a new ExtensionPathResolverTest.
Comment #270
spokjeIgnore, had an typo in a function name.
Comment #271
spokje#269
Would this do?
Comment #272
spokjeI've seem to have inherited a coding standards message
I'm pretty sure this can be fixed on commit? Seems a bit of TestBotTime-waste to run a full core test on an empty doc comment line...
Comment #273
daffie commentedUpdated the IS and the CR. with the API additions for the class
\Drupal\ckeditor\CKEditorPluginBase.Comment #274
daffie commentedAll code changes look good to me.
The patch does what IS says it should do.
The deprecations are mentioned in the CR.
The API additions are mentioned in the CR.
Both deprecations have testing for them.
All usages of the deprecated function have been removed with the exception of the deprecated functions themselfs and deprecation testing.
The protected methods
\Drupal\Core\Asset\LibraryDiscoveryParser::drupalGetPath()and\Drupal\Core\Config\ConfigInstaller::drupalGetPath()have been removed.When I do a code search on contrib modules for
drupalGetPath(, then all the occurrences that I found have their own implementations for that method. See: http://grep.xnddx.ru/search?text=drupalGetPath%28&filename=The protected method
\Drupal\Core\Theme\Registry::getPath()has been deprecated. The method now triggers a deprecation message. The class has been tagged@internaland no deprecation message test has been added.For me the patch is RTBC.
Comment #275
paulocsNice!
Comment #276
alexpottSo we removed ::drupalGetPath() because there is no testing. That's not right. We should leave the deprecations in as per #262. These one liner wrappers do not need testing an eyeball can see that these are fine. We don't know what is in custom and there is no reason to break it when we can issue a deprecation. We can remove private functions and these functions should have been created as private but they're not.
Comment #277
daffie commentedComment #279
berdirLots of conflicts with file_create_url()/batch builder and assert changes.
Also updated all deprecation messages. And restored 2 drupalGetPath() methods. One that is removed is in an inlined test class, I would say we can safely assume that to be internal and not needing to deprecate ;)
Comment #280
berdirFixed CS issues.
Comment #281
berdirNote on this:
$original_content is an unused variable, #3193163: Deprecate AssertLegacyTrait::verbose and remove its usage removed the verbose() call of it but did not remove the variable. So I just removed the line.
Comment #283
berdirFixing those test fails.
Comment #284
andypostLooks great except few unrelated changes
out of scope
Comment #285
daffie commentedPatch looks good. Just 2 nitpicks for me:
These new test methods need a docblock.
This is a special case. Can we also add a test with a regular module.
Comment #286
andypostFix for #284/285
Comment #287
andypostFix CS
Comment #288
daffie commentedAll code changes are good enough for me.
The IS and the CR are in order.
There is enough testing.
For me it is RTBC.
Removing the release manager review tag, because this is not going into 8.9 anymore.
Comment #289
alexpottThese methods really should not be on the public API of these plugins. Can they be protected instead of public?
Is there a follow up to inject the service?
$this->getModulePath()
Comment #290
dhirendra.mishra commentedLet me work on this.....
Comment #291
dhirendra.mishra commentedPlease review my Files below
Comment #292
alexpottAdding a constructor can cause issues for anything extending it. Fortunately this is not happening in contrib - http://grep.xnddx.ru/search?text=DrupalImageCaption&filename=
This is not necessary - tests have a method getModulePath() that can be used here. It's added by a trait in this issue.
Comment #293
dhirendra.mishra commentedPlease find the updated one from #292 comment.
Comment #294
dhirendra.mishra commentedPls ignore above one and find below files as per #292 comment
Comment #296
andypostAttempt to fix tests, the
DrupalImageCaptionplugin could use injection so it needsContainerFactoryPluginInterfaceand I see no reason to add protected method there (this plugin is not inherited fromCKEditorPluginBase- needs follow-up?)Also added type-hints to the methods and updated ckeditor's test plugins
Comment #297
andypostFixed test plugins to use proper DI, people often copy code from tests so better to use clean approach
Comment #298
andypostFix CS
Comment #299
daffie commentedThe points of @alexpott have been addressed.
Back to RTBC.
Comment #300
alexpottThese changes make me uneasy. It feels odd that all these plugins need a reference to the entire module extension list. I'm pondering if we should consider making the module paths available as container parameters. We already have the container.modules parameter. We could even only add the parameters that used so we don't have to add all module paths to the container.
We don't need the extension list theme here...
We can do
$this->themeHandler->getTheme($theme)->getPath().One less deprecation and less change.
Same here - this can be
$this->moduleHandler->getModule('update')->getPath()and then we don't need the extension list.Comment #301
berdir1. Isn't this just making the existing dependencies explicit? Not quite sure how the container parameter thing would work exactly, would we define a parameter for every enabled module, then you'd inject %module_path.ckeditor% into your plugin? We've been discussing whether we need/want #1308152: Add stream wrappers to access .json files in extensions or not for 10 years now. That would be the alternative, then you can just write "module://ckeditor/js/plugins/drupalimage/icons/drupalimage.png". But postponing this on a 10 year old issue doesn't sound like fun.
Comment #302
berdir1. Yeah, I'm not convinced that this would make things simpler. Yeah, it's quite a dependency to have, but from a performance standpoint, anything that even just invokes a hook or so is going to instantiate that anyway and the service _is_ based on the container.modules information. Accessing that directly would be quite awkward as we actually store the path to the .info.yml file, not the module directory, and you can't access something in an array directly, so you'd need to write it out:
dirname($container->getParameter('container.modules'])['ckeditor']['pathname']).And you would need to inject the whole modules array, I doubt that's any faster than injecting the service?
To allow for something like
%module_list.ckeditor%, we'd need to duplicate that information in the container into a top-level parameter for every module.Updated the two classes for 2 and 3.
Comment #303
daffie commentedThe point #300.1 has been answered by @Berdir in #301 and #302.
The points #300.2 and #300.3 from @alexpott have been fixed.
Back to RTBC.
Comment #304
alexpott@Berdir what I'm suggesting is a compiler pass that would look for
%module.path.ckeditor%and replace this with the correct string or set up the container param so it'll work. So we only get the necessary paths and then in order to use this service there's no cache get / state get... because it's just taking a string. In a future world maybe we could avoid caching the paths at all and rely on the container for having this info - and then only store this in state to prevent file system scans on cache clear. Given that the module list is already there this does not feel like a big stretch. However, I do think that we could punt this to a follow-up. Rather than try to achieve this here, created a follow-up #3223760: Get extension paths from container and not cacheCommitted 1110b04 and pushed to 9.3.x. Thanks!