silverstripe-cms/code/Forms/CMSMainAddForm.php
Guy Sartorelli 47dbda8381
API Make CMSMain more generic
Remove hardcoded references to pages and SiteTree
Remove assumption that records are versioned
Remove or validate assumptions about methods on the model class
Improve general architecture of CMSMain
2024-10-17 16:01:33 +13:00

224 lines
9.1 KiB
PHP

<?php
namespace SilverStripe\CMS\Forms;
use SilverStripe\CMS\Controllers\CMSMain;
use SilverStripe\CMS\Controllers\CMSPageEditController;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Control\HTTPResponse;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Convert;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\Form;
use SilverStripe\Forms\FormAction;
use SilverStripe\Forms\LiteralField;
use SilverStripe\Forms\OptionsetField;
use SilverStripe\Forms\SelectionGroup;
use SilverStripe\Forms\SelectionGroup_Item;
use SilverStripe\Forms\TreeDropdownField;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\Security\Security;
use SilverStripe\SiteConfig\SiteConfig;
class CMSMainAddForm extends Form
{
public function __construct(CMSMain $controller)
{
$modelClass = $controller->getModelClass();
$pageTypes = [];
$defaultIcon = Config::inst()->get($modelClass, 'icon_class'); // @TODO need a better place for default - maybe try default on class, and fallback to default on cmsmain?
foreach ($controller->RecordTypes() as $type) {
$class = $type->getField('ClassName');
$icon = Config::inst()->get($class, 'icon_class') ?: $defaultIcon;
// If the icon is the default and there's some specific icon being provided by `getPageIconURL`
// then we don't need to add the icon class. Otherwise the class take precedence.
if ($icon === $defaultIcon && !empty(singleton($class)->getPageIconURL())) {
$icon = '';
}
$html = sprintf(
'<span class="page-icon %s class-%s"></span><span class="title">%s</span><span class="form__field-description">%s</span>',
$icon,
Convert::raw2htmlid($class),
$type->getField('AddAction'),
$type->getField('Description')
);
$pageTypes[$class] = DBField::create_field('HTMLFragment', $html);
}
// Ensure generic page type shows on top
if (isset($pageTypes['Page'])) {
$pageTitle = $pageTypes['Page'];
$pageTypes = array_merge(['Page' => $pageTitle], $pageTypes);
}
$numericLabelTmpl = '<span class="step-label"><span class="flyout">Step %d. </span><span class="title">%s</span></span>';
$topTitle = _t(__CLASS__ . '.ParentMode_top', 'Top level');
$childTitle = _t(
__CLASS__ . '.ParentMode_child',
'Under another {type}',
['type' => mb_strtolower(DataObject::singleton($modelClass)->i18n_singular_name())]
);
$fields = FieldList::create(
$parentModeField = SelectionGroup::create(
'ParentModeField',
[
$topField = SelectionGroup_Item::create(
'top',
null,
$topTitle
),
SelectionGroup_Item::create(
'child',
$parentField = TreeDropdownField::create(
'ParentID',
'',
$modelClass,
'ID',
'TreeTitle'
),
$childTitle
)
]
),
LiteralField::create(
'RestrictedNote',
sprintf(
'<p class="alert alert-info message-restricted">%s</p>',
_t(
'SilverStripe\\CMS\\Controllers\\CMSMain.AddPageRestriction',
'Note: Some page types are not allowed for this selection'
)
)
),
OptionsetField::create(
'PageType',
DBField::create_field(
'HTMLFragment',
sprintf($numericLabelTmpl ?? '', 2, _t('SilverStripe\\CMS\\Controllers\\CMSMain.ChoosePageType', 'Choose page type'))
),
$pageTypes,
'Page'
)
);
$parentModeField->setTitle(DBField::create_field(
'HTMLFragment',
sprintf($numericLabelTmpl ?? '', 1, _t('SilverStripe\\CMS\\Controllers\\CMSMain.ChoosePageParentMode', 'Choose where to create this page'))
));
$parentField->setSearchFunction(function ($sourceObject, $labelField, $search) {
return DataObject::get($sourceObject)
->filterAny([
'MenuTitle:PartialMatch' => $search,
'Title:PartialMatch' => $search,
]);
});
$parentModeField->addExtraClass('parent-mode');
// CMSMain->currentRecordID() automatically sets the homepage,
// which we need to counteract in the default selection (which should default to root, ID=0)
if ($parentID = $controller->getRequest()->getVar('ParentID')) {
$parentModeField->setValue('child');
$parentField->setValue((int)$parentID);
} else {
$parentModeField->setValue('top');
}
// Check if the current user has enough permissions to create top level pages
// If not, then disable the option to do that
if (is_a($modelClass, SiteTree::class, true) && !SiteConfig::current_site_config()->canCreateTopLevel()) { // @TODO probably need to make this generic
$topField->setDisabled(true);
$parentModeField->setValue('child');
}
$actions = FieldList::create(
FormAction::create('doAdd', _t('SilverStripe\\CMS\\Controllers\\CMSMain.Create', 'Create'))
->addExtraClass('btn-primary font-icon-plus-circled')
->setUseButtonTag(true),
FormAction::create('doCancel', _t('SilverStripe\\CMS\\Controllers\\CMSMain.Cancel', 'Cancel'))
->addExtraClass('btn-secondary')
->setUseButtonTag(true)
);
$controller->extend('updatePageOptions', $fields);
parent::__construct($controller, 'AddForm', $fields, $actions);
$negotiator = $controller->getResponseNegotiator();
$this->setHTMLID('Form_AddForm')->setStrictFormMethodCheck(false);
$this->setAttribute('data-hints', $controller->TreeHints());
$this->setAttribute('data-childfilter', $controller->Link('childfilter'));
$this->setValidationResponseCallback(function () use ($negotiator, $controller) {
$request = $controller->getRequest();
if ($request->isAjax() && $negotiator) {
$result = $this->forTemplate();
return $negotiator->respond($request, [
'CurrentForm' => function () use ($result) {
return $result;
}
]);
}
return null;
});
$this->addExtraClass('flexbox-area-grow fill-height cms-add-form cms-content cms-edit-form ' . $controller->BaseCSSClasses());
$this->setTemplate($controller->getTemplatesWithSuffix('_AddForm'));
}
public function doAdd(array $data, Form $form): HTTPResponse
{
$controller = $this->getController();
$modelClass = $controller->getModelClass();
$className = isset($data['PageType']) ? $data['PageType'] : "Page";
$parentID = isset($data['ParentID']) ? (int)$data['ParentID'] : 0;
if (!$parentID && isset($data['Parent'])) {
$page = $modelClass::get_by_link($data['Parent']); // @TODO Obviously no good
if ($page) {
$parentID = $page->ID;
}
}
if (is_numeric($parentID) && $parentID > 0) {
$parentObj = DataObject::get($modelClass)->byID($parentID);
} else {
$parentObj = null;
}
if (!$parentObj || !$parentObj->ID) {
$parentID = 0;
}
if (!singleton($className)->canCreate(Security::getCurrentUser(), ['Parent' => $parentObj])) {
return Security::permissionFailure($controller);
}
$record = $controller->getNewItem("new-$className-$parentID", false);
$controller->extend('updateDoAdd', $record, $form);
$record->write();
$editController = CMSPageEditController::singleton();
$editController->setRequest($controller->getRequest());
$editController->setCurrentRecordID($record->ID);
$session = $this->getRequest()->getSession();
$session->set(
"FormInfo.Form_EditForm.formError.message",
_t('SilverStripe\\CMS\\Controllers\\CMSMain.PageAdded', 'Successfully created page')
);
$session->set("FormInfo.Form_EditForm.formError.type", 'good');
return $controller->redirect($editController->Link('show/' . $record->ID));
}
public function doCancel(): HTTPResponse
{
return $this->getController()->redirect(CMSMain::singleton()->Link()); // @TODO when there's no CMSPageEditController anymore, change this to $this->getController()->Link()
}
}