172 lines
5.2 KiB
PHP
172 lines
5.2 KiB
PHP
<?php
|
|
|
|
namespace SilverStripe\Security\Confirmation;
|
|
|
|
use SilverStripe\Core\Injector\Injector;
|
|
use SilverStripe\Control\RequestHandler;
|
|
use SilverStripe\Forms\Form as BaseForm;
|
|
use SilverStripe\Forms\FormAction;
|
|
use SilverStripe\Forms\FieldGroup;
|
|
use SilverStripe\Forms\FieldList;
|
|
use SilverStripe\Forms\HeaderField;
|
|
use SilverStripe\Forms\HiddenField;
|
|
use SilverStripe\Forms\LabelField;
|
|
use SilverStripe\ORM\ValidationException;
|
|
|
|
/**
|
|
* Basic confirmation form implementation.
|
|
*
|
|
* Renders the list of confirmation items on the screen
|
|
* and reconciles those with the confirmation storage.
|
|
*
|
|
* If the user confirms the action, marks the storage as confirmed
|
|
* and redirects to the success url (kept in the storage).
|
|
*
|
|
* If the user declines the action, cleans up the storage and
|
|
* redirects to the failure url (kept in the storage).
|
|
*/
|
|
class Form extends BaseForm
|
|
{
|
|
/**
|
|
* Confirmation storage instance
|
|
*
|
|
* @var Storage
|
|
*/
|
|
private $storage;
|
|
|
|
/**
|
|
* @param string $storageId confirmation storage identifier
|
|
* @param RequestHandler $controller active request handler
|
|
* @param string $formConstructor form constructor name
|
|
*/
|
|
public function __construct($storageId, RequestHandler $controller, $formConstructor)
|
|
{
|
|
$request = $controller->getRequest();
|
|
$storage = Injector::inst()->createWithArgs(Storage::class, [$request->getSession(), $storageId, false]);
|
|
|
|
if (count($storage->getItems() ?? [])) {
|
|
$fieldList = $this->buildFieldList($storage);
|
|
$actionList = $this->buildActionList($storage);
|
|
} else {
|
|
$fieldList = $this->buildEmptyFieldList();
|
|
$actionList = null;
|
|
}
|
|
|
|
parent::__construct($controller, $formConstructor, $fieldList, $actionList);
|
|
|
|
if ($storage->getHttpMethod() !== 'POST') {
|
|
$this->enableSecurityToken();
|
|
}
|
|
|
|
$this->storage = $storage;
|
|
}
|
|
|
|
/**
|
|
* The form refusal handler. Cleans up the confirmation storage
|
|
* and returns the failure redirection (kept in the storage)
|
|
*
|
|
* @return HTTPResponse redirect
|
|
*/
|
|
public function doRefuse()
|
|
{
|
|
$url = $this->storage->getFailureUrl();
|
|
$this->storage->cleanup();
|
|
return $this->controller->redirect($url);
|
|
}
|
|
|
|
/**
|
|
* The form confirmation handler. Checks all the items in the storage
|
|
* has been confirmed and marks them as such. Returns a redirect
|
|
* when all the storage items has been verified and marked as confirmed.
|
|
*
|
|
* @return HTTPResponse success url
|
|
*
|
|
* @throws ValidationException when the confirmation storage has an item missing on the form
|
|
*/
|
|
public function doConfirm()
|
|
{
|
|
$storage = $this->storage;
|
|
$data = $this->getData();
|
|
|
|
if (!$storage->confirm($data)) {
|
|
throw new ValidationException('Sorry, we could not verify the parameters');
|
|
}
|
|
|
|
$url = $storage->getSuccessUrl();
|
|
|
|
return $this->controller->redirect($url);
|
|
}
|
|
|
|
protected function buildActionList(Storage $storage)
|
|
{
|
|
$cancel = FormAction::create('doRefuse', _t(__CLASS__ . '.REFUSE', 'Cancel'));
|
|
$confirm = FormAction::create('doConfirm', _t(__CLASS__ . '.CONFIRM', 'Run the action'))->setAutofocus(true);
|
|
|
|
if ($storage->getHttpMethod() === 'POST') {
|
|
$confirm->setAttribute('formaction', htmlspecialchars($storage->getSuccessUrl() ?? ''));
|
|
}
|
|
|
|
return FieldList::create($cancel, $confirm);
|
|
}
|
|
|
|
/**
|
|
* Builds the form fields taking the confirmation items from the storage
|
|
*
|
|
* @param Storage $storage Confirmation storage instance
|
|
*
|
|
* @return FieldList
|
|
*/
|
|
protected function buildFieldList(Storage $storage)
|
|
{
|
|
$fields = [];
|
|
|
|
foreach ($storage->getItems() as $item) {
|
|
$group = [];
|
|
|
|
$group[] = HeaderField::create(null, $item->getName());
|
|
|
|
if ($item->getDescription()) {
|
|
$group[] = LabelField::create($item->getDescription());
|
|
}
|
|
|
|
$fields[] = FieldGroup::create(...$group);
|
|
}
|
|
|
|
foreach ($storage->getHashedItems() as $key => $val) {
|
|
$fields[] = HiddenField::create($key, null, $val);
|
|
}
|
|
|
|
if ($storage->getHttpMethod() === 'POST') {
|
|
// add the storage CSRF token
|
|
$fields[] = HiddenField::create($storage->getCsrfToken(), null, '1');
|
|
|
|
// replicate the original POST request parameters
|
|
// so that the new confirmed POST request has those
|
|
$data = $storage->getSuccessPostVars();
|
|
|
|
if (is_null($data)) {
|
|
throw new ValidationException('Sorry, your cookies seem to have expired. Try to repeat the initial action.');
|
|
}
|
|
|
|
foreach ($data as $key => $value) {
|
|
$fields[] = HiddenField::create($key, null, $value);
|
|
}
|
|
}
|
|
|
|
return FieldList::create(...$fields);
|
|
}
|
|
|
|
/**
|
|
* Builds the fields showing the form is empty and there's nothing
|
|
* to confirm
|
|
*
|
|
* @return FieldList
|
|
*/
|
|
protected function buildEmptyFieldList()
|
|
{
|
|
return FieldList::create(
|
|
HeaderField::create(null, _t(__CLASS__ . '.EMPTY_TITLE', 'Nothing to confirm'))
|
|
);
|
|
}
|
|
}
|