Happy New Year
[platal.git] / classes / plwizard.php
1 <?php
2 /***************************************************************************
3 * Copyright (C) 2003-2009 Polytechnique.org *
4 * http://opensource.polytechnique.org/ *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the Free Software *
18 * Foundation, Inc., *
19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
20 **************************************************************************/
21
22 /** A Wizard Page is a page of a wizard. It is a self-contained step which
23 * handles both the creation and initialisation of the step (by using the
24 * Wizard global state, if needed) and the processing of the action the
25 * user made on it.
26 */
27 interface PlWizardPage
28 {
29 /** Build a new instance of the class
30 * associated with the given wizard master.
31 */
32 public function __construct(PlWizard &$wiz);
33
34 /** Return the name of the templace describing the page.
35 */
36 public function template();
37
38 /** Prepare the page by assigning to it any useful value.
39 */
40 public function prepare(PlPage &$page, $id);
41
42 /** Process information resulting of the application of the page.
43 * This function must return a clue indicating the next page to show.
44 * This clue can be either a page id, a page number or a navigation
45 * id (PlWizard::FIRST_PAGE, PlWizard::NEXT_PAGE, PlWizard::CURRENT_PAGE
46 * PlWizard::PREVIOUS_PAGE, PlWizard::LAST_PAGE).
47 */
48 public function process();
49 }
50
51 /** A PlWizard is a set of pages through which the user can navigate,
52 * his action on a page determining which the next one will be.
53 *
54 * A Wizard can either a stateless wizard (which is only a set of
55 * independent pages through which the user can easily navigate) or
56 * stateful (a suite of steps where each step gives clue for the next
57 * one).
58 */
59 class PlWizard
60 {
61 const FIRST_PAGE = 'bt_first';
62 const NEXT_PAGE = 'bt_next';
63 const CURRENT_PAGE = 'bt_current';
64 const PREVIOUS_PAGE = 'bt_previous';
65 const LAST_PAGE = 'bt_last';
66
67 private $userdata = array();
68
69 protected $name;
70 protected $layout;
71 protected $stateless;
72 protected $ajax;
73 protected $ajax_animated;
74
75 protected $pages;
76 protected $titles;
77 protected $lookup;
78 protected $inv_lookup;
79
80 public function __construct($name, $layout, $stateless = false, $ajax = true, $ajax_animated = true)
81 {
82 $this->name = 'wiz_' . $name;
83 $this->layout = $layout;
84 $this->stateless = $stateless;
85 $this->pages = array();
86 $this->lookup = array();
87 $this->titles = array();
88 $this->ajax = $ajax;
89 $this->ajax_animated = $ajax_animated;
90 if (!isset($_SESSION[$this->name])) {
91 $_SESSION[$this->name] = array();
92 $_SESSION[$this->name . '_page'] = null;
93 $_SESSION[$this->name . '_stack'] = array();
94 }
95 }
96
97 public function addPage($class, $title, $id = null)
98 {
99 if ($id == null) {
100 $id = count($this->pages);
101 }
102 $this->lookup[$id] = count($this->pages);
103 $this->inv_lookup[] = $id;
104 $this->pages[] = $class;
105 $this->titles[] = $title;
106 }
107
108 public function addUserData($name, $value)
109 {
110 $this->userdata[$name] = $value;
111 }
112
113 public function getUserData($name, $default = null)
114 {
115 return $this->userdata[$name];
116 }
117
118 public function set($varname, $value)
119 {
120 $_SESSION[$this->name][$varname] = $value;
121 }
122
123 public function get($varname, $default = null)
124 {
125 return isset($_SESSION[$this->name][$varname]) ?
126 $_SESSION[$this->name][$varname] : $default;
127 }
128
129 public function v($varname, $default = "")
130 {
131 return $this->get($varname, $default);
132 }
133
134 public function i($varname, $default = 0)
135 {
136 return (int)$this->get($varname, $default);
137 }
138
139 public function clear($varname = null)
140 {
141 if (is_null($varname)) {
142 $_SESSION[$this->name] = array();
143 } else {
144 unset($_SESSION[$this->name][$varname]);
145 }
146 $_SESSION[$this->name . '_page'] = null;
147 }
148
149 private function getPage($id)
150 {
151 $page = $this->pages[$id];
152 return new $page($this);
153 }
154
155 public function apply(PlPage &$smarty, $baseurl, $pgid = null, $mode = 'normal')
156 {
157 if ($this->stateless && (isset($this->lookup[$pgid]) || isset($this->pages[$pgid]))) {
158 $curpage = is_numeric($pgid) ? $pgid : $this->lookup[$pgid];
159 } else if ($this->stateless && is_null($pgid)) {
160 $curpage = 0;
161 } else {
162 $curpage = $_SESSION[$this->name . '_page'];
163 }
164 $oldpage = $curpage;
165
166 // Process the previous page
167 if (Post::has('valid_page')) {
168 S::assert_xsrf_token();
169
170 $page = $this->getPage(Post::i('valid_page'));
171 $curpage = Post::i('valid_page');
172 $next = $page->process();
173 $last = $curpage;
174 switch ($next) {
175 case PlWizard::FIRST_PAGE:
176 $curpage = 0;
177 break;
178 case PlWizard::PREVIOUS_PAGE:
179 if (!$this->stateless && count($_SESSION[$this->name . '_stack'])) {
180 $curpage = array_pop($_SESSION[$this->name . '_stack']);
181 } elseif ($curpage && $this->stateless) {
182 $curpage--;
183 } else {
184 $curpage = 0;
185 }
186 break;
187 case PlWizard::NEXT_PAGE:
188 if ($curpage < count($this->pages) - 1) {
189 $curpage++;
190 }
191 break;
192 case PlWizard::LAST_PAGE:
193 $curpage = count($this->pages) - 1;
194 break;
195 case PlWizard::CURRENT_PAGE: break; // don't change the page
196 default:
197 $curpage = is_numeric($next) ? $next : $this->lookup[$next];
198 break;
199 }
200 if (!$this->stateless) {
201 array_push($_SESSION[$this->name . '_stack'], $last);
202 }
203 }
204 if (is_null($curpage)) {
205 $curpage = 0;
206 }
207
208 // Prepare the page
209 $_SESSION[$this->name . '_page'] = $curpage;
210 if ($curpage != $oldpage) {
211 pl_redirect($baseurl . '/' . $this->inv_lookup[$curpage]);
212 } else if (!isset($page)) {
213 $page = $this->getPage($curpage);
214 }
215 if ($mode == 'ajax') {
216 header('Content-Type: text/html; charset=utf-8');
217 $smarty->changeTpl($this->layout, NO_SKIN);
218 $smarty->assign('wiz_run_ajax', true);
219 } else {
220 $smarty->changeTpl($this->layout);
221 }
222 $smarty->assign('pages', $this->titles);
223 $smarty->assign('current', $curpage);
224 $smarty->assign('lookup', $this->inv_lookup);
225 $smarty->assign('stateless', $this->stateless);
226 $smarty->assign('wiz_baseurl', $baseurl);
227 $smarty->assign('wiz_ajax', $this->ajax);
228 $smarty->assign('wiz_animated', $this->ajax_animated);
229 $smarty->assign('tab_width', (int)(99 / count($this->pages)));
230 $smarty->assign('wiz_page', $page->template());
231 $smarty->assign('pl_no_errors', true);
232 $page->prepare($smarty, isset($this->inv_lookup[$curpage]) ? $this->inv_lookup[$curpage] : $curpage);
233 }
234 }
235
236 // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
237 ?>