Different behaviour of NotAllowedHandler & ExceptionHandler


#1

I have a custom ExceptionHandler, NotFoundHandler and NotAllowedHandler.

I am using Gofabian Negotiation Middleware

If I access a missing page then the request sent to NotFoundHandler::__invoke contains the middleware.

If I throw an Exception deep within my app I would expect it to contain the same middleware but it does not.

I’m assigning the ExceptionHandler like so:

// handle missing pages
$container['notFoundHandler'] = function($c) {
	return new \My\Exceptions\NotFoundHandler($c);
};
// handle access issues
$container['notAllowedHandler'] = function($c) {
	return new \My\Exceptions\NotAllowedHandler($c);
};
// handle PHP7 exceptions
$container['phpErrorHandler'] = function($c) {
	return new \My\Exceptions\ExceptionHandler($c);
};
// handle all other exceptions
$container['errorHandler'] = function($c) {
	return new \My\Exceptions\ExceptionHandler($c);
};

My Handlers contain this line in the __invoke method:

public function __invoke(Request $request, Response $response, $exception)
{
      switch ($request->getAttribute('negotiation')->getMediaType())
      {
              // logic here
}

Which in the case of the NotFound and NotAllowed handlers works fine, but in the ExceptionHandler case it throws another exception because the middleware is not set and I’m calling the getMediaType() method on null.

My question seems to be similar to this one Manually thrown exceptions do not traverse the middleware stack It seems to be advocating littering my code with try/ctach in order to stay clean… that’s not what I want.

For specific exceptions I will use try/catch but for everything else I want it to be handled by the default handler.

How can I get the processed middleware $request into my ExceptionHandler?


#2

Correct me someone if I am wrong, but I think because both Request and Response are immutable and exceptions and php errors are handled/processed in \Slim\App::process() method (where is actually that important try catch) you have access only to state of Request and Response objects in that particular method (that means this objects in that context are not affected by your application at all so far)

also I am not sure why you need ‘negotiation’ attributes etc. for unknown exception or php error, that should always end in HTTP 500 (ie. unhandled exception) ?


#3

I use ‘negotiation’ middleware on multi-language sites which support both HTML and JSON responses. The idea is that an error response can be made more friendly by tailoring it to the users language and method of interaction (ajax or html).

I can understand there being a need for some safety here by returning a ‘clean’ or ‘untainted’ $request and $response but it would be nice to keep the custom attributes.

Looking at \Slim\App::process() I can see it would not be trivial to implement so I’ll repeat the ‘negotiation’ middleware in my exception handler.