Completed
Push — master ( f44910...121be2 )
by Greg
02:10
created

BrowserMob   B

Complexity

Total Complexity 46

Size/Duplication

Total Lines 198
Duplicated Lines 9.09 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 12
Bugs 4 Features 3
Metric Value
wmc 46
c 12
b 4
f 3
lcom 1
cbo 6
dl 18
loc 198
rs 8.3999

10 Methods

Rating   Name   Duplication   Size   Complexity  
B _initialize() 0 21 5
A __pingProxy() 0 10 2
C __setProxyCapabilities() 0 73 24
A getProxyPort() 0 4 1
A openProxy() 0 13 3
A closeProxy() 0 8 2
A startHar() 9 9 2
A startPage() 9 9 2
A getHar() 0 4 1
A __call() 0 20 4

How to fix   Duplicated Code    Complexity   

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:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like BrowserMob often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use BrowserMob, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace Codeception\Extension;
3
4
use Codeception\Module;
5
use Codeception\Exception\ModuleException;
6
use Codeception\Exception\ModuleConfigException;
7
use \PHPBrowserMobProxy_Client as BMP;
8
use \Requests;
9
use \RuntimeException;
10
11
/**
12
 * @method void _open()
13
 * @method void _close()
14
 * @method string _newHar(string $label='')
15
 * @method string _newPage(string $label='')
16
 * @method string _blacklist(string $regexp, integer $status_code)
17
 * @method string _whitelist(string $regexp, integer $status_code)
18
 * @method string _basicAuth(string $domain, string[] $options)
19
 * @method string _headers(string[] $options)
20
 * @method string _responseInterceptor(string $js)
21
 * @method string _requestInterceptor(string $js)
22
 * @method Requests_Response _limits(string[] $options)
23
 * @method Requests_Response _timeouts(string[] $options)
24
 * @method string _remapHosts(string $address, string $ip_address)
25
 * @method string _waitForTrafficToStop(integer $quiet_period, integer $timeout)
26
 * @method string _clearDnsCache()
27
 * @method string _rewriteUrl(string $match, string $replace)
28
 * @method string _retry(integer $retry_count)
29
 */
30
class BrowserMob extends Module
31
{
32
33
    protected $config = ['host', 'port', 'autostart', 'blacklist', 'whitelist', 'limits', 'timeouts', 'redirect', 'retry', 'basicAuth', 'littleproxy'];
34
35
    protected $requiredFields = ['host'];
36
37
    protected $response;
38
39
    private $bmp;
40
41
    /**
42
     * @codeCoverageIgnore
43
     * @ignore Codeception specific
44
     */
45
    public function _initialize()
46
    {
47
        $host = $this->config['host'];
48
        if (isset($this->config['port'])) {
49
            $host = $host.':'.$this->config['port'];
50
        }
51
52
        // test if proxy is available
53
        if (static::__pingProxy($host)) {
54
            $this->bmp = new BMP($host);
55
        } else {
56
            throw new ModuleConfigException(__CLASS__, "Proxy '{$host}' cannot be reached");
57
        }
58
59
        // start a new BrowserMobProxy session
60
        if (isset($this->config['autostart'])) {
61
            if (true === (bool) $this->config['autostart']) {
62
                $this->openProxy();
63
            }
64
        }
65
    }
66
67
    protected static function __pingProxy($url)
68
    {
69
        try {
70
            $response = Requests::get('http://'.$url.'/proxy/');
71
        } catch (\Exception $e) {
72
            throw new ModuleException(__CLASS__, $e->getMessage());
73
        }
74
75
        return $response->success;
76
    }
77
78
    protected function __setProxyCapabilities($capabilities)
79
    {
80
        $response = null;
81
82
        foreach ($capabilities as $config => $data) {
83
            try {
84
                if (false === empty($data)) {
85
                    switch ((string) $config) {
86
                        case 'blacklist':
87
                            foreach ($data['patterns'] as $pattern) {
88
                                $response = $this->_blacklist($pattern, $data['code']);
89
                                if (isset($response->success)) {
90
                                    if (false === $response->success) {
91
                                        break;
92
                                    }
93
                                }
94
                            }
95
                            break;
96
                        case 'whitelist':
97
                            $patterns = implode(',', $data['patterns']);
98
                            $response = $this->_whitelist($patterns, $data['code']);
99
                            if (isset($response->success)) {
100
                                if (false === $response->success) {
101
                                    break;
102
                                }
103
                            }
104
                            break;
105
                        case 'limits':
106
                            $response = $this->_limits($data);
107
                            break;
108
                        case 'timeouts':
109
                            $response = $this->_timeouts($data);
110
                            break;
111
                        case 'redirect':
112
                            foreach ($data as $entry) {
113
                                $response = $this->_remapHosts($entry['address'], $entry['ip']);
114
                                if (isset($response->success)) {
115
                                    if (false === $response->success) {
116
                                        break;
117
                                    }
118
                                }
119
                            }
120
                            break;
121
                        case 'retry':
122
                            $response = $this->_retry($data);
123
                            break;
124
                        case 'basicAuth':
125
                            foreach ($data as $entry) {
126
                                $response = $this->_basicAuth($entry['domain'], $entry['options']);
127
                                if (isset($response->success)) {
128
                                    if (false === $response->success) {
129
                                        break;
130
                                    }
131
                                }
132
                            }
133
                            break;
134
                        default:
135
                            // do nothing
136
                    }
137
                }
138
            } catch (\Exception $e) {
139
                throw new ModuleConfigException(__CLASS__, $e->getMessage());
140
            }
141
142
            if (get_class($response) === 'Request')
143
            {
144
                $this->response = $response;
145
                if (false === $response->success) {
146
                    throw new ModuleConfigException(__CLASS__, "Proxy response error '{$response->status_code}' {$respone->body}");
147
                }
148
            }
149
        }
150
    }
151
152
    public function getProxyPort()
153
    {
154
        return $this->bmp->port;
155
    }
156
157
    public function openProxy($capabilities = null)
158
    {
159
        try {
160
            $this->bmp->open();
161
            if (empty($capabilities)) {
162
                $capabilities = $this->config;
163
            }
164
            $this->__setProxyCapabilities($capabilities);
165
        } catch (\Exception $e) {
166
            throw new ModuleException(__CLASS__, $e->getMessage());
167
        }
168
        return $this->getProxyPort();
169
    }
170
171
    public function closeProxy()
172
    {
173
        try {
174
            $this->bmp->close();
175
        } catch (\Exception $e) {
176
            throw new ModuleException(__CLASS__, $e->getMessage());
177
        }
178
    }
179
180 View Code Duplication
    public function startHar()
1 ignored issue
show
Duplication introduced by
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...
181
    {
182
        try {
183
            $this->response = $this->bmp->newHar();
184
        } catch (\Exception $e) {
185
            throw new ModuleException(__CLASS__, $e->getMessage());
186
        }
187
        return $this->response->success;
188
    }
189
190 View Code Duplication
    public function startPage()
1 ignored issue
show
Duplication introduced by
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...
191
    {
192
        try {
193
            $this->response = $this->bmp->newPage();
194
        } catch (\Exception $e) {
195
            throw new ModuleException(__CLASS__, $e->getMessage());
196
        }
197
        return $this->response->success;
198
    }
199
200
    public function getHar()
201
    {
202
        return $this->bmp->har;
203
    }
204
205
    // magic function that exposes BrowserMobProxy API pulic methods
206
    public function __call($method, $args)
207
    {
208
        // check if is a command call
209
        if (preg_match('/^_[A-z]+$/', $method)) {
210
            // extract standard method name
211
            $method = preg_filter('/_/', '', $method);
212
            // set call array for calling method
213
            $call = array($this->bmp, $method);
214
            // check if method is callable
215
            if (is_callable($call)) {
216
                $ret = call_user_func_array($call, $args);
217
            } else {
218
                throw new RuntimeException("Method ${method} does not exist or is not callable");
219
            }
220
        } else {
221
            throw new RuntimeException("Method ${method} does not exist or is not callable");
222
        }
223
        $ret = (isset($ret)) ? $ret : null;
224
        return $ret;
225
    }
226
227
}
228