Completed
Pull Request — master (#5)
by Samuel
03:56 queued 01:56
created

AbstractHandler::getResponseHandler()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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