PHPackages                             pitch/symfony-adr - 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. pitch/symfony-adr

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

pitch/symfony-adr
=================

This bundle makes it easier to follow ADR pattern while writing a Symfony application

v1.4.0(3y ago)2270[1 issues](https://github.com/ph-fritsche/symfony-adr/issues)1MITPHPPHP &gt;=7.4

Since May 5Pushed 3y ago1 watchersCompare

[ Source](https://github.com/ph-fritsche/symfony-adr)[ Packagist](https://packagist.org/packages/pitch/symfony-adr)[ RSS](/packages/pitch-symfony-adr/feed)WikiDiscussions master Synced yesterday

READMEChangelog (10)Dependencies (10)Versions (16)Used By (1)

ADR Bundle for Symfony
======================

[](#adr-bundle-for-symfony)

This bundle makes it easier to follow ADR pattern while writing a [Symfony](https://symfony.com) application.

Usage
-----

[](#usage)

### Turn controller into action

[](#turn-controller-into-action)

Decouple responder logic from action logic by moving it out of the controller. Just return the payload!

If a controller returns anything but a [`Response`](https://symfony.com/doc/current/components/http_foundation.html#response) object, Symfony dispatches a `kernel.view` event.

Now instead of registering a bunch of event listeners to be iterated through, implement [`ResponseHandlerInterface`](https://github.com/ph-fritsche/symfony-adr/blob/master/src/Responder/ResponseHandlerInterface.php).

```
namespace App\Responder;

use Pitch\AdrBundle\Responder\ResponseHandlerInterface;
use Pitch\AdrBundle\Responder\ResponsePayloadEvent;
use Symfony\Component\HttpFoundation\Response;

use App\Entity\MyPayload;

class MyPayloadHandler implements ResponseHandlerInterface
{
    public function getSupportedPayloadTypes(): array
    {
        return [
            MyPayload::class,
        ];
    }

    public function handleResponsePayload(
        ResponsePayloadEvent $payloadEvent
    ): void {
        $response = new Response();

        // prepare the response
        if ($payloadEvent->request->getAttribute('_foo') === 'bar') {
            // adjust the response according to the request
        }

        $payloadEvent->payload = $response;
    }
}
```

If your handler class is available as a service according to your `config/services.yaml`, it will be discovered and used whenever a `MyPayload` object is returned by a controller.

With default config just put the class into `src/Responder/MyPayloadHandler.php` and you are done.

Your response handler can report its priority in `getSupportedTypes`.

```
class MyPayloadHandler implements ResponseHandlerInterface
{
    public function getSupportedPayloadTypes(): array
    {
        return [
            MyPayload::class => 123,
            MyOtherPayload:class => 456,
        ];
    }
    //...
}
```

Or you can overwrite the handled types and priorities for response handlers in your `services.yml`.

```
services:
  App\Responder\MyPayloadHandler:
    tags:
      - name: pitch_adr.responder
        for: [App\Entity\MyPayload]
        priority: 1000
      - name: pitch_adr.responder
        for: [App\Entity\MyOtherPayload]
        priority: 0
```

You can easily debug your responder config per console command.

```
$ php bin/console debug:responder MyPayload

```

### Treat some exceptions as response payload

[](#treat-some-exceptions-as-response-payload)

A robust domain will have strict constraints and throw exceptions whenever an unexpected or invalid condition occurs and for every exception falling through your controller/action Symfony dispatches a `kernel.exception` event.

You can reserve this event for truly unexpected behavior without repeating similar try-catch-blocks across your controllers.

Define which exceptions should be catched for all controllers and be treated as response payload:

```
pitch_adr:
    graceful:
        - { value: RuntimeException, not: [BadRuntime, OtherBadRuntime] }
        - Foo
        - { not: GloballyBadException }
        - { value: Bar, not: BadBar }
```

If [Doctrine Annotations](https://github.com/doctrine/annotations/) is installed, you can define extra rules for your controller methods per annotation:

```
namespace App\Controller;

use Pitch\AdrBundle\Configuration\Graceful;

class MyController
{
    /**
     * @Graceful(not=LocallyBadException::class)
     * @Graceful(LocallyGoodException::class, not={ButNotThisOne::class, OrThatOne::class})
     */
    public function __invoke(
        Request $request
    ) {
        /// ...
    }
}
```

With PHP8 you can define extra rules per [Attribute](https://www.php.net/manual/en/language.attributes.overview.php):

```
namespace App\Controller;

use Pitch\AdrBundle\Configuration\Graceful;

class MyController
{
    #[Graceful(not: LocallyBadException::class)]
    #[Graceful(LocallyGoodException::class, not: [ButNotThisOne::class, OrThatOne::class])]
    public function __invoke(
        Request $request
    ) {
        /// ...
    }
}
```

Rules are applied in the order of appearance, method rules after global rules.

Now you can just create a `App\Responder\MyGoodRuntimeExceptionHandler` as described above.

### Default response handlers

[](#default-response-handlers)

The bundle automatically adds some response handlers for basic types with negative priority so that they will be called if none of your response handlers stops propagation earlier. If you don't want the default handlers to be added, you can modify this behavior per bundle configuration.

```
pitch_adr:
    defaultResponseHandlers: false # defaults to true
```

### Prioritised response handlers

[](#prioritised-response-handlers)

If consecutive response handlers (in the order of config priority) implement [`PrioritisedResponseHandlerInterface`](https://github.com/ph-fritsche/symfony-adr/blob/master/src/Responder/PrioritisedResponseHandlerInterface.php), that block of handlers will be reordered on runtime according the priority they report for the specific request per `getResponseHandlerPriority`.

```
Given the following response handlers are configured to handle a `SomePayloadType`:

900: HandlerA
600: PrioritisedHandler1 with getResponseHandlerPriority(): 1
500: PrioritisedHandler2 with getResponseHandlerPriority(): 2
400: PrioritisedHandler3 with getResponseHandlerPriority(): 0
100: HandlerB

these will be executed in the following order:

HandlerA
PrioritisedHandler2
PrioritisedHandler1
PrioritisedHandler3
HandlerB

```

### Negotiating content type in response handlers

[](#negotiating-content-type-in-response-handlers)

See [`JsonResponder`](https://github.com/ph-fritsche/symfony-adr/blob/master/src/Responder/Handler/JsonResponder.php) on how to implement your own prioritised response handlers that handle a payload according to the [Accept](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept) header on the request.

You can set a default content type for requests that don't include an Accept header. This can be done per container parameter or as controller annotation.

```
parameters:
    pitch_adr.defaultContentType: 'application/json'
```

```
use Pitch\AdrBundle\Configuration\DefaultContentType;

class MyController
{
    #[DefaultContentType('application/json')]
    public function __invoke()
    {
        // ...
    }
}
```

###  Health Score

26

—

LowBetter than 43% of packages

Maintenance10

Infrequent updates — may be unmaintained

Popularity14

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity60

Established project with proven stability

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 ~34 days

Recently: every ~97 days

Total

13

Last Release

1422d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/14faf0e942f2e3361ad07e017bf356d02bb7b76ab47d66a0d52faf4c03e6faec?d=identicon)[ph.fritsche](/maintainers/ph.fritsche)

---

Tags

symfonyadraction domain responder

###  Code Quality

TestsPHPUnit

Code StylePHP\_CodeSniffer

### Embed Badge

![Health badge](/badges/pitch-symfony-adr/health.svg)

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

###  Alternatives

[symfony/framework-bundle

Provides a tight integration between Symfony components and the Symfony full-stack framework

3.6k235.4M9.7k](/packages/symfony-framework-bundle)[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)[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)
