Problem/Motivation

#2807785: Move global constants from *.module files into interfaces deprecated a bunch of constants but it did not actually replace their usage. We should do this. This issue handles REGIONS_VISIBLE, and REGIONS_ALL. This is a bug because we've deprecated something but we've not completed the task and, more importantly, the old constants are in the System module and used by it but the new constants are in the Block module. That does not work.

Regions are properties of themes not blocks. They are declared in a theme's .info.yml file in the regions key and hidden via the regions_hidden key.

Proposed resolution

Current solution

Add a new Theme class that extends Extension and replaces the extension object in theme lists.

See API changes for a full scope of all the changes.

Other possible solutions

  • Add a new ThemeRegion service.
  • Add an object just to handle the theme extension's info array - discounted in #24 - we have code that depends on this being an array.
  • Add ThemeHandler::listAllRegions($name), ThemeHandler::listVisibleRegions($name) and ThemeHandler::getDefaultRegion($name) - discounted in #13

Remaining tasks

User interface changes

None

API changes

The main changes are:

  • system_region_list() use \Drupal::service('theme_handler')->getTheme()->listAllRegions() or \Drupal::service('theme_handler')->getTheme()->listVisibleRegions() instead.
  • system_default_region() use \Drupal::service('theme_handler')->getTheme()->getDefaultRegion() instead.
  • REGIONS_ALL, REGIONS_VISIBLE, \Drupal\block\BlockRepositoryInterface::REGIONS_ALL and \Drupal\block\BlockRepositoryInterface::REGIONS_VISIBLE are deprecated and should not be used.

As a result several objects that had helper methods to the global functions also have API deprecations:

  • \Drupal\block\BlockListBuilder::systemRegionList() use $this->themeHandler->getTheme()->listAllRegions() or $this->themeHandler->getTheme()->listVisibleRegions() instead.
  • \Drupal\block\Controller\BlockController::getVisibleRegionNames() use $this->themeHandler->getTheme()->listVisibleRegions() instead.
  • \Drupal\block_place\Plugin\DisplayVariant\PlaceBlockPageVariant::getVisibleRegionNames() use $this->themeHandler->getTheme()->listVisibleRegions() instead.

Several methods on the ThemeHandler return an array of Theme objects instead of Extension objects. As Theme extends from Extension this is allowed. These methods are:

  • \Drupal\Core\Extension\ThemeHandlerInterface::listInfo()
  • \Drupal\Core\Extension\ThemeHandlerInterface::rebuildThemeData()

\Drupal\Core\Extension\ThemeHandlerInterface::getTheme() now returns a Theme object.

The one "breaking" change is \Drupal\Core\Extension\ThemeHandlerInterface::addTheme() which now only accepts a Theme object. This change is worth it because this is an incredibly low level method that only exists so that maintenance pages and install pages can use themes before anything is installed. The hard break would help any custom or contrib code in the very unlikely event that they are using it.

New \Drupal\Core\Extension\Theme that extends \Drupal\Core\Extension\Extension and we can build up the abilities of over time so eventually we can replace everything with methods. No more $theme->info['foo'] and we can remove the public properties and turn them into value objects.

Data model changes

None

CommentFileSizeAuthor
#173 3015812-nr-bot_e0ovh3_c.txt91 bytesneeds-review-queue-bot
#171 3015812-nr-bot_damzgl84.txt91 bytesneeds-review-queue-bot
#133 3015812-nr-bot.txt147 bytesneeds-review-queue-bot
#130 3015812-130.patch43.97 KBameymudras
#127 3015812-127.patch44.08 KBviappidu
#126 Screenshot 2022-11-23 at 1.42.21 AM.png73.35 KBakram khan
#125 reroll_diff_123-125.txt22.54 KBakram khan
#125 3015812-125.patch32.66 KBakram khan
#123 3015812-123.patch44.54 KBsmustgrave
#123 interdiff-121-123.txt2.42 KBsmustgrave
#121 interdiff-3015812-120-121.txt1.59 KBvoleger
#121 3015812-121.patch44.93 KBvoleger
#120 interdiff-3015812-118-120.txt5.75 KBvoleger
#120 3015812-120.patch44.93 KBvoleger
#118 3015812-118.patch41 KBsmustgrave
#118 interdiff-116-118.txt1.02 KBsmustgrave
#116 3015812-117.patch42.35 KBandypost
#116 interdiff.txt539 bytesandypost
#115 interdiff.txt502 bytesandypost
#114 3015812-114.patch42.35 KBandypost
#114 interdiff.txt502 bytesandypost
#111 3015812-111.patch41.86 KBsmustgrave
#111 interdiff-108-111.txt1.55 KBsmustgrave
#108 3015812-108.patch41.91 KBsmustgrave
#108 interdiff-107-108.txt2.04 KBsmustgrave
#107 interdiff-3015812-103-107.txt10.92 KBvoleger
#107 3015812-107.patch41.9 KBvoleger
#103 3015812-103.patch41.81 KBandypost
#103 interdiff.txt11.75 KBandypost
#100 interdiff-3015812-94-100.txt1.96 KBvoleger
#100 3015812-100.patch42.24 KBvoleger
#94 interdiff-3015812-93-94.txt1.78 KBvoleger
#94 3015812-94.patch42.25 KBvoleger
#93 interdiff-3015812-91-93.txt2.96 KBvoleger
#93 3015812-93.patch42.24 KBvoleger
#91 interdiff-3015812-89-91.txt7.07 KBvoleger
#91 3015812-91.patch42.17 KBvoleger
#89 interdiff-3015812-88-89.txt1.33 KBvoleger
#89 3015812-89.patch37.33 KBvoleger
#88 interdiff-3015812-87-88.txt1.06 KBvoleger
#88 3015812-88.patch37.34 KBvoleger
#87 3015812-87.patch37.24 KBvoleger
#85 interdiff-3015812-82-85.txt0 bytesvoleger
#85 3015812-85.patch36.44 KBvoleger
#82 3015812-82.patch35.7 KBjofitz
#80 3015812-80.patch35.56 KBnikitagupta
#77 3015812-77.patch35.65 KBsuresh prabhu parkala
#72 3015812-72.patch37.45 KBhardik_patel_12
#66 3015812-66.patch41.07 KBravi.shankar
#63 interdiff-3015812-61-63.txt10.53 KBvoleger
#63 3015812-63.patch41.91 KBvoleger
#61 3015812-2-61.patch42.22 KBvacho
#48 3015812-2-48.patch42.2 KBalexpott
#48 46-48-interdiff.txt4.75 KBalexpott
#46 3015812-2-45.patch43.76 KBalexpott
#46 44-45-interdiff.txt678 bytesalexpott
#44 3015812-2-44.patch43.72 KBalexpott
#44 41-44-interdiff.txt3.45 KBalexpott
#41 3015812-2-41.patch43.75 KBalexpott
#40 3015812-2-40.patch43.72 KBalexpott
#39 3015812-2-39.patch44.41 KBalexpott
#39 36-39-interdiff.txt1.6 KBalexpott
#36 3015812-2-36.patch43.23 KBalexpott
#34 3015812-2-34.patch40.69 KBalexpott
#34 31-34-interdiff.txt1.42 KBalexpott
#31 3015812-2-31.patch39.27 KBalexpott
#31 27-31-interdiff.txt1.8 KBalexpott
#28 3015812-2-27.patch37.51 KBalexpott
#28 26-27-interdiff.txt2.01 KBalexpott
#27 3015812-2-27.patch37.51 KBalexpott
#24 3015812-24.patch33.8 KBalexpott
#24 23-24-interdiff.txt758 bytesalexpott
#23 3015812-23.patch33.95 KBalexpott
#23 21-23-interdiff.txt2.09 KBalexpott
#21 3015812-21.patch33.24 KBalexpott
#21 17-21-interdiff.txt1.62 KBalexpott
#17 3015812-17.patch31.37 KBalexpott
#10 3015812-10.patch27.89 KBalexpott
#10 8-10-interdiff.txt3.19 KBalexpott
#8 3015812-8.patch24.7 KBalexpott
#8 7-8-interdiff.txt16.85 KBalexpott
#8 2-8-interdiff.txt5.94 KBalexpott
#7 3015812-7.patch23.39 KBandypost
#7 interdiff.txt631 bytesandypost
#6 3015812-6.patch23.36 KBandypost
#6 interdiff.txt1.3 KBandypost
#5 3015812-5.patch23.24 KBandypost
#4 interdiff.txt13.15 KBandypost
#5 interdiff.txt3.32 KBandypost
#4 3015812-4.patch23.24 KBandypost
#2 3015812-2.patch22.53 KBalexpott

Issue fork drupal-3015812

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

alexpott created an issue. See original summary.

alexpott’s picture

Status: Active » Needs review
Issue tags: +Needs issue summary update
StatusFileSize
new22.53 KB

I think we should re-consider how we have deprecated REGIONS_ALL and REGIONS_VISIBLE. Regions are properties of themes not blocks. Yes blocks are placed in regions but the list of regions are determined by the theme not blocks.

The patch attached deprecated system_region_list() and system_default_region() and places the methods on the ThemeHandler - that because they are easiest to implement there and as you can see from some of the changes there are places where with what is already injected into objects this makes sense. I'm not sure - other ideas more than welcome.

andypost’s picture

Status: Needs review » Needs work
Issue tags: +@deprecated

That looks great and much cleaner

Maybe instead of new Translatable($label) extension api could provide that

+++ b/core/modules/block/src/BlockListBuilder.php
@@ -404,6 +418,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
   protected function systemRegionList($theme, $show = REGIONS_ALL) {
+    @trigger_error('@todo', E_USER_DEPRECATED);

+++ b/core/modules/block_place/src/Plugin/DisplayVariant/PlaceBlockPageVariant.php
@@ -133,7 +143,8 @@ public function build() {
   protected function getVisibleRegionNames($theme) {
...
+    @trigger_error('@todo', E_USER_DEPRECATED);

+++ b/core/modules/system/system.module
@@ -1062,25 +1064,18 @@ function system_rebuild_module_data() {
 function system_region_list($theme, $show = REGIONS_ALL) {
...
+  @trigger_error('@todo', E_USER_DEPRECATED);

@@ -1127,10 +1122,12 @@ function system_system_info_alter(&$info, Extension $file, $type) {
 function system_default_region($theme) {
...
+  @trigger_error('@todo', E_USER_DEPRECATED);

also needs testing for deprecated BC + exception

andypost’s picture

StatusFileSize
new13.15 KB
new23.24 KB

Added regions_hidden to theme init
As all of this methods getters - then let's call them not "list"
A bit of clean-up

andypost’s picture

Status: Needs work » Needs review
StatusFileSize
new3.32 KB
new23.24 KB

Clean-up renaming

andypost’s picture

StatusFileSize
new1.3 KB
new23.36 KB

Deletegated in theme init, hidden is not used in active theme so every usage should use theme handler

andypost’s picture

StatusFileSize
new631 bytes
new23.39 KB

make translation inline with core

alexpott’s picture

StatusFileSize
new5.94 KB
new16.85 KB
new24.7 KB

@andypost I think listBlah() is great for a getter that returns an array. But whatevs we don't have a standard here.

I think #6 and any changes to ActiveTheme is out-of-scope and should be done in another issue.

#7 is also out-of-scope.

+++ b/core/modules/system/system.module
@@ -1062,25 +1064,18 @@ function system_rebuild_module_data() {
-      $list[$name] = t($label);

This is the original code... the Layout stuff has added 'context' => 'layout_region' but that is an experimental module and there needs to be separate issue to introduce this to system_region_list().

All told I'm going to revert to #2 with improvements to block_rebuild() from #4.

Added a new change record and started to write it https://www.drupal.org/node/3015925 and added proper deprecation notices.

I still think we need to discuss whether the ThemeHandler is the correct place for this. For me a potentially better way would a Theme object that was built from the Extension object so you could do something like $this->themeHandler->getTheme($name)->listAllRegions() but this requires massive changes to the the theme listing system which are afoot in #2659940: Extension System, Part III: ThemeExtensionList and ThemeEngineExtensionList but even those changes have not yet given us properly typed Extensions objects ie Module / Theme / Profile. So maybe this is the best we can do at the moment. I think that changes to block_rebuild() show that putting this on the theme handler is not that bad a compromise.

Need to add deprecation tests.

alexpott’s picture

I guess the other option is to have a ThemeRegion service. It would depend on the theme_handler and string_translation services.

alexpott’s picture

StatusFileSize
new3.19 KB
new27.89 KB

Here's a test for region listing both via theme_handler and the legacy methods.

alexpott’s picture

Issue summary: View changes
Issue tags: -Needs issue summary update

Updated issue summary.

alexpott’s picture

Issue summary: View changes
tim.plunkett’s picture

the other option is to have a ThemeRegion service. It would depend on the theme_handler and string_translation services.

This sounds preferable, and also avoiding a BC break by not expanding ThemeHandlerInterface.

andypost’s picture

Tim do you have any thoughts about how to swap it later for #2924058: Discuss using Layout Builder to control full site layout and replace Block UI

andypost’s picture

@alexpott what if we add extension getFeatures() which will return specific extension info.yml parsing and validation object - surely followup

On my side I'd like to split theme info which is already dumplicated in activetheme class object

tim.plunkett’s picture

Making it a new service could probably help with that (as Layout Builder could swap out the service), but that issue isn't a current focus of the Layout Initiative

alexpott’s picture

Issue summary: View changes
StatusFileSize
new31.37 KB

Not sure about this being a service. I prefer the

Somehow move this a Theme extension object (not sure this is achievable).

option.

Here's a patch doing that. It introduces an ThemeInfo value object that handles the ->info part of the Theme extension object. That's let's us have methods :)

No interdiff because it is a fresh approach.

alexpott’s picture

Issue summary: View changes
alexpott’s picture

Issue summary: View changes

Status: Needs review » Needs work

The last submitted patch, 17: 3015812-17.patch, failed testing. View results

alexpott’s picture

Status: Needs work » Needs review
StatusFileSize
new1.62 KB
new33.24 KB

Accounting for the case where a block exists for a theme that is not installed :(

Status: Needs review » Needs work

The last submitted patch, 21: 3015812-21.patch, failed testing. View results

alexpott’s picture

Status: Needs work » Needs review
StatusFileSize
new2.09 KB
new33.95 KB

We need PHP 7.1's iterable type hint :( oh well. This is work aroundable.

alexpott’s picture

StatusFileSize
new758 bytes
new33.8 KB

Doh.

The last submitted patch, 23: 3015812-23.patch, failed testing. View results

Status: Needs review » Needs work

The last submitted patch, 24: 3015812-24.patch, failed testing. View results

alexpott’s picture

Status: Needs work » Needs review
StatusFileSize
new37.51 KB

Okay so array_intersect_key() doesn't work on \ArrayAccess objects :(

Here's another approach that confers quite a few advantages. It adds a Theme extension object that extends from Extension and documents the public properties. This will allow us to properly deprecate them and move to a value object.

No interdiff because it'd be every single line.

alexpott’s picture

StatusFileSize
new2.01 KB
new37.51 KB

Fixing some tests from #27.

The last submitted patch, 27: 3015812-2-27.patch, failed testing. View results

alexpott’s picture

Issue summary: View changes

Updated the issue summary with the current state.

alexpott’s picture

StatusFileSize
new1.8 KB
new39.27 KB

Ignore the patch in #28 it's the same as #27 :( - here are the fixes.

The last submitted patch, 28: 3015812-2-27.patch, failed testing. View results

Status: Needs review » Needs work

The last submitted patch, 31: 3015812-2-31.patch, failed testing. View results

alexpott’s picture

Status: Needs work » Needs review
StatusFileSize
new1.42 KB
new40.69 KB

So the LanguageBlockSettingsVisibilityTest is using a theme that is not installed. It shouldn't be doing that the link is not available in the UI and it would be impossible to add a block for a theme that is not installed because you'll get a dependency error.

alexpott’s picture

#2659940: Extension System, Part III: ThemeExtensionList and ThemeEngineExtensionList is back to RTBC - we should definitely do that one first as it is more important and will mean lots of changes to this one.

alexpott’s picture

Issue tags: +Needs issue summary update
StatusFileSize
new43.23 KB

Here's a rebase on top of #2659940: Extension System, Part III: ThemeExtensionList and ThemeEngineExtensionList

Need to update the issue summary a little with the impact. No interdiff because the changes are extensive and need to be reviewed in the context on the new theme extension list.

alexpott’s picture

Status: Needs review » Needs work

The last submitted patch, 36: 3015812-2-36.patch, failed testing. View results

alexpott’s picture

Status: Needs work » Needs review
StatusFileSize
new1.6 KB
new44.41 KB
alexpott’s picture

StatusFileSize
new43.72 KB

Rerolled now the weight patch landed.

alexpott’s picture

Title: Properly deprecate REGIONS_VISIBLE and REGIONS_ALL » Introduce new Theme extension object and properly deprecate REGIONS_VISIBLE and REGIONS_ALL
Issue summary: View changes
Issue tags: -Needs issue summary update
StatusFileSize
new43.75 KB

Let's kick another test off - I rebased my branch on the latest 8.7.x... no changes to #40.

The issue summary is up-to-date with the current patch. Changed title to reflect scope.

phenaproxima’s picture

  1. +++ b/core/lib/Drupal/Core/Extension/ExtensionList.php
    @@ -311,7 +311,8 @@ protected function doList() {
    +      $extension = $this->decorateExtension($extension);
    +      $extensions[$extension_name] = $extension;
     
    

    Nit: Why split this into two lines?

  2. +++ b/core/lib/Drupal/Core/Extension/ExtensionList.php
    @@ -540,25 +541,27 @@ public function getPath($extension_name) {
    +   * extensions info.yml information. This maybe be overridden to return an
    

    Should be "This may be overridden..."

  3. +++ b/core/lib/Drupal/Core/Extension/Theme.php
    @@ -0,0 +1,167 @@
    +   * Whether the Theme is installed or not.
    

    Nit: "Theme" should be "theme".

  4. +++ b/core/lib/Drupal/Core/Extension/Theme.php
    @@ -0,0 +1,167 @@
    +   * @todo Remove all code that relies on the $status property.
    +   *
    +   * @var int
    +   */
    +  public $status;
    

    To facilitate the removal of the property, maybe this would be a good time to add an isEnabled() method to replace it?

  5. +++ b/core/lib/Drupal/Core/Extension/Theme.php
    @@ -0,0 +1,167 @@
    +  /**
    +   * The info array based on the theme's .info.yml file.
    +   *
    +   * @var array
    +   */
    +  public $info;
    

    Should this default to an empty array?

  6. +++ b/core/lib/Drupal/Core/Extension/Theme.php
    @@ -0,0 +1,167 @@
    +  /**
    +   * The relative path to the theme engine extension file.
    +   *
    +   * @var string
    +   */
    +  public $owner;
    

    "Owner" seems like a strange name for this property. Maybe we should take this opportunity to rename it and add a magic __get() wrapper around "owner", if external code relies on it.

  7. +++ b/core/lib/Drupal/Core/Extension/Theme.php
    @@ -0,0 +1,167 @@
    +  /**
    +   * The internal name of the theme engine extension
    +   *
    +   * @var string
    +   */
    +  public $prefix;
    

    Same here.

  8. +++ b/core/lib/Drupal/Core/Extension/Theme.php
    @@ -0,0 +1,167 @@
    +   * @param int $status
    +   *   The theme's installation status.
    

    Should this be a boolean?

  9. +++ b/core/lib/Drupal/Core/Extension/Theme.php
    @@ -0,0 +1,167 @@
    +  public function __construct($root, Extension $extension, array $info, $status) {
    

    Passing an Extension object to this constructor seems strange. It almost feels like it should be a static createFromExtension() method...

  10. +++ b/core/lib/Drupal/Core/Extension/Theme.php
    @@ -0,0 +1,167 @@
    +    if ($this->info['base theme'] === FALSE) {
    +      unset($this->info['base theme']);
    +    }
    +    else {
    +      // Add the base theme as a proper dependency.
    +      $this->info['dependencies'][] = $this->info['base theme'];
    +    }
    

    What if 'base theme' is an empty string, or null? Maybe this should be an empty() check instead.

  11. +++ b/core/lib/Drupal/Core/Extension/Theme.php
    @@ -0,0 +1,167 @@
    +  public function getDefaultRegion() {
    +    return (string) key($this->listVisibleRegions());
    +  }
    

    Why does the return value need to be casted to a string?

  12. +++ b/core/lib/Drupal/Core/Extension/ThemeExtensionList.php
    @@ -104,19 +67,39 @@ public function __construct($root, $type, CacheBackendInterface $cache, InfoPars
    +    $engines = $this->engineList->getList();
    

    Where is this used?

  13. +++ b/core/lib/Drupal/Core/Extension/ThemeExtensionList.php
    @@ -245,24 +226,10 @@ protected function doGetBaseThemes(array $themes, $theme, array $used_themes = [
    +    $status = (int) isset($this->installedThemes[$extension->getName()]);
    

    Isn't there a method to retrieve the list of installed themes?

markhalliwell’s picture

Status: Needs review » Needs work
Issue tags: +Extension system, +Theme System Modernization Initiative

A little overlap from #42:

  1. +++ b/core/lib/Drupal/Core/Extension/Theme.php
    @@ -0,0 +1,167 @@
    +  /**
    +   * Whether the Theme is installed or not.
    +   *
    +   * @todo Remove all code that relies on the $status property.
    +   *
    +   * @var int
    +   */
    +  public $status;
    +
    +  /**
    +   * The info array based on the theme's .info.yml file.
    +   *
    +   * @var array
    +   */
    +  public $info;
    

    These should really be a part of Extension, they're not theme specific: http://cgit.drupalcode.org/drupal/tree/core/includes/common.inc?id=8.6.5...

  2. +++ b/core/lib/Drupal/Core/Extension/Theme.php
    @@ -0,0 +1,167 @@
    +  public function __construct($root, Extension $extension, array $info, $status) {
    +    if ($extension->getType() !== 'theme') {
    +      throw new \InvalidArgumentException('Constructing a Theme object using an extension that is not a theme makes no sense');
    +    }
    +    parent::__construct($root, 'theme', $extension->getPathname(), $extension->getExtensionFilename());
    +    $this->info = $info + static::getInfoDefaults();
    

    This is really weird and feels like a huge anti-pattern.

    The Theme object extends from Extension, it shouldn't need an Extension object to create a Theme object.

  3. +++ b/core/lib/Drupal/Core/Extension/ThemeExtensionList.php
    @@ -245,24 +226,10 @@ protected function doGetBaseThemes(array $themes, $theme, array $used_themes = [
    +  protected function decorateExtension(Extension $extension) {
    +    $info = $this->infoParser->parse($extension->getPathname());
    +    $status = (int) isset($this->installedThemes[$extension->getName()]);
    +    return new Theme($this->root, $extension, $info, $status);
    

    Decorating something shouldn't return a whole new object.

I'm also wondering if maybe this shouldn't be postponed on #2941757: Extension System, Part IV: Properly register all installed extensions/namespaces during container generation and #3023131: [PP-1] Extension System, Part IV: ExtensionHandler and ExtensionHandlerInterface. These issues will clear up a lot of how extensions are constructed/handled by ExtensionList and eliminate some of the weird hackery that's going on currently and the extended proposed changes that only add to the nightmare.

alexpott’s picture

Status: Needs work » Needs review
StatusFileSize
new3.45 KB
new43.72 KB

Thanks for the reviews
Re #42

  1. Because we don't want to pass the array version into $this->moduleHandler->alter('system_info', $extension->info, $extension, $this->type); - you are only supposed to be able to alter the info - not the extension object itself.
  2. Fixed
  3. Fixed
  4. I suggest we do that in followups because then we can use the deprecated property trait and concentrate on each property - this issue is doing enough
  5. Can't hurt
  6. Follow-up material for me and we should replace with a method so /shrug about renaming the property
  7. Follow-up material for me and we should replace with a method so /shrug about renaming the property
  8. This is BC. /shrug it is not biggie to me - extensions used to have a tri-state status enabled/disabled/uninstalled so perhaps this is hang up from then. Needs more discussion if we change it here.
  9. Changed this to no longer need an extension - less complexity now.
  10. No this is a very careful copy of the existing logic and it needs to be maintained.
  11. To conform to the interface in the super super rare case that the theme has no visible regions. key([]) returns NULL. Again this is BC it is what system_default_region() does with return isset($regions[0]) ? $regions[0] : '';
  12. Lower down in that method we do

          if (isset($engines[$engine])) {
            $theme->owner = $engines[$engine]->getExtensionPathname();
            $theme->prefix = $engines[$engine]->getName();
          }
    
  13. Yes. But still we need to maintain this property for BC - we could decide to get rid of it and tell people to use the get all installed method BUT I think the extension listing service should return extension objects which have the ability to know whether they are installed - this leads to very natural code.

RE #43

  1. There is nothing to stop us moving them up a class in a follow-up and I agree but issue scope.
  2. I think you like the words "anti pattern" too much. But anyway the principle of taking an object and decorating it is not one. As it is, I've refactored this out because we can have less complexity by not doing it.
  3. Yes it should. For example, this is exactly how decorating a service in Symfony works. Or our middleware. Or well any other implementation of the decorator pattern. What is different about this one is that we’re not storing the decorated extension object because that is not necessary. Anyhow, moot see 2.

For me this shouldn't be postponed on #2941757: Extension System, Part IV: Properly register all installed extensions/namespaces during container generation that is make extensive changes whereas this is a small change in the object returned from the extension list which allows us to gives these extension object type specific functionality which is a nice change because it makes code easier to understand and will allow us to finally move forward and refactor the public properties we've been jamming on to this object for too long.

markhalliwell’s picture

#43.1 There is nothing to stop us moving them up a class in a follow-up and I agree but issue scope.

Not entirely sure how this is issue scope when it's introducing official properties that belong to the parent class in the first place.

#43.2 I think you like the words "anti pattern" too much. But anyway the principle of taking an object and decorating it is not one.

I don't use it that much lol I wasn't aware that you were attempting to turn the Extension objects into decorated classes, which is why it looked quite odd for a sub-class to require a parent class. I tend to think of Extensions as stand-alone objects; able to be created using scalar values.

#43.3 Yes it should.

Please forgive my ignorance, I'm still not all that familiar with decorators as they aren't as prevalent on the FE (yet). Regardless, if this were to be a decorator, I think it'd need that name appended to the class to clarify what it's supposed to be doing. Given that it wasn't, I think that's what confused me the most.

For me this shouldn't be postponed on #2941757: Extension System, Part IV: Properly register all installed extensions/namespaces during container generation that is make extensive changes...

True, I was thinking to postpone more on #3023131: [PP-1] Extension System, Part IV: ExtensionHandler and ExtensionHandlerInterface as that will likely change a lot of how Extensions are listed/handled as a whole.

edit: separating this out because I think it got overlooked.

Perhaps instead of postponing we should mark Theme as @internal temporarily?

I suspect this object will undergo quite a lot of changes over several issues once it's introduced.

My only real concern is introducing something that isn't yet fully flushed out for the sake of expediency.

alexpott’s picture

StatusFileSize
new678 bytes
new43.76 KB

Added @todo to #3026232: Deprecate Theme extension object public properties to deprecate public property usage.

I've thought about making \Drupal\Core\Extension\ExtensionDiscovery return Theme objects instead of Extension objects but I think that that should continue to work with raw Extension object and leave decorating to the ExtensionList classes because:

  • In order to decorate properly you need to parse the info file
  • There's likely to be specific logic for theme or modules that's hard to get right during \Drupal\Core\Extension\ExtensionDiscovery::scanDirectory and we certainly don't want extension status bleeding down to that level.
dawehner’s picture

To be honest decoration is a really weird word. We do composition here and the extension has a clear limited scope. Inheritance isn't the only way how you can architect your data structures :)

alexpott’s picture

StatusFileSize
new4.75 KB
new42.2 KB

@markcarver it is fine for us to move the public properties up to extension but there really is out of scope here because that will involve tackling the module system - we don't have to here so let's not.

Wrt to change on the Theme object at the moment in HEAD everything is determined from the info array, the extension object and the theme status - the patch does not change that. And I've not seen future plans to change that. So the important thing here is that we agree the names of the public methods added to the Theme object and what public methods to add because that's what would be hard to change. Adding new method in future releases as we deprecate the public properties and provide decent getters for other things is allowed.

The new methods are:

  • listAllRegions()
  • listVisibleRegions()
  • getDefaultRegion()
  • static getInfoDefaults() (ended up removing this)
  • static getDefaultFeatures() (ended up removing this)

I think the first 3 are well placed and named but I'm conflicted about the other two. Actually as

  • static getInfoDefaults()
  • is never used outside the class we could make it a class property and be done. And we could leave _system_default_theme_features() in place and handle in a follow-up if we like. I've done that in the patch attached. Nice less new API and we can add similar stuff in the future if we like.

    @dawehner yeah it is tricky - in the \Drupal\Core\Extension\ExtensionList::decorateExtension() I think the future will be always replacing the extension object with something specific like Theme / Module / Profile / ThemeEngine but we're not there yet. But I agree we're not doing the decorator pattern here. And no we're not taking an Extension object in the constructor we're doing less of a decorator pattern. Maybe I should go back to doing a proper decorate pattern and hand off calls to the wrapped Extension object?

    alexpott’s picture

    Issue summary: View changes
    alexpott’s picture

    So I think the important discussion to have is the name and documentation of \Drupal\Core\Extension\ExtensionList::decorateExtension

    Here's the default implementation:

      /**
       * Decorates an extension object.
       *
       * The default behavior is to add a public $info property containing the
       * extensions info.yml information. This may be overridden to return an object
       * that extends the Extension object.
       *
       * @param \Drupal\Core\Extension\Extension $extension
       *   The extension to be decorated.
       *
       * @return \Drupal\Core\Extension\Extension
       *   The decorated extension.
       */
      protected function decorateExtension(Extension $extension) {
        $info = $this->infoParser->parse($extension->getPathname());
        // Add the info file modification time, so it becomes available for
        // contributed extensions to use for ordering extension lists.
        $info['mtime'] = $extension->getMTime();
    
        // Merge extension type-specific defaults.
        $extension->info = $info + $this->defaults;
        return $extension;
      }
    

    Here's the theme override:

      /**
       * {@inheritdoc}
       */
      protected function decorateExtension(Extension $extension) {
        $info = $this->infoParser->parse($extension->getPathname());
        $status = (int) isset($this->installedThemes[$extension->getName()]);
        return new Theme($this->root, $extension->getPathname(), $extension->getExtensionFilename(), $info, $status);
      }
    

    In the future when all extension types have their own object I think we should consider deprecating the base implementation and marking it abstract in a future major release.

    markhalliwell’s picture

    I'm not sure what the name should be. Personally, I don't believe replacing createExtensionInfo is necessarily the right move here.

    In fact, $info['mtime'] = $extension->getMTime(); is missing from the ThemeExtensionList implementation.

    Maybe it should be its own new method that invokes createExtensionInfo?

    I know this is out of scope, but food for thought... ExtensionInfo from #2186491: [meta] D8 Extension System: Discovery/Listing/Info was pretty much sidelined and merged with ExtensionList (which is already doing way too much IMO). It may be beneficial to rethink introducing this in another issue?

    ---

    I think we should temporarily mark Theme as @internal.

    I suspect this object will undergo quite a lot of changes over several issues once it's introduced.

    My only real concern is introducing something that isn't yet fully flushed out for the sake of expediency.

    phenaproxima’s picture

    I think we should temporarily mark Theme as @internal.

    +1 for this. I can't imagine too many people will extend or muck around with it, but we should at least make it as "sealed" and private as we realistically can, at least for now.

    andypost’s picture

    About naming field api using notion of "massage" to extend fields to widgets

    alexpott’s picture

    In fact, $info['mtime'] = $extension->getMTime(); is missing from the ThemeExtensionList implementation.

    Not it's not - see Theme::__construct()

    Wrt to marking it @internal - the problem with that is that is not really what I think you mean. People will interact with these objects. So they are not @internal - but what we don't what is for people to think this is an extensible API. So I think that we could argue that Theme should be final but the final debate is for another day because the topic of final seems contentious in the other issues it has come up in.

    markhalliwell’s picture

    Not it's not - see Theme::__construct()

    That isn't ThemeExtensionList. I was referring to the code snippets in #50 and how it's a little confusing that it splits the responsibility of populating the info array between ThemeExtensionList and Theme.

    Wrt to marking it @internal - the problem with that is that is not really what I think you mean. People will interact with these objects.

    People already interact with ExtensionList and it's marked @internal because we haven't yet finalized the service and for good reason. I don't see why we can't do that here as well. I don't see a reason why backing us into a corner is necessary just yet.

    +++ b/core/lib/Drupal/Core/Extension/ThemeHandler.php
    @@ -112,7 +112,7 @@ public function listInfo() {
    -  public function addTheme(Extension $theme) {
    +  public function addTheme(Theme $theme) {
    
    +++ b/core/lib/Drupal/Core/Extension/ThemeHandlerInterface.php
    @@ -95,10 +95,10 @@ public function listInfo();
    -  public function addTheme(Extension $theme);
    +  public function addTheme(Theme $theme);
    

    Ins't this technically a BC break (changing existing interfaces)?

    andypost’s picture

    Related issues: +#3035288: Deprecate theme_get_setting()
    claudiu.cristea’s picture

    @alexpott, @andypost

    Do you think that the actual theme_get_setting() could be moved as a method in the new Theme object, as it has been suggested in #3035288-7: Deprecate theme_get_setting()?

    andypost’s picture

    @claudiu.cristea I think it is because of encapsulation of this logic related exactly to theme - and Mark already explained it in #3035288-11: Deprecate theme_get_setting()
    So makes sense to figure #2024043: Add Module, Theme, Profile, and Extension value objects

    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.

    andypost’s picture

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

    StatusFileSize
    new42.22 KB

    I contrib to this cause rerolling.

    vacho’s picture

    Issue tags: -Needs reroll
    voleger’s picture

    StatusFileSize
    new41.91 KB
    new10.53 KB

    Fix CS issues

    ravi.shankar’s picture

    Status: Needs work » Needs review

    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.

    ravi.shankar’s picture

    StatusFileSize
    new41.07 KB

    Here is a re-roll of patch #63.

    gábor hojtsy’s picture

    Hm, so in #3111942: Remove all remaining @deprecated code from system module I attempted to remove the region constants. They were deprecated with a suggestion to use \Drupal\block\BlockRepositoryInterface:: instead. So if we are adding this new API in 8.9 that changes what the resolution for the deprecation is. How is that compatible with defining deprecations up until Drupal 8.8? Tagging for release manager review.

    berdir’s picture

    Yes, this missed the deadline and therefore the solution is likely to undeprecate that constant or change it to a D10 removal.

    alexpott’s picture

    Opened #3112263: Undeprecate REGIONS_* constants to remove the deprecation. We can then do something like this in Drupal 9.

    gábor hojtsy’s picture

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

    Moving to Drupal 9.1 then :)

    daffie’s picture

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

    Status: Needs work » Needs review
    StatusFileSize
    new37.45 KB

    Re-rolled for 9.1.x

    ravi.shankar’s picture

    Issue tags: -Needs reroll

    Removed needs re-roll tag.

    daffie’s picture

    Status: Needs review » Needs work

    The patch fails the testbot.

    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.

    andypost’s picture

    Issue tags: +Needs reroll

    for 9.2.0

    suresh prabhu parkala’s picture

    Status: Needs work » Needs review
    StatusFileSize
    new35.65 KB

    Re-roll against 9.2.x. Please review.

    andypost’s picture

    Status: Needs review » Needs work

    + * @expectedDeprecation system_region_list() is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use

    Wrong reroll

    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.

    nikitagupta’s picture

    Status: Needs work » Needs review
    StatusFileSize
    new35.56 KB
    daffie’s picture

    Status: Needs review » Needs work

    The testbot is not happy.

    jofitz’s picture

    Status: Needs work » Needs review
    Issue tags: -Needs reroll
    StatusFileSize
    new35.7 KB

    Let's start by re-rolling the patch from #80...

    daffie’s picture

    Status: Needs review » Needs work

    The patch is failing the testbot. See: https://dispatcher.drupalci.org/job/drupal_patches/93500/.

    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.

    voleger’s picture

    Issue tags: +LutskGCW22
    StatusFileSize
    new36.44 KB
    new0 bytes

    Rerolled #82
    No interdiff.

    andypost’s picture

    Issue tags: +ContributionWeekend2022

    re-roll went wrong

    voleger’s picture

    StatusFileSize
    new37.24 KB

    Since #63 patch lost some important parts, another rerolling based on #63

    voleger’s picture

    Status: Needs work » Needs review
    StatusFileSize
    new37.34 KB
    new1.06 KB

    Fix CS

    voleger’s picture

    StatusFileSize
    new37.33 KB
    new1.33 KB

    Status: Needs review » Needs work

    The last submitted patch, 89: 3015812-89.patch, failed testing. View results

    voleger’s picture

    Status: Needs work » Needs review
    StatusFileSize
    new42.17 KB
    new7.07 KB

    Fixed missing parts

    alexpott’s picture

    I always liked this patch. Really nice to see it moving again. Thanks @voleger. Now we're targeting Drupal 9 we can use return typehints and scalar typehints.

    1. +++ b/core/lib/Drupal/Core/Extension/ExtensionList.php
      @@ -542,25 +542,27 @@ public function getPath($extension_name) {
      +  protected function decorateExtension(Extension $extension) {
      

      Can add a return typehint.

    2. +++ b/core/lib/Drupal/Core/Extension/Theme.php
      @@ -0,0 +1,152 @@
      +  public function __construct($root, $pathname, $filename, array $info, $status) {
      

      Can add scalar typehints

    3. +++ b/core/lib/Drupal/Core/Extension/Theme.php
      @@ -0,0 +1,152 @@
      +  public function listAllRegions() {
      ...
      +  public function listVisibleRegions() {
      ...
      +  public function getDefaultRegion() {
      

      Can add return typehint

    4. +++ b/core/lib/Drupal/Core/Extension/ThemeExtensionList.php
      @@ -262,29 +241,10 @@ protected function doGetBaseThemes(array $themes, $theme, array $used_themes = [
      +  protected function decorateExtension(Extension $extension) {
      

      Will need a return typehint.

    voleger’s picture

    StatusFileSize
    new42.24 KB
    new2.96 KB

    Addressed #92

    voleger’s picture

    StatusFileSize
    new42.25 KB
    new1.78 KB

    Moved optional construct argument into the end of the list

    voleger’s picture

    Tests passed. Ready for the review

    andypost’s picture

    1. +++ b/core/lib/Drupal/Core/Extension/Theme.php
      @@ -0,0 +1,152 @@
      +   * Gets a list of all regions for the theme.
      ...
      +  public function listAllRegions(): array {
      

      s/Gets/Returns

    2. +++ b/core/lib/Drupal/Core/Extension/Theme.php
      @@ -0,0 +1,152 @@
      +   * Gets a list of visible regions for the theme.
      ...
      +  public function listVisibleRegions(): array {
      

      s/Gets/Returns

    3. +++ b/core/lib/Drupal/Core/Extension/Theme.php
      @@ -0,0 +1,152 @@
      +   * Gets the name of the default region for the theme.
      

      s/Gets/Returns

    4. +++ b/core/modules/block/block.module
      @@ -123,8 +123,10 @@ function block_theme_initialize($theme) {
      +    /** @var \Drupal\Core\Extension\Theme $theme_extension */
      +    $theme_extension = \Drupal::service('theme_handler')->getTheme($theme);
           // Apply only to new theme's visible regions.
      -    $regions = system_region_list($theme, REGIONS_VISIBLE);
      +    $regions = $theme_extension->listVisibleRegions();
      
      @@ -166,9 +168,10 @@ function block_modules_installed($modules) {
      -  foreach (\Drupal::service('theme_handler')->listInfo() as $theme => $data) {
      -    if ($data->status) {
      ...
      +  foreach (\Drupal::service('theme_handler')->listInfo() as $theme => $theme_extension) {
      +    if ($theme_extension->status) {
      +      $regions = $theme_extension->listAllRegions();
      
      +++ b/core/modules/block/src/BlockForm.php
      @@ -186,7 +186,7 @@ public function form(array $form, FormStateInterface $form_state) {
      -      '#options' => system_region_list($theme, REGIONS_VISIBLE),
      +      '#options' => $this->themeHandler->getTheme($theme)->listVisibleRegions(),
      
      @@ -198,7 +198,7 @@ public function form(array $form, FormStateInterface $form_state) {
      -    $form['region']['#options'] = system_region_list($form_state->getValue('theme'), REGIONS_VISIBLE);
      +    $form['region']['#options'] = $this->themeHandler->getTheme($form_state->getValue('theme'))->listVisibleRegions();
      
      +++ b/core/modules/block/src/BlockListBuilder.php
      @@ -197,7 +209,7 @@ protected function buildBlocksForm() {
      -    $regions = $this->systemRegionList($this->getThemeName(), REGIONS_VISIBLE);
      +    $regions = $this->themeHandler->getTheme($this->getThemeName())->listVisibleRegions();
      
      +++ b/core/modules/block/src/Controller/BlockController.php
      @@ -110,9 +110,15 @@ public function demo($theme) {
      +    return $this->themeHandler->getTheme($theme)->listVisibleRegions();
      
      +++ b/core/modules/block/src/Entity/Block.php
      @@ -346,10 +347,20 @@ public function preSave(EntityStorageInterface $storage) {
      +      $theme_extension = \Drupal::service('theme_handler')->getTheme($this->theme);
      

      wondering why theme handler used to access extension instead of \Drupal\Core\Extension\ExtensionList::get(), it may not need decoration and could use built-in caching. It reminds me abou #2941155: ModuleHandler should not maintain list of installed modules now that ModuleExtensionList exists

    5. +++ b/core/modules/block/src/Controller/BlockController.php
      @@ -110,9 +110,15 @@ public function demo($theme) {
      +   * @deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use
      +   *   $this->themeHandler->getTheme()->listVisibleRegions() instead.
      ...
      +    @trigger_error(__CLASS__ . '::getVisibleRegionNames() is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use $this->themeHandler->getTheme()->listVisibleRegions() instead. See https://www.drupal.org/node/3015925', E_USER_DEPRECATED);
      

      should use 9.4.0, not clear why 8.8.0 used

    andypost’s picture

    +++ b/core/lib/Drupal/Core/Extension/Theme.php
    @@ -0,0 +1,152 @@
    +   * Whether the theme is installed or not.
    ...
    +   * @var int
    ...
    +  public $status;
    ...
    +   * The info array based on the theme's .info.yml file.
    ...
    +   * @var array
    ...
    +  public $info = [
    +    'engine' => 'twig',
    +    'regions' => [
    +      'sidebar_first' => 'Left sidebar',
    +      'sidebar_second' => 'Right sidebar',
    +      'content' => 'Content',
    +      'header' => 'Header',
    +      'primary_menu' => 'Primary menu',
    +      'secondary_menu' => 'Secondary menu',
    +      'footer' => 'Footer',
    +      'highlighted' => 'Highlighted',
    +      'help' => 'Help',
    +      'page_top' => 'Page top',
    +      'page_bottom' => 'Page bottom',
    +      'breadcrumb' => 'Breadcrumb',
    ...
    +   * The relative path to the theme engine extension file.
    ...
    +   * @var string
    ...
    +  public $owner;
    ...
    +   * The internal name of the theme engine extension.
    ...
    +   * @var string
    ...
    +  public $prefix;
    

    not sure this properties should remain public

    alexpott’s picture

    Re #97 yes they should - we have to address this in a follow-up to deprecate public access (or make them read-only). The issue here is that they are already in use like this. So we shouldn't change that here.

    Re #96.4 and .5 - that's this patch showing it's age :)

    alexpott’s picture

    Also...
    Gets a list of all regions for the theme. could be Lists all the theme's regions.
    And Gets a list of visible regions for the theme. could be Lists all the theme's visible regions.

    Gets and Returns seem unnecessary... we can use the verb from the method name.

    voleger’s picture

    StatusFileSize
    new42.24 KB
    new1.96 KB

    Addressed #96 .1 .2 .5

    sourabhjain’s picture

    Status: Needs work » Needs review

    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.

    andypost’s picture

    StatusFileSize
    new11.75 KB
    new41.81 KB

    re-roll for 9.5

    Status: Needs review » Needs work

    The last submitted patch, 103: 3015812-103.patch, failed testing. View results

    andypost’s picture

    the failed test does not work with stark somehow but classy is missing

    catch’s picture

    Version: 9.5.x-dev » 10.0.x-dev
    +++ b/core/modules/system/system.module
    @@ -877,25 +888,35 @@ function system_check_directory($form_element, FormStateInterface $form_state) {
      *
      * @return
      *   An array of regions in the form $region['name'] = 'description'.
    + *
    + * @deprecated in drupal:9.5.0 and is removed from drupal:10.0.0. Use
    + *   \Drupal::service('theme_handler')->getTheme()->listAllRegions() or
    + *   \Drupal::service('theme_handler')->getTheme()->listVisibleRegions()
    + *   instead.
    + *
    + * @see https://www.drupal.org/node/3015925
      */
     function system_region_list($theme, $show = REGIONS_ALL) {
    -  if (!$theme instanceof Extension) {
    -    $themes = \Drupal::service('theme_handler')->listInfo();
    

    9.5 is closed to new code deprecations (modules and themes are still fair game) to give contrib a stable API to port against.

    So I think this needs to be targeted at 10.1.x now.

    Also I think this is probably more in 'major task' territory than 'major bug', seems like the 'bug' aspect of this is just a docs issue.

    voleger’s picture

    Version: 10.0.x-dev » 10.1.x-dev
    Category: Bug report » Task
    Status: Needs work » Needs review
    StatusFileSize
    new41.9 KB
    new10.92 KB

    rerolled for drupal:10.1.x

    smustgrave’s picture

    StatusFileSize
    new2.04 KB
    new41.91 KB
    andypost’s picture

    systemRegionList($theme should be deprecated as well

    anybody’s picture

    Status: Needs review » Needs work

    NW as of #109

    smustgrave’s picture

    Status: Needs work » Needs review
    StatusFileSize
    new1.55 KB
    new41.86 KB

    Rerolled but for #109 can you provide more detail? I see that systemRegionList is deprecated.

    andypost’s picture

    Status: Needs review » Needs work
    +++ b/core/lib/Drupal/Core/Extension/ExtensionList.php
    @@ -542,25 +542,27 @@ public function getPath($extension_name) {
         // Add the info file modification time, so it becomes available for
         // contributed extensions to use for ordering extension lists.
         $info['mtime'] = $extension->getMTime();
    
    +++ b/core/lib/Drupal/Core/Extension/Theme.php
    @@ -0,0 +1,152 @@
    +    $this->info['mtime'] = $this->getMTime();
    

    somehow phpstan giving false positive here as the method executed via magic \Drupal\Core\Extension\Extension::__call()

    
      /**
       * Re-routes method calls to SplFileInfo.
       *
       * Offers all SplFileInfo methods to consumers; e.g., $extension->getMTime().
       */
      public function __call($method, array $args) {
        if (!isset($this->splFileInfo)) {
          $this->splFileInfo = new \SplFileInfo($this->root . '/' . $this->pathname);
        }
        return call_user_func_array([$this->splFileInfo, $method], $args);
      }
    
    
    smustgrave’s picture

    So this a bug with something else?

    andypost’s picture

    Assigned: Unassigned » mac_weber
    Status: Needs work » Needs review
    StatusFileSize
    new502 bytes
    new42.35 KB

    Let's see if this will allow to pass, thanks to @mglaman

    andypost’s picture

    Assigned: mac_weber » Unassigned
    StatusFileSize
    new502 bytes
    andypost’s picture

    StatusFileSize
    new539 bytes
    new42.35 KB

    Fix CS

    Status: Needs review » Needs work

    The last submitted patch, 116: 3015812-117.patch, failed testing. View results

    smustgrave’s picture

    Status: Needs work » Needs review
    StatusFileSize
    new1.02 KB
    new41 KB

    Fixed failing test.

    andypost’s picture

    Status: Needs review » Reviewed & tested by the community

    I think it's ready for RM review

    +++ b/core/lib/Drupal/Core/Extension/Extension.php
    @@ -8,6 +8,8 @@
    + * @method int|false getMTime()
    

    There's issue for that #2959989: Deprecate Extension::__call() magic

    voleger’s picture

    StatusFileSize
    new44.93 KB
    new5.75 KB

    Added deprecation tests for protected methods from the Block module

    voleger’s picture

    StatusFileSize
    new44.93 KB
    new1.59 KB

    Fixed the typo in the test method name

    quietone’s picture

    Status: Reviewed & tested by the community » Needs work
    Issue tags: +Needs change record updates

    Sorry folks, the CR has an @todo. Can someone attend to that?

    And I think the deprecation notices for the constants needs to be changed.

    +++ b/core/modules/block/src/BlockRepositoryInterface.php
    @@ -7,14 +7,25 @@ interface BlockRepositoryInterface {
    +   * @deprecated in drupal:10.1.0 and is removed from drupal:11.0.0.
    +   *   It will not exist in Drupal 11, use
    +   *   \Drupal\Core\Extension\Theme::listVisibleRegions()
    +   *   instead.
    +   *
    +   * @see https://www.drupal.org/node/3015925
    +   * @see \Drupal\Core\Extension\Theme::listVisibleRegions()
    ...
    +   * @deprecated in drupal:10.1.0 and is removed from drupal:11.0.0.
    +   *   It will not exist in Drupal 11, use
    +   *   \Drupal\Core\Extension\Theme::listAllRegions() instead.
    +   *
    +   * @see https://www.drupal.org/node/3015925
    +   * @see \Drupal\Core\Extension\Theme::listAllRegions()
    

    While I do not see a specific case for deprecating constants, I also see no reason that this can't be same as for deprecating method parameters. That would mean the second @see in each case is removed as is "it will not exist in Drupal 1".

    smustgrave’s picture

    Status: Needs work » Needs review
    Issue tags: -Needs change record updates
    StatusFileSize
    new2.42 KB
    new44.54 KB

    Took the description of this ticket for the CR.

    Updated the comments too based on #122

    andypost’s picture

    Status: Needs review » Needs work
    +++ b/core/lib/Drupal/Core/Extension/Extension.php
    @@ -8,6 +8,8 @@
    + * @method int|false getMTime()
    

    could be removed as already commited #2959989: Deprecate Extension::__call() magic

    +++ b/core/lib/Drupal/Core/Extension/Theme.php
    @@ -0,0 +1,152 @@
    +    $this->info['mtime'] = $this->getMTime();
    

    needs fix

    akram khan’s picture

    StatusFileSize
    new32.66 KB
    new22.54 KB

    Updated Patch and address #124

    akram khan’s picture

    StatusFileSize
    new73.35 KB

    Sorry for added wrong in #125
    when applied patch #123 on 10.1.x it throwing some error added screen shot as well

    viappidu’s picture

    Status: Needs work » Needs review
    StatusFileSize
    new44.08 KB

    Worked 3015812-123.patch addressing comments on #124
    Main difference (after #2959989: Deprecate Extension::__call() magic):
    $this->info['mtime'] = $this->getMTime();
    Becomes
    $this->info['mtime'] = $this->getFileInfo()->getMTime();

    andypost’s picture

    Status: Needs review » Reviewed & tested by the community

    Checked last patch and looks like it's ready

    quietone’s picture

    Status: Reviewed & tested by the community » Needs work

    Sorry folks. The patch is fail commit code checks.

    ameymudras’s picture

    StatusFileSize
    new43.97 KB

    #127 was not getting applied, I have made changes and hopefully, it should work. Couldn't generate the interdiff here because of "Whitespace damage detected in input"

    ameymudras’s picture

    Status: Needs work » Needs review
    quietone’s picture

    This is tagged for a release manager review. In #67 a question was asked regarding the compatibility of the deprecation being added with the one added in the previous minor version. At that time that this was adding a deprecation to 8.9. Those concerns are no longer relevant because there isn't a supported version of Drupal with those deprecations. I discussed this issue with xjm and we agree.

    I am removing the 'Needs release manager review' tag.

    needs-review-queue-bot’s picture

    Status: Needs review » Needs work
    StatusFileSize
    new147 bytes

    The Needs Review Queue Bot tested this issue. It either no longer applies to Drupal core, or fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".

    Apart from a re-roll or rebase, this issue may need more work to address feedback in the issue or MR comments. To progress an issue, incorporate this feedback as part of the process of updating the issue. This helps other contributors to know what is outstanding.

    Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

    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.

    voleger’s picture

    Introduced MR which contains #130 patch.

    andypost’s picture

    btw when core will require PHP 8.5 we can deprecate constants https://wiki.php.net/rfc/attributes-on-constants

    nicxvan’s picture

    Component: system.module » extension system
    xjm’s picture

    For the RM review mentioned in #132.

    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.

    berdir’s picture

    Status: Needs work » Needs review

    Updated and rebased, still running tests, but I think in a state where it can be reviewed.

    claudiu.cristea’s picture

    Status: Needs review » Needs work

    I think the const replacing enum is missing

    berdir’s picture

    Status: Needs work » Needs review

    Enum is not missing. Issue summary has an overview of all the changes here. Still expecting some test fails, but the worst one should hopefully be fixed now.

    nicxvan’s picture

    Got some comments on the MR, I need to think about this approach a bit,

    It is nice to remove the need entirely of these constants.

    In not sure about the decorating pattern, but it seems to make sense.

    berdir’s picture

    Status: Needs review » Needs work

    I think the main remaining thing for me is the decorate naming/concept. This has been discussed quite a bit already, in #46/#47 for example. I don't think this is a decorator. Yes, a decorator does return a new object, but it's IMHO one that adheres to the original interface. That's not the case there. Theme is a child class that adds its own methods and concepts that do not exist on the parent. Decorator specifically allows to decorate the same object multiple times.

    @dawehner in #47 also talks that we use composition and not inheritance, but that's not true, neither then nor now. Theme extends Extension, so it is inheritance. We're working with value objects and not interfaces, as far as I see it's impossible to use composition here if we want Theme objects to be used as more generic Extension objects too.

    The only idea I have right now is to use a less opinionated, more generic term for this method, possibly just alterExtension(), which would kind of match the system_info_alter hook. Possibly wrap, *if* it were actually composition. Is there a verb that we could use that translates to "Use specific subclass"?

    I'm also wondering if we should split the info parsing from the altering/subclassing. I'm not really convinced of the move of the defaults and mtime from ThemeExtensionList to the Theme constructor. I think we could keep it where it is and then we have to change fewer things. This started before ThemeExtensionList existed, so the context here changed quite a bit.

    I think my proposal would be something like this:

    foreach ($extensions as $extension) {
          $extension->info = $this->createExtensionInfo($extension);
          $extension = $this->alterExtension($extension);
    }
    

    I thought about using $info and passing that around as a second argument, but that's no longer an alter then and it's doing multiple things again.

    Speaking of mtime, I was confused about that one too, because I don't see any usage of this in core outside of tests. This was added 14 years ago in #1355526: Add a way to determine the date a module was added so the modules page can use it for sort, even then it was just verified in tests. I'd assume that mtime is rarely useful with composer and modern deployment processes. And package manager and stuff is going to deal with "enable a recently enabled module" in its own way.

    berdir’s picture

    Status: Needs work » Needs review

    I implemented my suggested change now, essentially restoring createExtensionInfo() and introducing subClassExtension() per suggestion from @alexpott This significantly simplifies the required changes in the Extension component.

    There is more that could be done in ThemeExtensionList. This moves the status and only the status from doList() to subClassExtension() as that was in decorate before as well. We could:

    a) further reduce the required changes here by restoring how status is set now and deal with that later.
    b) keep it as is.
    c) Move more logic from doList and set them through the constructor/methods. There are still several dynamic properties being set there, like module_dependencies, base_themes and sub_themes. But we can't move everything as parts depend on having all themes and then adding that information.

    I think c) is a rabbit hole that will blow this up considerably. I don't care much between a) or b). What I would suggest is that we mark Theme as either @final or real final, to make it clear that we do not support subclassing this. We want to change the constructor, add methods and properties later without having to worry about subclasses.

    There are possibly even more options. We could do the subclass in doList() and not introduce subClassExtension() at all, then the parent would not need any changes, but I think this is fine as an extension point for other extension types later on.

    nicxvan’s picture

    Yeah a or b make sense.

    To be honest this feels manageable at this point so leaving it as is is probably fine.

    If we want to be extra careful rolling that bit back it's the way to go.

    @final makes sense too, I'm strongly against real final.

    alexpott’s picture

    Re #147 I guess reading that and thinking about my comment about readonly - means that actually I'd be in favour of (a). Let's do a minimal change.

    Also +1 to final or @final. I think in this case a real final might be better considering we know that this issue is the start of quite a few changes necessary to make the Theme class behave the way we'd like.

    berdir’s picture

    @alexpott, see updates, is that what you had in mind? I also added a @final, I agree with you, but I'm doing my best to avoid any holy wars around final, either is fine for me.

    alexpott’s picture

    This looks great and yeah avoiding holy wars seems like a good idea.

    nicxvan’s picture

    Status: Needs review » Reviewed & tested by the community

    I think this is ready for the next steps, I took another in depth look at the code, and it's come together very nicely!

    I also edited the CR pretty heavily, it was targeted towards 8.7!!!

    godotislate’s picture

    Status: Reviewed & tested by the community » Needs work

    NW for merge conflict.

    nicxvan’s picture

    Status: Needs work » Reviewed & tested by the community

    Rebased, it was a comment on a deprecated method that was removed in the deprecation removal bunch of issues.

    godotislate’s picture

    Status: Reviewed & tested by the community » Needs work

    The phpstan baseline needs a rebase. I also added comments to the MR.

    Also, I know the "decorate" or "subclassExtension" terminology has already been much discussed, so I don't want to block this, but I have an alternate idea that could be done in a follow up if people think it's worthwhile. Instead of copying an Extension object to a subclass object, we could do this:

    Add an optional "$extensionClass" constructor parameter and class property to ExtensionDiscovery, so that it looks like this:

      public function __construct(string $root, $use_info_parser = TRUE, ?array $profile_directories = NULL, ?string $site_path = NULL, protected string $extensionClass = Extension::class) {
        $this->root = $root;
        $this->profileDirectories = $profile_directories;
        $this->sitePath = $site_path;
        $this->infoParser = $use_info_parser ? new InfoParser($root) : NULL;
      }
    

    And in ExtensionDiscovery::scanDirectory() change
    new Extension($this->root, $type, $pathname, $filename)
    to new $this->extensionClass($this->root, $type, $pathname, $filename).
    The constructor of Theme would need to be changed to match Extension, so there'd be some brittleness there. The alternative would be to put it in a createExtension() method, but then every ExtensionList would need a corresponding discovery class with createExtension overridden.

    In ThemeExtensionList::getExtensionDiscovery():

      protected function getExtensionDiscovery() {
        return new ExtensionDiscovery($this->root, extensionClass: Theme::class);
      }
    
    nicxvan’s picture

    Thank you for the review!
    I reviewed all of your suggestions they look great. I will hold off on applying them to preserve my ability to rtbc.

    In reviewing your suggestions I noticed there are two properties we no longer need in the theme extension object as well.

    Happy to create a follow up for: 155.

    berdir’s picture

    I think the main concern I have with #155 and pushing the Theme object down into discovery is that we'd need to forever support partial theme objects. All the theme stuff that depends on the .info.yml content would need to be optional/nullable and then added during a later build phase, so we'd need to keep track of partial/finalized objects or something like that. If not for that I'd be fine exploring this also in this issue, but a follow-up to try that seems fine.

    godotislate’s picture

    Discussed with @nicxvan: prefix and owner properties on Theme should be deprecated here and then removed in a follow up for D12.

    Consulting with other release managers about the deprecated constants and protected methods.

    berdir’s picture

    Status: Needs work » Needs review

    As discussed on slack, removed two properties, I realized that extension objects allow dynamic properties and we have plenty of those, so it's fine to remove them, should not cause any issues in 11.x, although we might want to do do a 11.x MR just to be certain before merging.

    The remaining thing then is the deprecated controller/form method and how to handle that.

    nicxvan’s picture

    I reviewed this, looks great. I'm not going to mark it since we are waiting on the protected method question.

    godotislate’s picture

    Discussed with @catch and @xjm, and the general sentiment is that we care a lot about removing usage of deprecated code paths when they are being deprecated, to help make sure that they actually can be deprecated.

    So I gave this issue some more though in light of that. Since protected methods are not part of our BC promise, I looked at whether we could just remove them directly in 11.4. In contrib, there is of BlockListBuilder::systemRegionList() (https://git.drupalcode.org/project/block_ajax/-/blob/3.x/src/AjaxBlockLi...), so to minimize disruption, I think it's fine to go with deprecate the methods. But I still think it's best to remove the usage of the system_region_list() and the constants in those methods, and it's consistent with the change to BlockController::getVisibleRegionNames() anyway. I also took a quick peek at #1452100: Private file download returns access denied, when file attached to revision other than current, and compared to there, removing the deprecated function usage is straightforward enough.

    berdir’s picture

    Accepted the two suggestions for the implementation of the method, but not the constant changes, did I understand you correctly with that?

    > and compared to there, removing the deprecated function usage is straightforward enough.

    It certainly is. I'm happy as long as we don't imply that doing it here also means we must do it there and evaluate that separately considering the complexity there.

    godotislate’s picture

    It's fine to go forward without the constant changes.

    nicxvan’s picture

    Status: Needs review » Reviewed & tested by the community

    In that case I think this is ready again!

    • godotislate committed b30fe98d on main
      feat: #3015812 Introduce new Theme extension object and properly...

    godotislate’s picture

    Status: Reviewed & tested by the community » Patch (to be ported)

    Thanks to everyone who helped on this one over. Did my best to update credit.

    Committed b30fe98 and pushed to main. Thanks!

    There's a merge conflict on block.module for 11.x, so moving to Patch to be ported for that.

    Also just noticed that the URLs for the CR for the constant deprecations in system.module are wrong. Will push a fix for that shortly. Please make sure to include those changes in the 11.x port.

    • godotislate committed 1ab4bfda on main
      refactor: #3015812 Introduce new Theme extension object and properly...

    berdir’s picture

    Status: Patch (to be ported) » Needs review

    Created a new 11.x MR, including the follow-up.

    Had to fix/reintroduce a few additional changes that aren't in main. The migrate tests need the fix for new BlockHooks(), and deprecatation test method in core/tests/Drupal/Tests/Core/Extension/ThemeHandlerTest.php needed to be adjusted as well.

    needs-review-queue-bot’s picture

    Status: Needs review » Needs work
    StatusFileSize
    new91 bytes

    The Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".

    This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.

    Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

    berdir’s picture

    Status: Needs work » Needs review
    Issue tags: +no-needs-review-bot

    bot is confused about the 11.x branch I think.

    needs-review-queue-bot’s picture

    Status: Needs review » Needs work
    StatusFileSize
    new91 bytes

    The Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".

    This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.

    Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

    smustgrave’s picture

    Version: main » 11.x-dev
    Status: Needs work » Reviewed & tested by the community

    Surprised it ignored the tag

    smustgrave’s picture

    Status: Reviewed & tested by the community » Needs review

    Meant review per the bot

    nicxvan’s picture

    Status: Needs review » Reviewed & tested by the community

    Ok I reviewed this, pretty tedious.

    Only differences were:
    One additional case in ThemeHandlerTest needed updating to Theme.
    3 or 4 Migrate tests needed fixing for the block rebuild call.

    The tests are failing, but only committers have access to review this branch right now so please kick it back if it's a real failure.

    nicxvan’s picture

    • godotislate committed 0f4d171d on 11.x
      refactor: #3015812 Introduce new Theme extension object and properly...
    godotislate’s picture

    Status: Reviewed & tested by the community » Fixed

    Committed 0f4d171 and pushed to 11.x. Thanks!

    Now that this issue is closed, review the contribution record.

    As a contributor, attribute any organization that helped you, or if you volunteered your own time.

    Maintainers, credit people who helped resolve this issue.

    Status: Fixed » Closed (fixed)

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