/modules/Guzzle/Service/Command/OperationResponseParser.php
PHP | 195 lines | 117 code | 24 blank | 54 comment | 18 complexity | bbeeaf651605a494a97315e221f5eb1a MD5 | raw file
- <?php
- namespace Guzzle\Service\Command;
- use Guzzle\Http\Message\Response;
- use Guzzle\Service\Command\LocationVisitor\VisitorFlyweight;
- use Guzzle\Service\Command\LocationVisitor\Response\ResponseVisitorInterface;
- use Guzzle\Service\Description\Parameter;
- use Guzzle\Service\Description\OperationInterface;
- use Guzzle\Service\Description\Operation;
- use Guzzle\Service\Exception\ResponseClassException;
- use Guzzle\Service\Resource\Model;
- /**
- * Response parser that attempts to marshal responses into an associative array based on models in a service description
- */
- class OperationResponseParser extends DefaultResponseParser
- {
- /** @var VisitorFlyweight $factory Visitor factory */
- protected $factory;
- /** @var self */
- protected static $instance;
- /** @var bool */
- private $schemaInModels;
- /**
- * @return self
- * @codeCoverageIgnore
- */
- public static function getInstance()
- {
- if (!static::$instance) {
- static::$instance = new static(VisitorFlyweight::getInstance());
- }
- return static::$instance;
- }
- /**
- * @param VisitorFlyweight $factory Factory to use when creating visitors
- * @param bool $schemaInModels Set to true to inject schemas into models
- */
- public function __construct(VisitorFlyweight $factory, $schemaInModels = false)
- {
- $this->factory = $factory;
- $this->schemaInModels = $schemaInModels;
- }
- /**
- * 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));
- } else {
- // Only inject the schema into the model if "schemaInModel" is true
- return new Model($this->visitResult($model, $command, $response), $this->schemaInModels ? $model : null);
- }
- }
- /**
- * Parse a class object
- *
- * @param CommandInterface $command Command to parse into an object
- *
- * @return mixed
- * @throws ResponseClassException
- */
- protected function parseClass(CommandInterface $command)
- {
- // Emit the operation.parse_class event. If a listener injects a 'result' property, then that will be the result
- $event = new CreateResponseClassEvent(array('command' => $command));
- $command->getClient()->getEventDispatcher()->dispatch('command.parse_response', $event);
- if ($result = $event->getResult()) {
- return $result;
- }
- $className = $command->getOperation()->getResponseClass();
- if (!method_exists($className, 'fromCommand')) {
- throw new ResponseClassException("{$className} must exist and implement a static 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 = $knownProps = 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) {
- $knownProps[$schema->getName()] = 1;
- if ($location = $schema->getLocation()) {
- $foundVisitors[$location]->visit($command, $response, $schema, $result);
- }
- }
- // Remove any unknown and potentially unsafe top-level properties
- if ($additional === false) {
- $result = array_intersect_key($result, $knownProps);
- }
- // 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);
- }
- }
- }
- }