Skip to content
This repository was archived by the owner on Feb 10, 2023. It is now read-only.

Commit 2b14762

Browse files
Implement runtime auto-discovery
1 parent d23c515 commit 2b14762

File tree

57 files changed

+1979
-1
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+1979
-1
lines changed

.github/workflows/unit-tests.yml

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
name: PHPUnit
2+
3+
on:
4+
push:
5+
pull_request:
6+
7+
defaults:
8+
run:
9+
shell: bash
10+
11+
concurrency:
12+
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
13+
cancel-in-progress: true
14+
15+
permissions:
16+
contents: read
17+
18+
jobs:
19+
20+
tests:
21+
name: Tests
22+
23+
env:
24+
extensions: curl,mbstring
25+
26+
strategy:
27+
matrix:
28+
php:
29+
- '7.1'
30+
- '8.1'
31+
psr7:
32+
- guzzlehttp/psr7
33+
- laminas/laminas-diactoros
34+
- nyholm/psr7
35+
- slim/psr7
36+
client:
37+
- php-http/curl-client
38+
- symfony/http-client
39+
include:
40+
- php: '8.1'
41+
client: php-http/guzzle7-adapter
42+
psr7: guzzlehttp/psr7
43+
- php: '7.1'
44+
client: php-http/guzzle6-adapter
45+
psr7: guzzlehttp/psr7
46+
- php: '8.1'
47+
client: php-http/react-adapter
48+
psr7: nyholm/psr7
49+
- php: '7.1'
50+
client: php-http/react-adapter
51+
psr7: nyholm/psr7
52+
fail-fast: false
53+
54+
runs-on: ubuntu-22.04
55+
56+
steps:
57+
- name: Checkout
58+
uses: actions/checkout@v2
59+
with:
60+
fetch-depth: 2
61+
62+
- name: Setup PHP
63+
uses: shivammathur/setup-php@v2
64+
with:
65+
coverage: "none"
66+
ini-values: date.timezone=Europe/Paris,memory_limit=-1,default_socket_timeout=10,session.gc_probability=0,zend.assertions=1
67+
php-version: "${{ matrix.php }}"
68+
extensions: "${{ env.extensions }}"
69+
70+
- name: Install dependencies
71+
run: |
72+
echo "::group::composer update"
73+
composer require --ansi --no-update guzzlehttp/promises php-http/message-factory ${{ matrix.psr7 }} ${{ matrix.client }}
74+
composer update --ansi
75+
echo "::endgroup::"
76+
77+
echo "::group::install phpunit"
78+
./vendor/bin/simple-phpunit install
79+
echo "::endgroup::"
80+
81+
- name: Run tests
82+
run: |
83+
./vendor/bin/simple-phpunit

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
.phpunit.result.cache
12
composer.lock
23
vendor/

LICENSE

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Copyright (c) 2022 Fabien Potencier
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy
4+
of this software and associated documentation files (the "Software"), to deal
5+
in the Software without restriction, including without limitation the rights
6+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
copies of the Software, and to permit persons to whom the Software is furnished
8+
to do so, subject to the following conditions:
9+
10+
The above copyright notice and this permission notice shall be included in all
11+
copies or substantial portions of the Software.
12+
13+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
THE SOFTWARE.

README.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# FriendsOfPHP / Well-Known Implementations
2+
3+
This package helps reduce the proliferation of same-abstraction implementations
4+
in vendor directories.
5+
6+
It is targeted at SDK maintainers that write their code in a decoupled way but
7+
still need an actual implementation to provide a nice experience out of the box.
8+
9+
Without this package, one would e.g. require the "php-http/client-implementation"
10+
virtual package to signal that a given SDK uses HTTPlug to make API calls, and
11+
would also require "php-http/guzzle7-adapter" to install an actual
12+
implementation in case none is wired by the consuming app when calling the SDK.
13+
14+
But imagine that the consuming app already has a dependency on another
15+
"php-http/client-implementation": the SDK should ideally reuse that
16+
implementation and "php-http/guzzle7-adapter" should be removed from vendor/ with
17+
all its transitive dependencies. This would help with dependency-management and
18+
might enable better integration in debugging panels for example.
19+
20+
By requiring "friendsofphp/well-known-implementations" instead of
21+
"php-http/guzzle7-adapter", SDK maintainers can provide ideal experiences:
22+
because this package is also a composer-plugin (*TODO*), it will auto-install an
23+
actual implementation of the required abstraction when none is already installed,
24+
or reuse it if one is found.
25+
26+
In their constructors, SDKs should then reference the provided "well-known"
27+
classes and they will get whatever implementation is available:
28+
29+
```php
30+
class MySdk
31+
{
32+
public function __construct(
33+
private HttpClient $client = new WellKnownHttplugClient(),
34+
)
35+
{
36+
// ...
37+
}
38+
}
39+
```
40+
41+
As of now, the following abstractions are supported:
42+
- php-http/async-client-implementation
43+
- php-http/client-implementation
44+
- psr/http-client-implementation
45+
- psr/http-factory-implementation
46+
- psr/http-message-implementation
47+
48+
And the following vendors are supported:
49+
- Guzzle
50+
- HTTPlug
51+
- Laminas
52+
- Nyholm
53+
- React
54+
- Slim
55+
- Symfony
56+
57+
More abstractions / vendors can be added by contributions, e.g. for
58+
psr/log-implementation, psr/cache-implementation, psr/simple-cache-implementation.
59+
60+
If your favorite SDK does not use this package yet, please let them know about it
61+
or better: the send them a PR!

composer.json

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,23 @@
2626
"php-http/httplug": "^1|^2",
2727
"psr/http-client": "^1",
2828
"psr/http-factory": "^1",
29-
"psr/http-message": "^1"
29+
"psr/http-message": "^1",
30+
"symfony/phpunit-bridge": "^6"
3031
},
3132
"autoload": {
3233
"psr-4": {
3334
"FriendsOfPHP\\WellKnownImplementations\\": "src/"
3435
}
3536
},
37+
"conflict": {
38+
"guzzlehttp/guzzle": "<6",
39+
"guzzlehttp/psr7": "<1.4",
40+
"laminas/laminas-diactoros": "<2",
41+
"php-http/curl-client": "<2",
42+
"php-http/react-adapter": "<3"
43+
},
44+
"config": {
45+
"sort-packages": true
46+
},
3647
"minimum-stability": "dev"
3748
}

phpunit.xml.dist

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
3+
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/9.3/phpunit.xsd"
5+
backupGlobals="false"
6+
colors="true"
7+
bootstrap="vendor/autoload.php"
8+
failOnRisky="true"
9+
failOnWarning="true"
10+
>
11+
<php>
12+
<ini name="error_reporting" value="-1" />
13+
</php>
14+
15+
<testsuites>
16+
<testsuite name="Well-Known Implementations Test Suite">
17+
<directory>./tests/</directory>
18+
</testsuite>
19+
</testsuites>
20+
</phpunit>
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
3+
/*
4+
* (c) Fabien Potencier <[email protected]>
5+
*
6+
* For the full copyright and license information, please view the LICENSE
7+
* file that was distributed with this source code.
8+
*/
9+
10+
namespace FriendsOfPHP\WellKnownImplementations\Internal;
11+
12+
use Composer\InstalledVersions;
13+
14+
foreach ([
15+
'PSR7' => [
16+
'Nyholm' => 'nyholm/psr7',
17+
'Guzzle' => ['guzzlehttp/psr7' => '1.4'],
18+
'Slim' => 'slim/psr7',
19+
'Laminas' => 'laminas/laminas-diactoros',
20+
],
21+
'PSR18' => [
22+
'Symfony' => 'symfony/http-client',
23+
'Guzzle' => ['guzzlehttp/guzzle' => '7.0'],
24+
],
25+
'HTTPLUG' => [
26+
'Symfony' => ['symfony/http-client' => '4.4'],
27+
'PhpHttpGuzzle7' => 'php-http/guzzle7-adapter',
28+
'PhpHttpGuzzle6' => 'php-http/guzzle6-adapter',
29+
'PhpHttpCurl' => 'php-http/curl-client',
30+
'PhpHttpReact' => 'php-http/react-adapter',
31+
],
32+
] as $const => $packages) {
33+
if (\defined(__NAMESPACE__."\\{$const}_VENDOR")) {
34+
continue;
35+
}
36+
foreach ([false, true] as $includeDevRequirements) {
37+
foreach ($packages as $namespace => $versions) {
38+
foreach ((array) $versions as $package => $version) {
39+
if (\is_int($package)) {
40+
$package = $version;
41+
$version = null;
42+
}
43+
if (!InstalledVersions::isInstalled($package, $includeDevRequirements)) {
44+
continue 2;
45+
}
46+
if (null !== $version && version_compare($installed = InstalledVersions::getVersion($package) ?? $version, $version, '<') && 0 !== strpos($installed, 'dev-')) {
47+
continue 2;
48+
}
49+
}
50+
\define(__NAMESPACE__."\\{$const}_VENDOR", $namespace);
51+
continue 3;
52+
}
53+
}
54+
\define(__NAMESPACE__."\\{$const}_VENDOR", null);
55+
}
56+
/**
57+
* @internal
58+
*/
59+
class ConcreteImplementation
60+
{
61+
public const PSR7_VENDOR = PSR7_VENDOR;
62+
public const PSR18_VENDOR = PSR18_VENDOR;
63+
public const HTTPLUG_VENDOR = HTTPLUG_VENDOR;
64+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
/*
4+
* (c) Fabien Potencier <[email protected]>
5+
*
6+
* For the full copyright and license information, please view the LICENSE
7+
* file that was distributed with this source code.
8+
*/
9+
10+
namespace FriendsOfPHP\WellKnownImplementations\Internal\Guzzle;
11+
12+
use GuzzleHttp\Client;
13+
14+
class_alias(Client::class, GuzzlePsr18Client::class);
15+
16+
if (false) {
17+
/**
18+
* @internal
19+
*/
20+
class GuzzlePsr18Client extends Client
21+
{
22+
public function __construct()
23+
{
24+
}
25+
}
26+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
/*
4+
* (c) Fabien Potencier <[email protected]>
5+
*
6+
* For the full copyright and license information, please view the LICENSE
7+
* file that was distributed with this source code.
8+
*/
9+
10+
namespace FriendsOfPHP\WellKnownImplementations\Internal\Guzzle;
11+
12+
use GuzzleHttp\Psr7\Request;
13+
14+
class_alias(Request::class, GuzzlePsr7Request::class);
15+
16+
if (false) {
17+
/**
18+
* @internal
19+
*/
20+
class GuzzlePsr7Request extends Request
21+
{
22+
/**
23+
* @param UriInterface|string $uri
24+
*/
25+
public function __construct(string $method, $uri)
26+
{
27+
}
28+
}
29+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
/*
4+
* (c) Fabien Potencier <[email protected]>
5+
*
6+
* For the full copyright and license information, please view the LICENSE
7+
* file that was distributed with this source code.
8+
*/
9+
10+
namespace FriendsOfPHP\WellKnownImplementations\Internal\Guzzle;
11+
12+
use GuzzleHttp\Psr7\Response;
13+
14+
/**
15+
* @internal
16+
*/
17+
class GuzzlePsr7Response extends Response
18+
{
19+
public function __construct(int $code = 200, string $reasonPhrase = '')
20+
{
21+
parent::__construct($code, [], null, '1.1', 2 > \func_num_args() ? null : $reasonPhrase);
22+
}
23+
}

0 commit comments

Comments
 (0)