silverstripe-framework/admin/code/AddToCampaignHandler.php
Ingo Schommer 84cdb15a5f Simplify "add to campaign" dialog
Talked to @clarkepaul and simplified to avoid title duplication
2016-08-28 13:07:31 +12:00

273 lines
7.4 KiB
PHP

<?php
namespace SilverStripe\Admin;
use SilverStripe\Framework\Core\Injectable;
use SilverStripe\ORM\ArrayList;
use SilverStripe\ORM\FieldType\DBHTMLText;
use SilverStripe\ORM\Versioning\ChangeSet;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\Versioning\ChangeSetItem;
use ClassInfo;
use Object;
use DropdownField;
use FieldList;
use HiddenField;
use Form;
use CompositeField;
use LiteralField;
use Director;
use SS_HTTPResponse;
use FormAction;
use SS_HTTPResponse_Exception;
/**
* Class AddToCampaignHandler - handle the AddToCampaign action.
*
* This is a class designed to be delegated to by a Form action handler method in the EditForm of a LeftAndMain
* child class.
*
* Add To Campaign can be seen as an item action like "publish" or "rollback", but unlike those actions
* it needs one additional piece of information to execute, the ChangeSet ID.
*
* So this handler does one of two things to respond to the action request, depending on whether the ChangeSet ID
* was included in the submitted data
* - If it was, perform the Add To Campaign action (as per any other action)
* - If it wasn't, return a form to get the ChangeSet ID and then repeat this action submission
*
* To use, you'd add an action to your LeftAndMain subclass, like this:
*
* function addtocampaign($data, $form) {
* $handler = AddToCampaignHandler::create($form, $data);
* return $handler->handle();
* }
*
* and add an AddToCampaignHandler_FormAction to the EditForm, possibly through getCMSActions
*/
class AddToCampaignHandler {
use Injectable;
/**
* Parent controller for this form
*
* @var Controller
*/
protected $controller;
/**
* The submitted form data
*
* @var array
*/
protected $data;
/**
* Form name to use
*
* @var string
*/
protected $name;
protected $showTitle = true;
/**
* AddToCampaignHandler constructor.
*
* @param Controller $parentController Controller for this form
* @param array|DataObject $data The data submitted as part of that form
* @param string $name Form name
*/
public function __construct($controller = null, $data = [], $name = 'AddToCampaignForm') {
$this->controller = $controller;
if ($data instanceof DataObject) {
$data = $data->toMap();
}
$this->data = $data;
$this->name = $name;
}
public function setShowTitle($show) {
$this->showTitle = $show;
}
/**
* Perform the action. Either returns a Form or performs the action, as per the class doc
*
* @return DBHTMLText|SS_HTTPResponse
*/
public function handle() {
$object = $this->getObject($this->data['ID'], $this->data['ClassName']);
if (empty($this->data['Campaign'])) {
return $this->Form($object)->forTemplate();
} else {
return $this->addToCampaign($object, $this->data['Campaign']);
}
}
/**
* Get what ChangeSets are available for an item to be added to by this user
*
* @return ArrayList[ChangeSet]
*/
protected function getAvailableChangeSets() {
return ChangeSet::get()
->filter('State', ChangeSet::STATE_OPEN)
->filterByCallback(function($item) {
/** @var ChangeSet $item */
return $item->canView();
});
}
/**
* Safely get a DataObject from a client-supplied ID and ClassName, checking: argument
* validity; existence; and canView permissions.
*
* @param int $id The ID of the DataObject
* @param string $class The Class of the DataObject
* @return DataObject The referenced DataObject
* @throws SS_HTTPResponse_Exception
*/
protected function getObject($id, $class) {
$id = (int)$id;
$class = ClassInfo::class_name($class);
if (!$class || !is_subclass_of($class, 'SilverStripe\\ORM\\DataObject') || !Object::has_extension($class, 'SilverStripe\\ORM\\Versioning\\Versioned')) {
$this->controller->httpError(400, _t(
'AddToCampaign.ErrorGeneral',
'We apologise, but there was an error'
));
return null;
}
$object = DataObject::get($class)->byID($id);
if (!$object) {
$this->controller->httpError(404, _t(
'AddToCampaign.ErrorNotFound',
'That {Type} couldn\'t be found',
'',
['Type' => $class]
));
return null;
}
if (!$object->canView()) {
$this->controller->httpError(403, _t(
'AddToCampaign.ErrorItemPermissionDenied',
'It seems you don\'t have the necessary permissions to add {ObjectTitle} to a campaign',
'',
['ObjectTitle' => $object->Title]
)
);
return null;
}
return $object;
}
/**
* Builds a Form that mirrors the parent editForm, but with an extra field to collect the ChangeSet ID
*
* @param DataObject $object The object we're going to be adding to whichever ChangeSet is chosen
* @return Form
*/
public function Form($object) {
$inChangeSets = array_unique(ChangeSetItem::get_for_object($object)->column('ChangeSetID'));
$changeSets = $this->getAvailableChangeSets()->map();
$campaignDropdown = DropdownField::create('Campaign', '', $changeSets);
$campaignDropdown->setEmptyString(_t('Campaigns.AddToCampaignFormFieldLabel', 'Select a Campaign'));
$campaignDropdown->addExtraClass('noborder');
$campaignDropdown->setDisabledItems($inChangeSets);
$fields = new FieldList([
$campaignDropdown,
HiddenField::create('ID', null, $this->data['ID']),
HiddenField::create('ClassName', null, $this->data['ClassName'])
]);
if ($this->showTitle) {
$fields = new FieldList(
$header = new CompositeField(
new LiteralField(
'Heading',
sprintf('<h3>%s</h3>', _t('Campaigns.AddToCampaign', 'Add To Campaign'))
)
),
$content = new CompositeField($fields)
);
$header->addExtraClass('add-to-campaign__header');
$content->addExtraClass('add-to-campaign__content');
}
$form = new Form(
$this->controller,
$this->name,
$fields,
new FieldList(
$action = AddToCampaignHandler_FormAction::create()
)
);
$action->addExtraClass('add-to-campaign__action');
$form->setHTMLID('Form_EditForm_AddToCampaign');
$form->unsetValidator();
$form->loadDataFrom($this->data);
$form->addExtraClass('form--no-dividers add-to-campaign__form');
return $form;
}
/**
* Performs the actual action of adding the object to the ChangeSet, once the ChangeSet ID is known
*
* @param DataObject $object The object to add to the ChangeSet
* @param int $campaignID The ID of the ChangeSet to add $object to
* @return SS_HTTPResponse
* @throws SS_HTTPResponse_Exception
*/
public function addToCampaign($object, $campaignID) {
/** @var ChangeSet $changeSet */
$changeSet = ChangeSet::get()->byID($campaignID);
if (!$changeSet) {
$this->controller->httpError(404, _t(
'AddToCampaign.ErrorNotFound',
'That {Type} couldn\'t be found',
'',
['Type' => 'Campaign']
));
return null;
}
if (!$changeSet->canEdit()) {
$this->controller->httpError(403, _t(
'AddToCampaign.ErrorCampaignPermissionDenied',
'It seems you don\'t have the necessary permissions to add {ObjectTitle} to {CampaignTitle}',
'',
['ObjectTitle' => $object->Title, 'CampaignTitle' => $changeSet->Title]
));
return null;
}
$changeSet->addObject($object);
if (Director::is_ajax()) {
$response = new SS_HTTPResponse(_t(
'AddToCampaign.Success',
'Successfully added {ObjectTitle} to {CampaignTitle}',
'',
['ObjectTitle' => $object->Title, 'CampaignTitle' => $changeSet->Title]
), 200);
$response->addHeader('Content-Type', 'text/plain; charset=utf-8');
return $response;
} else {
return $this->controller->getController()->redirectBack();
}
}
}