/** * {@inheritdoc} */ public function getCacheContexts() { // The block by itself doesn't really vary by user, but some of its // implementations are (collection module, I'm looking at you). For the sake // of semplicity, we add the user context here already. $contexts = parent::getCacheContexts(); return Cache::mergeContexts($contexts, ['user']); }
/** * Tests private profile field access. */ public function testPrivateField() { $this->drupalLogin($this->adminUser); // Create a private profile field. $edit = ['new_storage_type' => 'string', 'label' => 'Secret', 'field_name' => 'secret']; $this->drupalPostForm("admin/config/people/profiles/types/manage/{$this->type->id()}/fields/add-field", $edit, t('Save and continue')); $this->drupalPostForm(NULL, [], t('Save field settings')); $edit = ['profile_private' => 1]; $this->drupalPostForm(NULL, $edit, t('Save settings')); // Fill in a field value. $this->drupalLogin($this->webUser); $uid = $this->webUser->id(); $secret = $this->randomMachineName(); $edit = ['field_secret[0][value]' => $secret]; $this->drupalPostForm("user/{$uid}/{$this->type->id()}", $edit, t('Save')); // User cache page need to be cleared to see new profile. Cache::invalidateTags(['user:'******'user_view']); // Verify that the private field value appears for the profile owner. $this->drupalGet("user/{$uid}"); $this->assertText($secret); // Verify that the private field value appears for the administrator. $this->drupalLogin($this->adminUser); $this->drupalGet("user/{$uid}"); $this->assertText($secret); // Verify that the private field value does not appear for other users. $this->drupalLogin($this->otherUser); $this->drupalGet("user/{$uid}"); $this->assertNoText($secret); }
/** * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { module_load_include('inc', 'sociallogin'); $data = get_authentication($form_state->getValue('api_key'), $form_state->getValue('api_secret')); if (isset($data['status']) && $data['status'] != 'status') { drupal_set_message($data['message'], $data['status']); return FALSE; } parent::SubmitForm($form, $form_state); $this->config('sociallogin.settings')->set('sso_site_name', $form_state->getValue('sso_site_name'))->set('api_key', $form_state->getValue('api_key'))->set('api_secret', $form_state->getValue('api_secret'))->set('username_option', $form_state->getValue('username_option'))->set('login_redirection', $form_state->getValue('login_redirection'))->set('register_redirection', $form_state->getValue('register_redirection'))->set('custom_login_url', $form_state->getValue('custom_login_url'))->set('custom_register_url', $form_state->getValue('custom_register_url'))->set('enable_linking', $form_state->getValue('enable_linking'))->set('linking_text', $form_state->getValue('linking_text'))->save(); if (count(\Drupal::moduleHandler()->getImplementations('add_extra_sociallogin_config_settings')) > 0) { // Call all modules that implement the hook, and let them make changes to $variables. $config_data = \Drupal::moduleHandler()->invokeAll('add_extra_sociallogin_config_settings'); } if (isset($config_data) && is_array($config_data)) { foreach ($config_data as $key => $value) { $this->config('sociallogin.settings')->set($value, $form_state->getValue($value))->save(); } } drupal_set_message(t('Social Login settings have been saved.'), 'status'); //Clear page cache foreach (Cache::getBins() as $service_id => $cache_backend) { if ($service_id == 'dynamic_page_cache') { $cache_backend->deleteAll(); } } }
/** * #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; }
/** * Tests contact link. */ public function testContactLink() { $accounts = array(); $accounts['root'] = User::load(1); // Create an account with access to all contact pages. $admin_account = $this->drupalCreateUser(array('administer users')); $accounts['admin'] = $admin_account; // Create an account with no access to contact pages. $no_contact_account = $this->drupalCreateUser(); $accounts['no_contact'] = $no_contact_account; // Create an account with access to contact pages. $contact_account = $this->drupalCreateUser(array('access user contact forms')); $accounts['contact'] = $contact_account; $this->drupalLogin($admin_account); $this->drupalGet('test-contact-link'); // The admin user has access to all contact links beside his own. $this->assertContactLinks($accounts, array('root', 'no_contact', 'contact')); $this->drupalLogin($no_contact_account); $this->drupalGet('test-contact-link'); // Ensure that the user without the permission doesn't see any link. $this->assertContactLinks($accounts, array()); $this->drupalLogin($contact_account); $this->drupalGet('test-contact-link'); $this->assertContactLinks($accounts, array('root', 'admin', 'no_contact')); // Disable contact link for no_contact. $this->userData->set('contact', $no_contact_account->id(), 'enabled', FALSE); // @todo Remove cache invalidation in https://www.drupal.org/node/2477903. Cache::invalidateTags($no_contact_account->getCacheTagsToInvalidate()); $this->drupalGet('test-contact-link'); $this->assertContactLinks($accounts, array('root', 'admin')); }
/** * {@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); }
/** * {@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; }
/** * {@inheritdoc} * * Cached by role, invalidated whenever permissions change. */ public function generate(AccountInterface $account) { // User 1 is the super user, and can always access all permissions. Use a // different, unique identifier for the hash. if ($account->id() == 1) { return $this->hash('is-super-user'); } $sorted_roles = $account->getRoles(); sort($sorted_roles); $role_list = implode(',', $sorted_roles); $cid = "user_permissions_hash:{$role_list}"; if ($static_cache = $this->static->get($cid)) { return $static_cache->data; } else { $tags = Cache::buildTags('config:user.role', $sorted_roles, '.'); if ($cache = $this->cache->get($cid)) { $permissions_hash = $cache->data; } else { $permissions_hash = $this->doGenerate($sorted_roles); $this->cache->set($cid, $permissions_hash, Cache::PERMANENT, $tags); } $this->static->set($cid, $permissions_hash, Cache::PERMANENT, $tags); } return $permissions_hash; }
/** * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { $this->config('dropdown_language.setting') ->set('wrapper', $form_state->getValue('wrapper')) ->save(); parent::submitForm($form, $form_state); Cache::invalidateTags(['rendered']); }
/** * {@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; }
/** * {@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); }
/** * Tests embedded users on node pages. */ function testPictureOnNodeComment() { $this->drupalLogin($this->web_user); // Save a new picture. $image = current($this->drupalGetTestFiles('image')); $file = $this->saveUserPicture($image); $node = $this->drupalCreateNode(array('type' => 'article')); // Enable user pictures on nodes. $this->container->get('config.factory')->get('system.theme.global')->set('features.node_user_picture', TRUE)->save(); // Verify that the image is displayed on the user account page. $this->drupalGet('node/' . $node->id()); $this->assertRaw(file_uri_target($file->getFileUri()), 'User picture found on node page.'); // Enable user pictures on comments, instead of nodes. $this->container->get('config.factory')->get('system.theme.global')->set('features.node_user_picture', FALSE)->set('features.comment_user_picture', TRUE)->save(); // @todo Remove when https://www.drupal.org/node/2040135 lands. Cache::invalidateTags(['rendered']); $edit = array('comment_body[0][value]' => $this->randomString()); $this->drupalPostForm('comment/reply/node/' . $node->id() . '/comment', $edit, t('Save')); $this->assertRaw(file_uri_target($file->getFileUri()), 'User picture found on comment.'); // Disable user pictures on comments and nodes. $this->container->get('config.factory')->get('system.theme.global')->set('features.node_user_picture', FALSE)->set('features.comment_user_picture', FALSE)->save(); // @todo Remove when https://www.drupal.org/node/2040135 lands. Cache::invalidateTags(['rendered']); $this->drupalGet('node/' . $node->id()); $this->assertNoRaw(file_uri_target($file->getFileUri()), 'User picture not found on node and comment.'); }
/** * 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); }
/** * Tests the path cache. */ function testPathCache() { // Create test node. $node1 = $this->drupalCreateNode(); // Create alias. $edit = array(); $edit['source'] = '/node/' . $node1->id(); $edit['alias'] = '/' . $this->randomMachineName(8); $this->drupalPostForm('admin/config/search/path/add', $edit, t('Save')); // Check the path alias whitelist cache. $whitelist = \Drupal::cache()->get('path_alias_whitelist'); $this->assertTrue($whitelist->data['node']); $this->assertFalse($whitelist->data['admin']); // Visit the system path for the node and confirm a cache entry is // created. \Drupal::cache('data')->deleteAll(); // Make sure the path is not converted to the alias. $this->drupalGet(trim($edit['source'], '/'), array('alias' => TRUE)); $this->assertTrue(\Drupal::cache('data')->get('preload-paths:' . $edit['source']), 'Cache entry was created.'); // Visit the alias for the node and confirm a cache entry is created. \Drupal::cache('data')->deleteAll(); // @todo Remove this once https://www.drupal.org/node/2480077 lands. Cache::invalidateTags(['rendered']); $this->drupalGet(trim($edit['alias'], '/')); $this->assertTrue(\Drupal::cache('data')->get('preload-paths:' . $edit['source']), 'Cache entry was created.'); }
/** * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { $this->config('juicebox.settings')->set('apply_markup_filter', $form_state->getvalue('apply_markup_filter'))->set('enable_cors', $form_state->getvalue('enable_cors'))->set('translate_interface', $form_state->getvalue('translate_interface'))->set('base_languagelist', $form_state->getvalue('base_languagelist'))->set('juicebox_multisize_small', $form_state->getvalue('juicebox_multisize_small'))->set('juicebox_multisize_medium', $form_state->getvalue('juicebox_multisize_medium'))->set('juicebox_multisize_large', $form_state->getvalue('juicebox_multisize_large'))->save(); // These settings are global and may affect any gallery embed or XML code, // so we need to clear everything tagged with juicebox_gallery cache tag. Cache::invalidateTags(array('juicebox_gallery')); drupal_set_message(t('The Juicebox configuration options have been saved')); }
/** * Confirms that our FinishResponseSubscriber logic works properly. */ public function testFinishResponseSubscriber() { $renderer_required_cache_contexts = ['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme', 'user.permissions']; $expected_cache_contexts = Cache::mergeContexts($renderer_required_cache_contexts, ['url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT]); // Confirm that the router can get to a controller. $this->drupalGet('router_test/test1'); $this->assertRaw('test1', 'The correct string was returned because the route was successful.'); // Check expected headers from FinishResponseSubscriber. $headers = $this->drupalGetHeaders(); $this->assertEqual($headers['x-ua-compatible'], 'IE=edge'); $this->assertEqual($headers['content-language'], 'en'); $this->assertEqual($headers['x-content-type-options'], 'nosniff'); $this->assertEqual($headers['x-frame-options'], 'SAMEORIGIN'); $this->drupalGet('router_test/test2'); $this->assertRaw('test2', 'The correct string was returned because the route was successful.'); // Check expected headers from FinishResponseSubscriber. $headers = $this->drupalGetHeaders(); $this->assertEqual($headers['x-drupal-cache-contexts'], implode(' ', $expected_cache_contexts)); $this->assertEqual($headers['x-drupal-cache-tags'], 'config:user.role.anonymous rendered'); // Confirm that the page wrapping is being added, so we're not getting a // raw body returned. $this->assertRaw('</html>', 'Page markup was found.'); // In some instances, the subrequest handling may get confused and render // a page inception style. This test verifies that is not happening. $this->assertNoPattern('#</body>.*</body>#s', 'There was no double-page effect from a misrendered subrequest.'); // Confirm that route-level access check's cacheability is applied to the // X-Drupal-Cache-Contexts and X-Drupal-Cache-Tags headers. // 1. controller result: render array, globally cacheable route access. $this->drupalGet('router_test/test18'); $headers = $this->drupalGetHeaders(); $this->assertEqual($headers['x-drupal-cache-contexts'], implode(' ', Cache::mergeContexts($renderer_required_cache_contexts, ['url']))); $this->assertEqual($headers['x-drupal-cache-tags'], 'config:user.role.anonymous foo rendered'); // 2. controller result: render array, per-role cacheable route access. $this->drupalGet('router_test/test19'); $headers = $this->drupalGetHeaders(); $this->assertEqual($headers['x-drupal-cache-contexts'], implode(' ', Cache::mergeContexts($renderer_required_cache_contexts, ['url', 'user.roles']))); $this->assertEqual($headers['x-drupal-cache-tags'], 'config:user.role.anonymous foo rendered'); // 3. controller result: Response object, globally cacheable route access. $this->drupalGet('router_test/test1'); $headers = $this->drupalGetHeaders(); $this->assertFalse(isset($headers['x-drupal-cache-contexts'])); $this->assertFalse(isset($headers['x-drupal-cache-tags'])); // 4. controller result: Response object, per-role cacheable route access. $this->drupalGet('router_test/test20'); $headers = $this->drupalGetHeaders(); $this->assertFalse(isset($headers['x-drupal-cache-contexts'])); $this->assertFalse(isset($headers['x-drupal-cache-tags'])); // 5. controller result: CacheableResponse object, globally cacheable route access. $this->drupalGet('router_test/test21'); $headers = $this->drupalGetHeaders(); $this->assertEqual($headers['x-drupal-cache-contexts'], ''); $this->assertEqual($headers['x-drupal-cache-tags'], ''); // 6. controller result: CacheableResponse object, per-role cacheable route access. $this->drupalGet('router_test/test22'); $headers = $this->drupalGetHeaders(); $this->assertEqual($headers['x-drupal-cache-contexts'], 'user.roles'); $this->assertEqual($headers['x-drupal-cache-tags'], ''); }
/** * Auxiliary function to get all available drupal caches. * * @return array The all available drupal caches */ public function getCaches() { if (!$this->caches) { foreach (Cache::getBins() as $name => $bin) { $this->caches[$name] = $bin; } } return $this->caches; }
/** * {@inheritdoc} */ public function delete() { $this->data = array(); $this->storage->delete($this->name); Cache::invalidateTags($this->getCacheTags()); $this->isNew = TRUE; $this->eventDispatcher->dispatch(LanguageConfigOverrideEvents::DELETE_OVERRIDE, new LanguageConfigOverrideCrudEvent($this)); $this->originalData = $this->data; return $this; }
/** * Clear cache tables. */ public function init() { $module_handler = \Drupal::moduleHandler(); $module_handler->invokeAll('cache_flush'); // Flush drupal cache tables. foreach (Cache::getBins() as $service_id => $cache_backend) { $cache_backend->deleteAll(); } // Clear all plugin caches. \Drupal::service('plugin.cache_clearer')->clearCachedDefinitions(); $this->prepare(); }
/** * Tests that #type=link bubbles outbound route/path processors' cacheability. */ function testLinkCacheability() { $cases = [['Regular link', 'internal:/user', [], ['contexts' => [], 'tags' => [], 'max-age' => Cache::PERMANENT]], ['Regular link, absolute', 'internal:/user', ['absolute' => TRUE], ['contexts' => ['url.site'], 'tags' => [], 'max-age' => Cache::PERMANENT]], ['Route processor link', 'route:system.run_cron', [], ['contexts' => [], 'tags' => [], 'max-age' => 0]], ['Route processor link, absolute', 'route:system.run_cron', ['absolute' => TRUE], ['contexts' => ['url.site'], 'tags' => [], 'max-age' => 0]], ['Path processor link', 'internal:/user/1', [], ['contexts' => [], 'tags' => ['user:1'], 'max-age' => Cache::PERMANENT]], ['Path processor link, absolute', 'internal:/user/1', ['absolute' => TRUE], ['contexts' => ['url.site'], 'tags' => ['user:1'], 'max-age' => Cache::PERMANENT]]]; foreach ($cases as $case) { list($title, $uri, $options, $expected_cacheability) = $case; $expected_cacheability['contexts'] = Cache::mergeContexts($expected_cacheability['contexts'], ['languages:language_interface', 'theme']); $link = ['#type' => 'link', '#title' => $title, '#options' => $options, '#url' => Url::fromUri($uri)]; \Drupal::service('renderer')->renderRoot($link); $this->pass($title); $this->assertEqual($expected_cacheability, $link['#cache']); } }
/** * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { $consumer_key = user_password(32); $consumer_secret = user_password(32); $key_hash = sha1($consumer_key); $uid = $form_state->getValue('uid'); $consumer = array('consumer_secret' => $consumer_secret, 'key_hash' => $key_hash); $this->user_data->set('oauth', $uid, $consumer_key, $consumer); drupal_set_message($this->t('Added a new consumer.')); Cache::invalidateTags(['oauth:' . $uid]); $form_state->setRedirect('oauth.user_consumer', array('user' => $uid)); }
/** * {@inheritdoc} */ public function invalidateTags(array $tags) { // Validate the tags. Cache::validateTags($tags); // Notify all added cache tags invalidators. foreach ($this->invalidators as $invalidator) { $invalidator->invalidateTags($tags); } // Additionally, notify each cache bin if it implements the service. foreach ($this->getInvalidatorCacheBins() as $bin) { $bin->invalidateTags($tags); } }
/** * Callback function called by the batch API when all operations are finished. * * @see https://api.drupal.org/api/drupal/core!includes!form.inc/group/batch/8 */ public static function finishGeneration($success, $results, $operations) { if ($success) { $remove_sitemap = empty($results['chunk_count']); if (!empty($results['generate']) || $remove_sitemap) { \Drupal::service('simple_sitemap.sitemap_generator')->generateSitemap($results['generate'], $remove_sitemap); } Cache::invalidateTags(['simple_sitemap']); drupal_set_message(t("The <a href='@url' target='_blank'>XML sitemap</a> has been regenerated for all languages.", ['@url' => $GLOBALS['base_url'] . '/sitemap.xml'])); } else { //todo: register error } }
/** * {@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} * * Cached by role, invalidated whenever permissions change. */ public function generate(AccountInterface $account) { $sorted_roles = $account->getRoles(); sort($sorted_roles); $role_list = implode(',', $sorted_roles); if ($cache = $this->cache->get("user_permissions_hash:{$role_list}")) { $permissions_hash = $cache->data; } else { $permissions_hash = $this->doGenerate($sorted_roles); $tags = Cache::buildTags('config:user.role', $sorted_roles, '.'); $this->cache->set("user_permissions_hash:{$role_list}", $permissions_hash, Cache::PERMANENT, $tags); } return $permissions_hash; }
/** * {@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); }
/** * Tests drupal_flush_all_caches(). */ function testFlushAllCaches() { // Create cache entries for each flushed cache bin. $bins = Cache::getBins(); $this->assertTrue($bins, 'Cache::getBins() returned bins to flush.'); foreach ($bins as $bin => $cache_backend) { $cid = 'test_cid_clear' . $bin; $cache_backend->set($cid, $this->defaultValue); } // Remove all caches then make sure that they are cleared. drupal_flush_all_caches(); foreach ($bins as $bin => $cache_backend) { $cid = 'test_cid_clear' . $bin; $this->assertFalse($this->checkCacheExists($cid, $this->defaultValue, $bin), format_string('All cache entries removed from @bin.', array('@bin' => $bin))); } }
/** * Tests adding and editing values using metatag. */ public function testMetatag() { // Create a test entity. $edit = ['name[0][value]' => 'Barfoo', 'user_id[0][target_id]' => 'foo (' . $this->adminUser->id() . ')', 'field_metatag[0][basic][metatag_test]' => 'Kilimanjaro']; $this->drupalPostForm('entity_test/add', $edit, t('Save')); $entities = entity_load_multiple_by_properties('entity_test', ['name' => 'Barfoo']); $this->assertEqual(1, count($entities), 'Entity was saved'); $entity = reset($entities); // Make sure tags that have a field value but no default value still show // up. $this->drupalGet('entity_test/' . $entity->id()); $this->assertResponse(200); $elements = $this->cssSelect('meta[name=metatag_test]'); $this->assertTrue(count($elements) === 1, 'Found keywords metatag_test from defaults'); $this->assertEqual((string) $elements[0]['content'], 'Kilimanjaro', 'Field value for metatag_test found when no default set.'); // @TODO: This should not be required, but metatags does not invalidate // cache upon setting globals. Cache::invalidateTags(array('entity_test:' . $entity->id())); // Update the Global defaults and test them. $values = array('keywords' => 'Purple monkey dishwasher'); $this->drupalPostForm('admin/config/search/metatag/global', $values, 'Save'); $this->assertText('Saved the Global Metatag defaults.'); $this->drupalGet('entity_test/' . $entity->id()); $this->assertResponse(200); $elements = $this->cssSelect('meta[name=keywords]'); $this->assertTrue(count($elements) === 1, 'Found keywords metatag from defaults'); $this->assertEqual((string) $elements[0]['content'], $values['keywords'], 'Default keywords applied'); // Tests metatags with URLs work. $edit = ['name[0][value]' => 'UrlTags', 'user_id[0][target_id]' => 'foo (' . $this->adminUser->id() . ')', 'field_metatag[0][advanced][original_source]' => 'http://example.com/foo.html']; $this->drupalPostForm('entity_test/add', $edit, t('Save')); $entities = entity_load_multiple_by_properties('entity_test', ['name' => 'UrlTags']); $this->assertEqual(1, count($entities), 'Entity was saved'); $entity = reset($entities); $this->drupalGet('entity_test/' . $entity->id()); $this->assertResponse(200); $elements = $this->cssSelect("meta[name='original-source']"); $this->assertTrue(count($elements) === 1, 'Found original source metatag from defaults'); $this->assertEqual((string) $elements[0]['content'], $edit['field_metatag[0][advanced][original_source]']); // Test a route where the entity for that route does not implement // ContentEntityInterface. $controller = \Drupal::entityTypeManager()->getStorage('contact_form'); $controller->create(array('id' => 'test_contact_form'))->save(); $account = $this->drupalCreateUser(array('access site-wide contact form')); $this->drupalLogin($account); $this->drupalGet('contact/test_contact_form'); $this->assertResponse(200); }
/** * 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.'); }