- Added SearchRequest compatibilty and began working on QueryBuilder processing

This commit is contained in:
Dave Mc Nicoll committed 2024-04-17 15:57:51 -04:00
1 parent ce4d6cdf7c
commit 4e120cea6c
20 files changed
+510 -141

No files matched your search

+119 -33
View File
@@ -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;
}
}