PDF rausgenommen
This commit is contained in:
508
msd2/tracking/piwik/libs/HTML/QuickForm2/Controller.php
Normal file
508
msd2/tracking/piwik/libs/HTML/QuickForm2/Controller.php
Normal file
@ -0,0 +1,508 @@
|
||||
<?php
|
||||
/**
|
||||
* Class implementing the Page Controller pattern for multipage forms
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENSE:
|
||||
*
|
||||
* Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>,
|
||||
* Bertrand Mansion <golgote@mamasam.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * The names of the authors may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @category HTML
|
||||
* @package HTML_QuickForm2
|
||||
* @author Alexey Borzov <avb@php.net>
|
||||
* @author Bertrand Mansion <golgote@mamasam.com>
|
||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||
* @version SVN: $Id: Controller.php 295963 2010-03-08 14:33:43Z avb $
|
||||
* @link http://pear.php.net/package/HTML_QuickForm2
|
||||
*/
|
||||
|
||||
/** The class representing a page of a multipage form */
|
||||
// require_once 'HTML/QuickForm2/Controller/Page.php';
|
||||
|
||||
/** Object wrapping around session variable used to store controller data */
|
||||
// require_once 'HTML/QuickForm2/Controller/SessionContainer.php';
|
||||
|
||||
/** Class presenting the values stored in session by Controller as submitted ones */
|
||||
// require_once 'HTML/QuickForm2/DataSource/Session.php';
|
||||
|
||||
/**
|
||||
* Class implementing the Page Controller pattern for multipage forms
|
||||
*
|
||||
* This class keeps track of pages and (default) action handlers for the form,
|
||||
* it manages $_SESSION container for the form values, allows setting
|
||||
* DataSources for the form as a whole and getting its value.
|
||||
*
|
||||
* @category HTML
|
||||
* @package HTML_QuickForm2
|
||||
* @author Alexey Borzov <avb@php.net>
|
||||
* @author Bertrand Mansion <golgote@mamasam.com>
|
||||
* @version Release: @package_version@
|
||||
*/
|
||||
class HTML_QuickForm2_Controller implements IteratorAggregate
|
||||
{
|
||||
/**
|
||||
* Key in $_REQUEST array that contains the ID of the Controller
|
||||
*/
|
||||
const KEY_ID = '_qfc_id';
|
||||
|
||||
/**
|
||||
* Key in $_SESSION array that contains the Controller data (needs ID substituted via sprintf())
|
||||
*/
|
||||
const KEY_CONTAINER = '_%s_container';
|
||||
|
||||
/**
|
||||
* Whether the form is a wizard
|
||||
* @var boolean
|
||||
*/
|
||||
protected $wizard = true;
|
||||
|
||||
/**
|
||||
* Whether Controller ID should be sent in GET and POST parameters
|
||||
* @var boolean
|
||||
*/
|
||||
protected $propagate = true;
|
||||
|
||||
/**
|
||||
* Controller ID
|
||||
* @var string
|
||||
*/
|
||||
protected $id = null;
|
||||
|
||||
/**
|
||||
* Contains the pages (instances of HTML_QuickForm2_Controller_Page) of the multipage form
|
||||
* @var array
|
||||
*/
|
||||
protected $pages = array();
|
||||
|
||||
/**
|
||||
* Contains the mapping of action names to handlers (objects implementing HTML_QuickForm2_Controller_Action)
|
||||
* @var array
|
||||
*/
|
||||
protected $handlers = array();
|
||||
|
||||
/**
|
||||
* The action extracted from HTTP request: array('page', 'action')
|
||||
* @var array
|
||||
*/
|
||||
protected $actionName = null;
|
||||
|
||||
/**
|
||||
* A wrapper around session variable used to store form data
|
||||
* @var HTML_QuickForm2_Controller_SessionContainer
|
||||
*/
|
||||
protected $sessionContainer = null;
|
||||
|
||||
/**
|
||||
* Finds a controller name in $_REQUEST
|
||||
*
|
||||
* @return string|null Returns nulle if either a KEY_ID is not present
|
||||
* in $_REQUEST or KEY_CONTAINER is not present in
|
||||
* $_SESSION
|
||||
*/
|
||||
public static function findControllerID()
|
||||
{
|
||||
if (empty($_REQUEST[self::KEY_ID])
|
||||
|| empty($_SESSION[sprintf(self::KEY_CONTAINER, $_REQUEST[self::KEY_ID])])
|
||||
) {
|
||||
return null;
|
||||
} else {
|
||||
return $_REQUEST[self::KEY_ID];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* Sets the form ID, whether to send this ID in POST and GET parameters,
|
||||
* wizard / non-wizard behaviour.
|
||||
*
|
||||
* Different forms should be given different IDs, as they are used to store
|
||||
* values in session. If $id is empty, the controller will try to find it
|
||||
* in $_REQUEST, throwing the exception if this fails.
|
||||
*
|
||||
* Wizard forms only allow going to the next page if all the previous ones
|
||||
* are valid.
|
||||
*
|
||||
* @param string Form ID
|
||||
* @param boolean Whether the form is a wizard
|
||||
* @param boolean Whether form's ID should be sent with GET and POST parameters
|
||||
* @throws HTML_QuickForm2_NotFoundException if ID is not given and cannot
|
||||
* be found in $_REQUEST, or session container is empty
|
||||
*/
|
||||
public function __construct($id = null, $wizard = true, $propagateId = false)
|
||||
{
|
||||
if (empty($id)) {
|
||||
$propagateId = true;
|
||||
$id = self::findControllerID();
|
||||
}
|
||||
if (empty($id)) {
|
||||
throw new HTML_QuickForm2_NotFoundException(
|
||||
'Controller ID not available in $_REQUEST or session ' .
|
||||
'container is empty, please provide ID to constructor'
|
||||
);
|
||||
}
|
||||
$this->id = $id;
|
||||
$this->wizard = (bool)$wizard;
|
||||
$this->propagate = (bool)$propagateId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the form is a wizard
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isWizard()
|
||||
{
|
||||
return $this->wizard;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the form ID
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether to send form id with GET and POST parameters
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function propagateId()
|
||||
{
|
||||
return $this->propagate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the session container with the controller data
|
||||
*
|
||||
* @return HTML_QuickForm2_Controller_SessionContainer
|
||||
*/
|
||||
public function getSessionContainer()
|
||||
{
|
||||
if (empty($this->sessionContainer)) {
|
||||
$this->sessionContainer = new HTML_QuickForm2_Controller_SessionContainer($this);
|
||||
}
|
||||
return $this->sessionContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the session variable containing the controller data
|
||||
*/
|
||||
public function destroySessionContainer()
|
||||
{
|
||||
unset($_SESSION[sprintf(self::KEY_CONTAINER, $this->id)]);
|
||||
$this->sessionContainer = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the name of the page and the action to perform with it from HTTP request data
|
||||
*
|
||||
* @return array first element is page name, second is action name
|
||||
*/
|
||||
public function getActionName()
|
||||
{
|
||||
if (is_array($this->actionName)) {
|
||||
return $this->actionName;
|
||||
}
|
||||
if (empty($this->pages)) {
|
||||
throw new HTML_QuickForm2_NotFoundException('No pages added to the form');
|
||||
}
|
||||
$names = array_map('preg_quote', array_keys($this->pages));
|
||||
$regex = '/^_qf_(' . implode('|', $names) . ')_(.+?)(_x)?$/';
|
||||
foreach (array_keys($_REQUEST) as $key) {
|
||||
if (preg_match($regex, $key, $matches)) {
|
||||
$this->actionName = array($matches[1], $matches[2]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!is_array($this->actionName)) {
|
||||
reset($this->pages);
|
||||
$this->actionName = array(key($this->pages), 'display');
|
||||
}
|
||||
return $this->actionName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the request
|
||||
*
|
||||
* This finds the page, the action to perform with it and passes the action
|
||||
* to the page's handle() method.
|
||||
*
|
||||
* @throws HTML_QuickForm2_Exception
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
list($page, $action) = $this->getActionName();
|
||||
return $this->pages[$page]->handle($action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a handler for a specific action
|
||||
*
|
||||
* @param string action name
|
||||
* @param HTML_QuickForm2_Controller_Action the handler for the action
|
||||
*/
|
||||
public function addHandler($actionName, HTML_QuickForm2_Controller_Action $action)
|
||||
{
|
||||
$this->handlers[$actionName] = $action;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles an action
|
||||
*
|
||||
* This will be called if the page itself does not have a handler for a
|
||||
* specific action. The method also loads and uses default handlers for
|
||||
* common actions, if specific ones were not added.
|
||||
*
|
||||
* @param HTML_QuickForm2_Controller_Page form page
|
||||
* @param string action name
|
||||
* @throws HTML_QuickForm2_NotFoundException if handler for an action is missing
|
||||
*/
|
||||
public function handle(HTML_QuickForm2_Controller_Page $page, $actionName)
|
||||
{
|
||||
if (!isset($this->handlers[$actionName])
|
||||
&& in_array($actionName, array('next', 'back', 'submit', 'display', 'jump'))
|
||||
) {
|
||||
$className = 'HTML_QuickForm2_Controller_Action_' . ucfirst($actionName);
|
||||
if (!class_exists($className)) {
|
||||
HTML_QuickForm2_Loader::loadClass($className);
|
||||
}
|
||||
$this->addHandler($actionName, new $className());
|
||||
}
|
||||
if (isset($this->handlers[$actionName])) {
|
||||
return $this->handlers[$actionName]->perform($page, $actionName);
|
||||
} else {
|
||||
throw new HTML_QuickForm2_NotFoundException(
|
||||
"Unhandled action '{$actionName}' for page '{$page->getForm()->getId()}'"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new page to the form
|
||||
*
|
||||
* @param HTML_QuickForm2_Controller_Page
|
||||
*/
|
||||
public function addPage(HTML_QuickForm2_Controller_Page $page)
|
||||
{
|
||||
$pageId = $page->getForm()->getId();
|
||||
if (!empty($this->pages[$pageId])) {
|
||||
throw new HTML_QuickForm2_InvalidArgumentException(
|
||||
"Duplicate page ID '{$pageId}'"
|
||||
);
|
||||
}
|
||||
$page->setController($this);
|
||||
$this->pages[$pageId] = $page;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a page
|
||||
*
|
||||
* @param string Page ID
|
||||
* @return HTML_QuickForm2_Controller_Page
|
||||
* @throws HTML_QuickForm2_NotFoundException if there is no page with
|
||||
* the given ID
|
||||
*/
|
||||
public function getPage($pageId)
|
||||
{
|
||||
if (!empty($this->pages[$pageId])) {
|
||||
return $this->pages[$pageId];
|
||||
} else {
|
||||
throw new HTML_QuickForm2_NotFoundException(
|
||||
"Unknown page '{$pageId}'"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the page preceding the given one
|
||||
*
|
||||
* @param HTML_QuickForm2_Controller_Page
|
||||
* @return HTML_QuickForm2_Controller_Page|null
|
||||
*/
|
||||
public function previousPage(HTML_QuickForm2_Controller_Page $reference)
|
||||
{
|
||||
$previous = null;
|
||||
foreach ($this->pages as $page) {
|
||||
if ($page === $reference) {
|
||||
return $previous;
|
||||
}
|
||||
$previous = $page;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the page following the given one
|
||||
*
|
||||
* @param HTML_QuickForm2_Controller_Page
|
||||
* @return HTML_QuickForm2_Controller_Page|null
|
||||
*/
|
||||
public function nextPage(HTML_QuickForm2_Controller_Page $reference)
|
||||
{
|
||||
$previous = null;
|
||||
foreach ($this->pages as $page) {
|
||||
if ($previous === $reference) {
|
||||
return $page;
|
||||
}
|
||||
$previous = $page;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the pages of the controller are valid
|
||||
*
|
||||
* @param HTML_QuickForm2_Controller_Page If given, check only the pages
|
||||
* before (not including) that page
|
||||
* @return bool
|
||||
*/
|
||||
public function isValid(HTML_QuickForm2_Controller_Page $reference = null)
|
||||
{
|
||||
$container = $this->getSessionContainer();
|
||||
foreach ($this->pages as $id => $page) {
|
||||
if ($reference === $page) {
|
||||
return true;
|
||||
}
|
||||
if (!$container->getValidationStatus($id)) {
|
||||
// We should handle the possible situation when the user has never
|
||||
// seen a page of a non-modal multipage form
|
||||
if (!$this->isWizard()
|
||||
&& null === $container->getValidationStatus($id)
|
||||
) {
|
||||
// Empty Session datasource makes the form look submitted
|
||||
$page->getForm()->setDatasources(array_merge(
|
||||
$container->getDatasources(),
|
||||
array(new HTML_QuickForm2_DataSource_Session(array()))
|
||||
));
|
||||
// This will store the "submitted" values in session and
|
||||
// return validation status
|
||||
if ($page->storeValues()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first page that failed validation
|
||||
*
|
||||
* @return HTML_QuickForm2_Controller_Page|null
|
||||
*/
|
||||
public function getFirstInvalidPage()
|
||||
{
|
||||
foreach ($this->pages as $id => $page) {
|
||||
if (!$this->getSessionContainer()->getValidationStatus($id)) {
|
||||
return $page;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new data source to the Controller
|
||||
*
|
||||
* Note that Controller data sources are stored in session, so your data source
|
||||
* implementation should properly handle its (un)serialization.
|
||||
*
|
||||
* @param HTML_QuickForm2_DataSource Data source
|
||||
*/
|
||||
public function addDataSource(HTML_QuickForm2_DataSource $datasource)
|
||||
{
|
||||
$this->getSessionContainer()->storeDatasources(
|
||||
array_merge($this->getSessionContainer()->getDatasources(),
|
||||
array($datasource))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the form's values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getValue()
|
||||
{
|
||||
$values = array();
|
||||
foreach (array_keys($this->pages) as $id) {
|
||||
$pageValues = $this->getSessionContainer()->getValues($id);
|
||||
// skip elements representing actions
|
||||
foreach ($pageValues as $key => $value) {
|
||||
if (0 !== strpos($key, '_qf')) {
|
||||
if (isset($values[$key]) && is_array($value)) {
|
||||
$values[$key] = self::arrayMerge($values[$key], $value);
|
||||
} else {
|
||||
$values[$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges two arrays
|
||||
*
|
||||
* Merges two arrays like the PHP function array_merge_recursive does,
|
||||
* the difference being that existing integer keys will not be renumbered.
|
||||
*
|
||||
* @param array
|
||||
* @param array
|
||||
* @return array resulting array
|
||||
*/
|
||||
protected static function arrayMerge($a, $b)
|
||||
{
|
||||
foreach ($b as $k => $v) {
|
||||
if (!is_array($v) || isset($a[$k]) && !is_array($a[$k])) {
|
||||
$a[$k] = $v;
|
||||
} else {
|
||||
$a[$k] = self::arrayMerge(isset($a[$k])? $a[$k]: array(), $v);
|
||||
}
|
||||
}
|
||||
return $a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an Iterator for the form's pages
|
||||
*
|
||||
* @return ArrayIterator
|
||||
*/
|
||||
public function getIterator()
|
||||
{
|
||||
return new ArrayIterator($this->pages);
|
||||
}
|
||||
}
|
||||
?>
|
Reference in New Issue
Block a user