Passed
Push — master ( 7115d0...94e88b )
by Robbie
05:00
created

SubsiteTest   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 470
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 470
rs 10
c 0
b 0
f 0
wmc 22

14 Methods

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

339
        /** @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...
340
            ['Title' => 'Main site'],
341
            ['Title' => 'Template'],
342
            ['Title' => 'Subsite1 Template'],
343
            ['Title' => 'Subsite2 Template'],
344
            ['Title' => 'Test 1'],
345
            ['Title' => 'Test 2'],
346
            ['Title' => 'Test 3'],
347
            ['Title' => 'Test Non-SSL'],
348
            ['Title' => 'Test SSL'],
349
            ['Title' => 'Test Vagrant VM on port 8080']
350
        ], $subsites, 'Lists all subsites');
0 ignored issues
show
Unused Code introduced by
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

350
        $this->/** @scrutinizer ignore-call */ 
351
               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...
351
    }
352
353
    public function testAllAccessibleSites()
354
    {
355
        $member = $this->objFromFixture(Member::class, 'subsite1member');
356
357
        $subsites = Subsite::all_accessible_sites(true, 'Main site', $member);
358
        $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

358
        /** @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...
359
            ['Title' => 'Subsite1 Template']
360
        ], $subsites, 'Lists member-accessible sites.');
0 ignored issues
show
Unused Code introduced by
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

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