Passed
Push — master ( 5b8a0d...bf7dd9 )
by Robbie
04:51
created

SiteTreeSubsitesTest::duplicateToSubsiteProvider()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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