Issues (37)

php/Extension/FluentSiteTreeExtensionTest.php (6 issues)

1
<?php
2
3
namespace TractorCow\Fluent\Tests\Extension;
4
5
use Page;
0 ignored issues
show
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\Forms\SiteTreeURLSegmentField;
7
use SilverStripe\CMS\Model\SiteTree;
8
use SilverStripe\Control\Director;
9
use SilverStripe\Core\Config\Config;
10
use SilverStripe\Dev\Debug;
11
use SilverStripe\Dev\SapphireTest;
12
use SilverStripe\Forms\FieldList;
13
use SilverStripe\Forms\LiteralField;
14
use SilverStripe\ORM\ArrayList;
15
use SilverStripe\ORM\DataObject;
16
use SilverStripe\View\ArrayData;
17
use TractorCow\Fluent\Extension\FluentDirectorExtension;
18
use TractorCow\Fluent\Extension\FluentSiteTreeExtension;
19
use TractorCow\Fluent\Model\Domain;
20
use TractorCow\Fluent\Model\Locale;
21
use TractorCow\Fluent\State\FluentState;
22
23
class FluentSiteTreeExtensionTest extends SapphireTest
24
{
25
    protected static $fixture_file = 'FluentSiteTreeExtensionTest.yml';
26
27
    protected static $required_extensions = [
28
        SiteTree::class => [
29
            FluentSiteTreeExtension::class,
30
        ],
31
    ];
32
33
    protected function setUp()
34
    {
35
        parent::setUp();
36
        Config::modify()
37
            ->set(Director::class, 'alternate_base_url', 'http://mocked')
38
            ->set(FluentDirectorExtension::class, 'disable_default_prefix', false);
39
40
        // Clear cache
41
        Locale::clearCached();
42
        Domain::clearCached();
43
        FluentState::singleton()
44
            ->setLocale('de_DE')
45
            ->setIsDomainMode(false);
46
    }
47
48
    public function testGetLocaleInformation()
49
    {
50
        FluentState::singleton()->withState(function (FluentState $newState) {
51
            $newState
52
                ->setLocale('de_DE')
53
                ->setIsDomainMode(false);
54
55
            /** @var Page|FluentSiteTreeExtension $page */
56
            $page = $this->objFromFixture(Page::class, 'nz-page');
57
            $result = $page->LocaleInformation('en_NZ');
58
59
            $this->assertInstanceOf(ArrayData::class, $result);
60
            $this->assertEquals([
61
                'Locale' => 'en_NZ',
62
                'LocaleRFC1766' => 'en-NZ',
63
                'Title' => 'English (New Zealand)',
64
                'LanguageNative' => 'English',
65
                'Language' => 'en',
66
                'Link' => '/newzealand/a-page/',
67
                'AbsoluteLink' => 'http://mocked/newzealand/a-page/',
68
                'LinkingMode' => 'link',
69
                'URLSegment' => 'newzealand'
70
            ], $result->toMap());
71
        });
72
    }
73
74
    public function testGetLocales()
75
    {
76
        FluentState::singleton()->withState(function (FluentState $newState) {
77
            $newState
78
                ->setLocale('de_DE')
79
                ->setIsDomainMode(false);
80
81
            /** @var Page|FluentSiteTreeExtension $page */
82
            $page = $this->objFromFixture(Page::class, 'nz-page');
83
            $result = $page->Locales();
84
85
            $this->assertInstanceOf(ArrayList::class, $result);
86
            $this->assertCount(5, $result);
87
            $this->assertListEquals([
88
                ['Locale' => 'en_NZ'],
89
                ['Locale' => 'de_DE'],
90
                ['Locale' => 'en_US'],
91
                ['Locale' => 'es_ES'],
92
                ['Locale' => 'zh_CN'],
93
            ], $result);
94
        });
95
    }
96
97
    /**
98
     * Tests for url generation
99
     *
100
     * @return array list of tests with values:
101
     *  - domain (or false for non-domain mode)
102
     *  - locale
103
     *  - disable_default_prefix flag
104
     *  - page id
105
     *  - expected link
106
     */
107
    public function provideURLTests()
108
    {
109
        return [
110
            // Non-domain tests
111
            [null, 'de_DE', false, 'home', '/'],
112
            [null, 'de_DE', false, 'about', '/german/about-us/'],
113
            [null, 'de_DE', false, 'staff', '/german/about-us/my-staff/'],
114
            // Since de_DE is the only locale on the www.example.de domain, ensure that the locale
115
            // isn't unnecessarily added to the link.
116
            // In this case disable_default_prefix is ignored
117
            // See https://github.com/tractorcow/silverstripe-fluent/issues/75
118
            ['www.example.de', 'de_DE', false, 'home', '/'],
119
            ['www.example.de', 'de_DE', false, 'about', '/about-us/'],
120
            ['www.example.de', 'de_DE', false, 'staff', '/about-us/my-staff/'],
121
122
            // Test domains with multiple locales
123
            //  - es_ES non default locale
124
            ['www.example.com', 'es_ES', false, 'home', '/es_ES/'],
125
            ['www.example.com', 'es_ES', false, 'about', '/es_ES/about-us/'],
126
            ['www.example.com', 'es_ES', false, 'staff', '/es_ES/about-us/my-staff/'],
127
            //  - en_US default locale
128
            ['www.example.com', 'en_US', false, 'home', '/'],
129
            ['www.example.com', 'en_US', false, 'about', '/usa/about-us/'],
130
            ['www.example.com', 'en_US', false, 'staff', '/usa/about-us/my-staff/'],
131
            //  - en_US default locale, but with disable_default_prefix on
132
            ['www.example.com', 'en_US', true, 'home', '/'],
133
            ['www.example.com', 'en_US', true, 'about', '/about-us/'],
134
            ['www.example.com', 'en_US', true, 'staff', '/about-us/my-staff/'],
135
136
            // Test cross-domain links include the opposing domain
137
            // - to default locale
138
            ['www.example.de', 'en_US', true, 'home', 'http://www.example.com/'],
139
            ['www.example.de', 'en_US', true, 'staff', 'http://www.example.com/about-us/my-staff/'],
140
            // - to non defalut locale
141
            ['www.example.de', 'es_ES', true, 'home', 'http://www.example.com/es_ES/'],
142
            ['www.example.de', 'es_ES', true, 'staff', 'http://www.example.com/es_ES/about-us/my-staff/'],
143
        ];
144
    }
145
146
    /**
147
     * Test that URLS for pages are generated correctly
148
     *
149
     * @dataProvider provideURLTests
150
     * @param string $domain
151
     * @param string $locale
152
     * @param bool $prefixDisabled
153
     * @param string $pageName
154
     * @param string $url
155
     */
156
    public function testFluentURLs($domain, $locale, $prefixDisabled, $pageName, $url)
157
    {
158
        FluentState::singleton()->withState(
159
            function (FluentState $newState) use ($domain, $locale, $prefixDisabled, $pageName, $url) {
160
                $newState
161
                    ->setLocale($locale)
162
                    ->setDomain($domain)
163
                    ->setIsDomainMode(!empty($domain));
164
165
                // Set url generation option
166
                Config::modify()
167
                    ->set(FluentDirectorExtension::class, 'disable_default_prefix', $prefixDisabled);
168
169
                /** @var Page|FluentSiteTreeExtension $page */
170
                $page = $this->objFromFixture('Page', $pageName);
171
                $this->assertEquals($url, $page->Link());
0 ignored issues
show
The method Link() does not exist on TractorCow\Fluent\Extens...FluentSiteTreeExtension. ( Ignorable by Annotation )

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

171
                $this->assertEquals($url, $page->/** @scrutinizer ignore-call */ Link());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
172
            }
173
        );
174
    }
175
176
    public function testUpdateStatusFlagsFluentInivisible()
177
    {
178
        /** @var Page|FluentSiteTreeExtension $page */
179
        $page = $this->objFromFixture('Page', 'home');
180
        $flags = $page->getStatusFlags();
0 ignored issues
show
The method getStatusFlags() does not exist on TractorCow\Fluent\Extens...FluentSiteTreeExtension. ( Ignorable by Annotation )

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

180
        /** @scrutinizer ignore-call */ 
181
        $flags = $page->getStatusFlags();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
181
182
        $this->assertTrue(array_key_exists('fluentinvisible', $flags));
183
    }
184
185
    public function testStatusMessageNotVisibile()
186
    {
187
        /** @var Page|FluentSiteTreeExtension $page */
188
        $page = $this->objFromFixture('Page', 'home');
189
        $fields = new FieldList();
190
191
        $page->updateCMSFields($fields);
192
193
        /** @var LiteralField $statusMessage */
194
        $statusMessage = $fields->fieldByName('LocaleStatusMessage');
195
196
        $this->assertNotNull($fields->fieldByName('LocaleStatusMessage'));
197
        $this->assertContains('This page is not visible', $statusMessage->getContent());
198
    }
199
200
    public function testStatusMessageInherited()
201
    {
202
        /** @var Page|FluentSiteTreeExtension $page */
203
        $page = $this->objFromFixture('Page', 'home');
204
        $page->config()->update('frontend_publish_required', false);
0 ignored issues
show
The method config() does not exist on TractorCow\Fluent\Extens...FluentSiteTreeExtension. ( Ignorable by Annotation )

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

204
        $page->/** @scrutinizer ignore-call */ 
205
               config()->update('frontend_publish_required', false);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
205
        $fields = new FieldList();
206
207
        $page->updateCMSFields($fields);
208
209
        /** @var LiteralField $statusMessage */
210
        $statusMessage = $fields->fieldByName('LocaleStatusMessage');
211
212
        $this->assertNotNull($fields->fieldByName('LocaleStatusMessage'));
213
        $this->assertContains('Content for this page may be inherited', $statusMessage->getContent());
214
    }
215
216
    public function testStatusMessageDrafted()
217
    {
218
        FluentState::singleton()->withState(function (FluentState $newState) {
219
            $newState
220
                ->setLocale('en_NZ')
221
                ->setIsDomainMode(false);
222
223
            /** @var Page|FluentSiteTreeExtension $page */
224
            $page = $this->objFromFixture('Page', 'home');
225
            $page->config()->update('frontend_publish_required', false);
226
            $page->write();
0 ignored issues
show
The method write() does not exist on TractorCow\Fluent\Extens...FluentSiteTreeExtension. ( Ignorable by Annotation )

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

226
            $page->/** @scrutinizer ignore-call */ 
227
                   write();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
227
            $fields = new FieldList();
228
229
            $page->updateCMSFields($fields);
230
231
            /** @var LiteralField $statusMessage */
232
            $statusMessage = $fields->fieldByName('LocaleStatusMessage');
233
234
            $this->assertNotNull($fields->fieldByName('LocaleStatusMessage'));
235
            $this->assertContains('A draft has been created for this locale', $statusMessage->getContent());
236
        });
237
    }
238
239
    public function testUpdateCMSActionsInherited()
240
    {
241
        /** @var Page|FluentSiteTreeExtension $page */
242
        $page = $this->objFromFixture('Page', 'home');
243
        $actions = $page->getCMSActions();
0 ignored issues
show
The method getCMSActions() does not exist on TractorCow\Fluent\Extens...FluentSiteTreeExtension. ( Ignorable by Annotation )

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

243
        /** @scrutinizer ignore-call */ 
244
        $actions = $page->getCMSActions();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
244
245
        /** @var \SilverStripe\Forms\CompositeField $majorActions */
246
        $majorActions = $actions->fieldByName('MajorActions');
247
248
        $this->assertNotNull($majorActions);
249
250
        if ($majorActions === null) {
251
            return;
252
        }
253
254
        $actionSave = $majorActions->getChildren()->fieldByName('action_save');
255
        $actionPublish = $majorActions->getChildren()->fieldByName('action_publish');
256
257
        $this->assertNotNull($actionSave);
258
        $this->assertNotNull($actionPublish);
259
260
        if ($actionSave === null || $actionPublish === null) {
261
            return;
262
        }
263
264
        $this->assertEquals('Copy to draft', $actionSave->Title());
265
        $this->assertEquals('Copy & publish', $actionPublish->Title());
266
    }
267
268
    public function testUpdateCMSActionsDrafted()
269
    {
270
        /** @var Page|FluentSiteTreeExtension $page */
271
        $page = $this->objFromFixture('Page', 'about');
272
        $actions = $page->getCMSActions();
273
274
        /** @var \SilverStripe\Forms\CompositeField $majorActions */
275
        $majorActions = $actions->fieldByName('MajorActions');
276
277
        $this->assertNotNull($majorActions);
278
279
        if ($majorActions === null) {
280
            return;
281
        }
282
283
        $actionSave = $majorActions->getChildren()->fieldByName('action_save');
284
        $actionPublish = $majorActions->getChildren()->fieldByName('action_publish');
285
286
        $this->assertNotNull($actionSave);
287
        $this->assertNotNull($actionPublish);
288
289
        if ($actionSave === null || $actionPublish === null) {
290
            return;
291
        }
292
293
        $this->assertEquals('Saved', $actionSave->Title());
294
        // The default value changed between SS 4.0 and 4.1 - assert it contains Publish instead of exact matching
295
        $this->assertContains('publish', strtolower($actionPublish->Title()));
296
    }
297
298
    /**
299
     * @param string $localeCode
300
     * @param string $fixture
301
     * @param string $expected
302
     * @dataProvider localePrefixUrlProvider
303
     */
304
    public function testAddLocalePrefixToUrlSegment($localeCode, $fixture, $expected)
305
    {
306
        FluentState::singleton()->withState(
307
            function (FluentState $newState) use ($localeCode, $fixture, $expected) {
308
                $newState
309
                    ->setLocale($localeCode)
310
                    ->setIsDomainMode(true);
311
312
                /** @var FieldList $fields */
313
                $fields = $this->objFromFixture(Page::class, $fixture)->getCMSFields();
314
315
                /** @var SiteTreeURLSegmentField $segmentField */
316
                $segmentField = $fields->fieldByName('Root.Main.URLSegment');
317
                $this->assertInstanceOf(SiteTreeURLSegmentField::class, $segmentField);
318
319
                $this->assertSame($expected, $segmentField->getURLPrefix());
320
            }
321
        );
322
    }
323
324
    public function testHomeVisibleOnFrontendBothConfigFalse()
325
    {
326
        Config::modify()->set(DataObject::class, 'cms_publish_required', false);
327
        Config::modify()->set(DataObject::class, 'frontend_publish_required', false);
328
329
        FluentState::singleton()->withState(function (FluentState $newState) {
330
            $newState
331
                ->setLocale('de_DE')
332
                ->setIsDomainMode(false)
333
                ->setIsFrontend(true);
334
335
            $page = Page::get()->filter('URLSegment', 'home')->first();
336
337
338
            $this->assertNotNull($page);
339
        });
340
    }
341
342
    public function testHomeVisibleOnFrontendOneConfigFalse()
343
    {
344
        Config::modify()->set(DataObject::class, 'cms_publish_required', true);
345
        Config::modify()->set(DataObject::class, 'frontend_publish_required', false);
346
347
        FluentState::singleton()->withState(function (FluentState $newState) {
348
            $newState
349
                ->setLocale('de_DE')
350
                ->setIsDomainMode(false)
351
                ->setIsFrontend(true);
352
353
            $page = Page::get()->filter('URLSegment', 'home')->first();
354
355
            $this->assertNotNull($page);
356
        });
357
    }
358
359
    public function testHomeNotVisibleOnFrontendBothConfigTrue()
360
    {
361
        Config::modify()->set(DataObject::class, 'cms_publish_required', true);
362
        Config::modify()->set(DataObject::class, 'frontend_publish_required', true);
363
364
        FluentState::singleton()->withState(function (FluentState $newState) {
365
            $newState
366
                ->setLocale('de_DE')
367
                ->setIsDomainMode(false)
368
                ->setIsFrontend(true);
369
370
            $page = Page::get()->filter('URLSegment', 'home')->first();
371
372
            $this->assertNull($page);
373
        });
374
    }
375
376
    public function testHomeNotVisibleOnFrontendOneConfigTrue()
377
    {
378
        Config::modify()->set(DataObject::class, 'cms_publish_required', false);
379
        Config::modify()->set(DataObject::class, 'frontend_publish_required', true);
380
381
        FluentState::singleton()->withState(function (FluentState $newState) {
382
            $newState
383
                ->setLocale('de_DE')
384
                ->setIsDomainMode(false)
385
                ->setIsFrontend(true);
386
387
            $page = Page::get()->filter('URLSegment', 'home')->first();
388
389
            $this->assertNull($page);
390
        });
391
    }
392
393
    public function testHomeVisibleInCMSBothConfigFalse()
394
    {
395
        Config::modify()->set(DataObject::class, 'cms_publish_required', false);
396
        Config::modify()->set(DataObject::class, 'frontend_publish_required', false);
397
398
        FluentState::singleton()->withState(function (FluentState $newState) {
399
            $newState
400
                ->setLocale('de_DE')
401
                ->setIsDomainMode(false)
402
                ->setIsFrontend(false);
403
404
            $page = Page::get()->filter('URLSegment', 'home')->first();
405
406
            $this->assertNotNull($page);
407
        });
408
    }
409
410
    public function testHomeVisibleInCMSOneConfigFalse()
411
    {
412
        Config::modify()->set(DataObject::class, 'cms_publish_required', false);
413
        Config::modify()->set(DataObject::class, 'frontend_publish_required', true);
414
415
        FluentState::singleton()->withState(function (FluentState $newState) {
416
            $newState
417
                ->setLocale('de_DE')
418
                ->setIsDomainMode(false)
419
                ->setIsFrontend(false);
420
421
            $page = Page::get()->filter('URLSegment', 'home')->first();
422
423
            $this->assertNotNull($page);
424
        });
425
    }
426
427
    public function testHomeNotVisibleInCMSBothConfigTrue()
428
    {
429
        Config::modify()->set(DataObject::class, 'cms_publish_required', true);
430
        Config::modify()->set(DataObject::class, 'frontend_publish_required', true);
431
432
        FluentState::singleton()->withState(function (FluentState $newState) {
433
            $newState
434
                ->setLocale('de_DE')
435
                ->setIsDomainMode(false)
436
                ->setIsFrontend(false);
437
438
            $page = Page::get()->filter('URLSegment', 'home')->first();
439
440
            $this->assertNull($page);
441
        });
442
    }
443
444
    public function testHomeNotVisibleInCMSOneConfigTrue()
445
    {
446
        Config::modify()->set(DataObject::class, 'cms_publish_required', true);
447
        Config::modify()->set(DataObject::class, 'frontend_publish_required', false);
448
449
        FluentState::singleton()->withState(function (FluentState $newState) {
450
            $newState
451
                ->setLocale('de_DE')
452
                ->setIsDomainMode(false)
453
                ->setIsFrontend(false);
454
455
            $page = Page::get()->filter('URLSegment', 'home')->first();
456
457
            $this->assertNull($page);
458
        });
459
    }
460
461
    /**
462
     * @return array[]
463
     */
464
    public function localePrefixUrlProvider()
465
    {
466
        return [
467
            'locale_with_domain' => ['en_US', 'about', 'http://www.example.com/usa/'],
468
            'locale_without_domain' => ['zh_CN', 'about', 'http://mocked/zh_CN/'],
469
            'locale_alone_on_domain_nested' => ['de_DE', 'staff', 'http://www.example.de/about-us/'],
470
        ];
471
    }
472
}
473