Decorators
Decorators wrap existing services to add behavior:
services:
logger:
constructor:
func: "log.New"
logging_decorator:
constructor:
func: "log.NewDecorator"
args:
- "@.inner" # Receives the decorated service
decorates: logger
decoration_priority: 10
metrics_decorator:
constructor:
func: "metrics.NewDecorator"
args:
- "@.inner"
decorates: logger
decoration_priority: 20 # Higher priority wraps firstExecution order: metrics(logging(logger))
Rules
- Must use
@.innerin constructor args to receive the decorated service - Multiple decorators on same service are ordered by
decoration_priority(descending) - The decorated service’s own ID becomes an alias to the outermost decorator,
so
@loggerresolves tometrics(logging(logger)) - The original definition is moved to
<decorator>.inner, which@.innerpoints at (the.innersuffix is reserved and cannot be used in service IDs) - The decorator type must be compatible with the decorated service type
- The base service and each decorator keep their own
sharedsetting: a shared service may be wrapped by a non-shared decorator and vice versa - The decorator does not inherit tags of the decorated base service. Tags declared on the base stay on its inner, undecorated definition, so tagged collections receive the undecorated instance (Symfony semantics) — tag the decorator explicitly if the collection should get the decorated one
- A decorator cannot itself be decorated