PHPackages                             webmunkeez/adr-bundle - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Framework](/categories/framework)
4. /
5. webmunkeez/adr-bundle

ActiveSymfony-bundle[Framework](/categories/framework)

webmunkeez/adr-bundle
=====================

Action-Domain-Responder pattern made for Symfony.

v2.3.0(2y ago)1117MITPHPPHP &gt;=8.1

Since Oct 14Pushed 2y ago1 watchersCompare

[ Source](https://github.com/yannissgarra/adr-bundle)[ Packagist](https://packagist.org/packages/webmunkeez/adr-bundle)[ Docs](https://github.com/yannissgarra/adr-bundle)[ RSS](/packages/webmunkeez-adr-bundle/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (17)Versions (55)Used By (0)

WebmunkeezADRBundle
===================

[](#webmunkeezadrbundle)

This bundle unleashes the **Action-Domain-Responder** pattern on Symfony applications.

Installation
------------

[](#installation)

Use Composer to install this bundle:

```
$ composer require webmunkeez/adr-bundle
```

Add the bundle in your application kernel:

```
// config/bundles.php

return [
    // ...
    Webmunkeez\ADRBundle\WebmunkeezADRBundle::class => ['all' => true],
    // ...
];
```

Usage
-----

[](#usage)

### Actions

[](#actions)

An **Action** is just an invokable class that has to implement `\Webmunkeez\ADRBundle\Action\ActionInterface`:

```
final class StoryDetailAction implements \Webmunkeez\ADRBundle\Action\ActionInterface
{
    public function __invoke(): Response
    {
        return $this->render($data);
    }

    public function render(?\Webmunkeez\ADRBundle\Response\ResponseDataInterface $data = null): Response
    {
        return new Response(...);
    }
}
```

But, it can be a more classic **Controller** that implements the same interface:

```
final class StoryController implements \Webmunkeez\ADRBundle\Action\ActionInterface
{
    public function detail(): Response
    {
        return $this->render($data);
    }

    public function render(?\Webmunkeez\ADRBundle\Response\ResponseDataInterface $data = null): Response
    {
        return new Response(...);
    }
}
```

(Each service that implements `ActionInterface` is automatically tagged `controller.service_arguments`)

### Responders

[](#responders)

**Responders** are services which take data (an object that implements `\Webmunkeez\ADRBundle\Response\ResponseDataInterface`) and return it in a **Response**.
It can be a response containing HTML or a JsonResponse, or whatever you want, as far as it is a `Symfony\Component\HttpFoundation\Response` instance.

In this bundle, there is a responder manager `\Webmunkeez\ADRBundle\Response\Responder` that you can inject into your actions (or controllers).

This responder manager takes all responders of your application (it uses a compiler pass to get all services tagged `webmunkeez_adr.responder` sorted by priority) and find the right one to render the response.

```
final class StoryDetailAction implements \Webmunkeez\ADRBundle\Action\ActionInterface
{
    private \Webmunkeez\ADRBundle\Response\Responder $responder;

    public function __construct(\Webmunkeez\ADRBundle\Response\Responder $responder)
    {
        $this->responder = $responder
    }

    public function __invoke(): Response
    {
        return $this->render($data);
    }

    public function render(?\Webmunkeez\ADRBundle\Response\ResponseDataInterface $data = null): Response
    {
        return $this->responder->render($data);
    }
}
```

You can use `\Webmunkeez\ADRBundle\Response\ResponderAwareInterface` and `\Webmunkeez\ADRBundle\Response\ResponderAwareTrait` to automatically inject Responder:

```
final class StoryDetailAction implements \Webmunkeez\ADRBundle\Action\ActionInterface, \Webmunkeez\ADRBundle\Response\ResponderAwareInterface
{
    use \Webmunkeez\ADRBundle\Response\ResponderAwareTrait;

    public function __invoke(): Response
    {
        return $this->render($data);
    }

    public function render(?\Webmunkeez\ADRBundle\Response\ResponseDataInterface $data = null): Response
    {
        return $this->responder->render($data);
    }
}
```

And you can use `\Webmunkeez\ADRBundle\Action\ActionTrait` to clean code:

```
final class StoryDetailAction implements \Webmunkeez\ADRBundle\Action\ActionInterface, \Webmunkeez\ADRBundle\Response\ResponderAwareInterface
{
    use \Webmunkeez\ADRBundle\Response\ResponderAwareTrait;
    use \Webmunkeez\ADRBundle\Action\ActionTrait;

    public function __invoke(): Response
    {
        return $this->render($data);
    }
}
```

Or directly extend `\Webmunkeez\ADRBundle\Action\AbstractAction`:

```
final class StoryDetailAction extends \Webmunkeez\ADRBundle\Action\AbstractAction
{
    public function __invoke(): Response
    {
        return $this->render($data);
    }
}
```

Responders are classes that implement `\Webmunkeez\ADRBundle\Response\ResponderInterface` (and so, they are automatically tagged `webmunkeez_adr.responder`):

```
final class XmlResponder implements \Webmunkeez\ADRBundle\Response\ResponderInterface
{
    private RequestStack $requestStack;
    private SerializerInterface $serializer;

    public function __construct(RequestStack $requestStack, SerializerInterface $serializer)
    {
        $this->requestStack = $requestStack;
        $this->serializer = $serializer;
    }

    public function supports(): bool
    {
        return 'xml' === $this->requestStack->getCurrentRequest()->getPreferredFormat();
    }

    public function render(?\Webmunkeez\ADRBundle\Response\ResponseDataInterface $data = null): Response
    {
        $xml = $this->serializer->serialize($data, 'xml');

        $response = new Response($xml);
        $response->headers->set('Content-Type', 'text/xml');

        return $response;
    }
}
```

As you can see, there are two methods: `supports` that defines conditions to "activate" the responder and `render` to make the response.

#### Core responders

[](#core-responders)

There are two core responders provided:

##### HtmlResponder

[](#htmlresponder)

`\Webmunkeez\ADRBundle\Response\HtmlResponder` that uses **Twig** for render html with a twig template. To indicate template, you have to use `\Webmunkeez\ADRBundle\Attribute\Template`:

```
use Webmunkeez\ADRBundle\Attribute\Template;

#[Template('story/detail.html.twig')]
final class StoryDetailAction implements \Webmunkeez\ADRBundle\Action\ActionInterface
{
    ...
}
```

This responder is active if the request contains `HTTP_ACCEPT text/html` header (warning: a twig template is needed for this responder, otherwise it will throw an `\Webmunkeez\ADRBundle\Exception\RenderingException` exception).
It has a `priority: -20`.

##### JsonResponder

[](#jsonresponder)

`\Webmunkeez\ADRBundle\Response\JsonResponder` that uses **Serializer** for render json (you can indicate serialization context with `\Webmunkeez\ADRBundle\Attribute\SerializationContext`):

```
use Webmunkeez\ADRBundle\Attribute\SerializationContext;

#[SerializationContext(['groups' => 'group_one'])]
final class StoryDetailAction implements \Webmunkeez\ADRBundle\Action\ActionInterface
{
    ...
}
```

This responder is active if the request contains `HTTP_ACCEPT application/json` header.
It has a `priority: -10`.

#### Custom responders

[](#custom-responders)

You can write your own reponders like in my previous `XmlResponder` example, by implementing `\Webmunkeez\ADRBundle\Response\ResponderInterface`.

Services implementing this interface are automatically tagged `webmunkeez_adr.responder` with `priority: 0`, and you can change it (in your `service.yaml` or by static `getDefaultPriority` method ; see [https://symfony.com/doc/current/service\_container/tags.html#tagged-services-with-priority](https://symfony.com/doc/current/service_container/tags.html#tagged-services-with-priority)).

You can define "generic" responders like html, json, xml and so on. But you can also define more specifics, by checking `$request->attributes->get('_controller')` to make a responder only for a specific action:

```
final class CustomResponder implements \Webmunkeez\ADRBundle\Response\ResponderInterface
{
    private RequestStack $requestStack;
    private Environment $twig;

    public function __construct(RequestStack $requestStack, Environment $twig)
    {
        $this->requestStack = $requestStack;
        $this->twig = $twig;
    }

    public function supports(): bool
    {
        $controller = $this->requestStack->getCurrentRequest()->attributes->get('_controller');
        $actionClass = false !== strpos($controller, '::') ? substr($controller, 0, strpos($controller, '::')) : $controller;

        return CustomResponderAction::class === $actionClass;
    }

    public function render(?\Webmunkeez\ADRBundle\Response\ResponseDataInterface $data = null): Response
    {
        $data = array_merge($data, ['customResponder' => true]);

        $html = $this->twig->render($this->requestStack->getCurrentRequest()->attributes->get('_template_path'), $data);

        return new Response($html);
    }
}
```

### Render Exception Listener

[](#render-exception-listener)

If there is an uncaught `\Webmunkeez\ADRBundle\Exception\RenderingException`, it will be catch by this listener which will throw an `\Symfony\Component\HttpKernel\Exception\NotAcceptableHttpException` that will embed the original exception.

### Exception Listener

[](#exception-listener)

If there is an uncaught `\Throwable`, it will be catch by this listener which will throw an `\Symfony\Component\HttpKernel\Exception\BadRequestHttpException` that will embed the original exception.

### Http Exception Listener

[](#http-exception-listener)

If you request an `Action` with `HTTP_ACCEPT application/json` header and if this `Action` throws an Exception that implements `\Symfony\Component\HttpKernel\Exception\HttpExceptionInterface`, its content will automatically be serialized in a JSON reading format to the `Response` body content.

###  Health Score

31

—

LowBetter than 68% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity11

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity72

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~14 days

Recently: every ~61 days

Total

54

Last Release

883d ago

Major Versions

v1.0.21 → v2.0.02022-05-23

PHP version history (3 changes)v1.0.0PHP &gt;=7.4.0

v1.0.11PHP &gt;=8.1.0

v2.0.6PHP &gt;=8.1

### Community

Maintainers

![](https://www.gravatar.com/avatar/77083015e90e5dfba99c4d06c8a766ed9afa2e0094819e0a5a95a433ea712f6f?d=identicon)[yannissgarra](/maintainers/yannissgarra)

---

Top Contributors

[![yannissgarra](https://avatars.githubusercontent.com/u/550934?v=4)](https://github.com/yannissgarra "yannissgarra (115 commits)")

---

Tags

symfonyAutowiringcontrollerstemplatesactionresponder

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/webmunkeez-adr-bundle/health.svg)

```
[![Health](https://phpackages.com/badges/webmunkeez-adr-bundle/health.svg)](https://phpackages.com/packages/webmunkeez-adr-bundle)
```

###  Alternatives

[shopware/platform

The Shopware e-commerce core

3.3k1.5M3](/packages/shopware-platform)[sulu/sulu

Core framework that implements the functionality of the Sulu content management system

1.3k1.3M152](/packages/sulu-sulu)[prestashop/prestashop

PrestaShop is an Open Source e-commerce platform, committed to providing the best shopping cart experience for both merchants and customers.

9.0k15.4k](/packages/prestashop-prestashop)[sylius/sylius

E-Commerce platform for PHP, based on Symfony framework.

8.4k5.6M647](/packages/sylius-sylius)[shopware/core

Shopware platform is the core for all Shopware ecommerce products.

595.2M386](/packages/shopware-core)[ec-cube/ec-cube

EC-CUBE EC open platform.

78527.0k1](/packages/ec-cube-ec-cube)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
