Passed
Branch master (d207f1)
by Robert
03:30
created

LiveEngageLaravel   D

Complexity

Total Complexity 58

Size/Duplication

Total Lines 402
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 58
dl 0
loc 402
ccs 0
cts 192
cp 0
rs 4.8387
c 0
b 0
f 0

21 Methods

Rating   Name   Duplication   Size   Complexity  
A __get() 0 3 1
A __construct() 0 5 2
B login() 0 25 1
A skills() 0 5 1
A get() 0 3 1
A retry() 0 5 1
B requestV2() 0 22 4
A limit() 0 5 1
A nonInteractive() 0 4 1
C history() 0 50 10
A domain() 0 9 2
B retrieveMsgHistory() 0 23 4
A key() 0 5 1
C requestV1() 0 51 7
C messagingHistory() 0 50 10
A __set() 0 3 1
A account() 0 5 1
A visitor() 0 12 2
A getAgentStatus() 0 21 3
A active() 0 4 1
B retrieveHistory() 0 24 3

How to fix   Complexity   

Complex Class

Complex classes like LiveEngageLaravel 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 LiveEngageLaravel, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace LivePersonInc\LiveEngageLaravel;
4
5
use Carbon\Carbon;
6
use GuzzleHttp\Client;
7
use GuzzleHttp\HandlerStack;
8
use GuzzleHttp\Subscriber\Oauth\Oauth1;
9
use LivePersonInc\LiveEngageLaravel\Models\Info;
10
use LivePersonInc\LiveEngageLaravel\Models\MessagingInfo;
11
use LivePersonInc\LiveEngageLaravel\Models\Payload;
12
use LivePersonInc\LiveEngageLaravel\Models\Visitor;
13
use LivePersonInc\LiveEngageLaravel\Models\Agent;
14
use LivePersonInc\LiveEngageLaravel\Models\Campaign;
15
use LivePersonInc\LiveEngageLaravel\Models\Engagement;
16
use LivePersonInc\LiveEngageLaravel\Models\Conversation;
17
use LivePersonInc\LiveEngageLaravel\Collections\EngagementHistory;
18
use LivePersonInc\LiveEngageLaravel\Collections\Humans;
19
use LivePersonInc\LiveEngageLaravel\Exceptions\LiveEngageException;
20
use LivePersonInc\LiveEngageLaravel\Collections\ConversationHistory;
21
22
class LiveEngageLaravel
23
{
24
	private $account = false;
25
	private $results = [];
26
	private $skills = [];
27
	private $next = false;
28
	private $prev = false;
29
	private $start;
30
	private $end;
31
	private $config = 'services.liveperson.default';
32
	private $version = '1.0';
33
	private $history_limit = 50;
34
	private $history = false;
35
	private $context = 'interactionHistoryRecords';
36
	private $interactive = true;
37
	private $ended = true;
38
	private $bearer = false;
39
40
	private $domain = false;
41
42
	private $retry_limit = 5;
43
	private $retry_counter = 0;
44
45
	public function __get($attribute)
46
	{
47
		return $this->$attribute;
48
	}
49
50
	public function __set($attribute, $value)
51
	{
52
		return $this->$attribute = $value;
53
	}
54
55
	public function __construct()
56
	{
57
		$this->account = config("{$this->config}.account");
58
		//$this->domain = config("{$this->config}.domain");
59
		$this->version = config("{$this->config}.version") ?: $this->version;
60
	}
61
62
	public function key($key = 'default')
63
	{
64
		$this->config = "services.liveperson.$key";
65
66
		return $this;
67
	}
68
	
69
	public function nonInteractive()
70
	{
71
		$this->interactive = false;
72
		return $this;
73
	}
74
	
75
	public function active()
76
	{
77
		$this->ended = false;
78
		return $this;
79
	}
80
81
	public function limit($limit)
82
	{
83
		$this->history_limit = $limit;
84
85
		return $this;
86
	}
87
88
	public function skills($skills)
89
	{
90
		$this->skills = $skills;
91
92
		return $this;
93
	}
94
95
	public function retry($limit)
96
	{
97
		$this->retry_limit = $limit;
98
99
		return $this;
100
	}
101
102
	public function get()
103
	{
104
		return $this->results;
105
	}
106
107
	public function account($accountid)
108
	{
109
		$this->account = $accountid;
110
111
		return $this;
112
	}
113
114
	public function domain($service)
115
	{
116
		$response = $this->requestV1("https://api.liveperson.net/api/account/{$this->account}/service/{$service}/baseURI.json?version={$this->version}", 'GET');
117
		if (is_a($response, 'Exception')) {
0 ignored issues
show
Bug introduced by
It seems like $response can also be of type mixed; however, parameter $object of is_a() does only seem to accept object|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

117
		if (is_a(/** @scrutinizer ignore-type */ $response, 'Exception')) {
Loading history...
118
			throw new \Exception('Unable to get LivePerson account domain', 101);
119
		} else {
120
			$this->domain = $response->baseURI;
121
122
			return $this;
123
		}
124
	}
125
126
	public function visitor($visitorID, $sessionID, $setData = false)
127
	{
128
		$this->domain('smt');
129
130
		if ($setData) {
131
			$url = "https://{$this->domain}/api/account/{$this->account}/monitoring/visitors/{$visitorID}/visits/current/events?v=1&sid={$sessionID}";
132
133
			return $this->requestV1($url, 'POST', $setData);
134
		} else {
135
			$url = "https://{$this->domain}/api/account/{$this->account}/monitoring/visitors/{$visitorID}/visits/current/state?v=1&sid={$sessionID}";
136
137
			return $this->requestV1($url, 'GET');
138
		}
139
	}
140
141
	final public function retrieveHistory(Carbon $start, Carbon $end, $url = false)
142
	{
143
		$this->domain('engHistDomain');
144
145
		$url = $url ?: "https://{$this->domain}/interaction_history/api/account/{$this->account}/interactions/search?limit={$this->history_limit}&offset=0";
146
147
		$start_str = $start->toW3cString();
148
		$end_str = $end->toW3cString();
149
150
		$data = [
151
			'interactive' => $this->interactive,
152
			'ended' => $this->ended,
153
			'start' => [
154
				'from' => strtotime($start_str).'000',
155
				'to' => strtotime($end_str).'000',
156
			],
157
		];
158
		if (count($this->skills)) {
159
			$data['skillIds'] = $this->skills;
160
		}
161
162
		$data = new Payload($data);
163
164
		return $this->requestV1($url, 'POST', $data);
165
	}
166
167
	final public function retrieveMsgHistory(Carbon $start, Carbon $end, $url = false)
168
	{
169
		$this->domain('msgHist');
170
171
		$url = $url ?: "https://{$this->domain}/messaging_history/api/account/{$this->account}/conversations/search?limit={$this->history_limit}&offset=0&sort=start:desc";
172
173
		$start_str = $start->toW3cString();
174
		$end_str = $end->toW3cString();
175
176
		$data = [
177
			'status' => $this->ended ? ['CLOSE'] : ['OPEN'],
178
			'start' => [
179
				'from' => strtotime($start_str).'000',
180
				'to' => strtotime($end_str).'000',
181
			],
182
		];
183
		if (count($this->skills)) {
184
			$data['skillIds'] = $this->skills;
185
		}
186
187
		$data = new Payload($data);
188
189
		return $this->requestV1($url, 'POST', $data);
190
	}
191
	
192
	public function getAgentStatus($skills)
193
	{
194
		$skills = is_array($skills) ? $skills : [$skills];
195
	
196
		$this->domain('msgHist');
197
		
198
		$url = "https://{$this->domain}/messaging_history/api/account/{$this->account}/agent-view/status";
199
		
200
		$data['skillIds'] = $skills;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$data was never initialized. Although not strictly required by PHP, it is generally a good practice to add $data = array(); before regardless.
Loading history...
201
		
202
		$response = $this->requestV1($url, 'POST', $data);
203
		$agents = [];
204
		
205
		foreach ($response->agentStatusRecords as $agent) {
206
			$agents[] = new Agent((array) $agent);
207
		}
208
		
209
		$collection = new Humans($agents);
210
		$collection->metaData = $response->_metadata;
0 ignored issues
show
Bug introduced by
The property metaData does not seem to exist on LivePersonInc\LiveEngageLaravel\Collections\Humans.
Loading history...
211
		
212
		return $collection;
213
		
214
	}
215
216
	public function messagingHistory(Carbon $start = null, Carbon $end = null)
217
	{
218
		$this->retry_counter = 0;
219
220
		$start = $start ?: (new Carbon())->today();
221
		$end = $end ?: (new Carbon())->today()->addHours(23)->addMinutes(59);
222
223
		$this->start = $start;
224
		$this->end = $end;
225
		
226
		$results_object = $this->retrieveMsgHistory($start, $end);
227
228
		if (is_object($results_object)) {
229
230
			$results = $results_object->conversationHistoryRecords;
231
			if (property_exists($results_object->_metadata, 'next')) {
232
				$this->next = $results_object->_metadata->next->href;
233
			} else {
234
				$this->next = false;
235
			}
236
			if (property_exists($results_object->_metadata, 'prev')) {
237
				$this->prev = $results_object->_metadata->prev->href;
238
			} else {
239
				$this->prev = false;
240
			}
241
	
242
			$history = [];
243
			foreach ($results as $item) {
244
				if (property_exists($item, 'info')) {
245
					$item->info = new MessagingInfo((array) $item->info);
246
				}
247
	
248
				if (property_exists($item, 'visitorInfo')) {
249
					$item->visitorInfo = new Visitor((array) $item->visitorInfo);
250
				}
251
	
252
				if (property_exists($item, 'campaign')) {
253
					$item->campaign = new Campaign((array) $item->campaign);
254
				}
255
	
256
				$history[] = new Conversation((array) $item);
257
			}
258
	
259
			$collection = new ConversationHistory($history, $this);
260
			$collection->metaData = $results_object->_metadata;
0 ignored issues
show
Bug introduced by
The property metaData does not seem to exist on LivePersonInc\LiveEngage...ons\ConversationHistory.
Loading history...
261
			
262
			return $collection;
263
			
264
		} else {
265
			return false;
266
		}
267
	}
268
269
	public function history(Carbon $start = null, Carbon $end = null)
270
	{
271
		$this->retry_counter = 0;
272
273
		$start = $start ?: (new Carbon())->today();
274
		$end = $end ?: (new Carbon())->today()->addHours(23)->addMinutes(59);
275
276
		$this->start = $start;
277
		$this->end = $end;
278
279
		$results_object = $this->retrieveHistory($start, $end);
280
		
281
		if (is_object($results_object)) {
282
		
283
			$results = $results_object->interactionHistoryRecords;
284
			if (property_exists($results_object->_metadata, 'next')) {
285
				$this->next = $results_object->_metadata->next->href;
286
			} else {
287
				//$this->next = false;
288
			}
289
			if (property_exists($results_object->_metadata, 'prev')) {
290
				$this->prev = $results_object->_metadata->prev->href;
291
			} else {
292
				//$this->prev = false;
293
			}
294
	
295
			$history = [];
296
			foreach ($results as $item) {
297
				if (property_exists($item, 'info')) {
298
					$item->info = new Info((array) $item->info);
299
				}
300
	
301
				if (property_exists($item, 'visitorInfo')) {
302
					$item->visitorInfo = new Visitor((array) $item->visitorInfo);
303
				}
304
	
305
				if (property_exists($item, 'campaign')) {
306
					$item->campaign = new Campaign((array) $item->campaign);
307
				}
308
	
309
				$history[] = new Engagement((array) $item);
310
			}
311
			
312
			$collection = new EngagementHistory($history, $this);
313
			$collection->metaData = $results_object->_metadata;
0 ignored issues
show
Bug introduced by
The property metaData does not seem to exist on LivePersonInc\LiveEngage...tions\EngagementHistory.
Loading history...
314
			
315
			return $collection;
316
			
317
		} else {
318
			return false;
319
		}
320
	}
321
	
322
	public function login()
323
	{
324
		$this->domain('agentVep');
325
		
326
		$consumer_key = config("{$this->config}.key");
327
		$consumer_secret = config("{$this->config}.secret");
328
		$token = config("{$this->config}.token");
329
		$secret = config("{$this->config}.token_secret");
330
		$username = config("{$this->config}.user_name");
331
		
332
		$auth = [
333
			'username'		  => $username,
334
			'appKey'			=> $consumer_key,
335
			'secret'			=> $consumer_secret,
336
			'accessToken'		=> $token,
337
			'accessTokenSecret' => $secret,
338
		];
339
		
340
		$url = "https://{$this->domain}/api/account/{$this->account}/login?v=1.3";
341
		
342
		$response = $this->requestV1($url, 'POST', $auth);
343
		
344
		$this->bearer = $response->bearer;
345
		
346
		return $this;
347
	}
348
	
349
	private function requestV2($url, $method, $payload = false)
0 ignored issues
show
Unused Code introduced by
The method requestV2() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
350
	{
351
		if (!$this->bearer) $this->login();
352
		
353
		$client = new Client();
354
		$args = [
355
			'headers' => [
356
				'Authorization' => $this->bearer
357
			]
358
		];
359
		
360
		if ($payload !== false) {
361
			$args['body'] = json_encode($payload);
362
		}
363
		
364
		try {
365
			$res = $client->request($method, $url, $args);
366
		} catch (\Exception $e) {
367
			throw $e;
368
		} 
369
		
370
		return json_decode($res->getBody());
371
	}
372
373
	private function requestV1($url, $method, $payload = false)
374
	{
375
		$consumer_key = config("{$this->config}.key");
376
		$consumer_secret = config("{$this->config}.secret");
377
		$token = config("{$this->config}.token");
378
		$secret = config("{$this->config}.token_secret");
379
380
		$stack = HandlerStack::create();
381
		$auth = new Oauth1([
382
			'consumer_key'	=> $consumer_key,
383
			'consumer_secret' => $consumer_secret,
384
			'token'		   => $token,
385
			'token_secret'	=> $secret,
386
			'signature_method'=> Oauth1::SIGNATURE_METHOD_HMAC,
387
		]);
388
		$stack->push($auth);
389
390
		$client = new Client([
391
			'handler' => $stack,
392
		]);
393
394
		$args = [
395
			'auth' => 'oauth',
396
			'headers' => [
397
				'content-type' => 'application/json',
398
			],
399
		];
400
401
		if ($payload !== false) {
402
			$args['body'] = json_encode($payload);
403
		}
404
405
		try {
406
			$res = $client->request($method, $url, $args);
407
408
			$response = json_decode($res->getBody());
409
		} catch (\GuzzleHttp\Exception\ConnectException $connection) {
410
			throw $connection;
411
		} catch (\GuzzleHttp\Exception\ClientException $clientException) {
412
			throw $clientException;
413
		} catch (\Exception $e) {
414
			if ($this->retry_counter < $this->retry_limit || $this->retry_limit == -1) {
415
				usleep(1500);
416
				$this->retry_counter++;
417
				$response = $this->requestV1($url, $payload);
418
			} else {
419
				throw new LiveEngageException("Retry limit has been exceeded ($this->retry_limit)", 100);
420
			}
421
		}
422
423
		return $response;
424
	}
425
}
426