/**
  * {@inheritdoc}
  */
 public function viewMultiple(array $entities = array(), $view_mode = 'full', $langcode = NULL)
 {
     // @todo Remove when https://www.drupal.org/node/2453059 lands.
     $default_cache_contexts = ['languages', 'theme'];
     /** @var \Drupal\block\BlockInterface[] $entities */
     $build = array();
     foreach ($entities as $entity) {
         $entity_id = $entity->id();
         $plugin = $entity->getPlugin();
         $plugin_id = $plugin->getPluginId();
         $base_id = $plugin->getBaseId();
         $derivative_id = $plugin->getDerivativeId();
         $configuration = $plugin->getConfiguration();
         // Create the render array for the block as a whole.
         // @see template_preprocess_block().
         $build[$entity_id] = array('#theme' => 'block', '#attributes' => array(), '#contextual_links' => array('block' => array('route_parameters' => array('block' => $entity->id()))), '#weight' => $entity->getWeight(), '#configuration' => $configuration, '#plugin_id' => $plugin_id, '#base_plugin_id' => $base_id, '#derivative_plugin_id' => $derivative_id, '#id' => $entity->id(), '#cache' => ['contexts' => Cache::mergeContexts($default_cache_contexts, $plugin->getCacheContexts()), 'tags' => Cache::mergeTags($this->getCacheTags(), $entity->getCacheTags(), $plugin->getCacheTags()), 'max-age' => $plugin->getCacheMaxAge()], '#block' => $entity);
         $build[$entity_id]['#configuration']['label'] = String::checkPlain($configuration['label']);
         if ($plugin->isCacheable()) {
             $build[$entity_id]['#pre_render'][] = array($this, 'buildBlock');
             // Generic cache keys, with the block plugin's custom keys appended.
             $default_cache_keys = array('entity_view', 'block', $entity->id());
             $build[$entity_id]['#cache']['keys'] = array_merge($default_cache_keys, $plugin->getCacheKeys());
         } else {
             $build[$entity_id] = $this->buildBlock($build[$entity_id]);
         }
         // Don't run in ::buildBlock() to ensure cache keys can be altered. If an
         // alter hook wants to modify the block contents, it can append another
         // #pre_render hook.
         $this->moduleHandler()->alter(array('block_view', "block_view_{$base_id}"), $build[$entity_id], $plugin);
     }
     return $build;
 }
 /**
  * Tests that the block is cached with the correct contexts and tags.
  */
 public function testBlock()
 {
     $block = $this->drupalPlaceBlock('block_content:' . $this->entity->uuid());
     $build = $this->container->get('entity.manager')->getViewBuilder('block')->view($block, 'block');
     // Render the block.
     // @todo The request stack manipulation won't be necessary once
     //   https://www.drupal.org/node/2367555 is fixed and the
     //   corresponding $request->isMethodSafe() checks are removed from
     //   Drupal\Core\Render\Renderer.
     $request_stack = $this->container->get('request_stack');
     $request_stack->push(new Request());
     $this->container->get('renderer')->renderRoot($build);
     $request_stack->pop();
     // Expected keys, contexts, and tags for the block.
     // @see \Drupal\block\BlockViewBuilder::viewMultiple()
     $expected_block_cache_keys = ['entity_view', 'block', $block->id()];
     $expected_block_cache_contexts = ['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme'];
     $expected_block_cache_tags = Cache::mergeTags(['block_view', 'rendered'], $block->getCacheTags(), $block->getPlugin()->getCacheTags());
     // Expected contexts and tags for the BlockContent entity.
     // @see \Drupal\Core\Entity\EntityViewBuilder::getBuildDefaults().
     $expected_entity_cache_contexts = ['theme'];
     $expected_entity_cache_tags = Cache::mergeTags(['block_content_view'], $this->entity->getCacheTags(), $this->getAdditionalCacheTagsForEntity($this->entity));
     // Verify that what was render cached matches the above expectations.
     $cid = $this->createCacheId($expected_block_cache_keys, $expected_block_cache_contexts);
     $redirected_cid = $this->createCacheId($expected_block_cache_keys, Cache::mergeContexts($expected_block_cache_contexts, $expected_entity_cache_contexts));
     $this->verifyRenderCache($cid, Cache::mergeTags($expected_block_cache_tags, $expected_entity_cache_tags), $cid !== $redirected_cid ? $redirected_cid : NULL);
 }
 /**
  * {@inheritdoc}
  */
 public function viewMultiple(array $entities = array(), $view_mode = 'full', $langcode = NULL)
 {
     /** @var \Drupal\block\BlockInterface[] $entities */
     $build = array();
     foreach ($entities as $entity) {
         $entity_id = $entity->id();
         $plugin = $entity->getPlugin();
         $plugin_id = $plugin->getPluginId();
         $base_id = $plugin->getBaseId();
         $derivative_id = $plugin->getDerivativeId();
         $configuration = $plugin->getConfiguration();
         // Create the render array for the block as a whole.
         // @see template_preprocess_block().
         $build[$entity_id] = array('#theme' => 'block', '#attributes' => array(), '#contextual_links' => array('block' => array('route_parameters' => array('block' => $entity->id()))), '#weight' => $entity->get('weight'), '#configuration' => $configuration, '#plugin_id' => $plugin_id, '#base_plugin_id' => $base_id, '#derivative_plugin_id' => $derivative_id, '#id' => $entity->id(), '#block' => $entity);
         $build[$entity_id]['#configuration']['label'] = String::checkPlain($configuration['label']);
         // Set cache tags; these always need to be set, whether the block is
         // cacheable or not, so that the page cache is correctly informed.
         $build[$entity_id]['#cache']['tags'] = Cache::mergeTags($this->getCacheTag(), $entity->getCacheTag(), $plugin->getCacheTags());
         if ($plugin->isCacheable()) {
             $build[$entity_id]['#pre_render'][] = array($this, 'buildBlock');
             // Generic cache keys, with the block plugin's custom keys appended
             // (usually cache context keys like 'cache_context.user.roles').
             $default_cache_keys = array('entity_view', 'block', $entity->id(), $this->languageManager->getCurrentLanguage()->getId(), 'cache_context.theme');
             $max_age = $plugin->getCacheMaxAge();
             $build[$entity_id]['#cache'] += array('keys' => array_merge($default_cache_keys, $plugin->getCacheKeys()), 'expire' => $max_age === Cache::PERMANENT ? Cache::PERMANENT : REQUEST_TIME + $max_age);
         } else {
             $build[$entity_id] = $this->buildBlock($build[$entity_id]);
         }
         // Don't run in ::buildBlock() to ensure cache keys can be altered. If an
         // alter hook wants to modify the block contents, it can append another
         // #pre_render hook.
         $this->moduleHandler()->alter(array('block_view', "block_view_{$base_id}"), $build[$entity_id], $plugin);
     }
     return $build;
 }
 /**
  * Tests the bubbling of cache tags.
  */
 public function testCacheTags()
 {
     /** @var \Drupal\Core\Render\RendererInterface $renderer */
     $renderer = $this->container->get('renderer');
     // Create the entity that will be commented upon.
     $commented_entity = entity_create('entity_test', array('name' => $this->randomMachineName()));
     $commented_entity->save();
     // Verify cache tags on the rendered entity before it has comments.
     $build = \Drupal::entityManager()->getViewBuilder('entity_test')->view($commented_entity);
     $renderer->renderRoot($build);
     $cache_context_tags = \Drupal::service('cache_contexts_manager')->convertTokensToKeys($build['#cache']['contexts'])->getCacheTags();
     $expected_cache_tags = Cache::mergeTags($cache_context_tags, ['entity_test_view', 'entity_test:' . $commented_entity->id(), 'comment_list', 'config:core.entity_form_display.comment.comment.default', 'config:field.field.comment.comment.comment_body', 'config:field.field.entity_test.entity_test.comment', 'config:field.storage.comment.comment_body', 'config:user.settings']);
     sort($expected_cache_tags);
     $this->assertEqual($build['#cache']['tags'], $expected_cache_tags);
     // Create a comment on that entity. Comment loading requires that the uid
     // also exists in the {users} table.
     $user = $this->createUser();
     $user->save();
     $comment = entity_create('comment', array('subject' => 'Llama', 'comment_body' => array('value' => 'Llamas are cool!', 'format' => 'plain_text'), 'entity_id' => $commented_entity->id(), 'entity_type' => 'entity_test', 'field_name' => 'comment', 'comment_type' => 'comment', 'status' => CommentInterface::PUBLISHED, 'uid' => $user->id()));
     $comment->save();
     // Load commented entity so comment_count gets computed.
     // @todo Remove the $reset = TRUE parameter after
     //   https://www.drupal.org/node/597236 lands. It's a temporary work-around.
     $commented_entity = entity_load('entity_test', $commented_entity->id(), TRUE);
     // Verify cache tags on the rendered entity when it has comments.
     $build = \Drupal::entityManager()->getViewBuilder('entity_test')->view($commented_entity);
     $renderer->renderRoot($build);
     $cache_context_tags = \Drupal::service('cache_contexts_manager')->convertTokensToKeys($build['#cache']['contexts'])->getCacheTags();
     $expected_cache_tags = Cache::mergeTags($cache_context_tags, ['entity_test_view', 'entity_test:' . $commented_entity->id(), 'comment_list', 'comment_view', 'comment:' . $comment->id(), 'config:filter.format.plain_text', 'user_view', 'user:2', 'config:core.entity_form_display.comment.comment.default', 'config:field.field.comment.comment.comment_body', 'config:field.field.entity_test.entity_test.comment', 'config:field.storage.comment.comment_body', 'config:user.settings']);
     sort($expected_cache_tags);
     $this->assertEqual($build['#cache']['tags'], $expected_cache_tags);
 }
Example #5
0
 /**
  * {@inheritdoc}
  */
 public function getDerivativeDefinitions($base_plugin_definition)
 {
     $this->derivatives = [];
     /** @var \Drupal\rng\Entity\EventType[] $event_types */
     foreach ($this->eventManager->getEventTypes() as $entity_type => $event_types) {
         $cache_tags = $this->entityManager->getDefinition($entity_type)->getListCacheTags();
         foreach ($event_types as $event_type) {
             $cache_tags = Cache::mergeTags($cache_tags, $event_type->getCacheTags());
         }
         // Only need one set of tasks task per entity type.
         if ($this->routeProvider->getRouteByName("entity.{$entity_type}.canonical")) {
             $event_default = "rng.event.{$entity_type}.event.default";
             $this->derivatives[$event_default] = array('title' => t('Event'), 'base_route' => "entity.{$entity_type}.canonical", 'route_name' => "rng.event.{$entity_type}.event", 'weight' => 30, 'cache_tags' => $cache_tags);
             $this->derivatives["rng.event.{$entity_type}.event.settings"] = array('title' => t('Settings'), 'route_name' => $this->derivatives[$event_default]['route_name'], 'parent_id' => 'rng.local_tasks:' . $event_default, 'weight' => 10, 'cache_tags' => $cache_tags);
             $this->derivatives["rng.event.{$entity_type}.event.access"] = array('title' => t('Access'), 'route_name' => "rng.event.{$entity_type}.access", 'parent_id' => 'rng.local_tasks:' . $event_default, 'weight' => 20, 'cache_tags' => $cache_tags);
             $this->derivatives["rng.event.{$entity_type}.event.messages"] = array('title' => t('Messages'), 'route_name' => "rng.event.{$entity_type}.messages", 'parent_id' => 'rng.local_tasks:' . $event_default, 'weight' => 30, 'cache_tags' => $cache_tags);
             $this->derivatives["rng.event.{$entity_type}.event.group.list"] = array('title' => t('Groups'), 'route_name' => "rng.event.{$entity_type}.group.list", 'parent_id' => 'rng.local_tasks:' . $event_default, 'weight' => 40, 'cache_tags' => $cache_tags);
             $this->derivatives["rng.event.{$entity_type}.register.type_list"] = array('route_name' => "rng.event.{$entity_type}.register.type_list", 'base_route' => "entity.{$entity_type}.canonical", 'title' => t('Register'), 'weight' => 40, 'cache_tags' => $cache_tags);
         }
     }
     foreach ($this->derivatives as &$entry) {
         $entry += $base_plugin_definition;
     }
     return parent::getDerivativeDefinitions($base_plugin_definition);
 }
 /**
  * #pre_render callback for building the regions.
  */
 public function buildRegions(array $build)
 {
     $cacheability = CacheableMetadata::createFromRenderArray($build)->addCacheableDependency($this);
     $contexts = $this->getContexts();
     foreach ($this->getRegionAssignments() as $region => $blocks) {
         if (!$blocks) {
             continue;
         }
         $region_name = Html::getClass("block-region-{$region}");
         $build[$region]['#prefix'] = '<div class="' . $region_name . '">';
         $build[$region]['#suffix'] = '</div>';
         /** @var \Drupal\Core\Block\BlockPluginInterface[] $blocks */
         $weight = 0;
         foreach ($blocks as $block_id => $block) {
             if ($block instanceof ContextAwarePluginInterface) {
                 $this->contextHandler()->applyContextMapping($block, $contexts);
             }
             $access = $block->access($this->account, TRUE);
             $cacheability->addCacheableDependency($access);
             if (!$access->isAllowed()) {
                 continue;
             }
             $block_build = ['#theme' => 'block', '#attributes' => [], '#weight' => $weight++, '#configuration' => $block->getConfiguration(), '#plugin_id' => $block->getPluginId(), '#base_plugin_id' => $block->getBaseId(), '#derivative_plugin_id' => $block->getDerivativeId(), '#block_plugin' => $block, '#pre_render' => [[$this, 'buildBlock']], '#cache' => ['keys' => ['page_manager_block_display', $this->id(), 'block', $block_id], 'tags' => Cache::mergeTags($this->getCacheTags(), $block->getCacheTags()), 'contexts' => $block->getCacheContexts(), 'max-age' => $block->getCacheMaxAge()]];
             // Merge the cacheability metadata of blocks into the page. This helps
             // to avoid cache redirects if the blocks have more cache contexts than
             // the page, which the page must respect as well.
             $cacheability->addCacheableDependency($block);
             $build[$region][$block_id] = $block_build;
         }
     }
     $build['#title'] = $this->renderPageTitle($this->configuration['page_title']);
     $cacheability->applyTo($build);
     return $build;
 }
Example #7
0
 /**
  * {@inheritdoc}
  */
 public function viewMultiple(array $entities = array(), $view_mode = 'full', $langcode = NULL)
 {
     /** @var \Drupal\block\BlockInterface[] $entities */
     $build = array();
     foreach ($entities as $entity) {
         $entity_id = $entity->id();
         $plugin = $entity->getPlugin();
         $cache_tags = Cache::mergeTags($this->getCacheTags(), $entity->getCacheTags());
         $cache_tags = Cache::mergeTags($cache_tags, $plugin->getCacheTags());
         // Create the render array for the block as a whole.
         // @see template_preprocess_block().
         $build[$entity_id] = array('#cache' => ['keys' => ['entity_view', 'block', $entity->id()], 'contexts' => Cache::mergeContexts($entity->getCacheContexts(), $plugin->getCacheContexts()), 'tags' => $cache_tags, 'max-age' => $plugin->getCacheMaxAge()], '#weight' => $entity->getWeight());
         // Allow altering of cacheability metadata or setting #create_placeholder.
         $this->moduleHandler->alter(['block_build', "block_build_" . $plugin->getBaseId()], $build[$entity_id], $plugin);
         if ($plugin instanceof MainContentBlockPluginInterface || $plugin instanceof TitleBlockPluginInterface) {
             // Immediately build a #pre_render-able block, since this block cannot
             // be built lazily.
             $build[$entity_id] += static::buildPreRenderableBlock($entity, $this->moduleHandler());
         } else {
             // Assign a #lazy_builder callback, which will generate a #pre_render-
             // able block lazily (when necessary).
             $build[$entity_id] += ['#lazy_builder' => [static::class . '::lazyBuilder', [$entity_id, $view_mode, $langcode]]];
         }
     }
     return $build;
 }
Example #8
0
 /**
  * {@inheritdoc}
  */
 public function buildForm(array $form, FormStateInterface $form_state)
 {
     $config = $this->config('system.site');
     // Display login form:
     $form['name'] = array('#type' => 'textfield', '#title' => $this->t('Username'), '#size' => 60, '#maxlength' => USERNAME_MAX_LENGTH, '#description' => $this->t('Enter your @s username.', array('@s' => $config->get('name'))), '#required' => TRUE, '#attributes' => array('autocorrect' => 'off', 'autocapitalize' => 'off', 'spellcheck' => 'false', 'autofocus' => 'autofocus'));
     $form['pass'] = array('#type' => 'password', '#title' => $this->t('Password'), '#size' => 60, '#description' => $this->t('Enter the password that accompanies your username.'), '#required' => TRUE);
     $form['actions'] = array('#type' => 'actions');
     $form['actions']['submit'] = array('#type' => 'submit', '#value' => $this->t('Log in'));
     $form['#validate'][] = '::validateName';
     $form['#validate'][] = '::validateAuthentication';
     $form['#validate'][] = '::validateFinal';
     $form['#cache']['tags'] = Cache::mergeTags(isset($form['#cache']['tags']) ? $form['#cache']['tags'] : [], $config->getCacheTags());
     return $form;
 }
 /**
  * {@inheritdoc}
  */
 public function invalidateTags(array $tags)
 {
     // When either an extension (module/theme) is (un)installed, purge
     // everything.
     if (in_array('config:core.extension', $tags)) {
         // @todo Purge everything. Blocked on https://github.com/d8-contrib-modules/cloudflare/issues/16.
         return;
     }
     // Also invalidate the cache tags as hashes, to automatically also work for
     // responses that exceed CloudFlare's Cache-Tag header limit.
     $hashes = CloudFlareCacheTagHeaderGenerator::cacheTagsToHashes($tags);
     $tags = Cache::mergeTags($tags, $hashes);
     $this->purgeTags($tags);
 }
Example #10
0
 /**
  * Tests comments as part of an RSS feed.
  */
 function testCommentRss()
 {
     // Find comment in RSS feed.
     $this->drupalLogin($this->webUser);
     $this->postComment($this->node, $this->randomMachineName(), $this->randomMachineName());
     $this->drupalGet('rss.xml');
     $cache_contexts = ['languages:language_interface', 'theme', 'url.site', 'user.node_grants:view', 'user.permissions', 'timezone'];
     $this->assertCacheContexts($cache_contexts);
     $cache_context_tags = \Drupal::service('cache_contexts_manager')->convertTokensToKeys($cache_contexts)->getCacheTags();
     $this->assertCacheTags(Cache::mergeTags($cache_context_tags, ['config:views.view.frontpage', 'node:1', 'node_list', 'node_view', 'user:3']));
     $raw = '<comments>' . $this->node->url('canonical', array('fragment' => 'comments', 'absolute' => TRUE)) . '</comments>';
     $this->assertRaw($raw, 'Comments as part of RSS feed.');
     // Hide comments from RSS feed and check presence.
     $this->node->set('comment', CommentItemInterface::HIDDEN);
     $this->node->save();
     $this->drupalGet('rss.xml');
     $this->assertNoRaw($raw, 'Hidden comments is not a part of RSS feed.');
 }
 /**
  * Asserts a view's result & output cache items' cache tags.
  *
  * @param \Drupal\views\ViewExecutable $view
  *   The view to test, must have caching enabled.
  * @param null|string[] $expected_results_cache
  *   NULL when expecting no results cache item, a set of cache tags expected
  *   to be set on the results cache item otherwise.
  * @param bool $views_caching_is_enabled
  *   Whether to expect an output cache item. If TRUE, the cache tags must
  *   match those in $expected_render_array_cache_tags.
  * @param string[] $expected_render_array_cache_tags
  *   A set of cache tags expected to be set on the built view's render array.
  *
  * @return array
  *   The render array
  */
 protected function assertViewsCacheTags(ViewExecutable $view, $expected_results_cache, $views_caching_is_enabled, array $expected_render_array_cache_tags)
 {
     $build = $view->preview();
     // Ensure the current request is a GET request so that render caching is
     // active for direct rendering of views, just like for actual requests.
     /** @var \Symfony\Component\HttpFoundation\RequestStack $request_stack */
     $request_stack = \Drupal::service('request_stack');
     $request_stack->push(new Request());
     \Drupal::service('renderer')->renderRoot($build);
     $request_stack->pop();
     // Render array cache tags.
     $this->pass('Checking render array cache tags.');
     sort($expected_render_array_cache_tags);
     $this->assertEqual($build['#cache']['tags'], $expected_render_array_cache_tags);
     if ($views_caching_is_enabled) {
         $this->pass('Checking Views results cache item cache tags.');
         /** @var \Drupal\views\Plugin\views\cache\CachePluginBase $cache_plugin */
         $cache_plugin = $view->display_handler->getPlugin('cache');
         // Results cache.
         $results_cache_item = \Drupal::cache('data')->get($cache_plugin->generateResultsKey());
         if (is_array($expected_results_cache)) {
             $this->assertTrue($results_cache_item, 'Results cache item found.');
             if ($results_cache_item) {
                 sort($expected_results_cache);
                 $this->assertEqual($results_cache_item->tags, $expected_results_cache);
             }
         } else {
             $this->assertFalse($results_cache_item, 'Results cache item not found.');
         }
         // Output cache.
         $this->pass('Checking Views output cache item cache tags.');
         $output_cache_item = \Drupal::cache('render')->get($cache_plugin->generateOutputKey());
         if ($views_caching_is_enabled === TRUE) {
             $this->assertTrue($output_cache_item, 'Output cache item found.');
             if ($output_cache_item) {
                 $this->assertEqual($output_cache_item->tags, Cache::mergeTags($expected_render_array_cache_tags, ['rendered']));
             }
         } else {
             $this->assertFalse($output_cache_item, 'Output cache item not found.');
         }
     }
     $view->destroy();
     return $build;
 }
 /**
  * {@inheritdoc}
  */
 public function getDerivativeDefinitions($base_plugin_definition)
 {
     $this->derivatives = [];
     /** @var \Drupal\rng\Entity\EventType[] $event_types */
     foreach ($this->eventManager->getEventTypes() as $entity_type => $event_types) {
         $cache_tags = $this->entityManager->getDefinition($entity_type)->getListCacheTags();
         foreach ($event_types as $event_type) {
             $cache_tags = Cache::mergeTags($cache_tags, $event_type->getCacheTags());
         }
         // Only need one set of actions per entity type.
         $this->derivatives["rng.event.{$entity_type}.event.access.reset"] = array('title' => $this->t('Reset/customize access rules'), 'route_name' => "rng.event.{$entity_type}.access.reset", 'class' => '\\Drupal\\rng\\Plugin\\Menu\\LocalAction\\ResetAccessRules', 'appears_on' => array("rng.event.{$entity_type}.access"), 'cache_tags' => $cache_tags);
         $this->derivatives["rng.event.{$entity_type}.event.message.add"] = array('title' => $this->t('Add message'), 'route_name' => "rng.event.{$entity_type}.messages.add", 'appears_on' => array("rng.event.{$entity_type}.messages"), 'cache_tags' => $cache_tags);
         $this->derivatives["rng.event.{$entity_type}.event.group.add"] = array('title' => $this->t('Add group'), 'route_name' => "rng.event.{$entity_type}.group.add", 'appears_on' => array("rng.event.{$entity_type}.group.list"), 'cache_tags' => $cache_tags);
     }
     foreach ($this->derivatives as &$entry) {
         $entry += $base_plugin_definition;
     }
     return $this->derivatives;
 }
Example #13
0
 /**
  * {@inheritdoc}
  */
 public function viewMultiple(array $entities = array(), $view_mode = 'full', $langcode = NULL)
 {
     /** @var \Drupal\block\BlockInterface[] $entities */
     $build = array();
     foreach ($entities as $entity) {
         $entity_id = $entity->id();
         $plugin = $entity->getPlugin();
         $plugin_id = $plugin->getPluginId();
         $base_id = $plugin->getBaseId();
         $derivative_id = $plugin->getDerivativeId();
         $configuration = $plugin->getConfiguration();
         // Create the render array for the block as a whole.
         // @see template_preprocess_block().
         $build[$entity_id] = array('#theme' => 'block', '#attributes' => array(), '#contextual_links' => array('block' => array('route_parameters' => array('block' => $entity->id()))), '#weight' => $entity->getWeight(), '#configuration' => $configuration, '#plugin_id' => $plugin_id, '#base_plugin_id' => $base_id, '#derivative_plugin_id' => $derivative_id, '#id' => $entity->id(), '#cache' => ['keys' => ['entity_view', 'block', $entity->id()], 'contexts' => $plugin->getCacheContexts(), 'tags' => Cache::mergeTags($this->getCacheTags(), $entity->getCacheTags(), $plugin->getCacheTags()), 'max-age' => $plugin->getCacheMaxAge()], '#pre_render' => [[$this, 'buildBlock']], '#block' => $entity);
         $build[$entity_id]['#configuration']['label'] = SafeMarkup::checkPlain($configuration['label']);
         // Don't run in ::buildBlock() to ensure cache keys can be altered. If an
         // alter hook wants to modify the block contents, it can append another
         // #pre_render hook.
         $this->moduleHandler()->alter(array('block_view', "block_view_{$base_id}"), $build[$entity_id], $plugin);
     }
     return $build;
 }
 /**
  * {@inheritdoc}
  */
 public function render(HtmlFragmentInterface $fragment, $status_code = 200)
 {
     // Converts the given HTML fragment which represents the main content region
     // of the page into a render array.
     $page_content['main'] = array('#markup' => $fragment->getContent());
     $page_content['#title'] = $fragment->getTitle();
     if ($fragment instanceof CacheableInterface) {
         $page_content['main']['#cache']['tags'] = $fragment->getCacheTags();
     }
     // Build the full page array by calling drupal_prepare_page(), which invokes
     // hook_page_build(). This adds the other regions to the page.
     $page_array = drupal_prepare_page($page_content);
     // Build the HtmlPage object.
     $page = new HtmlPage('', array(), $fragment->getTitle());
     $page = $this->preparePage($page, $page_array);
     $page->setBodyTop(drupal_render_root($page_array['page_top']));
     $page->setBodyBottom(drupal_render_root($page_array['page_bottom']));
     $page->setContent(drupal_render_root($page_array));
     $page->setStatusCode($status_code);
     drupal_process_attached($page_array);
     if (isset($page_array['page_top'])) {
         drupal_process_attached($page_array['page_top']);
     }
     if (isset($page_array['page_bottom'])) {
         drupal_process_attached($page_array['page_bottom']);
     }
     if ($fragment instanceof CacheableInterface) {
         // Persist cache tags associated with this page. Also associate the
         // "rendered" cache tag. This allows us to invalidate the entire render
         // cache, regardless of the cache bin.
         $cache_tags = Cache::mergeTags(isset($page_array['page_top']) ? $page_array['page_top']['#cache']['tags'] : [], $page_array['#cache']['tags'], isset($page_array['page_bottom']) ? $page_array['page_bottom']['#cache']['tags'] : [], ['rendered']);
         // Only keep unique cache tags. We need to prevent duplicates here already
         // rather than only in the cache layer, because they are also used by
         // reverse proxies (like Varnish), not only by Drupal's page cache.
         $page->setCacheTags(array_unique($cache_tags));
     }
     return $page;
 }
 /**
  * {@inheritdoc}
  */
 public function getCacheTags() {
   $tags = parent::getCacheTags();
   return Cache::mergeTags($tags, ['block_visibility_group:' . $this->id]);
 }
 /**
  * {@inheritdoc}
  */
 protected function calculateXmlCacheTags()
 {
     // Add tags for the entity that this XML comes from.
     $entity_tags = is_object($this->entity) && $this->entity instanceof CacheableDependencyInterface ? $this->entity->getCacheTags() : array();
     // Also fetch the tags from the display configuration as that is where our
     // gallery-specific settings are stored (so changes there should also
     // invalidate the XML).
     $display = entity_get_display($this->entityType, $this->entity->bundle(), $this->displayName);
     $display_tags = array();
     if ($display instanceof CacheableDependencyInterface) {
         $display_tags = $display->getCacheTags();
         // If this is not a custom display then we need to also include the
         // default display cache tags as Drupal may reference this display
         // elsewhere by the "default" label.
         if (!$display->status() || $display->isNew()) {
             $display_default = entity_get_display($this->entityType, $this->entity->bundle(), 'default');
             if ($display_default instanceof CacheableDependencyInterface) {
                 $display_tags = Cache::mergeTags($display_tags, $display_default->getCacheTags());
             }
         }
     }
     return Cache::mergeTags($entity_tags, $display_tags);
 }
 /**
  * Ensures that some cache tags are present in the current response.
  *
  * @param string[] $expected_tags
  *   The expected tags.
  * @param bool $include_default_tags
  *   (optional) Whether the default cache tags should be included.
  */
 protected function assertCacheTags(array $expected_tags, $include_default_tags = TRUE)
 {
     // The anonymous role cache tag is only added if the user is anonymous.
     if ($include_default_tags && \Drupal::currentUser()->isAnonymous()) {
         $expected_tags = Cache::mergeTags($expected_tags, ['config:user.role.anonymous']);
     }
     $actual_tags = $this->getCacheHeaderValues('X-Drupal-Cache-Tags');
     sort($expected_tags);
     sort($actual_tags);
     $this->assertIdentical($actual_tags, $expected_tags);
     $this->debugCacheTags($actual_tags, $expected_tags);
 }
 /**
  * Tests cache tags presence and invalidation of the entity at its URI.
  *
  * Tests the following cache tags:
  * - "<entity type>_view"
  * - "<entity_type>:<entity ID>"
  */
 public function testEntityUri()
 {
     $entity_url = $this->entity->urlInfo();
     $entity_type = $this->entity->getEntityTypeId();
     // Selects the view mode that will be used.
     $view_mode = $this->selectViewMode($entity_type);
     // The default cache contexts for rendered entities.
     $entity_cache_contexts = ['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme', 'user.permissions'];
     // Generate the standardized entity cache tags.
     $cache_tag = $this->entity->getCacheTags();
     $view_cache_tag = \Drupal::entityManager()->getViewBuilder($entity_type)->getCacheTags();
     $render_cache_tag = 'rendered';
     $this->pass("Test entity.", 'Debug');
     $this->verifyPageCache($entity_url, 'MISS');
     // Verify a cache hit, but also the presence of the correct cache tags.
     $this->verifyPageCache($entity_url, 'HIT');
     // Also verify the existence of an entity render cache entry, if this entity
     // type supports render caching.
     if (\Drupal::entityManager()->getDefinition($entity_type)->isRenderCacheable()) {
         $cache_keys = ['entity_view', $entity_type, $this->entity->id(), $view_mode];
         $cid = $this->createCacheId($cache_keys, $entity_cache_contexts);
         $redirected_cid = NULL;
         $additional_cache_contexts = $this->getAdditionalCacheContextsForEntity($this->entity);
         if (count($additional_cache_contexts)) {
             $redirected_cid = $this->createCacheId($cache_keys, Cache::mergeContexts($entity_cache_contexts, $additional_cache_contexts));
         }
         $expected_cache_tags = Cache::mergeTags($cache_tag, $view_cache_tag);
         $expected_cache_tags = Cache::mergeTags($expected_cache_tags, $this->getAdditionalCacheTagsForEntity($this->entity));
         $expected_cache_tags = Cache::mergeTags($expected_cache_tags, array($render_cache_tag));
         $this->verifyRenderCache($cid, $expected_cache_tags, $redirected_cid);
     }
     // Verify that after modifying the entity, there is a cache miss.
     $this->pass("Test modification of entity.", 'Debug');
     $this->entity->save();
     $this->verifyPageCache($entity_url, 'MISS');
     // Verify a cache hit.
     $this->verifyPageCache($entity_url, 'HIT');
     // Verify that after modifying the entity's display, there is a cache miss.
     $this->pass("Test modification of entity's '{$view_mode}' display.", 'Debug');
     $entity_display = entity_get_display($entity_type, $this->entity->bundle(), $view_mode);
     $entity_display->save();
     $this->verifyPageCache($entity_url, 'MISS');
     // Verify a cache hit.
     $this->verifyPageCache($entity_url, 'HIT');
     if ($bundle_entity_type_id = $this->entity->getEntityType()->getBundleEntityType()) {
         // Verify that after modifying the corresponding bundle entity, there is a
         // cache miss.
         $this->pass("Test modification of entity's bundle entity.", 'Debug');
         $bundle_entity = entity_load($bundle_entity_type_id, $this->entity->bundle());
         $bundle_entity->save();
         $this->verifyPageCache($entity_url, 'MISS');
         // Verify a cache hit.
         $this->verifyPageCache($entity_url, 'HIT');
     }
     if ($this->entity->getEntityType()->get('field_ui_base_route')) {
         // Verify that after modifying a configurable field on the entity, there
         // is a cache miss.
         $this->pass("Test modification of entity's configurable field.", 'Debug');
         $field_storage_name = $this->entity->getEntityTypeId() . '.configurable_field';
         $field_storage = FieldStorageConfig::load($field_storage_name);
         $field_storage->save();
         $this->verifyPageCache($entity_url, 'MISS');
         // Verify a cache hit.
         $this->verifyPageCache($entity_url, 'HIT');
         // Verify that after modifying a configurable field on the entity, there
         // is a cache miss.
         $this->pass("Test modification of entity's configurable field.", 'Debug');
         $field_name = $this->entity->getEntityTypeId() . '.' . $this->entity->bundle() . '.configurable_field';
         $field = FieldConfig::load($field_name);
         $field->save();
         $this->verifyPageCache($entity_url, 'MISS');
         // Verify a cache hit.
         $this->verifyPageCache($entity_url, 'HIT');
     }
     // Verify that after invalidating the entity's cache tag directly, there is
     // a cache miss.
     $this->pass("Test invalidation of entity's cache tag.", 'Debug');
     Cache::invalidateTags($this->entity->getCacheTagsToInvalidate());
     $this->verifyPageCache($entity_url, 'MISS');
     // Verify a cache hit.
     $this->verifyPageCache($entity_url, 'HIT');
     // Verify that after invalidating the generic entity type's view cache tag
     // directly, there is a cache miss.
     $this->pass("Test invalidation of entity's 'view' cache tag.", 'Debug');
     Cache::invalidateTags($view_cache_tag);
     $this->verifyPageCache($entity_url, 'MISS');
     // Verify a cache hit.
     $this->verifyPageCache($entity_url, 'HIT');
     // Verify that after deleting the entity, there is a cache miss.
     $this->pass('Test deletion of entity.', 'Debug');
     $this->entity->delete();
     $this->verifyPageCache($entity_url, 'MISS');
     $this->assertResponse(404);
 }
 /**
  * {@inheritdoc}
  */
 public function viewElements(FieldItemListInterface $items)
 {
     $elements = array();
     // Check if the formatter involves a link.
     if ($this->getSetting('image_link') == 'content') {
         $uri = $items->getEntity()->urlInfo();
         // @todo Remove when theme_responsive_image_formatter() has support for route name.
         $uri['path'] = $items->getEntity()->getSystemPath();
     } elseif ($this->getSetting('image_link') == 'file') {
         $link_file = TRUE;
     }
     $fallback_image_style = '';
     // Check if the user defined a custom fallback image style.
     if ($this->getSetting('fallback_image_style')) {
         $fallback_image_style = $this->getSetting('fallback_image_style');
     }
     // Collect cache tags to be added for each item in the field.
     $responsive_image_mapping = $this->responsiveImageMappingStorage->load($this->getSetting('responsive_image_mapping'));
     $image_styles_to_load = array();
     if ($fallback_image_style) {
         $image_styles_to_load[] = $fallback_image_style;
     }
     $cache_tags = [];
     if ($responsive_image_mapping) {
         $cache_tags = Cache::mergeTags($cache_tags, $responsive_image_mapping->getCacheTags());
         foreach ($responsive_image_mapping->getMappings() as $mapping) {
             // First mapping found is used as fallback.
             if (empty($fallback_image_style)) {
                 $fallback_image_style = $mapping['image_style'];
             }
             $image_styles_to_load[] = $mapping['image_style'];
         }
     }
     $image_styles = entity_load_multiple('image_style', $image_styles_to_load);
     foreach ($image_styles as $image_style) {
         $cache_tags = Cache::mergeTags($cache_tags, $image_style->getCacheTags());
     }
     foreach ($items as $delta => $item) {
         if (isset($link_file)) {
             $uri = array('path' => file_create_url($item->entity->getFileUri()), 'options' => array());
         }
         $elements[$delta] = array('#theme' => 'responsive_image_formatter', '#attached' => array('library' => array('core/picturefill')), '#item' => $item, '#image_style' => $fallback_image_style, '#mapping_id' => $responsive_image_mapping ? $responsive_image_mapping->id() : '', '#path' => isset($uri) ? $uri : '', '#cache' => array('tags' => $cache_tags));
     }
     return $elements;
 }
Example #20
0
 /**
  * Applies the cacheability of the current display to the given render array.
  *
  * @param array $element
  *   The render array with updated cacheability metadata.
  */
 protected function applyDisplayCachablityMetadata(array &$element)
 {
     /** @var \Drupal\views\Plugin\views\cache\CachePluginBase $cache */
     $cache = $this->getPlugin('cache');
     (new CacheableMetadata())->setCacheTags(Cache::mergeTags($this->view->getCacheTags(), isset($this->display['cache_metadata']['tags']) ? $this->display['cache_metadata']['tags'] : []))->setCacheContexts(isset($this->display['cache_metadata']['contexts']) ? $this->display['cache_metadata']['contexts'] : [])->setCacheMaxAge(Cache::mergeMaxAges($cache->getCacheMaxAge(), isset($this->display['cache_metadata']['max-age']) ? $this->display['cache_metadata']['max-age'] : Cache::PERMANENT))->merge(CacheableMetadata::createFromRenderArray($element))->applyTo($element);
 }
Example #21
0
 /**
  * Pre-render callback: Renders a processed text element into #markup.
  *
  * Runs all the enabled filters on a piece of text.
  *
  * Note: Because filters can inject JavaScript or execute PHP code, security
  * is vital here. When a user supplies a text format, you should validate it
  * using $format->access() before accepting/using it. This is normally done in
  * the validation stage of the Form API. You should for example never make a
  * preview of content in a disallowed format.
  *
  * @param array $element
  *   A structured array with the following key-value pairs:
  *   - #text: containing the text to be filtered
  *   - #format: containing the machine name of the filter format to be used to
  *     filter the text. Defaults to the fallback format.
  *   - #langcode: the language code of the text to be filtered, e.g. 'en' for
  *     English. This allows filters to be language-aware so language-specific
  *     text replacement can be implemented. Defaults to an empty string.
  *   - #filter_types_to_skip: an array of filter types to skip, or an empty
  *     array (default) to skip no filter types. All of the format's filters
  *     will be applied, except for filters of the types that are marked to be
  *     skipped. FilterInterface::TYPE_HTML_RESTRICTOR is the only type that
  *     cannot be skipped.
  *
  * @return array
  *   The passed-in element with the filtered text in '#markup'.
  *
  * @ingroup sanitization
  */
 public static function preRenderText($element)
 {
     $format_id = $element['#format'];
     $filter_types_to_skip = $element['#filter_types_to_skip'];
     $text = $element['#text'];
     $langcode = $element['#langcode'];
     if (!isset($format_id)) {
         $format_id = static::configFactory()->get('filter.settings')->get('fallback_format');
     }
     /** @var \Drupal\filter\Entity\FilterFormat $format **/
     $format = FilterFormat::load($format_id);
     // If the requested text format doesn't exist or its disabled, the text
     // cannot be filtered.
     if (!$format || !$format->status()) {
         $message = !$format ? 'Missing text format: %format.' : 'Disabled text format: %format.';
         static::logger('filter')->alert($message, array('%format' => $format_id));
         $element['#markup'] = '';
         return $element;
     }
     $filter_must_be_applied = function (FilterInterface $filter) use($filter_types_to_skip) {
         $enabled = $filter->status === TRUE;
         $type = $filter->getType();
         // Prevent FilterInterface::TYPE_HTML_RESTRICTOR from being skipped.
         $filter_type_must_be_applied = $type == FilterInterface::TYPE_HTML_RESTRICTOR || !in_array($type, $filter_types_to_skip);
         return $enabled && $filter_type_must_be_applied;
     };
     // Convert all Windows and Mac newlines to a single newline, so filters only
     // need to deal with one possibility.
     $text = str_replace(array("\r\n", "\r"), "\n", $text);
     // Get a complete list of filters, ordered properly.
     /** @var \Drupal\filter\Plugin\FilterInterface[] $filters **/
     $filters = $format->filters();
     // Give filters a chance to escape HTML-like data such as code or formulas.
     foreach ($filters as $filter) {
         if ($filter_must_be_applied($filter)) {
             $text = $filter->prepare($text, $langcode);
         }
     }
     // Perform filtering.
     $metadata = BubbleableMetadata::createFromRenderArray($element);
     foreach ($filters as $filter) {
         if ($filter_must_be_applied($filter)) {
             $result = $filter->process($text, $langcode);
             $metadata = $metadata->merge($result);
             $text = $result->getProcessedText();
         }
     }
     // Filtering and sanitizing have been done in
     // \Drupal\filter\Plugin\FilterInterface. $text is not guaranteed to be
     // safe, but it has been passed through the filter system and checked with
     // a text format, so it must be printed as is. (See the note about security
     // in the method documentation above.)
     $element['#markup'] = FilteredMarkup::create($text);
     // Set the updated bubbleable rendering metadata and the text format's
     // cache tag.
     $metadata->applyTo($element);
     $element['#cache']['tags'] = Cache::mergeTags($element['#cache']['tags'], $format->getCacheTags());
     return $element;
 }
Example #22
0
  /**
   * @covers ::render
   * @covers ::doRender
   * @covers \Drupal\Core\Render\RenderCache::get
   * @covers \Drupal\Core\Render\RenderCache::set
   * @covers \Drupal\Core\Render\RenderCache::createCacheID
   */
  public function testRenderCache() {
    $this->setUpRequest();
    $this->setupMemoryCache();

    // Create an empty element.
    $test_element = [
      '#cache' => [
        'keys' => ['render_cache_test'],
        'tags' => ['render_cache_tag'],
      ],
      '#markup' => '',
      'child' => [
        '#cache' => [
          'keys' => ['render_cache_test_child'],
          'tags' => ['render_cache_tag_child:1', 'render_cache_tag_child:2'],
        ],
        '#markup' => '',
      ],
    ];

    // Render the element and confirm that it goes through the rendering
    // process (which will set $element['#printed']).
    $element = $test_element;
    $this->renderer->renderRoot($element);
    $this->assertTrue(isset($element['#printed']), 'No cache hit');

    // Render the element again and confirm that it is retrieved from the cache
    // instead (so $element['#printed'] will not be set).
    $element = $test_element;
    $this->renderer->renderRoot($element);
    $this->assertFalse(isset($element['#printed']), 'Cache hit');

    // Test that cache tags are correctly collected from the render element,
    // including the ones from its subchild.
    $expected_tags = [
      'render_cache_tag',
      'render_cache_tag_child:1',
      'render_cache_tag_child:2',
    ];
    $this->assertEquals($expected_tags, $element['#cache']['tags'], 'Cache tags were collected from the element and its subchild.');

    // The cache item also has a 'rendered' cache tag.
    $cache_item = $this->cacheFactory->get('render')->get('render_cache_test:en:stark');
    $this->assertSame(Cache::mergeTags($expected_tags, ['rendered']), $cache_item->tags);
  }
 /**
  * Asserts that a block is built/rendered/cached with expected cacheability.
  *
  * @param string[] $expected_keys
  *   The expected cache keys.
  * @param string[] $expected_contexts
  *   The expected cache contexts.
  * @param string[] $expected_tags
  *   The expected cache tags.
  * @param int $expected_max_age
  *   The expected max-age.
  */
 protected function assertBlockRenderedWithExpectedCacheability(array $expected_keys, array $expected_contexts, array $expected_tags, $expected_max_age)
 {
     $required_cache_contexts = ['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme', 'user.permissions'];
     // Check that the expected cacheability metadata is present in:
     // - the built render array;
     $this->pass('Built render array');
     $build = $this->getBlockRenderArray();
     $this->assertIdentical($expected_keys, $build['#cache']['keys']);
     $this->assertIdentical($expected_contexts, $build['#cache']['contexts']);
     $this->assertIdentical($expected_tags, $build['#cache']['tags']);
     $this->assertIdentical($expected_max_age, $build['#cache']['max-age']);
     $this->assertFalse(isset($build['#create_placeholder']));
     // - the rendered render array;
     $this->pass('Rendered render array');
     $this->renderer->renderRoot($build);
     // - the render cache item.
     $this->pass('Render cache item');
     $final_cache_contexts = Cache::mergeContexts($expected_contexts, $required_cache_contexts);
     $cid = implode(':', $expected_keys) . ':' . implode(':', \Drupal::service('cache_contexts_manager')->convertTokensToKeys($final_cache_contexts)->getKeys());
     $cache_item = $this->container->get('cache.render')->get($cid);
     $this->assertTrue($cache_item, 'The block render element has been cached with the expected cache ID.');
     $this->assertIdentical(Cache::mergeTags($expected_tags, ['rendered']), $cache_item->tags);
     $this->assertIdentical($final_cache_contexts, $cache_item->data['#cache']['contexts']);
     $this->assertIdentical($expected_tags, $cache_item->data['#cache']['tags']);
     $this->assertIdentical($expected_max_age, $cache_item->data['#cache']['max-age']);
     $this->container->get('cache.render')->delete($cid);
 }
Example #24
0
 /**
  * Returns the row cache tags.
  *
  * @param ResultRow $row
  *   A result row.
  *
  * @return string[]
  *   The row cache tags.
  */
 public function getRowCacheTags(ResultRow $row)
 {
     $tags = !empty($row->_entity) ? $row->_entity->getCacheTags() : [];
     if (!empty($row->_relationship_entities)) {
         foreach ($row->_relationship_entities as $entity) {
             $tags = Cache::mergeTags($tags, $entity->getCacheTags());
         }
     }
     return $tags;
 }
Example #25
0
  /**
   * {@inheritdoc}
   */
  public function getCacheTags() {
    $tags = [];
    // Add cache tags for each row, if there is an entity associated with it.
    if (!$this->hasAggregate) {
      foreach ($this->getAllEntities() as $entity) {
        $tags = Cache::mergeTags($entity->getCacheTags(), $tags);
      }
    }

    return $tags;
  }
 /**
  * Attempt to fetch the gallery's XML via a sub-request to another page.
  *
  * This assumes that the gallery XML has already been embedded within a normal
  * HTML page, at the given path, within a <script> block.
  *
  * @param string $path
  *   The Drupal path to use for the sub-request.
  * @param string $id
  *   The id to search for within the sub-request content that will contain
  *   the embedded XML.
  * @return string
  *   The embedded XML if found or an empty string.
  */
 protected function fetchXmlSubRequest($path, $id)
 {
     $xml = '';
     // We want to pass-through all details of the master request, but for some
     // reason the sub-request may fail with a 406 if some server params unique
     // to an XMLHttpRequest are used. So we reset those to generic values by
     // just removing them from the request details passed-through.
     $server = $this->request->server;
     $server->remove('HTTP_ACCEPT');
     $server->remove('HTTP_X_REQUESTED_WITH');
     $subRequest = Request::create($this->request->getBaseUrl() . '/' . $path, 'GET', $this->request->query->all(), $this->request->cookies->all(), $this->request->files->all(), $server->all());
     // @todo: See if this session check is needed.
     $session = $this->request->getSession();
     if ($session) {
         $subRequest->setSession($session);
     }
     $subResponse = $this->httpKernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
     // Search for the XML within the sub-request markup. We could parse the
     // DOM for this with DOMDocument, but a regex lookup is more lightweight.
     $matches = array();
     preg_match('/<script[^>]*id=\\"' . $id . '\\"[^>]*>(.*)<\\/script>/simU', $subResponse->getContent(), $matches);
     if (!empty($matches[1]) && strpos($matches[1], '<?xml') === 0) {
         $xml = $matches[1];
         // Set the cache tags directly from the sub-request response.
         if ($subResponse instanceof CacheableResponseInterface) {
             $response_cacheability = $subResponse->getCacheableMetadata();
             $this->cacheTags = Cache::mergeTags($this->cacheTags, $response_cacheability->getCacheTags());
         }
     }
     return $xml;
 }
Example #27
0
 /**
  * Checks the behavior of the Serializer callback paths and row plugins.
  */
 public function testSerializerResponses()
 {
     // Test the serialize callback.
     $view = Views::getView('test_serializer_display_field');
     $view->initDisplay();
     $this->executeView($view);
     $actual_json = $this->drupalGetWithFormat('test/serialize/field', 'json');
     $this->assertResponse(200);
     $this->assertCacheTags($view->getCacheTags());
     $this->assertCacheContexts(['languages:language_interface', 'theme', 'request_format']);
     // @todo Due to https://www.drupal.org/node/2352009 we can't yet test the
     // propagation of cache max-age.
     // Test the http Content-type.
     $headers = $this->drupalGetHeaders();
     $this->assertEqual($headers['content-type'], 'application/json', 'The header Content-type is correct.');
     $expected = array();
     foreach ($view->result as $row) {
         $expected_row = array();
         foreach ($view->field as $id => $field) {
             $expected_row[$id] = $field->render($row);
         }
         $expected[] = $expected_row;
     }
     $this->assertIdentical($actual_json, json_encode($expected), 'The expected JSON output was found.');
     // Test that the rendered output and the preview output are the same.
     $view->destroy();
     $view->setDisplay('rest_export_1');
     // Mock the request content type by setting it on the display handler.
     $view->display_handler->setContentType('json');
     $output = $view->preview();
     $this->assertIdentical($actual_json, (string) drupal_render_root($output), 'The expected JSON preview output was found.');
     // Test a 403 callback.
     $this->drupalGet('test/serialize/denied');
     $this->assertResponse(403);
     // Test the entity rows.
     $view = Views::getView('test_serializer_display_entity');
     $view->initDisplay();
     $this->executeView($view);
     // Get the serializer service.
     $serializer = $this->container->get('serializer');
     $entities = array();
     foreach ($view->result as $row) {
         $entities[] = $row->_entity;
     }
     $expected = $serializer->serialize($entities, 'json');
     $actual_json = $this->drupalGetWithFormat('test/serialize/entity', 'json');
     $this->assertResponse(200);
     $this->assertIdentical($actual_json, $expected, 'The expected JSON output was found.');
     $expected_cache_tags = $view->getCacheTags();
     $expected_cache_tags[] = 'entity_test_list';
     /** @var \Drupal\Core\Entity\EntityInterface $entity */
     foreach ($entities as $entity) {
         $expected_cache_tags = Cache::mergeTags($expected_cache_tags, $entity->getCacheTags());
     }
     $this->assertCacheTags($expected_cache_tags);
     $this->assertCacheContexts(['languages:language_interface', 'theme', 'entity_test_view_grants', 'request_format']);
     $expected = $serializer->serialize($entities, 'hal_json');
     $actual_json = $this->drupalGetWithFormat('test/serialize/entity', 'hal_json');
     $this->assertIdentical($actual_json, $expected, 'The expected HAL output was found.');
     $this->assertCacheTags($expected_cache_tags);
     // Change the default format to xml.
     $view->setDisplay('rest_export_1');
     $view->getDisplay()->setOption('style', array('type' => 'serializer', 'options' => array('uses_fields' => FALSE, 'formats' => array('xml' => 'xml'))));
     $view->save();
     $expected = $serializer->serialize($entities, 'xml');
     $actual_xml = $this->drupalGet('test/serialize/entity');
     $this->assertIdentical($actual_xml, $expected, 'The expected XML output was found.');
     $this->assertCacheContexts(['languages:language_interface', 'theme', 'entity_test_view_grants', 'request_format']);
     // Allow multiple formats.
     $view->setDisplay('rest_export_1');
     $view->getDisplay()->setOption('style', array('type' => 'serializer', 'options' => array('uses_fields' => FALSE, 'formats' => array('xml' => 'xml', 'json' => 'json'))));
     $view->save();
     $expected = $serializer->serialize($entities, 'json');
     $actual_json = $this->drupalGetWithFormat('test/serialize/entity', 'json');
     $this->assertIdentical($actual_json, $expected, 'The expected JSON output was found.');
     $expected = $serializer->serialize($entities, 'xml');
     $actual_xml = $this->drupalGetWithFormat('test/serialize/entity', 'xml');
     $this->assertIdentical($actual_xml, $expected, 'The expected XML output was found.');
 }
Example #28
0
 /**
  * {@inheritdoc}
  */
 public function getCacheTags()
 {
     return Cache::mergeTags(parent::getCacheTags(), $this->configFactory->get('system.site')->getCacheTags());
 }
Example #29
0
 /**
  * Invalidates an entity's cache tags upon delete.
  *
  * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
  *   The entity type definition.
  * @param \Drupal\Core\Entity\EntityInterface[] $entities
  *   An array of entities.
  */
 protected static function invalidateTagsOnDelete(EntityTypeInterface $entity_type, array $entities)
 {
     $tags = $entity_type->getListCacheTags();
     foreach ($entities as $entity) {
         // An entity was deleted: invalidate its own cache tag, but also its list
         // cache tags. (A deleted entity may cause changes in a paged list on
         // other pages than the one it's on. The one it's on is handled by its own
         // cache tag, but subsequent list pages would not be invalidated, hence we
         // must invalidate its list cache tags as well.)
         $tags = Cache::mergeTags($tags, $entity->getCacheTags());
     }
     Cache::invalidateTags($tags);
 }
Example #30
0
 /**
  * {@inheritdoc}
  */
 public function getCacheTags()
 {
     return Cache::mergeTags(['config:' . $this->name], $this->cacheTags);
 }