In my persuit to continue making my code more maintainable and a bit cleaner, I have come across a new question with controllers.

Is it ok to have multiple layers of front-controllers.

What is a front controller?

If you are unfamiliar with a front controller, it is a single object for channeling the flow of a program based on request information. In most apps, you won't really think about front controllers since even the thinnest MVC frameworks will handle this for you and you'll call it a router. The Router often will check the URL and HTTP method and send it off to a lower layer controller and optionally pass the response of the controller to a presentation layer.

Why use multiple layers of front-controllers?

This is assuming a server-side MVC framework such as Django, Rails, or Laravel and you are using the built in router as your first line of Front Controllers. However, what happens when you need to further whittle down a request using more than just the URL and HTTP method. For this I would say let the router match on usual parameters and THEN pass it on to a thin Front Controller that further handles the requests and then passes on the remaining request to a Page Controller or Server Page. Yes, there are routers that allow you to route based on HTTP headers, request data, and more: but the syntax is awkward and creates multiple entry points into a single system.

Where would this come up?

One situation you may find yourself in would be handling Github Webhooks. When hitting your site, Github will send every event to a single API url on your site. The only way you can differentiate between the various event types is by checking the X-GitHub-Event HTTP header. I've seen a lot of people handling all of these events in a single controller and it gets really ugly really fast. So, I started thinking about ways to clean this up.

At first, I thought of using basic ADR: My traditional controller would send off the formated request data to a Domain layer that read in the HTTP header and… Domain shouldn't know how to talk about HTTP!??? Not to mention the mess of having a responder that could respond to all of the possible formats of data to handle all of the various responses for all of the possible events. It was a mess.

More Front Controllers to the Rescue!

Scratching my head for a second, I stopped and thought, "what if I had this controller ONLY look at the Request header and based on that pull a different controller out of IoC and return it's response?"

After a bit of practice I had something like this:

// routes.php

Route::post('/api/github-webhook', 'Acme\\Github\\WebhookFrontController@__invoke');

// controllers/Acme/Github/WebhookFrontController.php

<?php namespace Acme\\Github;

use Request;
use App as Application;

class WebhookFrontController extends \Controller
{
    public function __construct(Request $request, Application $app)
    {
        $this->request = $request;
        $this->app = $app;
    }

    public function __invoke()
    {
        switch ($this->request->header('X-GitHub-Event')) {
            case 'commit_comment':
                return $this->app->make('Acme\\Github\\CommitCommentController');
                break;
            case 'deployment':
                return $this->app->make('Acme\\Github\\DeploymentController');
                break;
            case 'push':
                return $this->app->make('Acme\\Github\\PushController');
                break;
            default:
                return $this->app->make('Acme\\Github\\InvalidEventController');
                break;
        }

        return $controller->__invoke($this->request);
    }
}

Then, your controller that is invoked by the Front Controller can be just like a normal old controller! If you want to use an ADR architecture or something more traditional to your architecture flow, it's up to you!