ENHANCEMENT: Refactored TableListField and subclasses to rely on the DataList to handle data manipulatation.

API CHANGE: A DataList can be passed as the 2nd argument to the constructor; this is the recommended approach for editing non-relations.
API CHANGE: You can't set a custom query; only a custom DataList.
API CHANGE: You can't have one of these fields editing data that doesn't correspond to a DataList - there must be some kind of DataObject behind it.
API CHANGE: If the field's name corresponds to a relation on the object being edited, then the relation is used as the data set - all the source* parameters are ignored.
API CHANGE: relationAutoSetting only works if your form has had the corresponding data object loaded with $form->loadDataFrom().
API CHANGE: relationAutoSetting can't be turned off; attach a non-relation DataList instead.
This commit is contained in:
Sam Minnee 2009-11-22 19:07:45 +13:00
parent 165f38361b
commit 319d2f4952
9 changed files with 136 additions and 300 deletions

View File

@ -104,12 +104,15 @@ class MemberTableField extends ComplexTableField {
} }
if($this->group) { if($this->group) {
user_error("MemberTableField's group setting doesn't yet work in the new-orm branch", E_USER_WARNING);
/*
$groupIDs = array($this->group->ID); $groupIDs = array($this->group->ID);
if($this->group->AllChildren()) $groupIDs = array_merge($groupIDs, $this->group->AllChildren()->column('ID')); if($this->group->AllChildren()) $groupIDs = array_merge($groupIDs, $this->group->AllChildren()->column('ID'));
$this->sourceFilter[] = sprintf( $this->sourceFilter[] = sprintf(
'"Group_Members"."GroupID" IN (%s)', '"Group_Members"."GroupID" IN (%s)',
implode(',', $groupIDs) implode(',', $groupIDs)
); );
*/
} }
$this->sourceJoin = " INNER JOIN \"Group_Members\" ON \"MemberID\"=\"Member\".\"ID\""; $this->sourceJoin = " INNER JOIN \"Group_Members\" ON \"MemberID\"=\"Member\".\"ID\"";

View File

@ -39,7 +39,7 @@ class ComplexTableField extends TableListField {
protected $detailFormFields; protected $detailFormFields;
protected $viewAction, $sourceJoin, $sourceItems; protected $viewAction;
/** /**
* @var Controller * @var Controller
@ -119,14 +119,6 @@ class ComplexTableField extends TableListField {
*/ */
protected $detailFormValidator = null; protected $detailFormValidator = null;
/**
* Automatically detect a has-one relationship
* in the popup (=child-class) and save the relation ID.
*
* @var boolean
*/
protected $relationAutoSetting = true;
/** /**
* Default size for the popup box * Default size for the popup box
*/ */
@ -210,31 +202,6 @@ class ComplexTableField extends TableListField {
parent::__construct($name, $sourceClass, $fieldList, $sourceFilter, $sourceSort, $sourceJoin); parent::__construct($name, $sourceClass, $fieldList, $sourceFilter, $sourceSort, $sourceJoin);
} }
/**
* Return the record filter for this table.
* It will automatically add a relation filter if relationAutoSetting is true, and it can determine an appropriate
* filter.
*/
function sourceFilter() {
$sourceFilter = parent::sourceFilter();
if($this->relationAutoSetting
&& $this->getParentClass()
&& ($filterKey = $this->getParentIdName($this->getParentClass(), $this->sourceClass()))
&& ($filterValue = $this->sourceID()) ) {
$newFilter = "\"$filterKey\" = '" . Convert::raw2sql($filterValue) . "'";
if($sourceFilter && is_array($sourceFilter)) {
// Note that the brackets below are taken into account when building this
$sourceFilter = implode(") AND (", $sourceFilter);
}
$sourceFilter = $sourceFilter ? "($sourceFilter) AND ($newFilter)" : $newFilter;
}
return $sourceFilter;
}
function isComposite() { function isComposite() {
return false; return false;
} }
@ -277,26 +244,22 @@ JS;
return $this->renderWith($this->template); return $this->renderWith($this->template);
} }
function sourceClass() {
return $this->sourceClass;
}
/** /**
* @return DataObjectSet * @return DataObjectSet
*/ */
function Items() { function Items() {
$this->sourceItems = $this->sourceItems(); $sourceItems = $this->sourceItems();
if(!$this->sourceItems) { if(!$sourceItems) {
return null; return null;
} }
$pageStart = (isset($_REQUEST['ctf'][$this->Name()]['start']) && is_numeric($_REQUEST['ctf'][$this->Name()]['start'])) ? $_REQUEST['ctf'][$this->Name()]['start'] : 0; $pageStart = (isset($_REQUEST['ctf'][$this->Name()]['start']) && is_numeric($_REQUEST['ctf'][$this->Name()]['start'])) ? $_REQUEST['ctf'][$this->Name()]['start'] : 0;
$this->sourceItems->setPageLimits($pageStart, $this->pageSize, $this->totalCount); $sourceItems->setPageLimits($pageStart, $this->pageSize, $this->totalCount);
$output = new DataObjectSet(); $output = new DataObjectSet();
foreach($this->sourceItems as $pageIndex=>$item) { foreach($sourceItems as $pageIndex=>$item) {
$output->push(new $this->itemClass($item, $this)); $output->push(Object::create($this->itemClass,$item, $this, $pageStart+$pageIndex));
} }
return $output; return $output;
} }
@ -548,26 +511,11 @@ JS;
if($this->getParentClass()) { if($this->getParentClass()) {
$detailFields->push(new HiddenField('ctf[parentClass]', '', $this->getParentClass())); $detailFields->push(new HiddenField('ctf[parentClass]', '', $this->getParentClass()));
if($manyManyRelationName && $this->relationAutoSetting) { // Hack for model admin: model admin will have included a dropdown for the relation itself
$detailFields->push(new HiddenField('ctf[manyManyRelation]', '', $manyManyRelationName));
}
if($hasManyRelationName && $this->relationAutoSetting) {
$detailFields->push(new HiddenField('ctf[hasManyRelation]', '', $hasManyRelationName));
}
if($manyManyRelationName || $hasManyRelationName) {
$detailFields->push(new HiddenField('ctf[sourceID]', '', $this->sourceID()));
}
$parentIdName = $this->getParentIdName($this->getParentClass(), $this->sourceClass()); $parentIdName = $this->getParentIdName($this->getParentClass(), $this->sourceClass());
if($parentIdName) { if($parentIdName) {
if($this->relationAutoSetting) { $detailFields->removeByName($parentIdName);
// Hack for model admin: model admin will have included a dropdown for the relation itself $detailFields->push(new HiddenField($parentIdName, '', $this->sourceID()));
$detailFields->removeByName($parentIdName);
$detailFields->push(new HiddenField($parentIdName, '', $this->sourceID()));
}
} }
} }
@ -614,16 +562,10 @@ JS;
} }
/** /**
* By default, a ComplexTableField will assume that the field name is the name of a has-many relation on the object being * @deprecated
* edited. It will identify the foreign key in the object being listed, and filter on that column, as well as auto-setting
* that column for newly created records.
*
* Calling $this->setRelationAutoSetting(false) will disable this functionality.
*
* @param boolean $value Should the relation auto-setting functionality be enabled?
*/ */
function setRelationAutoSetting($value) { function setRelationAutoSetting($value) {
$this->relationAutoSetting = $value; user_error("ComplexTableField::setRelationAutoSetting() is deprecated; manipulate the DataList instead", E_USER_WARNING);
} }
/** /**
@ -648,21 +590,8 @@ JS;
return Director::redirectBack(); return Director::redirectBack();
} }
// Save the many many relationship if it's available // Save this item into the given relationship
if(isset($data['ctf']['manyManyRelation'])) { $this->getDataList()->add($childData);
$parentRecord = DataObject::get_by_id($data['ctf']['parentClass'], (int) $data['ctf']['sourceID']);
$relationName = $data['ctf']['manyManyRelation'];
$componentSet = $parentRecord ? $parentRecord->getManyManyComponents($relationName) : null;
if($componentSet) $componentSet->add($childData);
}
if(isset($data['ctf']['hasManyRelation'])) {
$parentRecord = DataObject::get_by_id($data['ctf']['parentClass'], (int) $data['ctf']['sourceID']);
$relationName = $data['ctf']['hasManyRelation'];
$componentSet = $parentRecord ? $parentRecord->getComponents($relationName) : null;
if($componentSet) $componentSet->add($childData);
}
$referrer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null; $referrer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null;
@ -831,13 +760,8 @@ class ComplexTableField_ItemRequest extends TableListField_ItemRequest {
return Director::redirectBack(); return Director::redirectBack();
} }
// Save the many many relationship if it's available // Save this item into the given relationship
if(isset($data['ctf']['manyManyRelation'])) { $this->ctf->getDataList()->add($childData);
$parentRecord = DataObject::get_by_id($data['ctf']['parentClass'], (int) $data['ctf']['sourceID']);
$relationName = $data['ctf']['manyManyRelation'];
$componentSet = $parentRecord->getManyManyComponents($relationName);
$componentSet->add($dataObject);
}
$referrer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null; $referrer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null;

View File

@ -118,14 +118,12 @@ class FormScaffolder extends Object {
); );
} }
$relationshipFields = singleton($component)->summaryFields(); $relationshipFields = singleton($component)->summaryFields();
$foreignKey = $this->obj->getRemoteJoinField($relationship);
$ctf = new ComplexTableField( $ctf = new ComplexTableField(
$this, $this,
$relationship, $relationship,
$component, null,
$relationshipFields, $relationshipFields,
"getCMSFields", "getCMSFields"
"\"$foreignKey\" = " . $this->obj->ID
); );
$ctf->setPermissions(TableListField::permissions_for_object($component)); $ctf->setPermissions(TableListField::permissions_for_object($component));
if($this->tabbed) { if($this->tabbed) {
@ -146,17 +144,12 @@ class FormScaffolder extends Object {
} }
$relationshipFields = singleton($component)->summaryFields(); $relationshipFields = singleton($component)->summaryFields();
$filterWhere = $this->obj->getManyManyFilter($relationship, $component);
$filterJoin = $this->obj->getManyManyJoin($relationship, $component);
$ctf = new ComplexTableField( $ctf = new ComplexTableField(
$this, $this,
$relationship, $relationship,
$component, null,
$relationshipFields, $relationshipFields,
"getCMSFields", "getCMSFields"
$filterWhere,
'',
$filterJoin
); );
$ctf->setPermissions(TableListField::permissions_for_object($component)); $ctf->setPermissions(TableListField::permissions_for_object($component));
$ctf->popupClass = "ScaffoldingComplexTableField_Popup"; $ctf->popupClass = "ScaffoldingComplexTableField_Popup";

View File

@ -28,10 +28,6 @@
class TableField extends TableListField { class TableField extends TableListField {
protected $sourceClass;
protected $sourceFilter;
protected $fieldList; protected $fieldList;
/** /**
@ -53,10 +49,6 @@ class TableField extends TableListField {
*/ */
protected $fieldTypes; protected $fieldTypes;
protected $sourceSort;
protected $sourceJoin;
/** /**
* @var $template string Template-Overrides * @var $template string Template-Overrides
*/ */
@ -105,8 +97,6 @@ class TableField extends TableListField {
* *
* @var boolean * @var boolean
*/ */
protected $relationAutoSetting = true;
function __construct($name, $sourceClass, $fieldList = null, $fieldTypes, $filterField = null, function __construct($name, $sourceClass, $fieldList = null, $fieldTypes, $filterField = null,
$sourceFilter = null, $editExisting = true, $sourceSort = null, $sourceJoin = null) { $sourceFilter = null, $editExisting = true, $sourceSort = null, $sourceJoin = null) {
@ -174,6 +164,9 @@ class TableField extends TableListField {
$rows = $this->sortData(ArrayLib::invert($this->value)); $rows = $this->sortData(ArrayLib::invert($this->value));
// ignore all rows which are already saved // ignore all rows which are already saved
if(isset($rows['new'])) { if(isset($rows['new'])) {
if($sourceItems instanceof DataList) $sourceItems = $sourceItems->toDataObjectSet();
$newRows = $this->sortData($rows['new']); $newRows = $this->sortData($rows['new']);
// iterate over each value (not each row) // iterate over each value (not each row)
$i = 0; $i = 0;
@ -189,7 +182,7 @@ class TableField extends TableListField {
} }
// generate a temporary DataObject container (not saved in the database) // generate a temporary DataObject container (not saved in the database)
$sourceClass = $this->sourceClass; $sourceClass = $this->sourceClass();
$sourceItems->push(new $sourceClass($newRow)); $sourceItems->push(new $sourceClass($newRow));
$i++; $i++;
@ -264,16 +257,9 @@ class TableField extends TableListField {
$savedObjIds = $this->saveData($newFields,false); $savedObjIds = $this->saveData($newFields,false);
} }
// Optionally save the newly created records into a relationship // Add the new records to the DataList
// on $record. This assumes the name of this formfield instance if($savedObjIds) foreach($savedObjIds as $id => $status) {
// is set to a relationship name on $record. $this->getDataList()->add($id);
if($this->relationAutoSetting) {
$relationName = $this->Name();
if($record->has_many($relationName) || $record->many_many($relationName)) {
if($savedObjIds) foreach($savedObjIds as $id => $status) {
$record->$relationName()->add($id);
}
}
} }
// Update the internal source items cache // Update the internal source items cache
@ -386,9 +372,9 @@ class TableField extends TableListField {
// either look for an existing object, or create a new one // either look for an existing object, or create a new one
if($existingValues) { if($existingValues) {
$obj = DataObject::get_by_id($this->sourceClass, $objectid); $obj = DataObject::get_by_id($this->sourceClass(), $objectid);
} else { } else {
$sourceClass = $this->sourceClass; $sourceClass = $this->sourceClass();
$obj = new $sourceClass(); $obj = new $sourceClass();
} }
@ -491,13 +477,6 @@ class TableField extends TableListField {
return $this->renderWith($this->template); return $this->renderWith($this->template);
} }
/**
* @return Int
*/
function sourceID() {
return $this->filterField;
}
function setTransformationConditions($conditions) { function setTransformationConditions($conditions) {
$this->transformationConditions = $conditions; $this->transformationConditions = $conditions;
} }
@ -601,20 +580,6 @@ JS;
function setRequiredFields($fields) { function setRequiredFields($fields) {
$this->requiredFields = $fields; $this->requiredFields = $fields;
} }
/**
* @param boolean $value
*/
function setRelationAutoSetting($value) {
$this->relationAutoSetting = $value;
}
/**
* @return boolean
*/
function getRelationAutoSetting() {
return $this->relationAutoSetting;
}
} }
/** /**

View File

@ -21,19 +21,10 @@
* @subpackage fields-relational * @subpackage fields-relational
*/ */
class TableListField extends FormField { class TableListField extends FormField {
/** /**
* @var $cachedSourceItems DataObjectSet Prevent {@sourceItems()} from being called multiple times. * The {@link DataList} object defining the source data for this view/
*/ */
protected $cachedSourceItems; protected $dataList;
protected $sourceClass;
protected $sourceFilter = "";
protected $sourceSort = "";
protected $sourceJoin = array();
protected $fieldList; protected $fieldList;
@ -138,14 +129,6 @@ class TableListField extends FormField {
*/ */
public $defaultAction = ''; public $defaultAction = '';
/**
* @var $customQuery Specify custom query, e.g. for complicated having/groupby-constructs.
* Caution: TableListField automatically selects the ID from the {@sourceClass}, because it relies
* on this information e.g. in saving a TableField. Please use a custom select if you want to filter
* for other IDs in joined tables: $query->select[] = "MyJoinedTable.ID AS MyJoinedTableID"
*/
protected $customQuery;
/** /**
* @var $customCsvQuery Query for CSV-export (might need different fields or further filtering) * @var $customCsvQuery Query for CSV-export (might need different fields or further filtering)
*/ */
@ -257,26 +240,27 @@ class TableListField extends FormField {
protected $__cachedQuery; protected $__cachedQuery;
function __construct($name, $sourceClass, $fieldList = null, $sourceFilter = null, function __construct($name, $sourceClass = null, $fieldList = null, $sourceFilter = null,
$sourceSort = null, $sourceJoin = null) { $sourceSort = null, $sourceJoin = null) {
$this->fieldList = ($fieldList) ? $fieldList : singleton($sourceClass)->summaryFields(); $this->fieldList = ($fieldList) ? $fieldList : singleton($sourceClass)->summaryFields();
$this->sourceClass = $sourceClass;
$this->sourceFilter = $sourceFilter; if($sourceClass) {
$this->sourceSort = $sourceSort; // You can optionally pass a DataList as the 2nd argument to the constructor
$this->sourceJoin = $sourceJoin; if($sourceClass instanceof DataList) {
$this->dataList = $sourceClass;
} else {
$this->dataList = DataObject::get($sourceClass)->filter($sourceFilter)
->sort($sourceSort)->join($sourceJoin);
}
}
$this->readOnly = false; $this->readOnly = false;
parent::__construct($name); parent::__construct($name);
} }
/**
* Get the filter
*/
function sourceFilter() {
return $this->sourceFilter;
}
function index() { function index() {
return $this->FieldHolder(); return $this->FieldHolder();
} }
@ -287,7 +271,7 @@ class TableListField extends FormField {
); );
function sourceClass() { function sourceClass() {
return $this->sourceClass; return $this->getDataList()->dataClass();
} }
function handleItem($request) { function handleItem($request) {
@ -351,7 +335,7 @@ JS
$headings[] = new ArrayData(array( $headings[] = new ArrayData(array(
"Name" => $fieldName, "Name" => $fieldName,
"Title" => ($this->sourceClass) ? singleton($this->sourceClass)->fieldLabel($fieldTitle) : $fieldTitle, "Title" => ($this->sourceClass()) ? singleton($this->sourceClass())->fieldLabel($fieldTitle) : $fieldTitle,
"IsSortable" => $isSortable, "IsSortable" => $isSortable,
"SortLink" => $sortLink, "SortLink" => $sortLink,
"SortBy" => $isSorted, "SortBy" => $isSorted,
@ -403,27 +387,16 @@ JS
/** /**
* Provide a custom query to compute sourceItems. This is the preferred way to using * Provide a custom query to compute sourceItems. This is the preferred way to using
* {@setSourceItems}, because we can still paginate. * {@setSourceItems}, because we can still paginate.
* Caution: Other parameters such as {@sourceFilter} will be ignored.
* Please use this only as a fallback for really complex queries (e.g. involving HAVING and GROUPBY). * Please use this only as a fallback for really complex queries (e.g. involving HAVING and GROUPBY).
* *
* @param $query SS_Query * @param $query DataList
*/ */
function setCustomQuery(SQLQuery $query) { function setCustomQuery(DataList $dataList) {
// The type-hinting above doesn't seem to work consistently $this->dataList = $dataList;
if($query instanceof SQLQuery) {
$this->customQuery = $query;
} else {
user_error('TableList::setCustomQuery() should be passed a SQLQuery', E_USER_WARNING);
}
} }
function setCustomCsvQuery(SQLQuery $query) { function setCustomCsvQuery(DataList $dataList) {
// The type-hinting above doesn't seem to work consistently $this->customCsvQuery = $query;
if($query instanceof SQLQuery) {
$this->customCsvQuery = $query;
} else {
user_error('TableList::setCustomCsvQuery() should be passed a SQLQuery', E_USER_WARNING);
}
} }
function setCustomSourceItems(DataObjectSet $items) { function setCustomSourceItems(DataObjectSet $items) {
@ -436,45 +409,43 @@ JS
} }
function sourceItems() { function sourceItems() {
// Determine pagination limit, offset
$SQL_limit = ($this->showPagination && $this->pageSize) ? "{$this->pageSize}" : null; $SQL_limit = ($this->showPagination && $this->pageSize) ? "{$this->pageSize}" : null;
if(isset($_REQUEST['ctf'][$this->Name()]['start']) && is_numeric($_REQUEST['ctf'][$this->Name()]['start'])) { if(isset($_REQUEST['ctf'][$this->Name()]['start']) && is_numeric($_REQUEST['ctf'][$this->Name()]['start'])) {
$SQL_start = (isset($_REQUEST['ctf'][$this->Name()]['start'])) ? intval($_REQUEST['ctf'][$this->Name()]['start']) : "0"; $SQL_start = (isset($_REQUEST['ctf'][$this->Name()]['start'])) ? intval($_REQUEST['ctf'][$this->Name()]['start']) : "0";
} else { } else {
$SQL_start = 0; $SQL_start = 0;
} }
// Custom source items can be explicitly passed
if(isset($this->customSourceItems)) { if(isset($this->customSourceItems)) {
if($this->showPagination && $this->pageSize) { if($this->showPagination && $this->pageSize) {
$items = $this->customSourceItems->getRange($SQL_start, $SQL_limit); $items = $this->customSourceItems->getRange($SQL_start, $SQL_limit);
} else { } else {
$items = $this->customSourceItems; $items = $this->customSourceItems;
} }
} elseif(isset($this->cachedSourceItems)) {
$items = $this->cachedSourceItems; // Otherwise we use the internal data list
} else { } else {
// get query // get the DataList of items
$dataQuery = $this->getQuery(); $items = $this->getDataList();
// we don't limit when doing certain actions T // we don't limit when doing certain actions T
$methodName = isset($_REQUEST['url']) ? array_pop(explode('/', $_REQUEST['url'])) : null; $methodName = isset($_REQUEST['url']) ? array_pop(explode('/', $_REQUEST['url'])) : null;
if(!$methodName || !in_array($methodName,array('printall','export'))) { if(!$methodName || !in_array($methodName,array('printall','export'))) {
$dataQuery->limit(array( $items->limit(array(
'limit' => $SQL_limit, 'limit' => $SQL_limit,
'start' => (isset($SQL_start)) ? $SQL_start : null 'start' => (isset($SQL_start)) ? $SQL_start : null
)); ));
} }
// get data
$records = $dataQuery->execute();
$sourceClass = $this->sourceClass;
$dataobject = new $sourceClass();
$items = $dataobject->buildDataObjectSet($records, 'DataObjectSet');
$this->cachedSourceItems = $items;
} }
return $items; return $items;
} }
/**
* Return a DataObjectSet of TableListField_Item objects, suitable for display in the template.
*/
function Items() { function Items() {
$fieldItems = new DataObjectSet(); $fieldItems = new DataObjectSet();
if($items = $this->sourceItems()) foreach($items as $item) { if($items = $this->sourceItems()) foreach($items as $item) {
@ -484,16 +455,19 @@ JS
} }
/** /**
* Generates the query for sourceitems (without pagination/limit-clause) * Returns the DataList for this field.
*
* @return string
*/ */
function getQuery() { function getDataList() {
if($this->customQuery) { // Load the data from the form
$query = clone $this->customQuery; // Note that this will override any specific. This is so that explicitly-passed sets of
$baseClass = ClassInfo::baseDataClass($this->sourceClass); // parameters that represent a relation can be replaced with the relation itself. This is
} else { // a little clumsy and won't work if people have used a field name that is the same as a
$query = singleton($this->sourceClass)->extendedSQL($this->sourceFilter(), $this->sourceSort, null, $this->sourceJoin); // relation but have specified alternative parameters.
if($this->form) {
$relation = $this->name;
if($record = $this->form->getRecord()) {
if($record->hasMethod($relation)) $this->dataList = $record->$relation();
}
} }
if(!$this->dataList) { if(!$this->dataList) {
@ -513,18 +487,26 @@ JS
if($query->canSortBy($column)) $query->orderby = $column.' '.$dir; if($query->canSortBy($column)) $query->orderby = $column.' '.$dir;
} }
return $query; return $dl;
} }
function getCsvQuery() { function getCsvDataList() {
$baseClass = ClassInfo::baseDataClass($this->sourceClass); if($this->customCsvQuery) return $this->customCsvQuery;
if($this->customCsvQuery || $this->customQuery) { else return $this->getDataList();
$query = $this->customCsvQuery ? $this->customCsvQuery : $this->customQuery; }
} else {
$query = singleton($this->sourceClass)->extendedSQL($this->sourceFilter(), $this->sourceSort, null, $this->sourceJoin);
}
return clone $query; /**
* @deprecated Use getDataList() instead.
*/
function getQuery() {
return $this->getDataList()->dataQuery()->query();
}
/**
* @deprecated Use getCsvDataList() instead.
*/
function getCsvQuery() {
return $this->getCsvDataList()->dataQuery()->query();
} }
function FieldList() { function FieldList() {
@ -580,7 +562,7 @@ JS
$childId = Convert::raw2sql($_REQUEST['ctf']['childID']); $childId = Convert::raw2sql($_REQUEST['ctf']['childID']);
if (is_numeric($childId)) { if (is_numeric($childId)) {
$childObject = DataObject::get_by_id($this->sourceClass, $childId); $childObject = DataObject::get_by_id($this->sourceClass(), $childId);
if($childObject) $childObject->delete(); if($childObject) $childObject->delete();
} }
@ -903,19 +885,10 @@ JS
} }
function TotalCount() { function TotalCount() {
if($this->totalCount) { return $this->getDataList()->Count();
return $this->totalCount;
}
if($this->customSourceItems) {
return $this->customSourceItems->Count();
}
$this->totalCount = $this->getQuery()->unlimitedRowCount();
return $this->totalCount;
} }
/** /**
* ################################# * #################################
* Search * Search
@ -1158,19 +1131,19 @@ JS
// adding this to TODO probably add a method to the classes // adding this to TODO probably add a method to the classes
// to return they're translated string // to return they're translated string
// added by ruibarreiros @ 27/11/2007 // added by ruibarreiros @ 27/11/2007
return $this->sourceClass ? singleton($this->sourceClass)->singular_name() : $this->Name(); return $this->sourceClass() ? singleton($this->sourceClass())->singular_name() : $this->Name();
} }
function NameSingular() { function NameSingular() {
// same as Title() // same as Title()
// added by ruibarreiros @ 27/11/2007 // added by ruibarreiros @ 27/11/2007
return $this->sourceClass ? singleton($this->sourceClass)->singular_name() : $this->Name(); return $this->sourceClass() ? singleton($this->sourceClass())->singular_name() : $this->Name();
} }
function NamePlural() { function NamePlural() {
// same as Title() // same as Title()
// added by ruibarreiros @ 27/11/2007 // added by ruibarreiros @ 27/11/2007
return $this->sourceClass ? singleton($this->sourceClass)->plural_name() : $this->Name(); return $this->sourceClass() ? singleton($this->sourceClass())->plural_name() : $this->Name();
} }
function setTemplate($template) { function setTemplate($template) {

View File

@ -118,6 +118,7 @@ class ComplexTableFieldTest_Controller extends Controller {
new FormAction('doSubmit', 'Submit') new FormAction('doSubmit', 'Submit')
) )
); );
$form->loadDataFrom($team);
$form->disableSecurityToken(); $form->disableSecurityToken();
@ -148,6 +149,7 @@ class ComplexTableFieldTest_Controller extends Controller {
new FormAction('doSubmit', 'Submit') new FormAction('doSubmit', 'Submit')
) )
); );
$form->loadDataFrom($team);
$form->disableSecurityToken(); $form->disableSecurityToken();

View File

@ -6,6 +6,7 @@ ComplexTableFieldTest_Player:
ComplexTableFieldTest_Team: ComplexTableFieldTest_Team:
t1: t1:
Name: The Awesome People Name: The Awesome People
Players: =>ComplexTableFieldTest_Player.p1,=>ComplexTableFieldTest_Player.p2
t2: t2:
Name: Incredible Four Name: Incredible Four
ComplexTableFieldTest_Sponsor: ComplexTableFieldTest_Sponsor:

View File

@ -20,6 +20,9 @@ class FormScaffolderTest extends SapphireTest {
function testGetCMSFieldsSingleton() { function testGetCMSFieldsSingleton() {
$fields = singleton('FormScaffolderTest_Article')->getCMSFields(); $fields = singleton('FormScaffolderTest_Article')->getCMSFields();
$form = new Form(new Controller(), 'TestForm', $fields, new FieldSet());
$form->loadDataFrom(singleton('FormScaffolderTest_Article'));
$this->assertTrue($fields->hasTabSet(), 'getCMSFields() produces a TabSet'); $this->assertTrue($fields->hasTabSet(), 'getCMSFields() produces a TabSet');
$this->assertNotNull($fields->dataFieldByName('Title'), 'getCMSFields() includes db fields'); $this->assertNotNull($fields->dataFieldByName('Title'), 'getCMSFields() includes db fields');
$this->assertNotNull($fields->dataFieldByName('Content'), 'getCMSFields() includes db fields'); $this->assertNotNull($fields->dataFieldByName('Content'), 'getCMSFields() includes db fields');
@ -29,14 +32,22 @@ class FormScaffolderTest extends SapphireTest {
function testGetCMSFieldsInstance() { function testGetCMSFieldsInstance() {
$article1 = $this->objFromFixture('FormScaffolderTest_Article', 'article1'); $article1 = $this->objFromFixture('FormScaffolderTest_Article', 'article1');
$fields = $article1->getCMSFields(); $fields = $article1->getCMSFields();
$form = new Form(new Controller(), 'TestForm', $fields, new FieldSet());
$form->loadDataFrom($article1);
$this->assertNotNull($fields->dataFieldByName('AuthorID'), 'getCMSFields() includes has_one fields on instances'); $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'); $this->assertNotNull($fields->dataFieldByName('Tags'), 'getCMSFields() includes many_many fields if ID is present on instances');
} }
function testUpdateCMSFields() { function testUpdateCMSFields() {
$article1 = $this->objFromFixture('FormScaffolderTest_Article', 'article1'); $article1 = $this->objFromFixture('FormScaffolderTest_Article', 'article1');
$fields = $article1->getCMSFields(); $fields = $article1->getCMSFields();
$form = new Form(new Controller(), 'TestForm', $fields, new FieldSet());
$form->loadDataFrom($article1);
$this->assertNotNull( $this->assertNotNull(
$fields->dataFieldByName('AddedExtensionField'), $fields->dataFieldByName('AddedExtensionField'),
'getCMSFields() includes extended fields' 'getCMSFields() includes extended fields'
@ -45,18 +56,26 @@ class FormScaffolderTest extends SapphireTest {
function testRestrictCMSFields() { function testRestrictCMSFields() {
$article1 = $this->objFromFixture('FormScaffolderTest_Article', 'article1'); $article1 = $this->objFromFixture('FormScaffolderTest_Article', 'article1');
$fields = $article1->scaffoldFormFields(array( $fields = $article1->scaffoldFormFields(array(
'restrictFields' => array('Title') 'restrictFields' => array('Title')
)); ));
$form = new Form(new Controller(), 'TestForm', $fields, new FieldSet());
$form->loadDataFrom($article1);
$this->assertNotNull($fields->dataFieldByName('Title'), 'scaffoldCMSFields() includes explitly defined "restrictFields"'); $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'); $this->assertNull($fields->dataFieldByName('Content'), 'getCMSFields() doesnt include fields left out in a "restrictFields" definition');
} }
function testFieldClassesOnGetCMSFields() { function testFieldClassesOnGetCMSFields() {
$article1 = $this->objFromFixture('FormScaffolderTest_Article', 'article1'); $article1 = $this->objFromFixture('FormScaffolderTest_Article', 'article1');
$fields = $article1->scaffoldFormFields(array( $fields = $article1->scaffoldFormFields(array(
'fieldClasses' => array('Title' => 'HtmlEditorField') 'fieldClasses' => array('Title' => 'HtmlEditorField')
)); ));
$form = new Form(new Controller(), 'TestForm', $fields, new FieldSet());
$form->loadDataFrom($article1);
$this->assertNotNull( $this->assertNotNull(
$fields->dataFieldByName('Title') $fields->dataFieldByName('Title')
); );
@ -69,6 +88,9 @@ class FormScaffolderTest extends SapphireTest {
function testGetFormFields() { function testGetFormFields() {
$fields = singleton('FormScaffolderTest_Article')->getFrontEndFields(); $fields = singleton('FormScaffolderTest_Article')->getFrontEndFields();
$form = new Form(new Controller(), 'TestForm', $fields, new FieldSet());
$form->loadDataFrom(singleton('FormScaffolderTest_Article'));
$this->assertFalse($fields->hasTabSet(), 'getFrontEndFields() doesnt produce a TabSet by default'); $this->assertFalse($fields->hasTabSet(), 'getFrontEndFields() doesnt produce a TabSet by default');
} }
} }

View File

@ -166,7 +166,13 @@ class TableFieldTest extends SapphireTest {
$this->assertNotContains($perm1->ID, $tableField->sourceItems()->column('ID')); $this->assertNotContains($perm1->ID, $tableField->sourceItems()->column('ID'));
} }
/**
* Relation auto-setting is now the only option
*/
function testAutoRelationSettingOn() { function testAutoRelationSettingOn() {
$o = new TableFieldTest_Object();
$o->write();
$tf = new TableField( $tf = new TableField(
'HasManyRelations', 'HasManyRelations',
'TableFieldTest_HasManyRelation', 'TableFieldTest_HasManyRelation',
@ -180,69 +186,16 @@ class TableFieldTest extends SapphireTest {
// Test with auto relation setting // Test with auto relation setting
$form = new Form(new TableFieldTest_Controller(), "Form", new FieldSet($tf), new FieldSet()); $form = new Form(new TableFieldTest_Controller(), "Form", new FieldSet($tf), new FieldSet());
$form->loadDataFrom($o);
$tf->setValue(array( $tf->setValue(array(
'new' => array( 'new' => array(
'Value' => array('one','two',) 'Value' => array('one','two',)
) )
)); ));
$tf->setRelationAutoSetting(true);
$o = new TableFieldTest_Object();
$o->write();
$form->saveInto($o); $form->saveInto($o);
$this->assertEquals($o->HasManyRelations()->Count(), 2); $this->assertEquals(2, $o->HasManyRelations()->Count());
}
function testAutoRelationSettingOff() {
$tf = new TableField(
'HasManyRelations',
'TableFieldTest_HasManyRelation',
array(
'Value' => 'Value'
),
array(
'Value' => 'TextField'
)
);
// Test with auto relation setting
$form = new Form(new TableFieldTest_Controller(), "Form", new FieldSet($tf), new FieldSet());
$tf->setValue(array(
'new' => array(
'Value' => array('one','two',)
)
));
$tf->setRelationAutoSetting(false);
$o = new TableFieldTest_Object();
$o->write();
$form->saveInto($o);
$this->assertEquals($o->HasManyRelations()->Count(), 0);
}
function testDataValue() {
$tf = new TableField(
'TestTableField',
'TestTableField',
array(
'Currency' => 'Currency'
),
array(
'Currency' => 'CurrencyField'
)
);
$form = new Form(new TableFieldTest_Controller(), "Form", new FieldSet($tf), new FieldSet());
$tf->setValue(array(
'new' => array(
'Currency' => array(
'$1,234.56',
'1234.57',
)
)
));
$data = $form->getData();
// @todo Fix getData()
//$this->assertEquals($data['TestTableField']['new']['Currency'][0], 1234.56);
//$this->assertEquals($data['TestTableField']['new']['Currency'][1], 1234.57);
} }
function testHasItemsWhenSetAsArray() { function testHasItemsWhenSetAsArray() {