diff --git a/include/class.config.php b/include/class.config.php index c9125aaa3a4be615079695d4d3668c43e35c911b..73890ea402ba9041e45970ed9aeda5a96bf5fc6a 100644 --- a/include/class.config.php +++ b/include/class.config.php @@ -36,9 +36,8 @@ class Config { if ($this->section === null) return false; - if (!isset($_SESSION['cfg:'.$this->section])) - $_SESSION['cfg:'.$this->section] = array(); - $this->session = &$_SESSION['cfg:'.$this->section]; + if (isset($_SESSION['cfg:'.$this->section])) + $this->session = &$_SESSION['cfg:'.$this->section]; $this->load(); } @@ -64,7 +63,7 @@ class Config { } function get($key, $default=null) { - if (isset($this->session[$key])) + if (isset($this->session) && isset($this->session[$key])) return $this->session[$key]; elseif (isset($this->config[$key])) return $this->config[$key]['value']; @@ -83,6 +82,10 @@ class Config { } function persist($key, $value) { + if (!isset($this->session)) { + $this->session = &$_SESSION['cfg:'.$this->section]; + $this->session = array(); + } $this->session[$key] = $value; return true; } diff --git a/include/class.message.php b/include/class.message.php new file mode 100644 index 0000000000000000000000000000000000000000..e78de545fd7be7ccbf72cb81502c409a375d7495 --- /dev/null +++ b/include/class.message.php @@ -0,0 +1,248 @@ +<?php +/********************************************************************* + class.message.php + + Simple messages interface used to stash messages for display in a future + request. Mainly useful for the post-redirect-get pattern. + + Usage: + + <?php Messages::success('It worked!!'); ?> + + // In a later request + <?php + foreach (Messages::getMessages() as $msg) { + include 'path/to/message-template.tmp.php'; + } + ?> + + Jared Hancock <jared@osticket.com> + Peter Rotich <peter@osticket.com> + Copyright (c) 2006-2015 osTicket + http://www.osticket.com + + Released under the GNU General Public License WITHOUT ANY WARRANTY. + See LICENSE.TXT for details. + + vim: expandtab sw=4 ts=4 sts=4: +**********************************************************************/ + +interface Message { + function getTags(); + function getLevel(); + function __toString(); +} + +class Messages { + const ERROR = 50; + const WARNING = 40; + const WARN = self::WARNING; + const SUCCESS = 30; + const INFO = 20; + const DEBUG = 10; + const NOTSET = 0; + + static $_levelNames = array( + self::ERROR => 'ERROR', + self::WARNING => 'WARNING', + self::SUCCESS => 'SUCCESS', + self::INFO => 'INFO', + self::DEBUG => 'DEBUG', + self::NOTSET => 'NOTSET', + 'ERROR' => self::ERROR, + 'WARN' => self::WARNING, + 'WARNING' => self::WARNING, + 'SUCCESS' => self::SUCCESS, + 'INFO' => self::INFO, + 'DEBUG' => self::DEBUG, + 'NOTSET' => self::NOTSET, + ); + + static $messageClass = 'SimpleMessage'; + static $backend = 'SessionMessageStorage'; + + static function debug($message) { + static::addMessage(self::DEBUG, $message); + } + static function info($message) { + static::addMessage(self::INFO, $message); + } + static function success($message) { + static::addMessage(self::SUCCESS, $message); + } + static function warning($message) { + static::addMessage(self::WARNING, $message); + } + static function error($message) { + static::addMessage(self::ERROR, $message); + } + + static function addMessage($level, $message) { + $msg = new static::$messageClass($level, $message); + $bk = static::getMessages(); + $bk->add($level, $msg); + } + + static function getMessages() { + static $messages; + if (!isset($messages)) + $messages = new static::$backend(); + return $messages; + } + + static function setMessageClass($class) { + if (!is_subclass_of($class, 'Message')) + throw new InvalidArgumentException('Class must extend Message'); + self::$messageClass = $class; + } + + static function checkLevel($level) { + if (is_int($level)) { + $rv = $level; + } + elseif ((string) $level == $level) { + if (!isset(static::$_levelNames[$level])) + throw new InvalidArgumentException( + sprintf('Unknown level: %s', $level)); + $rv = static::$_levelNames[$level]; + } + else { + throw new InvalidArgumentException( + sprintf('Level not an integer or a valid string: %s', + $level)); + } + return $rv; + } + + static function getLevelName($level) { + return @self::$_levelNames[$level]; + } +} + +class SimpleMessage implements Message { + var $tags; + var $level; + var $msg; + + function __construct($level, $message, $extra_tags=array()) { + $this->level = $level; + $this->msg = $message; + $this->tags = $extra_tags ?: null; + } + + function getTags() { + $tags = array_merge( + array(Messages::getLevelTag($this->level)), + $this->tags ?: array()); + return implode(' ', $tags); + } + + function getLevel() { + return Messages::getLevelName($this->level); + } + + function __toString() { + return $this->msg; + } +} + +interface MessageStorageBackend extends \IteratorAggregate { + function setLevel($level); + function getLevel(); + + function update(); + function add($level, $message); +} + +abstract class BaseMessageStorage implements MessageStorageBackend { + var $level = Messages::NOTSET; + var $queued = array(); + var $used = false; + var $added_new = false; + + function isEnabledFor($level) { + Messages::checkLevel($level); + return $level >= $this->getLevel(); + } + + function setLevel($level) { + Messages::checkLevel($level); + $this->level = $level; + } + + function getLevel() { + return $this->level; + } + + function load() { + static $messages = false; + + if (!$messages) { + $messages = new ListObject($this->get()); + } + return $messages; + } + + function getIterator() { + $this->used = true; + $messages = $this->load(); + if ($this->queued) { + $messages->extend($this->queued); + $this->queued = array(); + } + if ($messages instanceof ListObject) + return $messages->getIterator(); + else + return new \ArrayIterator($messages); + } + + function update() { + if ($this->used) { + return $this->store($this->queued); + } + else { + $messages = $this->load(); + $messages->extend($this->queued); + return $this->store($messages); + } + } + + function add($level, $message) { + if (!$message) + return; + elseif (!$this->isEnabledFor($level)) + return; + + $this->added_new = true; + $this->queued[] = $message; + } + + abstract function get(); + abstract function store($messages); +} + +class SessionMessageStorage extends BaseMessageStorage { + var $list; + + function __construct() { + $this->list = @$_SESSION[':msgs'] ?: array(); + // Since no middleware exists in this framework, register a + // pre-shutdown hook + $self = $this; + Signal::connect('session.close', function($null, $info) use ($self) { + // Whether or not the session data should be re-encoded to + // reflect changes made in this routine + $info['touched'] = $this->added_new || ($this->used && count($this->list)); + $self->update(); + }); + } + + function get() { + return $this->list; + } + + function store($messages) { + $_SESSION[':msgs'] = $messages; + return array(); + } +} diff --git a/include/class.orm.php b/include/class.orm.php index adbf4829500ccbe6349dd537f83e7d3051586527..124b56be74afd5ae09325650e3845a58aca2fc4f 100644 --- a/include/class.orm.php +++ b/include/class.orm.php @@ -920,7 +920,6 @@ class QuerySet implements IteratorAggregate, ArrayAccess, Serializable, Countabl var $compiler = 'MySqlCompiler'; var $iterator = 'ModelInstanceManager'; - var $params; var $query; var $count; @@ -1076,8 +1075,8 @@ class QuerySet implements IteratorAggregate, ArrayAccess, Serializable, Countabl if (isset($this->_iterator)) { return $this->_iterator->count(); } - elseif (isset($this->_count)) { - return $this->_count; + elseif (isset($this->count)) { + return $this->count; } $class = $this->compiler; $compiler = new $class(); @@ -1167,6 +1166,7 @@ class QuerySet implements IteratorAggregate, ArrayAccess, Serializable, Countabl function __clone() { unset($this->_iterator); unset($this->query); + unset($this->count); } // IteratorAggregate interface @@ -1250,6 +1250,7 @@ EOF; unset($info['limit']); unset($info['offset']); unset($info['_iterator']); + unset($info['count']); return serialize($info); } @@ -2764,7 +2765,6 @@ class Q implements Serializable { const ANY = 0x0002; var $constraints; - var $flags; var $negated = false; var $ored = false; @@ -2816,19 +2816,11 @@ class Q implements Serializable { } function serialize() { - return serialize(array( - 'f' => - ($this->negated ? self::NEGATED : 0) - | ($this->ored ? self::ANY : 0), - 'c' => $this->constraints - )); + return serialize(array($this->negated, $this->ored, $this->constraints)); } function unserialize($data) { - $data = unserialize($data); - $this->constraints = $data['c']; - $this->ored = $data['f'] & self::ANY; - $this->negated = $data['f'] & self::NEGATED; + list($this->negated, $this->ored, $this->constraints) = unserialize($data); } } ?> diff --git a/include/class.osticket.php b/include/class.osticket.php index 35903aac99eb482190acd493261c5e52d2169d1b..23e363739dc895882f1ef2f98ced8f6db1f32838 100644 --- a/include/class.osticket.php +++ b/include/class.osticket.php @@ -21,6 +21,7 @@ require_once(INCLUDE_DIR.'class.csrf.php'); //CSRF token class. require_once(INCLUDE_DIR.'class.migrater.php'); require_once(INCLUDE_DIR.'class.plugin.php'); +require_once INCLUDE_DIR . 'class.message.php'; define('LOG_WARN',LOG_WARNING); diff --git a/include/class.ostsession.php b/include/class.ostsession.php index f649955494a8ba85460fcf2ff463bbc46ce3a9e6..e08ab604f061ffed25e157e8081c25c21f5878a8 100644 --- a/include/class.ostsession.php +++ b/include/class.ostsession.php @@ -151,8 +151,15 @@ abstract class SessionBackend { return $this->ttl; } + function write($id, $data) { + // Last chance session update + $i = new ArrayObject(array('touched' => false)); + Signal::send('session.close', null, $i); + return $this->update($id, $i['touched'] ? session_encode() : $data); + } + abstract function read($id); - abstract function write($id, $data); + abstract function update($id, $data); abstract function destroy($id); abstract function gc($maxlife); } @@ -179,7 +186,7 @@ extends SessionBackend { return $this->data; } - function write($id, $data){ + function update($id, $data){ global $thisstaff; if (md5($id.$data) == $this->data_hash) @@ -272,7 +279,7 @@ extends SessionBackend { return $data; } - function write($id, $data) { + function update($id, $data) { if (defined('DISABLE_SESSION') && $this->isnew) return; diff --git a/include/class.util.php b/include/class.util.php index 8fb9b3967a4ec5cb4e6d2117c58ece03baa1b0fd..8cdec42ed4c3c60b5163efe6ad345cf27f0a5315 100644 --- a/include/class.util.php +++ b/include/class.util.php @@ -15,7 +15,9 @@ class ListObject implements IteratorAggregate, ArrayAccess, Serializable, Counta protected $storage = array(); - function __construct(array $array=array()) { + function __construct($array=array()) { + if (!is_array($array) && !$array instanceof Traversable) + throw new InvalidArgumentException('Traversable object or array expected'); foreach ($array as $v) $this->storage[] = $v; } diff --git a/include/staff/header.inc.php b/include/staff/header.inc.php index 0b595def74aa9406e6b6f09d2a75e4a1ea06920c..4446de392fd2fff5575b00637505efdb1ddec853 100644 --- a/include/staff/header.inc.php +++ b/include/staff/header.inc.php @@ -100,4 +100,8 @@ if ($lang) { <div id="msg_notice"><?php echo $msg; ?></div> <?php }elseif($warn) { ?> <div id="msg_warning"><?php echo $warn; ?></div> - <?php } ?> + <?php } + foreach (Messages::getMessages() as $M) { ?> + <div class="<?php echo strtolower($M->getLevel()); ?>-banner"><?php + echo (string) $M; ?></div> +<?php } ?> diff --git a/scp/css/scp.css b/scp/css/scp.css index 3b96437344f7cc3c261e1344a7e225b7900b9fd0..48fe1f5bf32f8e6019db8b75d89cbba9af536283 100644 --- a/scp/css/scp.css +++ b/scp/css/scp.css @@ -106,6 +106,7 @@ a time.relative { .info-banner { margin: 0; padding: 5px; margin-bottom: 10px; color: #3a87ad; border: 1px solid #bce8f1; background-color: #d9edf7; } #msg_notice, +.success-banner, .notice-banner { margin: 0; padding: 5px 10px 5px 36px; margin-bottom: 10px; border: 1px solid #0a0; background: url('../images/icons/ok.png') 10px 50% no-repeat #e0ffe0; } #msg_warning, diff --git a/scp/lists.php b/scp/lists.php index 03a6daaaecada3cce8a737422777f9066b17d337..35fcef37d9d97ec0fd73e7ea7f7a6a6ac1a43cac 100644 --- a/scp/lists.php +++ b/scp/lists.php @@ -97,8 +97,7 @@ if($_POST) { case 'add': if ($list=DynamicList::add($_POST, $errors)) { $form = $list->getForm(true); - $msg = sprintf(__('Successfully added %s'), - __('this custom list')); + Messages::success(sprintf(__('Successfully added %s'), __('this custom list'))); // Redirect to list page $redirect = "lists.php?id={$list->id}#items"; } elseif ($errors) {