bulk comment fixes
[civicrm-core.git] / CRM / Core / StateMachine.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
06b69b18 4 | CiviCRM version 4.5 |
6a488035 5 +--------------------------------------------------------------------+
06b69b18 6 | Copyright CiviCRM LLC (c) 2004-2014 |
6a488035
TO
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
06b69b18 31 * @copyright CiviCRM LLC (c) 2004-2014
6a488035
TO
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 */
44class 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 the controller for this state machine
89 *
dd244018
EM
90 * @param const $action
91 *
92 * @return \CRM_Core_StateMachine
93 @access public
6a488035
TO
94 */
95 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 * @access public
107 */
108 public function getName() {
109 return $this->_name;
110 }
111
112 /**
113 * setter for name
114 *
115 * @param string
116 *
117 * @return void
118 * @access public
119 */
120 public function setName($name) {
121 $this->_name = $name;
122 }
123
124 /**
125 * do a state transition jump. 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 object $page CRM_Core_Form the current form-page
130 * @param string $actionName Current action name, as one Action object can serve multiple actions
131 * @param string $type The type of transition being requested (Next or Back)
132 *
133 * @return void
134 * @access public
135 */
136 function perform(&$page, $actionName, $type = 'Next') {
137 // save the form values and validation status to the session
138 $page->isFormBuilt() or $page->buildForm();
139
140 $pageName = $page->getAttribute('name');
141 $data = &$page->controller->container();
142
143 $data['values'][$pageName] = $page->exportValues();
144 $data['valid'][$pageName] = $page->validate();
145
146 // if we are going to the next state
147 // Modal form and page is invalid: don't go further
148 if ($type == 'Next' && !$data['valid'][$pageName]) {
149 return $page->handle('display');
150 }
151
152 $state = &$this->_states[$pageName];
153
154 // dont know how or why we landed here so abort and display
155 // current page
156 if (empty($state)) {
157 return $page->handle('display');
158 }
159
160 // the page is valid, process it if we are jumping to the next state
161 if ($type == 'Next') {
162 $page->mainProcess();
163 // we get the state again, since postProcess might have changed it
164 // this bug took me forever to find :) Lobo
165 $state = &$this->_states[$pageName];
166 $state->handleNextState($page);
167 }
168 else {
169 $state->handleBackState($page);
170 }
171 }
172
173 /**
174 * helper function to add a State to the state machine
175 *
176 * @param string $name the internal name
177 * @param int $type the type of state (START|FINISH|SIMPLE)
178 * @param object $prev the previous page if any
179 * @param object $next the next page if any
180 *
181 * @return void
182 * @access public
183 */
184 function addState($name, $type, $prev, $next) {
185 $this->_states[$name] = new CRM_Core_State($name, $type, $prev, $next, $this);
186 }
187
188 /**
189 * Given a name find the corresponding state
190 *
191 * @param string $name the state name
192 *
193 * @return object the state object
194 * @access public
195 */
196 function find($name) {
197 if (array_key_exists($name, $this->_states)) {
198 return $this->_states[$name];
199 }
200 else {
201 return NULL;
202 }
203 }
204
205 /**
206 * return the list of state objects
207 *
208 * @return array array of states in the state machine
209 * @access public
210 */
211 function getStates() {
212 return $this->_states;
213 }
214
215 /**
216 * return the state object corresponding to the name
217 *
218 * @param string $name name of page
219 *
220 * @return CRM_Core_State state object matching the name
221 * @access public
222 */
223 function &getState($name) {
224 if (isset($this->_states[$name])) {
225 return $this->_states[$name];
226 }
227
228 /*
229 * This is a gross hack for ajax driven requests where
230 * we change the form name to allow multiple edits to happen
231 * We need a cleaner way of doing this going forward
232 */
233 foreach ($this->_states as $n => $s ) {
234 if (substr($name, 0, strlen($n)) == $n) {
235 return $s;
236 }
237 }
238
239 return null;
240 }
241
242 /**
243 * return the list of form objects
244 *
245 * @return array array of pages in the state machine
246 * @access public
247 */
248 function getPages() {
249 return $this->_pages;
250 }
251
252 /**
253 * addSequentialStates: meta level function to create a simple
254 * wizard for a state machine that is completely sequential.
255 *
256 * @access public
257 *
258 * @param array $states states is an array of arrays. Each element
259 * of the top level array describes a state. Each state description
260 * includes the name, the display name and the class name
261 *
262 * @param array $pages (reference ) the array of page objects
263 *
264 * @return void
265 */
266 function addSequentialPages(&$pages) {
267 $this->_pages = &$pages;
268 $numPages = count($pages);
269
270 $this->_pageNames = array();
271 foreach ($pages as $tempName => $value) {
a7488080 272 if (!empty($value['className'])) {
6a488035
TO
273 $this->_pageNames[] = $tempName;
274 }
275 else {
276 $this->_pageNames[] = CRM_Utils_String::getClassName($tempName);
277 }
278 }
279
280 $i = 0;
281 foreach ($pages as $tempName => $value) {
282 $name = $this->_pageNames[$i];
283
284 $className = CRM_Utils_Array::value('className',
285 $value,
286 $tempName
287 );
288 $classPath = str_replace('_', '/', $className) . '.php';
289 if ($numPages == 1) {
290 $prev = $next = NULL;
291 $type = CRM_Core_State::START | CRM_Core_State::FINISH;
292 }
293 elseif ($i == 0) {
294 // start state
295 $prev = NULL;
296 $next = $this->_pageNames[$i + 1];
297 $type = CRM_Core_State::START;
298 }
299 elseif ($i == $numPages - 1) {
300 // finish state
301 $prev = $this->_pageNames[$i - 1];
302 $next = NULL;
303 $type = CRM_Core_State::FINISH;
304 }
305 else {
306 // in between simple state
307 $prev = $this->_pageNames[$i - 1];
308 $next = $this->_pageNames[$i + 1];
309 $type = CRM_Core_State::SIMPLE;
310 }
311
312 $this->addState($name, $type, $prev, $next);
313
314 $i++;
315 }
316 }
317
318 /**
319 * reset the state machine
320 *
321 * @return void
322 * @access public
323 */
324 function reset() {
325 $this->_controller->reset();
326 }
327
328 /**
329 * getter for action
330 *
331 * @return int
332 * @access public
333 */
334 function getAction() {
335 return $this->_action;
336 }
337
338 /**
339 * setter for content
340 *
341 * @param string $content the content generated by this state machine
342 *
343 * @return void
344 * @access public
345 */
346 function setContent(&$content) {
347 $this->_controller->setContent($content);
348 }
349
350 /**
351 * getter for content
352 *
353 * @return string
354 * @access public
355 */
356 function &getContent() {
357 return $this->_controller->getContent();
358 }
359
360 function getDestination() {
361 return $this->_controller->getDestination();
362 }
363
364 function getSkipRedirection() {
365 return $this->_controller->getSkipRedirection();
366 }
367
368 function fini() {
369 return $this->_controller->fini();
370 }
371
372 function cancelAction() {
373 return $this->_controller->cancelAction();
374 }
375
376 /**
377 * Should the controller reset the session
378 * In some cases, specifically search we want to remember
379 * state across various actions and want to go back to the
380 * beginning from the final state, but retain the same session
381 * values
382 *
383 * @return boolean
384 */
385 function shouldReset() {
386 return TRUE;
387}
388
389}
390