mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
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
This commit is contained in:
parent
269d42bf73
commit
49375c45c4
61
forms/HasManyComplexTableField.php
Normal file
61
forms/HasManyComplexTableField.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
class HasManyComplexTableField extends HasOneComplexTableField {
|
||||
|
||||
protected $itemClass = 'HasManyComplexTableField_Item';
|
||||
|
||||
function getParentIdName( $parentClass, $childClass ) {
|
||||
return $this->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
|
||||
<input id="$inputId" name="{$this->name}[{$this->htmlListField}]" type="hidden" value="$list"/>
|
||||
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 "<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}\"/>";
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
132
forms/HasOneComplexTableField.php
Normal file
132
forms/HasOneComplexTableField.php
Normal file
@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
class HasOneComplexTableField extends ComplexTableField {
|
||||
|
||||
public $joinField;
|
||||
|
||||
protected $addTitle;
|
||||
|
||||
protected $htmlListEndName = 'CheckedList'; // If you change the value, do not forget to change it also in the JS file
|
||||
|
||||
protected $htmlListField = 'selected'; // If you change the value, do not forget to change it also in the JS file
|
||||
|
||||
protected $template = 'RelationComplexTableField';
|
||||
|
||||
protected $itemClass = 'HasOneComplexTableField_Item';
|
||||
|
||||
function __construct( $controller, $name, $sourceClass, $fieldList, $detailFormFields = null, $sourceFilter = "", $sourceSort = "", $sourceJoin = "") {
|
||||
|
||||
parent::__construct( $controller, $name, $sourceClass, $fieldList, $detailFormFields, $sourceFilter, $sourceSort, $sourceJoin );
|
||||
|
||||
$this->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
|
||||
<input id="$inputId" name="{$this->name}[{$this->htmlListField}]" type="hidden" value="$val"/>
|
||||
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 "<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}\"/>";
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
76
forms/ManyManyComplexTableField.php
Normal file
76
forms/ManyManyComplexTableField.php
Normal file
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
class ManyManyComplexTableField extends HasManyComplexTableField {
|
||||
|
||||
protected $itemClass = 'ManyManyComplexTableField_Item';
|
||||
|
||||
function __construct( $controller, $name, $sourceClass, $fieldList, $detailFormFields = null, $sourceFilter = "", $sourceSort = "", $sourceJoin = "") {
|
||||
|
||||
parent::__construct( $controller, $name, $sourceClass, $fieldList, $detailFormFields, $sourceFilter, $sourceSort, $sourceJoin );
|
||||
|
||||
$parent = $this->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
|
||||
<input id="$inputId" name="{$this->name}[{$this->htmlListField}]" type="hidden" value="$list"/>
|
||||
HTML;
|
||||
}
|
||||
}
|
||||
|
||||
class ManyManyComplexTableField_Item extends ComplexTableField_Item {
|
||||
|
||||
function MarkingCheckbox() {
|
||||
$name = $this->parent->Name() . '[]';
|
||||
|
||||
if( $this->parent->IsReadOnly || ! $this->Can( 'edit' ) )
|
||||
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}\"/>";
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
112
javascript/RelationComplexTableField.js
Normal file
112
javascript/RelationComplexTableField.js
Normal file
@ -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');
|
Loading…
Reference in New Issue
Block a user