Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Removing deprecated TableListField and subclasses

These have been moved to a module called "legacytablefields"
located at https://github.com/silverstripe-labs/legacytablefields
  • Loading branch information...
commit 77337ae58c66c954caad0028db5acd79c7bcde6b 1 parent aeef4d6
@halkyon halkyon authored
Showing with 0 additions and 9,443 deletions.
  1. +0 −6 css/ComplexTableField.css
  2. +0 −30 css/HasManyFileField.css
  3. +0 −76 css/TableListField.css
  4. +0 −883 forms/ComplexTableField.php
  5. +0 −181 forms/HasManyComplexTableField.php
  6. +0 −109 forms/HasOneComplexTableField.php
  7. +0 −116 forms/ManyManyComplexTableField.php
  8. +0 −724 forms/TableField.php
  9. +0 −1,644 forms/TableListField.php
  10. +0 −156 javascript/ComplexTableField.js
  11. +0 −11 javascript/ComplexTableField_popup.js
  12. +0 −137 javascript/HasManyFileField.js
  13. +0 −117 javascript/RelationComplexTableField.js
  14. +0 −191 javascript/TableField.js
  15. +0 −374 javascript/TableListField.js
  16. +0 −41 lang/en.yml
  17. +0 −16 scss/ComplexTableField.scss
  18. +0 −124 scss/HasManyFileField.scss
  19. +0 −226 scss/TableListField.scss
  20. +0 −82 templates/ComplexTableField.ss
  21. +0 −42 templates/ComplexTableField_popup.ss
  22. +0 −67 templates/RelationComplexTableField.ss
  23. +0 −71 templates/TableField.ss
  24. +0 −85 templates/TableListField.ss
  25. +0 −12 templates/TableListField_printable.ss
  26. +0 −202 tests/forms/ComplexTableFieldTest.php
  27. +0 −16 tests/forms/ComplexTableFieldTest.yml
  28. +0 −263 tests/forms/TableFieldTest.php
  29. +0 −13 tests/forms/TableFieldTest.yml
  30. +0 −375 tests/forms/TableListFieldTest.php
  31. +0 −31 tests/forms/TableListFieldTest.yml
  32. +0 −101 thirdparty/scriptaculous/builder.js
  33. +0 −750 thirdparty/scriptaculous/controls.js
  34. +0 −581 thirdparty/scriptaculous/dragdrop.js
  35. +0 −904 thirdparty/scriptaculous/effects.js
  36. +0 −48 thirdparty/scriptaculous/scriptaculous.js
  37. +0 −275 thirdparty/scriptaculous/slider.js
  38. +0 −363 thirdparty/scriptaculous/unittest.js
View
6 css/ComplexTableField.css
@@ -1,6 +0,0 @@
-/* table */
-.ComplexTableField { margin-bottom: 10px; }
-.ComplexTableField tbody td { cursor: pointer; }
-.ComplexTableField tbody td.markingcheckbox { cursor: default; }
-
-.ui-dialog .ctf-dialog.ui-dialog-content { padding-right: 0; /* scrollbars */ }
View
30 css/HasManyFileField.css
@@ -1,30 +0,0 @@
-#right form .hasmanyfile a.addFile, #right form .hasmanyfile a.uploadFile, #right form .hasmanyfile .currentFiles li { font-size: 1.2em; padding-left: 3px; }
-
-#right form .hasmanyfile a.uploadFile { border-color: #cccccc #999999 #999999 #cccccc; border-style: solid; border-width: 2px; color: #333333; cursor: pointer; font-size: 11px; font-weight: bold; position: relative; top: -29px; left: 344px; text-decoration: none; overflow: visible; padding: 3px 5px; float: left; width: auto; }
-
-#right form .hasmanyfile a.removeFile { border-color: #cccccc #999999 #999999 #cccccc; border-style: solid; border-width: 2px; color: #333333; cursor: pointer; font-size: 10px; font-weight: bold; text-decoration: none; overflow: visible; padding: 3px 5px; width: auto; margin: -2px 0 0 10px; }
-
-#right form .hasmanyfile a.removeFile:hover { background: #CE0000; color: #fff; }
-
-#right form .hasmanyfile a.addFile { border-color: #cccccc #999999 #999999 #cccccc; border-style: solid; border-width: 2px; color: #333333; cursor: pointer; font-size: 11px; font-weight: bold; position: relative; top: -29px; left: 340px; text-decoration: none; overflow: visible; padding: 3px 5px; float: left; width: auto; }
-
-#right form .hasmanyfile a.addFile:hover, #right form .hasmanyfile a.uploadFile:hover { background: #fff; }
-
-#right form .hasmanyfile ul.currentFiles { padding-bottom: 5px; }
-
-#right form .hasmanyfile .currentFiles li { height: 30px; line-height: 30px; }
-
-#right form .hasmanyfile .clear { clear: both; }
-
-/* ICONS */
-#right form .hasmanyfile .currentFiles a[href$=".pdf"], #right form .hasmanyfile .currentFiles a[href$=".PDF"], #right form .hasmanyfile .currentFiles a.pdf { padding: 2px; padding-left: 20px; background: url(../images/icons/page_white_acrobat.png) no-repeat left center; }
-
-#right form .hasmanyfile .currentFiles a[href$=".doc"], #right form .hasmanyfile .currentFiles a[href$=".DOC"], #right form .hasmanyfile .currentFiles a.doc { padding: 2px; padding-left: 20px; background: url(../images/icons/page_word.png) no-repeat left center; }
-
-#right form .hasmanyfile .currentFiles a[href$=".xls"], #right form .hasmanyfile .currentFiles a[href$=".XLS"], #right form .hasmanyfile .currentFiles a.xls { padding: 2px; padding-left: 20px; background: url(../images/icons/page_excel.png) no-repeat left center; }
-
-#right form .hasmanyfile .currentFiles a[href$=".gz"], #right form .hasmanyfile .currentFiles a[href$=".GZ"], #right form .hasmanyfile .currentFiles a[href$=".gzip"], #right form .hasmanyfile .currentFiles a[href$=".GZIP"], #right form .hasmanyfile .currentFiles a[href$=".zip"], #right form .hasmanyfile .currentFiles a[href$=".ZIP"], #right form .hasmanyfile .currentFiles a.archive { padding: 2px; padding-left: 20px; background: url(../images/icons/page_white_zip.png) no-repeat left center; }
-
-#right form .hasmanyfile .currentFiles a[href$=".jpg"], #right form .hasmanyfile .currentFiles a[href$=".JPG"], #right form .hasmanyfile .currentFiles a[href$=".gif"], #right form .hasmanyfile .currentFiles a[href$=".GIF"], #right form .hasmanyfile .currentFiles a[href$=".png"], #right form .hasmanyfile .currentFiles a[href$=".PNG"], #right form .hasmanyfile .currentFiles a.image { padding: 2px; padding-left: 20px; background: url(../images/icons/icon-jpg.gif) no-repeat left center; }
-
-#right form .hasmanyfile .currentFiles a[href$=".exe"], #right form .hasmanyfile .currentFiles a[href$=".EXE"], #right form .hasmanyfile .currentFiles a.application { padding: 2px; padding-left: 20px; background: url(../images/icons/application.png) no-repeat left center; }
View
76 css/TableListField.css
@@ -1,76 +0,0 @@
-table.TableField, table.TableListField, .TableListField table.data, table.CMSList { border-collapse: collapse; border-spacing: 0; width: 100%; }
-
-/* Preventing IE6 from showing double borders */
-body > div table.TableField, body > div table.TableListField, body > div .TableListField table.data, body > div table.CMSList { border-collapse: separate; }
-
-table.TableField td, table.TableListField td, .TableListField table.data td, table.CMSList td { border-style: none; }
-
-table.TableField th, table.TableListField th, .TableListField table.data th, table.CMSList th { white-space: nowrap; }
-
-table.TableField thead th, .TableListField table.data thead th, table.CMSList thead th { white-space: nowrap; padding: 3px; font-size: 12px; text-align: left; }
-
-table.TableField thead th span, .TableListField table.data thead th span { font-size: 12px; }
-
-table.TableField thead th span.sortLink, .TableListField table.data thead th span.sortLink, table.CMSList thead th span.sortLink { overflow: hidden; }
-
-table.TableField tbody td, table.TableField tfoot td, .TableListField table.data tbody td, .TableListField table.data tfoot td, table.CMSList tbody td, table.CMSList tfoot td { padding: 2px 4px; }
-
-.TableListField table.data tfoot tr.addtogrouprow td { padding: 3px; }
-
-.TableListField table.data tfoot .actions { float: none; }
-
-.TableListField table.data tfoot tr.addtogrouprow input { width: 94%; }
-
-.TableField td input, .TableListField td input { width: 98%; }
-
-table.data tbody td input, table.data tbody td textarea { border: 0 !important; }
-
-table.TableField tbody td.checkbox, .TableListField table.data tbody td.checkbox, table.CMSList tbody td.checkbox { padding-left: 5px; background-image: url(../images/checkbox.png); background-repeat: repeat-x; background-position: left bottom; }
-
-.TableListField table.data tfoot .addlink img { vertical-align: middle; margin: 3px 6px 3px 3px; }
-
-.TableListField table.data tfoot tr td a { text-decoration: none; }
-
-.TableListField table.data tbody tr td a:hover, .TableListField table.data tfoot tr td a:hover { background: none; }
-
-/** Show a loading indication on a TableListField row */
-.TableListField tr.loading td.first { padding-left: 22px; background: url(../images/network-save.gif) 3px 2px no-repeat; }
-
-.right form .TableField span.readonly { border: 0; background: none; padding: 0; margin-bottom: 0; }
-
-.right form .TableListField td { background: #fff; }
-
-.TableListField div.utility { overflow: auto; }
-
-.TableListField div.utility .item { margin-top: 1em; padding: 3px 0 6px 0; display: block; float: left; }
-
-.TableListField div.utility a { text-decoration: none; color: #333; cursor: pointer; font-size: 11px; margin-right: 2px; overflow: visible; padding: 3px 2px; width: auto; }
-
-form .TableField .message { width: auto; }
-
-.TableListField .selectOptions { overflow: auto; font: 1.3em; margin: 0; padding: 0; }
-
-.TableListField .selectOptions li { float: left; margin: 0px 5px; }
-
-.TableListField .PageControls { margin: 5px 0; text-align: center; display: block; margin-bottom: 5px; position: relative; }
-
-.TableListField .PageControls * { display: inline; vertical-align: middle; font-weight: bold; }
-
-.TableListField .PageControls .Last { display: block; width: 40px; text-align: right; position: absolute; right: 0px; top: 0px; }
-
-.TableListField .PageControls .First { float: left; display: block; width: 40px; text-align: left; }
-
-#Pagination { margin-top: 10px; margin-left: auto; margin-right: auto; }
-#Pagination a { font-size: 14px; width: 1px; height: 1px; margin: 1px; }
-#Pagination span { display: inline; font-size: 14px; }
-#Pagination div { display: inline; }
-
-#Pagination_Next a { text-decoration: none; }
-
-#Pagination_Next a div { position: relative; left: -20px; }
-
-#Pagination_Next a img { position: relative; top: -15px; left: 5px; }
-
-#Pagination_Previous a { text-decoration: none; }
-
-#Pagination_Previous a img { position: relative; top: -15px; left: 35px; }
View
883 forms/ComplexTableField.php
@@ -1,883 +0,0 @@
-<?php
-/**
- * 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,
- * 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)
- *
- * @deprecated 3.1 Use GridField with GridFieldConfig_RecordEditor
- *
- * @todo Control width/height of popup by constructor (hardcoded at the moment)
- * @package forms
- * @subpackage fields-relational
- */
-class ComplexTableField extends TableListField {
-
- /**
- * Determines the fields of the detail pop-up form. It can take many forms:
- * - A FieldList object: Use that field set directly.
- * - A method name, eg, 'getCMSFields': Call that method on the child object to get the fields.
- */
- protected $addTitle;
-
- protected $detailFormFields;
-
- protected $viewAction;
-
- /**
- * @var Controller
- */
- protected $controller;
-
- /**
- * @var string Classname of the parent-relation to correctly link new records.
- */
- public $parentClass;
-
- /**
- * @var string Database column name for the used relation (e.g. FamilyID
- * if one Family has_many Individuals).
- */
- protected $parentIdName;
-
- /**
- * @var array Influence output without having to subclass the template.
- */
- protected $permissions = array(
- "add",
- "edit",
- "show",
- "delete",
- //"export",
- );
-
- /**
- * Template for main rendering
- *
- * @var string
- */
- protected $template = "ComplexTableField";
-
- /**
- * Template for popup (form rendering)
- *
- * @var string
- */
- public $templatePopup = "ComplexTableField_popup";
-
- /**
- * Classname for each row/item
- *
- * @var string
- */
- public $itemClass = 'ComplexTableField_Item';
-
- /**
- * Classname for the popup form
- *
- * @var string
- */
- public $popupClass = 'ComplexTableField_Popup';
-
- /**
- * @var boolean Trigger pagination (defaults to true for ComplexTableField)
- */
- protected $showPagination = true;
-
- /**
- * @var string Caption the popup will show (defaults to the selected action).
- * This is set by javascript and used by greybox.
- */
- protected $popupCaption = null;
-
- /**
- * @var callback A function callback invoked
- * after initializing the popup and its base calls to
- * the {@link Requirements} class.
- */
- public $requirementsForPopupCallback = null;
-
- /**
- * @var $detailFormValidator Validator
- */
- protected $detailFormValidator = null;
-
- /**
- * Default size for the popup box
- */
- protected $popupWidth = 560;
- protected $popupHeight = 390;
-
- public $defaultAction = 'show';
-
- public $actions = array(
- 'show' => array(
- 'label' => 'Show',
- 'icon' => 'framework/images/show.png',
- 'icon_disabled' => 'framework/images/show_disabled.png',
- 'class' => 'popuplink showlink',
- ),
- 'edit' => array(
- 'label' => 'Edit',
- 'icon' => 'framework/images/edit.gif',
- 'icon_disabled' => 'framework/images/edit_disabled.gif',
- 'class' => 'popuplink editlink',
- ),
- 'delete' => array(
- 'label' => 'Delete',
- 'icon' => 'framework/images/delete.gif',
- 'icon_disabled' => 'framework/images/delete_disabled.gif',
- 'class' => 'popuplink deletelink',
- ),
- );
-
- static $url_handlers = array(
- 'item/$ID' => 'handleItem',
- '$Action!' => '$Action',
- );
-
- public function handleItem($request) {
- return new ComplexTableField_ItemRequest($this, $request->param('ID'));
- }
-
- public function getViewer() {
- return new SSViewer($this->template);
- }
-
- public function setPopupSize($width, $height) {
- $width = (int)$width;
- $height = (int)$height;
-
- if($width < 0 || $height < 0) {
- user_error("setPopupSize expects non-negative arguments.", E_USER_WARNING);
- return;
- }
-
- $this->popupWidth = $width;
- $this->popupHeight = $height;
- }
-
- public function PopupWidth() {
- return $this->popupWidth;
- }
-
- public function PopupHeight() {
- return $this->popupHeight;
- }
-
- /**
- * See class comments
- *
- * @param Controller $controller
- * @param string $name
- * @param string $sourceClass
- * @param array $fieldList
- * @param FieldList $detailFormFields
- * @param string $sourceFilter
- * @param string $sourceSort
- * @param string $sourceJoin
- */
- public function __construct($controller, $name, $sourceClass, $fieldList = null, $detailFormFields = null,
- $sourceFilter = "", $sourceSort = "", $sourceJoin = "") {
-
- $this->detailFormFields = $detailFormFields;
- $this->controller = $controller;
- $this->pageSize = 10;
-
- parent::__construct($name, $sourceClass, $fieldList, $sourceFilter, $sourceSort, $sourceJoin);
- }
-
- public function isComposite() {
- return false;
- }
-
- /**
- * @return String
- */
- public function FieldHolder($properties = array()) {
- Requirements::javascript(THIRDPARTY_DIR . "/prototype/prototype.js");
- Requirements::javascript(THIRDPARTY_DIR . "/behaviour/behaviour.js");
- Requirements::javascript(THIRDPARTY_DIR . "/greybox/AmiJS.js");
- Requirements::javascript(THIRDPARTY_DIR . "/greybox/greybox.js");
- Requirements::add_i18n_javascript(FRAMEWORK_DIR . '/javascript/lang');
- Requirements::javascript(FRAMEWORK_DIR . '/javascript/TableListField.js');
- Requirements::javascript(FRAMEWORK_DIR . "/javascript/ComplexTableField.js");
- Requirements::css(THIRDPARTY_DIR . "/greybox/greybox.css");
- Requirements::css(FRAMEWORK_DIR . "/css/TableListField.css");
- Requirements::css(FRAMEWORK_DIR . "/css/ComplexTableField.css");
-
- // set caption if required
- if($this->popupCaption) {
- $id = $this->id();
- if(Director::is_ajax()) {
- $js = <<<JS
-$('$id').GB_Caption = '$this->popupCaption';
-JS;
- // FormResponse::add($js);
- } else {
- $js = <<<JS
-Event.observe(window, 'load', function() { \$('$id').GB_Caption = '$this->popupCaption'; });
-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);
- }
-
- /**
- * @return SS_List
- */
- public function Items() {
- $sourceItems = $this->sourceItems();
-
- if(!$sourceItems) {
- return null;
- }
-
-
- if(isset($_REQUEST['ctf'][$this->getName()]['start'])) {
- $pageStart = $_REQUEST['ctf'][$this->getName()]['start'];
- if(!is_numeric($pageStart)) $pageStart = 0;
- } else {
- $pageStart = 0;
- }
-
- $output = new ArrayList();
- foreach($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
- */
- public function setPopupCaption($caption) {
- $this->popupCaption = Convert::raw2js($caption);
- }
-
- /**
- * @param $validator Validator
- */
- public function setDetailFormValidator( Validator $validator ) {
- $this->detailFormValidator = $validator;
- }
-
- public function setAddTitle($addTitle) {
- if(is_string($addTitle))
- $this->addTitle = $addTitle;
- }
-
- public function Title() {
- return $this->addTitle ? $this->addTitle : parent::Title();
- }
-
- /**
- * Calculates the number of columns needed for colspans
- * used in template
- *
- * @return Int
- */
- public function ItemCount() {
- return count($this->fieldList);
- }
-
- /**
- * Used to toggle paging (makes no sense when adding a record)
- *
- * @return Boolean
- */
- public function IsAddMode() {
- return ($this->methodName == "add" || $this->request->param('Action') == 'AddForm');
- }
-
- public function sourceID() {
- $idField = $this->form->Fields()->dataFieldByName('ID');
-
- // disabled as it conflicts with scaffolded formfields, and not strictly necessary
- // if(!$idField) user_error("ComplexTableField needs a formfield named 'ID' to be present", E_USER_ERROR);
-
- // because action_callfieldmethod never actually loads data into the form,
- // we can't rely on $idField being populated, and fall back to the request-params.
- // this is a workaround for a bug where each subsequent popup-call didn't have ID
- // of the parent set, and so didn't properly save the relation
- return ($idField) ? $idField->Value() : (isset($_REQUEST['ctf']['ID']) ? $_REQUEST['ctf']['ID'] : null);
- }
-
-
-
- public function AddLink() {
- return Controller::join_links($this->Link(), 'add');
- }
-
- /**
- * @return FieldList
- */
- public function createFieldList() {
- $fieldset = new FieldList();
- foreach($this->fieldTypes as $key => $fieldType){
- $fieldset->push(new $fieldType($key));
- }
- return $fieldset;
- }
-
- public function setController($controller) {
- $this->controller = $controller;
- return $this;
- }
-
- public function setTemplatePopup($template) {
- $this->templatePopup = $template;
- return $this;
- }
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Return the object-specific fields for the given record, to be shown in the detail pop-up
- *
- * This won't include all the CTF-specific 'plumbing; this method is called by self::getFieldsFor()
- * and the result is then processed further to get the actual FieldList for the form.
- *
- * The default implementation of this processes the value of $this->detailFormFields; consequently, if you want to
- * set the value of the fields to something that $this->detailFormFields doesn't allow, you can do so by overloading
- * this method.
- */
- public function getCustomFieldsFor($childData) {
- if($this->detailFormFields instanceof FieldList) {
- return $this->detailFormFields;
- }
-
- $fieldsMethod = $this->detailFormFields;
-
- if(!is_string($fieldsMethod)) {
- $this->detailFormFields = 'getCMSFields';
- $fieldsMethod = 'getCMSFields';
- }
-
- if(!$childData->hasMethod($fieldsMethod)) {
- $fieldsMethod = 'getCMSFields';
- }
-
- return $childData->$fieldsMethod();
- }
-
- public function getFieldsFor($childData) {
- $detailFields = $this->getCustomFieldsFor($childData);
-
- // the ID field confuses the Controller-logic in finding the right view for ReferencedField
- $detailFields->removeByName('ID');
-
- // only add childID if we're not adding a record
- if($childData->ID) {
- $detailFields->push(new HiddenField('ctf[childID]', '', $childData->ID));
- }
-
- /* TODO: Figure out how to implement this
- if($this->getParentClass()) {
- $detailFields->push(new HiddenField('ctf[parentClass]', '', $this->getParentClass()));
-
- // Hack for model admin: model admin will have included a dropdown for the relation itself
- $parentIdName = $this->getParentIdName($this->getParentClass(), $this->sourceClass());
- if($parentIdName) {
- $detailFields->removeByName($parentIdName);
- $detailFields->push(new HiddenField($parentIdName, '', $this->sourceID()));
- }
- }
- */
-
- return $detailFields;
- }
-
- public function getValidatorFor($childData) {
- // if no custom validator is set, and there's on present on the object (e.g. Member), use it
- if(!isset($this->detailFormValidator) && $childData->hasMethod('getValidator')) {
- $this->detailFormValidator = $childData->getValidator();
- }
- return $this->detailFormValidator;
- }
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////
-
- public function add() {
- if(!$this->can('add')) return;
-
- return $this->customise(array(
- 'DetailForm' => $this->AddForm(),
- ))->renderWith($this->templatePopup);
- }
-
- public function AddForm($childID = null) {
- $className = $this->sourceClass();
- $childData = new $className();
-
- $fields = $this->getFieldsFor($childData);
- $validator = $this->getValidatorFor($childData);
-
- $form = new $this->popupClass(
- $this,
- 'AddForm',
- $fields,
- $validator,
- false,
- $childData
- );
-
- $form->loadDataFrom($childData);
-
- return $form;
- }
-
- /**
- * @deprecated 3.1
- */
- public function setRelationAutoSetting($value) {
- Deprecation::notice('3.0', 'Manipulate the DataList instead.');
- return $this;
- }
-
- /**
- * 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.
- *
- * This is for adding new item records. {@link ComplexTableField_ItemRequest::saveComplexTableField()}
- *
- * @see Form::ReferencedField
- */
- public function saveComplexTableField($data, $form, $params) {
- $className = $this->sourceClass();
- $childData = new $className();
- $form->saveInto($childData);
-
- try {
- $childData->write();
- } catch(ValidationException $e) {
- $form->sessionMessage($e->getResult()->message(), 'bad');
- return Controller::curr()->redirectBack();
- }
-
- // Save this item into the given relationship
- $this->getDataList()->add($childData);
-
- $referrer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null;
-
- $closeLink = sprintf(
- '<small><a href="%s" onclick="javascript:window.top.GB_hide(); return false;">(%s)</a></small>',
- $referrer,
- _t('ComplexTableField.CLOSEPOPUP', 'Close Popup')
- );
-
- $editLink = Controller::join_links($this->Link(), 'item/' . $childData->ID . '/edit');
-
- $message = _t(
- 'ComplexTableField.SUCCESSADD2', 'Added {name}',
- array('name' => $childData->singular_name())
- );
- $message .= '<a href="' . $editLink . '">' . $childData->Title . '</a>' . $closeLink;
-
- $form->sessionMessage($message, 'good');
-
- return Controller::curr()->redirectBack();
- }
-}
-
-/**
- * @todo Tie this into ComplexTableField_Item better.
- * @package forms
- * @subpackage fields-relational
- */
-class ComplexTableField_ItemRequest extends TableListField_ItemRequest {
- protected $ctf;
- protected $itemID;
- protected $methodName;
-
- static $url_handlers = array(
- '$Action!' => '$Action',
- '' => 'index',
- );
-
- public function Link($action = null) {
- return Controller::join_links($this->ctf->Link(), '/item/', $this->itemID, $action);
- }
-
- public function index() {
- return $this->show();
- }
-
- /**
- * Just a hook, processed in {DetailForm()}
- *
- * @return String
- */
- public function show() {
- if($this->ctf->Can('show') !== true) {
- return false;
- }
-
- $this->methodName = "show";
- return $this->renderWith($this->ctf->templatePopup);
- }
-
- /**
- * Returns a 1-element data object set that can be used for pagination.
- */
- /* this doesn't actually work :-(
- public function Paginator() {
- $paginatingSet = new ArrayList(array($this->dataObj()));
- $start = isset($_REQUEST['ctf']['start']) ? $_REQUEST['ctf']['start'] : 0;
- $paginatingSet->setPageLimits($start, 1, $this->ctf->TotalCount());
- return $paginatingSet;
- }
- */
-
- /**
- * Just a hook, processed in {DetailForm()}
- *
- * @return String
- */
- public function edit() {
- if($this->ctf->Can('edit') !== true) {
- return false;
- }
-
- $this->methodName = "edit";
-
- return $this->renderWith($this->ctf->templatePopup);
- }
-
- public function delete($request) {
- // Protect against CSRF on destructive action
- $token = $this->ctf->getForm()->getSecurityToken();
- if(!$token->checkRequest($request)) return $this->httpError(400);
-
- if($this->ctf->Can('delete') !== true) {
- return false;
- }
-
- $this->ctf->getDataList()->removeByID($this->itemID);
- }
-
- ///////////////////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Return the data object being manipulated
- */
- public function dataObj() {
- // used to discover fields if requested and for population of field
- if(is_numeric($this->itemID)) {
- // we have to use the basedataclass, otherwise we might exclude other subclasses
- return DataObject::get_by_id(
- ClassInfo::baseDataClass(Object::getCustomClass($this->ctf->sourceClass())), $this->itemID);
- }
-
- }
-
- /**
- * 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, some derived from the parent context (which is not accessible here) and delivered by
- * GET:ID, Identifier of the currently edited record (only if record is loaded).
- * <parentIDName>, Link back to the correct parent record (e.g. "parentID").
- * parentClass, Link back to correct container-class (the parent-record might have many 'has-one'-relationships)
- * CAUTION: "ID" in the DetailForm would be the "childID" in the overview table.
- *
- * @param int $childID
- */
- public function DetailForm($childID = null) {
- $childData = $this->dataObj();
-
- $fields = $this->ctf->getFieldsFor($childData);
- $validator = $this->ctf->getValidatorFor($childData);
- $readonly = ($this->methodName == "show");
-
- $form = new $this->ctf->popupClass(
- $this,
- "DetailForm",
- $fields,
- $validator,
- $readonly,
- $childData
- );
- // Don't use ComplexTableField_Popup.ss
- $form->setTemplate('Form');
-
- $form->loadDataFrom($childData);
- if ($readonly) $form->makeReadonly();
-
- return $form;
- }
-
- /**
- * 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.
- *
- * This is for editing existing item records. {@link ComplexTableField::saveComplexTableField()}
- *
- * @see Form::ReferencedField
- */
- public function saveComplexTableField($data, $form, $request) {
- $dataObject = $this->dataObj();
-
- try {
- $form->saveInto($dataObject);
- $dataObject->write();
- } catch(ValidationException $e) {
- $form->sessionMessage($e->getResult()->message(), 'bad');
- return Controller::curr()->redirectBack();
- }
-
- // Save this item into the given relationship
- $this->ctf->getDataList()->add($dataObject);
-
- $referrer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null;
-
- $closeLink = sprintf(
- '<small><a href="%s" onclick="javascript:window.top.GB_hide(); return false;">(%s)</a></small>',
- $referrer,
- _t('ComplexTableField.CLOSEPOPUP', 'Close Popup')
- );
- $message = sprintf(
- _t('ComplexTableField.SUCCESSEDIT', 'Saved %s %s %s'),
- $dataObject->singular_name(),
- '<a href="' . $this->Link('edit') . '">"' . htmlspecialchars($dataObject->Title, ENT_QUOTES) . '"</a>',
- $closeLink
- );
-
- $form->sessionMessage($message, 'good');
-
- return Controller::curr()->redirectBack();
- }
-
- public function PopupCurrentItem() {
- return $_REQUEST['ctf']['start']+1;
- }
-
- public function PopupFirstLink() {
- $this->ctf->LinkToItem();
-
- if(!isset($_REQUEST['ctf']['start']) || !is_numeric($_REQUEST['ctf']['start'])
- || $_REQUEST['ctf']['start'] == 0) {
- return null;
- }
-
- $start = 0;
- return Controller::join_links($this->Link(), "$this->methodName?ctf[start]={$start}");
- }
-
- public function PopupLastLink() {
- if(!isset($_REQUEST['ctf']['start']) || !is_numeric($_REQUEST['ctf']['start'])
- || $_REQUEST['ctf']['start'] == $this->TotalCount()-1) {
- return null;
- }
-
- $start = $this->TotalCount - 1;
- return Controller::join_links($this->Link(), "$this->methodName?ctf[start]={$start}");
- }
-
- public function PopupNextLink() {
- if(!isset($_REQUEST['ctf']['start']) || !is_numeric($_REQUEST['ctf']['start'])
- || $_REQUEST['ctf']['start'] == $this->TotalCount()-1) {
- return null;
- }
-
- $start = $_REQUEST['ctf']['start'] + 1;
- return Controller::join_links($this->Link(), "$this->methodName?ctf[start]={$start}");
- }
-
- public function PopupPrevLink() {
- if(!isset($_REQUEST['ctf']['start']) || !is_numeric($_REQUEST['ctf']['start'])
- || $_REQUEST['ctf']['start'] == 0) {
- return null;
- }
-
- $start = $_REQUEST['ctf']['start'] - 1;
- return Controller::join_links($this->Link(), "$this->methodName?ctf[start]={$start}");
- }
-
- /**
- * Method handles pagination in asset popup.
- *
- * @return Object SS_List
- */
-
- public function Pagination() {
- $this->pageSize = 9;
- $currentItem = $this->PopupCurrentItem();
- $result = new ArrayList();
- if($currentItem < 6) {
- $offset = 1;
- } elseif($this->TotalCount() - $currentItem <= 4) {
- $offset = $currentItem - (10 - ($this->TotalCount() - $currentItem));
- $offset = $offset <= 0 ? 1 : $offset;
- } else {
- $offset = $currentItem - 5;
- }
- for($i = $offset;$i <= $offset + $this->pageSize && $i <= $this->TotalCount();$i++) {
- $start = $i - 1;
- $links['link'] = Controller::join_links($this->Link() . "$this->methodName?ctf[start]={$start}");
- $links['number'] = $i;
- $links['active'] = $i == $currentItem ? false : true;
- $result->push(new ArrayData($links));
- }
- return $result;
- }
-
- public function ShowPagination() {
- return false;
- }
-
-
- /**
- * #################################
- * Utility
- * #################################
- */
-
- /**
- * Manually overwrites the parent-ID relations.
- * @see setParentClass()
- *
- * @param String $str Example: FamilyID (when one Individual has_one Family)
- */
- public function setParentIdName($str) {
- throw new Exception("setParentIdName is no longer necessary");
- }
-
- public function setTemplatePopup($template) {
- $this->templatePopup = $template;
- }
-
-
-}
-
-/**
- * Single row of a {@link ComplexTableField}.
- * @package forms
- * @subpackage fields-relational
- */
-class ComplexTableField_Item extends TableListField_Item {
- public function Link($action = null) {
- return Controller::join_links($this->parent->Link(), '/item/', $this->item->ID, $action);
- }
-
- public function EditLink() {
- return Controller::join_links($this->Link(), "edit");
- }
-
- public function ShowLink() {
- return Controller::join_links($this->Link(), "show");
- }
-
- public function DeleteLink() {
- return Controller::join_links($this->Link(), "delete");
- }
-
- /**
- * @param String $action
- * @return boolean
- */
- public function IsDefaultAction($action) {
- return ($action == $this->parent->defaultAction);
- }
-}
-
-
-/**
- * ComplexTablefield_popup is rendered with a lightbox and can load a more
- * detailed view of the source class your presenting.
- * You can customise the fields and requirements as well as any
- * permissions you might need.
- * @package forms
- * @subpackage fields-relational
- */
-class ComplexTableField_Popup extends Form {
- protected $sourceClass;
-
- protected $dataObject;
-
- public function __construct($controller, $name, $fields, $validator, $readonly, $dataObject) {
- $this->dataObject = $dataObject;
-
-
- $actions = new FieldList();
- if(!$readonly) {
- $actions->push(
- FormAction::create(
- "saveComplexTableField",
- _t('CMSMain.SAVE', 'Save')
- )
- ->addExtraClass('save ss-ui-action-constructive')
- ->setUseButtonTag(true)
- ->setAttribute('data-icon', 'accept')
- );
- }
-
- parent::__construct($controller, $name, $fields, $actions, $validator);
-
- if(!$this->dataObject->canEdit()) $this->makeReadonly();
- }
-
- public function forTemplate() {
- $ret = parent::forTemplate();
-
- Requirements::css(FRAMEWORK_DIR . '/css/ComplexTableField_popup.css');
- Requirements::javascript(FRAMEWORK_DIR . "/thirdparty/prototype/prototype.js");
- Requirements::javascript(FRAMEWORK_DIR . "/thirdparty/behaviour/behaviour.js");
- Requirements::javascript(FRAMEWORK_DIR . "/thirdparty/scriptaculous/scriptaculous.js");
- Requirements::javascript(FRAMEWORK_DIR . "/thirdparty/scriptaculous/scriptaculous/controls.js");
- Requirements::add_i18n_javascript(FRAMEWORK_DIR . '/javascript/lang');
- Requirements::javascript(FRAMEWORK_DIR . "/javascript/ComplexTableField_popup.js");
-
- // Append requirements from instance callbacks
- $parent = $this->getParentController();
- if($parent instanceof ComplexTableField) {
- $callback = $parent->requirementsForPopupCallback;
- } else {
- $callback = $parent->getParentController()->requirementsForPopupCallback;
- }
- if($callback) call_user_func($callback, $this);
-
- return $ret;
- }
-
- public function getTemplate() {
- return 'Form';
- }
-
- /**
- * @return ComplexTableField_ItemRequest
- */
- public function getParentController() {
- return $this->controller;
- }
-}
-
-
View
181 forms/HasManyComplexTableField.php
@@ -1,181 +0,0 @@
-<?php
-/**
- * ComplexTableField designed to edit a has_many join.
- *
- * This field allows you to show a 1-to-many relation with a group of DataObjects as a (readonly) tabular list. Its
- * most useful when you want to manage the relationship itself thanks the **check boxes** present on each line of the
- * table.
- *
- * Moreover, you can not do any mistake anymore in the relation by checking a DataObject already linked with another
- * of the parent class.
- *
- * See {@link ComplexTableField} for more documentation on the base-class.
- *
- * <b>Usage</b>
- *
- * <code>
- * $tablefield = new HasManyComplexTableField(
- * $this,
- * 'MyFruits',
- * 'Fruit',
- * array(
- * 'Name' => 'Name',
- * 'Color' => 'Color'
- * ),
- * 'getCMSFields_forPopup'
- * );
- * </code>
- *
- * Notice: You still have different ways to customize the popup window as in the parent-class
- * {@link ComplexTableField}.
- *
- * @see http://doc.silverstripe.org/tutorial/5-dataobject-relationship-management
- *
- * @deprecated 3.1 Use GridField with GridFieldConfig_RelationEditor
- *
- * @package forms
- * @subpackage fields-relational
- */
-class HasManyComplexTableField extends ComplexTableField {
-
- public $joinField;
-
- protected $addTitle;
-
- // If you change the value, do not forget to change it also in the JS file
- protected $htmlListEndName = 'CheckedList';
-
- // If you change the value, do not forget to change it also in the JS file
- protected $htmlListField = 'selected';
-
- public $template = 'RelationComplexTableField';
-
- public $itemClass = 'HasManyComplexTableField_Item';
-
- protected $relationAutoSetting = false;
-
- public function __construct($controller, $name, $sourceClass, $fieldList = null, $detailFormFields = null,
- $sourceFilter = "", $sourceSort = "", $sourceJoin = "") {
-
- parent::__construct($controller, $name, $sourceClass, $fieldList, $detailFormFields,
- $sourceFilter, $sourceSort, $sourceJoin);
-
- Deprecation::notice('3.0', 'Use GridField with GridFieldConfig_RelationEditor', Deprecation::SCOPE_CLASS);
-
- $this->Markable = true;
-
- if($controllerClass = $this->controllerClass()) {
- $this->joinField = $this->getParentIdName($controllerClass, $this->sourceClass);
- if(!$this->joinField) {
- user_error("Can't find a has_one relationship from '$this->sourceClass' to '$controllerClass'",
- E_USER_WARNING);
- }
- } else {
- user_error("Can't figure out the data class of $controller", E_USER_WARNING);
- }
-
- }
-
- public function FieldHolder($properties = array()) {
- $ret = parent::FieldHolder($properties);
-
- Requirements::add_i18n_javascript(FRAMEWORK_DIR . '/javascript/lang');
- Requirements::javascript(FRAMEWORK_DIR . "/javascript/HasManyFileField.js");
- Requirements::javascript(FRAMEWORK_DIR . '/javascript/RelationComplexTableField.js');
- Requirements::css(FRAMEWORK_DIR . '/css/HasManyFileField.css');
-
- return $ret;
- }
-
- /**
- * Try to determine the DataObject that this field is built on top of
- */
- public function controllerClass() {
- if($this->controller instanceof DataObject) return $this->controller->class;
- elseif($this->controller instanceof Controller) return $this->controller->data()->class;
- }
-
- public function getControllerID() {
- return $this->controller->ID;
- }
-
- public function saveInto(DataObjectInterface $record) {
- $fieldName = $this->name;
- $saveDest = $record->$fieldName();
-
- if(!$saveDest) {
- user_error("HasManyComplexTableField::saveInto() Field $fieldName not found on $record->class.$record->ID"
- , E_USER_ERROR);
- }
-
- $items = array();
-
- if($list = $this->value[ $this->htmlListField ]) {
- if($list != 'undefined')
- $items = explode(',', $list);
- }
-
- $saveDest->setByIDList($items);
- }
-
- public function setAddTitle($addTitle) {
- if(is_string($addTitle))
- $this->addTitle = $addTitle;
- }
-
- public function Title() {
- return $this->addTitle ? $this->addTitle : parent::Title();
- }
-
- /**
- * Get the IDs of the selected items, in a has_many or many_many relation
- */
- public function selectedItemIDs() {
- $fieldName = $this->name;
- $selectedItems = $this->form->getRecord()->$fieldName();
- $itemIDs = array();
- foreach($selectedItems as $item) $itemIDs[] = $item->ID;
- return $itemIDs;
- }
-
- public function ExtraData() {
- $items = array();
-
- $list = implode(',', $this->selectedItemIDs());
- $inputId = $this->id() . '_' . $this->htmlListEndName;
- return <<<HTML
- <input id="$inputId" name="{$this->name}[{$this->htmlListField}]" type="hidden" value="$list"/>
-HTML;
- }
-}
-
-/**
- * Single record of a {@link HasManyComplexTableField} field.
- * @package forms
- * @subpackage fields-relational
- */
-class HasManyComplexTableField_Item extends ComplexTableField_Item {
-
- public function MarkingCheckbox() {
- $name = $this->parent->getName() . '[]';
-
- if(!$this->parent->joinField) {
- user_error("joinField not set in HasManyComplexTableField '{$this->parent->name}'", E_USER_WARNING);
- return null;
- }
-
- $joinVal = $this->item->{$this->parent->joinField};
- $parentID = $this->parent->getControllerID();
-
- if($this->parent->IsReadOnly || ($joinVal > 0 && $joinVal != $parentID))
- return "<input class=\"checkbox\" type=\"checkbox\" name=\"$name\" value=\"{$this->item->ID}\"
- disabled=\"disabled\"/>";
- else if($joinVal == $parentID)
- return "<input class=\"checkbox\" type=\"checkbox\" name=\"$name\" value=\"{$this->item->ID}\"
- checked=\"checked\"/>";
- else
- return "<input class=\"checkbox\" type=\"checkbox\" name=\"$name\" value=\"{$this->item->ID}\"/>";
- }
-}
-
-
View
109 forms/HasOneComplexTableField.php
@@ -1,109 +0,0 @@
-<?php
-/**
- * ComplexTableField with a radio button column, designed to edit a has_one join.
- *
- * This [RelationTable](RelationTable) allows you to show a **1-to-1** or **1-to-many** relation with a group of
- * DataObjects as a (readonly) tabular list (similiar to [ComplexTableField](ComplexTableField)). Its most useful when
- * you want to manage the relationship itself thanks the **radio buttons** present on each line of the table.
- *
- * Moreover, you have the possibility to uncheck a radio button in order to make the relation as null.
- *
- * <b>Usage</b>
- *
- * <code>
- * $tablefield = new HasOneComplexTableField(
- * $this,
- * 'MyOnlyFruit',
- * 'Fruit',
- * array(
- * 'Name' => 'Name',
- * 'Color' => 'Color'
- * ),
- * 'getCMSFields_forPopup'
- * );
- * </code>
- *
- * **Notice** : You still have different ways to customize the popup window as in the parent-class
- * [ComplexTableField](ComplexTableField).
- *
- * This field is made to manage a **has_one** relation. In the SilverStripe relation between DataObjects, you can use
- * this relation for **1-to-1** and **1-to-many** relations.
- * By default, a HasOneComplexTableField manages a **1-to-many** relation. If you want to specify that the relation
- * that you manage is a **1-to-1** relation, add this code :
- *
- * <code>
- * $tablefield->setOneToOne();
- * </code>
- *
- * @package forms
- * @subpackage fields-relational
- */
-class HasOneComplexTableField extends HasManyComplexTableField {
-
- public $itemClass = 'HasOneComplexTableField_Item';
-
- public $isOneToOne = false;
-
- public function getParentIdName($parentClass, $childClass) {
- return $this->getParentIdNameRelation($parentClass, $childClass, 'has_one');
- }
-
- public function getControllerJoinID() {
- return $this->controller->{$this->joinField};
- }
-
- public function saveInto(DataObjectInterface $record) {
- $fieldName = $this->name;
- $fieldNameID = $fieldName . 'ID';
-
- $record->$fieldNameID = 0;
- if($val = $this->value[ $this->htmlListField ]) {
- if($val != 'undefined')
- $record->$fieldNameID = $val;
- }
-
- $record->write();
- }
-
- public function setOneToOne() {
- $this->isOneToOne = true;
- }
-
- public function isChildSet($childID) {
- return DataObject::get($this->controllerClass(), '"' . $this->joinField . "\" = '$childID'");
- }
-
- public function ExtraData() {
- $val = $this->getControllerJoinID() ? $this->getControllerJoinID() : '';
- $inputId = $this->id() . '_' . $this->htmlListEndName;
- return <<<HTML
- <input id="$inputId" name="{$this->name}[{$this->htmlListField}]" type="hidden" value="$val"/>
-HTML;
- }
-}
-
-/**
- * Single record of a {@link HasOneComplexTableField} field.
- * @package forms
- * @subpackage fields-relational
- */
-class HasOneComplexTableField_Item extends ComplexTableField_Item {
-
- public function MarkingCheckbox() {
- $name = $this->parent->getName() . '[]';
-
- $isOneToOne = $this->parent->isOneToOne;
- $joinVal = $this->parent->getControllerJoinID();
- $childID = $this->item->ID;
-
- if($this->parent->IsReadOnly || ($isOneToOne && $joinVal != $childID && $this->parent->isChildSet($childID)))
- return "<input class=\"radio\" type=\"radio\" name=\"$name\" value=\"{$this->item->ID}\"
- disabled=\"disabled\"/>";
- else if($joinVal == $childID)
- return "<input class=\"radio\" type=\"radio\" name=\"$name\" value=\"{$this->item->ID}\"
- checked=\"checked\"/>";
- else
- return "<input class=\"radio\" type=\"radio\" name=\"$name\" value=\"{$this->item->ID}\"/>";
- }
-}
-
View
116 forms/ManyManyComplexTableField.php
@@ -1,116 +0,0 @@
-<?php
-/**
- * Special ComplexTableField for editing a many_many relation.
- *
- * This field allows you to show a **many-to-many** relation with a group of
- * DataObjects as a (readonly) tabular list (similiar to {@link ComplexTableField}).
- * Its most useful when you want to manage the relationship itself
- * thanks to the check boxes present on each line of the table.
- *
- * See {@link ComplexTableField} for more documentation on the base-class.
- * See {@link HasManyComplexTableField} for more documentation on the relation table base-class.
- *
- * Note: This class relies on the fact that both sides of the relation have database tables.
- * If you are only creating a class as a logical extension (that is, it doesn't have any database fields),
- * then you will need to create a dummy static $db array because SilverStripe won't create a database
- * table unless needed.
- *
- * <b>Usage</b>
- *
- * <code>
- * $tablefield = new ManyManyComplexTableField(
- * $this,
- * 'MyFruits',
- * 'Fruit',
- * array(
- * 'Name' => 'Name',
- * 'Color' => 'Color'
- * ),
- * 'getCMSFields_forPopup'
- * );
- * </code>
- *
- * @deprecated 3.1 Use GridField with GridFieldConfig_RelationEditor
- *
- * @package forms
- * @subpackage fields-relational
- */
-class ManyManyComplexTableField extends HasManyComplexTableField {
-
- private $manyManyParentClass;
-
- public $itemClass = 'ManyManyComplexTableField_Item';
-
- public function __construct($controller, $name, $sourceClass, $fieldList = null, $detailFormFields = null,
- $sourceFilter = "", $sourceSort = "", $sourceJoin = "") {
-
- Deprecation::notice('3.0', 'Use GridField with GridFieldConfig_RelationEditor', Deprecation::SCOPE_CLASS);
-
- parent::__construct($controller, $name, $sourceClass, $fieldList, $detailFormFields,
- $sourceFilter, $sourceSort, $sourceJoin);
-
- $classes = array_reverse(ClassInfo::ancestry($this->controllerClass()));
- foreach($classes as $class) {
- $singleton = singleton($class);
- $manyManyRelations = $singleton->uninherited('many_many', true);
- if(isset($manyManyRelations) && array_key_exists($this->name, $manyManyRelations)) {
- $this->manyManyParentClass = $class;
- $manyManyTable = $class . '_' . $this->name;
- break;
- }
- $belongsManyManyRelations = $singleton->uninherited( 'belongs_many_many', true );
- if( isset( $belongsManyManyRelations ) && array_key_exists( $this->name, $belongsManyManyRelations ) ) {
- $this->manyManyParentClass = $class;
- $manyManyTable = $belongsManyManyRelations[$this->name] . '_' . $this->name;
- break;
- }
- }
- $tableClasses = ClassInfo::dataClassesFor($this->sourceClass);
- $source = array_shift($tableClasses);
- $sourceField = $this->sourceClass;
- if($this->manyManyParentClass == $sourceField)
- $sourceField = 'Child';
- $parentID = $this->controller->ID;
-
- $this->sourceJoin .= " LEFT JOIN \"$manyManyTable\"
- ON (\"$source\".\"ID\" = \"$manyManyTable\".\"{$sourceField}ID\"
- AND \"{$this->manyManyParentClass}ID\" = '$parentID')";
-
- $this->joinField = 'Checked';
- }
-
- public function getQuery() {
- $query = parent::getQuery();
- $query->selectField("CASE WHEN \"{$this->manyManyParentClass}ID\" IS NULL THEN '0' ELSE '1' END", "Checked");
- $query->groupby[] = "\"{$this->manyManyParentClass}ID\""; // necessary for Postgres
-
- return $query;
- }
-
- public function getParentIdName($parentClass, $childClass) {
- return $this->getParentIdNameRelation($parentClass, $childClass, 'many_many');
- }
-}
-
-/**
- * One record in a {@link ManyManyComplexTableField}.
- * @package forms
- * @subpackage fields-relational
- */
-class ManyManyComplexTableField_Item extends ComplexTableField_Item {
-
- public function MarkingCheckbox() {
- $name = $this->parent->getName() . '[]';
-
- if($this->parent->IsReadOnly)
- return "<input class=\"checkbox\" type=\"checkbox\" name=\"$name\" value=\"{$this->item->ID}\"
- disabled=\"disabled\"/>";
- else if($this->item->{$this->parent->joinField})
- return "<input class=\"checkbox\" type=\"checkbox\" name=\"$name\" value=\"{$this->item->ID}\"
- checked=\"checked\"/>";
- else
- return "<input class=\"checkbox\" type=\"checkbox\" name=\"$name\" value=\"{$this->item->ID}\"/>";
- }
-}
-
-
View
724 forms/TableField.php
@@ -1,724 +0,0 @@
-<?php
-/**
- * TableField behaves in the same manner as TableListField, however allows the addition of
- * fields and editing of attributes specified, and filtering results.
- *
- * Caution: If you insert DropdownFields in the fieldTypes-array, make sure they have an empty first option.
- * Otherwise the saving can't determine if a new row should really be saved.
- *
- * Caution: TableField relies on {@FormResponse} to reload the field after it is saved.
- * A TableField-instance should never be saved twice without reloading, because otherwise it
- * can't determine if a field is new (=create) or existing (=update), and will produce duplicates.
- *
- * IMPORTANT: This class is about to be deprecated in favour of a new GridFieldEditableColumns component,
- * see http://open.silverstripe.org/ticket/7045
- *
- * @package forms
- * @subpackage fields-relational
- */
-
-class TableField extends TableListField {
-
- protected $fieldList;
-
- /**
- * A "Field = Value" filter can be specified by setting $this->filterField and $this->filterValue. This has the
- * advantage of auto-populating new records
- */
- protected $filterField = null;
-
- /**
- * A "Field = Value" filter can be specified by setting $this->filterField and $this->filterValue. This has the
- * advantage of auto-populating new records
- */
- protected $filterValue = null;
-
- /**
- * @var $fieldTypes FieldList
- * Caution: Use {@setExtraData()} instead of manually adding HiddenFields if you want to
- * preset relations or other default data.
- */
- protected $fieldTypes;
-
- /**
- * @var $template string Template-Overrides
- */
- protected $template = "TableField";
-
- /**
- * @var $extraData array Any extra data that need to be included, e.g. to retain
- * has-many relations. Format: array('FieldName' => 'Value')
- */
- protected $extraData;
-
- protected $tempForm;
-
- /**
- * Influence output without having to subclass the template.
- */
- protected $permissions = array(
- "edit",
- "delete",
- "add",
- //"export",
- );
-
- public $transformationConditions = array();
-
- /**
- * @var $requiredFields array Required fields as a numerical array.
- * Please use an instance of Validator on the including
- * form.
- */
- protected $requiredFields = null;
-
- /**
- * Shows a row of empty fields for adding a new record
- * (turned on by default).
- * Please use {@link TableField::$permissions} to control
- * if the "add"-functionality incl. button is shown at all.
- *
- * @param boolean $showAddRow
- */
- public $showAddRow = true;
-
- /**
- * @param $name string The fieldname
- * @param $sourceClass string The source class of this field
- * @param $fieldList array An array of field headings of Fieldname => Heading Text (eg. heading1)
- * @param $fieldTypes array An array of field types of fieldname => fieldType (eg. formfield). Do not use for
- * extra data/hiddenfields.
- * @param $filterField string The field to filter by. Give the filter value in $sourceFilter. The value will
- * automatically be set on new records.
- * @param $sourceFilter string If $filterField has a value, then this is the value to filter by. Otherwise, it is
- * a SQL filter expression.
- * @param $editExisting boolean (Note: Has to stay on this position for legacy reasons)
- * @param $sourceSort string
- * @param $sourceJoin string
- */
- public function __construct($name, $sourceClass, $fieldList = null, $fieldTypes, $filterField = null,
- $sourceFilter = null, $editExisting = true, $sourceSort = null, $sourceJoin = null) {
-
- $this->fieldTypes = $fieldTypes;
- $this->filterField = $filterField;
-
- $this->editExisting = $editExisting;
-
- // If we specify filterField, then an implicit source filter of "filterField = sourceFilter" is used.
- if($filterField) {
- $this->filterValue = $sourceFilter;
- $sourceFilter = "\"$filterField\" = '" . Convert::raw2sql($sourceFilter) . "'";
- }
- parent::__construct($name, $sourceClass, $fieldList, $sourceFilter, $sourceSort, $sourceJoin);
- }
-
- /**
- * Displays the headings on the template
- *
- * @return SS_List
- */
- public function Headings() {
- $i=0;
- foreach($this->fieldList as $fieldName => $fieldTitle) {
- $extraClass = "col".$i;
- $class = $this->fieldTypes[$fieldName];
- if(is_object($class)) $class = "";
- $class = $class." ".$extraClass;
- $headings[] = new ArrayData(array("Name" => $fieldName, "Title" => $fieldTitle, "Class" => $class));
- $i++;
- }
- return new ArrayList($headings);
- }
-
- /**
- * Calculates the number of columns needed for colspans
- * used in template
- *
- * @return int
- */
- public function ItemCount() {
- return count($this->fieldList);
- }
-
- /**
- * Displays the items from {@link sourceItems()} using the encapsulation object.
- * If the field value has been set as an array (e.g. after a failed validation),
- * it generates the rows from array data instead.
- * Used in the formfield template to iterate over each row.
- *
- * @return SS_List Collection of {@link TableField_Item}
- */
- public function Items() {
- // holds TableField_Item instances
- $items = new ArrayList();
-
- $sourceItems = $this->sourceItems();
-
- // either load all rows from the field value,
- // (e.g. when validation failed), or from sourceItems()
- if($this->value) {
- if(!$sourceItems) $sourceItems = new ArrayList();
-
- // get an array keyed by rows, rather than values
- $rows = $this->sortData(ArrayLib::invert($this->value));
- // ignore all rows which are already saved
- if(isset($rows['new'])) {
- if($sourceItems instanceof DataList) {
- $sourceItems = new ArrayList($sourceItems->toArray());
- }
-
- $newRows = $this->sortData($rows['new']);
- // iterate over each value (not each row)
- $i = 0;
- foreach($newRows as $idx => $newRow){
- // set a pseudo-ID
- $newRow['ID'] = "new";
-
- // unset any extradata
- foreach($newRow as $k => $v){
- if($this->extraData && array_key_exists($k, $this->extraData)){
- unset($newRow[$k]);
- }
- }
-
- // generate a temporary DataObject container (not saved in the database)
- $sourceClass = $this->sourceClass();
- $sourceItems->add(new $sourceClass($newRow));
-
- $i++;
- }
- }
- }
-
- // generate a new TableField_Item instance from each collected item
- if($sourceItems) foreach($sourceItems as $sourceItem) {
- $items->push($this->generateTableFieldItem($sourceItem));
- }
-
- // add an empty TableField_Item for a single "add row"
- if($this->showAddRow && $this->Can('add')) {
- $items->push(new TableField_Item(null, $this, null, $this->fieldTypes, true));
- }
-
- return $items;
- }
-
- /**
- * Generates a new {@link TableField} instance
- * by loading a FieldList for this row into a temporary form.
- *
- * @param DataObject $dataObj
- * @return TableField_Item
- */
- protected function generateTableFieldItem($dataObj) {
- // Load the data in to a temporary form (for correct field types)
- $form = new Form(
- $this,
- null,
- $this->FieldSetForRow(),
- new FieldList()
- );
- $form->loadDataFrom($dataObj);
-
- // Add the item to our new ArrayList, with a wrapper class.
- return new TableField_Item($dataObj, $this, $form, $this->fieldTypes);
- }
-
- /**
- * @return array
- */
- public function FieldList() {
- return $this->fieldList;
- }
-
- /**
- * Saves the Dataobjects contained in the field
- */
- public function saveInto(DataObjectInterface $record) {
- // CMS sometimes tries to set the value to one.
- if(is_array($this->value)){
- $newFields = array();
-
- // Sort into proper array
- $value = ArrayLib::invert($this->value);
- $dataObjects = $this->sortData($value, $record->ID);
-
- // New fields are nested in their own sub-array, and need to be sorted separately
- if(isset($dataObjects['new']) && $dataObjects['new']) {
- $newFields = $this->sortData($dataObjects['new'], $record->ID);
- }
-
- // Update existing fields
- // @todo Should this be in an else{} statement?
- $savedObjIds = $this->saveData($dataObjects, $this->editExisting);
-
- // Save newly added record
- if($savedObjIds || $newFields) {
- $savedObjIds = $this->saveData($newFields,false);
- }
-
- // Add the new records to the DataList
- if($savedObjIds) foreach($savedObjIds as $id => $status) {
- $this->getDataList()->add($id);
- }
-
- // Update the internal source items cache
- $this->value = null;
- $items = $this->sourceItems();
-
- // FormResponse::update_dom_id($this->id(), $this->FieldHolder());
- }
- }
-
- /**
- * Get all {@link FormField} instances necessary for a single row,
- * respecting the casting set in {@link $fieldTypes}.
- * Doesn't populate with any data. Optionally performs a readonly
- * transformation if {@link $IsReadonly} is set, or the current user
- * doesn't have edit permissions.
- *
- * @return FieldList
- */
- public function FieldSetForRow() {
- $fieldset = new FieldList();
- if($this->fieldTypes){
- foreach($this->fieldTypes as $key => $fieldType) {
- if(isset($fieldType->class) && is_subclass_of($fieldType, 'FormField')) {
- // using clone, otherwise we would just add stuff to the same field-instance
- $field = clone $fieldType;
- } elseif(strpos($fieldType, '(') === false) {
- $field = new $fieldType($key);
- } else {
- $fieldName = $key;
- $fieldTitle = "";
- $field = eval("return new $fieldType;");
- }
- if($this->IsReadOnly || !$this->Can('edit')) {
- $field = $field->performReadonlyTransformation();
- }
- $fieldset->push($field);
- }
- }else{
- USER_ERROR("TableField::FieldSetForRow() - Fieldtypes were not specified",E_USER_WARNING);
- }
-
- return $fieldset;
- }
-
- public function performReadonlyTransformation() {
- $clone = clone $this;
- $clone->permissions = array('show');
- $clone->setReadonly(true);
- return $clone;
- }
-
- public function performDisabledTransformation() {
- $clone = clone $this;
- $clone->setPermissions(array('show'));
- $clone->setDisabled(true);
- return $clone;
- }
-
- /**
- * Needed for Form->callfieldmethod.
- */
- public function getField($fieldName, $combinedFieldName = null) {
- $fieldSet = $this->FieldSetForRow();
- $field = $fieldSet->dataFieldByName($fieldName);
- if(!$field) {
- return false;
- }
-
- if($combinedFieldName) {
- $field->Name = $combinedFieldName;
- }
-
- return $field;
- }
-
- /**
- * Called on save, it creates the appropriate objects and writes them
- * to the database.
- *
- * @param SS_List $dataObjects
- * @param boolean $existingValues If set to TRUE, it tries to find existing objects
- * based on the database IDs passed as array keys in $dataObjects parameter.
- * If set to FALSE, it will always create new object (default: TRUE)
- * @return array Array of saved object IDs in the key, and the status ("Updated") in the value
- */
- public function saveData($dataObjects, $existingValues = true) {
- if(!$dataObjects) return false;
-
- $savedObjIds = array();
- $fieldset = $this->FieldSetForRow();
-
- // add hiddenfields
- if($this->extraData) {
- foreach($this->extraData as $fieldName => $fieldValue) {
- $fieldset->push(new HiddenField($fieldName));
- }
- }
-
- $form = new Form($this, null, $fieldset, new FieldList());
-
- foreach ($dataObjects as $objectid => $fieldValues) {
- // 'new' counts as an empty column, don't save it
- if($objectid === "new") continue;
-
- // extra data was creating fields, but
- if($this->extraData) {
- $fieldValues = array_merge( $this->extraData, $fieldValues );
- }
-
- // either look for an existing object, or create a new one
- if($existingValues) {
- $obj = DataObject::get_by_id($this->sourceClass(), $objectid);
- } else {
- $sourceClass = $this->sourceClass();
- $obj = new $sourceClass();
- }
-
- // Legacy: Use the filter as a predefined relationship-ID
- if($this->filterField && $this->filterValue) {
- $filterField = $this->filterField;
- $obj->$filterField = $this->filterValue;
- }
-
- // Determine if there is changed data for saving
- $dataFields = array();
- foreach($fieldValues as $type => $value) {
- // if the field is an actual datafield (not a preset hiddenfield)
- if(is_array($this->extraData)) {
- if(!in_array($type, array_keys($this->extraData))) {
- $dataFields[$type] = $value;
- }
- // all fields are real
- } else {
- $dataFields[$type] = $value;
- }
- }
- $dataValues = ArrayLib::array_values_recursive($dataFields);
- // determine if any of the fields have a value (loose checking with empty())
- $hasData = false;
- foreach($dataValues as $value) {
- if(!empty($value)) $hasData = true;
- }
-
- if($hasData) {
- $form->loadDataFrom($fieldValues, true);
- $form->saveInto($obj);
-
- $objectid = $obj->write();
-
- $savedObjIds[$objectid] = "Updated";
- }
-
- }
-
- return $savedObjIds;
- }
-
- /**
- * Organises the data in the appropriate manner for saving
- *
- * @param array $data
- * @param int $recordID
- * @return array Collection of maps suitable to construct DataObjects
- */
- public function sortData($data, $recordID = null) {
- if(!$data) return false;
-
- $sortedData = array();
-
- foreach($data as $field => $rowData) {
- $i = 0;
- if(!is_array($rowData)) continue;
-
- foreach($rowData as $id => $value) {
- if($value == '$recordID') $value = $recordID;
-
- if($value) $sortedData[$id][$field] = $value;
-
- $i++;
- }
-
- // TODO ADD stuff for removing rows with incomplete data
- }
-
- return $sortedData;
- }
-
- /**
- * @param $extraData array
- */
- public function setExtraData($extraData) {
- $this->extraData = $extraData;
- return $this;
- }
-
- /**
- * @return array
- */
- public function getExtraData() {
- return $this->extraData;
- }
-
- /**
- * Sets the template to be rendered with
- */
- public function FieldHolder($properties = array()) {
- Requirements::javascript(FRAMEWORK_DIR . '/thirdparty/jquery/jquery.js');
- Requirements::javascript(THIRDPARTY_DIR . "/prototype/prototype.js");
- Requirements::javascript(FRAMEWORK_DIR . '/thirdparty/behaviour/behaviour.js');
- Requirements::add_i18n_javascript(FRAMEWORK_DIR . '/javascript/lang');
- Requirements::javascript(FRAMEWORK_DIR . '/javascript/TableListField.js');
- Requirements::javascript(FRAMEWORK_DIR . '/javascript/TableField.js');
- Requirements::css(FRAMEWORK_DIR . '/css/TableListField.css');
-
- $obj = $properties ? $this->customise($properties) : $this;
- return $obj->renderWith($this->template);
- }
-
- public function setTransformationConditions($conditions) {
- $this->transformationConditions = $conditions;
- return $this;
- }
-
- public function php($data) {
- $valid = true;
-
- if($data['methodName'] != 'delete') {
- $items = $this->Items();
- if($items) foreach($items as $item) {
- foreach($item->Fields() as $field) {
- $valid = $field->validate($this) && $valid;
- }
- }
-
- return $valid;
- } else {
- return $valid;
- }
- }
-
- public function validate($validator) {
- $errorMessage = '';
- $valid = true;
-
- // @todo should only contain new elements
- $items = $this->Items();
- if($items) foreach($items as $item) {
- foreach($item->Fields() as $field) {
- $valid = $field->validate($validator) && $valid;
- }
- }
-
- //debug::show($this->form->Message());
- if($this->requiredFields&&$sourceItemsNew&&$sourceItemsNew->count()) {
- foreach ($this->requiredFields as $field) {
- foreach($sourceItemsNew as $item){
- $cellName = $this->getName().'['.$item->ID.']['.$field.']';
- $cName = $this->getName().'[new]['.$field.'][]';
-
- if($fieldObj = $fields->dataFieldByName($cellName)) {
- if(!trim($fieldObj->Value())){
- $title = $fieldObj->Title();
- $errorMessage .= sprintf(
- _t('TableField.ISREQUIRED', "In %s '%s' is required"),
- $this->name,
- $title
- );
- $errorMessage .= "<br />";
- }
- }
- }
- }
- }
-
- if($errorMessage){
- $messageType .= "validation";
- $message .= "<br />".$errorMessage;
-
- $validator->validationError($this->name, $message, $messageType);
- }
-
- return $valid;
- }
-
- public function setRequiredFields($fields) {
- $this->requiredFields = $fields;
- return $this;
- }
-}
-
-/**
- * Single record in a TableField.
- * @package forms
- * @subpackage fields-relational
- * @see TableField
- */
-class TableField_Item extends TableListField_Item {
-
- /**
- * @var FieldList $fields
- */
- protected $fields;
-
- protected $data;
-
- protected $fieldTypes;
-
- protected $isAddRow;
-
- protected $extraData;
-
- /**
- * Each row contains a dataobject with any number of attributes
- * @param $ID int The ID of the record
- * @param $form Form A Form object containing all of the fields for this item. The data should be loaded in
- * @param $fieldTypes array An array of name => fieldtype for use when creating a new field
- * @param $parent TableListField The parent table for quick reference of names, and id's for storing values.
- */
- public function __construct($item = null, $parent, $form, $fieldTypes, $isAddRow = false) {
- $this->data = $form;
- $this->fieldTypes = $fieldTypes;
- $this->isAddRow = $isAddRow;
- $this->item = $item;
-
- parent::__construct(($this->item) ? $this->item : new DataObject(), $parent);
-
- $this->fields = $this->createFields();
- }
- /**
- * Represents each cell of the table with an attribute.
- *
- * @return FieldList
- */
- public function createFields() {
- // Existing record
- if($this->item && $this->data) {
- $form = $this->data;
- $this->fieldset = $form->Fields();
- $this->fieldset->removeByName('SecurityID');
- if($this->fieldset) {
- $i=0;
- foreach($this->fieldset as $field) {
- $origFieldName = $field->getName();
-
- // set unique fieldname with id
- $combinedFieldName = $this->parent->getName() . "[" . $this->ID() . "][" . $origFieldName . "]";
- // ensure to set field to nested array notation
- // if its an unsaved row, or the "add row" which is present by default
- if($this->isAddRow || $this->ID() == 'new') $combinedFieldName .= '[]';
-
- // get value
- if(strpos($origFieldName,'.') === false) {
- $value = $field->dataValue();
- } else {
- // this supports the syntax fieldName = Relation.RelatedField
- $fieldNameParts = explode('.', $origFieldName) ;
- $tmpItem = $this->item;
- for($j=0;$j<sizeof($fieldNameParts);$j++) {
- $relationMethod = $fieldNameParts[$j];
- $idField = $relationMethod . 'ID';
- if($j == sizeof($fieldNameParts)-1) {
- $value = $tmpItem->$relationMethod;
- } else {
- $tmpItem = $tmpItem->$relationMethod();
- }
- }
- }
-
- $field->Name = $combinedFieldName;
- $field->setValue($field->dataValue());
- $field->addExtraClass('col'.$i);
- $field->setForm($this->data);
-
- // transformation
- if(isset($this->parent->transformationConditions[$origFieldName])) {
- $transformation = $this->parent->transformationConditions[$origFieldName]['transformation'];
- $rule = str_replace("\$","\$this->item->",
- $this->parent->transformationConditions[$origFieldName]['rule']);
- $ruleApplies = null;
- eval('$ruleApplies = ('.$rule.');');
- if($ruleApplies) {
- $field = $field->$transformation();
- }
- }
-
- // formatting
- $item = $this->item;
- $value = $field->Value();
- if(array_key_exists($origFieldName, $this->parent->fieldFormatting)) {
- $format = str_replace('$value', "__VAL__", $this->parent->fieldFormatting[$origFieldName]);
- $format = preg_replace('/\$([A-Za-z0-9-_]+)/','$item->$1', $format);
- $format = str_replace('__VAL__', '$value', $format);
- eval('$value = "' . $format . '";');
- $field->dontEscape = true;
- $field->setValue($value);
- }
-
- $this->fields[] = $field;
- $i++;
- }
- }
- // New record
- } else {
- $list = $this->parent->FieldList();
- $i=0;
- foreach($list as $fieldName => $fieldTitle) {