Problem/Motivation
In #2788777: Allow a site-specific profile to be installed from existing config we excluded profiles from being installed that contain hook_install implementations.
The reasons for this was to exclude complexity, limit the scope of the issue and getting it done.
The complexity can be summarized as:
Install hooks in profiles were so far only called when a site was installed and after all the listed modules were installed and all the configuration was imported. Thus hook_install implementations were able to make a lot of assumptions about the state of the site when the code was executed.
When installing from configuration the configuration is synchronized and the install hooks are called as the extensions are installed and then the configuration is imported. In addition a profile can list modules to install which are not dependencies and, therefore, these modules can be uninstalled. The install hook can therefore also not rely on all the modules being installed.
The canonical example being standard expecting the contact module to be installed.
Right now if a profile wants to be able to be installed from config and still do something extra it has to not implement hook_install and instead define a custom install step.
Proposed resolution
to be defined
Temporary Workaround
Solution 1: Change profile to minimal in core.extension.yml
Changing profile from standard to minimal in core.extension.yml may do the trick.
[...] change the profile setting AND the profile name in the list of installed modules. Even though it's not a module it will still appear there so you need to change both instances.
From Drupal 8: Install Site From Existing Configuration by @philipnorton42.
If none of your modules or themes contain the string "standard", you can use this to replace via the command line:
sed -i 's|standard|minimal|g' core.extension.yml
Solution 2: Custom module
See @slucero's comment in #25. There are differences with hook_install, see hook_install_tasks for details. This is an example of how it can be used, replacing "PROFILE" with your profile's machine name:
/**
* Implements hook_install_tasks().
*/
function PROFILE_install_tasks(&$install_state) {
$tasks = [
'PROFILE_install_content' => [
'display_name' => t('Install default content'),
'type' => 'normal',
]
];
return $tasks;
}
/**
* Callback function to install default profile content.
*
* @see PROFILE_install_tasks()
*/
function PROFILE_install_content() {
...
}
Remaining tasks
find solution
implement it
test it
commit it
User interface changes
none probably.
API changes
to be seen.
Data model changes
none.
| Comment | File | Size | Author |
|---|---|---|---|
| #109 | CleanShot 2024-10-03 at 10.50.22@2x.png | 233.71 KB | alexpott |
| #91 | 2982052-nr-bot.txt | 6.04 KB | needs-review-queue-bot |
Issue fork drupal-2982052
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:
- 2982052-allow-an-install
changes, plain diff MR !4330
- 10.1.x
changes, plain diff MR !3138
Comments
Comment #2
bircherPossible solutions:
Comment #4
bircherI am in favour of re-tagging this issue as a bug in 8.6 and solve it by excluding profiles install hooks from executing when configuration is syncing. People not agreeing to this may change it back to task for 8.7.
The reason is that one can only have one profile and can not uninstall it, so it is reasonable to say that this hook was only ever intended to run when a site is created and not when a new instance is installed from given configuration. Then we can add a new hook if we really want or let distributions install their things via normal modules.
This would make the install from configuration workflow work with sites started with the standard profile. This is currently not possible and hance a bug.
Comment #5
webchick@bircher brought this up on the weekly cross-team initiative call... my 2 cents is that hook_install() is generally used for things like customizing the installation experience (setting defaults; inserting steps), and that whatever was done inside hook_install() will have already been done by the time the configuration is exported and used as installation fodder for the new site. So I think it would be fine to just skip running hook_install(). #notaframeworkmanager ;)
Comment #6
grimreaperHello,
I don't agree that everything in profile hook_install can be done in config. Even if it can be easily moved into a "my_profile_core" module install hook.
For example, let's take the standard profile install hook:
=> config
=> config
=> config
=> not config. (A part that I keep in my custom profiles. (kill uid 1 :D))
=> Can be rebuilt with cache rebuild.
=> not config. (I personnally don't generate default menu link in that way. I prefer migrate import from CSV.)
=> config
=> config
=> Not config. (Personnaly I don't use the shortcut module (maybe I should use it more).)
=> config
=> config
So yes, mostly config, But some parts to create default content entities.
As said, it can easily be done in a custom module hook_install.
My 2 cents on hook_install.
Comment #7
bircherI would argue that sites started from standard not getting the shortcuts set up when re-installing from config is better than not being able to do so at all.
We can always create a followup to this implementing a different hook and being more careful.
The whole reason for excluding profiles with hook install implementations was that they were wild west and were allowed to assume things incompatible with installing from config due to timing of the hook invocations and the config and other modules being installed.
here a first stab at this.
Comment #9
tstoecklerI actually opened #2990776: Remove config-editing parts from standard_install() in favor of exported configuration for #6 a while back, would love a review over there ;-)
Comment #10
mpotter commentedNot sure we want to force this assertion. There are cases with layout_builder where a block_content is added to the home page and after the config-import runs, the block_content is later imported (e.g. something like default_content). Thus I don't think the "block is broken/missing" should be an install blocker.
EDITED: Oh, nevermind, failed to notice that assert is in the TEST
Comment #11
mpotter commentedRerolling on 8.7 to trigger tests again.
Comment #13
mpotter commentedTrying again with 8.7 actually selected in the test run!
Comment #15
mpotter commentedThis should be setUpProfile not setUpSite I think.
Comment #17
bircherThanks for re-rolling the patch.
The attached version extends the test we copied before and makes it clear that it is just adding the hook. We could do just that maybe.
It also fixes the test by removing the condition in the form.
Comment #18
bircherwhat I just wrote above.
Comment #21
jhmnieuwenhuis commentedI tested with latest 8.7.x from http://git.drupal.org/project/drupal.git
Patched with 2982052-18.patch.
I get an error :
Error: Call to a member function getCacheTags() on null in Drupal\shortcut\Entity\Shortcut->getCacheTagsToInvalidate() (line 167 of /var/www/html/prrls-rmltst/web/core/modules/shortcut/src/Entity/Shortcut.php).
See attachment for complete log.
If i edit core/modules/shortcut/src/Entity/Shortcut.php the issue does not appear :
near line 167 I commented one line and added return array();
• /**
• * {@inheritdoc}
• */
• public function getCacheTagsToInvalidate() {
• // return $this->shortcut_set->entity->getCacheTags();
• return array();
• }
Comment #22
bircherAttached an updated patch.
I am not sure the error in #21 is a problem with drush or with the standard profile or something different.
Comment #23
jhmnieuwenhuis commentedTested the #22 patch with the latest 8.7.x from drupal.git.
Issue #21 still exists but apart from that it works fine !!
Drush version I use is 9.5.2
Comment #25
sluceroI encountered this issue while trying to prepare a custom install profile for use with the core v8.6 update to install from existing configuration. We had previously been using
config_installerand used an install hook in the profile to install default content.I was able to work around this issue without the previously posted patch by moving the install hook into a custom install task instead.
Comment #26
MakeLimeade commentedMaybe I'm dense or too late, but wouldn't a good fix to be if hook_install exists, don't do config import for the module except through a specific function call within hook_install? Then we can choose the order of operations, add tests for existence, etc.
Comment #27
dslobodyanik commentedPatch #22 works for me.
I tested with a fresh install of 8.8.0-dev and drush 9.6.2.
Comment #28
alexpottHere's another idea. The stuff we're doing in hook_install() in things like demo_umami and standard is now only config creation. How about we somehow put configuration into a read-only mode during a profiles hook install? That way you could install umami from configuration and end up with content and user 1 would be in the administrator group.
Comment #29
mlncn commentedI am also getting the same error with the patch in #22 as was reported in #21 when using the dev version of config_actions:
Error: Call to a member function getCacheTags() on null in Drupal\shortcut\Entity\Shortcut->getCacheTagsToInvalidate() (line 167 of /var/www/html/web/core/modules/shortcut/src/Entity/Shortcut.php).(With the 1.1 version of config_actions, i just get
Drupal\Core\Entity\EntityMalformedException: The entity does not have an ID)Comment #30
tstoecklerShameless plug for #2357215: Clean up hook_install() in Standard Install Profile which needs a review. That will allow Standard to be installed from configuration, we could handle Umami similarly in a follow-up. And in fact it might serve as a template for custom profiles to do the same which would alleviate the need for this patch. (I don't have anything against this in particular, it just seems that it's a bit tricky/controversial going by the discussion above, so just wanted to note an alternate approach.)
Comment #31
shrop commentedComment #32
andypostre-roll latest patch
Comment #34
josephdpurcell commentedI did not test the patch. However, since I ran into this issue and was looking for a workaround, seeing @slucero's comment in #25 I was able to try it and confirm it works.
I'm adding that as a workaround in the description to help others who may venture here.
Comment #35
tstoecklerComment #36
shrop commentedPatch in #32 would not apply for me for Drupal 8.8.1 on the Guardr Distro Project (https://github.com/guardrdistro/guardr-project).
Ran a couple of tests for patch in #32 and they do not apply to 8.8.x-dev so something is different there since last patch work and probably needs a re-roll.
Tests ran:
Comment #37
keopxHere reroll
Comment #39
alexpottThis issue is now a direct descendant of the CMI2 roadmap. @bircher and I plan to discuss this in the next CMI meeting.
Comment #40
damienmckennaIn D9 the line in ModuleInstaller.php has changed in core so it now passes a third argument to the invoke() method:
Should that argument still be passed in?
Comment #41
damienmckennaComment #43
loopy1492 commentedThis is our current work-around. We're importing the configuration post-install instead of installing from configuration. This is not ideal because the default entities created during site install cause configuration errors (such as shortcut_set_default).
Comment #44
loopy1492 commentedComment #45
loopy1492 commentedComment #46
loopy1492 commentedI've reconfigured the patch for 8.8.x and it seems to be throwing the same "Title Found" error from behat which I still haven't explored what that's all about.
But when I run blt setup locally, this is the result:
It seems like all the current patch does is remove all the conditionals from the code and doesn't actually resolve the underlying issue of the hook_install calls not evaluating for the standard profile when we try to install from config as indicated in https://www.drupal.org/node/2897299 . We just need to figure out how to execute all the install hooks prior to config import. I guess that's what the setup:drupal:install{import-config:true} does, but the only documentation of any of this seems to be located in drupal.org issues.
How BLT, Core, and Pipelines interact really needs to be fleshed out in the documentation especially considering how vehemently it's been recommended by Acquia. There seems to be a huge disconnect between the folks supporting this stuff and those of us on the front lines are the ones suffering for it.
Is it too much to ask the community to speak with one voice on this?
Comment #47
shrop commentedThis finding/update may point to why work could focus more on #2924549: Invoke hook after a site install is complete since #2357215: Clean up hook_install() in Standard Install Profile has been postponed?
- https://www.drupal.org/project/drupal/issues/2357215#comment-13442146
Comment #49
hardik_patel_12 commentedRe roll for 9.1.x and solving coding standards error also.
Comment #51
hardik_patel_12 commentedSolving failed test cases.
Comment #53
benjifisherThe testbot reports that the patch does not apply, and I see the same thing when I try to apply it to Drupal 8.9.9 with Composer. I guess the patch needs a reroll.
Comment #54
kishor_kolekar commentedComment #55
xavier.massonReroll the patch #51 for the Drupal 8.9.9.
Comment #56
alvar0hurtad0Doing the review.
Comment #57
alvar0hurtad0The patch does not apply on the 9.2.x branch,
I'm currently doing the reroll.
Comment #58
alvar0hurtad0This patch seems to resolve the conflict with this already commited patch:
https://git.drupalcode.org/project/drupal/commit/21689a39e8373eeac06d60e...
Comment #59
alvar0hurtad0Stop working on it for today.
Comment #60
estoyausenteThe patch apply properly, thanks for the reroll @alvar0hurtad0
Comment #61
mario.elias commentedCan someone assist? I am getting an error using #55.patch. I am using
Drupal version : 8.9.11,
Drush version : 10.3.6.
----
----
Thank you in advance.
Comment #62
scotwith1tThanks for the re-roll. Patch at #58 applies to D9.2-dev but when running
drush si --existing-config, getting this:Comment #63
johne commentedI got the same result "Error: Call to a member function getCacheTags() on null in Drupal\shortcut\Entity\Shortcut->getCacheTagsToInvalidate() (line 166 of /var/www/docroot/core/modules/shortcut/src/Entity/Shortcut.php)." using D9.1.4
Comment #65
bbuchert commentedPatch in #58 can not be applied with 8.9.15
Comment #66
jlatorre commentedI have the same issue on Drupal 8.9.14 after applying patch #55
[error] Error: Call to a member function getCacheTags() on null in Drupal\shortcut\Entity\Shortcut->getCacheTagsToInvalidate()Comment #67
jlatorre commentedWorkaround: Downgrading from standard to minimal profile using either profile switcher or a hook update, then reexporting the core.extension file. Then I am able to reinstall a new site from config without breaking the already installed website from initial standard profile:
Comment #68
mirom commentedRerolling patch for head 9.2
Comment #70
alexpott@jlatorre another way to achieve this is to use install profile generator and decouple from all core profiles - see https://www.drupal.org/project/install_profile_generator
Comment #71
kartagisI've installed the drupal commerce distribution and I got back these when I did a drush -y cim
Comment #72
sgourebi commentedGet started from #54 and fixed some issues with the profile standard.
Fixed duplicated entries in database in user.install
Fixed duplicated entries in database in node.install
Fixed the invalidation of the cache of shortcut entity.
Tested on Drupal 9.2.6, PHP 7.4.23 and MySQL 5.7.29
Comment #73
ankithashettyFixed custom command failure errors in #72.
Changing status to "Needs review" since there are patches to be reviewed in #68, #72, #73.
Thanks!
Comment #74
sandboxplWhen testing patch #73, installing everything from the scratch using existing config, triggers profile's install hook twice, it's also calling install hook of other modules twice.
Tested with:
- Drupal 9.2.5
- composer 2.1.3
- cweagans/composer-patches 1.7.1
- drush 10.3.4
Putting breakpoints here and there I can see that install_install_profile() and MYPROFILE_install() hook is executed twice.
I am able to reproduce this behavior when installing the project with drush and when installing the website via browser.
The diff produced by patching core 9.2.5 looks following:
Yet, if we will look at result code of patched code we've got following excerpt:
Even though the profile itself is properly identified as a type "profile" , following check doesn't pass (see screenshot):
So when I use custom profile, for some reason the getType() call still returns "module", and it executes hook twice.
This can be most likely with some workarounds , or by making sure that profile's install hook runs smoothly, but what worries me more is the fact that other modules are running install hooks twice.
I've literally hardcoded following lines in user_install() hook, removed my install profile and tried to install Standard profile via UI:
and I can see it dies:
( see screenshot attached as well )
Is it really necessary to invoke all install hooks twice?
Comment #75
piggito commentedI ported patch in #73 for d8.9 in case someone else didn't upgrade yet.
Comment #77
hchonovComment #78
gagarine commentedCan we as suggested in #4 ignore profiles install hooks when configuration is syncing? If the website was made with the standard profil, simply allow import and don't execute the install hook. We can provide a small helper text below the import to alert the user that the install hook is not going to be executed.
I believe this would solve 90% of this issue in the real world.
Comment #80
ravi.shankar commentedAdded reroll of patch #73 on Drupal 9.5.x.
Comment #82
ayush.khare commentedAdded reroll of patch #80 on Drupal 10.1.x
Comment #83
ayush.khare commentedFixed custom command failure.
Comment #84
andypostnot fixed(
Comment #85
pradhumanjain2311 commentedTry to fix CCF Errors in patch #83.
Comment #86
idiaz.ronceroIs it ok and intended that the patch modify the hook that's being called?
This (
hook_modules_installed)becomes this, which is calling
hook_installinstead.I realized that a contrib module (default content) wasn't working due to this change. The module uses
hook_modules_installedand with this patch applied, the hook never gets called.It might affect other contrib and core modules as well!
The code that wasn't gettin executed after this patch, for reference:
Comment #89
bhanu951 commentedBumped into this issue.
@idiaz.roncero , Tests seems havent run earlier. Lets check again and get clarified on your question.
Raised MR based on patch from #85
Comment #90
bhanu951 commentedComment #91
needs-review-queue-bot commentedThe 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.
Comment #92
monaw commentedfor those using Drupal 9.x, the solution of changing profile from standard to minimal in core.extension.yml from this article worked for me; hope it'll work for you too (:
Comment #93
ressaYes, that's a great tip in Drupal 8: Install Site From Existing Configuration from @philipnorton42, and it works well in Drupal 10 as well. Make sure you replace both instances.
If none of your modules or themes contain the string "standard", you can use this to replace via the command line:
sed -i 's|standard|minimal|g' core.extension.ymlComment #95
tyler36 commentedCame across this today with Drupal
10.1.MR needs rebasing but I get error: "Something went wrong. Please try again."
Comment #96
bhanu951 commented@tyler36 I will rebase it to 11.x , I have edit access wait for some time, if you are planning to work on it.
Comment #99
bhanu951 commentedComment #100
luenemannMore then 3000 tests are failing, for example:
Comment #101
donquixote commentedThe existing MR is weird.
Problem recap
Let's summarize what we need:
Proposed solution
The site-install from existing config should do two separate steps:
Probably this needs two separate processes.
Comment #102
bircherI am not particularly happy with the current MR, for one it changes things in node_install and user_install that seem unrelated. Also if we allow an install hook we should just add it to one of the test profiles, no need to create it in a test only.
But more importantly I don't think the proposed solution from #101 would work. If we install normally and then in a second step import the config some install profiles will still not work and we just find out later and have no way to predict it. The problem is that you can uninstall modules, but only sometimes! There are a bunch of uninstall validators that prevent you from uninstalling a module if there is content for it still. So if a install profiles adds something that prevents one of the optional modules to be uninstalled without any manual interaction then the "import config" step will fail.
This is in a way the same problem that prevented us from allowing install hooks in the first place. Install hooks were allowed to make assumptions that are not true in the "install from config" scenario, even if we don't run the install hook of the profile not when the extensions are installed but only at the end of the profile installation process. (ie a profile can assume that optional modules are installed in the normal installation, but not in the "from existing config" step, and of course the same is true for the default config in the profile)
It has now been a while that these profiles are missing out on a key feature of Drupal core. So maybe it is now ok to just call the profiles install hooks at the end of the install process and skip them in the normal extension installation. This would work in both cases install from config or not. Then if the hook makes assumptions about what is available then it is a bug in the profile and it should add checks around the assumptions.
Comment #103
elvin - albania drupal developerToday i came accross this: https://www.drupal.org/node/3432357
I was able to uninstall the "Standard" profile, export cofig, and then i was able to do a
drush site:install --existing-configsuccessfully.
Comment #104
alexpott@elvin - albania drupal developer yep I think that that change makes this change now unnecessary to pursue.
Comment #105
kartagisCorrected a grammatical typo in title.
Comment #106
ericvl@elvin
Is there a way to install Drupal and getting the choise of selecting the "existing configuration" without making use of Drush? Just by the user interface.
I don't have Drush on my site. therefor one needs access to the shell and I haven't.
Comment #107
alexpott@ericvl yes if you the exported config in a directory and
$settings['config_sync_directory']in your settings.php already and you visit the interactive installer you'll get the option to install from existing configuration via the UI.Comment #108
ericvl@alexpott
Thank you for the quick response but it doesn't work for me. I do not get the selectbutton for existing config.
I'm using Drupal 10.3.5. Maybe I should use the dev version?
What I do:
- export the configuration and import it back in so that the contents of the config_sync_directory mirrors what is in the database.
- remove the standard profile
- remove all tables in yhe database. Remark: the specs of the database are still in the settings.php
- I'm visiting the interactive installer by accessing the root of site (this redict to the installer)
- I can not select the existing config.
If you can spare a few minutes to look into this, thanks
Comment #109
alexpott@ericvl you need to uninstall the standard profile prior to exporting the configuration. Then on the select install profile screen you will see an option during the installer - where you select the install profile. See below:
This functionality has been part of Drupal for a while... see #2980670: Install a site from config if the config directory is set in settings.php
Comment #110
ericvl@alexpott
Thank you for helping me out. It works.
Sorry to bother you with such a stupid problem.
Thnx
Comment #112
ressaRan into this today, and simply replacing
standardwithminimalincore.extension.ymldid the trick, so adding under workaround in the Issue Summary.