1
|
|
|
<?php |
2
|
|
|
namespace Acelaya\ExpressiveErrorHandler\ErrorHandler; |
3
|
|
|
|
4
|
|
|
use Acelaya\ExpressiveErrorHandler\Exception\InvalidArgumentException; |
5
|
|
|
use Acelaya\ExpressiveErrorHandler\Log\LogMessageBuilderInterface; |
6
|
|
|
use Psr\Http\Message\ResponseInterface as Response; |
7
|
|
|
use Psr\Http\Message\ServerRequestInterface as Request; |
8
|
|
|
use Psr\Log\LoggerInterface; |
9
|
|
|
|
10
|
|
|
class ContentBasedErrorResponseGenerator implements ErrorResponseGeneratorInterface |
11
|
|
|
{ |
12
|
|
|
/** |
13
|
|
|
* @deprecated Inject the default content type to be used while creating this class |
14
|
|
|
*/ |
15
|
|
|
const DEFAULT_CONTENT = 'text/html'; |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* @var ErrorResponseGeneratorManagerInterface |
19
|
|
|
*/ |
20
|
|
|
private $errorHandlerManager; |
21
|
|
|
/** |
22
|
|
|
* @var LoggerInterface |
23
|
|
|
*/ |
24
|
|
|
private $logger; |
25
|
|
|
/** |
26
|
|
|
* @var LogMessageBuilderInterface |
27
|
|
|
*/ |
28
|
|
|
private $logMessageBuilder; |
29
|
|
|
/** |
30
|
|
|
* @var string |
31
|
|
|
*/ |
32
|
|
|
private $defaultContentType; |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* ContentBasedErrorResponseGenerator constructor. |
36
|
|
|
* @param ErrorResponseGeneratorManagerInterface|ErrorResponseGeneratorManager $errorHandlerManager |
37
|
|
|
* @param LoggerInterface $logger |
38
|
|
|
* @param LogMessageBuilderInterface $logMessageBuilder |
39
|
|
|
* @param string $defaultContentType |
40
|
|
|
*/ |
41
|
7 |
|
public function __construct( |
42
|
|
|
ErrorResponseGeneratorManagerInterface $errorHandlerManager, |
43
|
|
|
LoggerInterface $logger, |
44
|
|
|
LogMessageBuilderInterface $logMessageBuilder, |
45
|
|
|
$defaultContentType = 'text/html' |
46
|
|
|
) { |
47
|
7 |
|
$this->errorHandlerManager = $errorHandlerManager; |
48
|
7 |
|
$this->logger = $logger; |
49
|
7 |
|
$this->logMessageBuilder = $logMessageBuilder; |
50
|
7 |
|
$this->defaultContentType = $defaultContentType; |
51
|
7 |
|
} |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* Final handler for an application. |
55
|
|
|
* |
56
|
|
|
* @param \Throwable|\Exception $e |
57
|
|
|
* @param Request $request |
58
|
|
|
* @param Response $response |
59
|
|
|
* @return Response |
60
|
|
|
*/ |
61
|
5 |
|
public function __invoke($e, Request $request, Response $response) |
62
|
|
|
{ |
63
|
|
|
// Try to get an error handler for provided request accepted type |
64
|
5 |
|
$errorHandler = $this->resolveErrorHandlerFromAcceptHeader($request); |
65
|
4 |
|
$this->logger->error($this->logMessageBuilder->buildMessage($request, $response, $e)); |
|
|
|
|
66
|
4 |
|
return $errorHandler($e, $request, $response); |
67
|
|
|
} |
68
|
|
|
|
69
|
|
|
/** |
70
|
|
|
* Tries to resolve |
71
|
|
|
* |
72
|
|
|
* @param Request $request |
73
|
|
|
* @return callable |
74
|
|
|
* @throws InvalidArgumentException |
75
|
|
|
*/ |
76
|
5 |
|
protected function resolveErrorHandlerFromAcceptHeader(Request $request) |
77
|
|
|
{ |
78
|
|
|
// Try to find an error handler for one of the accepted content types |
79
|
5 |
|
$accepts = $request->hasHeader('Accept') ? $request->getHeaderLine('Accept') : $this->defaultContentType; |
80
|
|
|
/** @var array $accepts */ |
81
|
5 |
|
$accepts = explode(',', $accepts); |
82
|
5 |
|
foreach ($accepts as $accept) { |
83
|
5 |
|
if (! $this->errorHandlerManager->has($accept)) { |
84
|
4 |
|
continue; |
85
|
|
|
} |
86
|
|
|
|
87
|
2 |
|
return $this->errorHandlerManager->get($accept); |
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
// If it wasn't possible to find an error handler for accepted content type, use default one if registered |
91
|
3 |
|
if ($this->errorHandlerManager->has($this->defaultContentType)) { |
92
|
2 |
|
return $this->errorHandlerManager->get($this->defaultContentType); |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
// It wasn't possible to find an error handler |
96
|
1 |
|
throw new InvalidArgumentException(sprintf( |
97
|
|
|
'It wasn\'t possible to find an error handler for ["%s"] content types. ' |
98
|
1 |
|
. 'Make sure you have registered at least the default "%s" content type', |
99
|
1 |
|
implode('", "', $accepts), |
100
|
1 |
|
$this->defaultContentType |
101
|
|
|
)); |
102
|
|
|
} |
103
|
|
|
} |
104
|
|
|
|
This check looks at variables that have been passed in as parameters and are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.