Passed
Pull Request — master (#5)
by Samuel
03:45
created

AbstractHandler::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
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\Support\Collection;
8
use SMartins\Exceptions\JsonApi\Error;
9
use Illuminate\Auth\AuthenticationException;
10
use Illuminate\Validation\ValidationException;
11
use Illuminate\Auth\Access\AuthorizationException;
12
use SMartins\Exceptions\Response\ErrorHandledInterface;
13
use Illuminate\Database\Eloquent\ModelNotFoundException;
14
use SMartins\Exceptions\JsonApi\Response as JsonApiResponse;
15
use SMartins\Exceptions\Response\ErrorHandledCollectionInterface;
16
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
17
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
18
19
abstract class AbstractHandler
20
{
21
    /**
22
     * The exception thrown.
23
     *
24
     * @var \Exception
25
     */
26
    protected $exception;
27
28
    /**
29
     * An array where the key is the class exception and the value is the handler
30
     * class that will treat the exception.
31
     *
32
     * @var array
33
     */
34
    protected $exceptionHandlers = [];
35
36
    /**
37
     * An internal array where the key is the exception class and the value is
38
     * the handler class that will treat the exception.
39
     *
40
     * @var array
41
     */
42
    protected $internalExceptionHandlers = [
43
        Exception::class => Handler::class,
44
        ModelNotFoundException::class => ModelNotFoundHandler::class,
45
        AuthenticationException::class => AuthenticationHandler::class,
46
        ValidationException::class => ValidationHandler::class,
47
        BadRequestHttpException::class => BadRequestHttpHandler::class,
48
        'Laravel\Passport\Exceptions\MissingScopeException' => MissingScopeHandler::class,
49
        'League\OAuth2\Server\Exception\OAuthServerException' => OAuthServerHandler::class,
50
    ];
51
52
    /**
53
     * Create instance using the Exception to be handled.
54
     *
55
     * @param Exception $e
56
     */
57
    public function __construct(Exception $e)
58
    {
59
        $this->exception = $e;
60
    }
61
62
    /**
63
     * Handle with an exception according to specific definitions. Returns one
64
     * or more errors using the exception from $exceptions attribute.
65
     *
66
     * @todo Change the return type to any interface to make more extensible.
67
     *
68
     * @return \SMartins\Exceptions\Response\ErrorHandledInterface|\Smartins\Exceptions\Response\ErrorHandledCollectionInterface
69
     */
70
    abstract public function handle();
71
72
    /**
73
     * Get error code. If code is empty from config file based on type.
74
     *
75
     * @param  string $type Code type from config file
76
     * @return int
77
     */
78
    public function getCode($type = 'default')
79
    {
80
        if (empty($code = $this->exception->getCode())) {
81
            return config('json-exception-handler.codes.'.$type);
82
        }
83
84
        return $code;
85
    }
86
87
    /**
88
     * Return response with handled exception.
89
     *
90
     * @return \SMartins\Exceptions\Response\AbstractResponse
91
     */
92
    public function handleException()
93
    {
94
        $handler = $this->getExceptionHandler();
95
96
        $errors = $this->validatedHandledException($handler->handle());
97
98
        $responseHandler = $this->getResponseHandler();
99
100
        return new $responseHandler($errors);
101
    }
102
103
    /**
104
     * Validate response from handle method of handler class.
105
     *
106
     * @param \SMartins\Exceptions\Response\ErrorHandledInterface|\Smartins\Exceptions\Response\ErrorHandledCollectionInterface
107
     * @return \SMartins\Exceptions\Response\ErrorHandledCollectionInterface
108
     *
109
     * @throws \InvalidArgumentException
110
     */
111
    public function validatedHandledException($error)
112
    {
113
        if ($error instanceof ErrorHandledCollectionInterface) {
114
            return $error->validatedContent(ErrorHandledInterface::class);
115
        } elseif ($error instanceof ErrorHandledInterface) {
116
            return $error->toCollection()->setStatusCode($error->getStatus());
0 ignored issues
show
Bug introduced by
The method setStatusCode() does not exist on SMartins\Exceptions\Resp...dledCollectionInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to SMartins\Exceptions\Resp...dledCollectionInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

116
            return $error->toCollection()->/** @scrutinizer ignore-call */ setStatusCode($error->getStatus());
Loading history...
117
        }
118
119
        throw new InvalidArgumentException('The errors must be an instance of ['.ErrorHandledInterface::class.'] or ['.ErrorHandledCollectionInterface::class.'].');
120
    }
121
122
    /**
123
     * Get the class the will handle the Exception from exceptionHandlers attributes.
124
     *
125
     * @return mixed
126
     */
127
    public function getExceptionHandler()
128
    {
129
        $handlers = $this->getConfiguredHandlers();
130
131
        $handler = isset($handlers[get_class($this->exception)])
132
            ? $handlers[get_class($this->exception)]
133
            : $this->getDefaultHandler();
134
135
        return new $handler($this->exception);
136
    }
137
138
    /**
139
     * Get exception handlers from internal and set on App\Exceptions\Handler.php
140
     *
141
     * @return array
142
     */
143
    public function getConfiguredHandlers()
144
    {
145
        return array_merge($this->exceptionHandlers, $this->internalExceptionHandlers);
146
    }
147
148
    /**
149
     * Get default pointer using file and line of exception.
150
     *
151
     * @return string
152
     */
153
    public function getDefaultPointer()
154
    {
155
        return $this->exception->getFile().':'.$this->exception->getLine();
156
    }
157
158
    /**
159
     * Get default title from exception.
160
     *
161
     * @return string
162
     */
163
    public function getDefaultTitle()
164
    {
165
        return snake_case(class_basename($this->exception));
166
    }
167
168
    /**
169
     * Get default http code. Check if exception has getStatusCode() methods.
170
     * If not get from config file.
171
     *
172
     * @return int
173
     */
174
    public function getStatusCode()
175
    {
176
        if (method_exists($this->exception, 'getStatusCode')) {
177
            return $this->exception->getStatusCode();
178
        }
179
180
        return config('json-exception-handler.http_code');
181
    }
182
183
    /**
184
     * The default handler to handle not treated exceptions.
185
     *
186
     * @return \SMartins\Exceptions\Handlers\Handler
187
     */
188
    public function getDefaultHandler()
189
    {
190
        return new Handler($this->exception);
191
    }
192
193
    /**
194
     * Get default response handler of the if any response handler was defined
195
     * on config file.
196
     *
197
     * @return string
198
     */
199
    public function getDefaultResponseHandler()
200
    {
201
        return JsonApiResponse::class;
202
    }
203
204
    /**
205
     * Get the response class that will handle the json response.
206
     *
207
     * @todo Check if the response_handler on config is an instance of
208
     *       \SMartins\Exceptions\Response\AbstractResponse
209
     * @return string
210
     */
211
    public function getResponseHandler()
212
    {
213
        $response = config('json-exception-handler.response_handler');
214
215
        return $response ?? $this->getDefaultResponseHandler();
216
    }
217
218
    /**
219
     * Set exception handlers.
220
     *
221
     * @param array $handlers
222
     */
223
    public function setExceptionHandlers(array $handlers)
224
    {
225
        $this->exceptionHandlers = $handlers;
226
227
        return $this;
228
    }
229
}
230