/** * Parse a workflow defined as a PHP Array. * * The workflow definition passed as argument is turned into an array that can be * used by the WorkflowFileSource components. * * @param string $wId * @param array $definition * @param raoul2000\workflow\source\file\WorkflowFileSource $source * @return array The parse workflow array definition * @throws WorkflowValidationException */ public function parse($wId, $definition, $source) { if (empty($wId)) { throw new WorkflowValidationException("Missing argument : workflow Id"); } if (!\is_array($definition)) { throw new WorkflowValidationException("Workflow definition must be provided as an array"); } if (!ArrayHelper::isAssociative($definition)) { throw new WorkflowValidationException("Workflow definition must be provided as associative array"); } $initialStatusId = null; $normalized = []; $startStatusIdIndex = []; $endStatusIdIndex = []; foreach ($definition as $id => $targetStatusList) { list($workflowId, $statusId) = $source->parseStatusId($id, $wId); $absoluteStatusId = $workflowId . WorkflowFileSource::SEPARATOR_STATUS_NAME . $statusId; if ($workflowId != $wId) { throw new WorkflowValidationException('Status must belong to workflow : ' . $absoluteStatusId); } if (count($normalized) == 0) { $initialStatusId = $absoluteStatusId; $normalized['initialStatusId'] = $initialStatusId; $normalized[WorkflowFileSource::KEY_NODES] = []; } $startStatusIdIndex[] = $absoluteStatusId; $endStatusIds = []; if (\is_string($targetStatusList)) { $ids = array_map('trim', explode(',', $targetStatusList)); $endStatusIds = $this->normalizeStatusIds($ids, $wId, $source); } elseif (\is_array($targetStatusList)) { if (ArrayHelper::isAssociative($targetStatusList, false)) { throw new WorkflowValidationException("Associative array not supported (status : {$absoluteStatusId})"); } $endStatusIds = $this->normalizeStatusIds($targetStatusList, $wId, $source); } elseif ($targetStatusList === null) { $endStatusIds = []; } else { throw new WorkflowValidationException('End status list must be an array for status : ' . $absoluteStatusId); } if (count($endStatusIds)) { $normalized[WorkflowFileSource::KEY_NODES][$absoluteStatusId] = ['transition' => array_fill_keys($endStatusIds, [])]; $endStatusIdIndex = \array_merge($endStatusIdIndex, $endStatusIds); } else { $normalized[WorkflowFileSource::KEY_NODES][$absoluteStatusId] = null; } } $this->validate($wId, $source, $initialStatusId, $startStatusIdIndex, $endStatusIdIndex); return $normalized; }
/** * Parse a workflow defined as a PHP Array. * * The workflow definition passed as argument is turned into an array that can be * used by the WorkflowFileSource components. * * @param string $wId * @param array $definition * @param raoul2000\workflow\source\file\WorkflowFileSource $source * @return array The parse workflow array definition * @throws WorkflowValidationException */ public function parse($wId, $definition, $source) { $normalized = []; if (!isset($definition['initialStatusId'])) { throw new WorkflowValidationException('Missing "initialStatusId"'); } list($workflowId, $statusId) = $source->parseStatusId($definition['initialStatusId'], $wId); $initialStatusId = $workflowId . WorkflowFileSource::SEPARATOR_STATUS_NAME . $statusId; if ($workflowId != $wId) { throw new WorkflowValidationException('Initial status must belong to workflow : ' . $initialStatusId); } if (!isset($definition[WorkflowFileSource::KEY_NODES])) { throw new WorkflowValidationException("No status definition found"); } $normalized['initialStatusId'] = $initialStatusId; if (!\is_array($definition[WorkflowFileSource::KEY_NODES])) { throw new WorkflowValidationException('Invalid Status definition : array expected'); } $startStatusIdIndex = []; $endStatusIdIndex = []; foreach ($definition[WorkflowFileSource::KEY_NODES] as $key => $value) { $startStatusId = null; $startStatusDef = null; if (is_string($key)) { /** * 'status' => ['A' => ???] */ $startStatusId = $key; if ($value == null) { $startStatusDef = $startStatusId; // 'status' => ['A' => null] } elseif (\is_array($value)) { $startStatusDef = $value; // 'status' => ['A' => [ ...] ] } else { throw new WorkflowValidationException("Wrong definition for status {$startStatusId} : array expected"); } } elseif (is_string($value)) { /** * 'status' => 'A' */ $startStatusId = $value; $startStatusDef = $startStatusId; } else { throw new WorkflowValidationException("Wrong status definition : key = " . VarDumper::dumpAsString($key) . " value = " . VarDumper::dumpAsString($value)); } list($workflowId, $statusId) = $source->parseStatusId($startStatusId, $wId); $startStatusId = $startStatusIdIndex[] = $workflowId . WorkflowFileSource::SEPARATOR_STATUS_NAME . $statusId; if ($workflowId != $wId) { throw new WorkflowValidationException('Status must belong to workflow : ' . $startStatusId); } if (is_array($startStatusDef)) { if (count($startStatusDef) == 0) { /** * empty status config array * * 'A' => [] */ $normalized[WorkflowFileSource::KEY_NODES][$startStatusId] = null; } else { foreach ($startStatusDef as $startStatusKey => $startStatusValue) { if ($startStatusKey == WorkflowFileSource::KEY_METADATA) { /** * validate metadata * * 'A' => [ * 'metadata' => [ 'key' => 'value'] * ] */ if (\is_array($startStatusDef[WorkflowFileSource::KEY_METADATA])) { if (!ArrayHelper::isAssociative($startStatusDef[WorkflowFileSource::KEY_METADATA])) { throw new WorkflowValidationException("Invalid metadata definition for status {$startStatusId} : associative array expected"); } } else { throw new WorkflowValidationException("Invalid metadata definition for status {$startStatusId} : array expected"); } $normalized[WorkflowFileSource::KEY_NODES][$startStatusId][WorkflowFileSource::KEY_METADATA] = $startStatusDef[WorkflowFileSource::KEY_METADATA]; } elseif ($startStatusKey == 'transition') { $transitionDefinition = $startStatusDef['transition']; if (\is_string($transitionDefinition)) { /** * 'A' => [ * 'transition' => 'A, B, WID/C' * ] */ $ids = array_map('trim', explode(',', $transitionDefinition)); foreach ($ids as $id) { $pieces = $source->parseStatusId($id, $wId); $canEndStId = \implode(WorkflowFileSource::SEPARATOR_STATUS_NAME, $pieces); $endStatusIdIndex[] = $canEndStId; $normalized[WorkflowFileSource::KEY_NODES][$startStatusId]['transition'][$canEndStId] = []; } } elseif (\is_array($transitionDefinition)) { /** * 'transition' => [ ...] */ foreach ($transitionDefinition as $tkey => $tvalue) { if (\is_string($tkey)) { /** * 'transition' => [ 'A' => [] ] */ $endStatusId = $tkey; if (!\is_array($tvalue)) { throw new WorkflowValidationException("Wrong definition for between {$startStatusId} and {$endStatusId} : array expected"); } $transDef = $tvalue; } elseif (\is_string($tvalue)) { /** * 'transition' => 'A' */ $endStatusId = $tvalue; $transDef = null; } else { throw new WorkflowValidationException("Wrong transition definition for status {$startStatusId} : key = " . VarDumper::dumpAsString($tkey) . " value = " . VarDumper::dumpAsString($tvalue)); } $pieces = $source->parseStatusId($endStatusId, $wId); $canEndStId = \implode(WorkflowFileSource::SEPARATOR_STATUS_NAME, $pieces); $endStatusIdIndex[] = $canEndStId; if ($transDef != null) { $normalized[WorkflowFileSource::KEY_NODES][$startStatusId]['transition'][$canEndStId] = $transDef; } else { $normalized[WorkflowFileSource::KEY_NODES][$startStatusId]['transition'][$canEndStId] = []; } } } else { throw new WorkflowValidationException("Invalid transition definition format for status {$startStatusId} : string or array expected"); } } elseif (\is_string($startStatusKey)) { $normalized[WorkflowFileSource::KEY_NODES][$startStatusId][$startStatusKey] = $startStatusValue; } } } } else { //$startStatusDef is not array /** * Node IDS must be canonical and array keys * 'status' => [ * 'A' * ] * turned into * * 'status' => [ * 'WID/A' => null * ] */ $normalized[WorkflowFileSource::KEY_NODES][$startStatusId] = null; } } // copy remaining workflow properties foreach ($definition as $propName => $propValue) { if (is_string($propName)) { if ($propName != 'initialStatusId' && $propName != WorkflowFileSource::KEY_NODES) { $normalized[$propName] = $propValue; } } } $this->validate($wId, $source, $initialStatusId, $startStatusIdIndex, $endStatusIdIndex); return $normalized; }