Passed
Push — master ( a2340d...9d7d2b )
by butschster
06:32
created

Http::handle()   B

Complexity

Conditions 6
Paths 2

Size

Total Lines 51
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 36
CRAP Score 6.0007

Importance

Changes 0
Metric Value
eloc 31
dl 0
loc 51
ccs 36
cts 37
cp 0.973
rs 8.8017
c 0
b 0
f 0
cc 6
nc 2
nop 1
crap 6.0007

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
24
final class Http implements RequestHandlerInterface
25
{
26
    private ?RequestHandlerInterface $handler = null;
27
    private readonly TracerFactoryInterface $tracerFactory;
28
29 105
    public function __construct(
30
        private readonly HttpConfig $config,
31
        private readonly Pipeline $pipeline,
32
        private readonly ResponseFactoryInterface $responseFactory,
33
        private readonly ContainerInterface $container,
34
        ?TracerFactoryInterface $tracerFactory = null
35
    ) {
36 105
        foreach ($this->config->getMiddleware() as $middleware) {
37 58
            $this->pipeline->pushMiddleware($this->container->get($middleware));
38
        }
39
40 105
        $scope = $this->container instanceof ScopeInterface ? $this->container : new Container();
41 105
        $this->tracerFactory = $tracerFactory ?? new NullTracerFactory($scope);
0 ignored issues
show
Bug introduced by
It seems like $scope can also be of type Psr\Container\ContainerInterface; however, parameter $scope of Spiral\Telemetry\NullTracerFactory::__construct() does only seem to accept Spiral\Core\ScopeInterface|null, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

41
        $this->tracerFactory = $tracerFactory ?? new NullTracerFactory(/** @scrutinizer ignore-type */ $scope);
Loading history...
Bug introduced by
The property tracerFactory is declared read-only in Spiral\Http\Http.
Loading history...
42
    }
43
44 28
    public function getPipeline(): Pipeline
45
    {
46 28
        return $this->pipeline;
47
    }
48
49 103
    public function setHandler(callable|RequestHandlerInterface $handler): self
50
    {
51 103
        $this->handler = $handler instanceof RequestHandlerInterface
52 47
            ? $handler
53 66
            : new CallableHandler($handler, $this->responseFactory);
54
55 103
        return $this;
56
    }
57
58
    /**
59
     * @throws HttpException
60
     */
61 103
    public function handle(ServerRequestInterface $request): ResponseInterface
62
    {
63 103
        $callback = function (SpanInterface $span) use ($request): ResponseInterface {
64 103
            $dispatcher = $this->container->has(EventDispatcherInterface::class)
65 1
                ? $this->container->get(EventDispatcherInterface::class)
66 102
                : null;
67
68 103
            $dispatcher?->dispatch(new RequestReceived($request));
69
70 103
            if ($this->handler === null) {
71 1
                throw new HttpException('Unable to run HttpCore, no handler is set.');
72
            }
73
74 102
            $response = $this->pipeline->withHandler($this->handler)->handle($request);
75
76 97
            $span
77 97
                ->setAttribute(
78 97
                    'http.status_code',
79 97
                    $response->getStatusCode()
80 97
                )
81 97
                ->setAttribute(
82 97
                    'http.response_content_length',
83 97
                    $response->getHeaderLine('Content-Length') ?: $response->getBody()->getSize()
84 97
                )
85 97
                ->setStatus($response->getStatusCode() < 500 ? 'OK' : 'ERROR');
86
87 97
            $dispatcher?->dispatch(new RequestHandled($request, $response));
88
89 97
            return $response;
90 103
        };
91
92 103
        $tracer = $this->tracerFactory->make($request->getHeaders());
93
94
        /** @var ResponseInterface $response */
95 103
        $response = $tracer->trace(
96 103
            name: \sprintf('%s %s', $request->getMethod(), (string)$request->getUri()),
97 103
            callback: $callback,
98 103
            attributes: [
99 103
                'http.method' => $request->getMethod(),
100 103
                'http.url' => $request->getUri(),
101 103
                'http.headers' => $request->getHeaders(),
102 103
            ],
103 103
            scoped: true,
104 103
            traceKind: TraceKind::SERVER
105 103
        );
106
107 97
        foreach ($tracer->getContext() as $key => $value) {
108
            $response = $response->withHeader($key, $value);
109
        }
110
111 97
        return $response;
112
    }
113
}
114