Source of file SortableUploadField.php
Size: 8,409 Bytes - Last Modified: 2021-12-24T06:34:33+00:00
/var/www/docs.ssmods.com/process/src/src/Forms/SortableUploadField.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254 | <?php namespace Bummzack\SortableFile\Forms; use Psr\Log\LoggerInterface; use SilverStripe\AssetAdmin\Forms\UploadField; use SilverStripe\Assets\File; use SilverStripe\ORM\ArrayList; use SilverStripe\ORM\DataList; use SilverStripe\ORM\DataObjectInterface; use SilverStripe\ORM\DB; use SilverStripe\ORM\ManyManyList; use SilverStripe\ORM\ManyManyThroughList; use SilverStripe\ORM\ManyManyThroughQueryManipulator; use SilverStripe\ORM\Queries\SQLUpdate; use SilverStripe\ORM\Sortable; use SilverStripe\ORM\SS_List; use SilverStripe\ORM\UnsavedRelationList; /** * Extension of the UploadField to add sorting of files * * @author bummzack * @skipUpgrade */ class SortableUploadField extends UploadField { private static $dependencies = [ 'logger' => '%$Psr\Log\LoggerInterface', ]; /** * The column to be used for sorting * @var string */ protected $sortColumn = 'SortOrder'; /** * Raw submitted form data * @var null|array */ protected $rawSubmittal = null; /** * @var LoggerInterface */ public $logger; public function getSchemaDataDefaults() { $defaults = parent::getSchemaDataDefaults(); // Add a sortable prop for the react component $defaults['sortable'] = true; return $defaults; } /** * Set the column to be used for sorting * @param string $sortColumn * @return $this */ public function setSortColumn($sortColumn) { $this->sortColumn = $sortColumn; return $this; } /** * Returns the column to be used for sorting * @return string */ public function getSortColumn() { return $this->sortColumn; } /** * Return the files in sorted order * @return File[]|SS_List */ public function getItems() { $items = parent::getItems(); // An ArrayList won't contain our sort-column, thus it has to be sorted by the raw submittal data. // This is an issue that's seemingly exclusive to saving SiteConfig. if (($items instanceof ArrayList) && !empty($this->rawSubmittal)) { // flip the array, so that we can look up index by ID $sortLookup = array_flip($this->rawSubmittal); $itemsArray = $items->toArray(); usort($itemsArray, function ($itemA, $itemB) use ($sortLookup) { if (isset($sortLookup[$itemA->ID]) && isset($sortLookup[$itemB->ID])) { return $sortLookup[$itemA->ID] - $sortLookup[$itemB->ID]; } return 0; }); return ArrayList::create($itemsArray); } if ($items instanceof Sortable) { return $items->sort([$this->getSortColumn() => 'ASC', 'ID' => 'ASC']); } return $items; } public function saveInto(DataObjectInterface $record) { parent::saveInto($record); // Check required relation details are available $fieldname = $this->getName(); if (!$fieldname || !is_array($this->rawSubmittal)) { return $this; } // Check type of relation $relation = $record->hasMethod($fieldname) ? $record->$fieldname() : null; if ($relation) { $idList = $this->getItemIDs(); $rawList = $this->rawSubmittal; $sortColumn = $this->getSortColumn(); if ($relation instanceof ManyManyList) { try { // Apply the sorting, wrapped in a transaction. // If something goes wrong, the DB will not contain invalid data DB::get_conn()->withTransaction(function () use ($relation, $idList, $rawList, $record, $sortColumn) { $this->sortManyManyRelation($relation, $idList, $rawList, $record, $sortColumn); }); } catch (\Exception $ex) { $this->logger->warning('Unable to sort files in sortable relation.', ['exception' => $ex]); } } elseif ($relation instanceof ManyManyThroughList) { try { // Apply the sorting, wrapped in a transaction. // If something goes wrong, the DB will not contain invalid data DB::get_conn()->withTransaction(function () use ($relation, $idList, $rawList, $sortColumn) { $this->sortManyManyThroughRelation($relation, $idList, $rawList, $sortColumn); }); } catch (\Exception $ex) { $this->logger->warning('Unable to sort files in sortable relation.', ['exception' => $ex]); } } elseif ($relation instanceof UnsavedRelationList) { // With an unsaved relation list the items can just be removed and re-added $sort = 0; $relation->removeAll(); foreach ($rawList as $id) { if (in_array($id, $idList)) { $relation->add($id, [$sortColumn => $sort++]); } } } } return $this; } public function setSubmittedValue($value, $data = null) { // Intercept the incoming IDs since they are properly sorted if (is_array($value) && isset($value['Files'])) { $this->rawSubmittal = $value['Files']; } return $this->setValue($value, $data); } /** * Apply sorting to a many_many relation * @param ManyManyList $relation * @param array $idList * @param array $rawList * @param DataObjectInterface $record * @param $sortColumn */ protected function sortManyManyRelation( ManyManyList $relation, array $idList, array $rawList, DataObjectInterface $record, $sortColumn ) { $relation->getForeignID(); $ownerIdField = $relation->getForeignKey(); $fileIdField = $relation->getLocalKey(); $joinTable = '"' . $relation->getJoinTable() . '"'; $sort = 0; foreach ($rawList as $id) { if (in_array($id, $idList)) { // Use SQLUpdate to update the data in the join-table. // This is safe to do, since new records have already been written to the DB in the // parent::saveInto call. SQLUpdate::create($joinTable) ->setWhere([ "\"$ownerIdField\" = ?" => $record->ID, "\"$fileIdField\" = ?" => $id ]) ->assign($sortColumn, $sort++) ->execute(); } } } /** * Apply sorting to a many_many_through relation * @param ManyManyThroughList $relation * @param array $idList * @param array $rawList * @param $sortColumn * @throws \SilverStripe\ORM\ValidationException */ protected function sortManyManyThroughRelation( ManyManyThroughList $relation, array $idList, array $rawList, $sortColumn ) { $relation->getForeignID(); $dataQuery = $relation->dataQuery(); $manipulators = $dataQuery->getDataQueryManipulators(); $manyManyManipulator = null; foreach ($manipulators as $manipulator) { if ($manipulator instanceof ManyManyThroughQueryManipulator) { $manyManyManipulator = $manipulator; break; } } if (!$manyManyManipulator) { throw new \LogicException('No ManyManyThroughQueryManipulator found'); } $joinClass = $manyManyManipulator->getJoinClass(); $ownerIDField = $manyManyManipulator->getForeignKey(); $fileIdField = $manyManyManipulator->getLocalKey(); $sort = 0; foreach ($rawList as $id) { if (in_array($id, $idList)) { $fileRecord = DataList::create($joinClass)->filter([ $ownerIDField => $relation->getForeignID(), $fileIdField => $id ])->first(); if ($fileRecord) { $fileRecord->setField($sortColumn, $sort++); $fileRecord->write(); } } } } } |