/** * This method is capable of taking an active flow and trigger the * execution its steps until it finishes (ok or not) or reach a waiting * point. * * @param \TooBasic\Workflows\ItemFlowRepresentation $flow Flow to be * executed. * @param string $error Returns an error message when something went * wrong. * @return boolean Returns FALSE when an error was found. */ public function run(ItemFlowRepresentation $flow, &$error = false) { // // Defautl values. $out = true; // // Enforcing known factories to be loaded. $this->loadFactories(); // // Loading flow's workflow. $workflow = $this->getWorkflow($flow->workflow); // // Loading flow's workflow. $item = $this->_factories[$flow->type]->item($flow->item); // // Basic log prefixes. $logParams = array('workflow' => $flow->workflow); // // Logging operation start. $this->_log->log(LGGR_LOG_LEVEL_INFO, 'Running flow: ' . json_encode($flow->toArray()), $logParams); $this->_log->log(LGGR_LOG_LEVEL_INFO, ' item: ' . json_encode($item->toArray()), $logParams); // // Walking through each step until it's no longer ok or flagged to // stop. $continue = true; while ($continue && $flow->status == WKFL_ITEM_FLOW_STATUS_OK) { // // Asking the workflow to run a step. $continue = $workflow->runFor($flow, $item); // // Reloading flow to avoid errors. $flow->load($flow->id); // // Logging step execution results. $this->_log->log(LGGR_LOG_LEVEL_INFO, 'Current flow status: ' . json_encode($flow->toArray()), $logParams); $this->_log->log(LGGR_LOG_LEVEL_INFO, ' item status: ' . json_encode($item->toArray()), $logParams); $this->_log->log(LGGR_LOG_LEVEL_INFO, 'Continue?: ' . ($continue ? 'Yes' : 'No'), $logParams); } return $out; }
/** * This method is the one in charge of executing a step of a specific * item, analyze results and set the next step or errors. * * @param \TooBasic\Workflows\ItemFlowRepresentation $flow Item flow to be * executed. * @param \TooBasic\Workflows\Item $item Item to be analyzed * @return boolean Returns TRUE the current step pointed the execution of * a next step and the flow is not in a stopping status. * @throws \TooBasic\Workflows\WorkflowsException */ public function runFor(ItemFlowRepresentation $flow, Item $item) { // // Default values. $continue = true; $logParams = array('workflow' => $flow->workflow); // // Loading all required settings. $this->load(); // // Global dependencies. global $WKFLDefaults; // // Guessing the current step name. $currentStep = $flow->step; if (!$currentStep) { // // Getting the fist step from workflow when there's none. $currentStep = $this->_config->startsAt; $flow->step = $currentStep; $flow->persist(); } $this->_log->log(LGGR_LOG_LEVEL_INFO, "Current step: '{$currentStep}'", $logParams); // // Shortcuts. $stepConfig = $this->_config->steps->{$currentStep}; $stepPath = Paths::Instance()->customPaths($WKFLDefaults[WKFL_DEFAULTS_PATHS][WKFL_DEFAULTS_PATH_STEPS], Names::SnakeFilename($stepConfig->manager), Paths::ExtensionPHP); $stepClass = Names::ClassNameWithSuffix($stepConfig->manager, WKFL_CLASS_SUFFIX_STEP); $this->_log->log(LGGR_LOG_LEVEL_DEBUG, " path: '{$stepPath}'", $logParams); $this->_log->log(LGGR_LOG_LEVEL_DEBUG, " class: '{$stepClass}'", $logParams); $this->_log->log(LGGR_LOG_LEVEL_DEBUG, ' config: ' . json_encode($stepConfig), $logParams); // // Checking if the step's class is already loaded. if (!class_exists($stepClass)) { // // Checking class code file. if (!$stepPath || !is_readable($stepPath)) { $msg = "Unable to access class for step '{$currentStep}'."; $this->_log->log(LGGR_LOG_LEVEL_FATAL, $msg, $logParams); throw new WorkflowsException($msg); } require_once $stepPath; } // // Checking class existence. if (!class_exists($stepClass)) { $msg = "Class '{$stepClass}' not defined."; $this->_log->log(LGGR_LOG_LEVEL_FATAL, $msg, $logParams); throw new WorkflowsException($msg); } // // Getting a step execution class. $step = new $stepClass($item); // // Sharing log pointer. $step->setLog($this->_log); // // Step execution $step->execute(); // // Reloading item to avoid outdated data. $item->reload(); // // Checking that thers a connection configuration for the current // item status. $connection = false; if (isset($stepConfig->connections->{$item->status()})) { $connection = $stepConfig->connections->{$item->status()}; } else { $this->_log->log(LGGR_LOG_LEVEL_ERROR, "Unkwnon connection for item status '{$item->status()}'.", $logParams); $continue = false; $flow->status = WKFL_ITEM_FLOW_STATUS_FAILED; $flow->persist(); } // // Checking if there's a connection configuration to analyze. if ($connection) { // // Checking what action should be taken. if (isset($connection->step) || isset($connection->status)) { // // Setting the next step to take. if (isset($connection->step)) { $flow->step = $connection->step; } // // Setting new flows status. if (isset($connection->status)) { $flow->status = $connection->status; $continue = false; } } else { $this->_log->log(LGGR_LOG_LEVEL_ERROR, "Neither step not status configuration for connection on status '{$item->status()}'.", $logParams); $continue = false; $flow->status = WKFL_ITEM_FLOW_STATUS_FAILED; } // // If the flow has been set to wait, it should check if // the waiting has conditions. if ($flow->status == WKFL_ITEM_FLOW_STATUS_WAIT && isset($connection->wait)) { // // Checking configuration. if (!isset($connection->wait->attempts) || !isset($connection->wait->status)) { $this->_log->log(LGGR_LOG_LEVEL_ERROR, "Waiting configuration is incorrect.", $logParams); $continue = false; $flow->status = WKFL_ITEM_FLOW_STATUS_FAILED; } else { // // Incrising the attempts count. $flow->attempts++; // // Checking it already tried to many // times. if ($flow->attempts > $connection->wait->attempts) { // // Changing flow status and // resetting counts. $flow->status = $connection->wait->status; $flow->attempts = 0; $this->_log->log(LGGR_LOG_LEVEL_INFO, "Maximum attempts reached ({$connection->wait->attempts} attempts), changing flow status to '{$connection->wait->status}'.", $logParams); } else { $this->_log->log(LGGR_LOG_LEVEL_INFO, "Increasing attempts to {$flow->attempts}.", $logParams); } } } else { // // The rest of the status keep the attempts to // zero. $flow->attempts = 0; } // // Saving flow status. $flow->persist(); $this->_log->log(LGGR_LOG_LEVEL_INFO, "Next step: '{$flow->step}'. Next flow status: '{$flow->status}'.", $logParams); } return $continue; }