Completed
Push — master ( b0ffbf...043e1b )
by Daniel
02:39
created

tests/unit/TranslatableTest.php (7 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 7 and the first side effect is on line 1312.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * @todo Test Versioned getters
4
 * 
5
 * @package translatable
6
 */
7
class TranslatableTest extends FunctionalTest
8
{
9
    protected static $fixture_file = 'translatable/tests/unit/TranslatableTest.yml';
10
11
    protected $extraDataObjects = array(
12
        'TranslatableTest_DataObject',
13
        'TranslatableTest_OneByLocaleDataObject',
14
        'TranslatableTest_Page',
15
    );
16
    
17
    protected $requiredExtensions = array(
18
        'SiteTree' => array('Translatable', 'Versioned', 'EveryoneCanPublish'),
19
        'SiteConfig' => array('Translatable'),
20
        'TranslatableTest_DataObject' => array('Translatable'),
21
        'TranslatableTest_OneByLocaleDataObject' => array('Translatable'),
22
    );
23
    
24
    private $origLocale;
25
    
26
    protected $autoFollowRedirection = false;
27
28
    public function setUp()
29
    {
30
        parent::setUp();
31
        
32
        // whenever a translation is created, canTranslate() is checked
33
        $cmseditor = $this->objFromFixture('Member', 'cmseditor');
34
        $cmseditor->logIn();
35
        
36
        $this->origLocale = Translatable::default_locale();
37
        Translatable::set_default_locale("en_US");
38
    }
39
    
40
    public function tearDown()
41
    {
42
        Translatable::set_default_locale($this->origLocale);
43
        Translatable::set_current_locale($this->origLocale);
44
45
        parent::tearDown();
46
    }
47
48
    public function assertArrayEqualsAfterSort($expected, $actual, $message = null)
49
    {
50
        sort($expected);
51
        sort($actual);
52
        return $this->assertEquals($expected, $actual, $message);
53
    }
54
55
    public function testGetOneByLocale()
56
    {
57
        Translatable::disable_locale_filter();
58
        $this->assertEquals(
59
            0,
60
            TranslatableTest_OneByLocaleDataObject::get()->count(),
61
            'should not be any test objects yet'
62
        );
63
        Translatable::enable_locale_filter();
64
65
        $obj = new TranslatableTest_OneByLocaleDataObject();
66
        $obj->TranslatableProperty = 'test - en';
67
        $obj->write();
68
69
        Translatable::disable_locale_filter();
70
        $this->assertEquals(
71
            1,
72
            TranslatableTest_OneByLocaleDataObject::get()->count(),
73
            'should not be any test objects yet'
74
        );
75
        Translatable::enable_locale_filter();
76
77
        $found = Translatable::get_one_by_locale('TranslatableTest_OneByLocaleDataObject', $obj->Locale);
78
        $this->assertNotNull($found, 'should have found one for ' . $obj->Locale);
79
        $this->assertEquals($obj->ID, $found->ID);
80
81
        $translated = $obj->createTranslation('de_DE');
82
        $translated->write();
83
84
        Translatable::disable_locale_filter();
85
        $this->assertEquals(
86
            2,
87
            TranslatableTest_OneByLocaleDataObject::get()->count(),
88
            'should not be any test objects yet'
89
        );
90
        Translatable::enable_locale_filter();
91
92
        $found = Translatable::get_one_by_locale(
93
            'TranslatableTest_OneByLocaleDataObject',
94
            $translated->Locale
95
        );
96
        $this->assertNotNull($found, 'should have found one for ' . $translated->Locale);
97
        $this->assertEquals($translated->ID, $found->ID);
98
99
        // test again to make sure that get_one_by_locale works when locale filter disabled
100
        Translatable::disable_locale_filter();
101
        $found = Translatable::get_one_by_locale(
102
            'TranslatableTest_OneByLocaleDataObject',
103
            $translated->Locale
104
        );
105
        $this->assertEquals($translated->ID, $found->ID);
106
        Translatable::enable_locale_filter();
107
    }
108
109
    public function testLocaleFilteringEnabledAndDisabled()
110
    {
111
        $this->assertTrue(Translatable::locale_filter_enabled());
112
113
        // get our base page to use for testing
114
        $origPage = $this->objFromFixture('Page', 'testpage_en');
115
        $origPage->MenuTitle = 'unique-key-used-in-my-query';
116
        $origPage->write();
117
        $origPage->publish('Stage', 'Live');
118
119
        // create a translation of it so that we can see if translations are filtered
120
        $translatedPage = $origPage->createTranslation('de_DE');
121
        $translatedPage->MenuTitle = $origPage->MenuTitle;
122
        $translatedPage->write();
123
        $translatedPage->publish('Stage', 'Live');
124
125
        $where = sprintf("\"MenuTitle\" = '%s'", Convert::raw2sql($origPage->MenuTitle));
126
127
        // make sure that our query was filtered
128
        $this->assertEquals(1, Page::get()->where($where)->count());
129
130
        // test no filtering with disabled locale filter
131
        Translatable::disable_locale_filter();
132
        $this->assertEquals(2, Page::get()->where($where)->count());
133
        Translatable::enable_locale_filter();
134
135
        // make sure that our query was filtered after re-enabling the filter
136
        $this->assertEquals(1, Page::get()->where($where)->count());
137
138
        // test effectiveness of disabling locale filter with 3.x delayed querying
139
        // see https://github.com/silverstripe/silverstripe-translatable/issues/113
140
        Translatable::disable_locale_filter();
141
        // create the DataList while the locale filter is disabled
142
        $dataList = Page::get()->where($where);
143
        Translatable::enable_locale_filter();
144
        // but don't use it until later - after the filter is re-enabled
145
        $this->assertEquals(2, $dataList->count());
146
    }
147
    
148
    public function testLocaleGetParamRedirectsToTranslation()
149
    {
150
        $origPage = $this->objFromFixture('Page', 'testpage_en');
151
        $origPage->publish('Stage', 'Live');
152
        $translatedPage = $origPage->createTranslation('de_DE');
153
        $translatedPage->URLSegment = 'ueber-uns';
154
        $translatedPage->write();
155
        $translatedPage->publish('Stage', 'Live');
156
        
157
        // Need to log out, otherwise pages redirect to CMS views
158
        $this->session()->inst_set('loggedInAs', null);
159
        
160
        $response = $this->get($origPage->URLSegment);
161
        $this->assertEquals(200, $response->getStatusCode(), 'Page request without Locale GET param doesnt redirect');
162
        
163
        $response = $this->get(Controller::join_links($origPage->URLSegment, '?locale=de_DE'));
164
        $this->assertEquals(301, $response->getStatusCode(), 'Locale GET param causes redirect if it exists');
165
        $this->assertContains($translatedPage->URLSegment, $response->getHeader('Location'));
166
        
167
        $response = $this->get(Controller::join_links($origPage->URLSegment, '?locale=fr_FR'));
168
        $this->assertEquals(200, $response->getStatusCode(),
169
            'Locale GET param without existing translation shows original page'
170
        );
171
    }
172
    
173
    public function testTranslationGroups()
174
    {
175
        // first in french
176
        $frPage = new SiteTree();
177
        $frPage->Locale = 'fr_FR';
178
        $frPage->write();
179
        
180
        // second in english (from french "original")
181
        $enPage = $frPage->createTranslation('en_US');
182
        
183
        // third in spanish (from the english translation)
184
        $esPage = $enPage->createTranslation('es_ES');
185
        
186
        // test french
187
188
        $this->assertArrayEqualsAfterSort(
189
            array('en_US', 'es_ES'),
190
            $frPage->getTranslations()->column('Locale')
191
        );
192
        $this->assertNotNull($frPage->getTranslation('en_US'));
193
        $this->assertEquals(
194
            $frPage->getTranslation('en_US')->ID,
195
            $enPage->ID
196
        );
197
        $this->assertNotNull($frPage->getTranslation('es_ES'));
198
        $this->assertEquals(
199
            $frPage->getTranslation('es_ES')->ID,
200
            $esPage->ID
201
        );
202
        
203
        // test english
204
        $this->assertArrayEqualsAfterSort(
205
            array('es_ES', 'fr_FR'),
206
            $enPage->getTranslations()->column('Locale')
207
        );
208
        $this->assertNotNull($frPage->getTranslation('fr_FR'));
209
        $this->assertEquals(
210
            $enPage->getTranslation('fr_FR')->ID,
211
            $frPage->ID
212
        );
213
        $this->assertNotNull($frPage->getTranslation('es_ES'));
214
        $this->assertEquals(
215
            $enPage->getTranslation('es_ES')->ID,
216
            $esPage->ID
217
        );
218
        
219
        // test spanish
220
        $this->assertArrayEqualsAfterSort(
221
            array('en_US', 'fr_FR'),
222
            $esPage->getTranslations()->column('Locale')
223
        );
224
        $this->assertNotNull($esPage->getTranslation('fr_FR'));
225
        $this->assertEquals(
226
            $esPage->getTranslation('fr_FR')->ID,
227
            $frPage->ID
228
        );
229
        $this->assertNotNull($esPage->getTranslation('en_US'));
230
        $this->assertEquals(
231
            $esPage->getTranslation('en_US')->ID,
232
            $enPage->ID
233
        );
234
    }
235
236
    public function assertClass($class, $node)
237
    {
238
        $this->assertNotNull($node);
239
        $this->assertEquals($class, $node->ClassName);
240
        $this->assertEquals($class, get_class($node));
241
    }
242
243
    public function testChangingClassOfDefaultLocaleTranslationChangesOthers()
244
    {
245
        // see https://github.com/silverstripe/silverstripe-translatable/issues/97
246
        // create an English SiteTree
247
        $enST = new SiteTree();
248
        $enST->Locale = 'en_US';
249
        $enST->write();
250
251
        // create French and Spanish translations
252
        $frST = $enST->createTranslation('fr_FR');
253
        $esST = $enST->createTranslation('es_ES');
254
255
        // change the class name of the default locale's translation (as CMS admin would)
256
        $enST->setClassName('Page');
257
        $enST->write();
258
259
        // reload them all to get fresh instances
260
        $enPg = DataObject::get_by_id('Page', $enST->ID, $cache = false);
261
        $frPg = DataObject::get_by_id('Page', $frST->ID, $cache = false);
262
        $esPg = DataObject::get_by_id('Page', $esST->ID, $cache = false);
263
264
        // make sure they are all the right class
265
        $this->assertClass('Page', $enPg);
266
        $this->assertClass('Page', $frPg);
267
        $this->assertClass('Page', $esPg);
268
269
        // test that we get the right translations back from each instance
270
        $this->assertArrayEqualsAfterSort(
271
            array('fr_FR', 'es_ES'),
272
            $enPg->getTranslations()->column('Locale')
273
        );
274
        $this->assertArrayEqualsAfterSort(
275
            array('en_US', 'es_ES'),
276
            $frPg->getTranslations()->column('Locale')
277
        );
278
        $this->assertArrayEqualsAfterSort(
279
            array('en_US', 'fr_FR'),
280
            $esPg->getTranslations()->column('Locale')
281
        );
282
    }
283
284
    public function testChangingClassOfDefaultLocaleTranslationChangesOthersWhenPublished()
285
    {
286
        // create an English SiteTree
287
        $enST = new SiteTree();
288
        $enST->Locale = 'en_US';
289
        $enST->write();
290
        $enST->doPublish();
291
292
        // create and publish French and Spanish translations
293
        $frST = $enST->createTranslation('fr_FR');
294
        $this->assertTrue($frST->doPublish(), 'should have been able to publish French translation');
295
        $esST = $enST->createTranslation('es_ES');
296
        $this->assertTrue($esST->doPublish(), 'should have been able to publish Spanish translation');
297
298
        // change the class name of the default locale's translation (as CMS admin would)
299
        // and publish the change - we should see both versions of English change class
300
        $enST->setClassName('Page');
301
        $enST->doPublish();
302
        $this->assertClass('Page', Versioned::get_one_by_stage('SiteTree', 'Stage', '"ID" = ' . $enST->ID));
303
        $this->assertClass('Page', Versioned::get_one_by_stage('SiteTree', 'Live', '"ID" = ' . $enST->ID));
304
305
        // and all of the draft versions of translations:
306
        $this->assertClass('Page', Versioned::get_one_by_stage('SiteTree', 'Stage', '"ID" = ' . $frST->ID));
307
        $this->assertClass('Page', Versioned::get_one_by_stage('SiteTree', 'Stage', '"ID" = ' . $esST->ID));
308
309
        // and all of the live versions of translations as well:
310
        $this->assertClass('Page', Versioned::get_one_by_stage('SiteTree', 'Live', '"ID" = ' . $frST->ID));
311
        $this->assertClass('Page', Versioned::get_one_by_stage('SiteTree', 'Live', '"ID" = ' . $esST->ID));
312
    }
313
    
314
    public function testTranslationGroupsWhenTranslationIsSubclass()
315
    {
316
        // create an English SiteTree
317
        $enST = new SiteTree();
318
        $enST->Locale = 'en_US';
319
        $enST->write();
320
321
        // create French and Spanish translations
322
        $frST = $enST->createTranslation('fr_FR');
323
        $esST = $enST->createTranslation('es_ES');
324
325
        // test that we get the right translations back from each instance
326
        $this->assertArrayEqualsAfterSort(
327
            array('fr_FR', 'es_ES'),
328
            $enST->getTranslations()->column('Locale')
329
        );
330
        $this->assertArrayEqualsAfterSort(
331
            array('en_US', 'es_ES'),
332
            $frST->getTranslations()->column('Locale')
333
        );
334
        $this->assertArrayEqualsAfterSort(
335
            array('en_US', 'fr_FR'),
336
            $esST->getTranslations()->column('Locale')
337
        );
338
339
        // this should be considered an edge-case, but on some sites translations
340
        // may be allowed to be a subclass of the default locale's translation of
341
        // the same page.  In this case, we need to support getTranslations returning
342
        // all of the translations, even if one of the translations is a different
343
        // class from others
344
        $esST->setClassName('Page');
345
        $esST->write();
346
        $esPg = DataObject::get_by_id('Page', $esST->ID, $cache = false);
347
348
        // make sure we successfully changed the class
349
        $this->assertClass('Page', $esPg);
350
351
        // and make sure that the class of the others did not change
352
        $frST = DataObject::get_by_id('SiteTree', $frST->ID, $cache = false);
353
        $this->assertClass('SiteTree', $frST);
354
        $enST = DataObject::get_by_id('SiteTree', $enST->ID, $cache = false);
355
        $this->assertClass('SiteTree', $enST);
356
357
        // now that we know our edge case is successfully configured, we need to
358
        // make sure that we get the right translations back from everything
359
        $this->assertArrayEqualsAfterSort(
360
            array('fr_FR', 'es_ES'),
361
            $enST->getTranslations()->column('Locale')
362
        );
363
        $this->assertArrayEqualsAfterSort(
364
            array('en_US', 'es_ES'),
365
            $frST->getTranslations()->column('Locale')
366
        );
367
        $this->assertArrayEqualsAfterSort(
368
            array('en_US', 'fr_FR'),
369
            $esPg->getTranslations()->column('Locale')
370
        );
371
        $this->assertEquals($enST->ID, $esPg->getTranslation('en_US')->ID);
372
        $this->assertEquals($frST->ID, $esPg->getTranslation('fr_FR')->ID);
373
        $this->assertEquals($esPg->ID, $enST->getTranslation('es_ES')->ID);
374
        $this->assertEquals($esPg->ID, $frST->getTranslation('es_ES')->ID);
375
    }
376
377
    public function testTranslationGroupNotRemovedWhenSiteTreeUnpublished()
378
    {
379
        $enPage = new Page();
380
        $enPage->Locale = 'en_US';
381
        $enPage->write();
382
        $enPage->publish('Stage', 'Live');
383
        $enTranslationGroup = $enPage->getTranslationGroup();
384
        
385
        $frPage = $enPage->createTranslation('fr_FR');
386
        $frPage->write();
387
        $frPage->publish('Stage', 'Live');
388
        $frTranslationGroup = $frPage->getTranslationGroup();
389
        
390
        $enPage->doUnpublish();
391
        $this->assertEquals($enPage->getTranslationGroup(), $enTranslationGroup);
392
        
393
        $frPage->doUnpublish();
394
        $this->assertEquals($frPage->getTranslationGroup(), $frTranslationGroup);
395
    }
396
    
397
    public function testGetTranslationOnSiteTree()
398
    {
399
        $origPage = $this->objFromFixture('Page', 'testpage_en');
400
        
401
        $translatedPage = $origPage->createTranslation('fr_FR');
402
        $getTranslationPage = $origPage->getTranslation('fr_FR');
403
    
404
        $this->assertNotNull($getTranslationPage);
405
        $this->assertEquals($getTranslationPage->ID, $translatedPage->ID);
406
    }
407
    
408
    public function testGetTranslatedLanguages()
409
    {
410
        $origPage = $this->objFromFixture('Page', 'testpage_en');
411
        
412
        // through createTranslation()
413
        $translationAf = $origPage->createTranslation('af_ZA');
414
        
415
        // create a new language on an unrelated page which shouldnt be returned from $origPage
416
        $otherPage = new Page();
417
        $otherPage->write();
418
        $otherTranslationEs = $otherPage->createTranslation('es_ES');
419
        
420
        $this->assertEquals(
421
            $origPage->getTranslatedLangs(),
422
            array(
423
                'af_ZA',
424
                //'en_US', // default language is not included
425
            ),
426
            'Language codes are returned specifically for the queried page through getTranslatedLangs()'
427
        );
428
        
429
        $pageWithoutTranslations = new Page();
430
        $pageWithoutTranslations->write();
431
        $this->assertEquals(
432
            $pageWithoutTranslations->getTranslatedLangs(),
433
            array(),
434
            'A page without translations returns empty array through getTranslatedLangs(), ' .
435
            'even if translations for other pages exist in the database'
436
        );
437
        
438
        // manual creation of page without an original link
439
        $translationDeWithoutOriginal = new Page();
440
        $translationDeWithoutOriginal->Locale = 'de_DE';
441
        $translationDeWithoutOriginal->write();
442
        $this->assertEquals(
443
            $translationDeWithoutOriginal->getTranslatedLangs(),
444
            array(),
445
            'A translated page without an original doesn\'t return anything through getTranslatedLang()'
446
        );
447
    }
448
    
449
    public function testTranslationCantHaveSameURLSegmentAcrossLanguages()
450
    {
451
        $origPage = $this->objFromFixture('Page', 'testpage_en');
452
        $translatedPage = $origPage->createTranslation('de_DE');
453
        $this->assertEquals($translatedPage->URLSegment, 'testpage-de-de');
454
    
455
        $translatedPage->URLSegment = 'testpage'; // de_DE clashes with en_US
456
        $translatedPage->write();
457
        $this->assertNotEquals($origPage->URLSegment, $translatedPage->URLSegment);
458
459
        Translatable::set_current_locale('de_DE');
460
        Config::inst()->update('Translatable', 'enforce_global_unique_urls', false);
461
        $translatedPage->URLSegment = 'testpage'; // de_DE clashes with en_US
462
        $translatedPage->write();
463
        $this->assertEquals('testpage', $translatedPage->URLSegment);
464
        Config::inst()->update('Translatable', 'enforce_global_unique_urls', true);
465
        Translatable::set_current_locale('en_US');
466
    }
467
    
468
    public function testUpdateCMSFieldsOnSiteTree()
469
    {
470
        $pageOrigLang = new TranslatableTest_Page();
471
        $pageOrigLang->write();
472
        
473
        // first test with default language
474
        $fields = $pageOrigLang->getCMSFields();
475
        // title
476
        $this->assertInstanceOf(
477
            'TextField',
478
            $fields->dataFieldByName('Title'),
479
            'Translatable doesnt modify fields if called in default language (e.g. "non-translation mode")'
480
        );
481
        $this->assertNull(
482
            $fields->dataFieldByName('Title_original'),
483
            'Translatable doesnt modify fields if called in default language (e.g. "non-translation mode")'
484
        );
485
        // custom property
486
        $this->assertInstanceOf(
487
            'TextField',
488
            $fields->dataFieldByName('TranslatableProperty'),
489
            'Has custom field'
490
        );
491
        // custom has_one
492
        $this->assertInstanceOf(
493
            'DropdownField',
494
            $fields->dataFieldByName('TranslatableObjectID'),
495
            'Has custom dropdown field'
496
        );
497
        
498
        // then in "translation mode"
499
        $pageTranslated = $pageOrigLang->createTranslation('fr_FR');
500
        $fields = $pageTranslated->getCMSFields();
501
        // title
502
        $this->assertInstanceOf(
503
            'TextField',
504
            $fields->dataFieldByName('Title'),
505
            'Translatable leaves original formfield intact in "translation mode"'
506
        );
507
        $readonlyField = $fields->dataFieldByName('Title')->performReadonlyTransformation();
508
        $this->assertInstanceOf(
509
            $readonlyField->class,
510
            $fields->dataFieldByName('Title_original'),
511
            'Translatable adds the original value as a ReadonlyField in "translation mode"'
512
        );
513
        // custom property
514
        $this->assertInstanceOf(
515
            'ReadonlyField',
516
            $fields->dataFieldByName('TranslatableProperty_original'),
517
            'Adds original value for custom field as ReadonlyField'
518
        );
519
        $this->assertInstanceOf(
520
            'TextField',
521
            $fields->dataFieldByName('TranslatableProperty'),
522
            'Retains custom field as TextField'
523
        );
524
        // custom has_one
525
        $this->assertInstanceOf(
526
            'LookupField',
527
            $fields->dataFieldByName('TranslatableObjectID_original'),
528
            'Adds original value for custom dropdown field as LookupField (= readonly version of DropdownField)'
529
        );
530
        $this->assertInstanceOf(
531
            'DropdownField',
532
            $fields->dataFieldByName('TranslatableObjectID'),
533
            'Retains custom dropdown field as DropdownField'
534
        );
535
    }
536
    
537
    public function testDataObjectGetWithReadingLanguage()
538
    {
539
        $origTestPage = $this->objFromFixture('Page', 'testpage_en');
540
        $otherTestPage = $this->objFromFixture('Page', 'othertestpage_en');
541
        $translatedPage = $origTestPage->createTranslation('de_DE');
542
        
543
        // test in default language
544
        $resultPagesDefaultLang = DataObject::get(
545
            'Page',
546
            sprintf("\"SiteTree\".\"MenuTitle\" = '%s'", 'A Testpage')
547
        );
548
        $resultPagesDefaultLangIDs = $resultPagesDefaultLang->column('ID');
549
        foreach ($resultPagesDefaultLangIDs as $key => $val) {
550
            $resultPagesDefaultLangIDs[$key] = intval($val);
551
        }
552
        $this->assertEquals($resultPagesDefaultLang->Count(), 2);
553
        $this->assertContains((int)$origTestPage->ID, $resultPagesDefaultLangIDs);
554
        $this->assertContains((int)$otherTestPage->ID, $resultPagesDefaultLangIDs);
555
        $this->assertNotContains((int)$translatedPage->ID, $resultPagesDefaultLangIDs);
556
        
557
        // test in custom language
558
        Translatable::set_current_locale('de_DE');
559
        $resultPagesCustomLang = DataObject::get(
560
            'Page',
561
            sprintf("\"SiteTree\".\"MenuTitle\" = '%s'", 'A Testpage')
562
        );
563
        $resultPagesCustomLangIDs = $resultPagesCustomLang->column('ID');
564
        foreach ($resultPagesCustomLangIDs as $key => $val) {
565
            $resultPagesCustomLangIDs[$key] = intval($val);
566
        }
567
        $this->assertEquals($resultPagesCustomLang->Count(), 1);
568
        $this->assertNotContains((int)$origTestPage->ID, $resultPagesCustomLangIDs);
569
        $this->assertNotContains((int)$otherTestPage->ID, $resultPagesCustomLangIDs);
570
        $this->assertContains((int)$translatedPage->ID, $resultPagesCustomLangIDs);
571
        
572
        Translatable::set_current_locale('en_US');
573
    }
574
    
575
    public function testDataObjectGetByIdWithReadingLanguage()
576
    {
577
        $origPage = $this->objFromFixture('Page', 'testpage_en');
578
        $translatedPage = $origPage->createTranslation('de_DE');
579
        $compareOrigPage = DataObject::get_by_id('Page', $origPage->ID);
580
        
581
        $this->assertEquals(
582
            $origPage->ID,
583
            $compareOrigPage->ID,
584
            'DataObject::get_by_id() should work independently of the reading language'
585
        );
586
    }
587
    
588
    public function testDataObjectGetOneWithReadingLanguage()
589
    {
590
        $origPage = $this->objFromFixture('Page', 'testpage_en');
591
        $translatedPage = $origPage->createTranslation('de_DE');
592
        
593
        // running the same query twice with different 
594
        Translatable::set_current_locale('de_DE');
595
        $compareTranslatedPage = DataObject::get_one(
596
            'Page',
597
            sprintf("\"SiteTree\".\"Title\" = '%s'", $translatedPage->Title)
598
        );
599
        $this->assertNotNull($compareTranslatedPage);
600
        $this->assertEquals(
601
            $translatedPage->ID,
602
            $compareTranslatedPage->ID,
603
            "Translated page is found through get_one() when reading lang is not the default language"
604
        );
605
        
606
        // reset language to default
607
        Translatable::set_current_locale('en_US');
608
    }
609
    
610
    public function testModifyTranslationWithDefaultReadingLang()
611
    {
612
        $origPage = $this->objFromFixture('Page', 'testpage_en');
613
        $translatedPage = $origPage->createTranslation('de_DE');
614
        
615
        Translatable::set_current_locale('en_US');
616
        $translatedPage->Title = 'De Modified';
617
        $translatedPage->write();
618
        $savedTranslatedPage = $origPage->getTranslation('de_DE');
619
        $this->assertEquals(
620
            $savedTranslatedPage->Title,
621
            'De Modified',
622
            'Modifying a record in language which is not the reading language should still write the record correctly'
623
        );
624
        $this->assertEquals(
625
            $origPage->Title,
626
            'Home',
627
            'Modifying a record in language which is not the reading language does not modify the original record'
628
        );
629
    }
630
    
631
    public function testSiteTreePublication()
632
    {
633
        $origPage = $this->objFromFixture('Page', 'testpage_en');
634
        $translatedPage = $origPage->createTranslation('de_DE');
635
        
636
        Translatable::set_current_locale('en_US');
637
        $origPage->Title = 'En Modified';
638
        $origPage->write();
639
        // modifying a record in language which is not the reading language should still write the record correctly
640
        $translatedPage->Title = 'De Modified';
641
        $translatedPage->write();
642
        $origPage->publish('Stage', 'Live');
643
        $liveOrigPage = Versioned::get_one_by_stage('Page', 'Live', "\"SiteTree\".\"ID\" = {$origPage->ID}");
644
        $this->assertEquals(
645
            $liveOrigPage->Title,
646
            'En Modified',
647
            'Publishing a record in its original language publshes correct properties'
648
        );
649
    }
650
    
651
    public function testDeletingTranslationKeepsOriginal()
652
    {
653
        $origPage = $this->objFromFixture('Page', 'testpage_en');
654
        $translatedPage = $origPage->createTranslation('de_DE');
655
        $translatedPageID = $translatedPage->ID;
656
        $translatedPage->delete();
657
        
658
        $translatedPage->flushCache();
659
        $origPage->flushCache();
660
    
661
        $this->assertNull($origPage->getTranslation('de_DE'));
662
        $this->assertNotNull(DataObject::get_by_id('Page', $origPage->ID));
663
    }
664
    
665
    public function testHierarchyChildren()
666
    {
667
        $parentPage = $this->objFromFixture('Page', 'parent');
668
        $child1Page = $this->objFromFixture('Page', 'child1');
669
        $child2Page = $this->objFromFixture('Page', 'child2');
670
        $child3Page = $this->objFromFixture('Page', 'child3');
671
        $grandchildPage = $this->objFromFixture('Page', 'grandchild1');
672
        
673
        $parentPageTranslated = $parentPage->createTranslation('de_DE');
674
        $child4PageTranslated = new SiteTree();
675
        $child4PageTranslated->Locale = 'de_DE';
676
        $child4PageTranslated->ParentID = $parentPageTranslated->ID;
677
        $child4PageTranslated->write();
678
        
679
        Translatable::set_current_locale('en_US');
680
        $this->assertArrayEqualsAfterSort(
681
            array(
682
                $child1Page->ID,
683
                $child2Page->ID,
684
                $child3Page->ID
685
            ),
686
            $parentPage->Children()->column('ID'),
687
            "Showing Children() in default language doesnt show children in other languages"
688
        );
689
        
690
        Translatable::set_current_locale('de_DE');
691
        $parentPage->flushCache();
692
        $this->assertEquals(
693
            $parentPageTranslated->Children()->column('ID'),
694
            array($child4PageTranslated->ID),
695
            "Showing Children() in translation mode doesnt show children in default languages"
696
        );
697
        
698
        // reset language
699
        Translatable::set_current_locale('en_US');
700
    }
701
    
702
    public function testHierarchyLiveStageChildren()
703
    {
704
        $parentPage = $this->objFromFixture('Page', 'parent');
705
        $child1Page = $this->objFromFixture('Page', 'child1');
706
        $child1Page->publish('Stage', 'Live');
707
        $child2Page = $this->objFromFixture('Page', 'child2');
708
        $child3Page = $this->objFromFixture('Page', 'child3');
709
        $grandchildPage = $this->objFromFixture('Page', 'grandchild1');
710
        
711
        $parentPageTranslated = $parentPage->createTranslation('de_DE');
712
        
713
        $child4PageTranslated = new SiteTree();
714
        $child4PageTranslated->Locale = 'de_DE';
715
        $child4PageTranslated->ParentID = $parentPageTranslated->ID;
716
        $child4PageTranslated->write();
717
        $child4PageTranslated->publish('Stage', 'Live');
718
        
719
        $child5PageTranslated = new SiteTree();
720
        $child5PageTranslated->Locale = 'de_DE';
721
        $child5PageTranslated->ParentID = $parentPageTranslated->ID;
722
        $child5PageTranslated->write();
723
        
724
        Translatable::set_current_locale('en_US');
725
        $this->assertNotNull($parentPage->liveChildren());
726
        $this->assertEquals(
727
            $parentPage->liveChildren()->column('ID'),
728
            array(
729
                $child1Page->ID
730
            ),
731
            "Showing liveChildren() in default language doesnt show children in other languages"
732
        );
733
        $this->assertNotNull($parentPage->stageChildren());
734
        $this->assertArrayEqualsAfterSort(
735
            array(
736
                $child1Page->ID,
737
                $child2Page->ID,
738
                $child3Page->ID
739
            ),
740
            $parentPage->stageChildren()->column('ID'),
741
            "Showing stageChildren() in default language doesnt show children in other languages"
742
        );
743
        
744
        Translatable::set_current_locale('de_DE');
745
        $parentPage->flushCache();
746
        $this->assertNotNull($parentPageTranslated->liveChildren());
747
        $this->assertEquals(
748
            $parentPageTranslated->liveChildren()->column('ID'),
749
            array($child4PageTranslated->ID),
750
            "Showing liveChildren() in translation mode doesnt show children in default languages"
751
        );
752
        $this->assertNotNull($parentPageTranslated->stageChildren());
753
        $this->assertEquals(
754
            $parentPageTranslated->stageChildren()->column('ID'),
755
            array(
756
                $child4PageTranslated->ID,
757
                $child5PageTranslated->ID,
758
            ),
759
            "Showing stageChildren() in translation mode doesnt show children in default languages"
760
        );
761
        
762
        // reset language
763
        Translatable::set_current_locale('en_US');
764
    }
765
    
766
    public function testTranslatablePropertiesOnSiteTree()
767
    {
768
        $origObj = $this->objFromFixture('TranslatableTest_Page', 'testpage_en');
769
        
770
        $translatedObj = $origObj->createTranslation('fr_FR');
771
        $translatedObj->TranslatableProperty = 'fr_FR';
772
        $translatedObj->write();
773
        
774
        $this->assertEquals(
775
            $origObj->TranslatableProperty,
776
            'en_US',
777
            'Creating a translation doesnt affect database field on original object'
778
        );
779
        $this->assertEquals(
780
            $translatedObj->TranslatableProperty,
781
            'fr_FR',
782
            'Translated object saves database field independently of original object'
783
        );
784
    }
785
    
786 View Code Duplication
    public function testCreateTranslationOnSiteTree()
787
    {
788
        $origPage = $this->objFromFixture('Page', 'testpage_en');
789
        $translatedPage = $origPage->createTranslation('de_DE');
790
    
791
        $this->assertEquals($translatedPage->Locale, 'de_DE');
792
        $this->assertNotEquals($translatedPage->ID, $origPage->ID);
793
    
794
        $subsequentTranslatedPage = $origPage->createTranslation('de_DE');
795
        $this->assertEquals(
796
            $translatedPage->ID,
797
            $subsequentTranslatedPage->ID,
798
            'Subsequent calls to createTranslation() dont cause new records in database'
799
        );
800
    }
801
    
802
    public function testTranslatablePropertiesOnDataObject()
803
    {
804
        $origObj = $this->objFromFixture('TranslatableTest_DataObject', 'testobject_en');
805
        $translatedObj = $origObj->createTranslation('fr_FR');
806
        $translatedObj->TranslatableProperty = 'fr_FR';
807
        $translatedObj->TranslatableDecoratedProperty = 'fr_FR';
808
        $translatedObj->write();
809
        
810
        $this->assertEquals(
811
            $origObj->TranslatableProperty,
812
            'en_US',
813
            'Creating a translation doesnt affect database field on original object'
814
        );
815
        $this->assertEquals(
816
            $origObj->TranslatableDecoratedProperty,
817
            'en_US',
818
            'Creating a translation doesnt affect decorated database field on original object'
819
        );
820
        $this->assertEquals(
821
            $translatedObj->TranslatableProperty,
822
            'fr_FR',
823
            'Translated object saves database field independently of original object'
824
        );
825
        $this->assertEquals(
826
            $translatedObj->TranslatableDecoratedProperty,
827
            'fr_FR',
828
            'Translated object saves decorated database field independently of original object'
829
        );
830
    }
831
    
832
    public function testCreateTranslationWithoutOriginal()
833
    {
834
        $origParentPage = $this->objFromFixture('Page', 'testpage_en');
835
        $translatedParentPage = $origParentPage->createTranslation('de_DE');
836
    
837
        $translatedPageWithoutOriginal = new SiteTree();
838
        $translatedPageWithoutOriginal->ParentID = $translatedParentPage->ID;
839
        $translatedPageWithoutOriginal->Locale = 'de_DE';
840
        $translatedPageWithoutOriginal->write();
841
    
842
        Translatable::set_current_locale('de_DE');
843
        $this->assertEquals(
844
            $translatedParentPage->stageChildren()->column('ID'),
845
            array(
846
                $translatedPageWithoutOriginal->ID
847
            ),
848
            "Children() still works on a translated page even if no translation group is set"
849
        );
850
        
851
        Translatable::set_current_locale('en_US');
852
    }
853
    
854
    public function testCreateTranslationTranslatesUntranslatedParents()
855
    {
856
        $parentPage = $this->objFromFixture('Page', 'parent');
857
        $child1Page = $this->objFromFixture('Page', 'child1');
858
        $child1PageOrigID = $child1Page->ID;
859
        $grandChild1Page = $this->objFromFixture('Page', 'grandchild1');
860
        $grandChild2Page = $this->objFromFixture('Page', 'grandchild2');
861
    
862
        $this->assertFalse($grandChild1Page->hasTranslation('de_DE'));
863
        $this->assertFalse($child1Page->hasTranslation('de_DE'));
864
        $this->assertFalse($parentPage->hasTranslation('de_DE'));
865
    
866
        $translatedGrandChild1Page = $grandChild1Page->createTranslation('de_DE');
867
        $translatedGrandChild2Page = $grandChild2Page->createTranslation('de_DE');
868
        $translatedChildPage = $child1Page->getTranslation('de_DE');
869
        $translatedParentPage = $parentPage->getTranslation('de_DE');
870
    
871
        $this->assertTrue($grandChild1Page->hasTranslation('de_DE'));
872
        $this->assertEquals($translatedGrandChild1Page->ParentID, $translatedChildPage->ID);
873
    
874
        $this->assertTrue($grandChild2Page->hasTranslation('de_DE'));
875
        $this->assertEquals($translatedGrandChild2Page->ParentID, $translatedChildPage->ID);
876
    
877
        $this->assertTrue($child1Page->hasTranslation('de_DE'));
878
        $this->assertEquals($translatedChildPage->ParentID, $translatedParentPage->ID);
879
    
880
        $this->assertTrue($parentPage->hasTranslation('de_DE'));
881
    }
882
    
883
    public function testHierarchyAllChildrenIncludingDeleted()
884
    {
885
        // Original tree in 'en_US':
886
        //   parent
887
        //    child1 (Live only, deleted from stage)
888
        //    child2 (Stage only, never published)
889
        //    child3 (Stage only, never published, untranslated)
890
        // Translated tree in 'de_DE':
891
        //   parent
892
        //    child1 (Live only, deleted from stage)
893
        //    child2 (Stage only)
894
895
        // Create parent
896
        $parentPage = $this->objFromFixture('Page', 'parent');
897
        $parentPageID = $parentPage->ID;
898
        
899
        // Create parent translation
900
        $translatedParentPage = $parentPage->createTranslation('de_DE');
901
        $translatedParentPageID = $translatedParentPage->ID;
902
        
903
        // Create child1
904
        $child1Page = $this->objFromFixture('Page', 'child1');
905
        $child1PageID = $child1Page->ID;
906
        $child1Page->publish('Stage', 'Live');
907
        
908
        // Create child1 translation
909
        $child1PageTranslated = $child1Page->createTranslation('de_DE');
910
        $child1PageTranslatedID = $child1PageTranslated->ID;
911
        $child1PageTranslated->publish('Stage', 'Live');
912
        $child1PageTranslated->deleteFromStage('Stage'); // deleted from stage only, record still exists on live
913
        $child1Page->deleteFromStage('Stage'); // deleted from stage only, record still exists on live
914
915
        // Create child2
916
        $child2Page = $this->objFromFixture('Page', 'child2');
917
        $child2PageID = $child2Page->ID;
918
        
919
        // Create child2 translation
920
        $child2PageTranslated = $child2Page->createTranslation('de_DE');
921
        $child2PageTranslatedID = $child2PageTranslated->ID;
922
        
923
        // Create child3
924
        $child3Page = $this->objFromFixture('Page', 'child3');
925
        $child3PageID = $child3Page->ID;
926
        
927
        // on original parent in default language
928
        Translatable::set_current_locale('en_US');
929
        SiteTree::flush_and_destroy_cache();
930
        $parentPage = $this->objFromFixture('Page', 'parent');
931
        $children = $parentPage->AllChildrenIncludingDeleted();
932
        $this->assertArrayEqualsAfterSort(
933
            array(
934
                $child2PageID,
935
                $child3PageID,
936
                $child1PageID // $child1Page was deleted from stage, so the original record doesn't have the ID set
937
            ),
938
            $parentPage->AllChildrenIncludingDeleted()->column('ID'),
939
            "Showing AllChildrenIncludingDeleted() in default language doesnt show deleted children in other languages"
940
        );
941
    
942
        // on original parent in translation mode
943
        Translatable::set_current_locale('de_DE');
944
        SiteTree::flush_and_destroy_cache();
945
        $parentPage = $this->objFromFixture('Page', 'parent');
946
        $this->assertEquals(
947
            $translatedParentPage->AllChildrenIncludingDeleted()->column('ID'),
948
            array(
949
                $child2PageTranslatedID,
950
                // $child1PageTranslated was deleted from stage, so the original record doesn't have the ID set
951
                $child1PageTranslatedID
952
            ),
953
            "Showing AllChildrenIncludingDeleted() in translation mode with parent page in " .
954
            "translated language shows children in translated language"
955
        );
956
        
957
        Translatable::set_current_locale('de_DE');
958
        SiteTree::flush_and_destroy_cache();
959
        $parentPage = $this->objFromFixture('Page', 'parent');
960
        $this->assertEquals(
961
            $parentPage->AllChildrenIncludingDeleted()->column('ID'),
962
            array(),
963
            "Showing AllChildrenIncludingDeleted() in translation mode with parent page in " .
964
            "translated language shows children in default language"
965
        );
966
        
967
        // reset language
968
        Translatable::set_current_locale('en_US');
969
    }
970
    
971
    public function testRootUrlDefaultsToTranslatedLink()
972
    {
973
        $origPage = $this->objFromFixture('Page', 'homepage_en');
974
        $origPage->publish('Stage', 'Live');
975
        $translationDe = $origPage->createTranslation('de_DE');
976
        $translationDe->URLSegment = 'heim';
977
        $translationDe->write();
978
        $translationDe->publish('Stage', 'Live');
979
        
980
        // test with translatable
981
        Translatable::set_current_locale('de_DE');
982
        $this->assertEquals(
983
            RootURLController::get_homepage_link(),
984
            'heim',
985
            'Homepage with different URLSegment in non-default language is found'
986
        );
987
        
988
        // @todo Fix add/remove extension
989
        // test with translatable disabled
990
        // Object::remove_extension('Page', 'Translatable');
0 ignored issues
show
Unused Code Comprehensibility introduced by
64% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
991
        // 		$_SERVER['HTTP_HOST'] = '/';
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
992
        // 		$this->assertEquals(
993
        // 			RootURLController::get_homepage_urlsegment(), 
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
994
        // 			'home', 
995
        // 			'Homepage is showing in default language if ?lang GET variable is left out'
996
        // 		);
997
        // 		Object::add_extension('Page', 'Translatable');
0 ignored issues
show
Unused Code Comprehensibility introduced by
64% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
998
999
        // setting back to default
1000
        Translatable::set_current_locale('en_US');
1001
    }
1002
    
1003
    public function testSiteTreeChangePageTypeInMaster()
1004
    {
1005
        // create original
1006
        $origPage = new SiteTree();
1007
        $origPage->Locale = 'en_US';
1008
        $origPage->write();
1009
        $origPageID = $origPage->ID;
1010
        
1011
        // create translation
1012
        $translatedPage = $origPage->createTranslation('de_DE');
1013
        $translatedPageID = $translatedPage->ID;
1014
        
1015
        // change page type
1016
        $newPage = $origPage->newClassInstance('RedirectorPage');
1017
        $newPage->write();
1018
        
1019
        // re-fetch original page with new instance
1020
        $origPageChanged = DataObject::get_by_id('RedirectorPage', $origPageID);
1021
        $this->assertEquals($origPageChanged->ClassName, 'RedirectorPage',
1022
            'A ClassName change to an original page doesnt change original classname'
1023
        );
1024
        
1025
        // re-fetch the translation with new instance
1026
        Translatable::set_current_locale('de_DE');
1027
        $translatedPageChanged = DataObject::get_by_id('RedirectorPage', $translatedPageID);
1028
        $translatedPageChanged = $origPageChanged->getTranslation('de_DE');
1029
        $this->assertEquals($translatedPageChanged->ClassName, 'RedirectorPage',
1030
            'ClassName change on an original page also changes ClassName attribute of translation'
1031
        );
1032
    }
1033
    
1034
    public function testGetTranslationByStage()
1035
    {
1036
        $publishedPage = new SiteTree();
1037
        $publishedPage->Locale = 'en_US';
1038
        $publishedPage->Title = 'Published';
1039
        $publishedPage->write();
1040
        $publishedPage->publish('Stage', 'Live');
1041
        $publishedPage->Title = 'Unpublished';
1042
        $publishedPage->write();
1043
        
1044
        $publishedTranslatedPage = $publishedPage->createTranslation('de_DE');
1045
        $publishedTranslatedPage->Title = 'Publiziert';
1046
        $publishedTranslatedPage->write();
1047
        $publishedTranslatedPage->publish('Stage', 'Live');
1048
        $publishedTranslatedPage->Title = 'Unpubliziert';
1049
        $publishedTranslatedPage->write();
1050
        
1051
        $compareStage = $publishedPage->getTranslation('de_DE', 'Stage');
1052
        $this->assertNotNull($compareStage);
1053
        $this->assertEquals($compareStage->Title, 'Unpubliziert');
1054
        
1055
        $compareLive = $publishedPage->getTranslation('de_DE', 'Live');
1056
        $this->assertNotNull($compareLive);
1057
        $this->assertEquals($compareLive->Title, 'Publiziert');
1058
    }
1059
    
1060
    public function testCanTranslateAllowedLocales()
1061
    {
1062
        $origAllowedLocales = Translatable::get_allowed_locales();
1063
        
1064
        $cmseditor = $this->objFromFixture('Member', 'cmseditor');
1065
        
1066
        $testPage = $this->objFromFixture('Page', 'testpage_en');
1067
        $this->assertTrue(
1068
            $testPage->canTranslate($cmseditor, 'de_DE'),
1069
            "Users with canEdit() and TRANSLATE_ALL permission can create a new translation if locales are not limited"
1070
        );
1071
        
1072
        Translatable::set_allowed_locales(array('ja_JP'));
1073
        $this->assertTrue(
1074
            $testPage->canTranslate($cmseditor, 'ja_JP'),
1075
            "Users with canEdit() and TRANSLATE_ALL permission can create a new translation " .
1076
            "if locale is in Translatable::get_allowed_locales()"
1077
        );
1078
        $this->assertFalse(
1079
            $testPage->canTranslate($cmseditor, 'de_DE'),
1080
            "Users with canEdit() and TRANSLATE_ALL permission can't create a new translation if " .
1081
            "locale is not in Translatable::get_allowed_locales()"
1082
        );
1083
        
1084
        $this->assertInstanceOf(
1085
            'Page',
1086
            $testPage->createTranslation('ja_JP')
1087
        );
1088
        try {
1089
            $testPage->createTranslation('de_DE');
1090
            $this->setExpectedException("Exception");
1091
        } catch (Exception $e) {
1092
        }
1093
        
1094
        Translatable::set_allowed_locales($origAllowedLocales);
1095
    }
1096
    
1097
    public function testCanTranslatePermissionCodes()
1098
    {
1099
        $origAllowedLocales = Translatable::get_allowed_locales();
1100
        
1101
        Translatable::set_allowed_locales(array('ja_JP', 'de_DE'));
1102
        
1103
        $cmseditor = $this->objFromFixture('Member', 'cmseditor');
1104
        
1105
        $testPage = $this->objFromFixture('Page', 'testpage_en');
1106
        $this->assertTrue(
1107
            $testPage->canTranslate($cmseditor, 'de_DE'),
1108
            "Users with TRANSLATE_ALL permission can create a new translation"
1109
        );
1110
        
1111
        $translator = $this->objFromFixture('Member', 'germantranslator');
1112
        
1113
        $testPage = $this->objFromFixture('Page', 'testpage_en');
1114
        $this->assertTrue(
1115
            $testPage->canTranslate($translator, 'de_DE'),
1116
            "Users with TRANSLATE_<locale> permission can create a new translation"
1117
        );
1118
        
1119
        $this->assertFalse(
1120
            $testPage->canTranslate($translator, 'ja_JP'),
1121
            "Users without TRANSLATE_<locale> permission can create a new translation"
1122
        );
1123
        
1124
        Translatable::set_allowed_locales($origAllowedLocales);
1125
    }
1126
    
1127
    public function testLocalesForMember()
1128
    {
1129
        $origAllowedLocales = Translatable::get_allowed_locales();
1130
        Translatable::set_allowed_locales(array('de_DE', 'ja_JP'));
1131
        
1132
        $cmseditor = $this->objFromFixture('Member', 'cmseditor');
1133
        $translator = $this->objFromFixture('Member', 'germantranslator');
1134
        
1135
        $this->assertEquals(
1136
            array('de_DE', 'ja_JP'),
1137
            singleton('SiteTree')->getAllowedLocalesForMember($cmseditor),
1138
            'Members with TRANSLATE_ALL permission can edit all locales'
1139
        );
1140
        
1141
        $this->assertEquals(
1142
            array('de_DE'),
1143
            singleton('SiteTree')->getAllowedLocalesForMember($translator),
1144
            'Members with TRANSLATE_<locale> permission cant edit all locales'
1145
        );
1146
        
1147
        Translatable::set_allowed_locales($origAllowedLocales);
1148
    }
1149
    
1150
    public function testSavePageInCMS()
1151
    {
1152
        $adminUser = $this->objFromFixture('Member', 'admin');
1153
        $enPage = $this->objFromFixture('Page', 'testpage_en');
1154
        
1155
        $group = new Group();
1156
        $group->Title = 'Example Group';
1157
        $group->write();
1158
        
1159
        $frPage = $enPage->createTranslation('fr_FR');
1160
        $frPage->write();
1161
        
1162
        $adminUser->logIn();
1163
        
1164
        $cmsMain = new CMSPageEditController();
1165
        
1166
        $origLocale = Translatable::get_current_locale();
1167
        Translatable::set_current_locale('fr_FR');
1168
        
1169
        $form = $cmsMain->getEditForm($frPage->ID);
1170
        $form->loadDataFrom(array(
1171
            'Title' => 'Translated', // $db field
1172
        ));
1173
        $form->saveInto($frPage);
1174
        $frPage->write();
1175
    
1176
        $this->assertEquals('Translated', $frPage->Title);
1177
        
1178
        $adminUser->logOut();
1179
        Translatable::set_current_locale($origLocale);
1180
    }
1181
    
1182
    public function testAlternateGetByLink()
1183
    {
1184
        $parent     = $this->objFromFixture('Page', 'parent');
1185
        $child      = $this->objFromFixture('Page', 'child1');
1186
        $grandchild = $this->objFromFixture('Page', 'grandchild1');
1187
        
1188
        $parentTranslation = $parent->createTranslation('en_AU');
1189
        $parentTranslation->write();
1190
        
1191
        $childTranslation = $child->createTranslation('en_AU');
1192
        $childTranslation->write();
1193
        
1194
        $grandchildTranslation = $grandchild->createTranslation('en_AU');
1195
        $grandchildTranslation->write();
1196
        
1197
        Translatable::set_current_locale('en_AU');
1198
        
1199
        $this->assertEquals(
1200
            $parentTranslation->ID,
1201
            Sitetree::get_by_link($parentTranslation->Link())->ID,
1202
            'Top level pages can be found.'
1203
        );
1204
        
1205
        $this->assertEquals(
1206
            $childTranslation->ID,
1207
            SiteTree::get_by_link($childTranslation->Link())->ID,
1208
            'Child pages can be found.'
1209
        );
1210
        
1211
        $this->assertEquals(
1212
            $grandchildTranslation->ID,
1213
            SiteTree::get_by_link($grandchildTranslation->Link())->ID,
1214
            'Grandchild pages can be found.'
1215
        );
1216
    
1217
        // TODO Re-enable test after clarifying with ajshort (see r88503).
1218
        // Its unclear if this is valid behaviour, and/or necessary for translated nested URLs
1219
        // to work properly
1220
        // 
1221
        // $this->assertEquals (
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1222
        // 	$child->ID,
1223
        // 	SiteTree::get_by_link($parentTranslation->Link($child->URLSegment))->ID,
0 ignored issues
show
Unused Code Comprehensibility introduced by
65% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1224
        // 	'Links can be made up of multiple languages'
1225
        // );
1226
    }
1227
    
1228 View Code Duplication
    public function testSiteTreeGetByLinkFindsTranslationWithoutLocale()
1229
    {
1230
        $parent = $this->objFromFixture('Page', 'parent');
1231
        
1232
        $parentTranslation = $parent->createTranslation('en_AU');
1233
        $parentTranslation->URLSegment = 'parent-en-AU';
1234
        $parentTranslation->write();
1235
        
1236
        $match = Sitetree::get_by_link($parentTranslation->URLSegment);
1237
        $this->assertNotNull(
1238
            $match,
1239
            'SiteTree::get_by_link() doesnt need a locale setting to find translated pages'
1240
        );
1241
        $this->assertEquals(
1242
            $parentTranslation->ID,
1243
            $match->ID,
1244
            'SiteTree::get_by_link() doesnt need a locale setting to find translated pages'
1245
        );
1246
    }
1247
}
1248
1249
class TranslatableTest_OneByLocaleDataObject extends DataObject implements TestOnly
1250
{
1251
    private static $db = array(
1252
        'TranslatableProperty' => 'Text'
1253
    );
1254
}
1255
1256
class TranslatableTest_DataObject extends DataObject implements TestOnly
1257
{
1258
    // add_extension() used to add decorator at end of file
1259
1260
    private static $db = array(
1261
        'TranslatableProperty' => 'Text'
1262
    );
1263
}
1264
1265
class TranslatableTest_Extension extends DataExtension implements TestOnly
1266
{
1267
    private static $db = array(
1268
        'TranslatableDecoratedProperty' => 'Text'
1269
    );
1270
}
1271
1272
class TranslatableTest_Page extends Page implements TestOnly
1273
{
1274
    // static $extensions is inherited from SiteTree,
1275
    // we don't need to explicitly specify the fields
1276
1277
    private static $db = array(
1278
        'TranslatableProperty' => 'Text'
1279
    );
1280
1281
    private static $has_one = array(
1282
        'TranslatableObject' => 'TranslatableTest_DataObject'
1283
    );
1284
    
1285
    public function getCMSFields()
1286
    {
1287
        $fields = parent::getCMSFields();
1288
        $fields->addFieldToTab(
1289
            'Root.Main',
1290
            new TextField('TranslatableProperty')
1291
        );
1292
        $fields->addFieldToTab(
1293
            'Root.Main',
1294
            new DropdownField('TranslatableObjectID')
1295
        );
1296
        
1297
        $this->applyTranslatableFieldsUpdate($fields, 'updateCMSFields');
1298
1299
        return $fields;
1300
    }
1301
}
1302
1303
1304
class EveryoneCanPublish extends DataExtension
1305
{
1306
    public function canPublish($member = null)
1307
    {
1308
        return true;
1309
    }
1310
}
1311
1312
TranslatableTest_DataObject::add_extension('TranslatableTest_Extension');
1313