Passed
Push — master ( f9a48a...945dc8 )
by Mike
03:01
created

AbstractEntryPoint::execute()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 12
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 3

Importance

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