From 49375c45c480ab19ebe6f378626d96cfffbdfaef Mon Sep 17 00:00:00 2001 From: Romain Louis Date: Tue, 4 Sep 2007 03:30:59 +0000 Subject: [PATCH] Relation HasOne, HasMany and ManyMany ComplexTableField Adding git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@41200 467b73ca-7a2a-4603-9d3b-597d59a354a9 --- forms/HasManyComplexTableField.php | 61 +++++++++++ forms/HasOneComplexTableField.php | 132 ++++++++++++++++++++++++ forms/ManyManyComplexTableField.php | 76 ++++++++++++++ javascript/RelationComplexTableField.js | 112 ++++++++++++++++++++ 4 files changed, 381 insertions(+) create mode 100644 forms/HasManyComplexTableField.php create mode 100644 forms/HasOneComplexTableField.php create mode 100644 forms/ManyManyComplexTableField.php create mode 100644 javascript/RelationComplexTableField.js diff --git a/forms/HasManyComplexTableField.php b/forms/HasManyComplexTableField.php new file mode 100644 index 000000000..fafef6079 --- /dev/null +++ b/forms/HasManyComplexTableField.php @@ -0,0 +1,61 @@ +getParentIdNameRelation( $childClass, $parentClass, 'has_one' ); + } + + function getControllerID() { + return $this->controller->ID; + } + + function saveInto( DataObject $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 ] ) + $items = explode( ',', $list ); + + $saveDest->setByIDList( $items ); + } + + function ExtraData() { + $items = array(); + foreach( $this->unpagedSourceItems as $item ) { + if( $item->{$this->joinField} == $this->controller->ID ) + $items[] = $item->ID; + } + $list = implode( ',', $items ); + $inputId = $this->id() . '_' . $this->htmlListEndName; + return << +HTML; + } +} + +class HasManyComplexTableField_Item extends ComplexTableField_Item { + + function MarkingCheckbox() { + $name = $this->parent->Name() . '[]'; + + $joinVal = $this->item->{$this->parent->joinField}; + $parentID = $this->parent->getControllerID(); + + if( $this->parent->IsReadOnly || ! $this->Can( 'edit' ) || ( $joinVal > 0 && $joinVal != $parentID ) ) + return "item->ID}\" disabled=\"disabled\"/>"; + else if( $joinVal == $parentID ) + return "item->ID}\" checked=\"checked\"/>"; + else + return "item->ID}\"/>"; + } +} + +?> \ No newline at end of file diff --git a/forms/HasOneComplexTableField.php b/forms/HasOneComplexTableField.php new file mode 100644 index 000000000..1f7ccd782 --- /dev/null +++ b/forms/HasOneComplexTableField.php @@ -0,0 +1,132 @@ +Markable = true; + + $this->joinField = $this->getParentIdName( $this->controller->ClassName, $this->sourceClass ); + } + + function getQuery( $limitClause = null ) { + if( $this->customQuery ) { + $query = $this->customQuery; + $query->select[] = "{$this->sourceClass}.ID AS ID"; + $query->select[] = "{$this->sourceClass}.ClassName AS ClassName"; + $query->select[] = "{$this->sourceClass}.ClassName AS RecordClassName"; + } + else { + $query = singleton( $this->sourceClass )->extendedSQL( $this->sourceFilter, $this->sourceSort, $limitClause, $this->sourceJoin ); + + // Add more selected fields if they are from joined table. + + $SNG = singleton( $this->sourceClass ); + foreach( $this->FieldList() as $k => $title ) { + if( ! $SNG->hasField( $k ) && ! $SNG->hasMethod( 'get' . $k ) ) + $query->select[] = $k; + } + } + return clone $query; + } + + function sourceItems() { + if($this->sourceItems) + return $this->sourceItems; + + $limitClause = ''; + if( isset( $_REQUEST[ 'ctf' ][ $this->Name() ][ 'start' ] ) && is_numeric( $_REQUEST[ 'ctf' ][ $this->Name() ][ 'start' ] ) ) + $limitClause = $_REQUEST[ 'ctf' ][ $this->Name() ][ 'start' ] . ", $this->pageSize"; + else + $limitClause = "0, $this->pageSize"; + + $dataQuery = $this->getQuery( $limitClause ); + $records = $dataQuery->execute(); + $items = new DataObjectSet(); + foreach( $records as $record ) { + if( ! get_class( $record ) ) + $record = new DataObject( $record ); + $items->push( $record ); + } + + $dataQuery = $this->getQuery(); + $records = $dataQuery->execute(); + $unpagedItems = new DataObjectSet(); + foreach( $records as $record ) { + if( ! get_class( $record ) ) + $record = new DataObject( $record ); + $unpagedItems->push( $record ); + } + $this->unpagedSourceItems = $unpagedItems; + + $this->totalCount = ( $this->unpagedSourceItems ) ? $this->unpagedSourceItems->TotalItems() : null; + + return $items; + } + + function getControllerJoinID() { + return $this->controller->{$this->joinField}; + } + + function saveInto( DataObject $record ) { + $fieldName = $this->name; + $fieldNameID = $fieldName . 'ID'; + + if( $val = $this->value[ $this->htmlListField ] ) + $record->$fieldNameID = $val; + else + $record->$fieldNameID = 0; + + $record->write(); + } + + function setAddTitle( $addTitle ) { + if( is_string( $addTitle ) ) + $this->addTitle = $addTitle; + } + + function Title() { + return $this->addTitle ? $this->addTitle : parent::Title(); + } + + function ExtraData() { + $val = $this->getControllerJoinID() ? $this->getControllerJoinID() : ''; + $inputId = $this->id() . '_' . $this->htmlListEndName; + return << +HTML; + } +} + +class HasOneComplexTableField_Item extends ComplexTableField_Item { + + function MarkingCheckbox() { + $name = $this->parent->Name() . '[]'; + + $joinVal = $this->parent->getControllerJoinID(); + $childID = $this->item->ID; + + if( $this->parent->IsReadOnly || ! $this->Can( 'edit' ) ) + return "item->ID}\" disabled=\"disabled\"/>"; + else if( $joinVal == $childID ) + return "item->ID}\" checked=\"checked\"/>"; + else + return "item->ID}\"/>"; + } +} + +?> \ No newline at end of file diff --git a/forms/ManyManyComplexTableField.php b/forms/ManyManyComplexTableField.php new file mode 100644 index 000000000..81f0ac6d6 --- /dev/null +++ b/forms/ManyManyComplexTableField.php @@ -0,0 +1,76 @@ +controller->ClassName; + $manyManyTable = $parent . '_' . $this->name; + $source = $this->sourceClass; + $parentID = $this->controller->ID; + + $this->sourceJoin .= " LEFT JOIN `$manyManyTable` ON ( `$source`.`ID` = `{$source}ID` AND `{$parent}ID` = '$parentID' )"; + + $this->joinField = 'Checked'; + } + + function getQuery( $limitClause = null ) { + if( $this->customQuery ) { + $query = $this->customQuery; + $query->select[] = "{$this->sourceClass}.ID AS ID"; + $query->select[] = "{$this->sourceClass}.ClassName AS ClassName"; + $query->select[] = "{$this->sourceClass}.ClassName AS RecordClassName"; + } + else { + $query = singleton( $this->sourceClass )->extendedSQL( $this->sourceFilter, $this->sourceSort, $limitClause, $this->sourceJoin ); + + // Add more selected fields if they are from joined table. + + $SNG = singleton( $this->sourceClass ); + foreach( $this->FieldList() as $k => $title ) { + if( ! $SNG->hasField( $k ) && ! $SNG->hasMethod( 'get' . $k ) ) + $query->select[] = $k; + } + $parent = $this->controller->ClassName; + $query->select[] = "IF(`{$parent}ID` IS NULL, '0', '1') AS $this->joinField"; + } + return clone $query; + } + + function getParentIdName( $parentClass, $childClass ) { + return $this->getParentIdNameRelation( $parentClass, $childClass, 'many_many' ); + } + + function ExtraData() { + $items = array(); + foreach( $this->unpagedSourceItems as $item ) { + if( $item->{$this->joinField} ) + $items[] = $item->ID; + } + $list = implode( ',', $items ); + $inputId = $this->id() . '_' . $this->htmlListEndName; + return << +HTML; + } +} + +class ManyManyComplexTableField_Item extends ComplexTableField_Item { + + function MarkingCheckbox() { + $name = $this->parent->Name() . '[]'; + + if( $this->parent->IsReadOnly || ! $this->Can( 'edit' ) ) + return "item->ID}\" disabled=\"disabled\"/>"; + else if( $this->item->{$this->parent->joinField} ) + return "item->ID}\" checked=\"checked\"/>"; + else + return "item->ID}\"/>"; + } +} + +?> \ No newline at end of file diff --git a/javascript/RelationComplexTableField.js b/javascript/RelationComplexTableField.js new file mode 100644 index 000000000..754bb9c4d --- /dev/null +++ b/javascript/RelationComplexTableField.js @@ -0,0 +1,112 @@ +var checkedListNameArray = null; +var checkedListEndName = 'CheckedList'; +var checkedListField = 'selected'; +var checkedArray = null; + +Event.observe( window, 'load', function() { + $( 'sitetree' ).observeMethod( 'NodeClicked' , function() { + checkedListNameArray = null; + checkedArray = null; + } ); +} ); + +RelationComplexTableField = Class.create(); +RelationComplexTableField.prototype = { + + initialize: function() { + + // 1) Find The Hidden Field Where The IDs Will Be Stored + + var checkedList = document.getElementById( this.id + '_' + checkedListEndName ); + + // 2) Initialize The Array Or Update The Hidden Input Field And The HTML Table + + var checkedListName = checkedList.getAttribute( 'name' ); + if( checkedListNameArray == null ) { + checkedListNameArray = []; + checkedListNameArray.push( checkedListName ); + checkedArray = []; + if( checkedList.getAttribute( 'value' ) ) + checkedArray.push( checkedList.getAttribute( 'value' ).split( ',' ) ); + } + else if( checkedListNameArray.indexOf( checkedListName ) < 0 ) { + checkedListNameArray.push( checkedListName ); + if( checkedList.getAttribute( 'value' ) ) + checkedArray[ checkedListNameArray.length - 1 ] = checkedList.getAttribute( 'value' ).split( ',' ); + } + else { + + var index = checkedListNameArray.indexOf( checkedListName ); + + // a) Update The Hidden Input Field + + checkedList.setAttribute( 'value', checkedArray[ index ] ); + + // b) Update The HTML Table + + markingInputs = document.getElementsByName( checkedListName.substring( 0, checkedListName.indexOf( '[' ) ) + '[]' ); + + for( var i = 0; i < markingInputs.length; i++ ) { + markingInput = markingInputs[ i ]; + if( checkedArray[ index ] && checkedArray[ index ].indexOf( markingInput.getAttribute( 'value' ) ) > -1 ) { + markingInput.setAttribute( 'checked', 'checked' );} + else + markingInput.removeAttribute( 'checked' ); + } + } + + // 3) Create The Rules + + var rules = {}; + + rules[ '#' + this.id + ' table.data tbody td.markingcheckbox input' ] = { + onclick : function() { + + // 1) Find The Hidden Field Where The IDs Will Be Stored + + var checkedListName = this.getAttribute( 'name' ); + checkedListName = checkedListName.substring( 0, checkedListName.length - 1 ) + checkedListField + ']'; + var inputs = document.getElementsByTagName( 'input' ); + for( var i = 0; i < inputs.length; i++ ) { + var checkedList = inputs[ i ]; + if( checkedList.getAttribute( 'name' ) == checkedListName ) + break; + } + var index = checkedListNameArray.indexOf( checkedListName ); + + // 2) Update The Array + + if( checkedArray[ index ] && checkedArray[ index ].indexOf( this.getAttribute( 'value' ) ) > -1 ) { + index2 = checkedArray[ index ].indexOf( this.getAttribute( 'value' ) ); + var previousCheckedArray = checkedArray[ index ]; + checkedArray[ index ] = []; + for( var i = 0; i < previousCheckedArray.length; i++ ) { + if( i != index2 ) + checkedArray[ index ].push( previousCheckedArray[ i ] ); + } + if( this.getAttribute( 'type' ) == 'radio' ) + this.checked = false; + } + else if( checkedArray[ index ] ) { + if( this.getAttribute( 'type' ) == 'radio' ) + checkedArray[ index ] = []; + checkedArray[ index ].push( this.getAttribute( 'value' ) ); + } + else { + checkedArray[ index ] = []; + checkedArray[ index ].push( this.getAttribute( 'value' ) ); + } + + // 3) Update The Hidden Input Field + + checkedList.setAttribute( 'value', checkedArray[ index ] ); + } + }; + + Behaviour.register( rules ); + } +} + +RelationComplexTableField.applyTo('#Form_EditForm div.HasOneComplexTableField'); +RelationComplexTableField.applyTo('#Form_EditForm div.HasManyComplexTableField'); +RelationComplexTableField.applyTo('#Form_EditForm div.ManyManyComplexTableField'); \ No newline at end of file