{"id":21558547,"url":"https://github.com/elie29/zend-di-config","last_synced_at":"2026-01-03T16:16:55.308Z","repository":{"id":44928579,"uuid":"128076100","full_name":"elie29/zend-di-config","owner":"elie29","description":"PSR-11 PHP-DI container configurator for Laminas, Mezzio, ZF, Expressive applications or any framework that needs a PSR-11 container","archived":false,"fork":false,"pushed_at":"2025-03-11T13:16:27.000Z","size":1942,"stargazers_count":19,"open_issues_count":0,"forks_count":5,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-24T09:38:17.987Z","etag":null,"topics":["container","expressive-composer-installer","laminas","mezzio","mezzio-skeleton","php-di","php-di-container","psr-11","zend-expressive","zend-expressive-skeleton","zend-framework","zend-servicemanager"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/elie29.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-04-04T14:41:57.000Z","updated_at":"2025-03-12T08:35:35.000Z","dependencies_parsed_at":"2024-06-18T16:51:54.342Z","dependency_job_id":"bc2886b1-dede-4129-9ddd-b1f03a244b8f","html_url":"https://github.com/elie29/zend-di-config","commit_stats":{"total_commits":127,"total_committers":5,"mean_commits":25.4,"dds":"0.21259842519685035","last_synced_commit":"1d44c227c1dbbebb67e9a86512e8a7cd6e71be4f"},"previous_names":[],"tags_count":35,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elie29%2Fzend-di-config","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elie29%2Fzend-di-config/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elie29%2Fzend-di-config/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elie29%2Fzend-di-config/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/elie29","download_url":"https://codeload.github.com/elie29/zend-di-config/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248199570,"owners_count":21063709,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["container","expressive-composer-installer","laminas","mezzio","mezzio-skeleton","php-di","php-di-container","psr-11","zend-expressive","zend-expressive-skeleton","zend-framework","zend-servicemanager"],"created_at":"2024-11-24T08:15:08.340Z","updated_at":"2026-01-03T16:16:55.296Z","avatar_url":"https://github.com/elie29.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# zend-phpdi-config\n\n[![Build Status](https://github.com/elie29/zend-di-config/actions/workflows/php-build.yml/badge.svg)](https://github.com/elie29/zend-di-config/)\n[![Coverage Status](https://coveralls.io/repos/github/elie29/zend-di-config/badge.svg)](https://coveralls.io/github/elie29/zend-di-config)\n[![Packagist Downloads](https://img.shields.io/packagist/dt/elie29/zend-phpdi-config.svg)](https://packagist.org/packages/elie29/zend-phpdi-config)\n[![PHP Version](https://img.shields.io/packagist/php-v/elie29/zend-phpdi-config.svg)](https://packagist.org/packages/elie29/zend-phpdi-config)\n\n---\n\n## 🚀 Quick Start\n\n```bash\ncomposer require elie29/zend-phpdi-config\n```\n\n```php\n\u003c?php\n\ndeclare(strict_types=1);\n\nuse Elie\\PHPDI\\Config\\Config;\nuse Elie\\PHPDI\\Config\\ContainerFactory;\n\n$container = (new ContainerFactory())(\n    new Config(require __DIR__ . '/config/config.php')\n);\n```\n\n---\n\n## ✨ Features\n\n- 🧩 PSR-11 compatible container configuration\n- ⚡ Autowiring support\n- 🔗 Service manager compatibility (Laminas/Mezzio)\n- 💻 CLI tool for autowire entry management\n- 🗃️ Cache and proxy support\n- 🔄 Easy migration from other containers\n\n---\n\n## 📖 Introduction\n\n[zend-phpdi-config](https://packagist.org/packages/elie29/zend-phpdi-config) acts as a bridge to configure a PSR-11\ncompatible [PHP-DI](https://php-di.org) container using service manager configuration.\n\n**Requirements:** PHP 8.2 or higher\n\nIt can be used with [Laminas](https://getlaminas.org/) and [Mezzio](https://docs.mezzio.dev/) starting from v10.0.0\n\nThis library uses autowiring technique, cache compilation and cache definitions as defined\nin [PHP-DI](https://php-di.org).\n\n## 🛠️ Configuration\n\n[Service Manager Configuration](https://docs.laminas.dev/laminas-servicemanager/configuring-the-service-manager/)\n\nTo get a configured [PSR-11](https://www.php-fig.org/psr/psr-11/)\nPHP-DI container, do the following:\n\n```php\n\u003c?php\n\ndeclare(strict_types=1);\n\nuse Elie\\PHPDI\\Config\\Config;\nuse Elie\\PHPDI\\Config\\ContainerFactory;\n\n$factory = new ContainerFactory();\n\n$container = $factory(\n    new Config([\n        'dependencies' =\u003e [\n            'services'   =\u003e [],\n            'invokables' =\u003e [],\n            'autowires'  =\u003e [], // A new key added to support PHP-DI autowire technique\n            'factories'  =\u003e [],\n            'aliases'    =\u003e [],\n            'delegators' =\u003e [],\n        ],\n        // ... other configuration\n\n        // Enable compilation\n        Config::DI_CACHE_PATH =\u003e __DIR__, // Folder path\n\n        // Write proxies to file: cf. https://php-di.org/doc/lazy-injection.html\n        Config::DI_PROXY_PATH =\u003e __DIR__, // Folder path\n\n        // Disable autowire (enabled by default)\n        Config::USE_AUTOWIRE =\u003e false\n\n        // Enable cache\n        Config::ENABLE_CACHE_DEFINITION =\u003e false, // boolean, true if APCu is activated\n    ])\n);\n```\n\n### Configuration Keys\n\nThe `dependencies` configuration array supports the following keys:\n\n- **`services`**: Maps a service name to a specific service instance, class name, or callable.\n  - Values can be object instances, class names, or callables\n  - Used for registering pre-instantiated services or simple service definitions\n  - See [ServicesTest.php](tests/ServicesTest.php) for comprehensive examples\n\n- **`invokables`**: Maps service names to classes with no constructor dependencies.\n  - Can be an associative array (alias =\u003e class name) or indexed array (class names)\n  - When alias differs from class name, the alias is created automatically\n  - Classes must have no required constructor parameters\n  - See [InvokablesTest.php](tests/InvokablesTest.php) for comprehensive examples\n\n- **`autowires`**: Array of fully qualified class names to be autowired by PHP-DI.\n  - PHP-DI automatically resolves constructor dependencies through type-hinting\n  - Works with or without constructor parameters\n  - Create aliases separately in the `aliases` configuration if needed\n\n- **`factories`**: Maps service names to factory classes or callables.\n  - Factory classes must implement `__invoke(ContainerInterface $container)`\n  - Can reference other registered factories by name\n  - Factories must return the actual service instance (object, array, scalar, etc.), not service names\n  - Used when service instantiation requires custom or dynamic logic\n  - See [FactoriesTest.php](tests/FactoriesTest.php) for comprehensive examples\n\n- **`aliases`**: Maps alias names to service names or other aliases.\n  - Allows multiple names to resolve to the same service instance\n  - Can chain aliases (alias → alias → service)\n  - Only **`invokables`** create aliases automatically\n\n- **`delegators`**: Maps service names to arrays of delegator factory classes.\n  - Decorates or wraps services with additional functionality\n  - Delegators are applied in the order specified\n  - See [Laminas delegators documentation](https://docs.laminas.dev/laminas-servicemanager/delegators/) for details\n\n\u003e **N.B.:** All configuration except `dependencies` is merged into a `config` key within the `$container`:\n\u003e\n\u003e ```php\n\u003e $config = $container-\u003eget('config');\n\u003e ```\n\n---\n\n## 💻 CLI Usage\n\nThe CLI command `add-autowires-entry` creates the configuration file if it doesn't exist, otherwise it adds the entry\nto the autowires key.\n\nExample of adding ConsoleHelper to a config.php:\n\n```console\n./vendor/bin/add-autowires-entry config.php \"Laminas\\\\Stdlib\\\\ConsoleHelper\"\n[DONE] Changes written to config.php\n```\n\nYou can also add this as a Composer script:\n\n```json\n\"scripts\": {\n\"add-autowire\": \"add-autowires-entry config.php \\\"My\\\\Service\\\\Class\\\"\"\n}\n```\n\n---\n\n## 🧪 Development \u0026 Testing\n\n### Running Tests\n\n```bash\n# Run tests (no coverage)\ncomposer test\n\n# Run with coverage (requires Xdebug)\ncomposer test-coverage\n\n# Run coverage + serve HTML report\ncomposer cover  # Opens localhost:5001\n```\n\n### Git Hooks with GrumPHP\n\nThis project uses [GrumPHP](https://github.com/phpro/grumphp) to automatically run tests before each commit.\n\nAfter running `composer install`, GrumPHP will:\n\n- Install git hooks automatically\n- Run `composer test` before every commit\n- Block commits if tests fail\n\n**Bypass the hook** (not recommended):\n\n```bash\ngit commit --no-verify -m \"Your message\"\n```\n\n**Configure GrumPHP**: Edit [grumphp.yml](grumphp.yml) to customize tasks and behavior.\n\n---\n\n## 🐞 Troubleshooting / FAQ\n\n**Q: My service is not autowired.**\nA: Ensure it is listed in the `autowires` array and all dependencies are available.\n\n**Q: The CLI tool fails with a permissions error.**\nA: Make sure the config file directory is writable.\n\n**Q: How do I debug container errors?**\nA: Check that all dependencies are correctly defined and that your factories do not throw exceptions.\n\n---\n\n## Using with Mezzio (formerly Expressive)\n\nReplace contents of `config/container.php` with the following:\n\n```php\n\u003c?php\n\ndeclare(strict_types=1);\n\nuse Elie\\PHPDI\\Config\\Config;\nuse Elie\\PHPDI\\Config\\ContainerFactory;\n\n// Protect variables from global scope\nreturn call_user_func(function () {\n\n    $config = require __DIR__ . '/config.php';\n\n    $factory = new ContainerFactory();\n\n    // Container\n    return $factory(new Config($config));\n});\n\n```\n\n## Example of a ConfigProvider class\n\n```php\n\u003c?php\n\ndeclare(strict_types=1);\n\nclass ConfigProvider\n{\n\n    /**\n     * Returns the configuration array\n     */\n    public function __invoke(): array\n    {\n        return [\n            'dependencies' =\u003e $this-\u003egetDependencies()\n        ];\n    }\n\n    /**\n     * Returns the container dependencies\n     */\n    public function getDependencies(): array\n    {\n        return [\n            'autowires' =\u003e [\n                UserManager::class\n            ]\n        ];\n    }\n}\n```\n\nWhere UserManager depends on Mailer as follows:\n\n```php\n\u003c?php\n\ndeclare(strict_types=1);\n\nclass UserManager\n{\n    private $mailer;\n\n    public function __construct(Mailer $mailer)\n    {\n        $this-\u003emailer = $mailer;\n    }\n\n    public function register($email, $password)\n    {\n        $this-\u003emailer-\u003email($email, 'Hello and welcome!');\n    }\n}\n\nclass Mailer\n{\n    public function mail($recipient, $content)\n    {\n    }\n}\n\n```\n\n## Switching back to another container\n\nTo switch back to another container is straightforward:\n\n1. Create your factories with `__invoke` function\n2. Replace `autowires` key in ConfigProvider by `factories` key, then for each class name attach its correspondent\n   factory.\n\n## PSR 11 and Interop\\Container\\ContainerInterface\n\nV4.x supports as well Interop\\Container\\ContainerInterface\n\n## Migration guides\n\n- [Migration from 3.x to 4.0](docs/migration-4.0.md)\n- Migration from 4.x to 5.0: container-interop/container-interop was dropped in favor\n  of [PSR-11](https://packagist.org/packages/psr/container).\n\n---\n\n## 🤝 Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines on how to contribute, run tests, and submit pull requests.\n\n---\n\n## 📄 License\n\nThis project is licensed under the MIT License. See [LICENSE](LICENSE) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felie29%2Fzend-di-config","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Felie29%2Fzend-di-config","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felie29%2Fzend-di-config/lists"}