Problem/Motivation

hook_install() allows developers to do programatic things during a module or install profile installation. For example, the standard profile uses hook_install() to create 2 shortcut content entities. This can be problematic because if the install is done during configuration import configuration entities are created after any module installs have been done. This is because it is possible to change a configuration entity and make it depend on things that are yet to be installed.

This problem has affected #2788777: Allow a site-specific profile to be installed from existing config and the Lightning install profile.

Proposed resolution

Add documentation to hook_install() to make developers aware of the problems of relying on configuration entities during hook_install() and ways in which modules have got around this.

Add an argument to hook_install $is_syncing so that its front-and-foremost that hook_install implementations need to consider this.

We can use this in forum.install in core as the test-case.

Remaining tasks

User interface changes

None

API changes

None

Data model changes

None

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

alexpott created an issue. See original summary.

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

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

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.

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.

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.

mxr576’s picture

Bump!!! =]

I had the following problem:

The built-in config installer and (also the config_installer contrib) are giving me some hard times today...
* There are module A and module B.
* Module B depends on module A.
* Module A provides an entity type with entity view and form display modes and some fields. XY field on the entity type is not displayed by * default.
* Module B would like to make XY field visible on the entity type's form display mode when it gets installed.
We implemented this in a hook_install() and it worked perfectly, but with config installer(s) it does not work. The form display mode config does not exist when Module B's install hook is running, although Module A is already enabled. Tried to clear various caches, without any luck... Also checked some config import-related events, none of them seemed a reasonable replacement for this task.
Who has any idea what is going on here? (Drupal 8.7.10)

@berdir Highlighted on Slack that I should run if (!\Drupal::service('config.installer')->isSyncing()) {} in install hooks every time before I try to modify a config. That fixed the problem.

larowlan’s picture

Issue tags: +DrupalSouth 2019
larowlan’s picture

Title: Improve hook_install() documentation to include recommendations for config import » Improve hook_install() to include recommendations for config import and pass an $is_syncing argument
Issue summary: View changes

@alexpott mentioned in slack that it might be worthwhile to pass an is_syncing argument to the hook so it was more obvious that you needed to make a decision based on that.

I agree with that decision, updating the IS.

larowlan’s picture

Status: Active » Needs review
FileSize
3.3 KB

something like so

DanielVeza’s picture

+++ b/core/lib/Drupal/Core/Extension/module.api.php
@@ -220,15 +221,32 @@ function hook_modules_installed($modules) {
-function hook_install() {
+function hook_install($is_syncing) {

Could the param for this be $is_syncing = FALSE just to avoid changes being made to all existing hook_installs? Is that possible in this case?

larowlan’s picture

Could the param for this be $is_syncing = FALSE just to avoid changes being made to all existing hook_installs? Is that possible in this case?

This is just a sample implementation, and believe it or not, hooks don't have to add the argument if they don't want too (i.e. it will keep working without everyone having to change their implementations).

This is not dissimilar to hook_update_N if you want to use the $sandbox variable, you declare it as an argument, but if you don't it still keeps working. So I think we're good here - as you can see from the patch - I didn't change any of the other implementations, only forum module, but tests still passed.

alexpott’s picture

<3 this change. One look makes me wonder why didn't we get round to this earlier.

+++ b/core/lib/Drupal/Core/Extension/module.api.php
@@ -220,15 +221,32 @@ function hook_modules_installed($modules) {
+ *   TRUE if the module is being installed as part of a configuration import. In
+ *   these cases, your hook implementation should not make any changes to
+ *   configuration objects or entities.
...
+    // Create a default forum so forum posts can be created.
+    $term = Term::create([

Terms are content :D - I know this has been copied from the forum example but that's a bit special.

Funnily enough the only core examples are all about not importing content on install. So perhaps we should broaden the docs to be something like...

TRUE if the module is being installed as part of a configuration import. In these cases, your hook implementation needs to carefully consider what changes, if any, it should make. For example, it should not make any changes to configuration objects or entities.
larowlan’s picture

DanielVeza’s picture

That all looks good to me. Patch applies, standard profile and forum module all correctly enable. The install tasks for the forum module create the term as expected. All looks good to me.

I think we should change core/profiles/demo_umami/modules/demo_umami_content/demo_umami_content.install to use the new system as well, since that is using the service call. I couldn't find any more examples besides that in core.

Happy to RTBC once that is done or if you have a reason why you don't want to do that in this patch. :)

alexpott’s picture

Issue tags: +Needs change record

+1 to changing the Umami install hook too. We'll also need a change record to tell developers about this. As it is not mandatory we don't have any BC implications but a CR is still useful.

larowlan’s picture

alexpott’s picture

Status: Needs review » Needs work

Oops it's not demo_umami_install()...

It's demo_umami_content_install() and demo_umami_content_uninstall()... which actually brings about the excellent point that we should add this to hook_uninstall() too. Which in turn makes me ponder if this is something we should add to hook_modules_installed() and hook_modules_uninstalled().

alexpott’s picture

And that triggered more memories... we have \Drupal::isConfigSyncing() too... so we need to update media_library_install() too. \Drupal::isConfigSyncing() is very prevalent in contrib.

alexpott’s picture

I think adding to hook_modules_installed / uninstalled is a good idea.

Found at least one example that would benefit in contrib...

/**
 * Implements hook_modules_installed().
 */
function paragraphs_library_modules_installed($modules) {
  if (\Drupal::isConfigSyncing()) {
    return;
  }
larowlan’s picture

Status: Needs work » Needs review
FileSize
5.98 KB
8.58 KB

Oops it's not demo_umami_install()...

Yep, don't rush stuff

Fixed and added the equivalent for uninstall, and modules_installed, modules_uninstalled

DanielVeza’s picture

+++ b/core/lib/Drupal/Core/Extension/ModuleInstaller.php
@@ -354,6 +354,8 @@ public function install(array $module_list, $enable_dependencies = TRUE) {
+    $config_installer = \Drupal::service('config.installer');
+    $sync_status = $config_installer->isSyncing();

Nitpick - Can this be one-lined? Also happy to be overridden on this.

larowlan’s picture

DanielVeza’s picture

So sorry - Just did a last review and there is still one more - core/modules/media_library/media_library.install with !\Drupal::isConfigSyncing() in it.

larowlan’s picture

DanielVeza’s picture

Status: Needs review » Reviewed & tested by the community

Patch still applied, All config sync checks in install/uninstall hooks are changed.

Change record makes sense to me. Happy to mark as RTBC - Assuming the tests all come back green. :)

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

Committed and pushed c72abf07aa to 9.0.x and c3c3bc8d4c to 8.9.x. Thanks!

+++ b/core/lib/Drupal/Core/Extension/module.api.php
@@ -180,14 +180,22 @@ function hook_module_preinstall($module) {
+ * @param bool $is_syncing.

@@ -220,15 +228,26 @@ function hook_modules_installed($modules) {
+ * @param bool $is_syncing.

@@ -253,14 +272,22 @@ function hook_module_preuninstall($module) {
+ * @param bool $is_syncing.

@@ -278,13 +305,22 @@ function hook_modules_uninstalled($modules) {
+ * @param bool $is_syncing.

I removed the fullstop on commit.

FOUND 4 ERRORS AFFECTING 4 LINES
----------------------------------------------------------------------
 183 | ERROR | [x] Doc comment parameter name "$is_syncing." must not
     |       |     end with a dot
 231 | ERROR | [x] Doc comment parameter name "$is_syncing." must not
     |       |     end with a dot
 275 | ERROR | [x] Doc comment parameter name "$is_syncing." must not
     |       |     end with a dot
 308 | ERROR | [x] Doc comment parameter name "$is_syncing." must not
     |       |     end with a dot

  • alexpott committed c72abf0 on 9.0.x
    Issue #2914174 by larowlan, alexpott, DanielVeza: Improve hook_install...

  • alexpott committed c3c3bc8 on 8.9.x
    Issue #2914174 by larowlan, alexpott, DanielVeza: Improve hook_install...

Status: Fixed » Closed (fixed)

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