* Copyright 2001-2010 Strangecode, LLC * * This file is part of The Strangecode Codebase. * * The Strangecode Codebase is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your option) * any later version. * * The Strangecode Codebase is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * The Strangecode Codebase. If not, see . */ /** * PageSequence.inc.php * * The PageSequence class provides an interface to simplify the creation of a multi-step form. * * @requires This class requires Prefs.inc.php * @author Quinn Comendant * @version 1.01 */ require_once dirname(__FILE__) . '/Prefs.inc.php'; class PageSequence { var $current_step_id = 0; var $start_url; var $sequence_title = ''; var $seq = '_sequence_'; var $idle_timeout; /** * Constructor. Sets the title of this sequence and initializes session variables. * * @param array $params An associative array of PageSequence parameters. * @access public */ function PageSequence($params) { if (isset($params['sequence_title'])) { $this->sequence_title = $params['sequence_title']; $this->seq .= $params['sequence_title']; } // How long before resetting session? 60 minutes. $this->idle_timeout = isset($params['idle_timeout']) ? $params['idle_timeout'] : 3600; // Where is user to be redirected after startOver function call? $this->start_url = isset($params['start_url']) ? $params['start_url'] : $_SERVER['PHP_SELF']; // Initialize vars if not set. if (!isset($_SESSION[$this->seq]['steps'])) { $_SESSION[$this->seq]['steps'] = array(); } if (!isset($_SESSION[$this->seq]['data'])) { $_SESSION[$this->seq]['data'] = array(); } if (!isset($_SESSION[$this->seq]['defaults'])) { $_SESSION[$this->seq]['defaults'] = array(); } // Manage timeout. $this->_auto_timeout(); } /** * Create a new step at the end (or specified position) of the $steps array. * * @param string $step_id Uniqie identifyer for this step. * @param array $params Values for the creation of the step. * * @return boolean Success of the addition * @access public */ function addStep($step_id, $params) { // Keys for the steps array cannot be numeric. if (is_numeric($step_id)) { trigger_error('Step ID for function addStep cannot be numeric.', E_USER_WARNING); } // This step ID already exists. if (!is_null($this->getPosition($step_id))) { return false; } $_SESSION[$this->seq]['steps'][] = array( 'id' => $step_id, 'title' => isset($params['title']) ? $params['title'] : '', 'active' => isset($params['active']) ? $params['active'] : false, 'form_tpl' => isset($params['form_tpl']) ? $params['form_tpl'] : '', 'disp_tpl' => isset($params['disp_tpl']) ? $params['disp_tpl'] : '', 'required' => isset($params['required']) ? $params['required'] : false, 'completed' => isset($params['completed']) ? $params['completed'] : false, 'editable' => isset($params['editable']) ? $params['editable'] : true, ); } /** * Set the features of a step. Current step if step_id not specified. * * @param string $page_id ID of page. Leave null if modifying current step features. * @param array $feature Array of feature keys and values to set. * * @return bool true on success, false on failure */ function setFeature($step_id=null, $features) { $pos = isset($step_id) ? $this->getPosition($step_id) : $this->getPosition(); if (isset($features) && is_array($features) && isset($_SESSION[$this->seq]['steps'][$pos])) { $_SESSION[$this->seq]['steps'][$pos] = array_merge($_SESSION[$this->seq]['steps'][$pos], $features); } } /** * Returns a specified value from a registered step. * * @access public * * @param string $step_id Id of step with feature to return. * @param string $key Which value to return. * @param mixed $default Value to return if key not found in user_data. * * @return mixed Value stored in session. */ function getFeature($step_id, $key, $default='') { $pos = isset($step_id) ? $this->getPosition($step_id) : $this->getPosition(); if (isset($_SESSION[$this->seq]['steps'][$pos][$key])) { return $_SESSION[$this->seq]['steps'][$pos][$key]; } else { return $default; } } /** * Set the current step id. Which step are we on? * * @param string $step_id ID or number of current step. * @return string Actual step ID * @access public */ function setCurrent($step_id) { $app =& App::getInstance(); if (false !== ($pos = $this->getPosition($step_id))) { // Specified step exists (even if numeric). $this->current_step_id = $this->getID($pos); } else { // Step with specified key does not exist. $app->logMsg(sprintf('Step %s not defined in sequence %s', $step_id, $this->sequence_title), LOG_INFO, __FILE__, __LINE__); return false; } } /** * Get the current step id. * * @return int $pos Actual step position * @access public */ function getID($pos=null) { if (isset($pos)) { return $_SESSION[$this->seq]['steps'][$pos]['id']; } else { return $this->current_step_id; } } /** * Get the current step number. * * @param string $step_id ID or number of step to convert to position. * * @return string Actual step number * @access public */ function getPosition($step_id=null) { // Get current step id if step not provided. if (!isset($step_id)) { $step_id = $this->current_step_id; } if (is_numeric($step_id) && isset($_SESSION[$this->seq]['steps'][$step_id])) { // Step ID provided is a number...go directly to key. return $step_id; } else { // Step ID is a string. Loop through searching for match. foreach ($_SESSION[$this->seq]['steps'] as $pos=>$step) { if ($step['id'] == $step_id) { return $pos; } } // Step not found matching ID. return null; } } /** * Returns the ID of the step with required=true and completed=false * and active=true that falls before specified step_id. * * @param string $curr_step_id ID or number of current step. * @return string Prerequisite step ID or false if none. * @access public */ function getRequiredID($curr_step_id) { if ('' === $curr_step_id) { return $this->current_step_id; } foreach ($_SESSION[$this->seq]['steps'] as $pos=>$step) { if (is_numeric($curr_step_id) && $pos == $curr_step_id && $step['active']) { return $curr_step_id; } else if ($step['id'] == $curr_step_id && $step['active']) { return $curr_step_id; } if ($step['active'] && $step['required'] && !$step['completed']) { return $step['id']; } } return $curr_step_id; } /** * Returns the next step in the steps array or the first active required * uncompleted step. * * @return string Step identifier of the next step. * @access public */ function getNextID() { // Loop through all steps. foreach ($_SESSION[$this->seq]['steps'] as $pos=>$step) { // If a step is found that is active, required, and not completed, we must do that one. if ($step['active'] && $step['required'] && !$step['completed']) { return $step['id']; } // Otherwise do the first step after the current one that is active. if ($step['active'] && $pos > $this->getPosition()) { return $step['id']; } } return null; } /** * To set a set as 'completed'. * @return string Step identifier of the next step. * @access public */ function complete($step_id=null) { $pos = isset($step_id) ? $this->getPosition($step_id) : $this->getPosition(); $_SESSION[$this->seq]['steps'][$pos]['completed'] = true; } /** * Prints the a link that returns to the form for a step. * * @param string $form_type 'form' or 'disp'. * @param string $step_id ID of step. * @return string Filename of template. * @access public */ function printEditLink($step_id=null) { $app =& App::getInstance(); $pos = isset($step_id) ? $this->getPosition($step_id) : $this->getPosition(); if ($_SESSION[$this->seq]['steps'][$pos]['editable']) { printf('[%s]', $app->oHREF($_SERVER['PHP_SELF'] . '?step=' . $pos . '&boomerang=confirmation'), _("edit")); } } /** * Saves given $step_data (usually coming from $_POST) into $_SESSION * array with the $step_id as the key. * * @param string $step_id ID of current step. * @param mixed $step_data Data to place into session storage. * @return string Step identifier of the next step. * @access public */ function setDataDefault($data_key, $data_val) { if (!isset($_SESSION[$this->seq]['data'][$data_key])) { $_SESSION[$this->seq]['data'][$data_key] = $data_val; $_SESSION[$this->seq]['defaults'][$data_key] = $data_val; } } /** * Returns the value saved in $_SESSION for a specific data key. * * @param mixed $data_key Key of data to return from session data. * @access public */ function getData($data_key=null) { if (!isset($data_key)) { return $_SESSION[$this->seq]['data']; } if (isset($_SESSION[$this->seq]['data'][$data_key])) { return $_SESSION[$this->seq]['data'][$data_key]; } else { return null; } } /** * Deletes all data saved in $_SESSION. * * @param mixed $data_key Key of data to return from session data. * @access public */ function clearData($data_key=null) { if (isset($data_key)) { // Clear a specific key. $_SESSION[$this->seq]['data'][$key] = array(); } else { // Clear the whole thing. $_SESSION[$this->seq]['data'] = array(); } } /** * Deletes all data that are older than auto_timeout. Set current time if not not expired or not set. */ function _auto_timeout() { $app =& App::getInstance(); if (isset($_SESSION[$this->seq]['last_access_time']) && $_SESSION[$this->seq]['last_access_time'] < time() - $this->idle_timeout) { // Session has expired, flush all vars to start over. $this->startOver(); $app->dieURL($this->start_url); } else { // Set timer. $_SESSION[$this->seq]['last_access_time'] = time(); } } /** * Saves given array (usually coming from $_POST) into $_SESSION * * @param mixed $step_data Array of data to merge with session data. * @access public */ function registerData($step_data) { $_SESSION[$this->seq]['data'] = array_merge($_SESSION[$this->seq]['data'], $step_data); } /** * Reset all vars. * */ function startOver() { $this->current_step_id = 0; $_SESSION[$this->seq]['steps'] = array(); $_SESSION[$this->seq]['data'] = array(); $_SESSION[$this->seq]['defaults'] = array(); $_SESSION[$this->seq]['last_access_time'] = time(); } } // END CLASS ?>