- Added some more features to attributes and various Curl wrappers

This commit is contained in:
Dave M. 2026-07-01 13:24:04 -04:00
parent b1adf5a086
commit fe56a1727b
9 changed files with 142 additions and 15 deletions

View File

@ -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:

View File

@ -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;
}

View File

@ -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
{

View File

@ -0,0 +1,23 @@
<?php
namespace Ulmus\Api\Common;
use Psr\Http\Message\MessageInterface;
use Ulmus\Api\Stream\JsonStream;
use Ulmus\Api\Stream\XmlStream;
# @TODO !
trait XmlMessageTrait
{
public function getParsedBody() : null|array|object
{
return XmlStream::fromXmlEncoded( $this->getBody()->getContents() )->decode() ;
}
public function withParsedBody(mixed $data) : static
{
return (clone $this)->setBody(
XmlStream::fromContent($data)
);
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace Ulmus\Api\Response;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
use Ulmus\Api\Common\XmlMessageTrait;
use Ulmus\Api\Stream\XmlStream;
use Ulmus\Api\Common\StreamOutputInterface;
class XmlResponse extends Response implements StreamOutputInterface
{
use XmlMessageTrait;
public function __construct(null|StreamInterface $stream = null, int $statusCode = 200, array $headers = [])
{
parent::__construct($stream, $statusCode, $headers + [ 'Content-Type' => "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));
}
}

49
src/Stream/XmlStream.php Normal file
View File

@ -0,0 +1,49 @@
<?php
namespace Ulmus\Api\Stream;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
use Ulmus\Api\Common\HttpHeaderEnum;
use Ulmus\Api\Stream\Stream;
use Ulmus\Api\Common\StreamOutputInterface;
# @TODO
class XmlStream extends Stream
{
public function __construct()
{
}
public static function fromContent(mixed $content) : StreamInterface
{
#if ( false === $json = json_encode($content) ) {
# throw new \InvalidArgumentException(sprintf('Json encoding failed with message `%s`.', json_last_error_msg()));
# }
# @TODO !
#return static::fromJsonEncoded($json);
return static::fromXmlEncoded($content);
}
public static function fromXmlEncoded(string $xml) : StreamInterface
{
$obj = static::fromTemp($xml);
$obj->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);
}
}

View File

@ -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)));

View File

@ -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;