annotate core/modules/big_pipe/src/EventSubscriber/HtmlResponseBigPipeSubscriber.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 4c8ae668cc8c
children
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 namespace Drupal\big_pipe\EventSubscriber;
Chris@0 4
Chris@0 5 use Drupal\Core\Render\HtmlResponse;
Chris@0 6 use Drupal\big_pipe\Render\BigPipe;
Chris@0 7 use Drupal\big_pipe\Render\BigPipeResponse;
Chris@0 8 use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
Chris@0 9 use Symfony\Component\HttpKernel\KernelEvents;
Chris@0 10 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
Chris@0 11
Chris@0 12 /**
Chris@0 13 * Response subscriber to replace the HtmlResponse with a BigPipeResponse.
Chris@0 14 *
Chris@0 15 * @see \Drupal\big_pipe\Render\BigPipe
Chris@0 16 *
Chris@0 17 * @todo Refactor once https://www.drupal.org/node/2577631 lands.
Chris@0 18 */
Chris@0 19 class HtmlResponseBigPipeSubscriber implements EventSubscriberInterface {
Chris@0 20
Chris@0 21 /**
Chris@0 22 * The BigPipe service.
Chris@0 23 *
Chris@0 24 * @var \Drupal\big_pipe\Render\BigPipe
Chris@0 25 */
Chris@0 26 protected $bigPipe;
Chris@0 27
Chris@0 28 /**
Chris@0 29 * Constructs a HtmlResponseBigPipeSubscriber object.
Chris@0 30 *
Chris@0 31 * @param \Drupal\big_pipe\Render\BigPipe $big_pipe
Chris@0 32 * The BigPipe service.
Chris@0 33 */
Chris@0 34 public function __construct(BigPipe $big_pipe) {
Chris@0 35 $this->bigPipe = $big_pipe;
Chris@0 36 }
Chris@0 37
Chris@0 38 /**
Chris@0 39 * Adds markers to the response necessary for the BigPipe render strategy.
Chris@0 40 *
Chris@0 41 * @param \Symfony\Component\HttpKernel\Event\FilterResponseEvent $event
Chris@0 42 * The event to process.
Chris@0 43 */
Chris@0 44 public function onRespondEarly(FilterResponseEvent $event) {
Chris@0 45 $response = $event->getResponse();
Chris@0 46 if (!$response instanceof HtmlResponse) {
Chris@0 47 return;
Chris@0 48 }
Chris@0 49
Chris@0 50 // Wrap the scripts_bottom placeholder with a marker before and after,
Chris@0 51 // because \Drupal\big_pipe\Render\BigPipe needs to be able to extract that
Chris@0 52 // markup if there are no-JS BigPipe placeholders.
Chris@0 53 // @see \Drupal\big_pipe\Render\BigPipe::sendPreBody()
Chris@0 54 $attachments = $response->getAttachments();
Chris@0 55 if (isset($attachments['html_response_attachment_placeholders']['scripts_bottom'])) {
Chris@0 56 $scripts_bottom_placeholder = $attachments['html_response_attachment_placeholders']['scripts_bottom'];
Chris@0 57 $content = $response->getContent();
Chris@0 58 $content = str_replace($scripts_bottom_placeholder, '<drupal-big-pipe-scripts-bottom-marker>' . $scripts_bottom_placeholder . '<drupal-big-pipe-scripts-bottom-marker>', $content);
Chris@0 59 $response->setContent($content);
Chris@0 60 }
Chris@0 61 }
Chris@0 62
Chris@0 63 /**
Chris@0 64 * Transforms a HtmlResponse to a BigPipeResponse.
Chris@0 65 *
Chris@0 66 * @param \Symfony\Component\HttpKernel\Event\FilterResponseEvent $event
Chris@0 67 * The event to process.
Chris@0 68 */
Chris@0 69 public function onRespond(FilterResponseEvent $event) {
Chris@0 70 $response = $event->getResponse();
Chris@0 71 if (!$response instanceof HtmlResponse) {
Chris@0 72 return;
Chris@0 73 }
Chris@0 74
Chris@0 75 $attachments = $response->getAttachments();
Chris@0 76
Chris@0 77 // If there are no no-JS BigPipe placeholders, unwrap the scripts_bottom
Chris@0 78 // markup.
Chris@0 79 // @see onRespondEarly()
Chris@0 80 // @see \Drupal\big_pipe\Render\BigPipe::sendPreBody()
Chris@0 81 if (empty($attachments['big_pipe_nojs_placeholders'])) {
Chris@0 82 $content = $response->getContent();
Chris@0 83 $content = str_replace('<drupal-big-pipe-scripts-bottom-marker>', '', $content);
Chris@0 84 $response->setContent($content);
Chris@0 85 }
Chris@0 86
Chris@0 87 // If there are neither BigPipe placeholders nor no-JS BigPipe placeholders,
Chris@0 88 // there isn't anything dynamic in this response, and we can return early:
Chris@0 89 // there is no point in sending this response using BigPipe.
Chris@0 90 if (empty($attachments['big_pipe_placeholders']) && empty($attachments['big_pipe_nojs_placeholders'])) {
Chris@0 91 return;
Chris@0 92 }
Chris@0 93
Chris@0 94 $big_pipe_response = new BigPipeResponse($response);
Chris@0 95 $big_pipe_response->setBigPipeService($this->getBigPipeService($event));
Chris@0 96 $event->setResponse($big_pipe_response);
Chris@0 97 }
Chris@0 98
Chris@0 99 /**
Chris@0 100 * Returns the BigPipe service to use to send the current response.
Chris@0 101 *
Chris@0 102 * @param \Symfony\Component\HttpKernel\Event\FilterResponseEvent $event
Chris@0 103 * A response event.
Chris@0 104 *
Chris@0 105 * @return \Drupal\big_pipe\Render\BigPipe
Chris@0 106 * The BigPipe service.
Chris@0 107 */
Chris@0 108 protected function getBigPipeService(FilterResponseEvent $event) {
Chris@0 109 return $this->bigPipe;
Chris@0 110 }
Chris@0 111
Chris@0 112 /**
Chris@0 113 * {@inheritdoc}
Chris@0 114 */
Chris@0 115 public static function getSubscribedEvents() {
Chris@0 116 // Run after HtmlResponsePlaceholderStrategySubscriber (priority 5), i.e.
Chris@0 117 // after BigPipeStrategy has been applied, but before normal (priority 0)
Chris@0 118 // response subscribers have been applied, because by then it'll be too late
Chris@0 119 // to transform it into a BigPipeResponse.
Chris@0 120 $events[KernelEvents::RESPONSE][] = ['onRespondEarly', 3];
Chris@0 121
Chris@0 122 // Run as the last possible subscriber.
Chris@0 123 $events[KernelEvents::RESPONSE][] = ['onRespond', -10000];
Chris@0 124
Chris@0 125 return $events;
Chris@0 126 }
Chris@0 127
Chris@0 128 }