1 relationship. so u * can always derive one from the other * @var array */ protected $_pages; /** * The names of the pages. * * @var array */ protected $_pageNames; /** * The mode that the state machine is operating in. * @var int */ protected $_action = NULL; /** * The display name for this machine. * @var string */ protected $_name = NULL; /** * Class constructor. * * @param object $controller * The controller for this state machine. * * @param \const|int $action * * @return \CRM_Core_StateMachine */ public function __construct(&$controller, $action = CRM_Core_Action::NONE) { $this->_controller = &$controller; $this->_action = $action; $this->_states = array(); } /** * Getter for name. * * @return string */ public function getName() { return $this->_name; } /** * Setter for name. * * @param string $name * * @return void */ public function setName($name) { $this->_name = $name; } /** * Do a state transition jump. * * Currently only supported types are * Next and Back. The other actions (Cancel, Done, Submit etc) do * not need the state machine to figure out where to go * * @param CRM_Core_Form $page * The current form-page. * @param string $actionName * Current action name, as one Action object can serve multiple actions. * @param string $type * The type of transition being requested (Next or Back). * * @return void */ public function perform(&$page, $actionName, $type = 'Next') { // save the form values and validation status to the session $page->isFormBuilt() or $page->buildForm(); $pageName = $page->getAttribute('name'); $data = &$page->controller->container(); $data['values'][$pageName] = $page->exportValues(); $data['valid'][$pageName] = $page->validate(); // if we are going to the next state // Modal form and page is invalid: don't go further if ($type == 'Next' && !$data['valid'][$pageName]) { return $page->handle('display'); } $state = &$this->_states[$pageName]; // dont know how or why we landed here so abort and display // current page if (empty($state)) { return $page->handle('display'); } // the page is valid, process it if we are jumping to the next state if ($type == 'Next') { $page->mainProcess(); // we get the state again, since postProcess might have changed it // this bug took me forever to find :) Lobo $state = &$this->_states[$pageName]; $state->handleNextState($page); } else { $state->handleBackState($page); } } /** * Helper function to add a State to the state machine. * * @param string $name * The internal name. * @param int $type * The type of state (START|FINISH|SIMPLE). * @param object $prev * The previous page if any. * @param object $next * The next page if any. * * @return void */ public function addState($name, $type, $prev, $next) { $this->_states[$name] = new CRM_Core_State($name, $type, $prev, $next, $this); } /** * Given a name find the corresponding state. * * @param string $name * The state name. * * @return object * the state object */ public function find($name) { if (array_key_exists($name, $this->_states)) { return $this->_states[$name]; } else { return NULL; } } /** * Return the list of state objects. * * @return array * array of states in the state machine */ public function getStates() { return $this->_states; } /** * Return the state object corresponding to the name. * * @param string $name * Name of page. * * @return CRM_Core_State * state object matching the name */ public function &getState($name) { if (isset($this->_states[$name])) { return $this->_states[$name]; } /* * This is a gross hack for ajax driven requests where * we change the form name to allow multiple edits to happen * We need a cleaner way of doing this going forward */ foreach ($this->_states as $n => $s) { if (substr($name, 0, strlen($n)) == $n) { return $s; } } return NULL; } /** * Return the list of form objects. * * @return array * array of pages in the state machine */ public function getPages() { return $this->_pages; } /** * Add sequential pages. * * Meta level function to create a simple wizard for a state machine that is completely sequential. * * @param array $pages * (reference ) the array of page objects. */ public function addSequentialPages(&$pages) { $this->_pages = &$pages; $numPages = count($pages); $this->_pageNames = array(); foreach ($pages as $tempName => $value) { if (!empty($value['className'])) { $this->_pageNames[] = $tempName; } else { $this->_pageNames[] = CRM_Utils_String::getClassName($tempName); } } $i = 0; foreach ($pages as $tempName => $value) { $name = $this->_pageNames[$i]; $className = CRM_Utils_Array::value('className', $value, $tempName ); $classPath = str_replace('_', '/', $className) . '.php'; if ($numPages == 1) { $prev = $next = NULL; $type = CRM_Core_State::START | CRM_Core_State::FINISH; } elseif ($i == 0) { // start state $prev = NULL; $next = $this->_pageNames[$i + 1]; $type = CRM_Core_State::START; } elseif ($i == $numPages - 1) { // finish state $prev = $this->_pageNames[$i - 1]; $next = NULL; $type = CRM_Core_State::FINISH; } else { // in between simple state $prev = $this->_pageNames[$i - 1]; $next = $this->_pageNames[$i + 1]; $type = CRM_Core_State::SIMPLE; } $this->addState($name, $type, $prev, $next); $i++; } } /** * Reset the state machine. * * @return void */ public function reset() { $this->_controller->reset(); } /** * Getter for action. * * @return int */ public function getAction() { return $this->_action; } /** * Setter for content. * * @param string $content * The content generated by this state machine. * * @return void */ public function setContent(&$content) { $this->_controller->setContent($content); } /** * Getter for content. * * @return string */ public function &getContent() { return $this->_controller->getContent(); } /** * @return mixed */ public function getDestination() { return $this->_controller->getDestination(); } /** * @return mixed */ public function getSkipRedirection() { return $this->_controller->getSkipRedirection(); } /** * @return mixed */ public function fini() { return $this->_controller->fini(); } /** * @return mixed */ public function cancelAction() { return $this->_controller->cancelAction(); } /** * Should the controller reset the session * In some cases, specifically search we want to remember * state across various actions and want to go back to the * beginning from the final state, but retain the same session * values * * @return bool */ public function shouldReset() { return TRUE; } }