Code Monkey home page Code Monkey logo

provider-interop's Introduction

Service Provider Integration

This project provides a means of integrating PSR-11 containers at the provider-level.

STATUS: this is completely experimental and exploratory work - everything is subject to change!

Comparison with container-interop/service-provider

The approach proposed here is radically different from standardizing the service-providers themselves, which is a much harder problem.

What this project defines is a simpler, more high-level exchange of entries, accomplishing much the same thing as standardizing the providers themselves, while removing the decision for module-authors to write "standard" vs "proprietary" service-providers, allowing full use of all of the features of a selected container-implementation, and avoids compromising the internal integrity of individual containers.

The ServiceProviderInterface of container-interop/service-provider includes a set of rules about how the published entries must be treated by the receiving container. By contrast, the ServiceProviderInterface defined by this package uses a simpler and more formal contract, in the form of a second interface, which defines a "service registry" facet of a receiving container (or container-factory, builder, adapter, etc.)

Unlike container-interop/service-provider, where individual package vendors implement the ServiceProviderInterface many times over, the ServiceProviderInterface defined by this project is intended to be implemented once, by the vendor of the container package:

  • Implementing the ServiceProviderInterface enables the container to act as a service-provider, e.g. makes it capable of providing a container instance and exporting a list of entry identifiers.

  • Implementing the ServiceRegistryInterface enables the container to act as a service-registry, e.g. makes it capable of importing entries defined by an external service-provider.

In other words, the service-provider and service-registry facets provide a synchronous contract, enabling container (or factory/builder, adapter, etc.) implementations to act as either providers or importers of a set of container entries from a container instance.

As noted here, these interfaces may afford better separation of concerns, and may enable more patterns and concepts to be implemented, such as the notion of public vs private entries, and more flexibility in scenarios involving multiple containers.

Compared with the first attempt (0.1) to define this concept, this revision places control with the receiving container, as does the original service-provider proposal - but (like the first revision) attempts to reformulate the problem as finding a means of enabling interoperability between containers, as opposed to standardizing the way containers get configured.

Usage

To implement a self-contained "module", you will need to select a PSR-11 container-implementation that is capable of acting as a service-provider, e.g. implements ServiceProviderInterface to export it's entry identifiers, which may then be imported into a service-registry, e.g. another container, factory, builder or adapter, etc.

In the following example, assume that YourProvider implements ServiceProviderInterface to expose a ContainerInterface facet (or adapter) and a matching list of provided entry identifiers. The container itself is an implementation detail of your provider, which could be an adapter, an extended PSR-11 container, or any other structure capable of generating a container and list of entries.

Also, assume that $my_container is an instance of a container that is capable of acting as a service-registry, e.g. implements ServiceRegistryInterface to import entries from your configured instance of YourContainer.

In the following example, I am importing container entries provided by a container that your provider internally creates and configures:

// I create an instance of your module's provider:

$your_provider = new YourProvider();

// Your provider exposes a PSR-11 container and list of entry identifiers:

assert($your_provider instanceof ServiceProviderInterface);

// My container can act as a service-registry:

assert($my_container instanceof ServiceRegistryInteface);

// I can now import the entries defined by your provider into my container:

$my_container->registerProvider($your_provider);

Note that a service-provider can be anything - it doesn't have to be a full container implementation, it only has to expose entries in a PSR-11 format. In very simple scenarios, where your package does not benefit from using a container to bootstrap itself internally, you can implement ServiceProviderInterface directly.

Implementation

To implement the ServiceProviderInterface as a facet of a container, the container-implementation must provide a list of the published entry identifiers, for example by iterating over it's internal private map of entries, in some proprietary format:

class MyContainer implements ContainerInterface, ServiceProviderInterface
{
    /**
     * @var callable[] map where entry identifier maps to callable factory function
     */
    private $this->factory_functions = [];
    
    public function listIdentifiers()
    {
        return array_keys($this->factory_functions);
    }
    
    public function getContainer()
    {
        return $this;
    }
    
    // ...
}

Note that this is just an example - in a container-implementation with an immutable container and a mutable container-factory/builder, likely the factory/builder would act as the service-provider, such that the creation of the actual container can be deferred until an entry from it is first needed.

The ServiceRegistryInterface may be implemented as a facet of a mutable container, or as a facet of a container factory/builder, etc. and provides a means of importing entries into the internal service-registry of a container-implementation, wherever that may be.

For example:

class MyContainer implements ContainerInterface, ServiceRegistryInterface
{
    /**
     * @var callable[] map where entry identifier maps to callable factory function
     */
    private $this->factory_functions = [];
    
    public function registerProvider(ServiceProviderInterface $provider)
    {
        foreach ($provider->listIdentifiers() as $id) {
            $this->factory_functions[$id] = function () use ($id, $provider) {
                return $provider->getContainer()->get($id);
            };
        }
    }
    
    // ...
}

As you can see from this example, the first call to getContainer() is deferred until an entry is required from it for the first time - this fact allows for the implementation of caching (and other optimization) strategies, internally, in container/factory/adapter-implementations.

provider-interop's People

Contributors

mindplay-dk avatar

Watchers

 avatar  avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.