diff --git a/src/Adapter/Rest.php b/src/Adapter/Rest.php index 19d723d..2818a37 100644 --- a/src/Adapter/Rest.php +++ b/src/Adapter/Rest.php @@ -22,6 +22,8 @@ class Rest implements AdapterInterface protected array $options = []; + protected array $parameters = []; + public readonly string $url; public function setup(array $configuration): void @@ -29,15 +31,18 @@ class Rest implements AdapterInterface $this->url = rtrim($configuration['url'], '/'); $this->authorizationMethod = AuthenticationEnum::from($configuration['auth'] ?: AuthenticationEnum::Basic->value); - $this->authorization = ( new CurlAuthorization() )->fromAuthenticationEnum($this->authorizationMethod, $configuration); + $this->authorization = new CurlAuthorization($configuration); $this->headers = $configuration['headers'] ?? []; $this->options = $configuration['options'] ?? []; + $this->parameters = $configuration['parameters'] ?? []; } public function connect(): object { - return new CurlClient($this->headers, $this->options, $this->authorization); + $this->authorization = $this->authorization->fromAuthenticationEnum($this->authorizationMethod); + + return new CurlClient([], $this->options, $this->authorization); } public function buildDataSourceName(): string @@ -73,4 +78,19 @@ class Rest implements AdapterInterface { return RequestBuilder::class; } + + public function getCurlOptions() : array + { + return $this->options; + } + + public function getHeaders() : array + { + return $this->headers; + } + + public function getParameters() : array + { + return $this->parameters; + } } diff --git a/src/ApiRepository.php b/src/ApiRepository.php index 9a6133d..09abb17 100644 --- a/src/ApiRepository.php +++ b/src/ApiRepository.php @@ -4,10 +4,14 @@ namespace Ulmus\Api; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\StreamInterface; use Psr\Http\Message\UriInterface; use Ulmus\Api\Attribute\Obj\Api\ApiAction; use Ulmus\Api\Common\MethodEnum; +use Ulmus\Api\RequestBuilder\Filter; +use Ulmus\Api\RequestBuilder\UrlParameter; +use Ulmus\Api\SearchRequest\ApiSearchRequest; use Ulmus\Api\Stream\JsonStream; use Ulmus\Api\Stream\Stream; use Ulmus\Api\Request\JsonRequest; @@ -16,6 +20,7 @@ use Ulmus\Api\Transport\CurlClient; use Ulmus\Api\Transport\CurlTransport; use Ulmus\EntityCollection; use Ulmus\SearchRequest\SearchRequestInterface; +use Ulmus\Ulmus; class ApiRepository extends \Ulmus\Repository { @@ -23,8 +28,6 @@ class ApiRepository extends \Ulmus\Repository public CurlClient $client; - protected array $urlParameters = []; - public ResponseInterface $lastResponse; public function __construct(string $entity, string $alias = self::DEFAULT_ALIAS, ConnectionAdapter $adapter = null) @@ -34,18 +37,33 @@ class ApiRepository extends \Ulmus\Repository public function loadOne(): ? object { - $response = $this->executeRequest(Attribute\Obj\Api\Read::class); + return $this->loadOneFromAttribute(Attribute\Obj\Api\Read::class); + } + + public function loadOneFromAttribute(string $attributeClass): ? object + { + $response = $this->executeRequest($attributeClass); return $this->instanciateEntity()->fromArray($response->getParsedBody()); } public function loadAll() : EntityCollection { - $response = $this->executeRequest(Attribute\Obj\Api\Collection::class); + return $this->loadAllFromAttribute(Attribute\Obj\Api\Collection::class); + } + + public function loadAllFromAttribute(string $attributeClass) : EntityCollection + { + $response = $this->executeRequest($attributeClass); return $this->instanciateEntityCollection()->fromArray($response->getParsedBody()); } + public function search() : EntityCollection + { + return $this->loadAllFromAttribute(Attribute\Obj\Api\Search::class); + } + public function save(object|array $entity, ?array $fieldsAndValue = null, bool $replace = false): bool { $response = $this->executeRequest(Attribute\Obj\Api\Create::class, $entity->entityGetDataset()); @@ -63,38 +81,35 @@ class ApiRepository extends \Ulmus\Repository throw new \RuntimeException(sprintf("Could not find attribute class '%s' for class '%s'", $attributeClass, $this->entityClass)); } - $request = $this->prepareRequest($this->buildRequestUrl($attribute->url), $attribute->method, $data); + $request = $this->prepareRequest($this->buildRequestUrl($attribute->url), $attribute->method, $data, $this->adapter->adapter()->getHeaders(), $this->adapter->adapter()->getParameters()); - # @TODO !! SET HEADERS FROM CONFIG IN REQUEST HERE INSTEAD OF DIRECTLY IN TRANSPORT ! - # $request->withAddedHeader() + $request = $this->compileRequestParameters($request, $attribute); - $request = $this->callApiRequestCallback($request, $attribute); + $this->callApiRequestCallback($request, $attribute); - $transport = $this->adapter->adapter()->connect(); - - $transport->timeout = $attribute->timeout; - - $this->lastResponse = $response = $transport->fromRequest($request); + $response = $this->launchRequest($request, $attribute); $response = $this->callApiResponseCallback($response, $attribute); - $this->callApiDebugCallback($transport); - return $response; } - public function bindUrl(string $parameter, mixed $value) : self + protected function buildRequestUrl(string $uri) : string { - $this->urlParameters[$parameter] = $value; - - return $this; + return $this->adapter->adapter()->url . '/' . ltrim($uri, '/'); } - protected function buildRequestUrl(string $uri) :string + protected function launchRequest(RequestInterface $request, object $attribute) : ResponseInterface { - $uri = $this->prepareUri($uri, $this->urlParameters); + $transport = $this->adapter->adapter()->connect(); - return $this->adapter->adapter()->url . '/' . ltrim($uri, '/'); + $transport->timeout = $attribute->timeout; + + $this->lastResponse = $transport->fromRequest($request); + + $this->callApiDebugCallback($transport); + + return $this->lastResponse; } protected function prepareUri(string $route, array $arguments) : string @@ -135,9 +150,46 @@ class ApiRepository extends \Ulmus\Repository return $route; } - protected function prepareRequest(string|UriInterface $uri, MethodEnum $method, mixed $body = null, array $headers = []) : RequestInterface + protected function prepareRequest(string|UriInterface $uri, MethodEnum $method, mixed $body = null, array $headers = [], array $queryParameters = []) : ServerRequestInterface { - return new JsonRequest($uri, $method, $body === null ? Stream::fromTemp() : JsonStream::fromContent($body), $headers); + $request = new JsonRequest($uri, $method, $body === null ? Stream::fromTemp() : JsonStream::fromContent($body), $headers); + + # Adding parameters + $request = $request->withQueryParams($queryParameters); + + return $request; + } + + protected function compileRequestParameters(ServerRequestInterface $request, object $attribute) : ServerRequestInterface + { + $requestOptions = $this->queryBuilder->render(); + + $request = $this->applyFiltering($request, $attribute, $requestOptions[Filter::KEY] ?? []); + + $request = $this->applyUrlBinding($request, $attribute, $requestOptions[UrlParameter::KEY] ?? []); + + return $request; + } + + protected function applyUrlBinding(ServerRequestInterface $request, object $attribute, array $bindings) : ServerRequestInterface + { + $uriObj = $request->getUri(); + + $uri = $this->prepareUri($request->getUri()->render(), $bindings); + + return $request->withUri($uriObj->from($uri)); + } + + protected function applyFiltering(ServerRequestInterface $request, object $attribute, array $filters) : ServerRequestInterface + { + if ($attribute->searchMethod === MethodEnum::Get) { + $request = $request->withQueryParams($filters); + } + elseif ($attribute->searchMethod === MethodEnum::POST) { + $request = $request->withParsedBody($filters); + } + + return $request; } public function getApiAttribute(string $type) : ? object @@ -145,7 +197,7 @@ class ApiRepository extends \Ulmus\Repository return $this->entityClass::resolveEntity()->getAttributeImplementing($type); } - protected function callApiRequestCallback(RequestInterface $request, ApiAction $attribute) : RequestInterface + protected function callApiRequestCallback(RequestInterface $request, ApiAction $attribute) : ServerRequestInterface { return $this->adapter->apiHandler->handleRequest($request, $attribute); } @@ -160,19 +212,53 @@ class ApiRepository extends \Ulmus\Repository $this->adapter->apiHandler->debugResponse($transport, $this); } - public function filterServerRequest(SearchRequestInterface $searchRequest, bool $count = true) : self + public function collectionFromQuery(? string $entityClass = null) : EntityCollection { - return $searchRequest->filter($this) - ->wheres($searchRequest->wheres(), \Ulmus\Query\Where::OPERATOR_EQUAL, \Ulmus\Query\Where::CONDITION_AND) - ->likes($searchRequest->likes(), \Ulmus\Query\Where::CONDITION_OR) - ->orders($searchRequest->orders()) - ->groups($searchRequest->groups()) - ->offset($searchRequest->offset()) - ->limit($searchRequest->limit()); + $entityClass ??= $this->entityClass; + + $entityCollection = $entityClass::entityCollection(); + + $this->finalizeQuery(); + + foreach(Ulmus::iterateQueryBuilder($this->queryBuilder, $this->adapter) as $entityData) { + $entity = $this->instanciateEntity($entityClass); + $entity->loadedFromAdapter = $this->adapter->name; + + $entityCollection->append( $entity->resetVirtualProperties()->entityFillFromDataset($entityData) ); + } + + $this->eventExecute(\Ulmus\Event\Repository\CollectionFromQueryInterface::class, $entityCollection); + + return $entityCollection; + } + + public function filterServerRequest(SearchRequestInterface $searchRequest, bool $count = true) : \Ulmus\Repository + { + if ($searchRequest instanceof ApiSearchRequest) { + $this->bindings($searchRequest->bindings()); + } + + return parent::filterServerRequest($searchRequest, false); } public function count(): int { return 0; } + + public function bindUrl(string|\Stringable $field, mixed $value) : self + { + $this->queryBuilder->bindUrl($field, $value); + + return $this; + } + + public function bindings(array $fieldValues) : self + { + foreach($fieldValues as $field => $value) { + $this->bindUrl($field, $value); + } + + return $this; + } } \ No newline at end of file diff --git a/src/Attribute/Obj/Api/ApiAction.php b/src/Attribute/Obj/Api/ApiAction.php index 0fe6fa5..f1e6cee 100644 --- a/src/Attribute/Obj/Api/ApiAction.php +++ b/src/Attribute/Obj/Api/ApiAction.php @@ -11,5 +11,7 @@ abstract class ApiAction public string $url, public MethodEnum $method, public int $timeout = 30, + # Define how the search string will be build, passing params through the URL or into request's body + public MethodEnum $searchMethod = MethodEnum::Get, ) {} } \ No newline at end of file diff --git a/src/Attribute/Obj/Api/Collection.php b/src/Attribute/Obj/Api/Collection.php index 6b47878..26199bb 100644 --- a/src/Attribute/Obj/Api/Collection.php +++ b/src/Attribute/Obj/Api/Collection.php @@ -5,10 +5,12 @@ namespace Ulmus\Api\Attribute\Obj\Api; use Ulmus\Api\Common\MethodEnum; #[\Attribute(\Attribute::TARGET_CLASS)] -class Collection extends ApiAction { +class Collection extends ApiAction +{ public function __construct( public string $url, public MethodEnum $method = MethodEnum::Get, public int $timeout = 30, + public MethodEnum $searchMethod = MethodEnum::Get, ) {} } \ No newline at end of file diff --git a/src/Attribute/Obj/Api/Create.php b/src/Attribute/Obj/Api/Create.php index 4eff2ee..d5392a5 100644 --- a/src/Attribute/Obj/Api/Create.php +++ b/src/Attribute/Obj/Api/Create.php @@ -5,7 +5,8 @@ namespace Ulmus\Api\Attribute\Obj\Api; use Ulmus\Api\Common\MethodEnum; #[\Attribute(\Attribute::TARGET_CLASS)] -class Create extends ApiAction { +class Create extends ApiAction +{ public function __construct( public string $url, public MethodEnum $method = MethodEnum::Post, diff --git a/src/Attribute/Obj/Api/Delete.php b/src/Attribute/Obj/Api/Delete.php index 67c486b..9d87c50 100644 --- a/src/Attribute/Obj/Api/Delete.php +++ b/src/Attribute/Obj/Api/Delete.php @@ -5,7 +5,8 @@ namespace Ulmus\Api\Attribute\Obj\Api; use Ulmus\Api\Common\MethodEnum; #[\Attribute(\Attribute::TARGET_CLASS)] -class Delete extends ApiAction { +class Delete extends ApiAction +{ public function __construct( public string $url, public MethodEnum $method = MethodEnum::Delete, diff --git a/src/Attribute/Obj/Api/Read.php b/src/Attribute/Obj/Api/Read.php index c70ac54..79e835e 100644 --- a/src/Attribute/Obj/Api/Read.php +++ b/src/Attribute/Obj/Api/Read.php @@ -5,10 +5,12 @@ namespace Ulmus\Api\Attribute\Obj\Api; use Ulmus\Api\Common\MethodEnum; #[\Attribute(\Attribute::TARGET_CLASS)] -class Read extends ApiAction { +class Read extends ApiAction +{ public function __construct( public string $url, public MethodEnum $method = MethodEnum::Get, public int $timeout = 30, + public MethodEnum $searchMethod = MethodEnum::Get, ) {} } \ No newline at end of file diff --git a/src/Attribute/Obj/Api/Search.php b/src/Attribute/Obj/Api/Search.php new file mode 100644 index 0000000..cb4f36e --- /dev/null +++ b/src/Attribute/Obj/Api/Search.php @@ -0,0 +1,16 @@ +getBody()->getContents() )->decode() ; } - public function withParsedBody(mixed $data) : MessageInterface + public function withParsedBody(mixed $data) : static { return (clone $this)->setBody( JsonStream::fromContent($data) diff --git a/src/Common/StreamOutputInterface.php b/src/Common/StreamOutputInterface.php index 3b1baf0..0e6f6f6 100644 --- a/src/Common/StreamOutputInterface.php +++ b/src/Common/StreamOutputInterface.php @@ -7,5 +7,5 @@ use Psr\Http\Message\MessageInterface; interface StreamOutputInterface { public function getParsedBody() : mixed; - public function withParsedBody(mixed $data) : MessageInterface; + public function withParsedBody(mixed $data) : static; } \ No newline at end of file diff --git a/src/Request/Request.php b/src/Request/Request.php index a276aa6..de1e99c 100644 --- a/src/Request/Request.php +++ b/src/Request/Request.php @@ -2,13 +2,11 @@ namespace Ulmus\Api\Request; -use League\CommonMark\Block\Element\StringContainerInterface; -use Psr\Http\Message\RequestInterface; -use Psr\Http\Message\StreamInterface; -use Psr\Http\Message\UriInterface; -use Ulmus\Api\Common\{MethodEnum, Message, Stream, Uri}; +use Ulmus\Api\Common\{MethodEnum, Message, Uri, }; +use Ulmus\Api\Stream\{JsonStream, Stream}; +use Psr\Http\Message\{MessageInterface, ServerRequestInterface, UriInterface, RequestInterface, StreamInterface}; -class Request extends Message implements RequestInterface +class Request extends Message implements ServerRequestInterface { protected int $code; @@ -20,6 +18,10 @@ class Request extends Message implements RequestInterface protected MethodEnum $method; + protected array $cookies = []; + + protected array $files = []; + public function __construct(string|UriInterface $uri, MethodEnum $method, null|StreamInterface $stream = null, array $headers = []) { $this->method = $method; @@ -70,9 +72,9 @@ class Request extends Message implements RequestInterface return $this; } - public function getUri() + public function getUri() : UriInterface { - return (string) $this->uri; + return $this->uri; } public function withUri(UriInterface $uri, $preserveHost = false) @@ -101,4 +103,115 @@ class Request extends Message implements RequestInterface $fromUri->getHost(), $port && ! in_array($port, Uri::IGNORE_HTTP_PORT) ? ":{$port}" : "" ]); } -} \ No newline at end of file + + public function withQueryParams(array $query) : static + { + return (clone $this)->addQueryParams($query); + } + + protected function addQueryParams(array $query) : static + { + $rebuilt = http_build_query(array_merge($this->getQueryParams(), $query), "", null, PHP_QUERY_RFC3986); + + $this->getUri()->withQuery($rebuilt); + + return $this; + } + + public function getServerParams() : array + { + return []; + } + + public function getCookieParams() : array + { + return $this->cookies; + } + + public function withCookieParams(array $cookies) : static + { + return (clone $this)->setCookies($cookies); + } + + protected function setCookies(array $cookies) : static + { + $this->cookies = $cookies; + + return $this; + } + + public function getQueryParams() : array + { + parse_str($this->getUri()->getQuery(), $query); + + return $query; + } + + public function getUploadedFiles() : array + { + return $this->files; + } + + public function withUploadedFiles(array $uploadedFiles) : static + { + return (clone $this)->setUploadedFiles($uploadedFiles); + } + + protected function setUploadedFiles(array $uploadedFiles) : static + { + $this->files = $uploadedFiles; + + return $this; + } + + public function getParsedBody() : null|array|object + { + $raw = $this->getBody()->getContents(); + + $contentType = $this->getHeader('Content-Type')[0] ?? "application/x-www-form-urlencoded"; + + switch($contentType) { + case "application/x-www-form-urlencoded": + parse_str($raw, $result); + + return $result; + + case "multipart/form-data": + + return []; + + case "application/json": + return JsonStream::fromJsonEncoded( $raw )->decode(); + + } + + return [ sprintf("Unsupported content type: %s", $contentType) ]; + } + + public function withParsedBody(mixed $data) : static + { + return (clone $this)->setBody( + JsonStream::fromContent($data) + ); + } + + public function getAttributes() : array + { + // TODO: Implement getAttributes() method. + } + + public function getAttribute($name, $default = null) : mixed + { + // TODO: Implement getAttribute() method. + } + + public function withAttribute($name, $value) : static + { + // TODO: Implement withAttribute() method. + } + + public function withoutAttribute($name): static + { + // TODO: Implement withoutAttribute() method. + } +} diff --git a/src/RequestBuilder.php b/src/RequestBuilder.php index df9ebd7..c34ac6b 100644 --- a/src/RequestBuilder.php +++ b/src/RequestBuilder.php @@ -2,23 +2,19 @@ namespace Ulmus\Api; -use Ulmus; +use Ulmus, Ulmus\Query\QueryFragmentInterface; -class RequestBuilder implements Ulmus\Query\QueryBuilderInterface +class RequestBuilder implements Ulmus\QueryBuilder\QueryBuilderInterface { - public Ulmus\Query\QueryBuilderInterface $parent; + public Ulmus\QueryBuilder\QueryBuilderInterface $parent; - public array $parameters = []; + public RequestBuilder\Filter $filters; - public array $values = []; - - public string $whereConditionOperator = Ulmus\Query\Where::CONDITION_AND; - - public string $havingConditionOperator = Ulmus\Query\Where::CONDITION_AND; + public RequestBuilder\UrlParameter $urlParameters; protected int $parameterIndex = 0; - protected array $queryStack = []; + protected array $queryParamStack = []; public function values(array $dataset) : self { @@ -27,33 +23,36 @@ class RequestBuilder implements Ulmus\Query\QueryBuilderInterface return $this; } - public function where(/* stringable*/ $field, $value, string $operator = Ulmus\Query\Where::OPERATOR_EQUAL, string $condition = Ulmus\Query\Where::CONDITION_AND, bool $not = false) : self + public function where(\Stringable|string $field, mixed $value,) : self { - # Empty IN case - if ( [] === $value ) { - return $this; + if ( empty($this->filters) && ! $this->getFragment(RequestBuilder\Filter::class) ) { + $this->filters = new RequestBuilder\Filter(); + $this->push($this->filters); } - if ( $this->where ?? false ) { - $where = $this->where; - } - elseif ( null === ( $where = $this->getFragment(RequestBuilder\Filter::class) ) ) { - $this->where = $where = new RequestBuilder\Filter($this); - $this->push($where); - } - - $this->whereConditionOperator = $operator; - - $where->add($field, $value, $operator, $condition, $not); + $this->filters->add($field, $value); return $this; } - public function notWhere($field, $value, string $operator = Ulmus\Query\Where::CONDITION_AND) : self + public function bindUrl(\Stringable|string $field, mixed $value,) : self { - return $this->where($field, $value, $operator, true); + if ( empty($this->urlParameters) && ! $this->getFragment(RequestBuilder\UrlParameter::class) ) { + $this->urlParameters = new RequestBuilder\UrlParameter(); + $this->push($this->urlParameters); + } + + $this->urlParameters->add($field, $value); + + return $this; } + + /*public function notWhere($field, mixed $value) : self + { + return $this->filters($field, $value); + }*/ + public function limit(int $value) : self { /*if ( null === $limit = $this->getFragment(Ulmus\Query\Limit::class) ) { @@ -68,12 +67,12 @@ class RequestBuilder implements Ulmus\Query\QueryBuilderInterface public function offset(int $value) : self { - if ( null === $offset = $this->getFragment(Ulmus\Query\Offset::class) ) { + /*if ( null === $offset = $this->getFragment(Ulmus\Query\Offset::class) ) { $offset = new Ulmus\Query\Offset(); $this->push($offset); } - $offset->set($value); + $offset->set($value);*/ return $this; } @@ -83,23 +82,23 @@ class RequestBuilder implements Ulmus\Query\QueryBuilderInterface return $this; } - public function push(Ulmus\Query\Fragment $queryFragment) : self + public function push(QueryFragmentInterface $queryFragment) : self { - $this->queryStack[] = $queryFragment; + $this->queryParamStack[] = $queryFragment; return $this; } - public function pull(Ulmus\Query\Fragment $queryFragment) : self + public function pull(QueryFragmentInterface $queryFragment) : self { - return array_shift($this->queryStack); + return array_shift($this->queryParamStack); } public function render(bool $skipToken = false) : array { $stack = []; - foreach($this->queryStack as $fragment) { + foreach($this->queryParamStack as $fragment) { $stack = array_merge($stack, (array) $fragment->render($skipToken)); } @@ -108,16 +107,12 @@ class RequestBuilder implements Ulmus\Query\QueryBuilderInterface public function reset() : void { - $this->parameters = $this->values = $this->queryStack = []; - $this->whereConditionOperator = Ulmus\Query\Where::CONDITION_AND; - $this->parameterIndex = 0; - - unset($this->where); + unset($this->filters); } - public function getFragment(string $class, int $index = 0) : ? Ulmus\Query\Fragment + public function getFragment(string $class, int $index = 0) : ? QueryFragmentInterface { - foreach($this->queryStack as $item) { + foreach($this->queryParamStack as $item) { if ( get_class($item) === $class ) { if ( $index-- === 0 ) { return $item; @@ -128,11 +123,11 @@ class RequestBuilder implements Ulmus\Query\QueryBuilderInterface return null; } - public function removeFragment(\Ulmus\Query\Fragment|array|\Stringable|string $fragment) : void + public function removeFragment(QueryFragmentInterface|array|\Stringable|string $fragment) : void { - foreach($this->queryStack as $key => $item) { + foreach($this->queryParamStack as $key => $item) { if ( $item === $fragment ) { - unset($this->queryStack[$key]); + unset($this->queryParamStack[$key]); } } } @@ -141,24 +136,4 @@ class RequestBuilder implements Ulmus\Query\QueryBuilderInterface { return $this->render(); } - - public function addParameter($value, string $key = null) : string - { - if ( $this->parent ?? false ) { - return $this->parent->addParameter($value, $key); - } - - if ( $key === null ) { - $key = ":p" . $this->parameterIndex++; - } - - $this->parameters[$key] = $value; - - return $key; - } - - public function addValues(array $values) : void - { - $this->values = $values; - } } diff --git a/src/RequestBuilder/Filter.php b/src/RequestBuilder/Filter.php new file mode 100644 index 0000000..b81e084 --- /dev/null +++ b/src/RequestBuilder/Filter.php @@ -0,0 +1,24 @@ +conditionList[$field] = $value; + + return $this; + } + + public function render() : array + { + return [ + static::KEY => $this->conditionList + ]; + } +} diff --git a/src/RequestBuilder/Fragment.php b/src/RequestBuilder/Fragment.php new file mode 100644 index 0000000..3d36770 --- /dev/null +++ b/src/RequestBuilder/Fragment.php @@ -0,0 +1,14 @@ +conditionList[$field] = $value; + + return $this; + } + + public function render(bool $skipToken = false) : string + { + return http_build_query($this->conditionList); + } +} diff --git a/src/RequestBuilder/UrlParameter.php b/src/RequestBuilder/UrlParameter.php new file mode 100644 index 0000000..7d838aa --- /dev/null +++ b/src/RequestBuilder/UrlParameter.php @@ -0,0 +1,24 @@ +conditionList[$field] = $value; + + return $this; + } + + public function render() : array + { + return [ + static::KEY => $this->conditionList + ]; + } +} diff --git a/src/SearchRequest/ApiSearchRequest.php b/src/SearchRequest/ApiSearchRequest.php new file mode 100644 index 0000000..fd1c8b0 --- /dev/null +++ b/src/SearchRequest/ApiSearchRequest.php @@ -0,0 +1,43 @@ +bindings + [ + + ], fn($i) => !is_null($i)) + []; + } + + protected function parseAttributeMethod(object $attribute, string $field, string $propertyName,): void + { + switch ($attribute->method) { + case SearchMethodEnum::Manual: + if ($attribute instanceof BindParameter) { + $this->bindings[$field] = $this->$propertyName; + } + break; + + default: + $this->parseAttributeMethodParent($attribute, $field, $propertyName); + break; + } + } +} \ No newline at end of file diff --git a/src/SearchRequest/Attribute/BindParameter.php b/src/SearchRequest/Attribute/BindParameter.php new file mode 100644 index 0000000..093f9b9 --- /dev/null +++ b/src/SearchRequest/Attribute/BindParameter.php @@ -0,0 +1,16 @@ +bearer($configuration['token']); + $this->bearer($this->configuration['token']); break; case AuthenticationEnum::Key: - $this->key($configuration['token']); + $this->key($this->configuration['token']); break; case AuthenticationEnum::Token: - $this->token($configuration['token']); + $this->token($this->configuration['token']); break; case AuthenticationEnum::Basic: - $this->basic($configuration['username'], $configuration['password']); + $this->basic($this->configuration['username'], $this->configuration['password']); break; case AuthenticationEnum::Ntlm: - $this->ntlm($configuration['username'], $configuration['password']); + $this->ntlm($this->configuration['username'], $this->configuration['password']); break; case AuthenticationEnum::Negotiate: - $this->negotiate($configuration['username'], $configuration['password']); + $this->negotiate($this->configuration['username'], $this->configuration['password']); break; case AuthenticationEnum::OAuth2: - $this->oauth2($configuration['grant'], $configuration['oauth_token_url'], $configuration['redirect_uri'], $configuration['client_id'], $configuration['client_secret'], $configuration['scope']); + $this->oauth2($this->configuration['grant'], $this->configuration['oauth_token_url'], $this->configuration['redirect_uri'], $this->configuration['client_id'], $this->configuration['client_secret'], $this->configuration['scope']); break; } @@ -94,11 +98,11 @@ class CurlAuthorization public function oauth2(Oauth2GrantTypeEnum $grant, string $oauthTokenUrl, string $redirectUri, string $clientId, string $clientSecret, string $scope) : void { - #return; + $unid = sprintf("oauth_token_%s", md5(serialize($this->configuration))); - # TMP ! - if (false === ($_SESSION['grics_token'] ?? false)) { - # IF NO TOKEN OR TIMEOUT + $token = apcu_fetch($unid, $exists); + + if ( ! $exists ) { $provider = new GenericProvider([ 'clientId' => $clientId, 'clientSecret' => $clientSecret, @@ -111,22 +115,27 @@ class CurlAuthorization try { $accessToken = $provider->getAccessToken($grant->value); - $_SESSION['grics_token'] = $accessToken->getToken(); + $token = json_encode($accessToken); - # var_dump($accessToken); die(); - - # KEEP TOKEN IN APCU ! - } catch (\League\OAuth2\Client\Provider\Exception\IdentityProviderException $e) { - // Failed to get the access token - exit($e->getMessage()); + apcu_store($unid, $token, $accessToken->getExpires() - time() - 10); + } + catch (\League\OAuth2\Client\Provider\Exception\IdentityProviderException $e) { + throw $e; } } + try { + $decodedToken = json_decode($token, true, 512, JSON_THROW_ON_ERROR); + } + catch(\Exception $ex) { + throw new \InvalidArgumentException("Given OAuth2 token is not a parsable JSON stream."); + } - $this->bearer($_SESSION['grics_token']); + if ( empty($decodedToken) ) { + throw new \InvalidArgumentException("Given OAuth Token is empty"); + } - #var_dump($_SESSION['grics_token']);die(); - # SWITCH TO BEARER AUTH TYPE, SET TOKEN FROM APCU IF STILL VALID + $this->bearer($decodedToken['access_token']); } protected function userpass(int $authType, string $username, #[\SensitiveParameter] $password) : void