Completed
Push — master ( 14e52c...c7c88d )
by Mike
02:36
created

SugarAPI::getToken()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 3
rs 10
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
namespace SugarAPI\SDK;
4
5
use SugarAPI\SDK\Exception\AuthenticationException;
6
use SugarAPI\SDK\Exception\SDKException;
7
8
class SugarAPI {
9
10
    const API_URL = '/rest/v10/';
11
12
    /**
13
     * Default Settings for SugarAPI Object.
14
     * Includes Default Instance, and Default Authentication Ooptions
15
     * Example:
16
     *      array(
17
     *          'instance' => 'localhost',
18
     *          'auth' => array(
19
     *              'username' => 'admin',
20
     *              'password' => 'password',
21
     *              'client_id' => 'custom_client',
22
     *              'client_secret' => 's3cr3t',
23
     *              'platform' => 'custom_app'
24
     *          )
25
     *      );
26
     * @var array
27
     */
28
    protected static $_DEFAULTS = array();
29
30
    /**
31
     * The configured instance
32
     * @var
33
     */
34
    protected $instance;
35
36
    /**
37
     * The configured Rest v10 URL
38
     * @var
39
     */
40
    protected $url;
41
42
    /**
43
     * The configured Authentication options
44
     * @var array
45
     */
46
    protected $authOptions = array(
47
        'username' => '',
48
        'password' => '',
49
        'client_id' => '',
50
        'client_secret' => '',
51
        'platform' => ''
52
    );
53
54
    /**
55
     * The authentication token, after successful login to SugarAPI
56
     * @var
57
     */
58
    protected $authToken;
59
60
    /**
61
     * The time in which Auth Token expires, and needs to be refreshed
62
     * @var
63
     */
64
    protected $authExpiration;
65
66
    /**
67
     * The list of registered EntryPoints
68
     * @var array
69
     */
70
    private $entryPoints = array();
71
72
    public function __construct($instance = '', array $authOptions = array()){
73
        $this->loadDefaults();
74
        if (!empty($instance)){
75
            $this->setInstance($instance);
76
        }
77
        if (!empty($authOptions)){
78
            $this->setAuthOptions($authOptions);
79
        }
80
        $this->registerSDKEntryPoints();
81
    }
82
83
    /**
84
     * Configure the static property $_DEFAULTS with settings from defaults.php
85
     */
86
    protected function loadDefaults(){
87
        if (empty(static::$_DEFAULTS)) {
88
            include __DIR__ . DIRECTORY_SEPARATOR . 'defaults.php';
89
            if (isset($defaults)) {
0 ignored issues
show
Bug introduced by
The variable $defaults seems to never exist, and therefore isset should always return false. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
90
                static::$_DEFAULTS = $defaults;
91
            }
92
        }
93
        if (isset(static::$_DEFAULTS['instance'])){
94
            $this->setInstance(static::$_DEFAULTS['instance']);
95
        }
96
        if (isset(static::$_DEFAULTS['auth']) && is_array(static::$_DEFAULTS['auth'])){
97
            $this->setAuthOptions(static::$_DEFAULTS['auth']);
98
        }
99
    }
100
101
    /**
102
     * Configure the Authentication Options being used by SugarAPI Object
103
     * @param array $options
104
     */
105
    public function setAuthOptions(array $options){
106
        foreach ($this->authOptions as $key => $value){
107
            if (isset($options[$key])){
108
                $this->authOptions[$key] = $options[$key];
109
            }
110
        }
111
    }
112
113
    /**
114
     * Register the defined EntryPoints in SDK, located in src/EntryPoint/registry.php file
115
     * @throws SDKException
116
     */
117
    protected function registerSDKEntryPoints(){
118
        require __DIR__.DIRECTORY_SEPARATOR.'EntryPoint'.DIRECTORY_SEPARATOR.'registry.php';
119
        foreach ($entryPoints as $funcName => $className){
0 ignored issues
show
Bug introduced by
The variable $entryPoints does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
120
            $className = "SugarAPI\\SDK\\EntryPoint\\".$className;
121
            $this->registerEntryPoint($funcName, $className);
122
        }
123
    }
124
125
    /**
126
     * Register an EntryPoint method on the SugarAPI object.
127
     * Allows for loading custom EntryPoints, so long as custom EntryPoints are autoloaded accordingly
128
     * @param $funcName - name of Method to be called on SugarAPI Object
129
     * @param $className - full name of EntryPoint Class that will be utilized
130
     * @throws SDKException
131
     */
132
    public function registerEntryPoint($funcName, $className){
133
        if (isset($this->entryPoints[$funcName])){
134
            throw new SDKException('SDK method already defined. Method '.$funcName.' references Class '.$className);
135
        }
136
        $this->entryPoints[$funcName] = $className;
137
    }
138
139
    /**
140
     * Generates the EntryPoint objects based on the Method name that was called
141
     * @param $name
142
     * @param $params
143
     * @return mixed
144
     * @throws AuthenticationException
145
     * @throws SDKException
146
     */
147
    public function __call($name, $params){
148
        if (array_key_exists($name, $this->entryPoints)){
149
            $Class = $this->entryPoints[$name];
150
            $EntryPoint = new $Class($this->url, $params);
151
152
            if ($EntryPoint->authRequired()){
153
                if (isset($this->authToken)){
154
                    if ($this->authExpired()){
155
                        $this->refreshAuth();
156
                    }
157
                    $EntryPoint->configureAuth($this->authToken->access_token);
158
                }else{
159
                    throw new AuthenticationException('Authentication is required for EntryPoint ['.$name.'].');
160
                }
161
            }
162
            return $EntryPoint;
163
        }else{
164
            throw new SDKException('Method '.$name.', is not a registered method of the SugarAPI SDK');
165
        }
166
    }
167
168
    /**
169
     * Login to the configured SugarCRM instance, and stored the Auth Token
170
     * @throws AuthenticationException
171
     */
172
    public function login(){
173
        if (empty($this->authOptions['username']) || empty($this->authOptions['password'])){
174
            throw new AuthenticationException("Username or Password was not provided.");
175
        }
176
        $response = $this->oauth2Token()->data($this->authOptions)->execute()->getResponse();
0 ignored issues
show
Documentation Bug introduced by
The method oauth2Token does not exist on object<SugarAPI\SDK\SugarAPI>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
177
        if ($response->getStatus()=='200'){
178
            $this->setAuthToken($response->getBody());
179
        } else{
180
            throw new AuthenticationException($response->getBody());
181
        }
182
    }
183
184
    /**
185
     * Set the current AuthToken and Auth Expiration properties
186
     * @param stdObject $token
187
     */
188
    protected function setAuthToken($token){
189
        $this->authToken = $token;
190
        $this->authExpiration = time()+$token->expires_in;
191
    }
192
193
    /**
194
     * Refresh Auth Token to further API use
195
     */
196
    public function refreshAuth(){
197
        $refreshOptions = array(
198
            'client_id' => $this->authOptions->client_id,
199
            'client_secret' => $this->authOptions->client_secret,
200
            'refresh_token' => $this->authOptions->refresh_token
201
        );
202
        $response = $this->oauth2Refresh()->data($refreshOptions)->execute()->getResponse();
0 ignored issues
show
Documentation Bug introduced by
The method oauth2Refresh does not exist on object<SugarAPI\SDK\SugarAPI>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
203
        if ($response->getStatus()=='200'){
204
            $this->setAuthToken($response->getBody());
205
        } else{
206
            throw new AuthenticationException($response->getBody());
207
        }
208
    }
209
210
    /**
211
     * Check if current access token is expired
212
     * @return bool
213
     */
214
    public function authExpired(){
215
        return time() >= $this->authExpiration;
216
    }
217
218
    /**
219
     * Force Logout of SugarAPI Object
220
     */
221
    public function logout(){
222
       if (!empty($this->authToken)){
223
           $response = $this->oauth2Logout()->execute()->getResponse();
0 ignored issues
show
Bug introduced by
The method oauth2Logout() does not exist on SugarAPI\SDK\SugarAPI. Did you maybe mean logout()?

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...
224
           if ($response->getStatus()=='200'){
225
               unset($this->authToken);
226
               unset($this->authExpiration);
227
           }
228
       }
229
    }
230
231
    /**
232
     * Configure the instance that the SugarAPI object will be communicating with
233
     * @param $instance
234
     */
235
    public function setInstance($instance){
236
        if (strpos("http", $instance)===FALSE){
237
            $instance = "http://".$instance;
238
        }
239
        if (strpos("rest/v10", $instance)!==FALSE){
240
            $instance = str_replace("rest/v10", "", $instance);
241
        }
242
        $this->instance = $instance;
243
        $this->url = rtrim($this->instance, "/").self::API_URL;
244
    }
245
246
    /**
247
     * Get the configured Rest v10 URL
248
     * @return mixed
249
     */
250
    public function getURL(){
251
        return $this->url;
252
    }
253
254
    /**
255
     * Get the Authentication Token
256
     * @return mixed
257
     */
258
    public function getToken(){
259
        return $this->authToken;
260
    }
261
262
    /**
263
     * Get the configured Authentication Options
264
     * @return array
265
     */
266
    public function getAuthOptions(){
267
        return $this->authOptions;
268
    }
269
}