options = $options->package(); $this->requirement = $requirement->getRequirements(); $this->inputs = $requirement->getInputs(); } else if (!empty($packagedContract)) { $this->hydrate($packagedContract); } if (!empty($contractData)) { $this->setContractData($contractData); } if (!empty($optionData)) { $options = new \Workspace\UseCase\Options($this->options, $optionData); $this->optionData = $options->getOptions(); } } /** * Set base requirement. * @param \Workspace\UseCase\Requirement $requirement * @return \Workspace\Contract\AbstractBase */ public function setRequirement(\Workspace\UseCase\Requirement $requirement) { $this->requirement = $requirement->getRequirements(); $this->inputs = $requirement->getInputs(); return $this; } /** * Add a conditional use case. * @param string $name * @param \Workspace\UseCase\ConditionBase $condition * @param \Workspace\UseCase\Requirement $requirement * @return \Workspace\Contract\UseOnce */ public function addConditionalCase($name, \Workspace\UseCase\AbstractBase $condition, \Workspace\UseCase\Requirement $requirement) { $this->conditionalCases[$name] = array( 'Condition' => $condition->getPrerequisites(), 'Requirement' => $requirement->getRequirements() ); $stack = $requirement->getInputs(); foreach ($stack as $group => $fieldSet) { isset($this->inputs[$group]) || $this->inputs[$group] = array(); $this->inputs[$group] = array_merge($this->inputs[$group], $fieldSet); } return $this; } /** * Set contract dataset. * @param array $data * @return \Workspace\Contract\AbstractBase */ public function setData(array $data) { $this->data = $data; return $this; } /** * Package this contract into an array. * @return array */ public function package() { return array( 'LifeTime' => $this->lifeTime, 'Options' => $this->options, 'Requirement' => $this->requirement, 'Conditional' => $this->conditionalCases, 'Inputs' => $this->inputs, 'Data' => $this->data ); } /** * Hydrate contract from package. * @param array $packagedContract * @return \Workspace\Contract\UseOnce */ public function hydrate(array $packagedContract) { $this->lifeTime = $packagedContract['LifeTime']; $this->options = $packagedContract['Options']; $this->requirement = $packagedContract['Requirement']; $this->conditionalCases = $packagedContract['Conditional']; $this->inputs = $packagedContract['Inputs']; $this->data = $packagedContract['Data']; return $this; } /** * Set data inputs for contract. * @param array $input * @return \Workspace\Contract\AbstractBase */ public function setContractData(array $input) { $this->contractData = array(); isset($input['id']) && $this->contractData['id'] = $input['id']; foreach ($this->inputs as $group => $fieldSet) { $this->contractData[$group] = array(); foreach ($fieldSet as $field => $spec) { isset($input[$group][$field]) && $this->contractData[$group][$field] = $input[$group][$field]; } } return $this; } /** * Retrieve filtered contract data. * @return array */ public function getSignedContract($requestId, $hash) { $options = new \Workspace\Utility\ServiceInput('ParamSet', $this->optionData); $data = new \Workspace\Utility\ServiceInput('ParamSet', $this->contractData); $conditions = new \Workspace\Utility\ServiceInput('ParamSet', array(), $this->caseConditions); $contract = new \Workspace\Utility\ServiceInput('Contract', array( 'requestId' => $requestId, 'hash' => $hash, 'options' => $options->pack(), 'data' => $data->pack(), 'conditions' => $conditions->pack() )); return $contract->pack(); } /** * Cleanup array values. * @param array $input * @return array */ protected function cleanupStack(array $input) { foreach ($input as $field => $value) { if (is_array($value)) { $input[$field] = $this->cleanupStack($value); conitnue; } $input[$field] = strip_tags($value); } return $input; } /** * Cleanup inputs. */ protected function cleanupInputs() { $this->inputs = $this->cleanupStack($this->inputs); } /** * Evaluate the contract. IMPORTANT: setContractData() must be called before this method. * @param \Workspace\Workflow $workflow * @return boolean */ public function isValid(\Workspace\Workflow $workflow) { $valid = true; $messages = array(); $messages['Base'] = $this->checkRequiredInputs($workflow, $this->requirement, $this->contractData); !empty($messages['Base']) && $valid = false; foreach ($this->conditionalCases as $caseId => $case) { if ($this->checkCondition($case['Condition'], $this->contractData)) { $this->caseConditions[$caseId] = $caseId; $msgs = $this->checkRequiredInputs($workflow, $case['Requirement'], $this->contractData); if (!empty($msgs)) { $valid = false; isset($messages['Conditional']) || $messages['Conditional'] = array(); $messages['Conditional'][] = array('Condition' => $case['Condition'], 'Messages' => $msgs); } } } $this->validation = $messages; $validator = new \Utility\Service\Validator(); if (!$validator->validateGroupedInputSet($this->inputs, $this->contractData)) { $valid = false; $this->validation['ValidationErrors'] = $validator->getMessages(); } return $valid; } /** * Retrieve validation error messages. * @return array */ public function getMessages() { return $this->validation; } /** * Evaluate a condition collection. * @param array $conditions * @param array $input * @return boolean */ protected function checkCondition(array $conditions, array $input) { $valid = true; return $this->checkStack($conditions['Operator'], $conditions['Conditions'], $input); /* foreach ($conditions as $condition) { $cons = $condition['Conditions']; $check = $this->checkStack($condition['Operator'], $condition['Conditions'], $input); $valid = $valid && $check; } return $valid */; } /** * Evaluate condition stack. * @param string $base * @param array $conditions * @param array $input * @return boolean */ protected function checkStack($base, array $conditions, array $input) { $valid = ('and' == $base) ? true : false; foreach ($conditions as $condition) { if (!isset($condition['Conditions'])) { list($group, $field) = explode('.', $condition['Input']); if (!isset($input[$group][$field])) { if ('and' == $base) { return false; } else { continue; } } switch($condition['Operator']) { case '=': $check = ($input[$group][$field] == $condition['Value']); break; case '!=': $check = ($input[$group][$field] != $condition['Value']); break; case '<': $check = ($input[$group][$field] < $condition['Value']); break; case '>': $check = ($input[$group][$field] > $condition['Value']); break; case 'IN': $check = in_array($input[$group][$field], $condition['Value']); break; case 'NOT IN': $check = !in_array($input[$group][$field], $condition['Value']); break; } } else { $check = $this->checkStack($condition['Operator'], $condition['Conditions'], $input); } $valid = ('and' == $base) ? $valid && $check : $valid || $check; if ('and' == $base && !$valid) { return false; } if ('or' == $base && $valid) { return true; } } return $valid; } /** * Check that Required Fields are provided and that Unique Constraints adhered to. * @param \Workspace\Workflow $workflow * @param array $case * @param array $input * @return array */ protected function checkRequiredInputs(\Workspace\Workflow $workflow, array $case, array $inputs) { $messages = array(); foreach ($case as $group => $requirements) { $input = isset($inputs[$group]) ? $inputs[$group] : array(); foreach ($requirements as $requiredInput) { if (!isset($input[$requiredInput]) || (empty($input[$requiredInput]) && !$this->inputs[$group][$requiredInput]['Options']['AllowEmpty']) || (0 === $input[$requiredInput] && !$this->inputs[$group][$requiredInput]['Options']['AllowZero']) || (is_null($input[$requiredInput]) && !$this->inputs[$group][$requiredInput]['Options']['AllowNull'])) { isset($messages[$group]) || $messages[$group] = array(); $messages[$group][] = 'Required input `' . $requiredInput . '` not provided.'; } if ($this->inputs[$group][$requiredInput]['Options']['Unique']) { $contract = new \Workspace\Utility\ServiceInput('Contract', array( 'Group' => $group, 'Field' => $requiredInput, 'Value' => $input[$requiredInput] )); $serviceResponse = $workflow->fieldIsUnique($contract->pack()); if ('Error' == $serviceResponse['Status']) { $messages[$group][] = $serviceResponse['Message']; } } } } return $messages; } }