commiting uncommited changes on live site
[weblabels.fsf.org.git] / crm.fsf.org / 20131203 / files / sites / all / modules-old / civicrm / CRM / Core / StateMachine.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.6 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2015 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
26 */
27
28 /**
29 *
30 * @package CRM
31 * @copyright CiviCRM LLC (c) 2004-2015
32 * $Id$
33 *
34 */
35
36 /**
37 * Core StateMachine. All statemachines subclass for the core one
38 * for functionality specific to their needs.
39 *
40 * A statemachine keeps track of differnt states and forms for a
41 * html quickform controller.
42 *
43 */
44 class CRM_Core_StateMachine {
45
46 /**
47 * The controller of this state machine.
48 * @var object
49 */
50 protected $_controller;
51
52 /**
53 * The list of states that belong to this state machine.
54 * @var array
55 */
56 protected $_states;
57
58 /**
59 * The list of pages that belong to this state machine. Note
60 * that a state and a form have a 1 <-> 1 relationship. so u
61 * can always derive one from the other
62 * @var array
63 */
64 protected $_pages;
65
66 /**
67 * The names of the pages.
68 *
69 * @var array
70 */
71 protected $_pageNames;
72
73 /**
74 * The mode that the state machine is operating in.
75 * @var int
76 */
77 protected $_action = NULL;
78
79 /**
80 * The display name for this machine.
81 * @var string
82 */
83 protected $_name = NULL;
84
85 /**
86 * Class constructor.
87 *
88 * @param object $controller
89 * The controller for this state machine.
90 *
91 * @param \const|int $action
92 *
93 * @return \CRM_Core_StateMachine
94 */
95 public function __construct(&$controller, $action = CRM_Core_Action::NONE) {
96 $this->_controller = &$controller;
97 $this->_action = $action;
98
99 $this->_states = array();
100 }
101
102 /**
103 * Getter for name.
104 *
105 * @return string
106 */
107 public function getName() {
108 return $this->_name;
109 }
110
111 /**
112 * Setter for name.
113 *
114 * @param string $name
115 *
116 * @return void
117 */
118 public function setName($name) {
119 $this->_name = $name;
120 }
121
122 /**
123 * Do a state transition jump.
124 *
125 * Currently only supported types are
126 * Next and Back. The other actions (Cancel, Done, Submit etc) do
127 * not need the state machine to figure out where to go
128 *
129 * @param CRM_Core_Form $page
130 * The current form-page.
131 * @param string $actionName
132 * Current action name, as one Action object can serve multiple actions.
133 * @param string $type
134 * The type of transition being requested (Next or Back).
135 *
136 * @return void
137 */
138 public function perform(&$page, $actionName, $type = 'Next') {
139 // save the form values and validation status to the session
140 $page->isFormBuilt() or $page->buildForm();
141
142 $pageName = $page->getAttribute('name');
143 $data = &$page->controller->container();
144
145 $data['values'][$pageName] = $page->exportValues();
146 $data['valid'][$pageName] = $page->validate();
147
148 // if we are going to the next state
149 // Modal form and page is invalid: don't go further
150 if ($type == 'Next' && !$data['valid'][$pageName]) {
151 return $page->handle('display');
152 }
153
154 $state = &$this->_states[$pageName];
155
156 // dont know how or why we landed here so abort and display
157 // current page
158 if (empty($state)) {
159 return $page->handle('display');
160 }
161
162 // the page is valid, process it if we are jumping to the next state
163 if ($type == 'Next') {
164 $page->mainProcess();
165 // we get the state again, since postProcess might have changed it
166 // this bug took me forever to find :) Lobo
167 $state = &$this->_states[$pageName];
168 $state->handleNextState($page);
169 }
170 else {
171 $state->handleBackState($page);
172 }
173 }
174
175 /**
176 * Helper function to add a State to the state machine.
177 *
178 * @param string $name
179 * The internal name.
180 * @param int $type
181 * The type of state (START|FINISH|SIMPLE).
182 * @param object $prev
183 * The previous page if any.
184 * @param object $next
185 * The next page if any.
186 *
187 * @return void
188 */
189 public function addState($name, $type, $prev, $next) {
190 $this->_states[$name] = new CRM_Core_State($name, $type, $prev, $next, $this);
191 }
192
193 /**
194 * Given a name find the corresponding state.
195 *
196 * @param string $name
197 * The state name.
198 *
199 * @return object
200 * the state object
201 */
202 public function find($name) {
203 if (array_key_exists($name, $this->_states)) {
204 return $this->_states[$name];
205 }
206 else {
207 return NULL;
208 }
209 }
210
211 /**
212 * Return the list of state objects.
213 *
214 * @return array
215 * array of states in the state machine
216 */
217 public function getStates() {
218 return $this->_states;
219 }
220
221 /**
222 * Return the state object corresponding to the name.
223 *
224 * @param string $name
225 * Name of page.
226 *
227 * @return CRM_Core_State
228 * state object matching the name
229 */
230 public function &getState($name) {
231 if (isset($this->_states[$name])) {
232 return $this->_states[$name];
233 }
234
235 /*
236 * This is a gross hack for ajax driven requests where
237 * we change the form name to allow multiple edits to happen
238 * We need a cleaner way of doing this going forward
239 */
240 foreach ($this->_states as $n => $s) {
241 if (substr($name, 0, strlen($n)) == $n) {
242 return $s;
243 }
244 }
245
246 return NULL;
247 }
248
249 /**
250 * Return the list of form objects.
251 *
252 * @return array
253 * array of pages in the state machine
254 */
255 public function getPages() {
256 return $this->_pages;
257 }
258
259 /**
260 * Add sequential pages.
261 *
262 * Meta level function to create a simple wizard for a state machine that is completely sequential.
263 *
264 * @param array $pages
265 * (reference ) the array of page objects.
266 */
267 public function addSequentialPages(&$pages) {
268 $this->_pages = &$pages;
269 $numPages = count($pages);
270
271 $this->_pageNames = array();
272 foreach ($pages as $tempName => $value) {
273 if (!empty($value['className'])) {
274 $this->_pageNames[] = $tempName;
275 }
276 else {
277 $this->_pageNames[] = CRM_Utils_String::getClassName($tempName);
278 }
279 }
280
281 $i = 0;
282 foreach ($pages as $tempName => $value) {
283 $name = $this->_pageNames[$i];
284
285 $className = CRM_Utils_Array::value('className',
286 $value,
287 $tempName
288 );
289 $classPath = str_replace('_', '/', $className) . '.php';
290 if ($numPages == 1) {
291 $prev = $next = NULL;
292 $type = CRM_Core_State::START | CRM_Core_State::FINISH;
293 }
294 elseif ($i == 0) {
295 // start state
296 $prev = NULL;
297 $next = $this->_pageNames[$i + 1];
298 $type = CRM_Core_State::START;
299 }
300 elseif ($i == $numPages - 1) {
301 // finish state
302 $prev = $this->_pageNames[$i - 1];
303 $next = NULL;
304 $type = CRM_Core_State::FINISH;
305 }
306 else {
307 // in between simple state
308 $prev = $this->_pageNames[$i - 1];
309 $next = $this->_pageNames[$i + 1];
310 $type = CRM_Core_State::SIMPLE;
311 }
312
313 $this->addState($name, $type, $prev, $next);
314
315 $i++;
316 }
317 }
318
319 /**
320 * Reset the state machine.
321 *
322 * @return void
323 */
324 public function reset() {
325 $this->_controller->reset();
326 }
327
328 /**
329 * Getter for action.
330 *
331 * @return int
332 */
333 public function getAction() {
334 return $this->_action;
335 }
336
337 /**
338 * Setter for content.
339 *
340 * @param string $content
341 * The content generated by this state machine.
342 *
343 * @return void
344 */
345 public function setContent(&$content) {
346 $this->_controller->setContent($content);
347 }
348
349 /**
350 * Getter for content.
351 *
352 * @return string
353 */
354 public function &getContent() {
355 return $this->_controller->getContent();
356 }
357
358 /**
359 * @return mixed
360 */
361 public function getDestination() {
362 return $this->_controller->getDestination();
363 }
364
365 /**
366 * @return mixed
367 */
368 public function getSkipRedirection() {
369 return $this->_controller->getSkipRedirection();
370 }
371
372 /**
373 * @return mixed
374 */
375 public function fini() {
376 return $this->_controller->fini();
377 }
378
379 /**
380 * @return mixed
381 */
382 public function cancelAction() {
383 return $this->_controller->cancelAction();
384 }
385
386 /**
387 * Should the controller reset the session
388 * In some cases, specifically search we want to remember
389 * state across various actions and want to go back to the
390 * beginning from the final state, but retain the same session
391 * values
392 *
393 * @return bool
394 */
395 public function shouldReset() {
396 return TRUE;
397 }
398
399 }