factory = $factory; } /** * Add a location visitor to the command * * @param string $location Location to associate with the visitor * @param ResponseVisitorInterface $visitor Visitor to attach * * @return self */ public function addVisitor($location, ResponseVisitorInterface $visitor) { $this->factory->addResponseVisitor($location, $visitor); return $this; } protected function handleParsing(CommandInterface $command, Response $response, $contentType) { $operation = $command->getOperation(); $type = $operation->getResponseType(); $model = null; if ($type == OperationInterface::TYPE_MODEL) { $model = $operation->getServiceDescription()->getModel($operation->getResponseClass()); } elseif ($type == OperationInterface::TYPE_CLASS) { return $this->parseClass($command); } if (!$model) { // Return basic processing if the responseType is not model or the model cannot be found return parent::handleParsing($command, $response, $contentType); } elseif ($command[AbstractCommand::RESPONSE_PROCESSING] != AbstractCommand::TYPE_MODEL) { // Returns a model with no visiting if the command response processing is not model return new Model(parent::handleParsing($command, $response, $contentType), $model); } else { return new Model($this->visitResult($model, $command, $response), $model); } } /** * Parse a class object * * @param CommandInterface $command Command to parse into an object * * @return mixed * @throws ResponseClassException */ protected function parseClass(CommandInterface $command) { $className = $command->getOperation()->getResponseClass(); if (!class_exists($className)) { throw new ResponseClassException("{$className} does not exist"); } if (!method_exists($className, 'fromCommand')) { throw new ResponseClassException("{$className} must implement the fromCommand() method"); } return $className::fromCommand($command); } /** * Perform transformations on the result array * * @param Parameter $model Model that defines the structure * @param CommandInterface $command Command that performed the operation * @param Response $response Response received * * @return array Returns the array of result data */ protected function visitResult(Parameter $model, CommandInterface $command, Response $response) { $foundVisitors = $result = array(); $props = $model->getProperties(); foreach ($props as $schema) { if ($location = $schema->getLocation()) { // Trigger the before method on the first found visitor of this type if (!isset($foundVisitors[$location])) { $foundVisitors[$location] = $this->factory->getResponseVisitor($location); $foundVisitors[$location]->before($command, $result); } } } // Visit additional properties when it is an actual schema if (($additional = $model->getAdditionalProperties()) instanceof Parameter) { $this->visitAdditionalProperties($model, $command, $response, $additional, $result, $foundVisitors); } // Apply the parameter value with the location visitor foreach ($props as $schema) { if ($location = $schema->getLocation()) { $foundVisitors[$location]->visit($command, $response, $schema, $result); } } // Call the after() method of each found visitor foreach ($foundVisitors as $visitor) { $visitor->after($command); } return $result; } protected function visitAdditionalProperties( Parameter $model, CommandInterface $command, Response $response, Parameter $additional, &$result, array &$foundVisitors ) { // Only visit when a location is specified if ($location = $additional->getLocation()) { if (!isset($foundVisitors[$location])) { $foundVisitors[$location] = $this->factory->getResponseVisitor($location); $foundVisitors[$location]->before($command, $result); } // Only traverse if an array was parsed from the before() visitors if (is_array($result)) { // Find each additional property foreach (array_keys($result) as $key) { // Check if the model actually knows this property. If so, then it is not additional if (!$model->getProperty($key)) { // Set the name to the key so that we can parse it with each visitor $additional->setName($key); $foundVisitors[$location]->visit($command, $response, $additional, $result); } } // Reset the additionalProperties name to null $additional->setName(null); } } } }