From 45f87288fc94e4d2622c3552860c240c981a7a01 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Sat, 21 Nov 2009 03:20:26 +0000 Subject: [PATCH] API CHANGE Moved CMSMain/AssetAdmin/SecurityAdmin implementations for getEditForm() and save() to a common parent: LeftAndMain git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/cms/trunk@92834 467b73ca-7a2a-4603-9d3b-597d59a354a9 --- code/AssetAdmin.php | 68 +------------------ code/CMSMain.php | 154 +++++++++++++++++++++++++++---------------- code/LeftAndMain.php | 136 ++++++++++++++++++++------------------ 3 files changed, 174 insertions(+), 184 deletions(-) diff --git a/code/AssetAdmin.php b/code/AssetAdmin.php index de8262d4..bc14d259 100755 --- a/code/AssetAdmin.php +++ b/code/AssetAdmin.php @@ -261,61 +261,11 @@ HTML; public function currentPage() { $id = $this->currentPageID(); if($id && is_numeric($id)) { - return DataObject::get_by_id($this->stat('tree_class'), $id); + return DataObject::get_by_id('File', $id); } else if($id == 'root') { - return singleton($this->stat('tree_class')); + return singleton('File'); } } - - /** - * @return Form - */ - function EditForm($request = null) { - return $this->getEditForm(); - } - - /** - * Return the form that displays the details of a folder, including a file list and fields for editing the folder name. - */ - function getEditForm($id = null) { - if(!$id) $id = $this->currentPageID(); - - $record = ($id && $id != "root") ? DataObject::get_by_id("File", $id) : null; - if($record && !$record->canView()) return Security::permissionFailure($this); - - if($record) { - $fields = $record->getCMSFields(); - // Required for file tree setup - if(!$fields->dataFieldByName('ParentID')) $fields->push(new HiddenField('ParentID')); - - $actions = new FieldSet(); - - // Only show save button if not 'assets' folder - if($record->canEdit() && $id != 'root') { - $actions = new FieldSet( - new FormAction('save',_t('AssetAdmin.SAVEFOLDERNAME','Save folder name')) - ); - } - - $form = new Form($this, "EditForm", $fields, $actions); - if($record->ID) { - $form->loadDataFrom($record); - } else { - $form->loadDataFrom(array( - "ID" => "root", - "URL" => Director::absoluteBaseURL() . 'assets/', - )); - } - - if(!$record->canEdit()) { - $form->makeReadonly(); - } - } else { - $form = $this->EmptyForm(); - } - - return $form; - } /** * Return the entire site tree as a nested UL. @@ -377,7 +327,7 @@ HTML; * @return Form */ function AddForm() { - $typeMap = array('Folder' => singleton('Folder')->i18n_singular_name()); + $typeMap = array('Folder' => singleton($this->stat('tree_class'))->i18n_singular_name()); $typeField = new DropdownField('Type', false, $typeMap, 'Folder'); $form = new Form( $this, @@ -451,19 +401,7 @@ HTML; return $form; } - - public function save($urlParams, $form) { - // Don't save the root folder - there's no database record - if($_REQUEST['ID'] == 'root') { - FormResponse::status_message('Saved', 'good'); - return FormResponse::respond(); - } - $form->dataFieldByName('Title')->value = $form->dataFieldByName('Name')->value; - - return parent::save($urlParams, $form); - } - /** * ################################# * Garbage collection. diff --git a/code/CMSMain.php b/code/CMSMain.php index 5c605ab3..1ca0ef74 100755 --- a/code/CMSMain.php +++ b/code/CMSMain.php @@ -309,13 +309,6 @@ JS; } } - /** - * @return Form - */ - function EditForm($request = null) { - return $this->getEditForm(); - } - /** * Calls {@link SiteTree->getCMSFields()} */ @@ -323,16 +316,16 @@ JS; // Include JavaScript to ensure HtmlEditorField works. HtmlEditorField::include_js(); - if(!$id) $id = $this->currentPageID(); - - $record = ($id) ? $this->getRecord($id) : null; - if($record && !$record->canView()) return Security::permissionFailure($this); + $form = parent::getEditForm($id); + + // TODO Duplicate record fetching (see parent implementation) + if(!$id) $id = $this->currentPageID(); + $record = ($id && $id != "root") ? DataObject::get_by_id($this->stat('tree_class'), $id) : null; + + $fields = $form->Fields(); + $actions = $form->Actions(); if($record) { - $fields = $record->getCMSFields($this); - if ($fields == null) { - user_error("getCMSFields returned null on a '".get_class($record)."' object - it should return a FieldSet object. Perhaps you forgot to put a return statement at the end of your method?", E_USER_ERROR); - } $fields->push($idField = new HiddenField("ID", false, $id)); $fields->push($liveURLField = new HiddenField("LiveURLSegment")); $fields->push($stageURLField = new HiddenField("StageURLSegment")); @@ -349,47 +342,15 @@ JS; $stageURLField->setValue($record->AbsoluteLink()); } - // getAllCMSActions can be used to completely redefine the action list - if($record->hasMethod('getAllCMSActions')) { - $actions = $record->getAllCMSActions(); - } else { - $actions = $record->getCMSActions(); - // add default actions if none are defined - if(!$actions || !$actions->Count()) { - if($record->canEdit()) { - $actions->push(new FormAction('save',_t('CMSMain.SAVE','Save'))); - $actions->push($deleteAction = new FormAction('delete',_t('CMSMain.DELETE','Delete from the draft site'))); - $deleteAction->addExtraClass('delete'); - } - } - } + $deleteAction = new FormAction( + 'delete', + _t('CMSMain.DELETE','Delete from the draft site') + ); + $deleteAction->addExtraClass('delete'); + $actions->insertBefore($deleteAction, 'action_save'); - $form = new Form($this, "EditForm", $fields, $actions); - $form->loadDataFrom($record); - $form->disableDefaultAction(); - - // Add a default or custom validator. - // @todo Currently the default Validator.js implementation - // adds javascript to the document body, meaning it won't - // be included properly if the associated fields are loaded - // through ajax. This means only serverside validation - // will kick in for pages+validation loaded through ajax. - // This will be solved by using less obtrusive javascript validation - // in the future, see http://open.silverstripe.com/ticket/2915 and http://open.silverstripe.com/ticket/3386 - if($record->hasMethod('getCMSValidator')) { - $validator = $record->getCMSValidator(); - // The clientside (mainly LeftAndMain*.js) rely on ajax responses - // which can be evaluated as javascript, hence we need - // to override any global changes to the validation handler. - $validator->setJavascriptValidationHandler('prototype'); - $form->setValidator($validator); - } else { - $form->unsetValidator(); - } - - if(!$record->canEdit() || $record->IsDeletedFromStage) { - $readonlyFields = $form->Fields()->makeReadonly(); - $form->setFields($readonlyFields); + if($record->IsDeletedFromStage) { + $form->makeReadonly(); } } elseif ($id == 0) { $siteConfig = SiteConfig::current_site_config(); @@ -406,6 +367,89 @@ JS; //------------------------------------------------------------------------------------------// // Data saving handlers + /** + * Save and Publish page handler + */ + public function save($data, $form) { + $className = $this->stat('tree_class'); + + // Existing or new record? + $SQL_id = Convert::raw2sql($data['ID']); + if(substr($SQL_id,0,3) != 'new') { + $record = DataObject::get_by_id($className, $SQL_id); + if($record && !$record->canEdit()) return Security::permissionFailure($this); + } else { + if(!singleton($this->stat('tree_class'))->canCreate()) return Security::permissionFailure($this); + $record = $this->getNewItem($SQL_id, false); + } + + // TODO Coupling to SiteTree + $record->HasBrokenLink = 0; + $record->HasBrokenFile = 0; + + $record->writeWithoutVersion(); + + // Update the class instance if necessary + if($data['ClassName'] != $record->ClassName) { + $newClassName = $record->ClassName; + // The records originally saved attribute was overwritten by $form->saveInto($record) before. + // This is necessary for newClassInstance() to work as expected, and trigger change detection + // on the ClassName attribute + $record->setClassName($data['ClassName']); + // Replace $record with a new instance + $record = $record->newClassInstance($newClassName); + } + + // save form data into record + $form->saveInto($record, true); + $record->write(); + + // if changed to a single_instance_only page type + if ($record->stat('single_instance_only')) { + FormResponse::add("jQuery('#sitetree li.{$record->ClassName}').addClass('{$record->stat('single_instance_only_css_class')}');"); + FormResponse::add($this->hideSingleInstanceOnlyFromCreateFieldJS($record)); + } + else { + FormResponse::add("jQuery('#sitetree li.{$record->ClassName}').removeClass('{$record->stat('single_instance_only_css_class')}');"); + } + // if chnaged from a single_instance_only page type + $sampleOriginalClassObject = new $data['ClassName'](); + if($sampleOriginalClassObject->stat('single_instance_only')) { + FormResponse::add($this->showSingleInstanceOnlyInCreateFieldJS($sampleOriginalClassObject)); + } + + // If the 'Save & Publish' button was clicked, also publish the page + if (isset($data['publish']) && $data['publish'] == 1) { + $record->doPublish(); + + // Update classname with original and get new instance (see above for explanation) + $record->setClassName($data['ClassName']); + $publishedRecord = $record->newClassInstance($record->ClassName); + + $this->response->addHeader( + 'X-Status', + sprintf( + _t( + 'LeftAndMain.STATUSPUBLISHEDSUCCESS', + "Published '%s' successfully", + PR_MEDIUM, + 'Status message after publishing a page, showing the page title' + ), + $publishedRecord->Title + ) + ); + + $form->loadDataFrom($publishedRecord); + } else { + $this->response->addHeader('X-Status', _t('LeftAndMain.SAVEDUP')); + + // write process might've changed the record, so we reload before returning + $form->loadDataFrom($record); + } + + return $form->formHtmlContent(); + } + public function doAdd($data, $form) { $className = isset($data['PageType']) ? $data['PageType'] : "Page"; diff --git a/code/LeftAndMain.php b/code/LeftAndMain.php index c90bce82..13b3bdd9 100644 --- a/code/LeftAndMain.php +++ b/code/LeftAndMain.php @@ -534,7 +534,7 @@ class LeftAndMain extends Controller { } /** - * Save and Publish page handler + * Save handler */ public function save($data, $form) { $className = $this->stat('tree_class'); @@ -549,71 +549,15 @@ class LeftAndMain extends Controller { $record = $this->getNewItem($SQL_id, false); } - // TODO Coupling to SiteTree - $record->HasBrokenLink = 0; - $record->HasBrokenFile = 0; - - $record->writeWithoutVersion(); - - // Update the class instance if necessary - if($data['ClassName'] != $record->ClassName) { - $newClassName = $record->ClassName; - // The records originally saved attribute was overwritten by $form->saveInto($record) before. - // This is necessary for newClassInstance() to work as expected, and trigger change detection - // on the ClassName attribute - $record->setClassName($data['ClassName']); - // Replace $record with a new instance - $record = $record->newClassInstance($newClassName); - } - // save form data into record $form->saveInto($record, true); $record->write(); - - // if changed to a single_instance_only page type - if ($record->stat('single_instance_only')) { - FormResponse::add("jQuery('#sitetree li.{$record->ClassName}').addClass('{$record->stat('single_instance_only_css_class')}');"); - FormResponse::add($this->hideSingleInstanceOnlyFromCreateFieldJS($record)); - } - else { - FormResponse::add("jQuery('#sitetree li.{$record->ClassName}').removeClass('{$record->stat('single_instance_only_css_class')}');"); - } - // if chnaged from a single_instance_only page type - $sampleOriginalClassObject = new $data['ClassName'](); - if($sampleOriginalClassObject->stat('single_instance_only')) { - FormResponse::add($this->showSingleInstanceOnlyInCreateFieldJS($sampleOriginalClassObject)); - } + $this->extend('onAfterSave', $record); - // If the 'Save & Publish' button was clicked, also publish the page - if (isset($data['publish']) && $data['publish'] == 1) { - $record->doPublish(); - $this->extend('onAfterSave', $record); - - // Update classname with original and get new instance (see above for explanation) - $record->setClassName($data['ClassName']); - $publishedRecord = $record->newClassInstance($record->ClassName); - - $this->response->addHeader( - 'X-Status', - sprintf( - _t( - 'LeftAndMain.STATUSPUBLISHEDSUCCESS', - "Published '%s' successfully", - PR_MEDIUM, - 'Status message after publishing a page, showing the page title' - ), - $publishedRecord->Title - ) - ); - - $form->loadDataFrom($publishedRecord); - } else { - $this->extend('onAfterSave', $record); - $this->response->addHeader('X-Status', _t('LeftAndMain.SAVEDUP')); - - // write process might've changed the record, so we reload before returning - $form->loadDataFrom($record); - } + $this->response->addHeader('X-Status', _t('LeftAndMain.SAVEDUP')); + + // write process might've changed the record, so we reload before returning + $form->loadDataFrom($record); return $form->formHtmlContent(); } @@ -790,10 +734,74 @@ JS; * Form might be readonly if the current user doesn't have the permission to edit * the record. */ + /** + * @return Form + */ function EditForm($request = null) { - return $this->EmptyForm(); + return $this->getEditForm(); } - + + public function getEditForm($id = null) { + if(!$id) $id = $this->currentPageID(); + + $record = ($id && $id != "root") ? DataObject::get_by_id($this->stat('tree_class'), $id) : null; + if($record && !$record->canView()) return Security::permissionFailure($this); + + if($record) { + $fields = $record->getCMSFields(); + if ($fields == null) { + user_error( + "getCMSFields() returned null - it should return a FieldSet object. + Perhaps you forgot to put a return statement at the end of your method?", + E_USER_ERROR + ); + } + + if($record->hasMethod('getAllCMSActions')) { + $actions = $record->getAllCMSActions(); + } else { + $actions = $record->getCMSActions(); + // add default actions if none are defined + if(!$actions || !$actions->Count()) { + if($record->canEdit()) { + $actions->push(new FormAction('save',_t('CMSMain.SAVE','Save'))); + } + } + } + + $form = new Form($this, "EditForm", $fields, $actions); + $form->loadDataFrom($record); + + // Add a default or custom validator. + // @todo Currently the default Validator.js implementation + // adds javascript to the document body, meaning it won't + // be included properly if the associated fields are loaded + // through ajax. This means only serverside validation + // will kick in for pages+validation loaded through ajax. + // This will be solved by using less obtrusive javascript validation + // in the future, see http://open.silverstripe.com/ticket/2915 and + // http://open.silverstripe.com/ticket/3386 + if($record->hasMethod('getCMSValidator')) { + $validator = $record->getCMSValidator(); + // The clientside (mainly LeftAndMain*.js) rely on ajax responses + // which can be evaluated as javascript, hence we need + // to override any global changes to the validation handler. + $validator->setJavascriptValidationHandler('prototype'); + $form->setValidator($validator); + } else { + $form->unsetValidator(); + } + + if(!$record->canEdit()) { + $readonlyFields = $form->Fields()->makeReadonly(); + $form->setFields($readonlyFields); + } + } else { + $form = $this->EmptyForm(); + } + + return $form; + } /** * Returns a placeholder form, used by {@link getEditForm()} if no record is selected. * Our javascript logic always requires a form to be present in the CMS interface.