예제 #1
0
 /**
  * Loops through and displays all form errors.
  *
  * @param array $form
  *   An associative array containing the structure of the form.
  * @param \Drupal\Core\Form\FormStateInterface $form_state
  *   The current state of the form.
  */
 protected function displayErrorMessages(array $form, FormStateInterface $form_state)
 {
     $error_links = [];
     $errors = $form_state->getErrors();
     // Loop through all form errors and check if we need to display a link.
     foreach ($errors as $name => $error) {
         $form_element = FormElementHelper::getElementByName($name, $form);
         $title = FormElementHelper::getElementTitle($form_element);
         // Only show links to erroneous elements that are visible.
         $is_visible_element = Element::isVisibleElement($form_element);
         // Only show links for elements that have a title themselves or have
         // children with a title.
         $has_title = !empty($title);
         // Only show links for elements with an ID.
         $has_id = !empty($form_element['#id']);
         // Do not show links to elements with suppressed messages. Most often
         // their parent element is used for inline errors.
         if (!empty($form_element['#error_no_message'])) {
             unset($errors[$name]);
         } elseif ($is_visible_element && $has_title && $has_id) {
             $error_links[] = $this->l($title, Url::fromRoute('<none>', [], ['fragment' => $form_element['#id'], 'external' => TRUE]));
             unset($errors[$name]);
         }
     }
     // Set normal error messages for all remaining errors.
     foreach ($errors as $error) {
         $this->drupalSetMessage($error, 'error');
     }
     if (!empty($error_links)) {
         $render_array = [['#markup' => $this->formatPlural(count($error_links), '1 error has been found: ', '@count errors have been found: ')], ['#theme' => 'item_list', '#items' => $error_links, '#context' => ['list_style' => 'comma-list']]];
         $message = $this->renderer->renderPlain($render_array);
         $this->drupalSetMessage($message, 'error');
     }
 }
예제 #2
0
 /**
  * {@inheritdoc}
  */
 public function execute($entity = NULL)
 {
     if (empty($this->configuration['node'])) {
         $this->configuration['node'] = $entity;
     }
     $message = $this->token->replace($this->configuration['message'], $this->configuration);
     $build = ['#markup' => $message];
     // @todo Fix in https://www.drupal.org/node/2577827
     drupal_set_message($this->renderer->renderPlain($build));
 }
예제 #3
0
 /**
  * {@inheritdoc}
  */
 public function execute($comment = NULL)
 {
     $build = $this->viewBuilder->view($comment);
     $text = $this->renderer->renderPlain($build);
     foreach ($this->configuration['keywords'] as $keyword) {
         if (strpos($text, $keyword) !== FALSE) {
             $comment->setPublished(FALSE);
             $comment->save();
             break;
         }
     }
 }
  /**
   * Generates a response object after handing the un/flag request.
   *
   * Depending on the wrapper format of the request, it will either redirect
   * or return an ajax response.
   *
   * @param \Drupal\flag\FlagInterface $flag
   *   The flag entity.
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   The entity object.
   * @param \Symfony\Component\HttpFoundation\Request $request
   *   The request.
   *
   * @return \Drupal\Core\Ajax\AjaxResponse|\Symfony\Component\HttpFoundation\RedirectResponse
   *   The response object.
   */
  protected function generateResponse(FlagInterface $flag, EntityInterface $entity, Request $request) {
    if ($request->get(MainContentViewSubscriber::WRAPPER_FORMAT) == 'drupal_ajax') {
      // Create a new AJAX response.
      $response = new AjaxResponse();

      // Get the link type plugin.
      $link_type = $flag->getLinkTypePlugin();

      // Generate the link render array and get the link CSS ID.
      $link = $link_type->getLink($flag, $entity);
      $link_id = '#' . $link['link']['#attributes']['id'];

      // Create a new JQuery Replace command to update the link display.
      $replace = new ReplaceCommand($link_id, $this->renderer->renderPlain($link));
      $response->addCommand($replace);

      return $response;
    }
    else {
      // Redirect back to the entity. A passed in destination query parameter
      // will automatically override this.
      $url_info = $entity->toUrl();
      return $this->redirect($url_info->getRouteName(), $url_info->getRouteParameters());
    }

  }
예제 #5
0
 /**
  * Generates themed output early in a page request.
  *
  * @see \Drupal\system\Tests\Theme\ThemeEarlyInitializationTest::testRequestListener()
  */
 public function onRequest(GetResponseEvent $event)
 {
     if ($this->currentRouteMatch->getRouteName() === 'theme_test.request_listener') {
         // First, force the theme registry to be rebuilt on this page request.
         // This allows us to test a full initialization of the theme system in
         // the code below.
         drupal_theme_rebuild();
         // Next, initialize the theme system by storing themed text in a global
         // variable. We will use this later in
         // theme_test_request_listener_page_callback() to test that even when the
         // theme system is initialized this early, it is still capable of
         // returning output and theming the page as a whole.
         $more_link = array('#type' => 'more_link', '#url' => Url::fromRoute('user.page'), '#attributes' => array('title' => 'Themed output generated in a KernelEvents::REQUEST listener'));
         $GLOBALS['theme_test_output'] = $this->renderer->renderPlain($more_link);
     }
 }
예제 #6
0
 /**
  * Generates an overview table of older revisions of a node.
  *
  * @param \Drupal\node\NodeInterface $node
  *   A node object.
  *
  * @return array
  *   An array as expected by drupal_render().
  */
 public function revisionOverview(NodeInterface $node)
 {
     $account = $this->currentUser();
     $langcode = $node->language()->getId();
     $langname = $node->language()->getName();
     $languages = $node->getTranslationLanguages();
     $has_translations = count($languages) > 1;
     $node_storage = $this->entityManager()->getStorage('node');
     $type = $node->getType();
     $build['#title'] = $has_translations ? $this->t('@langname revisions for %title', ['@langname' => $langname, '%title' => $node->label()]) : $this->t('Revisions for %title', ['%title' => $node->label()]);
     $header = array($this->t('Revision'), $this->t('Operations'));
     $revert_permission = ($account->hasPermission("revert {$type} revisions") || $account->hasPermission('revert all revisions') || $account->hasPermission('administer nodes')) && $node->access('update');
     $delete_permission = ($account->hasPermission("delete {$type} revisions") || $account->hasPermission('delete all revisions') || $account->hasPermission('administer nodes')) && $node->access('delete');
     $rows = array();
     $vids = $node_storage->revisionIds($node);
     $latest_revision = TRUE;
     foreach (array_reverse($vids) as $vid) {
         /** @var \Drupal\node\NodeInterface $revision */
         $revision = $node_storage->loadRevision($vid);
         // Only show revisions that are affected by the language that is being
         // displayed.
         if ($revision->hasTranslation($langcode) && $revision->getTranslation($langcode)->isRevisionTranslationAffected()) {
             $username = ['#theme' => 'username', '#account' => $revision->getRevisionAuthor()];
             // Use revision link to link to revisions that are not active.
             $date = $this->dateFormatter->format($revision->revision_timestamp->value, 'short');
             if ($vid != $node->getRevisionId()) {
                 $link = $this->l($date, new Url('entity.node.revision', ['node' => $node->id(), 'node_revision' => $vid]));
             } else {
                 $link = $node->link($date);
             }
             $row = [];
             $column = ['data' => ['#type' => 'inline_template', '#template' => '{% trans %}{{ date }} by {{ username }}{% endtrans %}{% if message %}<p class="revision-log">{{ message }}</p>{% endif %}', '#context' => ['date' => $link, 'username' => $this->renderer->renderPlain($username), 'message' => ['#markup' => $revision->revision_log->value, '#allowed_tags' => Xss::getHtmlTagList()]]]];
             // @todo Simplify once https://www.drupal.org/node/2334319 lands.
             $this->renderer->addCacheableDependency($column['data'], $username);
             $row[] = $column;
             if ($latest_revision) {
                 $row[] = ['data' => ['#prefix' => '<em>', '#markup' => $this->t('Current revision'), '#suffix' => '</em>']];
                 foreach ($row as &$current) {
                     $current['class'] = ['revision-current'];
                 }
                 $latest_revision = FALSE;
             } else {
                 $links = [];
                 if ($revert_permission) {
                     $links['revert'] = ['title' => $this->t('Revert'), 'url' => $has_translations ? Url::fromRoute('node.revision_revert_translation_confirm', ['node' => $node->id(), 'node_revision' => $vid, 'langcode' => $langcode]) : Url::fromRoute('node.revision_revert_confirm', ['node' => $node->id(), 'node_revision' => $vid])];
                 }
                 if ($delete_permission) {
                     $links['delete'] = ['title' => $this->t('Delete'), 'url' => Url::fromRoute('node.revision_delete_confirm', ['node' => $node->id(), 'node_revision' => $vid])];
                 }
                 $row[] = ['data' => ['#type' => 'operations', '#links' => $links]];
             }
             $rows[] = $row;
         }
     }
     $build['node_revisions_table'] = array('#theme' => 'table', '#rows' => $rows, '#header' => $header, '#attached' => array('library' => array('node/drupal.node.admin')));
     return $build;
 }
 /**
  * Renders HTML response attachment placeholders.
  *
  * This is the last step where all of the attachments are placed into the
  * response object's contents.
  *
  * @param \Drupal\Core\Render\HtmlResponse $response
  *   The HTML response to update.
  * @param array $placeholders
  *   An array of placeholders, keyed by type with the placeholders
  *   present in the content of the response as values.
  * @param array $variables
  *   The variables to render and replace, keyed by type with renderable
  *   arrays as values.
  */
 protected function renderHtmlResponseAttachmentPlaceholders(HtmlResponse $response, array $placeholders, array $variables)
 {
     $content = $response->getContent();
     foreach ($placeholders as $type => $placeholder) {
         if (isset($variables[$type])) {
             $content = str_replace($placeholder, $this->renderer->renderPlain($variables[$type]), $content);
         }
     }
     $response->setContent($content);
 }
 /**
  * Prepares the AJAX commands to attach assets.
  *
  * @param \Drupal\Core\Ajax\AjaxResponse $response
  *   The AJAX response to update.
  * @param \Symfony\Component\HttpFoundation\Request $request
  *   The request object that the AJAX is responding to.
  *
  * @return array
  *   An array of commands ready to be returned as JSON.
  */
 protected function buildAttachmentsCommands(AjaxResponse $response, Request $request)
 {
     $ajax_page_state = $request->request->get('ajax_page_state');
     // Aggregate CSS/JS if necessary, but only during normal site operation.
     $optimize_css = !defined('MAINTENANCE_MODE') && $this->config->get('css.preprocess');
     $optimize_js = !defined('MAINTENANCE_MODE') && $this->config->get('js.preprocess');
     $attachments = $response->getAttachments();
     // Resolve the attached libraries into asset collections.
     $assets = new AttachedAssets();
     $assets->setLibraries(isset($attachments['library']) ? $attachments['library'] : [])->setAlreadyLoadedLibraries(isset($ajax_page_state['libraries']) ? explode(',', $ajax_page_state['libraries']) : [])->setSettings(isset($attachments['drupalSettings']) ? $attachments['drupalSettings'] : []);
     $css_assets = $this->assetResolver->getCssAssets($assets, $optimize_css);
     list($js_assets_header, $js_assets_footer) = $this->assetResolver->getJsAssets($assets, $optimize_js);
     // Render the HTML to load these files, and add AJAX commands to insert this
     // HTML in the page. Settings are handled separately, afterwards.
     $settings = [];
     if (isset($js_assets_header['drupalSettings'])) {
         $settings = $js_assets_header['drupalSettings']['data'];
         unset($js_assets_header['drupalSettings']);
     }
     if (isset($js_assets_footer['drupalSettings'])) {
         $settings = $js_assets_footer['drupalSettings']['data'];
         unset($js_assets_footer['drupalSettings']);
     }
     // Prepend commands to add the assets, preserving their relative order.
     $resource_commands = array();
     if ($css_assets) {
         $css_render_array = $this->cssCollectionRenderer->render($css_assets);
         $resource_commands[] = new AddCssCommand((string) $this->renderer->renderPlain($css_render_array));
     }
     if ($js_assets_header) {
         $js_header_render_array = $this->jsCollectionRenderer->render($js_assets_header);
         $resource_commands[] = new PrependCommand('head', (string) $this->renderer->renderPlain($js_header_render_array));
     }
     if ($js_assets_footer) {
         $js_footer_render_array = $this->jsCollectionRenderer->render($js_assets_footer);
         $resource_commands[] = new AppendCommand('body', (string) $this->renderer->renderPlain($js_footer_render_array));
     }
     foreach (array_reverse($resource_commands) as $resource_command) {
         $response->addCommand($resource_command, TRUE);
     }
     // Prepend a command to merge changes and additions to drupalSettings.
     if (!empty($settings)) {
         // During Ajax requests basic path-specific settings are excluded from
         // new drupalSettings values. The original page where this request comes
         // from already has the right values. An Ajax request would update them
         // with values for the Ajax request and incorrectly override the page's
         // values.
         // @see system_js_settings_alter()
         unset($settings['path']);
         $response->addCommand(new SettingsCommand($settings, TRUE), TRUE);
     }
     $commands = $response->getCommands();
     $this->moduleHandler->alter('ajax_render', $commands);
     return $commands;
 }
예제 #9
0
 /**
  * {@inheritdoc}
  */
 public function buildForm(array $form, FormStateInterface $form_state)
 {
     $form['actions'] = array('#type' => 'actions');
     $form['actions']['submit'] = array('#type' => 'submit', '#value' => $this->t('Run tests'), '#tableselect' => TRUE, '#button_type' => 'primary');
     $form['clean'] = array('#type' => 'fieldset', '#title' => $this->t('Clean test environment'), '#description' => $this->t('Remove tables with the prefix "simpletest" and temporary directories that are left over from tests that crashed. This is intended for developers when creating tests.'), '#weight' => 200);
     $form['clean']['op'] = array('#type' => 'submit', '#value' => $this->t('Clean environment'), '#submit' => array('simpletest_clean_environment'));
     // Do not needlessly re-execute a full test discovery if the user input
     // already contains an explicit list of test classes to run.
     $user_input = $form_state->getUserInput();
     if (!empty($user_input['tests'])) {
         return $form;
     }
     // JavaScript-only table filters.
     $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 test name…'), '#attributes' => array('class' => array('table-filter-text'), 'data-table' => '#simpletest-test-form', 'autocomplete' => 'off', 'title' => $this->t('Enter at least 3 characters of the test name or description to filter by.')));
     $form['tests'] = array('#type' => 'table', '#id' => 'simpletest-form-table', '#tableselect' => TRUE, '#header' => array(array('data' => $this->t('Test'), 'class' => array('simpletest-test-label')), array('data' => $this->t('Description'), 'class' => array('simpletest-test-description'))), '#empty' => $this->t('No tests to display.'), '#attached' => array('library' => array('simpletest/drupal.simpletest')));
     // Define the images used to expand/collapse the test groups.
     $image_collapsed = array('#theme' => 'image', '#uri' => 'core/misc/menu-collapsed.png', '#width' => '7', '#height' => '7', '#alt' => $this->t('Expand'), '#title' => $this->t('Expand'), '#suffix' => '<a href="#" class="simpletest-collapse">(' . $this->t('Expand') . ')</a>');
     $image_extended = array('#theme' => 'image', '#uri' => 'core/misc/menu-expanded.png', '#width' => '7', '#height' => '7', '#alt' => $this->t('Collapse'), '#title' => $this->t('Collapse'), '#suffix' => '<a href="#" class="simpletest-collapse">(' . $this->t('Collapse') . ')</a>');
     $form['tests']['#attached']['drupalSettings']['simpleTest']['images'] = [(string) $this->renderer->renderPlain($image_collapsed), (string) $this->renderer->renderPlain($image_extended)];
     // Generate the list of tests arranged by group.
     $groups = simpletest_test_get_all();
     foreach ($groups as $group => $tests) {
         $form['tests'][$group] = array('#attributes' => array('class' => array('simpletest-group')));
         // Make the class name safe for output on the page by replacing all
         // non-word/decimal characters with a dash (-).
         $group_class = 'module-' . strtolower(trim(preg_replace("/[^\\w\\d]/", "-", $group)));
         // Override tableselect column with custom selector for this group.
         // This group-select-all checkbox is injected via JavaScript.
         $form['tests'][$group]['select'] = array('#wrapper_attributes' => array('id' => $group_class, 'class' => array('simpletest-group-select-all')));
         $form['tests'][$group]['title'] = array('#prefix' => '<div class="simpletest-image" id="simpletest-test-group-' . $group_class . '"></div>', '#markup' => '<label for="' . $group_class . '-group-select-all">' . $group . '</label>', '#wrapper_attributes' => array('class' => array('simpletest-group-label')));
         $form['tests'][$group]['description'] = array('#markup' => '&nbsp;', '#wrapper_attributes' => array('class' => array('simpletest-group-description')));
         // Cycle through each test within the current group.
         foreach ($tests as $class => $info) {
             $form['tests'][$class] = array('#attributes' => array('class' => array($group_class . '-test', 'js-hide')));
             $form['tests'][$class]['title'] = array('#type' => 'label', '#title' => '\\' . $info['name'], '#wrapper_attributes' => array('class' => array('simpletest-test-label', 'table-filter-text-source')));
             $form['tests'][$class]['description'] = array('#prefix' => '<div class="description">', '#plain_text' => $info['description'], '#suffix' => '</div>', '#wrapper_attributes' => array('class' => array('simpletest-test-description', 'table-filter-text-source')));
         }
     }
     return $form;
 }
 /**
  * Tests JavaScript files that have querystrings attached get added right.
  */
 function testAddJsFileWithQueryString()
 {
     $build['#attached']['library'][] = 'common_test/querystring';
     $assets = AttachedAssets::createFromRenderArray($build);
     $css = $this->assetResolver->getCssAssets($assets, FALSE);
     $js = $this->assetResolver->getJsAssets($assets, FALSE)[1];
     $this->assertTrue(array_key_exists('core/modules/system/tests/modules/common_test/querystring.css?arg1=value1&arg2=value2', $css), 'CSS file with query string is correctly added.');
     $this->assertTrue(array_key_exists('core/modules/system/tests/modules/common_test/querystring.js?arg1=value1&arg2=value2', $js), 'JavaScript file with query string is correctly added.');
     $css_render_array = \Drupal::service('asset.css.collection_renderer')->render($css);
     $rendered_css = $this->renderer->renderPlain($css_render_array);
     $js_render_array = \Drupal::service('asset.js.collection_renderer')->render($js);
     $rendered_js = $this->renderer->renderPlain($js_render_array);
     $query_string = $this->container->get('state')->get('system.css_js_query_string') ?: '0';
     $this->assertNotIdentical(strpos($rendered_css, '<link rel="stylesheet" href="' . str_replace('&', '&amp;', file_url_transform_relative(file_create_url('core/modules/system/tests/modules/common_test/querystring.css?arg1=value1&arg2=value2'))) . '&amp;' . $query_string . '" media="all" />'), FALSE, 'CSS file with query string gets version query string correctly appended..');
     $this->assertNotIdentical(strpos($rendered_js, '<script src="' . str_replace('&', '&amp;', file_url_transform_relative(file_create_url('core/modules/system/tests/modules/common_test/querystring.js?arg1=value1&arg2=value2'))) . '&amp;' . $query_string . '"></script>'), FALSE, 'JavaScript file with query string gets version query string correctly appended.');
 }
예제 #11
0
 /**
  * Validation handler for the credentials form.
  *
  * @param array $form
  *   An associative array containing the structure of the form.
  * @param \Drupal\Core\Form\FormStateInterface $form_state
  *   The current state of the form.
  */
 public function validateCredentialForm(array &$form, FormStateInterface $form_state)
 {
     // Retrieve the database driver from the form, use reflection to get the
     // namespace, and then construct a valid database array the same as in
     // settings.php.
     $driver = $form_state->getValue('driver');
     $drivers = $this->getDatabaseTypes();
     $reflection = new \ReflectionClass($drivers[$driver]);
     $install_namespace = $reflection->getNamespaceName();
     $database = $form_state->getValue($driver);
     // Cut the trailing \Install from namespace.
     $database['namespace'] = substr($install_namespace, 0, strrpos($install_namespace, '\\'));
     $database['driver'] = $driver;
     // Validate the driver settings and just end here if we have any issues.
     if ($errors = $drivers[$driver]->validateDatabaseSettings($database)) {
         foreach ($errors as $name => $message) {
             $form_state->setErrorByName($name, $message);
         }
         return;
     }
     try {
         $connection = $this->getConnection($database);
         $version = $this->getLegacyDrupalVersion($connection);
         if (!$version) {
             $form_state->setErrorByName($database['driver'] . '][0', $this->t('Source database does not contain a recognizable Drupal version.'));
         } else {
             $this->createDatabaseStateSettings($database, $version);
             $migrations = $this->getMigrations('migrate_drupal_' . $version, $version);
             // Get the system data from source database.
             $system_data = $this->getSystemData($connection);
             // Convert the migration object into array
             // so that it can be stored in form storage.
             $migration_array = [];
             foreach ($migrations as $migration) {
                 $migration_array[$migration->id()] = $migration->label();
             }
             // Store the retrieved migration IDs in form storage.
             $form_state->set('migrations', $migration_array);
             $form_state->set('source_base_path', $form_state->getValue('source_base_path'));
             // Store the retrived system data in form storage.
             $form_state->set('system_data', $system_data);
         }
     } catch (\Exception $e) {
         $error_message = ['#type' => 'inline_template', '#template' => '{% trans %}Resolve the issue below to continue the upgrade.{% endtrans%}{{ errors }}', '#context' => ['errors' => ['#theme' => 'item_list', '#items' => [$e->getMessage()]]]];
         $form_state->setErrorByName($database['driver'] . '][0', $this->renderer->renderPlain($error_message));
     }
 }
 /**
  * Generates an overview table of older revisions of a node.
  *
  * @param \Drupal\node\NodeInterface $node
  *   A node object.
  *
  * @return array
  *   An array as expected by drupal_render().
  */
 public function revisionOverview(NodeInterface $node)
 {
     $account = $this->currentUser();
     $node_storage = $this->entityManager()->getStorage('node');
     $type = $node->getType();
     $build = array();
     $build['#title'] = $this->t('Revisions for %title', array('%title' => $node->label()));
     $header = array($this->t('Revision'), $this->t('Operations'));
     $revert_permission = ($account->hasPermission("revert {$type} revisions") || $account->hasPermission('revert all revisions') || $account->hasPermission('administer nodes')) && $node->access('update');
     $delete_permission = ($account->hasPermission("delete {$type} revisions") || $account->hasPermission('delete all revisions') || $account->hasPermission('administer nodes')) && $node->access('delete');
     $rows = array();
     $vids = $node_storage->revisionIds($node);
     foreach (array_reverse($vids) as $vid) {
         $revision = $node_storage->loadRevision($vid);
         $username = ['#theme' => 'username', '#account' => $revision->uid->entity];
         // Use revision link to link to revisions that are not active.
         $date = $this->dateFormatter->format($revision->revision_timestamp->value, 'short');
         if ($vid != $node->getRevisionId()) {
             $link = $this->l($date, new Url('entity.node.revision', ['node' => $node->id(), 'node_revision' => $vid]));
         } else {
             $link = $node->link($date);
         }
         $row = [];
         $column = ['data' => ['#type' => 'inline_template', '#template' => '{% trans %}{{ date }} by {{ username }}{% endtrans %}{% if message %}<p class="revision-log">{{ message }}</p>{% endif %}', '#context' => ['date' => $link, 'username' => $this->renderer->renderPlain($username), 'message' => Xss::filter($revision->revision_log->value)]]];
         // @todo Simplify once https://www.drupal.org/node/2334319 lands.
         $this->renderer->addCacheableDependency($column['data'], $username);
         $row[] = $column;
         if ($vid == $node->getRevisionId()) {
             $row[0]['class'] = ['revision-current'];
             $row[] = ['data' => SafeMarkup::placeholder($this->t('current revision')), 'class' => ['revision-current']];
         } else {
             $links = [];
             if ($revert_permission) {
                 $links['revert'] = ['title' => $this->t('Revert'), 'url' => Url::fromRoute('node.revision_revert_confirm', ['node' => $node->id(), 'node_revision' => $vid])];
             }
             if ($delete_permission) {
                 $links['delete'] = ['title' => $this->t('Delete'), 'url' => Url::fromRoute('node.revision_delete_confirm', ['node' => $node->id(), 'node_revision' => $vid])];
             }
             $row[] = ['data' => ['#type' => 'operations', '#links' => $links]];
         }
         $rows[] = $row;
     }
     $build['node_revisions_table'] = array('#theme' => 'table', '#rows' => $rows, '#header' => $header, '#attached' => array('library' => array('node/drupal.node.admin')));
     return $build;
 }
예제 #13
0
 /**
  * Get any database errors and links them to a form element.
  *
  * @param array $database
  *   An array of database settings.
  * @param string $settings_file
  *   The settings file that contains the database settings.
  *
  * @return array
  *   An array of form errors keyed by the element name and parents.
  */
 protected function getDatabaseErrors(array $database, $settings_file)
 {
     $errors = install_database_errors($database, $settings_file);
     $form_errors = array_filter($errors, function ($value) {
         // Errors keyed by something other than an integer already are linked to
         // form elements.
         return is_int($value);
     });
     // Find the generic errors.
     $errors = array_diff_key($errors, $form_errors);
     if (count($errors)) {
         $error_message = ['#type' => 'inline_template', '#template' => '{% trans %}Resolve all issues below to continue the installation. For help configuring your database server, see the <a href="https://www.drupal.org/getting-started/install">installation handbook</a>, or contact your hosting provider.{% endtrans%}{{ errors }}', '#context' => ['errors' => ['#theme' => 'item_list', '#items' => $errors]]];
         // These are generic errors, so we do not have any specific key of the
         // database connection array to attach them to; therefore, we just put
         // them in the error array with standard numeric keys.
         $form_errors[$database['driver'] . '][0'] = $this->renderer->renderPlain($error_message);
     }
     return $form_errors;
 }
예제 #14
0
 /**
  * Indexes a single node.
  *
  * @param \Drupal\node\NodeInterface $node
  *   The node to index.
  */
 protected function indexNode(NodeInterface $node)
 {
     $languages = $node->getTranslationLanguages();
     $node_render = $this->entityManager->getViewBuilder('node');
     foreach ($languages as $language) {
         $node = $node->getTranslation($language->getId());
         // Render the node.
         $build = $node_render->view($node, 'search_index', $language->getId());
         unset($build['#theme']);
         $rendered = $this->renderer->renderPlain($build);
         $text = '<h1>' . SafeMarkup::checkPlain($node->label($language->getId())) . '</h1>' . $rendered;
         // Fetch extra data normally not visible.
         $extra = $this->moduleHandler->invokeAll('node_update_index', array($node, $language->getId()));
         foreach ($extra as $t) {
             $text .= $t;
         }
         // Update index, using search index "type" equal to the plugin ID.
         search_index($this->getPluginId(), $node->id(), $language->getId(), $text);
     }
 }
예제 #15
0
 /**
  * {@inheritdoc}
  */
 public function settingsForm(array $form, FormStateInterface $form_state, EditorEntity $editor)
 {
     $settings = $editor->getSettings();
     $ckeditor_settings_toolbar = array('#theme' => 'ckeditor_settings_toolbar', '#editor' => $editor, '#plugins' => $this->ckeditorPluginManager->getButtons());
     $form['toolbar'] = array('#type' => 'container', '#attached' => array('library' => array('ckeditor/drupal.ckeditor.admin'), 'drupalSettings' => ['ckeditor' => ['toolbarAdmin' => (string) $this->renderer->renderPlain($ckeditor_settings_toolbar)]]), '#attributes' => array('class' => array('ckeditor-toolbar-configuration')));
     $form['toolbar']['button_groups'] = array('#type' => 'textarea', '#title' => t('Toolbar buttons'), '#default_value' => json_encode($settings['toolbar']['rows']), '#attributes' => array('class' => array('ckeditor-toolbar-textarea')));
     // CKEditor plugin settings, if any.
     $form['plugin_settings'] = array('#type' => 'vertical_tabs', '#title' => t('CKEditor plugin settings'), '#attributes' => array('id' => 'ckeditor-plugin-settings'));
     $this->ckeditorPluginManager->injectPluginSettingsForm($form, $form_state, $editor);
     if (count(Element::children($form['plugins'])) === 0) {
         unset($form['plugins']);
         unset($form['plugin_settings']);
     }
     // Hidden CKEditor instance. We need a hidden CKEditor instance with all
     // plugins enabled, so we can retrieve CKEditor's per-feature metadata (on
     // which tags, attributes, styles and classes are enabled). This metadata is
     // necessary for certain filters' (e.g. the html_filter filter) settings to
     // be updated accordingly.
     // Get a list of all external plugins and their corresponding files.
     $plugins = array_keys($this->ckeditorPluginManager->getDefinitions());
     $all_external_plugins = array();
     foreach ($plugins as $plugin_id) {
         $plugin = $this->ckeditorPluginManager->createInstance($plugin_id);
         if (!$plugin->isInternal()) {
             $all_external_plugins[$plugin_id] = $plugin->getFile();
         }
     }
     // Get a list of all buttons that are provided by all plugins.
     $all_buttons = array_reduce($this->ckeditorPluginManager->getButtons(), function ($result, $item) {
         return array_merge($result, array_keys($item));
     }, array());
     // Build a fake Editor object, which we'll use to generate JavaScript
     // settings for this fake Editor instance.
     $fake_editor = entity_create('editor', array('format' => $editor->id(), 'editor' => 'ckeditor', 'settings' => array('toolbar' => array('rows' => array(0 => array(0 => array('name' => 'All existing buttons', 'items' => $all_buttons)))), 'plugins' => $settings['plugins'])));
     $config = $this->getJSSettings($fake_editor);
     // Remove the ACF configuration that is generated based on filter settings,
     // because otherwise we cannot retrieve per-feature metadata.
     unset($config['allowedContent']);
     $form['hidden_ckeditor'] = array('#markup' => '<div id="ckeditor-hidden" class="hidden"></div>', '#attached' => array('drupalSettings' => ['ckeditor' => ['hiddenCKEditorConfig' => $config]]));
     return $form;
 }
예제 #16
0
 /**
  * Indexes a single node.
  *
  * @param \Drupal\node\NodeInterface $node
  *   The node to index.
  */
 protected function indexNode(NodeInterface $node)
 {
     $languages = $node->getTranslationLanguages();
     $node_render = $this->entityManager->getViewBuilder('node');
     foreach ($languages as $language) {
         $node = $node->getTranslation($language->getId());
         // Render the node.
         $build = $node_render->view($node, 'search_index', $language->getId());
         unset($build['#theme']);
         // Add the title to text so it is searchable.
         $build['search_title'] = ['#prefix' => '<h1>', '#plain_text' => $node->label(), '#suffix' => '</h1>', '#weight' => -1000];
         $text = $this->renderer->renderPlain($build);
         // Fetch extra data normally not visible.
         $extra = $this->moduleHandler->invokeAll('node_update_index', [$node]);
         foreach ($extra as $t) {
             $text .= $t;
         }
         // Update index, using search index "type" equal to the plugin ID.
         search_index($this->getPluginId(), $node->id(), $language->getId(), $text);
     }
 }
예제 #17
0
 /**
  * {@inheritdoc}
  */
 public function saveFile($uri, $destination, $extensions, AccountProxyInterface $user, $validators = [])
 {
     // Create the file entity.
     $file = $this->fileEntityFromUri($uri, $user);
     // Replace tokens. As the tokens might contain HTML we convert it to plain
     // text.
     $destination = PlainTextOutput::renderFromHtml($this->token->replace($destination));
     // Handle potentialy dangerous extensions.
     $renamed = $this->renameExecutableExtensions($file);
     // The .txt extension may not be in the allowed list of extensions. We have
     // to add it here or else the file upload will fail.
     if ($renamed && !empty($extensions)) {
         $extensions .= ' txt';
         drupal_set_message(t('For security reasons, your upload has been renamed to %filename.', ['%filename' => $file->getFilename()]));
     }
     // Validate the file.
     $errors = $this->validateFile($file, $extensions, $validators);
     if (!empty($errors)) {
         $message = ['error' => ['#markup' => t('The specified file %name could not be uploaded.', ['%name' => $file->getFilename()])], 'item_list' => ['#theme' => 'item_list', '#items' => $errors]];
         drupal_set_message($this->renderer->renderPlain($message), 'error');
         return FALSE;
     }
     // Prepare destination.
     if (!$this->prepareDestination($file, $destination)) {
         drupal_set_message(t('The file could not be uploaded because the destination %destination is invalid.', ['%destination' => $destination]), 'error');
         return FALSE;
     }
     // Move uploaded files from PHP's upload_tmp_dir to destination.
     $move_result = file_unmanaged_move($uri, $file->getFileUri());
     if (!$move_result) {
         drupal_set_message(t('File upload error. Could not move uploaded file.'), 'error');
         $this->logger->notice('Upload error. Could not move uploaded file %file to destination %destination.', ['%file' => $file->getFilename(), '%destination' => $file->getFileUri()]);
         return FALSE;
     }
     // Set the permissions on the new file.
     $this->fileSystem->chmod($file->getFileUri());
     // If we made it this far it's safe to record this file in the database.
     $file->save();
     return $file;
 }
예제 #18
0
 /**
  * {@inheritdoc}
  */
 public function buildForm(array $form, FormStateInterface $form_state, $node = NULL)
 {
     $account = $this->currentUser;
     $langcode = $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_CONTENT)->getId();
     $langname = $this->languageManager->getLanguageName($langcode);
     $languages = $node->getTranslationLanguages();
     $has_translations = count($languages) > 1;
     $node_storage = $this->entityManager->getStorage('node');
     $type = $node->getType();
     $vids = array_reverse($node_storage->revisionIds($node));
     $revision_count = count($vids);
     $build['#title'] = $has_translations ? $this->t('@langname revisions for %title', ['@langname' => $langname, '%title' => $node->label()]) : $this->t('Revisions for %title', ['%title' => $node->label()]);
     $build['nid'] = array('#type' => 'hidden', '#value' => $node->id());
     $table_header = array('revision' => $this->t('Revision'), 'operations' => $this->t('Operations'));
     // Allow comparisons only if there are 2 or more revisions.
     if ($revision_count > 1) {
         $table_header += array('select_column_one' => '', 'select_column_two' => '');
     }
     $rev_revert_perm = $account->hasPermission("revert {$type} revisions") || $account->hasPermission('revert all revisions') || $account->hasPermission('administer nodes');
     $rev_delete_perm = $account->hasPermission("delete {$type} revisions") || $account->hasPermission('delete all revisions') || $account->hasPermission('administer nodes');
     $revert_permission = $rev_revert_perm && $node->access('update');
     $delete_permission = $rev_delete_perm && $node->access('delete');
     // Contains the table listing the revisions.
     $build['node_revisions_table'] = array('#type' => 'table', '#header' => $table_header, '#attributes' => array('class' => array('diff-revisions')));
     $build['node_revisions_table']['#attached']['library'][] = 'diff/diff.general';
     $build['node_revisions_table']['#attached']['drupalSettings']['diffRevisionRadios'] = $this->config->get('general_settings.radio_behavior');
     $latest_revision = TRUE;
     // Add rows to the table.
     foreach ($vids as $vid) {
         if ($revision = $node_storage->loadRevision($vid)) {
             if ($revision->hasTranslation($langcode) && $revision->getTranslation($langcode)->isRevisionTranslationAffected()) {
                 $username = array('#theme' => 'username', '#account' => $revision->getRevisionAuthor());
                 $revision_date = $this->date->format($revision->getRevisionCreationTime(), 'short');
                 // Use revision link to link to revisions that are not active.
                 if ($vid != $node->getRevisionId()) {
                     $link = $this->l($revision_date, new Url('entity.node.revision', ['node' => $node->id(), 'node_revision' => $vid]));
                 } else {
                     $link = $node->link($revision_date);
                 }
                 // Default revision.
                 if ($latest_revision) {
                     $row = array('revision' => array('#type' => 'inline_template', '#template' => '{% trans %}{{ date }} by {{ username }}{% endtrans %}{% if message %}<p class="revision-log">{{ message }}</p>{% endif %}', '#context' => ['date' => $link, 'username' => $this->renderer->renderPlain($username), 'message' => ['#markup' => $revision->revision_log->value, '#allowed_tags' => Xss::getHtmlTagList()]]));
                     // Allow comparisons only if there are 2 or more revisions.
                     if ($revision_count > 1) {
                         $row += array('select_column_one' => array('#type' => 'radio', '#title_display' => 'invisible', '#name' => 'radios_left', '#return_value' => $vid, '#default_value' => FALSE), 'select_column_two' => array('#type' => 'radio', '#title_display' => 'invisible', '#name' => 'radios_right', '#default_value' => $vid, '#return_value' => $vid));
                     }
                     $row['operations'] = array('#prefix' => '<em>', '#markup' => $this->t('Current revision'), '#suffix' => '</em>', '#attributes' => array('class' => array('revision-current')));
                     $latest_revision = FALSE;
                 } else {
                     $route_params = array('node' => $node->id(), 'node_revision' => $vid, 'langcode' => $langcode);
                     $links = array();
                     if ($revert_permission) {
                         $links['revert'] = ['title' => $this->t('Revert'), 'url' => $has_translations ? Url::fromRoute('node.revision_revert_translation_confirm', ['node' => $node->id(), 'node_revision' => $vid, 'langcode' => $langcode]) : Url::fromRoute('node.revision_revert_confirm', ['node' => $node->id(), 'node_revision' => $vid])];
                     }
                     if ($delete_permission) {
                         $links['delete'] = array('title' => $this->t('Delete'), 'url' => Url::fromRoute('node.revision_delete_confirm', $route_params));
                     }
                     // Here we don't have to deal with 'only one revision' case because
                     // if there's only one revision it will also be the default one,
                     // entering on the first branch of this if else statement.
                     $row = array('revision' => array('#type' => 'inline_template', '#template' => '{% trans %}{{ date }} by {{ username }}{% endtrans %}{% if message %}<p class="revision-log">{{ message }}</p>{% endif %}', '#context' => ['date' => $link, 'username' => $this->renderer->renderPlain($username), 'message' => ['#markup' => $revision->revision_log->value, '#allowed_tags' => Xss::getHtmlTagList()]]), 'select_column_one' => array('#type' => 'radio', '#title_display' => 'invisible', '#name' => 'radios_left', '#return_value' => $vid, '#default_value' => isset($vids[1]) ? $vids[1] : FALSE), 'select_column_two' => array('#type' => 'radio', '#title_display' => 'invisible', '#name' => 'radios_right', '#return_value' => $vid, '#default_value' => FALSE), 'operations' => array('#type' => 'operations', '#links' => $links));
                 }
                 // Add the row to the table.
                 $build['node_revisions_table'][] = $row;
             }
         }
     }
     // Allow comparisons only if there are 2 or more revisions.
     if ($revision_count > 1) {
         $build['submit'] = array('#type' => 'submit', '#value' => t('Compare'), '#attributes' => array('class' => array('diff-button')));
     }
     return $build;
 }
 /**
  * Language translations overview page for a configuration name.
  *
  * @param \Symfony\Component\HttpFoundation\Request $request
  *   Page request object.
  * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
  *   The route match.
  * @param string $plugin_id
  *   The plugin ID of the mapper.
  *
  * @return array
  *   Page render array.
  */
 public function itemPage(Request $request, RouteMatchInterface $route_match, $plugin_id)
 {
     /** @var \Drupal\config_translation\ConfigMapperInterface $mapper */
     $mapper = $this->configMapperManager->createInstance($plugin_id);
     $mapper->populateFromRouteMatch($route_match);
     $page = array();
     $page['#title'] = $this->t('Translations for %label', array('%label' => $mapper->getTitle()));
     $languages = $this->languageManager->getLanguages();
     if (count($languages) == 1) {
         drupal_set_message($this->t('In order to translate configuration, the website must have at least two <a href=":url">languages</a>.', array(':url' => $this->url('entity.configurable_language.collection'))), 'warning');
     }
     try {
         $original_langcode = $mapper->getLangcode();
         $operations_access = TRUE;
     } catch (ConfigMapperLanguageException $exception) {
         $items = [];
         foreach ($mapper->getConfigNames() as $config_name) {
             $langcode = $mapper->getLangcodeFromConfig($config_name);
             $items[] = $this->t('@name: @langcode', ['@name' => $config_name, '@langcode' => $langcode]);
         }
         $message = ['message' => ['#markup' => $this->t('The configuration objects have different language codes so they cannot be translated:')], 'items' => ['#theme' => 'item_list', '#items' => $items]];
         drupal_set_message($this->renderer->renderPlain($message), 'warning');
         $original_langcode = LanguageInterface::LANGCODE_NOT_SPECIFIED;
         $operations_access = FALSE;
     }
     if (!isset($languages[$original_langcode])) {
         // If the language is not configured on the site, create a dummy language
         // object for this listing only to ensure the user gets useful info.
         $language_name = $this->languageManager->getLanguageName($original_langcode);
         $languages[$original_langcode] = new Language(array('id' => $original_langcode, 'name' => $language_name));
     }
     // We create a fake request object to pass into
     // ConfigMapperInterface::populateFromRouteMatch() for the different languages.
     // Creating a separate request for each language and route is neither easily
     // possible nor performant.
     $fake_request = $request->duplicate();
     $page['languages'] = array('#type' => 'table', '#header' => array($this->t('Language'), $this->t('Operations')));
     foreach ($languages as $language) {
         $langcode = $language->getId();
         // This is needed because
         // ConfigMapperInterface::getAddRouteParameters(), for example,
         // needs to return the correct language code for each table row.
         $fake_route_match = RouteMatch::createFromRequest($fake_request);
         $mapper->populateFromRouteMatch($fake_route_match);
         $mapper->setLangcode($langcode);
         // Prepare the language name and the operations depending on whether this
         // is the original language or not.
         if ($langcode == $original_langcode) {
             $language_name = '<strong>' . $this->t('@language (original)', array('@language' => $language->getName())) . '</strong>';
             // Check access for the path/route for editing, so we can decide to
             // include a link to edit or not.
             $edit_access = $this->accessManager->checkNamedRoute($mapper->getBaseRouteName(), $route_match->getRawParameters()->all(), $this->account);
             // Build list of operations.
             $operations = array();
             if ($edit_access) {
                 $operations['edit'] = array('title' => $this->t('Edit'), 'url' => Url::fromRoute($mapper->getBaseRouteName(), $mapper->getBaseRouteParameters(), ['query' => ['destination' => $mapper->getOverviewPath()]]));
             }
         } else {
             $language_name = $language->getName();
             $operations = array();
             // If no translation exists for this language, link to add one.
             if (!$mapper->hasTranslation($language)) {
                 $operations['add'] = array('title' => $this->t('Add'), 'url' => Url::fromRoute($mapper->getAddRouteName(), $mapper->getAddRouteParameters()));
             } else {
                 // Otherwise, link to edit the existing translation.
                 $operations['edit'] = array('title' => $this->t('Edit'), 'url' => Url::fromRoute($mapper->getEditRouteName(), $mapper->getEditRouteParameters()));
                 $operations['delete'] = array('title' => $this->t('Delete'), 'url' => Url::fromRoute($mapper->getDeleteRouteName(), $mapper->getDeleteRouteParameters()));
             }
         }
         $page['languages'][$langcode]['language'] = array('#markup' => $language_name);
         $page['languages'][$langcode]['operations'] = array('#type' => 'operations', '#links' => $operations, '#access' => $langcode == $original_langcode || $operations_access);
     }
     return $page;
 }
예제 #20
0
 /**
  * {@inheritdoc}
  */
 public function buildForm(array $form, FormStateInterface $form_state)
 {
     $form['actions'] = array('#type' => 'actions');
     $form['actions']['submit'] = array('#type' => 'submit', '#value' => $this->t('Import all'));
     $source_list = $this->syncStorage->listAll();
     $storage_comparer = new StorageComparer($this->syncStorage, $this->activeStorage, $this->configManager);
     if (empty($source_list) || !$storage_comparer->createChangelist()->hasChanges()) {
         $form['no_changes'] = array('#type' => 'table', '#header' => array($this->t('Name'), $this->t('Operations')), '#rows' => array(), '#empty' => $this->t('There are no configuration changes to import.'));
         $form['actions']['#access'] = FALSE;
         return $form;
     } elseif (!$storage_comparer->validateSiteUuid()) {
         drupal_set_message($this->t('The staged configuration cannot be imported, because it originates from a different site than this site. You can only synchronize configuration between cloned instances of this site.'), 'error');
         $form['actions']['#access'] = FALSE;
         return $form;
     }
     // A list of changes will be displayed, so check if the user should be
     // warned of potential losses to configuration.
     if ($this->snapshotStorage->exists('core.extension')) {
         $snapshot_comparer = new StorageComparer($this->activeStorage, $this->snapshotStorage, $this->configManager);
         if (!$form_state->getUserInput() && $snapshot_comparer->createChangelist()->hasChanges()) {
             $change_list = array();
             foreach ($snapshot_comparer->getAllCollectionNames() as $collection) {
                 foreach ($snapshot_comparer->getChangelist(NULL, $collection) as $config_names) {
                     if (empty($config_names)) {
                         continue;
                     }
                     foreach ($config_names as $config_name) {
                         $change_list[] = $config_name;
                     }
                 }
             }
             sort($change_list);
             $message = [['#markup' => $this->t('The following items in your active configuration have changes since the last import that may be lost on the next import.')], ['#theme' => 'item_list', '#items' => $change_list]];
             drupal_set_message($this->renderer->renderPlain($message), 'warning');
         }
     }
     // Store the comparer for use in the submit.
     $form_state->set('storage_comparer', $storage_comparer);
     // Add the AJAX library to the form for dialog support.
     $form['#attached']['library'][] = 'core/drupal.ajax';
     foreach ($storage_comparer->getAllCollectionNames() as $collection) {
         if ($collection != StorageInterface::DEFAULT_COLLECTION) {
             $form[$collection]['collection_heading'] = array('#type' => 'html_tag', '#tag' => 'h2', '#value' => $this->t('@collection configuration collection', array('@collection' => $collection)));
         }
         foreach ($storage_comparer->getChangelist(NULL, $collection) as $config_change_type => $config_names) {
             if (empty($config_names)) {
                 continue;
             }
             // @todo A table caption would be more appropriate, but does not have the
             //   visual importance of a heading.
             $form[$collection][$config_change_type]['heading'] = array('#type' => 'html_tag', '#tag' => 'h3');
             switch ($config_change_type) {
                 case 'create':
                     $form[$collection][$config_change_type]['heading']['#value'] = $this->formatPlural(count($config_names), '@count new', '@count new');
                     break;
                 case 'update':
                     $form[$collection][$config_change_type]['heading']['#value'] = $this->formatPlural(count($config_names), '@count changed', '@count changed');
                     break;
                 case 'delete':
                     $form[$collection][$config_change_type]['heading']['#value'] = $this->formatPlural(count($config_names), '@count removed', '@count removed');
                     break;
                 case 'rename':
                     $form[$collection][$config_change_type]['heading']['#value'] = $this->formatPlural(count($config_names), '@count renamed', '@count renamed');
                     break;
             }
             $form[$collection][$config_change_type]['list'] = array('#type' => 'table', '#header' => array($this->t('Name'), $this->t('Operations')));
             foreach ($config_names as $config_name) {
                 if ($config_change_type == 'rename') {
                     $names = $storage_comparer->extractRenameNames($config_name);
                     $route_options = array('source_name' => $names['old_name'], 'target_name' => $names['new_name']);
                     $config_name = $this->t('@source_name to @target_name', array('@source_name' => $names['old_name'], '@target_name' => $names['new_name']));
                 } else {
                     $route_options = array('source_name' => $config_name);
                 }
                 if ($collection != StorageInterface::DEFAULT_COLLECTION) {
                     $route_name = 'config.diff_collection';
                     $route_options['collection'] = $collection;
                 } else {
                     $route_name = 'config.diff';
                 }
                 $links['view_diff'] = array('title' => $this->t('View differences'), 'url' => Url::fromRoute($route_name, $route_options), 'attributes' => array('class' => array('use-ajax'), 'data-dialog-type' => 'modal', 'data-dialog-options' => json_encode(array('width' => 700))));
                 $form[$collection][$config_change_type]['list']['#rows'][] = array('name' => $config_name, 'operations' => array('data' => array('#type' => 'operations', '#links' => $links)));
             }
         }
     }
     return $form;
 }
예제 #21
0
 /**
  * Validation handler for the credentials form.
  *
  * @param array $form
  *   An associative array containing the structure of the form.
  * @param \Drupal\Core\Form\FormStateInterface $form_state
  *   The current state of the form.
  */
 public function validateCredentialForm(array &$form, FormStateInterface $form_state)
 {
     // Skip if rollback was chosen.
     if ($form_state->getValue('upgrade_option') == static::MIGRATE_UPGRADE_ROLLBACK) {
         return;
     }
     // Retrieve the database driver from the form, use reflection to get the
     // namespace and then construct a valid database array the same as in
     // settings.php.
     if ($driver = $form_state->getValue('driver')) {
         $drivers = $this->getDatabaseTypes();
         $reflection = new \ReflectionClass($drivers[$driver]);
         $install_namespace = $reflection->getNamespaceName();
         $database = $form_state->getValue($driver);
         // Cut the trailing \Install from namespace.
         $database['namespace'] = substr($install_namespace, 0, strrpos($install_namespace, '\\'));
         $database['driver'] = $driver;
         // Validate the driver settings and just end here if we have any issues.
         if ($errors = $drivers[$driver]->validateDatabaseSettings($database)) {
             foreach ($errors as $name => $message) {
                 $form_state->setErrorByName($name, $message);
             }
             return;
         }
     } else {
         $database = [];
         // Find a migration which has database credentials and use those.
         $query = $this->entityStorage->getQuery('OR');
         $ids = $query->execute();
         foreach ($ids as $id) {
             /** @var \Drupal\migrate\Entity\MigrationInterface $migration */
             $migration = Migration::load($id);
             $is_drupal_migration = FALSE;
             foreach ($migration->get('migration_tags') as $migration_tag) {
                 if (substr($migration_tag, 0, 7) === 'Drupal ') {
                     $is_drupal_migration = TRUE;
                     break;
                 }
             }
             if ($is_drupal_migration) {
                 $source = $migration->get('source');
                 if ($database = $this->state->get($source['database_state_key'])['database']) {
                     break;
                 }
             }
         }
     }
     try {
         // Get the template for migration.
         $migration_template = $this->getMigrationTemplates($database, $form_state->getValue('source_base_path'));
         // Get a copy of all the relevant migrations so we run them in next step.
         $migrations = $this->getMigrations($migration_template);
         // Get the system data from source database.
         $system_data = $this->getSystemData($database);
         // Convert the migration object into array
         // so that it can be stored in form storage.
         $migration_array = [];
         foreach ($migrations as $migration) {
             $migration_array[] = $migration->toArray();
         }
         // Store the retrieved migration templates in form storage.
         $form_state->set('migration_template', $migration_template);
         // Store the retrieved migration ids in form storage.
         $form_state->set('migration', $migration_array);
         // Store the retrived system data in from storage.
         $form_state->set('system_data', $system_data);
     } catch (\Exception $e) {
         $error_message = ['#type' => 'inline_template', '#template' => '{% trans %}Resolve the issue below to continue the upgrade.{% endtrans%}{{ errors }}', '#context' => ['errors' => ['#theme' => 'item_list', '#items' => [$e->getMessage()]]]];
         $form_state->setErrorByName($database['driver'] . '][0', $this->renderer->renderPlain($error_message));
     }
 }