{"id":18929520,"url":"https://github.com/thecodingmachine/container-installer","last_synced_at":"2025-06-12T23:03:59.584Z","repository":{"id":25900938,"uuid":"29341565","full_name":"thecodingmachine/container-installer","owner":"thecodingmachine","description":"This package contains a PHP dependency injection container detector and aggregator. The idea is to have potentially one DI container per composer package and to aggregate all those containers into a 'root' container.","archived":false,"fork":false,"pushed_at":"2015-02-06T12:50:27.000Z","size":200,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":18,"default_branch":"1.0","last_synced_at":"2025-06-01T11:51:20.921Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/thecodingmachine.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-01-16T09:24:37.000Z","updated_at":"2023-11-10T21:10:20.000Z","dependencies_parsed_at":"2022-08-22T20:20:21.766Z","dependency_job_id":null,"html_url":"https://github.com/thecodingmachine/container-installer","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/thecodingmachine/container-installer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thecodingmachine%2Fcontainer-installer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thecodingmachine%2Fcontainer-installer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thecodingmachine%2Fcontainer-installer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thecodingmachine%2Fcontainer-installer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thecodingmachine","download_url":"https://codeload.github.com/thecodingmachine/container-installer/tar.gz/refs/heads/1.0","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thecodingmachine%2Fcontainer-installer/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259546413,"owners_count":22874560,"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":[],"created_at":"2024-11-08T11:33:22.936Z","updated_at":"2025-06-12T23:03:59.560Z","avatar_url":"https://github.com/thecodingmachine.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"About Container-Installer\n=========================\n\nThis project is a test project developed as a proof of concept while working on the [ContainerInterop](https://github.com/container-interop/container-interop/) project.\n\nThe big picture\n---------------\n\nThe ultimate goal is to allow the application developer to easily create a \"root container\", \nthat can automatically detect and add containers contained in other packages into a global \ncomposite container that can be used by the application.\n\nCompared to the classical way of thinking about a web application, this is a paradigm shift.\n\n**In a \"classical\" application**, packages added to the application may add new instances to the main and only DI container.\nThis is what SF2 bundles, ZF2 modules or Mouf2 packages are doing.\n\n**Using this approach**, each package provides its own DI container that contains instances. DI containers are added\nto a global container that is queried.\n\nAbout this package\n------------------\n\nThe goal of this package is simply to provide an easy way for application developers to detect DI containers that might\nbe declared in Composer packages they use.\n\nThis project adds an additional step to Composer \"install\", just after the Composer dumps the autoloader.\nThe Container-Installer will scan all packages *composer.json* files and will look for a section like:\n\n```json\n{\n\t\"extra\": {\n\t\t\"container-interop\": {\n\t\t\t\"container-factory\": \"My\\\\ContainerFactory::getContainer\"\n\t\t}\n\t}\n}\n```\n\nThis section actually declares container factories that can be bundled in the package.\n\nThe \"container-factory\" parameter must point to a function or a static method that returns the container.\n\nHere is a sample implementation:\n\n```php\nclass ContainerFactory {\n\tprivate static $container;\n\n\t/**\n\t * This method is returning a configured container\n\t *\n\t * @param ContainerInterface $rootContainer\n\t * @return ContainerInterface\n\t */\n\tpublic static function getContainer(ContainerInterface $rootContainer) {\n\t\tif (!$this-\u003econtainer) {\n\t\t\t// Delegate dependencies fetching to the root container.\n\t\t\t$this-\u003econtainer = new Picotainer([\n\t\t\t\t\"hello\" =\u003e function(ContainerInterface $container) {\n\t\t\t\t\treturn array('hello' =\u003e $container-\u003eget('world'));\n\t\t\t\t}\n\t\t\t], $rootContainer);\n\t\t}\n\t\treturn $this-\u003econtainer;\n\t}\n}\n```\n\nA quick note about this code: we are providing a [Picotainer container](http://mouf-php.com/packages/mouf/picotainer/README.md).\nPicotainer is a minimalistic container fully compativle with the [ContainerInterop](https://github.com/container-interop/container-interop/) project.\n\n**Important**: the factory takes one compulsory parameter: the `$rootContainer`. If some entries in your container are containing\n*external dependencies* (dependencies that are not part of the container), then your container needs to be able\nto delegate dependencies fetching to the $rootContainer. For instance, `PimpleInterop` can delegate dependencies fetching if\nyou pass another container as the first argument of the constructor.\n\nNote: your package does not have to require the `mouf/container-installer` package. This is sweet because if \nother container aggregators follow the same convention (referencing factory code in `composer.json` extra section),\nthere can easily be many different implementations of a root-container (maybe one per framework). \n\n\n\nHow to use a root container in your project?\n============================================\n\nThis package will simply create a `containers.php` file at the root of your project.\nThis `containers.php` file will contain a list of containers in this form:\n\n```php\n\u003c?php\nreturn [\n    [\n        'name' =\u003e '__root___0',\n        'description' =\u003e 'Container number 0 for package __root__',\n        'factory' =\u003e My\\ContainerFactory::getContainer,\n        'enable' =\u003e true\n    ],\n];\n```\n\nPlease note that the developer can enable or disable packages manually, using the 'enable' attribute.\n\nFrom there it is up to the application developer to use that file.\n\nUsing Acclimate's CompositeContainer, a usage might look like this:\n\n```php\nuse Acclimate\\Container\\CompositeContainer;\n\n// Let's create a composite container\n$rootContainer = new CompositeContainer();\n\n// Let's get the containers list\n$container_descriptors = require 'containers.php';\n\n// Let's add containers to the root container.\nforeach ($container_descriptors as $descriptor) {\n    if (descriptor['enable']) {\n        $container = $descriptor['factory']($rootContainer);\n        $rootContainer-\u003eaddContainer($container);\n    }\n}\n\n$myEntry = $rootContainer-\u003eget('myEntry');\n```\n\nAllowed syntax\n--------------\nThose syntaxes are all valid to declare container factories in **composer.json**:\n\nSimply declaring a container-factory **via callback**:\n\n```json\n{\n\t\"extra\": {\n\t\t\"container-interop\": {\n\t\t\t\"container-factory\": \"My\\\\ContainerFactory::getContainer\"\n\t\t}\n\t}\n}\n```\n\nDeclaring an **array of container-factories via callback**:\n\n```json\n{\n\t\"extra\": {\n\t\t\"container-interop\": {\n\t\t\t\"container-factory\": [\n\t\t\t\t\"My\\\\ContainerFactory1::getContainer\",\n\t\t\t\t\"My\\\\ContainerFactory2::getContainer\",\n\t\t\t\t\"My\\\\ContainerFactory3::getContainer\"\n\t\t\t]\n\t\t}\n\t}\n}\n```\n\nDeclaring a container-factory **descriptor** (it contains additionnal data about the factory):\n\n```json\n{\n\t\"extra\": {\n\t\t\"container-interop\": {\n\t\t\t\"container-factory\": {\n\t\t\t\t\"name\": \"a unique name for the factory\",\n\t\t\t\t\"description\": \"a description of what the factory does\",\n\t\t\t\t\"factory\": \"My\\\\ContainerFactory::getContainer\"\n\t\t\t}\n\t\t}\n\t}\n}\n```\n\nNote: all parameters of a descriptor are optionnal, except for the \"factory\" part.\n\nDeclaring an **array of container-factory descriptors**:\n\n```json\n{\n\t\"extra\": {\n\t\t\"container-interop\": {\n\t\t\t\"container-factory\": \n\t\t\t[{\n\t\t\t\t\"name\": \"a unique name for the factory\",\n\t\t\t\t\"description\": \"a description of what the factory does\",\n\t\t\t\t\"factory\": \"My\\\\ContainerFactory::getContainer\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"name\": \"a unique name for another factory\",\n\t\t\t\t\"description\": \"a description of what the factory does\",\n\t\t\t\t\"factory\": \"My\\\\ContainerFactory2::getContainer\"\n\t\t\t}]\n\t\t}\n\t}\n}\n```\n\n\nBenefits\n--------\nEach package provides its container. The package is not dependent on the DI container used in the application.\nThis way, we can provide packages that are framework agnostic.\n\nDownsides\n---------\nThe classical implementation of the composite controller might imply a performance hit. We will need to think of a way to \nimprove the performance of the composite container (maybe by doing entries maps, mapping entries to their associated container...) \n\nAbout other projects\n--------------------\nThis is not the only project working on the \"one container per package\" paradigm. The [FrameworkInterop project](https://github.com/mnapoli/framework-interop)\nby @mnapoli is also taking the same route (although its scope is larger).\n\nAbout performance\n=================\n\nThe current implementation of RootContainer is relying on the Acclimate's CompositeContainer. It is \na proof-of-concept and no effort has been done performance-wise.\nThe more container you have in your application, the lower the performance should be (linearly).\n\nIt does not mean however that performance cannot be improved. There are many possible strategies to improve performance,\nlike building a map of all entries associated to their respective container. This is going further than\nthe current scope of this project.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthecodingmachine%2Fcontainer-installer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthecodingmachine%2Fcontainer-installer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthecodingmachine%2Fcontainer-installer/lists"}