chubbyphp / chubbyphp-laminas-config-factory
Package info
github.com/chubbyphp/chubbyphp-laminas-config-factory
pkg:composer/chubbyphp/chubbyphp-laminas-config-factory
Requires
- php: ^8.3
- psr/container: ^2.0.2
Requires (Dev)
- chubbyphp/chubbyphp-dev-helper: dev-master
- chubbyphp/chubbyphp-mock: ^2.2.2
- infection/infection: ^0.35.4
- php-coveralls/php-coveralls: ^2.9.1
- phpstan/extension-installer: ^1.4.3
- phpstan/phpstan: ^2.2.13
- phpunit/phpunit: ^12.5.34
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Description
An abstract service factory for laminas/laminas-servicemanager and any other PSR-11 container that can be configured with plain PHP arrays, such as chubbyphp/chubbyphp-container via chubbyphp/chubbyphp-laminas-config, Aura.Di, Pimple, Auryn, Symfony or PHP-DI.
It solves one recurring problem: a service factory should work both as a single default service and as one of several
named instances (for example default and secondary database connections) without duplicating the factory code.
The factory carries an optional name, and the helper methods use it to select the matching config section and
dependencies.
The concept originates from @DASPRiD in dasprid/container-interop-doctrine, now maintained as roave/psr-container-doctrine. This package extracts the idea, with small adjustments, so it can serve as the basis for any service factory.
Requirements
- php: ^8.3
- psr/container: ^2.0.2
Installation
Through Composer as chubbyphp/chubbyphp-laminas-config-factory.
composer require chubbyphp/chubbyphp-laminas-config-factory "^1.5"
Usage
Writing a factory
Extend AbstractFactory and implement __invoke(). The base class provides four helpers:
resolveConfig(array $config): returns$configas is for an unnamed factory, or$config[$name](default[]) for a named one.resolveDependency(ContainerInterface $container, string $class, string $factoryClass): returns the service$class . $namefrom the container if it exists, otherwise creates it withnew $factoryClass($name). The name is propagated, so asecondaryfactory resolvessecondarydependencies.resolveValue(ContainerInterface $container, mixed $value): replaces a string with the container service of that id if one exists, recursing into arrays. Other values are returned unchanged.callSetters(ContainerInterface $container, object $object, array $config): callsset<Key>()for every config entry, passing the value throughresolveValue().
<?php declare(strict_types=1); namespace MyProject\Factory; use Chubbyphp\Laminas\Config\Factory\AbstractFactory; use MyProject\Service\ServiceA; use MyProject\Service\ServiceB; use MyProject\Service\ServiceC; use Psr\Container\ContainerInterface; final class ServiceAFactory extends AbstractFactory { public function __invoke(ContainerInterface $container): ServiceA { $config = $this->resolveConfig( $container->get('config')['serviceA'] ?? [] ); $serviceA = new ServiceA( $this->resolveDependency( $container, ServiceB::class, ServiceBFactory::class ), $this->resolveDependency( $container, ServiceC::class, ServiceCFactory::class ) ); // calls $serviceA->setLogger($container->get('logger')) // and $serviceA->setTimeout(30) return $this->callSetters($container, $serviceA, $config); } }
Unnamed and named factories
<?php declare(strict_types=1); use MyProject\Factory\ServiceAFactory; use Psr\Container\ContainerInterface; /** @var ContainerInterface $container */ $container = ...; // unnamed: uses config['serviceA'] // and the dependencies ServiceB::class, ServiceC::class $serviceA = (new ServiceAFactory())($container); // named: uses config['serviceA']['default'] // and the dependencies ServiceB::class.'default', ServiceC::class.'default' $serviceA = (new ServiceAFactory('default'))($container); // named via static call, useful for container definitions $serviceA = [ServiceAFactory::class, 'default']($container);
The static form works because AbstractFactory::__callStatic() treats the method name as the factory name.
Container definition
The static form lets you register named services without writing a class per name. Example for laminas/laminas-servicemanager:
<?php declare(strict_types=1); use MyProject\Factory\ServiceAFactory; use MyProject\Service\ServiceA; return [ 'serviceA' => [ 'default' => ['logger' => 'logger', 'timeout' => 30], 'secondary' => ['logger' => 'secondaryLogger', 'timeout' => 60], ], 'dependencies' => [ 'factories' => [ ServiceA::class.'default' => [ServiceAFactory::class, 'default'], ServiceA::class.'secondary' => [ServiceAFactory::class, 'secondary'], ], ], ];
Copyright
2026 Dominik Zogg