Skip to content

Commit

Permalink
feat(http-routing-bundle,testing-bundle): multiple url prefixes can t…
Browse files Browse the repository at this point in the history
…rigger early route-loading

Fix: #164
  • Loading branch information
calvinalkan committed Dec 6, 2022
1 parent 7a34a60 commit b95f50c
Show file tree
Hide file tree
Showing 16 changed files with 795 additions and 438 deletions.
20 changes: 17 additions & 3 deletions src/Snicco/Bundle/http-routing/config/routing.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,25 @@
],

/*
* The API prefix will be used to configure your API routes correctly and to determine if the current request
* goes to an API-endpoint.
* This option must be set if you are using api-routing. Feel free to remove it otherwise.
* The API_PREFIX is prepended to all routes inside the API_ROUTE_DIRECTORIES IF you are using
* the DefaultRouteLoadingOptions class. This is the case by default.
*
* If you are not using api-routes, or if you have bound a custom RouteLoadingOptions class in the container
* you can remove this option.
*/
RoutingOption::API_PREFIX => '',
//RoutingOption::API_PREFIX => '/my-plugin',

/*
* This option determines which request are considered API requests, which consequently
* will be run much earlier in the WP loading cycle.
*
* If you are not using a custom RouteLoadingOption class you can remove this option as the
* bundle will take care of adding the value of RoutingOption::API_PREFIX to this configuration
* value automatically.
*/
RoutingOption::EARLY_ROUTES_PREFIXES => [],
//RoutingOption::EARLY_ROUTES_PREFIXES => ['/my-plugin/foo', '/my-plugin/bar'],

/*
* The following three values should only be changed if you are developing on different ports locally.
Expand Down
56 changes: 56 additions & 0 deletions src/Snicco/Bundle/http-routing/src/ApiRequestDetector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

declare(strict_types=1);

namespace Snicco\Bundle\HttpRouting;

use Psr\Http\Message\ServerRequestInterface;
use Snicco\Component\StrArr\Arr;
use Snicco\Component\StrArr\Str;
use Webmozart\Assert\Assert;

use function array_map;
use function is_string;
use function ltrim;

/**
* @psalm-internal Snicco
*/
final class ApiRequestDetector
{
/**
* @var non-empty-string[]
*/
private array $api_prefixes;

/**
* @param non-empty-string[]|non-empty-string $early_route_prefixes
*/
public function __construct($early_route_prefixes)
{
$early_route_prefixes = Arr::toArray($early_route_prefixes);

Assert::allNotEq($early_route_prefixes, '/');

$early_route_prefixes = array_map(fn (string $prefix) => '/' . ltrim($prefix, '/'), $early_route_prefixes);

$this->api_prefixes = $early_route_prefixes;
}

/**
* @param string|ServerRequestInterface $path_or_request
*/
public function isAPIRequest($path_or_request): bool
{
$path = is_string($path_or_request) ? $path_or_request : $path_or_request->getUri()
->getPath();

foreach ($this->api_prefixes as $prefix) {
if (Str::startsWith($path, $prefix)) {
return true;
}
}

return false;
}
}
29 changes: 8 additions & 21 deletions src/Snicco/Bundle/http-routing/src/HttpKernelRunner.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,10 @@
use Snicco\Bundle\HttpRouting\ResponseEmitter\ResponseEmitter;
use Snicco\Component\HttpRouting\Http\Psr7\Request;
use Snicco\Component\HttpRouting\Http\Response\DelegatedResponse;
use Snicco\Component\StrArr\Str;

use function add_action;
use function did_action;
use function doing_action;
use function ltrim;
use function sprintf;

use const PHP_INT_MIN;
Expand All @@ -36,33 +34,27 @@ final class HttpKernelRunner

private StreamFactoryInterface $stream_factory;

/**
* @param non-empty-string|null $api_prefix
*/
private ?string $api_prefix;
private ApiRequestDetector $api_request_detector;

/**
* @param non-empty-string|null $api_prefix
* @interal
*
* @psalm-internal Snicco\Bundle\HttpRouting
*/
public function __construct(
HttpKernel $http_kernel,
ServerRequestCreator $request_creator,
EventDispatcherInterface $event_dispatcher,
ResponseEmitter $emitter,
StreamFactoryInterface $stream_factory,
?string $api_prefix
ApiRequestDetector $api_request_detector
) {
$this->http_kernel = $http_kernel;
$this->request_creator = $request_creator;
$this->event_dispatcher = $event_dispatcher;
$this->emitter = $emitter;
$this->stream_factory = $stream_factory;

if (null !== $api_prefix) {
$api_prefix = '/' . ltrim($api_prefix, '/');
}

$this->api_prefix = $api_prefix;
$this->api_request_detector = $api_request_detector;
}

/**
Expand All @@ -78,7 +70,7 @@ public function listen(bool $is_admin, string $frontend_hook = 'wp_loaded', stri

$psr_request = $this->request_creator->fromGlobals();

if ($this->isApiRequest($psr_request)) {
if ($this->api_request_detector->isAPIRequest($psr_request)) {
add_action($api_hook, function () use ($psr_request): void {
$this->dispatchFrontendRequest(Request::fromPsr($psr_request, Request::TYPE_API));
}, PHP_INT_MIN);
Expand All @@ -104,7 +96,7 @@ public function run(): void

$psr_request = $this->request_creator->fromGlobals();

$type = $this->isApiRequest($psr_request)
$type = $this->api_request_detector->isAPIRequest($psr_request)
? Request::TYPE_API
: Request::TYPE_FRONTEND;

Expand Down Expand Up @@ -192,11 +184,6 @@ private function dispatchAdminRequest(ServerRequestInterface $psr_request): void
}
}

private function isApiRequest(ServerRequestInterface $request): bool
{
return $this->api_prefix && Str::startsWith($request->getUri()->getPath(), $this->api_prefix);
}

/**
* We must create the PSR request before WordPress calls {@see
* wp_magic_quotes} and nukes the real server request data.
Expand Down
Loading

0 comments on commit b95f50c

Please sign in to comment.