Completed
Push — master ( fef847...a6bce7 )
by David
01:19
created

CommonClassesStrategy::getPsr18Candidates()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
dl 0
loc 17
ccs 0
cts 0
cp 0
rs 9.7
c 0
b 0
f 0
cc 4
nc 5
nop 0
crap 20
1
<?php
2
3
namespace Http\Discovery\Strategy;
4
5
use GuzzleHttp\Promise\Promise;
6
use GuzzleHttp\Psr7\Request as GuzzleRequest;
7
use Http\Client\HttpAsyncClient;
8
use Http\Client\HttpClient;
9
use Http\Discovery\Exception\NotFoundException;
10
use Http\Discovery\MessageFactoryDiscovery;
11
use Http\Discovery\Psr17FactoryDiscovery;
12
use Http\Message\RequestFactory;
13
use Psr\Http\Message\RequestFactoryInterface as Psr17RequestFactory;
14
use Http\Message\MessageFactory;
15
use Http\Message\MessageFactory\GuzzleMessageFactory;
16
use Http\Message\StreamFactory;
17
use Http\Message\StreamFactory\GuzzleStreamFactory;
18
use Http\Message\UriFactory;
19
use Http\Message\UriFactory\GuzzleUriFactory;
20
use Http\Message\MessageFactory\DiactorosMessageFactory;
21
use Http\Message\StreamFactory\DiactorosStreamFactory;
22
use Http\Message\UriFactory\DiactorosUriFactory;
23
use Psr\Http\Client\ClientInterface as Psr18Client;
24
use Zend\Diactoros\Request as DiactorosRequest;
25
use Http\Message\MessageFactory\SlimMessageFactory;
26
use Http\Message\StreamFactory\SlimStreamFactory;
27
use Http\Message\UriFactory\SlimUriFactory;
28
use Slim\Http\Request as SlimRequest;
29
use GuzzleHttp\Client as GuzzleHttp;
30
use Http\Adapter\Guzzle6\Client as Guzzle6;
31
use Http\Adapter\Guzzle5\Client as Guzzle5;
32
use Http\Client\Curl\Client as Curl;
33
use Http\Client\Socket\Client as Socket;
34
use Http\Adapter\React\Client as React;
35
use Http\Adapter\Buzz\Client as Buzz;
36
use Http\Adapter\Cake\Client as Cake;
37
use Http\Adapter\Zend\Client as Zend;
38
use Http\Adapter\Artax\Client as Artax;
39
use Symfony\Component\HttpClient\HttplugClient as SymfonyHttplug;
40
use Symfony\Component\HttpClient\Psr18Client as SymfonyPsr18;
41
use Nyholm\Psr7\Factory\HttplugFactory as NyholmHttplugFactory;
42
43
/**
44
 * @internal
45
 *
46
 * @author Tobias Nyholm <[email protected]>
47
 */
48
final class CommonClassesStrategy implements DiscoveryStrategy
49
{
50
    /**
51
     * @var array
52
     */
53
    private static $classes = [
54
        MessageFactory::class => [
55
            ['class' => NyholmHttplugFactory::class, 'condition' => [NyholmHttplugFactory::class]],
56
            ['class' => GuzzleMessageFactory::class, 'condition' => [GuzzleRequest::class, GuzzleMessageFactory::class]],
57
            ['class' => DiactorosMessageFactory::class, 'condition' => [DiactorosRequest::class, DiactorosMessageFactory::class]],
58
            ['class' => SlimMessageFactory::class, 'condition' => [SlimRequest::class, SlimMessageFactory::class]],
59
        ],
60
        StreamFactory::class => [
61
            ['class' => NyholmHttplugFactory::class, 'condition' => [NyholmHttplugFactory::class]],
62
            ['class' => GuzzleStreamFactory::class, 'condition' => [GuzzleRequest::class, GuzzleStreamFactory::class]],
63
            ['class' => DiactorosStreamFactory::class, 'condition' => [DiactorosRequest::class, DiactorosStreamFactory::class]],
64
            ['class' => SlimStreamFactory::class, 'condition' => [SlimRequest::class, SlimStreamFactory::class]],
65
        ],
66
        UriFactory::class => [
67
            ['class' => NyholmHttplugFactory::class, 'condition' => [NyholmHttplugFactory::class]],
68
            ['class' => GuzzleUriFactory::class, 'condition' => [GuzzleRequest::class, GuzzleUriFactory::class]],
69
            ['class' => DiactorosUriFactory::class, 'condition' => [DiactorosRequest::class, DiactorosUriFactory::class]],
70
            ['class' => SlimUriFactory::class, 'condition' => [SlimRequest::class, SlimUriFactory::class]],
71
        ],
72
        HttpAsyncClient::class => [
73
            ['class' => SymfonyHttplug::class, 'condition' => [SymfonyHttplug::class, Promise::class, RequestFactory::class, [self::class, 'isPsr17FactoryInstalled']]],
74
            ['class' => Guzzle6::class, 'condition' => Guzzle6::class],
75
            ['class' => Curl::class, 'condition' => Curl::class],
76
            ['class' => React::class, 'condition' => React::class],
77
        ],
78
        HttpClient::class => [
79
            ['class' => SymfonyHttplug::class, 'condition' => [SymfonyHttplug::class, RequestFactory::class, [self::class, 'isPsr17FactoryInstalled']]],
80
            ['class' => Guzzle6::class, 'condition' => Guzzle6::class],
81
            ['class' => Guzzle5::class, 'condition' => Guzzle5::class],
82
            ['class' => Curl::class, 'condition' => Curl::class],
83
            ['class' => Socket::class, 'condition' => Socket::class],
84
            ['class' => Buzz::class, 'condition' => Buzz::class],
85
            ['class' => React::class, 'condition' => React::class],
86
            ['class' => Cake::class, 'condition' => Cake::class],
87
            ['class' => Zend::class, 'condition' => Zend::class],
88
            ['class' => Artax::class, 'condition' => Artax::class],
89
            [
90
                'class' => [self::class, 'buzzInstantiate'],
91
                'condition' => [\Buzz\Client\FileGetContents::class, \Buzz\Message\ResponseBuilder::class],
92
            ],
93
        ],
94
        Psr18Client::class => [
95
            [
96
                'class' => [self::class, 'symfonyPsr18Instantiate'],
97
                'condition' => [SymfonyPsr18::class, Psr17RequestFactory::class],
98
            ],
99
            [
100
                'class' => GuzzleHttp::class,
101
                'condition' => [self::class, 'isGuzzleImplementingPsr18'],
102
            ],
103
            [
104
                'class' => [self::class, 'buzzInstantiate'],
105
                'condition' => [\Buzz\Client\FileGetContents::class, \Buzz\Message\ResponseBuilder::class],
106
            ],
107
        ],
108
    ];
109
110
    /**
111
     * {@inheritdoc}
112
     */
113
    public static function getCandidates($type)
114
    {
115
        if (Psr18Client::class === $type) {
116
            return self::getPsr18Candidates();
117
        }
118
119
        return self::$classes[$type] ?? [];
120
    }
121
122
    /**
123
     * @return array The return value is always an array with zero or more elements. Each
124
     *               element is an array with two keys ['class' => string, 'condition' => mixed].
125
     */
126
    private static function getPsr18Candidates()
127
    {
128
        $candidates = self::$classes[Psr18Client::class];
129
130
        // HTTPlug 2.0 clients implements PSR18Client too.
131
        foreach (self::$classes[HttpClient::class] as $c) {
132
            try {
133
                if (is_subclass_of($c['class'], Psr18Client::class)) {
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of might return inconsistent results on some PHP versions if \Psr\Http\Client\ClientInterface::class can be an interface. If so, you could instead use ReflectionClass::implementsInterface.
Loading history...
134
                    $candidates[] = $c;
135
                }
136
            } catch (\Throwable $e) {
137
                trigger_error(sprintf('Got exception "%s (%s)" while checking if a PSR-18 Client is available', get_class($e), $e->getMessage()), E_USER_WARNING);
138
            }
139
        }
140
141
        return $candidates;
142
    }
143
144
    public static function buzzInstantiate()
145
    {
146
        return new \Buzz\Client\FileGetContents(MessageFactoryDiscovery::find());
147
    }
148
149
    public static function symfonyPsr18Instantiate()
150
    {
151
        return new SymfonyPsr18(null, Psr17FactoryDiscovery::findResponseFactory(), Psr17FactoryDiscovery::findStreamFactory());
152
    }
153
154
    public static function isGuzzleImplementingPsr18()
155
    {
156
        return defined('GuzzleHttp\ClientInterface::MAJOR_VERSION');
157
    }
158
159
    /**
160
     * Can be used as a condition.
161
     *
162
     * @return bool
163
     */
164
    public static function isPsr17FactoryInstalled()
165
    {
166
        try {
167
            Psr17FactoryDiscovery::findResponseFactory();
168
        } catch (NotFoundException $e) {
169
            return false;
170
        } catch (\Throwable $e) {
171
            trigger_error(sprintf('Got exception "%s (%s)" while checking if a PSR-17 ResponseFactory is available', get_class($e), $e->getMessage()), E_USER_WARNING);
172
173
            return false;
174
        }
175
176
        return true;
177
    }
178
}
179