symfony-opcua · v4.3.x
Docs · Reference

Bundle services

Every container service the bundle registers — public and private. Useful when overriding, decorating, or debugging the DI tree.

The bundle registers a handful of services into the container. This page lists each one with its purpose.

Discover yourself

bash terminal
php bin/console debug:container --show-arguments PhpOpcua\\SymfonyOpcua\\

…or:

bash terminal
php bin/console debug:autowiring opcua

Public services

Service ID Class Purpose
PhpOpcua\SymfonyOpcua\OpcuaManager OpcuaManager The manager
opcua alias of OpcuaManager Short id (legacy + convenience)
PhpOpcua\Client\OpcUaClientInterface factory → $manager->connection() Default-connection client
PhpOpcua\SymfonyOpcua\Command\SessionCommand SessionCommand The opcua:session console command

Private / internal services

Service ID Class Purpose
php_opcua.psr16_cache Symfony\Component\Cache\Psr16Cache PSR-16 wrapper around the cache pool
php_opcua.logger_locator Symfony\Component\DependencyInjection\ServiceLocator Maps log_channel → Monolog logger; only registered if at least one connection declares a log_channel
php_opcua.logger_resolver \Closure Closure returned by LoggerResolverFactory::create — only registered with the locator

These are private — Symfony marks them as public: false by default. Accessible only via service injection or getContainer() in test mode.

Service wiring overview

text DI graph
┌─────────────────────────────────────────────────────────────────────┐
│ PhpOpcua\SymfonyOpcua\OpcuaManager                                  │
│   $config              ← merged YAML tree                            │
│   $defaultLogger        ← Monolog "logger" or "monolog.logger.X"    │
│   $defaultCache         ← @php_opcua.psr16_cache                     │
│   $defaultEventDispatcher ← @event_dispatcher (nullable)             │
│   $loggerResolver       ← @php_opcua.logger_resolver (nullable)      │
└─────────────────────────────────────────────────────────────────────┘

        │ aliased as "opcua"

        │ factory call → connection()

┌─────────────────────────────────────────────────────────────────────┐
│ PhpOpcua\Client\OpcUaClientInterface                                │
│   Returned by OpcuaManager::connection(null)                         │
└─────────────────────────────────────────────────────────────────────┘

Logger resolver wiring

When at least one connection declares log_channel: <name>:

text logger resolver
php_opcua.logger_locator: ServiceLocator
    { foo: ServiceClosure(@monolog.logger.foo, NULL_ON_INVALID_REFERENCE),
      bar: ServiceClosure(@monolog.logger.bar, NULL_ON_INVALID_REFERENCE) }

php_opcua.logger_resolver: Closure
    factory: [App\Logging\LoggerResolverFactory, create]
    args:    [@php_opcua.logger_locator]

The closure receives a channel name → looks up in the locator → returns LoggerInterface or null (graceful fallback).

Overriding services

See Configuration · Parameters and overrides for the full pattern. Quick summary:

Decorate the manager

php decorator
use Symfony\Component\DependencyInjection\Attribute\AsDecorator;

#[AsDecorator(decorates: OpcuaManager::class)]
final class LoggingOpcuaManager extends OpcuaManager
{
    public function __construct(
        private OpcuaManager $inner,
        // ... your deps
    ) {}

    public function connect(?string $name = null): OpcUaClientInterface
    {
        // ... wrap
        return $this->inner->connect($name);
    }
}

Replace php_opcua.psr16_cache

text services.yaml
services:
    php_opcua.psr16_cache:
        class: App\Opcua\CustomPsr16Cache
        arguments: ['@my_cache_pool']

Container parameter — exposing the config

The bundle doesn't expose the full config as a container parameter by default. If you need it (for a HealthController listing connections), mirror it manually:

text services.yaml
parameters:
    app.opcua_config_connections:
        # mirror here, or pull from container build

Or, more practically, inject the full container parameter via %kernel.bundles_metadata% shenanigans — but that's overkill. The simplest is to pass the connection list explicitly to the controller.