silverstripe /
silverstripe-cms
| 1 | <?php |
||||
| 2 | |||||
| 3 | namespace SilverStripe\CMS\Tests\Controllers; |
||||
| 4 | |||||
| 5 | use Page; |
||||
|
0 ignored issues
–
show
|
|||||
| 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 | protected function setUp() : void |
||||
| 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
|
|||||
| 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
'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
Loading history...
|
|||||
| 285 | $matchedPage = SiteTree::get_by_link($url); |
||||
|
0 ignored issues
–
show
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
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 |
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:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths