mirror of
https://github.com/guzzle/guzzle.git
synced 2025-02-25 10:33:18 +01:00
Porting request visitors
This commit is contained in:
parent
aab0e6de47
commit
10f90a0356
@ -44,6 +44,10 @@ class GuzzleClient implements GuzzleClientInterface
|
||||
* - process: Specify if HTTP responses are parsed (defaults to true).
|
||||
* Changing this setting after the client has been created will have
|
||||
* no effect.
|
||||
* - request_locations: Associative array of location types mapping to
|
||||
* RequestLocationInterface objects.
|
||||
* - response_locations: Associative array of location types mapping to
|
||||
* ResponseLocationInterface objects.
|
||||
*/
|
||||
public function __construct(
|
||||
ClientInterface $client,
|
||||
@ -56,21 +60,7 @@ class GuzzleClient implements GuzzleClientInterface
|
||||
$config['defaults'] = [];
|
||||
}
|
||||
$this->config = new Collection($config);
|
||||
|
||||
// Use the passed in command factory or a custom factory if provided
|
||||
$this->commandFactory = isset($config['command_factory'])
|
||||
? $config['command_factory']
|
||||
: self::defaultCommandFactory($description);
|
||||
|
||||
// Add event listeners based on the configuration option
|
||||
$emitter = $this->getEmitter();
|
||||
if (!isset($config['validate']) || $config['validate'] === true) {
|
||||
$emitter->addSubscriber(new ValidateInput());
|
||||
}
|
||||
$emitter->addSubscriber(new PrepareRequest());
|
||||
if (!isset($config['process']) || $config['process'] === true) {
|
||||
$emitter->addSubscriber(new ProcessResponse());
|
||||
}
|
||||
$this->processConfig();
|
||||
}
|
||||
|
||||
public function __call($name, array $arguments)
|
||||
@ -172,4 +162,34 @@ class GuzzleClient implements GuzzleClientInterface
|
||||
return new Command($operation, $args, clone $client->getEmitter());
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the client based on the configuration settings of the client.
|
||||
*/
|
||||
protected function processConfig()
|
||||
{
|
||||
// Use the passed in command factory or a custom factory if provided
|
||||
$this->commandFactory = isset($config['command_factory'])
|
||||
? $config['command_factory']
|
||||
: self::defaultCommandFactory($this->description);
|
||||
|
||||
// Add event listeners based on the configuration option
|
||||
$emitter = $this->getEmitter();
|
||||
|
||||
if (!isset($this->config['validate']) ||
|
||||
$this->config['validate'] === true
|
||||
) {
|
||||
$emitter->addSubscriber(new ValidateInput());
|
||||
}
|
||||
|
||||
$emitter->addSubscriber(new PrepareRequest(
|
||||
$this->config['request_locations'] ?: []
|
||||
));
|
||||
|
||||
if (!isset($config['process']) || $config['process'] === true) {
|
||||
$emitter->addSubscriber(new ProcessResponse(
|
||||
$this->config['response_locations'] ?: []
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
71
src/Service/Guzzle/RequestLocation/AbstractLocation.php
Normal file
71
src/Service/Guzzle/RequestLocation/AbstractLocation.php
Normal file
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Service\Guzzle\RequestLocation;
|
||||
|
||||
use GuzzleHttp\Service\Guzzle\Description\Parameter;
|
||||
use GuzzleHttp\Message\RequestInterface;
|
||||
|
||||
abstract class AbstractLocation implements RequestLocationInterface
|
||||
{
|
||||
public function visit(
|
||||
RequestInterface $request,
|
||||
Parameter $param,
|
||||
$value,
|
||||
array $context
|
||||
) {}
|
||||
|
||||
public function after(
|
||||
RequestInterface $request,
|
||||
array $context
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Prepare (filter and set desired name for request item) the value for
|
||||
* request.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param Parameter $param
|
||||
*
|
||||
* @return array|mixed
|
||||
*/
|
||||
protected function prepareValue($value, Parameter $param)
|
||||
{
|
||||
return is_array($value)
|
||||
? $this->resolveRecursively($value, $param)
|
||||
: $param->filter($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively prepare and filter nested values.
|
||||
*
|
||||
* @param array $value Value to map
|
||||
* @param Parameter $param Parameter related to the current key.
|
||||
*
|
||||
* @return array Returns the mapped array
|
||||
*/
|
||||
protected function resolveRecursively(array $value, Parameter $param)
|
||||
{
|
||||
foreach ($value as $name => &$v) {
|
||||
switch ($param->getType()) {
|
||||
case 'object':
|
||||
if ($subParam = $param->getProperty($name)) {
|
||||
$key = $subParam->getWireName();
|
||||
$value[$key] = $this->prepareValue($v, $subParam);
|
||||
if ($name != $key) {
|
||||
unset($value[$name]);
|
||||
}
|
||||
} elseif ($param->getAdditionalProperties() instanceof Parameter) {
|
||||
$v = $this->prepareValue($v, $param->getAdditionalProperties());
|
||||
}
|
||||
break;
|
||||
case 'array':
|
||||
if ($items = $param->getItems()) {
|
||||
$v = $this->prepareValue($v, $items);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $param->filter($value);
|
||||
}
|
||||
}
|
22
src/Service/Guzzle/RequestLocation/BodyLocation.php
Normal file
22
src/Service/Guzzle/RequestLocation/BodyLocation.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Service\Guzzle\RequestLocation;
|
||||
|
||||
use GuzzleHttp\Service\Guzzle\Description\Parameter;
|
||||
use GuzzleHttp\Message\RequestInterface;
|
||||
use GuzzleHttp\Stream\Stream;
|
||||
|
||||
/**
|
||||
* Adds a body to a request
|
||||
*/
|
||||
class BodyLocation extends AbstractLocation
|
||||
{
|
||||
public function visit(
|
||||
RequestInterface $request,
|
||||
Parameter $param,
|
||||
$value,
|
||||
array $context
|
||||
) {
|
||||
$request->setBody(Stream::factory($param->filter($value)));
|
||||
}
|
||||
}
|
21
src/Service/Guzzle/RequestLocation/HeaderLocation.php
Normal file
21
src/Service/Guzzle/RequestLocation/HeaderLocation.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Service\Guzzle\RequestLocation;
|
||||
|
||||
use GuzzleHttp\Service\Guzzle\Description\Parameter;
|
||||
use GuzzleHttp\Message\RequestInterface;
|
||||
|
||||
/**
|
||||
* Request header location
|
||||
*/
|
||||
class HeaderLocation extends AbstractLocation
|
||||
{
|
||||
public function visit(
|
||||
RequestInterface $request,
|
||||
Parameter $param,
|
||||
$value,
|
||||
array $context
|
||||
) {
|
||||
$request->setHeader($param->getWireName(), $param->filter($value));
|
||||
}
|
||||
}
|
59
src/Service/Guzzle/RequestLocation/JsonLocation.php
Normal file
59
src/Service/Guzzle/RequestLocation/JsonLocation.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Service\Guzzle\RequestLocation;
|
||||
|
||||
use GuzzleHttp\Service\Guzzle\Description\Parameter;
|
||||
use GuzzleHttp\Message\RequestInterface;
|
||||
use GuzzleHttp\Stream\Stream;
|
||||
|
||||
/**
|
||||
* Creates a JSON document
|
||||
*/
|
||||
class JsonLocation extends AbstractLocation
|
||||
{
|
||||
/** @var bool Whether or not to add a Content-Type header when JSON is found */
|
||||
protected $jsonContentType;
|
||||
|
||||
/** @var \SplObjectStorage Data object for persisting JSON data */
|
||||
protected $data;
|
||||
|
||||
/**
|
||||
* @param string $contentType Content-Type header to add to the request if
|
||||
* JSON is added to the body. Pass an empty string to omit.
|
||||
*/
|
||||
public function __construct($contentType = 'application/json')
|
||||
{
|
||||
$this->jsonContentType = $contentType;
|
||||
$this->data = new \SplObjectStorage();
|
||||
}
|
||||
|
||||
public function visit(
|
||||
RequestInterface $request,
|
||||
Parameter $param,
|
||||
$value,
|
||||
array $context
|
||||
) {
|
||||
$json = isset($this->data[$context['command']])
|
||||
? $this->data[$context['command']]
|
||||
: [];
|
||||
$json[$param->getWireName()] = $this->prepareValue($value, $param);
|
||||
$this->data[$context['command']] = $json;
|
||||
}
|
||||
|
||||
public function after(
|
||||
RequestInterface $request,
|
||||
array $context
|
||||
) {
|
||||
if (!isset($this->data[$context['command']])) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't overwrite the Content-Type if one is set
|
||||
if ($this->jsonContentType && !$request->hasHeader('Content-Type')) {
|
||||
$request->setHeader('Content-Type', $this->jsonContentType);
|
||||
}
|
||||
|
||||
$request->setBody(Stream::factory(json_encode($this->data[$context['command']])));
|
||||
unset($this->data[$context['command']]);
|
||||
}
|
||||
}
|
30
src/Service/Guzzle/RequestLocation/PostFieldLocation.php
Normal file
30
src/Service/Guzzle/RequestLocation/PostFieldLocation.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Service\Guzzle\RequestLocation;
|
||||
|
||||
use GuzzleHttp\Service\Guzzle\Description\Parameter;
|
||||
use GuzzleHttp\Message\RequestInterface;
|
||||
use GuzzleHttp\Post\PostBodyInterface;
|
||||
|
||||
/**
|
||||
* Adds POST fields to a request
|
||||
*/
|
||||
class PostFieldLocation extends AbstractLocation
|
||||
{
|
||||
public function visit(
|
||||
RequestInterface $request,
|
||||
Parameter $param,
|
||||
$value,
|
||||
array $context
|
||||
) {
|
||||
$body = $request->getBody();
|
||||
if (!($body instanceof PostBodyInterface)) {
|
||||
throw new \RuntimeException('Must be a POST body interface');
|
||||
}
|
||||
|
||||
$body->setField(
|
||||
$param->getWireName(),
|
||||
$this->prepValue($value, $param)
|
||||
);
|
||||
}
|
||||
}
|
34
src/Service/Guzzle/RequestLocation/PostFileLocation.php
Normal file
34
src/Service/Guzzle/RequestLocation/PostFileLocation.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Service\Guzzle\RequestLocation;
|
||||
|
||||
use GuzzleHttp\Service\Guzzle\Description\Parameter;
|
||||
use GuzzleHttp\Message\RequestInterface;
|
||||
use GuzzleHttp\Post\PostBodyInterface;
|
||||
use GuzzleHttp\Post\PostFileInterface;
|
||||
use GuzzleHttp\Post\PostFile;
|
||||
|
||||
/**
|
||||
* Adds POST files to a request
|
||||
*/
|
||||
class PostFileLocation extends AbstractLocation
|
||||
{
|
||||
public function visit(
|
||||
RequestInterface $request,
|
||||
Parameter $param,
|
||||
$value,
|
||||
array $context
|
||||
) {
|
||||
$body = $request->getBody();
|
||||
if (!($body instanceof PostBodyInterface)) {
|
||||
throw new \RuntimeException('Must be a POST body interface');
|
||||
}
|
||||
|
||||
$value = $param->filter($value);
|
||||
if (!($value instanceof PostFileInterface)) {
|
||||
$value = new PostFile($param->getWireName(), $value);
|
||||
}
|
||||
|
||||
$body->addFile($value);
|
||||
}
|
||||
}
|
24
src/Service/Guzzle/RequestLocation/QueryLocation.php
Normal file
24
src/Service/Guzzle/RequestLocation/QueryLocation.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Service\Guzzle\RequestLocation;
|
||||
|
||||
use GuzzleHttp\Service\Guzzle\Description\Parameter;
|
||||
use GuzzleHttp\Message\RequestInterface;
|
||||
|
||||
/**
|
||||
* Adds query string values to requests
|
||||
*/
|
||||
class QueryLocation extends AbstractLocation
|
||||
{
|
||||
public function visit(
|
||||
RequestInterface $request,
|
||||
Parameter $param,
|
||||
$value,
|
||||
array $context
|
||||
) {
|
||||
$request->setHeader(
|
||||
$param->getWireName(),
|
||||
$this->prepValue($value, $param)
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Service\Guzzle\RequestLocation;
|
||||
|
||||
use GuzzleHttp\Service\Guzzle\Description\Parameter;
|
||||
use GuzzleHttp\Message\RequestInterface;
|
||||
|
||||
/**
|
||||
* Handles locations specified in a service description
|
||||
*/
|
||||
interface RequestLocationInterface
|
||||
{
|
||||
/**
|
||||
* Visits a location for each top-level parameter
|
||||
*
|
||||
* @param RequestInterface $request Request being modified
|
||||
* @param Parameter $param Parameter being visited
|
||||
* @param mixed $value Associated value
|
||||
* @param array $context Associative array containing a client
|
||||
* and command key.
|
||||
*/
|
||||
public function visit(
|
||||
RequestInterface $request,
|
||||
Parameter $param,
|
||||
$value,
|
||||
array $context
|
||||
);
|
||||
|
||||
/**
|
||||
* Called when all of the parameters of a command have been visited.
|
||||
*
|
||||
* @param RequestInterface $request Request being modified
|
||||
* @param array $context Associative array containing a client
|
||||
* and command key.
|
||||
*/
|
||||
public function after(
|
||||
RequestInterface $request,
|
||||
array $context
|
||||
);
|
||||
}
|
247
src/Service/Guzzle/RequestLocation/XmlLocation.php
Normal file
247
src/Service/Guzzle/RequestLocation/XmlLocation.php
Normal file
@ -0,0 +1,247 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Service\Guzzle\RequestLocation;
|
||||
|
||||
use GuzzleHttp\Service\Guzzle\Description\Operation;
|
||||
use GuzzleHttp\Service\Guzzle\Description\Parameter;
|
||||
use GuzzleHttp\Service\Guzzle\GuzzleCommandInterface;
|
||||
use GuzzleHttp\Message\RequestInterface;
|
||||
use GuzzleHttp\Stream\Stream;
|
||||
|
||||
/**
|
||||
* Creates an XML document
|
||||
*/
|
||||
class XmlLocation extends AbstractLocation
|
||||
{
|
||||
/** @var \SplObjectStorage Data object for persisting XML data */
|
||||
protected $data;
|
||||
|
||||
/** @var \XMLWriter XML writer resource */
|
||||
protected $writer;
|
||||
|
||||
/** @var bool Content-Type header added when XML is found */
|
||||
protected $contentType;
|
||||
|
||||
/**
|
||||
* @param string $contentType Set to a non-empty string to add a
|
||||
* Content-Type header to a request if any XML content is added to the
|
||||
* body. Pass an empty string to disable the addition of the header.
|
||||
*/
|
||||
public function __construct($contentType = 'application/xml')
|
||||
{
|
||||
$this->contentType = $contentType;
|
||||
$this->data = new \SplObjectStorage();
|
||||
}
|
||||
|
||||
public function visit(
|
||||
RequestInterface $request,
|
||||
Parameter $param,
|
||||
$value,
|
||||
array $context
|
||||
) {
|
||||
/* @var GuzzleCommandInterface $command */
|
||||
$command = $context['command'];
|
||||
$xml = isset($this->data[$command])
|
||||
? $this->data[$command]
|
||||
: $this->createRootElement($command->getOperation());
|
||||
$this->addXml($xml, $param, $value);
|
||||
$this->data[$command] = $xml;
|
||||
}
|
||||
|
||||
public function after(
|
||||
RequestInterface $request,
|
||||
array $context
|
||||
) {
|
||||
$xml = null;
|
||||
/* @var GuzzleCommandInterface $command */
|
||||
$command = $context['command'];
|
||||
|
||||
// If data was found that needs to be serialized, then do so
|
||||
if (isset($this->data[$command])) {
|
||||
$xml = $this->finishDocument($this->writer);
|
||||
unset($this->data[$command]);
|
||||
} else {
|
||||
// Check if XML should always be sent for the command
|
||||
$operation = $command->getOperation();
|
||||
if ($operation->getData('xmlAllowEmpty')) {
|
||||
$writer = $this->createRootElement($operation);
|
||||
$xml = $this->finishDocument($writer);
|
||||
}
|
||||
}
|
||||
|
||||
if ($xml) {
|
||||
$request->setBody(Stream::factory($xml));
|
||||
// Don't overwrite the Content-Type if one is set
|
||||
if ($this->contentType && !$request->hasHeader('Content-Type')) {
|
||||
$request->setHeader('Content-Type', $this->contentType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the root XML element to use with a request
|
||||
*
|
||||
* @param Operation $operation Operation object
|
||||
*
|
||||
* @return \XMLWriter
|
||||
*/
|
||||
protected function createRootElement(Operation $operation)
|
||||
{
|
||||
static $defaultRoot = array('name' => 'Request');
|
||||
// If no root element was specified, then just wrap the XML in 'Request'
|
||||
$root = $operation->getData('xmlRoot') ?: $defaultRoot;
|
||||
// Allow the XML declaration to be customized with xmlEncoding
|
||||
$encoding = $operation->getData('xmlEncoding');
|
||||
$writer = $this->startDocument($encoding);
|
||||
$writer->startElement($root['name']);
|
||||
|
||||
// Create the wrapping element with no namespaces if no namespaces were present
|
||||
if (!empty($root['namespaces'])) {
|
||||
// Create the wrapping element with an array of one or more namespaces
|
||||
foreach ((array) $root['namespaces'] as $prefix => $uri) {
|
||||
$nsLabel = 'xmlns';
|
||||
if (!is_numeric($prefix)) {
|
||||
$nsLabel .= ':'.$prefix;
|
||||
}
|
||||
$writer->writeAttribute($nsLabel, $uri);
|
||||
}
|
||||
}
|
||||
|
||||
return $writer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively build the XML body
|
||||
*
|
||||
* @param \XMLWriter $writer XML to modify
|
||||
* @param Parameter $param API Parameter
|
||||
* @param mixed $value Value to add
|
||||
*/
|
||||
protected function addXml(\XMLWriter $writer, Parameter $param, $value)
|
||||
{
|
||||
if ($value === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$value = $param->filter($value);
|
||||
$type = $param->getType();
|
||||
$name = $param->getWireName();
|
||||
$prefix = null;
|
||||
$namespace = $param->getData('xmlNamespace');
|
||||
if (false !== strpos($name, ':')) {
|
||||
list($prefix, $name) = explode(':', $name, 2);
|
||||
}
|
||||
|
||||
if ($type == 'object' || $type == 'array') {
|
||||
if (!$param->getData('xmlFlattened')) {
|
||||
$writer->startElementNS(null, $name, $namespace);
|
||||
}
|
||||
if ($param->getType() == 'array') {
|
||||
$this->addXmlArray($writer, $param, $value);
|
||||
} elseif ($param->getType() == 'object') {
|
||||
$this->addXmlObject($writer, $param, $value);
|
||||
}
|
||||
if (!$param->getData('xmlFlattened')) {
|
||||
$writer->endElement();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if ($param->getData('xmlAttribute')) {
|
||||
$this->writeAttribute($writer, $prefix, $name, $namespace, $value);
|
||||
} else {
|
||||
$this->writeElement($writer, $prefix, $name, $namespace, $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an attribute with namespace if used
|
||||
*
|
||||
* @param \XMLWriter $writer XMLWriter instance
|
||||
* @param string $prefix Namespace prefix if any
|
||||
* @param string $name Attribute name
|
||||
* @param string $namespace The uri of the namespace
|
||||
* @param string $value The attribute content
|
||||
*/
|
||||
protected function writeAttribute($writer, $prefix, $name, $namespace, $value)
|
||||
{
|
||||
if (empty($namespace)) {
|
||||
$writer->writeAttribute($name, $value);
|
||||
} else {
|
||||
$writer->writeAttributeNS($prefix, $name, $namespace, $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an element with namespace if used
|
||||
*
|
||||
* @param \XMLWriter $writer XML writer resource
|
||||
* @param string $prefix Namespace prefix if any
|
||||
* @param string $name Element name
|
||||
* @param string $namespace The uri of the namespace
|
||||
* @param string $value The element content
|
||||
*/
|
||||
protected function writeElement(\XMLWriter $writer, $prefix, $name, $namespace, $value)
|
||||
{
|
||||
$writer->startElementNS($prefix, $name, $namespace);
|
||||
if (strpbrk($value, '<>&')) {
|
||||
$writer->writeCData($value);
|
||||
} else {
|
||||
$writer->writeRaw($value);
|
||||
}
|
||||
$writer->endElement();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new xml writer and start a document
|
||||
*
|
||||
* @param string $encoding document encoding
|
||||
*
|
||||
* @return \XMLWriter the writer resource
|
||||
*/
|
||||
protected function startDocument($encoding)
|
||||
{
|
||||
$this->writer = new \XMLWriter();
|
||||
$this->writer->openMemory();
|
||||
$this->writer->startDocument('1.0', $encoding);
|
||||
|
||||
return $this->writer;
|
||||
}
|
||||
|
||||
/**
|
||||
* End the document and return the output
|
||||
*
|
||||
* @param \XMLWriter $writer
|
||||
*
|
||||
* @return \string the writer resource
|
||||
*/
|
||||
protected function finishDocument($writer)
|
||||
{
|
||||
$writer->endDocument();
|
||||
|
||||
return $writer->outputMemory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an array to the XML
|
||||
*/
|
||||
protected function addXmlArray(\XMLWriter $writer, Parameter $param, &$value)
|
||||
{
|
||||
if ($items = $param->getItems()) {
|
||||
foreach ($value as $v) {
|
||||
$this->addXml($writer, $items, $v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an object to the XML
|
||||
*/
|
||||
protected function addXmlObject(\XMLWriter $writer, Parameter $param, &$value)
|
||||
{
|
||||
foreach ($value as $name => $v) {
|
||||
if ($property = $param->getProperty($name)) {
|
||||
$this->addXml($writer, $property, $v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -3,15 +3,19 @@
|
||||
namespace GuzzleHttp\Service\Guzzle\Subscriber;
|
||||
|
||||
use GuzzleHttp\Event\SubscriberInterface;
|
||||
use GuzzleHttp\Message\RequestInterface as Request;
|
||||
use GuzzleHttp\Post\PostBodyInterface;
|
||||
use GuzzleHttp\Post\PostFile;
|
||||
use GuzzleHttp\Post\PostFileInterface;
|
||||
use GuzzleHttp\Stream\Stream;
|
||||
use GuzzleHttp\Message\RequestInterface;
|
||||
use GuzzleHttp\Service\Guzzle\GuzzleClientInterface;
|
||||
use GuzzleHttp\Service\Guzzle\GuzzleCommandInterface;
|
||||
use GuzzleHttp\Service\Guzzle\RequestLocation\BodyLocation;
|
||||
use GuzzleHttp\Service\Guzzle\RequestLocation\HeaderLocation;
|
||||
use GuzzleHttp\Service\Guzzle\RequestLocation\JsonLocation;
|
||||
use GuzzleHttp\Service\Guzzle\RequestLocation\PostFieldLocation;
|
||||
use GuzzleHttp\Service\Guzzle\RequestLocation\PostFileLocation;
|
||||
use GuzzleHttp\Service\Guzzle\RequestLocation\QueryLocation;
|
||||
use GuzzleHttp\Service\Guzzle\RequestLocation\XmlLocation;
|
||||
use GuzzleHttp\Service\PrepareEvent;
|
||||
use GuzzleHttp\Service\Guzzle\Description\Parameter;
|
||||
use GuzzleHttp\Service\Guzzle\RequestLocation\RequestLocationInterface;
|
||||
|
||||
/**
|
||||
* Subscriber used to create HTTP requests for commands based on a service
|
||||
@ -19,11 +23,35 @@ use GuzzleHttp\Service\Guzzle\Description\Parameter;
|
||||
*/
|
||||
class PrepareRequest implements SubscriberInterface
|
||||
{
|
||||
/** @var RequestLocationInterface[] */
|
||||
private $requestLocations;
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return ['prepare' => ['onPrepare']];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param RequestLocationInterface[] $requestLocations Extra request locations
|
||||
*/
|
||||
public function __construct(array $requestLocations = [])
|
||||
{
|
||||
static $defaultRequestLocations;
|
||||
if (!$defaultRequestLocations) {
|
||||
$defaultRequestLocations = [
|
||||
'body' => new BodyLocation(),
|
||||
'query' => new QueryLocation(),
|
||||
'header' => new HeaderLocation(),
|
||||
'json' => new JsonLocation(),
|
||||
'xml' => new XmlLocation(),
|
||||
'postField' => new PostFieldLocation(),
|
||||
'postFile' => new PostFileLocation()
|
||||
];
|
||||
}
|
||||
|
||||
$this->requestLocations = $requestLocations + $defaultRequestLocations;
|
||||
}
|
||||
|
||||
public function onPrepare(PrepareEvent $event)
|
||||
{
|
||||
/* @var GuzzleCommandInterface $command */
|
||||
@ -35,13 +63,52 @@ class PrepareRequest implements SubscriberInterface
|
||||
$event->setRequest($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a request for sending using location visitors
|
||||
*
|
||||
* @param GuzzleCommandInterface $command Command to prepare
|
||||
* @param GuzzleClientInterface $client Client that owns the command
|
||||
* @param RequestInterface $request Request being created
|
||||
* @throws \RuntimeException If a location cannot be handled
|
||||
*/
|
||||
protected function prepareRequest(
|
||||
GuzzleCommandInterface $command,
|
||||
GuzzleClientInterface $client,
|
||||
RequestInterface $request
|
||||
) {
|
||||
$visitedLocations = [];
|
||||
$context = ['client' => $client, 'command' => $command];
|
||||
foreach ($command->getOperation()->getParams() as $name => $param) {
|
||||
/* @var Parameter $param */
|
||||
$location = $param->getLocation();
|
||||
// Skip parameters that have not been set or are URI location
|
||||
if ($location == 'uri' || !$command->hasParam($name)) {
|
||||
continue;
|
||||
}
|
||||
if (!isset($this->requestLocations[$location])) {
|
||||
throw new \RuntimeException("No location registered for $location");
|
||||
}
|
||||
$visitedLocations[$location] = true;
|
||||
$this->requestLocations[$location]->visit(
|
||||
$request,
|
||||
$param,
|
||||
$command[$name],
|
||||
$context
|
||||
);
|
||||
}
|
||||
|
||||
foreach (array_keys($visitedLocations) as $location) {
|
||||
$this->requestLocations[$location]->after($request, $context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a request for the command and operation
|
||||
*
|
||||
* @param GuzzleCommandInterface $command Command being executed
|
||||
* @param GuzzleClientInterface $client Client used to execute the command
|
||||
*
|
||||
* @return Request
|
||||
* @return RequestInterface
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function createRequest(
|
||||
@ -91,135 +158,4 @@ class PrepareRequest implements SubscriberInterface
|
||||
$command['request_options'] ?: []
|
||||
);
|
||||
}
|
||||
|
||||
protected function prepareRequest(
|
||||
GuzzleCommandInterface $command,
|
||||
GuzzleClientInterface $client,
|
||||
Request $request
|
||||
) {
|
||||
static $methods;
|
||||
if (!$methods) {
|
||||
$methods = array_flip(get_class_methods(__CLASS__));
|
||||
}
|
||||
|
||||
$context = ['command' => $command, 'client' => $client];
|
||||
foreach ($command->getOperation()->getParams() as $name => $value) {
|
||||
/* @var Parameter $value */
|
||||
// Skip parameters that have not been set or are URI location
|
||||
if (!$command->hasParam($name) || $value->getLocation() == 'uri') {
|
||||
continue;
|
||||
}
|
||||
$method = 'visit_' . $value->getLocation();
|
||||
if (isset($methods[$method])) {
|
||||
$this->{$method}($request, $value, $command[$name], $context);
|
||||
} else {
|
||||
// @todo: Handle more complicated or custom locations somehow
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a header to the request.
|
||||
*/
|
||||
protected function visit_header(Request $request, Parameter $param, $value)
|
||||
{
|
||||
$request->setHeader($param->getWireName(), $param->filter($value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a query string value to the request.
|
||||
*/
|
||||
protected function visit_query(Request $request, Parameter $param, $value)
|
||||
{
|
||||
$request->setHeader($param->getWireName(), $this->prepValue($value, $param));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a body to the request.
|
||||
*/
|
||||
protected function visit_body(Request $request, Parameter $param, $value)
|
||||
{
|
||||
$request->setBody(Stream::factory($param->filter($value)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a POST field to the request.
|
||||
*/
|
||||
protected function visit_postField(Request $request, Parameter $param, $value)
|
||||
{
|
||||
$body = $request->getBody();
|
||||
if (!($body instanceof PostBodyInterface)) {
|
||||
throw new \RuntimeException('Must be a POST body interface');
|
||||
}
|
||||
|
||||
$body->setField($param->getWireName(), $this->prepValue($value, $param));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a POST file to the request.
|
||||
*/
|
||||
protected function visit_postFile(Request $request, Parameter $param, $value)
|
||||
{
|
||||
$body = $request->getBody();
|
||||
if (!($body instanceof PostBodyInterface)) {
|
||||
throw new \RuntimeException('Must be a POST body interface');
|
||||
}
|
||||
|
||||
$value = $param->filter($value);
|
||||
if (!($value instanceof PostFileInterface)) {
|
||||
$value = new PostFile($param->getWireName(), $value);
|
||||
}
|
||||
|
||||
$body->addFile($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare (filter and set desired name for request item) the value for
|
||||
* request.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param Parameter $param
|
||||
*
|
||||
* @return array|mixed
|
||||
*/
|
||||
protected function prepValue($value, Parameter $param)
|
||||
{
|
||||
return is_array($value)
|
||||
? $this->resolveRecursively($value, $param)
|
||||
: $param->filter($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively prepare and filter nested values.
|
||||
*
|
||||
* @param array $value Value to map
|
||||
* @param Parameter $param Parameter related to the current key.
|
||||
*
|
||||
* @return array Returns the mapped array
|
||||
*/
|
||||
protected function resolveRecursively(array $value, Parameter $param)
|
||||
{
|
||||
foreach ($value as $name => &$v) {
|
||||
switch ($param->getType()) {
|
||||
case 'object':
|
||||
if ($subParam = $param->getProperty($name)) {
|
||||
$key = $subParam->getWireName();
|
||||
$value[$key] = $this->prepValue($v, $subParam);
|
||||
if ($name != $key) {
|
||||
unset($value[$name]);
|
||||
}
|
||||
} elseif ($param->getAdditionalProperties() instanceof Parameter) {
|
||||
$v = $this->prepValue($v, $param->getAdditionalProperties());
|
||||
}
|
||||
break;
|
||||
case 'array':
|
||||
if ($items = $param->getItems()) {
|
||||
$v = $this->prepValue($v, $items);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $param->filter($value);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user