Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions src/Auth/Abstracts/AbstractAuthController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace MRussell\REST\Auth\Abstracts;

use Psr\Http\Message\ResponseInterface;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Psr7\Response;
use MRussell\REST\Auth\AuthControllerInterface;
Expand Down Expand Up @@ -189,21 +190,24 @@ public function authenticate(): bool
}
} catch (RequestException $exception) {
$response = $exception->getResponse();
if ($response) {
if ($response instanceof ResponseInterface) {
$statusCode = $response->getStatusCode();
$message = $exception->getMessage();
$content = $response->getBody()->getContents();
if (!empty($content)) {
$message .= "RESPONSE: $content";
$message .= 'RESPONSE: ' . $content;
}
$this->getLogger()->error("[REST] Authenticate Failed [$statusCode] - " . $message);

$this->getLogger()->error(sprintf('[REST] Authenticate Failed [%d] - ', $statusCode) . $message);
} else {
$this->getLogger()->error("[REST] Authenticate Request Exception - " . $exception->getMessage());
}

// @codeCoverageIgnoreStart
} catch (\Exception $exception) {
$this->getLogger()->error("[REST] Authenticate Exception - " . $exception->getMessage());
}

// @codeCoverageIgnoreEnd
return $ret;
}
Expand All @@ -226,21 +230,24 @@ public function logout(): bool
$this->getLogger()->debug($exception->getMessage());
} catch (RequestException $exception) {
$response = $exception->getResponse();
if ($response) {
if ($response instanceof ResponseInterface) {
$statusCode = $response->getStatusCode();
$message = $exception->getMessage();
$content = $response->getBody()->getContents();
if (!empty($content)) {
$message .= "RESPONSE: $content";
$message .= 'RESPONSE: ' . $content;
}
$this->getLogger()->error("[REST] Logout Failed [$statusCode] - " . $message);

$this->getLogger()->error(sprintf('[REST] Logout Failed [%d] - ', $statusCode) . $message);
} else {
$this->getLogger()->error("[REST] Logout Request Exception - " . $exception->getMessage());
}

// @codeCoverageIgnoreStart
} catch (\Exception $exception) {
$this->getLogger()->error("[REST] Logout Exception - " . $exception->getMessage());
}

// @codeCoverageIgnoreEnd
return $ret;
}
Expand Down
10 changes: 7 additions & 3 deletions src/Auth/Abstracts/AbstractOAuth2Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace MRussell\REST\Auth\Abstracts;

use Psr\Http\Message\ResponseInterface;
use GuzzleHttp\Exception\RequestException;
use Psr\SimpleCache\InvalidArgumentException;
use GuzzleHttp\Psr7\Response;
Expand Down Expand Up @@ -200,21 +201,24 @@ public function refresh(): bool
$this->getLogger()->debug($exception->getMessage());
} catch (RequestException $exception) {
$response = $exception->getResponse();
if ($response) {
if ($response instanceof ResponseInterface) {
$statusCode = $response->getStatusCode();
$message = $exception->getMessage();
$content = $response->getBody()->getContents();
if (!empty($content)) {
$message .= "RESPONSE: $content";
$message .= 'RESPONSE: ' . $content;
}
$this->getLogger()->error("[REST] OAuth Refresh Failed [$statusCode] - " . $message);

$this->getLogger()->error(sprintf('[REST] OAuth Refresh Failed [%d] - ', $statusCode) . $message);
} else {
$this->getLogger()->error("[REST] OAuth Refresh Request Exception - " . $exception->getMessage());
}

// @codeCoverageIgnoreStart
} catch (\Exception $exception) {
$this->getLogger()->error("[REST] Unknown OAuth Refresh Exception - " . $exception->getMessage());
}

// @codeCoverageIgnoreEnd
}

Expand Down
135 changes: 88 additions & 47 deletions src/Endpoint/Abstracts/AbstractEndpoint.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ abstract class AbstractEndpoint implements EndpointInterface, EventTriggerInterf

public const AUTH_REQUIRED = 2;

public const URL_VAR_CHAR = '$';

public const URL_OPTIONAL_VAR_CHAR = ':';

protected static array $_DEFAULT_PROPERTIES = [
self::PROPERTY_URL => '',
self::PROPERTY_HTTP_METHOD => '',
Expand Down Expand Up @@ -122,10 +126,44 @@ public function catchNon200Responses(bool $catch = true): static
*/
public function setUrlArgs(array $args): static
{
if (!empty($args) && $this->needsUrlArgs()) {
$args = $this->normalizeUrlArgs($args);
}

$this->_urlArgs = $args;
return $this;
}

protected function normalizeUrlArgs(array $urlArgs): array
{
$vars = $this->extractUrlVariables();
$argNum = 0;
$normalized = [];
foreach ($urlArgs as $key => $value) {
if (isset($vars[$key])) {
$normalized[$key] = $value;
if ($vars[$key]['index'] == $argNum) {
$argNum++;
}
} elseif (is_numeric($key) && !empty($value)) {
foreach ($vars as $var => $varProps) {
if (!isset($normalized[$var]) && !isset($urlArgs[$var])) {
if ($varProps['index'] == $key) {
$normalized[$var] = $value;
break;
} elseif ($varProps['index'] == $argNum) {
$normalized[$var] = $value;
break;
}
}
}
$argNum++;
}
}

return $normalized;
}

/**
* @inheritdoc
*/
Expand Down Expand Up @@ -208,7 +246,7 @@ public function getResponse(): Response|null
public function getResponseBody(bool $associative = true): mixed
{
$response = $this->getResponse();
return $response ? $this->getResponseContent($response, $associative) : null;
return $response instanceof Response ? $this->getResponseContent($response, $associative) : null;
}

public function getHttpClient(): Client
Expand Down Expand Up @@ -267,6 +305,7 @@ function (RequestException $e) use ($options): void {
if ($response instanceof Response) {
$this->setResponse($response);
}

if (isset($options['error']) && is_callable($options['error'])) {
$options['error']($e);
}
Expand Down Expand Up @@ -320,6 +359,7 @@ public function buildRequest(): Request
$data = $this->configurePayload();
$request = new Request($method, $url);
$request = $this->configureJsonRequest($request);

$this->_request = $this->configureRequest($request, $data);
return $this->_request;
}
Expand Down Expand Up @@ -381,53 +421,39 @@ protected function configureURL(array $urlArgs): string
{
$url = $this->getEndPointUrl();
$this->triggerEvent(self::EVENT_CONFIGURE_URL, $urlArgs);
if ($this->hasUrlArgs()) {
$urlArr = explode("/", $url);
$optional = false;
$optionNum = 0;
$keys = array_keys($urlArgs);
sort($keys);
foreach ($keys as $key) {
if (is_numeric($key)) {
$optionNum = $key;
break;
}
}

foreach ($urlArr as $key => $urlPart) {
$replace = null;
if (str_contains($urlPart, static::$_URL_VAR_CHARACTER)) {
if (str_contains($urlPart, ':')) {
$optional = true;
$replace = '';
}
if ($this->needsUrlArgs()) {
$url = $this->populateUrlWithArgs($url, $urlArgs);
}

$opt = str_replace([static::$_URL_VAR_CHARACTER, ':'], '', $urlPart);
if (isset($urlArgs[$opt])) {
$replace = $urlArgs[$opt];
}
return $url;
}

if (isset($urlArgs[$optionNum]) && ($replace == '' || $replace == null)) {
$replace = $urlArgs[$optionNum];
$optionNum += 1;
}
protected function populateUrlWithArgs(string $url, array $urlArgs): string
{
$urlArgs = $this->normalizeUrlArgs($urlArgs);
$variables = $this->extractUrlVariables($url);
$urlArr = explode("/", trim($url, "/"));
foreach ($variables as $variable => $props) {
$index = $props['index'];
$replace = $urlArgs[$index] ?? "";
if (isset($urlArgs[$variable])) {
$replace = $urlArgs[$variable];
}

if ($optional && $replace == '') {
$urlArr = array_slice($urlArr, 0, $key);
$pattern = preg_quote(static::URL_VAR_CHAR . static::URL_OPTIONAL_VAR_CHAR, "/") . "?" . preg_quote($variable, "/");
if (empty($replace) && $props['optional']) {
foreach ($urlArr as $i => $urlPart) {
if (preg_match(sprintf('/%s/', $pattern), $urlPart)) {
$urlArr = array_slice($urlArr, 0, $i);
break;
}

if ($replace !== null) {
$urlArr[$key] = $replace;
}
}
} elseif (!empty($replace)) {
$urlArr = preg_replace(sprintf('/%s/', $pattern), $replace, $urlArr);
}

$url = implode("/", $urlArr);
$url = rtrim($url, "/");
}

return $url;
return rtrim(implode("/", $urlArr), "/");
}

/**
Expand All @@ -436,7 +462,7 @@ protected function configureURL(array $urlArgs): string
*/
private function verifyUrl(string $url): bool
{
if (str_contains($url, static::$_URL_VAR_CHARACTER)) {
if (str_contains($url, static::URL_VAR_CHAR)) {
throw new InvalidUrl([static::class, $url]);
}

Expand All @@ -446,7 +472,7 @@ private function verifyUrl(string $url): bool
/**
* Checks if Endpoint URL requires Arguments
*/
protected function hasUrlArgs(): bool
protected function needsUrlArgs(): bool
{
$url = $this->getEndPointUrl();
$variables = $this->extractUrlVariables($url);
Expand All @@ -455,15 +481,30 @@ protected function hasUrlArgs(): bool

/**
* Helper method for extracting variables via Regex from a passed in URL
* @param $url
*/
protected function extractUrlVariables($url): array
protected function extractUrlVariables(string $url = null): array
{
$url = $url ?? $this->getEndPointUrl();
$variables = [];
$pattern = "/(" . preg_quote(static::$_URL_VAR_CHARACTER) . ".*?[^\\/]*)/";
if (preg_match_all($pattern, $url, $matches)) {
foreach ($matches as $match) {
$variables[] = $match[0];
$varChar = preg_quote(static::URL_VAR_CHAR, "/");
$urlArr = explode("/", trim($url, "/"));
$varIndex = 0;
foreach ($urlArr as $pathPart) {
$pattern = "/(" . $varChar . sprintf('[^%s]+)/', $varChar);
if (preg_match_all($pattern, $pathPart, $matches, PREG_SET_ORDER)) {
foreach ($matches as $match) {
$optional = str_contains($match[0], static::URL_OPTIONAL_VAR_CHAR);
$var = str_replace([static::URL_VAR_CHAR, static::URL_OPTIONAL_VAR_CHAR], '', $match[0]);
if (!isset($variables[$var])) {
$variables[$var] = [
'index' => $varIndex,
'optional' => $optional,
];
$varIndex++;
} else {
$variables[$var]['optional'] = $optional ? $variables[$var]['optional'] : $optional;
}
}
}
}

Expand Down
25 changes: 22 additions & 3 deletions src/Endpoint/Abstracts/AbstractModelEndpoint.php
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,26 @@ public function __call($name, $arguments): EndpointInterface
throw new UnknownModelAction([static::class, $name]);
}

public function setUrlArgs(array $args): static
{
parent::setUrlArgs($args);
$this->setIdFromUrlArgs();
return $this;
}

protected function setIdFromUrlArgs(): void
{
if (!empty($this->_urlArgs[static::MODEL_ID_VAR])) {
$id = $this->getId();
if ($id != $this->_urlArgs[static::MODEL_ID_VAR] && !empty($id)) {
$this->clear();
}
$prop = $this->getKeyProperty();
$this->set($prop, $this->_urlArgs[static::MODEL_ID_VAR]);
unset($this->_urlArgs[static::MODEL_ID_VAR]);
}
}

/**
* @inheritdoc
*/
Expand Down Expand Up @@ -290,14 +310,13 @@ protected function syncFromApi(array $model): void

protected function configureURL(array $urlArgs): string
{
if (empty($urlArgs[self::MODEL_ID_VAR])) {
if (empty($urlArgs[static::MODEL_ID_VAR])) {
switch ($this->getCurrentAction()) {
case self::MODEL_ACTION_CREATE:
$urlArgs[self::MODEL_ID_VAR] = '';
break;
default:
$idKey = $this->getKeyProperty();
$id = $this->get($idKey);
$id = $this->getId();
$urlArgs[self::MODEL_ID_VAR] = (empty($id) ? '' : $id);
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/Endpoint/Provider/AbstractEndpointProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ protected function addEndpointRegistry(string $name, array $properties): void
if (!isset($properties[self::ENDPOINT_CLASS])) {
throw new InvalidRegistration([$name]);
}

if (!isset($properties[self::ENDPOINT_NAME])) {
$properties[self::ENDPOINT_NAME] = $name;
}
Expand Down Expand Up @@ -120,12 +121,14 @@ protected function isInVersionRange(string $version, array $ranges): bool
if (is_numeric($compare)) {
$compare = "==";
}

$internalComp = true;
if (is_array($range)) {
foreach ($range as $c => $v) {
if (is_array($v)) {
continue;
}

if (!$this->isInVersionRange($version, [$c => $v])) {
$internalComp = false;
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ protected function addEndpointRegistry(string $name, array $properties): void
if (isset($properties[self::ENDPOINT_NAME])) {
$properties[self::ENDPOINT_NAME] = $name;
}

$this->registry[] = $properties;
$next = count($this->registry);
parent::addEndpointRegistry("$next", $properties);
}

protected function getEndpointDefinition(string $name, string $version = null): array
Expand Down
1 change: 1 addition & 0 deletions src/Endpoint/Traits/GenerateEndpointTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ protected function generateEndpoint(string $endpoint): EndpointInterface|null
$EP->setBaseUrl($this->getBaseUrl());
}
}

return $EP;
}
}
Loading