ulmus-api/src/ApiRepository.php

167 lines
5.6 KiB
PHP

<?php
namespace Ulmus\Api;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
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\Stream\JsonStream;
use Ulmus\Api\Stream\Stream;
use Ulmus\Api\Request\JsonRequest;
use Ulmus\Api\Request\Request;
use Ulmus\Api\Transport\CurlClient;
use Ulmus\EntityCollection;
use Ulmus\SearchRequest\SearchRequestInterface;
class ApiRepository extends \Ulmus\Repository
{
const DEFAULT_ALIAS = "";
public CurlClient $client;
protected array $urlParameters = [];
public ResponseInterface $lastResponse;
public function __construct(string $entity, string $alias = self::DEFAULT_ALIAS, ConnectionAdapter $adapter = null)
{
parent::__construct($entity, $alias, $adapter);
}
public function loadOne(): ? object
{
$response = $this->executeRequest(Attribute\Obj\Api\Read::class);
return $this->instanciateEntity()->fromArray($response->getParsedBody());
}
public function loadAll() : EntityCollection
{
$response = $this->executeRequest(Attribute\Obj\Api\Collection::class);
return $this->instanciateEntityCollection()->fromArray($response->getParsedBody());
}
public function save(object|array $entity, ?array $fieldsAndValue = null, bool $replace = false): bool
{
$response = $this->executeRequest(Attribute\Obj\Api\Create::class, $entity->entityGetDataset());
$entity->fromArray($response->getParsedBody());
return $response->getStatusCode() === 200;
}
public function executeRequest(string $attributeClass, mixed $data = null) : ResponseInterface
{
$attribute = $this->getApiAttribute($attributeClass);
if ($attribute === null) {
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->callApiRequestCallback($request, $attribute);
$transport = $this->adapter->adapter()->connect();
$transport->timeout = $attribute->timeout;
$this->lastResponse = $response = $transport->fromRequest($request);
$response = $this->callApiResponseCallback($response, $attribute);
return $response;
}
public function bindUrl(string $parameter, mixed $value) : self
{
$this->urlParameters[$parameter] = $value;
return $this;
}
protected function buildRequestUrl(string $uri) :string
{
$uri = $this->prepareUri($uri, $this->urlParameters);
return $this->adapter->adapter()->url . '/' . ltrim($uri, '/');
}
protected function prepareUri(string $route, array $arguments) : string
{
if ( preg_match_all('~{(.*?)}~si', $route, $matches, PREG_SET_ORDER) ) {
$search = [];
foreach($matches as $item) {
$default = null;
$variable = $item[1];
# Handles default
if (strpos($variable, "=") !== false) {
list($variable, $default) = explode('=', $item[1]);
}
if ( array_key_exists($variable, $arguments) ) {
$value = $arguments[$variable];
unset($arguments[$variable]);
}
else {
if ($default ?? false) {
$value = $default;
}
elseif ( strpos($route, "[{$matches[0][0]}]") !== false && $this->enforceExistingArguments) {
throw new \RuntimeException(sprintf("Error while preparing route %s : could not match variable '%s' into given arguments ( %s ) from %s::%s", $route, $variable, json_encode($arguments), $routeParam['class'], $routeParam['classMethod']));
}
}
$search[$item[0]] = rawurlencode($value ?? "");
}
$route = str_replace(array_keys($search), array_values($search), $route);
}
return $route;
}
protected function prepareRequest(string|UriInterface $uri, MethodEnum $method, mixed $body = null, array $headers = []) : RequestInterface
{
return new JsonRequest($uri, $method, $body === null ? Stream::fromTemp() : JsonStream::fromContent($body), $headers);
}
public function getApiAttribute(string $type) : ? object
{
return $this->entityClass::resolveEntity()->getAttributeImplementing($type);
}
protected function callApiRequestCallback(RequestInterface $request, ApiAction $attribute) : RequestInterface
{
return $this->adapter->apiHandler->handleRequest($request, $attribute);
}
protected function callApiResponseCallback(ResponseInterface $response, ApiAction $attribute) : ResponseInterface
{
return $this->adapter->apiHandler->handleResponse($response, $attribute);
}
public function filterServerRequest(SearchRequestInterface $searchRequest, bool $count = true) : self
{
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());
}
public function count(): int
{
return 0;
}
}