Test Failed
Pull Request — master (#816)
by butschster
06:13 queued 32s
created

Http::setHandler()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 4
c 0
b 0
f 0
dl 0
loc 7
rs 10
ccs 3
cts 3
cp 1
cc 2
nc 2
nop 1
crap 2
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\TracerFactory;
20
use Spiral\Telemetry\SpanInterface;
21
use Spiral\Telemetry\TraceKind;
22 99
use Spiral\Telemetry\TracerFactoryInterface;
23
use Spiral\Telemetry\TracerInterface;
24
25
final class Http implements RequestHandlerInterface
26
{
27
    private ?RequestHandlerInterface $handler = null;
28 99
29 58
    public function __construct(
30
        private readonly HttpConfig $config,
31
        private readonly Pipeline $pipeline,
32
        private readonly ResponseFactoryInterface $responseFactory,
33 23
        private readonly ContainerInterface $container,
34
        private readonly ?ScopeInterface $scope = new Container(),
35 23
        private readonly ?TracerFactoryInterface $tracerFactory = new TracerFactory()
36
    ) {
37
        foreach ($this->config->getMiddleware() as $middleware) {
38 97
            $this->pipeline->pushMiddleware($this->container->get($middleware));
39
        }
40 97
    }
41 47
42 60
    public function getPipeline(): Pipeline
43
    {
44 97
        return $this->pipeline;
45
    }
46
47
    public function setHandler(callable|RequestHandlerInterface $handler): self
48
    {
49
        $this->handler = $handler instanceof RequestHandlerInterface
50 97
            ? $handler
51
            : new CallableHandler($handler, $this->responseFactory);
52 97
53 1
        return $this;
54 96
    }
55
56
    /**
57 97
     * @throws HttpException
58
     */
59 97
    public function handle(ServerRequestInterface $request): ResponseInterface
60 1
    {
61
        $callback = function (SpanInterface $span) use ($request): ResponseInterface {
62
            $dispatcher = $this->container->has(EventDispatcherInterface::class)
63 96
                ? $this->container->get(EventDispatcherInterface::class)
64
                : null;
65 91
66
            $dispatcher?->dispatch(new RequestReceived($request));
67 91
68
            if ($this->handler === null) {
69
                throw new HttpException('Unable to run HttpCore, no handler is set.');
70
            }
71
72
            $response = $this->pipeline->withHandler($this->handler)->handle($request);
73
74
            $span
75
                ->setAttribute(
76
                    'http.status_code',
77
                    $response->getStatusCode()
78
                )
79
                ->setAttribute(
80
                    'http.response_content_length',
81
                    $response->getHeaderLine('Content-Length') ?: $response->getBody()->getSize()
82
                )
83
                ->setStatus($response->getStatusCode() < 500 ? 'OK' : 'ERROR');
84
85
            $dispatcher?->dispatch(new RequestHandled($request, $response));
86
87
            return $response;
88
        };
89
90
        $tracer = $this->tracerFactory->fromContext($request->getHeaders());
0 ignored issues
show
Bug introduced by
The method fromContext() does not exist on null. ( Ignorable by Annotation )

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

90
        /** @scrutinizer ignore-call */ 
91
        $tracer = $this->tracerFactory->fromContext($request->getHeaders());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
91
92
        return $this->scope->runScope([
0 ignored issues
show
Bug introduced by
The method runScope() does not exist on null. ( Ignorable by Annotation )

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

92
        return $this->scope->/** @scrutinizer ignore-call */ runScope([

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
93
            TracerInterface::class => $tracer,
94
        ], static function () use ($callback, $request, $tracer): ResponseInterface {
95
            /** @var ResponseInterface $response */
96
            $response = $tracer->trace(
97
                name: \sprintf('%s %s', $request->getMethod(), (string)$request->getUri()),
98
                callback: $callback,
99
                attributes: [
100
                    'http.method' => $request->getMethod(),
101
                    'http.url' => $request->getUri(),
102
                    'http.headers' => $request->getHeaders(),
103
                ],
104
                scoped: true,
105
                traceKind: TraceKind::SERVER
106
            );
107
108
            $context = $tracer->getContext();
109
110
            if ($context !== null) {
111
                foreach ($context as $key => $value) {
112
                    $response = $response->withHeader($key, $value);
113
                }
114
            }
115
116
            return $response;
117
        });
118
    }
119
}
120