Mercurial > hg > isophonics-drupal-site
comparison core/modules/link/tests/src/Functional/LinkFieldTest.php @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children | 1fec387a4317 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4c8ae668cc8c |
---|---|
1 <?php | |
2 | |
3 namespace Drupal\Tests\link\Functional; | |
4 | |
5 use Drupal\Component\Utility\Html; | |
6 use Drupal\Component\Utility\Unicode; | |
7 use Drupal\Core\Url; | |
8 use Drupal\entity_test\Entity\EntityTest; | |
9 use Drupal\field\Entity\FieldConfig; | |
10 use Drupal\link\LinkItemInterface; | |
11 use Drupal\node\NodeInterface; | |
12 use Drupal\Tests\BrowserTestBase; | |
13 use Drupal\field\Entity\FieldStorageConfig; | |
14 | |
15 /** | |
16 * Tests link field widgets and formatters. | |
17 * | |
18 * @group link | |
19 */ | |
20 class LinkFieldTest extends BrowserTestBase { | |
21 | |
22 /** | |
23 * Modules to enable. | |
24 * | |
25 * @var array | |
26 */ | |
27 public static $modules = ['entity_test', 'link', 'node']; | |
28 | |
29 /** | |
30 * A field to use in this test class. | |
31 * | |
32 * @var \Drupal\field\Entity\FieldStorageConfig | |
33 */ | |
34 protected $fieldStorage; | |
35 | |
36 /** | |
37 * The instance used in this test class. | |
38 * | |
39 * @var \Drupal\field\Entity\FieldConfig | |
40 */ | |
41 protected $field; | |
42 | |
43 protected function setUp() { | |
44 parent::setUp(); | |
45 | |
46 $this->drupalLogin($this->drupalCreateUser([ | |
47 'view test entity', | |
48 'administer entity_test content', | |
49 'link to any page', | |
50 ])); | |
51 } | |
52 | |
53 /** | |
54 * Tests link field URL validation. | |
55 */ | |
56 public function testURLValidation() { | |
57 $field_name = Unicode::strtolower($this->randomMachineName()); | |
58 // Create a field with settings to validate. | |
59 $this->fieldStorage = FieldStorageConfig::create([ | |
60 'field_name' => $field_name, | |
61 'entity_type' => 'entity_test', | |
62 'type' => 'link', | |
63 ]); | |
64 $this->fieldStorage->save(); | |
65 $this->field = FieldConfig::create([ | |
66 'field_storage' => $this->fieldStorage, | |
67 'bundle' => 'entity_test', | |
68 'settings' => [ | |
69 'title' => DRUPAL_DISABLED, | |
70 'link_type' => LinkItemInterface::LINK_GENERIC, | |
71 ], | |
72 ]); | |
73 $this->field->save(); | |
74 entity_get_form_display('entity_test', 'entity_test', 'default') | |
75 ->setComponent($field_name, [ | |
76 'type' => 'link_default', | |
77 'settings' => [ | |
78 'placeholder_url' => 'http://example.com', | |
79 ], | |
80 ]) | |
81 ->save(); | |
82 entity_get_display('entity_test', 'entity_test', 'full') | |
83 ->setComponent($field_name, [ | |
84 'type' => 'link', | |
85 ]) | |
86 ->save(); | |
87 | |
88 // Display creation form. | |
89 $this->drupalGet('entity_test/add'); | |
90 $this->assertFieldByName("{$field_name}[0][uri]", '', 'Link URL field is displayed'); | |
91 $this->assertRaw('placeholder="http://example.com"'); | |
92 | |
93 // Create a path alias. | |
94 \Drupal::service('path.alias_storage')->save('/admin', '/a/path/alias'); | |
95 | |
96 // Create a node to test the link widget. | |
97 $node = $this->drupalCreateNode(); | |
98 | |
99 $restricted_node = $this->drupalCreateNode(['status' => NodeInterface::NOT_PUBLISHED]); | |
100 | |
101 // Define some valid URLs (keys are the entered values, values are the | |
102 // strings displayed to the user). | |
103 $valid_external_entries = [ | |
104 'http://www.example.com/' => 'http://www.example.com/', | |
105 // Strings within parenthesis without leading space char. | |
106 'http://www.example.com/strings_(string_within_parenthesis)' => 'http://www.example.com/strings_(string_within_parenthesis)', | |
107 // Numbers within parenthesis without leading space char. | |
108 'http://www.example.com/numbers_(9999)' => 'http://www.example.com/numbers_(9999)', | |
109 ]; | |
110 $valid_internal_entries = [ | |
111 '/entity_test/add' => '/entity_test/add', | |
112 '/a/path/alias' => '/a/path/alias', | |
113 | |
114 // Front page, with query string and fragment. | |
115 '/' => '<front>', | |
116 '/?example=llama' => '<front>?example=llama', | |
117 '/#example' => '<front>#example', | |
118 | |
119 // @todo '<front>' is valid input for BC reasons, may be removed by | |
120 // https://www.drupal.org/node/2421941 | |
121 '<front>' => '<front>', | |
122 '<front>#example' => '<front>#example', | |
123 '<front>?example=llama' => '<front>?example=llama', | |
124 | |
125 // Query string and fragment. | |
126 '?example=llama' => '?example=llama', | |
127 '#example' => '#example', | |
128 | |
129 // Entity reference autocomplete value. | |
130 $node->label() . ' (1)' => $node->label() . ' (1)', | |
131 // Entity URI displayed as ER autocomplete value when displayed in a form. | |
132 'entity:node/1' => $node->label() . ' (1)', | |
133 // URI for an entity that exists, but is not accessible by the user. | |
134 'entity:node/' . $restricted_node->id() => '- Restricted access - (' . $restricted_node->id() . ')', | |
135 // URI for an entity that doesn't exist, but with a valid ID. | |
136 'entity:user/999999' => 'entity:user/999999', | |
137 ]; | |
138 | |
139 // Define some invalid URLs. | |
140 $validation_error_1 = "The path '@link_path' is invalid."; | |
141 $validation_error_2 = 'Manually entered paths should start with /, ? or #.'; | |
142 $validation_error_3 = "The path '@link_path' is inaccessible."; | |
143 $invalid_external_entries = [ | |
144 // Invalid protocol | |
145 'invalid://not-a-valid-protocol' => $validation_error_1, | |
146 // Missing host name | |
147 'http://' => $validation_error_1, | |
148 ]; | |
149 $invalid_internal_entries = [ | |
150 'no-leading-slash' => $validation_error_2, | |
151 'entity:non_existing_entity_type/yar' => $validation_error_1, | |
152 // URI for an entity that doesn't exist, with an invalid ID. | |
153 'entity:user/invalid-parameter' => $validation_error_1, | |
154 ]; | |
155 | |
156 // Test external and internal URLs for 'link_type' = LinkItemInterface::LINK_GENERIC. | |
157 $this->assertValidEntries($field_name, $valid_external_entries + $valid_internal_entries); | |
158 $this->assertInvalidEntries($field_name, $invalid_external_entries + $invalid_internal_entries); | |
159 | |
160 // Test external URLs for 'link_type' = LinkItemInterface::LINK_EXTERNAL. | |
161 $this->field->setSetting('link_type', LinkItemInterface::LINK_EXTERNAL); | |
162 $this->field->save(); | |
163 $this->assertValidEntries($field_name, $valid_external_entries); | |
164 $this->assertInvalidEntries($field_name, $valid_internal_entries + $invalid_external_entries); | |
165 | |
166 // Test external URLs for 'link_type' = LinkItemInterface::LINK_INTERNAL. | |
167 $this->field->setSetting('link_type', LinkItemInterface::LINK_INTERNAL); | |
168 $this->field->save(); | |
169 $this->assertValidEntries($field_name, $valid_internal_entries); | |
170 $this->assertInvalidEntries($field_name, $valid_external_entries + $invalid_internal_entries); | |
171 | |
172 // Ensure that users with 'link to any page', don't apply access checking. | |
173 $this->drupalLogin($this->drupalCreateUser([ | |
174 'view test entity', | |
175 'administer entity_test content', | |
176 ])); | |
177 $this->assertValidEntries($field_name, ['/entity_test/add' => '/entity_test/add']); | |
178 $this->assertInValidEntries($field_name, ['/admin' => $validation_error_3]); | |
179 } | |
180 | |
181 /** | |
182 * Asserts that valid URLs can be submitted. | |
183 * | |
184 * @param string $field_name | |
185 * The field name. | |
186 * @param array $valid_entries | |
187 * An array of valid URL entries. | |
188 */ | |
189 protected function assertValidEntries($field_name, array $valid_entries) { | |
190 foreach ($valid_entries as $uri => $string) { | |
191 $edit = [ | |
192 "{$field_name}[0][uri]" => $uri, | |
193 ]; | |
194 $this->drupalPostForm('entity_test/add', $edit, t('Save')); | |
195 preg_match('|entity_test/manage/(\d+)|', $this->getUrl(), $match); | |
196 $id = $match[1]; | |
197 $this->assertText(t('entity_test @id has been created.', ['@id' => $id])); | |
198 $this->assertRaw($string); | |
199 } | |
200 } | |
201 | |
202 /** | |
203 * Asserts that invalid URLs cannot be submitted. | |
204 * | |
205 * @param string $field_name | |
206 * The field name. | |
207 * @param array $invalid_entries | |
208 * An array of invalid URL entries. | |
209 */ | |
210 protected function assertInvalidEntries($field_name, array $invalid_entries) { | |
211 foreach ($invalid_entries as $invalid_value => $error_message) { | |
212 $edit = [ | |
213 "{$field_name}[0][uri]" => $invalid_value, | |
214 ]; | |
215 $this->drupalPostForm('entity_test/add', $edit, t('Save')); | |
216 $this->assertText(t($error_message, ['@link_path' => $invalid_value])); | |
217 } | |
218 } | |
219 | |
220 /** | |
221 * Tests the link title settings of a link field. | |
222 */ | |
223 public function testLinkTitle() { | |
224 $field_name = Unicode::strtolower($this->randomMachineName()); | |
225 // Create a field with settings to validate. | |
226 $this->fieldStorage = FieldStorageConfig::create([ | |
227 'field_name' => $field_name, | |
228 'entity_type' => 'entity_test', | |
229 'type' => 'link', | |
230 ]); | |
231 $this->fieldStorage->save(); | |
232 $this->field = FieldConfig::create([ | |
233 'field_storage' => $this->fieldStorage, | |
234 'bundle' => 'entity_test', | |
235 'label' => 'Read more about this entity', | |
236 'settings' => [ | |
237 'title' => DRUPAL_OPTIONAL, | |
238 'link_type' => LinkItemInterface::LINK_GENERIC, | |
239 ], | |
240 ]); | |
241 $this->field->save(); | |
242 entity_get_form_display('entity_test', 'entity_test', 'default') | |
243 ->setComponent($field_name, [ | |
244 'type' => 'link_default', | |
245 'settings' => [ | |
246 'placeholder_url' => 'http://example.com', | |
247 'placeholder_title' => 'Enter the text for this link', | |
248 ], | |
249 ]) | |
250 ->save(); | |
251 entity_get_display('entity_test', 'entity_test', 'full') | |
252 ->setComponent($field_name, [ | |
253 'type' => 'link', | |
254 'label' => 'hidden', | |
255 ]) | |
256 ->save(); | |
257 | |
258 // Verify that the link text field works according to the field setting. | |
259 foreach ([DRUPAL_DISABLED, DRUPAL_REQUIRED, DRUPAL_OPTIONAL] as $title_setting) { | |
260 // Update the link title field setting. | |
261 $this->field->setSetting('title', $title_setting); | |
262 $this->field->save(); | |
263 | |
264 // Display creation form. | |
265 $this->drupalGet('entity_test/add'); | |
266 // Assert label is shown. | |
267 $this->assertText('Read more about this entity'); | |
268 $this->assertFieldByName("{$field_name}[0][uri]", '', 'URL field found.'); | |
269 $this->assertRaw('placeholder="http://example.com"'); | |
270 | |
271 if ($title_setting === DRUPAL_DISABLED) { | |
272 $this->assertNoFieldByName("{$field_name}[0][title]", '', 'Link text field not found.'); | |
273 $this->assertNoRaw('placeholder="Enter the text for this link"'); | |
274 } | |
275 else { | |
276 $this->assertRaw('placeholder="Enter the text for this link"'); | |
277 | |
278 $this->assertFieldByName("{$field_name}[0][title]", '', 'Link text field found.'); | |
279 if ($title_setting === DRUPAL_REQUIRED) { | |
280 // Verify that the link text is required, if the URL is non-empty. | |
281 $edit = [ | |
282 "{$field_name}[0][uri]" => 'http://www.example.com', | |
283 ]; | |
284 $this->drupalPostForm(NULL, $edit, t('Save')); | |
285 $this->assertText(t('@name field is required.', ['@name' => t('Link text')])); | |
286 | |
287 // Verify that the link text is not required, if the URL is empty. | |
288 $edit = [ | |
289 "{$field_name}[0][uri]" => '', | |
290 ]; | |
291 $this->drupalPostForm(NULL, $edit, t('Save')); | |
292 $this->assertNoText(t('@name field is required.', ['@name' => t('Link text')])); | |
293 | |
294 // Verify that a URL and link text meets requirements. | |
295 $this->drupalGet('entity_test/add'); | |
296 $edit = [ | |
297 "{$field_name}[0][uri]" => 'http://www.example.com', | |
298 "{$field_name}[0][title]" => 'Example', | |
299 ]; | |
300 $this->drupalPostForm(NULL, $edit, t('Save')); | |
301 $this->assertNoText(t('@name field is required.', ['@name' => t('Link text')])); | |
302 } | |
303 } | |
304 } | |
305 | |
306 // Verify that a link without link text is rendered using the URL as text. | |
307 $value = 'http://www.example.com/'; | |
308 $edit = [ | |
309 "{$field_name}[0][uri]" => $value, | |
310 "{$field_name}[0][title]" => '', | |
311 ]; | |
312 $this->drupalPostForm(NULL, $edit, t('Save')); | |
313 preg_match('|entity_test/manage/(\d+)|', $this->getUrl(), $match); | |
314 $id = $match[1]; | |
315 $this->assertText(t('entity_test @id has been created.', ['@id' => $id])); | |
316 | |
317 $output = $this->renderTestEntity($id); | |
318 $expected_link = (string) \Drupal::l($value, Url::fromUri($value)); | |
319 $this->assertContains($expected_link, $output); | |
320 | |
321 // Verify that a link with text is rendered using the link text. | |
322 $title = $this->randomMachineName(); | |
323 $edit = [ | |
324 "{$field_name}[0][title]" => $title, | |
325 ]; | |
326 $this->drupalPostForm("entity_test/manage/$id/edit", $edit, t('Save')); | |
327 $this->assertText(t('entity_test @id has been updated.', ['@id' => $id])); | |
328 | |
329 $output = $this->renderTestEntity($id); | |
330 $expected_link = (string) \Drupal::l($title, Url::fromUri($value)); | |
331 $this->assertContains($expected_link, $output); | |
332 } | |
333 | |
334 /** | |
335 * Tests the default 'link' formatter. | |
336 */ | |
337 public function testLinkFormatter() { | |
338 $field_name = Unicode::strtolower($this->randomMachineName()); | |
339 // Create a field with settings to validate. | |
340 $this->fieldStorage = FieldStorageConfig::create([ | |
341 'field_name' => $field_name, | |
342 'entity_type' => 'entity_test', | |
343 'type' => 'link', | |
344 'cardinality' => 3, | |
345 ]); | |
346 $this->fieldStorage->save(); | |
347 FieldConfig::create([ | |
348 'field_storage' => $this->fieldStorage, | |
349 'label' => 'Read more about this entity', | |
350 'bundle' => 'entity_test', | |
351 'settings' => [ | |
352 'title' => DRUPAL_OPTIONAL, | |
353 'link_type' => LinkItemInterface::LINK_GENERIC, | |
354 ], | |
355 ])->save(); | |
356 entity_get_form_display('entity_test', 'entity_test', 'default') | |
357 ->setComponent($field_name, [ | |
358 'type' => 'link_default', | |
359 ]) | |
360 ->save(); | |
361 $display_options = [ | |
362 'type' => 'link', | |
363 'label' => 'hidden', | |
364 ]; | |
365 entity_get_display('entity_test', 'entity_test', 'full') | |
366 ->setComponent($field_name, $display_options) | |
367 ->save(); | |
368 | |
369 // Create an entity with three link field values: | |
370 // - The first field item uses a URL only. | |
371 // - The second field item uses a URL and link text. | |
372 // - The third field item uses a fragment-only URL with text. | |
373 // For consistency in assertion code below, the URL is assigned to the title | |
374 // variable for the first field. | |
375 $this->drupalGet('entity_test/add'); | |
376 $url1 = 'http://www.example.com/content/articles/archive?author=John&year=2012#com'; | |
377 $url2 = 'http://www.example.org/content/articles/archive?author=John&year=2012#org'; | |
378 $url3 = '#net'; | |
379 $title1 = $url1; | |
380 // Intentionally contains an ampersand that needs sanitization on output. | |
381 $title2 = 'A very long & strange example title that could break the nice layout of the site'; | |
382 $title3 = 'Fragment only'; | |
383 $edit = [ | |
384 "{$field_name}[0][uri]" => $url1, | |
385 // Note that $title1 is not submitted. | |
386 "{$field_name}[0][title]" => '', | |
387 "{$field_name}[1][uri]" => $url2, | |
388 "{$field_name}[1][title]" => $title2, | |
389 "{$field_name}[2][uri]" => $url3, | |
390 "{$field_name}[2][title]" => $title3, | |
391 ]; | |
392 // Assert label is shown. | |
393 $this->assertText('Read more about this entity'); | |
394 $this->drupalPostForm(NULL, $edit, t('Save')); | |
395 preg_match('|entity_test/manage/(\d+)|', $this->getUrl(), $match); | |
396 $id = $match[1]; | |
397 $this->assertText(t('entity_test @id has been created.', ['@id' => $id])); | |
398 | |
399 // Verify that the link is output according to the formatter settings. | |
400 // Not using generatePermutations(), since that leads to 32 cases, which | |
401 // would not test actual link field formatter functionality but rather | |
402 // the link generator and options/attributes. Only 'url_plain' has a | |
403 // dependency on 'url_only', so we have a total of ~10 cases. | |
404 $options = [ | |
405 'trim_length' => [NULL, 6], | |
406 'rel' => [NULL, 'nofollow'], | |
407 'target' => [NULL, '_blank'], | |
408 'url_only' => [ | |
409 ['url_only' => FALSE], | |
410 ['url_only' => FALSE, 'url_plain' => TRUE], | |
411 ['url_only' => TRUE], | |
412 ['url_only' => TRUE, 'url_plain' => TRUE], | |
413 ], | |
414 ]; | |
415 foreach ($options as $setting => $values) { | |
416 foreach ($values as $new_value) { | |
417 // Update the field formatter settings. | |
418 if (!is_array($new_value)) { | |
419 $display_options['settings'] = [$setting => $new_value]; | |
420 } | |
421 else { | |
422 $display_options['settings'] = $new_value; | |
423 } | |
424 entity_get_display('entity_test', 'entity_test', 'full') | |
425 ->setComponent($field_name, $display_options) | |
426 ->save(); | |
427 | |
428 $output = $this->renderTestEntity($id); | |
429 switch ($setting) { | |
430 case 'trim_length': | |
431 $url = $url1; | |
432 $title = isset($new_value) ? Unicode::truncate($title1, $new_value, FALSE, TRUE) : $title1; | |
433 $this->assertContains('<a href="' . Html::escape($url) . '">' . Html::escape($title) . '</a>', $output); | |
434 | |
435 $url = $url2; | |
436 $title = isset($new_value) ? Unicode::truncate($title2, $new_value, FALSE, TRUE) : $title2; | |
437 $this->assertContains('<a href="' . Html::escape($url) . '">' . Html::escape($title) . '</a>', $output); | |
438 | |
439 $url = $url3; | |
440 $title = isset($new_value) ? Unicode::truncate($title3, $new_value, FALSE, TRUE) : $title3; | |
441 $this->assertContains('<a href="' . Html::escape($url) . '">' . Html::escape($title) . '</a>', $output); | |
442 break; | |
443 | |
444 case 'rel': | |
445 $rel = isset($new_value) ? ' rel="' . $new_value . '"' : ''; | |
446 $this->assertContains('<a href="' . Html::escape($url1) . '"' . $rel . '>' . Html::escape($title1) . '</a>', $output); | |
447 $this->assertContains('<a href="' . Html::escape($url2) . '"' . $rel . '>' . Html::escape($title2) . '</a>', $output); | |
448 $this->assertContains('<a href="' . Html::escape($url3) . '"' . $rel . '>' . Html::escape($title3) . '</a>', $output); | |
449 break; | |
450 | |
451 case 'target': | |
452 $target = isset($new_value) ? ' target="' . $new_value . '"' : ''; | |
453 $this->assertContains('<a href="' . Html::escape($url1) . '"' . $target . '>' . Html::escape($title1) . '</a>', $output); | |
454 $this->assertContains('<a href="' . Html::escape($url2) . '"' . $target . '>' . Html::escape($title2) . '</a>', $output); | |
455 $this->assertContains('<a href="' . Html::escape($url3) . '"' . $target . '>' . Html::escape($title3) . '</a>', $output); | |
456 break; | |
457 | |
458 case 'url_only': | |
459 // In this case, $new_value is an array. | |
460 if (!$new_value['url_only']) { | |
461 $this->assertContains('<a href="' . Html::escape($url1) . '">' . Html::escape($title1) . '</a>', $output); | |
462 $this->assertContains('<a href="' . Html::escape($url2) . '">' . Html::escape($title2) . '</a>', $output); | |
463 $this->assertContains('<a href="' . Html::escape($url3) . '">' . Html::escape($title3) . '</a>', $output); | |
464 } | |
465 else { | |
466 if (empty($new_value['url_plain'])) { | |
467 $this->assertContains('<a href="' . Html::escape($url1) . '">' . Html::escape($url1) . '</a>', $output); | |
468 $this->assertContains('<a href="' . Html::escape($url2) . '">' . Html::escape($url2) . '</a>', $output); | |
469 $this->assertContains('<a href="' . Html::escape($url3) . '">' . Html::escape($url3) . '</a>', $output); | |
470 } | |
471 else { | |
472 $this->assertNotContains('<a href="' . Html::escape($url1) . '">' . Html::escape($url1) . '</a>', $output); | |
473 $this->assertNotContains('<a href="' . Html::escape($url2) . '">' . Html::escape($url2) . '</a>', $output); | |
474 $this->assertNotContains('<a href="' . Html::escape($url3) . '">' . Html::escape($url3) . '</a>', $output); | |
475 $this->assertContains(Html::escape($url1), $output); | |
476 $this->assertContains(Html::escape($url2), $output); | |
477 $this->assertContains(Html::escape($url3), $output); | |
478 } | |
479 } | |
480 break; | |
481 } | |
482 } | |
483 } | |
484 } | |
485 | |
486 /** | |
487 * Tests the 'link_separate' formatter. | |
488 * | |
489 * This test is mostly the same as testLinkFormatter(), but they cannot be | |
490 * merged, since they involve different configuration and output. | |
491 */ | |
492 public function testLinkSeparateFormatter() { | |
493 $field_name = Unicode::strtolower($this->randomMachineName()); | |
494 // Create a field with settings to validate. | |
495 $this->fieldStorage = FieldStorageConfig::create([ | |
496 'field_name' => $field_name, | |
497 'entity_type' => 'entity_test', | |
498 'type' => 'link', | |
499 'cardinality' => 3, | |
500 ]); | |
501 $this->fieldStorage->save(); | |
502 FieldConfig::create([ | |
503 'field_storage' => $this->fieldStorage, | |
504 'bundle' => 'entity_test', | |
505 'settings' => [ | |
506 'title' => DRUPAL_OPTIONAL, | |
507 'link_type' => LinkItemInterface::LINK_GENERIC, | |
508 ], | |
509 ])->save(); | |
510 $display_options = [ | |
511 'type' => 'link_separate', | |
512 'label' => 'hidden', | |
513 ]; | |
514 entity_get_form_display('entity_test', 'entity_test', 'default') | |
515 ->setComponent($field_name, [ | |
516 'type' => 'link_default', | |
517 ]) | |
518 ->save(); | |
519 entity_get_display('entity_test', 'entity_test', 'full') | |
520 ->setComponent($field_name, $display_options) | |
521 ->save(); | |
522 | |
523 // Create an entity with three link field values: | |
524 // - The first field item uses a URL only. | |
525 // - The second field item uses a URL and link text. | |
526 // - The third field item uses a fragment-only URL with text. | |
527 // For consistency in assertion code below, the URL is assigned to the title | |
528 // variable for the first field. | |
529 $this->drupalGet('entity_test/add'); | |
530 $url1 = 'http://www.example.com/content/articles/archive?author=John&year=2012#com'; | |
531 $url2 = 'http://www.example.org/content/articles/archive?author=John&year=2012#org'; | |
532 $url3 = '#net'; | |
533 // Intentionally contains an ampersand that needs sanitization on output. | |
534 $title2 = 'A very long & strange example title that could break the nice layout of the site'; | |
535 $title3 = 'Fragment only'; | |
536 $edit = [ | |
537 "{$field_name}[0][uri]" => $url1, | |
538 "{$field_name}[1][uri]" => $url2, | |
539 "{$field_name}[1][title]" => $title2, | |
540 "{$field_name}[2][uri]" => $url3, | |
541 "{$field_name}[2][title]" => $title3, | |
542 ]; | |
543 $this->drupalPostForm(NULL, $edit, t('Save')); | |
544 preg_match('|entity_test/manage/(\d+)|', $this->getUrl(), $match); | |
545 $id = $match[1]; | |
546 $this->assertText(t('entity_test @id has been created.', ['@id' => $id])); | |
547 | |
548 // Verify that the link is output according to the formatter settings. | |
549 $options = [ | |
550 'trim_length' => [NULL, 6], | |
551 'rel' => [NULL, 'nofollow'], | |
552 'target' => [NULL, '_blank'], | |
553 ]; | |
554 foreach ($options as $setting => $values) { | |
555 foreach ($values as $new_value) { | |
556 // Update the field formatter settings. | |
557 $display_options['settings'] = [$setting => $new_value]; | |
558 entity_get_display('entity_test', 'entity_test', 'full') | |
559 ->setComponent($field_name, $display_options) | |
560 ->save(); | |
561 | |
562 $output = $this->renderTestEntity($id); | |
563 switch ($setting) { | |
564 case 'trim_length': | |
565 $url = $url1; | |
566 $url_title = isset($new_value) ? Unicode::truncate($url, $new_value, FALSE, TRUE) : $url; | |
567 $expected = '<div class="link-item">'; | |
568 $expected .= '<div class="link-url"><a href="' . Html::escape($url) . '">' . Html::escape($url_title) . '</a></div>'; | |
569 $expected .= '</div>'; | |
570 $this->assertContains($expected, $output); | |
571 | |
572 $url = $url2; | |
573 $url_title = isset($new_value) ? Unicode::truncate($url, $new_value, FALSE, TRUE) : $url; | |
574 $title = isset($new_value) ? Unicode::truncate($title2, $new_value, FALSE, TRUE) : $title2; | |
575 $expected = '<div class="link-item">'; | |
576 $expected .= '<div class="link-title">' . Html::escape($title) . '</div>'; | |
577 $expected .= '<div class="link-url"><a href="' . Html::escape($url) . '">' . Html::escape($url_title) . '</a></div>'; | |
578 $expected .= '</div>'; | |
579 $this->assertContains($expected, $output); | |
580 | |
581 $url = $url3; | |
582 $url_title = isset($new_value) ? Unicode::truncate($url, $new_value, FALSE, TRUE) : $url; | |
583 $title = isset($new_value) ? Unicode::truncate($title3, $new_value, FALSE, TRUE) : $title3; | |
584 $expected = '<div class="link-item">'; | |
585 $expected .= '<div class="link-title">' . Html::escape($title) . '</div>'; | |
586 $expected .= '<div class="link-url"><a href="' . Html::escape($url) . '">' . Html::escape($url_title) . '</a></div>'; | |
587 $expected .= '</div>'; | |
588 $this->assertContains($expected, $output); | |
589 break; | |
590 | |
591 case 'rel': | |
592 $rel = isset($new_value) ? ' rel="' . $new_value . '"' : ''; | |
593 $this->assertContains('<div class="link-url"><a href="' . Html::escape($url1) . '"' . $rel . '>' . Html::escape($url1) . '</a></div>', $output); | |
594 $this->assertContains('<div class="link-url"><a href="' . Html::escape($url2) . '"' . $rel . '>' . Html::escape($url2) . '</a></div>', $output); | |
595 $this->assertContains('<div class="link-url"><a href="' . Html::escape($url3) . '"' . $rel . '>' . Html::escape($url3) . '</a></div>', $output); | |
596 break; | |
597 | |
598 case 'target': | |
599 $target = isset($new_value) ? ' target="' . $new_value . '"' : ''; | |
600 $this->assertContains('<div class="link-url"><a href="' . Html::escape($url1) . '"' . $target . '>' . Html::escape($url1) . '</a></div>', $output); | |
601 $this->assertContains('<div class="link-url"><a href="' . Html::escape($url2) . '"' . $target . '>' . Html::escape($url2) . '</a></div>', $output); | |
602 $this->assertContains('<div class="link-url"><a href="' . Html::escape($url3) . '"' . $target . '>' . Html::escape($url3) . '</a></div>', $output); | |
603 break; | |
604 } | |
605 } | |
606 } | |
607 } | |
608 | |
609 /** | |
610 * Test '#link_type' property exists on 'link_default' widget. | |
611 * | |
612 * Make sure the 'link_default' widget exposes a '#link_type' property on | |
613 * its element. Modules can use it to understand if a text form element is | |
614 * a link and also which LinkItemInterface::LINK_* is (EXTERNAL, GENERIC, | |
615 * INTERNAL). | |
616 */ | |
617 public function testLinkTypeOnLinkWidget() { | |
618 | |
619 $link_type = LinkItemInterface::LINK_EXTERNAL; | |
620 $field_name = Unicode::strtolower($this->randomMachineName()); | |
621 | |
622 // Create a field with settings to validate. | |
623 $this->fieldStorage = FieldStorageConfig::create([ | |
624 'field_name' => $field_name, | |
625 'entity_type' => 'entity_test', | |
626 'type' => 'link', | |
627 'cardinality' => 1, | |
628 ]); | |
629 $this->fieldStorage->save(); | |
630 FieldConfig::create([ | |
631 'field_storage' => $this->fieldStorage, | |
632 'label' => 'Read more about this entity', | |
633 'bundle' => 'entity_test', | |
634 'settings' => [ | |
635 'title' => DRUPAL_OPTIONAL, | |
636 'link_type' => $link_type, | |
637 ], | |
638 ])->save(); | |
639 | |
640 $this->container->get('entity.manager') | |
641 ->getStorage('entity_form_display') | |
642 ->load('entity_test.entity_test.default') | |
643 ->setComponent($field_name, [ | |
644 'type' => 'link_default', | |
645 ]) | |
646 ->save(); | |
647 | |
648 $form = \Drupal::service('entity.form_builder')->getForm(EntityTest::create()); | |
649 $this->assertEqual($form[$field_name]['widget'][0]['uri']['#link_type'], $link_type); | |
650 } | |
651 | |
652 | |
653 /** | |
654 * Tests editing a link to a non-node entity. | |
655 */ | |
656 public function testEditNonNodeEntityLink() { | |
657 | |
658 $entity_type_manager = \Drupal::entityTypeManager(); | |
659 $entity_test_storage = $entity_type_manager->getStorage('entity_test'); | |
660 | |
661 // Create a field with settings to validate. | |
662 $this->fieldStorage = FieldStorageConfig::create([ | |
663 'field_name' => 'field_link', | |
664 'entity_type' => 'entity_test', | |
665 'type' => 'link', | |
666 'cardinality' => 1, | |
667 ]); | |
668 $this->fieldStorage->save(); | |
669 FieldConfig::create([ | |
670 'field_storage' => $this->fieldStorage, | |
671 'label' => 'Read more about this entity', | |
672 'bundle' => 'entity_test', | |
673 'settings' => [ | |
674 'title' => DRUPAL_OPTIONAL, | |
675 ], | |
676 ])->save(); | |
677 | |
678 $entity_type_manager | |
679 ->getStorage('entity_form_display') | |
680 ->load('entity_test.entity_test.default') | |
681 ->setComponent('field_link', [ | |
682 'type' => 'link_default', | |
683 ]) | |
684 ->save(); | |
685 | |
686 // Create a node and a test entity to have a possibly valid reference for | |
687 // both. Create another test entity that references the first test entity. | |
688 $entity_test_link = $entity_test_storage->create(['name' => 'correct link target']); | |
689 $entity_test_link->save(); | |
690 | |
691 $node = $this->drupalCreateNode(['wrong link target']); | |
692 | |
693 $correct_link = 'entity:entity_test/' . $entity_test_link->id(); | |
694 $entity_test = $entity_test_storage->create([ | |
695 'name' => 'correct link target', | |
696 'field_link' => $correct_link, | |
697 ]); | |
698 $entity_test->save(); | |
699 | |
700 // Edit the entity and save it, verify the correct link is kept and not | |
701 // changed to point to a node. Currently, widget does not support non-node | |
702 // autocomplete and therefore must show the link unaltered. | |
703 $this->drupalGet($entity_test->toUrl('edit-form')); | |
704 $this->assertSession()->fieldValueEquals('field_link[0][uri]', $correct_link); | |
705 $this->drupalPostForm(NULL, [], 'Save'); | |
706 | |
707 $entity_test_storage->resetCache(); | |
708 $entity_test = $entity_test_storage->load($entity_test->id()); | |
709 | |
710 $this->assertEquals($correct_link, $entity_test->get('field_link')->uri); | |
711 } | |
712 | |
713 /** | |
714 * Renders a test_entity and returns the output. | |
715 * | |
716 * @param int $id | |
717 * The test_entity ID to render. | |
718 * @param string $view_mode | |
719 * (optional) The view mode to use for rendering. | |
720 * @param bool $reset | |
721 * (optional) Whether to reset the entity_test storage cache. Defaults to | |
722 * TRUE to simplify testing. | |
723 * | |
724 * @return string | |
725 * The rendered HTML output. | |
726 */ | |
727 protected function renderTestEntity($id, $view_mode = 'full', $reset = TRUE) { | |
728 if ($reset) { | |
729 $this->container->get('entity.manager')->getStorage('entity_test')->resetCache([$id]); | |
730 } | |
731 $entity = EntityTest::load($id); | |
732 $display = entity_get_display($entity->getEntityTypeId(), $entity->bundle(), $view_mode); | |
733 $content = $display->build($entity); | |
734 $output = \Drupal::service('renderer')->renderRoot($content); | |
735 $output = (string) $output; | |
736 $this->verbose($output); | |
737 return $output; | |
738 } | |
739 | |
740 } |