Search by

chubbyphp / chubbyphp-laminas-config-factory

dominikzogg

Package info

github.com/chubbyphp/chubbyphp-laminas-config-factory

pkg:composer/chubbyphp/chubbyphp-laminas-config-factory

Statistics

Installs: 46 999

Dependents: 17

Suggesters: 2

Stars: 3

Open Issues: 0

1.5.4 2026-09-11 17:34 UTC

This package is auto-updated.

Last update: 2026-09-11 17:34:45 UTC


README

CI Coverage Status Mutation testing badge Latest Stable Version Total Downloads Monthly Downloads

bugs code_smells coverage duplicated_lines_density ncloc sqale_rating alert_status reliability_rating security_rating sqale_index vulnerabilities

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

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 $config as is for an unnamed factory, or $config[$name] (default []) for a named one.
  • resolveDependency(ContainerInterface $container, string $class, string $factoryClass): returns the service $class . $name from the container if it exists, otherwise creates it with new $factoryClass($name). The name is propagated, so a secondary factory resolves secondary dependencies.
  • 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): calls set<Key>() for every config entry, passing the value through resolveValue().
<?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