Example #1
0
 /**
  * Parses the given source and returns an array which represent a flow
  * structure.
  *
  * This method is to be overriden by the appropriate driver for the given
  * file.
  *
  * @return array
  * @throws PIECE_FLOW_ERROR_INVALID_FORMAT
  */
 function _parseSource()
 {
     ob_start();
     $dom = domxml_open_mem(file_get_contents($this->_source));
     $contents = ob_get_contents();
     ob_end_clean();
     if (!$dom) {
         Piece_Flow_Error::push(PIECE_FLOW_ERROR_INVALID_FORMAT, "The file [{$this->_source}] containts invalid format. See below for more details.\n {$contents}");
         return;
     }
     $element = $dom->document_element();
     if ($element->has_attribute('firstState')) {
         $flow['firstState'] = $element->get_attribute('firstState');
     }
     $lastState = $element->get_elements_by_tagname('lastState');
     if (count($lastState)) {
         $flow['lastState'] = array();
         if ($lastState[0]->has_attribute('name')) {
             $flow['lastState']['name'] = $lastState[0]->get_attribute('name');
         }
         if ($lastState[0]->has_attribute('view')) {
             $flow['lastState']['view'] = $lastState[0]->get_attribute('view');
         }
         $flow['lastState'] = array_merge($flow['lastState'], $this->_parseState($lastState[0]));
     }
     $viewStates = $element->get_elements_by_tagname('viewState');
     $flow['viewState'] = $this->_parseViewStates($viewStates);
     $actionState = $element->get_elements_by_tagname('actionState');
     $flow['actionState'] = $this->_parseActionStates($actionState);
     $initial = $element->get_elements_by_tagname('initial');
     if (count($initial)) {
         $flow['initial'] = $this->_parseAction($initial[0]);
     }
     $final = $element->get_elements_by_tagname('final');
     if (count($final)) {
         $flow['final'] = $this->_parseAction($final[0]);
     }
     return $flow;
 }
Example #2
0
 /**
  * Creates a new Piece_Flow_Continuation_Server object and configure it.
  *
  * @return Piece_Flow_Continuation_Server
  * @throws PIECE_UNITY_ERROR_INVALID_CONFIGURATION
  */
 function &_createContinuationServer()
 {
     $continuationServer =& new Piece_Flow_Continuation_Server($this->_getConfiguration('enableSingleFlowMode'), $this->_getConfiguration('enableGC'), $this->_getConfiguration('gcExpirationTime'));
     $continuationServer->setCacheDirectory($this->_getConfiguration('cacheDirectory'));
     $continuationServer->setEventNameCallback(array(__CLASS__, 'getEventName'));
     $continuationServer->setFlowExecutionTicketCallback(array(__CLASS__, 'getFlowExecutionTicket'));
     $continuationServer->setFlowIDCallback(array(__CLASS__, 'getFlowID'));
     if ($this->_getConfiguration('useFlowMappings')) {
         $continuationServer->setConfigDirectory($this->_getConfiguration('configDirectory'));
         $continuationServer->setConfigExtension($this->_getConfiguration('configExtension'));
         foreach ($this->_getConfiguration('flowMappings') as $flowMapping) {
             if (array_key_exists('url', $flowMapping)) {
                 $flowMapping['uri'] = $flowMapping['url'];
             }
             Piece_Flow_Error::disableCallback();
             $continuationServer->addFlow($flowMapping['uri'], $flowMapping['flowName'], $flowMapping['isExclusive']);
             Piece_Flow_Error::enableCallback();
             if (Piece_Flow_Error::hasErrors()) {
                 Piece_Unity_Error::push(PIECE_UNITY_ERROR_INVALID_CONFIGURATION, "Failed to configure the plugin [ {$this->_name}.", 'exception', array(), Piece_Flow_Error::pop());
                 $return = null;
                 return $return;
             }
         }
     } else {
         foreach ($this->_getConfiguration('flowDefinitions') as $flowDefinition) {
             Piece_Flow_Error::disableCallback();
             $continuationServer->addFlow($flowDefinition['name'], $flowDefinition['file'], $flowDefinition['isExclusive']);
             Piece_Flow_Error::enableCallback();
             if (Piece_Flow_Error::hasErrors()) {
                 Piece_Unity_Error::push(PIECE_UNITY_ERROR_INVALID_CONFIGURATION, "Failed to configure the plugin [ {$this->_name}.", 'exception', array(), Piece_Flow_Error::pop());
                 $return = null;
                 return $return;
             }
         }
     }
     return $continuationServer;
 }
Example #3
0
 /**
  * Configures a state.
  *
  * @param array $state
  * @throws PIECE_FLOW_ERROR_PROTECTED_EVENT
  */
 function _configureState($state)
 {
     for ($i = 0, $count = count(@$state['transitions']); $i < $count; ++$i) {
         if ($state['transitions'][$i]['event'] == PIECE_FLOW_PROTECTED_EVENT || $this->_fsm->isProtectedEvent($state['transitions'][$i]['event'])) {
             Piece_Flow_Error::push(PIECE_FLOW_ERROR_PROTECTED_EVENT, "The event [ {$state['transitions'][$i]['event']} ] cannot be used in flow definitions.");
             return;
         }
         $this->_fsm->addTransition($state['name'], $state['transitions'][$i]['event'], $state['transitions'][$i]['nextState'], $this->_wrapEventTriggerAction(@$state['transitions'][$i]['action']), $this->_wrapAction(@$state['transitions'][$i]['guard']));
     }
     if (array_key_exists('entry', $state)) {
         $this->_fsm->setEntryAction($state['name'], $this->_wrapAction(@$state['entry']));
     }
     if (array_key_exists('exit', $state)) {
         $this->_fsm->setExitAction($state['name'], $this->_wrapAction(@$state['exit']));
     }
     if (array_key_exists('activity', $state)) {
         $this->_fsm->setActivity($state['name'], $this->_wrapEventTriggerAction(@$state['activity']));
     }
 }
Example #4
0
 /**
  * Gets the current state name for the active flow object.
  *
  * @return string
  * @throws PIECE_FLOW_ERROR_INVALID_OPERATION
  */
 function getCurrentStateName()
 {
     if (!$this->_flowExecution->activated()) {
         Piece_Flow_Error::push(PIECE_FLOW_ERROR_INVALID_OPERATION, __FUNCTION__ . ' method must be called after starting/continuing flows.');
         return;
     }
     $flow =& $this->_flowExecution->getActiveFlow();
     return $flow->getCurrentStateName();
 }
Example #5
0
 /**
  * Starts a flow execution.
  *
  * @param mixed &$payload
  * @return string
  * @throws PIECE_FLOW_ERROR_NOT_FOUND
  */
 function _start(&$payload)
 {
     if (!array_key_exists($this->_activeFlowID, $this->_flowDefinitions)) {
         Piece_Flow_Error::push(PIECE_FLOW_ERROR_NOT_FOUND, "The flow ID [ {$this->_activeFlowID} ] not found in the flow definitions.");
         return;
     }
     $flow =& new Piece_Flow();
     $flow->configure($this->_flowDefinitions[$this->_activeFlowID]['source'], null, $this->_cacheDirectory, $this->_actionDirectory, $this->_configDirectory, $this->_configExtension);
     if (Piece_Flow_Error::hasErrors()) {
         return;
     }
     while (true) {
         $flowExecutionTicket = $this->_generateFlowExecutionTicket();
         if (!$this->_flowExecution->hasFlowExecution($flowExecutionTicket)) {
             $this->_flowExecution->addFlowExecution($flowExecutionTicket, $flow, $this->_activeFlowID);
             if ($this->_isExclusive()) {
                 $this->_flowExecution->markFlowExecutionAsExclusive($flowExecutionTicket, $this->_activeFlowID);
             }
             break;
         }
     }
     $this->_flowExecution->activateFlowExecution($flowExecutionTicket, $this->_activeFlowID);
     $this->_activeFlowExecutionTicket = $flowExecutionTicket;
     $flow->setPayload($payload);
     $this->_prepareContext();
     $flow->start();
     if (Piece_Flow_Error::hasErrors()) {
         return;
     }
     return $flowExecutionTicket;
 }
Example #6
0
 /**
  * Reads configuration from the given source and creates
  * a Piece_Flow_Config object.
  *
  * @param mixed  $source
  * @param string $driverName
  * @param string $cacheDirectory
  * @param string $configDirectory
  * @param string $configExtension
  * @return Piece_Flow_Config
  * @throws PIECE_FLOW_ERROR_NOT_FOUND
  * @static
  */
 function &read($source, $driverName, $cacheDirectory, $configDirectory, $configExtension)
 {
     if (!is_callable($source)) {
         $flowName = $source;
         if (!is_null($configDirectory)) {
             $source = str_replace('_', '/', $source);
             $source = "{$configDirectory}/{$source}{$configExtension}";
         }
         if (is_null($driverName)) {
             $driverName = strtoupper(substr(strrchr($source, '.'), 1));
             if ($driverName != 'YAML' && $driverName != 'XML') {
                 $driverName = 'YAML';
             }
         }
         if ($driverName == 'XML') {
             if (version_compare(phpversion(), '5.0.0', '>=')) {
                 $driverName = 'XML5';
             } else {
                 $driverName = 'XML4';
             }
         }
     } else {
         $driverName = 'PHPArray';
     }
     $class = "Piece_Flow_ConfigReader_{$driverName}";
     if (!Piece_Flow_ClassLoader::loaded($class)) {
         Piece_Flow_ClassLoader::load($class);
         if (Piece_Flow_Error::hasErrors()) {
             $return = null;
             return $return;
         }
         if (!Piece_Flow_ClassLoader::loaded($class)) {
             Piece_Flow_Error::push(PIECE_FLOW_ERROR_NOT_FOUND, "The class [ {$class} ] not found in the loaded file.");
             $return = null;
             return $return;
         }
     }
     $driver =& new $class($source, $cacheDirectory);
     $config =& $driver->read();
     if (Piece_Flow_Error::hasErrors()) {
         $return = null;
         return $return;
     }
     if (!is_callable($source)) {
         if (is_null($configDirectory)) {
             $flowName = basename($source);
             $positionOfExtension = strrpos($flowName, '.');
             if ($positionOfExtension !== false) {
                 $flowName = substr($flowName, 0, $positionOfExtension);
             }
         }
         $config->setName($flowName);
     }
     return $config;
 }
Example #7
0
 /**
  * Parses the given source and returns an array which represent a flow
  * structure.
  *
  * This method is to be overriden by the appropriate driver for the given
  * file.
  *
  * @return array
  * @throws PIECE_FLOW_ERROR_INVALID_FORMAT
  */
 function _parseSource()
 {
     $dom = DOMDocument::loadXML(file_get_contents($this->_source));
     ob_start();
     $validationResult = $dom->relaxNGValidateSource($this->_schema);
     $contents = ob_get_contents();
     ob_end_clean();
     if (!$validationResult) {
         Piece_Flow_Error::push(PIECE_FLOW_ERROR_INVALID_FORMAT, "The file [{$this->_source}] containts invalid format. See below for more details.\n {$contents}");
         return;
     }
     $element = $dom->getElementsByTagName('flow')->item(0);
     if ($element->hasAttribute('firstState')) {
         $flow['firstState'] = $element->getAttribute('firstState');
     }
     $lastState = $element->getElementsByTagName('lastState')->item(0);
     if (!is_null($lastState)) {
         $flow['lastState'] = array();
         if ($lastState->hasAttribute('name')) {
             $flow['lastState']['name'] = $lastState->getAttribute('name');
         }
         if ($lastState->hasAttribute('view')) {
             $flow['lastState']['view'] = $lastState->getAttribute('view');
         }
         $flow['lastState'] = array_merge($flow['lastState'], $this->_parseState($lastState));
     }
     $flow['viewState'] = $this->_parseViewStates($element->getElementsByTagName('viewState'));
     $flow['actionState'] = $this->_parseActionStates($element->getElementsByTagName('actionState'));
     $initial = $element->getElementsByTagName('initial')->item(0);
     if (!is_null($initial)) {
         $flow['initial'] = $this->_parseAction($initial);
     }
     $final = $element->getElementsByTagName('final')->item(0);
     if (!is_null($final)) {
         $flow['final'] = $this->_parseAction($final);
     }
     return $flow;
 }
Example #8
0
 /**
  * Starts a flow execution.
  *
  * @param mixed &$payload
  * @return string
  * @throws PIECE_FLOW_ERROR_NOT_FOUND
  */
 function _start(&$payload)
 {
     if (!array_key_exists($this->_currentFlowName, $this->_flowDefinitions)) {
         Piece_Flow_Error::push(PIECE_FLOW_ERROR_NOT_FOUND, "The flow name [ {$this->_currentFlowName} ] not found in the flow definitions.");
         return;
     }
     $flow =& new Piece_Flow();
     $flow->configure($this->_flowDefinitions[$this->_currentFlowName]['file'], null, $this->_cacheDirectory);
     if (Piece_Flow_Error::hasErrors()) {
         return;
     }
     while (true) {
         $flowExecutionTicket = $this->_generateFlowExecutionTicket();
         if (!$this->_hasFlowExecutionTicket($flowExecutionTicket)) {
             $this->_flowExecutions[$flowExecutionTicket] =& $flow;
             break;
         }
     }
     $this->_currentFlowExecutionTicket = $flowExecutionTicket;
     $this->_activated = true;
     $flow->setPayload($payload);
     $flow->start();
     if (Piece_Flow_Error::hasErrors()) {
         return;
     }
     if ($this->_isExclusive()) {
         $this->_exclusiveFlowExecutionTicketsByFlowName[$this->_currentFlowName] = $flowExecutionTicket;
         $this->_exclusiveFlowNamesByFlowExecutionTicket[$flowExecutionTicket] = $this->_currentFlowName;
     }
     return $flowExecutionTicket;
 }
Example #9
0
 /**
  * Enables the last callback.
  *
  * @since Method available since Release 1.16.0
  */
 function enableCallback()
 {
     Piece_Flow_Error::popCallback();
 }
Example #10
0
 /**
  * Loads an action class corresponding to the given class name.
  *
  * @param string $class
  * @throws PIECE_FLOW_ERROR_NOT_GIVEN
  * @throws PIECE_FLOW_ERROR_NOT_FOUND
  */
 function load($class)
 {
     if (!Piece_Flow_ClassLoader::loaded($class)) {
         if (is_null($GLOBALS['PIECE_FLOW_Action_Directory'])) {
             Piece_Flow_Error::push(PIECE_FLOW_ERROR_NOT_GIVEN, 'The action directory is not given.');
             return;
         }
         Piece_Flow_ClassLoader::load($class, $GLOBALS['PIECE_FLOW_Action_Directory']);
         if (Piece_Flow_Error::hasErrors()) {
             return;
         }
         if (!Piece_Flow_ClassLoader::loaded($class)) {
             Piece_Flow_Error::push(PIECE_FLOW_ERROR_NOT_FOUND, "The class [ {$class} ] not found in the loaded file.");
         }
     }
 }
Example #11
0
 /**
  * Removes the payload from the FSM.
  *
  * @since Method available since Release 1.11.0
  */
 function clearPayload()
 {
     if (!is_a($this->_fsm, 'Stagehand_FSM')) {
         Piece_Flow_Error::push(PIECE_FLOW_ERROR_INVALID_OPERATION, __FUNCTION__ . ' method must be called after configuring flows.');
         return;
     }
     $this->_fsm->clearPayload();
 }
Example #12
0
 /**
  * Loads a class.
  *
  * @param string $class
  * @param string $directory
  * @throws PIECE_FLOW_ERROR_NOT_READABLE
  * @throws PIECE_FLOW_ERROR_NOT_FOUND
  * @throws PIECE_FLOW_ERROR_CANNOT_READ
  * @static
  */
 function load($class, $directory = null)
 {
     $file = str_replace('_', '/', $class) . '.php';
     if (!is_null($directory)) {
         $file = "{$directory}/{$file}";
         if (!file_exists($file)) {
             Piece_Flow_Error::push(PIECE_FLOW_ERROR_NOT_FOUND, "The class file [ {$file} ] for the class [ {$class} ] is not found.");
             return;
         }
         if (!is_readable($file)) {
             Piece_Flow_Error::push(PIECE_FLOW_ERROR_NOT_READABLE, "The class file [ {$file} ] is not readable.");
             return;
         }
     }
     if (!(include_once $file)) {
         Piece_Flow_Error::push(PIECE_FLOW_ERROR_CANNOT_READ, "The class file [ {$file} ] is not found or is not readable.");
     }
 }
Example #13
0
 /**
  * Invokes an event handler in an action.
  *
  * @param string $eventName
  * @param mixed  &$payload
  * @return string
  * @throws PIECE_FLOW_ERROR_NOT_FOUND
  */
 function _invokeEventHandler($eventName, &$payload)
 {
     if (!is_null($this->_actionDirectory)) {
         Piece_Flow_Action_Factory::setActionDirectory($this->_actionDirectory);
     }
     $action =& Piece_Flow_Action_Factory::factory($this->_class);
     if (Piece_Flow_Error::hasErrors()) {
         return;
     }
     if (!method_exists($action, $this->_method)) {
         Piece_Flow_Error::push(PIECE_FLOW_ERROR_NOT_FOUND, "The method [ {$this->_method} ] does not exist in the action class [ {$this->_class} ].");
         return;
     }
     if (method_exists($action, 'setFlow')) {
         $action->setFlow($this->_flow);
     }
     if (method_exists($action, 'setPayload')) {
         $action->setPayload($payload);
     }
     if (method_exists($action, 'setEvent')) {
         $action->setEvent($eventName);
     }
     if (method_exists($action, 'prepare')) {
         $action->prepare();
     }
     $result = call_user_func(array(&$action, $this->_method));
     if (method_exists($action, 'clear')) {
         $action->clear();
     }
     return $result;
 }
Example #14
0
 /**
  * Parses the given source and returns a Piece_Flow_Config object.
  *
  * @return Piece_Flow_Config
  * @since Method available since Release 1.11.0
  */
 function &_createConfigurationFromSource()
 {
     $flow = $this->_parseSource();
     if (Piece_Flow_Error::hasErrors()) {
         $return = null;
         return $return;
     }
     $this->_config =& new Piece_Flow_Config();
     $this->_configureFirstState(@$flow['firstState']);
     if (Piece_Flow_Error::hasErrors()) {
         $return = null;
         return $return;
     }
     $this->_configureLastState(@$flow['lastState']);
     if (Piece_Flow_Error::hasErrors()) {
         $return = null;
         return $return;
     }
     $this->_configureViewStates(@$flow['viewState']);
     if (Piece_Flow_Error::hasErrors()) {
         $return = null;
         return $return;
     }
     $this->_configureActionStates(@$flow['actionState']);
     if (Piece_Flow_Error::hasErrors()) {
         $return = null;
         return $return;
     }
     $this->_configureInitialAction(@$flow['initial']);
     if (Piece_Flow_Error::hasErrors()) {
         $return = null;
         return $return;
     }
     $this->_configureFinalAction(@$flow['final']);
     if (Piece_Flow_Error::hasErrors()) {
         $return = null;
         return $return;
     }
     return $this->_config;
 }