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 ( a4e2d6...e47a53 )
by Jorge
8s
created

Analytics::sendHit()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 24
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 24
rs 8.9713
c 0
b 0
f 0
cc 3
eloc 14
nc 3
nop 1
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
 * ==== GETTERS ====
18
 * General
19
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setProtocolVersion($value)
20
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setTrackingId($value)
21
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setAnonymizeIp($value)
22
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setDataSource($value)
23
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setQueueTime($value)
24
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setCacheBuster($value)
25
 *
26
 * User
27
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setClientId($value)
28
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setUserId($value)
29
 *
30
 * Session
31
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setSessionControl($value)
32
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setIpOverride($value)
33
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setUserAgentOverride($value)
34
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setGeographicalOverride($value)
35
 *
36
 * Traffic Sources
37
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setDocumentReferrer($value)
38
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setCampaignName($value)
39
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setCampaignSource($value)
40
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setCampaignMedium($value)
41
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setCampaignKeyword($value)
42
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setCampaignContent($value)
43
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setCampaignId($value)
44
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setGoogleAdwordsId($value)
45
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setGoogleDisplayAdsId($value)
46
 *
47
 * System Info
48
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setScreenResolution($value)
49
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setViewportSize($value)
50
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setDocumentEncoding($value)
51
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setScreenColors($value)
52
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setUserLanguage($value)
53
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setJavaEnabled($value)
54
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setFlashVersion($value)
55
 *
56
 * Hit
57
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setHitType($value)
58
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setNonInteractionHit($value)
59
 * @method \TheIconic\Tracking\GoogleAnalytics\AnalyticsResponse sendPageview()
60
 * @method \TheIconic\Tracking\GoogleAnalytics\AnalyticsResponse sendEvent()
61
 * @method \TheIconic\Tracking\GoogleAnalytics\AnalyticsResponse sendScreenview()
62
 * @method \TheIconic\Tracking\GoogleAnalytics\AnalyticsResponse sendTransaction()
63
 * @method \TheIconic\Tracking\GoogleAnalytics\AnalyticsResponse sendItem()
64
 * @method \TheIconic\Tracking\GoogleAnalytics\AnalyticsResponse sendSocial()
65
 * @method \TheIconic\Tracking\GoogleAnalytics\AnalyticsResponse sendException()
66
 * @method \TheIconic\Tracking\GoogleAnalytics\AnalyticsResponse sendTiming()
67
 *
68
 * Content Information
69
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setDocumentLocationUrl($value)
70
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setDocumentHostName($value)
71
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setDocumentPath($value)
72
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setDocumentTitle($value)
73
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setScreenName($value)
74
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setLinkId($value)
75
 *
76
 * App Tracking
77
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setApplicationName($value)
78
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setApplicationId($value)
79
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setApplicationVersion($value)
80
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setApplicationInstallerId($value)
81
 *
82
 * Event Tracking
83
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setEventCategory($value)
84
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setEventAction($value)
85
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setEventLabel($value)
86
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setEventValue($value)
87
 *
88
 * E-commerce
89
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setItemName($value)
90
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setItemPrice($value)
91
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setItemQuantity($value)
92
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setItemCode($value)
93
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setItemCategory($value)
94
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setCurrencyCode($value)
95
 *
96
 * Enhanced E-Commerce
97
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setTransactionId($value)
98
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setAffiliation($value)
99
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setRevenue($value)
100
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setTax($value)
101
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setShipping($value)
102
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setCouponCode($value)
103
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setProductActionList($value)
104
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setCheckoutStep($value)
105
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setCheckoutStepOption($value)
106
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics addProduct(array $productData)
107
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setProductAction($value)
108
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setProductActionToDetail()
109
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setProductActionToClick()
110
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setProductActionToAdd()
111
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setProductActionToRemove()
112
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setProductActionToCheckout()
113
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setProductActionToCheckoutOption()
114
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setProductActionToPurchase()
115
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setProductActionToRefund()
116
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setProductImpressionListName($value, $index)
117
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics addProductImpression(array $productData, $index)
118
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics addPromotion(array $promotionData)
119
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setPromotionAction($value)
120
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setPromotionActionToClick()
121
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setPromotionActionToView()
122
 *
123
 * Social Interactions
124
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setSocialNetwork($value)
125
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setSocialAction($value)
126
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setSocialActionTarget($value)
127
 *
128
 * Timing
129
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setUserTimingCategory($value)
130
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setUserTimingVariableName($value)
131
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setUserTimingTime($value)
132
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setUserTimingLabel($value)
133
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setPageLoadTime($value)
134
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setDnsTime($value)
135
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setPageDownloadTime($value)
136
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setRedirectResponseTime($value)
137
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setTcpConnectTime($value)
138
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setServerResponseTime($value)
139
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setDomInteractiveTime($value)
140
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setContentLoadTime($value)
141
 *
142
 * Exceptions
143
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setExceptionDescription($value)
144
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setIsExceptionFatal($value)
145
 *
146
 * Custom Dimension / Metrics
147
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setCustomDimension($value, $index)
148
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setCustomMetric($value, $index)
149
 *
150
 * Content Grouping
151
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setContentGroup($value, $index)
152
 *
153
 * Content Experiments
154
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setExperimentId($value)
155
 * @method \TheIconic\Tracking\GoogleAnalytics\Analytics setExperimentVariant($value)
156
 *
157
 * ==== SETTERS ====
158
 * General
159
 * @method string|int|null getProtocolVersion()
160
 * @method string|int|null getTrackingId()
161
 * @method string|int|null getAnonymizeIp()
162
 * @method string|int|null getDataSource()
163
 * @method string|int|null getQueueTime()
164
 * @method string|int|null getCacheBuster()
165
 *
166
 * User
167
 * @method string|int|null getClientId()
168
 * @method string|int|null getUserId()
169
 *
170
 * Session
171
 * @method string|int|null getSessionControl()
172
 * @method string|int|null getIpOverride()
173
 * @method string|int|null getUserAgentOverride()
174
 * @method string|int|null getGeographicalOverride()
175
 *
176
 * Traffic Sources
177
 * @method string|int|null getDocumentReferrer()
178
 * @method string|int|null getCampaignName()
179
 * @method string|int|null getCampaignSource()
180
 * @method string|int|null getCampaignMedium()
181
 * @method string|int|null getCampaignKeyword()
182
 * @method string|int|null getCampaignContent()
183
 * @method string|int|null getCampaignId()
184
 * @method string|int|null getGoogleAdwordsId()
185
 * @method string|int|null getGoogleDisplayAdsId()
186
 *
187
 * System Info
188
 * @method string|int|null getScreenResolution()
189
 * @method string|int|null getViewportSize()
190
 * @method string|int|null getDocumentEncoding()
191
 * @method string|int|null getScreenColors()
192
 * @method string|int|null getUserLanguage()
193
 * @method string|int|null getJavaEnabled()
194
 * @method string|int|null getFlashVersion()
195
 *
196
 * Hit
197
 * @method string|int|null getHitType()
198
 * @method string|int|null getNonInteractionHit()
199
 *
200
 * Content Information
201
 * @method string|int|null getDocumentLocationUrl()
202
 * @method string|int|null getDocumentHostName()
203
 * @method string|int|null getDocumentPath()
204
 * @method string|int|null getDocumentTitle()
205
 * @method string|int|null getScreenName()
206
 * @method string|int|null getLinkId()
207
 *
208
 * App Tracking
209
 * @method string|int|null getApplicationName()
210
 * @method string|int|null getApplicationId()
211
 * @method string|int|null getApplicationVersion()
212
 * @method string|int|null getApplicationInstallerId()
213
 *
214
 * Event Tracking
215
 * @method string|int|null getEventCategory()
216
 * @method string|int|null getEventAction()
217
 * @method string|int|null getEventLabel()
218
 * @method string|int|null getEventValue()
219
 *
220
 * E-commerce
221
 * @method string|int|null getItemName()
222
 * @method string|int|null getItemPrice()
223
 * @method string|int|null getItemQuantity()
224
 * @method string|int|null getItemCode()
225
 * @method string|int|null getItemCategory()
226
 * @method string|int|null getCurrencyCode()
227
 *
228
 * Enhanced E-Commerce
229
 * @method string|int|null getTransactionId()
230
 * @method string|int|null getAffiliation()
231
 * @method string|int|null getRevenue()
232
 * @method string|int|null getTax()
233
 * @method string|int|null getShipping()
234
 * @method string|int|null getCouponCode()
235
 * @method string|int|null getProductActionList()
236
 * @method string|int|null getCheckoutStep()
237
 * @method string|int|null getCheckoutStepOption()
238
 * @method string|int|null getProduct()
239
 * @method string|int|null getProductAction()
240
 * @method string|int|null getProductActionToDetail()
241
 * @method string|int|null getProductActionToClick()
242
 * @method string|int|null getProductActionToAdd()
243
 * @method string|int|null getProductActionToRemove()
244
 * @method string|int|null getProductActionToCheckout()
245
 * @method string|int|null getProductActionToCheckoutOption()
246
 * @method string|int|null getProductActionToPurchase()
247
 * @method string|int|null getProductActionToRefund()
248
 * @method string|int|null getProductImpressionListName($index)
249
 * @method string|int|null getProductImpression($listIndex)
250
 * @method string|int|null getPromotion()
251
 * @method string|int|null getPromotionAction()
252
 * @method string|int|null getPromotionActionToClick()
253
 * @method string|int|null getPromotionActionToView()
254
 *
255
 * Social Interactions
256
 * @method string|int|null getSocialNetwork()
257
 * @method string|int|null getSocialAction()
258
 * @method string|int|null getSocialActionTarget()
259
 *
260
 * Timing
261
 * @method string|int|null getUserTimingCategory()
262
 * @method string|int|null getUserTimingVariableName()
263
 * @method string|int|null getUserTimingTime()
264
 * @method string|int|null getUserTimingLabel()
265
 * @method string|int|null getPageLoadTime()
266
 * @method string|int|null getDnsTime()
267
 * @method string|int|null getPageDownloadTime()
268
 * @method string|int|null getRedirectResponseTime()
269
 * @method string|int|null getTcpConnectTime()
270
 * @method string|int|null getServerResponseTime()
271
 * @method string|int|null getDomInteractiveTime()
272
 * @method string|int|null getContentLoadTime()
273
 *
274
 * Exceptions
275
 * @method string|int|null getExceptionDescription()
276
 * @method string|int|null getIsExceptionFatal()
277
 *
278
 * Custom Dimension / Metrics
279
 * @method string|int|null getCustomDimension($index)
280
 * @method string|int|null getCustomMetric($index)
281
 *
282
 * Content Grouping
283
 * @method string|int|null getContentGroup($index)
284
 *
285
 * Content Experiments
286
 * @method string|int|null getExperimentId()
287
 * @method string|int|null getExperimentVariant()
288
 *
289
 * @package TheIconic\Tracking\GoogleAnalytics
290
 */
291
class Analytics
292
{
293
    /**
294
     * URI scheme for the GA API.
295
     *
296
     * @var string
297
     */
298
    protected $uriScheme = 'http';
299
300
    /**
301
     * Indicates if the request to GA will be asynchronous (non-blocking).
302
     *
303
     * @var boolean
304
     */
305
    protected $isAsyncRequest = false;
306
307
    /**
308
     * Endpoint to connect to when sending data to GA.
309
     *
310
     * @var string
311
     */
312
    protected $endpoint = '://www.google-analytics.com/collect';
313
314
    /**
315
     * Endpoint to connect to when validating hits.
316
     * @link https://developers.google.com/analytics/devguides/collection/protocol/v1/validating-hits
317
     *
318
     * @var string
319
     */
320
    protected $debugEndpoint = '://www.google-analytics.com/debug/collect';
321
322
    /**
323
     * Indicates if the request is in debug mode(validating hits).
324
     *
325
     * @var boolean
326
     */
327
    protected $isDebug = false;
328
329
    /**
330
     * Holds the single parameters added to the hit.
331
     *
332
     * @var SingleParameter[]
333
     */
334
    protected $singleParameters = [];
335
336
    /**
337
     * Holds the compound parameters collections added to the hit.
338
     *
339
     * @var  CompoundParameterCollection[]
340
     */
341
    protected $compoundParametersCollections = [];
342
343
    /**
344
     * Holds the HTTP client used to connect to GA.
345
     *
346
     * @var HttpClient
347
     */
348
    protected $httpClient;
349
350
    /**
351
     * Indicates if the request to GA will be executed (by default) or not.
352
     *
353
     * @var boolean
354
     */
355
    protected $isDisabled = false;
356
357
    
358
    /**
359
     * Initializes to a list of all the available parameters to be sent in a hit.
360
     *
361
     * @var array
362
     */
363
    protected $availableParameters = [
364
        'ApplicationId' => 'AppTracking\\ApplicationId',
365
        'ApplicationInstallerId' => 'AppTracking\\ApplicationInstallerId',
366
        'ApplicationName' => 'AppTracking\\ApplicationName',
367
        'ApplicationVersion' => 'AppTracking\\ApplicationVersion',
368
        'ExperimentId' => 'ContentExperiments\\ExperimentId',
369
        'ExperimentVariant' => 'ContentExperiments\\ExperimentVariant',
370
        'ContentGroup' => 'ContentGrouping\\ContentGroup',
371
        'DocumentHostName' => 'ContentInformation\\DocumentHostName',
372
        'DocumentLocationUrl' => 'ContentInformation\\DocumentLocationUrl',
373
        'DocumentPath' => 'ContentInformation\\DocumentPath',
374
        'DocumentTitle' => 'ContentInformation\\DocumentTitle',
375
        'LinkId' => 'ContentInformation\\LinkId',
376
        'ScreenName' => 'ContentInformation\\ScreenName',
377
        'CustomDimension' => 'CustomDimensionsMetrics\\CustomDimension',
378
        'CustomMetric' => 'CustomDimensionsMetrics\\CustomMetric',
379
        'CurrencyCode' => 'Ecommerce\\CurrencyCode',
380
        'ItemCategory' => 'Ecommerce\\ItemCategory',
381
        'ItemCode' => 'Ecommerce\\ItemCode',
382
        'ItemName' => 'Ecommerce\\ItemName',
383
        'ItemPrice' => 'Ecommerce\\ItemPrice',
384
        'ItemQuantity' => 'Ecommerce\\ItemQuantity',
385
        'Affiliation' => 'EnhancedEcommerce\\Affiliation',
386
        'CheckoutStep' => 'EnhancedEcommerce\\CheckoutStep',
387
        'CheckoutStepOption' => 'EnhancedEcommerce\\CheckoutStepOption',
388
        'CouponCode' => 'EnhancedEcommerce\\CouponCode',
389
        'Product' => 'EnhancedEcommerce\\Product',
390
        'ProductAction' => 'EnhancedEcommerce\\ProductAction',
391
        'ProductActionList' => 'EnhancedEcommerce\\ProductActionList',
392
        'ProductCollection' => 'EnhancedEcommerce\\ProductCollection',
393
        'ProductImpression' => 'EnhancedEcommerce\\ProductImpression',
394
        'ProductImpressionCollection' => 'EnhancedEcommerce\\ProductImpressionCollection',
395
        'ProductImpressionListName' => 'EnhancedEcommerce\\ProductImpressionListName',
396
        'Promotion' => 'EnhancedEcommerce\\Promotion',
397
        'PromotionAction' => 'EnhancedEcommerce\\PromotionAction',
398
        'PromotionCollection' => 'EnhancedEcommerce\\PromotionCollection',
399
        'Revenue' => 'EnhancedEcommerce\\Revenue',
400
        'Shipping' => 'EnhancedEcommerce\\Shipping',
401
        'Tax' => 'EnhancedEcommerce\\Tax',
402
        'TransactionId' => 'EnhancedEcommerce\\TransactionId',
403
        'EventAction' => 'Event\\EventAction',
404
        'EventCategory' => 'Event\\EventCategory',
405
        'EventLabel' => 'Event\\EventLabel',
406
        'EventValue' => 'Event\\EventValue',
407
        'ExceptionDescription' => 'Exceptions\\ExceptionDescription',
408
        'IsExceptionFatal' => 'Exceptions\\IsExceptionFatal',
409
        'AnonymizeIp' => 'General\\AnonymizeIp',
410
        'CacheBuster' => 'General\\CacheBuster',
411
        'DataSource' => 'General\\DataSource',
412
        'ProtocolVersion' => 'General\\ProtocolVersion',
413
        'QueueTime' => 'General\\QueueTime',
414
        'TrackingId' => 'General\\TrackingId',
415
        'HitType' => 'Hit\\HitType',
416
        'NonInteractionHit' => 'Hit\\NonInteractionHit',
417
        'GeographicalOverride' => 'Session\\GeographicalOverride',
418
        'IpOverride' => 'Session\\IpOverride',
419
        'SessionControl' => 'Session\\SessionControl',
420
        'UserAgentOverride' => 'Session\\UserAgentOverride',
421
        'SocialAction' => 'SocialInteractions\\SocialAction',
422
        'SocialActionTarget' => 'SocialInteractions\\SocialActionTarget',
423
        'SocialNetwork' => 'SocialInteractions\\SocialNetwork',
424
        'DocumentEncoding' => 'SystemInfo\\DocumentEncoding',
425
        'FlashVersion' => 'SystemInfo\\FlashVersion',
426
        'JavaEnabled' => 'SystemInfo\\JavaEnabled',
427
        'ScreenColors' => 'SystemInfo\\ScreenColors',
428
        'ScreenResolution' => 'SystemInfo\\ScreenResolution',
429
        'UserLanguage' => 'SystemInfo\\UserLanguage',
430
        'ViewportSize' => 'SystemInfo\\ViewportSize',
431
        'ContentLoadTime' => 'Timing\\ContentLoadTime',
432
        'DnsTime' => 'Timing\\DnsTime',
433
        'DomInteractiveTime' => 'Timing\\DomInteractiveTime',
434
        'PageDownloadTime' => 'Timing\\PageDownloadTime',
435
        'PageLoadTime' => 'Timing\\PageLoadTime',
436
        'RedirectResponseTime' => 'Timing\\RedirectResponseTime',
437
        'ServerResponseTime' => 'Timing\\ServerResponseTime',
438
        'TcpConnectTime' => 'Timing\\TcpConnectTime',
439
        'UserTimingCategory' => 'Timing\\UserTimingCategory',
440
        'UserTimingLabel' => 'Timing\\UserTimingLabel',
441
        'UserTimingTime' => 'Timing\\UserTimingTime',
442
        'UserTimingVariableName' => 'Timing\\UserTimingVariableName',
443
        'CampaignContent' => 'TrafficSources\\CampaignContent',
444
        'CampaignId' => 'TrafficSources\\CampaignId',
445
        'CampaignKeyword' => 'TrafficSources\\CampaignKeyword',
446
        'CampaignMedium' => 'TrafficSources\\CampaignMedium',
447
        'CampaignName' => 'TrafficSources\\CampaignName',
448
        'CampaignSource' => 'TrafficSources\\CampaignSource',
449
        'DocumentReferrer' => 'TrafficSources\\DocumentReferrer',
450
        'GoogleAdwordsId' => 'TrafficSources\\GoogleAdwordsId',
451
        'GoogleDisplayAdsId' => 'TrafficSources\\GoogleDisplayAdsId',
452
        'ClientId' => 'User\\ClientId',
453
        'UserId' => 'User\\UserId',
454
    ];
455
456
    /**
457
     * When passed with an argument of TRUE, it will send the hit using HTTPS instead of plain HTTP.
458
     * It parses the available parameters.
459
     *
460
     * @param bool $isSsl
461
     * @throws \InvalidArgumentException
462
     */
463
    public function __construct($isSsl = false, $isDisabled = false)
464
    {
465
        if (!is_bool($isSsl)) {
466
            throw new \InvalidArgumentException('First constructor argument "isSSL" must be boolean');
467
        }
468
469
        if (!is_bool($isDisabled)) {
470
            throw new \InvalidArgumentException('Second constructor argument "isDisabled" must be boolean');
471
        }
472
473
        if ($isSsl) {
474
            $this->uriScheme .= 's';
475
            $this->endpoint = str_replace('www', 'ssl', $this->endpoint);
476
        }
477
        
478
		$this->isDisabled = $isDisabled;
479
    }
480
481
    /**
482
     * Sets a request to be either synchronous or asynchronous (non-blocking).
483
     *
484
     * @api
485
     * @param boolean $isAsyncRequest
486
     * @return $this
487
     */
488
    public function setAsyncRequest($isAsyncRequest)
489
    {
490
        $this->isAsyncRequest = $isAsyncRequest;
491
492
        return $this;
493
    }
494
495
    /**
496
     * Makes the request to GA asynchronous (non-blocking).
497
     *
498
     * @deprecated Use setAsyncRequest(boolean $isAsyncRequest) instead. To be removed in next major version.
499
     *
500
     * @return $this
501
     */
502
    public function makeNonBlocking()
503
    {
504
        $this->isAsyncRequest = true;
505
506
        return $this;
507
    }
508
509
    /**
510
     * Sets the HttpClient.
511
     *
512
     * @internal
513
     * @param HttpClient $httpClient
514
     * @return $this
515
     */
516
    public function setHttpClient(HttpClient $httpClient)
517
    {
518
        $this->httpClient = $httpClient;
519
520
        return $this;
521
    }
522
523
    /**
524
     * Gets the HttpClient.
525
     *
526
     * @return HttpClient
527
     */
528
    protected function getHttpClient()
529
    {
530
        if ($this->httpClient === null) {
531
            // @codeCoverageIgnoreStart
532
            $this->setHttpClient(new HttpClient());
533
        }
534
        // @codeCoverageIgnoreEnd
535
536
        return $this->httpClient;
537
    }
538
539
    /**
540
     * Gets the full endpoint to GA.
541
     *
542
     * @return string
543
     */
544
    protected function getEndpoint()
545
    {
546
        return ($this->isDebug) ? $this->uriScheme . $this->debugEndpoint : $this->uriScheme . $this->endpoint;
547
    }
548
549
    /**
550
     * Sets debug mode to true or false.
551
     *
552
     * @api
553
     * @param bool $value
554
     * @return \TheIconic\Tracking\GoogleAnalytics\Analytics
555
     */
556
    public function setDebug($value)
557
    {
558
        $this->isDebug = $value;
559
560
        return $this;
561
    }
562
563
    /**
564
     * Sends a hit to GA. The hit will contain in the payload all the parameters added before.
565
     *
566
     * @param $methodName
567
     * @return AnalyticsResponse
568
     * @throws Exception\InvalidPayloadDataException
569
     */
570
    protected function sendHit($methodName)
571
    {
572
        $hitType = strtoupper(substr($methodName, 4));
573
574
        $hitConstant = $this->getParameterClassConstant(
575
            'TheIconic\Tracking\GoogleAnalytics\Parameters\Hit\HitType::HIT_TYPE_' . $hitType,
576
            'Hit type ' . $hitType . ' is not defined, check spelling'
577
        );
578
579
        $this->setHitType($hitConstant);
580
581
        if (!$this->hasMinimumRequiredParameters()) {
582
            throw new InvalidPayloadDataException();
583
        }
584
585
        if ($this->isDisabled) {
586
			return new NullAnalyticsResponse();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \TheIconic\Tr...ullAnalyticsResponse(); (TheIconic\Tracking\Googl...s\NullAnalyticsResponse) is incompatible with the return type documented by TheIconic\Tracking\Googl...tics\Analytics::sendHit of type TheIconic\Tracking\Googl...ytics\AnalyticsResponse.

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...
587
        } else {
588
            return $this->getHttpClient()->post(
589
                $this->getUrl(),
590
                $this->isAsyncRequest
591
            );
592
		}
593
    }
594
595
    /**
596
     * Build and returns URL used to send to Google Analytics.
597
     *
598
     * @api
599
     * @return string
600
     */
601
    public function getUrl()
602
    {
603
        $prepareUrl = new PrepareUrl;
604
605
        return $prepareUrl->build(
606
            $this->getEndpoint(),
607
            $this->singleParameters,
608
            $this->compoundParametersCollections
609
        );
610
    }
611
612
    /**
613
     * Validates the minimum required parameters for every GA hit are being sent.
614
     *
615
     * @SuppressWarnings(PHPMD.LongVariable)
616
     *
617
     * @return bool
618
     */
619
    protected function hasMinimumRequiredParameters()
620
    {
621
        $minimumRequiredParameters = [
622
            'v' => false,
623
            'tid' => false,
624
            'cid' => false,
625
            'uid' => false,
626
            't' => false,
627
        ];
628
629
        foreach ($minimumRequiredParameters as $parameterName => $isParamPresent) {
630
            if (in_array($parameterName, array_keys($this->singleParameters))) {
631
                $minimumRequiredParameters[$parameterName] = true;
632
            }
633
        }
634
635
        if ((!$minimumRequiredParameters['cid'] && $minimumRequiredParameters['uid'])) {
636
            $minimumRequiredParameters['cid'] = true;
637
        }
638
639
        if ((!$minimumRequiredParameters['uid'] && $minimumRequiredParameters['cid'])) {
640
            $minimumRequiredParameters['uid'] = true;
641
        }
642
643
        return !in_array(false, $minimumRequiredParameters, true);
644
    }
645
646
    /**
647
     * Sets a parameter action to the value specified by the method call.
648
     *
649
     * @param $parameter
650
     * @param $action
651
     * @return $this
652
     */
653
    protected function setParameterActionTo($parameter, $action)
654
    {
655
        $actionConstant = $this->getParameterClassConstant(
656
            'TheIconic\Tracking\GoogleAnalytics\Parameters\EnhancedEcommerce\\'
657
            . $parameter . 'Action::ACTION_' . strtoupper($action),
658
            $parameter . ' action ' . $action . ' does not exist, check spelling'
659
        );
660
661
        $function = 'set' . $parameter . 'Action';
662
663
        $this->$function($actionConstant);
664
665
        return $this;
666
    }
667
668
    /**
669
     * Gets a contant from a class dynamically.
670
     *
671
     * @param $constant
672
     * @param $exceptionMsg
673
     * @return mixed
674
     * @throws \BadMethodCallException
675
     */
676
    protected function getParameterClassConstant($constant, $exceptionMsg)
677
    {
678
        if (defined($constant)) {
679
            return constant($constant);
680
        } else {
681
            throw new \BadMethodCallException($exceptionMsg);
682
        }
683
    }
684
685
    /**
686
     * Sets the value for a parameter.
687
     *
688
     * @param $methodName
689
     * @param array $methodArguments
690
     * @return $this
691
     * @throws \InvalidArgumentException
692
     */
693
    protected function setParameter($methodName, array $methodArguments)
694
    {
695
        $parameterClass = substr($methodName, 3);
696
697
        $fullParameterClass = $this->getFullParameterClass($parameterClass, $methodName);
698
699
        $parameterIndex = $this->getIndexFromArguments($methodArguments);
700
701
        /** @var SingleParameter $parameterObject */
702
        $parameterObject = new $fullParameterClass($parameterIndex);
703
704
        if (!isset($methodArguments[0])) {
705
            throw new \InvalidArgumentException(
706
                'For Analytics object, you must specify a value to be set for ' . $methodName
707
            );
708
        } else {
709
            $parameterObject->setValue($methodArguments[0]);
710
        }
711
712
        $this->singleParameters[$parameterObject->getName()] = $parameterObject;
713
714
        return $this;
715
    }
716
717
    /**
718
     * Adds an item to a compund parameter collection.
719
     *
720
     * @SuppressWarnings(PHPMD.LongVariable)
721
     *
722
     * @param $methodName
723
     * @param array $methodArguments
724
     * @return $this
725
     * @throws \InvalidArgumentException
726
     */
727
    protected function addItem($methodName, array $methodArguments)
728
    {
729
        $parameterClass = substr($methodName, 3);
730
731
        $fullParameterClass = $this->getFullParameterClass($parameterClass, $methodName);
732
733
        if (!isset($methodArguments[0])) {
734
            throw new \InvalidArgumentException(
735
                'You must specify a ' . $parameterClass . ' to be add for ' . $methodName
736
            );
737
        } else {
738
            $parameterObject = new $fullParameterClass($methodArguments[0]);
739
        }
740
741
        $collectionIndex = $this->getIndexFromArguments($methodArguments);
742
743
        if (isset($this->compoundParametersCollections[$parameterClass . $collectionIndex])) {
744
            $this->compoundParametersCollections[$parameterClass . $collectionIndex]->add($parameterObject);
745
        } else {
746
            $fullParameterCollectionClass = $fullParameterClass . 'Collection';
747
748
            /** @var CompoundParameterCollection $parameterObjectCollection */
749
            $parameterObjectCollection = new $fullParameterCollectionClass($collectionIndex);
750
751
            $parameterObjectCollection->add($parameterObject);
752
753
            $this->compoundParametersCollections[$parameterClass . $collectionIndex] = $parameterObjectCollection;
754
        }
755
756
        return $this;
757
    }
758
759
    /**
760
     * Gets the value for a parameter.
761
     *
762
     * @SuppressWarnings(PHPMD.LongVariable)
763
     *
764
     * @param $methodName
765
     * @param array $methodArguments
766
     * @return string
767
     * @throws \InvalidArgumentException
768
     */
769
    protected function getParameter($methodName, array $methodArguments)
770
    {
771
        $parameterClass = substr($methodName, 3);
772
773
        $fullParameterClass = $this->getFullParameterClass($parameterClass, $methodName);
774
775
        // Handle index arguments
776
        $parameterIndex = '';
777
        if (isset($methodArguments[0]) && is_numeric($methodArguments[0])) {
778
            $parameterIndex = $methodArguments[0];
779
        }
780
781
        // Handle compoundParametersCollections
782
        if (isset($this->compoundParametersCollections[$parameterClass . $parameterIndex])) {
783
            // If compoundParametersCollections contains our Objects, return them well-formatted
784
            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 string.

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...
785
        } else {
786
            $fullParameterCollectionClass = $fullParameterClass . 'Collection';
787
788
            // Test if the class Collection exist
789
            if (class_exists($fullParameterCollectionClass)) {
790
                return null;
791
            }
792
            // If not, it's a SingleParameter Object, continue the magic
793
        }
794
795
        /** @var SingleParameter $parameterObject */
796
        $parameterObject = new $fullParameterClass($parameterIndex);
797
798
        if (!array_key_exists($parameterObject->getName(), $this->singleParameters)) {
799
            return null;
800
        }
801
802
        $currentParameterObject = $this->singleParameters[$parameterObject->getName()];
803
804
        return $currentParameterObject->getValue();
805
806
    }
807
808
    /**
809
     * Gets the index value from the arguments.
810
     *
811
     * @param $methodArguments
812
     * @return string
813
     */
814
    protected function getIndexFromArguments($methodArguments)
815
    {
816
        $index = '';
817
        if (isset($methodArguments[1]) && is_numeric($methodArguments[1])) {
818
            $index = $methodArguments[1];
819
        }
820
821
        return $index;
822
    }
823
824
    /**
825
     * Gets the fully qualified name for a parameter.
826
     *
827
     * @param $parameterClass
828
     * @param $methodName
829
     * @return string
830
     * @throws \BadMethodCallException
831
     */
832
    protected function getFullParameterClass($parameterClass, $methodName)
833
    {
834
        if (empty($this->availableParameters[$parameterClass])) {
835
            throw new \BadMethodCallException('Method ' . $methodName . ' not defined for Analytics class');
836
        } else {
837
            return '\\TheIconic\\Tracking\\GoogleAnalytics\\Parameters\\' . $this->availableParameters[$parameterClass];
838
        }
839
    }
840
841
    /**
842
     * Routes the method call to the adequate protected method.
843
     *
844
     * @param $methodName
845
     * @param array $methodArguments
846
     * @return mixed
847
     * @throws \BadMethodCallException
848
     */
849
    public function __call($methodName, array $methodArguments)
850
    {
851
        $methodName = $this->fixTypos($methodName);
852
853
        if (preg_match('/^set(Product|Promotion)ActionTo(\w+)/', $methodName, $matches)) {
854
            return $this->setParameterActionTo($matches[1], $matches[2]);
855
        }
856
857
        if (preg_match('/^(set)(\w+)/', $methodName, $matches)) {
858
            return $this->setParameter($methodName, $methodArguments);
859
        }
860
861
        if (preg_match('/^(add)(\w+)/', $methodName, $matches)) {
862
            return $this->addItem($methodName, $methodArguments);
863
        }
864
865
        if (preg_match('/^(send)(\w+)/', $methodName, $matches)) {
866
            return $this->sendHit($methodName);
867
        }
868
869
        // Get Parameters
870
        if (preg_match('/^(get)(\w+)/', $methodName, $matches)) {
871
            return $this->getParameter($methodName, $methodArguments);
872
        }
873
874
        throw new \BadMethodCallException('Method ' . $methodName . ' not defined for Analytics class');
875
    }
876
877
    /**
878
     * Fix typos that went into releases, this way we ensure we don't break scripts in production.
879
     *
880
     * @param string $methodName
881
     * @return string
882
     */
883
    protected function fixTypos($methodName)
884
    {
885
        // @TODO deprecated in v2, to be removed in v3
886
        if ($methodName === 'setUserTiminCategory') {
887
            $methodName = 'setUserTimingCategory';
888
        }
889
890
        return $methodName;
891
    }
892
}
893