public ModuleInstaller::install(array $module_list, $enable_dependencies = TRUE)
Installs a given list of modules.
Order of events:
- Gather and add module dependencies to $module_list (if applicable).
- For each module that is being installed:
- Invoke hook_module_preinstall().
- Install module schema and update system registries and caches.
- Invoke hook_install() and add it to the list of installed modules.
- Invoke hook_modules_installed().
To install test modules add
1 | $settings [ 'extension_discovery_scan_tests' ] = TRUE; |
to your settings.php.
Parameters
string[] $module_list: An array of module names.
bool $enable_dependencies: (optional) If TRUE, dependencies will automatically be installed in the correct order. This incurs a significant performance cost, so use FALSE if you know $module_list is already complete.
Return value
bool TRUE if the modules were successfully installed.
Throws
\Drupal\Core\Extension\MissingDependencyException Thrown when a requested module, or a dependency of one, can not be found.
Overrides ModuleInstallerInterface::install
See also
File
- core/lib/Drupal/Core/Extension/ModuleInstaller.php, line 77
Class
- ModuleInstaller
- Default implementation of the module installer.
Namespace
Drupal\Core\Extension
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 | public function install( array $module_list , $enable_dependencies = TRUE) { $extension_config = \Drupal::configFactory()->getEditable( 'core.extension' ); if ( $enable_dependencies ) { // Get all module data so we can find dependencies and sort. $module_data = system_rebuild_module_data(); $module_list = $module_list ? array_combine ( $module_list , $module_list ) : array (); if ( $missing_modules = array_diff_key ( $module_list , $module_data )) { // One or more of the given modules doesn't exist. throw new MissingDependencyException(sprintf( 'Unable to install modules %s due to missing modules %s.' , implode( ', ' , $module_list ), implode( ', ' , $missing_modules ))); } // Only process currently uninstalled modules. $installed_modules = $extension_config ->get( 'module' ) ? : array (); if (! $module_list = array_diff_key ( $module_list , $installed_modules )) { // Nothing to do. All modules already installed. return TRUE; } // Add dependencies to the list. The new modules will be processed as // the while loop continues. while (list( $module ) = each( $module_list )) { foreach ( array_keys ( $module_data [ $module ]->requires) as $dependency ) { if (!isset( $module_data [ $dependency ])) { // The dependency does not exist. throw new MissingDependencyException( "Unable to install modules: module '$module' is missing its dependency module $dependency." ); } // Skip already installed modules. if (!isset( $module_list [ $dependency ]) && !isset( $installed_modules [ $dependency ])) { $module_list [ $dependency ] = $dependency ; } } } // Set the actual module weights. $module_list = array_map ( function ( $module ) use ( $module_data ) { return $module_data [ $module ]->sort; }, $module_list ); // Sort the module list by their weights (reverse). arsort( $module_list ); $module_list = array_keys ( $module_list ); } // Required for module installation checks. include_once $this ->root . '/core/includes/install.inc' ; /** @var \Drupal\Core\Config\ConfigInstaller $config_installer */ $config_installer = \Drupal::service( 'config.installer' ); $sync_status = $config_installer ->isSyncing(); if ( $sync_status ) { $source_storage = $config_installer ->getSourceStorage(); } $modules_installed = array (); foreach ( $module_list as $module ) { $enabled = $extension_config ->get( "module.$module" ) !== NULL; if (! $enabled ) { // Throw an exception if the module name is too long. if ( strlen ( $module ) > DRUPAL_EXTENSION_NAME_MAX_LENGTH) { throw new ExtensionNameLengthException( "Module name '$module' is over the maximum allowed length of " . DRUPAL_EXTENSION_NAME_MAX_LENGTH . ' characters' ); } // Check the validity of the default configuration. This will throw // exceptions if the configuration is not valid. $config_installer ->checkConfigurationToInstall( 'module' , $module ); // Save this data without checking schema. This is a performance // improvement for module installation. $extension_config ->set( "module.$module" , 0) ->set( 'module' , module_config_sort( $extension_config ->get( 'module' ))) ->save(TRUE); // Prepare the new module list, sorted by weight, including filenames. // This list is used for both the ModuleHandler and DrupalKernel. It // needs to be kept in sync between both. A DrupalKernel reboot or // rebuild will automatically re-instantiate a new ModuleHandler that // uses the new module list of the kernel. However, DrupalKernel does // not cause any modules to be loaded. // Furthermore, the currently active (fixed) module list can be // different from the configured list of enabled modules. For all active // modules not contained in the configured enabled modules, we assume a // weight of 0. $current_module_filenames = $this ->moduleHandler->getModuleList(); $current_modules = array_fill_keys( array_keys ( $current_module_filenames ), 0); $current_modules = module_config_sort( array_merge ( $current_modules , $extension_config ->get( 'module' ))); $module_filenames = array (); foreach ( $current_modules as $name => $weight ) { if (isset( $current_module_filenames [ $name ])) { $module_filenames [ $name ] = $current_module_filenames [ $name ]; } else { $module_path = drupal_get_path( 'module' , $name ); $pathname = "$module_path/$name.info.yml" ; $filename = file_exists ( $module_path . "/$name.module" ) ? "$name.module" : NULL; $module_filenames [ $name ] = new Extension( $this ->root, 'module' , $pathname , $filename ); } } // Update the module handler in order to load the module's code. // This allows the module to participate in hooks and its existence to // be discovered by other modules. // The current ModuleHandler instance is obsolete with the kernel // rebuild below. $this ->moduleHandler->setModuleList( $module_filenames ); $this ->moduleHandler->load( $module ); module_load_install( $module ); // Clear the static cache of system_rebuild_module_data() to pick up the // new module, since it merges the installation status of modules into // its statically cached list. drupal_static_reset( 'system_rebuild_module_data' ); // Update the kernel to include it. $this ->updateKernel( $module_filenames ); // Allow modules to react prior to the installation of a module. $this ->moduleHandler->invokeAll( 'module_preinstall' , array ( $module )); // Now install the module's schema if necessary. drupal_install_schema( $module ); // Clear plugin manager caches. \Drupal::getContainer()->get( 'plugin.cache_clearer' )->clearCachedDefinitions(); // Set the schema version to the number of the last update provided by // the module, or the minimum core schema version. $version = \Drupal::CORE_MINIMUM_SCHEMA_VERSION; $versions = drupal_get_schema_versions( $module ); if ( $versions ) { $version = max(max( $versions ), $version ); } // Notify interested components that this module's entity types and // field storage definitions are new. For example, a SQL-based storage // handler can use this as an opportunity to create the necessary // database tables. // @todo Clean this up in https://www.drupal.org/node/2350111. $entity_manager = \Drupal::entityManager(); $update_manager = \Drupal::entityDefinitionUpdateManager(); foreach ( $entity_manager ->getDefinitions() as $entity_type ) { if ( $entity_type ->getProvider() == $module ) { $update_manager ->installEntityType( $entity_type ); } elseif ( $entity_type ->isSubclassOf(FieldableEntityInterface::CLASS)) { // The module being installed may be adding new fields to existing // entity types. Field definitions for any entity type defined by // the module are handled in the if branch. foreach ( $entity_manager ->getFieldStorageDefinitions( $entity_type ->id()) as $storage_definition ) { if ( $storage_definition ->getProvider() == $module ) { // If the module being installed is also defining a storage key // for the entity type, the entity schema may not exist yet. It // will be created later in that case. try { $update_manager ->installFieldStorageDefinition( $storage_definition ->getName(), $entity_type ->id(), $module , $storage_definition ); } catch (EntityStorageException $e ) { watchdog_exception( 'system' , $e , 'An error occurred while notifying the creation of the @name field storage definition: "!message" in %function (line %line of %file).' , [ '@name' => $storage_definition ->getName()]); } } } } } // Install default configuration of the module. $config_installer = \Drupal::service( 'config.installer' ); if ( $sync_status ) { $config_installer ->setSyncing(TRUE) ->setSourceStorage( $source_storage ); } \Drupal::service( 'config.installer' )->installDefaultConfig( 'module' , $module ); // If the module has no current updates, but has some that were // previously removed, set the version to the value of // hook_update_last_removed(). if ( $last_removed = $this ->moduleHandler->invoke( $module , 'update_last_removed' )) { $version = max( $version , $last_removed ); } drupal_set_installed_schema_version( $module , $version ); // Ensure that all post_update functions are registered already. /** @var \Drupal\Core\Update\UpdateRegistry $post_update_registry */ $post_update_registry = \Drupal::service( 'update.post_update_registry' ); $post_update_registry ->registerInvokedUpdates( $post_update_registry ->getModuleUpdateFunctions( $module )); // Record the fact that it was installed. $modules_installed [] = $module ; // Drupal's stream wrappers needs to be re-registered in case a // module-provided stream wrapper is used later in the same request. In // particular, this happens when installing Drupal via Drush, as the // 'translations' stream wrapper is provided by Interface Translation // module and is later used to import translations. \Drupal::service( 'stream_wrapper_manager' )->register(); // Update the theme registry to include it. drupal_theme_rebuild(); // Modules can alter theme info, so refresh theme data. // @todo ThemeHandler cannot be injected into ModuleHandler, since that // causes a circular service dependency. \Drupal::service( 'theme_handler' )->refreshInfo(); // In order to make uninstalling transactional if anything uses routes. \Drupal::getContainer()->set( 'router.route_provider.old' , \Drupal::service( 'router.route_provider' )); \Drupal::getContainer()->set( 'router.route_provider' , \Drupal::service( 'router.route_provider.lazy_builder' )); // Allow the module to perform install tasks. $this ->moduleHandler->invoke( $module , 'install' ); // Record the fact that it was installed. \Drupal::logger( 'system' )->info( '%module module installed.' , array ( '%module' => $module )); } } // If any modules were newly installed, invoke hook_modules_installed(). if (! empty ( $modules_installed )) { \Drupal::getContainer()->set( 'router.route_provider' , \Drupal::service( 'router.route_provider.old' )); if (!\Drupal::service( 'router.route_provider.lazy_builder' )->hasRebuilt()) { // Rebuild routes after installing module. This is done here on top of // \Drupal\Core\Routing\RouteBuilder::destruct to not run into errors on // fastCGI which executes ::destruct() after the module installation // page was sent already. \Drupal::service( 'router.builder' )->rebuild(); } $this ->moduleHandler->invokeAll( 'modules_installed' , array ( $modules_installed )); } return TRUE; } |
Please login to continue.