Passed
Pull Request — master (#5)
by Samuel
03:18 queued 01:41
created

AbstractHandler::handleException()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 0
dl 0
loc 9
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace SMartins\Exceptions\Handlers;
4
5
use Exception;
6
use InvalidArgumentException;
7
use Illuminate\Auth\AuthenticationException;
8
use Illuminate\Validation\ValidationException;
9
use SMartins\Exceptions\Response\ErrorHandledInterface;
10
use Illuminate\Database\Eloquent\ModelNotFoundException;
11
use SMartins\Exceptions\JsonApi\Response as JsonApiResponse;
12
use SMartins\Exceptions\Response\ErrorHandledCollectionInterface;
13
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
14
15
abstract class AbstractHandler
16
{
17
    /**
18
     * The exception thrown.
19
     *
20
     * @var \Exception
21
     */
22
    protected $exception;
23
24
    /**
25
     * An array where the key is the class exception and the value is the handler
26
     * class that will treat the exception.
27
     *
28
     * @var array
29
     */
30
    protected $exceptionHandlers = [];
31
32
    /**
33
     * An internal array where the key is the exception class and the value is
34
     * the handler class that will treat the exception.
35
     *
36
     * @var array
37
     */
38
    protected $internalExceptionHandlers = [
39
        Exception::class => Handler::class,
40
        ModelNotFoundException::class => ModelNotFoundHandler::class,
41
        AuthenticationException::class => AuthenticationHandler::class,
42
        ValidationException::class => ValidationHandler::class,
43
        BadRequestHttpException::class => BadRequestHttpHandler::class,
44
        'Laravel\Passport\Exceptions\MissingScopeException' => MissingScopeHandler::class,
45
        'League\OAuth2\Server\Exception\OAuthServerException' => OAuthServerHandler::class,
46
    ];
47
48
    /**
49
     * Create instance using the Exception to be handled.
50
     *
51
     * @param Exception $e
52
     */
53
    public function __construct(Exception $e)
54
    {
55
        $this->exception = $e;
56
    }
57
58
    /**
59
     * Handle with an exception according to specific definitions. Returns one
60
     * or more errors using the exception from $exceptions attribute.
61
     *
62
     * @return ErrorHandledInterface|ErrorHandledCollectionInterface
63
     */
64
    abstract public function handle();
65
66
    /**
67
     * Get error code. If code is empty from config file based on type.
68
     *
69
     * @param  string $type Code type from config file
70
     * @return int
71
     */
72
    public function getCode($type = 'default')
73
    {
74
        if (empty($code = $this->exception->getCode())) {
75
            return config('json-exception-handler.codes.'.$type);
76
        }
77
78
        return $code;
79
    }
80
81
    /**
82
     * Return response with handled exception.
83
     *
84
     * @return \SMartins\Exceptions\Response\AbstractResponse
85
     * @throws \SMartins\Exceptions\Response\InvalidContentException
86
     */
87
    public function handleException()
88
    {
89
        $handler = $this->getExceptionHandler();
90
91
        $errors = $this->validatedHandledException($handler->handle());
92
93
        $responseHandler = $this->getResponseHandler();
94
95
        return new $responseHandler($errors);
96
    }
97
98
    /**
99
     * Validate response from handle method of handler class.
100
     *
101
     * @param ErrorHandledInterface|ErrorHandledCollectionInterface
102
     * @return ErrorHandledCollectionInterface
103
     *
104
     * @throws \SMartins\Exceptions\Response\InvalidContentException
105
     */
106
    public function validatedHandledException($error)
107
    {
108
        if ($error instanceof ErrorHandledCollectionInterface) {
109
            return $error->validatedContent(ErrorHandledInterface::class);
110
        } elseif ($error instanceof ErrorHandledInterface) {
111
            return $error->toCollection()->setStatusCode($error->getStatus());
112
        }
113
114
        throw new InvalidArgumentException('The errors must be an instance of ['.ErrorHandledInterface::class.'] or ['.ErrorHandledCollectionInterface::class.'].');
115
    }
116
117
    /**
118
     * Get the class the will handle the Exception from exceptionHandlers attributes.
119
     *
120
     * @return mixed
121
     */
122
    public function getExceptionHandler()
123
    {
124
        $handlers = $this->getConfiguredHandlers();
125
126
        $handler = isset($handlers[get_class($this->exception)])
127
            ? $handlers[get_class($this->exception)]
128
            : $this->getDefaultHandler();
129
130
        return new $handler($this->exception);
131
    }
132
133
    /**
134
     * Get exception handlers from internal and set on App\Exceptions\Handler.php.
135
     *
136
     * @return array
137
     */
138
    public function getConfiguredHandlers()
139
    {
140
        return array_merge($this->internalExceptionHandlers, $this->exceptionHandlers);
141
    }
142
143
    /**
144
     * Get default pointer using file and line of exception.
145
     *
146
     * @return string
147
     */
148
    public function getDefaultPointer()
149
    {
150
        return $this->exception->getFile().':'.$this->exception->getLine();
151
    }
152
153
    /**
154
     * Get default title from exception.
155
     *
156
     * @return string
157
     */
158
    public function getDefaultTitle()
159
    {
160
        return snake_case(class_basename($this->exception));
161
    }
162
163
    /**
164
     * Get default http code. Check if exception has getStatusCode() methods.
165
     * If not get from config file.
166
     *
167
     * @return int
168
     */
169
    public function getStatusCode()
170
    {
171
        if (method_exists($this->exception, 'getStatusCode')) {
172
            return $this->exception->getStatusCode();
173
        }
174
175
        return config('json-exception-handler.http_code');
176
    }
177
178
    /**
179
     * The default handler to handle not treated exceptions.
180
     *
181
     * @return \SMartins\Exceptions\Handlers\Handler
182
     */
183
    public function getDefaultHandler()
184
    {
185
        return new Handler($this->exception);
186
    }
187
188
    /**
189
     * Get default response handler of the if any response handler was defined
190
     * on config file.
191
     *
192
     * @return string
193
     */
194
    public function getDefaultResponseHandler()
195
    {
196
        return JsonApiResponse::class;
197
    }
198
199
    /**
200
     * Get the response class that will handle the json response.
201
     *
202
     * @todo Check if the response_handler on config is an instance of
203
     *       \SMartins\Exceptions\Response\AbstractResponse
204
     * @return string
205
     */
206
    public function getResponseHandler()
207
    {
208
        $response = config('json-exception-handler.response_handler');
209
210
        return $response ?? $this->getDefaultResponseHandler();
211
    }
212
213
    /**
214
     * Set exception handlers.
215
     *
216
     * @param array $handlers
217
     * @return AbstractHandler
218
     */
219
    public function setExceptionHandlers(array $handlers)
220
    {
221
        $this->exceptionHandlers = $handlers;
222
223
        return $this;
224
    }
225
}
226