PHPackages                             xphere/tag-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. [Utility &amp; Helpers](/categories/utility)
4. /
5. xphere/tag-bundle

AbandonedArchivedSymfony-bundle[Utility &amp; Helpers](/categories/utility)

xphere/tag-bundle
=================

Helps collecting tagged services to inject them into others

1.8(9y ago)110.2k1MITPHP

Since Jun 10Pushed 9y ago2 watchersCompare

[ Source](https://github.com/xphere/tag-bundle)[ Packagist](https://packagist.org/packages/xphere/tag-bundle)[ Docs](https://github.com/xphere/tag-bundle)[ RSS](/packages/xphere-tag-bundle/feed)WikiDiscussions master Synced 1mo ago

READMEChangelogDependencies (4)Versions (15)Used By (0)

xphere/tag-bundle
=================

[](#xpheretag-bundle)

Are you tired to add `CompilerPass`es just to collect some services tagged on your container?

Say NO to most of them with this bundle!

[![SensioLabsInsight](https://camo.githubusercontent.com/20dc2d01027842d38e4145e4ec76170fcb57477c5dae92652a8f6325979505e5/68747470733a2f2f696e73696768742e73656e73696f6c6162732e636f6d2f70726f6a656374732f64636364613865622d383834622d343536622d616465612d3361383231613765633163332f736d616c6c2e706e67)](https://insight.sensiolabs.com/projects/dccda8eb-884b-456b-adea-3a821a7ec1c3)

⚠ Note ⚠
--------

[](#-note-)

Mind the namespace change

- Before `0.4.0`: `Berny\Bundle\TagBundle`
- After `0.4.0`: `xPheRe\Bundle\TagBundle`

Why I would want that?
----------------------

[](#why-i-would-want-that)

More than often you want to search for services tagged with a particular tag and call some method in your service with them. This can be done with a custom `CompilerPass`.

```
services:
    my_plugin_enumerator:
        class: PluginEnumerator

    useless_plugin:
        class: UselessPlugin
        tag: - { name: my_plugin }

    even_more_useless_plugin:
        class: EvenMoreUselessPlugin
        tag: - { name: my_plugin }
```

```
class PluginEnumeratorConsumerCompilerPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        if (!$container->has('my_plugin_enumerator')) {
            return;
        }

        $definition = $container->findDefinition('my_plugin_enumerator');

        $taggedServices = $container->findTaggedServices('my_plugin');

        foreach ($taggedServices as $id => $attributes) {
            $definition->addMethodCall('addPlugin', array(new Reference($id)));
        }
    }
}
```

Another use case is to inject a service to every other that is tagged with a particular tag. An example:

```
services:
    my_event_dispatcher:
        class: MyEventDispatcher

    useless_service:
        class: UselessService
        tag: - { name: my_event_dispatcher.aware }

    even_more_useless_service:
        class: EvenMoreUselessService
        tag: - { name: my_event_dispatcher.aware }
```

```
class MyEventDispatcherInjectableCompilerPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        if (!$container->has('my_event_dispatcher')) {
            return;
        }

        $reference = new Reference('my_event_dispatcher');
        $taggedServices = $container->findTaggedServices('my_event_dispatcher.aware');

        foreach ($taggedServices as $id => $attributes) {
            $definition = $container->findDefinition($id);
            $definition->addMethodCall('setMyEventDispatcher', array($reference));
        }
    }
}
```

This boilerplate is repeated once and again in every project I've seen. With this bundle you can say goodbye to most of this compiler passes.

Features
--------

[](#features)

With this bundle you can:

- Tag a service as a consumer of another tag.
- Tag a service as injectable into others.

Compatibility
-------------

[](#compatibility)

Tested under Symfony2, from 2.0.10 to 2.6.3

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

[](#installation)

### From [composer/packagist](https://getcomposer.org)

[](#from-composerpackagist)

- Require `xphere/tag-bundle` package in your composer
- Add the bundle to your `AppKernel.php`

Usage
-----

[](#usage)

### Consumer

[](#consumer)

You can define a service as a "tag consumer" of another tag, and let the bundle make the relationship between them. Just tag your service as a `tag.consumer` and specify which `tag` to collect and which `method` to call.

The first example using this bundle is just configuration:

```
services:
    my_plugin_enumerator:
        class: PluginEnumerator
        tags:
            - { name: tag.consumer, tag: my_plugin, method: addPlugin }

    useless_plugin:
        class: UselessPlugin
        tag: - { name: my_plugin }

    even_more_useless_plugin:
        class: EvenMoreUselessPlugin
        tag: - { name: my_plugin }
```

The only change is the tag in `my_plugin_enumerator`. The `CompilerPass` boilerplate is gone.

This calls `PluginEnumerator::addPlugin` with each `my_plugin`, but you can also call this once with all services using the `bulk` parameter.

```
services:
    my_plugin_enumerator:
        class: PluginEnumerator
        tags:
            - { name: tag.consumer, tag: my_plugin, method: addPlugins, bulk: true }
```

This is calling `PluginEnumerator::addPlugins` just once, with an array of the services.

To make the service consume its dependencies through it's constructor, just omit the `method` attribute in the tag.

### Injectable

[](#injectable)

You can define a service as a "tag injectable" from another tag, and let the bundle do the hard work. Just tag your service as a `tag.injectable` and specify which `tag` to collect and which `method` to call in each service.

The second example in the introduction will be like this:

```
services:
    my_event_dispatcher:
        class: MyEventDispatcher
        tag: - { name: tag.injectable, tag: my_event_dispatcher.aware, method: setMyEventDispatcher }

    useless_service:
        class: UselessService
        tag: - { name: my_event_dispatcher.aware }

    even_more_useless_service:
        class: EvenMoreUselessService
        tag: - { name: my_event_dispatcher.aware }
```

The only change is the tag in `my_event_dispatcher`. The `CompilerPass` boilerplate is also gone.

This forces all `my_event_dispatcher.aware` to have a `setMyEventDispatcher` method. But you can change that for a particular service with the `method` parameter.

```
services:
    my_event_dispatcher:
        class: MyEventDispatcher
        tag: - { name: tag.injectable, tag: my_event_dispatcher.aware, method: setMyEventDispatcher }

    useless_service:
        class: UselessService
        tag: - { name: my_event_dispatcher.aware, method: setEventDispatcher }

    even_more_useless_service:
        class: EvenMoreUselessService
        tag: - { name: my_event_dispatcher.aware }
```

Now it's calling `setEventDispatcher` for `UselessService`, and the default method for the others.

Advanced usage
--------------

[](#advanced-usage)

That's all about the basics, there are more options available for major control over your dependencies, though.

### Order

[](#order)

You can specify the order in which services will be injected into the consumer with the `order` field in each tag. Lower orderings have priority over higher orders. Tagged services with no order will be injected after ordered ones. In case of a tie between orders, keeps symfony declaration order.

### Indexing bulk services

[](#indexing-bulk-services)

When bulk is active, you can specify a `key` which will be used to index each tag, instead of a plain array.

```
services:
    my_command_bus:
        class: MyCommandBus
        tags:
            - { name: tag.consumer, tag: my_command_handler, bulk: true, key: handles }

    my_class_command_handler:
        class: MyClassCommandHandler
        tag: - { name: my_command_handler, handles: MyClass }

    other_class_command_handler:
        class: OtherClassCommandHandler
        tag: - { name: my_command_handler, handles: OtherClass }
```

This results in the next injection:

```
[
    'MyClass' => new MyClassCommandHandler(),
    'OtherClass' => new OtherClassCommandHandler(),
]
```

You can also specify that multiple elements will collide with same index and needs to collect arrays instead of single services with the `multiple` field in your consumer definition.

```
services:
    my_event_bus:
        class: MyEventBus
        tags:
            - { name: tag.consumer, tag: my_event_handler, bulk: true, key: listensTo, multiple: true }

    first_event_handler:
        class: FirstEventHandler
        tag: - { name: my_event_handler, listensTo: MyEvent }

    second_event_handler:
        class: SecondEventHandler
        tag: - { name: my_event_handler, listensTo: OtherEvent }

    third_event_handler:
        class: ThirdEventHandler
        tag: - { name: my_event_handler, listensTo: MyEvent }
```

This results in the next injection:

```
[
    'MyEvent' => [
        new FirstEventHandler(),
        new ThirdEventHandler(),
    ],
    'OtherEvent' => [
        new SecondEventHandler(),
    ],
]
```

Multiple also honors ordering, if specified.

### Reference

[](#reference)

As usual, dependencies are injected directly to your service, but you can inject your dependencies as service ids instead by setting the field `reference` to `false` in your consumer definition.

### InstanceOf

[](#instanceof)

You can force your dependencies to be an instance of a class or interface with the field `instanceof` in your consumer definition.

### No bundle

[](#no-bundle)

You can add manually `TagConsumerPass` or `TagInjectablePass` (or both) without adding the "whole" bundle to your `Kernel`, even customize the tag names used to apply them.

In your `Kernel`:

```
[...]
use xPheRe\Bundle\TagBundle\DependencyInjection\Compiler\TagConsumerPass;
use xPheRe\Bundle\TagBundle\DependencyInjection\Compiler\TagInjectablePass;
[...]

class AppKernel extends Kernel
{
    [...]
    protected function prepareContainer(ContainerBuilder $container)
    {
        parent::prepareContainer($container);

        $container->addCompilerPass(new TagConsumerPass('tag_collector'));
        $container->addCompilerPass(new TagInjectablePass('tag_injectable'));
    }
    [...]
}
```

###  Health Score

35

—

LowBetter than 80% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity23

Limited adoption so far

Community11

Small or concentrated contributor base

Maturity71

Established project with proven stability

 Bus Factor1

Top contributor holds 98.1% 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 ~97 days

Recently: every ~66 days

Total

14

Last Release

3459d ago

Major Versions

0.4.0 → 1.02015-08-10

1.8 → 2.0.x-dev2016-11-28

### Community

Maintainers

![](https://www.gravatar.com/avatar/608fb6577803c78b31cf7ade299388f44ffe2e13f4cc773c331944773cca6b97?d=identicon)[xphere](/maintainers/xphere)

---

Top Contributors

[![xphere](https://avatars.githubusercontent.com/u/170968?v=4)](https://github.com/xphere "xphere (51 commits)")[![rogergros](https://avatars.githubusercontent.com/u/2053670?v=4)](https://github.com/rogergros "rogergros (1 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/xphere-tag-bundle/health.svg)

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

###  Alternatives

[symfony/ux-chartjs

Chart.js integration for Symfony

1003.2M18](/packages/symfony-ux-chartjs)[codefog/contao-haste

haste extension for Contao Open Source CMS

42650.8k139](/packages/codefog-contao-haste)[spomky-labs/pwa-bundle

Progressive Web App Manifest Generator Bundle for Symfony.

6144.4k1](/packages/spomky-labs-pwa-bundle)[symfony/ux-cropperjs

Cropper.js integration for Symfony

19280.3k3](/packages/symfony-ux-cropperjs)[netgen/content-browser

Netgen Content Browser is a Symfony bundle that provides an interface which selects items from any kind of backend and returns the IDs of selected items back to the calling code.

14112.1k8](/packages/netgen-content-browser)[pentiminax/ux-datatables

DataTables.net integration for Symfony

605.6k](/packages/pentiminax-ux-datatables)

PHPackages © 2026

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