Completed
Push — master ( 3656be...0c0759 )
by Mike
03:02
created

AbstractEntryPoint::setData()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 3
nc 1
nop 1
1
<?php
2
3
namespace SugarAPI\SDK\EntryPoint\Abstracts;
4
5
6
use SugarAPI\SDK\EntryPoint\Interfaces\EPInterface;
7
use SugarAPI\SDK\Exception\EntryPoint\InvalidRequestException;
8
use SugarAPI\SDK\Exception\EntryPoint\InvalidURLException;
9
use SugarAPI\SDK\Exception\EntryPoint\RequiredDataException;
10
use SugarAPI\SDK\Exception\EntryPoint\RequiredOptionsException;
11
use SugarAPI\SDK\Response\Interfaces\ResponseInterface;
12
use SugarAPI\SDK\Request\Interfaces\RequestInterface;
13
14
/**
15
 * Class AbstractEntryPoint
16
 * @package SugarAPI\SDK\EntryPoint\Abstracts
17
 * @method EPInterface ping()
18
 * @method EPInterface getRecord(string $module = '')
19
 * @method EPInterface getAttachment(string $module = '',string $record_id = '')
20
 * @method EPInterface getChangeLog(string $module = '',string $record_id = '')
21
 * @method EPInterface filterRelated(string $module = '')
22
 * @method EPInterface getRelated(string $module = '',string $record_id = '',string $relationship = '',string $related_id = '')
23
 * @method EPInterface me()
24
 * @method EPInterface search()
25
 * @method EPInterface oauth2Token()
26
 * @method EPInterface oauth2Refresh()
27
 * @method EPInterface createRecord()
28
 * @method EPInterface filterRecords()
29
 * @method EPInterface attachFile()
30
 * @method EPInterface oauth2Logout()
31
 * @method EPInterface createRelated()
32
 * @method EPInterface linkRecords()
33
 * @method EPInterface bulk()
34
 * @method EPInterface updateRecord()
35
 * @method EPInterface favorite()
36
 * @method EPInterface deleteRecord()
37
 * @method EPInterface unfavorite()
38
 * @method EPInterface deleteFile()
39
 * @method EPInterface unlinkRecords()
40
 */
41
abstract class AbstractEntryPoint implements EPInterface {
42
43
    /**
44
     * Whether or not Authentication is Required
45
     * @var bool
46
     */
47
    protected $_AUTH_REQUIRED = true;
48
49
    /**
50
     * The URL for the EntryPoint
51
     * - When configuring URL you define URL Parameters with $variables
52
     *      Examples:
53
     *          - Forecasts/$record_id
54
     * - $module Variable is a keyword to place the Module property into the URL
55
     *      Examples:
56
     *          - $module/$record
57
     * - Options property is used to replace variables in the order in which they are passed
58
     *
59
     * @var string
60
     */
61
    protected $_URL;
62
63
    /**
64
     * An array of Required Data properties that should be passed in the Request
65
     * @var array
66
     */
67
    protected $_REQUIRED_DATA = array();
68
69
    /**
70
     * The required type of Data to be given to the EntryPoint. If none, different types can be passed in.
71
     * @var string
72
     */
73
    protected $_DATA_TYPE;
74
75
    /**
76
     * The configured URL for the EntryPoint
77
     * @var string
78
     */
79
    protected $Url;
80
81
    /**
82
     * The initial URL passed into the EntryPoint
83
     * @var
84
     */
85
    protected $baseUrl;
86
87
    /**
88
     * The passed in Options for the EntryPoint
89
     * - If $module variable is used in $_URL static property, then 1st option will be used as Module
90
     * @var array
91
     */
92
    protected $Options = array();
93
94
    /**
95
     * The data being passed to the API EntryPoint
96
     * @var mixed - array||stdClass
97
     */
98
    protected $Data;
99
100
    /**
101
     * The Request Object, used by the EntryPoint to submit the data
102
     * @var RequestInterface
103
     */
104
    protected $Request;
105
106
    /**
107
     * The Response Object, returned by the Request Object
108
     * @var ResponseInterface
109
     */
110
    protected $Response;
111
112
    /**
113
     * Access Token for authentication
114
     * @var string
115
     */
116
    protected $accessToken;
117
118
119
    public function __construct($baseUrl,array $options = array()){
120
        $this->baseUrl = $baseUrl;
121
122
        if (!empty($options)) {
123
            $this->setOptions($options);
124
        }elseif(!$this->requiresOptions()){
125
            $this->configureURL();
126
        }
127
    }
128
129
    /**
130
     * @inheritdoc
131
     */
132
    public function setOptions(array $options){
133
        $this->Options = $options;
134
        $this->configureURL();
135
        return $this;
136
    }
137
138
    /**
139
     * @inheritdoc
140
     * @throws RequiredDataException - When passed in data contains issues
141
     */
142
    public function setData($data){
143
        $this->Data = $data;
144
        return $this;
145
    }
146
147
    /**
148
     * @inheritdoc
149
     */
150
    public function setAuth($accessToken) {
151
        $this->accessToken = $accessToken;
152
        return $this;
153
    }
154
155
    /**
156
     * @inheritdoc
157
     */
158
    public function setUrl($url) {
159
        $this->Url = $url;
160
        return $this;
161
    }
162
163
    /**
164
     * @inheritdoc
165
     */
166
    public function setRequest(RequestInterface $Request) {
167
        $this->Request = $Request;
168
        return $this;
169
    }
170
171
    /**
172
     * @inheritdoc
173
     */
174
    public function setResponse(ResponseInterface $Response) {
175
        $this->Response = $Response;
176
        return $this;
177
    }
178
179
    /**
180
     * @inheritdoc
181
     */
182
    public function getOptions(){
183
        return $this->Options;
184
    }
185
186
    /**
187
     * @inheritdoc
188
     */
189
    public function getData(){
190
        return $this->Data;
191
    }
192
193
    /**
194
     * @inheritdoc
195
     */
196
    public function getUrl(){
197
        return $this->Url;
198
    }
199
200
    /**
201
     * @inheritdoc
202
     */
203
    public function getResponse(){
204
        return $this->Response;
205
    }
206
207
    /**
208
     * @inheritdoc
209
     */
210
    public function getRequest(){
211
        return $this->Request;
212
    }
213
214
    /**
215
     * @inheritdoc
216
     * @param null $data - short form data for EntryPoint, which is configure by configureData method
217
     * @return $this
218
     * @throws InvalidRequestException
219
     * @throws InvalidURLException
220
     */
221
    public function execute($data = NULL){
222
        $data =  ($data === NULL?$this->Data:$data);
223
        $this->configureData($data);
224
        if ($this->verifyOptions() && is_object($this->Request)) {
225
            $this->configureRequest();
226
            $this->Request->send();
227
        }else{
228
            throw new InvalidRequestException(get_called_class(),"Request property not configured");
229
        }
230
        return $this;
231
    }
232
233
    /**
234
     * @inheritdoc
235
     */
236
    public function authRequired() {
237
        return $this->_AUTH_REQUIRED;
238
    }
239
240
    /**
241
     * Verifies URL and Data are setup, then sets them on the Request Object
242
     * @throws InvalidURLException
243
     * @throws RequiredDataException
244
     */
245
    protected function configureRequest(){
246
        if ($this->verifyUrl()) {
247
            $this->Request->setURL($this->Url);
248
        }
249
        if ($this->verifyData() && !empty($this->Data)) {
250
            $this->Request->setBody($this->Data);
251
        }
252
        $this->configureAuth();
253
    }
254
255
    /**
256
     * Configures the authentication header on the Request object
257
     */
258
    protected function configureAuth(){
259
        if ($this->authRequired()) {
260
            $this->Request->addHeader('OAuth-Token', $this->accessToken);
261
        }
262
    }
263
264
    /**
265
     * Configures Data for the EntryPoint. Used mainly as an override function on implemented EntryPoints.
266
     * @var $data
267
     */
268
    protected function configureData($data){
269
        if (!empty($this->_REQUIRED_DATA)&&is_array($data)){
270
            $data = $this->configureDefaultData($data);
271
        }
272
        $this->setData($data);
273
    }
274
275
    /**
276
     * Configure Defaults on a Data array based on the Required Data property
277
     * @param array $data
278
     * @return array
279
     */
280
    protected function configureDefaultData(array $data){
281
        foreach($this->_REQUIRED_DATA as $property => $value){
282
            if (!isset($data[$property]) && $value!==NULL){
283
                $data[$property] = $value;
284
            }
285
        }
286
        return $data;
287
    }
288
289
    /**
290
     * Configures the URL, by updating any variable placeholders in the URL property on the EntryPoint
291
     * - Replaces $module with $this->Module
292
     * - Replaces all other variables starting with $, with options in the order they were given
293
     */
294
    protected function configureURL(){
295
        $url = $this->_URL;
296
        if ($this->requiresOptions()) {
297
            $urlParts = explode("/", $this->_URL);
298
            $o = 0;
299
            foreach ($urlParts as $key => $part) {
300
                if (strpos($part, "$") !== FALSE) {
301
                    if (isset($this->Options[$o])) {
302
                        $urlParts[$key] = $this->Options[$o];
303
                        $o++;
304
                    }
305
                }
306
            }
307
            $url = implode($urlParts,"/");
308
        }
309
        $url = $this->baseUrl.$url;
310
        $this->setUrl($url);
311
    }
312
313
    /**
314
     * Verify if URL is configured properly
315
     * @return bool
316
     * @throws InvalidURLException
317
     */
318
    protected function verifyUrl(){
319
        $UrlArray = explode("?",$this->Url);
320
        if (strpos($UrlArray[0],"$") !== FALSE){
321
            throw new InvalidURLException(get_called_class(),"Configured URL is ".$this->Url);
322
        }
323
        return true;
324
    }
325
326
    /**
327
     * Verify URL variables have been removed, and that valid number of options were passed.
328
     * @return bool
329
     * @throws RequiredOptionsException
330
     */
331
    protected function verifyOptions(){
332
        $urlVarCount = substr_count($this->_URL,"$");
333
        $optionCount = 0;
334
        $optionCount += count($this->Options);
335
        if ($urlVarCount>$optionCount){
336
            throw new RequiredOptionsException(get_called_class(),"URL requires $urlVarCount options, only $optionCount provided.");
337
        }
338
        return true;
339
    }
340
341
    /**
342
     * Validate the Data property on the EntryPoint
343
     * @return bool
344
     * @throws RequiredDataException
345
     */
346
    protected function verifyData(){
347
        if (isset($this->_DATA_TYPE)||!empty($this->_DATA_TYPE)) {
348
            $this->verifyDataType();
349
        }
350
        if (!empty($this->_REQUIRED_DATA)){
351
            $this->verifyRequiredData();
352
        }
353
        return true;
354
    }
355
356
    /**
357
     * Validate DataType on the EntryPoint object
358
     * @return bool
359
     * @throws RequiredDataException
360
     */
361
    protected function verifyDataType(){
362
        if (gettype($this->Data) !== $this->_DATA_TYPE) {
363
            throw new RequiredDataException(get_called_class(),"Valid DataType is {$this->_DATA_TYPE}");
364
        }
365
        return true;
366
    }
367
368
    /**
369
     * Validate Required Data for the EntryPoint
370
     * @return bool
371
     * @throws RequiredDataException
372
     */
373
    protected function verifyRequiredData(){
374
        $errors = array();
375
        foreach($this->_REQUIRED_DATA as $property => $defaultValue){
376
            if (!isset($this->Data[$property])){
377
                $errors[] = $property;
378
            }
379
        }
380
        if (count($errors)>0){
381
            throw new RequiredDataException(get_called_class(),"Missing data for ".implode(",",$errors));
382
        }
383
        return true;
384
    }
385
386
    /**
387
     * Checks if EntryPoint URL contains requires Options
388
     * @return bool
389
     */
390
    protected function requiresOptions(){
391
        return strpos($this->_URL,"$") === FALSE?FALSE:TRUE;
392
    }
393
394
}