Skip to content

Commit

Permalink
Merge branch refs/heads/master into feature/scopes
Browse files Browse the repository at this point in the history
  • Loading branch information
spiralbot committed May 30, 2024
1 parent a433340 commit 7cce9df
Show file tree
Hide file tree
Showing 8 changed files with 167 additions and 75 deletions.
12 changes: 6 additions & 6 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,17 @@
"php": ">=8.1",
"ext-json": "*",
"ext-mbstring": "*",
"spiral/core": "^3.13",
"spiral/files": "^3.13",
"spiral/streams": "^3.13",
"spiral/telemetry": "^3.13",
"spiral/core": "^3.14",
"spiral/files": "^3.14",
"spiral/streams": "^3.14",
"spiral/telemetry": "^3.14",
"psr/http-message": "^1.0|^2.0",
"psr/http-factory": "^1.0",
"psr/http-server-middleware": "^1.0",
"psr/event-dispatcher": "^1.0"
},
"require-dev": {
"spiral/boot": "^3.13",
"spiral/boot": "^3.14",
"phpunit/phpunit": "^10.1",
"mockery/mockery": "^1.5",
"nyholm/psr7": "^1.5",
Expand All @@ -58,7 +58,7 @@
},
"extra": {
"branch-alias": {
"dev-master": "3.13.x-dev"
"dev-master": "3.14.x-dev"
}
},
"config": {
Expand Down
29 changes: 29 additions & 0 deletions src/CurrentRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace Spiral\Http;

use Psr\Http\Message\ServerRequestInterface;
use Spiral\Core\Attribute\Scope;
use Spiral\Http\Exception\HttpException;

/**
* Provides access to the current request in the `http` scope.
* @internal
*/
#[Scope('http')]
final class CurrentRequest
{
private ?ServerRequestInterface $request = null;

public function set(ServerRequestInterface $request): void
{
$this->request = $request;
}

public function get(): ?ServerRequestInterface
{
return $this->request;
}
}
13 changes: 6 additions & 7 deletions src/Http.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ public function __construct(
private readonly Pipeline $pipeline,
private readonly ResponseFactoryInterface $responseFactory,
private readonly ContainerInterface $container,
?TracerFactoryInterface $tracerFactory = null
?TracerFactoryInterface $tracerFactory = null,
private readonly ?EventDispatcherInterface $dispatcher = null,
) {
foreach ($this->config->getMiddleware() as $middleware) {
$this->pipeline->pushMiddleware($this->container->get($middleware));
Expand Down Expand Up @@ -60,12 +61,10 @@ public function setHandler(callable|RequestHandlerInterface $handler): self
*/
public function handle(ServerRequestInterface $request): ResponseInterface
{
$callback = function (SpanInterface $span) use ($request): ResponseInterface {
$dispatcher = $this->container->has(EventDispatcherInterface::class)
? $this->container->get(EventDispatcherInterface::class)
: null;
$callback = function (SpanInterface $span, CurrentRequest $currentRequest) use ($request): ResponseInterface {
$currentRequest->set($request);

$dispatcher?->dispatch(new RequestReceived($request));
$this->dispatcher?->dispatch(new RequestReceived($request));

if ($this->handler === null) {
throw new HttpException('Unable to run HttpCore, no handler is set.');
Expand All @@ -84,7 +83,7 @@ public function handle(ServerRequestInterface $request): ResponseInterface
)
->setStatus($response->getStatusCode() < 500 ? 'OK' : 'ERROR');

$dispatcher?->dispatch(new RequestHandled($request, $response));
$this->dispatcher?->dispatch(new RequestHandled($request, $response));

return $response;
};
Expand Down
66 changes: 39 additions & 27 deletions src/Pipeline.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Spiral\Core\Attribute\Proxy;
use Spiral\Core\ContainerScope;
use Spiral\Core\ScopeInterface;
use Spiral\Http\Event\MiddlewareProcessing;
use Spiral\Http\Exception\PipelineException;
Expand All @@ -29,7 +31,7 @@ final class Pipeline implements RequestHandlerInterface, MiddlewareInterface
private ?RequestHandlerInterface $handler = null;

public function __construct(
private readonly ScopeInterface $scope,
#[Proxy] private readonly ScopeInterface $scope,
private readonly ?EventDispatcherInterface $dispatcher = null,
?TracerInterface $tracer = null
) {
Expand Down Expand Up @@ -61,40 +63,50 @@ public function handle(Request $request): Response
throw new PipelineException('Unable to run pipeline, no handler given.');
}

$position = $this->position++;
if (isset($this->middleware[$position])) {
// todo: find a better solution in the Spiral v4.0
/** @var CurrentRequest|null $currentRequest */
$currentRequest = ContainerScope::getContainer()?->get(CurrentRequest::class);

$previousRequest = $currentRequest?->get();
$currentRequest?->set($request);
try {
$position = $this->position++;
if (!isset($this->middleware[$position])) {
return $this->handler->handle($request);
}

$middleware = $this->middleware[$position];
$this->dispatcher?->dispatch(new MiddlewareProcessing($request, $middleware));

$callback = function (SpanInterface $span) use ($request, $middleware): Response {
$response = $middleware->process($request, $this);

$span
->setAttribute(
'http.status_code',
$response->getStatusCode()
)
->setAttribute(
'http.response_content_length',
$response->getHeaderLine('Content-Length') ?: $response->getBody()->getSize()
)
->setStatus($response->getStatusCode() < 500 ? 'OK' : 'ERROR');

return $response;
};

return $this->tracer->trace(
name: \sprintf('Middleware processing [%s]', $middleware::class),
callback: function (SpanInterface $span) use ($request, $middleware): Response {
$response = $middleware->process($request, $this);

$span
->setAttribute(
'http.status_code',
$response->getStatusCode()
)
->setAttribute(
'http.response_content_length',
$response->getHeaderLine('Content-Length') ?: $response->getBody()->getSize()
)
->setStatus($response->getStatusCode() < 500 ? 'OK' : 'ERROR');

return $response;
},
scoped: true,
callback: $callback,
attributes: [
'http.middleware' => $middleware::class,
]
],
scoped: true
);
} finally {
if ($previousRequest !== null) {
$currentRequest?->set($previousRequest);
}
}

$handler = $this->handler;
return $this->scope->runScope(
[Request::class => $request],
static fn (): Response => $handler->handle($request)
);
}
}
5 changes: 4 additions & 1 deletion src/Request/InputManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\UploadedFileInterface;
use Psr\Http\Message\UriInterface;
use Spiral\Core\Attribute\Proxy;
use Spiral\Core\Attribute\Scope;
use Spiral\Core\Attribute\Singleton;
use Spiral\Core\Exception\ScopeException;
use Spiral\Http\Config\HttpConfig;
Expand Down Expand Up @@ -48,6 +50,7 @@
* @method mixed attribute(string $name, mixed $default = null)
*/
#[Singleton]
#[Scope('http.request')]
final class InputManager
{
/**
Expand Down Expand Up @@ -115,7 +118,7 @@ final class InputManager

public function __construct(
/** @invisible */
private readonly ContainerInterface $container,
#[Proxy] private readonly ContainerInterface $container,
/** @invisible */
HttpConfig $config = new HttpConfig()
) {
Expand Down
30 changes: 10 additions & 20 deletions tests/HttpTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@
use Mockery as m;
use PHPUnit\Framework\TestCase;
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Http\Message\ServerRequestInterface;
use Spiral\Core\Container;
use Spiral\Core\ContainerScope;
use Spiral\Core\Options;
use Spiral\Http\CallableHandler;
use Spiral\Http\Config\HttpConfig;
use Spiral\Http\Event\RequestHandled;
Expand All @@ -23,15 +22,17 @@
use Spiral\Tests\Http\Diactoros\ResponseFactory;
use Nyholm\Psr7\ServerRequest;

class HttpTest extends TestCase
final class HttpTest extends TestCase
{
use m\Adapter\Phpunit\MockeryPHPUnitIntegration;

private Container $container;

public function setUp(): void
{
$this->container = new Container();
$options = new Options();
$options->checkScope = false;
$this->container = new Container(options: $options);
$this->container->bind(TracerInterface::class, new NullTracer($this->container));
}

Expand Down Expand Up @@ -223,20 +224,6 @@ public function testMiddlewareTraitReversed(): void
$this->assertSame('hello?', (string)$response->getBody());
}

public function testScope(): void
{
$core = $this->getCore();

$core->setHandler(function () {
$this->assertTrue(ContainerScope::getContainer()->has(ServerRequestInterface::class));

return 'OK';
});

$response = $core->handle(new ServerRequest('GET', ''));
$this->assertSame('OK', (string)$response->getBody());
}

public function testPassException(): void
{
$this->expectException(\RuntimeException::class);
Expand Down Expand Up @@ -293,7 +280,7 @@ public function testPassingTracerIntoScope(): void
$tracerFactory->shouldReceive('make')
->once()
->with(['foo' => ['bar']])
->andReturn($tracer = new NullTracer());
->andReturn(new NullTracer($this->container));

$response = $http->handle($request);
$this->assertSame('hello world', (string)$response->getBody());
Expand All @@ -307,7 +294,10 @@ protected function getCore(array $middleware = []): Http
$config,
new Pipeline($this->container),
new ResponseFactory($config),
$this->container
$this->container,
dispatcher: $this->container->has(EventDispatcherInterface::class)
? $this->container->get(EventDispatcherInterface::class)
: null,
);
}

Expand Down
Loading

0 comments on commit 7cce9df

Please sign in to comment.