Completed
Push — master ( 623c91...fef847 )
by David
01:30
created

CommonClassesStrategy::getPsr18Candidates()   B

Complexity

Conditions 7
Paths 20

Size

Total Lines 28

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 0
Metric Value
dl 0
loc 28
ccs 0
cts 0
cp 0
rs 8.5386
c 0
b 0
f 0
cc 7
nc 20
nop 0
crap 56
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' => GuzzleHttp::class,
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 = [];
129
130
        // Guzzle 6 does not implement the PSR-18 client interface, but Guzzle 7 does.
131
        foreach (self::$classes[Psr18Client::class] ?? [] as $c) {
132
            if (GuzzleHttp::class === $c['class']) {
133
                if (defined('GuzzleHttp\ClientInterface::MAJOR_VERSION')) {
134
                    $candidates[] = $c;
135
                }
136
            } else {
137
                $candidates[] = $c;
138
            }
139
        }
140
141
        // HTTPlug 2.0 clients implements PSR18Client too.
142
        foreach (self::$classes[HttpClient::class] as $c) {
143
            try {
144
                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...
145
                    $candidates[] = $c;
146
                }
147
            } catch (\Throwable $e) {
148
                trigger_error(sprintf('Got exception "%s (%s)" while checking if a PSR-18 Client is available', get_class($e), $e->getMessage()), E_USER_WARNING);
149
            }
150
        }
151
152
        return $candidates;
153
    }
154
155
    public static function buzzInstantiate()
156
    {
157
        return new \Buzz\Client\FileGetContents(MessageFactoryDiscovery::find());
158
    }
159
160
    public static function symfonyPsr18Instantiate()
161
    {
162
        return new SymfonyPsr18(null, Psr17FactoryDiscovery::findResponseFactory(), Psr17FactoryDiscovery::findStreamFactory());
163
    }
164
165
    /**
166
     * Can be used as a condition.
167
     *
168
     * @return bool
169
     */
170
    public static function isPsr17FactoryInstalled()
171
    {
172
        try {
173
            Psr17FactoryDiscovery::findResponseFactory();
174
        } catch (NotFoundException $e) {
175
            return false;
176
        } catch (\Throwable $e) {
177
            trigger_error(sprintf('Got exception "%s (%s)" while checking if a PSR-17 ResponseFactory is available', get_class($e), $e->getMessage()), E_USER_WARNING);
178
179
            return false;
180
        }
181
182
        return true;
183
    }
184
}
185