mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
71dad5f685
Previous behaviour was to return false, which has been described as a confusing bug on https://github.com/silverstripe/silverstripe-framework/issues/1397 where the issue was identified.
1180 lines
40 KiB
PHP
1180 lines
40 KiB
PHP
<?php
|
|
|
|
namespace SilverStripe\Forms\Tests;
|
|
|
|
use SilverStripe\Dev\SapphireTest;
|
|
use SilverStripe\Forms\ConfirmedPasswordField;
|
|
use SilverStripe\Forms\FieldList;
|
|
use SilverStripe\Forms\FormField;
|
|
use SilverStripe\Forms\LiteralField;
|
|
use SilverStripe\Forms\Tab;
|
|
use SilverStripe\Forms\TextField;
|
|
use SilverStripe\Forms\EmailField;
|
|
use SilverStripe\Forms\FieldGroup;
|
|
use SilverStripe\Forms\TextareaField;
|
|
use SilverStripe\Forms\TabSet;
|
|
use SilverStripe\Forms\NumericField;
|
|
use SilverStripe\Forms\CompositeField;
|
|
use SilverStripe\Forms\FormAction;
|
|
use SilverStripe\Forms\HiddenField;
|
|
|
|
/**
|
|
* Tests for FieldList
|
|
*
|
|
* @skipUpgrade
|
|
* @todo test for {@link FieldList->setValues()}. Need to check
|
|
* that the values that were set are the correct ones given back.
|
|
* @todo test for {@link FieldList->transform()} and {@link FieldList->makeReadonly()}.
|
|
* Need to ensure that it correctly transforms the FieldList object.
|
|
* @todo test for {@link FieldList->HiddenFields()}. Need to check
|
|
* the fields returned are the correct HiddenField objects for a
|
|
* given FieldList instance.
|
|
* @todo test for {@link FieldList->dataFields()}.
|
|
* @todo test for {@link FieldList->findOrMakeTab()}.
|
|
* @todo the same as above with insertBefore() and insertAfter()
|
|
*/
|
|
class FieldListTest extends SapphireTest
|
|
{
|
|
public function testRecursiveWalk()
|
|
{
|
|
$fields = array(
|
|
new TextField('Name'),
|
|
new EmailField('Email'),
|
|
new HiddenField('Hidden'),
|
|
new LiteralField('Literal', 'Literal content'),
|
|
new CompositeField(
|
|
new TextField('Day'),
|
|
new TextField('Month'),
|
|
new TextField('Year')
|
|
),
|
|
);
|
|
$fieldList = new FieldList($fields);
|
|
|
|
$count = 0;
|
|
|
|
$fieldList->recursiveWalk(function (FormField $field) use (&$count) {
|
|
++$count;
|
|
});
|
|
|
|
$this->assertEquals(8, $count);
|
|
}
|
|
|
|
public function testFlattenFields()
|
|
{
|
|
$fields = array(
|
|
new TextField('Name'),
|
|
new EmailField('Email'),
|
|
new HiddenField('Hidden'),
|
|
new LiteralField('Literal', 'Literal content'),
|
|
$composite = new CompositeField(
|
|
$day = new TextField('Day'),
|
|
$month = new TextField('Month'),
|
|
$year = new TextField('Year')
|
|
),
|
|
);
|
|
$fieldList = new FieldList($fields);
|
|
|
|
array_pop($fields);
|
|
array_push($fields, $composite, $day, $month, $year);
|
|
|
|
$this->assertEquals($fields, $fieldList->flattenFields()->toArray());
|
|
}
|
|
|
|
public function testSaveableFields()
|
|
{
|
|
$fields = array(
|
|
new TextField('Name'),
|
|
new EmailField('Email'),
|
|
new HiddenField('Hidden'),
|
|
new LiteralField('Literal', 'Literal content'),
|
|
new CompositeField(
|
|
$day = new TextField('Day'),
|
|
$month = new TextField('Month'),
|
|
$year = new TextField('Year')
|
|
),
|
|
);
|
|
$fieldList = new FieldList($fields);
|
|
|
|
array_pop($fields);
|
|
array_pop($fields);
|
|
array_push($fields, $day, $month, $year);
|
|
|
|
$this->assertEquals($fields, array_values($fieldList->saveableFields()));
|
|
}
|
|
|
|
public function testFieldNames()
|
|
{
|
|
$fields = array(
|
|
new TextField('Name'),
|
|
new EmailField('Email'),
|
|
new HiddenField('Hidden'),
|
|
new LiteralField('Literal', 'Literal content'),
|
|
new CompositeField(
|
|
$day = new TextField('Day'),
|
|
$month = new TextField('Month'),
|
|
$year = new TextField('Year')
|
|
),
|
|
);
|
|
$fieldList = new FieldList($fields);
|
|
|
|
$this->assertEquals(['Name', 'Email', 'Hidden', 'Day', 'Month', 'Year'], $fieldList->dataFieldNames());
|
|
}
|
|
|
|
/**
|
|
* Test adding a field to a tab in a set.
|
|
*/
|
|
public function testAddFieldToTab()
|
|
{
|
|
$fields = new FieldList();
|
|
$tab = new Tab('Root');
|
|
$fields->push($tab);
|
|
|
|
/* We add field objects to the FieldList, using two different methods */
|
|
$fields->addFieldToTab('Root', new TextField('Country'));
|
|
$fields->addFieldsToTab(
|
|
'Root',
|
|
array(
|
|
new EmailField('Email'),
|
|
new TextField('Name'),
|
|
)
|
|
);
|
|
|
|
/* Check that the field objects were created */
|
|
$this->assertNotNull($fields->dataFieldByName('Country'));
|
|
$this->assertNotNull($fields->dataFieldByName('Email'));
|
|
$this->assertNotNull($fields->dataFieldByName('Name'));
|
|
|
|
/* The field objects in the set should be the same as the ones we created */
|
|
$this->assertSame($fields->dataFieldByName('Country'), $tab->fieldByName('Country'));
|
|
$this->assertSame($fields->dataFieldByName('Email'), $tab->fieldByName('Email'));
|
|
$this->assertSame($fields->dataFieldByName('Name'), $tab->fieldByName('Name'));
|
|
|
|
/* We'll have 3 fields inside the tab */
|
|
$this->assertEquals(3, $tab->Fields()->count());
|
|
}
|
|
|
|
/**
|
|
* Test that groups can be added to a fieldlist
|
|
*/
|
|
public function testFieldgroup()
|
|
{
|
|
$fields = new FieldList();
|
|
$tab = new Tab('Root');
|
|
$fields->push($tab);
|
|
|
|
$fields->addFieldsToTab(
|
|
'Root',
|
|
array(
|
|
$group1 = new FieldGroup(
|
|
new TextField('Name'),
|
|
new EmailField('Email')
|
|
),
|
|
$group2 = new FieldGroup(
|
|
new TextField('Company'),
|
|
new TextareaField('Address')
|
|
)
|
|
)
|
|
);
|
|
|
|
/* Check that the field objects were created */
|
|
$this->assertNotNull($fields->dataFieldByName('Name'));
|
|
$this->assertNotNull($fields->dataFieldByName('Email'));
|
|
$this->assertNotNull($fields->dataFieldByName('Company'));
|
|
$this->assertNotNull($fields->dataFieldByName('Address'));
|
|
|
|
/* The field objects in the set should be the same as the ones we created */
|
|
$this->assertSame($fields->dataFieldByName('Name'), $group1->fieldByName('Name'));
|
|
$this->assertSame($fields->dataFieldByName('Email'), $group1->fieldByName('Email'));
|
|
$this->assertSame($fields->dataFieldByName('Company'), $group2->fieldByName('Company'));
|
|
$this->assertSame($fields->dataFieldByName('Address'), $group2->fieldByName('Address'));
|
|
|
|
/* We'll have 2 fields directly inside the tab */
|
|
$this->assertEquals(2, $tab->Fields()->count());
|
|
}
|
|
|
|
/**
|
|
* Test removing a single field from a tab in a set.
|
|
*/
|
|
public function testRemoveSingleFieldFromTab()
|
|
{
|
|
$fields = new FieldList();
|
|
$tab = new Tab('Root');
|
|
$fields->push($tab);
|
|
|
|
/* We add a field to the "Root" tab */
|
|
$fields->addFieldToTab('Root', new TextField('Country'));
|
|
|
|
/* We have 1 field inside the tab, which is the field we just created */
|
|
$this->assertEquals(1, $tab->Fields()->count());
|
|
|
|
/* We remove the field from the tab */
|
|
$fields->removeFieldFromTab('Root', 'Country');
|
|
|
|
/* We'll have no fields in the tab now */
|
|
$this->assertEquals(0, $tab->Fields()->count());
|
|
}
|
|
|
|
public function testRemoveTab()
|
|
{
|
|
$fields = new FieldList(
|
|
new TabSet(
|
|
'Root',
|
|
$tab1 = new Tab('Tab1'),
|
|
$tab2 = new Tab('Tab2'),
|
|
$tab3 = new Tab('Tab3')
|
|
)
|
|
);
|
|
|
|
$fields->removeByName('Tab2');
|
|
$this->assertNull($fields->fieldByName('Root')->fieldByName('Tab2'));
|
|
|
|
$this->assertEquals($tab1, $fields->fieldByName('Root')->fieldByName('Tab1'));
|
|
}
|
|
|
|
public function testHasTabSet()
|
|
{
|
|
$untabbedFields = new FieldList(
|
|
new TextField('Field1')
|
|
);
|
|
$this->assertFalse($untabbedFields->hasTabSet());
|
|
|
|
$tabbedFields = new FieldList(
|
|
new TabSet(
|
|
'Root',
|
|
new Tab('Tab1')
|
|
)
|
|
);
|
|
$this->assertTrue($tabbedFields->hasTabSet());
|
|
}
|
|
|
|
public function testFindTab()
|
|
{
|
|
$fields = new FieldList(
|
|
$root = new TabSet(
|
|
'Root',
|
|
$tab1 = new Tab('Tab1'),
|
|
$tab2 = new Tab('Tab2'),
|
|
$tab3 = new Tab('Tab3'),
|
|
$more = new TabSet(
|
|
'More',
|
|
$tab4 = new Tab('Tab4')
|
|
)
|
|
)
|
|
);
|
|
|
|
$this->assertEquals($fields->findTab('Root'), $root);
|
|
$this->assertNull($fields->findTab('Tab5'));
|
|
|
|
$this->assertNull($fields->findTab('Tab3'));
|
|
$this->assertEquals($fields->findTab('Root.Tab3'), $tab3);
|
|
|
|
$this->assertNull($fields->findTab('More'));
|
|
$this->assertEquals($fields->findTab('Root.More'), $more);
|
|
$this->assertEquals($fields->findTab('Root.More.Tab4'), $tab4);
|
|
}
|
|
|
|
/**
|
|
* Test removing an array of fields from a tab in a set.
|
|
*/
|
|
public function testRemoveMultipleFieldsFromTab()
|
|
{
|
|
$fields = new FieldList();
|
|
$tab = new Tab('Root');
|
|
$fields->push($tab);
|
|
|
|
/* We add an array of fields, using addFieldsToTab() */
|
|
$fields->addFieldsToTab(
|
|
'Root',
|
|
array(
|
|
new TextField('Name', 'Your name'),
|
|
new EmailField('Email', 'Email address'),
|
|
new NumericField('Number', 'Insert a number')
|
|
)
|
|
);
|
|
|
|
/* We have 3 fields inside the tab, which we just created */
|
|
$this->assertEquals(3, $tab->Fields()->count());
|
|
|
|
/* We remove the 3 fields from the tab */
|
|
$fields->removeFieldsFromTab(
|
|
'Root',
|
|
array(
|
|
'Name',
|
|
'Email',
|
|
'Number'
|
|
)
|
|
);
|
|
|
|
/* We have no fields in the tab now */
|
|
$this->assertEquals(0, $tab->Fields()->count());
|
|
}
|
|
|
|
public function testRemoveFieldByName()
|
|
{
|
|
$fields = new FieldList();
|
|
$fields->push(new TextField('Name', 'Your name'));
|
|
|
|
$this->assertEquals(1, $fields->count());
|
|
$fields->removeByName('Name');
|
|
$this->assertEquals(0, $fields->count());
|
|
|
|
$fields->push(new TextField('Name[Field]', 'Your name'));
|
|
$this->assertEquals(1, $fields->count());
|
|
$fields->removeByName('Name[Field]');
|
|
$this->assertEquals(0, $fields->count());
|
|
}
|
|
|
|
public function testDataFieldByName()
|
|
{
|
|
$fields = new FieldList();
|
|
$fields->push($basic = new TextField('Name', 'Your name'));
|
|
$fields->push($brack = new TextField('Name[Field]', 'Your name'));
|
|
|
|
$this->assertEquals($basic, $fields->dataFieldByName('Name'));
|
|
$this->assertEquals($brack, $fields->dataFieldByName('Name[Field]'));
|
|
}
|
|
|
|
/**
|
|
* Test removing multiple fields from a set by their names in an array.
|
|
*/
|
|
public function testRemoveFieldsByName()
|
|
{
|
|
$fields = new FieldList();
|
|
|
|
/* First of all, we add some fields into our FieldList object */
|
|
$fields->push(new TextField('Name', 'Your name'));
|
|
$fields->push(new TextField('Email', 'Your email'));
|
|
|
|
/* We have 2 fields in our set now */
|
|
$this->assertEquals(2, $fields->count());
|
|
|
|
/* Then, we call up removeByName() to take it out again */
|
|
$fields->removeByName(array('Name', 'Email'));
|
|
|
|
/* We have 0 fields in our set now, as we've just removed the one we added */
|
|
$this->assertEquals(0, $fields->count());
|
|
}
|
|
|
|
/**
|
|
* Test replacing a field with another one.
|
|
*/
|
|
public function testReplaceField()
|
|
{
|
|
$fields = new FieldList();
|
|
$tab = new Tab('Root');
|
|
$fields->push($tab);
|
|
|
|
/* A field gets added to the set */
|
|
$fields->addFieldToTab('Root', new TextField('Country'));
|
|
|
|
$this->assertSame($fields->dataFieldByName('Country'), $tab->fieldByName('Country'));
|
|
|
|
$fields->replaceField('Country', new EmailField('Email'));
|
|
$this->assertEquals(1, $tab->Fields()->count());
|
|
|
|
$fields = new FieldList();
|
|
$fields->push(new TextField('Name', 'Your name'));
|
|
$brack = new TextField('Name[Field]', 'Your name');
|
|
|
|
$fields->replaceField('Name', $brack);
|
|
$this->assertEquals(1, $fields->count());
|
|
|
|
$this->assertEquals('Name[Field]', $fields->first()->getName());
|
|
}
|
|
|
|
public function testRenameField()
|
|
{
|
|
$fields = new FieldList();
|
|
$nameField = new TextField('Name', 'Before title');
|
|
$fields->push($nameField);
|
|
|
|
/* The title of the field object is the same as what we put in */
|
|
$this->assertSame('Before title', $nameField->Title());
|
|
|
|
/* The field gets renamed to a different title */
|
|
$fields->renameField('Name', 'After title');
|
|
|
|
/* The title of the field object is the title we renamed to, this
|
|
includes the original object we created ($nameField), and getting
|
|
the field back out of the set */
|
|
$this->assertSame('After title', $nameField->Title());
|
|
$this->assertSame('After title', $fields->dataFieldByName('Name')->Title());
|
|
}
|
|
|
|
public function testReplaceAFieldInADifferentTab()
|
|
{
|
|
/* A FieldList gets created with a TabSet and some field objects */
|
|
$FieldList = new FieldList(
|
|
new TabSet(
|
|
'Root',
|
|
$main = new Tab(
|
|
'Main',
|
|
new TextField('A'),
|
|
new TextField('B')
|
|
),
|
|
$other = new Tab(
|
|
'Other',
|
|
new TextField('C'),
|
|
new TextField('D')
|
|
)
|
|
)
|
|
);
|
|
|
|
/* The field "A" gets added to the FieldList we just created created */
|
|
$FieldList->addFieldToTab('Root.Other', $newA = new TextField('A', 'New Title'));
|
|
|
|
/* The field named "A" has been removed from the Main tab to make way for our new field named "A" in
|
|
* Other tab. */
|
|
$this->assertEquals(1, $main->Fields()->count());
|
|
$this->assertEquals(3, $other->Fields()->count());
|
|
}
|
|
|
|
/**
|
|
* Test finding a field that's inside a tabset, within another tab.
|
|
*/
|
|
public function testNestedTabsFindingFieldByName()
|
|
{
|
|
$fields = new FieldList();
|
|
|
|
/* 2 tabs get created within a TabSet inside our set */
|
|
$tab = new TabSet(
|
|
'Root',
|
|
new TabSet(
|
|
'MyContent',
|
|
$mainTab = new Tab('Main'),
|
|
$otherTab = new Tab('Others')
|
|
)
|
|
);
|
|
$fields->push($tab);
|
|
|
|
/* Some fields get added to the 2 tabs we just created */
|
|
$fields->addFieldToTab('Root.MyContent.Main', new TextField('Country'));
|
|
$fields->addFieldToTab('Root.MyContent.Others', new TextField('Email'));
|
|
|
|
/* The fields we just added actually exists in the set */
|
|
$this->assertNotNull($fields->dataFieldByName('Country'));
|
|
$this->assertNotNull($fields->dataFieldByName('Email'));
|
|
|
|
/* The fields we just added actually exist in the tabs */
|
|
$this->assertNotNull($mainTab->fieldByName('Country'));
|
|
$this->assertNotNull($otherTab->fieldByName('Email'));
|
|
|
|
/* We have 1 field for each of the tabs */
|
|
$this->assertEquals(1, $mainTab->Fields()->count());
|
|
$this->assertEquals(1, $otherTab->Fields()->count());
|
|
|
|
$this->assertNotNull($fields->fieldByName('Root.MyContent'));
|
|
$this->assertNotNull($fields->fieldByName('Root.MyContent'));
|
|
}
|
|
|
|
public function testTabTitles()
|
|
{
|
|
$set = new FieldList(
|
|
$rootTabSet = new TabSet(
|
|
'Root',
|
|
$tabSetWithoutTitle = new TabSet('TabSetWithoutTitle'),
|
|
$tabSetWithTitle = new TabSet(
|
|
'TabSetWithTitle',
|
|
'My TabSet Title',
|
|
new Tab('ExistingChildTab')
|
|
)
|
|
)
|
|
);
|
|
|
|
$this->assertEquals(
|
|
$tabSetWithTitle->Title(),
|
|
'My TabSet Title',
|
|
'Automatic conversion of tab identifiers through findOrMakeTab() with FormField::name_to_label()'
|
|
);
|
|
|
|
$tabWithoutTitle = $set->findOrMakeTab('Root.TabWithoutTitle');
|
|
$this->assertEquals(
|
|
$tabWithoutTitle->Title(),
|
|
'Tab Without Title',
|
|
'Automatic conversion of tab identifiers through findOrMakeTab() with FormField::name_to_label()'
|
|
);
|
|
|
|
$tabWithTitle = $set->findOrMakeTab('Root.TabWithTitle', 'My Tab with Title');
|
|
$this->assertEquals(
|
|
$tabWithTitle->Title(),
|
|
'My Tab with Title',
|
|
'Setting of simple tab titles through findOrMakeTab()'
|
|
);
|
|
|
|
$childTabWithTitle = $set->findOrMakeTab('Root.TabSetWithoutTitle.NewChildTab', 'My Child Tab Title');
|
|
$this->assertEquals(
|
|
$childTabWithTitle->Title(),
|
|
'My Child Tab Title',
|
|
'Setting of nested tab titles through findOrMakeTab() works on last child tab'
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Test pushing a field to a set.
|
|
*
|
|
* This tests {@link FieldList->push()}.
|
|
*/
|
|
public function testPushFieldToSet()
|
|
{
|
|
$fields = new FieldList();
|
|
|
|
/* A field named Country is added to the set */
|
|
$fields->push(new TextField('Country'));
|
|
|
|
/* We only have 1 field in the set */
|
|
$this->assertEquals(1, $fields->count());
|
|
|
|
/* Another field called Email is added to the set */
|
|
$fields->push(new EmailField('Email'));
|
|
|
|
/* There are now 2 fields in the set */
|
|
$this->assertEquals(2, $fields->count());
|
|
|
|
// Test that pushing a composite field without a name onto the set works
|
|
// See ticket #2932
|
|
$fields->push(
|
|
new CompositeField(
|
|
new TextField('Test1'),
|
|
new TextField('Test2')
|
|
)
|
|
);
|
|
$this->assertEquals(3, $fields->count());
|
|
}
|
|
|
|
/**
|
|
* Test pushing a field to the beginning of a set.
|
|
*
|
|
* This tests {@link FieldList->unshift()}.
|
|
*/
|
|
public function testPushFieldToBeginningOfSet()
|
|
{
|
|
$fields = new FieldList();
|
|
|
|
/* A field named Country is added to the set */
|
|
$fields->unshift(new TextField('Country'));
|
|
|
|
/* We only have 1 field in the set */
|
|
$this->assertEquals(1, $fields->count());
|
|
|
|
/* Another field called Email is added to the set */
|
|
$fields->unshift(new EmailField('Email'));
|
|
|
|
/* There are now 2 fields in the set */
|
|
$this->assertEquals(2, $fields->count());
|
|
|
|
/* The most recently added field is at the beginning of the set */
|
|
$this->assertEquals('Email', $fields->first()->getName());
|
|
|
|
// Test that pushing a composite field without a name onto the set works
|
|
$fields->unshift(
|
|
new CompositeField(
|
|
new TextField('Test1'),
|
|
new TextField('Test2')
|
|
)
|
|
);
|
|
$this->assertEquals(3, $fields->count());
|
|
}
|
|
|
|
/**
|
|
* Test inserting a field before another in a set.
|
|
*
|
|
* This tests {@link FieldList->insertBefore()}.
|
|
*/
|
|
public function testInsertBeforeFieldToSet()
|
|
{
|
|
$fields = new FieldList();
|
|
|
|
/* 3 fields are added to the set */
|
|
$fields->push(new TextField('Country'));
|
|
$fields->push(new TextField('Email'));
|
|
$fields->push(new TextField('FirstName'));
|
|
|
|
/* We now have 3 fields in the set */
|
|
$this->assertEquals(3, $fields->count());
|
|
|
|
/* We insert another field called Title before the FirstName field */
|
|
$fields->insertBefore('FirstName', new TextField('Title'));
|
|
|
|
/* The field we just added actually exists in the set */
|
|
$this->assertNotNull($fields->dataFieldByName('Title'));
|
|
|
|
/* We now have 4 fields in the set */
|
|
$this->assertEquals(4, $fields->count());
|
|
|
|
/* The position of the Title field is at number 3 */
|
|
$this->assertEquals('Title', $fields[2]->getName());
|
|
|
|
/* Test arguments are accepted in either order */
|
|
$fields->insertBefore('FirstName', new TextField('Surname'));
|
|
|
|
/* The field we just added actually exists in the set */
|
|
$this->assertNotNull($fields->dataFieldByName('Surname'));
|
|
|
|
/* We now have 5 fields in the set */
|
|
$this->assertEquals(5, $fields->count());
|
|
|
|
/* The position of the Surname field is at number 4 */
|
|
$this->assertEquals('Surname', $fields[3]->getName());
|
|
|
|
/* Test that inserting before a field that doesn't exist simply appends
|
|
* Confirm that a composite field doesn't break this */
|
|
$fields->push(new CompositeField([ new TextField('Nested1'), new TextField('Nested2')]));
|
|
$this->assertTrue((bool)$fields->insertBefore('DoesNotExist', new TextField('MyName')));
|
|
$this->assertEquals('MyName', $fields->Last()->Name);
|
|
}
|
|
|
|
public function testInsertBeforeMultipleFields()
|
|
{
|
|
$fields = new FieldList(
|
|
$root = new TabSet(
|
|
"Root",
|
|
$main = new Tab(
|
|
"Main",
|
|
$a = new TextField("A"),
|
|
$b = new TextField("B")
|
|
)
|
|
)
|
|
);
|
|
|
|
$fields->addFieldsToTab(
|
|
'Root.Main',
|
|
array(
|
|
new TextField('NewField1'),
|
|
new TextField('NewField2')
|
|
),
|
|
'B'
|
|
);
|
|
|
|
$this->assertEquals(
|
|
array_keys($fields->dataFields()),
|
|
array(
|
|
'A',
|
|
'NewField1',
|
|
'NewField2',
|
|
'B'
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Test inserting a field after another in a set.
|
|
*/
|
|
public function testInsertAfterFieldToSet()
|
|
{
|
|
$fields = new FieldList();
|
|
|
|
/* 3 fields are added to the set */
|
|
$fields->push(new TextField('Country'));
|
|
$fields->push(new TextField('Email'));
|
|
$fields->push(new TextField('FirstName'));
|
|
|
|
/* We now have 3 fields in the set */
|
|
$this->assertEquals(3, $fields->count());
|
|
|
|
/* A field called Title is inserted after the Country field */
|
|
$fields->insertAfter('Country', new TextField('Title'));
|
|
|
|
/* The field we just added actually exists in the set */
|
|
$this->assertNotNull($fields->dataFieldByName('Title'));
|
|
|
|
/* We now have 4 fields in the FieldList */
|
|
$this->assertEquals(4, $fields->count());
|
|
|
|
/* The position of the Title field should be at number 2 */
|
|
$this->assertEquals('Title', $fields[1]->getName());
|
|
|
|
/* Test arguments are accepted in either order */
|
|
$fields->insertAfter('FirstName', new TextField('Surname'));
|
|
|
|
/* The field we just added actually exists in the set */
|
|
$this->assertNotNull($fields->dataFieldByName('Surname'));
|
|
|
|
/* We now have 5 fields in the set */
|
|
$this->assertEquals(5, $fields->count());
|
|
|
|
/* The position of the Surname field is at number 5 */
|
|
$this->assertEquals('Surname', $fields[4]->getName());
|
|
|
|
/* Test that inserting before a field that doesn't exist simply appends
|
|
* Confirm that a composite field doesn't break this */
|
|
$fields->push(new CompositeField([ new TextField('Nested1'), new TextField('Nested2')]));
|
|
$this->assertTrue((bool)$fields->insertAfter('DoesNotExist', new TextField('MyName')));
|
|
$this->assertEquals('MyName', $fields->Last()->Name);
|
|
}
|
|
|
|
public function testrootFieldList()
|
|
{
|
|
/* Given a nested set of FormField, CompositeField, and FieldList objects */
|
|
$FieldList = new FieldList(
|
|
$root = new TabSet(
|
|
"Root",
|
|
$main = new Tab(
|
|
"Main",
|
|
$a = new TextField("A"),
|
|
$b = new TextField("B")
|
|
)
|
|
)
|
|
);
|
|
|
|
/* rootFieldList() should always evaluate to the same object: the topmost FieldList */
|
|
$this->assertSame($FieldList, $FieldList->rootFieldList());
|
|
$this->assertSame($FieldList, $root->rootFieldList());
|
|
$this->assertSame($FieldList, $main->rootFieldList());
|
|
$this->assertSame($FieldList, $a->rootFieldList());
|
|
$this->assertSame($FieldList, $b->rootFieldList());
|
|
|
|
/* If we push additional fields, they should also have the same rootFieldList() */
|
|
$root->push($other = new Tab("Other"));
|
|
$other->push($c = new TextField("C"));
|
|
$root->push($third = new Tab("Third", $d = new TextField("D")));
|
|
|
|
$this->assertSame($FieldList, $other->rootFieldList());
|
|
$this->assertSame($FieldList, $third->rootFieldList());
|
|
$this->assertSame($FieldList, $c->rootFieldList());
|
|
$this->assertSame($FieldList, $d->rootFieldList());
|
|
}
|
|
|
|
public function testAddingDuplicateReplacesOldField()
|
|
{
|
|
/* Given a nested set of FormField, CompositeField, and FieldList objects */
|
|
$FieldList = new FieldList(
|
|
$root = new TabSet(
|
|
"Root",
|
|
$main = new Tab(
|
|
"Main",
|
|
$a = new TextField("A"),
|
|
$b = new TextField("B")
|
|
)
|
|
)
|
|
);
|
|
|
|
/* Adding new fields of the same names should replace the original fields */
|
|
$newA = new TextField("A", "New A");
|
|
$newB = new TextField("B", "New B");
|
|
|
|
$FieldList->addFieldToTab("Root.Main", $newA);
|
|
$FieldList->addFieldToTab("Root.Other", $newB);
|
|
|
|
$this->assertSame($newA, $FieldList->dataFieldByName("A"));
|
|
$this->assertSame($newB, $FieldList->dataFieldByName("B"));
|
|
$this->assertEquals(1, $main->Fields()->count());
|
|
|
|
/* Pushing fields on the end of the field set should remove them from the tab */
|
|
$thirdA = new TextField("A", "Third A");
|
|
$thirdB = new TextField("B", "Third B");
|
|
$FieldList->push($thirdA);
|
|
$FieldList->push($thirdB);
|
|
|
|
$this->assertSame($thirdA, $FieldList->fieldByName("A"));
|
|
$this->assertSame($thirdB, $FieldList->fieldByName("B"));
|
|
|
|
$this->assertEquals(0, $main->Fields()->count());
|
|
}
|
|
|
|
public function testAddingFieldToNonExistentTabCreatesThatTab()
|
|
{
|
|
$FieldList = new FieldList(
|
|
$root = new TabSet(
|
|
"Root",
|
|
$main = new Tab(
|
|
"Main",
|
|
$a = new TextField("A")
|
|
)
|
|
)
|
|
);
|
|
|
|
/* Add a field to a non-existent tab, and it will be created */
|
|
$FieldList->addFieldToTab("Root.Other", $b = new TextField("B"));
|
|
$this->assertNotNull($FieldList->fieldByName('Root')->fieldByName('Other'));
|
|
$this->assertSame($b, $FieldList->fieldByName('Root')->fieldByName('Other')->Fields()->first());
|
|
}
|
|
|
|
public function testAddingFieldToATabWithTheSameNameAsTheField()
|
|
{
|
|
$FieldList = new FieldList(
|
|
$root = new TabSet(
|
|
"Root",
|
|
$main = new Tab(
|
|
"Main",
|
|
$a = new TextField("A")
|
|
)
|
|
)
|
|
);
|
|
|
|
/* If you have a tab with the same name as the field, then technically it's a duplicate. However, it's
|
|
* allowed because tab isn't a data field. Only duplicate data fields are problematic */
|
|
$FieldList->addFieldToTab("Root.MyName", $myName = new TextField("MyName"));
|
|
$this->assertNotNull($FieldList->fieldByName('Root')->fieldByName('MyName'));
|
|
$this->assertSame($myName, $FieldList->fieldByName('Root')->fieldByName('MyName')->Fields()->first());
|
|
}
|
|
|
|
public function testInsertBeforeWithNestedCompositeFields()
|
|
{
|
|
$FieldList = new FieldList(
|
|
new TextField('A_pre'),
|
|
new TextField('A'),
|
|
new TextField('A_post'),
|
|
$compositeA = new CompositeField(
|
|
new TextField('B_pre'),
|
|
new TextField('B'),
|
|
new TextField('B_post'),
|
|
$compositeB = new CompositeField(
|
|
new TextField('C_pre'),
|
|
new TextField('C'),
|
|
new TextField('C_post')
|
|
)
|
|
)
|
|
);
|
|
|
|
$FieldList->insertBefore(
|
|
'A',
|
|
$A_insertbefore = new TextField('A_insertbefore')
|
|
);
|
|
$this->assertSame(
|
|
$A_insertbefore,
|
|
$FieldList->dataFieldByName('A_insertbefore'),
|
|
'Field on toplevel FieldList can be inserted'
|
|
);
|
|
|
|
$FieldList->insertBefore(
|
|
'B',
|
|
$B_insertbefore = new TextField('B_insertbefore')
|
|
);
|
|
$this->assertSame(
|
|
$FieldList->dataFieldByName('B_insertbefore'),
|
|
$B_insertbefore,
|
|
'Field on one nesting level FieldList can be inserted'
|
|
);
|
|
|
|
$FieldList->insertBefore(
|
|
'C',
|
|
$C_insertbefore = new TextField('C_insertbefore')
|
|
);
|
|
$this->assertSame(
|
|
$FieldList->dataFieldByName('C_insertbefore'),
|
|
$C_insertbefore,
|
|
'Field on two nesting levels FieldList can be inserted'
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @todo check actual placement of fields
|
|
*/
|
|
public function testInsertBeforeWithNestedTabsets()
|
|
{
|
|
$FieldListA = new FieldList(
|
|
$tabSetA = new TabSet(
|
|
'TabSet_A',
|
|
$tabA1 = new Tab(
|
|
'Tab_A1',
|
|
new TextField('A_pre'),
|
|
new TextField('A'),
|
|
new TextField('A_post')
|
|
),
|
|
$tabB1 = new Tab(
|
|
'Tab_B1',
|
|
new TextField('B')
|
|
)
|
|
)
|
|
);
|
|
$tabSetA->insertBefore(
|
|
'A',
|
|
$A_insertbefore = new TextField('A_insertbefore')
|
|
);
|
|
$this->assertEquals(
|
|
$FieldListA->dataFieldByName('A_insertbefore'),
|
|
$A_insertbefore,
|
|
'Field on toplevel tab can be inserted'
|
|
);
|
|
|
|
$this->assertEquals(0, $tabA1->fieldPosition('A_pre'));
|
|
$this->assertEquals(1, $tabA1->fieldPosition('A_insertbefore'));
|
|
$this->assertEquals(2, $tabA1->fieldPosition('A'));
|
|
$this->assertEquals(3, $tabA1->fieldPosition('A_post'));
|
|
|
|
$FieldListB = new FieldList(
|
|
new TabSet(
|
|
'TabSet_A',
|
|
$tabsetB = new TabSet(
|
|
'TabSet_B',
|
|
$tabB1 = new Tab(
|
|
'Tab_B1',
|
|
new TextField('C')
|
|
),
|
|
$tabB2 = new Tab(
|
|
'Tab_B2',
|
|
new TextField('B_pre'),
|
|
new TextField('B'),
|
|
new TextField('B_post')
|
|
)
|
|
)
|
|
)
|
|
);
|
|
$FieldListB->insertBefore(
|
|
'B',
|
|
$B_insertbefore = new TextField('B_insertbefore')
|
|
);
|
|
$this->assertSame(
|
|
$FieldListB->dataFieldByName('B_insertbefore'),
|
|
$B_insertbefore,
|
|
'Field on nested tab can be inserted'
|
|
);
|
|
$this->assertEquals(0, $tabB2->fieldPosition('B_pre'));
|
|
$this->assertEquals(1, $tabB2->fieldPosition('B_insertbefore'));
|
|
$this->assertEquals(2, $tabB2->fieldPosition('B'));
|
|
$this->assertEquals(3, $tabB2->fieldPosition('B_post'));
|
|
}
|
|
|
|
public function testInsertAfterWithNestedCompositeFields()
|
|
{
|
|
$FieldList = new FieldList(
|
|
new TextField('A_pre'),
|
|
new TextField('A'),
|
|
new TextField('A_post'),
|
|
$compositeA = new CompositeField(
|
|
new TextField('B_pre'),
|
|
new TextField('B'),
|
|
new TextField('B_post'),
|
|
$compositeB = new CompositeField(
|
|
new TextField('C_pre'),
|
|
new TextField('C'),
|
|
new TextField('C_post')
|
|
)
|
|
)
|
|
);
|
|
|
|
$FieldList->insertAfter(
|
|
'A',
|
|
$A_insertafter = new TextField('A_insertafter')
|
|
);
|
|
$this->assertSame(
|
|
$A_insertafter,
|
|
$FieldList->dataFieldByName('A_insertafter'),
|
|
'Field on toplevel FieldList can be inserted after'
|
|
);
|
|
|
|
$FieldList->insertAfter(
|
|
'B',
|
|
$B_insertafter = new TextField('B_insertafter')
|
|
);
|
|
$this->assertSame(
|
|
$FieldList->dataFieldByName('B_insertafter'),
|
|
$B_insertafter,
|
|
'Field on one nesting level FieldList can be inserted after'
|
|
);
|
|
|
|
$FieldList->insertAfter(
|
|
'C',
|
|
$C_insertafter = new TextField('C_insertafter')
|
|
);
|
|
$this->assertSame(
|
|
$FieldList->dataFieldByName('C_insertafter'),
|
|
$C_insertafter,
|
|
'Field on two nesting levels FieldList can be inserted after'
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @todo check actual placement of fields
|
|
*/
|
|
public function testInsertAfterWithNestedTabsets()
|
|
{
|
|
$FieldListA = new FieldList(
|
|
$tabSetA = new TabSet(
|
|
'TabSet_A',
|
|
$tabA1 = new Tab(
|
|
'Tab_A1',
|
|
new TextField('A_pre'),
|
|
new TextField('A'),
|
|
new TextField('A_post')
|
|
),
|
|
$tabB1 = new Tab(
|
|
'Tab_B1',
|
|
new TextField('B')
|
|
)
|
|
)
|
|
);
|
|
$tabSetA->insertAfter(
|
|
'A',
|
|
$A_insertafter = new TextField('A_insertafter')
|
|
);
|
|
$this->assertEquals(
|
|
$FieldListA->dataFieldByName('A_insertafter'),
|
|
$A_insertafter,
|
|
'Field on toplevel tab can be inserted after'
|
|
);
|
|
$this->assertEquals(0, $tabA1->fieldPosition('A_pre'));
|
|
$this->assertEquals(1, $tabA1->fieldPosition('A'));
|
|
$this->assertEquals(2, $tabA1->fieldPosition('A_insertafter'));
|
|
$this->assertEquals(3, $tabA1->fieldPosition('A_post'));
|
|
|
|
$FieldListB = new FieldList(
|
|
new TabSet(
|
|
'TabSet_A',
|
|
$tabsetB = new TabSet(
|
|
'TabSet_B',
|
|
$tabB1 = new Tab(
|
|
'Tab_B1',
|
|
new TextField('C')
|
|
),
|
|
$tabB2 = new Tab(
|
|
'Tab_B2',
|
|
new TextField('B_pre'),
|
|
new TextField('B'),
|
|
new TextField('B_post')
|
|
)
|
|
)
|
|
)
|
|
);
|
|
$FieldListB->insertAfter(
|
|
'B',
|
|
$B_insertafter = new TextField('B_insertafter')
|
|
);
|
|
$this->assertSame(
|
|
$FieldListB->dataFieldByName('B_insertafter'),
|
|
$B_insertafter,
|
|
'Field on nested tab can be inserted after'
|
|
);
|
|
$this->assertEquals(0, $tabB2->fieldPosition('B_pre'));
|
|
$this->assertEquals(1, $tabB2->fieldPosition('B'));
|
|
$this->assertEquals(2, $tabB2->fieldPosition('B_insertafter'));
|
|
$this->assertEquals(3, $tabB2->fieldPosition('B_post'));
|
|
}
|
|
/**
|
|
* FieldList::changeFieldOrder() should place specified fields in given
|
|
* order then add any unspecified remainders at the end. Can be given an
|
|
* array or list of arguments.
|
|
*/
|
|
public function testChangeFieldOrder()
|
|
{
|
|
$fieldNames = array('A','B','C','D','E');
|
|
$setArray = new FieldList();
|
|
$setArgs = new FieldList();
|
|
foreach ($fieldNames as $fN) {
|
|
$setArray->push(new TextField($fN));
|
|
$setArgs->push(new TextField($fN));
|
|
}
|
|
|
|
$setArray->changeFieldOrder(array('D','B','E'));
|
|
$this->assertEquals(0, $setArray->fieldPosition('D'));
|
|
$this->assertEquals(1, $setArray->fieldPosition('B'));
|
|
$this->assertEquals(2, $setArray->fieldPosition('E'));
|
|
$this->assertEquals(3, $setArray->fieldPosition('A'));
|
|
$this->assertEquals(4, $setArray->fieldPosition('C'));
|
|
|
|
$setArgs->changeFieldOrder('D', 'B', 'E');
|
|
$this->assertEquals(0, $setArgs->fieldPosition('D'));
|
|
$this->assertEquals(1, $setArgs->fieldPosition('B'));
|
|
$this->assertEquals(2, $setArgs->fieldPosition('E'));
|
|
$this->assertEquals(3, $setArgs->fieldPosition('A'));
|
|
$this->assertEquals(4, $setArgs->fieldPosition('C'));
|
|
|
|
unset($setArray, $setArgs);
|
|
}
|
|
|
|
public function testFieldPosition()
|
|
{
|
|
$set = new FieldList(
|
|
new TextField('A'),
|
|
new TextField('B'),
|
|
new TextField('C')
|
|
);
|
|
|
|
$this->assertEquals(0, $set->fieldPosition('A'));
|
|
$this->assertEquals(1, $set->fieldPosition('B'));
|
|
$this->assertEquals(2, $set->fieldPosition('C'));
|
|
|
|
$set->insertBefore('B', new TextField('AB'));
|
|
$this->assertEquals(0, $set->fieldPosition('A'));
|
|
$this->assertEquals(1, $set->fieldPosition('AB'));
|
|
$this->assertEquals(2, $set->fieldPosition('B'));
|
|
$this->assertEquals(3, $set->fieldPosition('C'));
|
|
|
|
unset($set);
|
|
}
|
|
|
|
/**
|
|
* FieldList::forTemplate() returns a concatenation of FieldHolder values.
|
|
*/
|
|
public function testForTemplate()
|
|
{
|
|
$set = new FieldList(
|
|
$a = new TextField('A'),
|
|
$b = new TextField('B')
|
|
);
|
|
|
|
$this->assertEquals($a->FieldHolder() . $b->FieldHolder(), $set->forTemplate());
|
|
}
|
|
|
|
/**
|
|
* FieldList::forTemplate() for an action list returns a concatenation of Field values.
|
|
* Internally, this works by having FormAction::FieldHolder return just the field, but it's an important
|
|
* use-case to test.
|
|
*/
|
|
public function testForTemplateForActionList()
|
|
{
|
|
$set = new FieldList(
|
|
$a = new FormAction('A'),
|
|
$b = new FormAction('B')
|
|
);
|
|
|
|
$this->assertEquals($a->Field() . $b->Field(), $set->forTemplate());
|
|
}
|
|
|
|
public function testMakeFieldReadonly()
|
|
{
|
|
$FieldList = new FieldList(
|
|
new TabSet(
|
|
'Root',
|
|
new Tab(
|
|
'Main',
|
|
new TextField('A'),
|
|
new TextField('B')
|
|
)
|
|
)
|
|
);
|
|
|
|
$FieldList->makeFieldReadonly('A');
|
|
$this->assertTrue(
|
|
$FieldList->dataFieldByName('A')->isReadonly(),
|
|
'Field nested inside a TabSet and FieldList can be marked readonly by FieldList->makeFieldReadonly()'
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Test VisibleFields and HiddenFields
|
|
*/
|
|
public function testVisibleAndHiddenFields()
|
|
{
|
|
$fields = new FieldList(
|
|
new TextField("A"),
|
|
new TextField("B"),
|
|
new HiddenField("C"),
|
|
new Tabset(
|
|
"Root",
|
|
new Tab(
|
|
"D",
|
|
new TextField("D1"),
|
|
new HiddenField("D2")
|
|
)
|
|
)
|
|
);
|
|
|
|
$hidden = $fields->HiddenFields();
|
|
// Inside hidden fields, all HiddenField objects are included, even nested ones
|
|
$this->assertNotNull($hidden->dataFieldByName('C'));
|
|
$this->assertNotNull($hidden->dataFieldByName('D2'));
|
|
// Visible fields are not
|
|
$this->assertNull($hidden->dataFieldByName('B'));
|
|
$this->assertNull($hidden->dataFieldByName('D1'));
|
|
|
|
$visible = $fields->VisibleFields();
|
|
// Visible fields exclude top level HiddenField objects
|
|
$this->assertNotNull($visible->dataFieldByName('A'));
|
|
$this->assertNull($visible->dataFieldByName('C'));
|
|
// But they don't exclude nested HiddenField objects. This is a limitation; you should
|
|
// put all your HiddenFields at the top level.
|
|
$this->assertNotNull($visible->dataFieldByName('D2'));
|
|
}
|
|
}
|