drupal-civicrm/sites/all/modules/civicrm/packages/HTML/QuickForm/Controller.php

543 lines
17 KiB
PHP
Raw Permalink Normal View History

2018-01-14 15:10:16 +02:00
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* The class representing a Controller of MVC design pattern.
*
* PHP versions 4 and 5
*
* LICENSE: This source file is subject to version 3.01 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_01.txt If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
*
* @category HTML
* @package HTML_QuickForm_Controller
* @author Alexey Borzov <avb@php.net>
* @author Bertrand Mansion <bmansion@mamasam.com>
* @copyright 2003-2007 The PHP Group
* @license http://www.php.net/license/3_01.txt PHP License 3.01
* @version CVS: $Id: Controller.php,v 1.13 2007/05/18 09:34:18 avb Exp $
* @link http://pear.php.net/package/HTML_QuickForm_Controller
*/
/**
* The class representing a page of a multipage form.
*/
require_once 'HTML/QuickForm/Page.php';
/**
* The class representing a Controller of MVC design pattern.
*
* This class keeps track of pages and (default) action handlers for the form,
* it manages keeping the form values in session, setting defaults and
* constants for the form as a whole and getting its submit values.
*
* Generally you don't need to subclass this.
*
* @category HTML
* @package HTML_QuickForm_Controller
* @author Alexey Borzov <avb@php.net>
* @author Bertrand Mansion <bmansion@mamasam.com>
* @version Release: 1.0.9
*/
class HTML_QuickForm_Controller
{
/**
* Contains the pages (HTML_QuickForm_Page objects) of the miultipage form
* @var array
*/
var $_pages = array();
/**
* Contains the mapping of actions to corresponding HTML_QuickForm_Action objects
* @var array
*/
var $_actions = array();
/**
* Name of the form, used to store the values in session
* @var string
*/
var $_name;
/**
* Whether the form is modal
* @var bool
*/
var $_modal = true;
/**
* The action extracted from HTTP request: array('page', 'action')
* @var array
*/
var $_actionName = null;
/**
* Class constructor.
*
* Sets the form name and modal/non-modal behaviuor. Different multipage
* forms should have different names, as they are used to store form
* values in session. Modal forms allow passing to the next page only when
* all of the previous pages are valid.
*
* @access public
* @param string form name
* @param bool whether the form is modal
*/
function __construct($name, $modal = true)
{
$this->_name = $name;
$this->_modal = $modal;
}
/**
* Returns a reference to a session variable containing the form-page
* values and pages' validation status.
*
* This is a "low-level" method, use exportValues() if you want just to
* get the form's values.
*
* @access public
* @param bool If true, then reset the container: clear all default, constant and submitted values
* @return array
*/
function &container($reset = false)
{
$name = '_' . $this->_name . '_container';
if (!isset($_SESSION[$name]) || $reset) {
$_SESSION[$name] = array(
'defaults' => array(),
'constants' => array(),
'values' => array(),
'valid' => array()
);
}
foreach (array_keys($this->_pages) as $pageName) {
if (!isset($_SESSION[$name]['values'][$pageName])) {
$_SESSION[$name]['values'][$pageName] = array();
$_SESSION[$name]['valid'][$pageName] = null;
}
}
return $_SESSION[$name];
}
/**
* Processes the request.
*
* This finds the current page, the current action and passes the action
* to the page's handle() method.
*
* @access public
* @throws PEAR_Error
*/
function run()
{
// the names of the action and page should be saved
list($page, $action) = $this->_actionName = $this->getActionName();
return $this->_pages[$page]->handle($action);
}
/**
* Registers a handler for a specific action.
*
* @access public
* @param string name of the action
* @param HTML_QuickForm_Action the handler for the action
*/
function addAction($actionName, $action)
{
$this->_actions[$actionName] = $action;
}
/**
* Adds a new page to the form
*
* @access public
* @param HTML_QuickForm_Page
*/
function addPage(&$page)
{
$page->controller =& $this;
$this->_pages[$page->getAttribute('id')] =& $page;
}
/**
* Returns a page
*
* @access public
* @param string Name of a page
* @return HTML_QuickForm_Page A reference to the page
* @throws PEAR_Error
*/
function &getPage($pageName)
{
if (!isset($this->_pages[$pageName])) {
return PEAR::raiseError('HTML_QuickForm_Controller: Unknown page "' . $pageName . '"');
}
return $this->_pages[$pageName];
}
/**
* Handles an action.
*
* This will be called if the page itself does not have a handler
* to a specific action. The method also loads and uses default handlers
* for common actions, if specific ones were not added.
*
* @access public
* @param HTML_QuickForm_Page The page that failed to handle the action
* @param string Name of the action
* @throws PEAR_Error
*/
function handle(&$page, $actionName)
{
if (isset($this->_actions[$actionName])) {
return $this->_actions[$actionName]->perform($page, $actionName);
}
switch ($actionName) {
case 'next':
case 'back':
case 'submit':
case 'display':
case 'jump':
include_once 'HTML/QuickForm/Action/' . ucfirst($actionName) . '.php';
$className = 'HTML_QuickForm_Action_' . $actionName;
$this->_actions[$actionName] = new $className();
return $this->_actions[$actionName]->perform($page, $actionName);
break;
default:
return PEAR::raiseError('HTML_QuickForm_Controller: Unhandled action "' . $actionName . '" in page "' . $page->getAttribute('id') . '"');
} // switch
}
/**
* Checks whether the form is modal.
*
* @access public
* @return bool
*/
function isModal()
{
return $this->_modal;
}
/**
* Checks whether the pages of the controller are valid
*
* @access public
* @param string If set, check only the pages before (not including) that page
* @return bool
* @throws PEAR_Error
*/
function isValid($pageName = null)
{
$data =& $this->container();
foreach (array_keys($this->_pages) as $key) {
if (isset($pageName) && $pageName == $key) {
return true;
} elseif (!$data['valid'][$key]) {
// We should handle the possible situation when the user has never
// seen a page of a non-modal multipage form
if (!$this->isModal() && null === $data['valid'][$key]) {
$page =& $this->_pages[$key];
// Fix for bug #8687: the unseen page was considered
// submitted, so defaults for checkboxes and multiselects
// were not used. Shouldn't break anything since this flag
// will be reset right below in loadValues().
$page->_flagSubmitted = false;
// Use controller's defaults and constants, if present
$this->applyDefaults($key);
$page->isFormBuilt() or $page->BuildForm();
// We use defaults and constants as if they were submitted
$data['values'][$key] = $page->exportValues();
$page->loadValues($data['values'][$key]);
// Is the page now valid?
if (PEAR::isError($valid = $page->validate())) {
return $valid;
}
$data['valid'][$key] = $valid;
if (true === $valid) {
continue;
}
}
return false;
}
}
return true;
}
/**
* Returns the name of the page before the given.
*
* @access public
* @param string
* @return string
*/
function getPrevName($pageName)
{
$prev = null;
foreach (array_keys($this->_pages) as $key) {
if ($key == $pageName) {
return $prev;
}
$prev = $key;
}
}
/**
* Returns the name of the page after the given.
*
* @access public
* @param string
* @return string
*/
function getNextName($pageName)
{
$prev = null;
foreach (array_keys($this->_pages) as $key) {
if ($prev == $pageName) {
return $key;
}
$prev = $key;
}
return null;
}
/**
* Finds the (first) invalid page
*
* @access public
* @return string Name of an invalid page
*/
function findInvalid()
{
$data =& $this->container();
foreach (array_keys($this->_pages) as $key) {
if (!$data['valid'][$key]) {
return $key;
}
}
return null;
}
/**
* Extracts the names of the current page and the current action from
* HTTP request data.
*
* @access public
* @return array first element is page name, second is action name
*/
function getActionName()
{
if (is_array($this->_actionName)) {
return $this->_actionName;
}
$names = array_map('preg_quote', array_keys($this->_pages));
$regex = '/^_qf_(' . implode('|', $names) . ')_(.+?)(_.+?)?(_x)?$/';
$data =& $this->container();
unset( $data['_qf_button_name'] );
foreach (array_keys($_REQUEST) as $key) {
if (preg_match($regex, $key, $matches)) {
$data['_qf_button_name'] = $key;
if ( array_key_exists( 3, $matches ) ) {
$key = preg_replace( '/_(x|y)$/', '', $key );
}
return array($matches[1], $matches[2]);
}
}
if (isset($_REQUEST['_qf_default'])) {
$matches = explode(':', $_REQUEST['_qf_default'], 2);
if (isset($this->_pages[$matches[0]])) {
return $matches;
}
}
reset($this->_pages);
return array(key($this->_pages), 'display');
}
/**
* Initializes default form values.
*
* @access public
* @param array default values
* @param mixed filter(s) to apply to default values
* @throws PEAR_Error
*/
function setDefaults($defaultValues = null, $filter = null)
{
if (is_array($defaultValues)) {
$data =& $this->container();
return $this->_setDefaultsOrConstants($data['defaults'], $defaultValues, $filter);
}
}
/**
* Initializes constant form values.
* These values won't get overridden by POST or GET vars
*
* @access public
* @param array constant values
* @param mixed filter(s) to apply to constant values
* @throws PEAR_Error
*/
function setConstants($constantValues = null, $filter = null)
{
if (is_array($constantValues)) {
$data =& $this->container();
return $this->_setDefaultsOrConstants($data['constants'], $constantValues, $filter);
}
}
/**
* Adds new values to defaults or constants array
*
* @access private
* @param array array to add values to (either defaults or constants)
* @param array values to add
* @param mixed filters to apply to new values
* @throws PEAR_Error
*/
function _setDefaultsOrConstants(&$values, $newValues, $filter = null)
{
if (isset($filter)) {
if (is_array($filter) && (2 != count($filter) || !is_callable($filter))) {
foreach ($filter as $val) {
if (!is_callable($val)) {
return PEAR::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm_Controller::_setDefaultsOrConstants()", 'HTML_QuickForm_Error', true);
} else {
$newValues = $this->_arrayMapRecursive($val, $newValues);
}
}
} elseif (!is_callable($filter)) {
return PEAR::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm_Controller::_setDefaultsOrConstants()", 'HTML_QuickForm_Error', true);
} else {
$newValues = $this->_arrayMapRecursive($val, $newValues);
}
}
$values = HTML_QuickForm::arrayMerge($values, $newValues);
}
/**
* Recursively applies the callback function to the value
*
* @param mixed Callback function
* @param mixed Value to process
* @access private
* @return mixed Processed values
*/
function _arrayMapRecursive($callback, $value)
{
if (!is_array($value)) {
return call_user_func($callback, $value);
} else {
$map = array();
foreach ($value as $k => $v) {
$map[$k] = $this->_arrayMapRecursive($callback, $v);
}
return $map;
}
}
/**
* Sets the default values for the given page
*
* @access public
* @param string Name of a page
*/
function applyDefaults($pageName)
{
$data =& $this->container();
if (!empty($data['defaults'])) {
$this->_pages[$pageName]->setDefaults($data['defaults']);
}
if (!empty($data['constants'])) {
$this->_pages[$pageName]->setConstants($data['constants']);
}
}
/**
* Returns the form's values
*
* @access public
* @param string name of the page, if not set then returns values for all pages
* @return array
*/
function exportValues($pageName = null)
{
$data =& $this->container();
$values = array();
if (isset($pageName)) {
$pages = array($pageName);
} else {
$pages = array_keys($data['values']);
}
foreach ($pages as $page) {
// skip elements representing actions
foreach ($data['values'][$page] as $key => $value) {
if (0 !== strpos($key, '_qf_')) {
if (isset($values[$key]) && is_array($value)) {
$values[$key] = HTML_QuickForm::arrayMerge($values[$key], $value);
} else {
$values[$key] = $value;
}
}
}
}
return $values;
}
/**
* Returns the element's value
*
* @access public
* @param string name of the page
* @param string name of the element in the page
* @return mixed value for the element
*/
function exportValue($pageName, $elementName)
{
$data =& $this->container();
return isset($data['values'][$pageName][$elementName])? $data['values'][$pageName][$elementName]: null;
}
/**
* resets a specifc page in the container
*
* @access public
* @param string name of the page
* @return void
*/
function resetPage($pageName, $valid = null)
{
$data =& $this->container();
if (isset($data['values'][$pageName]) ||
isset($data['valid'][$pageName])) {
$data['values'][$pageName] = array( );
$data['valid'][$pageName] = $valid;
}
}
}
?>