/** * Starts the batch process depending on where it was requested from. */ public function start() { switch ($this->batchInfo['from']) { case 'form': batch_set($this->batch); break; case 'drush': batch_set($this->batch); $this->batch =& batch_get(); $this->batch['progressive'] = FALSE; drush_log(t(self::BATCH_INIT_MESSAGE), 'status'); drush_backend_batch_process(); break; case 'backend': batch_set($this->batch); $this->batch =& batch_get(); $this->batch['progressive'] = FALSE; batch_process(); //todo: Does not take advantage of batch API and eventually runs out of memory on very large sites. break; case 'nobatch': $context = []; foreach ($this->batch['operations'] as $i => $operation) { $operation[1][] =& $context; call_user_func_array($operation[0], $operation[1]); } self::finishGeneration(TRUE, $context['results'], []); break; } }
/** * Test the programmatic form submission workflow. */ function testSubmissionWorkflow() { // Backup the current batch status and reset it to avoid conflicts while // processing the dummy form submit handler. $current_batch = $batch =& batch_get(); $batch = array(); // Test that a programmatic form submission is rejected when a required // textfield is omitted and correctly processed when it is provided. $this->submitForm(array(), FALSE); $this->submitForm(array('textfield' => 'test 1'), TRUE); $this->submitForm(array(), FALSE); $this->submitForm(array('textfield' => 'test 2'), TRUE); // Test that a programmatic form submission can turn on and off checkboxes // which are, by default, checked. $this->submitForm(array('textfield' => 'dummy value', 'checkboxes' => array(1 => 1, 2 => 2)), TRUE); $this->submitForm(array('textfield' => 'dummy value', 'checkboxes' => array(1 => 1, 2 => NULL)), TRUE); $this->submitForm(array('textfield' => 'dummy value', 'checkboxes' => array(1 => NULL, 2 => 2)), TRUE); $this->submitForm(array('textfield' => 'dummy value', 'checkboxes' => array(1 => NULL, 2 => NULL)), TRUE); // Test that a programmatic form submission can correctly click a button // that limits validation errors based on user input. Since we do not // submit any values for "textfield" here and the textfield is required, we // only expect form validation to pass when validation is limited to a // different field. $this->submitForm(array('op' => 'Submit with limited validation', 'field_to_validate' => 'all'), FALSE); $this->submitForm(array('op' => 'Submit with limited validation', 'field_to_validate' => 'textfield'), FALSE); $this->submitForm(array('op' => 'Submit with limited validation', 'field_to_validate' => 'field_to_validate'), TRUE); // Restore the current batch status. $batch = $current_batch; }
/** * {@inheritdoc} */ public function buildForm(array $form, FormStateInterface $form_state) { // Don't show the form when batch operations are in progress. if ($batch = batch_get() && isset($batch['current_set'])) { return array('#theme' => ''); } // Make sure that we validate because this form might be submitted // multiple times per page. $form_state['must_validate'] = TRUE; /** @var \Drupal\views\ViewExecutable $view */ $view = $form_state['view']; $display =& $form_state['display']; $form_state['input'] = $view->getExposedInput(); // Let form plugins know this is for exposed widgets. $form_state['exposed'] = TRUE; // Check if the form was already created if ($cache = $this->exposedFormCache->getForm($view->storage->id(), $view->current_display)) { return $cache; } $form['#info'] = array(); // Go through each handler and let it generate its exposed widget. foreach ($view->display_handler->handlers as $type => $value) { /** @var \Drupal\views\Plugin\views\HandlerBase $handler */ foreach ($view->{$type} as $id => $handler) { if ($handler->canExpose() && $handler->isExposed()) { // Grouped exposed filters have their own forms. // Instead of render the standard exposed form, a new Select or // Radio form field is rendered with the available groups. // When an user choose an option the selected value is split // into the operator and value that the item represents. if ($handler->isAGroup()) { $handler->groupForm($form, $form_state); $id = $handler->options['group_info']['identifier']; } else { $handler->buildExposedForm($form, $form_state); } if ($info = $handler->exposedInfo()) { $form['#info']["{$type}-{$id}"] = $info; } } } } $form['actions'] = array('#type' => 'actions'); $form['actions']['submit'] = array('#name' => '', '#type' => 'submit', '#value' => $this->t('Apply'), '#id' => drupal_html_id('edit-submit-' . $view->storage->id())); $form['#action'] = url($view->display_handler->getUrl()); $form['#theme'] = $view->buildThemeFunctions('views_exposed_form'); $form['#id'] = drupal_clean_css_identifier('views_exposed_form-' . String::checkPlain($view->storage->id()) . '-' . String::checkPlain($display['id'])); // $form['#attributes']['class'] = array('views-exposed-form'); /** @var \Drupal\views\Plugin\views\exposed_form\ExposedFormPluginBase $exposed_form_plugin */ $exposed_form_plugin = $form_state['exposed_form_plugin']; $exposed_form_plugin->exposedFormAlter($form, $form_state); // Save the form. $this->exposedFormCache->setForm($view->storage->id(), $view->current_display, $form); return $form; }
/** * Block a user and remove or reassign their content. */ public function cancel() { if (drush_get_option('delete-content')) { user_cancel(array(), $this->id(), 'user_cancel_delete'); } else { user_cancel(array(), $this->id(), 'user_cancel_reassign'); } // I got the following technique here: http://drupal.org/node/638712 $batch =& batch_get(); $batch['progressive'] = FALSE; batch_process(); }
/** * {@inheritdoc} */ public function determineActiveTheme(RouteMatchInterface $route_match) { // Retrieve the current state of the batch. $request = $this->requestStack->getCurrentRequest(); $batch =& batch_get(); if (!$batch && $request->request->has('id')) { $batch = $this->batchStorage->load($request->request->get('id')); } // Use the same theme as the page that started the batch. if (!empty($batch['theme'])) { return $batch['theme']; } }
/** * Checks for translation updates and displays the translations status. * * Manually checks the translation status without the use of cron. * * @return \Symfony\Component\HttpFoundation\RedirectResponse * A redirection to translations reports page. */ public function checkTranslation() { $this->moduleHandler()->loadInclude('locale', 'inc', 'locale.compare'); // Check translation status of all translatable project in all languages. // First we clear the cached list of projects. Although not strictly // necessary, this is helpful in case the project list is out of sync. locale_translation_flush_projects(); locale_translation_check_projects(); // Execute a batch if required. A batch is only used when remote files // are checked. if (batch_get()) { return batch_process('admin/reports/translations'); } return $this->redirect('locale.translate_status'); }
/** * Checks for translation updates and displays the translations status. * * Manually checks the translation status without the use of cron. * * @return \Symfony\Component\HttpFoundation\RedirectResponse * A redirection to translations reports page. */ public function checkTranslation() { $this->moduleHandler()->loadInclude('locale', 'inc', 'locale.compare'); // Check translation status of all translatable project in all languages. // First we clear the cached list of projects. Although not strictly // necessary, this is helpful in case the project list is out of sync. locale_translation_flush_projects(); locale_translation_check_projects(); // Execute a batch if required. A batch is only used when remote files // are checked. if (batch_get()) { return batch_process('admin/reports/translations'); } // @todo Use $this->redirect() after https://drupal.org/node/1978926. return new RedirectResponse($this->getUrlGenerator()->generateFromPath('admin/reports/translations', array('absolute' => TRUE))); }
case 'selection': if (isset($_GET['token']) && $_GET['token'] == drupal_get_token('update')) { $output = update_selection_page(); break; } case 'Apply pending updates': if (isset($_GET['token']) && $_GET['token'] == drupal_get_token('update')) { update_batch(); break; } case 'info': $output = update_info_page(); break; case 'results': $output = update_results_page(); break; // Regular batch ops : defer to batch processing API // Regular batch ops : defer to batch processing API default: update_task_list('run'); $output = _batch_page(); break; } } else { $output = update_access_denied_page(); } if (isset($output) && $output) { // We defer the display of messages until all updates are done. $progress_page = ($batch = batch_get()) && isset($batch['running']); print theme('update_page', $output, !$progress_page); }
public function processBatch() { $batch =& batch_get(); $batch['progressive'] = FALSE; batch_process(); }
if (!empty($results['page_title'])) { drupal_set_title(check_plain($results['page_title'])); } if (!empty($results['page_message'])) { drupal_set_message($results['page_message']['message'], $results['page_message']['type']); } $output = theme('authorize_report', array('messages' => $results['messages'])); $links = array(); if (is_array($results['tasks'])) { $links += $results['tasks']; } $links = array_merge($links, array(l(t('Administration pages'), 'admin'), l(t('Front page'), '<front>'))); $output .= theme('item_list', array('items' => $links)); } elseif (isset($_GET['batch'])) { $output = _batch_page(); } else { if (empty($_SESSION['authorize_operation']) || empty($_SESSION['authorize_filetransfer_backends'])) { $output = t('It appears you have reached this page in error.'); } elseif (!($batch = batch_get())) { // We have a batch to process, show the filetransfer form. $output = drupal_render(drupal_get_form('authorize_filetransfer_form')); } } // We defer the display of messages until all operations are done. $show_messages = !(($batch = batch_get()) && isset($batch['running'])); } else { $output = authorize_access_denied_page(); } if (!empty($output)) { print theme('update_page', array('content' => $output, 'show_messages' => $show_messages)); }
/** * Sets up a Drupal site for running functional and integration tests. * * Installs Drupal with the installation profile specified in * \Drupal\simpletest\WebTestBase::$profile into the prefixed database. * * Afterwards, installs any additional modules specified in the static * \Drupal\simpletest\WebTestBase::$modules property of each class in the * class hierarchy. * * After installation all caches are flushed and several configuration values * are reset to the values of the parent site executing the test, since the * default values may be incompatible with the environment in which tests are * being executed. */ protected function setUp() { // When running tests through the Simpletest UI (vs. on the command line), // Simpletest's batch conflicts with the installer's batch. Batch API does // not support the concept of nested batches (in which the nested is not // progressive), so we need to temporarily pretend there was no batch. // Backup the currently running Simpletest batch. $this->originalBatch = batch_get(); // Define information about the user 1 account. $this->rootUser = new UserSession(array('uid' => 1, 'name' => 'admin', 'mail' => '*****@*****.**', 'pass_raw' => $this->randomMachineName())); // The child site derives its session name from the database prefix when // running web tests. $this->generateSessionName($this->databasePrefix); // Reset the static batch to remove Simpletest's batch operations. $batch =& batch_get(); $batch = array(); // Get parameters for install_drupal() before removing global variables. $parameters = $this->installParameters(); // Prepare installer settings that are not install_drupal() parameters. // Copy and prepare an actual settings.php, so as to resemble a regular // installation. // Not using File API; a potential error must trigger a PHP warning. $directory = DRUPAL_ROOT . '/' . $this->siteDirectory; copy(DRUPAL_ROOT . '/sites/default/default.settings.php', $directory . '/settings.php'); copy(DRUPAL_ROOT . '/sites/default/default.services.yml', $directory . '/services.yml'); // All file system paths are created by System module during installation. // @see system_requirements() // @see TestBase::prepareEnvironment() $settings['settings']['file_public_path'] = (object) array('value' => $this->publicFilesDirectory, 'required' => TRUE); $settings['settings']['file_private_path'] = (object) array('value' => $this->privateFilesDirectory, 'required' => TRUE); // Save the original site directory path, so that extensions in the // site-specific directory can still be discovered in the test site // environment. // @see \Drupal\Core\Extension\ExtensionDiscovery::scan() $settings['settings']['test_parent_site'] = (object) array('value' => $this->originalSite, 'required' => TRUE); // Add the parent profile's search path to the child site's search paths. // @see \Drupal\Core\Extension\ExtensionDiscovery::getProfileDirectories() $settings['conf']['simpletest.settings']['parent_profile'] = (object) array('value' => $this->originalProfile, 'required' => TRUE); $settings['settings']['apcu_ensure_unique_prefix'] = (object) array('value' => FALSE, 'required' => TRUE); $this->writeSettings($settings); // Allow for test-specific overrides. $settings_testing_file = DRUPAL_ROOT . '/' . $this->originalSite . '/settings.testing.php'; if (file_exists($settings_testing_file)) { // Copy the testing-specific settings.php overrides in place. copy($settings_testing_file, $directory . '/settings.testing.php'); // Add the name of the testing class to settings.php and include the // testing specific overrides file_put_contents($directory . '/settings.php', "\n\$test_class = '" . get_class($this) . "';\n" . 'include DRUPAL_ROOT . \'/\' . $site_path . \'/settings.testing.php\';' . "\n", FILE_APPEND); } $settings_services_file = DRUPAL_ROOT . '/' . $this->originalSite . '/testing.services.yml'; if (file_exists($settings_services_file)) { // Copy the testing-specific service overrides in place. copy($settings_services_file, $directory . '/services.yml'); } if ($this->strictConfigSchema) { // Add a listener to validate configuration schema on save. $yaml = new \Symfony\Component\Yaml\Yaml(); $services = $yaml->parse($directory . '/services.yml'); $services['services']['simpletest.config_schema_checker'] = ['class' => 'Drupal\\Core\\Config\\Testing\\ConfigSchemaChecker', 'arguments' => ['@config.typed'], 'tags' => [['name' => 'event_subscriber']]]; file_put_contents($directory . '/services.yml', $yaml->dump($services)); } // Since Drupal is bootstrapped already, install_begin_request() will not // bootstrap again. Hence, we have to reload the newly written custom // settings.php manually. $class_loader = (require DRUPAL_ROOT . '/autoload.php'); Settings::initialize(DRUPAL_ROOT, $this->siteDirectory, $class_loader); // Execute the non-interactive installer. require_once DRUPAL_ROOT . '/core/includes/install.core.inc'; install_drupal($class_loader, $parameters); // Import new settings.php written by the installer. Settings::initialize(DRUPAL_ROOT, $this->siteDirectory, $class_loader); foreach ($GLOBALS['config_directories'] as $type => $path) { $this->configDirectories[$type] = $path; } // After writing settings.php, the installer removes write permissions // from the site directory. To allow drupal_generate_test_ua() to write // a file containing the private key for drupal_valid_test_ua(), the site // directory has to be writable. // TestBase::restoreEnvironment() will delete the entire site directory. // Not using File API; a potential error must trigger a PHP warning. chmod($directory, 0777); $request = \Drupal::request(); $this->kernel = DrupalKernel::createFromRequest($request, $class_loader, 'prod', TRUE); $this->kernel->prepareLegacyRequest($request); // Force the container to be built from scratch instead of loaded from the // disk. This forces us to not accidentally load the parent site. $container = $this->kernel->rebuildContainer(); $config = $container->get('config.factory'); // Manually create and configure private and temporary files directories. // While these could be preset/enforced in settings.php like the public // files directory above, some tests expect them to be configurable in the // UI. If declared in settings.php, they would no longer be configurable. file_prepare_directory($this->privateFilesDirectory, FILE_CREATE_DIRECTORY); file_prepare_directory($this->tempFilesDirectory, FILE_CREATE_DIRECTORY); $config->getEditable('system.file')->set('path.temporary', $this->tempFilesDirectory)->save(); // Manually configure the test mail collector implementation to prevent // tests from sending out emails and collect them in state instead. // While this should be enforced via settings.php prior to installation, // some tests expect to be able to test mail system implementations. $config->getEditable('system.mail')->set('interface.default', 'test_mail_collector')->save(); // By default, verbosely display all errors and disable all production // environment optimizations for all tests to avoid needless overhead and // ensure a sane default experience for test authors. // @see https://www.drupal.org/node/2259167 $config->getEditable('system.logging')->set('error_level', 'verbose')->save(); $config->getEditable('system.performance')->set('css.preprocess', FALSE)->set('js.preprocess', FALSE)->save(); // Collect modules to install. $class = get_class($this); $modules = array(); while ($class) { if (property_exists($class, 'modules')) { $modules = array_merge($modules, $class::$modules); } $class = get_parent_class($class); } if ($modules) { $modules = array_unique($modules); try { $success = $container->get('module_installer')->install($modules, TRUE); $this->assertTrue($success, SafeMarkup::format('Enabled modules: %modules', array('%modules' => implode(', ', $modules)))); } catch (\Drupal\Core\Extension\MissingDependencyException $e) { // The exception message has all the details. $this->fail($e->getMessage()); } $this->rebuildContainer(); } // Restore the original Simpletest batch. $batch =& batch_get(); $batch = $this->originalBatch; // Reset/rebuild all data structures after enabling the modules, primarily // to synchronize all data structures and caches between the test runner and // the child site. // @see \Drupal\Core\DrupalKernel::bootCode() // @todo Test-specific setUp() methods may set up further fixtures; find a // way to execute this after setUp() is done, or to eliminate it entirely. $this->resetAll(); $this->kernel->prepareLegacyRequest($request); // Explicitly call register() again on the container registered in \Drupal. // @todo This should already be called through // DrupalKernel::prepareLegacyRequest() -> DrupalKernel::boot() but that // appears to be calling a different container. $this->container->get('stream_wrapper_manager')->register(); }
/** * Wraps batch_get(). */ protected function &batchGet() { return batch_get(); }
/** * Run an individual installation task. * * @param $task * An array of information about the task to be run. * @param $install_state * An array of information about the current installation state. This is * passed in by reference so that it can be modified by the task. * @return * The output of the task function, if there is any. */ function install_run_task($task, &$install_state) { $function = $task['function']; if ($task['type'] == 'form') { require_once DRUPAL_ROOT . '/includes/form.inc'; if ($install_state['interactive']) { // For interactive forms, build the form and ensure that it will not // redirect, since the installer handles its own redirection only after // marking the form submission task complete. $form_state = array('args' => array(&$install_state), 'no_redirect' => TRUE); $form = drupal_build_form($function, $form_state); // If a successful form submission did not occur, the form needs to be // rendered, which means the task is not complete yet. if (empty($form_state['executed'])) { $install_state['task_not_complete'] = TRUE; return drupal_render($form); } // Otherwise, return nothing so the next task will run in the same // request. return; } else { // For non-interactive forms, submit the form programmatically with the // values taken from the installation state. Throw an exception if any // errors were encountered. $form_state = array('values' => !empty($install_state['forms'][$function]) ? $install_state['forms'][$function] : array()); drupal_form_submit($function, $form_state, $install_state); $errors = form_get_errors(); if (!empty($errors)) { throw new Exception(implode("\n", $errors)); } } } elseif ($task['type'] == 'batch') { // Start a new batch based on the task function, if one is not running // already. $current_batch = variable_get('install_current_batch'); if (!$install_state['interactive'] || !$current_batch) { $batch = $function($install_state); if (empty($batch)) { // If the task did some processing and decided no batch was necessary, // there is nothing more to do here. return; } batch_set($batch); // For interactive batches, we need to store the fact that this batch // task is currently running. Otherwise, we need to make sure the batch // will complete in one page request. if ($install_state['interactive']) { variable_set('install_current_batch', $function); } else { $batch =& batch_get(); $batch['progressive'] = FALSE; } // Process the batch. For progressive batches, this will redirect. // Otherwise, the batch will complete. batch_process(install_redirect_url($install_state), install_full_redirect_url($install_state)); } elseif ($current_batch == $function) { include_once DRUPAL_ROOT . '/includes/batch.inc'; $output = _batch_page(); // The task is complete when we try to access the batch page and receive // FALSE in return, since this means we are at a URL where we are no // longer requesting a batch ID. if ($output === FALSE) { // Return nothing so the next task will run in the same request. variable_del('install_current_batch'); return; } else { // We need to force the page request to end if the task is not // complete, since the batch API sometimes prints JSON output // rather than returning a themed page. $install_state['task_not_complete'] = $install_state['stop_page_request'] = TRUE; return $output; } } } else { // For normal tasks, just return the function result, whatever it is. return $function($install_state); } }
/** * Redirect to a provided url at the end of the request. * * @param string $url * Redirect destination url. */ protected function doExecute($url) { $current_path = $this->currentPathStack->getPath(); $is_rules_admin_page = strpos($current_path, 'admin/config/workflow/rules') !== FALSE; // Make sure we do not redirect away from the rules admin pages. if ($is_rules_admin_page) { $this->logger->warning('Skipped page redirect on a rules admin page.'); return; } // Make sure we do not redirect during batch processing. $batch = batch_get(); if (isset($batch['current_set'])) { $this->logger->warning('Skipped page redirect during batch processing.'); return; } $this->request->attributes->set('_rules_redirect_action_url', $url); }
* Not documenting all parameters is allowed. * * @param Node $node * The loaded node entity that we will use to do whatever. */ function mymodule_form_callback($form, &$form_state, Node $node) { } $x = 'Some markup text<br />'; // Inline if statements with ?: are allowed. $x = $y == $z ? 23 : 42; // Standard watchdog message. watchdog('mymodule', 'Log message here.'); // For assigning by reference it is allowed that there is no space after the // "=" oeprator. $batch =& batch_get(); // Security issue: http://drupal.org/node/750148 preg_match('/.+/i', 'subject'); preg_match('/.+/imsuxADSUXJ', 'subject'); preg_filter('/.+/i', 'replacement', 'subject'); preg_replace('/.+/i', 'replacement', 'subject'); // Use a not so common delimiter. preg_match('@.+@i', 'subject'); preg_match('@.+@imsuxADSUXJ', 'subject'); preg_filter('@.+@i', 'replacement', 'subject'); preg_replace('@.+@i', 'replacement', 'subject'); preg_match("/test(\\d+)/is", 'subject'); interface MyWellNamedInterface { } // Correctly formed try/catch block.
/** * Restore the original batch. * * @see ::setBatch */ protected function restoreBatch() { // Restore the original Simpletest batch. $batch =& batch_get(); $batch = $this->originalBatch; }
/** * {@inheritdoc} */ public function processBatch() { $this->validateDrupalSite(); $batch =& batch_get(); $batch['progressive'] = FALSE; batch_process(); }
/** * Mock the batch_set() function. */ function batch_set($batch_definition) { if ($batch_definition) { $batch =& batch_get(); // Nothing more then current_set should be mocked for testing purposes. $batch['current_set'] = $batch_definition; } }