/** * Tests if a translated and tokenized string is properly escaped by Twig. * * In each assert* call we add a new line at the expected result to match the * newline at the end of the template file. */ public function testLocalizedTokenizedString() { $tests_to_do = [1 => ['original' => 'Go to the <a href="[locale_test:security_test1]">frontpage</a>', 'replaced' => 'Go to the <a href="javascript:alert(&#039;Mooooh!&#039;);">frontpage</a>'], 2 => ['original' => 'Hello <strong>[locale_test:security_test2]</strong>!', 'replaced' => 'Hello <strong>&lt;script&gt;alert(&#039;Mooooh!&#039;);&lt;/script&gt;</strong>!']]; foreach ($tests_to_do as $i => $test) { $original_string = $test['original']; $rendered_original_string = \Drupal::theme()->render('locale_test_tokenized', ['content' => $original_string]); // Twig assumes that strings are unsafe so it escapes them, and so the // original and the rendered version should be different. $this->assertNotEqual($rendered_original_string, $original_string . "\n", 'Security test ' . $i . ' before translation'); // Pass the original string to the t() function to get it marked as safe. $safe_string = t($original_string); $rendered_safe_string = \Drupal::theme()->render('locale_test_tokenized', ['content' => $safe_string]); // t() function always marks the string as safe so it won't be escaped, // and should be the same as the original. $this->assertEqual($rendered_safe_string, $original_string . "\n", 'Security test ' . $i . ' after translation before token replacement'); // Replace tokens in the safe string to inject it with dangerous content. // @see locale_test_tokens(). $unsafe_string = \Drupal::token()->replace($safe_string); $rendered_unsafe_string = \Drupal::theme()->render('locale_test_tokenized', ['content' => $unsafe_string]); // Token replacement changes the string so it is not marked as safe // anymore. Check it is escaped the way we expect. $this->assertEqual($rendered_unsafe_string, $test['replaced'] . "\n", 'Security test ' . $i . ' after translation after token replacement'); } }
/** * {@inheritdoc} */ public function massageRenderValues(&$field_settings, $values) { if (isset($values['classes'])) { $classes = is_array($values['classes']) ? implode(' ', $values['classes']) : $values['classes']; if (!empty($classes)) { $field_settings['classes'] = $classes; } } // Token replacement. if ($entity = $this->getEntity()) { // Tokens $apply_to = array( 'classes', ); foreach ($apply_to as $identifier) { $field_settings[$identifier] = \Drupal::token()->replace( $field_settings[$identifier], array($entity->getEntityTypeId() => $entity), array('clear' => TRUE) ); } } parent::massageRenderValues($field_settings, $values); }
/** * {@inheritdoc} */ public function completeSale($order, $login = FALSE) { // Empty that cart... $this->emptyCart(); // Force the order to load from the DB instead of the entity cache. // @todo Remove this once uc_payment_enter() can modify order objects? // @todo Should we be overwriting $order with this newly-loaded db_order? $db_order = $this->entityManager()->getStorage('uc_order')->loadUnchanged($order->id()); $order->data = $db_order->data; // Ensure that user creation and triggers are only run once. if (empty($order->data->complete_sale)) { $this->completeSaleAccount($order); // Move an order's status from "In checkout" to "Pending". if ($order->getStateId() == 'in_checkout') { $order->setStatusId(uc_order_state_default('post_checkout')); } $order->save(); // Invoke the checkout complete trigger and hook. $account = $order->getUser(); $this->moduleHandler()->invokeAll('uc_checkout_complete', array($order, $account)); // rules_invoke_event('uc_checkout_complete', $order); } $type = $order->data->complete_sale; // Log in new users, if requested. if ($type == 'new_user' && $login && $this->currentUser()->isAnonymous()) { $type = 'new_user_logged_in'; user_login_finalize($order->getUser()); } $message = $this->config('uc_cart.messages')->get($type); $message = \Drupal::token()->replace($message, array('uc_order' => $order)); $variables['!new_username'] = isset($order->data->new_user_name) ? $order->data->new_user_name : ''; $variables['!new_password'] = isset($order->password) ? $order->password : t('Your password'); $message = strtr($message, $variables); return array('#theme' => 'uc_cart_complete_sale', '#message' => Xss::filterAdmin($message), '#order' => $order); }
/** * {@inheritdoc} */ public function viewElements(FieldItemListInterface $items) { $element = array(); $entity = $items->getEntity(); $settings = $this->getSettings(); foreach ($items as $delta => $item) { // By default use the full URL as the link text. $url = $this->buildUrl($item); $link_title = $url->toString(); // If the link text field value is available, use it for the text. if (empty($settings['url_only']) && !empty($item->title)) { // Unsanitized token replacement here because $options['html'] is FALSE // by default in l(). $link_title = \Drupal::token()->replace($item->title, array($entity->getEntityTypeId() => $entity), array('sanitize' => FALSE, 'clear' => TRUE)); } // The link_separate formatter has two titles; the link text (as in the // field values) and the URL itself. If there is no link text value, // $link_title defaults to the URL, so it needs to be unset. // The URL version may need to be trimmed as well. if (empty($item->title)) { $link_title = NULL; } $url_title = $url->toString(); if (!empty($settings['trim_length'])) { $link_title = truncate_utf8($link_title, $settings['trim_length'], FALSE, TRUE); $url_title = truncate_utf8($url_title, $settings['trim_length'], FALSE, TRUE); } $element[$delta] = array('#theme' => 'link_formatter_link_separate', '#title' => $link_title, '#url_title' => $url_title, '#url' => $url); } return $element; }
/** * Creates a node, then tests the statistics tokens generated from it. */ function testStatisticsTokenReplacement() { $language_interface = \Drupal::languageManager()->getCurrentLanguage(); // Create user and node. $user = $this->drupalCreateUser(array('create page content')); $this->drupalLogin($user); $node = $this->drupalCreateNode(array('type' => 'page', 'uid' => $user->id())); // Hit the node. $this->drupalGet('node/' . $node->id()); // Manually calling statistics.php, simulating ajax behavior. $nid = $node->id(); $post = http_build_query(array('nid' => $nid)); $headers = array('Content-Type' => 'application/x-www-form-urlencoded'); global $base_url; $stats_path = $base_url . '/' . drupal_get_path('module', 'statistics') . '/statistics.php'; $client = \Drupal::service('http_client_factory')->fromOptions(['config/curl' => [CURLOPT_TIMEOUT => 10]]); $client->post($stats_path, array('headers' => $headers, 'body' => $post)); $statistics = statistics_get($node->id()); // Generate and test tokens. $tests = array(); $tests['[node:total-count]'] = 1; $tests['[node:day-count]'] = 1; $tests['[node:last-view]'] = format_date($statistics['timestamp']); $tests['[node:last-view:short]'] = format_date($statistics['timestamp'], 'short'); // Test to make sure that we generated something for each token. $this->assertFalse(in_array(0, array_map('strlen', $tests)), 'No empty tokens generated.'); foreach ($tests as $input => $expected) { $output = \Drupal::token()->replace($input, array('node' => $node), array('langcode' => $language_interface->getId())); $this->assertEqual($output, $expected, format_string('Statistics token %token replaced.', array('%token' => $input))); } }
public function assertToken($type, $object, $token, $expected) { $bubbleable_metadata = new BubbleableMetadata(); $tokens = \Drupal::token()->generate($type, array($token => $token), array($type => $object), [], $bubbleable_metadata); $tokens += array($token => ''); $this->assertIdentical($tokens[$token], $expected, t("Token value for [@type:@token] was '@actual', expected value '@expected'.", array('@type' => $type, '@token' => $token, '@actual' => $tokens[$token], '@expected' => $expected))); }
/** * Tests the normal formatter display on node display. */ function testUploadPath() { $field_name = strtolower($this->randomMachineName()); $type_name = 'article'; $this->createFileField($field_name, 'node', $type_name); $test_file = $this->getTestFile('text'); // Create a new node. $nid = $this->uploadNodeFile($test_file, $field_name, $type_name); // Check that the file was uploaded to the file root. $node = node_load($nid, TRUE); $node_file = file_load($node->{$field_name}->target_id); $this->assertPathMatch('public://' . $test_file->getFilename(), $node_file->getFileUri(), format_string('The file %file was uploaded to the correct path.', array('%file' => $node_file->getFileUri()))); // Change the path to contain multiple subdirectories. $this->updateFileField($field_name, $type_name, array('file_directory' => 'foo/bar/baz')); // Upload a new file into the subdirectories. $nid = $this->uploadNodeFile($test_file, $field_name, $type_name); // Check that the file was uploaded into the subdirectory. $node = node_load($nid, TRUE); $node_file = file_load($node->{$field_name}->target_id, TRUE); $this->assertPathMatch('public://foo/bar/baz/' . $test_file->getFilename(), $node_file->getFileUri(), format_string('The file %file was uploaded to the correct path.', array('%file' => $node_file->getFileUri()))); // Check the path when used with tokens. // Change the path to contain multiple token directories. $this->updateFileField($field_name, $type_name, array('file_directory' => '[current-user:uid]/[current-user:name]')); // Upload a new file into the token subdirectories. $nid = $this->uploadNodeFile($test_file, $field_name, $type_name); // Check that the file was uploaded into the subdirectory. $node = node_load($nid, TRUE); $node_file = file_load($node->{$field_name}->target_id); // Do token replacement using the same user which uploaded the file, not // the user running the test case. $data = array('user' => $this->admin_user); $subdirectory = \Drupal::token()->replace('[user:uid]/[user:name]', $data); $this->assertPathMatch('public://' . $subdirectory . '/' . $test_file->getFilename(), $node_file->getFileUri(), format_string('The file %file was uploaded to the correct path with token replacements.', array('%file' => $node_file->getFileUri()))); }
/** * Tests core token replacements generated from a view. */ function testTokenReplacement() { $token_handler = \Drupal::token(); $view = Views::getView('test_tokens'); $view->setDisplay('page_1'); $this->executeView($view); $expected = array('[view:label]' => 'Test tokens', '[view:description]' => 'Test view to token replacement tests.', '[view:id]' => 'test_tokens', '[view:title]' => 'Test token page', '[view:url]' => $view->getUrl(NULL, 'page_1')->setAbsolute(TRUE)->toString(), '[view:total-rows]' => (string) $view->total_rows, '[view:base-table]' => 'views_test_data', '[view:base-field]' => 'id', '[view:items-per-page]' => '10', '[view:current-page]' => '1', '[view:page-count]' => '1'); $base_bubbleable_metadata = BubbleableMetadata::createFromObject($view->storage); $metadata_tests = []; $metadata_tests['[view:label]'] = $base_bubbleable_metadata; $metadata_tests['[view:description]'] = $base_bubbleable_metadata; $metadata_tests['[view:id]'] = $base_bubbleable_metadata; $metadata_tests['[view:title]'] = $base_bubbleable_metadata; $metadata_tests['[view:url]'] = $base_bubbleable_metadata; $metadata_tests['[view:total-rows]'] = $base_bubbleable_metadata; $metadata_tests['[view:base-table]'] = $base_bubbleable_metadata; $metadata_tests['[view:base-field]'] = $base_bubbleable_metadata; $metadata_tests['[view:items-per-page]'] = $base_bubbleable_metadata; $metadata_tests['[view:current-page]'] = $base_bubbleable_metadata; $metadata_tests['[view:page-count]'] = $base_bubbleable_metadata; foreach ($expected as $token => $expected_output) { $bubbleable_metadata = new BubbleableMetadata(); $output = $token_handler->replace($token, array('view' => $view), [], $bubbleable_metadata); $this->assertIdentical($output, $expected_output, format_string('Token %token replaced correctly.', array('%token' => $token))); $this->assertEqual($bubbleable_metadata, $metadata_tests[$token]); } }
/** * Creates a node, then tests the tokens generated from it. */ function testSchedulerTokenReplacement() { $this->drupalLogin($this->adminUser); $node_storage = $this->container->get('entity.manager')->getStorage('node'); $date_formatter = \Drupal::service('date.formatter'); // Define timestamps for consistent use when repeated throughout this test. $publish_on_timestamp = REQUEST_TIME + 3600; $unpublish_on_timestamp = REQUEST_TIME + 7200; // Create an unpublished page with scheduled dates. $settings = ['type' => 'page', 'status' => FALSE, 'publish_on' => $publish_on_timestamp, 'unpublish_on' => $unpublish_on_timestamp]; $node = $this->drupalCreateNode($settings); // Show that the node is scheduled. $this->drupalGet('admin/content/scheduled'); // Create array of test case data. $test_cases = array(['token_format' => '', 'date_format' => 'medium', 'custom' => ''], ['token_format' => ':long', 'date_format' => 'long', 'custom' => ''], ['token_format' => ':raw', 'date_format' => 'custom', 'custom' => 'U'], ['token_format' => ':custom:jS F g:ia e O', 'date_format' => 'custom', 'custom' => 'jS F g:ia e O']); foreach ($test_cases as $test_data) { // Edit the node and set the body tokens to use the format being tested. $edit = ['body[0][value]' => 'Publish on: [node:scheduler-publish' . $test_data['token_format'] . ']. Unpublish on: [node:scheduler-unpublish' . $test_data['token_format'] . '].']; $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and keep unpublished')); $this->drupalGet('node/' . $node->id()); // Refresh the node and get the body output value. $node_storage->resetCache(array($node->id())); $node = $node_storage->load($node->id()); $body_output = \Drupal::token()->replace($node->body->value, array('node' => $node)); // Create the expected text for the body. $publish_on_date = $date_formatter->format($publish_on_timestamp, $test_data['date_format'], $test_data['custom']); $unpublish_on_date = $date_formatter->format($unpublish_on_timestamp, $test_data['date_format'], $test_data['custom']); $expected_output = 'Publish on: ' . $publish_on_date . '. Unpublish on: ' . $unpublish_on_date . '.'; // Check that the actual text matches the expected value. $this->assertEqual($body_output, $expected_output, 'Scheduler tokens replaced correctly for ' . $test_data['token_format'] . ' format.'); } }
/** * Assert that the provided token matches the provided value. * * @param string $token * The token to test. * @param string $value * The value to check against the token. * @param array $data * The data to process the token with. * * @return bool * TRUE if the assertion succeeded, FALSE otherwise. */ public function assertToken($token, $value, $data) { $result = \Drupal::token()->replace($token, $data); return $this->assertEqual($result, $value, $this->t('Token @token equals @value', [ '@token' => $token, '@value' => $value, ])); }
public function setUp() { parent::setUp(); // Install default system configuration. $this->installConfig(array('system')); $this->interfaceLanguage = \Drupal::languageManager()->getCurrentLanguage(); $this->tokenService = \Drupal::token(); }
/** * Tests token integration. */ function testTokenIntegration() { $token_service = \Drupal::token(); $tokens = array('[currency:code]' => 'XXX', '[currency:number]' => '999', '[currency:subunits]' => '0'); $data = array('currency' => 'XXX'); foreach ($tokens as $token => $replacement) { $this->assertEqual($token_service->replace($token, $data), $replacement); } }
protected function setUp() { parent::setUp(); // Install default system configuration. $this->installConfig(array('system')); \Drupal::service('router.builder')->rebuild(); $this->interfaceLanguage = \Drupal::languageManager()->getCurrentLanguage(); $this->tokenService = \Drupal::token(); }
/** * Tests the interface to manage metatag defaults. */ function testDefaults() { // Save the default title to test the Revert operation at the end. $metatag_defaults = \Drupal::config('metatag.metatag_defaults.global'); $default_title = $metatag_defaults->get('tags')['title']; // Initiate session with a user who can manage metatags. $permissions = array('administer site configuration', 'administer meta tags'); $account = $this->drupalCreateUser($permissions); $this->drupalLogin($account); // Check that the user can see the list of metatag defaults. $this->drupalGet('admin/structure/metatag_defaults'); $this->assertResponse(200); // Check that the Global defaults were created. $this->assertLinkByHref('/admin/structure/metatag_defaults/global', 0, t('Global defaults were created on installation.')); // Check that Global and entity defaults can't be deleted. $this->assertNoLinkByHref('/admin/structure/metatag_defaults/global/delete', 0, t('Global defaults can\'t be deleted')); $this->assertNoLinkByHref('/admin/structure/metatag_defaults/node/delete', 0, t('Entity defaults can\'t be deleted')); // Check that the module defaults were injected into the Global config entity. $this->drupalGet('admin/structure/metatag_defaults/global'); $this->assertFieldById('edit-title', $metatag_defaults->get('title'), t('Metatag defaults were injected into the Global configuration entity.')); // Update the Global defaults and test them. $values = array('title' => 'Test title', 'description' => 'Test description'); $this->drupalPostForm('admin/structure/metatag_defaults/global', $values, 'Save'); $this->assertText('Saved the Global Metatag defaults.'); $this->drupalGet('hit-a-404'); foreach ($values as $metatag => $value) { $this->assertRaw($value, t('Updated metatag @tag was found in the HEAD section of the page.', array('@tag' => $metatag))); } // Check that tokens are processed. $values = array('title' => '[site:name] | Test title', 'description' => '[site:name] | Test description'); $this->drupalPostForm('admin/structure/metatag_defaults/global', $values, 'Save'); $this->assertText('Saved the Global Metatag defaults.'); drupal_flush_all_caches(); $this->drupalGet('hit-a-404'); foreach ($values as $metatag => $value) { $processed_value = \Drupal::token()->replace($value); $this->assertRaw($processed_value, t('Processed token for metatag @tag was found in the HEAD section of the page.', array('@tag' => $metatag))); } // Test the Robots plugin. $robots_values = array('index', 'follow', 'noydir'); $form_values = array(); foreach ($robots_values as $value) { $values['robots[' . $value . ']'] = TRUE; } $this->drupalPostForm('admin/structure/metatag_defaults/global', $values, 'Save'); $this->assertText('Saved the Global Metatag defaults.'); drupal_flush_all_caches(); $this->drupalGet('hit-a-404'); $robots_value = implode(', ', $robots_values); $this->assertRaw($robots_value, t('Robots metatag has the expected values.')); // Test reverting global configuration to its defaults. $this->drupalPostForm('admin/structure/metatag_defaults/global/revert', array(), 'Revert'); $this->assertText('Reverted Global defaults.'); $this->assertText($default_title, 'Global title was reverted to its default value.'); $this->drupalLogout(); }
function assertNoTokens($type, array $data, array $tokens, array $options = array()) { $input = $this->mapTokenNames($type, $tokens); $replacements = \Drupal::token()->generate($type, $input, $data, $options); foreach ($tokens as $name) { $token = $input[$name]; $this->assertTrue(!isset($replacements[$token]), t("Token value for @token was not generated.", array('@type' => $type, '@token' => $token))); } return $values; }
/** * Tests core token replacements generated from a view without results. */ function testTokenReplacementNoResults() { $token_handler = \Drupal::token(); $view = Views::getView('test_tokens'); $view->setDisplay('page_2'); $this->executeView($view); $expected = array('[view:page-count]' => '1'); foreach ($expected as $token => $expected_output) { $output = $token_handler->replace($token, array('view' => $view)); $this->assertIdentical($output, $expected_output, format_string('Token %token replaced correctly.', array('%token' => $token))); } }
/** * Tests core token replacements generated from a view. */ function testTokenReplacement() { $token_handler = \Drupal::token(); $view = Views::getView('test_tokens'); $view->setDisplay('page_1'); $this->executeView($view); $expected = array('[view:label]' => 'Test tokens', '[view:description]' => 'Test view to token replacement tests.', '[view:id]' => 'test_tokens', '[view:title]' => 'Test token page', '[view:url]' => url('test_tokens', array('absolute' => TRUE)), '[view:total-rows]' => (string) $view->total_rows, '[view:base-table]' => 'views_test_data', '[view:base-field]' => 'id', '[view:items-per-page]' => '10', '[view:current-page]' => '1', '[view:page-count]' => '1'); foreach ($expected as $token => $expected_output) { $output = $token_handler->replace($token, array('view' => $view)); $this->assertIdentical($output, $expected_output, format_string('Token %token replaced correctly.', array('%token' => $token))); } }
/** * Replace tokens with their values using the core token service. * * @param $string * @param $data * @param array $settings * @return mixed|string */ private function coreReplace($string, $data, $settings = array()) { // @TODO: Remove this temp code. // This is just here as a way to see all available tokens in debugger. $tokens = \Drupal::token()->getInfo(); $options = array('clear' => TRUE); // Replace tokens with core Token service. $replaced = \Drupal::token()->replace($string, $data, $options); // Ensure that there are no double-slash sequences due to empty token values. $replaced = preg_replace('/\\/+/', '/', $replaced); return $replaced; }
/** * Scans dummy text, then tests the output. */ function testTokenScan() { // Define text with valid and not valid, fake and existing token-like // strings. $text = 'First a [valid:simple], but dummy token, and a dummy [valid:token with: spaces].'; $text .= 'Then a [not valid:token].'; $text .= 'Last an existing token: [node:author:name].'; $token_wannabes = \Drupal::token()->scan($text); $this->assertTrue(isset($token_wannabes['valid']['simple']), 'A simple valid token has been matched.'); $this->assertTrue(isset($token_wannabes['valid']['token with: spaces']), 'A valid token with space characters in the token name has been matched.'); $this->assertFalse(isset($token_wannabes['not valid']), 'An invalid token with spaces in the token type has not been matched.'); $this->assertTrue(isset($token_wannabes['node']), 'An existing valid token has been matched.'); }
/** * Creates a file, then tests the tokens generated from it. */ function testFileTokenReplacement() { $node_storage = $this->container->get('entity.manager')->getStorage('node'); $token_service = \Drupal::token(); $language_interface = \Drupal::languageManager()->getCurrentLanguage(); // Create file field. $type_name = 'article'; $field_name = 'field_' . strtolower($this->randomMachineName()); $this->createFileField($field_name, 'node', $type_name); $test_file = $this->getTestFile('text'); // Coping a file to test uploads with non-latin filenames. $filename = drupal_dirname($test_file->getFileUri()) . '/текстовый файл.txt'; $test_file = file_copy($test_file, $filename); // Create a new node with the uploaded file. $nid = $this->uploadNodeFile($test_file, $field_name, $type_name); // Load the node and the file. $node_storage->resetCache(array($nid)); $node = $node_storage->load($nid); $file = file_load($node->{$field_name}->target_id); // Generate and test sanitized tokens. $tests = array(); $tests['[file:fid]'] = $file->id(); $tests['[file:name]'] = String::checkPlain($file->getFilename()); $tests['[file:path]'] = String::checkPlain($file->getFileUri()); $tests['[file:mime]'] = String::checkPlain($file->getMimeType()); $tests['[file:size]'] = format_size($file->getSize()); $tests['[file:url]'] = String::checkPlain(file_create_url($file->getFileUri())); $tests['[file:created]'] = format_date($file->getCreatedTime(), 'medium', '', NULL, $language_interface->getId()); $tests['[file:created:short]'] = format_date($file->getCreatedTime(), 'short', '', NULL, $language_interface->getId()); $tests['[file:changed]'] = format_date($file->getChangedTime(), 'medium', '', NULL, $language_interface->getId()); $tests['[file:changed:short]'] = format_date($file->getChangedTime(), 'short', '', NULL, $language_interface->getId()); $tests['[file:owner]'] = String::checkPlain(user_format_name($this->adminUser)); $tests['[file:owner:uid]'] = $file->getOwnerId(); // Test to make sure that we generated something for each token. $this->assertFalse(in_array(0, array_map('strlen', $tests)), 'No empty tokens generated.'); foreach ($tests as $input => $expected) { $output = $token_service->replace($input, array('file' => $file), array('langcode' => $language_interface->getId())); $this->assertEqual($output, $expected, format_string('Sanitized file token %token replaced.', array('%token' => $input))); } // Generate and test unsanitized tokens. $tests['[file:name]'] = $file->getFilename(); $tests['[file:path]'] = $file->getFileUri(); $tests['[file:mime]'] = $file->getMimeType(); $tests['[file:size]'] = format_size($file->getSize()); foreach ($tests as $input => $expected) { $output = $token_service->replace($input, array('file' => $file), array('langcode' => $language_interface->getId(), 'sanitize' => FALSE)); $this->assertEqual($output, $expected, format_string('Unsanitized file token %token replaced.', array('%token' => $input))); } }
/** * Provide replacement values for placeholder tokens. * * This hook is invoked when someone calls * \Drupal\Core\Utility\Token::replace(). That function first scans the text for * [type:token] patterns, and splits the needed tokens into groups by type. * Then hook_tokens() is invoked on each token-type group, allowing your module * to respond by providing replacement text for any of the tokens in the group * that your module knows how to process. * * A module implementing this hook should also implement hook_token_info() in * order to list its available tokens on editing screens. * * @param $type * The machine-readable name of the type (group) of token being replaced, such * as 'node', 'user', or another type defined by a hook_token_info() * implementation. * @param $tokens * An array of tokens to be replaced. The keys are the machine-readable token * names, and the values are the raw [type:token] strings that appeared in the * original text. * @param array $data * An associative array of data objects to be used when generating replacement * values, as supplied in the $data parameter to * \Drupal\Core\Utility\Token::replace(). * @param array $options * An associative array of options for token replacement; see * \Drupal\Core\Utility\Token::replace() for possible values. * @param \Drupal\Core\Render\BubbleableMetadata $bubbleable_metadata * The bubbleable metadata. Prior to invoking this hook, * \Drupal\Core\Utility\Token::generate() collects metadata for all of the * data objects in $data. For any data sources not in $data, but that are * used by the token replacement logic, such as global configuration (e.g., * 'system.site') and related objects (e.g., $node->getOwner()), * implementations of this hook must add the corresponding metadata. * For example: * @code * $bubbleable_metadata->addCacheableDependency(\Drupal::config('system.site')); * $bubbleable_metadata->addCacheableDependency($node->getOwner()); * @endcode * * Additionally, implementations of this hook, must forward * $bubbleable_metadata to the chained tokens that they invoke. * For example: * @code * if ($created_tokens = $token_service->findWithPrefix($tokens, 'created')) { * $replacements = $token_service->generate('date', $created_tokens, array('date' => $node->getCreatedTime()), $options, $bubbleable_metadata); * } * @endcode * * @return array * An associative array of replacement values, keyed by the raw [type:token] * strings from the original text. * * @see hook_token_info() * @see hook_tokens_alter() */ function hook_tokens($type, $tokens, array $data, array $options, \Drupal\Core\Render\BubbleableMetadata $bubbleable_metadata) { $token_service = \Drupal::token(); $url_options = array('absolute' => TRUE); if (isset($options['langcode'])) { $url_options['language'] = \Drupal::languageManager()->getLanguage($options['langcode']); $langcode = $options['langcode']; } else { $langcode = NULL; } $sanitize = !empty($options['sanitize']); $replacements = array(); if ($type == 'node' && !empty($data['node'])) { /** @var \Drupal\node\NodeInterface $node */ $node = $data['node']; foreach ($tokens as $name => $original) { switch ($name) { // Simple key values on the node. case 'nid': $replacements[$original] = $node->nid; break; case 'title': $replacements[$original] = $sanitize ? Html::escape($node->getTitle()) : $node->getTitle(); break; case 'edit-url': $replacements[$original] = $node->url('edit-form', $url_options); break; // Default values for the chained tokens handled below. // Default values for the chained tokens handled below. case 'author': $account = $node->getOwner() ? $node->getOwner() : User::load(0); $replacements[$original] = $sanitize ? Html::escape($account->label()) : $account->label(); $bubbleable_metadata->addCacheableDependency($account); break; case 'created': $replacements[$original] = format_date($node->getCreatedTime(), 'medium', '', NULL, $langcode); break; } } if ($author_tokens = $token_service->findWithPrefix($tokens, 'author')) { $replacements = $token_service->generate('user', $author_tokens, array('user' => $node->getOwner()), $options, $bubbleable_metadata); } if ($created_tokens = $token_service->findWithPrefix($tokens, 'created')) { $replacements = $token_service->generate('date', $created_tokens, array('date' => $node->getCreatedTime()), $options, $bubbleable_metadata); } } return $replacements; }
/** * Function copied from TokenTestHelper::assertTokens(). */ public function assertTokens($type, array $data, array $tokens, array $options = array()) { $input = $this->mapTokenNames($type, array_keys($tokens)); $replacements = \Drupal::token()->generate($type, $input, $data, $options); foreach ($tokens as $name => $expected) { $token = $input[$name]; if (!isset($expected)) { $this->assertTrue(!isset($values[$token]), t("Token value for @token was not generated.", array('@type' => $type, '@token' => $token))); } elseif (!isset($replacements[$token])) { $this->fail(t("Token value for @token was not generated.", array('@type' => $type, '@token' => $token))); } elseif (!empty($options['regex'])) { $this->assertTrue(preg_match('/^' . $expected . '$/', $replacements[$token]), t("Token value for @token was '@actual', matching regular expression pattern '@expected'.", array('@type' => $type, '@token' => $token, '@actual' => $replacements[$token], '@expected' => $expected))); } else { $this->assertIdentical($replacements[$token], $expected, t("Token value for @token was '@actual', expected value '@expected'.", array('@type' => $type, '@token' => $token, '@actual' => $replacements[$token], '@expected' => $expected))); } } return $replacements; }
function testEntityMapping() { $this->assertIdentical(token_get_entity_mapping('token', 'node'), 'node'); $this->assertIdentical(token_get_entity_mapping('token', 'term'), 'taxonomy_term'); $this->assertIdentical(token_get_entity_mapping('token', 'vocabulary'), 'taxonomy_vocabulary'); $this->assertIdentical(token_get_entity_mapping('token', 'invalid'), FALSE); $this->assertIdentical(token_get_entity_mapping('token', 'invalid', TRUE), 'invalid'); $this->assertIdentical(token_get_entity_mapping('entity', 'node'), 'node'); $this->assertIdentical(token_get_entity_mapping('entity', 'taxonomy_term'), 'term'); $this->assertIdentical(token_get_entity_mapping('entity', 'taxonomy_vocabulary'), 'vocabulary'); $this->assertIdentical(token_get_entity_mapping('entity', 'invalid'), FALSE); $this->assertIdentical(token_get_entity_mapping('entity', 'invalid', TRUE), 'invalid'); // Test that when we send the mis-matched entity type into token_replace() // that we still get the tokens replaced. $vocabulary = entity_load('taxonomy_vocabulary', 'tags'); $term = $this->addTerm($vocabulary); $this->assertIdentical(\Drupal::token()->replace('[vocabulary:name]', array('taxonomy_vocabulary' => $vocabulary)), $vocabulary->label()); $this->assertIdentical(\Drupal::token()->replace('[term:name][term:vocabulary:name]', array('taxonomy_term' => $term)), $term->label() . $vocabulary->label()); }
/** * Tests the normal formatter display on node display. */ function testUploadPath() { /** @var \Drupal\node\NodeStorageInterface $node_storage */ $node_storage = $this->container->get('entity.manager')->getStorage('node'); $field_name = strtolower($this->randomMachineName()); $type_name = 'article'; $this->createFileField($field_name, 'node', $type_name); /** @var \Drupal\file\FileInterface $test_file */ $test_file = $this->getTestFile('text'); // Create a new node. $nid = $this->uploadNodeFile($test_file, $field_name, $type_name); // Check that the file was uploaded to the correct location. $node_storage->resetCache(array($nid)); $node = $node_storage->load($nid); /** @var \Drupal\file\FileInterface $node_file */ $node_file = $node->{$field_name}->entity; $date_formatter = $this->container->get('date.formatter'); $expected_filename = 'public://' . $date_formatter->format(REQUEST_TIME, 'custom', 'Y') . '-' . $date_formatter->format(REQUEST_TIME, 'custom', 'm') . '/' . $test_file->getFilename(); $this->assertPathMatch($expected_filename, $node_file->getFileUri(), format_string('The file %file was uploaded to the correct path.', array('%file' => $node_file->getFileUri()))); // Change the path to contain multiple subdirectories. $this->updateFileField($field_name, $type_name, array('file_directory' => 'foo/bar/baz')); // Upload a new file into the subdirectories. $nid = $this->uploadNodeFile($test_file, $field_name, $type_name); // Check that the file was uploaded into the subdirectory. $node_storage->resetCache(array($nid)); $node = $node_storage->load($nid); $node_file = File::load($node->{$field_name}->target_id); $this->assertPathMatch('public://foo/bar/baz/' . $test_file->getFilename(), $node_file->getFileUri(), format_string('The file %file was uploaded to the correct path.', array('%file' => $node_file->getFileUri()))); // Check the path when used with tokens. // Change the path to contain multiple token directories. $this->updateFileField($field_name, $type_name, array('file_directory' => '[current-user:uid]/[current-user:name]')); // Upload a new file into the token subdirectories. $nid = $this->uploadNodeFile($test_file, $field_name, $type_name); // Check that the file was uploaded into the subdirectory. $node_storage->resetCache(array($nid)); $node = $node_storage->load($nid); $node_file = File::load($node->{$field_name}->target_id); // Do token replacement using the same user which uploaded the file, not // the user running the test case. $data = array('user' => $this->adminUser); $subdirectory = \Drupal::token()->replace('[user:uid]/[user:name]', $data); $this->assertPathMatch('public://' . $subdirectory . '/' . $test_file->getFilename(), $node_file->getFileUri(), format_string('The file %file was uploaded to the correct path with token replacements.', array('%file' => $node_file->getFileUri()))); }
function testEntityMapping() { /** @var \Drupal\token\TokenEntityMapperInterface $mapper */ $mapper = \Drupal::service('token.entity_mapper'); $this->assertIdentical($mapper->getEntityTypeForTokenType('node'), 'node'); $this->assertIdentical($mapper->getEntityTypeForTokenType('term'), 'taxonomy_term'); $this->assertIdentical($mapper->getEntityTypeForTokenType('vocabulary'), 'taxonomy_vocabulary'); $this->assertIdentical($mapper->getEntityTypeForTokenType('invalid'), FALSE); $this->assertIdentical($mapper->getEntityTypeForTokenType('invalid', TRUE), 'invalid'); $this->assertIdentical($mapper->getTokenTypeForEntityType('node'), 'node'); $this->assertIdentical($mapper->getTokenTypeForEntityType('taxonomy_term'), 'term'); $this->assertIdentical($mapper->getTokenTypeForEntityType('taxonomy_vocabulary'), 'vocabulary'); $this->assertIdentical($mapper->getTokenTypeForEntityType('invalid'), FALSE); $this->assertIdentical($mapper->getTokenTypeForEntityType('invalid', TRUE), 'invalid'); // Test that when we send the mis-matched entity type into token_replace() // that we still get the tokens replaced. $vocabulary = entity_load('taxonomy_vocabulary', 'tags'); $term = $this->addTerm($vocabulary); $this->assertIdentical(\Drupal::token()->replace('[vocabulary:name]', array('taxonomy_vocabulary' => $vocabulary)), $vocabulary->label()); $this->assertIdentical(\Drupal::token()->replace('[term:name][term:vocabulary:name]', array('taxonomy_term' => $term)), $term->label() . $vocabulary->label()); }
/** * {@inheritdoc} */ public function viewElements(FieldItemListInterface $items, $langcode) { $element = array(); $entity = $items->getEntity(); $settings = $this->getSettings(); foreach ($items as $delta => $item) { // By default use the full URL as the link text. $url = $this->buildUrl($item); $link_title = $url->toString(); // If the link text field value is available, use it for the text. if (empty($settings['url_only']) && !empty($item->title)) { // Unsanitized token replacement here because the entire link title // gets auto-escaped during link generation in // \Drupal\Core\Utility\LinkGenerator::generate(). $link_title = \Drupal::token()->replace($item->title, [$entity->getEntityTypeId() => $entity], ['clear' => TRUE]); } // The link_separate formatter has two titles; the link text (as in the // field values) and the URL itself. If there is no link text value, // $link_title defaults to the URL, so it needs to be unset. // The URL version may need to be trimmed as well. if (empty($item->title)) { $link_title = NULL; } $url_title = $url->toString(); if (!empty($settings['trim_length'])) { $link_title = Unicode::truncate($link_title, $settings['trim_length'], FALSE, TRUE); $url_title = Unicode::truncate($url_title, $settings['trim_length'], FALSE, TRUE); } $element[$delta] = array('#theme' => 'link_formatter_link_separate', '#title' => $link_title, '#url_title' => $url_title, '#url' => $url); if (!empty($item->_attributes)) { // Set our RDFa attributes on the <a> element that is being built. $url->setOption('attributes', $item->_attributes); // Unset field item attributes since they have been included in the // formatter output and should not be rendered in the field template. unset($item->_attributes); } } return $element; }
/** * {@inheritdoc} */ public function viewElements(FieldItemListInterface $items, $langcode) { $element = array(); $entity = $items->getEntity(); $settings = $this->getSettings(); foreach ($items as $delta => $item) { // By default use the full URL as the link text. $url = $this->buildUrl($item); $link_title = $url->toString(); // If the title field value is available, use it for the link text. if (empty($settings['url_only']) && !empty($item->title)) { // Unsanitized token replacement here because the entire link title // gets auto-escaped during link generation in // \Drupal\Core\Utility\LinkGenerator::generate(). $link_title = \Drupal::token()->replace($item->title, [$entity->getEntityTypeId() => $entity], ['clear' => TRUE]); } // Trim the link text to the desired length. if (!empty($settings['trim_length'])) { $link_title = Unicode::truncate($link_title, $settings['trim_length'], FALSE, TRUE); } if (!empty($settings['url_only']) && !empty($settings['url_plain'])) { $element[$delta] = array('#plain_text' => $link_title); if (!empty($item->_attributes)) { // Piggyback on the metadata attributes, which will be placed in the // field template wrapper, and set the URL value in a content // attribute. // @todo Does RDF need a URL rather than an internal URI here? // @see \Drupal\Tests\rdf\Kernel\Field\LinkFieldRdfaTest. $content = str_replace('internal:/', '', $item->uri); $item->_attributes += array('content' => $content); } } else { $element[$delta] = array('#type' => 'link', '#title' => $link_title, '#options' => $url->getOptions()); $element[$delta]['#url'] = $url; if (!empty($item->_attributes)) { $element[$delta]['#options'] += array('attributes' => array()); $element[$delta]['#options']['attributes'] += $item->_attributes; // Unset field item attributes since they have been included in the // formatter output and should not be rendered in the field template. unset($item->_attributes); } } } return $element; }
/** * Creates a user, then tests the tokens generated from it. */ function testUserTokenReplacement() { $token_service = \Drupal::token(); $language_interface = \Drupal::languageManager()->getCurrentLanguage(); $url_options = array('absolute' => TRUE, 'language' => $language_interface); // Create two users and log them in one after another. $user1 = $this->drupalCreateUser(array()); $user2 = $this->drupalCreateUser(array()); $this->drupalLogin($user1); $this->drupalLogout(); $this->drupalLogin($user2); $account = user_load($user1->id()); $global_account = user_load(\Drupal::currentUser()->id()); // Generate and test sanitized tokens. $tests = array(); $tests['[user:uid]'] = $account->id(); $tests['[user:name]'] = String::checkPlain(user_format_name($account)); $tests['[user:mail]'] = String::checkPlain($account->getEmail()); $tests['[user:url]'] = $account->url('canonical', $url_options); $tests['[user:edit-url]'] = $account->url('edit-form', $url_options); $tests['[user:last-login]'] = format_date($account->getLastLoginTime(), 'medium', '', NULL, $language_interface->getId()); $tests['[user:last-login:short]'] = format_date($account->getLastLoginTime(), 'short', '', NULL, $language_interface->getId()); $tests['[user:created]'] = format_date($account->getCreatedTime(), 'medium', '', NULL, $language_interface->getId()); $tests['[user:created:short]'] = format_date($account->getCreatedTime(), 'short', '', NULL, $language_interface->getId()); $tests['[current-user:name]'] = String::checkPlain(user_format_name($global_account)); // Test to make sure that we generated something for each token. $this->assertFalse(in_array(0, array_map('strlen', $tests)), 'No empty tokens generated.'); foreach ($tests as $input => $expected) { $output = $token_service->replace($input, array('user' => $account), array('langcode' => $language_interface->getId())); $this->assertEqual($output, $expected, format_string('Sanitized user token %token replaced.', array('%token' => $input))); } // Generate and test unsanitized tokens. $tests['[user:name]'] = user_format_name($account); $tests['[user:mail]'] = $account->getEmail(); $tests['[current-user:name]'] = user_format_name($global_account); foreach ($tests as $input => $expected) { $output = $token_service->replace($input, array('user' => $account), array('langcode' => $language_interface->getId(), 'sanitize' => FALSE)); $this->assertEqual($output, $expected, format_string('Unsanitized user token %token replaced.', array('%token' => $input))); } // Generate login and cancel link. $tests = array(); $tests['[user:one-time-login-url]'] = user_pass_reset_url($account); $tests['[user:cancel-url]'] = user_cancel_url($account); // Generate tokens with interface language. $link = \Drupal::url('user.page', [], array('absolute' => TRUE)); foreach ($tests as $input => $expected) { $output = $token_service->replace($input, array('user' => $account), array('langcode' => $language_interface->getId(), 'callback' => 'user_mail_tokens', 'sanitize' => FALSE, 'clear' => TRUE)); $this->assertTrue(strpos($output, $link) === 0, 'Generated URL is in interface language.'); } // Generate tokens with the user's preferred language. $account->preferred_langcode = 'de'; $account->save(); $link = \Drupal::url('user.page', [], array('language' => \Drupal::languageManager()->getLanguage($account->getPreferredLangcode()), 'absolute' => TRUE)); foreach ($tests as $input => $expected) { $output = $token_service->replace($input, array('user' => $account), array('callback' => 'user_mail_tokens', 'sanitize' => FALSE, 'clear' => TRUE)); $this->assertTrue(strpos($output, $link) === 0, "Generated URL is in the user's preferred language."); } // Generate tokens with one specific language. $link = \Drupal::url('user.page', [], array('language' => \Drupal::languageManager()->getLanguage('de'), 'absolute' => TRUE)); foreach ($tests as $input => $expected) { foreach (array($user1, $user2) as $account) { $output = $token_service->replace($input, array('user' => $account), array('langcode' => 'de', 'callback' => 'user_mail_tokens', 'sanitize' => FALSE, 'clear' => TRUE)); $this->assertTrue(strpos($output, $link) === 0, "Generated URL in in the requested language."); } } }
/** * Tests global tokens. */ public function testRenderAreaToken() { $admin_user = $this->drupalCreateUser(array('administer views', 'administer site configuration')); $this->drupalLogin($admin_user); $view = Views::getView('test_example_area'); $view->initHandlers(); $this->drupalGet('admin/structure/views/nojs/handler/test_example_area/default/empty/test_example'); // Test that the list is token present. $element = $this->xpath('//ul[@class="global-tokens"]'); $this->assertTrue($element, 'Token list found on the options form.'); $empty_handler =& $view->empty['test_example']; // Test the list of available tokens. $available = $empty_handler->getAvailableGlobalTokens(); foreach (array('site', 'view') as $type) { $this->assertTrue(!empty($available[$type]) && is_array($available[$type])); // Test that each item exists in the list. foreach ($available[$type] as $token => $info) { $this->assertText("[{$type}:{$token}]"); } } // Test the rendered output of a token. $empty_handler->options['string'] = '[site:name]'; // Test we have the site:name token in the output. $output = $view->preview(); $output = $this->container->get('renderer')->renderRoot($output); $expected = \Drupal::token()->replace('[site:name]'); $this->assertTrue(strpos($output, $expected) !== FALSE); }
/** * Determines the URI for a file field. * * @param array $settings * The array of field settings. * @param array $data * An array of token objects to pass to token_replace(). * * @return string * An unsanitized file directory URI with tokens replaced. The result of * the token replacement is then converted to plain text and returned. */ protected static function doGetUploadLocation(array $settings, $data = []) { $destination = trim($settings['file_directory'], '/'); // Replace tokens. As the tokens might contain HTML we convert it to plain // text. $destination = PlainTextOutput::renderFromHtml(\Drupal::token()->replace($destination, $data)); return $settings['uri_scheme'] . '://' . $destination; }