GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( a33860...8fdd51 )
by Jorge
7s
created

Analytics::getParameter()   B

Complexity

Conditions 6
Paths 8

Size

Total Lines 37
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 37
rs 8.439
cc 6
eloc 17
nc 8
nop 2
1
<?php
2
3
namespace TheIconic\Tracking\GoogleAnalytics;
4
5
use TheIconic\Tracking\GoogleAnalytics\Parameters\SingleParameter;
6
use TheIconic\Tracking\GoogleAnalytics\Parameters\CompoundParameterCollection;
7
use TheIconic\Tracking\GoogleAnalytics\Network\HttpClient;
8
use TheIconic\Tracking\GoogleAnalytics\Network\PrepareUrl;
9
use TheIconic\Tracking\GoogleAnalytics\Exception\InvalidPayloadDataException;
10
11
/**
12
 * Class Analytics
13
 *
14
 * The main interface for the clients, it relies heavily in magic methods exposing
15
 * an interface with method tags.
16
 *
17
 * General
18
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setProtocolVersion($value)
19
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setTrackingId($value)
20
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setAnonymizeIp($value)
21
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setDataSource($value)
22
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setQueueTime($value)
23
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setCacheBuster($value)
24
 *
25
 * User
26
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setClientId($value)
27
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setUserId($value)
28
 *
29
 * Session
30
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setSessionControl($value)
31
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setIpOverride($value)
32
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setUserAgentOverride($value)
33
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setGeographicalOverride($value)
34
 *
35
 * Traffic Sources
36
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setDocumentReferrer($value)
37
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setCampaignName($value)
38
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setCampaignSource($value)
39
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setCampaignMedium($value)
40
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setCampaignKeyword($value)
41
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setCampaignContent($value)
42
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setCampaignId($value)
43
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setGoogleAdwordsId($value)
44
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setGoogleDisplayAdsId($value)
45
 *
46
 * System Info
47
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setScreenResolution($value)
48
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setViewportSize($value)
49
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setDocumentEncoding($value)
50
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setScreenColors($value)
51
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setUserLanguage($value)
52
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setJavaEnabled($value)
53
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setFlashVersion($value)
54
 *
55
 * Hit
56
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setHitType($value)
57
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setNonInteractionHit($value)
58
 * @method \TheIconic\Tracking\GoogleAnalytics\AnalyticsResponse sendPageview()
59
 * @method \TheIconic\Tracking\GoogleAnalytics\AnalyticsResponse sendEvent()
60
 * @method \TheIconic\Tracking\GoogleAnalytics\AnalyticsResponse sendScreenview()
61
 * @method \TheIconic\Tracking\GoogleAnalytics\AnalyticsResponse sendTransaction()
62
 * @method \TheIconic\Tracking\GoogleAnalytics\AnalyticsResponse sendItem()
63
 * @method \TheIconic\Tracking\GoogleAnalytics\AnalyticsResponse sendSocial()
64
 * @method \TheIconic\Tracking\GoogleAnalytics\AnalyticsResponse sendException()
65
 * @method \TheIconic\Tracking\GoogleAnalytics\AnalyticsResponse sendTiming()
66
 *
67
 * Content Information
68
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setDocumentLocationUrl($value)
69
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setDocumentHostName($value)
70
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setDocumentPath($value)
71
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setDocumentTitle($value)
72
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setScreenName($value)
73
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setLinkId($value)
74
 *
75
 * App Tracking
76
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setApplicationName($value)
77
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setApplicationId($value)
78
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setApplicationVersion($value)
79
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setApplicationInstallerId($value)
80
 *
81
 * Event Tracking
82
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setEventCategory($value)
83
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setEventAction($value)
84
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setEventLabel($value)
85
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setEventValue($value)
86
 *
87
 * E-commerce
88
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setItemName($value)
89
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setItemPrice($value)
90
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setItemQuantity($value)
91
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setItemCode($value)
92
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setItemCategory($value)
93
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setCurrencyCode($value)
94
 *
95
 * Enhanced E-Commerce
96
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setTransactionId($value)
97
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setAffiliation($value)
98
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setRevenue($value)
99
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setTax($value)
100
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setShipping($value)
101
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setCouponCode($value)
102
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setProductActionList($value)
103
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setCheckoutStep($value)
104
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setCheckoutStepOption($value)
105
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics addProduct(array $productData)
106
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setProductAction($value)
107
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setProductActionToDetail()
108
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setProductActionToClick()
109
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setProductActionToAdd()
110
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setProductActionToRemove()
111
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setProductActionToCheckout()
112
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setProductActionToCheckoutOption()
113
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setProductActionToPurchase()
114
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setProductActionToRefund()
115
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setProductImpressionListName($value, $index)
116
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics addProductImpression(array $productData, $index)
117
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics addPromotion(array $promotionData)
118
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setPromotionAction($value)
119
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setPromotionActionToClick()
120
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setPromotionActionToView()
121
 *
122
 * Social Interactions
123
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setSocialNetwork($value)
124
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setSocialAction($value)
125
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setSocialActionTarget($value)
126
 *
127
 * Timing
128
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setUserTimingCategory($value)
129
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setUserTimingVariableName($value)
130
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setUserTimingTime($value)
131
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setUserTimingLabel($value)
132
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setPageLoadTime($value)
133
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setDnsTime($value)
134
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setPageDownloadTime($value)
135
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setRedirectResponseTime($value)
136
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setTcpConnectTime($value)
137
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setServerResponseTime($value)
138
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setDomInteractiveTime($value)
139
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setContentLoadTime($value)
140
 *
141
 * Exceptions
142
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setExceptionDescription($value)
143
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setIsExceptionFatal($value)
144
 *
145
 * Custom Dimension / Metrics
146
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setCustomDimension($value, $index)
147
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setCustomMetric($value, $index)
148
 *
149
 * Content Grouping
150
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setContentGroup($value, $index)
151
 *
152
 * Content Experiments
153
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setExperimentId($value)
154
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setExperimentVariant($value)
155
 *
156
 *
157
 * @package TheIconic\Tracking\GoogleAnalytics
158
 */
159
class Analytics
160
{
161
    /**
162
     * URI scheme for the GA API.
163
     *
164
     * @var string
165
     */
166
    private $uriScheme = 'http';
167
168
    /**
169
     * Indicates if the request to GA will be asynchronous (non-blocking).
170
     *
171
     * @var boolean
172
     */
173
    private $isAsyncRequest = false;
174
175
    /**
176
     * Endpoint to connect to when sending data to GA.
177
     *
178
     * @var string
179
     */
180
    private $endpoint = '://www.google-analytics.com/collect';
181
182
    /**
183
     * Endpoint to connect to when validating hits.
184
     * @link https://developers.google.com/analytics/devguides/collection/protocol/v1/validating-hits
185
     *
186
     * @var string
187
     */
188
    private $debugEndpoint = '://www.google-analytics.com/debug/collect';
189
190
    /**
191
     * Indicates if the request is in debug mode(validating hits).
192
     *
193
     * @var boolean
194
     */
195
    private $isDebug = false;
196
197
    /**
198
     * Holds the single parameters added to the hit.
199
     *
200
     * @var SingleParameter[]
201
     */
202
    private $singleParameters = [];
203
204
    /**
205
     * Holds the compound parameters collections added to the hit.
206
     *
207
     * @var  CompoundParameterCollection[]
208
     */
209
    private $compoundParametersCollections = [];
210
211
    /**
212
     * Holds the HTTP client used to connect to GA.
213
     *
214
     * @var HttpClient
215
     */
216
    private $httpClient;
217
218
    /**
219
     * Initializes to a list of all the available parameters to be sent in a hit.
220
     *
221
     * @var array
222
     */
223
    private $availableParameters = [
224
        'ApplicationId' => 'AppTracking\\ApplicationId',
225
        'ApplicationInstallerId' => 'AppTracking\\ApplicationInstallerId',
226
        'ApplicationName' => 'AppTracking\\ApplicationName',
227
        'ApplicationVersion' => 'AppTracking\\ApplicationVersion',
228
        'ExperimentId' => 'ContentExperiments\\ExperimentId',
229
        'ExperimentVariant' => 'ContentExperiments\\ExperimentVariant',
230
        'ContentGroup' => 'ContentGrouping\\ContentGroup',
231
        'DocumentHostName' => 'ContentInformation\\DocumentHostName',
232
        'DocumentLocationUrl' => 'ContentInformation\\DocumentLocationUrl',
233
        'DocumentPath' => 'ContentInformation\\DocumentPath',
234
        'DocumentTitle' => 'ContentInformation\\DocumentTitle',
235
        'LinkId' => 'ContentInformation\\LinkId',
236
        'ScreenName' => 'ContentInformation\\ScreenName',
237
        'CustomDimension' => 'CustomDimensionsMetrics\\CustomDimension',
238
        'CustomMetric' => 'CustomDimensionsMetrics\\CustomMetric',
239
        'CurrencyCode' => 'Ecommerce\\CurrencyCode',
240
        'ItemCategory' => 'Ecommerce\\ItemCategory',
241
        'ItemCode' => 'Ecommerce\\ItemCode',
242
        'ItemName' => 'Ecommerce\\ItemName',
243
        'ItemPrice' => 'Ecommerce\\ItemPrice',
244
        'ItemQuantity' => 'Ecommerce\\ItemQuantity',
245
        'Affiliation' => 'EnhancedEcommerce\\Affiliation',
246
        'CheckoutStep' => 'EnhancedEcommerce\\CheckoutStep',
247
        'CheckoutStepOption' => 'EnhancedEcommerce\\CheckoutStepOption',
248
        'CouponCode' => 'EnhancedEcommerce\\CouponCode',
249
        'Product' => 'EnhancedEcommerce\\Product',
250
        'ProductAction' => 'EnhancedEcommerce\\ProductAction',
251
        'ProductActionList' => 'EnhancedEcommerce\\ProductActionList',
252
        'ProductCollection' => 'EnhancedEcommerce\\ProductCollection',
253
        'ProductImpression' => 'EnhancedEcommerce\\ProductImpression',
254
        'ProductImpressionCollection' => 'EnhancedEcommerce\\ProductImpressionCollection',
255
        'ProductImpressionListName' => 'EnhancedEcommerce\\ProductImpressionListName',
256
        'Promotion' => 'EnhancedEcommerce\\Promotion',
257
        'PromotionAction' => 'EnhancedEcommerce\\PromotionAction',
258
        'PromotionCollection' => 'EnhancedEcommerce\\PromotionCollection',
259
        'Revenue' => 'EnhancedEcommerce\\Revenue',
260
        'Shipping' => 'EnhancedEcommerce\\Shipping',
261
        'Tax' => 'EnhancedEcommerce\\Tax',
262
        'TransactionId' => 'EnhancedEcommerce\\TransactionId',
263
        'EventAction' => 'Event\\EventAction',
264
        'EventCategory' => 'Event\\EventCategory',
265
        'EventLabel' => 'Event\\EventLabel',
266
        'EventValue' => 'Event\\EventValue',
267
        'ExceptionDescription' => 'Exceptions\\ExceptionDescription',
268
        'IsExceptionFatal' => 'Exceptions\\IsExceptionFatal',
269
        'AnonymizeIp' => 'General\\AnonymizeIp',
270
        'CacheBuster' => 'General\\CacheBuster',
271
        'DataSource' => 'General\\DataSource',
272
        'ProtocolVersion' => 'General\\ProtocolVersion',
273
        'QueueTime' => 'General\\QueueTime',
274
        'TrackingId' => 'General\\TrackingId',
275
        'HitType' => 'Hit\\HitType',
276
        'NonInteractionHit' => 'Hit\\NonInteractionHit',
277
        'GeographicalOverride' => 'Session\\GeographicalOverride',
278
        'IpOverride' => 'Session\\IpOverride',
279
        'SessionControl' => 'Session\\SessionControl',
280
        'UserAgentOverride' => 'Session\\UserAgentOverride',
281
        'SocialAction' => 'SocialInteractions\\SocialAction',
282
        'SocialActionTarget' => 'SocialInteractions\\SocialActionTarget',
283
        'SocialNetwork' => 'SocialInteractions\\SocialNetwork',
284
        'DocumentEncoding' => 'SystemInfo\\DocumentEncoding',
285
        'FlashVersion' => 'SystemInfo\\FlashVersion',
286
        'JavaEnabled' => 'SystemInfo\\JavaEnabled',
287
        'ScreenColors' => 'SystemInfo\\ScreenColors',
288
        'ScreenResolution' => 'SystemInfo\\ScreenResolution',
289
        'UserLanguage' => 'SystemInfo\\UserLanguage',
290
        'ViewportSize' => 'SystemInfo\\ViewportSize',
291
        'ContentLoadTime' => 'Timing\\ContentLoadTime',
292
        'DnsTime' => 'Timing\\DnsTime',
293
        'DomInteractiveTime' => 'Timing\\DomInteractiveTime',
294
        'PageDownloadTime' => 'Timing\\PageDownloadTime',
295
        'PageLoadTime' => 'Timing\\PageLoadTime',
296
        'RedirectResponseTime' => 'Timing\\RedirectResponseTime',
297
        'ServerResponseTime' => 'Timing\\ServerResponseTime',
298
        'TcpConnectTime' => 'Timing\\TcpConnectTime',
299
        'UserTimingCategory' => 'Timing\\UserTimingCategory',
300
        'UserTimingLabel' => 'Timing\\UserTimingLabel',
301
        'UserTimingTime' => 'Timing\\UserTimingTime',
302
        'UserTimingVariableName' => 'Timing\\UserTimingVariableName',
303
        'CampaignContent' => 'TrafficSources\\CampaignContent',
304
        'CampaignId' => 'TrafficSources\\CampaignId',
305
        'CampaignKeyword' => 'TrafficSources\\CampaignKeyword',
306
        'CampaignMedium' => 'TrafficSources\\CampaignMedium',
307
        'CampaignName' => 'TrafficSources\\CampaignName',
308
        'CampaignSource' => 'TrafficSources\\CampaignSource',
309
        'DocumentReferrer' => 'TrafficSources\\DocumentReferrer',
310
        'GoogleAdwordsId' => 'TrafficSources\\GoogleAdwordsId',
311
        'GoogleDisplayAdsId' => 'TrafficSources\\GoogleDisplayAdsId',
312
        'ClientId' => 'User\\ClientId',
313
        'UserId' => 'User\\UserId',
314
    ];
315
316
    /**
317
     * When passed with an argument of TRUE, it will send the hit using HTTPS instead of plain HTTP.
318
     * It parses the available parameters.
319
     *
320
     * @param bool $isSsl
321
     * @throws \InvalidArgumentException
322
     */
323
    public function __construct($isSsl = false)
324
    {
325
        if (!is_bool($isSsl)) {
326
            throw new \InvalidArgumentException('First constructor argument "isSSL" must be boolean');
327
        }
328
329
        if ($isSsl) {
330
            $this->uriScheme .= 's';
331
            $this->endpoint = str_replace('www', 'ssl', $this->endpoint);
332
        }
333
    }
334
335
    /**
336
     * Sets a request to be either synchronous or asynchronous (non-blocking).
337
     *
338
     * @param boolean $isAsyncRequest
339
     * @return $this
340
     */
341
    public function setAsyncRequest($isAsyncRequest)
342
    {
343
        $this->isAsyncRequest = $isAsyncRequest;
344
345
        return $this;
346
    }
347
348
    /**
349
     * Makes the request to GA asynchronous (non-blocking).
350
     *
351
     * @deprecated Use setAsyncRequest(boolean $isAsyncRequest) instead. To be removed in next major version.
352
     *
353
     * @return $this
354
     */
355
    public function makeNonBlocking()
356
    {
357
        $this->isAsyncRequest = true;
358
359
        return $this;
360
    }
361
362
    /**
363
     * Sets the HttpClient.
364
     *
365
     * @param HttpClient $httpClient
366
     * @return $this
367
     */
368
    public function setHttpClient(HttpClient $httpClient)
369
    {
370
        $this->httpClient = $httpClient;
371
372
        return $this;
373
    }
374
375
    /**
376
     * Gets the HttpClient.
377
     *
378
     * @return HttpClient
379
     */
380
    private function getHttpClient()
381
    {
382
        if ($this->httpClient === null) {
383
            // @codeCoverageIgnoreStart
384
            $this->setHttpClient(new HttpClient());
385
        }
386
        // @codeCoverageIgnoreEnd
387
388
        return $this->httpClient;
389
    }
390
391
    /**
392
     * Gets the full endpoint to GA.
393
     *
394
     * @return string
395
     */
396
    private function getEndpoint()
397
    {
398
        return ($this->isDebug) ? $this->uriScheme . $this->debugEndpoint : $this->uriScheme . $this->endpoint;
399
    }
400
401
    /**
402
     * Sets debug mode to true or false.
403
     *
404
     * @param bool $value
405
     * @return \TheIconic\Tracking\GoogleAnalytics\Analytics
406
     */
407
    public function setDebug($value)
408
    {
409
        $this->isDebug = $value;
410
411
        return $this;
412
    }
413
414
    /**
415
     * Sends a hit to GA. The hit will contain in the payload all the parameters added before.
416
     *
417
     * @param $methodName
418
     * @return AnalyticsResponse
419
     * @throws Exception\InvalidPayloadDataException
420
     */
421
    private function sendHit($methodName)
422
    {
423
        $hitType = strtoupper(substr($methodName, 4));
424
425
        $hitConstant = $this->getParameterClassConstant(
426
            'TheIconic\Tracking\GoogleAnalytics\Parameters\Hit\HitType::HIT_TYPE_' . $hitType,
427
            'Hit type ' . $hitType . ' is not defined, check spelling'
428
        );
429
430
        $this->setHitType($hitConstant);
431
432
        if (!$this->hasMinimumRequiredParameters()) {
433
            throw new InvalidPayloadDataException();
434
        }
435
436
        return $this->getHttpClient()->post(
437
            $this->getUrl(),
438
            $this->isAsyncRequest
439
        );
440
    }
441
442
    /**
443
     * Build and returns URL used to send to Google Analytics.
444
     *
445
     * @return string
446
     */
447
    public function getUrl()
448
    {
449
        $prepareUrl = new PrepareUrl;
450
451
        return $prepareUrl->build(
452
            $this->getEndpoint(),
453
            $this->singleParameters,
454
            $this->compoundParametersCollections
455
        );
456
    }
457
458
    /**
459
     * Validates the minimum required parameters for every GA hit are being sent.
460
     *
461
     * @SuppressWarnings(PHPMD.LongVariable)
462
     *
463
     * @return bool
464
     */
465
    private function hasMinimumRequiredParameters()
466
    {
467
        $minimumRequiredParameters = [
468
            'v' => false,
469
            'tid' => false,
470
            'cid' => false,
471
            't' => false,
472
        ];
473
474
        foreach ($minimumRequiredParameters as $parameterName => $isParamPresent) {
475
            if (in_array($parameterName, array_keys($this->singleParameters))) {
476
                $minimumRequiredParameters[$parameterName] = true;
477
            }
478
        }
479
480
        return !in_array(false, $minimumRequiredParameters, true);
481
    }
482
483
    /**
484
     * Sets a parameter action to the value specified by the method call.
485
     *
486
     * @param $parameter
487
     * @param $action
488
     * @return $this
489
     */
490
    private function setParameterActionTo($parameter, $action)
491
    {
492
        $actionConstant = $this->getParameterClassConstant(
493
            'TheIconic\Tracking\GoogleAnalytics\Parameters\EnhancedEcommerce\\'
494
            . $parameter . 'Action::ACTION_' . strtoupper($action),
495
            $parameter . ' action ' . $action . ' does not exist, check spelling'
496
        );
497
498
        $function = 'set' . $parameter . 'Action';
499
500
        $this->$function($actionConstant);
501
502
        return $this;
503
    }
504
505
    /**
506
     * Gets a contant from a class dynamically.
507
     *
508
     * @param $constant
509
     * @param $exceptionMsg
510
     * @return mixed
511
     * @throws \BadMethodCallException
512
     */
513
    private function getParameterClassConstant($constant, $exceptionMsg)
514
    {
515
        if (defined($constant)) {
516
            return constant($constant);
517
        } else {
518
            throw new \BadMethodCallException($exceptionMsg);
519
        }
520
    }
521
522
    /**
523
     * Sets the value for a parameter.
524
     *
525
     * @param $methodName
526
     * @param array $methodArguments
527
     * @return $this
528
     * @throws \InvalidArgumentException
529
     */
530
    private function setParameter($methodName, array $methodArguments)
531
    {
532
        $parameterClass = substr($methodName, 3);
533
534
        $fullParameterClass = $this->getFullParameterClass($parameterClass, $methodName);
535
536
        $parameterIndex = $this->getIndexFromArguments($methodArguments);
537
538
        /** @var SingleParameter $parameterObject */
539
        $parameterObject = new $fullParameterClass($parameterIndex);
540
541
        if (!isset($methodArguments[0])) {
542
            throw new \InvalidArgumentException(
543
                'For Analytics object, you must specify a value to be set for ' . $methodName
544
            );
545
        } else {
546
            $parameterObject->setValue($methodArguments[0]);
547
        }
548
549
        $this->singleParameters[$parameterObject->getName()] = $parameterObject;
550
551
        return $this;
552
    }
553
554
    /**
555
     * Adds an item to a compund parameter collection.
556
     *
557
     * @SuppressWarnings(PHPMD.LongVariable)
558
     *
559
     * @param $methodName
560
     * @param array $methodArguments
561
     * @return $this
562
     * @throws \InvalidArgumentException
563
     */
564
    private function addItem($methodName, array $methodArguments)
565
    {
566
        $parameterClass = substr($methodName, 3);
567
568
        $fullParameterClass = $this->getFullParameterClass($parameterClass, $methodName);
569
570
        if (!isset($methodArguments[0])) {
571
            throw new \InvalidArgumentException(
572
                'You must specify a ' . $parameterClass . ' to be add for ' . $methodName
573
            );
574
        } else {
575
            $parameterObject = new $fullParameterClass($methodArguments[0]);
576
        }
577
578
        $collectionIndex = $this->getIndexFromArguments($methodArguments);
579
580
        if (isset($this->compoundParametersCollections[$parameterClass . $collectionIndex])) {
581
            $this->compoundParametersCollections[$parameterClass . $collectionIndex]->add($parameterObject);
582
        } else {
583
            $fullParameterCollectionClass = $fullParameterClass . 'Collection';
584
585
            /** @var CompoundParameterCollection $parameterObjectCollection */
586
            $parameterObjectCollection = new $fullParameterCollectionClass($collectionIndex);
587
588
            $parameterObjectCollection->add($parameterObject);
589
590
            $this->compoundParametersCollections[$parameterClass . $collectionIndex] = $parameterObjectCollection;
591
        }
592
593
        return $this;
594
    }
595
596
    /**
597
     * Gets the value for a parameter.
598
     *
599
     * @param $methodName
600
     * @param array $methodArguments
601
     * @return $this
602
     * @throws \InvalidArgumentException
603
     */
604
    private function getParameter($methodName, array $methodArguments)
605
    {
606
        $parameterClass = substr($methodName, 3);
607
608
        $fullParameterClass = $this->getFullParameterClass($parameterClass, $methodName);
609
610
        // Handle index arguments
611
        $parameterIndex = '';
612
        if (isset($methodArguments[0]) && is_numeric($methodArguments[0])) {
613
            $parameterIndex = $methodArguments[0];
614
        }
615
616
        // Handle compoundParametersCollections
617
        if (isset($this->compoundParametersCollections[$parameterClass . $parameterIndex])) {
618
            // If compoundParametersCollections contains our Objects, return them well-formatted
619
            return $this->compoundParametersCollections[$parameterClass . $parameterIndex]->getReadableItems();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->compoundPa...x]->getReadableItems(); (array) is incompatible with the return type documented by TheIconic\Tracking\Googl...Analytics::getParameter of type TheIconic\Tracking\GoogleAnalytics\Analytics.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
620
        } else {
621
            $fullParameterCollectionClass = $fullParameterClass . 'Collection';
622
623
            // Test if the class Collection exist
624
            if(class_exists($fullParameterCollectionClass)){
625
                return null;
626
            }
627
            // If not, it's a SingleParameter Object, continue the magic
628
        }
629
630
        /** @var SingleParameter $parameterObject */
631
        $parameterObject = new $fullParameterClass($parameterIndex);
632
633
        if(!array_key_exists($parameterObject->getName(), $this->singleParameters)){
634
            return null;
635
        }
636
        $currentParameterObject = $this->singleParameters[$parameterObject->getName()];
637
638
        return $currentParameterObject->getValue();
639
640
    }
641
642
    /**
643
     * Gets the index value from the arguments.
644
     *
645
     * @param $methodArguments
646
     * @return string
647
     */
648
    private function getIndexFromArguments($methodArguments)
649
    {
650
        $index = '';
651
        if (isset($methodArguments[1]) && is_numeric($methodArguments[1])) {
652
            $index = $methodArguments[1];
653
        }
654
655
        return $index;
656
    }
657
658
    /**
659
     * Gets the fully qualified name for a parameter.
660
     *
661
     * @param $parameterClass
662
     * @param $methodName
663
     * @return string
664
     * @throws \BadMethodCallException
665
     */
666
    private function getFullParameterClass($parameterClass, $methodName)
667
    {
668
        if (empty($this->availableParameters[$parameterClass])) {
669
            throw new \BadMethodCallException('Method ' . $methodName . ' not defined for Analytics class');
670
        } else {
671
            return '\\TheIconic\\Tracking\\GoogleAnalytics\\Parameters\\' . $this->availableParameters[$parameterClass];
672
        }
673
    }
674
675
    /**
676
     * Routes the method call to the adequate private method.
677
     *
678
     * @param $methodName
679
     * @param array $methodArguments
680
     * @return $this|AnalyticsResponse
681
     * @throws \BadMethodCallException
682
     */
683
    public function __call($methodName, array $methodArguments)
684
    {
685
        $methodName = $this->fixTypos($methodName);
686
687
        if (preg_match('/^set(Product|Promotion)ActionTo(\w+)/', $methodName, $matches)) {
688
            return $this->setParameterActionTo($matches[1], $matches[2]);
689
        }
690
691
        if (preg_match('/^(set)(\w+)/', $methodName, $matches)) {
692
            return $this->setParameter($methodName, $methodArguments);
693
        }
694
695
        if (preg_match('/^(add)(\w+)/', $methodName, $matches)) {
696
            return $this->addItem($methodName, $methodArguments);
697
        }
698
699
        if (preg_match('/^(send)(\w+)/', $methodName, $matches)) {
700
            return $this->sendHit($methodName);
701
        }
702
703
        // Get Parameters
704
        if (preg_match('/^(get)(\w+)/', $methodName, $matches)) {
705
            return $this->getParameter($methodName, $methodArguments);
706
        }
707
708
        throw new \BadMethodCallException('Method ' . $methodName . ' not defined for Analytics class');
709
    }
710
711
    /**
712
     * Fix typos that went into releases, this way we ensure we don't break scripts in production.
713
     *
714
     * @param string $methodName
715
     * @return string
716
     */
717
    private function fixTypos($methodName)
718
    {
719
        // deprecated in v2, to be removed in v3
720
        if ($methodName === 'setUserTiminCategory') {
721
            $methodName = 'setUserTimingCategory';
722
        }
723
724
        return $methodName;
725
    }
726
}
727