Completed
Push — master ( d2e5ad...577245 )
by Tobias
13s queued 11s
created

Configuration::getConfigTreeBuilder()   B

Complexity

Conditions 4
Paths 1

Size

Total Lines 145

Duplication

Lines 11
Ratio 7.59 %

Code Coverage

Tests 123
CRAP Score 4.0016

Importance

Changes 0
Metric Value
cc 4
nc 1
nop 0
dl 11
loc 145
ccs 123
cts 129
cp 0.9535
crap 4.0016
rs 8
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/*
4
 * This file is part of the FOSRestBundle package.
5
 *
6
 * (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace FOS\RestBundle\DependencyInjection;
13
14
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
15
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
16
use Symfony\Component\Config\Definition\ConfigurationInterface;
17
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
18
use Symfony\Component\HttpFoundation\Response;
19
use Symfony\Component\OptionsResolver\OptionsResolver;
20
use Symfony\Component\Serializer\Encoder\XmlEncoder;
21
22
/**
23
 * This class contains the configuration information for the bundle.
24
 *
25
 * This information is solely responsible for how the different configuration
26
 * sections are normalized, and merged.
27
 *
28
 * @author Lukas Kahwe Smith <[email protected]>
29
 *
30
 * @internal
31
 */
32
final class Configuration implements ConfigurationInterface
33
{
34
    private $debug;
35
36 62
    public function __construct(bool $debug)
37
    {
38 62
        $this->debug = $debug;
39 62
    }
40
41 61
    public function getConfigTreeBuilder(): TreeBuilder
42
    {
43 61
        $treeBuilder = new TreeBuilder('fos_rest');
44
45 61
        $rootNode = $treeBuilder->getRootNode();
46
47
        $rootNode
48 61
            ->children()
49 61
                ->scalarNode('disable_csrf_role')->defaultNull()->end()
50 61
                ->arrayNode('access_denied_listener')
51 61
                    ->canBeEnabled()
52 61
                    ->beforeNormalization()
53 View Code Duplication
                        ->ifArray()->then(function ($v) {
54
                            if (!empty($v) && empty($v['formats'])) {
55
                                unset($v['enabled']);
56
                                $v = ['enabled' => true, 'formats' => $v];
57
                            }
58
59
                            return $v;
60 61
                        })
61 61
                    ->end()
62 61
                    ->fixXmlConfig('format', 'formats')
63 61
                    ->children()
64 61
                        ->scalarNode('service')->defaultNull()->end()
65 61
                        ->arrayNode('formats')
66 61
                            ->useAttributeAsKey('name')
67 61
                            ->prototype('boolean')->end()
68 61
                        ->end()
69 61
                    ->end()
70 61
                ->end()
71 61
                ->scalarNode('unauthorized_challenge')->defaultNull()->end()
72 61
                ->arrayNode('param_fetcher_listener')
73 61
                    ->beforeNormalization()
74 61
                        ->ifString()
75 View Code Duplication
                        ->then(function ($v) {
76 1
                            return ['enabled' => in_array($v, ['force', 'true']), 'force' => 'force' === $v];
77 61
                        })
78 61
                    ->end()
79 61
                    ->canBeEnabled()
80 61
                    ->children()
81 61
                        ->booleanNode('force')->defaultFalse()->end()
82 61
                        ->scalarNode('service')->defaultNull()->end()
83 61
                    ->end()
84 61
                ->end()
85 61
                ->scalarNode('cache_dir')->cannotBeEmpty()->defaultValue('%kernel.cache_dir%/fos_rest')->end()
86 61
                ->arrayNode('allowed_methods_listener')
87 61
                    ->canBeEnabled()
88 61
                    ->children()
89 61
                        ->scalarNode('service')->defaultNull()->end()
90 61
                    ->end()
91 61
                ->end()
92 61
                ->booleanNode('routing_loader')
93 61
                    ->defaultValue(false)
94 61
                    ->validate()
95 61
                        ->ifTrue()
96 61
                        ->thenInvalid('only "false" is supported')
97 61
                    ->end()
98 61
                ->end()
99 61
                ->arrayNode('body_converter')
100 61
                    ->canBeEnabled()
101 61
                    ->children()
102 61
                        ->scalarNode('validate')
103 61
                            ->defaultFalse()
104 61
                            ->beforeNormalization()
105 61
                                ->ifTrue()
106
                                ->then(function ($value) {
107 1
                                    if (!class_exists(OptionsResolver::class)) {
108
                                        throw new InvalidConfigurationException("'body_converter.validate: true' requires OptionsResolver component installation ( composer require symfony/options-resolver )");
109
                                    }
110
111 1
                                    return $value;
112 61
                                })
113 61
                            ->end()
114 61
                        ->end()
115 61
                        ->scalarNode('validation_errors_argument')->defaultValue('validationErrors')->end()
116 61
                    ->end()
117 61
                ->end()
118 61
                ->arrayNode('service')
119 61
                    ->addDefaultsIfNotSet()
120 61
                    ->children()
121 61
                        ->scalarNode('templating')
122 61
                            ->defaultNull()
123 61
                            ->validate()
124 61
                                ->ifString()
125 61
                                ->thenInvalid('only null is supported')
126 61
                            ->end()
127 61
                        ->end()
128 61
                        ->scalarNode('serializer')->defaultNull()->end()
129 61
                        ->scalarNode('view_handler')->defaultValue('fos_rest.view_handler.default')->end()
130 61
                        ->scalarNode('inflector')
131 61
                            ->defaultNull()
132 61
                            ->validate()
133 61
                                ->ifString()
134 61
                                ->thenInvalid('only null is supported')
135 61
                            ->end()
136 61
                        ->end()
137 61
                        ->scalarNode('validator')->defaultValue('validator')->end()
138 61
                    ->end()
139 61
                ->end()
140 61
                ->arrayNode('serializer')
141 61
                    ->addDefaultsIfNotSet()
142 61
                    ->children()
143 61
                        ->scalarNode('version')->defaultNull()->end()
144 61
                        ->arrayNode('groups')
145 61
                            ->prototype('scalar')->end()
146 61
                        ->end()
147 61
                        ->booleanNode('serialize_null')->defaultFalse()->end()
148 61
                    ->end()
149 61
                ->end()
150 61
                ->arrayNode('zone')
151 61
                    ->cannotBeOverwritten()
152 61
                    ->prototype('array')
153 61
                    ->fixXmlConfig('ip')
154 61
                    ->children()
155 61
                        ->scalarNode('path')
156 61
                            ->defaultNull()
157 61
                            ->info('use the urldecoded format')
158 61
                            ->example('^/path to resource/')
159 61
                        ->end()
160 61
                        ->scalarNode('host')->defaultNull()->end()
161 61
                        ->arrayNode('methods')
162
                            ->beforeNormalization()->ifString()->then(function ($v) {
163
                                return preg_split('/\s*,\s*/', $v);
164 61
                            })->end()
165 61
                            ->prototype('scalar')->end()
166 61
                        ->end()
167 61
                        ->arrayNode('ips')
168
                            ->beforeNormalization()->ifString()->then(function ($v) {
169 1
                                return array($v);
170 61
                            })->end()
171 61
                            ->prototype('scalar')->end()
172 61
                        ->end()
173 61
                    ->end()
174 61
                ->end()
175 61
            ->end()
176 61
        ->end();
177
178 61
        $this->addViewSection($rootNode);
0 ignored issues
show
Compatibility introduced by
$rootNode of type object<Symfony\Component...Builder\NodeDefinition> is not a sub-type of object<Symfony\Component...er\ArrayNodeDefinition>. It seems like you assume a child class of the class Symfony\Component\Config...\Builder\NodeDefinition to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
179 61
        $this->addExceptionSection($rootNode);
0 ignored issues
show
Compatibility introduced by
$rootNode of type object<Symfony\Component...Builder\NodeDefinition> is not a sub-type of object<Symfony\Component...er\ArrayNodeDefinition>. It seems like you assume a child class of the class Symfony\Component\Config...\Builder\NodeDefinition to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
180 61
        $this->addBodyListenerSection($rootNode);
0 ignored issues
show
Compatibility introduced by
$rootNode of type object<Symfony\Component...Builder\NodeDefinition> is not a sub-type of object<Symfony\Component...er\ArrayNodeDefinition>. It seems like you assume a child class of the class Symfony\Component\Config...\Builder\NodeDefinition to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
181 61
        $this->addFormatListenerSection($rootNode);
0 ignored issues
show
Compatibility introduced by
$rootNode of type object<Symfony\Component...Builder\NodeDefinition> is not a sub-type of object<Symfony\Component...er\ArrayNodeDefinition>. It seems like you assume a child class of the class Symfony\Component\Config...\Builder\NodeDefinition to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
182 61
        $this->addVersioningSection($rootNode);
0 ignored issues
show
Compatibility introduced by
$rootNode of type object<Symfony\Component...Builder\NodeDefinition> is not a sub-type of object<Symfony\Component...er\ArrayNodeDefinition>. It seems like you assume a child class of the class Symfony\Component\Config...\Builder\NodeDefinition to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
183
184 61
        return $treeBuilder;
185
    }
186
187 61
    private function addViewSection(ArrayNodeDefinition $rootNode): void
188
    {
189
        $rootNode
190 61
            ->children()
191 61
                ->arrayNode('view')
192 61
                    ->fixXmlConfig('format', 'formats')
193 61
                    ->fixXmlConfig('mime_type', 'mime_types')
194 61
                    ->fixXmlConfig('force_redirect', 'force_redirects')
195 61
                    ->addDefaultsIfNotSet()
196 61
                    ->children()
197 61
                        ->scalarNode('default_engine')
198 61
                            ->defaultNull()
199 61
                            ->validate()
200 61
                                ->ifString()
201 61
                                ->thenInvalid('only null is supported')
202 61
                            ->end()
203 61
                        ->end()
204 61
                        ->arrayNode('force_redirects')
205 61
                            ->useAttributeAsKey('name')
206 61
                            ->defaultValue([])
207 61
                            ->validate()
208
                                ->ifTrue(function ($v) { return [] !== $v; })
209 61
                                ->thenInvalid('only the empty array is supported')
210 61
                            ->end()
211 61
                            ->prototype('boolean')->end()
212 61
                        ->end()
213 61
                        ->arrayNode('mime_types')
214 61
                            ->canBeEnabled()
215 61
                            ->beforeNormalization()
216 View Code Duplication
                                ->ifArray()->then(function ($v) {
217 1
                                    if (!empty($v) && empty($v['formats'])) {
218 1
                                        unset($v['enabled']);
219 1
                                        $v = ['enabled' => true, 'formats' => $v];
220
                                    }
221
222 1
                                    return $v;
223 61
                                })
224 61
                            ->end()
225 61
                            ->fixXmlConfig('format', 'formats')
226 61
                            ->children()
227 61
                                ->scalarNode('service')->defaultNull()->end()
228 61
                                ->arrayNode('formats')
229 61
                                    ->useAttributeAsKey('name')
230 61
                                    ->prototype('array')
231 61
                                        ->beforeNormalization()
232 61
                                            ->ifString()
233
                                            ->then(function ($v) { return array($v); })
234 61
                                        ->end()
235 61
                                        ->prototype('scalar')->end()
236 61
                                    ->end()
237 61
                                ->end()
238 61
                            ->end()
239 61
                        ->end()
240 61
                        ->arrayNode('formats')
241 61
                            ->useAttributeAsKey('name')
242 61
                            ->defaultValue(['json' => true, 'xml' => true])
243 61
                            ->prototype('boolean')->end()
244 61
                        ->end()
245 61
                        ->arrayNode('view_response_listener')
246 61
                            ->beforeNormalization()
247 61
                                ->ifString()
248 View Code Duplication
                                ->then(function ($v) {
249 4
                                    return ['enabled' => in_array($v, ['force', 'true']), 'force' => 'force' === $v];
250 61
                                })
251 61
                            ->end()
252 61
                            ->canBeEnabled()
253 61
                            ->children()
254 61
                                ->booleanNode('force')->defaultFalse()->end()
255 61
                                ->scalarNode('service')->defaultNull()->end()
256 61
                            ->end()
257 61
                        ->end()
258 61
                        ->scalarNode('failed_validation')->defaultValue(Response::HTTP_BAD_REQUEST)->end()
259 61
                        ->scalarNode('empty_content')->defaultValue(Response::HTTP_NO_CONTENT)->end()
260 61
                        ->booleanNode('serialize_null')->defaultFalse()->end()
261 61
                        ->arrayNode('jsonp_handler')
262 61
                            ->canBeUnset()
263 61
                            ->children()
264 61
                                ->scalarNode('callback_param')->defaultValue('callback')->end()
265 61
                                ->scalarNode('mime_type')->defaultValue('application/javascript+jsonp')->end()
266 61
                            ->end()
267 61
                        ->end()
268 61
                    ->end()
269 61
                ->end()
270 61
            ->end();
271 61
    }
272
273 61
    private function addBodyListenerSection(ArrayNodeDefinition $rootNode): void
274
    {
275 61
        $decodersDefaultValue = ['json' => 'fos_rest.decoder.json'];
276 61
        if (class_exists(XmlEncoder::class)) {
277 61
            $decodersDefaultValue['xml'] = 'fos_rest.decoder.xml';
278
        }
279
        $rootNode
280 61
            ->children()
281 61
                ->arrayNode('body_listener')
282 61
                    ->fixXmlConfig('decoder', 'decoders')
283 61
                    ->addDefaultsIfNotSet()
284 61
                    ->canBeUnset()
285 61
                    ->canBeEnabled()
286 61
                    ->children()
287 61
                        ->scalarNode('service')->defaultNull()->end()
288 61
                        ->scalarNode('default_format')->defaultNull()->end()
289 61
                        ->booleanNode('throw_exception_on_unsupported_content_type')
290 61
                            ->defaultFalse()
291 61
                        ->end()
292 61
                        ->arrayNode('decoders')
293 61
                            ->useAttributeAsKey('name')
294 61
                            ->defaultValue($decodersDefaultValue)
295 61
                            ->prototype('scalar')->end()
296 61
                        ->end()
297 61
                        ->arrayNode('array_normalizer')
298 61
                            ->addDefaultsIfNotSet()
299 61
                            ->beforeNormalization()
300
                                ->ifString()->then(function ($v) {
301 1
                                    return ['service' => $v];
302 61
                                })
303 61
                            ->end()
304 61
                            ->children()
305 61
                                ->scalarNode('service')->defaultNull()->end()
306 61
                                ->booleanNode('forms')->defaultFalse()->end()
307 61
                            ->end()
308 61
                        ->end()
309 61
                    ->end()
310 61
                ->end()
311 61
            ->end();
312 61
    }
313
314 61
    private function addFormatListenerSection(ArrayNodeDefinition $rootNode): void
315
    {
316
        $rootNode
317 61
            ->children()
318 61
                ->arrayNode('format_listener')
319 61
                    ->fixXmlConfig('rule', 'rules')
320 61
                    ->addDefaultsIfNotSet()
321 61
                    ->canBeUnset()
322 61
                    ->beforeNormalization()
323
                        ->ifTrue(function ($v) {
324
                            // check if we got an assoc array in rules
325 6
                            return isset($v['rules'])
326 6
                                && is_array($v['rules'])
327 6
                                && array_keys($v['rules']) !== range(0, count($v['rules']) - 1);
328 61
                        })
329
                        ->then(function ($v) {
330 1
                            $v['rules'] = [$v['rules']];
331
332 1
                            return $v;
333 61
                        })
334 61
                    ->end()
335 61
                    ->canBeEnabled()
336 61
                    ->children()
337 61
                        ->scalarNode('service')->defaultNull()->end()
338 61
                        ->arrayNode('rules')
339 61
                            ->performNoDeepMerging()
340 61
                            ->prototype('array')
341 61
                                ->fixXmlConfig('priority', 'priorities')
342 61
                                ->fixXmlConfig('attribute', 'attributes')
343 61
                                ->children()
344 61
                                    ->scalarNode('path')->defaultNull()->info('URL path info')->end()
345 61
                                    ->scalarNode('host')->defaultNull()->info('URL host name')->end()
346 61
                                    ->variableNode('methods')->defaultNull()->info('Method for URL')->end()
347 61
                                    ->arrayNode('attributes')
348 61
                                        ->useAttributeAsKey('name')
349 61
                                        ->prototype('variable')->end()
350 61
                                    ->end()
351 61
                                    ->booleanNode('stop')->defaultFalse()->end()
352 61
                                    ->booleanNode('prefer_extension')->defaultTrue()->end()
353 61
                                    ->scalarNode('fallback_format')->defaultValue('html')->end()
354 61
                                    ->arrayNode('priorities')
355
                                        ->beforeNormalization()->ifString()->then(function ($v) {
356
                                            return preg_split('/\s*,\s*/', $v);
357 61
                                        })->end()
358 61
                                        ->prototype('scalar')->end()
359 61
                                    ->end()
360 61
                                ->end()
361 61
                            ->end()
362 61
                        ->end()
363 61
                    ->end()
364 61
                ->end()
365 61
            ->end();
366 61
    }
367
368 61
    private function addVersioningSection(ArrayNodeDefinition $rootNode): void
369
    {
370
        $rootNode
371 61
        ->children()
372 61
            ->arrayNode('versioning')
373 61
                ->canBeEnabled()
374 61
                ->children()
375 61
                    ->scalarNode('default_version')->defaultNull()->end()
376 61
                    ->arrayNode('resolvers')
377 61
                        ->addDefaultsIfNotSet()
378 61
                        ->children()
379 61
                            ->arrayNode('query')
380 61
                                ->canBeDisabled()
381 61
                                ->children()
382 61
                                    ->scalarNode('parameter_name')->defaultValue('version')->end()
383 61
                                ->end()
384 61
                            ->end()
385 61
                            ->arrayNode('custom_header')
386 61
                                ->canBeDisabled()
387 61
                                ->children()
388 61
                                    ->scalarNode('header_name')->defaultValue('X-Accept-Version')->end()
389 61
                                ->end()
390 61
                            ->end()
391 61
                            ->arrayNode('media_type')
392 61
                                ->canBeDisabled()
393 61
                                ->children()
394 61
                                    ->scalarNode('regex')->defaultValue('/(v|version)=(?P<version>[0-9\.]+)/')->end()
395 61
                                ->end()
396 61
                            ->end()
397 61
                        ->end()
398 61
                    ->end()
399 61
                    ->arrayNode('guessing_order')
400 61
                        ->defaultValue(['query', 'custom_header', 'media_type'])
401 61
                        ->validate()
402
                            ->ifTrue(function ($v) {
403
                                foreach ($v as $resolver) {
404
                                    if (!in_array($resolver, ['query', 'custom_header', 'media_type'])) {
405
                                        return true;
406
                                    }
407
                                }
408 61
                            })
409 61
                            ->thenInvalid('Versioning guessing order can only contain "query", "custom_header", "media_type".')
410 61
                        ->end()
411 61
                        ->prototype('scalar')->end()
412 61
                    ->end()
413 61
                ->end()
414 61
            ->end()
415 61
        ->end();
416 61
    }
417
418 61
    private function addExceptionSection(ArrayNodeDefinition $rootNode): void
419
    {
420
        $rootNode
421 61
            ->children()
422 61
                ->arrayNode('exception')
423 61
                    ->fixXmlConfig('code', 'codes')
424 61
                    ->fixXmlConfig('message', 'messages')
425 61
                    ->addDefaultsIfNotSet()
426 61
                    ->canBeEnabled()
427 61
                    ->children()
428 61
                        ->booleanNode('map_exception_codes')
429 61
                            ->defaultFalse()
430 61
                            ->info('Enables an event listener that maps exception codes to response status codes based on the map configured with the "fos_rest.exception.codes" option.')
431 61
                        ->end()
432 61
                        ->booleanNode('exception_listener')
433 61
                            ->defaultValue(false)
434 61
                            ->validate()
435 61
                                ->ifTrue()
436 61
                                ->thenInvalid('only "false" is supported')
437 61
                            ->end()
438 61
                        ->end()
439 61
                        ->booleanNode('serialize_exceptions')
440 61
                            ->defaultValue(false)
441 61
                            ->validate()
442 61
                                ->ifTrue()
443 61
                                ->thenInvalid('only "false" is supported')
444 61
                            ->end()
445 61
                        ->end()
446 61
                        ->enumNode('flatten_exception_format')
447 61
                            ->defaultValue('legacy')
448 61
                            ->values(['legacy', 'rfc7807'])
449 61
                        ->end()
450 61
                        ->booleanNode('serializer_error_renderer')->defaultValue(false)->end()
451 61
                        ->arrayNode('codes')
452 61
                            ->useAttributeAsKey('name')
453 61
                            ->beforeNormalization()
454 61
                                ->ifArray()
455
                                ->then(function (array $items) {
456 13
                                    foreach ($items as &$item) {
457 13
                                        if (is_int($item)) {
458 3
                                            continue;
459
                                        }
460
461 10
                                        if (!defined(sprintf('%s::%s', Response::class, $item))) {
462 9
                                            throw new InvalidConfigurationException(sprintf('Invalid HTTP code in fos_rest.exception.codes, see %s for all valid codes.', Response::class));
463
                                        }
464
465 1
                                        $item = constant(sprintf('%s::%s', Response::class, $item));
466
                                    }
467
468 4
                                    return $items;
469 61
                                })
470 61
                            ->end()
471 61
                            ->prototype('integer')->end()
472
473 61
                            ->validate()
474 61
                            ->ifArray()
475
                                ->then(function (array $items) {
476 4
                                    foreach ($items as $class => $code) {
477 4
                                        $this->testExceptionExists($class);
478
                                    }
479
480 3
                                    return $items;
481 61
                                })
482 61
                            ->end()
483 61
                        ->end()
484 61
                        ->arrayNode('messages')
485 61
                            ->useAttributeAsKey('name')
486 61
                            ->prototype('boolean')->end()
487 61
                            ->validate()
488 61
                                ->ifArray()
489
                                ->then(function (array $items) {
490 9
                                    foreach ($items as $class => $nomatter) {
491 9
                                        $this->testExceptionExists($class);
492
                                    }
493
494 8
                                    return $items;
495 61
                                })
496 61
                            ->end()
497 61
                        ->end()
498 61
                        ->booleanNode('debug')
499 61
                            ->defaultValue($this->debug)
500 61
                        ->end()
501 61
                    ->end()
502 61
                ->end()
503 61
            ->end();
504 61
    }
505
506 13
    private function testExceptionExists(string $throwable): void
507
    {
508 13
        if (!is_subclass_of($throwable, \Throwable::class)) {
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of might return inconsistent results on some PHP versions if \Throwable::class can be an interface. If so, you could instead use ReflectionClass::implementsInterface.
Loading history...
509 2
            throw new InvalidConfigurationException(sprintf('FOSRestBundle exception mapper: Could not load class "%s" or the class does not extend from "%s". Most probably this is a configuration problem.', $throwable, \Throwable::class));
510
        }
511 11
    }
512
}
513