Issues (144)

tests/php/SubsiteTest.php (7 issues)

1
<?php
2
3
namespace SilverStripe\Subsites\Tests;
4
5
use Page;
6
use SilverStripe\CMS\Model\SiteTree;
7
use SilverStripe\Control\Director;
8
use SilverStripe\Core\Config\Config;
9
use SilverStripe\ORM\DataObject;
10
use SilverStripe\Security\Member;
11
use SilverStripe\Subsites\Model\Subsite;
12
use SilverStripe\Subsites\Model\SubsiteDomain;
13
use SilverStripe\Subsites\State\SubsiteState;
14
use UnexpectedValueException;
15
16
class SubsiteTest extends BaseSubsiteTest
17
{
18
    protected static $fixture_file = 'SubsiteTest.yml';
19
20
    protected $usesTransactions = false;
21
22
    /**
23
     * Original value of $_REQUEST
24
     *
25
     * @var array
26
     */
27
    protected $origServer = [];
28
29
    protected function setUp()
30
    {
31
        parent::setUp();
32
33
        Config::modify()
34
            ->set(Director::class, 'alternate_base_url', '/')
35
            ->set(Subsite::class, 'strict_subdomain_matching', false)
36
            ->set(Subsite::class, 'write_hostmap', false);
37
38
        $this->origServer = $_SERVER;
39
    }
40
41
    protected function tearDown()
42
    {
43
        $_SERVER = $this->origServer;
44
45
        parent::tearDown();
46
    }
47
48
    /**
49
     * Create a new subsite from the template and verify that all the template's pages are copied
50
     */
51
    public function testSubsiteCreation()
52
    {
53
        // Create the instance
54
        $template = $this->objFromFixture(Subsite::class, 'main');
55
56
        // Test that changeSubsite is working
57
        Subsite::changeSubsite($template->ID);
58
        $this->assertEquals($template->ID, SubsiteState::singleton()->getSubsiteId());
59
        $tmplStaff = $this->objFromFixture('Page', 'staff');
0 ignored issues
show
The assignment to $tmplStaff is dead and can be removed.
Loading history...
60
        $tmplHome = DataObject::get_one('Page', "\"URLSegment\" = 'home'");
0 ignored issues
show
The assignment to $tmplHome is dead and can be removed.
Loading history...
61
62
        // Publish all the pages in the template, testing that DataObject::get only returns pages
63
        // from the chosen subsite
64
        $pages = DataObject::get(SiteTree::class);
65
        $totalPages = $pages->count();
0 ignored issues
show
The assignment to $totalPages is dead and can be removed.
Loading history...
66
        foreach ($pages as $page) {
67
            $this->assertEquals($template->ID, $page->SubsiteID);
68
            $page->copyVersionToStage('Stage', 'Live');
69
        }
70
71
        // Create a new site
72
        $subsite = $template->duplicate();
73
74
        // Check title
75
        $this->assertEquals($subsite->Title, $template->Title);
76
77
        // Another test that changeSubsite is working
78
        $subsite->activate();
79
80
        $siteHome = DataObject::get_one('Page', "\"URLSegment\" = 'home'");
81
        $this->assertNotEquals($siteHome, false, 'Home Page for subsite not found');
82
        $this->assertEquals(
83
            $subsite->ID,
84
            $siteHome->SubsiteID,
85
            'createInstance() copies existing pages retaining the same URLSegment'
86
        );
87
88
        Subsite::changeSubsite(0);
89
    }
90
91
    /**
92
     * Confirm that domain lookup is working
93
     */
94
    public function testDomainLookup()
95
    {
96
        // Clear existing fixtures
97
        foreach (DataObject::get(Subsite::class) as $subsite) {
98
            $subsite->delete();
99
        }
100
        foreach (DataObject::get(SubsiteDomain::class) as $domain) {
101
            $domain->delete();
102
        }
103
104
        // Much more expressive than YML in this case
105
        $subsite1 = $this->createSubsiteWithDomains([
106
            'one.example.org' => true,
107
            'one.*' => false,
108
        ]);
109
        $subsite2 = $this->createSubsiteWithDomains([
110
            'two.mysite.com' => true,
111
            '*.mysite.com' => false,
112
            'subdomain.onmultiplesubsites.com' => false,
113
        ]);
114
        $subsite3 = $this->createSubsiteWithDomains([
115
            'three.*' => true, // wildcards in primary domain are not recommended
116
            'subdomain.unique.com' => false,
117
            '*.onmultiplesubsites.com' => false,
118
        ]);
119
120
        $this->assertEquals(
121
            $subsite3->ID,
122
            Subsite::getSubsiteIDForDomain('subdomain.unique.com'),
123
            'Full unique match'
124
        );
125
126
        $this->assertEquals(
127
            $subsite1->ID,
128
            Subsite::getSubsiteIDForDomain('one.example.org'),
129
            'Full match, doesn\'t complain about multiple matches within a single subsite'
130
        );
131
132
        $failed = false;
133
        try {
134
            Subsite::getSubsiteIDForDomain('subdomain.onmultiplesubsites.com');
135
        } catch (UnexpectedValueException $e) {
136
            $failed = true;
137
        }
138
        $this->assertTrue(
139
            $failed,
140
            'Fails on multiple matches with wildcard vs. www across multiple subsites'
141
        );
142
143
        $this->assertEquals(
144
            $subsite1->ID,
145
            Subsite::getSubsiteIDForDomain('one.unique.com'),
146
            'Fuzzy match suffixed with wildcard (rule "one.*")'
147
        );
148
149
        $this->assertEquals(
150
            $subsite2->ID,
151
            Subsite::getSubsiteIDForDomain('two.mysite.com'),
152
            'Matches correct subsite for rule'
153
        );
154
155
        $this->assertEquals(
156
            $subsite2->ID,
157
            Subsite::getSubsiteIDForDomain('other.mysite.com'),
158
            'Fuzzy match prefixed with wildcard (rule "*.mysite.com")'
159
        );
160
161
        $this->assertEquals(
162
            0,
163
            Subsite::getSubsiteIDForDomain('unknown.madeup.com'),
164
            "Doesn't match unknown subsite"
165
        );
166
    }
167
168
    public function testStrictSubdomainMatching()
169
    {
170
        // Clear existing fixtures
171
        foreach (DataObject::get(Subsite::class) as $subsite) {
172
            $subsite->delete();
173
        }
174
        foreach (DataObject::get(SubsiteDomain::class) as $domain) {
175
            $domain->delete();
176
        }
177
178
        // Much more expressive than YML in this case
179
        $subsite1 = $this->createSubsiteWithDomains([
180
            'example.org' => true,
181
            'example.com' => false,
182
            '*.wildcard.com' => false,
183
        ]);
184
        $subsite2 = $this->createSubsiteWithDomains([
185
            'www.example.org' => true,
186
            'www.wildcard.com' => false,
187
        ]);
188
189
        Config::modify()->set(Subsite::class, 'strict_subdomain_matching', false);
190
191
        $this->assertEquals(
192
            $subsite1->ID,
193
            Subsite::getSubsiteIDForDomain('example.org'),
194
            'Exact matches without strict checking when not using www prefix'
195
        );
196
        $this->assertEquals(
197
            $subsite1->ID,
198
            Subsite::getSubsiteIDForDomain('example.org:1123'),
199
            'Exact matches without strict checking when not using www prefix and ignores port'
200
        );
201
        $this->assertEquals(
202
            $subsite1->ID,
203
            Subsite::getSubsiteIDForDomain('www.example.org'),
204
            'Matches without strict checking when using www prefix, '
205
            .'still matching first domain regardless of www prefix  (falling back to subsite primary key ordering)'
206
        );
207
        $this->assertEquals(
208
            $subsite1->ID,
209
            Subsite::getSubsiteIDForDomain('www.example.org:9923'),
210
            'Matches without strict checking when using www prefix, '
211
            .'still matching first domain without prefix  (falling back to primary key ordering and ignoring port)'
212
        );
213
        $this->assertEquals(
214
            $subsite1->ID,
215
            Subsite::getSubsiteIDForDomain('www.example.com'),
216
            'Fuzzy matches without strict checking with www prefix'
217
        );
218
        $this->assertEquals(
219
            0,
220
            Subsite::getSubsiteIDForDomain('www.wildcard.com'),
221
            'Doesn\'t match www prefix without strict check, even if a wildcard subdomain is in place'
222
        );
223
224
        Config::modify()->set(Subsite::class, 'strict_subdomain_matching', true);
225
226
        $this->assertEquals(
227
            $subsite1->ID,
228
            Subsite::getSubsiteIDForDomain('example.org'),
229
            'Matches with strict checking when not using www prefix'
230
        );
231
        $this->assertEquals(
232
            $subsite1->ID,
233
            Subsite::getSubsiteIDForDomain('example.org:123'),
234
            'Matches with strict checking when not using www prefix and ignores port'
235
        );
236
        $this->assertEquals(
237
            $subsite2->ID, // not 1
238
            Subsite::getSubsiteIDForDomain('www.example.org'),
239
            'Matches with strict checking when using www prefix'
240
        );
241
        $this->assertEquals(
242
            0,
243
            Subsite::getSubsiteIDForDomain('www.example.com'),
244
            'Doesn\'t fuzzy match with strict checking when using www prefix'
245
        );
246
        $failed = false;
247
        try {
248
            Subsite::getSubsiteIDForDomain('www.wildcard.com');
249
        } catch (UnexpectedValueException $e) {
250
            $failed = true;
251
        }
252
        $this->assertTrue(
253
            $failed,
254
            'Fails on multiple matches with strict checking and wildcard vs. www'
255
        );
256
    }
257
258
    protected function createSubsiteWithDomains($domains)
259
    {
260
        $subsite = new Subsite([
261
            'Title' => 'My Subsite'
262
        ]);
263
        $subsite->write();
264
        foreach ($domains as $domainStr => $isPrimary) {
265
            $domain = new SubsiteDomain([
266
                'Domain' => $domainStr,
267
                'IsPrimary' => $isPrimary,
268
                'SubsiteID' => $subsite->ID
269
            ]);
270
            $domain->write();
271
        }
272
273
        return $subsite;
274
    }
275
276
    /**
277
     * Test the Subsite->domain() method
278
     */
279
    public function testDefaultDomain()
280
    {
281
        $this->assertEquals(
282
            'one.example.org',
283
            $this->objFromFixture(Subsite::class, 'domaintest1')->domain()
284
        );
285
286
        $this->assertEquals(
287
            'two.mysite.com',
288
            $this->objFromFixture(Subsite::class, 'domaintest2')->domain()
289
        );
290
291
        $_SERVER['HTTP_HOST'] = 'www.example.org';
292
        $this->assertEquals(
293
            'three.example.org',
294
            $this->objFromFixture(Subsite::class, 'domaintest3')->domain()
295
        );
296
297
        $_SERVER['HTTP_HOST'] = 'mysite.example.org';
298
        $this->assertEquals(
299
            'three.mysite.example.org',
300
            $this->objFromFixture(Subsite::class, 'domaintest3')->domain()
301
        );
302
303
        $this->assertEquals($_SERVER['HTTP_HOST'], singleton(Subsite::class)->PrimaryDomain);
304
        $this->assertEquals(
305
            'http://' . $_SERVER['HTTP_HOST'] . Director::baseURL(),
306
            singleton(Subsite::class)->absoluteBaseURL()
307
        );
308
    }
309
310
    /**
311
     * Tests that Subsite and SubsiteDomain both respect http protocol correctly
312
     *
313
     * @param string $class Fixture class name
314
     * @param string $identifier Fixture identifier
315
     * @param bool $currentIsSecure Whether the current base URL should be secure
316
     * @param string $expected The expected base URL for the subsite or subsite domain
317
     * @dataProvider domainProtocolProvider
318
     */
319
    public function testDomainProtocol($class, $identifier, $currentIsSecure, $expected)
320
    {
321
        /** @var Subsite|SubsiteDomain $model */
322
        $model = $this->objFromFixture($class, $identifier);
323
        $protocol = $currentIsSecure ? 'https' : 'http';
324
        Config::modify()->set(Director::class, 'alternate_base_url', $protocol . '://www.mysite.com');
325
        $this->assertSame($expected, $model->absoluteBaseURL());
326
    }
327
328
    public function domainProtocolProvider()
329
    {
330
        return [
331
            [Subsite::class, 'domaintest2', false, 'http://two.mysite.com/'],
332
            [SubsiteDomain::class, 'dt2a', false, 'http://two.mysite.com/'],
333
            [SubsiteDomain::class, 'dt2b', false, 'http://subsite.mysite.com/'],
334
            [Subsite::class, 'domaintest4', false, 'https://www.primary.com/'],
335
            [SubsiteDomain::class, 'dt4a', false, 'https://www.primary.com/'],
336
            [SubsiteDomain::class, 'dt4b', false, 'http://www.secondary.com/'],
337
            [Subsite::class, 'domaintest5', false, 'http://www.tertiary.com/'],
338
            [SubsiteDomain::class, 'dt5', false,  'http://www.tertiary.com/'],
339
            [Subsite::class, 'domaintest2', true, 'https://two.mysite.com/'],
340
            [SubsiteDomain::class, 'dt2a', true, 'https://two.mysite.com/'],
341
            [SubsiteDomain::class, 'dt2b', true, 'https://subsite.mysite.com/'],
342
            [Subsite::class, 'domaintest4', true, 'https://www.primary.com/'],
343
            [SubsiteDomain::class, 'dt4a', true, 'https://www.primary.com/'],
344
            [SubsiteDomain::class, 'dt4b', true, 'http://www.secondary.com/'],
345
            [Subsite::class, 'domaintest5', true, 'http://www.tertiary.com/'],
346
            [SubsiteDomain::class, 'dt5', true, 'http://www.tertiary.com/'],
347
        ];
348
    }
349
350
    public function testAllSites()
351
    {
352
        $subsites = Subsite::all_sites();
353
        $this->assertDOSEquals([
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\Dev\SapphireTest::assertDOSEquals() has been deprecated: 4.0.0:5.0.0 Use assertListEquals() instead ( Ignorable by Annotation )

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

353
        /** @scrutinizer ignore-deprecated */ $this->assertDOSEquals([

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
354
            ['Title' => 'Main site'],
355
            ['Title' => 'Template'],
356
            ['Title' => 'Subsite1 Template'],
357
            ['Title' => 'Subsite2 Template'],
358
            ['Title' => 'Test 1'],
359
            ['Title' => 'Test 2'],
360
            ['Title' => 'Test 3'],
361
            ['Title' => 'Test Non-SSL'],
362
            ['Title' => 'Test SSL'],
363
            ['Title' => 'Test Vagrant VM on port 8080']
364
        ], $subsites, 'Lists all subsites');
0 ignored issues
show
The call to SilverStripe\Dev\SapphireTest::assertDOSEquals() has too many arguments starting with 'Lists all subsites'. ( Ignorable by Annotation )

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

364
        $this->/** @scrutinizer ignore-call */ 
365
               assertDOSEquals([

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
365
    }
366
367
    public function testAllAccessibleSites()
368
    {
369
        $member = $this->objFromFixture(Member::class, 'subsite1member');
370
371
        $subsites = Subsite::all_accessible_sites(true, 'Main site', $member);
372
        $this->assertDOSEquals([
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\Dev\SapphireTest::assertDOSEquals() has been deprecated: 4.0.0:5.0.0 Use assertListEquals() instead ( Ignorable by Annotation )

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

372
        /** @scrutinizer ignore-deprecated */ $this->assertDOSEquals([

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
373
            ['Title' => 'Subsite1 Template']
374
        ], $subsites, 'Lists member-accessible sites.');
0 ignored issues
show
The call to SilverStripe\Dev\SapphireTest::assertDOSEquals() has too many arguments starting with 'Lists member-accessible sites.'. ( Ignorable by Annotation )

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

374
        $this->/** @scrutinizer ignore-call */ 
375
               assertDOSEquals([

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
375
    }
376
377
    /**
378
     * Test Subsite::accessible_sites()
379
     */
380
    public function testAccessibleSites()
381
    {
382
        $member1Sites = Subsite::accessible_sites(
383
            'CMS_ACCESS_CMSMain',
384
            false,
385
            null,
386
            $this->objFromFixture(Member::class, 'subsite1member')
387
        );
388
        $member1SiteTitles = $member1Sites->column('Title');
389
        sort($member1SiteTitles);
390
        $this->assertEquals('Subsite1 Template', $member1SiteTitles[0], 'Member can get to a subsite via a group');
391
392
        $adminSites = Subsite::accessible_sites(
393
            'CMS_ACCESS_CMSMain',
394
            false,
395
            null,
396
            $this->objFromFixture(Member::class, 'admin')
397
        );
398
        $adminSiteTitles = $adminSites->column('Title');
399
        sort($adminSiteTitles);
400
        $this->assertEquals([
401
            'Subsite1 Template',
402
            'Subsite2 Template',
403
            'Template',
404
            'Test 1',
405
            'Test 2',
406
            'Test 3',
407
            'Test Non-SSL',
408
            'Test SSL',
409
            'Test Vagrant VM on port 8080'
410
        ], array_values($adminSiteTitles));
411
412
        $member2Sites = Subsite::accessible_sites(
413
            'CMS_ACCESS_CMSMain',
414
            false,
415
            null,
416
            $this->objFromFixture(Member::class, 'subsite1member2')
417
        );
418
        $member2SiteTitles = $member2Sites->column('Title');
419
        sort($member2SiteTitles);
420
        $this->assertEquals('Subsite1 Template', $member2SiteTitles[0], 'Member can get to subsite via a group role');
421
    }
422
423
    public function testhasMainSitePermission()
424
    {
425
        $admin = $this->objFromFixture(Member::class, 'admin');
426
        $subsite1member = $this->objFromFixture(Member::class, 'subsite1member');
427
        $subsite1admin = $this->objFromFixture(Member::class, 'subsite1admin');
428
        $allsubsitesauthor = $this->objFromFixture(Member::class, 'allsubsitesauthor');
429
430
        $this->assertTrue(
431
            Subsite::hasMainSitePermission($admin),
432
            'Default permissions granted for super-admin'
433
        );
434
        $this->assertTrue(
435
            Subsite::hasMainSitePermission($admin, ['ADMIN']),
436
            'ADMIN permissions granted for super-admin'
437
        );
438
        $this->assertFalse(
439
            Subsite::hasMainSitePermission($subsite1admin, ['ADMIN']),
440
            'ADMIN permissions (on main site) denied for subsite1 admin'
441
        );
442
        $this->assertFalse(
443
            Subsite::hasMainSitePermission($subsite1admin, ['CMS_ACCESS_CMSMain']),
444
            'CMS_ACCESS_CMSMain (on main site) denied for subsite1 admin'
445
        );
446
        $this->assertFalse(
447
            Subsite::hasMainSitePermission($allsubsitesauthor, ['ADMIN']),
448
            'ADMIN permissions (on main site) denied for CMS author with edit rights on all subsites'
449
        );
450
        $this->assertTrue(
451
            Subsite::hasMainSitePermission($allsubsitesauthor, ['CMS_ACCESS_CMSMain']),
452
            'CMS_ACCESS_CMSMain (on main site) granted for CMS author with edit rights on all subsites'
453
        );
454
        $this->assertFalse(
455
            Subsite::hasMainSitePermission($subsite1member, ['ADMIN']),
456
            'ADMIN (on main site) denied for subsite1 subsite1 cms author'
457
        );
458
        $this->assertFalse(
459
            Subsite::hasMainSitePermission($subsite1member, ['CMS_ACCESS_CMSMain']),
460
            'CMS_ACCESS_CMSMain (on main site) denied for subsite1 cms author'
461
        );
462
    }
463
464
    public function testDuplicateSubsite()
465
    {
466
        // get subsite1 & create page
467
        $subsite1 = $this->objFromFixture(Subsite::class, 'domaintest1');
468
        $subsite1->activate();
469
        $page1 = new Page();
470
        $page1->Title = 'MyAwesomePage';
471
        $page1->write();
472
        $page1->doPublish();
473
        $this->assertEquals($page1->SubsiteID, $subsite1->ID);
474
475
        // duplicate
476
        $subsite2 = $subsite1->duplicate();
477
        $subsite2->activate();
478
        // change content on dupe
479
        $page2 = DataObject::get_one('Page', "\"Title\" = 'MyAwesomePage'");
480
        $page2->Title = 'MyNewAwesomePage';
481
        $page2->write();
482
        $page2->doPublish();
483
484
        // check change & check change has not affected subiste1
485
        $subsite1->activate();
486
        $this->assertEquals('MyAwesomePage', DataObject::get_by_id('Page', $page1->ID)->Title);
487
        $subsite2->activate();
488
        $this->assertEquals('MyNewAwesomePage', DataObject::get_by_id('Page', $page2->ID)->Title);
489
    }
490
491
    public function testDefaultPageCreatedWhenCreatingSubsite()
492
    {
493
        $subsite = new Subsite();
494
        $subsite->Title = 'New Subsite';
495
        $subsite->write();
496
        $subsite->activate();
497
498
        $pages = SiteTree::get();
499
        $this->assertGreaterThanOrEqual(1, $pages->count());
500
    }
501
}
502