-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Working example of auto-discovery through composer plugin #46
Comments
Hey Pierre! First, I'm really glad you open the topic of auto-discovery. Your idea looks a bit like what Flex is doing in Symfony 4 (copying configuration files in the user workspace where the user can freely change those). I have been playing a bit myself with autodiscovery and went a completely different way. Regarding your proposal, I like it a lot too. There is only one issue I see. If you require service providers using a glob, you are not controlling the order of loading of your service providers. Yet, order sometimes matter (especially when a service provider is overriding the services of another service provider). You would need to find a way to control the order of loading of the service providers. If we look at the broad picture, a lot is done regarding auto-discovery nowaday. Symfony 4 has Flex (which really is an autodiscovery of Symfony bundles + some additional tools). Laravel 5.5 introduced auto-discovery too. Zend Expressive has it. I would really be thrilled if we could find a common way for packages to expose that they are providing service providers. It could be done using a "providers.php" file like you did. It could be a JSON file. Or we could put it in the "extra" section of the composer.json file... I don't think we need to go much further. On top of that, any framework could provide the autodiscovery mechanism that best fits its needs. What do you think? |
Hi David thanks for your answer, Puli seemed a bit ambitious to me (if I remember well it attempts to manage both type of assets + assets). Also the project seems dead. Concerning your project, I saw it a while ago. If I understand well the published assets ultimately look like arrays provided by service providers?
First just to be clear this approach does not require to use a glob pattern: it is just focusing on how to properly import providers.php files, the collecting logic is left to the project/framework.
About the order the service providers are imported, my opinion is well designed service providers of packages should not depend on the order they are loaded. I can't figure out a case where a package should have priority over another ? Could you show me an example ? If you are thinking about multiple implementations of the same interface, we agree we should have a way to handle that. On the other side, yes the project service providers should be loaded after auto-discovered ones if they override some of their entries. That's why collecting logic is left to the project/framework. You can collect all the imported packages service providers then load the project ones in the order needed.
Going with php files is nice because once imported you can edit them like any other php files. I remember conversations here about commenting out a service provider to track bugs, or even use service providers with constructor parameters, well this is simple and easy with php files and totally impossible with json.
Yes it is also possible to let frameworks have their own mechanism for importing providers.php files. I fact my first approach was a regular composer plugin any project could use to import providers.php files + the destination folder path in the extra keys. Then I went with a composer installer plugin because I felt it was more elegant to just have to configure the destination path. But you're right, frameworks could choose to adopt another naming convention for imported files or whatever. I don't really care which way to go. I just think there should be a generic composer plugin for non-framework users, maintained by multiple people. I think there is more and more developers embracing a non-framework philosophy (including myself) and there should be a standard solution for them. Also I think it would be cool to have one vendor namespace with generic service providers packages for many popular php packages. A bit like Oscar's middleware repo. |
Since this relates to the topic of service provider discovery, I am closing this issue - the service provider PSR itself does not require service discovery. I understand that service discovery is something that several members of this working group desired, but a service discovery standard (which might depend on this PSR) could be defined independently. I am closing this issue in order to reduce scope. If you think further discussion is require, please open a thread in Discussions. |
For my personal project I came up with an approach using a composer installer plugin for service providers auto-discovery.
I'd like to show you a working example and I'm very eager to hear about your remarks and criticisms before going further with it.
Approach overview
Have a provider installer plugin for
service-provider
package types. Those packages contain aproviders.php
file at root, returning an array of service providers they expose:Then a project can define a destination folder path under an
extra
key of itscomposer.json
file.service-provider
packages are installed like any other packages.service-provider
package'sproviders.php
files are imported in the defined destination folder on install, following a naming scheme ensuring no collision.providers.php
files are imported only on theservice-provider
package first install and are removed when uninstalled.It is up to the project developer to collect imported service provider, for example by using a simple
glob
pattern.Example
Lets install the example project:
git clone git@github.com:pmall/providers-example.git
In the
composer.json
file you can see a few requiredservice-provider
packages:Two from my personal project for the sake of example:
ellipse/providers-http
ellipse/providers-session
Another one under the
services
vendor namespace for a more generic service:services/dbal
The
extra['providers']['path']
key of thecomposer.json
file is set to the projectconfig
directory, which is empty when creating the project.After running
composer install
you can see the packagesproviders.php
files has been imported in theconfig
directory:They are grouped by vendor namespace so paths can't collide. Plus
'providers-'
prefixes and'-providers'
suffixes are removed from the package names. It allows a vendor namespace to both contain a package named{vendor}/{name}
for the actual package and aservice-provider
package named{vendor}/providers-{name}
for its service providers.You probably noticed
ellipse/dispatcher.php
file has been imported whereasellipse/providers-dispatcher
it is not a dependency of the rootcomposer.json
file. It has been imported because it is a dependency ofellipse/providers-http
package.Also (interesting to mention even if what the imported service provider does is irrelevant for this presentation) those service provider constructors take an array of factory extensions, they are exposing and documenting values the developer would configure.
Finally the
container.php
file at the root of the project directory collect them and build a working Psr-11 container with a simpleglob
pattern. You can require it in a php cli and callget()
with a provided id.Detailed mechanism
composer.json
file.composer.lock
file is present or the package name is not present in thecomposer.lock
file. It ensures an importedproviders.php
file which was manually renamed/deleted during development is not imported again when the application is deployed.providers.php
file is present at theservice-providers
package root.{destination path}/{vendor}/{name}.php
file is not already present in the project.{destination path}/{vendor}/{name}.php
+ remove'providers-'
prefixes and'-providers'
suffixes from the package names.{destination path}/{vendor}/{name}.php
file is removed if present when the package is uninstaled.Why I like this approach
providers.php
files to be imported in their project by defining a destination folder path. Yetservice-provider
packages are still useful without auto-dicovery enabled because service providers can still be consumed manually.providers.php
file in the destination folder path.providers.php
files, like comment service providers out, change their order or completely delete some. Service providers can even come with constructor parameters with suitable default values.providers.php
files is versioned under the project VCS.glob
patterns should be enough in most cases but more complex logic can be performed depending on the project.service-provider
packages can require another one.service-provider
packages can be set as dev requirements in which case the importedproviders.php
file path would reflect this. Not sure about what convention would be the best but it is achievable. Developers could then have a collecting logic importing dev service providers only in dev environment. For example, try to removeservices/dbal
from the example above and install it again as dev requirement.service-provider
packages and theirproviders.php
files are grouped together under the same vendor namespace.services
) can be maintained by the community and containservice-providers
packages for widely used php package.So what's your through about this ?
The text was updated successfully, but these errors were encountered: