Security update for Core, with self-updated composer
[yaffs-website] / web / core / modules / path / tests / src / Functional / PathLanguageTest.php
1 <?php
2
3 namespace Drupal\Tests\path\Functional;
4
5 /**
6  * Confirm that paths work with translated nodes.
7  *
8  * @group path
9  */
10 class PathLanguageTest extends PathTestBase {
11
12   /**
13    * Modules to enable.
14    *
15    * @var array
16    */
17   public static $modules = ['path', 'locale', 'locale_test', 'content_translation'];
18
19   /**
20    * An user with permissions to administer content types.
21    *
22    * @var \Drupal\user\UserInterface
23    */
24   protected $webUser;
25
26   protected function setUp() {
27     parent::setUp();
28
29     $permissions = [
30       'access administration pages',
31       'administer content translation',
32       'administer content types',
33       'administer languages',
34       'administer url aliases',
35       'create content translations',
36       'create page content',
37       'create url aliases',
38       'edit any page content',
39       'translate any entity',
40     ];
41     // Create and log in user.
42     $this->webUser = $this->drupalCreateUser($permissions);
43     $this->drupalLogin($this->webUser);
44
45     // Enable French language.
46     $edit = [];
47     $edit['predefined_langcode'] = 'fr';
48
49     $this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
50
51     // Enable URL language detection and selection.
52     $edit = ['language_interface[enabled][language-url]' => 1];
53     $this->drupalPostForm('admin/config/regional/language/detection', $edit, t('Save settings'));
54
55     // Enable translation for page node.
56     $edit = [
57       'entity_types[node]' => 1,
58       'settings[node][page][translatable]' => 1,
59       'settings[node][page][fields][path]' => 1,
60       'settings[node][page][fields][body]' => 1,
61       'settings[node][page][settings][language][language_alterable]' => 1,
62     ];
63     $this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration'));
64     \Drupal::entityManager()->clearCachedDefinitions();
65
66     $definitions = \Drupal::entityManager()->getFieldDefinitions('node', 'page');
67     $this->assertTrue($definitions['path']->isTranslatable(), 'Node path is translatable.');
68     $this->assertTrue($definitions['body']->isTranslatable(), 'Node body is translatable.');
69   }
70
71   /**
72    * Test alias functionality through the admin interfaces.
73    */
74   public function testAliasTranslation() {
75     $node_storage = $this->container->get('entity.manager')->getStorage('node');
76     $english_node = $this->drupalCreateNode(['type' => 'page', 'langcode' => 'en']);
77     $english_alias = $this->randomMachineName();
78
79     // Edit the node to set language and path.
80     $edit = [];
81     $edit['path[0][alias]'] = '/' . $english_alias;
82     $this->drupalPostForm('node/' . $english_node->id() . '/edit', $edit, t('Save'));
83
84     // Confirm that the alias works.
85     $this->drupalGet($english_alias);
86     $this->assertText($english_node->body->value, 'Alias works.');
87
88     // Translate the node into French.
89     $this->drupalGet('node/' . $english_node->id() . '/translations');
90     $this->clickLink(t('Add'));
91
92     $edit = [];
93     $edit['title[0][value]'] = $this->randomMachineName();
94     $edit['body[0][value]'] = $this->randomMachineName();
95     $french_alias = $this->randomMachineName();
96     $edit['path[0][alias]'] = '/' . $french_alias;
97     $this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
98
99     // Clear the path lookup cache.
100     $this->container->get('path.alias_manager')->cacheClear();
101
102     // Languages are cached on many levels, and we need to clear those caches.
103     $this->container->get('language_manager')->reset();
104     $this->rebuildContainer();
105     $languages = $this->container->get('language_manager')->getLanguages();
106
107     // Ensure the node was created.
108     $node_storage->resetCache([$english_node->id()]);
109     $english_node = $node_storage->load($english_node->id());
110     $english_node_french_translation = $english_node->getTranslation('fr');
111     $this->assertTrue($english_node->hasTranslation('fr'), 'Node found in database.');
112
113     // Confirm that the alias works.
114     $this->drupalGet('fr' . $edit['path[0][alias]']);
115     $this->assertText($english_node_french_translation->body->value, 'Alias for French translation works.');
116
117     // Confirm that the alias is returned for the URL. Languages are cached on
118     // many levels, and we need to clear those caches.
119     $this->container->get('language_manager')->reset();
120     $languages = $this->container->get('language_manager')->getLanguages();
121     $url = $english_node_french_translation->url('canonical', ['language' => $languages['fr']]);
122
123     $this->assertTrue(strpos($url, $edit['path[0][alias]']), 'URL contains the path alias.');
124
125     // Confirm that the alias works even when changing language negotiation
126     // options. Enable User language detection and selection over URL one.
127     $edit = [
128       'language_interface[enabled][language-user]' => 1,
129       'language_interface[weight][language-user]' => -9,
130       'language_interface[enabled][language-url]' => 1,
131       'language_interface[weight][language-url]' => -8,
132     ];
133     $this->drupalPostForm('admin/config/regional/language/detection', $edit, t('Save settings'));
134
135     // Change user language preference.
136     $edit = ['preferred_langcode' => 'fr'];
137     $this->drupalPostForm("user/" . $this->webUser->id() . "/edit", $edit, t('Save'));
138
139     // Check that the English alias works. In this situation French is the
140     // current UI and content language, while URL language is English (since we
141     // do not have a path prefix we fall back to the site's default language).
142     // We need to ensure that the user language preference is not taken into
143     // account while determining the path alias language, because if this
144     // happens we have no way to check that the path alias is valid: there is no
145     // path alias for French matching the english alias. So the alias manager
146     // needs to use the URL language to check whether the alias is valid.
147     $this->drupalGet($english_alias);
148     $this->assertText($english_node_french_translation->body->value, 'English alias, but French preferred by the user: French translation.');
149
150     // Check that the French alias works.
151     $this->drupalGet("fr/$french_alias");
152     $this->assertText($english_node_french_translation->body->value, 'Alias for French translation works.');
153
154     // Disable URL language negotiation.
155     $edit = ['language_interface[enabled][language-url]' => FALSE];
156     $this->drupalPostForm('admin/config/regional/language/detection', $edit, t('Save settings'));
157
158     // Check that the English alias still works.
159     $this->drupalGet($english_alias);
160     $this->assertText($english_node_french_translation->body->value, 'English alias, but French preferred by the user: French translation.');
161
162     // Check that the French alias is not available. We check the unprefixed
163     // alias because we disabled URL language negotiation above. In this
164     // situation only aliases in the default language and language neutral ones
165     // should keep working.
166     $this->drupalGet($french_alias);
167     $this->assertResponse(404, 'Alias for French translation is unavailable when URL language negotiation is disabled.');
168
169     // The alias manager has an internal path lookup cache. Check to see that
170     // it has the appropriate contents at this point.
171     $this->container->get('path.alias_manager')->cacheClear();
172     $french_node_path = $this->container->get('path.alias_manager')->getPathByAlias('/' . $french_alias, 'fr');
173     $this->assertEqual($french_node_path, '/node/' . $english_node_french_translation->id(), 'Normal path works.');
174     // Second call should return the same path.
175     $french_node_path = $this->container->get('path.alias_manager')->getPathByAlias('/' . $french_alias, 'fr');
176     $this->assertEqual($french_node_path, '/node/' . $english_node_french_translation->id(), 'Normal path is the same.');
177
178     // Confirm that the alias works.
179     $french_node_alias = $this->container->get('path.alias_manager')->getAliasByPath('/node/' . $english_node_french_translation->id(), 'fr');
180     $this->assertEqual($french_node_alias, '/' . $french_alias, 'Alias works.');
181     // Second call should return the same alias.
182     $french_node_alias = $this->container->get('path.alias_manager')->getAliasByPath('/node/' . $english_node_french_translation->id(), 'fr');
183     $this->assertEqual($french_node_alias, '/' . $french_alias, 'Alias is the same.');
184
185     // Confirm that the alias is removed if the translation is deleted.
186     $english_node->removeTranslation('fr');
187     $english_node->save();
188     $this->assertFalse($this->container->get('path.alias_storage')->aliasExists('/' . $french_alias, 'fr'), 'Alias for French translation is removed when translation is deleted.');
189
190     // Check that the English alias still works.
191     $this->drupalGet($english_alias);
192     $this->assertTrue($this->container->get('path.alias_storage')->aliasExists('/' . $english_alias, 'en'), 'English alias is not deleted when French translation is removed.');
193     $this->assertText($english_node->body->value, 'English alias still works');
194   }
195
196 }