Skip to content
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

improve discovery documentation #305

Merged
merged 1 commit into from
Apr 28, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 65 additions & 21 deletions discovery.rst
Original file line number Diff line number Diff line change
@@ -1,29 +1,26 @@
Discovery
=========

The discovery service allows to find installed resources and install missing ones.
The discovery service allows to find installed resources and auto-install missing ones.

Currently available discovery services:

- HTTP Client Discovery
- HTTP Async Client Discovery
- PSR-17 Factory Discovery
- PSR-18 HTTP Client Discovery
- PSR-7 Message Factory Discovery (deprecated in favor of PSR-17)
- PSR-7 URI Factory Discovery (deprecated in favor of PSR-17)
- PSR-7 Stream Factory Discovery (deprecated in favor of PSR-17)
- HTTP Async Client Discovery
- HTTP Client Discovery (deprecated in favor of PSR-18)
- Mock Client Discovery (not enabled by default)
- PSR-7 Message Factory Discovery (deprecated)
- PSR-7 URI Factory Discovery (deprecated)
- PSR-7 Stream Factory Discovery (deprecated)

The principle is always the same: you call the static ``find`` method on the discovery service if no explicit
implementation was specified. The discovery service will try to locate a suitable implementation.
If no implementation is found, an ``Http\Discovery\Exception\NotFoundException`` is thrown.

.. versionadded:: 0.9
The exception ``Http\Discovery\NotFoundException`` has been moved to ``Http\Discovery\Exception\NotFoundException``.
The principle is always the same: you call the static ``find`` method on the discovery service. The
discovery service will try to locate a suitable implementation. If no implementation is found, an
``Http\Discovery\Exception\NotFoundException`` is thrown.

Discovery is simply a convenience wrapper to statically access clients and factories for when
Dependency Injection is not an option. Discovery is useful in libraries that want to offer
zero-configuration services relying on the virtual packages.
Dependency Injection is not an option. Discovery is particularly useful in libraries that want to
offer zero-configuration services relying on the virtual packages.

Auto-installation
-----------------
Expand All @@ -35,10 +32,10 @@ Discovery embeds a composer plugin that can auto-install missing implementations
when an application does not specify any specific implementation.

If a library requires both ``php-http/discovery`` and one of the supported virtual packages
(see :doc:`library-developers`), but no implementation for the virtual package is already
(see :doc:`httplug/library-developers`), but no implementation for the virtual package is already
installed, the plugin will auto-install the best matching known implementation.

For example, if one is using ``react/event-loop``, the plugin will select ``php-http/react-adapter``
For example, if the project requires ``react/event-loop``, the plugin will select ``php-http/react-adapter``
to meet a missing dependency on ``php-http/client-implementation``.

The following abstractions are currently supported:
Expand All @@ -49,18 +46,65 @@ The following abstractions are currently supported:
- ``psr/http-factory-implementation``
- ``psr/http-message-implementation``

.. note::
Auto-installation is only done for libraries that directly require ``php-http/discovery`` to
avoid unexpected dependency installation.

If you do not want auto-installation to happen, you can chose to not enable the composer
plugin of the discovery component:

``composer config allow-plugins.php-http/discovery false``


.. _discovery-strategies:

Strategies
----------

The package supports multiple discovery strategies and comes with two out-of-the-box:
The package uses strategies to select an implementation.

The default strategy contains a list of preferences that looks for well-known implementations:
Symfony, Guzzle, Diactoros and Slim Framework.

Once a strategy provided a candidate, the result is cached in memory and reused for further
discovery calls in the same process.

To register a custom strategy, implement the ``Http\Discovery\Strategy\DiscoveryStrategy``
interface and register your strategy with the ``prependStrategy``, ``appendStrategy`` or
``setStrategies`` method of the corresponding discovery type.

Implementation Pinning
----------------------

- A built-in strategy supporting the HTTPlug adapters, clients and factories (including Symfony, Guzzle, Diactoros and Slim Framework)
.. versionadded:: 1.17
Pinning the preferred implementation is available since v1.17.

Strategies provide candidates of a type which gets evaluated by the discovery service.
When it finds the best candidate, it caches it and stops looking in further strategies.
In case there are several implementations available, the application can pin which implementation
to prefer. You can specify the implementation for one of the standards in the ``extra.discovery``
section of the application ``composer.json`` file:

.. code-block:: json

"extra": {
"discovery": {
"psr/http-factory-implementation": "GuzzleHttp\\Psr7\\HttpFactory"
}
}

You can also pin single interfaces, e.g. for the PSR-17 factories:

.. code-block:: json

"extra": {
"discovery": {
"Psr\\Http\\Message\\RequestFactoryInterface": "Slim\\Psr7\\Factory\\RequestFactory"
}
}

.. note::
Implementation pinning only works if the composer plugin of discovery is allowed. If you
disabled the plugin, you need to configure your own discovery if you need a specific
implementation selection.

Installation
------------
Expand Down Expand Up @@ -351,7 +395,7 @@ to the Discovery. Let's take a look::
// Test...
}
}

In the example of a test class above, we have our ``MyCustomService`` which
relies on an HTTP Client implementation. We do not need to test that the actual
request our custom service makes is successful in this test class, so it makes
Expand Down