mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 12:05:37 +00:00
FEATURE Added ForeignKey and used it in relation- and databasefield getters in DataObject
FEATURE Added FormScaffolder for more flexible scaffolding of FieldSets from DataObject metadata API CHANGE Removed DataObject->addScaffoldRelationFields(), now in separate class FormScaffolder API CHANGE Changed parameters for DataObject->scaffoldSearchFields() to unify them with scaffoldFormFields() API CHANGE Added optional $params parameter to DataObject->getCMSFields() to be passed on to scaffoldFormFields() API CHANGE Renamed DataObject->getFormFields() to getFrontEndFields() ENHANCEMENT Added $params parameter to all DBField->scaffoldFormField() subclasses API CHANGE Added third optional parameter $object to DBField::create() to comply with ForeignKey and PrimaryKey constructors git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@64157 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
parent
57a84d5408
commit
a24ccecb69
@ -1198,61 +1198,6 @@ class DataObject extends ViewableData implements DataObjectInterface {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the scaffold-generated relation fields to the given field set
|
||||
*/
|
||||
protected function addScaffoldRelationFields($fieldSet) {
|
||||
// make sure we have a tabset
|
||||
if(($this->has_many() || $this->many_many()) && !$fieldSet->fieldByName('Root')) {
|
||||
$oldFields = $fieldSet;
|
||||
$fieldSet = new FieldSet(new TabSet("Root", new Tab("Main")));
|
||||
foreach($oldFields as $field) {
|
||||
$fieldSet->addFieldToTab("Root.Main", $field);
|
||||
}
|
||||
}
|
||||
|
||||
if($this->has_many()) {
|
||||
// Add each relation as a separate tab
|
||||
foreach($this->has_many() as $relationship => $component) {
|
||||
$relationTab = $fieldSet->findOrMakeTab("Root.$relationship", $this->fieldLabel($relationship));
|
||||
$relationshipFields = singleton($component)->summaryFields();
|
||||
$foreignKey = $this->getComponentJoinField($relationship);
|
||||
$ctf = new ComplexTableField(
|
||||
$this,
|
||||
$relationship,
|
||||
$component,
|
||||
$relationshipFields,
|
||||
"getCMSFields",
|
||||
"$foreignKey = $this->ID"
|
||||
);
|
||||
$ctf->setPermissions(TableListField::permissions_for_object($component));
|
||||
$fieldSet->addFieldToTab("Root.$relationship", $ctf);
|
||||
}
|
||||
}
|
||||
if ($this->many_many()) {
|
||||
foreach($this->many_many() as $relationship => $component) {
|
||||
$relationTab = $fieldSet->findOrMakeTab("Root.$relationship", $this->fieldLabel($relationship));
|
||||
$relationshipFields = singleton($component)->summaryFields();
|
||||
$filterWhere = $this->getManyManyFilter($relationship, $component);
|
||||
$filterJoin = $this->getManyManyJoin($relationship, $component);
|
||||
$ctf = new ComplexTableField(
|
||||
$this,
|
||||
$relationship,
|
||||
$component,
|
||||
$relationshipFields,
|
||||
"getCMSFields",
|
||||
$filterWhere,
|
||||
'',
|
||||
$filterJoin
|
||||
);
|
||||
$ctf->setPermissions(TableListField::permissions_for_object($component));
|
||||
$ctf->popupClass = "ScaffoldingComplexTableField_Popup";
|
||||
$fieldSet->addFieldToTab("Root.$relationship", $ctf);
|
||||
}
|
||||
}
|
||||
return $fieldSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull out a join clause for a many-many relationship.
|
||||
*
|
||||
@ -1453,18 +1398,26 @@ class DataObject extends ViewableData implements DataObjectInterface {
|
||||
*
|
||||
* @usedby {@link SearchContext}
|
||||
*
|
||||
* @param array $restrictFields
|
||||
* @param array $fieldClasses
|
||||
* @param array $_params
|
||||
* 'fieldClasses': Associative array of field names as keys and FormField classes as values
|
||||
* 'restrictFields': Numeric array of a field name whitelist
|
||||
* @return FieldSet
|
||||
*/
|
||||
public function scaffoldSearchFields($restrictFields = null, $fieldClasses = null) {
|
||||
public function scaffoldSearchFields($_params = null) {
|
||||
$params = array_merge(
|
||||
array(
|
||||
'fieldClasses' => false,
|
||||
'restrictFields' => false
|
||||
),
|
||||
(array)$_params
|
||||
);
|
||||
$fields = new FieldSet();
|
||||
foreach($this->searchableFields() as $fieldName => $spec) {
|
||||
if($restrictFields && !in_array($fieldName, $restrictFields)) continue;
|
||||
if($params['restrictFields'] && !in_array($fieldName, $params['restrictFields'])) continue;
|
||||
|
||||
// If a custom fieldclass is provided as a string, use it
|
||||
if($fieldClasses && isset($fieldClasses[$fieldName])) {
|
||||
$fieldClass = $fieldClasses[$fieldName];
|
||||
if($params['fieldClasses'] && isset($params['fieldClasses'][$fieldName])) {
|
||||
$fieldClass = $params['fieldClasses'][$fieldName];
|
||||
$field = new $fieldClass($fieldName);
|
||||
// If we explicitly set a field, then construct that
|
||||
} else if(isset($spec['field'])) {
|
||||
@ -1502,65 +1455,33 @@ class DataObject extends ViewableData implements DataObjectInterface {
|
||||
* based on default {@link FormField} mapping in {@link DBField::scaffoldFormField()}.
|
||||
* Field labels/titles will be auto generated from {@link DataObject::fieldLabels()}.
|
||||
*
|
||||
* @uses DBField::scaffoldFormField()
|
||||
* @uses DataObject::fieldLabels()
|
||||
* @uses FormScaffolder
|
||||
*
|
||||
* @param
|
||||
* @param array $fieldClasses Optional mapping of fieldnames to subclasses of {@link DBField}
|
||||
* @param array $_params Associative array passing through properties to {@link FormScaffolder}.
|
||||
* @return FieldSet
|
||||
*/
|
||||
public function scaffoldFormFields($restrictFields = null, $fieldClasses = null) {
|
||||
$fields = new FieldSet();
|
||||
foreach($this->db() as $fieldName => $fieldType) {
|
||||
if($restrictFields && !in_array($fieldName, $restrictFields)) continue;
|
||||
|
||||
// @todo Pass localized title
|
||||
if(isset($fieldClasses[$fieldName])) {
|
||||
$fieldClass = $fieldClasses[$fieldName];
|
||||
$fieldObject = new $fieldClass($fieldName);
|
||||
} else {
|
||||
$fieldObject = $this->dbObject($fieldName)->scaffoldFormField();
|
||||
}
|
||||
$fieldObject->setTitle($this->fieldLabel($fieldName));
|
||||
$fields->push($fieldObject);
|
||||
}
|
||||
foreach($this->has_one() as $relationship => $component) {
|
||||
if($restrictFields && !in_array($relationship, $restrictFields)) continue;
|
||||
|
||||
$model = singleton($component);
|
||||
$records = DataObject::get($component);
|
||||
$collect = ($model->hasMethod('customSelectOption')) ? 'customSelectOption' : 'Title';
|
||||
$options = $records ? $records->filter_map('ID', $collect) : array();
|
||||
$fields->push(new DropdownField($relationship.'ID', $this->fieldLabel($relationship), $options));
|
||||
}
|
||||
return $fields;
|
||||
public function scaffoldFormFields($_params = null) {
|
||||
$params = array_merge(
|
||||
array(
|
||||
'tabbed' => false,
|
||||
'includeRelations' => false,
|
||||
'restrictFields' => false,
|
||||
'fieldClasses' => false,
|
||||
'ajaxSafe' => false
|
||||
),
|
||||
(array)$_params
|
||||
);
|
||||
|
||||
$fs = new FormScaffolder($this);
|
||||
$fs->tabbed = $params['tabbed'];
|
||||
$fs->includeRelations = $params['includeRelations'];
|
||||
$fs->restrictFields = $params['restrictFields'];
|
||||
$fs->fieldClasses = $params['fieldClasses'];
|
||||
$fs->ajaxSafe = $params['ajaxSafe'];
|
||||
|
||||
return $fs->getFieldSet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns automatically generated fields useable within the CMS.
|
||||
* Does not include relations, you can add them by using
|
||||
* {@link addScaffoldRelationFields()}. Call {@link getCMSFields()}
|
||||
* to get all fields including relational tables and decorated
|
||||
* fields in a TabSet.
|
||||
*
|
||||
* @uses getCMSFields()
|
||||
*
|
||||
* @return FieldSet Tabbed fields
|
||||
*/
|
||||
public function scaffoldCMSFields($restrictFields = null, $fieldClasses = null) {
|
||||
$untabbedFields = $this->scaffoldFormFields($restrictFields, $fieldClasses);
|
||||
|
||||
// make sure we have a tabset
|
||||
if(!$untabbedFields->hasTabSet()) {
|
||||
$tabbedFields = new FieldSet(new TabSet("Root", new Tab("Main")));
|
||||
foreach($untabbedFields as $field) {
|
||||
$tabbedFields->addFieldToTab("Root.Main", $field);
|
||||
}
|
||||
}
|
||||
|
||||
return $tabbedFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Centerpiece of every data administration interface in Silverstripe,
|
||||
* which returns a {@link FieldSet} suitable for a {@link Form} object.
|
||||
@ -1582,36 +1503,40 @@ class DataObject extends ViewableData implements DataObjectInterface {
|
||||
*
|
||||
* @see Good example of complex FormField building: SiteTree::getCMSFields()
|
||||
*
|
||||
* @param array $params See {@link scaffoldFormFields()}
|
||||
* @return FieldSet Returns a TabSet for usage within the CMS - don't use for frontend forms.
|
||||
*/
|
||||
public function getCMSFields() {
|
||||
// should be a plain FieldSet without tabs
|
||||
$tabbedFields = $this->scaffoldCMSFields();
|
||||
|
||||
// If we don't have an ID, then relation fields don't work
|
||||
if($this->ID) {
|
||||
$tabbedFields = $this->addScaffoldRelationFields($tabbedFields);
|
||||
}
|
||||
public function getCMSFields($params = null) {
|
||||
$tabbedFields = $this->scaffoldFormFields(array_merge(
|
||||
array(
|
||||
'includeRelations' => true,
|
||||
'tabbed' => true,
|
||||
'ajaxSafe' => true
|
||||
),
|
||||
(array)$params
|
||||
));
|
||||
|
||||
$this->extend('updateCMSFields', $tabbedFields);
|
||||
|
||||
return $tabbedFields;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Used for simple frontend forms without relation editing
|
||||
* or {@link TabSet} behaviour. Uses {@link scaffoldFormFields()}
|
||||
* by default. To customize, either overload this method in your
|
||||
* subclass, or decorate it by {@link DataObjectDecorator->updateFormFields()}.
|
||||
*
|
||||
* @todo Decide on naming for "website|frontend|site|page" and stick with it in the API
|
||||
*
|
||||
* @param array $params See {@link scaffoldFormFields()}
|
||||
* @return FieldSet Always returns a simple field collection without TabSet.
|
||||
*/
|
||||
public function getFormFields() {
|
||||
$fields = $this->scaffoldFormFields();
|
||||
$this->extend('updateFormFields', $fields);
|
||||
public function getFrontEndFields($params = null) {
|
||||
$untabbedFields = $this->scaffoldFormFields($params);
|
||||
$this->extend('updateFormFields', $untabbedFields);
|
||||
|
||||
return $fields;
|
||||
return $untabbedFields;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1827,7 +1752,7 @@ class DataObject extends ViewableData implements DataObjectInterface {
|
||||
// add foreign key
|
||||
$hasOne = $this->uninherited('has_one', true);
|
||||
if($hasOne) foreach($hasOne as $fieldName => $fieldSchema) {
|
||||
$fieldMap[$fieldName . 'ID'] = "Int";
|
||||
$fieldMap[$fieldName . 'ID'] = "ForeignKey";
|
||||
}
|
||||
|
||||
// set cached fieldmap
|
||||
@ -1995,7 +1920,8 @@ class DataObject extends ViewableData implements DataObjectInterface {
|
||||
|
||||
// Special case for has_one relationships
|
||||
} else if(preg_match('/ID$/', $fieldName) && $this->has_one(substr($fieldName,0,-2))) {
|
||||
return DBField::create('Int', $this->record[$fieldName], $fieldName);
|
||||
$val = (isset($this->record[$fieldName])) ? $this->record[$fieldName] : null;
|
||||
return DBField::create('ForeignKey', $val, $fieldName, $this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2515,7 +2441,7 @@ class DataObject extends ViewableData implements DataObjectInterface {
|
||||
$def = $db;
|
||||
if($has_one) {
|
||||
foreach($has_one as $field => $joinTo) {
|
||||
$def[$field . 'ID'] = "Int";
|
||||
$def[$field . 'ID'] = "ForeignKey";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,7 @@ class Boolean extends DBField {
|
||||
}
|
||||
}
|
||||
|
||||
public function scaffoldFormField($title = null) {
|
||||
public function scaffoldFormField($title = null, $params = null) {
|
||||
return new CheckboxField($this->name, $title);
|
||||
}
|
||||
|
||||
|
@ -45,8 +45,8 @@ abstract class DBField extends ViewableData {
|
||||
* Create a DBField object that's not bound to any particular field.
|
||||
* Useful for accessing the classes behaviour for other parts of your code.
|
||||
*/
|
||||
static function create($className, $value, $name = null) {
|
||||
$dbField = Object::create($className, $name);
|
||||
static function create($className, $value, $name = null, $object = null) {
|
||||
$dbField = Object::create($className, $name, $object);
|
||||
$dbField->setValue($value);
|
||||
return $dbField;
|
||||
}
|
||||
|
@ -236,7 +236,7 @@ class Date extends DBField {
|
||||
}
|
||||
}
|
||||
|
||||
public function scaffoldFormField($title = null) {
|
||||
public function scaffoldFormField($title = null, $params = null) {
|
||||
return new DateField($this->name, $title);
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ if(!class_exists('Datetime')) {
|
||||
DB::requireField($this->tableName, $this->name, "datetime");
|
||||
}
|
||||
|
||||
public function scaffoldFormField($title = null) {
|
||||
public function scaffoldFormField($title = null, $params = null) {
|
||||
return new PopupDateTimeField($this->name, $title);
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ class Decimal extends DBField {
|
||||
}
|
||||
}
|
||||
|
||||
public function scaffoldFormField($title = null) {
|
||||
public function scaffoldFormField($title = null, $params = null) {
|
||||
return new NumericField($this->name, $title);
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@ class Enum extends DBField {
|
||||
}
|
||||
|
||||
|
||||
public function scaffoldFormField($title = null) {
|
||||
public function scaffoldFormField($title = null, $params = null) {
|
||||
return $this->formField($title);
|
||||
}
|
||||
|
||||
|
52
core/model/fieldtypes/ForeignKey.php
Normal file
52
core/model/fieldtypes/ForeignKey.php
Normal file
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
/**
|
||||
* A special type Int field used for foreign keys in has_one relationships.
|
||||
*
|
||||
* @param string $name
|
||||
* @param DataOject $object The object that the foreign key is stored on (should have a relation with $name)
|
||||
*
|
||||
* @package sapphire
|
||||
* @subpackage model
|
||||
*/
|
||||
class ForeignKey extends Int {
|
||||
|
||||
/**
|
||||
* @var DataObject
|
||||
*/
|
||||
protected $object;
|
||||
|
||||
protected static $default_search_filter_class = 'ExactMatchMultiFilter';
|
||||
|
||||
function __construct($name, $object) {
|
||||
$this->object = $object;
|
||||
parent::__construct($name);
|
||||
}
|
||||
|
||||
public function scaffoldFormField($title = null, $params = null) {
|
||||
$relationName = substr($this->name,0,-2);
|
||||
$hasOneClass = $this->object->has_one($relationName);
|
||||
|
||||
if($hasOneClass && singleton($hasOneClass) instanceof Image) {
|
||||
if(isset($params['ajax']) && $params['ajax']) {
|
||||
$field = new ImageField($relationName, $title, $this->value);
|
||||
} else {
|
||||
$field = new SimpleImageField($relationName, $title, $this->value);
|
||||
}
|
||||
} elseif($hasOneClass && singleton($hasOneClass) instanceof File) {
|
||||
if(isset($params['ajax']) && $params['ajax']) {
|
||||
$field = new FileIframeField($relationName, $title, $this->value);
|
||||
} else {
|
||||
$field = new FileField($relationName, $title, $this->value);
|
||||
}
|
||||
} else {
|
||||
$objs = DataObject::get($this->object->class);
|
||||
$titleField = (singleton($this->object->class)->hasField('Title')) ? "Title" : "Name";
|
||||
$map = ($objs) ? $objs->toDropdownMap("ID", $titleField) : false;
|
||||
$field = new DropdownField($this->name, $title, $map, null, null, ' ');
|
||||
}
|
||||
|
||||
return $field;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -65,7 +65,7 @@ class HTMLText extends Text {
|
||||
return $summary;
|
||||
}
|
||||
|
||||
public function scaffoldFormField($title = null) {
|
||||
public function scaffoldFormField($title = null, $params = null) {
|
||||
return new HtmlEditorField($this->name, $title);
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
*/
|
||||
class HTMLVarchar extends Varchar {
|
||||
|
||||
public function scaffoldFormField($title = null) {
|
||||
public function scaffoldFormField($title = null, $params = null) {
|
||||
return new HtmlOneLineField($this->name, $title);
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ class Int extends DBField {
|
||||
return sprintf( '%d', $this->value );
|
||||
}
|
||||
|
||||
public function scaffoldFormField($title = null) {
|
||||
public function scaffoldFormField($title = null, $params = null) {
|
||||
return new NumericField($this->name, $title);
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@ class PrimaryKey extends Int {
|
||||
parent::__construct($name);
|
||||
}
|
||||
|
||||
public function scaffoldFormField($title = null) {
|
||||
public function scaffoldFormField($title = null, $params = null) {
|
||||
$objs = DataObject::get($this->object->class);
|
||||
|
||||
$titleField = (singleton($this->object->class)->hasField('Title')) ? "Title" : "Name";
|
||||
|
@ -34,7 +34,7 @@ class SSDatetime extends Date {
|
||||
return date('Y-m-d%20H:i:s', strtotime($this->value));
|
||||
}
|
||||
|
||||
public function scaffoldFormField($title = null) {
|
||||
public function scaffoldFormField($title = null, $params = null) {
|
||||
return new PopupDateTimeField($this->name, $title);
|
||||
}
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ class Time extends DBField {
|
||||
DB::requireField($this->tableName, $this->name, "time");
|
||||
}
|
||||
|
||||
public function scaffoldFormField($title = null) {
|
||||
public function scaffoldFormField($title = null, $params = null) {
|
||||
return new TimeField($this->name, $title);
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ class Year extends DBField {
|
||||
DB::requireField($this->tableName, $this->name, "year(4)");
|
||||
}
|
||||
|
||||
public function scaffoldFormField($title = null) {
|
||||
public function scaffoldFormField($title = null, $params = null) {
|
||||
$selectBox = new DropdownField($this->name, $title);
|
||||
$selectBox->setSource($this->getDefaultOptions());
|
||||
return $selectBox;
|
||||
|
187
forms/FormScaffolder.php
Normal file
187
forms/FormScaffolder.php
Normal file
@ -0,0 +1,187 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* @package sapphire
|
||||
* @subpackage forms
|
||||
*
|
||||
* @uses DBField::scaffoldFormField()
|
||||
* @uses DataObject::fieldLabels()
|
||||
*/
|
||||
class FormScaffolder extends Object {
|
||||
|
||||
/**
|
||||
* @var DataObject $obj The object defining the fields to be scaffolded
|
||||
* through its metadata like $db, $searchable_fields, etc.
|
||||
*/
|
||||
protected $obj;
|
||||
|
||||
/**
|
||||
* @var boolean $tabbed Return fields in a tabset, with all main fields in the path "Root.Main",
|
||||
* relation fields in "Root.<relationname>" (if {@link $includeRelations} is enabled).
|
||||
*/
|
||||
public $tabbed = false;
|
||||
|
||||
/**
|
||||
* @var boolean $ajaxSafe
|
||||
*/
|
||||
public $ajaxSafe = false;
|
||||
|
||||
/**
|
||||
* @var array $restrictFields Numeric array of a field name whitelist.
|
||||
* If left blank, all fields from {@link DataObject->db()} will be included.
|
||||
*
|
||||
* @todo Implement restrictions for has_many and many_many relations.
|
||||
*/
|
||||
public $restrictFields;
|
||||
|
||||
/**
|
||||
* @var array $fieldClasses Optional mapping of fieldnames to subclasses of {@link FormField}.
|
||||
* By default the scaffolder will determine the field instance by {@link DBField::scaffoldFormField()}.
|
||||
*
|
||||
* @todo Implement fieldClasses for has_many and many_many relations
|
||||
*/
|
||||
public $fieldClasses;
|
||||
|
||||
/**
|
||||
* @var boolean $includeRelations Include has_one, has_many and many_many relations
|
||||
*/
|
||||
public $includeRelations = false;
|
||||
|
||||
/**
|
||||
* @param DataObject $obj
|
||||
* @param array $params
|
||||
*/
|
||||
function __construct($obj) {
|
||||
$this->obj = $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the form fields as defined through the metadata
|
||||
* on {@link $obj} and the custom parameters passed to FormScaffolder.
|
||||
* Depending on those parameters, the fields can be used in ajax-context,
|
||||
* contain {@link TabSet}s etc.
|
||||
*
|
||||
* @return FieldSet
|
||||
*/
|
||||
public function getFieldSet() {
|
||||
$fields = new FieldSet();
|
||||
|
||||
// tabbed or untabbed
|
||||
if($this->tabbed) $fields->push(new TabSet("Root", new Tab("Main")));
|
||||
|
||||
// add database fields
|
||||
foreach($this->obj->db() as $fieldName => $fieldType) {
|
||||
if($this->restrictFields && !in_array($fieldName, $this->restrictFields)) continue;
|
||||
|
||||
// @todo Pass localized title
|
||||
if($this->fieldClasses && isset($this->fieldClasses[$fieldName])) {
|
||||
$fieldClass = $this->fieldClasses[$fieldName];
|
||||
$fieldObject = new $fieldClass($fieldName);
|
||||
} else {
|
||||
$fieldObject = $this->obj->dbObject($fieldName)->scaffoldFormField(null, $this->getParamsArray());
|
||||
}
|
||||
$fieldObject->setTitle($this->obj->fieldLabel($fieldName));
|
||||
if($this->tabbed) {
|
||||
$fields->addFieldToTab("Root.Main", $fieldObject);
|
||||
} else {
|
||||
$fields->push($fieldObject);
|
||||
}
|
||||
}
|
||||
|
||||
// add has_one relation fields
|
||||
if($this->obj->has_one() && ($this->includeRelations === true || isset($this->includeRelations['has_one']))) {
|
||||
foreach($this->obj->has_one() as $relationship => $component) {
|
||||
if($this->restrictFields && !in_array($relationship, $this->restrictFields)) continue;
|
||||
$hasOneField = $this->obj->dbObject("{$relationship}ID")->scaffoldFormField(null, $this->getParamsArray());
|
||||
if($this->tabbed) {
|
||||
$fields->addFieldToTab("Root.Main", $hasOneField);
|
||||
} else {
|
||||
$fields->push($hasOneField);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// only add relational fields if an ID is present
|
||||
if($this->obj->ID) {
|
||||
// add has_many relation fields
|
||||
if($this->obj->has_many() && ($this->includeRelations === true || isset($this->includeRelations['has_many']))) {
|
||||
foreach($this->obj->has_many() as $relationship => $component) {
|
||||
if($this->tabbed) {
|
||||
$relationTab = $fields->findOrMakeTab(
|
||||
"Root.$relationship",
|
||||
$this->obj->fieldLabel($relationship)
|
||||
);
|
||||
}
|
||||
$relationshipFields = singleton($component)->summaryFields();
|
||||
$foreignKey = $this->obj->getComponentJoinField($relationship);
|
||||
$ctf = new ComplexTableField(
|
||||
$this,
|
||||
$relationship,
|
||||
$component,
|
||||
$relationshipFields,
|
||||
"getCMSFields",
|
||||
"$foreignKey = $this->obj->ID"
|
||||
);
|
||||
$ctf->setPermissions(TableListField::permissions_for_object($component));
|
||||
if($this->tabbed) {
|
||||
$fields->addFieldToTab("Root.$relationship", $ctf);
|
||||
} else {
|
||||
$fields->push($ctf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($this->obj->many_many() && ($this->includeRelations === true || isset($this->includeRelations['many_many']))) {
|
||||
foreach($this->obj->many_many() as $relationship => $component) {
|
||||
if($this->tabbed) {
|
||||
$relationTab = $fields->findOrMakeTab(
|
||||
"Root.$relationship",
|
||||
$this->obj->fieldLabel($relationship)
|
||||
);
|
||||
}
|
||||
|
||||
$relationshipFields = singleton($component)->summaryFields();
|
||||
$filterWhere = $this->obj->getManyManyFilter($relationship, $component);
|
||||
$filterJoin = $this->obj->getManyManyJoin($relationship, $component);
|
||||
$ctf = new ComplexTableField(
|
||||
$this,
|
||||
$relationship,
|
||||
$component,
|
||||
$relationshipFields,
|
||||
"getCMSFields",
|
||||
$filterWhere,
|
||||
'',
|
||||
$filterJoin
|
||||
);
|
||||
$ctf->setPermissions(TableListField::permissions_for_object($component));
|
||||
$ctf->popupClass = "ScaffoldingComplexTableField_Popup";
|
||||
if($this->tabbed) {
|
||||
$fields->addFieldToTab("Root.$relationship", $ctf);
|
||||
} else {
|
||||
$fields->push($ctf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array suitable for passing on to {@link DBField->scaffoldFormField()}
|
||||
* without tying this call to a FormScaffolder interface.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getParamsArray() {
|
||||
return array(
|
||||
'tabbed' => $this->tabbed,
|
||||
'includeRelations' => $this->includeRelations,
|
||||
'restrictFields' => $this->restrictFields,
|
||||
'fieldClasses' => $this->fieldClasses,
|
||||
'ajaxSafe' => $this->ajaxSafe
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
110
tests/forms/FormScaffolderTest.php
Normal file
110
tests/forms/FormScaffolderTest.php
Normal file
@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Tests for DataObject FormField scaffolding
|
||||
*
|
||||
* @package sapphire
|
||||
* @subpackage tests
|
||||
*
|
||||
*/
|
||||
class FormScaffolderTest extends SapphireTest {
|
||||
|
||||
static $fixture_file = 'sapphire/tests/forms/FormScaffolderTest.yml';
|
||||
|
||||
function testGetCMSFieldsSingleton() {
|
||||
$fields = singleton('FormScaffolderTest_Article')->getCMSFields();
|
||||
$this->assertTrue($fields->hasTabSet(), 'getCMSFields() produces a TabSet');
|
||||
$this->assertNotNull($fields->dataFieldByName('Title'), 'getCMSFields() includes db fields');
|
||||
$this->assertNotNull($fields->dataFieldByName('Content'), 'getCMSFields() includes db fields');
|
||||
$this->assertNotNull($fields->dataFieldByName('AuthorID'), 'getCMSFields() includes has_one fields on singletons');
|
||||
$this->assertNull($fields->dataFieldByName('Tags'), 'getCMSFields() doesnt include many_many fields if no ID is present');
|
||||
}
|
||||
|
||||
function testGetCMSFieldsInstance() {
|
||||
$article1 = $this->objFromFixture('FormScaffolderTest_Article', 'article1');
|
||||
$fields = $article1->getCMSFields();
|
||||
$this->assertNotNull($fields->dataFieldByName('AuthorID'), 'getCMSFields() includes has_one fields on instances');
|
||||
$this->assertNotNull($fields->dataFieldByName('Tags'), 'getCMSFields() includes many_many fields if ID is present on instances');
|
||||
}
|
||||
|
||||
function testUpdateCMSFields() {
|
||||
$article1 = $this->objFromFixture('FormScaffolderTest_Article', 'article1');
|
||||
$fields = $article1->getCMSFields();
|
||||
$this->assertNotNull(
|
||||
$fields->dataFieldByName('AddedDecoratorField'),
|
||||
'getCMSFields() includes decorated fields'
|
||||
);
|
||||
}
|
||||
|
||||
function testRestrictCMSFields() {
|
||||
$article1 = $this->objFromFixture('FormScaffolderTest_Article', 'article1');
|
||||
$fields = $article1->scaffoldFormFields(array(
|
||||
'restrictFields' => array('Title')
|
||||
));
|
||||
$this->assertNotNull($fields->dataFieldByName('Title'), 'scaffoldCMSFields() includes explitly defined "restrictFields"');
|
||||
$this->assertNull($fields->dataFieldByName('Content'), 'getCMSFields() doesnt include fields left out in a "restrictFields" definition');
|
||||
}
|
||||
|
||||
function testFieldClassesOnGetCMSFields() {
|
||||
$article1 = $this->objFromFixture('FormScaffolderTest_Article', 'article1');
|
||||
$fields = $article1->scaffoldFormFields(array(
|
||||
'fieldClasses' => array('Title' => 'HtmlEditorField')
|
||||
));
|
||||
$this->assertNotNull(
|
||||
$fields->dataFieldByName('Title')
|
||||
);
|
||||
$this->assertEquals(
|
||||
get_class($fields->dataFieldByName('Title')),
|
||||
'HtmlEditorField',
|
||||
'getCMSFields() doesnt include fields left out in a "restrictFields" definition'
|
||||
);
|
||||
}
|
||||
|
||||
function testGetFormFields() {
|
||||
$fields = singleton('FormScaffolderTest_Article')->getFrontEndFields();
|
||||
$this->assertFalse($fields->hasTabSet(), 'getFrontEndFields() doesnt produce a TabSet by default');
|
||||
}
|
||||
}
|
||||
|
||||
class FormScaffolderTest_Article extends DataObject implements TestOnly {
|
||||
static $db = array(
|
||||
'Title' => 'Varchar',
|
||||
'Content' => 'HTMLText'
|
||||
);
|
||||
static $has_one = array(
|
||||
'Author' => 'FormScaffolderTest_Author'
|
||||
);
|
||||
static $many_many = array(
|
||||
'Tags' => 'FormScaffolderTest_Tag',
|
||||
);
|
||||
}
|
||||
|
||||
class FormScaffolderTest_Author extends Member implements TestOnly {
|
||||
static $has_one = array(
|
||||
'ProfileImage' => 'Image'
|
||||
);
|
||||
static $has_many = array(
|
||||
'Articles' => 'FormScaffolderTest_Article'
|
||||
);
|
||||
}
|
||||
class FormScaffolderTest_Tag extends DataObject implements TestOnly {
|
||||
static $db = array(
|
||||
'Title' => 'Varchar',
|
||||
);
|
||||
static $belongs_many_many = array(
|
||||
'Articles' => 'FormScaffolderTest_Article'
|
||||
);
|
||||
}
|
||||
class FormScaffolderTest_ArticleDecorator extends DataObjectDecorator implements TestOnly {
|
||||
static $db = array(
|
||||
'DecoratedField' => 'Varchar'
|
||||
);
|
||||
function updateCMSFields(&$fields) {
|
||||
$fields->addFieldToTab('Root.Main',
|
||||
new TextField('AddedDecoratorField')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
DataObject::add_extension('FormScaffolderTest_Article', 'FormScaffolderTest_ArticleDecorator');
|
||||
?>
|
12
tests/forms/FormScaffolderTest.yml
Normal file
12
tests/forms/FormScaffolderTest.yml
Normal file
@ -0,0 +1,12 @@
|
||||
FormScaffolderTest_Tag:
|
||||
tag1:
|
||||
Title: Tag 1
|
||||
FormScaffolderTest_Article:
|
||||
article1:
|
||||
Title: Article 1
|
||||
Content: Test
|
||||
Tags: =>FormScaffolderTest_Tag.tag1
|
||||
FormScaffolderTest_Author:
|
||||
author1:
|
||||
FirstName: Author 1
|
||||
Tags: =>FormScaffolderTest_Article.article1
|
Loading…
x
Reference in New Issue
Block a user