Completed
Push — master ( bf7dd9...e4fe53 )
by Robbie
04:30 queued 10s
created

SubsiteTest::domainProtocolProvider()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 19
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 17
nc 1
nop 0
dl 0
loc 19
rs 9.7
c 0
b 0
f 0
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('example.org:1123'),
197
            'Exact matches without strict checking when not using www prefix and ignores port'
198
        );
199
        $this->assertEquals(
200
            $subsite1->ID,
201
            Subsite::getSubsiteIDForDomain('www.example.org'),
202
            'Matches without strict checking when using www prefix, '
203
            .'still matching first domain regardless of www prefix  (falling back to subsite primary key ordering)'
204
        );
205
        $this->assertEquals(
206
            $subsite1->ID,
207
            Subsite::getSubsiteIDForDomain('www.example.org:9923'),
208
            'Matches without strict checking when using www prefix, '
209
            .'still matching first domain without prefix  (falling back to primary key ordering and ignoring port)'
210
        );
211
        $this->assertEquals(
212
            $subsite1->ID,
213
            Subsite::getSubsiteIDForDomain('www.example.com'),
214
            'Fuzzy matches without strict checking with www prefix'
215
        );
216
        $this->assertEquals(
217
            0,
218
            Subsite::getSubsiteIDForDomain('www.wildcard.com'),
219
            'Doesn\'t match www prefix without strict check, even if a wildcard subdomain is in place'
220
        );
221
222
        Config::modify()->set(Subsite::class, 'strict_subdomain_matching', true);
223
224
        $this->assertEquals(
225
            $subsite1->ID,
226
            Subsite::getSubsiteIDForDomain('example.org'),
227
            'Matches with strict checking when not using www prefix'
228
        );
229
        $this->assertEquals(
230
            $subsite1->ID,
231
            Subsite::getSubsiteIDForDomain('example.org:123'),
232
            'Matches with strict checking when not using www prefix and ignores port'
233
        );
234
        $this->assertEquals(
235
            $subsite2->ID, // not 1
236
            Subsite::getSubsiteIDForDomain('www.example.org'),
237
            'Matches with strict checking when using www prefix'
238
        );
239
        $this->assertEquals(
240
            0,
241
            Subsite::getSubsiteIDForDomain('www.example.com'),
242
            'Doesn\'t fuzzy match with strict checking when using www prefix'
243
        );
244
        $failed = false;
245
        try {
246
            Subsite::getSubsiteIDForDomain('www.wildcard.com');
247
        } catch (UnexpectedValueException $e) {
248
            $failed = true;
249
        }
250
        $this->assertTrue(
251
            $failed,
252
            'Fails on multiple matches with strict checking and wildcard vs. www'
253
        );
254
    }
255
256
    protected function createSubsiteWithDomains($domains)
257
    {
258
        $subsite = new Subsite([
259
            'Title' => 'My Subsite'
260
        ]);
261
        $subsite->write();
262
        foreach ($domains as $domainStr => $isPrimary) {
263
            $domain = new SubsiteDomain([
264
                'Domain' => $domainStr,
265
                'IsPrimary' => $isPrimary,
266
                'SubsiteID' => $subsite->ID
267
            ]);
268
            $domain->write();
269
        }
270
271
        return $subsite;
272
    }
273
274
    /**
275
     * Test the Subsite->domain() method
276
     */
277
    public function testDefaultDomain()
278
    {
279
        $this->assertEquals(
280
            'one.example.org',
281
            $this->objFromFixture(Subsite::class, 'domaintest1')->domain()
282
        );
283
284
        $this->assertEquals(
285
            'two.mysite.com',
286
            $this->objFromFixture(Subsite::class, 'domaintest2')->domain()
287
        );
288
289
        $_SERVER['HTTP_HOST'] = 'www.example.org';
290
        $this->assertEquals(
291
            'three.example.org',
292
            $this->objFromFixture(Subsite::class, 'domaintest3')->domain()
293
        );
294
295
        $_SERVER['HTTP_HOST'] = 'mysite.example.org';
296
        $this->assertEquals(
297
            'three.mysite.example.org',
298
            $this->objFromFixture(Subsite::class, 'domaintest3')->domain()
299
        );
300
301
        $this->assertEquals($_SERVER['HTTP_HOST'], singleton(Subsite::class)->PrimaryDomain);
302
        $this->assertEquals(
303
            'http://' . $_SERVER['HTTP_HOST'] . Director::baseURL(),
304
            singleton(Subsite::class)->absoluteBaseURL()
305
        );
306
    }
307
308
    /**
309
     * Tests that Subsite and SubsiteDomain both respect http protocol correctly
310
     *
311
     * @param string $class Fixture class name
312
     * @param string $identifier Fixture identifier
313
     * @param bool $currentIsSecure Whether the current base URL should be secure
314
     * @param string $expected The expected base URL for the subsite or subsite domain
315
     * @dataProvider domainProtocolProvider
316
     */
317
    public function testDomainProtocol($class, $identifier, $currentIsSecure, $expected)
318
    {
319
        /** @var Subsite|SubsiteDomain $model */
320
        $model = $this->objFromFixture($class, $identifier);
321
        $protocol = $currentIsSecure ? 'https' : 'http';
322
        Config::modify()->set(Director::class, 'alternate_base_url', $protocol . '://www.mysite.com');
323
        $this->assertSame($expected, $model->absoluteBaseURL());
324
    }
325
326
    public function domainProtocolProvider()
327
    {
328
        return [
329
            [Subsite::class, 'domaintest2', false, 'http://two.mysite.com/'],
330
            [SubsiteDomain::class, 'dt2a', false, 'http://two.mysite.com/'],
331
            [SubsiteDomain::class, 'dt2b', false, 'http://subsite.mysite.com/'],
332
            [Subsite::class, 'domaintest4', false, 'https://www.primary.com/'],
333
            [SubsiteDomain::class, 'dt4a', false, 'https://www.primary.com/'],
334
            [SubsiteDomain::class, 'dt4b', false, 'http://www.secondary.com/'],
335
            [Subsite::class, 'domaintest5', false, 'http://www.tertiary.com/'],
336
            [SubsiteDomain::class, 'dt5', false,  'http://www.tertiary.com/'],
337
            [Subsite::class, 'domaintest2', true, 'https://two.mysite.com/'],
338
            [SubsiteDomain::class, 'dt2a', true, 'https://two.mysite.com/'],
339
            [SubsiteDomain::class, 'dt2b', true, 'https://subsite.mysite.com/'],
340
            [Subsite::class, 'domaintest4', true, 'https://www.primary.com/'],
341
            [SubsiteDomain::class, 'dt4a', true, 'https://www.primary.com/'],
342
            [SubsiteDomain::class, 'dt4b', true, 'http://www.secondary.com/'],
343
            [Subsite::class, 'domaintest5', true, 'http://www.tertiary.com/'],
344
            [SubsiteDomain::class, 'dt5', true, 'http://www.tertiary.com/'],
345
        ];
346
    }
347
348
    public function testAllSites()
349
    {
350
        $subsites = Subsite::all_sites();
351
        $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

351
        /** @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...
352
            ['Title' => 'Main site'],
353
            ['Title' => 'Template'],
354
            ['Title' => 'Subsite1 Template'],
355
            ['Title' => 'Subsite2 Template'],
356
            ['Title' => 'Test 1'],
357
            ['Title' => 'Test 2'],
358
            ['Title' => 'Test 3'],
359
            ['Title' => 'Test Non-SSL'],
360
            ['Title' => 'Test SSL'],
361
            ['Title' => 'Test Vagrant VM on port 8080']
362
        ], $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

362
        $this->/** @scrutinizer ignore-call */ 
363
               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...
363
    }
364
365
    public function testAllAccessibleSites()
366
    {
367
        $member = $this->objFromFixture(Member::class, 'subsite1member');
368
369
        $subsites = Subsite::all_accessible_sites(true, 'Main site', $member);
370
        $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

370
        /** @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...
371
            ['Title' => 'Subsite1 Template']
372
        ], $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

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