2727use Illuminate \Auth \AuthenticationException ;
2828use Illuminate \Contracts \Container \Container ;
2929use Illuminate \Foundation \Exceptions \Handler as ExceptionsHandler ;
30- use Illuminate \Http \Request ;
3130use Negotiation \Negotiator ;
3231use Symfony \Component \HttpFoundation \Exception \RequestExceptionInterface ;
3332use Symfony \Component \HttpKernel \Exception \HttpExceptionInterface as SymfonyHttpExceptionInterface ;
@@ -52,112 +51,114 @@ public function __construct(
5251 ?Negotiator $ negotiator = null ,
5352 private readonly ?array $ exceptionToStatus = null ,
5453 private readonly ?bool $ debug = false ,
54+ private readonly ?array $ errorFormats = null ,
5555 ) {
5656 $ this ->resourceMetadataCollectionFactory = $ resourceMetadataCollectionFactory ;
5757 $ this ->negotiator = $ negotiator ;
58- // calls register
5958 parent ::__construct ($ container );
60- $ this ->register ();
6159 }
6260
63- public function register (): void
61+ public function render ( $ request , \ Throwable $ exception )
6462 {
65- $ this ->renderable ( function ( \ Throwable $ exception , Request $ request ) {
66- $ apiOperation = $ this -> initializeOperation ( $ request );
67- if (!$ apiOperation ) {
68- return null ;
69- }
63+ $ apiOperation = $ this ->initializeOperation ( $ request );
64+
65+ if (!$ apiOperation ) {
66+ return parent :: render ( $ request , $ exception ) ;
67+ }
7068
71- $ formats = config ( ' api-platform.error_formats ' ) ?? ['jsonproblem ' => ['application/problem+json ' ]];
72- $ format = $ request ->getRequestFormat () ?? $ this ->getRequestFormat ($ request , $ formats , false );
69+ $ formats = $ this -> errorFormats ?? ['jsonproblem ' => ['application/problem+json ' ]];
70+ $ format = $ request ->getRequestFormat () ?? $ this ->getRequestFormat ($ request , $ formats , false );
7371
74- if ($ this ->resourceClassResolver ->isResourceClass ($ exception ::class)) {
75- $ resourceCollection = $ this ->resourceMetadataCollectionFactory ->create ($ exception ::class);
72+ if ($ this ->resourceClassResolver ->isResourceClass ($ exception ::class)) {
73+ $ resourceCollection = $ this ->resourceMetadataCollectionFactory ->create ($ exception ::class);
7674
77- $ operation = null ;
78- foreach ($ resourceCollection as $ resource ) {
79- foreach ($ resource ->getOperations () as $ op ) {
80- foreach ($ op ->getOutputFormats () as $ key => $ value ) {
81- if ($ key === $ format ) {
82- $ operation = $ op ;
83- break 3 ;
84- }
75+ $ operation = null ;
76+ foreach ($ resourceCollection as $ resource ) {
77+ foreach ($ resource ->getOperations () as $ op ) {
78+ foreach ($ op ->getOutputFormats () as $ key => $ value ) {
79+ if ($ key === $ format ) {
80+ $ operation = $ op ;
81+ break 3 ;
8582 }
8683 }
8784 }
85+ }
8886
89- // No operation found for the requested format, we take the first available
90- if (!$ operation ) {
91- $ operation = $ resourceCollection ->getOperation ();
92- }
93- $ errorResource = $ exception ;
94- if ($ errorResource instanceof ProblemExceptionInterface && $ operation instanceof HttpOperation) {
95- $ statusCode = $ this ->getStatusCode ($ apiOperation , $ operation , $ exception );
96- $ operation = $ operation ->withStatus ($ statusCode );
97- if ($ errorResource instanceof StatusAwareExceptionInterface) {
98- $ errorResource ->setStatus ($ statusCode );
99- }
100- }
101- } else {
102- // Create a generic, rfc7807 compatible error according to the wanted format
103- $ operation = $ this ->resourceMetadataCollectionFactory ->create (Error::class)->getOperation ($ this ->getFormatOperation ($ format ));
104- // status code may be overridden by the exceptionToStatus option
105- $ statusCode = 500 ;
106- if ($ operation instanceof HttpOperation) {
107- $ statusCode = $ this ->getStatusCode ($ apiOperation , $ operation , $ exception );
108- $ operation = $ operation ->withStatus ($ statusCode );
87+ // No operation found for the requested format, we take the first available
88+ if (!$ operation ) {
89+ $ operation = $ resourceCollection ->getOperation ();
90+ }
91+ $ errorResource = $ exception ;
92+ if ($ errorResource instanceof ProblemExceptionInterface && $ operation instanceof HttpOperation) {
93+ $ statusCode = $ this ->getStatusCode ($ apiOperation , $ operation , $ exception );
94+ $ operation = $ operation ->withStatus ($ statusCode );
95+ if ($ errorResource instanceof StatusAwareExceptionInterface) {
96+ $ errorResource ->setStatus ($ statusCode );
10997 }
110-
111- $ errorResource = Error::createFromException ($ exception , $ statusCode );
11298 }
113-
114- /** @var HttpOperation $operation */
115- if (!$ operation ->getProvider ()) {
116- static ::$ error = $ errorResource ;
117- $ operation = $ operation ->withProvider ([self ::class, 'provide ' ]);
99+ } else {
100+ // Create a generic, rfc7807 compatible error according to the wanted format
101+ $ operation = $ this ->resourceMetadataCollectionFactory ->create (Error::class)->getOperation ($ this ->getFormatOperation ($ format ));
102+ // status code may be overridden by the exceptionToStatus option
103+ $ statusCode = 500 ;
104+ if ($ operation instanceof HttpOperation) {
105+ $ statusCode = $ this ->getStatusCode ($ apiOperation , $ operation , $ exception );
106+ $ operation = $ operation ->withStatus ($ statusCode );
118107 }
119108
120- // For our swagger Ui errors
121- if ('html ' === $ format ) {
122- $ operation = $ operation ->withOutputFormats (['html ' => ['text/html ' ]]);
123- }
109+ $ errorResource = Error::createFromException ($ exception , $ statusCode );
110+ }
124111
125- $ identifiers = [];
126- try {
127- $ identifiers = $ this -> identifiersExtractor ?->getIdentifiersFromItem( $ errorResource, $ operation ) ?? [] ;
128- } catch ( \ Exception $ e ) {
129- }
112+ /** @var HttpOperation $operation */
113+ if (! $ operation -> getProvider ()) {
114+ static :: $ error = $ errorResource ;
115+ $ operation = $ operation -> withProvider ([ self ::class, ' provide ' ]);
116+ }
130117
131- $ normalizationContext = $ operation -> getNormalizationContext () ?? [];
132- if (!( $ normalizationContext [ ' api_error_resource ' ] ?? false ) ) {
133- $ normalizationContext += [ ' api_error_resource ' => true ] ;
134- }
118+ // For our swagger Ui errors
119+ if (' html ' === $ format ) {
120+ $ operation = $ operation -> withOutputFormats ([ ' html ' => [ ' text/html ' ]]) ;
121+ }
135122
136- if (!isset ($ normalizationContext [AbstractObjectNormalizer::IGNORED_ATTRIBUTES ])) {
137- $ normalizationContext [AbstractObjectNormalizer::IGNORED_ATTRIBUTES ] = true === $ this ->debug ? [] : ['originalTrace ' ];
138- }
123+ $ identifiers = [];
124+ try {
125+ $ identifiers = $ this ->identifiersExtractor ?->getIdentifiersFromItem($ errorResource , $ operation ) ?? [];
126+ } catch (\Exception $ e ) {
127+ }
139128
140- $ operation = $ operation ->withNormalizationContext ($ normalizationContext );
141-
142- $ dup = $ request ->duplicate (null , null , []);
143- $ dup ->setMethod ('GET ' );
144- $ dup ->attributes ->set ('_api_resource_class ' , $ operation ->getClass ());
145- $ dup ->attributes ->set ('_api_previous_operation ' , $ apiOperation );
146- $ dup ->attributes ->set ('_api_operation ' , $ operation );
147- $ dup ->attributes ->set ('_api_operation_name ' , $ operation ->getName ());
148- $ dup ->attributes ->set ('exception ' , $ exception );
149- // These are for swagger
150- $ dup ->attributes ->set ('_api_original_route ' , $ request ->attributes ->get ('_route ' ));
151- $ dup ->attributes ->set ('_api_original_uri_variables ' , $ request ->attributes ->get ('_api_uri_variables ' ));
152- $ dup ->attributes ->set ('_api_original_route_params ' , $ request ->attributes ->get ('_route_params ' ));
153- $ dup ->attributes ->set ('_api_requested_operation ' , $ request ->attributes ->get ('_api_requested_operation ' ));
154-
155- foreach ($ identifiers as $ name => $ value ) {
156- $ dup ->attributes ->set ($ name , $ value );
157- }
129+ $ normalizationContext = $ operation ->getNormalizationContext () ?? [];
130+ if (!($ normalizationContext ['api_error_resource ' ] ?? false )) {
131+ $ normalizationContext += ['api_error_resource ' => true ];
132+ }
133+
134+ if (!isset ($ normalizationContext [AbstractObjectNormalizer::IGNORED_ATTRIBUTES ])) {
135+ $ normalizationContext [AbstractObjectNormalizer::IGNORED_ATTRIBUTES ] = true === $ this ->debug ? [] : ['originalTrace ' ];
136+ }
158137
138+ $ operation = $ operation ->withNormalizationContext ($ normalizationContext );
139+
140+ $ dup = $ request ->duplicate (null , null , []);
141+ $ dup ->setMethod ('GET ' );
142+ $ dup ->attributes ->set ('_api_resource_class ' , $ operation ->getClass ());
143+ $ dup ->attributes ->set ('_api_previous_operation ' , $ apiOperation );
144+ $ dup ->attributes ->set ('_api_operation ' , $ operation );
145+ $ dup ->attributes ->set ('_api_operation_name ' , $ operation ->getName ());
146+ $ dup ->attributes ->set ('exception ' , $ exception );
147+ // These are for swagger
148+ $ dup ->attributes ->set ('_api_original_route ' , $ request ->attributes ->get ('_route ' ));
149+ $ dup ->attributes ->set ('_api_original_uri_variables ' , $ request ->attributes ->get ('_api_uri_variables ' ));
150+ $ dup ->attributes ->set ('_api_original_route_params ' , $ request ->attributes ->get ('_route_params ' ));
151+ $ dup ->attributes ->set ('_api_requested_operation ' , $ request ->attributes ->get ('_api_requested_operation ' ));
152+
153+ foreach ($ identifiers as $ name => $ value ) {
154+ $ dup ->attributes ->set ($ name , $ value );
155+ }
156+
157+ try {
159158 return $ this ->apiPlatformController ->__invoke ($ dup );
160- });
159+ } catch (\Throwable $ e ) {
160+ return parent ::render ($ dup , $ e );
161+ }
161162 }
162163
163164 private function getStatusCode (?HttpOperation $ apiOperation , ?HttpOperation $ errorOperation , \Throwable $ exception ): int
0 commit comments