Passed
Push — master ( 301f96...5c3d68 )
by Robbie
05:48
created

ModelAsControllerTest::testAllowMultibyte()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 30
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 22
nc 1
nop 0
dl 0
loc 30
rs 9.568
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\CMS\Tests\Controllers;
4
5
use Page;
0 ignored issues
show
Bug introduced by
The type Page was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
6
use SilverStripe\CMS\Controllers\ContentController;
7
use SilverStripe\CMS\Controllers\ModelAsController;
8
use SilverStripe\CMS\Controllers\OldPageRedirector;
9
use SilverStripe\CMS\Controllers\RootURLController;
10
use SilverStripe\CMS\Model\SiteTree;
11
use SilverStripe\Control\Controller;
12
use SilverStripe\Control\Director;
13
use SilverStripe\Core\Config\Config;
14
use SilverStripe\Dev\FunctionalTest;
15
use SilverStripe\Versioned\Versioned;
16
use SilverStripe\View\Parsers\URLSegmentFilter;
17
18
class ModelAsControllerTest extends FunctionalTest
19
{
20
    protected $usesDatabase = true;
21
22
    protected $autoFollowRedirection = false;
23
24
    protected static $required_extensions = [
25
        ModelAsController::class => [
26
            OldPageRedirector::class,
27
        ],
28
        ContentController::class => [
29
            OldPageRedirector::class,
30
        ],
31
    ];
32
33
    /**
34
     * New tests require nested urls to be enabled, but the site might not
35
     * support nested URLs.
36
     * This setup will enable nested-urls for this test and resets the state
37
     * after the tests have been performed.
38
     */
39
    public function setUp()
40
    {
41
        parent::setUp();
42
        Config::modify()->set(SiteTree::class, 'nested_urls', true);
43
    }
44
45
46
    protected function generateNestedPagesFixture()
47
    {
48
        $level1 = SiteTree::create();
49
        $level1->Title      = 'First Level';
50
        $level1->URLSegment = 'level1';
51
        $level1->write();
52
        $level1->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
53
54
        $level1->URLSegment = 'newlevel1';
55
        $level1->write();
56
        $level1->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
57
58
        $level2 = SiteTree::create();
59
        $level2->Title      = 'Second Level';
60
        $level2->URLSegment = 'level2';
61
        $level2->ParentID = $level1->ID;
62
        $level2->write();
63
        $level2->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
64
65
        $level2->URLSegment = 'newlevel2';
66
        $level2->write();
67
        $level2->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
68
69
        $level3 = SiteTree::create();
70
        $level3->Title = "Level 3";
71
        $level3->URLSegment = 'level3';
72
        $level3->ParentID = $level2->ID;
73
        $level3->write();
74
        $level3->copyVersionToStage('Stage', 'Live');
75
76
        $level3->URLSegment = 'newlevel3';
77
        $level3->write();
78
        $level3->copyVersionToStage('Stage', 'Live');
79
    }
80
81
    /**
82
     * We're building up a page hierarchy ("nested URLs") and rename
83
     * all the individual pages afterwards. The assumption is that
84
     * all pages will be found by their old segments.
85
     *
86
     * NOTE: This test requires nested_urls
87
     *
88
     * Original: level1/level2/level3
89
     * Republished as: newlevel1/newlevel2/newlevel3
90
     */
91
    public function testRedirectsNestedRenamedPages()
92
    {
93
        $this->generateNestedPagesFixture();
94
95
        // check a first level URLSegment
96
        $response = $this->get('level1/action');
97
        $this->assertEquals($response->getStatusCode(), 301);
98
        $this->assertEquals(
99
            Controller::join_links(Director::baseURL() . 'newlevel1/action'),
100
            $response->getHeader('Location')
101
        );
102
103
        // check second level URLSegment
104
        $response = $this->get('newlevel1/level2');
105
        $this->assertEquals($response->getStatusCode(), 301);
106
        $this->assertEquals(
107
            Controller::join_links(Director::baseURL() . 'newlevel1/newlevel2/'),
108
            $response->getHeader('Location')
109
        );
110
111
        // check third level URLSegment
112
        $response = $this->get('newlevel1/newlevel2/level3');
113
        $this->assertEquals($response->getStatusCode(), 301);
114
        $this->assertEquals(
115
            Controller::join_links(Director::baseURL() . 'newlevel1/newlevel2/newlevel3/'),
116
            $response->getHeader('Location')
117
        );
118
119
        $response = $this->get('newlevel1/newlevel2/level3');
0 ignored issues
show
Unused Code introduced by
The assignment to $response is dead and can be removed.
Loading history...
120
    }
121
122
    /**
123
     * Test that the redirect works even with a lot of nested pages
124
     * Original: /oldurl/level2/level3/level4/level5
125
     * New: /newurl/level2/level3/level4/level5
126
     */
127
    public function testHeavilyNestedRenamedRedirectedPages()
128
    {
129
        $page = SiteTree::create();
130
        $page->Title      = 'First Level';
131
        $page->URLSegment = 'oldurl';
132
        $page->write();
133
        $page->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
134
135
        $page->URLSegment = 'newurl';
136
        $page->write();
137
        $page->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
138
139
        $page2 = SiteTree::create();
140
        $page2->Title      = 'Second Level Page';
141
        $page2->URLSegment = 'level2';
142
        $page2->ParentID = $page->ID;
143
        $page2->write();
144
        $page2->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
145
146
        $page3 = SiteTree::create();
147
        $page3->Title      = 'Third Level Page';
148
        $page3->URLSegment = 'level3';
149
        $page3->ParentID = $page2->ID;
150
        $page3->write();
151
        $page3->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
152
153
        $page4 = SiteTree::create();
154
        $page4->Title      = 'Fourth Level Page';
155
        $page4->URLSegment = 'level4';
156
        $page4->ParentID = $page3->ID;
157
        $page4->write();
158
        $page4->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
159
160
        $page5 = SiteTree::create();
161
        $page5->Title      = 'Fifth Level Page';
162
        $page5->URLSegment = 'level5';
163
        $page5->ParentID = $page4->ID;
164
        $page5->write();
165
        $page5->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
166
167
        // Test that the redirect still works fine when trying to access the most nested page
168
        $response = $this->get('oldurl/level2/level3/level4/level5/');
169
        $this->assertEquals($response->getStatusCode(), 301);
170
        $this->assertEquals(
171
            Controller::join_links(Director::baseURL() . 'newurl/level2/level3/level4/level5/'),
172
            $response->getHeader('Location')
173
        );
174
    }
175
176
177
    public function testRedirectionForPreNestedurlsBookmarks()
178
    {
179
        $this->generateNestedPagesFixture();
180
181
        // Up-to-date URLs will be redirected to the appropriate subdirectory
182
        $response = $this->get('newlevel3');
183
        $this->assertEquals(301, $response->getStatusCode());
184
        $this->assertEquals(
185
            Director::baseURL() . 'newlevel1/newlevel2/newlevel3/',
186
            $response->getHeader("Location")
187
        );
188
189
        // So will the legacy ones
190
        $response = $this->get('level3');
191
        $this->assertEquals(301, $response->getStatusCode());
192
        $this->assertEquals(
193
            Director::baseURL() . 'newlevel1/newlevel2/newlevel3/',
194
            $response->getHeader("Location")
195
        );
196
    }
197
198
    public function testDoesntRedirectToNestedChildrenOutsideOfOwnHierarchy()
199
    {
200
        $this->generateNestedPagesFixture();
201
202
        $otherParent = SiteTree::create([
203
            'URLSegment' => 'otherparent',
204
        ]);
205
        $otherParent->write();
206
        $otherParent->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
207
208
        $response = $this->get('level1/otherparent');
209
        $this->assertEquals($response->getStatusCode(), 301);
210
211
        $response = $this->get('newlevel1/otherparent');
212
        $this->assertEquals(
213
            $response->getStatusCode(),
214
            404,
215
            'Requesting an unrelated page on a renamed parent should be interpreted as a missing action, not a redirect'
216
        );
217
    }
218
219
    /**
220
     *
221
     * NOTE: This test requires nested_urls
222
     *
223
     */
224
    public function testRedirectsNestedRenamedPagesWithGetParameters()
225
    {
226
        $this->generateNestedPagesFixture();
227
228
        // check third level URLSegment
229
        $response = $this->get('newlevel1/newlevel2/level3/?foo=bar&test=test');
230
        $this->assertEquals($response->getStatusCode(), 301);
231
        $this->assertEquals(
232
            Controller::join_links(Director::baseURL() . 'newlevel1/newlevel2/newlevel3/', '?foo=bar&test=test'),
233
            $response->getHeader('Location')
234
        );
235
    }
236
237
    /**
238
     *
239
     * NOTE: This test requires nested_urls
240
     *
241
     */
242
    public function testDoesntRedirectToNestedRenamedPageWhenNewExists()
243
    {
244
        $this->generateNestedPagesFixture();
245
246
        $otherLevel1 = SiteTree::create([
247
            'Title' => "Other Level 1",
248
            'URLSegment' => 'level1',
249
        ]);
250
        $otherLevel1->write();
251
        $otherLevel1->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
252
253
        $response = $this->get('level1');
254
        $this->assertEquals(
255
            $response->getStatusCode(),
256
            200
257
        );
258
259
        $response = $this->get('level1/newlevel2');
260
        $this->assertEquals(
261
            $response->getStatusCode(),
262
            404,
263
            'The old newlevel2/ URLSegment is checked as an action on the new page, which shouldnt exist.'
264
        );
265
    }
266
267
    /**
268
     *
269
     * NOTE: This test requires nested_urls
270
     *
271
     */
272
    public function testFindOldPage()
273
    {
274
        $page = SiteTree::create();
275
        $page->Title      = 'First Level';
276
        $page->URLSegment = 'oldurl';
277
        $page->write();
278
        $page->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
279
280
        $page->URLSegment = 'newurl';
281
        $page->write();
282
        $page->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
283
284
        $url = OldPageRedirector::find_old_page('oldurl');
0 ignored issues
show
Bug introduced by
'oldurl' of type string is incompatible with the type array expected by parameter $params of SilverStripe\CMS\Control...rector::find_old_page(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

284
        $url = OldPageRedirector::find_old_page(/** @scrutinizer ignore-type */ 'oldurl');
Loading history...
285
        $matchedPage = SiteTree::get_by_link($url);
0 ignored issues
show
Bug introduced by
It seems like $url can also be of type false; however, parameter $link of SilverStripe\CMS\Model\SiteTree::get_by_link() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

285
        $matchedPage = SiteTree::get_by_link(/** @scrutinizer ignore-type */ $url);
Loading history...
286
        $this->assertEquals('First Level', $matchedPage->Title);
287
288
        $page2 = SiteTree::create();
289
        $page2->Title      = 'Second Level Page';
290
        $page2->URLSegment = 'oldpage2';
291
        $page2->ParentID = $page->ID;
292
        $page2->write();
293
        $page2->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
294
295
        $page2->URLSegment = 'newpage2';
296
        $page2->write();
297
        $page2->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
298
299
        $url = OldPageRedirector::find_old_page('oldpage2', $page2->ParentID);
300
        $matchedPage = SiteTree::get_by_link($url);
301
        $this->assertEquals('Second Level Page', $matchedPage->Title);
302
303
        $url = OldPageRedirector::find_old_page('oldpage2', $page2->ID);
304
        $matchedPage = SiteTree::get_by_link($url);
305
        $this->assertEquals(false, $matchedPage);
306
    }
307
308
    /**
309
     * go to a page that's been published but is child of an unpublished page
310
     *
311
     * NOTE: This test requires nested_urls
312
     */
313
    public function testChildOfDraft()
314
    {
315
        RootURLController::reset();
316
        Config::modify()->set(SiteTree::class, 'nested_urls', true);
317
318
        $draft = SiteTree::create();
319
        $draft->Title = 'Root Leve Draft Page';
320
        $draft->URLSegment = 'root';
321
        $draft->write();
322
323
        $published = SiteTree::create();
324
        $published->Title = 'Published Page Under Draft Page';
325
        $published->URLSegment = 'sub-root';
326
        $published->write();
327
        $published->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
328
        $response = $this->get('root/sub-root');
329
330
        $this->assertEquals(
331
            $response->getStatusCode(),
332
            404,
333
            'The page should not be found since its parent has not been published, in this case ' .
334
            'http://<yousitename>/root/sub-root or http://<yousitename>/sub-root'
335
        );
336
    }
337
338
    public function testAllowMultibyte()
339
    {
340
        Config::modify()->set(URLSegmentFilter::class, 'default_allow_multibyte', true);
341
342
        $parent = new Page();
343
        $parent->Title = 'Multibyte test';
344
        $parent->URLSegment = 'بلاگ';
345
        $parent->write();
346
        $parent->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
347
348
        $child = new Page();
349
        $child->Title = 'Multibyte test';
350
        $child->URLSegment = 'فضة';
351
        $child->ParentID = $parent->ID;
352
        $child->write();
353
        $child->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
354
355
        // Emulate browser behaviour around multibyte URL encodings
356
        $response = $this->get(rawurlencode('بلاگ'));
357
        $this->assertEquals(
358
            $response->getStatusCode(),
359
            200,
360
            'Routes toplevel paths'
361
        );
362
363
        $response = $this->get(join('/', [rawurlencode('بلاگ'), rawurlencode('فضة')]));
364
        $this->assertEquals(
365
            $response->getStatusCode(),
366
            200,
367
            'Routes nested paths'
368
        );
369
    }
370
}
371