Skip to content

Commit

Permalink
Refactoring to minimal dependencies + add native support for baraja-c…
Browse files Browse the repository at this point in the history
…ore/cas. (#46)

* Native support for baraja-core/cas.

* Simplify internal implementation, use native code.

* Schema: Remove legacy experiment.

* Response: Remove legacy getArray method.

* Codestyle formatting.

* Remove experimental firewall method.

* Tracy is only possible dependecy.
  • Loading branch information
janbarasek authored Nov 3, 2022
1 parent dc503e6 commit b94baa6
Show file tree
Hide file tree
Showing 12 changed files with 94 additions and 322 deletions.
2 changes: 0 additions & 2 deletions .phpstorm.meta.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
exitPoint(\Baraja\StructuredApi\BaseEndpoint::sendSuccess());
exitPoint(\Baraja\StructuredApi\BaseEndpoint::sendError());
exitPoint(\Baraja\StructuredApi\BaseEndpoint::sendItems());
exitPoint(\Baraja\StructuredApi\BaseEndpoint::redirect());
exitPoint(\Baraja\StructuredApi\BaseEndpoint::redirectUrl());
exitPoint(\Baraja\StructuredApi\ThrowStatusResponse::invoke());
exitPoint(\Baraja\StructuredApi\Response\Status\StatusResponse::invoke());
exitPoint(\Baraja\StructuredApi\Response\Status\ErrorResponse::invoke());
Expand Down
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@
"nette/http": "^3.1",
"nette/application": "^3.1",
"nette/robot-loader": "^3.3",
"nette/caching": "^3.1",
"nette/security": "^3.1"
"nette/caching": "^3.1"
},
"require-dev": {
"phpstan/phpstan": "^1.0",
Expand All @@ -31,6 +30,7 @@
"phpstan/phpstan-strict-rules": "^1.0",
"spaze/phpstan-disallowed-calls": "^2.0",
"baraja-core/localization": "^2.0",
"baraja-core/cas": "^1.0",
"tracy/tracy": "^2.8",
"roave/security-advisories": "dev-master"
},
Expand Down
77 changes: 25 additions & 52 deletions src/ApiManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Baraja\StructuredApi;


use Baraja\Localization\Localization;
use Baraja\RuntimeInvokeException;
use Baraja\Serializer\Serializer;
use Baraja\ServiceMethodInvoker;
Expand Down Expand Up @@ -61,26 +62,26 @@ public function __construct(
public function run(?string $path = null, ?array $params = [], ?string $method = null, bool $throw = false): void
{
$path ??= Url::get()->getRelativeUrl();
$this->checkFirewall();
$method = $method === null || $method === '' ? Helpers::httpMethod() : $method;
$params = array_merge($this->safeGetParams($path), $this->getBodyParams($method), $params ?? []);
$panel = new Panel($path, $params, $method);
Debugger::getBar()->addPanel($panel);
$isDebugger = class_exists(Debugger::class);
if ($isDebugger) {
Debugger::getBar()->addPanel($panel);
}

if (preg_match('/^api\/v(?<v>\d{1,3}(?:\.\d{1,3})?)\/(?<path>.*?)$/', $path, $pathParser) === 1) {
try {
$route = $this->route((string) preg_replace('/^(.*?)(\?.*|)$/', '$1', $pathParser['path']), $pathParser['v'], $params);
$response = null;
try {
$endpoint = $this->getEndpointService($route['class'], $params);
$endpoint = $this->getEndpointService($route['class']);
$panel->setEndpoint($endpoint);
$response = $this->process($endpoint, $params, $route['action'], $method, $panel);
$panel->setResponse($response);
} catch (StructuredApiException $e) {
throw $e;
} catch (\Throwable $e) {
$isDebugger = class_exists(Debugger::class);
if ($isDebugger === true) {
if ($isDebugger) {
Debugger::log($e, ILogger::EXCEPTION);
}

Expand Down Expand Up @@ -149,39 +150,14 @@ public function getEndpoints(): array
* Create new API endpoint instance with all injected dependencies.
*
* @param class-string $className
* @param array<string|int, mixed> $params
* @internal
*/
public function getEndpointService(string $className, array $params): Endpoint
public function getEndpointService(string $className): Endpoint
{
$endpoint = $this->container->getEndpoint($className);
$endpoint->setConvention($this->convention);

$createReflection = static function (object $class, string $propertyName): ?\ReflectionProperty {
try {
$ref = new \ReflectionProperty($class, $propertyName);
$ref->setAccessible(true);

return $ref;
} catch (\ReflectionException) {
$refClass = new \ReflectionClass($class);
$parentClass = $refClass->getParentClass();
while ($parentClass !== false) {
try {
$ref = $parentClass->getProperty($propertyName);
$ref->setAccessible(true);

return $ref;
} catch (\ReflectionException) {
$parentClass = $refClass->getParentClass();
}
}
}

return null;
};

$createReflection($endpoint, 'data')?->setValue($endpoint, $params);
if ($endpoint instanceof BaseEndpoint) {
$endpoint->convention = $this->convention;
}

return $endpoint;
}
Expand Down Expand Up @@ -336,8 +312,17 @@ private function invokeActionMethod(
array $params,
Panel $panel,
): ?Response {
$endpoint->startup();
$endpoint->startupCheck();
if (PHP_SAPI !== 'cli') {
$httpRequest = class_exists(Request::class)
? $this->container->getByType(Request::class)
: null;
$localization = class_exists(Localization::class)
? $this->container->getByType(Localization::class)
: null;
if ($httpRequest !== null && $localization !== null) {
$localization->processHttpRequest($httpRequest);
}
}

try {
$invoker = new ServiceMethodInvoker($this->projectEntityRepository);
Expand Down Expand Up @@ -381,8 +366,9 @@ private function invokeActionMethod(
if ($method !== 'GET' && $response === null) {
$response = new JsonResponse($this->convention, ['state' => 'ok']);
}

$endpoint->saveState();
if ($endpoint instanceof BaseEndpoint) {
$endpoint->saveState();
}

return $response;
}
Expand Down Expand Up @@ -432,19 +418,6 @@ private function getBodyParams(string $method): array
}


private function checkFirewall(): void
{
if (str_contains($_SERVER['HTTP_USER_AGENT'] ?? '', 'CloudFlare-AlwaysOnline') === true) {
header('HTTP/1.0 403 Forbidden');
echo '<title>Access denied | API endpoint</title>';
echo '<h1>Access denied</h1>';
echo '<p>API endpoint crawling is disabled for robots.</p>';
echo '<p><b>Information for developers:</b> Endpoint API indexing is disabled for privacy reasons. At the same time, robots can crawl a disproportionate amount of data, copying your valuable data.';
die;
}
}


private function rewriteInvalidArgumentException(\InvalidArgumentException $e): ?Response
{
$message = null;
Expand Down
37 changes: 37 additions & 0 deletions src/Bridge/LinkGeneratorBridge.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

declare(strict_types=1);

namespace Baraja\StructuredApi\Bridge;


use Nette\Application\LinkGenerator;

final class LinkGeneratorBridge
{
public function __construct(
private ?LinkGenerator $linkGenerator = null,
) {
}


/**
* Generates URL to presenter.
*
* @param string $dest in format "[[[module:]presenter:]action] [#fragment]"
* @param array<string, mixed> $params
* @throws \InvalidArgumentException
*/
public function link(string $dest, array $params = []): string
{
if ($this->linkGenerator === null) {
throw new \RuntimeException('Service LinkGenerator is not available. Did you install nette/application?');
}

try {
return $this->linkGenerator->link(ltrim($dest, ':'), $params);
} catch (\Throwable $e) {
throw new \InvalidArgumentException($e->getMessage(), $e->getCode());
}
}
}
Loading

0 comments on commit b94baa6

Please sign in to comment.