/**
  * {@inheritdoc}
  */
 public function buildForm(array $form, FormStateInterface $form_state, Request $request = NULL)
 {
     $current_path = $request->attributes->get('_system_path');
     $current_url = Url::createFromRequest($request);
     $devel_config = $this->config('devel.settings');
     $form['queries'] = array('#type' => 'fieldset', '#title' => t('Query log'));
     $description = t('Display a log of the database queries needed to generate the current page, and the execution time for each. Also, queries which are repeated during a single page view are summed in the # column, and printed in red since they are candidates for caching.');
     $form['queries']['query_display'] = array('#type' => 'checkbox', '#title' => t('Display query log'), '#default_value' => $devel_config->get('query_display'), '#description' => $description);
     $form['queries']['settings'] = array('#type' => 'container', '#states' => array('invisible' => array('input[name="query_display"]' => array('checked' => FALSE))));
     $form['queries']['settings']['query_sort'] = array('#type' => 'radios', '#title' => t('Sort query log'), '#default_value' => $devel_config->get('query_sort'), '#options' => array(t('by source'), t('by duration')), '#description' => t('The query table can be sorted in the order that the queries were executed or by descending duration.'));
     $form['queries']['settings']['execution'] = array('#type' => 'textfield', '#title' => t('Slow query highlighting'), '#default_value' => $devel_config->get('execution'), '#size' => 4, '#maxlength' => 4, '#description' => t('Enter an integer in milliseconds. Any query which takes longer than this many milliseconds will be highlighted in the query log. This indicates a possibly inefficient query, or a candidate for caching.'));
     $form['api_url'] = array('#type' => 'textfield', '#title' => t('API Site'), '#default_value' => $devel_config->get('api_url'), '#description' => t('The base URL for your developer documentation links. You might change this if you run <a href="!url">api.module</a> locally.', array('!url' => Url::fromUri('http://drupal.org/project/api')->toString())));
     $form['timer'] = array('#type' => 'checkbox', '#title' => t('Display page timer'), '#default_value' => $devel_config->get('timer'), '#description' => t('Display page execution time in the query log box.'));
     $form['memory'] = array('#type' => 'checkbox', '#title' => t('Display memory usage'), '#default_value' => $devel_config->get('memory'), '#description' => t('Display how much memory is used to generate the current page. This will show memory usage when devel_init() is called and when devel_exit() is called.'));
     $form['redirect_page'] = array('#type' => 'checkbox', '#title' => t('Display redirection page'), '#default_value' => $devel_config->get('redirect_page'), '#description' => t('When a module executes drupal_goto(), the query log and other developer information is lost. Enabling this setting presents an intermediate page to developers so that the log can be examined before continuing to the destination page.'));
     $form['page_alter'] = array('#type' => 'checkbox', '#title' => t('Display $page array'), '#default_value' => $devel_config->get('page_alter'), '#description' => t('Display $page array from <a href="http://api.drupal.org/api/function/hook_page_alter/7">hook_page_alter()</a> in the messages area of each page.'));
     $form['raw_names'] = array('#type' => 'checkbox', '#title' => t('Display machine names of permissions and modules'), '#default_value' => $devel_config->get('raw_names'), '#description' => t('Display the language-independent machine names of the permissions in mouse-over hints on the !Permissions page and the module base file names on the @Permissions and !Modules pages.', array('!Permissions' => $this->l(t('Permissions'), Url::fromRoute('user.admin_permissions')), '@Permissions' => t('Permissions'), '!Modules' => $this->l(t('Modules'), Url::fromRoute('system.modules_list')))));
     $error_handlers = devel_get_handlers();
     $form['error_handlers'] = array('#type' => 'select', '#title' => t('Error handlers'), '#options' => array(DEVEL_ERROR_HANDLER_NONE => t('None'), DEVEL_ERROR_HANDLER_STANDARD => t('Standard Drupal'), DEVEL_ERROR_HANDLER_BACKTRACE_DPM => t('Krumo backtrace in the message area'), DEVEL_ERROR_HANDLER_BACKTRACE_KRUMO => t('Krumo backtrace above the rendered page')), '#multiple' => TRUE, '#default_value' => empty($error_handlers) ? DEVEL_ERROR_HANDLER_NONE : $error_handlers, '#description' => SafeMarkup::set(t('Select the error handler(s) to use, in case you <a href="@choose">choose to show errors on screen</a>.', array('@choose' => $this->url('system.logging_settings'))) . '<ul>' . '<li>' . t('<em>None</em> is a good option when stepping through the site in your debugger.') . '</li>' . '<li>' . t('<em>Standard Drupal</em> does not display all the information that is often needed to resolve an issue.') . '</li>' . '<li>' . t('<em>Krumo backtrace</em> displays nice debug information when any type of error is noticed, but only to users with the %perm permission.', array('%perm' => t('Access developer information'))) . '</li></ul>' . t('Depending on the situation, the theme, the size of the call stack and the arguments, etc., some handlers may not display their messages, or display them on the subsequent page. Select <em>Standard Drupal</em> <strong>and</strong> <em>Krumo backtrace above the rendered page</em> to maximize your chances of not missing any messages.') . '<br />' . t('Demonstrate the current error handler(s):') . ' ' . $this->l('notice', $current_url, array('query' => array('demo' => 'notice'))) . ', ' . $this->l('notice+warning', $current_url, array('query' => array('demo' => 'warning'))) . ', ' . $this->l('notice+warning+error', $current_url, array('query' => array('demo' => 'error'))) . ' ' . t('(The presentation of the @error is determined by PHP.)', array('@error' => 'error'))));
     $form['error_handlers']['#size'] = count($form['error_handlers']['#options']);
     if ($request->query->has('demo')) {
         if ($request->getMethod() == 'GET') {
             $this->demonstrateErrorHandlers($request->query->get('demo'));
         }
         $request->query->remove('demo');
     }
     $options = array('default', 'blue', 'green', 'orange', 'white', 'disabled');
     $form['krumo_skin'] = array('#type' => 'radios', '#title' => t('Krumo display'), '#description' => t('Select a skin for your debug messages or select <em>disabled</em> to display object and array output in standard PHP format.'), '#options' => array_combine($options, $options), '#default_value' => $devel_config->get('krumo_skin'));
     $form['rebuild_theme'] = array('#type' => 'checkbox', '#title' => t('Rebuild the theme information like the registry'), '#description' => t('While creating new templates, change the $theme.info.yml and theme_ overrides the theme information needs to be rebuilt.'), '#default_value' => $devel_config->get('rebuild_theme'));
     $form['use_uncompressed_jquery'] = array('#type' => 'checkbox', '#title' => t('Use uncompressed jQuery'), '#default_value' => $devel_config->get('use_uncompressed_jquery'), '#description' => t("Use a human-readable version of jQuery instead of the minified version that ships with Drupal, to make JavaScript debugging easier."));
     return parent::buildForm($form, $form_state);
 }
Exemple #2
0
 /**
  * Test the user login block.
  */
 function testUserLoginBlock()
 {
     // Make sure the validation error is displayed when try to login with
     // invalid username/password.
     $edit['name'] = $this->randomMachineName();
     $edit['pass'] = $this->randomMachineName();
     $this->drupalPostForm('node', $edit, t('Log in'));
     $this->assertRaw(\Drupal::translation()->formatPlural(1, '1 error has been found: !errors', '@count errors have been found: !errors', ['!errors' => SafeMarkup::set('<a href="#edit-name">Username</a>')]));
     $this->assertText(t('Sorry, unrecognized username or password.'));
     // Create a user with some permission that anonymous users lack.
     $user = $this->drupalCreateUser(array('administer permissions'));
     // Log in using the block.
     $edit = array();
     $edit['name'] = $user->getUsername();
     $edit['pass'] = $user->pass_raw;
     $this->drupalPostForm('admin/people/permissions', $edit, t('Log in'));
     $this->assertNoText(t('User login'), 'Logged in.');
     // Check that we are still on the same page.
     $this->assertUrl(\Drupal::url('user.admin_permissions', [], ['absolute' => TRUE]), [], 'Still on the same page after login for access denied page');
     // Now, log out and repeat with a non-403 page.
     $this->drupalLogout();
     $this->drupalPostForm('filter/tips', $edit, t('Log in'));
     $this->assertNoText(t('User login'), 'Logged in.');
     $this->assertPattern('!<title.*?' . t('Compose tips') . '.*?</title>!', 'Still on the same page after login for allowed page');
     // Check that the user login block is not vulnerable to information
     // disclosure to third party sites.
     $this->drupalLogout();
     $this->drupalPostForm('http://example.com/', $edit, t('Log in'), array('external' => FALSE));
     // Check that we remain on the site after login.
     $this->assertUrl($user->url('canonical', ['absolute' => TRUE]), [], 'Redirected to user profile page after login from the frontpage');
 }
 /**
  * Implodes the meta and link elements for the template.
  *
  * @return string
  *   A string of meta and link tags.
  */
 public function getHead()
 {
     // Each MetaElement or LinkElement is a subclass of
     // \Drupal\Core\Page\HeadElement and generates safe output when __toString()
     // is called on it. Thus, the whole concatenation is also safe.
     return SafeMarkup::set(implode("\n", $this->getMetaElements()) . implode("\n", $this->getLinkElements()));
 }
 /**
  * Tests the integration.
  */
 public function testIntegration()
 {
     // Remove the watchdog entries added by the potential batch process.
     $this->container->get('database')->truncate('watchdog')->execute();
     $entries = array();
     // Setup a watchdog entry without tokens.
     $entries[] = array('message' => $this->randomMachineName(), 'variables' => array('link' => \Drupal::l('Link', new Url('<front>'))));
     // Setup a watchdog entry with one token.
     $entries[] = array('message' => '@token1', 'variables' => array('@token1' => $this->randomMachineName(), 'link' => \Drupal::l('Link', new Url('<front>'))));
     // Setup a watchdog entry with two tokens.
     $entries[] = array('message' => '@token1 !token2', 'variables' => array('@token1' => $this->randomMachineName(), '!token2' => $this->randomMachineName(), 'link' => \Drupal::l(SafeMarkup::set('<object>Link</object>'), new Url('<front>'))));
     $logger_factory = $this->container->get('logger.factory');
     foreach ($entries as $entry) {
         $entry += array('type' => 'test-views', 'severity' => RfcLogLevel::NOTICE);
         $logger_factory->get($entry['type'])->log($entry['severity'], $entry['message'], $entry['variables']);
     }
     $view = Views::getView('test_dblog');
     $this->executeView($view);
     $view->initStyle();
     foreach ($entries as $index => $entry) {
         $this->assertEqual($view->style_plugin->getField($index, 'message'), SafeMarkup::format($entry['message'], $entry['variables']));
         $this->assertEqual($view->style_plugin->getField($index, 'link'), Xss::filterAdmin($entry['variables']['link']));
     }
     // Disable replacing variables and check that the tokens aren't replaced.
     $view->destroy();
     $view->storage->invalidateCaches();
     $view->initHandlers();
     $this->executeView($view);
     $view->initStyle();
     $view->field['message']->options['replace_variables'] = FALSE;
     foreach ($entries as $index => $entry) {
         $this->assertEqual($view->style_plugin->getField($index, 'message'), $entry['message']);
     }
 }
 /**
  * Pre-render callback: Renders a generic HTML tag with attributes into #markup.
  *
  * Note: It is the caller's responsibility to sanitize any input parameters.
  * This callback does not perform sanitization.
  *
  * @param array $element
  *   An associative array containing:
  *   - #tag: The tag name to output. Typical tags added to the HTML HEAD:
  *     - meta: To provide meta information, such as a page refresh.
  *     - link: To refer to stylesheets and other contextual information.
  *     - script: To load JavaScript.
  *     The value of #tag is not escaped or sanitized, so do not pass in user
  *     input.
  *   - #attributes: (optional) An array of HTML attributes to apply to the
  *     tag.
  *   - #value: (optional) A string containing tag content, such as inline
  *     CSS.
  *   - #value_prefix: (optional) A string to prepend to #value, e.g. a CDATA
  *     wrapper prefix.
  *   - #value_suffix: (optional) A string to append to #value, e.g. a CDATA
  *     wrapper suffix.
  *
  * @return array
  */
 public static function preRenderHtmlTag($element)
 {
     $attributes = isset($element['#attributes']) ? new Attribute($element['#attributes']) : '';
     if (!isset($element['#value'])) {
         // This function is intended for internal use, so we assume that no unsafe
         // values are passed in #tag. The attributes are already safe because
         // Attribute output is already automatically sanitized.
         // @todo Escape this properly instead? https://www.drupal.org/node/2296101
         $markup = SafeMarkup::set('<' . $element['#tag'] . $attributes . " />\n");
     } else {
         $markup = '<' . $element['#tag'] . $attributes . '>';
         if (isset($element['#value_prefix'])) {
             $markup .= $element['#value_prefix'];
         }
         $markup .= $element['#value'];
         if (isset($element['#value_suffix'])) {
             $markup .= $element['#value_suffix'];
         }
         $markup .= '</' . $element['#tag'] . ">\n";
         // @todo We cannot actually guarantee this markup is safe. Consider a fix
         //   in: https://www.drupal.org/node/2296101
         $markup = SafeMarkup::set($markup);
     }
     if (!empty($element['#noscript'])) {
         $element['#markup'] = '<noscript>' . $markup . '</noscript>';
     } else {
         $element['#markup'] = $markup;
     }
     return $element;
 }
 /**
  * {@inheritdoc}
  */
 public function get(array $elements)
 {
     // Form submissions rely on the form being built during the POST request,
     // and render caching of forms prevents this from happening.
     // @todo remove the isMethodSafe() check when
     //       https://www.drupal.org/node/2367555 lands.
     if (!$this->requestStack->getCurrentRequest()->isMethodSafe() || !($cid = $this->createCacheID($elements))) {
         return FALSE;
     }
     $bin = isset($elements['#cache']['bin']) ? $elements['#cache']['bin'] : 'render';
     if (!empty($cid) && ($cache_bin = $this->cacheFactory->get($bin)) && ($cache = $cache_bin->get($cid))) {
         $cached_element = $cache->data;
         // Two-tier caching: redirect to actual (post-bubbling) cache item.
         // @see \Drupal\Core\Render\RendererInterface::render()
         // @see ::set()
         if (isset($cached_element['#cache_redirect'])) {
             return $this->get($cached_element);
         }
         // Ensure that any safe properties are marked safe.
         foreach ($cached_element['#safe_cache_properties'] as $cache_property) {
             SafeMarkup::set($cached_element[$cache_property]);
         }
         unset($cached_element['#safe_cache_properties']);
         // Return the cached element.
         return $cached_element;
     }
     return FALSE;
 }
 /**
  * Execute the search.
  *
  * This is a dummy search, so when search "executes", we just return a dummy
  * result containing the keywords and a list of conditions.
  *
  * @return array
  *   A structured list of search results
  */
 public function execute()
 {
     $results = array();
     if (!$this->isSearchExecutable()) {
         return $results;
     }
     return array(array('link' => url('node'), 'type' => 'Dummy result type', 'title' => 'Dummy title', 'snippet' => SafeMarkup::set("Dummy search snippet to display. Keywords: {$this->keywords}\n\nConditions: " . print_r($this->searchParameters, TRUE))));
 }
 /**
  * {@inheritdoc}
  */
 public function buildRow(EntityInterface $view)
 {
     $row = parent::buildRow($view);
     $display_paths = '';
     $separator = '';
     foreach ($this->getDisplayPaths($view) as $display_path) {
         $display_paths .= $separator . SafeMarkup::escape($display_path);
         $separator = ', ';
     }
     return array('data' => array('view_name' => array('data' => array('#theme' => 'views_ui_view_info', '#view' => $view, '#displays' => $this->getDisplaysList($view))), 'description' => array('data' => array('#markup' => String::checkPlain($view->get('description'))), 'class' => array('views-table-filter-text-source')), 'tag' => $view->get('tag'), 'path' => SafeMarkup::set($display_paths), 'operations' => $row['operations']), 'title' => $this->t('Machine name: @name', array('@name' => $view->id())), 'class' => array($view->status() ? 'views-ui-list-enabled' : 'views-ui-list-disabled'));
 }
 /**
  * Renders this object to an HTML element string.
  *
  * @return string
  */
 public function __toString()
 {
     // Render the attributes via the attribute template class.
     // @todo Should HeadElement just extend the Attribute classes?
     $attributes = new Attribute($this->attributes);
     $rendered = (string) $attributes;
     $string = "<{$this->element}{$rendered} />";
     if ($this->noScript) {
         $string = "<noscript>{$string}</noscript>";
     }
     return SafeMarkup::set($string);
 }
Exemple #10
0
 /**
  * {@inheritdoc}
  *
  * @param \Drupal\filter\Entity\FilterFormat $filter_format
  *   The filter format for which this dialog corresponds.
  */
 public function buildForm(array $form, array &$form_state, FilterFormat $filter_format = NULL)
 {
     // The default values are set directly from \Drupal::request()->request,
     // provided by the editor plugin opening the dialog.
     if (!isset($form_state['image_element'])) {
         $form_state['image_element'] = isset($form_state['input']['editor_object']) ? $form_state['input']['editor_object'] : array();
     }
     $image_element = $form_state['image_element'];
     $form['#tree'] = TRUE;
     $form['#attached']['library'][] = 'editor/drupal.editor.dialog';
     $form['#prefix'] = '<div id="editor-image-dialog-form">';
     $form['#suffix'] = '</div>';
     $editor = editor_load($filter_format->format);
     // Construct strings to use in the upload validators.
     $image_upload = $editor->getImageUploadSettings();
     if (!empty($image_upload['dimensions'])) {
         $max_dimensions = $image_upload['dimensions']['max_width'] . 'x' . $image_upload['dimensions']['max_height'];
     } else {
         $max_dimensions = 0;
     }
     $max_filesize = min(Bytes::toInt($image_upload['max_size']), file_upload_max_size());
     $existing_file = isset($image_element['data-editor-file-uuid']) ? entity_load_by_uuid('file', $image_element['data-editor-file-uuid']) : NULL;
     $fid = $existing_file ? $existing_file->id() : NULL;
     $form['fid'] = array('#title' => $this->t('Image'), '#type' => 'managed_file', '#upload_location' => $image_upload['scheme'] . '://' . $image_upload['directory'], '#default_value' => $fid ? array($fid) : NULL, '#upload_validators' => array('file_validate_extensions' => array('gif png jpg jpeg'), 'file_validate_size' => array($max_filesize), 'file_validate_image_resolution' => array($max_dimensions)), '#required' => TRUE);
     $form['attributes']['src'] = array('#title' => $this->t('URL'), '#type' => 'textfield', '#default_value' => isset($image_element['src']) ? $image_element['src'] : '', '#maxlength' => 2048, '#required' => TRUE);
     // If the editor has image uploads enabled, show a managed_file form item,
     // otherwise show a (file URL) text form item.
     if ($image_upload['status']) {
         $form['attributes']['src']['#access'] = FALSE;
         $form['attributes']['src']['#required'] = FALSE;
     } else {
         $form['fid']['#access'] = FALSE;
         $form['fid']['#required'] = FALSE;
     }
     $form['attributes']['alt'] = array('#title' => $this->t('Alternative text'), '#type' => 'textfield', '#required' => TRUE, '#default_value' => isset($image_element['alt']) ? $image_element['alt'] : '', '#maxlength' => 2048);
     $form['dimensions'] = array('#type' => 'item', '#title' => $this->t('Image size'), '#field_prefix' => SafeMarkup::set('<div class="container-inline">'), '#field_suffix' => SafeMarkup::set('</div>'));
     $form['dimensions']['width'] = array('#title' => $this->t('Width'), '#title_display' => 'invisible', '#type' => 'number', '#default_value' => isset($image_element['width']) ? $image_element['width'] : '', '#size' => 8, '#maxlength' => 8, '#min' => 1, '#max' => 99999, '#placeholder' => $this->t('width'), '#field_suffix' => ' x ', '#parents' => array('attributes', 'width'));
     $form['dimensions']['height'] = array('#title' => $this->t('Height'), '#title_display' => 'invisible', '#type' => 'number', '#default_value' => isset($image_element['height']) ? $image_element['height'] : '', '#size' => 8, '#maxlength' => 8, '#min' => 1, '#max' => 99999, '#placeholder' => $this->t('height'), '#field_suffix' => $this->t('pixels'), '#parents' => array('attributes', 'height'));
     // When Drupal core's filter_caption is being used, the text editor may
     // offer the ability to change the alignment.
     if (isset($image_element['data-align'])) {
         $form['align'] = array('#title' => $this->t('Align'), '#type' => 'radios', '#options' => array('none' => $this->t('None'), 'left' => $this->t('Left'), 'center' => $this->t('Center'), 'right' => $this->t('Right')), '#default_value' => $image_element['data-align'] === '' ? 'none' : $image_element['data-align'], '#wrapper_attributes' => array('class' => array('container-inline')), '#attributes' => array('class' => array('container-inline')), '#parents' => array('attributes', 'data-align'));
     }
     // When Drupal core's filter_caption is being used, the text editor may
     // offer the ability to in-place edit the image's caption: show a toggle.
     if (isset($image_element['hasCaption'])) {
         $form['caption'] = array('#title' => $this->t('Caption'), '#type' => 'checkbox', '#default_value' => $image_element['hasCaption'] === 'true', '#parents' => array('attributes', 'hasCaption'));
     }
     $form['actions'] = array('#type' => 'actions');
     $form['actions']['save_modal'] = array('#type' => 'submit', '#value' => $this->t('Save'), '#submit' => array(), '#ajax' => array('callback' => array($this, 'submitForm'), 'event' => 'click'));
     return $form;
 }
Exemple #11
0
 protected function _flushLine($new_tag)
 {
     $this->_flushGroup($new_tag);
     if ($this->line != '') {
         // @todo This is probably not the right place to do this. To be
         //   addressed in https://drupal.org/node/2280963
         array_push($this->lines, SafeMarkup::set($this->line));
     } else {
         // make empty lines visible by inserting an NBSP
         array_push($this->lines, $this::NBSP);
     }
     $this->line = '';
 }
Exemple #12
0
 /**
  * Filters an HTML string to prevent XSS vulnerabilities.
  *
  * Like \Drupal\Component\Utility\Xss::filterAdmin(), but with a shorter list
  * of allowed tags.
  *
  * Used for items entered by administrators, like field descriptions, allowed
  * values, where some (mainly inline) mark-up may be desired (so
  * \Drupal\Component\Utility\SafeMarkup::checkPlain() is not acceptable).
  *
  * @param string $string
  *   The string with raw HTML in it.
  *
  * @return \Drupal\Component\Utility\SafeMarkup
  *   An XSS safe version of $string, or an empty string if $string is not
  *   valid UTF-8.
  */
 public function fieldFilterXss($string)
 {
     // All known XSS vectors are filtered out by
     // \Drupal\Component\Utility\Xss::filter(), all tags in the markup are
     // allowed intentionally by the trait, and no danger is added in by
     // \Drupal\Component\Utility\HTML::normalize(). Since the normalized value
     // is essentially the same markup, designate this string as safe as well.
     // This method is an internal part of field sanitization, so the resultant,
     // sanitized string should be printable as is.
     //
     // @todo Free this memory in https://www.drupal.org/node/2505963.
     return SafeMarkup::set(Html::normalize(Xss::filter($string, $this->allowedTags())));
 }
 /**
  * Renders an exception error message without further exceptions.
  *
  * @param \Exception $exception
  *   The exception object that was thrown.
  *
  * @return string
  *   An error message.
  */
 public static function renderExceptionSafe(\Exception $exception)
 {
     $decode = static::decodeException($exception);
     $backtrace = $decode['backtrace'];
     unset($decode['backtrace']);
     // Remove 'main()'.
     array_shift($backtrace);
     $output = String::format('%type: !message in %function (line %line of %file).', $decode);
     // Even though it is possible that this method is called on a public-facing
     // site, it is only called when the exception handler itself threw an
     // exception, which normally means that a code change caused the system to
     // no longer function correctly (as opposed to a user-triggered error), so
     // we assume that it is safe to include a verbose backtrace.
     $output .= '<pre>' . static::formatBacktrace($backtrace) . '</pre>';
     return SafeMarkup::set($output);
 }
 /**
  * Implements \Drupal\Core\TypedData\TypedDataInterface::getValue().
  */
 public function getValue($langcode = NULL)
 {
     if ($this->processed !== NULL) {
         return $this->processed;
     }
     $item = $this->getParent();
     $text = $item->{$this->definition->getSetting('text source')};
     // Avoid running check_markup() or
     // \Drupal\Component\Utility\String::checkPlain() on empty strings.
     if (!isset($text) || $text === '') {
         $this->processed = '';
     } elseif ($item->getFieldDefinition()->getSetting('text_processing')) {
         $this->processed = check_markup($text, $item->format, $item->getLangcode());
     } else {
         // Escape all HTML and retain newlines.
         // @see \Drupal\Core\Field\Plugin\Field\FieldFormatter\StringFormatter
         $this->processed = SafeMarkup::set(nl2br(String::checkPlain($text)));
     }
     return $this->processed;
 }
 /**
  * Formats a message composed by drupal_mail().
  *
  * @see http://api.drupal.org/api/drupal/includes--mail.inc/interface/MailSystemInterface/7
  *
  * @param array $message
  *   A message array holding all relevant details for the message.
  *
  * @return string
  *   The message as it should be sent.
  */
 public function format(array $message)
 {
     // Get default mail line endings and merge all lines in the e-mail body
     // separated by the mail line endings.
     $line_endings = Settings::get('mail_line_endings', PHP_EOL);
     $message['body'] = SafeMarkup::set(implode($line_endings, $message['body']));
     // Get applicable format.
     $applicable_format = $this->getApplicableFormat($message);
     // Theme message if format is set to be HTML.
     if ($applicable_format == SWIFTMAILER_FORMAT_HTML) {
         $render = array('#theme' => isset($message['params']['theme']) ? $message['params']['theme'] : 'swiftmailer', '#message' => $message);
         $message['body'] = $this->renderer->renderRoot($render);
         if ($this->config['message']['convert_mode'] || !empty($message['params']['convert'])) {
             $converter = new Html2Text($message['body']);
             $message['plain'] = $converter->get_text();
         }
     }
     // Process any images specified by 'image:' which are to be added later
     // in the process. All we do here is to alter the message so that image
     // paths are replaced with cid's. Each image gets added to the array
     // which keeps track of which images to embed in the e-mail.
     $embeddable_images = array();
     preg_match_all('/"image:([^"]+)"/', $message['body'], $embeddable_images);
     for ($i = 0; $i < count($embeddable_images[0]); $i++) {
         $image_id = $embeddable_images[0][$i];
         $image_path = trim($embeddable_images[1][$i]);
         $image_name = basename($image_path);
         if (Unicode::substr($image_path, 0, 1) == '/') {
             $image_path = Unicode::substr($image_path, 1);
         }
         $image = new stdClass();
         $image->uri = $image_path;
         $image->filename = $image_name;
         $image->filemime = file_get_mimetype($image_path);
         $image->cid = rand(0, 9999999999.0);
         $message['params']['images'][] = $image;
         $message['body'] = preg_replace($image_id, 'cid:' . $image->cid, $message['body']);
     }
     return $message;
 }
Exemple #16
0
 /**
  * {@inheritdoc}
  */
 public function process($text, $langcode)
 {
     $result = new FilterProcessResult($text);
     if (stristr($text, 'data-caption') !== FALSE) {
         $dom = Html::load($text);
         $xpath = new \DOMXPath($dom);
         foreach ($xpath->query('//*[@data-caption]') as $node) {
             // Read the data-caption attribute's value, then delete it.
             $caption = SafeMarkup::checkPlain($node->getAttribute('data-caption'));
             $node->removeAttribute('data-caption');
             // Sanitize caption: decode HTML encoding, limit allowed HTML tags; only
             // allow inline tags that are allowed by default, plus <br>.
             $caption = Html::decodeEntities($caption);
             $caption = SafeMarkup::xssFilter($caption, array('a', 'em', 'strong', 'cite', 'code', 'br'));
             // The caption must be non-empty.
             if (Unicode::strlen($caption) === 0) {
                 continue;
             }
             // Given the updated node and caption: re-render it with a caption, but
             // bubble up the value of the class attribute of the captioned element,
             // this allows it to collaborate with e.g. the filter_align filter.
             $classes = $node->getAttribute('class');
             $node->removeAttribute('class');
             $filter_caption = array('#theme' => 'filter_caption', '#node' => SafeMarkup::set($node->C14N()), '#tag' => $node->tagName, '#caption' => $caption, '#classes' => $classes);
             $altered_html = drupal_render($filter_caption);
             // Load the altered HTML into a new DOMDocument and retrieve the element.
             $updated_node = Html::load($altered_html)->getElementsByTagName('body')->item(0)->childNodes->item(0);
             // Import the updated node from the new DOMDocument into the original
             // one, importing also the child nodes of the updated node.
             $updated_node = $dom->importNode($updated_node, TRUE);
             // Finally, replace the original image node with the new image node!
             $node->parentNode->replaceChild($updated_node, $node);
         }
         $result->setProcessedText(Html::serialize($dom))->addAttachments(array('library' => array('filter/caption')));
     }
     return $result;
 }
 /**
  * {@inheritdoc}
  */
 public function buildRow(EntityInterface $field)
 {
     if ($field->locked) {
         $row['class'] = array('menu-disabled');
         $row['data']['id'] = t('@field_name (Locked)', array('@field_name' => $field->name));
     } else {
         $row['data']['id'] = $field->name;
     }
     $field_type = $this->fieldTypes[$field->type];
     $row['data']['type'] = t('@type (module: @module)', array('@type' => $field_type['label'], '@module' => $field_type['provider']));
     $usage = array();
     foreach ($field->getBundles() as $bundle) {
         if ($route_info = FieldUI::getOverviewRouteInfo($field->entity_type, $bundle)) {
             $usage[] = \Drupal::linkGenerator()->generateFromUrl($this->bundles[$field->entity_type][$bundle]['label'], $route_info);
         } else {
             $usage[] = $this->bundles[$field->entity_type][$bundle]['label'];
         }
     }
     $usage_escaped = '';
     $separator = '';
     foreach ($usage as $usage_item) {
         $usage_escaped .= $separator . SafeMarkup::escape($usage_item);
         $separator = ', ';
     }
     $row['data']['usage'] = SafeMarkup::set($usage_escaped);
     return $row;
 }
Exemple #18
0
 /**
  * Lists all plugins and what enabled Views use them.
  *
  * @return array
  *   The Views plugins report page.
  */
 public function reportPlugins()
 {
     $rows = Views::pluginList();
     foreach ($rows as &$row) {
         // Link each view name to the view itself.
         foreach ($row['views'] as $row_name => $view) {
             $row['views'][$row_name] = $this->l($view, new Url('entity.view.edit_form', array('view' => $view)));
         }
         $row['views'] = SafeMarkup::set(implode(', ', $row['views']));
     }
     // Sort rows by field name.
     ksort($rows);
     return array('#type' => 'table', '#header' => array(t('Type'), t('Name'), t('Provided by'), t('Used in')), '#rows' => $rows, '#empty' => t('There are no enabled views.'));
 }
 /**
  * Tests the link method with html.
  *
  * @see \Drupal\Core\Utility\LinkGenerator::generate()
  */
 public function testGenerateWithHtml()
 {
     $this->urlGenerator->expects($this->at(0))->method('generateFromRoute')->with('test_route_5', array(), $this->defaultOptions)->will($this->returnValue('/test-route-5'));
     $this->urlGenerator->expects($this->at(1))->method('generateFromRoute')->with('test_route_5', array(), $this->defaultOptions)->will($this->returnValue('/test-route-5'));
     // Test that HTML tags are stripped from the 'title' attribute.
     $url = new Url('test_route_5', array(), array('attributes' => array('title' => '<em>HTML Tooltip</em>')));
     $url->setUrlGenerator($this->urlGenerator);
     $result = $this->linkGenerator->generate('Test', $url);
     $this->assertLink(array('attributes' => array('href' => '/test-route-5', 'title' => 'HTML Tooltip')), $result);
     // Test that safe HTML is output inside the anchor tag unescaped.
     $url = new Url('test_route_5', array());
     $url->setUrlGenerator($this->urlGenerator);
     $result = $this->linkGenerator->generate(SafeMarkup::set('<em>HTML output</em>'), $url);
     $this->assertLink(array('attributes' => array('href' => '/test-route-5'), 'child' => array('tag' => 'em')), $result);
 }
Exemple #20
0
 public function render($row)
 {
     global $base_url;
     $nid = $row->{$this->field_alias};
     if (!is_numeric($nid)) {
         return;
     }
     $display_mode = $this->options['view_mode'];
     if ($display_mode == 'default') {
         $display_mode = \Drupal::config('system.rss')->get('items.view_mode');
     }
     // Load the specified node:
     /** @var \Drupal\node\NodeInterface $node */
     $node = $this->nodes[$nid];
     if (empty($node)) {
         return;
     }
     $item_text = '';
     $node->link = $node->url('canonical', array('absolute' => TRUE));
     $node->rss_namespaces = array();
     $node->rss_elements = array(array('key' => 'pubDate', 'value' => gmdate('r', $node->getCreatedTime())), array('key' => 'dc:creator', 'value' => $node->getOwner()->getUsername()), array('key' => 'guid', 'value' => $node->id() . ' at ' . $base_url, 'attributes' => array('isPermaLink' => 'false')));
     // The node gets built and modules add to or modify $node->rss_elements
     // and $node->rss_namespaces.
     $build_mode = $display_mode;
     $build = node_view($node, $build_mode);
     unset($build['#theme']);
     if (!empty($node->rss_namespaces)) {
         $this->view->style_plugin->namespaces = array_merge($this->view->style_plugin->namespaces, $node->rss_namespaces);
     } elseif (function_exists('rdf_get_namespaces')) {
         // Merge RDF namespaces in the XML namespaces in case they are used
         // further in the RSS content.
         $xml_rdf_namespaces = array();
         foreach (rdf_get_namespaces() as $prefix => $uri) {
             $xml_rdf_namespaces['xmlns:' . $prefix] = $uri;
         }
         $this->view->style_plugin->namespaces += $xml_rdf_namespaces;
     }
     if ($display_mode != 'title') {
         // We render node contents.
         $item_text .= drupal_render_root($build);
     }
     $item = new \stdClass();
     $item->description = SafeMarkup::set($item_text);
     $item->title = $node->label();
     $item->link = $node->link;
     $item->elements = $node->rss_elements;
     $item->nid = $node->id();
     $theme_function = array('#theme' => $this->themeFunctions(), '#view' => $this->view, '#options' => $this->options, '#row' => $item);
     return drupal_render_root($theme_function);
 }
 /**
  * @covers ::setCache
  */
 public function testSetCacheWithSafeStrings()
 {
     SafeMarkup::set('a_safe_string');
     $form_build_id = 'the_form_build_id';
     $form = ['#form_id' => 'the_form_id'];
     $form_state = new FormState();
     $this->formCacheStore->expects($this->once())->method('setWithExpire')->with($form_build_id, $form, $this->isType('int'));
     $form_state_data = $form_state->getCacheableArray();
     $form_state_data['build_info']['safe_strings'] = ['a_safe_string' => ['html' => TRUE]];
     $this->formStateCacheStore->expects($this->once())->method('setWithExpire')->with($form_build_id, $form_state_data, $this->isType('int'));
     $this->formCache->setCache($form_build_id, $form, $form_state);
 }
 /**
  * Render a field using advanced settings.
  *
  * This renders a field normally, then decides if render-as-link and
  * text-replacement rendering is necessary.
  *
  * @param \Drupal\views\ResultRow $values
  *   The values retrieved from a single row of a view's query result.
  */
 public function advancedRender(ResultRow $values)
 {
     if ($this->allowAdvancedRender() && method_exists($this, 'render_item')) {
         $raw_items = $this->getItems($values);
         // If there are no items, set the original value to NULL.
         if (empty($raw_items)) {
             $this->original_value = NULL;
         }
     } else {
         $value = $this->render($values);
         if (is_array($value)) {
             $value = drupal_render($value);
         }
         $this->last_render = $value;
         $this->original_value = $value;
     }
     if ($this->allowAdvancedRender()) {
         $tokens = NULL;
         if (method_exists($this, 'render_item')) {
             $items = array();
             foreach ($raw_items as $count => $item) {
                 $value = $this->render_item($count, $item);
                 if (is_array($value)) {
                     $value = drupal_render($value);
                 }
                 $this->last_render = $value;
                 $this->original_value = $this->last_render;
                 $alter = $item + $this->options['alter'];
                 $alter['phase'] = static::RENDER_TEXT_PHASE_SINGLE_ITEM;
                 $items[] = $this->renderText($alter);
             }
             $value = $this->renderItems($items);
         } else {
             $alter = array('phase' => static::RENDER_TEXT_PHASE_COMPLETELY) + $this->options['alter'];
             $value = $this->renderText($alter);
         }
         if (is_array($value)) {
             $value = drupal_render($value);
         }
         // This happens here so that renderAsLink can get the unaltered value of
         // this field as a token rather than the altered value.
         $this->last_render = $value;
     }
     if (empty($this->last_render)) {
         if ($this->isValueEmpty($this->last_render, $this->options['empty_zero'], FALSE)) {
             $alter = $this->options['alter'];
             $alter['alter_text'] = 1;
             $alter['text'] = $this->options['empty'];
             $alter['phase'] = static::RENDER_TEXT_PHASE_EMPTY;
             $this->last_render = $this->renderText($alter);
         }
     }
     // @todo Fix this in https://www.drupal.org/node/2280961
     $this->last_render = SafeMarkup::set($this->last_render);
     return $this->last_render;
 }
 /**
  * Handles any exception as a generic error page for HTML.
  *
  * @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event
  *   The event to process.
  */
 protected function onHtml(GetResponseForExceptionEvent $event)
 {
     $exception = $event->getException();
     $error = Error::decodeException($exception);
     // Display the message if the current error reporting level allows this type
     // of message to be displayed, and unconditionally in update.php.
     if (error_displayable($error)) {
         $class = 'error';
         // If error type is 'User notice' then treat it as debug information
         // instead of an error message.
         // @see debug()
         if ($error['%type'] == 'User notice') {
             $error['%type'] = 'Debug';
             $class = 'status';
         }
         // Attempt to reduce verbosity by removing DRUPAL_ROOT from the file path
         // in the message. This does not happen for (false) security.
         $root_length = strlen(DRUPAL_ROOT);
         if (substr($error['%file'], 0, $root_length) == DRUPAL_ROOT) {
             $error['%file'] = substr($error['%file'], $root_length + 1);
         }
         // Do not translate the string to avoid errors producing more errors.
         unset($error['backtrace']);
         $message = SafeMarkup::format('%type: !message in %function (line %line of %file).', $error);
         // Check if verbose error reporting is on.
         if ($this->getErrorLevel() == ERROR_REPORTING_DISPLAY_VERBOSE) {
             $backtrace_exception = $exception;
             while ($backtrace_exception->getPrevious()) {
                 $backtrace_exception = $backtrace_exception->getPrevious();
             }
             $backtrace = $backtrace_exception->getTrace();
             // First trace is the error itself, already contained in the message.
             // While the second trace is the error source and also contained in the
             // message, the message doesn't contain argument values, so we output it
             // once more in the backtrace.
             array_shift($backtrace);
             // Generate a backtrace containing only scalar argument values. Make
             // sure the backtrace is escaped as it can contain user submitted data.
             $message .= '<pre class="backtrace">' . SafeMarkup::escape(Error::formatBacktrace($backtrace)) . '</pre>';
         }
         drupal_set_message(SafeMarkup::set($message), $class, TRUE);
     }
     $content = $this->t('The website encountered an unexpected error. Please try again later.');
     $response = $this->bareHtmlPageRenderer->renderBarePage(['#markup' => $content], $this->t('Error'), 'maintenance_page');
     if ($exception instanceof HttpExceptionInterface) {
         $response->setStatusCode($exception->getStatusCode());
         $response->headers->add($exception->getHeaders());
     } else {
         $response->setStatusCode(Response::HTTP_INTERNAL_SERVER_ERROR, '500 Service unavailable (with message)');
     }
     $event->setResponse($response);
 }
 /**
  * {@inheritdoc}
  */
 public function buildForm(array $form, array &$form_state, $test_id = NULL)
 {
     $this->buildStatusImageMap();
     // Make sure there are test results to display and a re-run is not being
     // performed.
     $results = array();
     if (is_numeric($test_id) && !($results = $this->getResults($test_id))) {
         drupal_set_message($this->t('No test results to display.'), 'error');
         return new RedirectResponse(url('admin/config/development/testing', array('absolute' => TRUE)));
     }
     // Load all classes and include CSS.
     $form['#attached']['css'][] = drupal_get_path('module', 'simpletest') . '/css/simpletest.module.css';
     // Keep track of which test cases passed or failed.
     $filter = array('pass' => array(), 'fail' => array());
     // Summary result widget.
     $form['result'] = array('#type' => 'fieldset', '#title' => $this->t('Results'));
     $form['result']['summary'] = $summary = array('#theme' => 'simpletest_result_summary', '#pass' => 0, '#fail' => 0, '#exception' => 0, '#debug' => 0);
     simpletest_classloader_register();
     // Cycle through each test group.
     $header = array($this->t('Message'), $this->t('Group'), $this->t('Filename'), $this->t('Line'), $this->t('Function'), array('colspan' => 2, 'data' => $this->t('Status')));
     $form['result']['results'] = array();
     foreach ($results as $group => $assertions) {
         // Create group details with summary information.
         $info = TestDiscovery::getTestInfo(new \ReflectionClass($group));
         $form['result']['results'][$group] = array('#type' => 'details', '#title' => $info['name'], '#open' => TRUE, '#description' => $info['description']);
         $form['result']['results'][$group]['summary'] = $summary;
         $group_summary =& $form['result']['results'][$group]['summary'];
         // Create table of assertions for the group.
         $rows = array();
         foreach ($assertions as $assertion) {
             $row = array();
             // Assertion messages are in code, so we assume they are safe.
             $row[] = SafeMarkup::set($assertion->message);
             $row[] = $assertion->message_group;
             $row[] = drupal_basename($assertion->file);
             $row[] = $assertion->line;
             $row[] = $assertion->function;
             $row[] = $this->statusImageMap[$assertion->status];
             $class = 'simpletest-' . $assertion->status;
             if ($assertion->message_group == 'Debug') {
                 $class = 'simpletest-debug';
             }
             $rows[] = array('data' => $row, 'class' => array($class));
             $group_summary['#' . $assertion->status]++;
             $form['result']['summary']['#' . $assertion->status]++;
         }
         $form['result']['results'][$group]['table'] = array('#type' => 'table', '#header' => $header, '#rows' => $rows);
         // Set summary information.
         $group_summary['#ok'] = $group_summary['#fail'] + $group_summary['#exception'] == 0;
         $form['result']['results'][$group]['#open'] = !$group_summary['#ok'];
         // Store test group (class) as for use in filter.
         $filter[$group_summary['#ok'] ? 'pass' : 'fail'][] = $group;
     }
     // Overall summary status.
     $form['result']['summary']['#ok'] = $form['result']['summary']['#fail'] + $form['result']['summary']['#exception'] == 0;
     // Actions.
     $form['#action'] = url('admin/config/development/testing/results/re-run');
     $form['action'] = array('#type' => 'fieldset', '#title' => $this->t('Actions'), '#attributes' => array('class' => array('container-inline')), '#weight' => -11);
     $form['action']['filter'] = array('#type' => 'select', '#title' => 'Filter', '#options' => array('all' => $this->t('All (@count)', array('@count' => count($filter['pass']) + count($filter['fail']))), 'pass' => $this->t('Pass (@count)', array('@count' => count($filter['pass']))), 'fail' => $this->t('Fail (@count)', array('@count' => count($filter['fail'])))));
     $form['action']['filter']['#default_value'] = $filter['fail'] ? 'fail' : 'all';
     // Categorized test classes for to be used with selected filter value.
     $form['action']['filter_pass'] = array('#type' => 'hidden', '#default_value' => implode(',', $filter['pass']));
     $form['action']['filter_fail'] = array('#type' => 'hidden', '#default_value' => implode(',', $filter['fail']));
     $form['action']['op'] = array('#type' => 'submit', '#value' => $this->t('Run tests'));
     $form['action']['return'] = array('#type' => 'link', '#title' => $this->t('Return to list'), '#href' => 'admin/config/development/testing');
     if (is_numeric($test_id)) {
         simpletest_clean_results_table($test_id);
     }
     return $form;
 }
 /**
  * Processes a generic exception into an HTTP 500 response.
  *
  * @param \Symfony\Component\Debug\Exception\FlattenException $exception
  *   Metadata about the exception that was thrown.
  * @param \Symfony\Component\HttpFoundation\Request $request
  *   The request object that triggered this exception.
  *
  * @return \Symfony\Component\HttpFoundation\Response
  *   A response object.
  */
 public function on500Html(FlattenException $exception, Request $request)
 {
     $error = $this->decodeException($exception);
     // Because the kernel doesn't run until full bootstrap, we know that
     // most subsystems are already initialized.
     $headers = array();
     // When running inside the testing framework, we relay the errors
     // to the tested site by the way of HTTP headers.
     if (DRUPAL_TEST_IN_CHILD_SITE && !headers_sent() && (!defined('SIMPLETEST_COLLECT_ERRORS') || SIMPLETEST_COLLECT_ERRORS)) {
         // $number does not use drupal_static as it should not be reset
         // as it uniquely identifies each PHP error.
         static $number = 0;
         $assertion = array($error['!message'], $error['%type'], array('function' => $error['%function'], 'file' => $error['%file'], 'line' => $error['%line']));
         $headers['X-Drupal-Assertion-' . $number] = rawurlencode(serialize($assertion));
         $number++;
     }
     watchdog('php', '%type: !message in %function (line %line of %file).', $error, $error['severity_level']);
     // Display the message if the current error reporting level allows this type
     // of message to be displayed, and unconditionnaly in update.php.
     if (error_displayable($error)) {
         $class = 'error';
         // If error type is 'User notice' then treat it as debug information
         // instead of an error message.
         // @see debug()
         if ($error['%type'] == 'User notice') {
             $error['%type'] = 'Debug';
             $class = 'status';
         }
         // Attempt to reduce verbosity by removing DRUPAL_ROOT from the file path
         // in the message. This does not happen for (false) security.
         $root_length = strlen(DRUPAL_ROOT);
         if (substr($error['%file'], 0, $root_length) == DRUPAL_ROOT) {
             $error['%file'] = substr($error['%file'], $root_length + 1);
         }
         // Should not translate the string to avoid errors producing more errors.
         $message = String::format('%type: !message in %function (line %line of %file).', $error);
         // Check if verbose error reporting is on.
         $error_level = $this->container->get('config.factory')->get('system.logging')->get('error_level');
         if ($error_level == ERROR_REPORTING_DISPLAY_VERBOSE) {
             $backtrace_exception = $exception;
             while ($backtrace_exception->getPrevious()) {
                 $backtrace_exception = $backtrace_exception->getPrevious();
             }
             $backtrace = $backtrace_exception->getTrace();
             // First trace is the error itself, already contained in the message.
             // While the second trace is the error source and also contained in the
             // message, the message doesn't contain argument values, so we output it
             // once more in the backtrace.
             array_shift($backtrace);
             // Generate a backtrace containing only scalar argument values.
             $message .= '<pre class="backtrace">' . Error::formatFlattenedBacktrace($backtrace) . '</pre>';
         }
         drupal_set_message(SafeMarkup::set($message), $class, TRUE);
     }
     $content = $this->t('The website has encountered an error. Please try again later.');
     $output = DefaultHtmlPageRenderer::renderPage($content, $this->t('Error'));
     $response = new Response($output);
     $response->setStatusCode(500, '500 Service unavailable (with message)');
     return $response;
 }
Exemple #26
0
 /**
  * See the docs for ::render().
  */
 protected function doRender(&$elements, $is_root_call = FALSE)
 {
     if (!isset($elements['#access']) && isset($elements['#access_callback'])) {
         if (is_string($elements['#access_callback']) && strpos($elements['#access_callback'], '::') === FALSE) {
             $elements['#access_callback'] = $this->controllerResolver->getControllerFromDefinition($elements['#access_callback']);
         }
         $elements['#access'] = call_user_func($elements['#access_callback'], $elements);
     }
     // Early-return nothing if user does not have access.
     if (empty($elements) || isset($elements['#access']) && !$elements['#access']) {
         return '';
     }
     // Do not print elements twice.
     if (!empty($elements['#printed'])) {
         return '';
     }
     if (!isset(static::$stack)) {
         static::$stack = new \SplStack();
     }
     static::$stack->push(new BubbleableMetadata());
     // Set the bubbleable rendering metadata that has configurable defaults, if:
     // - this is the root call, to ensure that the final render array definitely
     //   has these configurable defaults, even when no subtree is render cached.
     // - this is a render cacheable subtree, to ensure that the cached data has
     //   the configurable defaults (which may affect the ID and invalidation).
     if ($is_root_call || isset($elements['#cache']['keys'])) {
         $required_cache_contexts = $this->rendererConfig['required_cache_contexts'];
         if (isset($elements['#cache']['contexts'])) {
             $elements['#cache']['contexts'] = Cache::mergeContexts($elements['#cache']['contexts'], $required_cache_contexts);
         } else {
             $elements['#cache']['contexts'] = $required_cache_contexts;
         }
     }
     // Try to fetch the prerendered element from cache, run any
     // #post_render_cache callbacks and return the final markup.
     if (isset($elements['#cache']['keys'])) {
         $cached_element = $this->renderCache->get($elements);
         if ($cached_element !== FALSE) {
             $elements = $cached_element;
             // Only when we're not in a root (non-recursive) drupal_render() call,
             // #post_render_cache callbacks must be executed, to prevent breaking
             // the render cache in case of nested elements with #cache set.
             if ($is_root_call) {
                 $this->processPostRenderCache($elements);
             }
             // Mark the element markup as safe. If we have cached children, we need
             // to mark them as safe too. The parent markup contains the child
             // markup, so if the parent markup is safe, then the markup of the
             // individual children must be safe as well.
             $elements['#markup'] = SafeMarkup::set($elements['#markup']);
             if (!empty($elements['#cache_properties'])) {
                 foreach (Element::children($cached_element) as $key) {
                     SafeMarkup::set($cached_element[$key]['#markup']);
                 }
             }
             // The render cache item contains all the bubbleable rendering metadata
             // for the subtree.
             $this->updateStack($elements);
             // Render cache hit, so rendering is finished, all necessary info
             // collected!
             $this->bubbleStack();
             return $elements['#markup'];
         }
     }
     // Two-tier caching: track pre-bubbling elements' #cache for later
     // comparison.
     // @see \Drupal\Core\Render\RenderCacheInterface::get()
     // @see \Drupal\Core\Render\RenderCacheInterface::set()
     $pre_bubbling_elements = [];
     $pre_bubbling_elements['#cache'] = isset($elements['#cache']) ? $elements['#cache'] : [];
     // If the default values for this element have not been loaded yet, populate
     // them.
     if (isset($elements['#type']) && empty($elements['#defaults_loaded'])) {
         $elements += $this->elementInfo->getInfo($elements['#type']);
     }
     // Make any final changes to the element before it is rendered. This means
     // that the $element or the children can be altered or corrected before the
     // element is rendered into the final text.
     if (isset($elements['#pre_render'])) {
         foreach ($elements['#pre_render'] as $callable) {
             if (is_string($callable) && strpos($callable, '::') === FALSE) {
                 $callable = $this->controllerResolver->getControllerFromDefinition($callable);
             }
             $elements = call_user_func($callable, $elements);
         }
     }
     // Defaults for bubbleable rendering metadata.
     $elements['#cache']['tags'] = isset($elements['#cache']['tags']) ? $elements['#cache']['tags'] : array();
     $elements['#cache']['max-age'] = isset($elements['#cache']['max-age']) ? $elements['#cache']['max-age'] : Cache::PERMANENT;
     $elements['#attached'] = isset($elements['#attached']) ? $elements['#attached'] : array();
     $elements['#post_render_cache'] = isset($elements['#post_render_cache']) ? $elements['#post_render_cache'] : array();
     // Allow #pre_render to abort rendering.
     if (!empty($elements['#printed'])) {
         // The #printed element contains all the bubbleable rendering metadata for
         // the subtree.
         $this->updateStack($elements);
         // #printed, so rendering is finished, all necessary info collected!
         $this->bubbleStack();
         return '';
     }
     // Add any JavaScript state information associated with the element.
     if (!empty($elements['#states'])) {
         drupal_process_states($elements);
     }
     // Get the children of the element, sorted by weight.
     $children = Element::children($elements, TRUE);
     // Initialize this element's #children, unless a #pre_render callback
     // already preset #children.
     if (!isset($elements['#children'])) {
         $elements['#children'] = '';
     }
     // @todo Simplify after https://www.drupal.org/node/2273925.
     if (isset($elements['#markup'])) {
         $elements['#markup'] = SafeMarkup::set($elements['#markup']);
     }
     // Assume that if #theme is set it represents an implemented hook.
     $theme_is_implemented = isset($elements['#theme']);
     // Check the elements for insecure HTML and pass through sanitization.
     if (isset($elements)) {
         $markup_keys = array('#description', '#field_prefix', '#field_suffix');
         foreach ($markup_keys as $key) {
             if (!empty($elements[$key]) && is_scalar($elements[$key])) {
                 $elements[$key] = SafeMarkup::checkAdminXss($elements[$key]);
             }
         }
     }
     // Call the element's #theme function if it is set. Then any children of the
     // element have to be rendered there. If the internal #render_children
     // property is set, do not call the #theme function to prevent infinite
     // recursion.
     if ($theme_is_implemented && !isset($elements['#render_children'])) {
         $elements['#children'] = $this->theme->render($elements['#theme'], $elements);
         // If ThemeManagerInterface::render() returns FALSE this means that the
         // hook in #theme was not found in the registry and so we need to update
         // our flag accordingly. This is common for theme suggestions.
         $theme_is_implemented = $elements['#children'] !== FALSE;
     }
     // If #theme is not implemented or #render_children is set and the element
     // has an empty #children attribute, render the children now. This is the
     // same process as Renderer::render() but is inlined for speed.
     if ((!$theme_is_implemented || isset($elements['#render_children'])) && empty($elements['#children'])) {
         foreach ($children as $key) {
             $elements['#children'] .= $this->doRender($elements[$key]);
         }
         $elements['#children'] = SafeMarkup::set($elements['#children']);
     }
     // If #theme is not implemented and the element has raw #markup as a
     // fallback, prepend the content in #markup to #children. In this case
     // #children will contain whatever is provided by #pre_render prepended to
     // what is rendered recursively above. If #theme is implemented then it is
     // the responsibility of that theme implementation to render #markup if
     // required. Eventually #theme_wrappers will expect both #markup and
     // #children to be a single string as #children.
     if (!$theme_is_implemented && isset($elements['#markup'])) {
         $elements['#children'] = SafeMarkup::set($elements['#markup'] . $elements['#children']);
     }
     // Let the theme functions in #theme_wrappers add markup around the rendered
     // children.
     // #states and #attached have to be processed before #theme_wrappers,
     // because the #type 'page' render array from drupal_prepare_page() would
     // render the $page and wrap it into the html.html.twig template without the
     // attached assets otherwise.
     // If the internal #render_children property is set, do not call the
     // #theme_wrappers function(s) to prevent infinite recursion.
     if (isset($elements['#theme_wrappers']) && !isset($elements['#render_children'])) {
         foreach ($elements['#theme_wrappers'] as $key => $value) {
             // If the value of a #theme_wrappers item is an array then the theme
             // hook is found in the key of the item and the value contains attribute
             // overrides. Attribute overrides replace key/value pairs in $elements
             // for only this ThemeManagerInterface::render() call. This allows
             // #theme hooks and #theme_wrappers hooks to share variable names
             // without conflict or ambiguity.
             $wrapper_elements = $elements;
             if (is_string($key)) {
                 $wrapper_hook = $key;
                 foreach ($value as $attribute => $override) {
                     $wrapper_elements[$attribute] = $override;
                 }
             } else {
                 $wrapper_hook = $value;
             }
             $elements['#children'] = $this->theme->render($wrapper_hook, $wrapper_elements);
         }
     }
     // Filter the outputted content and make any last changes before the content
     // is sent to the browser. The changes are made on $content which allows the
     // outputted text to be filtered.
     if (isset($elements['#post_render'])) {
         foreach ($elements['#post_render'] as $callable) {
             if (is_string($callable) && strpos($callable, '::') === FALSE) {
                 $callable = $this->controllerResolver->getControllerFromDefinition($callable);
             }
             $elements['#children'] = call_user_func($callable, $elements['#children'], $elements);
         }
     }
     // We store the resulting output in $elements['#markup'], to be consistent
     // with how render cached output gets stored. This ensures that
     // #post_render_cache callbacks get the same data to work with, no matter if
     // #cache is disabled, #cache is enabled, there is a cache hit or miss.
     $prefix = isset($elements['#prefix']) ? SafeMarkup::checkAdminXss($elements['#prefix']) : '';
     $suffix = isset($elements['#suffix']) ? SafeMarkup::checkAdminXss($elements['#suffix']) : '';
     $elements['#markup'] = $prefix . $elements['#children'] . $suffix;
     // We've rendered this element (and its subtree!), now update the stack.
     $this->updateStack($elements);
     // Cache the processed element if both $pre_bubbling_elements and $elements
     // have the metadata necessary to generate a cache ID.
     if (isset($pre_bubbling_elements['#cache']['keys']) && isset($elements['#cache']['keys'])) {
         if ($pre_bubbling_elements['#cache']['keys'] !== $elements['#cache']['keys']) {
             throw new \LogicException('Cache keys may not be changed after initial setup. Use the contexts property instead to bubble additional metadata.');
         }
         $this->renderCache->set($elements, $pre_bubbling_elements);
     }
     // Only when we're in a root (non-recursive) drupal_render() call,
     // #post_render_cache callbacks must be executed, to prevent breaking the
     // render cache in case of nested elements with #cache set.
     //
     // By running them here, we ensure that:
     // - they run when #cache is disabled,
     // - they run when #cache is enabled and there is a cache miss.
     // Only the case of a cache hit when #cache is enabled, is not handled here,
     // that is handled earlier in Renderer::render().
     if ($is_root_call) {
         // We've already called ::updateStack() earlier, which updated both the
         // element and current stack frame. However,
         // Renderer::processPostRenderCache() can both change the element
         // further and create and render new child elements, so provide a fresh
         // stack frame to collect those additions, merge them back to the element,
         // and then update the current frame to match the modified element state.
         do {
             static::$stack->push(new BubbleableMetadata());
             $this->processPostRenderCache($elements);
             $post_render_additions = static::$stack->pop();
             $elements['#post_render_cache'] = NULL;
             BubbleableMetadata::createFromRenderArray($elements)->merge($post_render_additions)->applyTo($elements);
         } while (!empty($elements['#post_render_cache']));
         if (static::$stack->count() !== 1) {
             throw new \LogicException('A stray drupal_render() invocation with $is_root_call = TRUE is causing bubbling of attached assets to break.');
         }
     }
     // Rendering is finished, all necessary info collected!
     $this->bubbleStack();
     $elements['#printed'] = TRUE;
     $elements['#markup'] = SafeMarkup::set($elements['#markup']);
     return $elements['#markup'];
 }
Exemple #27
0
 /**
  * @covers ::setCache
  */
 public function testSetCacheWithSafeStrings()
 {
     // A call to SafeMarkup::set() is appropriate in this test as a way to add a
     // string to the safe list in the simplest way possible. Normally, avoid it.
     SafeMarkup::set('a_safe_string');
     $form_build_id = 'the_form_build_id';
     $form = ['#form_id' => 'the_form_id'];
     $form_state = new FormState();
     $this->formCacheStore->expects($this->once())->method('setWithExpire')->with($form_build_id, $form, $this->isType('int'));
     $form_state_data = $form_state->getCacheableArray();
     $form_state_data['build_info']['safe_strings'] = ['a_safe_string' => ['html' => TRUE]];
     $this->formStateCacheStore->expects($this->once())->method('setWithExpire')->with($form_build_id, $form_state_data, $this->isType('int'));
     $this->formCache->setCache($form_build_id, $form, $form_state);
 }
Exemple #28
0
 /**
  * Displays a listing of database log messages.
  *
  * Messages are truncated at 56 chars.
  * Full-length messages can be viewed on the message details page.
  *
  * @return array
  *   A render array as expected by drupal_render().
  *
  * @see dblog_clear_log_form()
  * @see dblog_event()
  */
 public function overview()
 {
     $filter = $this->buildFilterQuery();
     $rows = array();
     $classes = static::getLogLevelClassMap();
     $this->moduleHandler->loadInclude('dblog', 'admin.inc');
     $build['dblog_filter_form'] = $this->formBuilder->getForm('Drupal\\dblog\\Form\\DblogFilterForm');
     $build['dblog_clear_log_form'] = $this->formBuilder->getForm('Drupal\\dblog\\Form\\DblogClearLogForm');
     $header = array('', array('data' => $this->t('Type'), 'field' => 'w.type', 'class' => array(RESPONSIVE_PRIORITY_MEDIUM)), array('data' => $this->t('Date'), 'field' => 'w.wid', 'sort' => 'desc', 'class' => array(RESPONSIVE_PRIORITY_LOW)), $this->t('Message'), array('data' => $this->t('User'), 'field' => 'ufd.name', 'class' => array(RESPONSIVE_PRIORITY_MEDIUM)), array('data' => $this->t('Operations'), 'class' => array(RESPONSIVE_PRIORITY_LOW)));
     $query = $this->database->select('watchdog', 'w')->extend('\\Drupal\\Core\\Database\\Query\\PagerSelectExtender')->extend('\\Drupal\\Core\\Database\\Query\\TableSortExtender');
     $query->fields('w', array('wid', 'uid', 'severity', 'type', 'timestamp', 'message', 'variables', 'link'));
     $query->leftJoin('users_field_data', 'ufd', 'w.uid = ufd.uid');
     if (!empty($filter['where'])) {
         $query->where($filter['where'], $filter['args']);
     }
     $result = $query->limit(50)->orderByHeader($header)->execute();
     foreach ($result as $dblog) {
         $message = $this->formatMessage($dblog);
         if ($message && isset($dblog->wid)) {
             // Truncate link_text to 56 chars of message.
             // @todo Reevaluate the SafeMarkup::set() in
             //   https://www.drupal.org/node/2399261.
             $log_text = SafeMarkup::set(Unicode::truncate(Xss::filter($message, array()), 56, TRUE, TRUE));
             $message = $this->l($log_text, new Url('dblog.event', array('event_id' => $dblog->wid), array('attributes' => array('title' => Unicode::truncate(strip_tags($message), 256, TRUE, TRUE)))));
         }
         $username = array('#theme' => 'username', '#account' => $this->userStorage->load($dblog->uid));
         $rows[] = array('data' => array(array('class' => array('icon')), $this->t($dblog->type), $this->dateFormatter->format($dblog->timestamp, 'short'), $message, array('data' => $username), Xss::filter($dblog->link)), 'class' => array(Html::getClass('dblog-' . $dblog->type), $classes[$dblog->severity]));
     }
     $build['dblog_table'] = array('#type' => 'table', '#header' => $header, '#rows' => $rows, '#attributes' => array('id' => 'admin-dblog', 'class' => array('admin-dblog')), '#empty' => $this->t('No log messages available.'), '#attached' => array('library' => array('dblog/drupal.dblog')));
     $build['dblog_pager'] = array('#type' => 'pager');
     return $build;
 }
Exemple #29
0
 /**
  * Prepares search results for rendering.
  *
  * @param \Drupal\Core\Database\StatementInterface $found
  *   Results found from a successful search query execute() method.
  *
  * @return array
  *   Array of search result item render arrays (empty array if no results).
  */
 protected function prepareResults(StatementInterface $found)
 {
     $results = array();
     $node_storage = $this->entityManager->getStorage('node');
     $node_render = $this->entityManager->getViewBuilder('node');
     $keys = $this->keywords;
     foreach ($found as $item) {
         // Render the node.
         /** @var \Drupal\node\NodeInterface $node */
         $node = $node_storage->load($item->sid)->getTranslation($item->langcode);
         $build = $node_render->view($node, 'search_result', $item->langcode);
         /** @var \Drupal\node\NodeTypeInterface $type*/
         $type = $this->entityManager->getStorage('node_type')->load($node->bundle());
         unset($build['#theme']);
         $build['#pre_render'][] = array($this, 'removeSubmittedInfo');
         // Fetch comment count for snippet.
         $rendered = SafeMarkup::set($this->renderer->renderPlain($build) . ' ' . SafeMarkup::escape($this->moduleHandler->invoke('comment', 'node_update_index', array($node, $item->langcode))));
         $extra = $this->moduleHandler->invokeAll('node_search_result', array($node, $item->langcode));
         $language = $this->languageManager->getLanguage($item->langcode);
         $username = array('#theme' => 'username', '#account' => $node->getOwner());
         $result = array('link' => $node->url('canonical', array('absolute' => TRUE, 'language' => $language)), 'type' => SafeMarkup::checkPlain($type->label()), 'title' => $node->label(), 'node' => $node, 'extra' => $extra, 'score' => $item->calculated_score, 'snippet' => search_excerpt($keys, $rendered, $item->langcode), 'langcode' => $node->language()->getId());
         if ($type->displaySubmitted()) {
             $result += array('user' => $this->renderer->renderPlain($username), 'date' => $node->getChangedTime());
         }
         $results[] = $result;
     }
     return $results;
 }
Exemple #30
0
 public function renderPreview($display_id, $args = array())
 {
     // Save the current path so it can be restored before returning from this function.
     $old_q = current_path();
     // Determine where the query and performance statistics should be output.
     $config = \Drupal::config('views.settings');
     $show_query = $config->get('ui.show.sql_query.enabled');
     $show_info = $config->get('ui.show.preview_information');
     $show_location = $config->get('ui.show.sql_query.where');
     $show_stats = $config->get('ui.show.performance_statistics');
     if ($show_stats) {
         $show_stats = $config->get('ui.show.sql_query.where');
     }
     $combined = $show_query && $show_stats;
     $rows = array('query' => array(), 'statistics' => array());
     $output = '';
     $errors = $this->executable->validate();
     $this->executable->destroy();
     if (empty($errors)) {
         $this->ajax = TRUE;
         $this->executable->live_preview = TRUE;
         // AJAX happens via HTTP POST but everything expects exposed data to
         // be in GET. Copy stuff but remove ajax-framework specific keys.
         // If we're clicking on links in a preview, though, we could actually
         // have some input in the query parameters, so we merge request() and
         // query() to ensure we get it all.
         $exposed_input = array_merge(\Drupal::request()->request->all(), \Drupal::request()->query->all());
         foreach (array('view_name', 'view_display_id', 'view_args', 'view_path', 'view_dom_id', 'pager_element', 'view_base_path', 'ajax_html_ids', 'ajax_page_state', 'form_id', 'form_build_id', 'form_token') as $key) {
             if (isset($exposed_input[$key])) {
                 unset($exposed_input[$key]);
             }
         }
         $this->executable->setExposedInput($exposed_input);
         if (!$this->executable->setDisplay($display_id)) {
             return t('Invalid display id @display', array('@display' => $display_id));
         }
         $this->executable->setArguments($args);
         // Store the current view URL for later use:
         if ($this->executable->display_handler->getOption('path')) {
             $path = $this->executable->getUrl();
         }
         // Make view links come back to preview.
         $this->override_path = 'admin/structure/views/view/' . $this->id() . '/preview/' . $display_id;
         // Also override the current path so we get the pager.
         $original_path = current_path();
         $q = _current_path($this->override_path);
         if ($args) {
             $q .= '/' . implode('/', $args);
             _current_path($q);
         }
         // Suppress contextual links of entities within the result set during a
         // Preview.
         // @todo We'll want to add contextual links specific to editing the View, so
         //   the suppression may need to be moved deeper into the Preview pipeline.
         views_ui_contextual_links_suppress_push();
         $show_additional_queries = $config->get('ui.show.additional_queries');
         Timer::start('entity.view.preview_form');
         if ($show_additional_queries) {
             $this->startQueryCapture();
         }
         // Execute/get the view preview.
         $preview = $this->executable->preview($display_id, $args);
         $preview = drupal_render($preview);
         if ($show_additional_queries) {
             $this->endQueryCapture();
         }
         $this->render_time = Timer::stop('entity.view.preview_form');
         views_ui_contextual_links_suppress_pop();
         // Reset variables.
         unset($this->override_path);
         _current_path($original_path);
         // Prepare the query information and statistics to show either above or
         // below the view preview.
         if ($show_info || $show_query || $show_stats) {
             // Get information from the preview for display.
             if (!empty($this->executable->build_info['query'])) {
                 if ($show_query) {
                     $query_string = $this->executable->build_info['query'];
                     // Only the sql default class has a method getArguments.
                     $quoted = array();
                     if ($this->executable->query instanceof Sql) {
                         $quoted = $query_string->getArguments();
                         $connection = Database::getConnection();
                         foreach ($quoted as $key => $val) {
                             if (is_array($val)) {
                                 $quoted[$key] = implode(', ', array_map(array($connection, 'quote'), $val));
                             } else {
                                 $quoted[$key] = $connection->quote($val);
                             }
                         }
                     }
                     $rows['query'][] = array(array('data' => array('#type' => 'inline_template', '#template' => "<strong>{% trans 'Query' %}</strong>")), array('data' => array('#type' => 'inline_template', '#template' => '<pre>{{ query }}</pre>', '#context' => array('query' => strtr($query_string, $quoted)))));
                     if (!empty($this->additionalQueries)) {
                         $queries = '<strong>' . t('These queries were run during view rendering:') . '</strong>';
                         foreach ($this->additionalQueries as $query) {
                             if ($queries) {
                                 $queries .= "\n";
                             }
                             $query_string = strtr($query['query'], $query['args']);
                             $queries .= t('[@time ms] @query', array('@time' => round($query['time'] * 100000, 1) / 100000.0, '@query' => $query_string));
                         }
                         $rows['query'][] = array(array('data' => array('#type' => 'inline_template', '#template' => "<strong>{% trans 'Other queries' %}</strong>")), SafeMarkup::set('<pre>' . $queries . '</pre>'));
                     }
                 }
                 if ($show_info) {
                     $rows['query'][] = array(array('data' => array('#type' => 'inline_template', '#template' => "<strong>{% trans 'Title' %}</strong>")), Xss::filterAdmin($this->executable->getTitle()));
                     if (isset($path)) {
                         $path = _l($path, $path);
                     } else {
                         $path = t('This display has no path.');
                     }
                     $rows['query'][] = array(SafeMarkup::set('<strong>' . t('Path') . '</strong>'), $path);
                 }
                 if ($show_stats) {
                     $rows['statistics'][] = array('<strong>' . t('Query build time') . '</strong>', t('@time ms', array('@time' => intval($this->executable->build_time * 100000) / 100)));
                     $rows['statistics'][] = array('<strong>' . t('Query execute time') . '</strong>', t('@time ms', array('@time' => intval($this->executable->execute_time * 100000) / 100)));
                     $rows['statistics'][] = array('<strong>' . t('View render time') . '</strong>', t('@time ms', array('@time' => intval($this->executable->render_time * 100000) / 100)));
                 }
                 \Drupal::moduleHandler()->alter('views_preview_info', $rows, $this->executable);
             } else {
                 // No query was run. Display that information in place of either the
                 // query or the performance statistics, whichever comes first.
                 if ($combined || $show_location === 'above') {
                     $rows['query'] = array(array(SafeMarkup::set('<strong>' . t('Query') . '</strong>'), t('No query was run')));
                 } else {
                     $rows['statistics'] = array(array(SafeMarkup::set('<strong>' . t('Query') . '</strong>'), t('No query was run')));
                 }
             }
         }
     } else {
         foreach ($errors as $display_errors) {
             foreach ($display_errors as $error) {
                 drupal_set_message($error, 'error');
             }
         }
         $preview = t('Unable to preview due to validation errors.');
     }
     // Assemble the preview, the query info, and the query statistics in the
     // requested order.
     $table = array('#type' => 'table', '#prefix' => '<div class="views-query-info">', '#suffix' => '</div>');
     if ($show_location === 'above' || $show_location === 'below') {
         if ($combined) {
             $table['#rows'] = array_merge($rows['query'], $rows['statistics']);
         } else {
             $table['#rows'] = $rows['query'];
         }
     } elseif ($show_stats === 'above' || $show_stats === 'below') {
         $table['#rows'] = $rows['statistics'];
     }
     if ($show_location === 'above' || $show_stats === 'above') {
         $output .= drupal_render($table) . $preview;
     } elseif ($show_location === 'below' || $show_stats === 'below') {
         $output .= $preview . drupal_render($table);
     }
     _current_path($old_q);
     return $output;
 }