/** * @param \Drupal\Console\Style\DrupalStyle $io */ private function runPostUpdates(DrupalStyle $io) { $postUpdates = $this->postUpdateRegistry->getPendingUpdateInformation(); foreach ($postUpdates as $module_name => $module_updates) { foreach ($module_updates['pending'] as $update_number => $update) { if ($this->module != 'all' && $this->update_n !== null && $this->update_n != $update_number) { continue; } if ($this->update_n > $module_updates['start']) { $io->info($this->trans('commands.update.execute.messages.executing-required-previous-updates')); } for ($update_index = $module_updates['start']; $update_index <= $update_number; $update_index++) { $io->info(sprintf($this->trans('commands.update.execute.messages.executing-update'), $update_index, $module_name)); try { $function = sprintf('%s_post_update_%s', $module_name, $update_index); drupal_flush_all_caches(); update_invoke_post_update($function); } catch (\Exception $e) { watchdog_exception('update', $e); $io->error($e->getMessage()); } } } } }
/** * Starts the database update batch process. * * @param \Symfony\Component\HttpFoundation\Request $request * The current request object. */ protected function triggerBatch(Request $request) { $maintenance_mode = $this->state->get('system.maintenance_mode', FALSE); // Store the current maintenance mode status in the session so that it can // be restored at the end of the batch. $_SESSION['maintenance_mode'] = $maintenance_mode; // During the update, always put the site into maintenance mode so that // in-progress schema changes do not affect visiting users. if (empty($maintenance_mode)) { $this->state->set('system.maintenance_mode', TRUE); } $operations = array(); // Resolve any update dependencies to determine the actual updates that will // be run and the order they will be run in. $start = $this->getModuleUpdates(); $updates = update_resolve_dependencies($start); // Store the dependencies for each update function in an array which the // batch API can pass in to the batch operation each time it is called. (We // do not store the entire update dependency array here because it is // potentially very large.) $dependency_map = array(); foreach ($updates as $function => $update) { $dependency_map[$function] = !empty($update['reverse_paths']) ? array_keys($update['reverse_paths']) : array(); } // Determine updates to be performed. foreach ($updates as $function => $update) { if ($update['allowed']) { // Set the installed version of each module so updates will start at the // correct place. (The updates are already sorted, so we can simply base // this on the first one we come across in the above foreach loop.) if (isset($start[$update['module']])) { drupal_set_installed_schema_version($update['module'], $update['number'] - 1); unset($start[$update['module']]); } $operations[] = array('update_do_one', array($update['module'], $update['number'], $dependency_map[$function])); } } $post_updates = $this->postUpdateRegistry->getPendingUpdateFunctions(); if ($post_updates) { // Now we rebuild all caches and after that execute the hook_post_update() // functions. $operations[] = ['drupal_flush_all_caches', []]; foreach ($post_updates as $function) { $operations[] = ['update_invoke_post_update', [$function]]; } } $batch['operations'] = $operations; $batch += array('title' => $this->t('Updating'), 'init_message' => $this->t('Starting updates'), 'error_message' => $this->t('An unrecoverable error has occurred. You can find the error message below. It is advised to copy it to the clipboard for reference.'), 'finished' => array('\\Drupal\\system\\Controller\\DbUpdateController', 'batchFinished')); batch_set($batch); // @todo Revisit once https://www.drupal.org/node/2548095 is in. return batch_process(Url::fromUri('base://results'), Url::fromUri('base://start')); }
/** * @param \Drupal\Console\Style\DrupalStyle $io */ private function populatePostUpdate(DrupalStyle $io) { $io->info($this->trans('commands.update.debug.messages.module-list-post-update')); $tableHeader = [$this->trans('commands.update.debug.messages.module'), $this->trans('commands.update.debug.messages.post-update'), $this->trans('commands.update.debug.messages.description')]; $postUpdates = $this->postUpdateRegistry->getPendingUpdateInformation(); $tableRows = []; foreach ($postUpdates as $module => $module_updates) { foreach ($module_updates['pending'] as $postUpdateFunction => $message) { $tableRows[] = [$module, $postUpdateFunction, $message]; } } $io->table($tableHeader, $tableRows); }
/** * @covers ::filterOutInvokedUpdatesByModule */ public function testFilterOutInvokedUpdatesByModule() { $this->setupBasicModules(); $key_value = $this->prophesize(KeyValueStoreInterface::class); $key_value->get('existing_updates', [])->willReturn(['module_a_post_update_b', 'module_a_post_update_a', 'module_b_post_update_a'])->shouldBeCalledTimes(1); $key_value->set('existing_updates', ['module_b_post_update_a'])->willReturn(NULL)->shouldBeCalledTimes(1); $key_value = $key_value->reveal(); $update_registry = new UpdateRegistry('vfs://drupal', 'sites/default', ['module_a', 'module_b'], $key_value, FALSE); $update_registry->filterOutInvokedUpdatesByModule('module_a'); }