Passed
Push — int-types ( 949579...4b2be5 )
by Sam
05:58
created

FieldListTest::testContainerField()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 7
nc 1
nop 0
dl 0
loc 12
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\Forms\Tests;
4
5
use SilverStripe\Dev\SapphireTest;
6
use SilverStripe\Forms\ConfirmedPasswordField;
7
use SilverStripe\Forms\FieldList;
8
use SilverStripe\Forms\FormField;
9
use SilverStripe\Forms\LiteralField;
10
use SilverStripe\Forms\Tab;
11
use SilverStripe\Forms\TextField;
12
use SilverStripe\Forms\EmailField;
13
use SilverStripe\Forms\FieldGroup;
14
use SilverStripe\Forms\TextareaField;
15
use SilverStripe\Forms\TabSet;
16
use SilverStripe\Forms\NumericField;
17
use SilverStripe\Forms\CompositeField;
18
use SilverStripe\Forms\FormAction;
19
use SilverStripe\Forms\HiddenField;
20
21
/**
22
 * Tests for FieldList
23
 *
24
 * @skipUpgrade
25
 * @todo        test for {@link FieldList->setValues()}. Need to check
26
 *  that the values that were set are the correct ones given back.
27
 * @todo        test for {@link FieldList->transform()} and {@link FieldList->makeReadonly()}.
28
 *  Need to ensure that it correctly transforms the FieldList object.
29
 * @todo        test for {@link FieldList->HiddenFields()}. Need to check
30
 *  the fields returned are the correct HiddenField objects for a
31
 *  given FieldList instance.
32
 * @todo        test for {@link FieldList->dataFields()}.
33
 * @todo        test for {@link FieldList->findOrMakeTab()}.
34
 * @todo        the same as above with insertBefore() and insertAfter()
35
 */
36
class FieldListTest extends SapphireTest
37
{
38
    public function testRecursiveWalk()
39
    {
40
        $fields = array(
41
            new TextField('Name'),
42
            new EmailField('Email'),
43
            new HiddenField('Hidden'),
44
            new LiteralField('Literal', 'Literal content'),
45
            new CompositeField(
46
                new TextField('Day'),
47
                new TextField('Month'),
48
                new TextField('Year')
49
            ),
50
        );
51
        $fieldList = new FieldList($fields);
52
53
        $count = 0;
54
55
        $fieldList->recursiveWalk(function (FormField $field) use (&$count) {
0 ignored issues
show
Unused Code introduced by
The parameter $field is not used and could be removed. ( Ignorable by Annotation )

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

55
        $fieldList->recursiveWalk(function (/** @scrutinizer ignore-unused */ FormField $field) use (&$count) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
56
            ++$count;
57
        });
58
59
        $this->assertEquals(8, $count);
60
    }
61
62
    public function testFlattenFields()
63
    {
64
        $fields = array(
65
            new TextField('Name'),
66
            new EmailField('Email'),
67
            new HiddenField('Hidden'),
68
            new LiteralField('Literal', 'Literal content'),
69
            $composite = new CompositeField(
70
                $day = new TextField('Day'),
71
                $month = new TextField('Month'),
72
                $year = new TextField('Year')
73
            ),
74
        );
75
        $fieldList = new FieldList($fields);
76
77
        array_pop($fields);
78
        array_push($fields, $composite, $day, $month, $year);
79
80
        $this->assertEquals($fields, $fieldList->flattenFields()->toArray());
81
    }
82
83
    public function testSaveableFields()
84
    {
85
        $fields = array(
86
            new TextField('Name'),
87
            new EmailField('Email'),
88
            new HiddenField('Hidden'),
89
            new LiteralField('Literal', 'Literal content'),
90
            new CompositeField(
91
                $day = new TextField('Day'),
92
                $month = new TextField('Month'),
93
                $year = new TextField('Year')
94
            ),
95
        );
96
        $fieldList = new FieldList($fields);
97
98
        array_pop($fields);
99
        array_pop($fields);
100
        array_push($fields, $day, $month, $year);
101
102
        $this->assertEquals($fields, array_values($fieldList->saveableFields()));
103
    }
104
105
    public function testFieldNames()
106
    {
107
        $fields = array(
108
            new TextField('Name'),
109
            new EmailField('Email'),
110
            new HiddenField('Hidden'),
111
            new LiteralField('Literal', 'Literal content'),
112
            new CompositeField(
113
                $day = new TextField('Day'),
114
                $month = new TextField('Month'),
115
                $year = new TextField('Year')
116
            ),
117
        );
118
        $fieldList = new FieldList($fields);
119
120
        $this->assertEquals(['Name', 'Email', 'Hidden', 'Day', 'Month', 'Year'], $fieldList->dataFieldNames());
121
    }
122
123
    /**
124
     * Test adding a field to a tab in a set.
125
     */
126
    public function testAddFieldToTab()
127
    {
128
        $fields = new FieldList();
129
        $tab = new Tab('Root');
130
        $fields->push($tab);
131
132
        /* We add field objects to the FieldList, using two different methods */
133
        $fields->addFieldToTab('Root', new TextField('Country'));
134
        $fields->addFieldsToTab(
135
            'Root',
136
            array(
137
            new EmailField('Email'),
138
            new TextField('Name'),
139
            )
140
        );
141
142
        /* Check that the field objects were created */
143
        $this->assertNotNull($fields->dataFieldByName('Country'));
144
        $this->assertNotNull($fields->dataFieldByName('Email'));
145
        $this->assertNotNull($fields->dataFieldByName('Name'));
146
147
        /* The field objects in the set should be the same as the ones we created */
148
        $this->assertSame($fields->dataFieldByName('Country'), $tab->fieldByName('Country'));
149
        $this->assertSame($fields->dataFieldByName('Email'), $tab->fieldByName('Email'));
150
        $this->assertSame($fields->dataFieldByName('Name'), $tab->fieldByName('Name'));
151
152
        /* We'll have 3 fields inside the tab */
153
        $this->assertEquals(3, $tab->Fields()->count());
154
    }
155
156
    /**
157
     * Test that groups can be added to a fieldlist
158
     */
159
    public function testFieldgroup()
160
    {
161
        $fields = new FieldList();
162
        $tab = new Tab('Root');
163
        $fields->push($tab);
164
165
        $fields->addFieldsToTab(
166
            'Root',
167
            array(
168
            $group1 = new FieldGroup(
169
                new TextField('Name'),
170
                new EmailField('Email')
171
            ),
172
            $group2 = new FieldGroup(
173
                new TextField('Company'),
174
                new TextareaField('Address')
175
            )
176
            )
177
        );
178
179
        /* Check that the field objects were created */
180
        $this->assertNotNull($fields->dataFieldByName('Name'));
181
        $this->assertNotNull($fields->dataFieldByName('Email'));
182
        $this->assertNotNull($fields->dataFieldByName('Company'));
183
        $this->assertNotNull($fields->dataFieldByName('Address'));
184
185
        /* The field objects in the set should be the same as the ones we created */
186
        $this->assertSame($fields->dataFieldByName('Name'), $group1->fieldByName('Name'));
187
        $this->assertSame($fields->dataFieldByName('Email'), $group1->fieldByName('Email'));
188
        $this->assertSame($fields->dataFieldByName('Company'), $group2->fieldByName('Company'));
189
        $this->assertSame($fields->dataFieldByName('Address'), $group2->fieldByName('Address'));
190
191
        /* We'll have 2 fields directly inside the tab */
192
        $this->assertEquals(2, $tab->Fields()->count());
193
    }
194
195
    /**
196
     * Test removing a single field from a tab in a set.
197
     */
198
    public function testRemoveSingleFieldFromTab()
199
    {
200
        $fields = new FieldList();
201
        $tab = new Tab('Root');
202
        $fields->push($tab);
203
204
        /* We add a field to the "Root" tab */
205
        $fields->addFieldToTab('Root', new TextField('Country'));
206
207
        /* We have 1 field inside the tab, which is the field we just created */
208
        $this->assertEquals(1, $tab->Fields()->count());
209
210
        /* We remove the field from the tab */
211
        $fields->removeFieldFromTab('Root', 'Country');
212
213
        /* We'll have no fields in the tab now */
214
        $this->assertEquals(0, $tab->Fields()->count());
215
    }
216
217
    public function testRemoveTab()
218
    {
219
        $fields = new FieldList(
220
            new TabSet(
221
                'Root',
222
                $tab1 = new Tab('Tab1'),
223
                $tab2 = new Tab('Tab2'),
224
                $tab3 = new Tab('Tab3')
225
            )
226
        );
227
228
        $fields->removeByName('Tab2');
229
        $this->assertNull($fields->fieldByName('Root')->fieldByName('Tab2'));
0 ignored issues
show
Bug introduced by
The method fieldByName() does not exist on SilverStripe\Forms\FormField. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

229
        $this->assertNull($fields->fieldByName('Root')->/** @scrutinizer ignore-call */ fieldByName('Tab2'));
Loading history...
230
231
        $this->assertEquals($tab1, $fields->fieldByName('Root')->fieldByName('Tab1'));
232
    }
233
234
    public function testHasTabSet()
235
    {
236
        $untabbedFields = new FieldList(
237
            new TextField('Field1')
238
        );
239
        $this->assertFalse($untabbedFields->hasTabSet());
240
241
        $tabbedFields = new FieldList(
242
            new TabSet(
243
                'Root',
244
                new Tab('Tab1')
245
            )
246
        );
247
        $this->assertTrue($tabbedFields->hasTabSet());
248
    }
249
250
    public function testFindTab()
251
    {
252
        $fields = new FieldList(
253
            $root = new TabSet(
254
                'Root',
255
                $tab1 = new Tab('Tab1'),
256
                $tab2 = new Tab('Tab2'),
257
                $tab3 = new Tab('Tab3'),
258
                $more = new TabSet(
259
                    'More',
260
                    $tab4 = new Tab('Tab4')
261
                )
262
            )
263
        );
264
265
        $this->assertEquals($fields->findTab('Root'), $root);
266
        $this->assertNull($fields->findTab('Tab5'));
267
268
        $this->assertNull($fields->findTab('Tab3'));
269
        $this->assertEquals($fields->findTab('Root.Tab3'), $tab3);
270
271
        $this->assertNull($fields->findTab('More'));
272
        $this->assertEquals($fields->findTab('Root.More'), $more);
273
        $this->assertEquals($fields->findTab('Root.More.Tab4'), $tab4);
274
    }
275
276
    /**
277
     * Test removing an array of fields from a tab in a set.
278
     */
279
    public function testRemoveMultipleFieldsFromTab()
280
    {
281
        $fields = new FieldList();
282
        $tab = new Tab('Root');
283
        $fields->push($tab);
284
285
        /* We add an array of fields, using addFieldsToTab() */
286
        $fields->addFieldsToTab(
287
            'Root',
288
            array(
289
            new TextField('Name', 'Your name'),
290
            new EmailField('Email', 'Email address'),
291
            new NumericField('Number', 'Insert a number')
292
            )
293
        );
294
295
        /* We have 3 fields inside the tab, which we just created */
296
        $this->assertEquals(3, $tab->Fields()->count());
297
298
        /* We remove the 3 fields from the tab */
299
        $fields->removeFieldsFromTab(
300
            'Root',
301
            array(
302
            'Name',
303
            'Email',
304
            'Number'
305
            )
306
        );
307
308
        /* We have no fields in the tab now */
309
        $this->assertEquals(0, $tab->Fields()->count());
310
    }
311
312
    public function testRemoveFieldByName()
313
    {
314
        $fields = new FieldList();
315
        $fields->push(new TextField('Name', 'Your name'));
316
317
        $this->assertEquals(1, $fields->count());
318
        $fields->removeByName('Name');
319
        $this->assertEquals(0, $fields->count());
320
321
        $fields->push(new TextField('Name[Field]', 'Your name'));
322
        $this->assertEquals(1, $fields->count());
323
        $fields->removeByName('Name[Field]');
324
        $this->assertEquals(0, $fields->count());
325
    }
326
327
    public function testDataFieldByName()
328
    {
329
        $fields = new FieldList();
330
        $fields->push($basic = new TextField('Name', 'Your name'));
331
        $fields->push($brack = new TextField('Name[Field]', 'Your name'));
332
333
        $this->assertEquals($basic, $fields->dataFieldByName('Name'));
334
        $this->assertEquals($brack, $fields->dataFieldByName('Name[Field]'));
335
    }
336
337
    /**
338
     * Test removing multiple fields from a set by their names in an array.
339
     */
340
    public function testRemoveFieldsByName()
341
    {
342
        $fields = new FieldList();
343
344
        /* First of all, we add some fields into our FieldList object */
345
        $fields->push(new TextField('Name', 'Your name'));
346
        $fields->push(new TextField('Email', 'Your email'));
347
348
        /* We have 2 fields in our set now */
349
        $this->assertEquals(2, $fields->count());
350
351
        /* Then, we call up removeByName() to take it out again */
352
        $fields->removeByName(array('Name', 'Email'));
353
354
        /* We have 0 fields in our set now, as we've just removed the one we added */
355
        $this->assertEquals(0, $fields->count());
356
    }
357
358
    /**
359
     * Test replacing a field with another one.
360
     */
361
    public function testReplaceField()
362
    {
363
        $fields = new FieldList();
364
        $tab = new Tab('Root');
365
        $fields->push($tab);
366
367
        /* A field gets added to the set */
368
        $fields->addFieldToTab('Root', new TextField('Country'));
369
370
        $this->assertSame($fields->dataFieldByName('Country'), $tab->fieldByName('Country'));
371
372
        $fields->replaceField('Country', new EmailField('Email'));
373
        $this->assertEquals(1, $tab->Fields()->count());
374
375
        $fields = new FieldList();
376
        $fields->push(new TextField('Name', 'Your name'));
377
        $brack = new TextField('Name[Field]', 'Your name');
378
379
        $fields->replaceField('Name', $brack);
380
        $this->assertEquals(1, $fields->count());
381
382
        $this->assertEquals('Name[Field]', $fields->first()->getName());
383
    }
384
385
    public function testRenameField()
386
    {
387
        $fields = new FieldList();
388
        $nameField = new TextField('Name', 'Before title');
389
        $fields->push($nameField);
390
391
        /* The title of the field object is the same as what we put in */
392
        $this->assertSame('Before title', $nameField->Title());
393
394
        /* The field gets renamed to a different title */
395
        $fields->renameField('Name', 'After title');
396
397
        /* The title of the field object is the title we renamed to, this
398
        includes the original object we created ($nameField), and getting
399
        the field back out of the set */
400
        $this->assertSame('After title', $nameField->Title());
401
        $this->assertSame('After title', $fields->dataFieldByName('Name')->Title());
402
    }
403
404
    public function testReplaceAFieldInADifferentTab()
405
    {
406
        /* A FieldList gets created with a TabSet and some field objects */
407
        $FieldList = new FieldList(
408
            new TabSet(
409
                'Root',
410
                $main = new Tab(
411
                    'Main',
412
                    new TextField('A'),
413
                    new TextField('B')
414
                ),
415
                $other = new Tab(
416
                    'Other',
417
                    new TextField('C'),
418
                    new TextField('D')
419
                )
420
            )
421
        );
422
423
        /* The field "A" gets added to the FieldList we just created created */
424
        $FieldList->addFieldToTab('Root.Other', $newA = new TextField('A', 'New Title'));
425
426
        /* The field named "A" has been removed from the Main tab to make way for our new field named "A" in
427
        * Other tab. */
428
        $this->assertEquals(1, $main->Fields()->count());
429
        $this->assertEquals(3, $other->Fields()->count());
430
    }
431
432
    /**
433
     * Test finding a field that's inside a tabset, within another tab.
434
     */
435
    public function testNestedTabsFindingFieldByName()
436
    {
437
        $fields = new FieldList();
438
439
        /* 2 tabs get created within a TabSet inside our set */
440
        $tab = new TabSet(
441
            'Root',
442
            new TabSet(
443
                'MyContent',
444
                $mainTab = new Tab('Main'),
445
                $otherTab = new Tab('Others')
446
            )
447
        );
448
        $fields->push($tab);
449
450
        /* Some fields get added to the 2 tabs we just created */
451
        $fields->addFieldToTab('Root.MyContent.Main', new TextField('Country'));
452
        $fields->addFieldToTab('Root.MyContent.Others', new TextField('Email'));
453
454
        /* The fields we just added actually exists in the set */
455
        $this->assertNotNull($fields->dataFieldByName('Country'));
456
        $this->assertNotNull($fields->dataFieldByName('Email'));
457
458
        /* The fields we just added actually exist in the tabs */
459
        $this->assertNotNull($mainTab->fieldByName('Country'));
460
        $this->assertNotNull($otherTab->fieldByName('Email'));
461
462
        /* We have 1 field for each of the tabs */
463
        $this->assertEquals(1, $mainTab->Fields()->count());
464
        $this->assertEquals(1, $otherTab->Fields()->count());
465
466
        $this->assertNotNull($fields->fieldByName('Root.MyContent'));
467
        $this->assertNotNull($fields->fieldByName('Root.MyContent'));
468
    }
469
470
    public function testTabTitles()
471
    {
472
        $set = new FieldList(
473
            $rootTabSet = new TabSet(
474
                'Root',
475
                $tabSetWithoutTitle = new TabSet('TabSetWithoutTitle'),
476
                $tabSetWithTitle = new TabSet(
477
                    'TabSetWithTitle',
478
                    'My TabSet Title',
479
                    new Tab('ExistingChildTab')
480
                )
481
            )
482
        );
483
484
        $this->assertEquals(
485
            $tabSetWithTitle->Title(),
486
            'My TabSet Title',
487
            'Automatic conversion of tab identifiers through findOrMakeTab() with FormField::name_to_label()'
488
        );
489
490
        $tabWithoutTitle = $set->findOrMakeTab('Root.TabWithoutTitle');
491
        $this->assertEquals(
492
            $tabWithoutTitle->Title(),
493
            'Tab Without Title',
494
            'Automatic conversion of tab identifiers through findOrMakeTab() with FormField::name_to_label()'
495
        );
496
497
        $tabWithTitle = $set->findOrMakeTab('Root.TabWithTitle', 'My Tab with Title');
498
        $this->assertEquals(
499
            $tabWithTitle->Title(),
500
            'My Tab with Title',
501
            'Setting of simple tab titles through findOrMakeTab()'
502
        );
503
504
        $childTabWithTitle = $set->findOrMakeTab('Root.TabSetWithoutTitle.NewChildTab', 'My Child Tab Title');
505
        $this->assertEquals(
506
            $childTabWithTitle->Title(),
507
            'My Child Tab Title',
508
            'Setting of nested tab titles through findOrMakeTab() works on last child tab'
509
        );
510
    }
511
512
    /**
513
     * Test pushing a field to a set.
514
     *
515
     * This tests {@link FieldList->push()}.
516
     */
517
    public function testPushFieldToSet()
518
    {
519
        $fields = new FieldList();
520
521
        /* A field named Country is added to the set */
522
        $fields->push(new TextField('Country'));
523
524
        /* We only have 1 field in the set */
525
        $this->assertEquals(1, $fields->count());
526
527
        /* Another field called Email is added to the set */
528
        $fields->push(new EmailField('Email'));
529
530
        /* There are now 2 fields in the set */
531
        $this->assertEquals(2, $fields->count());
532
533
        // Test that pushing a composite field without a name onto the set works
534
        // See ticket #2932
535
        $fields->push(
536
            new CompositeField(
537
                new TextField('Test1'),
538
                new TextField('Test2')
539
            )
540
        );
541
        $this->assertEquals(3, $fields->count());
542
    }
543
544
    /**
545
     * Test pushing a field to the beginning of a set.
546
     *
547
     * This tests {@link FieldList->unshift()}.
548
     */
549
    public function testPushFieldToBeginningOfSet()
550
    {
551
        $fields = new FieldList();
552
553
        /* A field named Country is added to the set */
554
        $fields->unshift(new TextField('Country'));
555
556
        /* We only have 1 field in the set */
557
        $this->assertEquals(1, $fields->count());
558
559
        /* Another field called Email is added to the set */
560
        $fields->unshift(new EmailField('Email'));
561
562
        /* There are now 2 fields in the set */
563
        $this->assertEquals(2, $fields->count());
564
565
        /* The most recently added field is at the beginning of the set */
566
        $this->assertEquals('Email', $fields->first()->getName());
567
568
        // Test that pushing a composite field without a name onto the set works
569
        $fields->unshift(
570
            new CompositeField(
571
                new TextField('Test1'),
572
                new TextField('Test2')
573
            )
574
        );
575
        $this->assertEquals(3, $fields->count());
576
    }
577
578
    /**
579
     * Test inserting a field before another in a set.
580
     *
581
     * This tests {@link FieldList->insertBefore()}.
582
     */
583
    public function testInsertBeforeFieldToSet()
584
    {
585
        $fields = new FieldList();
586
587
        /* 3 fields are added to the set */
588
        $fields->push(new TextField('Country'));
589
        $fields->push(new TextField('Email'));
590
        $fields->push(new TextField('FirstName'));
591
592
        /* We now have 3 fields in the set */
593
        $this->assertEquals(3, $fields->count());
594
595
        /* We insert another field called Title before the FirstName field */
596
        $fields->insertBefore('FirstName', new TextField('Title'));
597
598
        /* The field we just added actually exists in the set */
599
        $this->assertNotNull($fields->dataFieldByName('Title'));
600
601
        /* We now have 4 fields in the set */
602
        $this->assertEquals(4, $fields->count());
603
604
        /* The position of the Title field is at number 3 */
605
        $this->assertEquals('Title', $fields[2]->getName());
0 ignored issues
show
Bug introduced by
The method getName() does not exist on SilverStripe\ORM\DataObject. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

605
        $this->assertEquals('Title', $fields[2]->/** @scrutinizer ignore-call */ getName());
Loading history...
606
607
        /* Test arguments are accepted in either order */
608
        $fields->insertBefore('FirstName', new TextField('Surname'));
609
610
        /* The field we just added actually exists in the set */
611
        $this->assertNotNull($fields->dataFieldByName('Surname'));
612
613
        /* We now have 5 fields in the set */
614
        $this->assertEquals(5, $fields->count());
615
616
        /* The position of the Surname field is at number 4 */
617
        $this->assertEquals('Surname', $fields[3]->getName());
618
619
        /* Test that inserting before a field that doesn't exist simply appends
620
         * Confirm that a composite field doesn't break this */
621
        $fields->push(new CompositeField([ new TextField('Nested1'), new TextField('Nested2')]));
622
        $this->assertTrue((bool)$fields->insertBefore('DoesNotExist', new TextField('MyName')));
623
        $this->assertEquals('MyName', $fields->Last()->Name);
624
    }
625
626
    public function testInsertBeforeMultipleFields()
627
    {
628
        $fields = new FieldList(
629
            $root = new TabSet(
630
                "Root",
631
                $main = new Tab(
632
                    "Main",
633
                    $a = new TextField("A"),
634
                    $b = new TextField("B")
635
                )
636
            )
637
        );
638
639
        $fields->addFieldsToTab(
640
            'Root.Main',
641
            array(
642
            new TextField('NewField1'),
643
            new TextField('NewField2')
644
            ),
645
            'B'
646
        );
647
648
        $this->assertEquals(
649
            array_keys($fields->dataFields()),
650
            array(
651
            'A',
652
            'NewField1',
653
            'NewField2',
654
            'B'
655
            )
656
        );
657
    }
658
659
    /**
660
     * Test inserting a field after another in a set.
661
     */
662
    public function testInsertAfterFieldToSet()
663
    {
664
        $fields = new FieldList();
665
666
        /* 3 fields are added to the set */
667
        $fields->push(new TextField('Country'));
668
        $fields->push(new TextField('Email'));
669
        $fields->push(new TextField('FirstName'));
670
671
        /* We now have 3 fields in the set */
672
        $this->assertEquals(3, $fields->count());
673
674
        /* A field called Title is inserted after the Country field */
675
        $fields->insertAfter('Country', new TextField('Title'));
676
677
        /* The field we just added actually exists in the set */
678
        $this->assertNotNull($fields->dataFieldByName('Title'));
679
680
        /* We now have 4 fields in the FieldList */
681
        $this->assertEquals(4, $fields->count());
682
683
        /* The position of the Title field should be at number 2 */
684
        $this->assertEquals('Title', $fields[1]->getName());
685
686
        /* Test arguments are accepted in either order */
687
        $fields->insertAfter('FirstName', new TextField('Surname'));
688
689
        /* The field we just added actually exists in the set */
690
        $this->assertNotNull($fields->dataFieldByName('Surname'));
691
692
        /* We now have 5 fields in the set */
693
        $this->assertEquals(5, $fields->count());
694
695
        /* The position of the Surname field is at number 5 */
696
        $this->assertEquals('Surname', $fields[4]->getName());
697
698
        /* Test that inserting before a field that doesn't exist simply appends
699
         * Confirm that a composite field doesn't break this */
700
        $fields->push(new CompositeField([ new TextField('Nested1'), new TextField('Nested2')]));
701
        $this->assertTrue((bool)$fields->insertAfter('DoesNotExist', new TextField('MyName')));
702
        $this->assertEquals('MyName', $fields->Last()->Name);
703
    }
704
705
    public function testrootFieldList()
706
    {
707
        /* Given a nested set of FormField, CompositeField, and FieldList objects */
708
        $FieldList = new FieldList(
709
            $root = new TabSet(
710
                "Root",
711
                $main = new Tab(
712
                    "Main",
713
                    $a = new TextField("A"),
714
                    $b = new TextField("B")
715
                )
716
            )
717
        );
718
719
        /* rootFieldList() should always evaluate to the same object: the topmost FieldList */
720
        $this->assertSame($FieldList, $FieldList->rootFieldList());
721
        $this->assertSame($FieldList, $root->rootFieldList());
722
        $this->assertSame($FieldList, $main->rootFieldList());
723
        $this->assertSame($FieldList, $a->rootFieldList());
724
        $this->assertSame($FieldList, $b->rootFieldList());
725
726
        /* If we push additional fields, they should also have the same rootFieldList() */
727
        $root->push($other = new Tab("Other"));
728
        $other->push($c = new TextField("C"));
729
        $root->push($third = new Tab("Third", $d = new TextField("D")));
730
731
        $this->assertSame($FieldList, $other->rootFieldList());
732
        $this->assertSame($FieldList, $third->rootFieldList());
733
        $this->assertSame($FieldList, $c->rootFieldList());
734
        $this->assertSame($FieldList, $d->rootFieldList());
735
    }
736
737
    public function testAddingDuplicateReplacesOldField()
738
    {
739
        /* Given a nested set of FormField, CompositeField, and FieldList objects */
740
        $FieldList = new FieldList(
741
            $root = new TabSet(
742
                "Root",
743
                $main = new Tab(
744
                    "Main",
745
                    $a = new TextField("A"),
746
                    $b = new TextField("B")
747
                )
748
            )
749
        );
750
751
        /* Adding new fields of the same names should replace the original fields */
752
        $newA = new TextField("A", "New A");
753
        $newB = new TextField("B", "New B");
754
755
        $FieldList->addFieldToTab("Root.Main", $newA);
756
        $FieldList->addFieldToTab("Root.Other", $newB);
757
758
        $this->assertSame($newA, $FieldList->dataFieldByName("A"));
759
        $this->assertSame($newB, $FieldList->dataFieldByName("B"));
760
        $this->assertEquals(1, $main->Fields()->count());
761
762
        /* Pushing fields on the end of the field set should remove them from the tab */
763
        $thirdA = new TextField("A", "Third A");
764
        $thirdB = new TextField("B", "Third B");
765
        $FieldList->push($thirdA);
766
        $FieldList->push($thirdB);
767
768
        $this->assertSame($thirdA, $FieldList->fieldByName("A"));
769
        $this->assertSame($thirdB, $FieldList->fieldByName("B"));
770
771
        $this->assertEquals(0, $main->Fields()->count());
772
    }
773
774
    public function testAddingFieldToNonExistentTabCreatesThatTab()
775
    {
776
        $FieldList = new FieldList(
777
            $root = new TabSet(
778
                "Root",
779
                $main = new Tab(
780
                    "Main",
781
                    $a = new TextField("A")
782
                )
783
            )
784
        );
785
786
        /* Add a field to a non-existent tab, and it will be created */
787
        $FieldList->addFieldToTab("Root.Other", $b = new TextField("B"));
788
        $this->assertNotNull($FieldList->fieldByName('Root')->fieldByName('Other'));
789
        $this->assertSame($b, $FieldList->fieldByName('Root')->fieldByName('Other')->Fields()->first());
790
    }
791
792
    public function testAddingFieldToATabWithTheSameNameAsTheField()
793
    {
794
        $FieldList = new FieldList(
795
            $root = new TabSet(
796
                "Root",
797
                $main = new Tab(
798
                    "Main",
799
                    $a = new TextField("A")
800
                )
801
            )
802
        );
803
804
        /* If you have a tab with the same name as the field, then technically it's a duplicate. However, it's
805
        * allowed because tab isn't a data field.  Only duplicate data fields are problematic */
806
        $FieldList->addFieldToTab("Root.MyName", $myName = new TextField("MyName"));
807
        $this->assertNotNull($FieldList->fieldByName('Root')->fieldByName('MyName'));
808
        $this->assertSame($myName, $FieldList->fieldByName('Root')->fieldByName('MyName')->Fields()->first());
809
    }
810
811
    public function testInsertBeforeWithNestedCompositeFields()
812
    {
813
        $FieldList = new FieldList(
814
            new TextField('A_pre'),
815
            new TextField('A'),
816
            new TextField('A_post'),
817
            $compositeA = new CompositeField(
818
                new TextField('B_pre'),
819
                new TextField('B'),
820
                new TextField('B_post'),
821
                $compositeB = new CompositeField(
822
                    new TextField('C_pre'),
823
                    new TextField('C'),
824
                    new TextField('C_post')
825
                )
826
            )
827
        );
828
829
        $FieldList->insertBefore(
830
            'A',
831
            $A_insertbefore = new TextField('A_insertbefore')
832
        );
833
        $this->assertSame(
834
            $A_insertbefore,
835
            $FieldList->dataFieldByName('A_insertbefore'),
836
            'Field on toplevel FieldList can be inserted'
837
        );
838
839
        $FieldList->insertBefore(
840
            'B',
841
            $B_insertbefore = new TextField('B_insertbefore')
842
        );
843
        $this->assertSame(
844
            $FieldList->dataFieldByName('B_insertbefore'),
845
            $B_insertbefore,
846
            'Field on one nesting level FieldList can be inserted'
847
        );
848
849
        $FieldList->insertBefore(
850
            'C',
851
            $C_insertbefore = new TextField('C_insertbefore')
852
        );
853
        $this->assertSame(
854
            $FieldList->dataFieldByName('C_insertbefore'),
855
            $C_insertbefore,
856
            'Field on two nesting levels FieldList can be inserted'
857
        );
858
    }
859
860
    /**
861
     * @todo check actual placement of fields
862
     */
863
    public function testInsertBeforeWithNestedTabsets()
864
    {
865
        $FieldListA = new FieldList(
866
            $tabSetA = new TabSet(
867
                'TabSet_A',
868
                $tabA1 = new Tab(
869
                    'Tab_A1',
870
                    new TextField('A_pre'),
871
                    new TextField('A'),
872
                    new TextField('A_post')
873
                ),
874
                $tabB1 = new Tab(
875
                    'Tab_B1',
876
                    new TextField('B')
877
                )
878
            )
879
        );
880
        $tabSetA->insertBefore(
881
            'A',
882
            $A_insertbefore = new TextField('A_insertbefore')
883
        );
884
        $this->assertEquals(
885
            $FieldListA->dataFieldByName('A_insertbefore'),
886
            $A_insertbefore,
887
            'Field on toplevel tab can be inserted'
888
        );
889
890
        $this->assertEquals(0, $tabA1->fieldPosition('A_pre'));
891
        $this->assertEquals(1, $tabA1->fieldPosition('A_insertbefore'));
892
        $this->assertEquals(2, $tabA1->fieldPosition('A'));
893
        $this->assertEquals(3, $tabA1->fieldPosition('A_post'));
894
895
        $FieldListB = new FieldList(
896
            new TabSet(
897
                'TabSet_A',
898
                $tabsetB = new TabSet(
899
                    'TabSet_B',
900
                    $tabB1 = new Tab(
901
                        'Tab_B1',
902
                        new TextField('C')
903
                    ),
904
                    $tabB2 = new Tab(
905
                        'Tab_B2',
906
                        new TextField('B_pre'),
907
                        new TextField('B'),
908
                        new TextField('B_post')
909
                    )
910
                )
911
            )
912
        );
913
        $FieldListB->insertBefore(
914
            'B',
915
            $B_insertbefore = new TextField('B_insertbefore')
916
        );
917
        $this->assertSame(
918
            $FieldListB->dataFieldByName('B_insertbefore'),
919
            $B_insertbefore,
920
            'Field on nested tab can be inserted'
921
        );
922
        $this->assertEquals(0, $tabB2->fieldPosition('B_pre'));
923
        $this->assertEquals(1, $tabB2->fieldPosition('B_insertbefore'));
924
        $this->assertEquals(2, $tabB2->fieldPosition('B'));
925
        $this->assertEquals(3, $tabB2->fieldPosition('B_post'));
926
    }
927
928
    public function testInsertAfterWithNestedCompositeFields()
929
    {
930
        $FieldList = new FieldList(
931
            new TextField('A_pre'),
932
            new TextField('A'),
933
            new TextField('A_post'),
934
            $compositeA = new CompositeField(
935
                new TextField('B_pre'),
936
                new TextField('B'),
937
                new TextField('B_post'),
938
                $compositeB = new CompositeField(
939
                    new TextField('C_pre'),
940
                    new TextField('C'),
941
                    new TextField('C_post')
942
                )
943
            )
944
        );
945
946
        $FieldList->insertAfter(
947
            'A',
948
            $A_insertafter = new TextField('A_insertafter')
949
        );
950
        $this->assertSame(
951
            $A_insertafter,
952
            $FieldList->dataFieldByName('A_insertafter'),
953
            'Field on toplevel FieldList can be inserted after'
954
        );
955
956
        $FieldList->insertAfter(
957
            'B',
958
            $B_insertafter = new TextField('B_insertafter')
959
        );
960
        $this->assertSame(
961
            $FieldList->dataFieldByName('B_insertafter'),
962
            $B_insertafter,
963
            'Field on one nesting level FieldList can be inserted after'
964
        );
965
966
        $FieldList->insertAfter(
967
            'C',
968
            $C_insertafter = new TextField('C_insertafter')
969
        );
970
        $this->assertSame(
971
            $FieldList->dataFieldByName('C_insertafter'),
972
            $C_insertafter,
973
            'Field on two nesting levels FieldList can be inserted after'
974
        );
975
    }
976
977
    /**
978
     * @todo check actual placement of fields
979
     */
980
    public function testInsertAfterWithNestedTabsets()
981
    {
982
        $FieldListA = new FieldList(
983
            $tabSetA = new TabSet(
984
                'TabSet_A',
985
                $tabA1 = new Tab(
986
                    'Tab_A1',
987
                    new TextField('A_pre'),
988
                    new TextField('A'),
989
                    new TextField('A_post')
990
                ),
991
                $tabB1 = new Tab(
992
                    'Tab_B1',
993
                    new TextField('B')
994
                )
995
            )
996
        );
997
        $tabSetA->insertAfter(
998
            'A',
999
            $A_insertafter = new TextField('A_insertafter')
1000
        );
1001
        $this->assertEquals(
1002
            $FieldListA->dataFieldByName('A_insertafter'),
1003
            $A_insertafter,
1004
            'Field on toplevel tab can be inserted after'
1005
        );
1006
        $this->assertEquals(0, $tabA1->fieldPosition('A_pre'));
1007
        $this->assertEquals(1, $tabA1->fieldPosition('A'));
1008
        $this->assertEquals(2, $tabA1->fieldPosition('A_insertafter'));
1009
        $this->assertEquals(3, $tabA1->fieldPosition('A_post'));
1010
1011
        $FieldListB = new FieldList(
1012
            new TabSet(
1013
                'TabSet_A',
1014
                $tabsetB = new TabSet(
1015
                    'TabSet_B',
1016
                    $tabB1 = new Tab(
1017
                        'Tab_B1',
1018
                        new TextField('C')
1019
                    ),
1020
                    $tabB2 = new Tab(
1021
                        'Tab_B2',
1022
                        new TextField('B_pre'),
1023
                        new TextField('B'),
1024
                        new TextField('B_post')
1025
                    )
1026
                )
1027
            )
1028
        );
1029
        $FieldListB->insertAfter(
1030
            'B',
1031
            $B_insertafter = new TextField('B_insertafter')
1032
        );
1033
        $this->assertSame(
1034
            $FieldListB->dataFieldByName('B_insertafter'),
1035
            $B_insertafter,
1036
            'Field on nested tab can be inserted after'
1037
        );
1038
        $this->assertEquals(0, $tabB2->fieldPosition('B_pre'));
1039
        $this->assertEquals(1, $tabB2->fieldPosition('B'));
1040
        $this->assertEquals(2, $tabB2->fieldPosition('B_insertafter'));
1041
        $this->assertEquals(3, $tabB2->fieldPosition('B_post'));
1042
    }
1043
    /**
1044
     * FieldList::changeFieldOrder() should place specified fields in given
1045
     * order then add any unspecified remainders at the end. Can be given an
1046
     * array or list of arguments.
1047
     */
1048
    public function testChangeFieldOrder()
1049
    {
1050
        $fieldNames = array('A','B','C','D','E');
1051
        $setArray = new FieldList();
1052
        $setArgs = new FieldList();
1053
        foreach ($fieldNames as $fN) {
1054
            $setArray->push(new TextField($fN));
1055
            $setArgs->push(new TextField($fN));
1056
        }
1057
1058
        $setArray->changeFieldOrder(array('D','B','E'));
1059
        $this->assertEquals(0, $setArray->fieldPosition('D'));
1060
        $this->assertEquals(1, $setArray->fieldPosition('B'));
1061
        $this->assertEquals(2, $setArray->fieldPosition('E'));
1062
        $this->assertEquals(3, $setArray->fieldPosition('A'));
1063
        $this->assertEquals(4, $setArray->fieldPosition('C'));
1064
1065
        $setArgs->changeFieldOrder('D', 'B', 'E');
1066
        $this->assertEquals(0, $setArgs->fieldPosition('D'));
1067
        $this->assertEquals(1, $setArgs->fieldPosition('B'));
1068
        $this->assertEquals(2, $setArgs->fieldPosition('E'));
1069
        $this->assertEquals(3, $setArgs->fieldPosition('A'));
1070
        $this->assertEquals(4, $setArgs->fieldPosition('C'));
1071
1072
        unset($setArray, $setArgs);
1073
    }
1074
1075
    public function testFieldPosition()
1076
    {
1077
        $set = new FieldList(
1078
            new TextField('A'),
1079
            new TextField('B'),
1080
            new TextField('C')
1081
        );
1082
1083
        $this->assertEquals(0, $set->fieldPosition('A'));
1084
        $this->assertEquals(1, $set->fieldPosition('B'));
1085
        $this->assertEquals(2, $set->fieldPosition('C'));
1086
1087
        $set->insertBefore('B', new TextField('AB'));
1088
        $this->assertEquals(0, $set->fieldPosition('A'));
1089
        $this->assertEquals(1, $set->fieldPosition('AB'));
1090
        $this->assertEquals(2, $set->fieldPosition('B'));
1091
        $this->assertEquals(3, $set->fieldPosition('C'));
1092
1093
        unset($set);
1094
    }
1095
1096
    /**
1097
     * FieldList::forTemplate() returns a concatenation of FieldHolder values.
1098
     */
1099
    public function testForTemplate()
1100
    {
1101
        $set = new FieldList(
1102
            $a = new TextField('A'),
1103
            $b = new TextField('B')
1104
        );
1105
1106
        $this->assertEquals($a->FieldHolder() . $b->FieldHolder(), $set->forTemplate());
1107
    }
1108
1109
    /**
1110
     * FieldList::forTemplate() for an action list returns a concatenation of Field values.
1111
     * Internally, this works by having FormAction::FieldHolder return just the field, but it's an important
1112
     * use-case to test.
1113
     */
1114
    public function testForTemplateForActionList()
1115
    {
1116
        $set = new FieldList(
1117
            $a = new FormAction('A'),
1118
            $b = new FormAction('B')
1119
        );
1120
1121
        $this->assertEquals($a->Field() . $b->Field(), $set->forTemplate());
1122
    }
1123
1124
    public function testMakeFieldReadonly()
1125
    {
1126
        $FieldList = new FieldList(
1127
            new TabSet(
1128
                'Root',
1129
                new Tab(
1130
                    'Main',
1131
                    new TextField('A'),
1132
                    new TextField('B')
1133
                )
1134
            )
1135
        );
1136
1137
        $FieldList->makeFieldReadonly('A');
1138
        $this->assertTrue(
1139
            $FieldList->dataFieldByName('A')->isReadonly(),
1140
            'Field nested inside a TabSet and FieldList can be marked readonly by FieldList->makeFieldReadonly()'
1141
        );
1142
    }
1143
1144
    /**
1145
     * Test VisibleFields and HiddenFields
1146
     */
1147
    public function testVisibleAndHiddenFields()
1148
    {
1149
        $fields = new FieldList(
1150
            new TextField("A"),
1151
            new TextField("B"),
1152
            new HiddenField("C"),
1153
            new Tabset(
1154
                "Root",
1155
                new Tab(
1156
                    "D",
1157
                    new TextField("D1"),
1158
                    new HiddenField("D2")
1159
                )
1160
            )
1161
        );
1162
1163
        $hidden = $fields->HiddenFields();
1164
        // Inside hidden fields, all HiddenField objects are included, even nested ones
1165
        $this->assertNotNull($hidden->dataFieldByName('C'));
1166
        $this->assertNotNull($hidden->dataFieldByName('D2'));
1167
        // Visible fields are not
1168
        $this->assertNull($hidden->dataFieldByName('B'));
1169
        $this->assertNull($hidden->dataFieldByName('D1'));
1170
1171
        $visible = $fields->VisibleFields();
1172
        // Visible fields exclude top level HiddenField objects
1173
        $this->assertNotNull($visible->dataFieldByName('A'));
1174
        $this->assertNull($visible->dataFieldByName('C'));
1175
        // But they don't exclude nested HiddenField objects.  This is a limitation; you should
1176
        // put all your HiddenFields at the top level.
1177
        $this->assertNotNull($visible->dataFieldByName('D2'));
1178
    }
1179
1180
    public function testContainerField()
1181
    {
1182
        $fieldlist = new FieldList();
1183
        $container = CompositeField::create();
1184
1185
        $this->assertNull($fieldlist->getContainerField());
1186
1187
        $fieldlist->setContainerField($container);
1188
        $this->assertEquals($container, $fieldlist->getContainerField());
1189
1190
        $fieldlist->setContainerField(null);
1191
        $this->assertNull($fieldlist->getContainerField());
0 ignored issues
show
Bug introduced by
Are you sure the usage of $fieldlist->getContainerField() targeting SilverStripe\Forms\FieldList::getContainerField() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
1192
    }
1193
}
1194