Guzzle4HttpAdapter   A
last analyzed

Complexity

Total Complexity 12

Size/Duplication

Total Lines 144
Duplicated Lines 22.92 %

Coupling/Cohesion

Components 1
Dependencies 11

Test Coverage

Coverage 86.46%

Importance

Changes 0
Metric Value
wmc 12
lcom 1
cbo 11
dl 33
loc 144
ccs 83
cts 96
cp 0.8646
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 2
A getName() 0 4 1
B sendInternalRequest() 24 24 2
A sendInternalRequests() 0 11 3
A createFile() 0 4 1
A createRequest() 9 59 3

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
/*
4
 * This file is part of the Ivory Http Adapter package.
5
 *
6
 * (c) Eric GELOEN <[email protected]>
7
 *
8
 * For the full copyright and license information, please read the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Ivory\HttpAdapter;
13
14
use Guzzle\Http\Message\RequestInterface;
15
use GuzzleHttp\Client;
16
use GuzzleHttp\ClientInterface;
17
use GuzzleHttp\Event\CompleteEvent;
18
use GuzzleHttp\Event\ErrorEvent;
19
use GuzzleHttp\Exception\RequestException;
20
use GuzzleHttp\Pool;
21
use Ivory\HttpAdapter\Message\InternalRequestInterface;
22
use Ivory\HttpAdapter\Normalizer\BodyNormalizer;
23
24
/**
25
 * @author GeLo <[email protected]>
26
 */
27
class Guzzle4HttpAdapter extends AbstractCurlHttpAdapter
28
{
29
    /**
30
     * @var ClientInterface
31
     */
32
    private $client;
33
34
    /**
35
     * @param ClientInterface|null        $client
36
     * @param ConfigurationInterface|null $configuration
37
     */
38 704
    public function __construct(ClientInterface $client = null, ConfigurationInterface $configuration = null)
39
    {
40 704
        parent::__construct($configuration, false);
41
42 704
        $this->client = $client ?: new Client();
43 704
    }
44
45
    /**
46
     * {@inheritdoc}
47
     */
48 24
    public function getName()
49
    {
50 24
        return 'guzzle4';
51
    }
52
53
    /**
54
     * {@inheritdoc}
55
     */
56 672 View Code Duplication
    protected function sendInternalRequest(InternalRequestInterface $internalRequest)
0 ignored issues
show
Duplication introduced by Eric GELOEN
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
57
    {
58
        try {
59 656
            $response = $this->client->send($this->createRequest($internalRequest));
0 ignored issues
show
Documentation introduced by Eric GELOEN
$this->createRequest($internalRequest) is of type object<Guzzle\Http\Message\RequestInterface>, but the function expects a object<Psr\Http\Message\RequestInterface>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
60 656
        } catch (RequestException $e) {
61 24
            throw HttpAdapterException::cannotFetchUri(
62 24
                $e->getRequest()->getUrl(),
0 ignored issues
show
Bug introduced by Eric GELOEN
The method getUrl() does not seem to exist on object<Psr\Http\Message\RequestInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
63 24
                $this->getName(),
64 24
                $e->getMessage()
65 24
            );
66
        }
67
68 632
        return $this->getConfiguration()->getMessageFactory()->createResponse(
69 632
            (int) $response->getStatusCode(),
70 632
            $response->getProtocolVersion(),
71 632
            $response->getHeaders(),
72 632
            BodyNormalizer::normalize(
73
                function () use ($response) {
74 584
                    return $response->getBody()->detach();
75 672
                },
76 648
                $internalRequest->getMethod()
77 632
            )
78 644
        );
79 4
    }
80
81
    /**
82
     * {@inheritdoc}
83
     */
84 16
    protected function sendInternalRequests(array $internalRequests, $success, $error)
85
    {
86 16
        $requests = [];
87 16
        foreach ($internalRequests as $internalRequest) {
88 16
            $requests[] = $this->createRequest($internalRequest, $success, $error);
89 16
        }
90
91 16
        class_exists('GuzzleHttp\Pool')
92 16
            ? Pool::batch($this->client, $requests)
93 16
            : \GuzzleHttp\batch($this->client, $requests);
94 16
    }
95
96
    /**
97
     * {@inheritdoc}
98
     */
99 80
    protected function createFile($file)
100
    {
101 80
        return fopen($file, 'r');
0 ignored issues
show
Bug Best Practice introduced by Eric GELOEN
The return type of return fopen($file, 'r'); (resource) is incompatible with the return type of the parent method Ivory\HttpAdapter\Abstra...HttpAdapter::createFile of type CurlFile|string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
102
    }
103
104
    /**
105
     * @param InternalRequestInterface $internalRequest
106
     * @param callable|null            $success
107
     * @param callable|null            $error
108
     *
109
     * @return RequestInterface the request
110
     */
111 672
    private function createRequest(InternalRequestInterface $internalRequest, $success = null, $error = null)
112
    {
113 672
        $request = $this->client->createRequest(
0 ignored issues
show
Bug introduced by Eric GELOEN
The method createRequest() does not exist on GuzzleHttp\ClientInterface. Did you maybe mean request()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
114 672
            $internalRequest->getMethod(),
115 672
            (string) $internalRequest->getUri(),
116
            [
117 672
                'exceptions'      => false,
118 672
                'allow_redirects' => false,
119 672
                'timeout'         => $this->getConfiguration()->getTimeout(),
120 672
                'connect_timeout' => $this->getConfiguration()->getTimeout(),
121 672
                'version'         => $internalRequest->getProtocolVersion(),
122 672
                'headers'         => $this->prepareHeaders($internalRequest),
123 672
                'body'            => $this->prepareContent($internalRequest),
124
            ]
125 672
        );
126
127 672
        if (is_callable($success)) {
128 16
            $messageFactory = $this->getConfiguration()->getMessageFactory();
129
130 16
            $request->getEmitter()->on(
131 16
                'complete',
132
                function (CompleteEvent $event) use ($success, $internalRequest, $messageFactory) {
133 16
                    $response = $messageFactory->createResponse(
134 16
                        (int) $event->getResponse()->getStatusCode(),
135 16
                        $event->getResponse()->getProtocolVersion(),
136 16
                        $event->getResponse()->getHeaders(),
137 16
                        BodyNormalizer::normalize(
138
                            function () use ($event) {
139 16
                                return $event->getResponse()->getBody()->detach();
140 16
                            },
141 16
                            $internalRequest->getMethod()
142 16
                        )
143 16
                    );
144
145 16
                    $response = $response->withParameter('request', $internalRequest);
146 16
                    call_user_func($success, $response);
147 16
                }
148 16
            );
149 16
        }
150
151 672
        if (is_callable($error)) {
152 16
            $httpAdapterName = $this->getName();
153
154 16
            $request->getEmitter()->on(
155 16
                'error',
156 10 View Code Duplication
                function (ErrorEvent $event) use ($error, $internalRequest, $httpAdapterName) {
0 ignored issues
show
Duplication introduced by Eric GELOEN
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
157 8
                    $exception = HttpAdapterException::cannotFetchUri(
158 8
                        $event->getException()->getRequest()->getUrl(),
159 8
                        $httpAdapterName,
160 8
                        $event->getException()->getMessage()
161 10
                    );
162 8
                    $exception->setRequest($internalRequest);
163 8
                    call_user_func($error, $exception);
164 8
                }
165 16
            );
166 16
        }
167
168 672
        return $request;
169
    }
170
}
171