Retriever::getComingFrom()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
namespace whm\Smoke\Extensions\SmokeResponseRetriever\Retriever\ListRetriever;
4
5
use GuzzleHttp\Psr7\Request;
6
use phm\HttpWebdriverClient\Http\Client\HttpClient;
7
use phm\HttpWebdriverClient\Http\MultiRequestsException;
8
use Psr\Http\Message\UriInterface;
9
use whm\Crawler\Http\RequestFactory;
10
use whm\Html\Uri;
11
use whm\Smoke\Extensions\SmokeResponseRetriever\Retriever\Retriever as SmokeRetriever;
12
use whm\Smoke\Extensions\SmokeResponseRetriever\RetrieverException;
13
use whm\Smoke\Scanner\SessionContainer;
14
15
class Retriever implements SmokeRetriever
16
{
17
    private $urls = [];
18
19
    /**
20
     * @var HttpClient
21
     */
22
    private $httpClient;
23
    private $urlStack = [];
24
25
    private $redirects = array();
26
27
    /**
28
     * @var SessionContainer
29
     */
30
    private $sessionContainer;
31
32
    public function init($urls)
33
    {
34
        if (is_array($urls)) {
35
            foreach ($urls as $key => $urlList) {
36
                foreach ($urlList as $url) {
37
                    if (is_array($url)) {
38
                        $uri = new Uri($url['url']);
39
                        if (array_key_exists('cookies', $url)) {
40
                            foreach ($url['cookies'] as $cookie) {
41
                                foreach ($cookie as $key => $value) {
42
                                    $uri->addCookie($key, $value);
43
                                }
44
                            }
45
                        }
46
                        if (array_key_exists('session', $url)) {
47
                            $sessionName = $url['session'];
48
                            $uri->setSessionIdentifier($sessionName);
49
                        }
50
                    } else {
51
                        $uri = new Uri($url);
52
                    }
53
                    $this->urls[(string)$uri] = ['url' => $uri, 'system' => $key];
54
                }
55
            }
56
            $this->urlStack = $this->urls;
57
        }
58
    }
59
60
    /**
61
     * @param Uri $uri
62
     *
63
     * @return Request
64
     */
65
    private function createRequest(Uri $uri)
66
    {
67
        $headers = ['Accept-Encoding' => 'gzip', 'Connection' => 'keep-alive'];
68
69
        if ($uri->getSessionIdentifier()) {
70
            $session = $this->sessionContainer->getSession($uri->getSessionIdentifier());
71
72
            foreach ($session->getCookies() as $key => $value) {
73
                $uri->addCookie($key, $value);
74
            }
75
        }
76
77
        $request = RequestFactory::getRequest($uri, 'GET', 'php://memory', $headers);
78
79
        return $request;
80
    }
81
82
    public function next()
83
    {
84
        if (empty($this->urlStack)) {
85
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type declared by the interface whm\Smoke\Extensions\Smo...triever\Retriever::next of type Psr\Http\Message\ResponseInterface.

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...
86
        }
87
88
        $url = array_pop($this->urlStack);
89
90
        if ($url['url'] instanceof UriInterface) {
91
            $urlObject = $url['url'];
92
        } else {
93
            $urlObject = new Uri($url['url']);
94
        }
95
96
        $request = $this->createRequest($urlObject);
97
98
        try {
99
            $responses = $this->httpClient->sendRequests(array($request));
100
        } catch (MultiRequestsException $e) {
101
            $exceptions = $e->getExceptions();
102
            /* @var \Exception[] $exceptions */
103
104
            $errorMessages = '';
105
            foreach ($exceptions as $exception) {
106
                // @fixme this must be part of the http client
107
                $message = $exception->getMessage();
108
                if (strpos($message, 'An error occurred when fetching the URI') === 0) {
109
                    $corruptUrl = substr($message, '41', strpos($message, '"', 41) - 41);
110
                    if (strpos($corruptUrl, '/') === 0) {
111
112
                        $mainUri = $request->getUri();
113
                        $this->redirects[(string)$mainUri->getScheme() . '://' . $mainUri->getHost() . $corruptUrl] = (string)$mainUri;
114
115
                        $this->urls[] = ['url' => $mainUri->getScheme() . '://' . $mainUri->getHost() . $corruptUrl, 'system' => $url['system']];
116
                        $this->urlStack[] = ['url' => $mainUri->getScheme() . '://' . $mainUri->getHost() . $corruptUrl, 'system' => $url['system']];
117
118
                        return $this->next();
119
                    }
120
121
                    // the error handling should be done withing the calling class
122
                    echo "\n   " . $exception->getMessage() . "\n";
123
124
                    return $this->next();
125
                } else {
126
                    $errorMessages .= $exception->getMessage() . "\n";
127
                }
128
            }
129
            if ($errorMessages !== '') {
130
                throw new \RuntimeException($errorMessages);
131
            }
132
        }
133
134
        if (empty($responses)) {
135
            return $this->next();
136
        } else {
137
            return $responses[0];
138
        }
139
    }
140
141 View Code Duplication
    public function getOriginUri(UriInterface $uri)
142
    {
143
        if (array_key_exists((string)$uri, $this->redirects)) {
144
            return $this->urls[$this->redirects[(string)$uri]]['url'];
145
        }
146
147
        return $uri;
148
    }
149
150
    public function getComingFrom(UriInterface $uri)
151
    {
152
        return $uri;
153
    }
154
155 View Code Duplication
    public function getSystem(UriInterface $uri)
156
    {
157
        if (array_key_exists((string)$uri, $this->redirects)) {
158
            return $this->urls[$this->redirects[(string)$uri]]['system'];
159
        }
160
161
        return $this->urls[(string)$uri]['system'];
162
    }
163
164
    public function getSystems()
165
    {
166
        $systems = [];
167
        foreach ($this->urls as $key => $url) {
168
            $systems[] = $url['system'];
169
        }
170
171
        return $systems;
172
    }
173
174
    public function setHttpClient(HttpClient $httpClient)
175
    {
176
        $this->httpClient = $httpClient;
177
    }
178
179
    public function setSessionContainer(SessionContainer $sessionContainer)
180
    {
181
        $this->sessionContainer = $sessionContainer;
182
    }
183
184
    public function getOccuredExceptions()
185
    {
186
        return [];
187
    }
188
}
189