Skip to content

Commit

Permalink
Use own Guzzle Serializer to workaround wrong encoded URL
Browse files Browse the repository at this point in the history
  • Loading branch information
szeidler committed Apr 14, 2022
1 parent b836900 commit 1a7dced
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 3 deletions.
2 changes: 1 addition & 1 deletion service.json
Original file line number Diff line number Diff line change
Expand Up @@ -175,4 +175,4 @@
"extends": "BaseResponse"
}
}
}
}
6 changes: 4 additions & 2 deletions src/FotowebClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Fotoweb\Middleware\TokenMiddleware;
use Fotoweb\OAuth2\GrantType\AuthorizationCodeWithPkce;
use Fotoweb\Response\FotowebResult;
use Fotoweb\Serializer\GuzzleSerializer;
use GuzzleHttp\Client;
use GuzzleHttp\Command\CommandInterface;
use GuzzleHttp\Command\Guzzle\Description;
Expand Down Expand Up @@ -43,10 +44,11 @@ class FotowebClient extends GuzzleClient
*/
public function __construct(array $config = [])
{
$description = $this->getServiceDescriptionFromConfig($config);
parent::__construct(
$this->getClientFromConfig($config),
$this->getServiceDescriptionFromConfig($config),
null,
$description,
new GuzzleSerializer($description),
$this->responseToResultTransformer(),
null,
$config
Expand Down
170 changes: 170 additions & 0 deletions src/Serializer/GuzzleSerializer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
<?php
namespace Fotoweb\Serializer;

use GuzzleHttp\Command\CommandInterface;
use GuzzleHttp\Command\Guzzle\DescriptionInterface;
use GuzzleHttp\Command\Guzzle\Operation;
use GuzzleHttp\Command\Guzzle\Parameter;
use GuzzleHttp\Command\Guzzle\RequestLocation\BodyLocation;
use GuzzleHttp\Command\Guzzle\RequestLocation\FormParamLocation;
use GuzzleHttp\Command\Guzzle\RequestLocation\HeaderLocation;
use GuzzleHttp\Command\Guzzle\RequestLocation\JsonLocation;
use GuzzleHttp\Command\Guzzle\RequestLocation\MultiPartLocation;
use GuzzleHttp\Command\Guzzle\RequestLocation\QueryLocation;
use GuzzleHttp\Command\Guzzle\RequestLocation\RequestLocationInterface;
use GuzzleHttp\Command\Guzzle\RequestLocation\XmlLocation;
use GuzzleHttp\Command\Guzzle\Serializer;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Uri;
use Psr\Http\Message\RequestInterface;

/**
* Serializes requests for a given command.
*/
class GuzzleSerializer
{
/** @var RequestLocationInterface[] */
private $locations;

/** @var DescriptionInterface */
private $description;

/**
* @param DescriptionInterface $description
* @param RequestLocationInterface[] $requestLocations Extra request locations
*/
public function __construct(
DescriptionInterface $description,
array $requestLocations = []
) {
static $defaultRequestLocations;
if (!$defaultRequestLocations) {
$defaultRequestLocations = [
'body' => new BodyLocation(),
'query' => new QueryLocation(),
'header' => new HeaderLocation(),
'json' => new JsonLocation(),
'xml' => new XmlLocation(),
'formParam' => new FormParamLocation(),
'multipart' => new MultiPartLocation(),
];
}

$this->locations = $requestLocations + $defaultRequestLocations;
$this->description = $description;
}

/**
* @param CommandInterface $command
* @return RequestInterface
*/
public function __invoke(CommandInterface $command)
{
$request = $this->createRequest($command);
return $this->prepareRequest($command, $request);
}

/**
* Prepares a request for sending using location visitors
*
* @param CommandInterface $command
* @param RequestInterface $request Request being created
* @return RequestInterface
* @throws \RuntimeException If a location cannot be handled
*/
protected function prepareRequest(
CommandInterface $command,
RequestInterface $request
) {
$visitedLocations = [];
$operation = $this->description->getOperation($command->getName());

// Visit each actual parameter
foreach ($operation->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->locations[$location])) {
throw new \RuntimeException("No location registered for $name");
}
$visitedLocations[$location] = true;
$request = $this->locations[$location]->visit($command, $request, $param);
}

// Ensure that the after() method is invoked for additionalParameters
/** @var Parameter $additional */
if ($additional = $operation->getAdditionalParameters()) {
$visitedLocations[$additional->getLocation()] = true;
}

// Call the after() method for each visited location
foreach (array_keys($visitedLocations) as $location) {
$request = $this->locations[$location]->after($command, $request, $operation);
}

return $request;
}

/**
* Create a request for the command and operation
*
* @param CommandInterface $command
*
* @return RequestInterface
* @throws \RuntimeException
*/
protected function createRequest(CommandInterface $command)
{
$operation = $this->description->getOperation($command->getName());

// If command does not specify a template, assume the client's base URL.
if (null === $operation->getUri()) {
return new Request(
$operation->getHttpMethod(),
$this->description->getBaseUri()
);
}

return $this->createCommandWithUri($operation, $command);
}

/**
* Create a request for an operation with a uri merged onto a base URI
*
* @param \GuzzleHttp\Command\Guzzle\Operation $operation
* @param \GuzzleHttp\Command\CommandInterface $command
*
* @return \GuzzleHttp\Psr7\Request
*/
private function createCommandWithUri(
Operation $operation,
CommandInterface $command
) {
// Get the path values and use the client config settings
$variables = [];
foreach ($operation->getParams() as $name => $arg) {
/* @var Parameter $arg */
if ($arg->getLocation() == 'uri') {
if (isset($command[$name])) {
$variables[$name] = $arg->filter($command[$name]);
if (!is_array($variables[$name])) {
$variables[$name] = (string) $variables[$name];
}
}
}
}

$uri = $operation->getUri();
foreach ($variables as $key => $value) {
$uri = str_replace('{' . $key . '}', $value, $uri);
}

return new Request(
$operation->getHttpMethod(),
Uri::resolve($this->description->getBaseUri(), $uri)
);
}
}

0 comments on commit 1a7dced

Please sign in to comment.