Source of file GridFieldSortableRows.php
Size: 35,736 Bytes - Last Modified: 2021-12-23T10:56:57+00:00
/var/www/docs.ssmods.com/process/src/src/Forms/GridFieldSortableRows.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806 | <?php 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; use SilverStripe\Core\Injector\Injector; 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; use SilverStripe\ORM\DataObjectSchema; use SilverStripe\ORM\DataQuery; use SilverStripe\ORM\DB; use SilverStripe\ORM\ManyManyList; use SilverStripe\ORM\ManyManyThroughList; use SilverStripe\ORM\RelationList; use SilverStripe\ORM\SS_List; use SilverStripe\ORM\UnsavedRelationList; use SilverStripe\ORM\ValidationException; use SilverStripe\Versioned\Versioned; use SilverStripe\View\ArrayData; use SilverStripe\View\Requirements; /** * This component provides a checkbox which when checked enables drag-and-drop re-ordering of elements displayed in a {@link GridField} * * @package forms */ 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); Requirements::css('undefinedoffset/sortablegridfield:css/GridFieldSortableRows.css'); Requirements::javascript('undefinedoffset/sortablegridfield:javascript/GridFieldSortableRows.js'); $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 || $list instanceof ManyManyThroughList); if (!$many_many) { $sng = singleton($gridField->getModelClass()); $fieldType = $sng->config()->db[$this->sortColumn]; if (!$fieldType || !($fieldType == 'Int' || $fieldType == 'SilverStripe\\ORM\\FieldType\\DBInt' || is_subclass_of($fieldType, 'SilverStripe\\ORM\\FieldType\\DBInt'))) { if (is_array($fieldType)) { user_error('Sort column ' . $this->sortColumn . ' could not be found in ' . $gridField->getModelClass() . '\'s ancestry', E_USER_ERROR); } else { user_error('Sort column ' . $this->sortColumn . ' must be an instance of SilverStripe\\ORM\\FieldType\\DBInt, column is of type ' . $fieldType, E_USER_ERROR); } 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) { $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']; //For ManyManyThroughLists get the right join table if ($list instanceof ManyManyThroughList && class_exists($table)) { $table=$schema->tableName($table); } $extraFields = $list->getExtraFields(); 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]))) { user_error('Sort column ' . $this->sortColumn . ' must be an SilverStripe\\ORM\\FieldType\\DBInt, column is of type ' . $extraFields[$this->sortColumn], E_USER_ERROR); 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)) { $table = DataObject::getSchema()->tableName($class); } 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)) { $table = DataObject::getSchema()->tableName($class); 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()); $baseDataTable = DataObject::getSchema()->tableName($baseDataClass); } //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(); } $modelClass = $gridField->getModelClass(); $hasVersioned = $this->hasVersionedExtension($modelClass); 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) { 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) . '\')' : '')); } if ($this->update_versioned_stage && $this->hasVersionedExtension($gridField->getModelClass())) { 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 { 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); } if ($this->update_versioned_stage && $this->hasVersionedExtension($gridField->getModelClass())) { DB::query('UPDATE "' . $table . '_' . $this->update_versioned_stage . '" SET "' . $sortColumn . '" = ' . ($max + $i) . ' WHERE "ID" = ' . $obj->ID); if ($this->hasVersionedExtension($baseDataClass)) { DB::query('UPDATE "' . $baseDataTable . '_' . $this->update_versioned_stage . '" 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) { DB::query('UPDATE "' . $baseDataTable . '" SET "LastEdited" = \'' . date('Y-m-d H:i:s') . '\'' . ' WHERE "ID" IN(\'' . implode('\',\'', $topIncremented) . '\')'); if ($this->update_versioned_stage && $this->hasVersionedExtension($gridField->getModelClass()) && $this->hasVersionedExtension($baseDataClass)) { DB::query('UPDATE "' . $baseDataTable . '_' . $this->update_versioned_stage . '" 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 || $items instanceof ManyManyThroughList); $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) { $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']; //For ManyManyThroughLists get the right join table if ($items instanceof ManyManyThroughList && class_exists($table)) { $table=$schema->tableName($table); } } 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)) { $table = DataObject::getSchema()->tableName($class); } 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)) { $table = DataObject::getSchema()->tableName($class); 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()); $baseDataTable = DataObject::getSchema()->tableName($baseDataClass); } //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']); $modelClass = $gridField->getModelClass(); $hasVersioned = $this->hasVersionedExtension($modelClass); 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 { 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); DB::query('UPDATE "' . $baseDataTable . '" SET "LastEdited" = \'' . date('Y-m-d H:i:s') . '\'' . ' WHERE "ID" = ' . $id); } if ($this->update_versioned_stage && $hasVersioned) { DB::query('UPDATE "' . $table . '_' . $this->update_versioned_stage . '" SET "' . $sortColumn . '" = ' . (($sort + 1) + $pageOffset) . ' WHERE "ID" = ' . $id); if ($this->hasVersionedExtension($baseDataClass)) { DB::query('UPDATE "' . $baseDataTable . '_' . $this->update_versioned_stage . '" 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 || $items instanceof ManyManyThroughList); $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) { $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']; //For ManyManyThroughLists get the right join table if ($items instanceof ManyManyThroughList && class_exists($table)) { $table=$schema->tableName($table); } } 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)) { $table = DataObject::getSchema()->tableName($class); 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) { if ($obj->ID == $targetItem->ID || $i >= count($sortPositions)) { 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 * * @param $className * @return string * @deprecated Use DataObject::getSchema()->tableName() instead */ public function mapTableNameAndReturn($className) { return DataObject::getSchema()->tableName($className); } } |