protected function execute(InputInterface $input, OutputInterface $output) { $io = new DrupalStyle($input, $output); $status = $input->getOption('status'); $type = $input->getOption('type'); if (strtolower($status) == 'enabled') { $status = 1; } elseif (strtolower($status) == 'disabled') { $status = 0; } else { $status = -1; } if (strtolower($type) == 'core') { $type = 'core'; } elseif (strtolower($type) == 'no-core') { $type = ''; } else { $type = null; } $tableHeader = [$this->trans('commands.module.debug.messages.id'), $this->trans('commands.module.debug.messages.name'), $this->trans('commands.module.debug.messages.status'), $this->trans('commands.module.debug.messages.package'), $this->trans('commands.module.debug.messages.schema-version'), $this->trans('commands.module.debug.messages.origin')]; $tableRows = []; $modules = system_rebuild_module_data(); foreach ($modules as $module_id => $module) { if ($status >= 0 && $status != $module->status) { continue; } if ($type !== null && $type !== $module->origin) { continue; } $module_status = $module->status ? $this->trans('commands.module.debug.messages.enabled') : $this->trans('commands.module.debug.messages.disabled'); $schema_version = drupal_get_installed_schema_version($module_id) != -1 ? drupal_get_installed_schema_version($module_id) : ''; $tableRows[] = [$module_id, $module->info['name'], $module_status, $module->info['package'], $schema_version, $module->origin]; } $io->table($tableHeader, $tableRows, 'compact'); }
/** * {@inheritdoc} */ public function buildForm(array $form, FormStateInterface $form_state) { // Get a list of all available modules. $modules = system_rebuild_module_data(); $uninstallable = array_filter($modules, function ($module) use($modules) { return empty($modules[$module->getName()]->info['required']) && drupal_get_installed_schema_version($module->getName()) > SCHEMA_UNINSTALLED && $module->getName() !== 'devel'; }); $form['filters'] = array('#type' => 'container', '#attributes' => array('class' => array('table-filter', 'js-show'))); $form['filters']['text'] = array('#type' => 'search', '#title' => $this->t('Search'), '#size' => 30, '#placeholder' => $this->t('Enter module name'), '#attributes' => array('class' => array('table-filter-text'), 'data-table' => '#devel-reinstall-form', 'autocomplete' => 'off', 'title' => $this->t('Enter a part of the module name or description to filter by.'))); // Only build the rest of the form if there are any modules available to // uninstall; if (empty($uninstallable)) { return $form; } $header = array('name' => $this->t('Name'), 'description' => $this->t('Description')); $rows = array(); foreach ($uninstallable as $module) { $name = $module->info['name'] ?: $module->getName(); $rows[$module->getName()] = array('name' => array('data' => array('#type' => 'inline_template', '#template' => '<label class="module-name table-filter-text-source">{{ module_name }}</label>', '#context' => array('module_name' => $name))), 'description' => array('data' => $module->info['description'], 'class' => array('description'))); } $form['reinstall'] = array('#type' => 'tableselect', '#header' => $header, '#options' => $rows, '#js_select' => FALSE, '#empty' => $this->t('No modules are available to uninstall.')); $form['#attached']['library'][] = 'system/drupal.system.modules'; $form['actions'] = array('#type' => 'actions'); $form['actions']['submit'] = array('#type' => 'submit', '#value' => $this->t('Reinstall')); return $form; }
/** * Tests recorded schema versions of early installed modules in the installer. */ public function testRequiredModuleSchemaVersions() { $version = drupal_get_installed_schema_version('system', TRUE); $this->assertTrue($version > 0, 'System module version is > 0.'); $version = drupal_get_installed_schema_version('user', TRUE); $this->assertTrue($version > 0, 'User module version is > 0.'); }
function update_script_selection_form() { $form = array(); $form['start'] = array('#tree' => TRUE, '#type' => 'fieldset', '#title' => 'Select versions', '#collapsible' => TRUE, '#collapsed' => TRUE); // Ensure system.module's updates appear first $form['start']['system'] = array(); $modules = drupal_get_installed_schema_version(NULL, FALSE, TRUE); foreach ($modules as $module => $schema_version) { $updates = drupal_get_schema_versions($module); // Skip incompatible module updates completely, otherwise test schema versions. if (!update_check_incompatibility($module) && $updates !== FALSE && $schema_version >= 0) { // module_invoke returns NULL for nonexisting hooks, so if no updates // are removed, it will == 0. $last_removed = module_invoke($module, 'update_last_removed'); if ($schema_version < $last_removed) { $form['start'][$module] = array('#value' => '<em>' . $module . '</em> module can not be updated. Its schema version is ' . $schema_version . '. Updates up to and including ' . $last_removed . ' have been removed in this release. In order to update <em>' . $module . '</em> module, you will first <a href="http://drupal.org/upgrade">need to upgrade</a> to the last version in which these updates were available.', '#prefix' => '<div class="warning">', '#suffix' => '</div>'); $form['start']['#collapsed'] = FALSE; continue; } $updates = drupal_map_assoc($updates); $updates[] = 'No updates available'; $default = $schema_version; foreach (array_keys($updates) as $update) { if ($update > $schema_version) { $default = $update; break; } } $form['start'][$module] = array('#type' => 'select', '#title' => $module . ' module', '#default_value' => $default, '#options' => $updates); } } $form['has_js'] = array('#type' => 'hidden', '#default_value' => FALSE); $form['submit'] = array('#type' => 'submit', '#value' => 'Update'); return $form; }
protected function execute(InputInterface $input, OutputInterface $output) { $io = new DrupalStyle($input, $output); $this->get('site')->loadLegacyFile('/core/modules/system/system.module'); $status = strtolower($input->getOption('status')); $type = strtolower($input->getOption('type')); $modules = strtolower($input->getArgument('module')); if ($modules) { $config = $this->getApplication()->getConfig(); $repo = $config->get('application.composer.repositories.default'); foreach ($modules as $module) { $url = sprintf('%s/packages/drupal/%s.json', $config->get('application.composer.packages.default'), $module); try { $data = $this->getApplication()->getHttpClientHelper()->getUrlAsJson($repo . $url); } catch (\Exception $e) { $io->error(sprintf($this->trans('commands.module.debug.messages.no-results'), $module)); return 1; } $tableHeader = ['<info>' . $data->package->name . '</info>']; $tableRows = []; $tableRows[] = [$data->package->description]; $tableRows[] = ['<comment>' . $this->trans('commands.module.debug.messages.total-downloads') . '</comment>', $data->package->downloads->total]; $tableRows[] = ['<comment>' . $this->trans('commands.module.debug.messages.total-monthly') . '</comment>', $data->package->downloads->monthly]; $tableRows[] = ['<comment>' . $this->trans('commands.module.debug.messages.total-daily') . '</comment>', $data->package->downloads->daily]; $io->table($tableHeader, $tableRows, 'compact'); } return 0; } if ($status == 'installed') { $status = 1; } elseif ($status == 'uninstalled') { $status = 0; } else { $status = -1; } if ($type == 'core') { $type = 'core'; } elseif ($type == 'no-core') { $type = ''; } else { $type = null; } $tableHeader = [$this->trans('commands.module.debug.messages.id'), $this->trans('commands.module.debug.messages.name'), $this->trans('commands.module.debug.messages.package'), $this->trans('commands.module.debug.messages.version'), $this->trans('commands.module.debug.messages.schema-version'), $this->trans('commands.module.debug.messages.status'), $this->trans('commands.module.debug.messages.origin')]; $tableRows = []; $modules = system_rebuild_module_data(); foreach ($modules as $module_id => $module) { if ($status >= 0 && $status != $module->status) { continue; } if ($type !== null && $type !== $module->origin) { continue; } $module_status = $module->status ? $this->trans('commands.module.debug.messages.installed') : $this->trans('commands.module.debug.messages.uninstalled'); $module_origin = $module->origin ? $module->origin : 'no core'; $schema_version = drupal_get_installed_schema_version($module_id) != -1 ? drupal_get_installed_schema_version($module_id) : ''; $tableRows[] = [$module_id, $module->info['name'], $module->info['package'], $module->info['version'], $schema_version, $module_status, $module_origin]; } $io->table($tableHeader, $tableRows, 'compact'); }
/** * Tests recorded schema versions of early installed modules in the installer. */ public function testRequiredModuleSchemaVersions() { $version = drupal_get_installed_schema_version('system', TRUE); $this->assertTrue($version > 0, 'System module version is > 0.'); $version = drupal_get_installed_schema_version('user', TRUE); $this->assertTrue($version > 0, 'User module version is > 0.'); $post_update_key_value = \Drupal::keyValue('post_update'); $existing_updates = $post_update_key_value->get('existing_updates', []); $this->assertTrue(in_array('module_test_post_update_test', $existing_updates)); }
/** * Test that updates are properly run. */ public function testUpdateHookN() { // Increment the schema version. \Drupal::state()->set('update_test_schema_version', 8001); $this->runUpdates(); // Ensure schema has changed. $this->assertEqual(drupal_get_installed_schema_version('update_test_schema', TRUE), 8001); // Ensure the index was added for column a. $this->assertTrue(db_index_exists('update_test_schema_table', 'test'), 'Version 8001 of the update_test_schema module is installed.'); }
function update_script_selection_form() { $form = array(); $count = 0; $form['start'] = array('#tree' => TRUE, '#type' => 'fieldset', '#collapsed' => TRUE, '#collapsible' => TRUE); // Ensure system.module's updates appear first $form['start']['system'] = array(); $modules = drupal_get_installed_schema_version(NULL, FALSE, TRUE); foreach ($modules as $module => $schema_version) { $pending = array(); $updates = drupal_get_schema_versions($module); // Skip incompatible module updates completely, otherwise test schema versions. if (!update_check_incompatibility($module) && $updates !== FALSE && $schema_version >= 0) { // module_invoke returns NULL for nonexisting hooks, so if no updates // are removed, it will == 0. $last_removed = module_invoke($module, 'update_last_removed'); if ($schema_version < $last_removed) { $form['start'][$module] = array('#title' => $module, '#item' => '<em>' . $module . '</em> module can not be updated. Its schema version is ' . $schema_version . '. Updates up to and including ' . $last_removed . ' have been removed in this release. In order to update <em>' . $module . '</em> module, you will first <a href="http://drupal.org/upgrade">need to upgrade</a> to the last version in which these updates were available.', '#prefix' => '<div class="warning">', '#suffix' => '</div>'); continue; } $updates = drupal_map_assoc($updates); foreach (array_keys($updates) as $update) { if ($update > $schema_version) { // The description for an update comes from its Doxygen. $func = new ReflectionFunction($module . '_update_' . $update); $description = str_replace(array("\n", '*', '/'), '', $func->getDocComment()); $pending[] = "{$update} - {$description}"; if (!isset($default)) { $default = $update; } } } if (!empty($pending)) { if (!isset($default)) { $default = $schema_version; } $form['start'][$module] = array('#type' => 'hidden', '#value' => $default); $form['start'][$module . '_updates'] = array('#markup' => theme('item_list', $pending, $module . ' module')); } } unset($default); $count = $count + count($pending); } if (empty($count)) { drupal_set_message(t('No pending updates.')); unset($form); $form['links'] = array('#markup' => theme('item_list', update_helpful_links())); } else { $form['help'] = array('#markup' => '<p>The version of Drupal you are updating from has been automatically detected.</p>', '#weight' => -5); $form['start']['#title'] = strtr('!num pending updates', array('!num' => $count)); $form['has_js'] = array('#type' => 'hidden', '#default_value' => FALSE); $form['submit'] = array('#type' => 'submit', '#value' => 'Apply pending updates'); } return $form; }
function testWith7x() { // Ensure that the minimum schema version is 8000, despite 7200 update // hooks and a 7XXX hook_update_last_removed(). $this->assertEqual(drupal_get_installed_schema_version('update_test_with_7x'), 8000); // Try to manually set the schema version to 7110 and ensure that no // updates are allowed. drupal_set_installed_schema_version('update_test_with_7x', 7110); // Click through update.php with 'administer software updates' permission. $this->drupalLogin($this->update_user); $this->drupalPostForm($this->update_url, array(), t('Continue'), array('external' => TRUE)); $this->assertText(t('Some of the pending updates cannot be applied because their dependencies were not met.')); }
/** * Disable all blocks with missing context IDs in block_update_8001(). */ function block_post_update_disable_blocks_with_missing_contexts() { // Don't execute the function if block_update_8002() got executed already, // which used to do the same. Note: Its okay to check here, because // update_do_one() does not update the installed schema version until the // batch is finished. $module_schema = drupal_get_installed_schema_version('block'); // The state entry 'block_update_8002_placeholder' is used in order to // indicate that the placeholder block_update_8002() function has been // executed, so this function needs to be executed as well. If the non // placeholder version of block_update_8002() got executed already, the state // won't be set and we skip this update. if ($module_schema >= 8002 && !\Drupal::state()->get('block_update_8002_placeholder', FALSE)) { return; } // Cleanup the state entry as its no longer needed. \Drupal::state()->delete('block_update_8002'); $block_update_8001 = \Drupal::keyValue('update_backup')->get('block_update_8001', []); $block_ids = array_keys($block_update_8001); $block_storage = \Drupal::entityManager()->getStorage('block'); $blocks = $block_storage->loadMultiple($block_ids); /** @var $blocks \Drupal\block\BlockInterface[] */ foreach ($blocks as $block) { // This block has had conditions removed due to an inability to resolve // contexts in block_update_8001() so disable it. // Disable currently enabled blocks. if ($block_update_8001[$block->id()]['status']) { $block->setStatus(FALSE); $block->save(); } } // Provides a list of plugin labels, keyed by plugin ID. $condition_plugin_id_label_map = array_column(\Drupal::service('plugin.manager.condition')->getDefinitions(), 'label', 'id'); // Override with the UI labels we are aware of. Sadly they are not machine // accessible, see // \Drupal\node\Plugin\Condition\NodeType::buildConfigurationForm(). $condition_plugin_id_label_map['node_type'] = t('Content types'); $condition_plugin_id_label_map['request_path'] = t('Pages'); $condition_plugin_id_label_map['user_role'] = t('Roles'); if (count($block_ids) > 0) { $message = t('Encountered an unknown context mapping key coming probably from a contributed or custom module: One or more mappings could not be updated. Please manually review your visibility settings for the following blocks, which are disabled now:'); $message .= '<ul>'; foreach ($blocks as $disabled_block_id => $disabled_block) { $message .= '<li>' . t('@label (Visibility: @plugin_ids)', array('@label' => $disabled_block->get('settings')['label'], '@plugin_ids' => implode(', ', array_intersect_key($condition_plugin_id_label_map, array_flip(array_keys($block_update_8001[$disabled_block_id]['missing_context_ids'])))))) . '</li>'; } $message .= '</ul>'; return $message; } }
/** * Test that updates are properly run. */ public function testUpdateHookN() { // Increment the schema version. \Drupal::state()->set('update_test_schema_version', 8001); $this->runUpdates(); $select = \Drupal::database()->select('watchdog'); $select->orderBy('wid', 'DESC'); $select->range(0, 5); $select->fields('watchdog', ['message']); $container_cannot_be_saved_messages = array_filter(iterator_to_array($select->execute()), function ($row) { return strpos($row->message, 'Container cannot be saved to cache.') !== FALSE; }); $this->assertEqual([], $container_cannot_be_saved_messages); // Ensure schema has changed. $this->assertEqual(drupal_get_installed_schema_version('update_test_schema', TRUE), 8001); // Ensure the index was added for column a. $this->assertTrue(db_index_exists('update_test_schema_table', 'test'), 'Version 8001 of the update_test_schema module is installed.'); }
/** * Tests that update hooks are properly run. */ public function testUpdateHooks() { // Verify that the 8000 schema is in place. $this->assertEqual(drupal_get_installed_schema_version('update_test_schema'), 8000); $this->assertFalse(db_index_exists('update_test_schema_table', 'test'), 'Version 8000 of the update_test_schema module is installed.'); // Increment the schema version. \Drupal::state()->set('update_test_schema_version', 8001); $this->drupalLogin($this->user); $this->drupalGet($this->updateUrl, ['external' => TRUE]); $this->clickLink(t('Continue')); $this->assertRaw('Schema version 8001.'); // Run the update hooks. $this->clickLink(t('Apply pending updates')); // Ensure schema has changed. $this->assertEqual(drupal_get_installed_schema_version('update_test_schema', TRUE), 8001); // Ensure the index was added for column a. $this->assertTrue(db_index_exists('update_test_schema_table', 'test'), 'Version 8001 of the update_test_schema module is installed.'); }
protected function getAllModules($status, $type, $output, $table) { $this->getDrupalHelper()->loadLegacyFile('/core/includes/schema.inc'); $table->setHeaders([$this->trans('commands.module.debug.messages.id'), $this->trans('commands.module.debug.messages.name'), $this->trans('commands.module.debug.messages.status'), $this->trans('commands.module.debug.messages.package'), $this->trans('commands.module.debug.messages.schema-version'), $this->trans('commands.module.debug.messages.origin')]); $table->setlayout($table::LAYOUT_COMPACT); $modules = system_rebuild_module_data(); foreach ($modules as $module_id => $module) { if ($status >= 0 && $status != $module->status) { continue; } if ($type !== null && $type !== $module->origin) { continue; } $module_status = $module->status ? $this->trans('commands.module.debug.messages.enabled') : $this->trans('commands.module.debug.messages.disabled'); $schema_version = drupal_get_installed_schema_version($module_id) != -1 ? drupal_get_installed_schema_version($module_id) : ''; $table->addRow([$module_id, $module->info['name'], $module_status, $module->info['package'], $schema_version, $module->origin]); } $table->render($output); }
/** * Tests that the database was properly loaded. */ public function testDatabaseLoaded() { $hook_updates = ['user' => '8000', 'node' => '8003', 'system' => '8013']; foreach ($hook_updates as $module => $schema) { $this->assertEqual(drupal_get_installed_schema_version($module), $schema, new FormattableMarkup('Module @module schema is @schema', ['@module' => $module, '@schema' => $schema])); } // Test post_update key value stores contains a list of the update functions // that have run. $existing_updates = array_count_values(\Drupal::keyValue('post_update')->get('existing_updates')); $expected_updates = ['system_post_update_recalculate_configuration_entity_dependencies', 'field_post_update_save_custom_storage_property', 'field_post_update_entity_reference_handler_setting', 'block_post_update_disable_blocks_with_missing_contexts', 'views_post_update_update_cacheability_metadata']; foreach ($expected_updates as $expected_update) { $this->assertEqual($existing_updates[$expected_update], 1, new FormattableMarkup("@expected_update exists in 'existing_updates' key and only appears once.", ['@expected_update' => $expected_update])); } // @todo there are no updates to run. // $this->runUpdates(); $this->assertEqual(\Drupal::config('system.site')->get('name'), 'Site-Install'); $this->drupalGet('<front>'); $this->assertText('Site-Install'); }
/** * Tests that the database was properly loaded. */ public function testDatabaseLoaded() { $extensions = \Drupal::service('config.storage')->read('core.extension'); $this->assertFalse(isset($extensions['theme']['stable']), 'Stable is not installed before updating.'); $hook_updates = ['user' => '8000', 'node' => '8003', 'system' => '8013']; foreach ($hook_updates as $module => $schema) { $this->assertEqual(drupal_get_installed_schema_version($module), $schema, new FormattableMarkup('Module @module schema is @schema', ['@module' => $module, '@schema' => $schema])); } // Test post_update key value stores contains a list of the update functions // that have run. $existing_updates = array_count_values(\Drupal::keyValue('post_update')->get('existing_updates')); $expected_updates = ['system_post_update_recalculate_configuration_entity_dependencies', 'field_post_update_save_custom_storage_property', 'field_post_update_entity_reference_handler_setting', 'block_post_update_disable_blocks_with_missing_contexts', 'views_post_update_update_cacheability_metadata']; foreach ($expected_updates as $expected_update) { $this->assertEqual($existing_updates[$expected_update], 1, new FormattableMarkup("@expected_update exists in 'existing_updates' key and only appears once.", ['@expected_update' => $expected_update])); } $this->runUpdates(); $this->assertEqual(\Drupal::config('system.site')->get('name'), 'Site-Install'); $this->drupalGet('<front>'); $this->assertText('Site-Install'); $extensions = \Drupal::service('config.storage')->read('core.extension'); $this->assertTrue(isset($extensions['theme']['stable']), 'Stable is installed after updating.'); $blocks = \Drupal::entityManager()->getStorage('block')->loadByProperties(['theme' => 'stable']); $this->assertTrue(empty($blocks), 'No blocks have been placed for Stable.'); }
/** * Helper function to run updates via the browser. */ protected function updateScriptTest($maintenance_mode) { $schema_version = drupal_get_installed_schema_version('update_script_test'); $this->assertEqual($schema_version, 8001, 'update_script_test is initially installed with schema version 8001.'); // Set the installed schema version to one less than the current update. drupal_set_installed_schema_version('update_script_test', $schema_version - 1); $schema_version = drupal_get_installed_schema_version('update_script_test', TRUE); $this->assertEqual($schema_version, 8000, 'update_script_test schema version overridden to 8000.'); // Click through update.php with 'administer software updates' permission. $this->drupalLogin($this->updateUser); if ($maintenance_mode) { $this->assertText('Operating in maintenance mode.'); } else { $this->assertNoText('Operating in maintenance mode.'); } $this->drupalGet($this->updateUrl, array('external' => TRUE)); $this->clickLink(t('Continue')); $this->clickLink(t('Apply pending updates')); // Verify that updates were completed successfully. $this->assertText('Updates were attempted.'); $this->assertLink('site'); $this->assertText('The update_script_test_update_8001() update was executed successfully.'); // Verify that no 7.x updates were run. $this->assertNoText('The update_script_test_update_7200() update was executed successfully.'); $this->assertNoText('The update_script_test_update_7201() update was executed successfully.'); // Verify that there are no links to different parts of the workflow. $this->assertNoLink('Administration pages'); $this->assertNoLinkByHrefInMainRegion('update.php', 0); $this->assertNoLink('logged'); // Verify the front page can be visited following the upgrade. $this->clickLink('Front page'); $this->assertResponse(200); }
/** * Perform Drupal 6.x to 7.x updates that are required for update.php * to function properly. * * This function runs when update.php is run the first time for 7.x, * even before updates are selected or performed. It is important * that if updates are not ultimately performed that no changes are * made which make it impossible to continue using the prior version. */ function update_fix_d7_requirements() { $ret = array(); // Rewrite the settings.php file if necessary. // @see update_prepare_d7_bootstrap(). global $update_rewrite_settings, $db_url; if (!empty($update_rewrite_settings)) { $databases = update_parse_db_url($db_url); file_put_contents(conf_path() . '/settings.php', "\n" . '$databases = ' . var_export($databases, TRUE) . ';', FILE_APPEND); } if (drupal_get_installed_schema_version('system') < 7000 && !variable_get('update_d7_requirements', FALSE)) { // Add the cache_path table. $schema['cache_path'] = drupal_get_schema_unprocessed('system', 'cache'); $schema['cache_path']['description'] = 'Cache table used for path alias lookups.'; db_create_table($ret, 'cache_path', $schema['cache_path']); variable_set('update_d7_requirements', TRUE); // Add column for locale context. if (db_table_exists('locales_source')) { db_add_field($ret, 'locales_source', 'context', array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => '', 'description' => 'The context this string applies to.')); } } return $ret; }
/** * Tests uninstalling a module that is a "dependency" of a profile. */ function testUninstallProfileDependency() { $profile = 'minimal'; $dependency = 'dblog'; $this->settingsSet('install_profile', $profile); $this->enableModules(array('module_test', $profile)); drupal_static_reset('system_rebuild_module_data'); $data = system_rebuild_module_data(); $this->assertTrue(isset($data[$profile]->requires[$dependency])); $this->moduleHandler()->install(array($dependency)); $this->assertTrue($this->moduleHandler()->moduleExists($dependency)); // Uninstall the profile module "dependency". $result = $this->moduleHandler()->uninstall(array($dependency)); $this->assertTrue($result, 'ModuleHandler::uninstall() returns TRUE.'); $this->assertFalse($this->moduleHandler()->moduleExists($dependency)); $this->assertEqual(drupal_get_installed_schema_version($dependency), SCHEMA_UNINSTALLED, "{$dependency} module was uninstalled."); // Verify that the installation profile itself was not uninstalled. $uninstalled_modules = \Drupal::state()->get('module_test.uninstall_order') ?: array(); $this->assertTrue(in_array($dependency, $uninstalled_modules), "{$dependency} module is in the list of uninstalled modules."); $this->assertFalse(in_array($profile, $uninstalled_modules), 'The installation profile is not in the list of uninstalled modules.'); }
/** * Perform Drupal 5.x to 6.x updates that are required for update.php * to function properly. * * This function runs when update.php is run the first time for 6.x, * even before updates are selected or performed. It is important * that if updates are not ultimately performed that no changes are * made which make it impossible to continue using the prior version. * Just adding columns is safe. However, renaming the * system.description column to owner is not. Therefore, we add the * system.owner column and leave it to system_update_6008() to copy * the data from description and remove description. The same for * renaming locales_target.locale to locales_target.language, which * will be finished by locale_update_6002(). */ function update_fix_d6_requirements() { $ret = array(); if (drupal_get_installed_schema_version('system') < 6000 && !variable_get('update_d6_requirements', FALSE)) { $spec = array('type' => 'int', 'size' => 'small', 'default' => 0, 'not null' => TRUE); db_add_field($ret, 'cache', 'serialized', $spec); db_add_field($ret, 'cache_filter', 'serialized', $spec); db_add_field($ret, 'cache_page', 'serialized', $spec); db_add_field($ret, 'cache_menu', 'serialized', $spec); db_add_field($ret, 'system', 'info', array('type' => 'text')); db_add_field($ret, 'system', 'owner', array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => '')); if (db_table_exists('locales_target')) { db_add_field($ret, 'locales_target', 'language', array('type' => 'varchar', 'length' => 12, 'not null' => TRUE, 'default' => '')); } if (db_table_exists('locales_source')) { db_add_field($ret, 'locales_source', 'textgroup', array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => 'default')); db_add_field($ret, 'locales_source', 'version', array('type' => 'varchar', 'length' => 20, 'not null' => TRUE, 'default' => 'none')); } variable_set('update_d6_requirements', TRUE); // Create the cache_block table. See system_update_6027() for more details. $schema['cache_block'] = array('fields' => array('cid' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''), 'data' => array('type' => 'blob', 'not null' => FALSE, 'size' => 'big'), 'expire' => array('type' => 'int', 'not null' => TRUE, 'default' => 0), 'created' => array('type' => 'int', 'not null' => TRUE, 'default' => 0), 'headers' => array('type' => 'text', 'not null' => FALSE), 'serialized' => array('type' => 'int', 'size' => 'small', 'not null' => TRUE, 'default' => 0)), 'indexes' => array('expire' => array('expire')), 'primary key' => array('cid')); db_create_table($ret, 'cache_block', $schema['cache_block']); // Create the semaphore table now -- the menu system after 6.15 depends on // this table, and menu code runs in updates prior to the table being // created in its original update function, system_update_6054(). $schema['semaphore'] = array('fields' => array('name' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''), 'value' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''), 'expire' => array('type' => 'float', 'size' => 'big', 'not null' => TRUE)), 'indexes' => array('expire' => array('expire')), 'primary key' => array('name')); db_create_table($ret, 'semaphore', $schema['semaphore']); } return $ret; }
/** * {@inheritdoc} */ public function uninstall(array $module_list, $uninstall_dependents = TRUE) { // 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 (array_diff_key($module_list, $module_data)) { // One or more of the given modules doesn't exist. return FALSE; } // Only process currently installed modules. $extension_config = \Drupal::config('core.extension'); $installed_modules = $extension_config->get('module') ?: array(); if (!($module_list = array_intersect_key($module_list, $installed_modules))) { // Nothing to do. All modules already uninstalled. return TRUE; } if ($uninstall_dependents) { // Add dependent modules to the list. The new modules will be processed as // the while loop continues. $profile = drupal_get_profile(); while (list($module) = each($module_list)) { foreach (array_keys($module_data[$module]->required_by) as $dependent) { if (!isset($module_data[$dependent])) { // The dependent module does not exist. return FALSE; } // Skip already uninstalled modules. if (isset($installed_modules[$dependent]) && !isset($module_list[$dependent]) && $dependent != $profile) { $module_list[$dependent] = $dependent; } } } } // 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. asort($module_list); $module_list = array_keys($module_list); // Only process modules that are enabled. A module is only enabled if it is // configured as enabled. Custom or overridden module handlers might contain // the module already, which means that it might be loaded, but not // necessarily installed. $schema_store = \Drupal::keyValue('system.schema'); $entity_manager = \Drupal::entityManager(); foreach ($module_list as $module) { // Clean up all entity bundles (including fields) of every entity type // provided by the module that is being uninstalled. foreach ($entity_manager->getDefinitions() as $entity_type_id => $entity_type) { if ($entity_type->getProvider() == $module) { foreach (array_keys($entity_manager->getBundleInfo($entity_type_id)) as $bundle) { $entity_manager->onBundleDelete($bundle, $entity_type_id); } } } // Allow modules to react prior to the uninstallation of a module. $this->invokeAll('module_preuninstall', array($module)); // Uninstall the module. module_load_install($module); $this->invoke($module, 'uninstall'); // Remove all configuration belonging to the module. \Drupal::service('config.manager')->uninstall('module', $module); // Notify the entity manager that this module's entity types are being // deleted, so that it can notify all interested handlers. For example, // a SQL-based storage handler can use this as an opportunity to drop // the corresponding database tables. foreach ($entity_manager->getDefinitions() as $entity_type) { if ($entity_type->getProvider() == $module) { $entity_manager->onEntityTypeDelete($entity_type); } } // Remove the schema. drupal_uninstall_schema($module); // Remove the module's entry from the config. $extension_config->clear("module.{$module}")->save(); // Update the module handler to remove the module. // The current ModuleHandler instance is obsolete with the kernel rebuild // below. $module_filenames = $this->getModuleList(); unset($module_filenames[$module]); $this->setModuleList($module_filenames); // Remove any potential cache bins provided by the module. $this->removeCacheBins($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'); // Clear plugin manager caches and flag router to rebuild if requested. \Drupal::getContainer()->get('plugin.cache_clearer')->clearCachedDefinitions(); \Drupal::service('router.builder_indicator')->setRebuildNeeded(); // Update the kernel to exclude the uninstalled modules. \Drupal::service('kernel')->updateModules($module_filenames, $module_filenames); // Update the theme registry to remove the newly uninstalled module. 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. // @see https://drupal.org/node/2208429 \Drupal::service('theme_handler')->refreshInfo(); \Drupal::logger('system')->info('%module module uninstalled.', array('%module' => $module)); $schema_store->delete($module); } drupal_get_installed_schema_version(NULL, TRUE); // Let other modules react. $this->invokeAll('modules_uninstalled', array($module_list)); return TRUE; }
/** * Set the parent id, type and field name to the already created paragraphs. * * @param $sandbox */ function paragraphs_post_update_set_paragraphs_parent_fields(&$sandbox) { // Don't execute the function if paragraphs_update_8003() was already executed // which used to do the same. $module_schema = drupal_get_installed_schema_version('paragraphs'); // The state entry 'paragraphs_update_8003_placeholder' is used in order to // indicate that the placeholder paragraphs_update_8003() function has been // executed, so this function needs to be executed as well. If the non // placeholder version of paragraphs_update_8003() got executed already, the // state won't be set and we skip this update. if ($module_schema >= 8003 && !\Drupal::state()->get('paragraphs_update_8003_placeholder', FALSE)) { return; } if (!isset($sandbox['current_paragraph_field_id'])) { $paragraph_field_ids = []; // Get all the entity reference revisions fields. $map = \Drupal::service('entity_field.manager')->getFieldMapByFieldType('entity_reference_revisions'); foreach ($map as $entity_type_id => $info) { foreach ($info as $name => $data) { if (FieldStorageConfig::loadByName($entity_type_id, $name)->getSetting('target_type') == 'paragraph') { $paragraph_field_ids[] = "{$entity_type_id}.{$name}"; } } } if (!$paragraph_field_ids) { // There are no paragraph fields. Return before initializing the sandbox. return; } // Initialize the sandbox. $sandbox['current_paragraph_field_id'] = 0; $sandbox['paragraph_field_ids'] = $paragraph_field_ids; $sandbox['max'] = count($paragraph_field_ids); $sandbox['progress'] = 0; } /** @var \Drupal\field\FieldStorageConfigInterface $field_storage */ $field_storage = FieldStorageConfig::load($sandbox['paragraph_field_ids'][$sandbox['current_paragraph_field_id']]); // For revisionable entity types, we load and update all revisions. $target_entity_type = \Drupal::entityTypeManager()->getDefinition($field_storage->getTargetEntityTypeId()); if ($target_entity_type->isRevisionable()) { $revision_id = $target_entity_type->getKey('revision'); $entity_ids = \Drupal::entityQuery($field_storage->getTargetEntityTypeId())->condition($field_storage->getName(), NULL, 'IS NOT NULL')->range($sandbox['progress'], Settings::get('paragraph_limit', 50))->allRevisions()->sort($revision_id, 'ASC')->execute(); } else { $id = $target_entity_type->getKey('id'); $entity_ids = \Drupal::entityQuery($field_storage->getTargetEntityTypeId())->condition($field_storage->getName(), NULL, 'IS NOT NULL')->range($sandbox['progress'], Settings::get('paragraph_limit', 50))->sort($id, 'ASC')->execute(); } foreach ($entity_ids as $revision_id => $entity_id) { // For revisionable entity types, we load a specific revision otherwise load // the entity. if ($target_entity_type->isRevisionable()) { $host_entity = \Drupal::entityTypeManager()->getStorage($field_storage->getTargetEntityTypeId())->loadRevision($revision_id); } else { $host_entity = \Drupal::entityTypeManager()->getStorage($field_storage->getTargetEntityTypeId())->load($entity_id); } foreach ($host_entity->get($field_storage->getName()) as $field_item) { // Skip broken and already updated references (e.g. Nested paragraphs). if ($field_item->entity && empty($field_item->entity->parent_type->value)) { // Set the parent fields and save, ensure that no new revision is // created. $field_item->entity->parent_type = $field_storage->getTargetEntityTypeId(); $field_item->entity->parent_id = $host_entity->id(); $field_item->entity->parent_field_name = $field_storage->getName(); $field_item->entity->setNewRevision(FALSE); $field_item->entity->save(); } } } // Continue with the next paragraph_field_id when the loaded entities are less // than paragraph_limit. if (count($entity_ids) < Settings::get('paragraph_limit', 50)) { $sandbox['current_paragraph_field_id']++; $sandbox['progress'] = 0; } else { $sandbox['progress'] += Settings::get('paragraph_limit', 50); } // Update #finished, 1 if the the whole update has finished. $sandbox['#finished'] = empty($sandbox['max']) ? 1 : $sandbox['current_paragraph_field_id'] / $sandbox['max']; }
/** * @inheritDoc */ public function getModules() { $modules = array(); $module_data = system_rebuild_module_data(); foreach ($module_data as $module_name => $extension) { if (!isset($extension->info['hidden']) && $extension->origin != 'core') { $extension->schema_version = drupal_get_installed_schema_version($module_name); $modules[] = new CRM_Core_Module('drupal.' . $module_name, $extension->status == 1 ? TRUE : FALSE); } } return $modules; }
/** * Gather site profile information about this site. * * @param string $method * Optional identifier for the method initiating request. * Values could be 'cron' or 'menu callback' or 'drush'. * * @return array * An associative array keyed by types of information. */ public function get($method = '') { // Get file hashes and compute serialized version. list($hashes, $fileinfo) = $this->getFileHashes(); $hashes_string = serialize($hashes); // Get the Drupal version $drupal_version = $this->getVersionInfo(); $stored = $this->dataStoreGet(array('platform')); if (!empty($stored['platform'])) { $platform = $stored['platform']; } else { $platform = $this->getPlatform(); } $spi = array('rpc_version' => ACQUIA_SPI_DATA_VERSION, 'spi_data_version' => ACQUIA_SPI_DATA_VERSION, 'site_key' => sha1(\Drupal::service('private_key')->get()), 'modules' => $this->getModules(), 'platform' => $platform, 'quantum' => $this->getQuantum(), 'system_status' => $this->getSystemStatus(), 'failed_logins' => $this->config('acquia_connector.settings')->get('spi.send_watchdog') ? $this->getFailedLogins() : array(), '404s' => $this->config('acquia_connector.settings')->get('spi.send_watchdog') ? $this->get404s() : array(), 'watchdog_size' => $this->getWatchdogSize(), 'watchdog_data' => $this->config('acquia_connector.settings')->get('spi.send_watchdog') ? $this->getWatchdogData() : array(), 'last_nodes' => $this->config('acquia_connector.settings')->get('spi.send_node_user') ? $this->getLastNodes() : array(), 'last_users' => $this->config('acquia_connector.settings')->get('spi.send_node_user') ? $this->getLastUsers() : array(), 'extra_files' => $this->checkFilesPresent(), 'ssl_login' => $this->checkLogin(), 'file_hashes' => $hashes, 'hashes_md5' => md5($hashes_string), 'hashes_sha1' => sha1($hashes_string), 'fileinfo' => $fileinfo, 'distribution' => isset($drupal_version['distribution']) ? $drupal_version['distribution'] : '', 'base_version' => $drupal_version['base_version'], 'build_data' => $drupal_version, 'roles' => Json::encode(user_roles()), 'uid_0_present' => $this->getUidZerroIsPresent()); $scheme = parse_url($this->config('acquia_connector.settings')->get('spi.server'), PHP_URL_SCHEME); $via_ssl = in_array('ssl', stream_get_transports(), TRUE) && $scheme == 'https' ? TRUE : FALSE; if ($this->config('acquia_connector.settings')->get('spi.ssl_override')) { $via_ssl = TRUE; } $additional_data = array(); $security_review = new SecurityReviewController(); $security_review_results = $security_review->runSecurityReview(); // It's worth sending along node access control information even if there are // no modules implementing it - some alerts are simpler if we know we don't // have to worry about node access. // Check for node grants modules. $additional_data['node_grants_modules'] = \Drupal::moduleHandler()->getImplementations('node_grants'); // Check for node access modules. $additional_data['node_access_modules'] = \Drupal::moduleHandler()->getImplementations('node_access'); if (!empty($security_review_results)) { $additional_data['security_review'] = $security_review_results['security_review']; } // Collect all user-contributed custom tests that pass validation. $custom_tests_results = $this->testCollect(); if (!empty($custom_tests_results)) { $additional_data['custom_tests'] = $custom_tests_results; } $spi_data = \Drupal::moduleHandler()->invokeAll('acquia_connector_spi_get'); if (!empty($spi_data)) { foreach ($spi_data as $name => $data) { if (is_string($name) && is_array($data)) { $additional_data[$name] = $data; } } } // Database updates required? // Based on code from system.install $additional_data['pending_updates'] = FALSE; foreach (\Drupal::moduleHandler()->getModuleList() as $module => $filename) { $updates = drupal_get_schema_versions($module); if ($updates !== FALSE) { $default = drupal_get_installed_schema_version($module); if (max($updates) > $default) { $additional_data['pending_updates'] = TRUE; break; } } } if (!$additional_data['pending_updates'] && \Drupal::service('entity.definition_update_manager')->needsUpdates()) { $additional_data['pending_updates'] = TRUE; } if (!empty($additional_data)) { // JSON encode this additional data. $spi['additional_data'] = json_encode($additional_data); } if (!empty($method)) { $spi['send_method'] = $method; } if (!$via_ssl) { return $spi; } else { $variablesController = new VariablesController(); // Values returned only over SSL $spi_ssl = array('system_vars' => $variablesController->getVariablesData(), 'settings_ra' => $this->getSettingsPermissions(), 'admin_count' => $this->config('acquia_connector.settings')->get('spi.admin_priv') ? $this->getAdminCount() : '', 'admin_name' => $this->config('acquia_connector.settings')->get('spi.admin_priv') ? $this->getSuperName() : ''); return array_merge($spi, $spi_ssl); } }
/** * Tests uninstalling a module that has content. */ function testUninstallContentDependency() { $this->enableModules(array('module_test', 'entity_test', 'text', 'user', 'help')); $this->assertTrue($this->moduleHandler()->moduleExists('entity_test'), 'Test module is enabled.'); $this->assertTrue($this->moduleHandler()->moduleExists('module_test'), 'Test module is enabled.'); $this->installSchema('user', 'users_data'); $entity_types = \Drupal::entityManager()->getDefinitions(); foreach ($entity_types as $entity_type) { if ('entity_test' == $entity_type->getProvider()) { $this->installEntitySchema($entity_type->id()); } } // Create a fake dependency. // entity_test will depend on help. This way help can not be uninstalled // when there is test content preventing entity_test from being uninstalled. \Drupal::state()->set('module_test.dependency', 'dependency'); drupal_static_reset('system_rebuild_module_data'); // Create an entity so that the modules can not be disabled. $entity = entity_create('entity_test', array('name' => $this->randomString())); $entity->save(); // Uninstalling entity_test is not possible when there is content. try { $message = 'ModuleHandler::uninstall() throws ModuleUninstallValidatorException upon uninstalling a module which does not pass validation.'; $this->moduleInstaller()->uninstall(array('entity_test')); $this->fail($message); } catch (ModuleUninstallValidatorException $e) { $this->pass(get_class($e) . ': ' . $e->getMessage()); } // Uninstalling help needs entity_test to be un-installable. try { $message = 'ModuleHandler::uninstall() throws ModuleUninstallValidatorException upon uninstalling a module which does not pass validation.'; $this->moduleInstaller()->uninstall(array('help')); $this->fail($message); } catch (ModuleUninstallValidatorException $e) { $this->pass(get_class($e) . ': ' . $e->getMessage()); } // Deleting the entity. $entity->delete(); $result = $this->moduleInstaller()->uninstall(array('help')); $this->assertTrue($result, 'ModuleHandler::uninstall() returns TRUE.'); $this->assertEqual(drupal_get_installed_schema_version('entity_test'), SCHEMA_UNINSTALLED, "entity_test module was uninstalled."); }
function update_selection_page() { $output = '<p>The version of Drupal you are updating from has been automatically detected. You can select a different version, but you should not need to.</p>'; $output .= '<p>Click Update to start the update process.</p>'; $form = array(); $form['start'] = array('#tree' => TRUE, '#type' => 'fieldset', '#title' => 'Select versions', '#collapsible' => TRUE, '#collapsed' => TRUE); foreach (module_list() as $module) { $updates = drupal_get_schema_versions($module); if ($updates !== FALSE) { $updates = drupal_map_assoc($updates); $updates[] = 'No updates available'; $form['start'][$module] = array('#type' => 'select', '#title' => $module . ' module', '#default_value' => array_search(drupal_get_installed_schema_version($module), $updates) + 1, '#options' => $updates); } } $form['has_js'] = array('#type' => 'hidden', '#default_value' => FALSE, '#attributes' => array('id' => 'edit-has_js')); $form['submit'] = array('#type' => 'submit', '#value' => 'Update'); drupal_set_title('Drupal database update'); // Prevent browser from using cached drupal.js or update.js drupal_add_js('misc/update.js', TRUE); $output .= drupal_get_form('update_script_selection_form', $form); return $output; }
/** * {@inheritdoc} */ public function uninstall(array $module_list, $uninstall_dependents = TRUE) { // 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 (array_diff_key($module_list, $module_data)) { // One or more of the given modules doesn't exist. return FALSE; } $extension_config = \Drupal::configFactory()->getEditable('core.extension'); $installed_modules = $extension_config->get('module') ?: array(); if (!($module_list = array_intersect_key($module_list, $installed_modules))) { // Nothing to do. All modules already uninstalled. return TRUE; } if ($uninstall_dependents) { // Add dependent modules to the list. The new modules will be processed as // the while loop continues. $profile = drupal_get_profile(); while (list($module) = each($module_list)) { foreach (array_keys($module_data[$module]->required_by) as $dependent) { if (!isset($module_data[$dependent])) { // The dependent module does not exist. return FALSE; } // Skip already uninstalled modules. if (isset($installed_modules[$dependent]) && !isset($module_list[$dependent]) && $dependent != $profile) { $module_list[$dependent] = $dependent; } } } } // Use the validators and throw an exception with the reasons. if ($reasons = $this->validateUninstall($module_list)) { foreach ($reasons as $reason) { $reason_message[] = implode(', ', $reason); } throw new ModuleUninstallValidatorException('The following reasons prevent the modules from being uninstalled: ' . implode('; ', $reason_message)); } // 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. asort($module_list); $module_list = array_keys($module_list); // Only process modules that are enabled. A module is only enabled if it is // configured as enabled. Custom or overridden module handlers might contain // the module already, which means that it might be loaded, but not // necessarily installed. foreach ($module_list as $module) { // Clean up all entity bundles (including fields) of every entity type // provided by the module that is being uninstalled. // @todo Clean this up in https://www.drupal.org/node/2350111. $entity_manager = \Drupal::entityManager(); foreach ($entity_manager->getDefinitions() as $entity_type_id => $entity_type) { if ($entity_type->getProvider() == $module) { foreach (array_keys($entity_manager->getBundleInfo($entity_type_id)) as $bundle) { $entity_manager->onBundleDelete($bundle, $entity_type_id); } } } // Allow modules to react prior to the uninstallation of a module. $this->moduleHandler->invokeAll('module_preuninstall', array($module)); // Uninstall the module. module_load_install($module); $this->moduleHandler->invoke($module, 'uninstall'); // Remove all configuration belonging to the module. \Drupal::service('config.manager')->uninstall('module', $module); // 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')); // Notify interested components that this module's entity types are being // deleted. For example, a SQL-based storage handler can use this as an // opportunity to drop the corresponding database tables. // @todo Clean this up in https://www.drupal.org/node/2350111. $update_manager = \Drupal::entityDefinitionUpdateManager(); foreach ($entity_manager->getDefinitions() as $entity_type) { if ($entity_type->getProvider() == $module) { $update_manager->uninstallEntityType($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. $entity_type_id = $entity_type->id(); /** @var \Drupal\Core\Entity\FieldableEntityStorageInterface $storage */ $storage = $entity_manager->getStorage($entity_type_id); foreach ($entity_manager->getFieldStorageDefinitions($entity_type_id) as $storage_definition) { // @todo We need to trigger field purging here. // See https://www.drupal.org/node/2282119. if ($storage_definition->getProvider() == $module && !$storage->countFieldData($storage_definition, TRUE)) { $update_manager->uninstallFieldStorageDefinition($storage_definition); } } } } // Remove the schema. drupal_uninstall_schema($module); // Remove the module's entry from the config. Don't check schema when // uninstalling a module since we are only clearing a key. \Drupal::configFactory()->getEditable('core.extension')->clear("module.{$module}")->save(TRUE); // Update the module handler to remove the module. // The current ModuleHandler instance is obsolete with the kernel rebuild // below. $module_filenames = $this->moduleHandler->getModuleList(); unset($module_filenames[$module]); $this->moduleHandler->setModuleList($module_filenames); // Remove any potential cache bins provided by the module. $this->removeCacheBins($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'); // Clear plugin manager caches. \Drupal::getContainer()->get('plugin.cache_clearer')->clearCachedDefinitions(); // Update the kernel to exclude the uninstalled modules. $this->updateKernel($module_filenames); // Update the theme registry to remove the newly uninstalled module. 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. // @see https://www.drupal.org/node/2208429 \Drupal::service('theme_handler')->refreshInfo(); \Drupal::logger('system')->info('%module module uninstalled.', array('%module' => $module)); $schema_store = \Drupal::keyValue('system.schema'); $schema_store->delete($module); /** @var \Drupal\Core\Update\UpdateRegistry $post_update_registry */ $post_update_registry = \Drupal::service('update.post_update_registry'); $post_update_registry->filterOutInvokedUpdatesByModule($module); } // 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 uninstallation page // was sent already. \Drupal::service('router.builder')->rebuild(); drupal_get_installed_schema_version(NULL, TRUE); // Let other modules react. $this->moduleHandler->invokeAll('modules_uninstalled', array($module_list)); // Flush all persistent caches. // Any cache entry might implicitly depend on the uninstalled modules, // so clear all of them explicitly. $this->moduleHandler->invokeAll('cache_flush'); foreach (Cache::getBins() as $service_id => $cache_backend) { $cache_backend->deleteAll(); } return TRUE; }
/** * Enables a drupal module * @param string $name name of the module * @return boolean success */ function drupalModuleEnable($name) { if (module_exists($name)) { return TRUE; } include_once './includes/install.inc'; module_rebuild_cache(); // Rebuild the module cache if (drupal_get_installed_schema_version($name, TRUE) == SCHEMA_UNINSTALLED) { drupal_install_modules(array($name)); } else { $try = module_enable(array($name)); } if (module_exists($name)) { if (!isset($this->_cleanupModules[$name])) { $this->_cleanupModules[$name] = 0; return TRUE; } } else { die("required module {$name} could not be enabled (probably file does not exist)"); } }
/** * Tests update.php after performing a successful update. */ function testSuccessfulUpdateFunctionality() { $schema_version = drupal_get_installed_schema_version('update_script_test'); $this->assertEqual($schema_version, 8001, 'update_script_test is initially installed with schema version 8001.'); // Set the installed schema version to one less than the current update. drupal_set_installed_schema_version('update_script_test', $schema_version - 1); $schema_version = drupal_get_installed_schema_version('update_script_test', TRUE); $this->assertEqual($schema_version, 8000, 'update_script_test schema version overridden to 8000.'); // Click through update.php with 'administer software updates' permission. $this->drupalLogin($this->updateUser); $this->drupalGet($this->updateUrl, array('external' => TRUE)); $this->clickLink(t('Continue')); $this->clickLink(t('Apply pending updates')); // Verify that updates were completed successfully. $this->assertText('Updates were attempted.'); $this->assertLink('site'); $this->assertText('The update_script_test_update_8001() update was executed successfully.'); // Verify that no 7.x updates were run. $this->assertNoText('The update_script_test_update_7200() update was executed successfully.'); $this->assertNoText('The update_script_test_update_7201() update was executed successfully.'); // Verify that there are no links to different parts of the workflow. $this->assertNoLink('Administration pages'); $this->assertNoLinkByHref('update.php', 0); $this->assertNoLink('logged'); // Verify the front page can be visited following the upgrade. $this->clickLink('Front page'); $this->assertResponse(200); // Reset the static cache to ensure we have the most current setting. $schema_version = drupal_get_installed_schema_version('update_script_test', TRUE); $this->assertEqual($schema_version, 8001, 'update_script_test schema version is 8001 after updating.'); // Set the installed schema version to one less than the current update. drupal_set_installed_schema_version('update_script_test', $schema_version - 1); $schema_version = drupal_get_installed_schema_version('update_script_test', TRUE); $this->assertEqual($schema_version, 8000, 'update_script_test schema version overridden to 8000.'); // Click through update.php with 'access administration pages' and // 'access site reports' permissions. $admin_user = $this->drupalCreateUser(array('administer software updates', 'access administration pages', 'access site reports', 'access site in maintenance mode')); $this->drupalLogin($admin_user); $this->drupalGet($this->updateUrl, array('external' => TRUE)); $this->clickLink(t('Continue')); $this->clickLink(t('Apply pending updates')); $this->assertText('Updates were attempted.'); $this->assertLink('logged'); $this->assertLink('Administration pages'); $this->assertNoLinkByHref('update.php', 1); $this->clickLink('Administration pages'); $this->assertResponse(200); }
/** * {@inheritdoc} */ public function buildForm(array $form, FormStateInterface $form_state) { // Make sure the install API is available. include_once DRUPAL_ROOT . '/core/includes/install.inc'; // Get a list of all available modules. $modules = system_rebuild_module_data(); $uninstallable = array_filter($modules, function ($module) use($modules) { return empty($modules[$module->getName()]->info['required']) && $module->status; }); // Include system.admin.inc so we can use the sort callbacks. $this->moduleHandler->loadInclude('system', 'inc', 'system.admin'); $form['filters'] = array('#type' => 'container', '#attributes' => array('class' => array('table-filter', 'js-show'))); $form['filters']['text'] = array('#type' => 'search', '#title' => $this->t('Search'), '#size' => 30, '#placeholder' => $this->t('Enter module name'), '#attributes' => array('class' => array('table-filter-text'), 'data-table' => '#system-modules-uninstall', 'autocomplete' => 'off', 'title' => $this->t('Enter a part of the module name or description to filter by.'))); $form['modules'] = array(); // Only build the rest of the form if there are any modules available to // uninstall; if (empty($uninstallable)) { return $form; } $profile = drupal_get_profile(); // Sort all modules by their name. uasort($uninstallable, 'system_sort_modules_by_info_name'); $validation_reasons = $this->moduleInstaller->validateUninstall(array_keys($uninstallable)); $form['uninstall'] = array('#tree' => TRUE); foreach ($uninstallable as $module_key => $module) { $name = $module->info['name'] ?: $module->getName(); $form['modules'][$module->getName()]['#module_name'] = $name; $form['modules'][$module->getName()]['name']['#markup'] = $name; $form['modules'][$module->getName()]['description']['#markup'] = $this->t($module->info['description']); $form['uninstall'][$module->getName()] = array('#type' => 'checkbox', '#title' => $this->t('Uninstall @module module', array('@module' => $name)), '#title_display' => 'invisible'); // If a validator returns reasons not to uninstall a module, // list the reasons and disable the check box. if (isset($validation_reasons[$module_key])) { $form['modules'][$module->getName()]['#validation_reasons'] = $validation_reasons[$module_key]; $form['uninstall'][$module->getName()]['#disabled'] = TRUE; } // All modules which depend on this one must be uninstalled first, before // we can allow this module to be uninstalled. (The installation profile // is excluded from this list.) foreach (array_keys($module->required_by) as $dependent) { if ($dependent != $profile && drupal_get_installed_schema_version($dependent) != SCHEMA_UNINSTALLED) { $name = isset($modules[$dependent]->info['name']) ? $modules[$dependent]->info['name'] : $dependent; $form['modules'][$module->getName()]['#required_by'][] = $name; $form['uninstall'][$module->getName()]['#disabled'] = TRUE; } } } $form['#attached']['library'][] = 'system/drupal.system.modules'; $form['actions'] = array('#type' => 'actions'); $form['actions']['submit'] = array('#type' => 'submit', '#value' => $this->t('Uninstall')); return $form; }
function update_script_selection_form() { $form = array(); $form['start'] = array('#tree' => TRUE, '#type' => 'fieldset', '#title' => 'Select versions', '#collapsible' => TRUE, '#collapsed' => TRUE); // Ensure system.module's updates appear first $form['start']['system'] = array(); foreach (module_list() as $module) { $updates = drupal_get_schema_versions($module); if ($updates !== FALSE) { $updates = drupal_map_assoc($updates); $updates[] = 'No updates available'; $default = drupal_get_installed_schema_version($module); foreach (array_keys($updates) as $update) { if ($update > $default) { $default = $update; break; } } $form['start'][$module] = array('#type' => 'select', '#title' => $module . ' module', '#default_value' => $default, '#options' => $updates); } } $form['has_js'] = array('#type' => 'hidden', '#default_value' => FALSE, '#attributes' => array('id' => 'edit-has_js')); $form['submit'] = array('#type' => 'submit', '#value' => 'Update'); return $form; }