Skip to content

Refactor #39

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

Merged
merged 7 commits into from
Nov 24, 2015
Merged
Show file tree
Hide file tree
Changes from 2 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
35 changes: 24 additions & 11 deletions docs/discovery.md → docs/components/discovery.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
# Discovery

The discovery service is a set of static classes which allows to find and use installed resources. This is useful in libraries that want to offer zero-configuration services and rely only on the virtual packages, e.g. `php-http/client-implementation` or `psr/http-message-implementation`.

The discovery service is a set of static classes which allows to find and use installed resources.
This is useful in libraries that want to offer zero-configuration services and rely only on the virtual packages.

Currently available discovery services:

- HTTP Client Discovery
- PSR-7 Message Factory Discovery
- PSR-7 URI Factory Discovery
- PSR-7 Stream Factory Discovery

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\NotFoundException` is thrown.

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\NotFoundException` is thrown.

## Installation

```
$ composer require php-http/discovery
```


## HTTP Client Discovery

This type of discovery finds an HTTP Client implementation.
Expand All @@ -33,7 +38,7 @@ class MyClass
protected $httpClient;

/**
* @param HttpClient|null $httpClient Client to do HTTP requests, if not set, autodiscovery will be used to find a HTTP client.
* @param HttpClient|null $httpClient
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why remove the phpdoc explanation?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if it's an addition. The example code is pretty clean I think. I can add it back if you think it adds any value.

Copy link
Contributor

@dbu dbu Nov 24, 2015 via email

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*/
public function __construct(HttpClient $httpClient = null)
{
Expand All @@ -42,6 +47,7 @@ class MyClass
}
```


## HTTP Async Client Discovery

This type of discovery finds a HTTP Async Client implementation.
Expand All @@ -58,7 +64,7 @@ class MyClass
protected $httpAsyncClient;

/**
* @param HttpAsyncClient|null $httpAsyncClient Client to do HTTP requests, if not set, autodiscovery will be used to find an asynchronous client.
* @param HttpAsyncClient|null $httpAsyncClient
*/
public function __construct(HttpAsyncClient $httpAsyncClient = null)
{
Expand All @@ -67,9 +73,11 @@ class MyClass
}
```


## PSR-7 Message Factory Discovery

This type of discovery finds a [message factory](message-factory.md) for a [PSR-7](http://www.php-fig.org/psr/psr-7/) Message implementation.
This type of discovery finds a [message factory](message-factory.md)
for a [PSR-7](http://www.php-fig.org/psr/psr-7/) Message implementation.

``` php
use Http\Message\MessageFactory;
Expand All @@ -95,7 +103,7 @@ class MyClass

## PSR-7 URI Factory Discovery

This type of discovery finds a uri factory for a [PSR-7](http://www.php-fig.org/psr/psr-7/) URI implementation.
This type of discovery finds a URI factory for a [PSR-7](http://www.php-fig.org/psr/psr-7/) URI implementation.

``` php
use Http\Message\UriFactory;
Expand All @@ -121,14 +129,17 @@ class MyClass

## Integrating your own implementation with the discovery mechanism

The `php-http/discovery` has built-in support for some implementations. To use a different implementation or override the default when several implementations are available in your codebase, you can register a class explicitly with the corresponding discovery service. For example:
The `php-http/discovery` has built-in support for some implementations.
To use a different implementation or override the default when several implementations are available in your codebase,
you can register a class explicitly with the corresponding discovery service. For example:

``` php
HttpClientDiscovery::register('Acme\MyClient', true);
```

- `class`: The class that is instantiated. This class MUST NOT require any constructor arguments.
- `condition`: The condition that is evaluated to boolean to decide whether the class can be instantiated. The following types are allowed:
- `condition`: The condition that is evaluated to boolean to decide whether the class can be instantiated.
The following types are allowed:
- string: Checked for class existence
- callable: Called and evaluated to boolean
- boolean: Can be true or false
Expand All @@ -141,8 +152,10 @@ Classes registered manually are put on top of the list.

### Writing your own discovery

Each discovery service is based on the `ClassDiscovery` and has to specify a `cache` property and a `class` property to specify classes for the corresponding service.
Since they are static, this properties need to be redeclared in each discovery class. If `ClassDiscovery` would declare them, they would be shared between the discovery classes which would make no sense.
Each discovery service is based on the `ClassDiscovery` and has to specify a `cache` property and a `class` property
to specify classes for the corresponding service. Since they are static, this properties need to be redeclared
in each discovery class. If `ClassDiscovery` would declare them,
they would be shared between the discovery classes which would make no sense.

Here is an example discovery:

Expand Down
44 changes: 44 additions & 0 deletions docs/components/message-factory.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Message Factory

**Factory interfaces for PSR-7 HTTP Message.**


## Rationale

While it should be possible to use every PSR-7 aware HTTP client with any RequestInterface implementation,
creating the request objects will still tie an application to a specific implementation.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/an application/the code/ ?

we have to work hard on consistent wording: application is the thing the end user writes. the largest issue right here however is third party libraries.

In the case of reusable libraries, an application could end up installing several request implementations.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If each reusable library is tied to a specific message implementation, an application could en up installing several message implementations.

The factories abstract away from this.

The FIG was pretty straightforward by NOT putting any construction logic into PSR-7.
The `MessageFactory` aims to provide an easy way to construct messages.


## Usage

This package provides interfaces for PSR-7 factories including:

- `MessageFactory`
- `ServerRequestFactory` - WIP (PRs welcome)
- `StreamFactory`
- `UploadedFileFactory` - WIP (PRs welcome)
- `UriFactory`


A [virtual package](/httplug/virtual-package) ([php-http/message-factory-implementation](https://packagist.org/providers/php-http/message-factory-implementation))
MAY be introduced which MUST be versioned together with this package.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how do you mean may? does it exist or not? if it does not exist we should not confuse the reader.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At the time I wrote this, I didn't have an exact idea whether we should have a virtual package or not. Ideally message factories should come together with message implementations, so I would say we don't need a virtual package here. Also, we have our factories in the discovery layer.

Copy link
Contributor

@dbu dbu Nov 24, 2015 via email

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


The adapter repositories provide wrapper classes for those factories to
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

link to the adapters here? and why wrapper? i would say they provide these factories. (whether they do it by means of forwarding to other factories or by using new is implementation detail).

what about clients, do they also provide factories? does every adapter provide factories? or are we creating confusion here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly, I have no idea what this is. 😛 Probably it was about somehow wrapping specific implementations, but makes no sense.

implement the `Http\Message\MessageFactory` interface.


### General usage
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i don't get what this section is trying to explain. lets remove it (or add a concrete example)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tries to explain how to generally implement a Factory, but probably makes no sense.

Copy link
Contributor

@dbu dbu Nov 24, 2015 via email

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, removed it (which is not visible from email).


``` php
use Http\Message\SomeFactory;

class MyFactory implements SomeFactory
{

}
```
69 changes: 0 additions & 69 deletions docs/httplug.md

This file was deleted.

113 changes: 113 additions & 0 deletions docs/httplug/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# HTTPlug HTTP client abstraction

HTTPlug is an abstraction for HTTP clients. There are two main use cases:

1. Usage in a project/application
2. Usage in a reusable package

In both cases, the `Http\Client\HttpClient` provides a `sendRequest` method to send a PSR-7 `RequestInterface`
and returns a PSR-7 `ResponseInterface`or throws an exception that implements `Http\Client\Exception`.

There is also the `Http\Client\HttpAsyncClient` which provides the `sendAsyncRequest` method to send
a request asynchronously and returns a `Http\Client\Promise`.

It can be used later to retrieve a PSR-7 `ResponseInterface` or an exception that implements `Http\Client\Exception`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/It can be used later to retrieve/The promise allows to specify handlers for/



<p class="text-warning">
Contract for the `Http\Client\Promise` is temporary until
[PSR is released](https://groups.google.com/forum/?fromgroups#!topic/php-fig/wzQWpLvNSjs).
Once it is out, we will use this PSR in the main client and deprecate the old contract.
</p>


See the [tutorial](tutorial.md) for a concrete example.


## HTTPlug implementations

HTTPlug implementations typically are either HTTP clients of their own, or adapters wrapping existing clients
like Guzzle 6. In the latter case, they will depend on the required client implementation,
so you only need to require the adapter and not the actual client.


There are two kind of implementations:

- [php-http/client-implementation](https://packagist.org/providers/php-http/client-implementation):
the synchronous implementation that waits for the response / error before returning from the `sendRequest` method.
- [php-http/async-client-implementation](https://packagist.org/providers/php-http/async-client-implementation):
the asynchronous implementation that immediately returns a `Http\Client\Promise`,
allowing to send several requests in parallel and handling responses later.

Check links above for the full list of implementations.

<p class="text-warning">
Note: Until HTTPlug 1.0 becomes stable, we will focus on the Guzzle6 adapter.
</p>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i would say lets remove this box



## Usage in a project
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Usage in an application ?


When writing an application, you need to require a concrete
[implementation](https://packagist.org/providers/php-http/client-implementation).

See [virtual package](virtual-package.md) for more information on the topic of working with HTTPlug implementations.


## Installation in a reusable package

In many cases, packages are designed to be reused from the very beginning.
For example, API clients are usually used in other packages/applications, not on their own.

In these cases, they should **not rely on a concrete implementation** (like Guzzle 6),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/In these cases, they/Reusable packages/

but only require any implementation of HTTPlug. HTTPlug uses the concept of virtual packages.
Instead of depending on only the interfaces, which would be missing an implementation,
or depending on one concrete implementation, you should depend on the virtual package `php-http/client-implementation`
or `php-http/async-client-implementation`. There is no package with that name,
but all clients and adapters implementing HTTPlug declare that they provide one of this virtual package or both.

You need to edit the `composer.json` of your package to add the virtual package.
For development (installing the package standalone, running tests),
add a concrete implementation in the `require-dev` section to make the project installable:

``` json
...
"require": {
"php-http/client-implementation": "^1.0"
},
"require-dev": {
"php-http/guzzle6-adapter": "^1.0"
},
...
```

For extra convenience, you can use the [Discovery Component](/components/discovery) system to free the user of your
package from having to instantiate the client.
You should however always accept injecting the client instance to allow the user to configure the client as needed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we add a code sample here? i think this stays rather theoretical

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is explained in the Discover documentation.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

then lets link to that example. maybe add to the paragraph above See also the [example in the discovery documentation](...).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The discovery component is already linked above.

Copy link
Contributor

@dbu dbu Nov 24, 2015 via email

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better?

Copy link
Contributor

@dbu dbu Nov 24, 2015 via email

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Users of your package will have to select a concrete adapter in their project to make your package installable.
Best point them to the [virtual package](virtual-package.md) howto page.

To be able to send requests, you should not depend on a specific PSR-7 implementation,
but use the [Message Factory Component](/components/message-factory) system.


### Framework Integration

HTTPlug can be used in any PHP based project.
Nonetheless, we provide particular integration for some popular frameworks:

- [HttplugBundle](https://github.com/php-http/HttplugBundle/) integration with the Symfony framework.


## History

This project has been started by [Eric Geloen](https://github.com/egeloen) as
Ivory Http Adapter](https://github.com/egeloen/ivory-http-adapter). It never made it to a stable release,
but it relied on PSR-7 which was not stable either that time. Because of the constantly changing PSR-7,
Eric had to rewrite the library over and over again (at least the message handling part,
which in most cases affected every adapter as well).

In 2015, a decision has been made to move the library to it's own organization, so PHP HTTP was born.

See [migrating](migrating.md) for a guide how to migrate your code from the Ivory adapter to HTTPlug.
31 changes: 31 additions & 0 deletions docs/httplug/migrating.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Migrating to HTTPlug

If you currently use a concrete HTTP client implementation or the Ivory Http Adapter,
migrating to Httplug should not be very hard.


## Migrating from Ivory Http Adapter

The monolithic ivory package has been separated into several smaller, more specific packages.

Instead of `Ivory\HttpAdapter\PsrHttpAdapter`, use `Http\Client\HttpClient`.
The HttpClient simply has a method to send requests.

If you used the `Ivory\HttpAdapter\HttpAdapter`, have a look at the [Utilities](utils.md)
and use the `Http\Client\Utils\HttpMethodsClient` which wraps any HttpClient and provides the convenience methods
to send requests without creating RequestInterface instances.


## Migrating from Guzzle

Replace usage of `GuzzleHttp\ClientInterface` with `Http\Client\HttpClient`.
The `send` method is called `sendRequest`.
Instead of the `$options` argument, configure the client appropriately during set up.
If you need different settings, create different instances of the client.
You can use [plugins](plugins.md) to further tune your client.

If you used the `request` method, have a look at the [Utilities](utils.md) and
use the `Http\Client\Utils\HttpMethodsClient` which wraps any HttpClient and provides the convenience methods
to send requests without creating RequestInterface instances.

Asynchronous request support will land in HTTPlug soon.
Loading