mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge pull request #6472 from silbinarywolf/feat-fieldlist-nestedfields
feat(FieldList): Add nestedFields() function to return a flat array of all deeply nested fields in a FieldList.
This commit is contained in:
commit
623daed5ab
@ -58,6 +58,38 @@ class FieldList extends ArrayList
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterate over each field in the current list recursively
|
||||||
|
*
|
||||||
|
* @param callable $callback
|
||||||
|
*/
|
||||||
|
public function recursiveWalk(callable $callback)
|
||||||
|
{
|
||||||
|
$stack = $this->toArray();
|
||||||
|
while (!empty($stack)) {
|
||||||
|
/** @var FormField $field */
|
||||||
|
$field = array_shift($stack);
|
||||||
|
$callback($field);
|
||||||
|
if ($field instanceof CompositeField) {
|
||||||
|
$stack = array_merge($field->getChildren()->toArray(), $stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a flattened list of all fields
|
||||||
|
*
|
||||||
|
* @return static
|
||||||
|
*/
|
||||||
|
public function flattenFields()
|
||||||
|
{
|
||||||
|
$fields = [];
|
||||||
|
$this->recursiveWalk(function (FormField $field) use (&$fields) {
|
||||||
|
$fields[] = $field;
|
||||||
|
});
|
||||||
|
return static::create($fields);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a sequential set of all fields that have data. This excludes wrapper composite fields
|
* Return a sequential set of all fields that have data. This excludes wrapper composite fields
|
||||||
* as well as heading / help text fields.
|
* as well as heading / help text fields.
|
||||||
@ -66,8 +98,19 @@ class FieldList extends ArrayList
|
|||||||
*/
|
*/
|
||||||
public function dataFields()
|
public function dataFields()
|
||||||
{
|
{
|
||||||
if (!$this->sequentialSet) {
|
if (empty($this->sequentialSet)) {
|
||||||
$this->collateDataFields($this->sequentialSet);
|
$fields = [];
|
||||||
|
$this->recursiveWalk(function (FormField $field) use (&$fields) {
|
||||||
|
if (!$field->hasData()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$name = $field->getName();
|
||||||
|
if (isset($fields[$name])) {
|
||||||
|
$this->fieldNameError($field, __FUNCTION__);
|
||||||
|
}
|
||||||
|
$fields[$name] = $field;
|
||||||
|
});
|
||||||
|
$this->sequentialSet = $fields;
|
||||||
}
|
}
|
||||||
return $this->sequentialSet;
|
return $this->sequentialSet;
|
||||||
}
|
}
|
||||||
@ -77,20 +120,76 @@ class FieldList extends ArrayList
|
|||||||
*/
|
*/
|
||||||
public function saveableFields()
|
public function saveableFields()
|
||||||
{
|
{
|
||||||
if (!$this->sequentialSaveableSet) {
|
if (empty($this->sequentialSaveableSet)) {
|
||||||
$this->collateDataFields($this->sequentialSaveableSet, true);
|
$fields = [];
|
||||||
|
$this->recursiveWalk(function (FormField $field) use (&$fields) {
|
||||||
|
if (!$field->canSubmitValue()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$name = $field->getName();
|
||||||
|
if (isset($fields[$name])) {
|
||||||
|
$this->fieldNameError($field, __FUNCTION__);
|
||||||
|
}
|
||||||
|
$fields[$name] = $field;
|
||||||
|
});
|
||||||
|
$this->sequentialSaveableSet = $fields;
|
||||||
}
|
}
|
||||||
return $this->sequentialSaveableSet;
|
return $this->sequentialSaveableSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return array of all field names
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function dataFieldNames()
|
||||||
|
{
|
||||||
|
return array_keys($this->dataFields());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger an error for duplicate field names
|
||||||
|
*
|
||||||
|
* @param FormField $field
|
||||||
|
* @param $functionName
|
||||||
|
*/
|
||||||
|
protected function fieldNameError(FormField $field, $functionName)
|
||||||
|
{
|
||||||
|
if ($this->form) {
|
||||||
|
$errorSuffix = sprintf(
|
||||||
|
" in your '%s' form called '%s'",
|
||||||
|
get_class($this->form),
|
||||||
|
$this->form->getName()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$errorSuffix = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
user_error(
|
||||||
|
sprintf(
|
||||||
|
"%s() I noticed that a field called '%s' appears twice%s",
|
||||||
|
$functionName,
|
||||||
|
$field->getName(),
|
||||||
|
$errorSuffix
|
||||||
|
),
|
||||||
|
E_USER_ERROR
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
protected function flushFieldsCache()
|
protected function flushFieldsCache()
|
||||||
{
|
{
|
||||||
$this->sequentialSet = null;
|
$this->sequentialSet = null;
|
||||||
$this->sequentialSaveableSet = null;
|
$this->sequentialSaveableSet = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated 4.1..5.0 Please use dataFields or saveableFields
|
||||||
|
* @param $list
|
||||||
|
* @param bool $saveableOnly
|
||||||
|
*/
|
||||||
protected function collateDataFields(&$list, $saveableOnly = false)
|
protected function collateDataFields(&$list, $saveableOnly = false)
|
||||||
{
|
{
|
||||||
|
Deprecation::notice('5.0', 'Please use dataFields or SaveableFields');
|
||||||
if (!isset($list)) {
|
if (!isset($list)) {
|
||||||
$list = array();
|
$list = array();
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,10 @@
|
|||||||
namespace SilverStripe\Forms\Tests;
|
namespace SilverStripe\Forms\Tests;
|
||||||
|
|
||||||
use SilverStripe\Dev\SapphireTest;
|
use SilverStripe\Dev\SapphireTest;
|
||||||
|
use SilverStripe\Forms\ConfirmedPasswordField;
|
||||||
use SilverStripe\Forms\FieldList;
|
use SilverStripe\Forms\FieldList;
|
||||||
|
use SilverStripe\Forms\FormField;
|
||||||
|
use SilverStripe\Forms\LiteralField;
|
||||||
use SilverStripe\Forms\Tab;
|
use SilverStripe\Forms\Tab;
|
||||||
use SilverStripe\Forms\TextField;
|
use SilverStripe\Forms\TextField;
|
||||||
use SilverStripe\Forms\EmailField;
|
use SilverStripe\Forms\EmailField;
|
||||||
@ -32,6 +35,90 @@ use SilverStripe\Forms\HiddenField;
|
|||||||
*/
|
*/
|
||||||
class FieldListTest extends SapphireTest
|
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.
|
* Test adding a field to a tab in a set.
|
||||||
|
Loading…
Reference in New Issue
Block a user