App   A
last analyzed

Complexity

Total Complexity 40

Size/Duplication

Total Lines 264
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 93
c 2
b 0
f 0
dl 0
loc 264
rs 9.2
wmc 40

15 Methods

Rating   Name   Duplication   Size   Complexity  
A setAppSecret() 0 4 1
A __construct() 0 12 4
A setAppID() 0 4 1
A getAppSecret() 0 3 1
A getAPIChallenge() 0 13 4
A setAPIChallenge() 0 9 2
A setAccessToken() 0 9 2
A getAppID() 0 3 1
A refreshAccessToken() 0 19 4
B fetchAccessToken() 0 28 8
A getAuthHeaders() 0 5 1
A getSites() 0 16 2
A getAuthURL() 0 9 2
A getAccessToken() 0 10 4
A curl_api() 0 10 3

How to fix   Complexity   

Complex Class

Complex classes like App 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.

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 App, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Lifeboat;
4
5
use Lifeboat\Exceptions\InvalidArgumentException;
6
use Lifeboat\Exceptions\OAuthException;
7
use Lifeboat\Utils\Curl;
8
use Lifeboat\Utils\URL;
9
use Lifeboat\Utils\Utils;
10
11
/**
12
 * Class App
13
 * @package Lifeboat
14
 */
15
class App extends Connector {
16
17
    const CODE_URL      = '/oauth/code';
18
19
    const ACCESS_TOKEN_PARAM    = 'lb_app_access_token';
20
    const API_CHALLENGE_PARAM   = 'lb_app_api_challenge';
21
22
    private $_app_id;
23
    private $_app_secret;
24
    private $_api_challenge = '';
25
26
    /**
27
     * @param string $app_id
28
     * @param string $app_secret
29
     * @param string $auth_domain
30
     */
31
    public function __construct(string $app_id, string $app_secret, string $auth_domain = self::AUTH_DOMAIN)
32
    {
33
        if (!$app_id || !$app_secret) {
34
            throw new InvalidArgumentException(static::class . "expects an app_id and app_secret");
35
        }
36
37
        $this->setAppID($app_id);
38
        $this->setAppSecret($app_secret);
39
        $this->_auth_domain = rtrim($auth_domain, '/');
40
41
        if (session_status() === PHP_SESSION_ACTIVE) {
42
            $this->setAccessToken($_SESSION[self::ACCESS_TOKEN_PARAM] ?? '');
43
        }
44
    }
45
46
    /**
47
     * @return string
48
     */
49
    public function getAppID(): string
50
    {
51
        return $this->_app_id;
52
    }
53
54
    /**
55
     * @param string $id
56
     * @return $this
57
     */
58
    public function setAppID(string $id): App
59
    {
60
        $this->_app_id = $id;
61
        return $this;
62
    }
63
64
    /**
65
     * @return string
66
     */
67
    public function getAppSecret(): string
68
    {
69
        return $this->_app_secret;
70
    }
71
72
    /**
73
     * @param string $token
74
     * @return $this
75
     */
76
    public function setAccessToken(string $token): App
77
    {
78
        $this->_access_token = $token;
79
80
        if (session_status() === PHP_SESSION_ACTIVE) {
81
            $_SESSION[self::ACCESS_TOKEN_PARAM] = $this->_access_token;
82
        }
83
84
        return $this;
85
    }
86
87
    /**
88
     * @param string $secret
89
     * @return $this
90
     */
91
    public function setAppSecret(string $secret): App
92
    {
93
        $this->_app_secret = $secret;
94
        return $this;
95
    }
96
97
    /**
98
     * @param string $challenge
99
     * @return $this
100
     */
101
    public function setAPIChallenge(string $challenge): App
102
    {
103
        $this->_api_challenge = $challenge;
104
105
        if (session_status() === PHP_SESSION_ACTIVE) {
106
            $_SESSION[self::API_CHALLENGE_PARAM] = $this->_api_challenge;
107
        }
108
109
        return $this;
110
    }
111
112
    /**
113
     * @param bool $check_session
114
     * @return string
115
     */
116
    public function getAPIChallenge(bool $check_session = true): string
117
    {
118
        if ($this->_api_challenge) return $this->_api_challenge;
119
120
        if ($check_session && session_status() === PHP_SESSION_ACTIVE) {
121
            $this->setAPIChallenge($_SESSION[self::API_CHALLENGE_PARAM] ?? '');
122
            return $this->getAPIChallenge(false);
123
        }
124
125
        $this->_api_challenge = Utils::create_random_string(128);
126
        $this->setAPIChallenge($this->_api_challenge);
127
128
        return $this->_api_challenge;
129
    }
130
131
    /**
132
     * @param string $process_url
133
     * @param string $error_url
134
     * @param string $challenge
135
     * @return string
136
     */
137
    public function getAuthURL(string $process_url, string $error_url, string $challenge): string
138
    {
139
        $url    = URL::setGetVar('app_id', $this->getAppID(), $this->auth_url(self::CODE_URL));
140
        $url    = URL::setGetVar('process_url', urlencode($process_url), $url);
141
        $url    = URL::setGetVar('error_url', urlencode($error_url), $url);
142
143
        if ($this->getSiteKey()) $url = URL::setGetVar('site_key', $this->getSiteKey(), $url);
144
145
        return URL::setGetVar('challenge', Utils::pack($challenge), $url);
146
    }
147
148
    /**
149
     * @param string|null $code
150
     * @return string
151
     */
152
    public function fetchAccessToken(string $code = null): string
153
    {
154
        $curl = new Curl($this->auth_url('/oauth/token'), [
155
            'app_id'        => $this->getAppID(),
156
            'challenge'     => $this->getAPIChallenge(),
157
            'app_secret'    => $this->getAppSecret(),
158
            'site_key'      => $this->getSiteKey(),
159
            'code'          => $code
160
        ]);
161
162
        $curl->setMethod('POST');
163
        $response = $curl->curl();
164
        $json = $response->getJSON();
165
166
        if (!$response->isValid() || !$json || !array_key_exists('access_token', $json)) {
167
            if (array_key_exists('error', $json)) throw new OAuthException($json['error']);
168
            return '';
169
        } else {
170
            $this->setAccessToken($json['access_token']);
171
172
            if (array_key_exists('store_data', $json) &&
173
                array_key_exists('domain', $json['store_data']) &&
174
                array_key_exists('site_key', $json['store_data'])
175
            ) {
176
                $this->setActiveSite($json['store_data']['domain'], $json['store_data']['site_key']);
177
            }
178
179
            return $this->getAccessToken(false);
180
        }
181
    }
182
183
    /**
184
     * @param bool $check_session
185
     * @return string
186
     */
187
    public function getAccessToken(bool $check_session = true): string
188
    {
189
        if ($this->_access_token) return $this->_access_token;
190
191
        if ($check_session && session_status() === PHP_SESSION_ACTIVE) {
192
            $this->setAccessToken($_SESSION[self::ACCESS_TOKEN_PARAM] ?? '');
193
            return $this->getAccessToken(false);
194
        }
195
196
        return '';
197
    }
198
199
    /**
200
     * Makes a request to the API to refresh the current access token
201
     *
202
     * @return $this
203
     * @throws OAuthException
204
     */
205
    public function refreshAccessToken(): Connector
206
    {
207
        $curl = new Curl($this->auth_url('/oauth/refresh_token'), [
208
            'access_token'  => $this->getAccessToken(),
209
            'app_id'        => $this->getAppID(),
210
            'site_key'      => $this->getSiteKey()
211
        ]);
212
213
        $curl->setMethod('POST');
214
        $response = $curl->curl();
215
        $json = $response->getJSON();
216
217
        if (!$response->isValid() || !$json || !array_key_exists('access_token', $json)) {
218
            throw new OAuthException($response->getError());
219
        } else {
220
            $this->setAccessToken($json['access_token']);
221
        }
222
223
        return $this;
224
    }
225
226
227
    /**
228
     * @return array
229
     * @throws OAuthException
230
     */
231
    public function getSites(): array
232
    {
233
        $curl = new Curl($this->auth_url(self::SITES_URL), [
234
            'access_token'  => $this->getAccessToken(),
235
            'app_id'        => $this->getAppID()
236
        ]);
237
238
        $curl->setMethod('POST');
239
        $response = $curl->curl();
240
241
        if (!$response->isValid()) {
242
            $error = $response->getJSON();
243
            throw new OAuthException($error['error'], $error['code']);
244
        }
245
246
        return $response->getJSON() ?? [];
247
    }
248
249
    /**
250
     * @param string $url
251
     * @param string $method
252
     * @param array $data
253
     * @param array $headers
254
     * @param bool $retry
255
     * @return CurlResponse
256
     * @throws OAuthException
257
     */
258
    public function curl_api(string $url, string $method = 'GET', array $data = [], array $headers = [], bool $retry = true): CurlResponse
259
    {
260
        $response = parent::curl_api($url, $method, $data, $headers);
261
262
        if ($retry && $response->getHTTPCode() === 401) {
263
            $this->fetchAccessToken();
264
            return $this->curl_api($url, $method, $data, $headers, false);
265
        }
266
267
        return $response;
268
    }
269
270
    /**
271
     * @return array
272
     * @throws Exceptions\OAuthException
273
     */
274
    public function getAuthHeaders(): array
275
    {
276
        $headers = parent::getAuthHeaders();
277
        $headers['app-id'] = $this->getAppID();
278
        return $headers;
279
    }
280
}
281