Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Load Drush services for themes as well as modules. #3089

Conversation

NickDickinsonWilde
Copy link

In Drush 8.x themes could define Drush commands as well as modules. In 9.x, this is no longer the case.
This patch re-implements that.

// Also add Drush services from all modules
// Also add Drush services from all modules & themes.
$extensions = $this->getConfigStorage()->read('core.extension');
$this->moduleList += isset($extensions['theme']) ? $extensions['theme'] : [];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if this is prudent. This field is not only used by Drush, but is used throughout Drupal. Adding the themes to the module list might have unintended consequences. It would probably be much better to simply build a list of themes in local variables, and then have a separate loop over $theme_filenames to call addDrushServiceProvider.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmmm... yes that does make sense; I wasn't considering that - I was thinking this only affects Drush. Ah well... quite easy to modify. I'll swap over to local/adjust the implementation. A bit more code/close to duplication but seems very worth it to not be altering core data without tons of testing
thanks for the review :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could have less duplication by merging the module list and theme list, but I don't think you should do that either. You're not supposed to ever have a module and a theme with the same name, but I've seen that violated before, so best keep the lists separated (unless Drupal is actually preventing that now -- have not tried recently).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I've seen that before too, which should have made me think about keeping it separate

$listing->setProfileDirectories($profile_directories);

// Now find themes.
$this->moduleData += $listing->scan('theme');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment - not sure that it is safe to modify $this->moduleData like this.

@greg-1-anderson
Copy link
Member

This is great, thanks! I'm not 100% sure about my comments, but some of the field access here looks potentially unsafe. If it would work equivalently to use local variables in those places, that would be preferable.

To facilitat this, also have to add the theme namespaces to the autoloader.
@@ -60,6 +63,7 @@ protected function initializeContainer()
if ($this->shouldDrushInvalidateContainer()) {
$this->invalidateContainer();
}
$this->classLoaderAddMultiplePsr4($this->getModuleNamespacesPsr4($this->getThemeFileNames()));
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has to be added somewhere to add the theme folders to the autoloader. I did a bit of investigating and I think this is the best spot but it's the item I'm least sure about.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did this happen as a side effect of adding the themes to the module list before?

Does the active theme have its autoloader added?

Copy link
Author

@NickDickinsonWilde NickDickinsonWilde Oct 22, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, didn't need it before because, one of the uses of $this->moduleList was propagating the autoloader. (that line is basically copy & paste but with module changed to theme)

All enabled themes get their autoloader added by this - in Drupal core, themes don't get added to the autoloader at all.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This part is the hang up for me. I'm worried about the unpredictable consequences of Drush adding theme classes that Drupal does not add to the autoloader. Maybe this is no big deal; each theme should be uniquely namespaced, and if no one references the class, then it should not matter if it's autoloadable. I am concerned by the fact that this happens all the time when using Drush, whether or not a theme command is being executed. If this did cause a change in behavior, it could be really difficult to track down.

It might be safer to only add the autoloader when a theme command is executed. This is what the Terminus plugin mechanism does. The consequence of doing something similar for themes is that theme commands would have access to all of the classes defined in the theme, whether or not the theme was enabled, but hooks in the theme only have access to the command / hook classes in disabled themes (but should still have access to all classes in the enabled theme).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm... I'm 95% sure I can simply implement that with a bit of copy/paste from there and editing. Investigating, thanks :)

Copy link
Member

@greg-1-anderson greg-1-anderson Nov 7, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Terminus has an autoload file that it can include, which is probably not going to be the case here. You may need to instantiate your own class loader. The Composer class loader works well in this capacity. I've done so successfully in the past, but at the moment I can't quite remember where, or I'd provide a link.

@ericmulder1980
Copy link

Always great to find out there is a working patch for problems you come across. We really need this patch for the ZURB Foundation theme as creating subthemes currently does not work. More info at : https://www.drupal.org/node/2920472

I can confirm that the patch works. Any possible ETA on when this could be merged? Perhaps a beta-9 release?

@weitzman
Copy link
Member

The PR wont be merged as is. The next step is in #3089 (comment)

@NickDickinsonWilde
Copy link
Author

Finally got some time today to work on this more.

I didn't end up implementing a runtime autoload function for the theme namespaces. A quick investigation revealed that was going to be more complicated than I was first suspecting.
So I'm implemented it slight differently:

  • Only themes with a Drush services yml will be added to the autoloader
  • Only the theme/src/Commands folder is added to the autoloader.

I believe this should reduce the risk of accidental collisions sufficiently as well as reducing possibility for accidental effects. Anyways, I look forward to hearing your thoughts on whether that resolves your concerns.

if ($this->themeNames) {
return $this->themeNames;
}
$extensions = $this->getConfigStorage()->read('core.extension');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets use a Drupal API like \Drupal::service('theme_handler')->listInfo(); or system_list('theme')

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't do that unless we load core/includes/module.inc. At this point in the bootstrap process, it isn't yet which means system_list() is unavailable and ->listInfo() uses it.

@@ -203,4 +214,77 @@ protected function addDrushServiceProvider($serviceProviderName, $serviceYmlPath
$this->serviceYamls['app'][$serviceProviderName] = $serviceYmlPath;
}
}

/**
* populates theme data on the filesystem.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Start with upper case.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

* @see Drupal\Core\DrupalKernel::moduleData().
*/
protected function themeData($theme_list)
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not too clear why we need this code. Why is iterating over all enabled themes sufficient? Are we wanting to catch the case where Drush integration is in the parent thee? What does simpletest have to do with anything?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've simplified this slightly. This is necessary to populate the Drupal path cache so that drupal_get_path() and similar function work for themes. I think we can remove the simpletest stuff as we're not loading themes for testing - it is in the core Drupal\Core\DrupalKernel::moduleData() but reviewing it, we don't need it for this use case, so removed.

@NickDickinsonWilde
Copy link
Author

@weitzman or @greg-1-anderson either of you have any time to give this a re-review with those changes?
thanks

@weitzman
Copy link
Member

I took a quick look and still dont feel especially comfortable with this. I'm very sensitive to maintenance/complexity costs these days. Lets see what @greg-1-anderson thainks.

@weitzman
Copy link
Member

weitzman commented Feb 8, 2018

Folks wanting this should work on modernizing Drupal's theme system. I'd like to highlight catch's excellent comment on this issue.

@weitzman
Copy link
Member

weitzman commented Mar 4, 2018

i'm going to cll this 'wont fix'. please work in drupal core to resolve this.

@weitzman weitzman closed this Mar 4, 2018
@NickDickinsonWilde
Copy link
Author

Keep forgetting to comment back. I totally understand wanting to minimize stuff like this diverging from Drupal loader/maintainability etc and makes sense. Thanks for all the review and discussion. When I have time I'll check out that issue on the core queue you linked, thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants