# Part 3: Extending OXID eShop using the Symfony DI container

**URL:** <https://forum.oxid-esales.com/t/part-3-extending-oxid-eshop-using-the-symfony-di-container/96504>\
**Category:** Blog Posts über OXID\
**Tags:** entwicklung-dev\
**Created:** [April 17, 2020, 11:03am UTC](https://forum.oxid-esales.com/t/part-3-extending-oxid-eshop-using-the-symfony-di-container/96504 "2020-04-17T11:03:09Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![koltan](https://forum.oxid-esales.com/letter_avatar_proxy/v4/letter/k/ed655f/32.png) [@koltan](https://forum.oxid-esales.com/u/koltan)\
**Post date:** [April 17, 2020, 11:03am UTC](https://forum.oxid-esales.com/t/part-3-extending-oxid-eshop-using-the-symfony-di-container/96504/1 "2020-04-17T11:03:09Z")

</div>

## Extension of the shop logic using the Symfony DI container

In the [second part](https://forum.oxid-esales.com/t/part-2-dependency-injection-within-modules/96456) of this blog post series we learned how modules can use the DI container, simply by placing a `services.yaml` file in the module’s root directory. However, we did the actual code extension in the traditional way by registering an extension in the metadata.php file for a shop class.

## General problems with direct extensions of shop services

But why not simply extend a shop service directly in the `services.yaml `file? In this case, the file extension with the somewhat strange `_parent` construct could be dropped. Why not just create a subclass of a shop service and register it under the key of the original class? That, actually, would be obvious.

Unfortunately, that won’t work: As a matter of fact, OXID framework will refuse to activate a module in which a service from the shop is overwritten. Why this harassment? Here are two reasons:

On the one hand, only a single module could extend one service. If two different modules try to do so, the module which is activated later, wins. This isn’t a desirable behaviour, is it.

## Extend Multishop environments

Secondly, in a multi store environment, the change would automatically be active for all shops. One of the advantages of OXID modules is that they can be activated selectively for individual shops, while their installation in other shops would have no effect. But this would not work if shop services would have been replaced. In this case, all services would have always be changed for the entire installation.

But doesn’t this also apply to internal services of a module? In general yes – in practice no. Because, as described in the last blog post, we’d need to have a traditional entry point that is instantiated via `oxNew()`. And this entry point would depend on whether the module is activated in a shop or not. This prevents that internal services of a module are called for sub-shops for which they are not intended.

## Overwriting Shop Services with Modules

But what if I know for sure that only one of my modules overwrites this one shop service, and that I need the change for all my sub-shops? Shouldn’t I be able to use the capabilities of the DI container? This is indeed a legitimate request. And this is where the `var/configuration/configurable_services.yaml` file mentioned in the last blog post comes into the game. This is the only place where all services may be replaced by alternative implementations. The implementation itself can lie quietly in a module and can also be configured through the module’s `services.yaml` file. Only the alternative implementation of the one service to be replaced needs to be entered in the `configurable_services.yaml` file. This has to be done manually. The developer should make a conscious decision: Yes, I want to overwrite a shop service and I want to do this with exactly this one class from my module. In this way, the `configurable_services.yaml` file also becomes documentation of which shop services have been replaced by alternative implementations in a particular project.

## OXID composer packages

These implementations do not necessarily have to be located in an OXID module. There is also the possibility to do this in a normal composer package. And the DI container can also be used in this package: If the type is set to “oxideshop-component” in the `composer.json` file of a composer package, the OXID composer plugin checks if there is a `services.yaml` file in this package. If so, it will be included in the `generated_services.yaml` file like an OXID module. The same applies here as for the `services.yaml` file in modules: services can be configured within the package, but it is not possible to replace shop services. To do this, the service must be entered in the `configurable_services.yaml` file.

However, this type of extension is an either/or: either a service is replaced or not. But what about code extensions that should only be active in certain subshops? The traditional OXID programming style with `oxNew()` allows you to enable or disable class extensions specifically for individual subshops. With entries in the `configurable_services.yaml` file this is not possible. What is entered here is valid for the entire installation, independent of the respective shop.

## Shop-specific Symfony Events

This is where the other extension option comes into play, which is provided by the Symfony DI container: Events. A detailed explanation of how events work and how to configure them can be found in the [Symfony documentation](https://symfony.com/doc/current/event_dispatcher.html).

The principle is simple: event calls are placed at various points in the shop code. For these events you can subscribe to a so-called `EventSubscriber`; and when the execution of the code reaches the appropriate place, the code of the `EventSubscriber` is called. The subscriber is passed the event object, which, depending on the event, can also contain a certain payload. The [developer documentation](https://docs.oxid-esales.com/developer/en/6.2/development/tell_me_about/event/index.html) contains information on which events there are; there are also code examples that explain how to use them.

It should only be pointed out here that the `EventSubscribers` can be written in a way that they are only called for shops for which the module is also activated. This can be easily done by not simply letting the subscriber implement the `EventSubscriber interface `provided by Symfony, but inheriting it from the class `AbstractShopAwareEventSubscriber`, which is part of the OXID framework. This automatically ensures that the corresponding `EventSubscribers` are configured to know for which shops they are active. This is also done in the `generated_services.yaml `file mentioned in the previous blog post of this series.

The same mechanism is implemented for the [OXID console](https://docs.oxid-esales.com/developer/en/6.2/development/tell_me_about/console.html), which is based on the [Symfony console](https://symfony.com/doc/current/console.html). Again, you can register console commands in the DI container so that they are only active for certain shops. The abstract class to inherit from is called `AbstractShopAwareCommand`, which is not very original.

And this brings us to the end of our short tour, where we showed how the Symfony DI container integrated in OXID can be used in module and project development. We hope that this helps you in your work; and of course we are always happy about Feedback.

---

<div class="post-metadata">

**Author:** ![system](https://forum.oxid-esales.com/user_avatar/forum.oxid-esales.com/system/32/4245_2.png) [@system](https://forum.oxid-esales.com/u/system)\
**Post date:** [July 13, 2026, 8:37pm UTC](https://forum.oxid-esales.com/t/part-3-extending-oxid-eshop-using-the-symfony-di-container/96504/2 "2026-07-13T20:37:53Z")

</div>


