Categories


Recent Posts


Archives


A Brief Look at Every Symfony Service Configuration

astorm

Frustrated by Magento? Then you’ll love Commerce Bug, the must have debugging extension for anyone using Magento. Whether you’re just starting out or you’re a seasoned pro, Commerce Bug will save you and your team hours everyday. Grab a copy and start working with Magento instead of against it.

Updated for Magento 2! No Frills Magento Layout is the only Magento front end book you'll ever need. Get your copy today!

This entry is part 4 of 4 in the series Sylius for Magento and PHP Developers. Earlier posts include Five First Impressions of the Sylius eCommerce System, Symfony's Service Container, and Symfony: Autowiring Services. This is the most recent post in the series.

This was almost a series of quickies posts — while it’s impractical to dive deep on each/every one of these Symfony service configuration values, there is some value to briefly talking about each one and linking off to the official docs. There’s nothing worse than debugging a problem and finding a handful of service configurations you’ve never seen before.

The examples in this article all assume you’re using symfony’s yaml configuration files, but everything should apply equally to the XML and PHP variants.

Finally — these are quick thoughts dashed off by someone without a huge amount of practical Symfony experience. If something seems off or funky that’s probably because it is off or funky. Corrections are warmly welcomed.

Service Configuration: Modern Symfony

autowire

The autowire configuration lets Symfony know you want to automatically pass parameters to the constructor of a service based on its type hints. It’s what I usually call automatic constructor dependency injection, and I’ve written more about it here.

tags

The tags configuration allows you to add a list of tags to your service configuration. These tags are primarily used to tell Symfony that this service should be considered for some special role in Symfony. For example, give your service the twig.extension tag and Symfony will treat it as a twig extension when it initializes its twig template engine.

autoconfigure

The autoconfigure configuration, when set to true, tells the system to “automatically apply certain configuration to your services“.

That’s not the most useful description, is it?

To understand autoconfigure, you need to understand how Symfony has worked historically. If you wanted a service class to play a role in some other Symfony system, you would typically need to tag that service with a specific name, and then (maybe) apply some extra configuration.

If your service has autoconfigure set to true, then Symfony will handle this automatically if your service class implements a specific interface or extends a certain class. For example, consider this code

use Symfony\Component\Console\Command\Command;
//...
$container->registerForAutoconfiguration(Command::class)
    ->addTag('console.command');

This is where Symfony tells the container

Hey — if a service is autoconfigured AND it extends the Symfony\Component\Console\Command\Command class, then automatically tag it with the console.command tag

Then, when Symfony’s container sees the console.command tag, it knows it should include the service as a command for the bin/console command.

In practice, autoconfigure is an attempt to move the responsibility of “identifying a service class for a particular role” away from the service configuration and into PHP code. Extend the right class or implement the right interface, and Symfony will just know your class is meant to do something.

bind

The bind configuration is related to autowiring, in that it allows you to

  1. Tell Symfony what to pass in for arguments without a type hint
  2. Tell Symfony to pass in a different service than is indicated via the type hint

It’s important to note that for the second use-case, this new service will still need to either extend the type hint’s class or implement its interface, as that’s just how PHP work.

Service Configuration: Classes, Hierarchy, and Naming

alias

The alias configuration allows you to create a second name for your service, and will also allow you to alias a private service as public.

parent

The parent configuration lets your service inherit the configuration of another service in your system.

abstract

The abstract configuration allows you to link a service to an abstract PHP class. Without an abstract configuration, Symfony would try to instantiate the abstract class, which is a fatal PHP error.

class

As we’ve seen, the class configuration allows you to set the class name symfony should use when instantiating your service object.

synthetic

Symfony allows you to inject new services into the container at runtime. However you still need a configuration entry for the service you plan to inject. The synthetic configuration tells Symfony that you plan to inject a service at runtime.

We haven’t talked much about it, but Symfony’s container code is actually compiled. Whenever you make a change to the service configuration Symfony will regenerate a bunch of PHP code in the background. Unlike other container systems (we’re looking at you Magento 2) this process is (100%?) seamless and you don’t need to do any manual cache clearing during development to see service configuration changes.

Service Configuration: Object Instances

shared

The shared configuration, which defaults to true, determines whether the service container will return the same instance of a service object every time (shared:true) or if the service container will return a different instance of the service object every time (shared:false). Another way to think about this is a shared service acts similar to singleton object, while a non-shared service acts similar to a regular object instantiation.

It sounds like Symfony had more complex ideas around object/container scope that have been deprecated since version 2.8.

public

A public service is a service you can access directly via the service container. A private service (public:false) is a service that may not be accessed directly via the service container. In modern versions of Symfony, services are private by default.

factory

Symfony’s service systems gets developers out of the business of instantiating service objects directly — however, sometimes the service.yaml configuration options aren’t powerful enough to instantiate your service the way you want. In these cases, the factory configuration allows you specify a class and method name that Symfony will use to instantiate your service object.

configurator

The configurator configuration allows you to provide a class and method that symfony will use to configure your service after it’s instantiated. That is, Symfony will pass the instantiated service object to this method and then your code will have a chance to configure it.

Service Configuration: Argument Injecting

arguments

The arguments configuration allows you to tell Symfony what values or services it should pass to a service object when instantiating it.

properties

The properties configuration allows you to set public properties on your service object.

calls

The calls configuration allows you to specify a method and list of arguments that Symfony will call instantiating the service. This is another way to get dependencies into your service object.

Service Configuration: Miscellaneous

deprecated

The deprecated configuration allows you to mark a particular service as deprecated (ths is software-speak for “we may remove this soon and you probably don’t want to use it”). These deprecation messages will end up in the Symfony logs, as well as the default Symfony developer toolbar.

file

The file configuration allows you to load a PHP file right before your service is loaded. Two things that might trip you up

  1. You need to use the full, non-relative, path to the file. The %kernel.root_dir% parameter-variable is useful here.

  2. If you’re loading resources with the resource configuration, you’ll need to include your file in the exclude list.

This seems like a useful, but old, configuration field. I would not be surprised to see this one go away in a future version of Symfony.

decorates, decoration_inner_name, and decoration_priority

Symfony’s services contain an implementation of the decorator pattern. The decorator pattern is — poorly named, and usually poorly explained (although this video does a pretty good job of it, if you can stand “enthusiastic YouTube persona”).

The elevator pitch for decorators is instead of creating a hierarchy of classes, it creates a hierarchy of object instantiation. An object is instantiated, and then passed to the constructor of a second object, and then that object is passed to the constructor of a third object, etc. If you’ve ever used middleware in Laravel you’ve been using something implemented with the decorator (or a decorator-like) pattern.

lazy

When a service is configured with lazy:true, this tells Symfony that it should defer instantiating the service object until a method on that service object is actually called. This magic is implemented via the Proxy design pattern.

Configurations Not Directly Related to a Service

_defaults

The _defaults configuration lives under the services: key, but is not a service configuration

#File: config/services.yaml
services:
    _default:
        #...

This configuration field allows you to set a configuration value for all your services — i.e. a default value. It works for most of the service configuration values we’ve discussed so far, and Symfony will complain with a useful message if you try to set something that’s not allowed in _default.

parameters

The parameters configuration lives at the top level of the services configuration

#File: config/services.yaml

parameters:
    locale: 'en'
    # ...
services:
    # ...

The parameters section of your configuration allows you to set values that can be used later on via services template variable. i.e. you’d be able to reference the value of locale later on in your service configuration via the string %locale%.

resource, exclude

You can use the resource and exclude configuration to import many services at once directly from PHP classes. The syntax is a little weird, as it looks like a service configuration

services:
    App\:
        resource: '../src/*'
        exclude: '../src/{Entity,Migrations,Tests,Kernel.php}'

These configuration fields live under a PHP namespace prefix that lives under the services: key. These two configuration fields are covered in greater detail in the Symfony: Autowiring Services article.

imports

The imports configuration lives at the top level of a service configuration file

#File config/services.yaml

imports:
    #...
services:
    #...

The imports section allows you to load service configurations from other files, and is primarily useful as an organizational tool.

Copyright © Alan Storm 1975 – 2019 All Rights Reserved

Originally Posted: 13th February 2019