Issues (144)

tests/php/SiteTreeSubsitesTest.php (3 issues)

1
<?php
2
3
namespace SilverStripe\Subsites\Tests;
4
5
use Page;
6
use SilverStripe\CMS\Controllers\CMSMain;
7
use SilverStripe\CMS\Controllers\ModelAsController;
8
use SilverStripe\CMS\Forms\SiteTreeURLSegmentField;
9
use SilverStripe\CMS\Model\SiteTree;
10
use SilverStripe\Control\Director;
11
use SilverStripe\Core\Config\Config;
12
use SilverStripe\Core\Convert;
13
use SilverStripe\Core\Injector\Injector;
14
use SilverStripe\ErrorPage\ErrorPage;
15
use SilverStripe\Forms\FieldList;
16
use SilverStripe\Security\Member;
17
use SilverStripe\SiteConfig\SiteConfig;
18
use SilverStripe\Subsites\Extensions\SiteTreeSubsites;
19
use SilverStripe\Subsites\Model\Subsite;
20
use SilverStripe\Subsites\Pages\SubsitesVirtualPage;
21
use SilverStripe\Subsites\Service\ThemeResolver;
22
use SilverStripe\Subsites\Tests\SiteTreeSubsitesTest\TestClassA;
23
use SilverStripe\Subsites\Tests\SiteTreeSubsitesTest\TestClassB;
24
use SilverStripe\Subsites\Tests\SiteTreeSubsitesTest\TestErrorPage;
25
use SilverStripe\Versioned\Versioned;
26
use SilverStripe\View\SSViewer;
27
use TractorCow\Fluent\Extension\FluentSiteTreeExtension;
28
29
class SiteTreeSubsitesTest extends BaseSubsiteTest
30
{
31
    protected static $fixture_file = 'SubsiteTest.yml';
32
33
    protected static $extra_dataobjects = [
34
        TestClassA::class,
35
        TestClassB::class,
36
        TestErrorPage::class
37
    ];
38
39
    protected static $illegal_extensions = [
40
        SiteTree::class => [
41
            FluentSiteTreeExtension::class,
42
        ],
43
    ];
44
45
    protected function setUp()
46
    {
47
        // We have our own home page fixtures, prevent the default one being created in this test suite.
48
        Config::modify()->set(SiteTree::class, 'create_default_pages', false);
49
50
        parent::setUp();
51
    }
52
53
    public function testPagesInDifferentSubsitesCanShareURLSegment()
54
    {
55
        $subsiteMain = $this->objFromFixture(Subsite::class, 'main');
0 ignored issues
show
The assignment to $subsiteMain is dead and can be removed.
Loading history...
56
        $subsite1 = $this->objFromFixture(Subsite::class, 'subsite1');
57
58
        $pageMain = new SiteTree();
59
        $pageMain->URLSegment = 'testpage';
60
        $pageMain->write();
61
        $pageMain->copyVersionToStage('Stage', 'Live');
62
63
        $pageMainOther = new SiteTree();
64
        $pageMainOther->URLSegment = 'testpage';
65
        $pageMainOther->write();
66
        $pageMainOther->copyVersionToStage('Stage', 'Live');
67
68
        $this->assertNotEquals(
69
            $pageMain->URLSegment,
70
            $pageMainOther->URLSegment,
71
            'Pages in same subsite cant share the same URL'
72
        );
73
74
        Subsite::changeSubsite($subsite1->ID);
75
76
        $pageSubsite1 = new SiteTree();
77
        $pageSubsite1->URLSegment = 'testpage';
78
        $pageSubsite1->write();
79
        $pageSubsite1->copyVersionToStage('Stage', 'Live');
80
81
        $this->assertEquals(
82
            $pageMain->URLSegment,
83
            $pageSubsite1->URLSegment,
84
            'Pages in different subsites can share the same URL'
85
        );
86
    }
87
88
    public function testBasicSanity()
89
    {
90
        $this->assertInstanceOf(SiteConfig::class, singleton(SiteTree::class)->getSiteConfig());
91
        // The following assert is breaking in Translatable.
92
        $this->assertInstanceOf(FieldList::class, singleton(SiteTree::class)->getCMSFields());
93
        $this->assertInstanceOf(FieldList::class, singleton(SubsitesVirtualPage::class)->getCMSFields());
94
        $this->assertTrue(is_array(singleton(SiteTreeSubsites::class)->extraStatics()));
95
    }
96
97
    public function errorPageLocationsProvider()
98
    {
99
        return [
100
            ['domaintest1', '/error-500-one.example.org.html'],
101
            ['domaintestVagrant', '/error-500-localhost8080.html']
102
        ];
103
    }
104
105
    /**
106
     * @dataProvider errorPageLocationsProvider
107
     */
108
    public function testErrorPageLocations($subsiteFixtureName, $expectedFilename)
109
    {
110
        $static_path = Config::inst()->get(ErrorPage::class, 'static_filepath');
111
112
        $subsite = $this->objFromFixture(Subsite::class, $subsiteFixtureName);
113
        $expected_path = $static_path . $expectedFilename;
114
115
        Subsite::changeSubsite($subsite->ID);
116
        $path = TestErrorPage::get_error_filename_spy(500);
117
118
        $this->assertEquals($expected_path, $path);
119
    }
120
121
    public function testCanEditSiteTree()
122
    {
123
        $admin = $this->objFromFixture(Member::class, 'admin');
124
        $subsite1member = $this->objFromFixture(Member::class, 'subsite1member');
125
        $subsite2member = $this->objFromFixture(Member::class, 'subsite2member');
126
        $mainpage = $this->objFromFixture('Page', 'home');
127
        $subsite1page = $this->objFromFixture('Page', 'subsite1_home');
128
        $subsite2page = $this->objFromFixture('Page', 'subsite2_home');
0 ignored issues
show
The assignment to $subsite2page is dead and can be removed.
Loading history...
129
        $subsite1 = $this->objFromFixture(Subsite::class, 'subsite1');
130
        $subsite2 = $this->objFromFixture(Subsite::class, 'subsite2');
0 ignored issues
show
The assignment to $subsite2 is dead and can be removed.
Loading history...
131
132
        // Cant pass member as arguments to canEdit() because of GroupSubsites
133
        $this->logInAs($admin);
134
135
        $this->assertTrue(
136
            (bool)$subsite1page->canEdit(),
137
            'Administrators can edit all subsites'
138
        );
139
140
        // @todo: Workaround because GroupSubsites->augmentSQL() is relying on session state
141
        Subsite::changeSubsite($subsite1);
142
143
        $this->logInAs($subsite1member->ID);
144
        $this->assertTrue(
145
            (bool)$subsite1page->canEdit(),
146
            'Members can edit pages on a subsite if they are in a group belonging to this subsite'
147
        );
148
149
        $this->logInAs($subsite2member->ID);
150
        $this->assertFalse(
151
            (bool)$subsite1page->canEdit(),
152
            'Members cant edit pages on a subsite if they are not in a group belonging to this subsite'
153
        );
154
155
        // @todo: Workaround because GroupSubsites->augmentSQL() is relying on session state
156
        Subsite::changeSubsite(0);
157
        $this->assertFalse(
158
            $mainpage->canEdit(),
159
            'Members cant edit pages on the main site if they are not in a group allowing this'
160
        );
161
    }
162
163
    /**
164
     * Similar to {@link SubsitesVirtualPageTest->testSubsiteVirtualPageCanHaveSameUrlsegmentAsOtherSubsite()}.
165
     */
166
    public function testTwoPagesWithSameURLOnDifferentSubsites()
167
    {
168
        // Set up a couple of pages with the same URL on different subsites
169
        $s1 = $this->objFromFixture(Subsite::class, 'domaintest1');
170
        $s2 = $this->objFromFixture(Subsite::class, 'domaintest2');
171
172
        $p1 = new SiteTree();
173
        $p1->Title = $p1->URLSegment = 'test-page';
174
        $p1->SubsiteID = $s1->ID;
175
        $p1->write();
176
177
        $p2 = new SiteTree();
178
        $p2->Title = $p1->URLSegment = 'test-page';
179
        $p2->SubsiteID = $s2->ID;
180
        $p2->write();
181
182
        // Check that the URLs weren't modified in our set-up
183
        $this->assertEquals('test-page', $p1->URLSegment);
184
        $this->assertEquals('test-page', $p2->URLSegment);
185
186
        // Check that if we switch between the different subsites, we receive the correct pages
187
        Subsite::changeSubsite($s1);
188
        $this->assertEquals($p1->ID, SiteTree::get_by_link('test-page')->ID);
189
190
        Subsite::changeSubsite($s2);
191
        $this->assertEquals($p2->ID, SiteTree::get_by_link('test-page')->ID);
192
    }
193
194
    public function testPageTypesBlacklistInClassDropdown()
195
    {
196
        $this->logInAs('editor');
197
198
        $s1 = $this->objFromFixture(Subsite::class, 'domaintest1');
199
        $s2 = $this->objFromFixture(Subsite::class, 'domaintest2');
200
        $page = singleton(SiteTree::class);
201
202
        $s1->PageTypeBlacklist = json_encode([TestClassA::class, ErrorPage::class]);
203
        $s1->write();
204
205
        Subsite::changeSubsite($s1);
206
        $settingsFields = $page->getSettingsFields()->dataFieldByName('ClassName')->getSource();
207
208
        $this->assertArrayNotHasKey(
209
            ErrorPage::class,
210
            $settingsFields
211
        );
212
        $this->assertArrayNotHasKey(
213
            TestClassA::class,
214
            $settingsFields
215
        );
216
        $this->assertArrayHasKey(
217
            TestClassB::class,
218
            $settingsFields
219
        );
220
221
        Subsite::changeSubsite($s2);
222
        $settingsFields = $page->getSettingsFields()->dataFieldByName('ClassName')->getSource();
223
        $this->assertArrayHasKey(
224
            ErrorPage::class,
225
            $settingsFields
226
        );
227
        $this->assertArrayHasKey(
228
            TestClassA::class,
229
            $settingsFields
230
        );
231
        $this->assertArrayHasKey(
232
            TestClassB::class,
233
            $settingsFields
234
        );
235
    }
236
237
    public function testCopyToSubsite()
238
    {
239
        // Remove baseurl if testing in subdir
240
        Config::modify()->set(Director::class, 'alternate_base_url', '/');
241
242
        /** @var Subsite $otherSubsite */
243
        $otherSubsite = $this->objFromFixture(Subsite::class, 'subsite1');
244
        $staffPage = $this->objFromFixture(Page::class, 'staff'); // nested page
245
        $contactPage = $this->objFromFixture(Page::class, 'contact'); // top level page
246
247
        $staffPage2 = $staffPage->duplicateToSubsite($otherSubsite->ID);
248
        $contactPage2 = $contactPage->duplicateToSubsite($otherSubsite->ID);
249
250
        $this->assertNotEquals($staffPage->ID, $staffPage2->ID);
251
        $this->assertNotEquals($staffPage->SubsiteID, $staffPage2->SubsiteID);
252
        $this->assertNotEquals($contactPage->ID, $contactPage2->ID);
253
        $this->assertNotEquals($contactPage->SubsiteID, $contactPage2->SubsiteID);
254
        $this->assertEmpty($staffPage2->ParentID);
255
        $this->assertEmpty($contactPage2->ParentID);
256
        $this->assertNotEmpty($staffPage->ParentID);
257
        $this->assertEmpty($contactPage->ParentID);
258
259
        // Staff is shifted to top level and given a unique url segment
260
        $domain = $otherSubsite->domain();
261
        $this->assertEquals('http://' . $domain . '/staff-2/', $staffPage2->AbsoluteLink());
262
        $this->assertEquals('http://' . $domain . '/contact-us-2/', $contactPage2->AbsoluteLink());
263
    }
264
265
    public function testPageTypesBlacklistInCMSMain()
266
    {
267
        $this->logInAs('editor');
268
269
        $s1 = $this->objFromFixture(Subsite::class, 'domaintest1');
270
        $s2 = $this->objFromFixture(Subsite::class, 'domaintest2');
271
272
        $s1->PageTypeBlacklist = json_encode([TestClassA::class, ErrorPage::class]);
273
        $s1->write();
274
275
        Subsite::changeSubsite($s1);
276
        $cmsmain = CMSMain::create();
277
        $hints = json_decode($cmsmain->SiteTreeHints(), true);
278
        $classes = $hints['Root']['disallowedChildren'];
279
        $this->assertContains(ErrorPage::class, $classes);
280
        $this->assertContains(TestClassA::class, $classes);
281
        $this->assertNotContains(TestClassB::class, $classes);
282
283
        Subsite::changeSubsite($s2);
284
        // SS 4.1 and above
285
        if ($cmsmain->hasMethod('getHintsCache')) {
286
            $cmsmain->getHintsCache()->clear();
287
        }
288
        $hints = json_decode($cmsmain->SiteTreeHints(), true);
289
290
        $classes = $hints['Root']['disallowedChildren'];
291
        $this->assertNotContains(ErrorPage::class, $classes);
292
        $this->assertNotContains(TestClassA::class, $classes);
293
        $this->assertNotContains(TestClassB::class, $classes);
294
    }
295
296
    /**
297
     * Tests that url segments between subsites don't conflict, but do conflict within them
298
     */
299
    public function testValidateURLSegment()
300
    {
301
        $this->logInWithPermission('ADMIN');
302
        // Saving existing page in the same subsite doesn't change urls
303
        $mainHome = $this->objFromFixture(Page::class, 'home');
304
        $mainSubsiteID = $this->idFromFixture(Subsite::class, 'main');
305
        Subsite::changeSubsite($mainSubsiteID);
306
        $mainHome->Content = '<p>Some new content</p>';
307
        $mainHome->write();
308
        $this->assertEquals('home', $mainHome->URLSegment);
309
        $mainHome->publishRecursive();
310
        $mainHomeLive = Versioned::get_one_by_stage('Page', 'Live', sprintf('"SiteTree"."ID" = \'%d\'', $mainHome->ID));
311
        $this->assertEquals('home', $mainHomeLive->URLSegment);
312
313
        // Saving existing page in another subsite doesn't change urls
314
        Subsite::changeSubsite($mainSubsiteID);
315
        $subsite1Home = $this->objFromFixture('Page', 'subsite1_home');
316
        $subsite1Home->Content = '<p>In subsite 1</p>';
317
        $subsite1Home->write();
318
        $this->assertEquals('home', $subsite1Home->URLSegment);
319
        $subsite1Home->publishRecursive();
320
        $subsite1HomeLive = Versioned::get_one_by_stage(
321
            'Page',
322
            'Live',
323
            sprintf('"SiteTree"."ID" = \'%d\'', $subsite1Home->ID)
324
        );
325
        $this->assertEquals('home', $subsite1HomeLive->URLSegment);
326
327
        // Creating a new page in a subsite doesn't conflict with urls in other subsites
328
        $subsite1ID = $this->idFromFixture(Subsite::class, 'subsite1');
329
        Subsite::changeSubsite($subsite1ID);
330
        $subsite1NewPage = new Page();
331
        $subsite1NewPage->SubsiteID = $subsite1ID;
332
        $subsite1NewPage->Title = 'Important Page (Subsite 1)';
333
        $subsite1NewPage->URLSegment = 'important-page'; // Also exists in main subsite
334
        $subsite1NewPage->write();
335
        $this->assertEquals('important-page', $subsite1NewPage->URLSegment);
336
        $subsite1NewPage->publishRecursive();
337
        $subsite1NewPageLive = Versioned::get_one_by_stage(
338
            'Page',
339
            'Live',
340
            sprintf('"SiteTree"."ID" = \'%d\'', $subsite1NewPage->ID)
341
        );
342
        $this->assertEquals('important-page', $subsite1NewPageLive->URLSegment);
343
344
        // Creating a new page in a subsite DOES conflict with urls in the same subsite
345
        $subsite1NewPage2 = new Page();
346
        $subsite1NewPage2->SubsiteID = $subsite1ID;
347
        $subsite1NewPage2->Title = 'Important Page (Subsite 1)';
348
        $subsite1NewPage2->URLSegment = 'important-page'; // Also exists in main subsite
349
        $subsite1NewPage2->write();
350
        $this->assertEquals('important-page-2', $subsite1NewPage2->URLSegment);
351
        $subsite1NewPage2->publishRecursive();
352
        $subsite1NewPage2Live = Versioned::get_one_by_stage(
353
            'Page',
354
            'Live',
355
            sprintf('"SiteTree"."ID" = \'%d\'', $subsite1NewPage2->ID)
356
        );
357
        $this->assertEquals('important-page-2', $subsite1NewPage2Live->URLSegment);
358
359
        // Original page is left un-modified
360
        $mainSubsiteImportantPageID = $this->idFromFixture('Page', 'importantpage');
361
        $mainSubsiteImportantPage = Page::get()->byID($mainSubsiteImportantPageID);
362
        $this->assertEquals('important-page', $mainSubsiteImportantPage->URLSegment);
363
        $mainSubsiteImportantPage->Content = '<p>New Important Page Content</p>';
364
        $mainSubsiteImportantPage->write();
365
        $this->assertEquals('important-page', $mainSubsiteImportantPage->URLSegment);
366
    }
367
368
    /**
369
     * @param bool $withChildren
370
     * @param int $expectedChildren
371
     * @dataProvider duplicateToSubsiteProvider
372
     */
373
    public function testDuplicateToSubsite($withChildren, $expectedChildren)
374
    {
375
        /** @var SiteTree $page */
376
        $page = $this->objFromFixture(Page::class, 'about');
377
        /** @var Subsite $newSubsite */
378
        $newSubsite = $this->objFromFixture(Subsite::class, 'subsite1');
379
380
        /** @var SiteTree $duplicatedPage */
381
        $duplicatedPage = $page->duplicateToSubsite($newSubsite->ID, $withChildren);
382
        $this->assertInstanceOf(SiteTree::class, $duplicatedPage, 'A new page is returned');
383
384
        $this->assertEquals($newSubsite->ID, $duplicatedPage->SubsiteID, 'Ensure returned records are on new subsite');
385
386
        $this->assertCount(1, $page->AllChildren());
387
        $this->assertCount(
388
            $expectedChildren,
389
            $duplicatedPage->AllChildren(),
390
            'Duplicated page also duplicates children'
391
        );
392
    }
393
394
    /**
395
     * @return array[]
396
     */
397
    public function duplicateToSubsiteProvider()
398
    {
399
        return [
400
            [true, 1],
401
            [false, 0],
402
        ];
403
    }
404
405
    public function testThemeResolverIsUsedForSettingThemeList()
406
    {
407
        $firstResolver = $this->createMock(ThemeResolver::class);
408
        $firstResolver->expects($this->never())->method('getThemeList');
409
        Injector::inst()->registerService($firstResolver, ThemeResolver::class);
410
411
        $subsitePage = $this->objFromFixture(Page::class, 'home');
412
        Subsite::changeSubsite($subsitePage->SubsiteID);
413
        $controller = ModelAsController::controller_for($subsitePage);
414
        SiteTree::singleton()->extend('contentcontrollerInit', $controller);
415
416
        $secondResolver = $this->createMock(ThemeResolver::class);
417
        $secondResolver->expects($this->once())->method('getThemeList');
418
        Injector::inst()->registerService($secondResolver, ThemeResolver::class);
419
420
        $subsitePage = $this->objFromFixture(Page::class, 'subsite1_home');
421
        Subsite::changeSubsite($subsitePage->SubsiteID);
422
        $controller = ModelAsController::controller_for($subsitePage);
423
        SiteTree::singleton()->extend('contentcontrollerInit', $controller);
424
    }
425
426
    public function provideAlternateAbsoluteLink()
427
    {
428
        return [
429
            ['home', null, 'http://localhost/'],
430
            ['home', 'myaction', 'http://localhost/home/myaction'],
431
            ['contact', null, 'http://localhost/contact-us/'],
432
            ['contact', 'myaction', 'http://localhost/contact-us/myaction'],
433
            ['subsite1_home', null, 'http://subsite1.localhost/'],
434
            ['subsite1_home', 'myaction', 'http://subsite1.localhost/home/myaction'],
435
            ['subsite1_contactus', null, 'http://subsite1.localhost/contact-us/'],
436
            ['subsite1_contactus', 'myaction', 'http://subsite1.localhost/contact-us/myaction']
437
        ];
438
    }
439
440
    /**
441
     * @dataProvider provideAlternateAbsoluteLink
442
     * @param string $pageFixtureName
443
     * @param string|null $action
444
     * @param string $expectedAbsoluteLink
445
     */
446
    public function testAlternateAbsoluteLink($pageFixtureName, $action, $expectedAbsoluteLink)
447
    {
448
        // Setting a control value, in case base url is set for the installation under test
449
        Config::modify()->set(Director::class, 'alternate_base_url', 'http://localhost/');
450
451
        /** @var Page $page */
452
        $page = $this->objFromFixture(Page::class, $pageFixtureName);
453
454
        $result = $page->AbsoluteLink($action);
455
456
        $this->assertEquals($expectedAbsoluteLink, $result);
457
    }
458
459
    public function testURLSegmentBaseIsSetToSubsiteBaseURL()
460
    {
461
        // This subsite has a domain with 'one.example.org' as the primary domain
462
        /** @var Subsite $subsite */
463
        $subsite = $this->objFromFixture(Subsite::class, 'domaintest1');
464
        Subsite::changeSubsite($subsite);
465
466
        $page = new SiteTree();
467
        $page->SubsiteID = $subsite->ID;
468
        $page->write();
469
        $fields = $page->getCMSFields();
470
471
        /** @var SiteTreeURLSegmentField $urlSegmentField */
472
        $urlSegmentField = $fields->dataFieldByName('URLSegment');
473
        $this->assertInstanceOf(SiteTreeURLSegmentField::class, $urlSegmentField);
474
475
        $this->assertSame('http://one.example.org/', $urlSegmentField->getURLPrefix());
476
    }
477
}
478