- Added SearchRequest compatibilty and began working on QueryBuilder processing
This commit is contained in:
		
							parent
							
								
									ce4d6cdf7c
								
							
						
					
					
						commit
						4e120cea6c
					
				@ -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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -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,
 | 
			
		||||
    ) {}
 | 
			
		||||
}
 | 
			
		||||
@ -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,
 | 
			
		||||
    ) {}
 | 
			
		||||
}
 | 
			
		||||
@ -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,
 | 
			
		||||
 | 
			
		||||
@ -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,
 | 
			
		||||
 | 
			
		||||
@ -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,
 | 
			
		||||
    ) {}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										16
									
								
								src/Attribute/Obj/Api/Search.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/Attribute/Obj/Api/Search.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Ulmus\Api\Attribute\Obj\Api;
 | 
			
		||||
 | 
			
		||||
use Ulmus\Api\Common\MethodEnum;
 | 
			
		||||
 | 
			
		||||
#[\Attribute(\Attribute::TARGET_CLASS)]
 | 
			
		||||
class Search extends ApiAction
 | 
			
		||||
{
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        public string $url,
 | 
			
		||||
        public MethodEnum $method = MethodEnum::Get,
 | 
			
		||||
        public int $timeout = 30,
 | 
			
		||||
        public MethodEnum $searchMethod = MethodEnum::Get,
 | 
			
		||||
    ) {}
 | 
			
		||||
}
 | 
			
		||||
@ -5,7 +5,8 @@ namespace Ulmus\Api\Attribute\Obj\Api;
 | 
			
		||||
use Ulmus\Api\Common\MethodEnum;
 | 
			
		||||
 | 
			
		||||
#[\Attribute(\Attribute::TARGET_CLASS)]
 | 
			
		||||
class Update extends ApiAction {
 | 
			
		||||
class Update extends ApiAction
 | 
			
		||||
{
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        public string $url,
 | 
			
		||||
        public MethodEnum $method = MethodEnum::Patch,
 | 
			
		||||
 | 
			
		||||
@ -7,12 +7,12 @@ use Ulmus\Api\Stream\JsonStream;
 | 
			
		||||
 | 
			
		||||
trait JsonMessageTrait
 | 
			
		||||
{
 | 
			
		||||
    public function getParsedBody(): mixed
 | 
			
		||||
    public function getParsedBody() : null|array|object
 | 
			
		||||
    {
 | 
			
		||||
        return JsonStream::fromJsonEncoded( $this->getBody()->getContents() )->decode() ;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function withParsedBody(mixed $data) : MessageInterface
 | 
			
		||||
    public function withParsedBody(mixed $data) : static
 | 
			
		||||
    {
 | 
			
		||||
        return (clone $this)->setBody(
 | 
			
		||||
            JsonStream::fromContent($data)
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
}
 | 
			
		||||
@ -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}" : ""
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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.
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										24
									
								
								src/RequestBuilder/Filter.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/RequestBuilder/Filter.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,24 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Ulmus\Api\RequestBuilder;
 | 
			
		||||
 | 
			
		||||
class Filter extends Fragment
 | 
			
		||||
{
 | 
			
		||||
    public const KEY = "filters";
 | 
			
		||||
 | 
			
		||||
    public array $conditionList;
 | 
			
		||||
 | 
			
		||||
    public function add($field, mixed $value) : self
 | 
			
		||||
    {
 | 
			
		||||
        $this->conditionList[$field] = $value;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function render() : array
 | 
			
		||||
    {
 | 
			
		||||
        return [
 | 
			
		||||
            static::KEY => $this->conditionList
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										14
									
								
								src/RequestBuilder/Fragment.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/RequestBuilder/Fragment.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,14 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Ulmus\Api\RequestBuilder;
 | 
			
		||||
 | 
			
		||||
use Ulmus\Query\QueryFragmentInterface;
 | 
			
		||||
 | 
			
		||||
abstract class Fragment implements QueryFragmentInterface {
 | 
			
		||||
 | 
			
		||||
    protected int $encodingType = \PHP_QUERY_RFC3986;
 | 
			
		||||
 | 
			
		||||
    protected ? string $querySeparator = null;
 | 
			
		||||
 | 
			
		||||
    public abstract function render() : array;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										20
									
								
								src/RequestBuilder/Pagination.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/RequestBuilder/Pagination.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Ulmus\Api\RequestBuilder;
 | 
			
		||||
 | 
			
		||||
class Pagination extends Fragment {
 | 
			
		||||
 | 
			
		||||
    public array $conditionList;
 | 
			
		||||
 | 
			
		||||
    public function add($field, mixed $value) : self
 | 
			
		||||
    {
 | 
			
		||||
        $this->conditionList[$field] = $value;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function render(bool $skipToken = false) : string
 | 
			
		||||
    {
 | 
			
		||||
        return http_build_query($this->conditionList);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										24
									
								
								src/RequestBuilder/UrlParameter.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/RequestBuilder/UrlParameter.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,24 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Ulmus\Api\RequestBuilder;
 | 
			
		||||
 | 
			
		||||
class UrlParameter extends Fragment
 | 
			
		||||
{
 | 
			
		||||
    public const KEY = "bindings";
 | 
			
		||||
 | 
			
		||||
    public array $conditionList;
 | 
			
		||||
 | 
			
		||||
    public function add($field, mixed $value) : self
 | 
			
		||||
    {
 | 
			
		||||
        $this->conditionList[$field] = $value;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function render() : array
 | 
			
		||||
    {
 | 
			
		||||
        return [
 | 
			
		||||
            static::KEY => $this->conditionList
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										43
									
								
								src/SearchRequest/ApiSearchRequest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/SearchRequest/ApiSearchRequest.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,43 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Ulmus\Api\SearchRequest;
 | 
			
		||||
 | 
			
		||||
use Psr\Http\Message\ServerRequestInterface;
 | 
			
		||||
use Ulmus\{Api\SearchRequest\Attribute\BindParameter,
 | 
			
		||||
    Repository,
 | 
			
		||||
    SearchRequest\SearchMethodEnum,
 | 
			
		||||
    SearchRequest\SearchRequest,
 | 
			
		||||
    SearchRequest\SearchRequestFromRequestTrait,
 | 
			
		||||
    SearchRequest\SearchRequestInterface,
 | 
			
		||||
    SearchRequest\SearchRequestPaginationTrait};
 | 
			
		||||
 | 
			
		||||
class ApiSearchRequest extends SearchRequest implements SearchRequestInterface
 | 
			
		||||
{
 | 
			
		||||
    use SearchRequestPaginationTrait, SearchRequestFromRequestTrait {
 | 
			
		||||
        parseAttributeMethod as parseAttributeMethodParent;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected array $bindings = [];
 | 
			
		||||
 | 
			
		||||
    public function bindings(): iterable
 | 
			
		||||
    {
 | 
			
		||||
        return array_filter($this->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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										16
									
								
								src/SearchRequest/Attribute/BindParameter.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/SearchRequest/Attribute/BindParameter.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Ulmus\Api\SearchRequest\Attribute;
 | 
			
		||||
 | 
			
		||||
use Ulmus\SearchRequest\{ SearchMethodEnum, Attribute\SearchParameter };
 | 
			
		||||
 | 
			
		||||
#[\Attribute(\Attribute::TARGET_PROPERTY)]
 | 
			
		||||
class BindParameter extends SearchParameter
 | 
			
		||||
{
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        public ? string $parameter = null,
 | 
			
		||||
        public ? string $field = null,
 | 
			
		||||
        public bool $toggle = false,
 | 
			
		||||
        public SearchMethodEnum $method = SearchMethodEnum::Manual,
 | 
			
		||||
    ) {}
 | 
			
		||||
}
 | 
			
		||||
@ -7,39 +7,43 @@ use Ulmus\Api\Common\AuthenticationEnum;
 | 
			
		||||
 | 
			
		||||
class CurlAuthorization
 | 
			
		||||
{
 | 
			
		||||
    public array $headers = [];
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        #[\SensitiveParameter]
 | 
			
		||||
        public array $configuration,
 | 
			
		||||
        #[\SensitiveParameter]
 | 
			
		||||
        public array $headers = [],
 | 
			
		||||
        public array $options = [],
 | 
			
		||||
    ) { }
 | 
			
		||||
 | 
			
		||||
    public array $options = [];
 | 
			
		||||
 | 
			
		||||
    public function fromAuthenticationEnum(AuthenticationEnum $auth, #[\SensitiveParameter] array $configuration,) : static
 | 
			
		||||
    public function fromAuthenticationEnum(AuthenticationEnum $auth,) : static
 | 
			
		||||
    {
 | 
			
		||||
        switch($auth) {
 | 
			
		||||
            case AuthenticationEnum::Bearer:
 | 
			
		||||
                $this->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
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user