Skip to content

Commit

Permalink
API Support composite react formfields
Browse files Browse the repository at this point in the history
Cleanup and standardise CompositeField API and subclasses
  • Loading branch information
Damian Mooyman committed Jul 15, 2016
1 parent d19955a commit 9e1b12a
Show file tree
Hide file tree
Showing 10 changed files with 315 additions and 177 deletions.
148 changes: 89 additions & 59 deletions forms/CompositeField.php
Expand Up @@ -57,10 +57,24 @@ public function __construct($children = null) {
}
$this->children->setContainerField($this);

// Skipping FormField::__construct(), but we have to make sure this
// doesn't count as a broken constructor
$this->brokenOnConstruct = false;
Object::__construct();
parent::__construct(null, false);
}

/**
* Merge child field data into this form
*/
public function getSchemaDataDefaults() {
$defaults = parent::getSchemaDataDefaults();
$children = $this->getChildren();
if($children && $children->count()) {
$childSchema = [];
/** @var FormField $child */
foreach($children as $child) {
$childSchema[] = $child->getSchemaData();
}
$defaults['children'] = $childSchema;
}
return $defaults;
}

/**
Expand All @@ -72,11 +86,6 @@ public function FieldList() {
return $this->children;
}

public function setID($id) {
$this->id = $id;
return $this;
}

/**
* Accessor method for $this->children
*
Expand All @@ -88,14 +97,16 @@ public function getChildren() {

/**
* @param FieldList $children
* @return $this
*/
public function setChildren($children) {
$this->children = $children;
return $this;
}

/**
* @param string
* @param string $tag
* @return $this
*/
public function setTag($tag) {
$this->tag = $tag;
Expand All @@ -111,7 +122,8 @@ public function getTag() {
}

/**
* @param string
* @param string $legend
* @return $this
*/
public function setLegend($legend) {
$this->legend = $legend;
Expand Down Expand Up @@ -147,7 +159,6 @@ public function getAttributes() {
'tabindex' => null,
'type' => null,
'value' => null,
'type' => null,
'title' => ($this->tag == 'fieldset') ? null : $this->legend
)
);
Expand All @@ -158,38 +169,46 @@ public function getAttributes() {
* list.
*
* Sequentialisation is used when connecting the form to its data source
*
* @param array $list
* @param bool $saveableOnly
*/
public function collateDataFields(&$list, $saveableOnly = false) {
foreach($this->children as $field) {
if(is_object($field)) {
if($field->isComposite()) $field->collateDataFields($list, $saveableOnly);
if($saveableOnly) {
$isIncluded = ($field->hasData() && !$field->isReadonly() && !$field->isDisabled());
} else {
$isIncluded = ($field->hasData());
}
if($isIncluded) {
$name = $field->getName();
if($name) {
$formName = (isset($this->form)) ? $this->form->FormName() : '(unknown form)';
if(isset($list[$name])) {
user_error("collateDataFields() I noticed that a field called '$name' appears twice in"
. " your form: '{$formName}'. One is a '{$field->class}' and the other is a"
. " '{$list[$name]->class}'", E_USER_ERROR);
}
$list[$name] = $field;
if(! $field instanceof FormField) {
continue;
}
if($field instanceof CompositeField) {
$field->collateDataFields($list, $saveableOnly);
}
if($saveableOnly) {
$isIncluded = ($field->hasData() && !$field->isReadonly() && !$field->isDisabled());
} else {
$isIncluded = ($field->hasData());
}
if($isIncluded) {
$name = $field->getName();
if($name) {
$formName = (isset($this->form)) ? $this->form->FormName() : '(unknown form)';
if(isset($list[$name])) {
user_error("collateDataFields() I noticed that a field called '$name' appears twice in"
. " your form: '{$formName}'. One is a '{$field->class}' and the other is a"
. " '{$list[$name]->class}'", E_USER_ERROR);
}
$list[$name] = $field;
}
}
}
}

public function setForm($form) {
foreach($this->children as $f)
if(is_object($f)) $f->setForm($form);
foreach($this->children as $field) {
if ($field instanceof FormField) {
$field->setForm($form);
}
}

parent::setForm($form);

return $this;
}

Expand Down Expand Up @@ -234,20 +253,23 @@ public function unshift(FormField $field) {

/**
* @uses FieldList->insertBefore()
*
* @param string $insertBefore
* @param FormField $field
* @return false|FormField
*/
public function insertBefore($insertBefore, $field) {
$ret = $this->children->insertBefore($insertBefore, $field);
$this->sequentialSet = null;
return $ret;
return $this->children->insertBefore($insertBefore, $field);
}

/**
* @uses FieldList->insertAfter()
* @param string $insertAfter
* @param FormField $field
* @return false|FormField
*/
public function insertAfter($insertAfter, $field) {
$ret = $this->children->insertAfter($insertAfter, $field);
$this->sequentialSet = null;
return $ret;
return $this->children->insertAfter($insertAfter, $field);
}

/**
Expand Down Expand Up @@ -281,9 +303,10 @@ public function rootFieldList() {
public function performReadonlyTransformation() {
$newChildren = new FieldList();
$clone = clone $this;
if($clone->getChildren()) foreach($clone->getChildren() as $idx => $child) {
if(is_object($child)) $child = $child->transform(new ReadonlyTransformation());
$newChildren->push($child, $idx);
if($clone->getChildren()) foreach($clone->getChildren() as $child) {
/** @var FormField $child */
$child = $child->transform(new ReadonlyTransformation());
$newChildren->push($child);
}

$clone->children = $newChildren;
Expand All @@ -303,9 +326,10 @@ public function performReadonlyTransformation() {
public function performDisabledTransformation() {
$newChildren = new FieldList();
$clone = clone $this;
if($clone->getChildren()) foreach($clone->getChildren() as $idx => $child) {
if(is_object($child)) $child = $child->transform(new DisabledTransformation());
$newChildren->push($child, $idx);
if($clone->getChildren()) foreach($clone->getChildren() as $child) {
/** @var FormField $child */
$child = $child->transform(new DisabledTransformation());
$newChildren->push($child);
}

$clone->children = $newChildren;
Expand All @@ -332,12 +356,19 @@ public function IsReadonly() {
* be found.
*/
public function fieldPosition($field) {
if(is_string($field)) $field = $this->fieldByName($field);
if(!$field) return false;
if(is_string($field)) {
$field = $this->fieldByName($field);
}
if(!$field) {
return false;
}

$i = 0;
foreach($this->children as $child) {
if($child->getName() == $field->getName()) return $i;
/** @var FormField $child */
if($child->getName() == $field->getName()) {
return $i;
}
$i++;
}

Expand All @@ -348,25 +379,23 @@ public function fieldPosition($field) {
* Transform the named field into a readonly feld.
*
* @param string|FormField
* @return bool
*/
public function makeFieldReadonly($field) {
$fieldName = ($field instanceof FormField) ? $field->getName() : $field;

// Iterate on items, looking for the applicable field
foreach($this->children as $i => $item) {
if($item->isComposite()) {
$item->makeFieldReadonly($fieldName);
} else {
if($item instanceof CompositeField) {
if($item->makeFieldReadonly($fieldName)) {
return true;
};
} elseif($item instanceof FormField && $item->getName() == $fieldName) {
// Once it's found, use FormField::transform to turn the field into a readonly version of itself.
if($item->getName() == $fieldName) {
$this->children->replaceField($fieldName, $item->transform(new ReadonlyTransformation()));
$this->children->replaceField($fieldName, $item->transform(new ReadonlyTransformation()));

// Clear an internal cache
$this->sequentialSet = null;

// A true results indicates that the field was found
return true;
}
// A true results indicates that the field was found
return true;
}
}
return false;
Expand All @@ -389,7 +418,8 @@ public function debug() {
*/
public function validate($validator) {
$valid = true;
foreach($this->children as $idx => $child){
foreach($this->children as $child){
/** @var FormField $child */
$valid = ($child && $child->validate($validator) && $valid);
}
return $valid;
Expand Down
44 changes: 32 additions & 12 deletions forms/FieldGroup.php
Expand Up @@ -59,33 +59,56 @@ class FieldGroup extends CompositeField {

protected $zebra;

public function __construct($arg1 = null, $arg2 = null) {
if(is_array($arg1) || is_a($arg1, 'FieldSet')) {
$fields = $arg1;
/**
* Create a new field group.
*
* Accepts any number of arguments.
*
* @param mixed $titleOrField Either the field title, list of fields, or first field
* @param mixed ...$otherFields Subsequent fields or field list (if passing in title to $titleOrField)
*/
public function __construct($titleOrField = null, $otherFields = null) {
$title = null;
if(is_array($titleOrField) || $titleOrField instanceof FieldList) {
$fields = $titleOrField;

// This would be discarded otherwise
if($otherFields) {
throw new InvalidArgumentException(
'$otherFields is not accepted if passing in field list to $titleOrField'
);
}

} else if(is_array($arg2) || is_a($arg2, 'FieldList')) {
$this->title = $arg1;
$fields = $arg2;
} else if(is_array($otherFields) || $otherFields instanceof FieldList) {
$title = $titleOrField;
$fields = $otherFields;

} else {
$fields = func_get_args();
if(!is_object(reset($fields))) $this->title = array_shift($fields);
if(!is_object(reset($fields))) {
$title = array_shift($fields);
}
}

parent::__construct($fields);

if($title) {
$this->setTitle($title);
}
}

/**
* Returns the name (ID) for the element.
* In some cases the FieldGroup doesn't have a title, but we still want
* the ID / name to be set. This code, generates the ID from the nested children
*/
public function Name(){
public function getName(){
if(!$this->title) {
$fs = $this->FieldList();
$compositeTitle = '';
$count = 0;
foreach($fs as $subfield){
/** @var FormField $subfield */
$compositeTitle .= $subfield->getName();
if($subfield->getName()) $count++;
}
Expand All @@ -101,6 +124,7 @@ public function Name(){
* Set an odd/even class
*
* @param string $zebra one of odd or even.
* @return $this
*/
public function setZebra($zebra) {
if($zebra == 'odd' || $zebra == 'even') $this->zebra = $zebra;
Expand Down Expand Up @@ -142,8 +166,4 @@ public function MessageType() {

return (isset($MessageType)) ? implode(". ", $MessageType) : "";
}

public function php($data) {
return;
}
}
1 change: 0 additions & 1 deletion forms/FieldList.php
Expand Up @@ -651,7 +651,6 @@ public function getTabPathRewrites() {
* @return String Rewritten path, based on {@link tabPathRewrites}
*/
protected function rewriteTabPath($name) {
$isRunningTest = (class_exists('SapphireTest', false) && SapphireTest::is_running_test());
foreach($this->getTabPathRewrites() as $regex => $replace) {
if(preg_match($regex, $name)) {
$newName = preg_replace($regex, $replace, $name);
Expand Down

0 comments on commit 9e1b12a

Please sign in to comment.