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