Solving The “Widget Problem” In ADR

The “widget problem” is when you have several panels or content areas on an HTML page that have different data sources. You might have a main content area, then a calendar off to the side, with perhaps a list of recent news items or blog posts, a todo or reminder widget, and maybe other information panels. The problem is that they each have different data sources, and may not always be displayed in every circumstance — perhaps they are only shown to some users based on their preferences, or under certain conditions.

So how, in Action-Domain-Responder, do we get the “right” data for the set of widgets that are actually going to be displayed? (We’ll presume here that the entire page is being rendered server-side, for delivery as a whole to the client.)

The answer is “the same as with anything else” – we just have more kinds of data to get from the domain. The domain has all the data needed, and the knowledge necessary to figure out which data elements to return.

Let’s start with the Action, which is intentionally very spare: it only collects input, calls the Domain with that input, then invokes the Responder:

class PageAction
    public function __construct(
        PageService $domain,
        PageResponder $responder
    ) {
        $this->domain = $domain;
        $this->responder = $responder;

    public function __invoke(HttpRequest $request)
        $payload = $this->domain->fetchPageData(
        return $this->responder->respond($request, $payload);

The domain work is where the heavy lifting happens. The example below returns the domain objects and data wrapped in a Domain Payload object.

class PageService
    // presume $userService, $sessionService, and $database
    // dependencies are injected via constructor

    public function fetchPageData($sessionId, $pageName)
        $session = $this->sessionService->resume($sessionId);
        $user = $this->userService->fetch($session->userId);

        // the main page data
        $mainData = $this->fetchMainData($pageName);
        if (! $mainData) {
            return new Payload('NOT_FOUND');

        // an array of widgets to show
        $widgets = [];

        // different users might prefer to see different widgets
        foreach ($user->getWidgetsToShow() as $widgetName) {
            $method = "fetch{$widgetName}Data";
            $widgets[$widgetName] = $this->$method();


        return new Payload('FOUND', [
            'user' => $user,
            'page_name' => $pageName,
            'main_data' => $mainData,
            'widgets' => $widgets

    protected function fetchMainData($page_name)
        return $this->database->fetchRow(
            "SELECT * FROM pages WHERE page_name = ? LIMIT 1",

    protected function fetchTodoData() { ... }

    protected function fetchRemindersData() { ... }

    protected function fetchUpcomingEventsData() { ... }

    protected function fetchCalendarData() { ... }


Finally, the Responder work becomes as straightforward as: “Is there Todo data to present? Then render the Todo widget via a Todo helper using the Todo data.” It could be as simple as this:

class PageResponder
    // ...

    public function respond(Request $request, Payload $payload)
        if ($payload->getStatus() == 'NOT_FOUND') {
            return new Response(404);

        $output = $payload->getOutput();

        $html = '';
        $html .= $this->renderHeader($output['page_name'];
        $html .= $this->renderNav();
        $html .= $this->renderMain($output['main_data']);

        foreach ($output['widgets'] as $widgetName => $widgetData) {
            $method = "render{$widgetName}Html";
            $html .= $this->$method($widgetData);

        return new Response(200, $html);

    protected function renderHeader($request, $pageName) { ... }

    protected function renderNav($request) { ... }

    protected function renderMain($request, $mainData) { ... }

    protected function renderTodoHtml($request, $widgetData) { ... }

    protected function renderRemindersHtml($request, $widgetData) { ... }

    protected function renderUpcomingEventsHtml($request, $widgetData) { ... }

    protected function renderCalendarHtml($request, $widgetData) { ... }

One alternative here is for some client-side Javascript to make one additional call per widget or panel to retrieve widget-specific data, then render that data on the client. The server-side work becomes less complex (one action per widget, and transform the data to JSON instead of HTML) – but the client-side work becomes more complex, and you have more HTTP calls back-and-forth to build the page.

Are you stuck with a legacy PHP application? You should buy my book because it gives you a step-by-step guide to improving your codebase, all while keeping it running the whole time.

11 thoughts on “Solving The “Widget Problem” In ADR

  1. While this looks like a pretty good solution, the example implementation looks like it would only work for 1 page (or rather: 1 type of page). In practice, you’ll often have the same widgets on multiple pages – for instance on this blog the same widgets are used for the index, archive, articles and pages. In more complex applications, you might have some widgets that are always shown, some that are shown only on specific pages and some that are always shown except on specific pages; and their ordering could be different on every page; and user settings (and perhaps the date and/or time, or location of the visitor, or …) could come into play.

    Do you have any thoughts on how you would do that?

    For the domain part, I think I would create a WidgetService for the PageService to call onto (with a way for the PageService to include & exclude specific widgets).
    For the response my first idea is to also create a WidgetRenderer so that the PageResponder can just to $html .= $this->widgetResponder->render($output[‘widgets’]);

    That approach feels OK for a small application, but both the WidgetService and the WidgetRenderer could become huge if there are enough widgets (though I guess those could both be broken up into smaller classes if needed).

    Again, I like the idea, I’m just not sure how it would be best implemented in a more complex scenario.

  2. It strikes me that does little to uncouple the widgets from the other layers of content within the page. And it appears to require rather a lot of custom code to implement. Is there a significant advantage of ESI I’m not seeing here?

  3. Since you want to reuse widgets (components) I do not think this approach will “scale”. We have “copied” the ADR pattern and use something similar for widgets. We have an widget controller which does similar things like an action class, data is fetched from the domain layer and “rendered” by the widget renderer. The difference between the widget renderer and the responder is, that the widget renderer is only allowed to return HTML. You are not able to modify response headers and such. Is an exception thrown of any kind, the widget won’t be displayed. That way in our templates we can simply include widgets where we want, pass parameters to the different instances and get the HTML output back.

  4. Mistake: you have different parameters order in fetchPageData method in first two code samples.

    • html code was skipped 🙁

      Try again like this:
      [div id=”my-cool-widget” data-init=”{{ widget_data|json_encode() }}”]… main widget code …[/div]

  5. Great post.
    I have always tried to have this kind of separation between my controller actions, domain layer and response generator. But never been satisfied, my domain layer always ends up doing more than what it should be responsible for.
    The payload communication channel between the domain and the responder (relayed by the action) will be the key take away for me. Thank you for that.

    Some replies raised valid critics of how the HTML is generated. But I think the post is more about how to get “widget data to be rendered” in ADR than how the widgets are rendered. I am sure the PO does not generate HTML this way in real applications.

    My way of handling it is to have the responder build “View” objects that can output the final widget presentation. When generating HTML the responder hands the “View” objects over to a template that knows where to display each view.

Leave a Reply

Your email address will not be published. Required fields are marked *