BigPipe::sendPlaceholders

protected BigPipe::sendPlaceholders(array $placeholders, array $placeholder_order, AttachedAssetsInterface $cumulative_assets)

Sends BigPipe placeholders' replacements as embedded AJAX responses.

Parameters

array $placeholders: Associative array; the BigPipe placeholders. Keys are the BigPipe placeholder IDs.

array $placeholder_order: Indexed array; the order in which the BigPipe placeholders must be sent. Values are the BigPipe placeholder IDs. (These values correspond to keys in $placeholders.)

\Drupal\Core\Asset\AttachedAssetsInterface $cumulative_assets: The cumulative assets sent so far; to be updated while rendering BigPipe placeholders.

Throws

\Exception If an exception is thrown during the rendering of a placeholder, it is caught to allow the other placeholders to still be replaced. But when error logging is configured to be verbose, the exception is rethrown to simplify debugging.

File

core/modules/big_pipe/src/Render/BigPipe.php, line 365

Class

BigPipe
The default BigPipe service.

Namespace

Drupal\big_pipe\Render

Code

protected function sendPlaceholders(array $placeholders, array $placeholder_order, AttachedAssetsInterface $cumulative_assets) {
  // Return early if there are no BigPipe placeholders to send.
  if (empty($placeholders)) {
    return;
  }

  // Send the start signal.
  print "\n";
  print static::START_SIGNAL;
  print "\n";
  flush();

  // A BigPipe response consists of a HTML response plus multiple embedded
  // AJAX responses. To process the attachments of those AJAX responses, we
  // need a fake request that is identical to the master request, but with
  // one change: it must have the right Accept header, otherwise the work-
  // around for a bug in IE9 will cause not JSON, but <textarea>-wrapped JSON
  // to be returned.
  // @see \Drupal\Core\EventSubscriber\AjaxResponseSubscriber::onResponse()
  $fake_request = $this->requestStack->getMasterRequest()->duplicate();
  $fake_request->headers->set('Accept', 'application/vnd.drupal-ajax');

  foreach ($placeholder_order as $placeholder_id) {
    if (!isset($placeholders[$placeholder_id])) {
      continue;
    }

    // Render the placeholder.
    $placeholder_render_array = $placeholders[$placeholder_id];
    try {
      $elements = $this->renderPlaceholder($placeholder_id, $placeholder_render_array);
    }
    catch (\Exception $e) {
      if ($this->configFactory->get('system.logging')->get('error_level') === ERROR_REPORTING_DISPLAY_VERBOSE) {
        throw $e;
      }
      else {
        trigger_error($e, E_USER_ERROR);
        continue;
      }
    }

    // Create a new AjaxResponse.
    $ajax_response = new AjaxResponse();
    // JavaScript's querySelector automatically decodes HTML entities in
    // attributes, so we must decode the entities of the current BigPipe
    // placeholder ID (which has HTML entities encoded since we use it to find
    // the placeholders).
    $big_pipe_js_placeholder_id = Html::decodeEntities($placeholder_id);
    $ajax_response->addCommand(new ReplaceCommand(sprintf('[data-big-pipe-placeholder-id="%s"]', $big_pipe_js_placeholder_id), $elements['#markup']));
    $ajax_response->setAttachments($elements['#attached']);

    // Push a fake request with the asset libraries loaded so far and dispatch
    // KernelEvents::RESPONSE event. This results in the attachments for the
    // AJAX response being processed by AjaxResponseAttachmentsProcessor and
    // hence:
    // - the necessary AJAX commands to load the necessary missing asset
    //   libraries and updated AJAX page state are added to the AJAX response
    // - the attachments associated with the response are finalized, which
    //   allows us to track the total set of asset libraries sent in the
    //   initial HTML response plus all embedded AJAX responses sent so far.
    $fake_request->request->set('ajax_page_state', ['libraries' => implode(',', $cumulative_assets->getAlreadyLoadedLibraries())] + $cumulative_assets->getSettings()['ajaxPageState']);
    try {
      $ajax_response = $this->filterEmbeddedResponse($fake_request, $ajax_response);
    }
    catch (\Exception $e) {
      if ($this->configFactory->get('system.logging')->get('error_level') === ERROR_REPORTING_DISPLAY_VERBOSE) {
        throw $e;
      }
      else {
        trigger_error($e, E_USER_ERROR);
        continue;
      }
    }

    // Send this embedded AJAX response.
    $json = $ajax_response->getContent();
    $output = <<<EOF
    <script type="application/vnd.drupal-ajax" data-big-pipe-replacement-for-placeholder-with-id="$placeholder_id">
    $json
    </script>
EOF;
    print $output;
    flush();

    // Another placeholder was rendered and sent, track the set of asset
    // libraries sent so far. Any new settings are already sent; we don't need
    // to track those.
    if (isset($ajax_response->getAttachments()['drupalSettings']['ajaxPageState']['libraries'])) {
      $cumulative_assets->setAlreadyLoadedLibraries(explode(',', $ajax_response->getAttachments()['drupalSettings']['ajaxPageState']['libraries']));
    }
  }

  // Send the stop signal.
  print "\n";
  print static::STOP_SIGNAL;
  print "\n";
  flush();
}
doc_Drupal
2016-10-29 08:46:14
Comments
Leave a Comment

Please login to continue.