elie29/zend-phpdi-config

PSR-11 PHP-DI autowire container configurator for Laminas, Mezzio, ZF2, ZF3 and Zend Expressive applications

v9.0.2 2025-03-11 13:11 UTC

README

Build Status Coverage Status Packagist Downloads

🚀 Quick Start

composer require elie29/zend-phpdi-config
// config.php
use Elie\PHPDI\Config\Config;
use Elie\PHPDI\Config\ContainerFactory;

$container = (new ContainerFactory())(
    new Config(require __DIR__ . '/config.php')
);

✨ Features

  • 🧩 PSR-11 compatible container configuration
  • ⚡ Autowiring support
  • 🔗 Service manager compatibility (Laminas/Mezzio)
  • 💻 CLI tool for autowire entry management
  • 🗃️ Cache and proxy support
  • 🔄 Easy migration from other containers

📖 Introduction

zend-phpdi-config acts as a bridge to configure a PSR-11 compatible PHP-DI container using service manager configuration. It can be used with Laminas and Mezzio starting from v6.0.0

This library uses autowiring technique, cache compilation and cache definitions as defined in PHP-DI.

🛠️ Configuration

Service Manager Configuration

To get a configured PSR-11 PHP-DI container, do the following:

<?php

use Elie\PHPDI\Config\Config;
use Elie\PHPDI\Config\ContainerFactory;

$factory = new ContainerFactory();

$container = $factory(
    new Config([
        'dependencies' => [
            'services'   => [],
            'invokables' => [],
            'autowires'  => [], // A new key added to support PHP-DI autowire technique
            'factories'  => [],
            'aliases'    => [],
            'delegators' => [],
        ],
        // ... other configuration

        // Enable compilation
        Config::DI_CACHE_PATH => __DIR__, // Folder path

        // Write proxies to file : cf. https://php-di.org/doc/lazy-injection.html
        Config::DI_PROXY_PATH => __DIR__, // Folder path

        // Disable autowire (enabled by default)
        Config::USE_AUTOWIRE => false

        // Enable cache
        Config::ENABLE_CACHE_DEFINITION => false, // boolean, true if APCu is activated
    ])
);

The dependencies sub associative array can contain the following keys:

  • services: an associative array that maps a key to a specific service instance or service name.
  • invokables: an associative array that map a key to a constructor-less service; i.e., for services that do not require arguments to the constructor. The key and service name usually are the same; if they are not, the key is treated as an alias. It could also be an array of services.
  • autowires: an array of service with or without a constructor; PHP-DI offers an autowire technique that will scan the code and see what are the parameters needed in the constructors. Any aliases needed should be created in the aliases configuration.
  • factories: an associative array that maps a service name to a factory class name, or any callable. Factory classes must be instantiable without arguments, and callable once instantiated (i.e., implement the __invoke() method).
  • aliases: an associative array that maps an alias to a service name (or another alias).
  • delegators: an associative array that maps service names to lists of delegator factory keys, see the Expressive delegators documentation for more details.

N.B.: The whole configuration -- unless dependencies -- is merged in a config key within the $container:

$config = $container->get('config');

💻 CLI Usage

The CLI command add-autowires-entry creates the configuration file if it doesn't exist, otherwise it adds the entry to the autowires key.

Example of adding ConsoleHelper to a config.php:

./vendor/bin/add-autowires-entry config.php "Laminas\\Stdlib\\ConsoleHelper"
[DONE] Changes written to config.php

You can also add this as a Composer script:

"scripts": {
    "add-autowire": "add-autowires-entry config.php \"My\\Service\\Class\""
}

🐞 Troubleshooting / FAQ

Q: My service is not autowired. A: Ensure it is listed in the autowires array and all dependencies are available.

Q: The CLI tool fails with a permissions error. A: Make sure the config file directory is writable.

Q: How do I debug container errors? A: Check that all dependencies are correctly defined and that your factories do not throw exceptions.

Using with Expressive

Replace contents of config/container.php with the following:

<?php

declare(strict_types = 1);

use Elie\PHPDI\Config\Config;
use Elie\PHPDI\Config\ContainerFactory;

// Protect variables from global scope
return call_user_func(function () {

    $config = require __DIR__ . '/config.php';

    $factory = new ContainerFactory();

    // Container
    return $factory(new Config($config));
});

Example of a ConfigProvider class

<?php

class ConfigProvider
{

    /**
     * Returns the configuration array
     */
    public function __invoke(): array
    {
        return [
            'dependencies' => $this->getDependencies()
        ];
    }

    /**
     * Returns the container dependencies
     */
    public function getDependencies(): array
    {
        return [
            'autowires' => [
                UserManager::class
            ]
        ];
    }
}

Where UserManager depends on Mailer as follow:

class UserManager
{
    private $mailer;

    public function __construct(Mailer $mailer)
    {
        $this->mailer = $mailer;
    }

    public function register($email, $password)
    {
        $this->mailer->mail($email, 'Hello and welcome!');
    }
}

class Mailer
{
    public function mail($recipient, $content)
    {
    }
}

Switching back to another container

To switch back to another container is very easy:

  1. Create your factories with __invoke function
  2. Replace autowires key in ConfigProvider by factories key, then for each class name attach its correspondent factory.

PSR 11 and Interop\Container\ContainerInterface

V4.x supports as well Interop\Container\ContainerInterface

Migration guides

🤝 Contributing

See CONTRIBUTING.md for guidelines on how to contribute, run tests, and submit pull requests.

📄 License

This project is licensed under the MIT License. See LICENSE for details.