/** * 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 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']); }
/** * 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 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.'); }
/** * 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) { $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')); }
/** * {@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; }
/** * {@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)); }
/** * 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 } }
/** * 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); }
public function testTagInvalidations() { // Create cache entry in multiple bins. $tags = array('test_tag' => array(1, 2, 3)); $bins = array('data', 'bootstrap', 'render'); foreach ($bins as $bin) { $bin = \Drupal::cache($bin); $bin->set('test', 'value', Cache::PERMANENT, $tags); $this->assertTrue($bin->get('test'), 'Cache item was set in bin.'); } $invalidations_before = intval(db_select('cachetags')->fields('cachetags', array('invalidations'))->condition('tag', 'test_tag:2')->execute()->fetchField()); Cache::invalidateTags(array('test_tag' => array(2))); // Test that cache entry has been invalidated in multiple bins. foreach ($bins as $bin) { $bin = \Drupal::cache($bin); $this->assertFalse($bin->get('test'), 'Tag invalidation affected item in bin.'); } // Test that only one tag invalidation has occurred. $invalidations_after = intval(db_select('cachetags')->fields('cachetags', array('invalidations'))->condition('tag', 'test_tag:2')->execute()->fetchField()); $this->assertEqual($invalidations_after, $invalidations_before + 1, 'Only one addition cache tag invalidation has occurred after invalidating a tag used in multiple bins.'); }
/** * Test that cache tags are properly persisted. * * Since tag based invalidation works, we know that our tag properly * persisted. */ function testPageCacheTags() { $config = $this->config('system.performance'); $config->set('cache.page.max_age', 300); $config->save(); $path = 'system-test/cache_tags_page'; $tags = array('system_test_cache_tags_page'); $this->drupalGet($path); $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS'); // Verify a cache hit, but also the presence of the correct cache tags. $this->drupalGet($path); $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT'); $cid_parts = array(\Drupal::url('system_test.cache_tags_page', array(), array('absolute' => TRUE)), 'html'); $cid = implode(':', $cid_parts); $cache_entry = \Drupal::cache('render')->get($cid); sort($cache_entry->tags); $expected_tags = array('pre_render', 'rendered', 'system_test_cache_tags_page'); $this->assertIdentical($cache_entry->tags, $expected_tags); Cache::invalidateTags($tags); $this->drupalGet($path); $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS'); }
/** * Tests the flow of a profile type that has multiple enabled. */ public function testMultipleProfileType() { $this->drupalLogin($this->adminUser); $edit = ['multiple' => 1]; $this->drupalPostForm("admin/config/people/profiles/types/manage/{$this->type->id()}", $edit, t('Save')); $this->assertRaw(new FormattableMarkup('%type profile type has been updated.', ['%type' => $this->type->label()])); $web_user1 = $this->drupalCreateUser(["view own {$this->type->id()} profile", "add own {$this->type->id()} profile", "edit own {$this->type->id()} profile"]); $this->drupalLogin($web_user1); $value = $this->randomMachineName(); $edit = ["{$this->field->getName()}[0][value]" => $value]; $this->drupalPostForm("user/{$web_user1->id()}/{$this->type->id()}", $edit, t('Save')); $this->assertRaw(new FormattableMarkup('%type profile has been created.', ['%type' => $this->type->label()])); $this->drupalGet("user/{$web_user1->id()}/{$this->type->id()}"); $this->assertLinkByHref("user/{$web_user1->id()}/{$this->type->id()}/add"); $this->assertText($value); $value2 = $this->randomMachineName(); $edit = ["{$this->field->getName()}[0][value]" => $value2]; $this->drupalPostForm("user/{$web_user1->id()}/{$this->type->id()}/add", $edit, t('Save')); $this->assertRaw(new FormattableMarkup('%type profile has been created.', ['%type' => $this->type->label()])); Cache::invalidateTags(['profile_view']); $this->drupalGet("user/{$web_user1->id()}/{$this->type->id()}"); $this->assertText($value2); }
/** * Create a "Basic page" node and verify its consistency in the database. */ function testNodeViewModeChange() { $web_user = $this->drupalCreateUser(array('create page content', 'edit own page content')); $this->drupalLogin($web_user); // Create a node. $edit = array(); $edit['title[0][value]'] = $this->randomMachineName(8); $edit['body[0][value]'] = t('Data that should appear only in the body for the node.'); $edit['body[0][summary]'] = t('Extra data that should appear only in the teaser for the node.'); $this->drupalPostForm('node/add/page', $edit, t('Save')); $node = $this->drupalGetNodeByTitle($edit['title[0][value]']); // Set the flag to alter the view mode and view the node. \Drupal::state()->set('node_test_change_view_mode', 'teaser'); Cache::invalidateTags(['rendered']); $this->drupalGet('node/' . $node->id()); // Check that teaser mode is viewed. $this->assertText('Extra data that should appear only in the teaser for the node.', 'Teaser text present'); // Make sure body text is not present. $this->assertNoText('Data that should appear only in the body for the node.', 'Body text not present'); // Test that the correct build mode has been set. $build = $this->drupalBuildEntityView($node); $this->assertEqual($build['#view_mode'], 'teaser', 'The view mode has correctly been set to teaser.'); }
/** * Test "user.roles" cache context. */ function testCachePerRole() { \Drupal::state()->set('block_test.cache_contexts', ['user.roles']); // Enable our test block. Set some content for it to display. $current_content = $this->randomMachineName(); \Drupal::state()->set('block_test.content', $current_content); $this->drupalLogin($this->normalUser); $this->drupalGet(''); $this->assertText($current_content, 'Block content displays.'); // Change the content, but the cached copy should still be served. $old_content = $current_content; $current_content = $this->randomMachineName(); \Drupal::state()->set('block_test.content', $current_content); $this->drupalGet(''); $this->assertText($old_content, 'Block is served from the cache.'); // Clear the cache and verify that the stale data is no longer there. Cache::invalidateTags(array('block_view')); $this->drupalGet(''); $this->assertNoText($old_content, 'Block cache clear removes stale cache data.'); $this->assertText($current_content, 'Fresh block content is displayed after clearing the cache.'); // Test whether the cached data is served for the correct users. $old_content = $current_content; $current_content = $this->randomMachineName(); \Drupal::state()->set('block_test.content', $current_content); $this->drupalLogout(); $this->drupalGet(''); $this->assertNoText($old_content, 'Anonymous user does not see content cached per-role for normal user.'); $this->drupalLogin($this->normalUserAlt); $this->drupalGet(''); $this->assertText($old_content, 'User with the same roles sees per-role cached content.'); $this->drupalLogin($this->adminUser); $this->drupalGet(''); $this->assertNoText($old_content, 'Admin user does not see content cached per-role for normal user.'); $this->drupalLogin($this->normalUser); $this->drupalGet(''); $this->assertText($old_content, 'Block is served from the per-role cache.'); }
/** * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { parent::submitForm($form, $form_state); /** @var $index \Drupal\search_api\IndexInterface */ $index = $this->getEntity(); $index->setOptions($form_state->getValue('options', array()) + $this->originalEntity->getOptions()); $datasources = $form_state->getValue('datasources', array()); /** @var \Drupal\search_api\Datasource\DatasourceInterface[] $datasource_plugins */ $datasource_plugins = $this->originalEntity->getDatasources(FALSE); $datasource_configuration = array(); foreach ($datasources as $datasource_id) { $datasource = $datasource_plugins[$datasource_id]; $datasource_form = !empty($form['datasource_configs'][$datasource_id]) ? $form['datasource_configs'][$datasource_id] : array(); $datasource_form_state = new SubFormState($form_state, array('datasource_configs', $datasource_id)); $datasource->submitConfigurationForm($datasource_form, $datasource_form_state); $datasource_configuration[$datasource_id] = $datasource->getConfiguration(); } $index->set('datasource_configs', $datasource_configuration); // Call submitConfigurationForm() for the (possibly new) tracker. // @todo It seems if we change the tracker, we would validate/submit the old // tracker's form using the new tracker. Shouldn't be done, of course. // Similar above for datasources, though there of course the values will // just always be empty (because datasources have their plugin ID in the // form structure). $tracker_id = $form_state->getValue('tracker', NULL); if ($this->originalEntity->getTrackerId() == $tracker_id) { $tracker = $this->originalEntity->getTracker(); } else { $tracker = $this->trackerPluginManager->createInstance($tracker_id, array('index' => $this->originalEntity)); } $tracker_form_state = new SubFormState($form_state, array('tracker_config')); $tracker->submitConfigurationForm($form['tracker_config'], $tracker_form_state); $index->set('tracker_config', $tracker->getConfiguration()); // Invalidate caches, so this gets picked up by the views wizard. Cache::invalidateTags(array('views_data')); // Remove this line when https://www.drupal.org/node/2370365 gets fixed. Cache::invalidateTags(array('extension:views')); }
/** * {@inheritdoc} */ public function clearCachedBundles() { $this->bundleInfo = array(); Cache::invalidateTags(array('entity_bundles')); // Entity bundles are exposed as data types, clear that cache too. $this->typedDataManager->clearCachedDefinitions(); }
/** * {@inheritdoc} */ public function clearCachedDefinitions() { if ($this->cacheBackend) { if ($this->cacheTags) { // Use the cache tags to clear the cache. Cache::invalidateTags($this->cacheTags); } else { $this->cacheBackend->delete($this->cacheKey); } } $this->definitions = NULL; }
/** * Clear out cached data for a view. */ public function cacheFlush() { Cache::invalidateTags($this->view->storage->getCacheTags()); }
/** * {@inheritdoc} */ public function disable() { // An entity was disabled, invalidate its own cache tag. Cache::invalidateTags($this->getCacheTags()); return $this->setStatus(FALSE); }
/** * Tests various code snippets. */ function testSnippets() { $container = \Drupal::getContainer(); // Cache snippets from section "The Drupal Cache" in Chapter 1. // Make up some test data. $bin = 'default'; $cid = 'my_cid'; $data = 'my_data'; $nid = 5; $tags = array('node:' . $nid); // Cache the data. Get the class in two different ways. $cache_class = \Drupal::cache($bin); $this->assertTrue($cache_class, 'Cache class is not null'); $cache_class = $container->get('cache.' . $bin); $cache_class->set($cid, $data, CacheBackendInterface::CACHE_PERMANENT, $tags); // Check that we can retrieve data from the cache. $out = $cache_class->get($cid); $this->outputVariable($out, 'Cache get method output'); $this->assertEqual($data, $out->data, 'Cached data could be retrieved'); // Invalidate the data and check that it cannot be retrieved. Cache::invalidateTags($tags); $out = $cache_class->get($cid); $this->assertFalse($out, 'After invalidating tags, cached data cannot be retrieved'); // Theme snippets from section "Making Your Output Themeable" in Chapter 2. $build['hello'] = array('#input1' => t('Hello World!'), '#theme' => 'mymodule_hookname'); $output = drupal_render_root($build); $expected = '<div>Hello World!</div>'; $this->outputHTML($output, 'Theme template output'); $this->assertEqual(trim($output), $expected, 'Theme template worked in render array'); // Config API snippets from "Configuration API in Drupal 8" section in // chapter 2. // Test reading the settings several different ways. $config = \Drupal::config('mymodule.settings'); $this->assertTrue($config, 'Config class is not null'); $config = $container->get('config.factory')->getEditable('mymodule.settings'); $all = $config->get(); $this->outputVariable($all, 'Full configuration output'); $button_label = $all['submit_button_label']; $this->assertEqual($button_label, 'Submit', 'Read correct button label from overall get'); $button_label = $config->get('submit_button_label'); $this->assertEqual($button_label, 'Submit', 'Read correct button label with specific get'); $name_field_info = $all['name_field_settings']; $name_label = $name_field_info['field_label']; $this->assertEqual($name_label, 'Your name', 'Read correct name field label from overall get'); $name_field_info = $config->get('name_field_settings'); $this->outputVariable($name_field_info, 'Name field configuration output'); $name_label = $name_field_info['field_label']; $this->assertEqual($name_label, 'Your name', 'Read correct name field label from field settings get'); $name_label = $config->get('name_field_settings.field_label'); $this->assertEqual($name_label, 'Your name', 'Read correct name field label from specific get'); // Change the submit label. $new_label = "Save"; $config->set('submit_button_label', $new_label); $config->save(); // Get a new config object, to make sure it was really saved. $new_config = \Drupal::config('mymodule.settings'); $button_label = $new_config->get('submit_button_label'); $this->assertEqual($button_label, 'Save', 'Read correct button label after save'); // State API snippets from "State API in Drupal 8" section in chapter 2. // Get $state in two ways. $state = \Drupal::state(); $this->assertTrue($state, 'State is not null'); $state = $container->get('state'); $value = 'Some test data'; $state->set('mymodule.my_state_variable_name', $value); $new_value = $state->get('mymodule.my_state_variable_name'); $this->assertEqual($value, $new_value, 'State get worked correctly'); $state->delete('mymodule.my_state_variable_name'); $new_value = $state->get('mymodule.my_state_variable_name'); $this->assertNull($new_value, 'After delete, could not retrieve state value'); // Snippets from "Internationalizing User Interface Text" section in // chapter 2. Good code only; bad code examples are omitted. $button_text = t('Save'); $this->assertEqual($button_text, 'Save', 't() worked OK on simple string'); $user_name = 'foo'; $message_string = t('Hello @user_name', array('@user_name' => $user_name)); $this->outputHTML($message_string, 't() with variables output'); $this->assertEqual($message_string, 'Hello foo', 't() worked OK on string with variable'); $test = (object) array(); $foo = $test instanceof MyClass; // Database snippets from "Querying the Database with the Database API" // section in Chapter 2. // Make a blocked user for querying purposes. $account = $this->drupalCreateUser(array()); $account->status = 0; $account->save(); // Query by status 0 (blocked). $desired_status = 0; $found = FALSE; $result = db_query('SELECT * FROM {users_field_data} u WHERE u.status = :status', array(':status' => $desired_status)); foreach ($result as $record) { $this->outputVariable($record, 'User database record'); if ($record->uid == $account->id()) { $found = TRUE; } } $this->assertTrue($found, 'Created user was found by status query'); // Test the ability to query by user name. $found = FALSE; $result = db_query('SELECT * FROM {users_field_data} u WHERE u.name = :name', array(':name' => $account->getUsername())); foreach ($result as $record) { if ($record->uid == $account->id()) { $found = TRUE; } } $this->assertTrue($found, 'Created user was found by name query'); // Create a node, for query purposes. $newnode = $this->drupalCreateNode(); // Log in as user who can access content. $account = $this->drupalCreateUser(array('access content')); $this->drupalLogin($account); $query = db_select('node', 'n'); $query->innerJoin('node_field_data', 'nd', 'n.nid = nd.nid AND n.vid = nd.vid'); $query->innerJoin('users_field_data', 'u', 'u.uid = nd.uid'); $query->addField('nd', 'changed', 'last_updated'); $query->extend('Drupal\\Core\\Database\\Query\\PagerSelectExtender')->limit(20)->fields('nd', array('title', 'nid'))->fields('u', array('name'))->addTag('node_access')->condition('nd.status', 1); $result = $query->execute(); $found = FALSE; foreach ($result as $node) { $title = $node->title; if ($node->nid == $newnode->id()) { $found = TRUE; $this->verbose("Found node with title {$title}"); } } $this->assertTrue($found, "Found node in query"); // Snippets from the "Cleansing and Checking User-Provided Input" // section in Chapter 2. Only "good" code is included. $text = '<h2>Text with HTML</h2>'; $plain_text = htmlentities($text); $url = 'http://example.com'; $url_object = Url::fromUri($url); $output = Drupal::l($text, $url_object); $this->outputHTML($output, 'l() output'); $this->assertEqual($output, '<a href="' . $url . '">' . $plain_text . '</a>', 'l output is as expected'); // Form builder snippet from "Basic Form Generation and Processing in // Drupal 8", chapter 4. $my_render_array['personal_data_form'] = \Drupal::formBuilder()->getForm('Drupal\\mymodule\\Form\\PersonalDataForm'); $this->outputVariable($my_render_array, 'Personal data form array'); $this->assertTrue(isset($my_render_array['personal_data_form']['first_name']), 'First name field is present in form array'); $builder = $container->get('form_builder'); $my_render_array['personal_data_form'] = $builder->getForm('Drupal\\mymodule\\Form\\PersonalDataForm'); $this->assertTrue(isset($my_render_array['personal_data_form']['first_name']), 'First name field is present in form array'); // Entity query snippets from "Querying and Loading Entities in Drupal 8", // chapter 4. // Try various methods for retrieving the query. $query = \Drupal::entityQuery('node'); $this->assertTrue($query, 'Query is not null'); $query = \Drupal::entityQueryAggregate('node'); $this->assertTrue($query, 'Query is not null'); $query_service = $container->get('entity.query'); $query = $query_service->getAggregate('node'); $this->assertTrue($query, 'Query is not null'); // Try an actual query. $query = $query_service->get('node'); $query->condition('type', $newnode->getType()); $ids = $query->execute(); // Try different methods of getting storage manager. $storage = \Drupal::entityManager()->getStorage('node'); $this->assertTrue($storage, 'Storage is not null'); // Load the entities and verify. $storage = $container->get('entity.manager')->getStorage('node'); $entities = $storage->loadMultiple($ids); $this->assertEqual(count($entities), 1, 'One node was found'); $first = reset($entities); $this->assertEqual($first->getTitle(), $newnode->getTitle(), 'Correct node was found'); }
/** * Test the setting of forms to be immutable. */ public function testFormImmutability() { // Install the module that provides the test form. $this->container->get('module_installer')->install(['page_cache_form_test']); // Uninstall the page_cache module to verify that form is immutable // regardless of the internal page cache module. $this->container->get('module_installer')->uninstall(['page_cache']); \Drupal::service('router.builder')->rebuild(); $this->drupalGet('page_cache_form_test_immutability'); $this->assertText("Immutable: TRUE", "Form is immutable."); // The immutable flag is set unconditionally by system_form_alter(), set // a flag to tell page_cache_form_test_module_implements_alter() to disable // that implementation. \Drupal::state()->set('page_cache_bypass_form_immutability', TRUE); \Drupal::moduleHandler()->resetImplementations(); Cache::invalidateTags(['rendered']); $this->drupalGet('page_cache_form_test_immutability'); $this->assertText("Immutable: FALSE", "Form is not immutable,"); }
/** * Invalidates theme registry caches. * * To be called when the list of enabled extensions is changed. */ public function reset() { // Reset the runtime registry. foreach ($this->runtimeRegistry as $runtime_registry) { $runtime_registry->clear(); } $this->runtimeRegistry = []; $this->registry = []; Cache::invalidateTags(array('theme_registry')); return $this; }
/** * {@inheritdoc} * * Override to never invalidate the individual entities' cache tags; the * config system already invalidates them. */ protected static function invalidateTagsOnDelete(EntityTypeInterface $entity_type, array $entities) { Cache::invalidateTags($entity_type->getListCacheTags()); }
/** * Allow modules to respond to the invalidation of the Views cache. * * This hook will fire whenever a view is enabled, disabled, created, * updated, or deleted. * * @see views_invalidate_cache() */ function hook_views_invalidate_cache() { \Drupal\Core\Cache\Cache::invalidateTags(array('views' => TRUE)); }
/** * {@inheritdoc} */ public function saveBookLink(array $link, $new) { // Keep track of Book IDs for cache clear. $affected_bids[$link['bid']] = $link['bid']; $link += $this->getLinkDefaults($link['nid']); if ($new) { // Insert new. $parents = $this->getBookParents($link, (array) $this->loadBookLink($link['pid'], FALSE)); $this->bookOutlineStorage->insert($link, $parents); // Update the has_children status of the parent. $this->updateParent($link); } else { $original = $this->loadBookLink($link['nid'], FALSE); // Using the Book ID as the key keeps this unique. $affected_bids[$original['bid']] = $original['bid']; // Handle links that are moving. if ($link['bid'] != $original['bid'] || $link['pid'] != $original['pid']) { // Update the bid for this page and all children. if ($link['pid'] == 0) { $link['depth'] = 1; $parent = array(); } elseif (($parent_link = $this->loadBookLink($link['pid'], FALSE)) && $parent_link['bid'] != $link['bid']) { $link['pid'] = $link['bid']; $parent = $this->loadBookLink($link['pid'], FALSE); $link['depth'] = $parent['depth'] + 1; } else { $parent = $this->loadBookLink($link['pid'], FALSE); $link['depth'] = $parent['depth'] + 1; } $this->setParents($link, $parent); $this->moveChildren($link, $original); // Update the has_children status of the original parent. $this->updateOriginalParent($original); // Update the has_children status of the new parent. $this->updateParent($link); } // Update the weight and pid. $this->bookOutlineStorage->update($link['nid'], array('weight' => $link['weight'], 'pid' => $link['pid'], 'bid' => $link['bid'])); } $cache_tags = []; foreach ($affected_bids as $bid) { $cache_tags[] = 'bid:' . $bid; } Cache::invalidateTags($cache_tags); return $link; }
/** * {@inheritdoc} */ public function postSave(EntityStorageInterface $storage, $update = TRUE) { parent::postSave($storage, $update); // Entity::postSave() calls Entity::invalidateTagsOnSave(), which only // handles the regular cases. The Item entity has one special case: a newly // created Item is *also* associated with a Feed, so we must invalidate the // associated Feed's cache tag. if (!$update) { Cache::invalidateTags($this->getCacheTagsToInvalidate()); } }
/** * 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); }
/** * 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); }
/** * Test that cache tags are properly set and bubbled up to the page cache. * * Verify that invalidation of these cache tags works: * - "block:<block ID>" * - "block_plugin:<block plugin ID>" */ public function testBlockCacheTags() { // The page cache only works for anonymous users. $this->drupalLogout(); // Enable page caching. $config = \Drupal::config('system.performance'); $config->set('cache.page.use_internal', 1); $config->set('cache.page.max_age', 300); $config->save(); // Place the "Powered by Drupal" block. $block = $this->drupalPlaceBlock('system_powered_by_block', array('id' => 'powered', 'cache' => array('max_age' => 315360000))); // Prime the page cache. $this->drupalGet('<front>'); $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS'); // Verify a cache hit, but also the presence of the correct cache tags in // both the page and block caches. $this->drupalGet('<front>'); $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT'); $cid_parts = array(url('<front>', array('absolute' => TRUE)), 'html'); $cid = sha1(implode(':', $cid_parts)); $cache_entry = \Drupal::cache('render')->get($cid); $expected_cache_tags = array('theme:stark', 'theme_global_settings:1', 'block_view:1', 'block:powered', 'block_plugin:system_powered_by_block', 'rendered:1'); $this->assertIdentical($cache_entry->tags, $expected_cache_tags); $cache_entry = \Drupal::cache('render')->get('entity_view:block:powered:en:stark'); $expected_cache_tags = array('block_view:1', 'block:powered', 'theme:stark', 'block_plugin:system_powered_by_block', 'rendered:1'); $this->assertIdentical($cache_entry->tags, $expected_cache_tags); // The "Powered by Drupal" block is modified; verify a cache miss. $block->set('region', 'content'); $block->save(); $this->drupalGet('<front>'); $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS'); // Now we should have a cache hit again. $this->drupalGet('<front>'); $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT'); // Place the "Powered by Drupal" block another time; verify a cache miss. $block_2 = $this->drupalPlaceBlock('system_powered_by_block', array('id' => 'powered-2', 'cache' => array('max_age' => 315360000))); $this->drupalGet('<front>'); $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS'); // Verify a cache hit, but also the presence of the correct cache tags. $this->drupalGet('<front>'); $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT'); $cid_parts = array(url('<front>', array('absolute' => TRUE)), 'html'); $cid = sha1(implode(':', $cid_parts)); $cache_entry = \Drupal::cache('render')->get($cid); $expected_cache_tags = array('theme:stark', 'theme_global_settings:1', 'block_view:1', 'block:powered-2', 'block:powered', 'block_plugin:system_powered_by_block', 'rendered:1'); $this->assertEqual($cache_entry->tags, $expected_cache_tags); $expected_cache_tags = array('block_view:1', 'block:powered', 'theme:stark', 'block_plugin:system_powered_by_block', 'rendered:1'); $cache_entry = \Drupal::cache('render')->get('entity_view:block:powered:en:stark'); $this->assertIdentical($cache_entry->tags, $expected_cache_tags); $expected_cache_tags = array('block_view:1', 'block:powered-2', 'theme:stark', 'block_plugin:system_powered_by_block', 'rendered:1'); $cache_entry = \Drupal::cache('render')->get('entity_view:block:powered-2:en:stark'); $this->assertIdentical($cache_entry->tags, $expected_cache_tags); // The plugin providing the "Powered by Drupal" block is modified; verify a // cache miss. Cache::invalidateTags(array('block_plugin:system_powered_by_block')); $this->drupalGet('<front>'); $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS'); // Now we should have a cache hit again. $this->drupalGet('<front>'); $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT'); // Delete the "Powered by Drupal" blocks; verify a cache miss. entity_delete_multiple('block', array('powered', 'powered-2')); $this->drupalGet('<front>'); $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS'); }