summaryrefslogtreecommitdiff
path: root/framework/Web/UI/TSessionPageStatePersister.php
blob: 5448fd229aada7fe643ed6fba676f6a2ac73bfea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
<?php
/**
 * TSessionPageStatePersister class file
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @link http://www.pradosoft.com/
 * @copyright Copyright &copy; 2005-2013 PradoSoft
 * @license http://www.pradosoft.com/license/
 * @version $Id: TSessionPageStatePersister.php 3245 2013-01-07 20:23:32Z ctrlaltca $
 * @package System.Web.UI
 */

/**
 * TSessionPageStatePersister class
 *
 * TSessionPageStatePersister implements a page state persistent method based on
 * sessions. Page state are stored in user sessions and therefore, this persister
 * requires session to be started and available.
 *
 * TSessionPageStatePersister keeps limited number of history states in session,
 * mainly to preserve the precious server storage. The number is specified
 * by {@link setHistorySize HistorySize}, which defaults to 10.
 *
 * There are a couple of ways to use TSessionPageStatePersister.
 * One can override the page's {@link TPage::getStatePersister()} method and
 * create a TSessionPageStatePersister instance there.
 * Or one can configure the pages to use TSessionPageStatePersister in page configurations
 * as follows,
 * <code>
 *   <pages StatePersisterClass="System.Web.UI.TSessionPageStatePersister" />
 * </code>
 * The above configuration will affect the pages under the directory containing
 * this configuration and all its subdirectories.
 * To configure individual pages to use TSessionPageStatePersister, use
 * <code>
 *   <pages>
 *     <page id="PageID" StatePersisterClass="System.Web.UI.TSessionPageStatePersister" />
 *   </pages>
 * </code>
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @version $Id: TSessionPageStatePersister.php 3245 2013-01-07 20:23:32Z ctrlaltca $
 * @package System.Web.UI
 * @since 3.1
 */
class TSessionPageStatePersister extends TComponent implements IPageStatePersister
{
	const STATE_SESSION_KEY='PRADO_SESSION_PAGESTATE';
	const QUEUE_SESSION_KEY='PRADO_SESSION_STATEQUEUE';

	private $_page;
	private $_historySize=10;

	/**
	 * @param TPage the page that this persister works for
	 */
	public function getPage()
	{
		return $this->_page;
	}

	/**
	 * @param TPage the page that this persister works for.
	 */
	public function setPage(TPage $page)
	{
		$this->_page=$page;
	}

	/**
	 * @return integer maximum number of page states that should be kept in session. Defaults to 10.
	 */
	public function getHistorySize()
	{
		return $this->_historySize;
	}

	/**
	 * @param integer maximum number of page states that should be kept in session
	 * @throws TInvalidDataValueException if the number is smaller than 1.
	 */
	public function setHistorySize($value)
	{
		if(($value=TPropertyValue::ensureInteger($value))>0)
			$this->_historySize=$value;
		else
			throw new TInvalidDataValueException('sessionpagestatepersister_historysize_invalid');
	}
	/**
	 * Saves state in session.
	 * @param mixed state to be stored
	 */
	public function save($state)
	{
		$session=$this->_page->getSession();
		$session->open();
		$data=serialize($state);
		$timestamp=(string)microtime(true);
		$key=self::STATE_SESSION_KEY.$timestamp;
		$session->add($key,$data);
		if(($queue=$session->itemAt(self::QUEUE_SESSION_KEY))===null)
			$queue=array();
		$queue[]=$key;
		if(count($queue)>$this->getHistorySize())
		{
			$expiredKey=array_shift($queue);
			$session->remove($expiredKey);
		}
		$session->add(self::QUEUE_SESSION_KEY,$queue);
		$this->_page->setClientState(TPageStateFormatter::serialize($this->_page,$timestamp));
	}

	/**
	 * Loads page state from session.
	 * @return mixed the restored state
	 * @throws THttpException if page state is corrupted
	 */
	public function load()
	{
		if(($timestamp=TPageStateFormatter::unserialize($this->_page,$this->_page->getRequestClientState()))!==null)
		{
			$session=$this->_page->getSession();
			$session->open();
			$key=self::STATE_SESSION_KEY.$timestamp;
			if(($data=$session->itemAt($key))!==null)
				return unserialize($data);
		}
		throw new THttpException(400,'sessionpagestatepersister_pagestate_corrupted');
	}
}