diff --git a/src/Adapter/Rest.php b/src/Adapter/Rest.php index c166ed9..f04b949 100644 --- a/src/Adapter/Rest.php +++ b/src/Adapter/Rest.php @@ -50,7 +50,7 @@ class Rest implements AdapterInterface return "https"; } - public function writableValue(mixed $value) : mixed + public function writableValue(mixed $value) : mixed { switch (true) { case $value instanceof \UnitEnum: diff --git a/src/ApiRepository.php b/src/ApiRepository.php index b6fb183..84a2b3e 100644 --- a/src/ApiRepository.php +++ b/src/ApiRepository.php @@ -40,9 +40,7 @@ class ApiRepository extends \Ulmus\Repository public function loadOneFromAttribute(string $attributeClass): ? object { - $response = $this->executeRequest($attributeClass); - - return $this->instanciateEntity()->fromArray($response->getParsedBody()); + return $this->instanciateEntity(null, $this->executeRequest($attributeClass)->getParsedBody()); } public function loadAll() : EntityCollection @@ -96,6 +94,10 @@ class ApiRepository extends \Ulmus\Repository throw new \RuntimeException(sprintf("Could not find attribute class '%s' for class '%s'", $attributeClass, $this->entityClass)); } + if (method_exists($this->adapter->apiHandler, 'executingRequest')) { + $this->adapter->apiHandler->executingRequest($this, $attribute); + } + $request = $this->prepareRequest($this->buildRequestUrl($attribute->url), $attribute->method, $data, $this->adapter->adapter()->getHeaders(), $this->adapter->adapter()->getParameters()); $request = $this->compileRequestParameters($request, $attribute); @@ -170,7 +172,8 @@ class ApiRepository extends \Ulmus\Repository $request = new JsonRequest($uri, $method, $body === null ? Stream::fromTemp() : JsonStream::fromContent($body), $headers); # Adding parameters - $request = $request->withQueryParams($queryParameters); + $request = $request->withQueryParams($queryParameters) + ->withAttribute('repository', $this); return $request; } diff --git a/src/Common/ContentTypeEnum.php b/src/Common/ContentTypeEnum.php index 52d8934..e84bd99 100644 --- a/src/Common/ContentTypeEnum.php +++ b/src/Common/ContentTypeEnum.php @@ -5,8 +5,10 @@ namespace Ulmus\Api\Common; enum ContentTypeEnum : string { case Json = "application/json"; - case Multipart = "multipart/form-data"; + case Xml = "application/xml"; + case RssXml = "application/rss+xml"; case UrlEncoded = "application/x-www-form-urlencoded"; + case Multipart = "multipart/form-data"; public function defaultBody() : string { diff --git a/src/Common/XmlMessageTrait.php b/src/Common/XmlMessageTrait.php new file mode 100644 index 0000000..deb741a --- /dev/null +++ b/src/Common/XmlMessageTrait.php @@ -0,0 +1,23 @@ +getBody()->getContents() )->decode() ; + } + + public function withParsedBody(mixed $data) : static + { + return (clone $this)->setBody( + XmlStream::fromContent($data) + ); + } +} \ No newline at end of file diff --git a/src/Request/Request.php b/src/Request/Request.php index de1e99c..ee7369d 100644 --- a/src/Request/Request.php +++ b/src/Request/Request.php @@ -22,6 +22,8 @@ class Request extends Message implements ServerRequestInterface protected array $files = []; + protected array $attributes = []; + public function __construct(string|UriInterface $uri, MethodEnum $method, null|StreamInterface $stream = null, array $headers = []) { $this->method = $method; @@ -197,21 +199,25 @@ class Request extends Message implements ServerRequestInterface public function getAttributes() : array { - // TODO: Implement getAttributes() method. + return $this->attributes; } public function getAttribute($name, $default = null) : mixed { - // TODO: Implement getAttribute() method. + return array_key_exists($name, $this->attributes) ? $this->attributes[$name] : $default; } public function withAttribute($name, $value) : static { - // TODO: Implement withAttribute() method. + $this->attributes[$name] = $value; + + return $this; } public function withoutAttribute($name): static { - // TODO: Implement withoutAttribute() method. + unset($this->attributes[$name]); + + return $this; } } diff --git a/src/Response/XmlResponse.php b/src/Response/XmlResponse.php new file mode 100644 index 0000000..e8947d1 --- /dev/null +++ b/src/Response/XmlResponse.php @@ -0,0 +1,29 @@ + "application/xml" ]); + } + + public static function fromResponse(ResponseInterface $response) : static + { + return new static($response->getBody(), $response->getStatusCode(), $response->getHeaders()); + } + + public static function createFrom(mixed $content) : ResponseInterface + { + return new static(XmlStream::fromContent($content)); + } +} \ No newline at end of file diff --git a/src/Stream/XmlStream.php b/src/Stream/XmlStream.php new file mode 100644 index 0000000..26f2183 --- /dev/null +++ b/src/Stream/XmlStream.php @@ -0,0 +1,49 @@ +rewind(); + + return $obj; + } + + public function decode(): mixed + { + $content = $this->getContents(); + + if ($content === "") { + return null; + } + + return json_decode(json_encode((array) \simplexml_load_string($content)), true); + } +} \ No newline at end of file diff --git a/src/Transport/CurlAuthorization.php b/src/Transport/CurlAuthorization.php index 258d85a..6611762 100644 --- a/src/Transport/CurlAuthorization.php +++ b/src/Transport/CurlAuthorization.php @@ -18,6 +18,10 @@ class CurlAuthorization public function fromAuthenticationEnum(AuthenticationEnum $auth,) : static { switch($auth) { + case AuthenticationEnum::Custom: + $this->customHeader($this->configuration['header'], $this->configuration['secret']); + break; + case AuthenticationEnum::Bearer: $this->bearer($this->configuration['token']); break; @@ -96,6 +100,11 @@ class CurlAuthorization $this->userpass(CURLAUTH_NEGOTIATE, $username, $password); } + public function customHeader(string $header, #[\SensitiveParameter] string $token) : void + { + $this->headers[$header] = $token; + } + public function oauth2(Oauth2GrantTypeEnum $grant, string $oauthTokenUrl, string $redirectUri, string $clientId, string $clientSecret, string $scope) : void { $unid = sprintf("oauth_token_%s", md5(serialize($this->configuration))); diff --git a/src/Transport/CurlTransport.php b/src/Transport/CurlTransport.php index f8c6dcc..e31691b 100644 --- a/src/Transport/CurlTransport.php +++ b/src/Transport/CurlTransport.php @@ -6,7 +6,7 @@ use Ulmus\Api\Common\{ ContentTypeEnum, MethodEnum, HttpHeaderEnum }; use Ulmus\Api\Stream\JsonStream; use Ulmus\Api\Stream\Stream; use Psr\Http\Message\{RequestInterface, ResponseInterface, StreamInterface}; -use Ulmus\Api\Response\{ Response, JsonResponse }; +use Ulmus\Api\Response\{Response, JsonResponse, XmlResponse}; abstract class CurlTransport { @@ -37,9 +37,9 @@ abstract class CurlTransport { return $this->request(MethodEnum::Post, $url, $data, $headers, $curlOptions); } - public function get(string $url, mixed $data, array $headers = [], array $curlOptions = []) : mixed + public function get(string $url, array $headers = [], array $curlOptions = []) : mixed { - return $this->request(MethodEnum::Get, $url, $data, $headers, $curlOptions); + return $this->request(MethodEnum::Get, $url, null, $headers, $curlOptions); } public function delete(string $url, mixed $data, array $headers = [], array $curlOptions = []) : mixed @@ -130,8 +130,14 @@ abstract class CurlTransport { $response = $response->withBody( Stream::fromMemory($result) ); - if ( $response->hasHeader('Content-Type') && false !== strpos($response->getHeader('Content-Type')[0], 'json') ) { - $response = JsonResponse::fromResponse($response); + if ($response->hasHeader('Content-Type') ) { + list($mime) = explode(';', $response->getHeader('Content-Type')[0]); + + return match(ContentTypeEnum::tryFrom($mime)) { + ContentTypeEnum::Json => JsonResponse::fromResponse($response), + ContentTypeEnum::RssXml, ContentTypeEnum::Xml => XmlResponse::fromResponse($response), + default => $response, + }; } return $response;