Problem/Motivation

Not all installed extensions, and their respective namespaces, are properly registered within the container.

This issue is, primarily, relevant to themes and theme engines as modules and profiles are currently hardcoded.

Certain requests only bootstrap so far. If a theme provides a static callback (in the form of #pre_render, #ajax, or #lazy_builder) to a method in one of its classes, this lives in a render array which can become cached. Because of this caching, the entire theme system does not necessarily need to be loaded just to execute a callback. Thus, the namespaces are never registered and the classes cannot be found.

It is a common misnomer that extension namespaces are registered on install.

Currently, the ThemeExtensionList is what instantiates and registers all installed theme namespaces.

DrupalKernel::compileContainer automatically registers module namespaces, simply because they can provide services (since themes cannot). However, these namespaces are done after the service providers have been determined and effectively cut all other installed extension types out of being properly registered.

There are also no significant tests to ensure that these namespaces are registered properly and whether or not they would in fact break contrib.

Proposed resolution

Register all installed extensions and their namespaces as separate container parameters:

  • container.namespaces.core - Drupal specific ['Core', 'Component'] namespaces.
  • container.namespaces.module
  • container.namespaces.profile
  • container.namespaces.theme
  • container.namespaces.theme_engine
  • container.namespaces.all - all of the above namespaces

For BC reasons, the existing container.namespaces parameter/service needs to be aliased to the following namespaces:

  • container.namespaces.core
  • container.namespaces.module
  • container.namespaces.profile

And then deprecate the use of container.namespaces when #2954562: [PP-2] Create provider based plugin managers makes it way in to allow plugin managers to choose which namespaces to allow.

Remaining tasks

  • Create tests
  • Create a patch

User interface changes

None

API changes

Data model changes

None

CommentFileSizeAuthor
#75 2941757_75.patch7.11 KBmile23
#63 2941757-63.patch89.94 KBmarkhalliwell
#63 interdiff-2941757-61-63.txt599 bytesmarkhalliwell
#61 2941757-61.patch89.96 KBmarkhalliwell
#61 interdiff-2941757-60-61.txt30.93 KBmarkhalliwell
#61 2941757-61-tests-only.patch6.59 KBmarkhalliwell
#60 2941757-60.patch72.66 KBmarkhalliwell
#60 interdiff-2941757-58-60.txt23.46 KBmarkhalliwell
#58 2941757-58.patch55.42 KBmarkhalliwell
#58 interdiff-2941757-56-58.txt1.54 KBmarkhalliwell
#56 2941757-56.patch55.03 KBmarkhalliwell
#56 interdiff-2941757-54-56.txt2.52 KBmarkhalliwell
#54 2941757-54.patch54.71 KBmarkhalliwell
#54 interdiff-2941757-52-54.txt19.88 KBmarkhalliwell
#52 2941757-52.patch55 KBmarkhalliwell
#52 interdiff-2941757-50-52.txt4.51 KBmarkhalliwell
#50 2941757-50.patch53.57 KBmarkhalliwell
#50 interdiff-2941757-47-50.txt11.03 KBmarkhalliwell
#47 2941757-47.patch51.4 KBmarkhalliwell
#47 interdiff-2941757-45-47.txt28.9 KBmarkhalliwell
#45 2941757-45.patch45.62 KBmarkhalliwell
#45 interdiff-2941757-41-45.txt3.18 KBmarkhalliwell
#41 2941757-41.patch43.86 KBmarkhalliwell
#41 interdiff-2941757-40-41.txt756 bytesmarkhalliwell
#40 2941757-40.patch43.66 KBmarkhalliwell
#40 interdiff-2941757-38-40.txt747 bytesmarkhalliwell
#38 2941757-38.patch43.66 KBmarkhalliwell
#38 interdiff-2941757-36-38.txt1.8 KBmarkhalliwell
#36 2941757-36.patch43.69 KBmarkhalliwell
#36 interdiff-2941757-34-36.txt915 bytesmarkhalliwell
#34 2941757-34.patch43.68 KBmarkhalliwell
#34 interdiff-2941757-31-34.txt10.95 KBmarkhalliwell
#31 2941757-31.patch42.44 KBmarkhalliwell
#31 interdiff-2941757-29-31.txt3.41 KBmarkhalliwell
#29 2941757-29.patch41.96 KBmarkhalliwell
#29 interdiff-2941757-27-29.txt761 bytesmarkhalliwell
#27 2941757-27.patch41.9 KBmarkhalliwell

Issue fork drupal-2941757

Command icon 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

markcarver created an issue. See original summary.

markhalliwell’s picture

Title: Properly register installed extension namespaces in container » Extension System, Part III: Properly register installed extension namespaces in container
almaudoh’s picture

It might be better if #2659940: Extension System, Part III: ThemeExtensionList and ThemeEngineExtensionList is committed first so we would have a clean ThemeExtensionList API to use in fixing this issue.

markhalliwell’s picture

Title: Extension System, Part III: Properly register installed extension namespaces in container » [PP-1] Extension System, Part III: Properly register installed extension namespaces in container
Status: Active » Postponed
Parent issue: » #2659940: Extension System, Part III: ThemeExtensionList and ThemeEngineExtensionList
Related issues: -#2659940: Extension System, Part III: ThemeExtensionList and ThemeEngineExtensionList

Sure, that makes sense.

markhalliwell’s picture

Assigned: Unassigned » markhalliwell

Hopefully #2659940: Extension System, Part III: ThemeExtensionList and ThemeEngineExtensionList will make its way in soon and then I'll start tackling this.

markhalliwell’s picture

Issue summary: View changes
markhalliwell’s picture

Issue summary: View changes
markhalliwell’s picture

Issue summary: View changes
markhalliwell’s picture

Issue summary: View changes
markhalliwell’s picture

Issue summary: View changes
markhalliwell’s picture

Issue summary: View changes
dawehner’s picture

DrupalKernel::compileContainer automatically registers module namespaces, simply because can provide services (not themes). But these namespaces are done after the service providers have been determined and effectively cut all other installed extension types out of being properly registered.

Well, one complexity we always need to keep in mind is the following. Depending on the current request you can have different kind of active themes. Given that we cannot just make the namespaces available on boot-time. Code might do things conditionally whether a specific theme is loaded or not.
This point is also the reason why themes shouldn't have a .services.yml file

I'm curios, what blocks us from expanding \Drupal\Core\Theme\ThemeInitialization::loadActiveTheme to register the theme and all its parents namespaces?

markhalliwell’s picture

Depending on the current request you can have different kind of active themes.

Correct, but this is becoming less and less of an “issue” due to the OO advancements we’re implementing.

Given that we cannot just make the namespaces available on boot-time.

Yes we can.

Code might do things conditionally whether a specific theme is loaded or not.

This issue isn’t about actually loading any classes. That is well out of scope. It’s about just ensuring that their namespaces are registered in the autoloader so, when they are needed, they can be found.

This point is also the reason why themes shouldn't have a .services.yml file

No, the reason themes shouldn’t have services is because then they’d just be modules (and because themes weren’t installable before).

I'm curios, what blocks us from expanding \Drupal\Core\Theme\ThemeInitialization::loadActiveTheme to register the theme and all its parents namespaces?

Because, as the IS states, this is too late in the process and, quite frankly, overkill. We shouldn’t have to “boot up the entire theme system” just so namespaces can be registered.

The main reason this needs to be done in the kernel is because certain requests only bootstrap so far. If a theme provides a static #pre_render, #ajax, or #lazy_builder callback to a method in one of its classes, this lives in a render array which can become cached. Because of this caching, the entire theme system does not neccessarily need to be loaded just to execute a callback. Thus, the namespaces are never registered and the classes cannot be found.

dawehner’s picture

The main reason this needs to be done in the kernel is because certain requests only bootstrap so far. If a theme provides a static #pre_render, #ajax, or #lazy_builder callback to a method in one of its classes, this lives in a render array which can become cached. Because of this caching, the entire theme system does not neccessarily need to be loaded just to execute a callback. Thus, the namespaces are never registered and the classes cannot be found.

Please put that into the issue summary so everyone can quickly see the problem.

markhalliwell’s picture

markhalliwell’s picture

Issue summary: View changes

Please put that into the issue summary so everyone can quickly see the problem.

Pretty sure it is implied, but I suppose it needs to be stated.

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

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

andypost’s picture

Title: [PP-1] Extension System, Part III: Properly register installed extension namespaces in container » Extension System, Part III: Properly register installed extension namespaces in container
Status: Postponed » Active

Unblocked

mile23’s picture

OK, so based on #14, the problem is that we have a cached render array, and it has callbacks to class methods in the theme extension that are not available because they are not autoloadable.

So we have to somehow autoload the theme(s) to which the cache belongs so that it can render to HTML, but we also want to remain performant by not bootstrapping resources we don't need for this to occur.

Since the proposed resolution suggests making a service called container.namespaces.theme, let's just assume that we could somehow enable autoloading for all enabled themes early in the boot process. That process entails scanning for extensions and then calling addPsr4() on the autoloader.

In that case, we don't need those services. We need to discover the themes at some layer similar to DrupalKernel::handle() just after intializeSettings(). This lets the autoloader find classes that get used by the theme. I'm not sure if ExtensionDiscovery is suitable for this, because it might need some services. But assuming it is suitable, since we know where the src/ directory is within extensions, we can then just tell the autoloader per theme and then we're done.

We could also do this for all enabled extensions, since we're touching the filesystem already.

In this case the issue should rescope to: Register autoloading for extensions early in boot process.

Note that if it were our policy to require the use of Composer to add extensions, this issue would not exist. The autoload mapping would always be present in autoload.php, because we'd register it so early in the boot process it happened during deploy. :-)

markhalliwell’s picture

So we have to somehow autoload the theme(s) to which the cache belongs so that it can render to HTML, but we also want to remain performant by not bootstrapping resources we don't need for this to occur.

No. This issue isn't about bootstrapping/loading anything, let alone the theme system (that's way out of scope).

In this case the issue should rescope to: Register autoloading for extensions early in boot process.

That's what this issue already is: "Properly register installed extension namespaces in container"

markhalliwell’s picture

Title: Extension System, Part III: Properly register installed extension namespaces in container » Extension System, Part IV: Properly register all installed extensions/namespaces in container
Issue summary: View changes

Cleaned up IS to remove verbose project specific info.

markhalliwell’s picture

Need to look at #2021959-33: Refactor module handling responsibilities out of DrupalKernel to see what can be salvaged from that issue/patch (similar goal to this issue).

markhalliwell’s picture

Title: Extension System, Part IV: Properly register all installed extensions/namespaces in container » Extension System, Part IV: Properly register all installed extensions/namespaces in container (ExtensionHandler)

This is a catch-22.

To get ExtensionHandler working requires installed extensions registered with the container, to get registered extensions requires ExtensionList/ExtensionHandler.

Both this issue and #3023131: [PP-1] Extension System, Part IV: ExtensionHandler and ExtensionHandlerInterface must happen at the same time.

markhalliwell’s picture

Issue summary: View changes
markhalliwell’s picture

Title: Extension System, Part IV: Properly register all installed extensions/namespaces in container (ExtensionHandler) » Extension System, Part IV: Properly register all installed extensions/namespaces in container

Turns out we can do this is steps after all.

markhalliwell’s picture

Status: Active » Needs review
StatusFileSize
new41.9 KB

Ok... an initial stab at this.

Doesn't include any new tests yet... but I think it should pass all existing tests (had to modify a couple existing ones slightly).

Status: Needs review » Needs work

The last submitted patch, 27: 2941757-27.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

markhalliwell’s picture

Status: Needs work » Needs review
StatusFileSize
new761 bytes
new41.96 KB

Guess the installed extensions instance really needs to be added in the constructor. Had some worries about the class loader not yet being initialized (properly), but it seems to be working ok.

Status: Needs review » Needs work

The last submitted patch, 29: 2941757-29.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

markhalliwell’s picture

Status: Needs work » Needs review
StatusFileSize
new3.41 KB
new42.44 KB

Ok... let's try this.

markhalliwell’s picture

Issue summary: View changes

Status: Needs review » Needs work

The last submitted patch, 31: 2941757-31.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

markhalliwell’s picture

Status: Needs work » Needs review
StatusFileSize
new10.95 KB
new43.68 KB

Status: Needs review » Needs work

The last submitted patch, 34: 2941757-34.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

markhalliwell’s picture

Status: Needs work » Needs review
StatusFileSize
new915 bytes
new43.69 KB

Sigh...

Status: Needs review » Needs work

The last submitted patch, 36: 2941757-36.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

markhalliwell’s picture

Status: Needs work » Needs review
StatusFileSize
new1.8 KB
new43.66 KB

Almost there (I think)...

Status: Needs review » Needs work

The last submitted patch, 38: 2941757-38.patch, failed testing. View results

markhalliwell’s picture

Status: Needs work » Needs review
StatusFileSize
new747 bytes
new43.66 KB
markhalliwell’s picture

StatusFileSize
new756 bytes
new43.86 KB

Ok, I think this is finally it. At least it should fix the majority of all the "major" test failures. There may still be a few left.

The last submitted patch, 40: 2941757-40.patch, failed testing. View results

Status: Needs review » Needs work

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

markhalliwell’s picture

Assigned: markhalliwell » Unassigned

Awesome! There's only a few left. Maybe someone else wants to take a look and see what I may have missed.

markhalliwell’s picture

Status: Needs work » Needs review
StatusFileSize
new3.18 KB
new45.62 KB

Status: Needs review » Needs work

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

markhalliwell’s picture

Status: Needs work » Needs review
StatusFileSize
new28.9 KB
new51.4 KB

Had to do a lot of local debugging to sort through some of this mess. Just FYI, the kernel/extensions are extremely fragile... hence why this is a great first step. Ultimately I think this should just be a wrapper around ExtensionList instances, but we're not there yet.

Anyway, I'm hoping this fixes the remaining tests... 🤞

Status: Needs review » Needs work

The last submitted patch, 47: 2941757-47.patch, failed testing. View results

andypost’s picture

Nice step ahead! some nits from skiming

  1. +++ b/core/lib/Drupal/Core/DrupalKernel.php
    @@ -733,58 +725,38 @@ public function prepareLegacyRequest(Request $request) {
    +   * Implements Drupal\Core\DrupalKernelInterface::updateModules().
    ...
    +   * @todo Replace with "drupal.update.installed_extensions" event.
    +   * @see https://www.drupal.org/project/drupal/issues/3023131
    ...
    +  public function updateModules(array $module_list, array $module_filenames = []) {
    +    $installed = $this->getInstalledExtensions();
    

    if this API going to be public makes sense to change arguments and describe them

  2. +++ b/core/lib/Drupal/Core/Installer/InstallerKernel.php
    @@ -13,10 +13,17 @@ class InstallerKernel extends DrupalKernel {
       protected function initializeContainer() {
    +    global $install_state;
    

    would be great to get rid of it

markhalliwell’s picture

Status: Needs work » Needs review
StatusFileSize
new11.03 KB
new53.57 KB

#49.1: This method already exists and is public. I really don't like this method and want to deprecate it and replace it with something better, but I think that may be out of scope for now. My goal is to simply get this working.

#49.2: Same as above, this already existed. I'm not entirely sure this is the most appropriate issue to tackle removing this.

---

On a side note: I've been doing even more local testing to try and figure out what's going on with the last remaining failures.

The best I can guess is that somehow normal procedural functions/constants (that aren't namespaced) can't be found.

In fact, I did a little searching and found #1912474: Unable to pre-populate db in settings.php.

That issue describes almost verbatim the same error messages I'm running into here now.

First I get:

Exception: Warning: Use of undefined constant USERNAME_MAX_LENGTH - assumed 'USERNAME_MAX_LENGTH' (this will throw an Error in a future version of PHP)
Drupal\Core\Installer\Form\SiteConfigureForm->buildForm()() (Line: 178)

Found #3015752: Properly deprecate USERNAME_MAX_LENGTH and USER_REGISTER_* constants, but then I run into:

Warning: call_user_func_array() expects parameter 1 to be a valid callback, function 'user_form_process_password_confirm' not found or invalid function name

That issue was closed as a dup of #2155701: Installer starts with fatal error/exception "table 'semaphore' not found" if settings.php contains $databases already, but I fail to see what exactly it did to rectify the warnings.

Could use some help here if someone is more familiar with \Drupal\Core\Installer\InstallerKernel and \Drupal\Core\Test\TestRunnerKernel.

---

Attaching patch of where I left off of solving a minor bug with cross profile modules and duplicate namespace registration.

Status: Needs review » Needs work

The last submitted patch, 50: 2941757-50.patch, failed testing. View results

markhalliwell’s picture

Status: Needs work » Needs review
StatusFileSize
new4.51 KB
new55 KB

It seems any pre-emptive extension setting must happen in initializeContainer.

I still cannot, for the life of me, figure out the errors in #50.

Any direction would be helpful.

---

edit: this includes a change/addition of InstallerKernel::isConfigEmpty since it really shouldn't be changing the scope of getConfigStorage to public when it's just used in one place.

Status: Needs review » Needs work

The last submitted patch, 52: 2941757-52.patch, failed testing. View results

markhalliwell’s picture

Status: Needs work » Needs review
StatusFileSize
new19.88 KB
new54.71 KB

Ok, I think I may actually have figured out the issues; at least I was able to get \Drupal\FunctionalTests\Installer\StandardInstallerTest::testInstaller passing locally anyway.

+++ b/core/lib/Drupal/Core/Extension/InstalledExtensions.php
@@ -0,0 +1,676 @@
+      $profiles = array_intersect_key($allProfiles, array_flip($this->getConfigExtensions()));

I think this was the main issue. The original code intersected $this->module_list, which is the currently set "install" list... not what is stored in config.

+++ b/core/lib/Drupal/Core/Extension/InstalledExtensions.php
@@ -0,0 +1,676 @@
+    // If installed extensions is not yet set, parse it from config.
+    if ($empty && ($extensions = $this->getConfigExtensions())) {
+      $this->add($extensions);
+    }

I also moved said "initial list" from config back to DrupalKernel, which I think had another small part in the failures.

I'll get started on the new tests if/when this passes the existing ones (with some minor modifications).

🤞

Status: Needs review » Needs work

The last submitted patch, 54: 2941757-54.patch, failed testing. View results

markhalliwell’s picture

Status: Needs work » Needs review
StatusFileSize
new2.52 KB
new55.03 KB

Awesome! This patch should now pass 😁

Status: Needs review » Needs work

The last submitted patch, 56: 2941757-56.patch, failed testing. View results

markhalliwell’s picture

Status: Needs work » Needs review
StatusFileSize
new1.54 KB
new55.42 KB

I really hate run-tests.sh...

markhalliwell’s picture

w00t!!!! 🎉

markhalliwell’s picture

Assigned: Unassigned » markhalliwell
Issue tags: +Extension system
StatusFileSize
new23.46 KB
new72.66 KB

Here are the initial tests. Still needs a bit more work so I'll reassign this issue to myself as I'll likely be working on them this week.

markhalliwell’s picture

Assigned: markhalliwell » Unassigned
Issue tags: +Needs framework manager review
StatusFileSize
new6.59 KB
new30.93 KB
new89.96 KB

Ok, this should complete the necessary tests. Patch is officially "done", barring review(s).

Status: Needs review » Needs work

The last submitted patch, 61: 2941757-61.patch, failed testing. View results

markhalliwell’s picture

Status: Needs work » Needs review
StatusFileSize
new599 bytes
new89.94 KB

Ugh, c&p fail...

The last submitted patch, 61: 2941757-61-tests-only.patch, failed testing. View results

dawehner’s picture

May I ask a question which might be obvious to answer. Reading up the issue summary it seems to have an assumption that themes need to have complex logic, written in an OOP style.
I wonder though why themes can't use a corresponding module instead and put the logic in there.

Themes are this weird system as they are loaded dynamically. Putting them into the container might create the assumption they should be autoloadable at any given point in time, but as you know, that's not true. If they aren't the active theme, they cannot be loaded.

+++ b/core/lib/Drupal/Core/Extension/InstalledExtensions.php
@@ -0,0 +1,596 @@
+class InstalledExtensions {

I'm confused about this. Isn't that the same as the Extension list conceptually?

markhalliwell’s picture

Reading up the issue summary it seems to have an assumption that themes need to have complex logic, written in an OOP style.

I don't really see how describing a legitimate bug is a generalization/assumption for "all themes". In fact, the IS describes a very advanced use case where callbacks are cached in a render array. Advanced or not, it's still an issue.

Given that the overall goal is to move everything to OO, themes should be no exception.

Themes don't "need to have" complex logic, but when they do (especially when dealing with an external framework like Bootstrap)... the system should be able to handle it.

I wonder though why themes can't use a corresponding module instead and put the logic in there.

#474684: Allow themes to declare dependencies on modules

I'm still baffled by this way of thinking though. If this were the case, why have themes at all? Why couldn't we just put everything in a module?

The average [sub-]theme will likely not be as complex, but base themes like Drupal Bootstrap are.

Also, what type of "logic" we're referring to here? Complex or not, presentation logic should still live within a theme, not a module. This presentation logic can still be cached in a render array referencing a theme class callback.

Ultimately, I'd like to see #2869859: [PP-1] Refactor theme hooks/registry into plugin managers make its way in which would allow [base-]themes the ability to properly intercept the entire discovery (registry) and rendering process without the need of any "additional module" or antiquated theme special "hook/alter".

Just because things have been the way they have been for so long doesn't mean it has to stay that way.

Themes are this weird system as they are loaded dynamically. Putting them into the container might create the assumption they should be autoloadable at any given point in time, but as you know, that's not true. If they aren't the active theme, they cannot be loaded.

That's an extremely heavy burden to put on the kernel.

Does the kernel know which blocks should be added to a page?

No. This kind of logic should be left to whatever mechanism is in place that is responsible for determining this kind of logic.

We don't know when or where a theme may be used (at this step), but we do know that it is installed.

Installed extension namespaces should be registered with the autoloader, plain and simple.

It's up to other subsystems (i.e. elements, render api, render cache, theme registry, etc.) to ensure that if their logic depends on which "active" theme that they build necessary caches based on said "active" theme; which they already do and we have tests for.

I'm confused about this [InstalledExtensions]. Isn't that the same as the Extension list conceptually?

Yes/no.

I perhaps should have explained a little more in #24 and #26.

This code is literally just putting what was already in DrupalKernel into a separate service/class.

Currently ExtensionList has a dependency on ModuleHandler. There are also a lot of other services ExtensionList currently relies on.

I originally went down the path of "let's just use ExtensionList", but given the required dependencies and circular references it would create, I decided to create a separate encapsulating service/class was a needed first step in this process.

That is why I marked InstalledExtensions as @internal. Ultimately, I don't see this class sticking around. We'll probably remove it in #3023131: [PP-1] Extension System, Part IV: ExtensionHandler and ExtensionHandlerInterface or if we don't clean up the ExtensionList during that issue, an issue shortly after that.

I didn't want to create a massive patch that no one could review. That's why I created InstalledExtensions as a way to allow us to make this change and introduce tests without breaking all of core (which you can see above, is very easy to do at this level).

After speaking with @alexpott in slack, I think that ultimately this entire process in the kernel will become a ServiceProvider decoration of the container and we can just let the various ExtensionList services handle it.

Until we decouple ExtensionList from ModuleHandler though, this step is needed.

markhalliwell’s picture

Themes are this weird system as they are loaded dynamically. Putting them into the container might create the assumption they should be autoloadable at any given point in time, but as you know, that's not true. If they aren't the active theme, they cannot be loaded.

+++ b/core/lib/Drupal/Core/Extension/ThemeHandler.php
@@ -113,11 +113,6 @@ public function listInfo() {
   public function addTheme(Extension $theme) {
-    // Register the namespaces of installed themes.
-    // @todo Implement proper theme registration
-    // https://www.drupal.org/project/drupal/issues/2941757
-    \Drupal::service('class_loader')->addPsr4('Drupal\\' . $theme->getName() . '\\', $this->root . '/' . $theme->getPath() . '/src');

This was already registering all installed themes; not just the "active" theme. However, this is too late in the process and requires the theme system to be initialized which may not happen during a slimmed down bootstrap (hence this issue).

markhalliwell’s picture

Bump...

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.

psf_’s picture

I applied the #63 patch trying to solve the issue https://www.drupal.org/project/jsonapi_extras/issues/3045087 but it breaks all the site, before that the issue #3045087 breaks only with clear cache and a few more actions.

The issue #3045087 is that the class FieldItemNormalizerImpostor it's not found in some installations. That class live in jsonapi_extras module but have jsonapi namespace. I have two cloned servers, in one work and in the other not, I think that maybe for different update process steps.

psf_’s picture

markhalliwell’s picture

That issue is a byproduct of that module doing some weird namespacing hackery (that doesn't follow PSR-4 btw):
https://git.drupalcode.org/project/jsonapi_extras/blob/8.x-3.x/src/Jsona...

It doesn't really have anything to do with this issue.

markhalliwell’s picture

markhalliwell’s picture

Bump... again

mile23’s picture

Title: Extension System, Part IV: Properly register all installed extensions/namespaces in container » Extension System, Part IV: Properly register all installed extensions/namespaces during container generation
StatusFileSize
new7.11 KB

Bump duly noted. :-)

It occurs to me that this discovery stuff is similar to what’s needed for #2242947: Integrate Symfony Console component to natively support command line operations, and so let’s look at it here, too.

Reply to @dawehner in #66:

Installed extension namespaces should be registered with the autoloader, plain and simple.

OK, so the goal is to autoload extensions that are enabled, not autoload extensions that are not enabled, and do it all in one pass so that the autoloader can find anything that would be needed during rendering without special-case loading for themes etc.

This means we need a bunch of services, such as all the dependencies of config (namely a backend, probably a database).

So since all of these dependencies are services, we can’t add the extension namespaces to the class loader until after the container has been compiled. We don’t want to instantiate any services until after that phase. So, you know… never mind what I said in #20. :-)

We already have a class_loader synthetic service. This service is used throughout core, and is just the classloader object. This would be a great place to implement our own superclass of ClassLoader, which knows how to look for extension namespaces. However, we don’t have a way to generate that. Composer makes this class loader for us, and we’re supposed to add prefixes and that's it.

So we can make a factory service. This service consumes all the services necessary to find autoload info within extensions, and then adds that info to the existing classloader. Let’s call it class_loader.factory.

The next question is: How do we inject the classloader into the factory object? In this regard, we must look at CoreServiceProvider. We must inject the classloader into CoreServiceProvider, which then injects it into a compile pass object.

The compile pass object ExtensionNamespaceCompilerPass can then define the class_loader.factory service, using the injected classloader object, as well as whatever other service references we need in order to add the extension autoloading info.

This factory is the ExtensionNamespaceClassLoaderFactory class.

We change the class_loader service so that it is not synthetic, and instead generated by our factory.

Then, finally, when some code somewhere dereferences the class_loader service, this factory object and the associated services will be used to add all the PSR-4 or whatever from all the extensions.

I experimented with the container configurator pattern and for that you still need an existing service to be configured. In our case, that means doing all the same stuff to make sure the class loader object is injected into the service that’s created, so it would be essentially this patch plus a configurator object.

This patch is a proof-of-concept that puts all this class loading infrastructure in place, and should behave normally. The only cheating it does is to force DrupalKernel::allowDumping to always be FALSE. This makes for a longer run time, but if the concept is sound and there is some consensus, we can begin to work on teasing out the usages that break this. It’s probably something simple that I managed to overlook.

This patch does not solve the problem of loading the extensions, but you can see where you should put that code in ExtensionNamespaceClassLoaderFactory.

Different approach, so no interdiff.

mile23’s picture

PHP Fatal error: Uncaught TypeError: Argument 1 passed to Drupal\Core\CoreServiceProvider::__construct() must be an instance of Composer\Autoload\ClassLoader, instance of Symfony\Component\ClassLoader\ApcClassLoader given, called in /var/www/html/core/lib/Drupal/Core/DrupalKernel.php on line 619 and defined in /var/www/html/core/lib/Drupal/Core/CoreServiceProvider.php:54
Yah, why can't there be an interface?

markhalliwell’s picture

While I understand the end goal/desire of #75, wouldn't it make more sense to create a follow-up to do that?

If this issue is any indication (#27-#63), this is a complicated area and doing this in steps would probably be best.

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

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

daffie’s picture

Status: Needs review » Needs work
Issue tags: +Needs reroll
daffie’s picture

Issue tags: -Needs reroll

The patch does not need a reroll. It just needs work. :)

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

catch’s picture

andypost’s picture

dpi’s picture

Created a autoloading-related issue for ensuring classes are added to the autoloader before container cache is unserialized @ #3522410: Using instances of classes defined by modules in service container parameters causes fatal errors

nicxvan made their first commit to this issue’s fork.

nicxvan’s picture

I deleted my comment it was meant for a different issue.

nicxvan’s picture

I think I want to work on the theme namespaces.

nicxvan’s picture

Status: Needs work » Postponed (maintainer needs more info)

We now register theme namespaces on container build which happens during theme install.

I'm not clear why we wanted them in different container parameters in this issue.

Postponing for an update with the new information if this is still relevant.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.