Completed
Push — master ( c7c88d...7873ee )
by Mike
02:24
created

AbstractClient::__construct()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 9
rs 9.6666
cc 3
eloc 6
nc 4
nop 2
1
<?php
2
3
namespace SugarAPI\SDK\Client\Abstracts;
4
5
use SugarAPI\SDK\Client\Interfaces\ClientInterface;
6
use SugarAPI\SDK\Exception\EntryPoint\EntryPointException;
7
use SugarAPI\SDK\Helpers\Helpers;
8
use SugarAPI\SDK\EntryPoint\POST\OAuth2Logout;
9
use SugarAPI\SDK\EntryPoint\POST\OAuth2Token;
10
use SugarAPI\SDK\EntryPoint\POST\RefreshToken;
11
use SugarAPI\SDK\Exception\Authentication\AuthenticationException;
12
13
abstract class AbstractClient implements ClientInterface {
14
15
    /**
16
     * Array of Statically Bound Tokens for SDK Clients
17
     * - Allows for reinstating objects in multiple areas, without needing to Sign-in
18
     * - Allows for multiple client_id's to be used between SDK Clients
19
     *
20
     * @var array = array(
21
     *      $client_id => $token
22
     * )
23
     */
24
    protected static $_STORED_TOKENS = array();
25
26
27
    /**
28
     * The configured server domain name/url on the SDK Client
29
     * @var string
30
     */
31
    protected $server;
32
33
    /**
34
     * The API Url configured on the SDK Client
35
     * @var string
36
     */
37
    protected $apiURL;
38
39
    /**
40
     * The full token object returned by the Login method
41
     * @var \stdClass
42
     */
43
    protected $token;
44
45
    /**
46
     * Array of OAuth Creds to be used by SDK Client
47
     * @var array
48
     */
49
    protected $credentials;
50
51
    /**
52
     * Token expiration time
53
     * @var
54
     */
55
    protected $expiration;
56
57
    /**
58
     * The list of registered EntryPoints
59
     * @var array
60
     */
61
    protected $entryPoints = array();
62
63
    public function __construct($server = '',array $credentials = array()){
64
        if (!empty($server)) {
65
            $this->setServer($server);
66
        }
67
        if (!empty($credentials)){
68
            $this->setCredentials($credentials);
69
        }
70
        $this->registerSDKEntryPoints();
71
    }
72
73
    /**
74
     * @inheritdoc
75
     */
76
    public function setServer($server) {
77
        $this->server = $server;
78
        $this->apiURL = Helpers::configureAPIURL($this->server);
79
        return $this;
80
    }
81
82
    /**
83
     * @inheritdoc
84
     */
85
    public function getAPIUrl() {
86
        return $this->apiURL;
87
    }
88
89
    /**
90
     * @inheritdoc
91
     * Retrieves stored token based on passed in Credentials
92
     */
93
    public function setCredentials(array $credentials){
94
        $this->credentials = $credentials;
95
        $token = static::getStoredToken($this->credentials['client_id']);
96
        if (!empty($token)){
97
            $this->setToken($token);
98
        }
99
        return $this;
100
    }
101
102
    /**
103
     * @inheritdoc
104
     */
105
    public function setToken(\stdClass $token){
106
        $this->token = $token;
107
        $this->expiration = time()+$token->expires_in;
108
        return $this;
109
    }
110
111
    /**
112
     * @inheritdoc
113
     */
114
    public function getToken(){
115
        return $this->token;
116
    }
117
118
    /**
119
     * @inheritdoc
120
     */
121
    public function getCredentials(){
122
        return $this->credentials;
123
    }
124
125
    /**
126
     * @inheritdoc
127
     */
128
    public function getServer() {
129
        return $this->server;
130
    }
131
132
    /**
133
     * @inheritdoc
134
     */
135
    public function authenticated(){
136
        return time() < $this->expiration;
137
    }
138
139
    /**
140
     * Register the defined EntryPoints in SDK, located in src/EntryPoint/registry.php file
141
     * @throws EntryPointException
142
     */
143
    protected function registerSDKEntryPoints(){
144
        $entryPoints = Helpers::getSDKEntryPointRegistry();
145
        foreach ($entryPoints as $funcName => $className){
146
            $this->registerEntryPoint($funcName, $className);
147
        }
148
    }
149
150
    /**
151
     * @param $funcName
152
     * @param $className
153
     * @return bool
154
     * @throws EntryPointException
155
     */
156
    public function registerEntryPoint($funcName, $className){
157
        $implements = class_implements($className);
158
        if (is_array($implements) && in_array('SugarAPI\SDK\EntryPoint\Interfaces\EPInterface',$implements)){
159
            $this->entryPoints[$funcName] = $className;
160
        }else{
161
            throw new EntryPointException($className,'Class must extend SugarAPI\SDK\EntryPoint\Interfaces\EPInterface');
162
        }
163
        return $this;
164
    }
165
166
    /**
167
     * Generates the EntryPoint objects based on a Method name that was called
168
     * @param $name
169
     * @param $params
170
     * @return mixed
171
     * @throws EntryPointException
172
     */
173
    public function __call($name, $params){
174
        if (array_key_exists($name, $this->entryPoints)){
175
            $Class = $this->entryPoints[$name];
176
            $EntryPoint = new $Class($this->apiURL, $params);
177
178
            if ($EntryPoint->authRequired()){
179
                if (isset($this->token) && $this->authenticated()) {
180
                    $EntryPoint->setAuth($this->getToken()->access_token);
181
                }
182
            }
183
            return $EntryPoint;
184
        }else{
185
            throw new EntryPointException($name,'Unregistered EntryPoint');
186
        }
187
    }
188
189
    /**
190
     * @inheritdoc
191
     * @throws AuthenticationException - When Login request fails
192
     */
193 View Code Duplication
    public function login() {
0 ignored issues
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...
194
        $EP = new OAuth2Token($this->apiURL);
195
        $response = $EP->execute($this->credentials)->getResponse();
196
        if ($response->getStatus()=='200'){
197
            $this->setToken($response->getBody(false));
0 ignored issues
show
Unused Code introduced by
The call to AbstractResponse::getBody() has too many arguments starting with false.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
Documentation introduced by
$response->getBody(false) is of type string, but the function expects a object<stdClass>.

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...
198
            static::storeToken($this->token,$this->credentials['client_id']);
199
        } else {
200
            $error = $response->getBody();
201
            throw new AuthenticationException("Login Response [".$error['error']."] ".$error['error_message']);
202
        }
203
        return $this;
204
    }
205
206
    /**
207
     * @inheritdoc
208
     * @throws AuthenticationException - When Refresh Request fails
209
     */
210
    public function refreshToken(){
211
        $refreshOptions = array(
212
            'client_id' => $this->credentials->client_id,
213
            'client_secret' => $this->credentials->client_secret,
214
            'refresh_token' => $this->credentials->refresh_token
215
        );
216
        $EP = new RefreshToken($this->apiURL);
217
        $response = $EP->execute($refreshOptions)->getResponse();
218
        if ($response->getStatus()=='200'){
219
            $this->setToken($response->getBody(false));
0 ignored issues
show
Unused Code introduced by
The call to AbstractResponse::getBody() has too many arguments starting with false.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
Documentation introduced by
$response->getBody(false) is of type string, but the function expects a object<stdClass>.

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...
220
            static::storeToken($this->token,$this->credentials['client_id']);
221
        }else{
222
            $error = $response->getBody();
223
            throw new AuthenticationException("Refresh Response [".$error['error']."] ".$error['error_message']);
224
        }
225
        return $this;
226
    }
227
228
    /**
229
     * @inheritdoc
230
     * @throws AuthenticationException - When logout request fails
231
     */
232 View Code Duplication
    public function logout(){
0 ignored issues
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...
233
        if ($this->authenticated()){
234
            $EP = new OAuth2Logout($this->apiURL);
235
            $response = $EP->execute()->getResponse();
236
            if ($response->getStatus()=='200'){
237
                unset($this->token);
238
                static::removeStoredToken($this->credentials['client_id']);
239
            }else{
240
                $error = $response->getBody();
241
                throw new AuthenticationException("Logout Response [".$error['error']."] ".$error['message']);
242
            }
243
        }
244
        return $this;
245
    }
246
247
    /**
248
     * @inheritdoc
249
     */
250
    public static function storeToken($token, $client_id) {
251
        static::$_STORED_TOKENS[$client_id] = $token;
252
        return true;
253
    }
254
255
    /**
256
     * @inheritdoc
257
     */
258
    public static function getStoredToken($client_id) {
259
        return static::$_STORED_TOKENS[$client_id];
260
    }
261
262
    /**
263
     * @inheritdoc
264
     */
265
    public static function removeStoredToken($client_id) {
266
        unset(static::$_STORED_TOKENS[$client_id]);
267
        return true;
268
    }
269
270
}