Hey Rasmus,

Thanks for the feedback!

Version 0.4 of the ongoing original proposal looks pretty solid to me by 
> now.
>
> The alternative proposal involves strings with PHP-like type-hints that 
> need to be parsed and checked at run-time. Seems a bit brittle, more 
> complex than I'd like, and doesn't really seem necessary.
>

Both proposals do not have the same maturity level. Maybe you should not 
focus too much on the implementation details of the Symfony proposal but on 
the general idea.
For instance, we could propose to replace the "PHP-like type-hints"  
strings by proper classes. Like:

return [
    "my_service" => new Type(MyService::class, $isOptional)
];

Or for the "ServiceSubscriberInterface" (the interface that publishes the 
list of required dependencies of a given service provider), it could be 
interesting to replace the type by a "ValidatorInterface".

Something like:

interface ValidatorInterface {
    public function validateDependency($entry);
}

class MyServiceProvider implements ..., ServiceSubscriberInterface
{
    public function getSubscribedServices()

    {
        return [
            'debug' => new CanBeNull(new(MustBeBool()),
            'twig_extensions' => new CanBeNull(new 
MustBeArrayOf(TwigExtentionInterface::class)),

        ];
    }

}

This could allow very interesting possibilities (we could do more than only 
checking the type of the dependencies).

Also, as Nicoas noted, both proposals are not mutually exclusive.

@Nicolas, what do you think?

The only thing missing for me, from the first proposal, is the ability for 
> providers to depend on providers, somehow. These past few years, I've been 
> part of building a big system at work - and we have so many providers now, 
> with so many dependencies, one of the most common problems is "hey, this 
> provider gave me some component that needs a dependency X, which other 
> provider is supposed to provide me with X?"
>
> The second proposal seems to address the need to check for missing 
> dependencies up front - but what we'd really like, is a declarative means 
> of saying "this provider depends on that provider", since, almost 100% of 
> the time, in an environment where literally everything is bootstrapped by 
> providers, the answer to "X is missing" is going to be "Add the provider of 
> X", rather than "bootstrap X yourself".
>
> Another common problem is the order in which providers get bootstrapped - 
> if one provider needs to override a registration of another, the order 
> matters.
>
> One idea to solve both of these issues, is to introduce a provider ID of 
> some sort. The provider's own class name would be an obvious candidate, 
> though the Composer package name might be a safer choice, since ::class 
> might not provide static analysis when a provider isn't installed.
>
> So basically two methods:
>
>     function getProviderID(): string;
>     function listRequiredProviders(): string[]
>
> The container can now get the full list of providers, use a topological 
> sort to figure out the correct order in which to bootstrap these providers, 
> check for missing providers, etc.
>
> This enables "abstract" providers as well - for example, a provider might 
> depend on "psr/cache", which might be the Provider ID of numerous packages 
> with an agreed-upon ID and bootstrapping scope. This would build on the 
> idea of abstract Composer packages and make that concept more useful - 
> since merely installing a package (with correct version and dependcies etc) 
> is all that Composer can guarantee, this lets us guarantee that it's 
> provider has also been bootstrapped.
>
> I think, at this point, that's the only missing feature for me.
>

I completely agree that we need to discuss the way we handle the 
dependencies between service providers. We never really had a discussion on 
this topic, and I'm facing the same issue as you are.

I'm not completely sold to the idea of adding a notion of "providerID" as 
you present it. It's not a notion that exists in any existing framework. 
Also, making it "explicit" adds another layer of complexity to the 
solution. I'd rather have a service-provider declares that it requires a 
"Psr\Log\LoggerInterface" entry rather than having a service-provider 
declares that it requires a "psr3-service-provider" service provider (at 
the class level)

That being said, I agree that we could use the notion of "virtual packages" 
already available in Composer to carry that meaning (at the package level)

Let's take an example with 2 service providers.

Service provider "myService" provides a "MyService" entry that requires a 
"Psr\Log\LoggerInterface" entry to be available in the container.
Service provider "monolog" provides a "Psr\Log\LoggerInterface" entry.

In the composer.json of the package containing the MonologServiceProvider, 
we could add:

{
    "provide": { "psr-3-service-provider": "1.0.0" }
}

In the composer.json of the package containing the "myService" service 
provider, we could add:

{
    "require": { "psr-3-service-provider": "^1" }
}

That way, it would be impossible to install the service provider of 
"myService" without having a package that provides a service provider with 
a PSR-3 logger in it (quite similar to your "providerID".

If we can find some way to automatically register service-providers in our 
container (like Symfony Flex is doing with bundles), we are pretty much ok. 
Composer can guarantee we have the necessary classes in our workspace and 
the "autodiscovery" of service providers (we need to figure that out) takes 
care of registering the service providers in the container. Problem solved.

++
David.

-- 
You received this message because you are subscribed to the Google Groups "PHP 
Framework Interoperability Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to php-fig+unsubscr...@googlegroups.com.
To post to this group, send email to php-fig@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/php-fig/4f980c60-a577-43c2-9b49-27b0ea9d0c2c%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to