2012-05-09 19:14:34 +02:00
< ? php
2017-05-27 06:45:28 +02:00
namespace UndefinedOffset\SortableGridField\Forms ;
use SilverStripe\Admin\ModelAdmin ;
use SilverStripe\Control\Controller ;
use SilverStripe\Core\ClassInfo ;
use SilverStripe\Core\Config\Config ;
use SilverStripe\Core\Extensible ;
2017-11-27 15:17:17 +01:00
use SilverStripe\Core\Injector\Injector ;
2017-05-27 06:45:28 +02:00
use SilverStripe\Forms\GridField\GridField ;
use SilverStripe\Forms\GridField\GridField_ActionProvider ;
use SilverStripe\Forms\GridField\GridField_DataManipulator ;
use SilverStripe\Forms\GridField\GridField_FormAction ;
use SilverStripe\Forms\GridField\GridField_HTMLProvider ;
use SilverStripe\Forms\GridField\GridFieldFilterHeader ;
use SilverStripe\Forms\GridField\GridFieldPaginator ;
use SilverStripe\Forms\GridField\GridFieldSortableHeader ;
use SilverStripe\ORM\DataList ;
use SilverStripe\ORM\DataObject ;
2017-11-27 15:17:17 +01:00
use SilverStripe\ORM\DataObjectSchema ;
2017-05-27 06:45:28 +02:00
use SilverStripe\ORM\DataQuery ;
use SilverStripe\ORM\DB ;
use SilverStripe\ORM\ManyManyList ;
2018-12-13 19:05:12 +01:00
use SilverStripe\ORM\ManyManyThroughList ;
2017-05-27 06:45:28 +02:00
use SilverStripe\ORM\RelationList ;
use SilverStripe\ORM\SS_List ;
use SilverStripe\ORM\UnsavedRelationList ;
use SilverStripe\ORM\ValidationException ;
use SilverStripe\Versioned\Versioned ;
2017-11-01 13:34:29 +01:00
use SilverStripe\View\ArrayData ;
2017-05-27 06:45:28 +02:00
use SilverStripe\View\Requirements ;
2012-05-09 19:14:34 +02:00
/**
2012-05-15 16:04:40 +02:00
* This component provides a checkbox which when checked enables drag - and - drop re - ordering of elements displayed in a { @ link GridField }
*
2012-05-09 19:14:34 +02:00
* @ package forms
*/
2017-05-27 06:45:28 +02:00
class GridFieldSortableRows implements GridField_HTMLProvider , GridField_ActionProvider , GridField_DataManipulator
{
/** @var string */
protected $sortColumn ;
/** @var bool */
protected $disable_selection = true ;
/** @var bool */
protected $append_to_top = false ;
/** @var null|string */
protected $update_versioned_stage = null ;
/** @var null|string */
protected $custom_relation_name = null ;
/**
* @ param string $sortColumn Column that should be used to update the sort information
* @ param bool $disableSelection Disable selection on the GridField when dragging
* @ param string $updateVersionStage Name of the versioned stage to update this disabled by default unless this is set
* @ param string $customRelationName Name of the relationship to use , if left null the name is determined from the GridField ' s name
*/
public function __construct ( $sortColumn , $disableSelection = true , $updateVersionStage = null , $customRelationName = null )
{
$this -> sortColumn = $sortColumn ;
$this -> disable_selection = $disableSelection ;
$this -> update_versioned_stage = $updateVersionStage ;
$this -> custom_relation_name = $customRelationName ;
}
/**
* Returns a map where the keys are fragment names and the values are pieces of HTML to add to these fragments .
* @ param GridField $gridField Grid Field Reference
* @ return array Map where the keys are fragment names and the values are pieces of HTML to add to these fragments .
*/
public function getHTMLFragments ( $gridField )
{
$dataList = $gridField -> getList ();
if ( class_exists ( 'UnsavedRelationList' ) && $dataList instanceof UnsavedRelationList ) {
return array ();
}
$state = $gridField -> State -> GridFieldSortableRows ;
if ( ! is_bool ( $state -> sortableToggle )) {
$state -> sortableToggle = false ;
}
//Ensure user can edit
if ( ! singleton ( $gridField -> getModelClass ()) -> canEdit ()) {
return array ();
}
//Sort order toggle
$sortOrderToggle = GridField_FormAction :: create (
$gridField ,
'sortablerows-toggle' ,
'sorttoggle' ,
'sortableRowsToggle' ,
null
) -> addExtraClass ( 'sortablerows-toggle' );
$sortOrderSave = GridField_FormAction :: create (
$gridField ,
'sortablerows-savesort' ,
'savesort' ,
'saveGridRowSort' ,
null
) -> addExtraClass ( 'sortablerows-savesort' );
//Sort to Page Action
$sortToPage = GridField_FormAction :: create (
$gridField ,
'sortablerows-sorttopage' ,
'sorttopage' ,
'sortToPage' ,
null
) -> addExtraClass ( 'sortablerows-sorttopage' );
$data = array ( 'SortableToggle' => $sortOrderToggle ,
'SortOrderSave' => $sortOrderSave ,
'SortToPage' => $sortToPage ,
'Checked' => ( $state -> sortableToggle == true ? ' checked = "checked"' : '' ),
'List' => $dataList );
$forTemplate = new arrayData ( $data );
2017-11-01 13:34:29 +01:00
Requirements :: css ( 'undefinedoffset/sortablegridfield:css/GridFieldSortableRows.css' );
Requirements :: javascript ( 'undefinedoffset/sortablegridfield:javascript/GridFieldSortableRows.js' );
2017-05-27 06:45:28 +02:00
$args = array ( 'Colspan' => count ( $gridField -> getColumns ()), 'ID' => $gridField -> ID (), 'DisableSelection' => $this -> disable_selection );
$fragments = array ( 'header' => $forTemplate -> renderWith ( 'SortableGridField\Forms\Includes\GridFieldSortableRows' , $args ));
if ( $gridField -> getConfig () -> getComponentByType ( GridFieldPaginator :: class )) {
$fragments [ 'after' ] = $forTemplate -> renderWith ( 'SortableGridField\Forms\Includes\GridFieldSortableRows_paginator' );
}
return $fragments ;
}
/**
* Manipulate the datalist as needed by this grid modifier .
* @ param GridField $gridField Grid Field Reference
* @ param SS_List | DataList $dataList Data List to adjust
* @ return DataList Modified Data List
*/
public function getManipulatedData ( GridField $gridField , SS_List $dataList )
{
//Detect and correct items with a sort column value of 0 (push to bottom)
$this -> fixSortColumn ( $gridField , $dataList );
$headerState = $gridField -> State -> GridFieldSortableHeader ;
$state = $gridField -> State -> GridFieldSortableRows ;
if (( ! is_bool ( $state -> sortableToggle ) || $state -> sortableToggle === false ) && $headerState && is_string ( $headerState -> SortColumn ) && is_string ( $headerState -> SortDirection )) {
return $dataList -> sort ( $headerState -> SortColumn , $headerState -> SortDirection );
}
if ( $state -> sortableToggle === true ) {
$gridField -> getConfig () -> removeComponentsByType ( GridFieldFilterHeader :: class );
$gridField -> getConfig () -> removeComponentsByType ( GridFieldSortableHeader :: class );
}
return $dataList -> sort ( $this -> sortColumn );
}
/**
* Sets if new records should be appended to the top or the bottom of the list
* @ param bool $value Boolean true to append to the top false to append to the bottom
* @ return GridFieldSortableRows Returns the current instance
*/
public function setAppendToTop ( $value )
{
$this -> append_to_top = $value ;
return $this ;
}
/**
* @ param bool $value Boolean true to disable selection of table contents false to enable selection
* @ return GridFieldSortableRows Returns the current instance
*/
public function setDisableSelection ( $value )
{
$this -> disable_selection = $value ;
return $this ;
}
/**
* Sets the suffix of the versioned stage that should be updated along side the default stage
* @ param string $value Versioned Stage to update this is disabled by default unless this is set
* @ return GridFieldSortableRows Returns the current instance
*/
public function setUpdateVersionedStage ( $value )
{
$this -> update_versioned_stage = $value ;
return $this ;
}
/**
* Sets the name of the relationship to use , by default the name is determined from the GridField ' s name
* @ param string $value Name of the relationship to use , by default the name is determined from the GridField ' s name
* @ return GridFieldSortableRows Returns the current instance
*/
public function setCustomRelationName ( $value )
{
$this -> custom_relation_name = $value ;
return $this ;
}
/**
* Detects and corrects items with a sort column value of 0 , by appending them to the bottom of the list
* @ param GridField $gridField Grid Field Reference
* @ param SS_List | DataList $dataList Data List of items to be checked
*/
protected function fixSortColumn ( $gridField , SS_List $dataList )
{
if ( $dataList instanceof UnsavedRelationList ) {
return ;
}
/** @var SS_List|DataList $list */
$list = clone $dataList ;
$list = $list -> alterDataQuery ( function ( $query , SS_List $tmplist ) {
/** @var DataQuery $query */
$query -> limit ( array ());
return $query ;
});
$many_many = ( $list instanceof ManyManyList );
if ( ! $many_many ) {
2018-12-13 19:05:12 +01:00
if ( $list instanceof ManyManyThroughList ) {
$fieldType = $list -> getExtraFields ();
$fieldType = $fieldType [ $this -> sortColumn ];
} else {
$sng = singleton ( $gridField -> getModelClass ());
$fieldType = $sng -> config () -> db [ $this -> sortColumn ];
}
2017-05-27 06:45:28 +02:00
2018-03-07 14:46:08 +01:00
if ( ! $fieldType || ! ( $fieldType == 'Int' || $fieldType == 'SilverStripe\\ORM\\FieldType\\DBInt' || is_subclass_of ( $fieldType , 'SilverStripe\\ORM\\FieldType\\DBInt' ))) {
2017-05-27 06:45:28 +02:00
if ( is_array ( $fieldType )) {
user_error ( 'Sort column ' . $this -> sortColumn . ' could not be found in ' . $gridField -> getModelClass () . '\'s ancestry' , E_USER_ERROR );
} else {
2018-03-01 15:45:44 +01:00
user_error ( 'Sort column ' . $this -> sortColumn . ' must be an instance of SilverStripe\\ORM\\FieldType\\DBInt, column is of type ' . $fieldType , E_USER_ERROR );
2017-05-27 06:45:28 +02:00
}
exit ;
}
}
$max = $list -> Max ( $this -> sortColumn );
$list = $list -> filter ( $this -> sortColumn , 0 ) -> sort ( " Created,ID " );
if ( $list -> Count () > 0 ) {
$owner = $gridField -> getForm () -> getRecord ();
$sortColumn = $this -> sortColumn ;
$i = 1 ;
if ( $many_many ) {
2017-11-27 15:17:17 +01:00
$schema = Injector :: inst () -> get ( DataObjectSchema :: class );
$componentDetails = $schema -> manyManyComponent ( get_class ( $owner ), ( ! empty ( $this -> custom_relation_name ) ? $this -> custom_relation_name : $gridField -> getName ()));
$parentField = $componentDetails [ 'parentField' ];
$componentField = $componentDetails [ 'childField' ];
$table = $componentDetails [ 'join' ];
2017-05-27 06:45:28 +02:00
2017-11-27 15:17:17 +01:00
$extraFields = $schema -> manyManyExtraFieldsForComponent ( get_class ( $owner ), ( ! empty ( $this -> custom_relation_name ) ? $this -> custom_relation_name : $gridField -> getName ()));
2017-05-27 06:45:28 +02:00
2018-03-07 14:46:08 +01:00
if ( ! $extraFields || ! array_key_exists ( $this -> sortColumn , $extraFields ) || ! ( $extraFields [ $this -> sortColumn ] == 'Int' || $extraFields [ $this -> sortColumn ] == 'SilverStripe\\ORM\\FieldType\\DBInt' || is_subclass_of ( 'SilverStripe\\ORM\\FieldType\\DBInt' , $extraFields [ $this -> sortColumn ]))) {
2017-11-27 15:17:17 +01:00
user_error ( 'Sort column ' . $this -> sortColumn . ' must be an SilverStripe\\ORM\\FieldType\\DBInt, column is of type ' . $extraFields [ $this -> sortColumn ], E_USER_ERROR );
2017-05-27 06:45:28 +02:00
exit ;
}
} else {
//Find table containing the sort column
$table = false ;
$class = $gridField -> getModelClass ();
$db = Config :: inst () -> get ( $class , " db " , CONFIG :: UNINHERITED );
if ( ! empty ( $db ) && array_key_exists ( $sortColumn , $db )) {
2017-12-11 16:49:30 +01:00
$table = DataObject :: getSchema () -> tableName ( $class );
2017-05-27 06:45:28 +02:00
} else {
$classes = ClassInfo :: ancestry ( $class , true );
foreach ( $classes as $class ) {
$db = Config :: inst () -> get ( $class , " db " , CONFIG :: UNINHERITED );
if ( ! empty ( $db ) && array_key_exists ( $sortColumn , $db )) {
2017-12-11 16:49:30 +01:00
$table = DataObject :: getSchema () -> tableName ( $class );
2017-05-27 06:45:28 +02:00
break ;
}
}
}
if ( $table === false ) {
user_error ( 'Sort column ' . $this -> sortColumn . ' could not be found in ' . $gridField -> getModelClass () . '\'s ancestry' , E_USER_ERROR );
exit ;
}
$baseDataClass = DataObject :: getSchema () -> baseDataClass ( $gridField -> getModelClass ());
2017-12-11 17:27:42 +01:00
$baseDataTable = DataObject :: getSchema () -> tableName ( $baseDataClass );
2017-05-27 06:45:28 +02:00
}
//Start transaction if supported
if ( DB :: get_conn () -> supportsTransactions ()) {
DB :: get_conn () -> transactionStart ();
}
$idCondition = null ;
if ( $this -> append_to_top && ! ( $list instanceof RelationList )) {
$idCondition = '"ID" IN(\'' . implode ( " ',' " , $dataList -> getIDList ()) . '\')' ;
}
if ( $this -> append_to_top ) {
$topIncremented = array ();
}
2018-07-04 19:00:42 +02:00
$modelClass = $gridField -> getModelClass ();
$hasVersioned = $this -> hasVersionedExtension ( $modelClass );
2017-05-27 06:45:28 +02:00
foreach ( $list as $obj ) {
if ( $many_many ) {
if ( $this -> append_to_top ) {
//Upgrade all the records (including the last inserted from 0 to 1)
DB :: query ( 'UPDATE "' . $table
. '" SET "' . $sortColumn . '" = "' . $sortColumn . '"+1'
. ' WHERE "' . $parentField . '" = ' . $owner -> ID . ( ! empty ( $topIncremented ) ? ' AND "' . $componentField . '" NOT IN(\'' . implode ( '\',\'' , $topIncremented ) . '\')' : '' ));
$topIncremented [] = $obj -> ID ;
} else {
//Append the last record to the bottom
DB :: query ( 'UPDATE "' . $table
. '" SET "' . $sortColumn . '" = ' . ( $max + $i )
. ' WHERE "' . $componentField . '" = ' . $obj -> ID . ' AND "' . $parentField . '" = ' . $owner -> ID );
}
} else if ( $this -> append_to_top ) {
2018-07-04 19:00:42 +02:00
if ( $hasVersioned ) {
// For versioned objects, modify them with the ORM so that the *_versions table is updated
$itemsToUpdate = $modelClass :: get () -> where (( $list instanceof RelationList ? '"' . $list -> foreignKey . '" = ' . $owner -> ID : $idCondition ) . ( ! empty ( $topIncremented ) ? ' AND "ID" NOT IN(\'' . implode ( '\',\'' , $topIncremented ) . '\')' : '' ));
if ( $itemsToUpdate -> exists ()) {
foreach ( $itemsToUpdate as $item ) {
$item -> $sortColumn = $item -> $sortColumn + 1 ;
$item -> write ();
}
}
} else {
//Upgrade all the records (including the last inserted from 0 to 1)
DB :: query ( 'UPDATE "' . $table
. '" SET "' . $sortColumn . '" = "' . $sortColumn . '"+1'
. ' WHERE ' . ( $list instanceof RelationList ? '"' . $list -> foreignKey . '" = ' . $owner -> ID : $idCondition ) . ( ! empty ( $topIncremented ) ? ' AND "ID" NOT IN(\'' . implode ( '\',\'' , $topIncremented ) . '\')' : '' ));
}
2017-05-27 06:45:28 +02:00
2017-12-11 17:27:42 +01:00
if ( $this -> update_versioned_stage && $this -> hasVersionedExtension ( $gridField -> getModelClass ())) {
2017-05-27 06:45:28 +02:00
DB :: query ( 'UPDATE "' . $table . '_' . $this -> update_versioned_stage
. '" SET "' . $sortColumn . '" = "' . $sortColumn . '"+1'
. ' WHERE ' . ( $list instanceof RelationList ? '"' . $list -> foreignKey . '" = ' . $owner -> ID : $idCondition ) . ( ! empty ( $topIncremented ) ? ' AND "ID" NOT IN(\'' . implode ( '\',\'' , $topIncremented ) . '\')' : '' ));
}
$topIncremented [] = $obj -> ID ;
} else {
2018-07-04 19:00:42 +02:00
if ( $hasVersioned ) {
// For versioned objects, modify them with the ORM so that the *_versions table is updated
$obj -> $sortColumn = ( $max + $i );
$obj -> write ();
} else {
//Append the last record to the bottom
DB :: query ( 'UPDATE "' . $table
. '" SET "' . $sortColumn . '" = ' . ( $max + $i )
. ' WHERE "ID" = ' . $obj -> ID );
//LastEdited
DB :: query ( 'UPDATE "' . $baseDataTable
. '" SET "LastEdited" = \'' . date ( 'Y-m-d H:i:s' ) . '\''
. ' WHERE "ID" = ' . $obj -> ID );
}
2017-05-27 06:45:28 +02:00
2017-12-11 17:27:42 +01:00
if ( $this -> update_versioned_stage && $this -> hasVersionedExtension ( $gridField -> getModelClass ())) {
2017-05-27 06:45:28 +02:00
DB :: query ( 'UPDATE "' . $table . '_' . $this -> update_versioned_stage
. '" SET "' . $sortColumn . '" = ' . ( $max + $i )
. ' WHERE "ID" = ' . $obj -> ID );
2017-12-11 17:27:42 +01:00
if ( $this -> hasVersionedExtension ( $baseDataClass )) {
DB :: query ( 'UPDATE "' . $baseDataTable . '_' . $this -> update_versioned_stage
2017-05-27 06:45:28 +02:00
. '" SET "LastEdited" = \'' . date ( 'Y-m-d H:i:s' ) . '\''
. ' WHERE "ID" = ' . $obj -> ID );
}
}
}
$i ++ ;
}
//Update LastEdited for affected records when using append to top on a many_many relationship
if ( ! $many_many && $this -> append_to_top && count ( $topIncremented ) > 0 ) {
2017-12-11 17:27:42 +01:00
DB :: query ( 'UPDATE "' . $baseDataTable
2017-05-27 06:45:28 +02:00
. '" SET "LastEdited" = \'' . date ( 'Y-m-d H:i:s' ) . '\''
. ' WHERE "ID" IN(\'' . implode ( '\',\'' , $topIncremented ) . '\')' );
2017-12-11 17:27:42 +01:00
if ( $this -> update_versioned_stage && $this -> hasVersionedExtension ( $gridField -> getModelClass ()) && $this -> hasVersionedExtension ( $baseDataClass )) {
DB :: query ( 'UPDATE "' . $baseDataTable . '_' . $this -> update_versioned_stage
2017-05-27 06:45:28 +02:00
. '" SET "LastEdited" = \'' . date ( 'Y-m-d H:i:s' ) . '\''
. ' WHERE "ID" IN(\'' . implode ( '\',\'' , $topIncremented ) . '\')' );
}
}
//End transaction if supported
if ( DB :: get_conn () -> supportsTransactions ()) {
DB :: get_conn () -> transactionEnd ();
}
}
}
/**
* Return a list of the actions handled by this action provider .
* @ param GridField $gridField Grid Field Reference
* @ return array array with action identifier strings .
*/
public function getActions ( $gridField )
{
return array ( 'saveGridRowSort' , 'sortableRowsToggle' , 'sortToPage' );
}
/**
* Handle an action on the given grid field .
* @ param GridField $gridField Grid Field Reference
* @ param String $actionName Action identifier , see { @ link getActions ()} .
* @ param array $arguments Arguments relevant for this
* @ param array $data All form data
*/
public function handleAction ( GridField $gridField , $actionName , $arguments , $data )
{
$state = $gridField -> State -> GridFieldSortableRows ;
if ( ! is_bool ( $state -> sortableToggle )) {
$state -> sortableToggle = false ;
} else if ( $state -> sortableToggle == true ) {
$gridField -> getConfig () -> removeComponentsByType ( GridFieldFilterHeader :: class );
$gridField -> getConfig () -> removeComponentsByType ( GridFieldSortableHeader :: class );
}
if ( $actionName == 'savegridrowsort' ) {
return $this -> saveGridRowSort ( $gridField , $data );
} else if ( $actionName == 'sorttopage' ) {
return $this -> sortToPage ( $gridField , $data );
}
}
/**
* Handles saving of the row sort order
* @ param GridField $gridField Grid Field Reference
* @ param array $data Data submitted in the request
* @ throws ValidationException If user has no edit permissions
*/
protected function saveGridRowSort ( GridField $gridField , $data )
{
$dataList = $gridField -> getList ();
if ( $dataList instanceof UnsavedRelationList ) {
user_error ( 'Cannot sort an UnsavedRelationList' , E_USER_ERROR );
return ;
}
if ( ! singleton ( $gridField -> getModelClass ()) -> canEdit ()) {
throw new ValidationException ( _t ( 'GridFieldSortableRows.EditPermissionsFailure' , " No edit permissions " ), 0 );
}
if ( empty ( $data [ 'ItemIDs' ])) {
user_error ( 'No items to sort' , E_USER_ERROR );
}
$className = $gridField -> getModelClass ();
$owner = $gridField -> Form -> getRecord ();
$items = clone $gridField -> getList ();
$many_many = ( $items instanceof ManyManyList );
$sortColumn = $this -> sortColumn ;
$pageOffset = 0 ;
if ( $paginator = $gridField -> getConfig () -> getComponentsByType ( GridFieldPaginator :: class ) -> First ()) {
$pageState = $gridField -> State -> GridFieldPaginator ;
if ( $pageState -> currentPage && is_int ( $pageState -> currentPage ) && $pageState -> currentPage > 1 ) {
$pageOffset = $paginator -> getItemsPerPage () * ( $pageState -> currentPage - 1 );
}
}
if ( $many_many ) {
2017-11-27 15:17:17 +01:00
$schema = Injector :: inst () -> get ( DataObjectSchema :: class );
$componentDetails = $schema -> manyManyComponent ( get_class ( $owner ), ( ! empty ( $this -> custom_relation_name ) ? $this -> custom_relation_name : $gridField -> getName ()));
$parentField = $componentDetails [ 'parentField' ];
$componentField = $componentDetails [ 'childField' ];
$table = $componentDetails [ 'join' ];
2017-05-27 06:45:28 +02:00
} else {
//Find table containing the sort column
$table = false ;
$class = $gridField -> getModelClass ();
$db = Config :: inst () -> get ( $class , " db " , CONFIG :: UNINHERITED );
if ( ! empty ( $db ) && array_key_exists ( $sortColumn , $db )) {
2017-12-11 16:49:30 +01:00
$table = DataObject :: getSchema () -> tableName ( $class );
2017-05-27 06:45:28 +02:00
} else {
$classes = ClassInfo :: ancestry ( $class , true );
foreach ( $classes as $class ) {
$db = Config :: inst () -> get ( $class , " db " , CONFIG :: UNINHERITED );
if ( ! empty ( $db ) && array_key_exists ( $sortColumn , $db )) {
2017-12-11 16:49:30 +01:00
$table = DataObject :: getSchema () -> tableName ( $class );
2017-05-27 06:45:28 +02:00
break ;
}
}
}
if ( $table === false ) {
user_error ( 'Sort column ' . $this -> sortColumn . ' could not be found in ' . $gridField -> getModelClass () . '\'s ancestry' , E_USER_ERROR );
exit ;
}
$baseDataClass = DataObject :: getSchema () -> baseDataClass ( $gridField -> getModelClass ());
2017-12-11 17:27:42 +01:00
$baseDataTable = DataObject :: getSchema () -> tableName ( $baseDataClass );
2017-05-27 06:45:28 +02:00
}
//Event to notify the Controller or owner DataObject before list sort
if ( $owner && $owner instanceof DataObject && method_exists ( $owner , 'onBeforeGridFieldRowSort' )) {
$owner -> onBeforeGridFieldRowSort ( clone $items );
} else if ( Controller :: has_curr () && Controller :: curr () instanceof ModelAdmin && method_exists ( Controller :: curr (), 'onBeforeGridFieldRowSort' )) {
Controller :: curr () -> onBeforeGridFieldRowSort ( clone $items );
}
//Start transaction if supported
if ( DB :: get_conn () -> supportsTransactions ()) {
DB :: get_conn () -> transactionStart ();
}
//Perform sorting
$ids = explode ( ',' , $data [ 'ItemIDs' ]);
2018-07-04 19:00:42 +02:00
$modelClass = $gridField -> getModelClass ();
$hasVersioned = $this -> hasVersionedExtension ( $modelClass );
2017-05-27 06:45:28 +02:00
for ( $sort = 0 ; $sort < count ( $ids ); $sort ++ ) {
$id = intval ( $ids [ $sort ]);
if ( $many_many ) {
DB :: query ( 'UPDATE "' . $table
. '" SET "' . $sortColumn . '" = ' . (( $sort + 1 ) + $pageOffset )
. ' WHERE "' . $componentField . '" = ' . $id . ' AND "' . $parentField . '" = ' . $owner -> ID );
} else {
2018-07-04 19:00:42 +02:00
if ( $hasVersioned ) {
// For versioned objects, modify them with the ORM so that the *_versions table is updated
$obj = $modelClass :: get () -> byID ( intval ( $id ));
if ( ! empty ( $obj ) && $obj !== false && $obj -> exists ()) {
$obj -> $sortColumn = (( $sort + 1 ) + $pageOffset );
$obj -> write ();
}
} else {
DB :: query ( 'UPDATE "' . $table
. '" SET "' . $sortColumn . '" = ' . (( $sort + 1 ) + $pageOffset )
. ' WHERE "ID" = ' . $id );
2017-05-27 06:45:28 +02:00
2018-07-04 19:00:42 +02:00
DB :: query ( 'UPDATE "' . $baseDataTable
. '" SET "LastEdited" = \'' . date ( 'Y-m-d H:i:s' ) . '\''
. ' WHERE "ID" = ' . $id );
}
2017-05-27 06:45:28 +02:00
2018-07-04 19:00:42 +02:00
if ( $this -> update_versioned_stage && $hasVersioned ) {
2017-05-27 06:45:28 +02:00
DB :: query ( 'UPDATE "' . $table . '_' . $this -> update_versioned_stage
. '" SET "' . $sortColumn . '" = ' . (( $sort + 1 ) + $pageOffset )
. ' WHERE "ID" = ' . $id );
2017-12-11 17:27:42 +01:00
if ( $this -> hasVersionedExtension ( $baseDataClass )) {
DB :: query ( 'UPDATE "' . $baseDataTable . '_' . $this -> update_versioned_stage
2017-05-27 06:45:28 +02:00
. '" SET "LastEdited" = \'' . date ( 'Y-m-d H:i:s' ) . '\''
. ' WHERE "ID" = ' . $id );
}
}
}
}
//End transaction if supported
if ( DB :: get_conn () -> supportsTransactions ()) {
DB :: get_conn () -> transactionEnd ();
}
//Event to notify the Controller or owner DataObject after list sort
if ( $owner && $owner instanceof DataObject && method_exists ( $owner , 'onAfterGridFieldRowSort' )) {
$owner -> onAfterGridFieldRowSort ( clone $items );
} else if ( Controller :: has_curr () && Controller :: curr () instanceof ModelAdmin && method_exists ( Controller :: curr (), 'onAfterGridFieldRowSort' )) {
Controller :: curr () -> onAfterGridFieldRowSort ( clone $items );
}
}
/**
* Handles sorting across pages
* @ param GridField $gridField Grid Field Reference
* @ param array $data Data submitted in the request
*/
protected function sortToPage ( GridField $gridField , $data )
{
if ( ! $paginator = $gridField -> getConfig () -> getComponentsByType ( GridFieldPaginator :: class ) -> First ()) {
user_error ( 'Paginator not detected' , E_USER_ERROR );
}
if ( empty ( $data [ 'ItemID' ])) {
user_error ( 'No item to sort' , E_USER_ERROR );
}
if ( empty ( $data [ 'Target' ])) {
user_error ( 'No target page' , E_USER_ERROR );
}
/** @var Extensible $className */
$className = $gridField -> getModelClass ();
$owner = $gridField -> Form -> getRecord ();
/** @var DataList $items */
$items = clone $gridField -> getList ();
$many_many = ( $items instanceof ManyManyList );
$sortColumn = $this -> sortColumn ;
$targetItem = $items -> byID ( intval ( $data [ 'ItemID' ]));
if ( ! $targetItem ) {
user_error ( 'Target item not found' , E_USER_ERROR );
}
$currentPage = 1 ;
$pageState = $gridField -> State -> GridFieldPaginator ;
if ( $pageState -> currentPage && $pageState -> currentPage > 1 ) {
$currentPage = $pageState -> currentPage ;
}
if ( $many_many ) {
2017-12-11 16:49:30 +01:00
$schema = Injector :: inst () -> get ( DataObjectSchema :: class );
$componentDetails = $schema -> manyManyComponent ( get_class ( $owner ), ( ! empty ( $this -> custom_relation_name ) ? $this -> custom_relation_name : $gridField -> getName ()));
$parentField = $componentDetails [ 'parentField' ];
$componentField = $componentDetails [ 'childField' ];
$table = $componentDetails [ 'join' ];
2017-05-27 06:45:28 +02:00
}
if ( $data [ 'Target' ] == 'previouspage' ) {
$items = $items -> limit ( $paginator -> getItemsPerPage () + 1 , ( $paginator -> getItemsPerPage () * ( $currentPage - 1 )) - 1 );
} else if ( $data [ 'Target' ] == 'nextpage' ) {
$items = $items -> limit ( $paginator -> getItemsPerPage () + 1 , $paginator -> getItemsPerPage () * ( $currentPage - 1 ));
} else {
user_error ( 'Not implemented: ' . $data [ 'Target' ], E_USER_ERROR );
}
$sortPositions = $items -> column ( $sortColumn );
//Event to notify the Controller or owner DataObject before list sort
if ( $owner && $owner instanceof DataObject && method_exists ( $owner , 'onBeforeGridFieldPageSort' )) {
$owner -> onBeforeGridFieldPageSort ( clone $items );
} else if ( Controller :: has_curr () && Controller :: curr () instanceof ModelAdmin && method_exists ( Controller :: curr (), 'onBeforeGridFieldPageSort' )) {
Controller :: curr () -> onBeforeGridFieldPageSort ( clone $items );
}
//Find the sort column
if ( $this -> update_versioned_stage && $this -> hasVersionedExtension ( $className )) {
$table = false ;
$classes = ClassInfo :: ancestry ( $className , true );
foreach ( $classes as $class ) {
$db = Config :: inst () -> get ( $class , " db " , CONFIG :: UNINHERITED );
if ( ! empty ( $db ) && array_key_exists ( $sortColumn , $db )) {
2017-12-11 16:49:30 +01:00
$table = DataObject :: getSchema () -> tableName ( $class );
2017-05-27 06:45:28 +02:00
break ;
}
}
if ( $table === false ) {
user_error ( 'Sort column ' . $this -> sortColumn . ' could not be found in ' . $gridField -> getModelClass () . '\'s ancestry' , E_USER_ERROR );
exit ;
}
}
//Start transaction if supported
if ( DB :: get_conn () -> supportsTransactions ()) {
DB :: get_conn () -> transactionStart ();
}
if ( $data [ 'Target' ] == 'previouspage' ) {
if ( $many_many ) {
DB :: query ( 'UPDATE "' . $table
. '" SET "' . $sortColumn . '" = ' . $sortPositions [ 0 ]
. ' WHERE "' . $componentField . '" = ' . $targetItem -> ID . ' AND "' . $parentField . '" = ' . $owner -> ID );
} else {
$targetItem -> $sortColumn = $sortPositions [ 0 ];
$targetItem -> write ();
if ( $this -> update_versioned_stage && $this -> hasVersionedExtension ( $className )) {
DB :: query ( 'UPDATE "' . $table . '_' . $this -> update_versioned_stage
. '" SET "' . $sortColumn . '" = ' . $sortPositions [ 0 ]
. ' WHERE "ID" = ' . $targetItem -> ID );
}
}
$i = 1 ;
foreach ( $items as $obj ) {
2018-05-31 19:56:51 +02:00
if ( $obj -> ID == $targetItem -> ID || $i >= count ( $sortPositions )) {
2017-05-27 06:45:28 +02:00
continue ;
}
if ( $many_many ) {
DB :: query ( 'UPDATE "' . $table
. '" SET "' . $sortColumn . '" = ' . $sortPositions [ $i ]
. ' WHERE "' . $componentField . '" = ' . $obj -> ID . ' AND "' . $parentField . '" = ' . $owner -> ID );
} else {
$obj -> $sortColumn = $sortPositions [ $i ];
$obj -> write ();
if ( $this -> update_versioned_stage && $this -> hasVersionedExtension ( $className )) {
DB :: query ( 'UPDATE "' . $table . '_' . $this -> update_versioned_stage
. '" SET "' . $sortColumn . '" = ' . $sortPositions [ $i ]
. ' WHERE "ID" = ' . $obj -> ID );
}
}
$i ++ ;
}
} else {
if ( $many_many ) {
DB :: query ( 'UPDATE "' . $table
. '" SET "' . $sortColumn . '" = ' . $sortPositions [ count ( $sortPositions ) - 1 ]
. ' WHERE "' . $componentField . '" = ' . $targetItem -> ID . ' AND "' . $parentField . '" = ' . $owner -> ID );
} else {
$targetItem -> $sortColumn = $sortPositions [ count ( $sortPositions ) - 1 ];
$targetItem -> write ();
if ( $this -> update_versioned_stage && $this -> hasVersionedExtension ( $className )) {
DB :: query ( 'UPDATE "' . $table . '_' . $this -> update_versioned_stage
. '" SET "' . $sortColumn . '" = ' . $sortPositions [ count ( $sortPositions ) - 1 ]
. ' WHERE "ID" = ' . $targetItem -> ID );
}
}
$i = 0 ;
foreach ( $items as $obj ) {
if ( $obj -> ID == $targetItem -> ID ) {
continue ;
}
if ( $many_many ) {
DB :: query ( 'UPDATE "' . $table
. '" SET "' . $sortColumn . '" = ' . $sortPositions [ $i ]
. ' WHERE "' . $componentField . '" = ' . $obj -> ID . ' AND "' . $parentField . '" = ' . $owner -> ID );
} else {
$obj -> $sortColumn = $sortPositions [ $i ];
$obj -> write ();
if ( $this -> update_versioned_stage && $this -> hasVersionedExtension ( $className )) {
DB :: query ( 'UPDATE "' . $table . '_' . $this -> update_versioned_stage
. '" SET "' . $sortColumn . '" = ' . $sortPositions [ $i ]
. ' WHERE "ID" = ' . $obj -> ID );
}
}
$i ++ ;
}
}
//End transaction if supported
if ( DB :: get_conn () -> supportsTransactions ()) {
DB :: get_conn () -> transactionEnd ();
}
//Event to notify the Controller or owner DataObject after list sort
if ( $owner && $owner instanceof DataObject && method_exists ( $owner , 'onAfterGridFieldPageSort' )) {
$owner -> onAfterGridFieldPageSort ( clone $items );
} else if ( Controller :: has_curr () && Controller :: curr () instanceof ModelAdmin && method_exists ( Controller :: curr (), 'onAfterGridFieldPageSort' )) {
Controller :: curr () -> onAfterGridFieldPageSort ( clone $items );
}
}
/**
* Check to see if the given class name has the Versioned extension
*
* @ param Extensible | string $className
* @ return bool
*/
public function hasVersionedExtension ( $className )
{
return $className :: has_extension ( Versioned :: class );
}
/**
* Checks to see if $table_name is declared on the DataObject , if not returns string as given
*
2017-12-11 17:27:42 +01:00
* @ param $className
2017-12-11 16:49:30 +01:00
* @ return string
* @ deprecated Use DataObject :: getSchema () -> tableName () instead
2017-05-27 06:45:28 +02:00
*/
2017-12-11 17:27:42 +01:00
public function mapTableNameAndReturn ( $className )
2017-05-27 06:45:28 +02:00
{
2017-12-11 17:27:42 +01:00
return DataObject :: getSchema () -> tableName ( $className );
2017-05-27 06:45:28 +02:00
}
2012-05-09 19:14:34 +02:00
}