mirror of
https://github.com/Icinga/icingaweb2-module-businessprocess.git
synced 2026-02-10 06:23:05 -05:00
QuickForm: initial import, makes things easier
This commit is contained in:
parent
4a05f19b00
commit
0c633491d4
3 changed files with 511 additions and 0 deletions
53
library/Businessprocess/Web/Form/CsrfToken.php
Normal file
53
library/Businessprocess/Web/Form/CsrfToken.php
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Businessprocess\Web\Form;
|
||||
|
||||
class CsrfToken
|
||||
{
|
||||
/**
|
||||
* Check whether the given token is valid
|
||||
*
|
||||
* @param string $token Token
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isValid($token)
|
||||
{
|
||||
if (strpos($token, '|') === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
list($seed, $token) = explode('|', $elementValue);
|
||||
|
||||
if (!is_numeric($seed)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $token === hash('sha256', self::getSessionId() . $seed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new token
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function generate()
|
||||
{
|
||||
$seed = mt_rand();
|
||||
$token = hash('sha256', self::getSessionId() . $seed);
|
||||
|
||||
return sprintf('%s|%s', $seed, $token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current session id
|
||||
*
|
||||
* TODO: we should do this through our App or Session object
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function getSessionId()
|
||||
{
|
||||
return session_id();
|
||||
}
|
||||
}
|
||||
37
library/Businessprocess/Web/Form/FormLoader.php
Normal file
37
library/Businessprocess/Web/Form/FormLoader.php
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Businessprocess\Web\Form;
|
||||
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Application\Modules\Module;
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
|
||||
class FormLoader
|
||||
{
|
||||
public static function load($name, Module $module = null)
|
||||
{
|
||||
if ($module === null) {
|
||||
$basedir = Icinga::app()->getApplicationDir('forms');
|
||||
$ns = '\\Icinga\\Web\\Forms\\';
|
||||
} else {
|
||||
$basedir = $module->getFormDir();
|
||||
$ns = '\\Icinga\\Module\\' . ucfirst($module->getName()) . '\\Forms\\';
|
||||
}
|
||||
if (preg_match('~^[a-z0-9/]+$~i', $name)) {
|
||||
$parts = preg_split('~/~', $name);
|
||||
$class = ucfirst(array_pop($parts)) . 'Form';
|
||||
$file = sprintf('%s/%s/%s.php', rtrim($basedir, '/'), implode('/', $parts), $class);
|
||||
if (file_exists($file)) {
|
||||
require_once($file);
|
||||
$class = $ns . $class;
|
||||
$options = array();
|
||||
if ($module !== null) {
|
||||
$options['icingaModule'] = $module;
|
||||
}
|
||||
|
||||
return new $class($options);
|
||||
}
|
||||
}
|
||||
throw new ProgrammingError(sprintf('Cannot load %s (%s), no such form', $name, $file));
|
||||
}
|
||||
}
|
||||
421
library/Businessprocess/Web/Form/QuickForm.php
Normal file
421
library/Businessprocess/Web/Form/QuickForm.php
Normal file
|
|
@ -0,0 +1,421 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Businessprocess\Web\Form;
|
||||
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Application\Modules\Module;
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Web\Request;
|
||||
use Icinga\Web\Url;
|
||||
use Zend_Form;
|
||||
|
||||
/**
|
||||
* QuickForm wants to be a base class for simple forms
|
||||
*/
|
||||
abstract class QuickForm extends Zend_Form
|
||||
{
|
||||
const ID = '__FORM_NAME';
|
||||
|
||||
const CSRF = '__FORM_CSRF';
|
||||
|
||||
/**
|
||||
* The name of this form
|
||||
*/
|
||||
protected $formName;
|
||||
|
||||
/**
|
||||
* Whether the form has been sent
|
||||
*/
|
||||
protected $hasBeenSent;
|
||||
|
||||
/**
|
||||
* Whether the form has been sent
|
||||
*/
|
||||
protected $hasBeenSubmitted;
|
||||
|
||||
/**
|
||||
* The submit caption, element - still tbd
|
||||
*/
|
||||
// protected $submit;
|
||||
|
||||
/**
|
||||
* Our request
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
protected $successUrl;
|
||||
|
||||
protected $succeeded;
|
||||
|
||||
protected $successMessage;
|
||||
|
||||
protected $submitLabel;
|
||||
|
||||
protected $submitButtonName;
|
||||
|
||||
/**
|
||||
* Whether form elements have already been created
|
||||
*/
|
||||
protected $didSetup = false;
|
||||
|
||||
/**
|
||||
* The Icinga module this form belongs to. Usually only set if the
|
||||
* form is initialized through the FormLoader
|
||||
*/
|
||||
protected $icingaModule;
|
||||
|
||||
protected $icingaModuleName;
|
||||
|
||||
protected $hintCount = 0;
|
||||
|
||||
public function __construct($options = null)
|
||||
{
|
||||
parent::__construct($this->handleOptions($options));
|
||||
$this->setMethod('post');
|
||||
$this->setAction(Url::fromRequest());
|
||||
$this->createIdElement();
|
||||
$this->regenerateCsrfToken();
|
||||
}
|
||||
|
||||
protected function handleOptions($options = null)
|
||||
{
|
||||
if ($options === null) {
|
||||
return $options;
|
||||
}
|
||||
|
||||
if (array_key_exists('icingaModule', $options)) {
|
||||
$this->icingaModule = $options['icingaModule'];
|
||||
$this->icingaModuleName = $this->icingaModule->getName();
|
||||
unset($options['icingaModule']);
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
protected function addSubmitButtonIfSet()
|
||||
{
|
||||
if (false !== ($label = $this->getSubmitLabel())) {
|
||||
$el = $this->createElement('submit', $label)->setLabel($label)->removeDecorator('Label');
|
||||
$this->submitButtonName = $el->getName();
|
||||
$this->addElement($el);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This is ugly, we need to defer button creation
|
||||
protected function moveSubmitToBottom()
|
||||
{
|
||||
$name = $this->submitButtonName;
|
||||
if ($name && ($submit = $this->getElement($name))) {
|
||||
$this->removeElement($name);
|
||||
$this->addElement($submit);
|
||||
}
|
||||
}
|
||||
|
||||
protected function createIdElement()
|
||||
{
|
||||
$this->detectName();
|
||||
$this->addHidden(self::ID, $this->getName());
|
||||
$this->getElement(self::ID)->setIgnore(true);
|
||||
}
|
||||
|
||||
protected function getSentValue($name, $default = null)
|
||||
{
|
||||
$request = $this->getRequest();
|
||||
|
||||
if ($request->isPost()) {
|
||||
return $request->getPost($name);
|
||||
} else {
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSubmitLabel()
|
||||
{
|
||||
if ($this->submitLabel === null) {
|
||||
return $this->translate('Submit');
|
||||
}
|
||||
|
||||
return $this->submitLabel;
|
||||
}
|
||||
|
||||
public function setSubmitLabel($label)
|
||||
{
|
||||
$this->submitLabel = $label;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function loadForm($name, Module $module = null)
|
||||
{
|
||||
if ($module === null) {
|
||||
$module = $this->icingaModule;
|
||||
}
|
||||
|
||||
return FormLoader::load($name, $module);
|
||||
}
|
||||
|
||||
public function regenerateCsrfToken()
|
||||
{
|
||||
if (! $element = $this->getElement(self::CSRF)) {
|
||||
$this->addHidden(self::CSRF, CsrfToken::generate());
|
||||
$element = $this->getElement(self::CSRF);
|
||||
}
|
||||
$element->setIgnore(true);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeCsrfToken()
|
||||
{
|
||||
$this->removeElement(self::CSRF);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function addHidden($name, $value = null)
|
||||
{
|
||||
$this->addElement('hidden', $name);
|
||||
$el = $this->getElement($name);
|
||||
$el->setDecorators(array('ViewHelper'));
|
||||
if ($value !== null) {
|
||||
$this->setDefault($name, $value);
|
||||
$el->setValue($value);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function addHtmlHint($html, $options = array())
|
||||
{
|
||||
return $this->addHtml('<div class="hint">' . $html . '</div>', $options);
|
||||
}
|
||||
|
||||
public function addHtml($html, $options = array())
|
||||
{
|
||||
$name = '_HINT' . ++$this->hintCount;
|
||||
$this->addElement('note', $name, $options);
|
||||
$this->getElement($name)
|
||||
->setValue($html)
|
||||
->setIgnore(true)
|
||||
->removeDecorator('Label');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function optionalEnum($enum)
|
||||
{
|
||||
return array(
|
||||
null => $this->translate('- please choose -')
|
||||
) + $enum;
|
||||
}
|
||||
|
||||
public function succeeded()
|
||||
{
|
||||
return $this->succeeded;
|
||||
}
|
||||
|
||||
public function setSuccessUrl($url)
|
||||
{
|
||||
$this->successUrl = $url;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setup()
|
||||
{
|
||||
}
|
||||
|
||||
protected function onSetup()
|
||||
{
|
||||
}
|
||||
|
||||
public function setAction($action)
|
||||
{
|
||||
if ($action instanceof Url) {
|
||||
$action = $action->getAbsoluteUrl('&');
|
||||
}
|
||||
|
||||
return parent::setAction($action);
|
||||
}
|
||||
|
||||
public function setIcingaModule(Module $module)
|
||||
{
|
||||
$this->icingaModule = $module;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function hasBeenSubmitted()
|
||||
{
|
||||
if ($this->hasBeenSubmitted === null) {
|
||||
$req = $this->getRequest();
|
||||
if ($req->isPost()) {
|
||||
$post = $req->getPost();
|
||||
$name = $this->submitButtonName;
|
||||
|
||||
if ($name === null) {
|
||||
$this->hasBeenSubmitted = $this->hasBeenSent();
|
||||
} else {
|
||||
$el = $this->getElement($name);
|
||||
$this->hasBeenSubmitted = array_key_exists($name, $post)
|
||||
&& $post[$name] === $this->getSubmitLabel();
|
||||
}
|
||||
} else {
|
||||
$this->hasBeenSubmitted === false;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->hasBeenSubmitted;
|
||||
}
|
||||
|
||||
protected function beforeValidation($data = array())
|
||||
{
|
||||
}
|
||||
|
||||
public function prepareElements()
|
||||
{
|
||||
if (! $this->didSetup) {
|
||||
$this->setup();
|
||||
$this->addSubmitButtonIfSet();
|
||||
$this->onSetup();
|
||||
$this->didSetup = true;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function handleRequest(Request $request = null)
|
||||
{
|
||||
if ($request !== null) {
|
||||
$this->setRequest($request);
|
||||
}
|
||||
|
||||
if ($this->hasBeenSent()) {
|
||||
$post = $this->getRequest()->getPost();
|
||||
if ($this->hasBeenSubmitted()) {
|
||||
$this->beforeValidation($post);
|
||||
if ($this->isValid($post)) {
|
||||
$this->onSuccess();
|
||||
$this->succeeded = true;
|
||||
} else {
|
||||
$this->onFailure();
|
||||
$this->succeeded = false;
|
||||
}
|
||||
} else {
|
||||
$this->setDefaults($post);
|
||||
}
|
||||
} else {
|
||||
// Well...
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function translate($string)
|
||||
{
|
||||
if ($this->icingaModuleName === null) {
|
||||
return t($string);
|
||||
} else {
|
||||
return mt($this->icingaModuleName, $string);
|
||||
}
|
||||
}
|
||||
|
||||
public function onSuccess()
|
||||
{
|
||||
$this->redirectOnSuccess();
|
||||
}
|
||||
|
||||
public function setSuccessMessage($message)
|
||||
{
|
||||
$this->successMessage = $message;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSuccessMessage($message = null)
|
||||
{
|
||||
if ($message !== null) {
|
||||
return $message;
|
||||
}
|
||||
if ($this->successMessage === null) {
|
||||
return t('Form has successfully been sent');
|
||||
}
|
||||
return $this->successMessage;
|
||||
}
|
||||
|
||||
public function redirectOnSuccess($message = null)
|
||||
{
|
||||
$url = $this->successUrl ?: $this->getAction();
|
||||
$this->notifySuccess($this->getSuccessMessage($message));
|
||||
$this->redirectAndExit($url);
|
||||
}
|
||||
|
||||
public function onFailure()
|
||||
{
|
||||
}
|
||||
|
||||
public function notifySuccess($message = null)
|
||||
{
|
||||
if ($message === null) {
|
||||
$message = t('Form has successfully been sent');
|
||||
}
|
||||
Notification::success($message);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function notifyError($message)
|
||||
{
|
||||
Notification::error($message);
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function redirectAndExit($url)
|
||||
{
|
||||
Icinga::app()->getFrontController()->getResponse()->redirectAndExit($url);
|
||||
}
|
||||
|
||||
protected function onRequest()
|
||||
{
|
||||
}
|
||||
|
||||
public function setRequest(Request $request)
|
||||
{
|
||||
if ($this->request !== null) {
|
||||
throw new ProgrammingError('Unable to set request twice');
|
||||
}
|
||||
|
||||
$this->request = $request;
|
||||
$this->prepareElements();
|
||||
$this->onRequest();
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRequest()
|
||||
{
|
||||
if ($this->request === null) {
|
||||
$this->setRequest(Icinga::app()->getFrontController()->getRequest());
|
||||
}
|
||||
return $this->request;
|
||||
}
|
||||
|
||||
public function hasBeenSent()
|
||||
{
|
||||
if ($this->hasBeenSent === null) {
|
||||
$req = $this->getRequest();
|
||||
if ($req->isPost()) {
|
||||
$post = $req->getPost();
|
||||
$this->hasBeenSent = array_key_exists(self::ID, $post) &&
|
||||
$post[self::ID] === $this->getName();
|
||||
} else {
|
||||
$this->hasBeenSent === false;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->hasBeenSent;
|
||||
}
|
||||
|
||||
protected function detectName()
|
||||
{
|
||||
if ($this->formName !== null) {
|
||||
$this->setName($this->formName);
|
||||
} else {
|
||||
$this->setName(get_class($this));
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue