Source of file ArchiveAdmin.php
Size: 14,050 Bytes - Last Modified: 2021-12-23T10:36:08+00:00
/var/www/docs.ssmods.com/process/src/src/ArchiveAdmin.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374 | <?php namespace SilverStripe\VersionedAdmin; use SilverStripe\Admin\ModelAdmin; use SilverStripe\Control\Controller; use SilverStripe\Core\ClassInfo; use SilverStripe\Core\Injector\Injector; use SilverStripe\Forms\DropdownField; use SilverStripe\Forms\FieldList; use SilverStripe\Forms\Form; use SilverStripe\Forms\GridField\GridField; use SilverStripe\Forms\GridField\GridField_ActionMenu; use SilverStripe\Forms\GridField\GridFieldConfig_Base; use SilverStripe\Forms\GridField\GridFieldDataColumns; use SilverStripe\Forms\GridField\GridFieldDetailForm; use SilverStripe\Forms\GridField\GridFieldFilterHeader; use SilverStripe\Forms\GridField\GridFieldViewButton; use SilverStripe\ORM\ArrayList; use SilverStripe\ORM\DataObject; use SilverStripe\ORM\FieldType\DBDatetime; use SilverStripe\Versioned\GridFieldRestoreAction; use SilverStripe\Versioned\Versioned; use SilverStripe\Versioned\VersionedGridFieldState\VersionedGridFieldState; use SilverStripe\VersionedAdmin\Interfaces\ArchiveViewProvider; use SilverStripe\View\ArrayData; /** * Archive admin is a section of the CMS that displays archived records * from versioned objects and allows for users to restore them. * * Shows tabs for any implementors of {@link ArchiveViewProvider} and * display any other versioned objects in a dropdown */ class ArchiveAdmin extends ModelAdmin { private static $url_segment = 'archive'; private static $menu_title = 'Archive'; private static $menu_icon_class = 'font-icon-box'; public $showSearchForm = false; protected function init() { parent::init(); // Set the default model class to SiteTree, as long as silverstripe/cms is installed // This is done otherwise File will be the default set in ModelAdmin::init() which is basically random $class = 'SilverStripe\\CMS\\Model\\SiteTree'; if (!$this->getRequest()->param('ModelClass') && !$this->request->getVar('others') && class_exists($class)) { $this->modelClass = $class; } } /** * Produces an edit form with relevant prioritised tabs for Pages, Blocks and Files * * @param int|null $id * @param FieldList|null $fields * @return Form A Form object with one tab per {@link \SilverStripe\Forms\GridField\GridField} */ public function getEditForm($id = null, $fields = null) { $fields = FieldList::create(); $modelClass = $this->request->getVar('others') ? 'others' : $this->modelClass; $classInst = Injector::inst()->get($this->modelClass); if (ClassInfo::hasMethod($classInst, 'getArchiveField')) { $listField = $classInst->getArchiveField(); $fields->push($listField); } else { $otherVersionedObjects = $this->getVersionedModels('other'); $modelSelectField = $this->getOtherModelSelectorField($modelClass); $fields->push($modelSelectField); // If a valid other model name is passed via a request param // then show a gridfield with archived records if (array_search($modelClass, $otherVersionedObjects)) { $listField = $this->createArchiveGridField('Others', $modelClass); $listColumns = $listField->getConfig()->getComponentByType(GridFieldDataColumns::class); $listColumns->setDisplayFields([ 'Title' => _t(__CLASS__ . '.COLUMN_TITLE', 'Title'), 'allVersions.first.LastEdited' => _t(__CLASS__ . '.COLUMN_DATEARCHIVED', 'Date Archived'), 'allVersions.first.Author.Name' => _t(__CLASS__ . '.COLUMN_ARCHIVEDBY', 'Archived By'), ]); $listColumns->setFieldFormatting([ 'allVersions.first.LastEdited' => function ($val, $item) { return DBDatetime::create_field('Datetime', $val)->Ago(); }, ]); $fields->push($listField); } } $form = Form::create( $this, 'EditForm', $fields, FieldList::create() )->setHTMLID('Form_EditForm'); $form->setTemplate($this->getTemplatesWithSuffix('_EditForm')); $form->setAttribute('data-pjax-fragment', 'CurrentForm'); $form->addExtraClass( 'ArchiveAdmin discardchanges cms-edit-form cms-panel-padded center flexbox-area-grow '. $this->BaseCSSClasses() ); $form->setFormAction(Controller::join_links( $this->Link($this->sanitiseClassName($this->modelClass)), 'EditForm' )); $this->extend('updateEditForm', $form); return $form; } /** * Create a gridfield which displays archived objects * * @param string $title * @param string $class * @return GridField */ public static function createArchiveGridField($title, $class) { $config = GridFieldConfig_Base::create(); $config->removeComponentsByType(VersionedGridFieldState::class); $config->removeComponentsByType(GridFieldFilterHeader::class); $config->addComponent(new GridFieldDetailForm); $config->addComponent(new GridFieldViewButton); $config->addComponent(new GridFieldRestoreAction); $config->addComponent(new GridField_ActionMenu); $singleton = singleton($class); $list = $singleton->get(); $baseTable = $singleton->baseTable(); $list = $list ->setDataQueryParam('Versioned.mode', 'latest_versions'); // Join a temporary alias BaseTable_Draft, renaming this on execution to BaseTable // See Versioned::augmentSQL() For reference on this alias $draftTable = $baseTable . '_Draft'; $list = $list ->leftJoin( $draftTable, "\"{$baseTable}\".\"ID\" = \"{$draftTable}\".\"ID\"" ); if ($singleton->hasStages()) { $liveTable = $baseTable . '_Live'; $list = $list->leftJoin( $liveTable, "\"{$baseTable}\".\"ID\" = \"{$liveTable}\".\"ID\"" ); } $list = $list->where("\"{$draftTable}\".\"ID\" IS NULL"); $list = $list->sort('LastEdited DESC'); $field = GridField::create( $title, false, $list, $config ); $field->setModelClass($class); return $field; } /** * Returns versioned objects, can be filtered for 'main' (has a tab) * or 'other' and is exposed through the 'Others' tab, returns all * by default * * @param string|null $filter Filter by 'main' or 'other' * @param boolean $forDisplay Include titles as values in the returned array * @return array */ public function getVersionedModels($filter = null, $forDisplay = false) { // Get dataobjects with staged versioning $versionedClasses = array_filter( ClassInfo::subclassesFor(DataObject::class), function ($class) { return DataObject::has_extension($class, Versioned::class); } ); $archiveProviders = ClassInfo::implementorsOf(ArchiveViewProvider::class); $disabledHandledClasses = []; // Get the classes that are declared as handled by the disabled providers foreach ($archiveProviders as $provider) { if (!Injector::inst()->get($provider)->isArchiveFieldEnabled()) { $disabledProviderClass = Injector::inst()->get($provider)->getArchiveFieldClass(); $disabledHandledClasses[] = $disabledProviderClass; $disabledHandledClasses = array_merge( $disabledHandledClasses, array_keys(ClassInfo::subclassesFor($disabledProviderClass)) ); } } // Remove any subclasses that would also be handled by those disabled providers $versionedClasses = array_diff_key($versionedClasses, array_flip($disabledHandledClasses)); // If there is a valid filter passed if ($filter && in_array($filter, ['main', 'other'])) { $archiveProviderClasses = []; // Get the classes that are decalred as handled by ArchiveViewProviders foreach ($archiveProviders as $provider) { $archiveProviderClass = Injector::inst()->get($provider)->getArchiveFieldClass(); $archiveProviderClasses[] = $archiveProviderClass; } switch ($filter) { case 'other': $handledClasses = []; // Get any subclasses that would also be handled by those providers foreach ($archiveProviderClasses as $archiveProviderClass) { $handledClasses = array_merge( $handledClasses, array_keys(ClassInfo::subclassesFor($archiveProviderClass)) ); } $versionedClasses = array_filter( $versionedClasses, function ($class) use ($handledClasses) { return !in_array(strtolower($class), $handledClasses); } ); break; default: // 'main' $versionedClasses = array_filter( $versionedClasses, function ($class) use ($archiveProviderClasses) { return in_array($class, $archiveProviderClasses); } ); break; } } // Formats array as [$className => i18n_plural_name] if ($forDisplay) { $versionedClasses = array_flip($versionedClasses); foreach (array_keys($versionedClasses) as $className) { $versionedClasses[$className] = ucfirst($className::singleton()->i18n_plural_name()); } } return $versionedClasses; } /** * Creates a dropdown field that displays other archived models * * @param string $currentModel The model that is currently selected * @return DropdownField */ public function getOtherModelSelectorField($currentModel = '') { $otherVersionedObjects = $this->getVersionedModels('other', true); $modelSelectField = DropdownField::create( 'OtherDropdown', _t(__CLASS__ . '.SELECT_TYPE', 'Select a content type'), $otherVersionedObjects, $currentModel ); $modelSelectField->setAttribute( 'data-others-archive-url', $this->Link('/') ); $modelSelectField->addExtraClass('other-model-selector'); $modelSelectField->setEmptyString(_t(__CLASS__ . '.SELECT_EMPTY', 'Select…')); $modelSelectField->setHasEmptyDefault(true); return $modelSelectField; } /** * Use 'Archive' as the top title rather than the model title * * @param bool $unlinked * @return ArrayList */ public function Breadcrumbs($unlinked = false) { $items = parent::Breadcrumbs($unlinked); $items[0]->Title = $this->menu_title(); return $items; } /** * Archive admin needs some extra logic for whether an archive tab should be shown * * @return array Map of class name to an array of 'title' (see {@link $managed_models}) */ public function getManagedModels() { $models = $this->getVersionedModels(); // Normalize models to have their model class in array key and all names as the value are uppercased foreach ($models as $k => $v) { $archivedModels[$v] = array('title' => ucfirst(singleton($v)->i18n_plural_name())); unset($archivedModels[$k]); } return $archivedModels; } /** * Add the special 'Others' tab * * @return ArrayList An ArrayList of all managed models to build the tabs for this ModelAdmin */ public function getManagedModelTabs() { $forms = ArrayList::create(); $mainModels = $this->getVersionedModels('main', true); // Display order should be Pages > Blocks > Files > Other // Pages, Blocks, Files are treated specially and have extensions defined in _config/archive-admin.yml $order = ['Pages', 'Blocks', 'Files']; uasort($mainModels, function ($a, $b) use ($order) { return array_search($a, $order) < array_search($b, $order) ? -1 : 1; }); foreach ($mainModels as $class => $title) { $classInst = Injector::inst()->get($class); if (ClassInfo::hasMethod($classInst, 'isArchiveFieldEnabled') && $classInst->isArchiveFieldEnabled() ) { $forms->push(ArrayData::create([ 'Title' => $title, 'ClassName' => $class, 'Link' => $this->Link($this->sanitiseClassName($class)), 'LinkOrCurrent' => ($class === $this->modelClass) ? 'current' : 'link' ])); } } $otherModels = $this->getVersionedModels('other', true); if ($otherModels) { $isOtherActive = ( $this->request->getVar('others') !== null || array_key_exists($this->modelClass, $otherModels) ); $forms->push(ArrayData::create([ 'Title' => _t(__CLASS__ . '.TAB_OTHERS', 'Other'), 'ClassName' => 'Others', 'Link' => $this->Link('?others=1'), 'LinkOrCurrent' => ($isOtherActive ? 'current' : 'link') ])); } $forms->first()->LinkOrCurrent = 'link'; return $forms; } } |