zendframework / zend-expressive

PSR-15 middleware in minutes!
BSD 3-Clause "New" or "Revised" License
711 stars 197 forks source link

Piped 'child' application throws exception and shows 'Internal Server Error' without parent error configuration #349

Closed RossJHagan closed 8 years ago

RossJHagan commented 8 years ago

This is more of a 'help me understand' question than a real issue.

I'm using a parent expressive application - taking cues from the two cookbook articles on modular layout and using expressive from a subdirectory. I'm using a parent application to help in refactoring a larger app one section at a time. The parent has no particular configuration set up as I've been treating it as a placeholder to pipe the child applications through and letting me modularise our larger application in phases. (Which is wonderful, Expressive is just a great refactoring tool for monolithic apps!!)

The child app has all the 'appropriate' configurations for error handling. When the child throws an error all I see is 'Internal Server Error' - I had expected to see a full Whoops based pretty error page.

Solution As I have found, configuring the parent application with the appropriate error handler configuration will solve this issue.

Question Am I simply doing it wrong by omitting error handler configuration on the parent? I realise my expectations were faulty. I had just been expecting the configuration from the piped child application to be used to handle errors that occur in that path. It took longer than I care to admit for the lightbulb moment to occur that the parent must have its own configuration for that to work. [Not to suggest it's particularly sane to allow different error handler configuration across piped apps]

I'm happy to contribute to the docs or expand on them where possible, I just want to suggest edits that are in line the intended behaviour.

Recreating

This is a much simplified version. In case it helps, use the skeleton installer and opt for: FastRoute, Aura.Di, Twig and Whoops as the options.

In index.php use this:

<?php

use Zend\Expressive\AppFactory;

// Delegate static file requests back to the PHP built-in webserver
if (php_sapi_name() === 'cli-server'
    && is_file(__DIR__ . parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH))
) {
    return false;
}

chdir(dirname(__DIR__));
require 'vendor/autoload.php';

$di = (new \Aura\Di\ContainerBuilder())->newInstance();

$baseApp = AppFactory::create($di);

/** @var \Interop\Container\ContainerInterface $container */
$container = require 'config/container.php';

/** @var \Zend\Expressive\Application $app */
$subApp = $container->get(\Zend\Expressive\Application::class);

$baseApp->pipe('/test', $subApp);

$baseApp->run();

You can then serve the app, and access at localhost:8080/test/.

Then simply throwing a \RuntimeException in the start of the skeleton's HomePageAction constructor (or wherever you prefer) will get the Internal Server Error.

Changing it to run the 'subApp' directly again will get the Whoops page back.

RossJHagan commented 8 years ago

As a bit of closure for this issue in case someone stumbles on it, I ended up giving up on the piping of a subapplication and just ran the sub-app directly.

The deciding factor was realising that actually if I was piping separate applications, the template error handler would need to be different because they would be different areas of the site with a different layout. It was easier to untangle the configuration into completely separate applications and just reuse common configuration parts as needed. This was ultimately a better fit for the strategy I was taking anyway.