• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

IlyasDeckers / ody-core / 13532154862

25 Feb 2025 10:24PM UTC coverage: 30.374% (+1.7%) from 28.706%
13532154862

push

github

web-flow
Update php.yml

544 of 1791 relevant lines covered (30.37%)

9.13 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

14.89
/src/Middleware/ErrorMiddleware.php
1
<?php
2
declare(strict_types=1);
3

4
namespace Ody\Core\Middleware;
5

6
use Psr\Http\Message\ResponseFactoryInterface;
7
use Psr\Http\Message\ResponseInterface;
8
use Psr\Http\Message\ServerRequestInterface;
9
use Psr\Http\Server\MiddlewareInterface;
10
use Psr\Http\Server\RequestHandlerInterface;
11
use Psr\Log\LoggerInterface;
12
use Ody\Core\Exception\HttpException;
13
use Ody\Core\Handlers\ErrorHandler;
14
use Ody\Core\Interfaces\CallableResolverInterface;
15
use Ody\Core\Interfaces\ErrorHandlerInterface;
16
use Throwable;
17

18
use function get_class;
19
use function is_subclass_of;
20

21
/** @api */
22
class ErrorMiddleware implements MiddlewareInterface
23
{
24
    protected CallableResolverInterface $callableResolver;
25

26
    protected ResponseFactoryInterface $responseFactory;
27

28
    protected bool $displayErrorDetails;
29

30
    protected bool $logErrors;
31

32
    protected bool $logErrorDetails;
33

34
    protected ?LoggerInterface $logger = null;
35

36
    /**
37
     * @var ErrorHandlerInterface[]|callable[]|string[]
38
     */
39
    protected array $handlers = [];
40

41
    /**
42
     * @var ErrorHandlerInterface[]|callable[]|string[]
43
     */
44
    protected array $subClassHandlers = [];
45

46
    /**
47
     * @var ErrorHandlerInterface|callable|string|null
48
     */
49
    protected $defaultErrorHandler;
50

51
    public function __construct(
1✔
52
        CallableResolverInterface $callableResolver,
53
        ResponseFactoryInterface $responseFactory,
54
        bool $displayErrorDetails,
55
        bool $logErrors,
56
        bool $logErrorDetails,
57
        ?LoggerInterface $logger = null
58
    ) {
59
        $this->callableResolver = $callableResolver;
1✔
60
        $this->responseFactory = $responseFactory;
1✔
61
        $this->displayErrorDetails = $displayErrorDetails;
1✔
62
        $this->logErrors = $logErrors;
1✔
63
        $this->logErrorDetails = $logErrorDetails;
1✔
64
        $this->logger = $logger;
1✔
65
    }
66

67
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
×
68
    {
69
        try {
70
            return $handler->handle($request);
×
71
        } catch (Throwable $e) {
×
72
            return $this->handleException($request, $e);
×
73
        }
74
    }
75

76
    public function handleException(ServerRequestInterface $request, Throwable $exception): ResponseInterface
×
77
    {
78
        if ($exception instanceof HttpException) {
×
79
            $request = $exception->getRequest();
×
80
        }
81

82
        $exceptionType = get_class($exception);
×
83
        $handler = $this->getErrorHandler($exceptionType);
×
84

85
        return $handler($request, $exception, $this->displayErrorDetails, $this->logErrors, $this->logErrorDetails);
×
86
    }
87

88
    /**
89
     * Get callable to handle scenarios where an error
90
     * occurs when processing the current request.
91
     *
92
     * @param string $type Exception/Throwable name. ie: RuntimeException::class
93
     * @return callable|ErrorHandler
94
     */
95
    public function getErrorHandler(string $type)
×
96
    {
97
        if (isset($this->handlers[$type])) {
×
98
            return $this->callableResolver->resolve($this->handlers[$type]);
×
99
        }
100

101
        if (isset($this->subClassHandlers[$type])) {
×
102
            return $this->callableResolver->resolve($this->subClassHandlers[$type]);
×
103
        }
104

105
        foreach ($this->subClassHandlers as $class => $handler) {
×
106
            if (is_subclass_of($type, $class)) {
×
107
                return $this->callableResolver->resolve($handler);
×
108
            }
109
        }
110

111
        return $this->getDefaultErrorHandler();
×
112
    }
113

114
    /**
115
     * Get default error handler
116
     *
117
     * @return ErrorHandler|callable
118
     */
119
    public function getDefaultErrorHandler()
×
120
    {
121
        if ($this->defaultErrorHandler === null) {
×
122
            $this->defaultErrorHandler = new ErrorHandler(
×
123
                $this->callableResolver,
×
124
                $this->responseFactory,
×
125
                $this->logger
×
126
            );
×
127
        }
128

129
        return $this->callableResolver->resolve($this->defaultErrorHandler);
×
130
    }
131

132
    /**
133
     * Set callable as the default application error handler.
134
     *
135
     * The callable signature MUST match the ErrorHandlerInterface
136
     *
137
     * @see \Ody\Core\Interfaces\ErrorHandlerInterface
138
     *
139
     * 1. Instance of \Psr\Http\Message\ServerRequestInterface
140
     * 2. Instance of \Throwable
141
     * 3. Boolean $displayErrorDetails
142
     * 4. Boolean $logErrors
143
     * 5. Boolean $logErrorDetails
144
     *
145
     * The callable MUST return an instance of
146
     * \Psr\Http\Message\ResponseInterface.
147
     *
148
     * @param string|callable|ErrorHandler $handler
149
     */
150
    public function setDefaultErrorHandler($handler): self
×
151
    {
152
        $this->defaultErrorHandler = $handler;
×
153
        return $this;
×
154
    }
155

156
    /**
157
     * Set callable to handle scenarios where an error
158
     * occurs when processing the current request.
159
     *
160
     * The callable signature MUST match the ErrorHandlerInterface
161
     *
162
     * Pass true to $handleSubclasses to make the handler handle all subclasses of
163
     * the type as well. Pass an array of classes to make the same function handle multiple exceptions.
164
     *
165
     * @see \Ody\Core\Interfaces\ErrorHandlerInterface
166
     *
167
     * 1. Instance of \Psr\Http\Message\ServerRequestInterface
168
     * 2. Instance of \Throwable
169
     * 3. Boolean $displayErrorDetails
170
     * 4. Boolean $logErrors
171
     * 5. Boolean $logErrorDetails
172
     *
173
     * The callable MUST return an instance of
174
     * \Psr\Http\Message\ResponseInterface.
175
     *
176
     * @param string|string[] $typeOrTypes Exception/Throwable name.
177
     * ie: RuntimeException::class or an array of classes
178
     * ie: [HttpNotFoundException::class, HttpMethodNotAllowedException::class]
179
     * @param string|callable|ErrorHandlerInterface $handler
180
     */
181
    public function setErrorHandler($typeOrTypes, $handler, bool $handleSubclasses = false): self
×
182
    {
183
        if (is_array($typeOrTypes)) {
×
184
            foreach ($typeOrTypes as $type) {
×
185
                $this->addErrorHandler($type, $handler, $handleSubclasses);
×
186
            }
187
        } else {
188
            $this->addErrorHandler($typeOrTypes, $handler, $handleSubclasses);
×
189
        }
190

191
        return $this;
×
192
    }
193

194
    /**
195
     * Used internally to avoid code repetition when passing multiple exceptions to setErrorHandler().
196
     * @param string|callable|ErrorHandlerInterface $handler
197
     */
198
    private function addErrorHandler(string $type, $handler, bool $handleSubclasses): void
×
199
    {
200
        if ($handleSubclasses) {
×
201
            $this->subClassHandlers[$type] = $handler;
×
202
        } else {
203
            $this->handlers[$type] = $handler;
×
204
        }
205
    }
206
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc