Passed
Pull Request — master (#816)
by butschster
06:49
created

Http::handle()   B

Complexity

Conditions 6
Paths 1

Size

Total Lines 54
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 26
CRAP Score 6.0018

Importance

Changes 0
Metric Value
eloc 34
dl 0
loc 54
rs 8.7537
c 0
b 0
f 0
ccs 26
cts 27
cp 0.963
cc 6
nc 1
nop 1
crap 6.0018

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Spiral\Http;
6
7
use Psr\Container\ContainerInterface;
8
use Psr\EventDispatcher\EventDispatcherInterface;
9
use Psr\Http\Message\ResponseFactoryInterface;
10
use Psr\Http\Message\ResponseInterface;
11
use Psr\Http\Message\ServerRequestInterface;
12
use Psr\Http\Server\RequestHandlerInterface;
13
use Spiral\Core\Container;
14
use Spiral\Core\ScopeInterface;
15
use Spiral\Http\Config\HttpConfig;
16
use Spiral\Http\Event\RequestHandled;
17
use Spiral\Http\Event\RequestReceived;
18
use Spiral\Http\Exception\HttpException;
19
use Spiral\Telemetry\NullTracerFactory;
20
use Spiral\Telemetry\SpanInterface;
21
use Spiral\Telemetry\TraceKind;
22
use Spiral\Telemetry\TracerFactoryInterface;
23
use Spiral\Telemetry\TracerInterface;
24
25
final class Http implements RequestHandlerInterface
26
{
27
    private ?RequestHandlerInterface $handler = null;
28
    private readonly TracerFactoryInterface $tracerFactory;
29
    private readonly ScopeInterface $scope;
30
31 100
    public function __construct(
32
        private readonly HttpConfig $config,
33
        private readonly Pipeline $pipeline,
34
        private readonly ResponseFactoryInterface $responseFactory,
35
        private readonly ContainerInterface $container,
36
        ?ScopeInterface $scope = null,
37
        ?TracerFactoryInterface $tracerFactory = null
38
    ) {
39 100
        foreach ($this->config->getMiddleware() as $middleware) {
40 58
            $this->pipeline->pushMiddleware($this->container->get($middleware));
41
        }
42
43 100
        $this->scope = $scope ?? ($this->container instanceof ScopeInterface ? $this->container : new Container());
0 ignored issues
show
Bug introduced by
The property scope is declared read-only in Spiral\Http\Http.
Loading history...
44 100
        $this->tracerFactory = $tracerFactory ?? new NullTracerFactory($this->scope);
0 ignored issues
show
Bug introduced by
The property tracerFactory is declared read-only in Spiral\Http\Http.
Loading history...
45
    }
46
47 23
    public function getPipeline(): Pipeline
48
    {
49 23
        return $this->pipeline;
50
    }
51
52 98
    public function setHandler(callable|RequestHandlerInterface $handler): self
53
    {
54 98
        $this->handler = $handler instanceof RequestHandlerInterface
55 47
            ? $handler
56 61
            : new CallableHandler($handler, $this->responseFactory);
57
58 98
        return $this;
59
    }
60
61
    /**
62
     * @throws HttpException
63
     */
64 98
    public function handle(ServerRequestInterface $request): ResponseInterface
65
    {
66 98
        $callback = function (SpanInterface $span) use ($request): ResponseInterface {
67 98
            $dispatcher = $this->container->has(EventDispatcherInterface::class)
68 1
                ? $this->container->get(EventDispatcherInterface::class)
69 97
                : null;
70
71 98
            $dispatcher?->dispatch(new RequestReceived($request));
72
73 98
            if ($this->handler === null) {
74 1
                throw new HttpException('Unable to run HttpCore, no handler is set.');
75
            }
76
77 97
            $response = $this->pipeline->withHandler($this->handler)->handle($request);
78
79
            $span
80 92
                ->setAttribute(
81
                    'http.status_code',
82 92
                    $response->getStatusCode()
83
                )
84 92
                ->setAttribute(
85
                    'http.response_content_length',
86 92
                    $response->getHeaderLine('Content-Length') ?: $response->getBody()->getSize()
87
                )
88 92
                ->setStatus($response->getStatusCode() < 500 ? 'OK' : 'ERROR');
89
90 92
            $dispatcher?->dispatch(new RequestHandled($request, $response));
91
92 92
            return $response;
93
        };
94
95 98
        $tracer = $this->tracerFactory->make($request->getHeaders());
96
97 98
        return $this->scope->runScope([
98
            TracerInterface::class => $tracer,
99 98
        ], static function () use ($callback, $request, $tracer): ResponseInterface {
100
            /** @var ResponseInterface $response */
101 98
            $response = $tracer->trace(
102 98
                name: \sprintf('%s %s', $request->getMethod(), (string)$request->getUri()),
103
                callback: $callback,
104
                attributes: [
105 98
                    'http.method' => $request->getMethod(),
106 98
                    'http.url' => $request->getUri(),
107 98
                    'http.headers' => $request->getHeaders(),
108
                ],
109
                scoped: true,
110
                traceKind: TraceKind::SERVER
111
            );
112
113 92
            foreach ($tracer->getContext() as $key => $value) {
114
                $response = $response->withHeader($key, $value);
115
            }
116
117 92
            return $response;
118
        });
119
    }
120
}
121