diff --git a/forms/ComplexTableField.php b/forms/ComplexTableField.php index d9b05662a..6659403d6 100755 --- a/forms/ComplexTableField.php +++ b/forms/ComplexTableField.php @@ -4,22 +4,22 @@ * Provides a tabuar list in your form with view, edit and add links to edit records * with a "has-one"-relationship. Detail-views are shown in a greybox-iframe. * Features pagination in the overview as well as the detail-views. - * - * CAUTION: You need to make sure that the original form-call to the main controller (e.g. EditForm()) - * returns a form which includes this field even if no data is loaded, + * + * CAUTION: You need to make sure that the original form-call to the main controller (e.g. EditForm()) + * returns a form which includes this field even if no data is loaded, * to provide a "starting point" for action_callfieldmethod and ReferencedField. - * + * * All URL data sent to and from ComplexTableField is encapsulated in $_REQUEST['ctf'] * to avoid side-effects with the main controller. - * + * * Example-URL for a "DetailForm"-call explained: * "/admin/family/?executeForm=EditForm&action_callfieldmethod&fieldName=Individual&childID=7&methodName=edit" * - executeForm Name of the form on the main rendering page (e.g. "FamilyAdmin") * - action_callfieldmethod Trigger to call a method of a single field in "EditForm" instead of rendering the whole thing * - fieldName Name of the targeted formField * - methodName Method on the formfield (e.g. "ComplexTableField") - * - childID Identifier of the database-record (the targeted table is determined by the $sourceClass parameter) - * + * - childID Identifier of the database-record (the targeted table is determined by the $sourceClass parameter) + * * TODO Find a less fragile solution for accessing this field through the main controller and ReferencedField, e.g. * build a seperate CTF-instance (doesn't necessarly have to be connected to the original by ReferencedField) * TODO Control width/height of popup by constructor (hardcoded at the moment) @@ -28,19 +28,19 @@ * TODO Use automatic has-many and many-many functions to return a ComponentSet rather than building the join manually */ class ComplexTableField extends TableListField { - + protected $detailFormFields, $viewAction, $sourceJoin, $sourceItems, $unpagedSourceItems; - + /** * @var Controller */ protected $controller; - + /** * @var string Classname of the parent-relation to correctly link new records. */ protected $parentClass; - + /** * @var array Influence output without having to subclass the template. */ @@ -58,9 +58,9 @@ class ComplexTableField extends TableListField { * Template-Overrides */ protected $template = "ComplexTableField"; - + protected $templatePopup = "ComplexTableField_popup"; - + /** * @var boolean Trigger pagination (defaults to true for ComplexTableField) */ @@ -71,7 +71,7 @@ class ComplexTableField extends TableListField { * This is set by javascript and used by greybox. */ protected $popupCaption = null; - + /** * @var $detailFormValidator Validator */ @@ -93,7 +93,7 @@ class ComplexTableField extends TableListField { $this->detailFormFields = $detailFormFields; $this->controller = $controller; $this->pageSize = 10; - + Requirements::javascript("jsparty/greybox/AmiJS.js"); Requirements::javascript("jsparty/greybox/greybox.js"); Requirements::javascript('sapphire/javascript/TableListField.js'); @@ -127,28 +127,28 @@ JS; Requirements::customScript($js); } } - + // compute sourceItems here instead of Items() to ensure that // pagination and filters are respected on template accessors $this->sourceItems(); return $this->renderWith($this->template); } - + /** * Returns non-paginated items. * Please use Items() for pagination. * This function is called whenever a complete result-set is needed, * so even if a single record is displayed in a popup, we need the results * to make pagination work. - * + * * TODO Merge with more efficient querying of TableListField */ function sourceItems() { if($this->sourceItems) { return $this->sourceItems; } - + $limitClause = ""; if($this->pageSize) { $limitClause = "{$this->pageSize}"; @@ -161,44 +161,44 @@ JS; } $sourceItems = DataObject::get($this->sourceClass, $this->sourceFilter, $this->sourceSort, $this->sourceJoin, $limitClause); - + $this->unpagedSourceItems = DataObject::get($this->sourceClass, $this->sourceFilter, $this->sourceSort, $this->sourceJoin); - + $this->totalCount = ($this->unpagedSourceItems) ? $this->unpagedSourceItems->TotalItems() : null; - + return $sourceItems; } - + /** * @return DataObjectSet */ function Items() { $this->sourceItems = $this->sourceItems(); - + if(!$this->sourceItems) { return null; } - + $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); - + $output = new DataObjectSet(); foreach($this->sourceItems as $pageIndex=>$item) { $output->push(Object::create($this->itemClass,$item, $this, $pageStart+$pageIndex)); } return $output; } - + /** * Sets the popup-title by javascript. Make sure to use FormResponse in ajax-requests, * otherwise the title-change will only take effect on items existing during page-load. - * + * * @param $caption String */ function setPopupCaption($caption) { - $this->popupCaption = Convert::raw2js($caption); + $this->popupCaption = Convert::raw2js($caption); } - + /** * Renders view, edit and add, depending on the given information. * The form needs several parameters to function independently of its "parent-form", some derived from the context into a hidden-field, @@ -209,7 +209,7 @@ JS; * CAUTION: "ID" in the DetailForm would be the "childID" in the overview table. */ function DetailForm() { - + // Get all the requests $ID = isset($_REQUEST['ctf']['ID']) ? Convert::raw2xml($_REQUEST['ctf']['ID']) : null; $childID = isset($_REQUEST['ctf']['childID']) ? Convert::raw2xml($_REQUEST['ctf']['childID']) : null; @@ -265,11 +265,11 @@ JS; // the ID field confuses the Controller-logic in finding the right view for ReferencedField $detailFields->removeByName('ID'); - + // add a namespaced ID instead thats "converted" by saveComplexTableField() $detailFields->push(new HiddenField("ctf[childID]","",$childID)); $detailFields->push(new HiddenField("ctf[ClassName]","",$this->sourceClass)); - + $readonly = ($this->methodName == "show"); // if no custom validator is set, and there's on present on the object (e.g. Member), use it @@ -281,7 +281,7 @@ JS; if (is_numeric($childID)) { if ($this->methodName == "show" || $this->methodName == "edit") { - + $form->loadDataFrom($childData); } } @@ -289,10 +289,10 @@ JS; if ($this->methodName == "show") { $form->makeReadonly(); } - + return $form; } - + /** * @param $validator Validator */ @@ -303,87 +303,87 @@ JS; /** * Returns the content of this formfield without surrounding layout. Triggered by Javascript * to update content after a DetailForm-save-action. - * + * * @return String */ function ajax_render() { return $this->renderWith($this->template); } - + /** * Just a hook, processed in {DetailForm()} - * + * * @return String */ function show() { if($this->Can('show') !== true) { return false; } - + $this->methodName = "edit"; - + $this->sourceItems = $this->sourceItems(); - + $this->pageSize = 1; if(isset($_REQUEST['ctf'][$this->Name()]['start']) && is_numeric($_REQUEST['ctf'][$this->Name()]['start'])) { $this->unpagedSourceItems->setPageLimits($_REQUEST['ctf'][$this->Name()]['start'], $this->pageSize, $this->totalCount); } - + echo $this->renderWith($this->templatePopup); } /** * Just a hook, processed in {DetailForm()} - * + * * @return String */ function edit() { if($this->Can('edit') !== true) { return false; } - + $this->methodName = "edit"; - + $this->sourceItems = $this->sourceItems(); - + $this->pageSize = 1; - + if(is_numeric($_REQUEST['ctf']['start'])) { $this->unpagedSourceItems->setPageLimits($_REQUEST['ctf']['start'], $this->pageSize, $this->totalCount); } - + echo $this->renderWith($this->templatePopup); } /** * Just a hook, processed in {DetailForm()} - * + * * @return String */ function add() { if($this->Can('add') !== true) { return false; } - + $this->methodName = "add"; - + echo $this->renderWith($this->templatePopup); } /** * Calculates the number of columns needed for colspans * used in template - * + * * @return Int */ function ItemCount() { return count($this->fieldList); } - + /** * Used to toggle paging (makes no sense when adding a record) - * + * * @return Boolean */ function IsAddMode() { @@ -411,7 +411,7 @@ JS; function PopupBaseLink() { return $this->FormAction() . "&action_callfieldmethod&fieldName={$this->Name()}&ctf[ID]={$this->sourceID()}"; } - + function PopupCurrentItem() { return $_REQUEST['ctf']['start']+1; } @@ -420,27 +420,27 @@ JS; if(!is_numeric($_REQUEST['ctf']['start']) || $_REQUEST['ctf']['start'] == 0) { return null; } - + $item = $this->unpagedSourceItems->First(); $start = 0; return $this->PopupBaseLink() . "&methodName={$_REQUEST['methodName']}&ctf[childID]={$item->ID}&ctf[start]={$start}"; } - + function PopupLastLink() { if(!is_numeric($_REQUEST['ctf']['start']) || $_REQUEST['ctf']['start'] == $this->totalCount-1) { return null; } - + $item = $this->unpagedSourceItems->Last(); $start = $this->totalCount - 1; return $this->PopupBaseLink() . "&methodName={$_REQUEST['methodName']}&ctf[childID]={$item->ID}&ctf[start]={$start}"; } - + function PopupNextLink() { if(!is_numeric($_REQUEST['ctf']['start']) || $_REQUEST['ctf']['start'] == $this->totalCount-1) { return null; } - + $item = $this->unpagedSourceItems->getOffset($_REQUEST['ctf']['start'] + 1); $start = $_REQUEST['ctf']['start'] + 1; @@ -451,7 +451,7 @@ JS; if(!is_numeric($_REQUEST['ctf']['start']) || $_REQUEST['ctf']['start'] == 0) { return null; } - + $item = $this->unpagedSourceItems->getOffset($_REQUEST['ctf']['start'] - 1); $start = $_REQUEST['ctf']['start'] - 1; @@ -487,8 +487,8 @@ JS; return $result; } - - + + /** * ################################# * Utilty @@ -500,7 +500,7 @@ JS; */ function PopupClasses() { global $_ALL_CLASSES; - + $items = array(); $parents = $_ALL_CLASSES['parents'][$this->class]; foreach($parents as $parent) { @@ -510,11 +510,11 @@ JS; return implode(" ", $items); } - + function AddLink() { return "{$this->PopupBaseLink()}&methodName=add"; } - + /** * @return FieldSet */ @@ -525,11 +525,11 @@ JS; } return $fieldset; } - + /** * Determines on which relation-class the DetailForm is saved * by looking at the surrounding form-record. - * + * * @return String */ function getParentClass() { @@ -547,13 +547,13 @@ JS; * (Optional) Setter for a correct parent-relation-class. * Defaults to the record loaded into the surrounding form as a fallback. * Caution: Please use the classname, not the actual column-name in the database. - * + * * @param $className string */ function setParentClass($className) { $this->parentClass = $className; } - + /** * Returns the db-fieldname of the currently used has_one-relationship. */ @@ -575,12 +575,12 @@ JS; } return false; } - + function setTemplatePopup($template) { $this->templatePopup = $template; } - - + + } class ComplexTableField_Item extends TableListField_Item { @@ -588,13 +588,13 @@ class ComplexTableField_Item extends TableListField_Item { * Needed to transfer pagination-status from overview. */ protected $start; - + function __construct(DataObject $item, ComplexTableField $parent, $start) { $this->start = $start; - + parent::__construct($item, $parent); } - + function PopupBaseLink() { return $this->parent->FormAction() . "&action_callfieldmethod&fieldName={$this->parent->Name()}&ctf[childID]={$this->item->ID}&ctf[ID]={$this->parent->sourceID()}&ctf[start]={$this->start}"; } @@ -615,7 +615,7 @@ class ComplexTableField_Item extends TableListField_Item { /** * ComplexTablefield_popup is rendered with a lightbox and can load a more - * detailed view of the source class your presenting. + * detailed view of the source class your presenting. * You can customise the fields and requirements as well as any * permissions you might need. */ @@ -623,10 +623,10 @@ class ComplexTableField_Popup extends Form { protected $sourceClass; function __construct($controller, $name, $field, $sourceClass, $readonly=false, $validator = null) { - + /** * WARNING: DO NOT CHANGE THE ORDER OF THESE JS FILES - * Some have special requirements. + * Some have special requirements. */ Requirements::clear(); //Requirements::css('cms/css/layout.css'); @@ -647,7 +647,7 @@ class ComplexTableField_Popup extends Form { Requirements::javascript("sapphire/javascript/TableField.js"); Requirements::javascript("sapphire/javascript/ComplexTableField.js"); Requirements::javascript("sapphire/javascript/ComplexTableField_popup.js"); - + $this->sourceClass = $sourceClass; if(singleton($sourceClass)->hasMethod('getRequirementsForPopup')){ singleton($sourceClass)->getRequirementsForPopup(); @@ -667,23 +667,23 @@ class ComplexTableField_Popup extends Form { function FieldHolder() { return $this->renderWith('ComplexTableField_Form'); } - + function ShowPagination() { return $this->controller->ShowPagination(); } - - + + /** * Use the URL-Parameter "action_saveComplexTableField" * to provide a clue to the main controller if the main form has to be rendered, * even if there is no action relevant for the main controller (to provide the instance of ComplexTableField - * which in turn saves the record. - * + * which in turn saves the record. + * * @see {Form::ReferencedField}). */ function saveComplexTableField() { $id = Convert::raw2sql($_REQUEST['ctf']['childID']); - + if (is_numeric($id)) { $childObject = DataObject::get_by_id($this->sourceClass, $id); } else {