Completed
Push — master ( 3cac8a...a3ee60 )
by Adrien
07:35
created

Server::execute()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2.0116

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 2
nop 1
dl 0
loc 14
ccs 6
cts 7
cp 0.8571
crap 2.0116
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Application\Api;
6
7
use Doctrine\DBAL\Exception\DriverException;
8
use GraphQL\Error\Debug;
9
use GraphQL\Executor\ExecutionResult;
10
use GraphQL\GraphQL;
11
use GraphQL\Server\ServerConfig;
12
use GraphQL\Server\StandardServer;
13
use Psr\Http\Message\ServerRequestInterface;
14
use Throwable;
15
use Zend\Expressive\Session\SessionMiddleware;
16
17
/**
18
 * A thin wrapper to serve GraphQL via HTTP or CLI
19
 */
20
class Server
21
{
22
    private $server;
23
24
    /**
25
     * @var ServerConfig
26
     */
27
    private $config;
28
29 34
    public function __construct(bool $debug)
30
    {
31 34
        GraphQL::setDefaultFieldResolver(new DefaultFieldResolver());
32 34
        $this->config = ServerConfig::create([
33 34
            'schema' => new Schema(),
34
            'queryBatching' => true,
35 34
            'debug' => $debug ? Debug::INCLUDE_DEBUG_MESSAGE | Debug::INCLUDE_TRACE : false,
36
            'errorsHandler' => function (array $errors, callable $formatter) {
37 6
                $result = [];
38 6
                foreach ($errors as $e) {
39 6
                    $result[] = $this->handleError($e, $formatter);
40
                }
41
42 6
                return $result;
43 34
            },
44
        ]);
45 34
        $this->server = new StandardServer($this->config);
46 34
    }
47
48
    /**
49
     * @param ServerRequestInterface $request
50
     *
51
     * @return ExecutionResult|ExecutionResult[]
52
     */
53 34
    public function execute(ServerRequestInterface $request)
54
    {
55 34
        if (!$request->getParsedBody()) {
56
            $request = $request->withParsedBody(json_decode($request->getBody()->getContents(), true));
57
        }
58
59
        // Affect it to global request so it is available for log purpose in case of error
60 34
        $_REQUEST = $request->getParsedBody();
61
62
        // Set current session as the only context we will ever need
63 34
        $session = $request->getAttribute(SessionMiddleware::SESSION_ATTRIBUTE);
64 34
        $this->config->setContext($session);
65
66 34
        return $this->server->executePsrRequest($request);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->server->executePsrRequest($request) also could return the type GraphQL\Executor\Promise\Promise which is incompatible with the documented return type GraphQL\Executor\Executi...xecutor\ExecutionResult.
Loading history...
67
    }
68
69
    /**
70
     * Send response to CLI
71
     *
72
     * @param ExecutionResult $result
73
     */
74
    public function sendCli(ExecutionResult $result): void
75
    {
76
        echo json_encode($result, JSON_PRETTY_PRINT) . PHP_EOL;
77
    }
78
79
    /**
80
     * Custom error handler to log in DB and show trigger messages to end-user
81
     *
82
     * @param Throwable $exception
83
     * @param callable $formatter
84
     *
85
     * @return array
86
     */
87 6
    private function handleError(Throwable $exception, callable $formatter): array
88
    {
89
        // Always log exception in DB (and by email)
90 6
        _log()->err($exception);
91
92
        // If we are absolutely certain that the error comes from one of our trigger with a custom message for end-user,
93
        // then wrap the exception to make it showable to the end-user
94 6
        $previous = $exception->getPrevious();
95 6
        if ($previous instanceof DriverException && $previous->getSQLState() === '45000' && $previous->getPrevious() && $previous->getPrevious()->getPrevious()) {
96
            $message = $previous->getPrevious()->getPrevious()->getMessage();
97
            $userMessage = preg_replace('~SQLSTATE\[45000\]: <<Unknown error>>: \d+ ~', '', $message, -1, $count);
98
            if ($count === 1) {
99
                $exception = new Exception($userMessage, null, $exception);
100
            }
101
        }
102
103 6
        return $formatter($exception);
104
    }
105
}
106