Passed
Push — v4 ( 140115...483dd2 )
by Andrew
26:45 queued 20:28
created

Analytics::addCommerceProductDetailView()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
nc 1
nop 3
dl 0
loc 3
rs 10
c 1
b 0
f 0
1
<?php
2
/**
3
 * Instant Analytics plugin for Craft CMS
4
 *
5
 * @author    nystudio107
0 ignored issues
show
Coding Style introduced by
The tag in position 1 should be the @package tag
Loading history...
Coding Style introduced by
Content of the @author tag must be in the form "Display Name <[email protected]>"
Loading history...
6
 * @copyright Copyright (c) 2017 nystudio107
0 ignored issues
show
Coding Style introduced by
The tag in position 2 should be the @author tag
Loading history...
Coding Style introduced by
@copyright tag must contain a year and the name of the copyright holder
Loading history...
7
 * @link      http://nystudio107.com
0 ignored issues
show
Coding Style introduced by
The tag in position 3 should be the @copyright tag
Loading history...
8
 * @package   InstantAnalytics
0 ignored issues
show
Coding Style introduced by
The tag in position 4 should be the @link tag
Loading history...
9
 * @since     1.0.0
10
 */
0 ignored issues
show
Coding Style introduced by
PHP version not specified
Loading history...
Coding Style introduced by
Missing @category tag in file comment
Loading history...
Coding Style introduced by
Missing @license tag in file comment
Loading history...
11
12
namespace nystudio107\instantanalyticsGa4\ga4;
13
14
use Br33f\Ga4\MeasurementProtocol\Dto\Event\AbstractEvent;
15
use Br33f\Ga4\MeasurementProtocol\Dto\Request\BaseRequest;
16
use Br33f\Ga4\MeasurementProtocol\Dto\Response\BaseResponse;
17
use Br33f\Ga4\MeasurementProtocol\HttpClient;
18
use Craft;
19
use craft\commerce\elements\Product;
0 ignored issues
show
Bug introduced by
The type craft\commerce\elements\Product was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
20
use craft\commerce\elements\Variant;
0 ignored issues
show
Bug introduced by
The type craft\commerce\elements\Variant was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
21
use craft\errors\MissingComponentException;
22
use craft\helpers\App;
23
use nystudio107\instantanalyticsGa4\helpers\Analytics as AnalyticsHelper;
24
use nystudio107\instantanalyticsGa4\InstantAnalytics;
25
use nystudio107\seomatic\Seomatic;
0 ignored issues
show
Bug introduced by
The type nystudio107\seomatic\Seomatic was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
26
27
/**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
28
 * @author    nystudio107
0 ignored issues
show
Coding Style introduced by
The tag in position 1 should be the @package tag
Loading history...
Coding Style introduced by
Content of the @author tag must be in the form "Display Name <[email protected]>"
Loading history...
Coding Style introduced by
Tag value for @author tag indented incorrectly; expected 2 spaces but found 4
Loading history...
29
 * @package   InstantAnalytics
0 ignored issues
show
Coding Style introduced by
Tag value for @package tag indented incorrectly; expected 1 spaces but found 3
Loading history...
30
 * @since     1.2.0
0 ignored issues
show
Coding Style introduced by
The tag in position 3 should be the @author tag
Loading history...
Coding Style introduced by
Tag value for @since tag indented incorrectly; expected 3 spaces but found 5
Loading history...
31
 *
32
 * @method Analytics setAllowGoogleSignals(string $value)
33
 * @method Analytics setAllowAdPersonalizationSignals(string $value)
34
 * @method Analytics setCampaignContent(string $value)
35
 * @method Analytics setCampaignId(string $value)
36
 * @method Analytics setCampaignMedium(string $value)
37
 * @method Analytics setCampaignName(string $value)
38
 * @method Analytics setCampaignSource(string $value)
39
 * @method Analytics setCampaignTerm(string $value)
40
 * @method Analytics setCampaign(string $value)
41
 * @method Analytics setClientId(string $value)
42
 * @method Analytics setContentGroup(string $value)
43
 * @method Analytics setCookieDomain(string $value)
44
 * @method Analytics setCookieExpires(string $value)
45
 * @method Analytics setCookieFlags(string $value)
46
 * @method Analytics setCookiePath(string $value)
47
 * @method Analytics setCookiePrefix(string $value)
48
 * @method Analytics setCookieUpdate(string $value)
49
 * @method Analytics setLanguage(string $value)
50
 * @method Analytics setPageLocation(string $value)
51
 * @method Analytics setPageReferrer(string $value)
52
 * @method Analytics setPageTitle(string $value)
53
 * @method Analytics setSendPageView(string $value)
54
 * @method Analytics setScreenResolution(string $value)
55
 * @method Analytics setUserId(string $value)
56
 */
0 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @link tag in class comment
Loading history...
57
class Analytics
58
{
59
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
60
     * @var BaseRequest|null
61
     */
62
    private ?BaseRequest $_request = null;
63
64
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
65
     * @var Service|null|false
66
     */
67
    private mixed $_service = null;
68
69
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
70
     * @var string|null
71
     */
72
    private ?string $_affiliation = null;
73
74
    private ?bool $_shouldSendAnalytics = null;
75
76
    /**
77
     * Component factory for creating events.
78
     *
79
     * @return ComponentFactory
80
     */
81
    public function create(): ComponentFactory
82
    {
83
        return new ComponentFactory();
84
    }
85
86
    /**
87
     * Add an event to be sent to Google
88
     *
89
     * @param AbstractEvent $event
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
90
     * @return BaseRequest
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
91
     */
92
    public function addEvent(AbstractEvent $event): BaseRequest
93
    {
94
        return $this->request()->addEvent($event);
95
    }
96
97
    /**
98
     * Send the events collected so far.
99
     *
100
     * @return BaseResponse|null
101
     * @throws \Br33f\Ga4\MeasurementProtocol\Exception\HydrationException
102
     * @throws \Br33f\Ga4\MeasurementProtocol\Exception\ValidationException
103
     */
104
    public function sendCollectedEvents(): ?BaseResponse
105
    {
106
        if ($this->_shouldSendAnalytics === null) {
107
            $this->_shouldSendAnalytics = AnalyticsHelper::shouldSendAnalytics();
108
        }
109
110
        if (!$this->_shouldSendAnalytics) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->_shouldSendAnalytics of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
111
            return null;
112
        }
113
114
        $service = $this->service();
115
116
        if (!$service) {
117
            return null;
118
        }
119
120
        $request = $this->request();
121
        $eventCount = count($request->getEvents()->getEventList());
122
123
        if (!InstantAnalytics::$settings->sendAnalyticsData) {
124
            InstantAnalytics::$plugin->logAnalyticsEvent(
0 ignored issues
show
Bug introduced by
The method logAnalyticsEvent() does not exist on null. ( Ignorable by Annotation )

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

124
            InstantAnalytics::$plugin->/** @scrutinizer ignore-call */ 
125
                                       logAnalyticsEvent(

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
125
                'Analytics not enabled - skipped sending {count} events',
126
                ['count' => $eventCount],
127
                __METHOD__
128
            );
129
130
            return null;
131
        }
132
133
        if ($eventCount === 0) {
134
            InstantAnalytics::$plugin->logAnalyticsEvent(
135
                'No events collected to send',
136
                [],
137
                __METHOD__
138
            );
139
140
            return null;
141
        }
142
143
        InstantAnalytics::$plugin->logAnalyticsEvent(
144
            'Sending {count} analytics events',
145
            ['count' => $eventCount],
146
            __METHOD__
147
        );
148
149
        $response = $service->send($request);
150
151
        // Clear events already sent from the list.
152
        $request->getEvents()->setEventList([]);
153
154
        return $response;
155
    }
156
157
    /**
158
     * Set affiliation for all the events that incorporate Commerce Product info for the remaining duration of request.
159
     *
160
     * @param string $affiliation
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
161
     * @return $this
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
162
     */
163
    public function setAffiliation(string $affiliation): self
164
    {
165
        $this->_affiliation = $affiliation;
166
        return $this;
167
    }
168
169
    public function getAffiliation(): ?string
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function getAffiliation()
Loading history...
170
    {
171
        return $this->_affiliation;
172
    }
173
174
    /**
175
     * Add a commerce item list impression.
176
     *
177
     * @param Product|Variant $productVariant
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
178
     * @param $index
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
179
     * @param string $listName
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 10 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
180
     * @throws \yii\base\InvalidConfigException
0 ignored issues
show
Coding Style introduced by
Tag @throws cannot be grouped with parameter tags in a doc comment
Loading history...
181
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
182
    public function addCommerceProductImpression(Product|Variant $productVariant, $index, string $listName = 'default') {
0 ignored issues
show
Coding Style introduced by
Opening brace should be on a new line
Loading history...
183
        InstantAnalytics::$plugin->commerce->addCommerceProductImpression($productVariant, $index, $listName);
184
    }
185
186
    /**
187
     * Add a commerce item list impression.
188
     *
189
     * @param Product|Variant $productVariant
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 6 spaces but found 1
Loading history...
190
     * @param $index
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 6 spaces but found 1
Loading history...
191
     * @param string $listName
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 10 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 6 spaces but found 1
Loading history...
192
     * @deprecated `Analytics::addCommerceProductDetailView()` is deprecated. Use `Analytics::addCommerceProductImpression()` instead.
0 ignored issues
show
Coding Style introduced by
Tag @deprecated cannot be grouped with parameter tags in a doc comment
Loading history...
193
     * @throws \yii\base\InvalidConfigException
0 ignored issues
show
Coding Style introduced by
Tag @throws cannot be grouped with parameter tags in a doc comment
Loading history...
Coding Style introduced by
Tag value for @throws tag indented incorrectly; expected 5 spaces but found 1
Loading history...
194
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
195
    public function addCommerceProductDetailView(Product|Variant $productVariant, $index, string $listName = 'default') {
0 ignored issues
show
Coding Style introduced by
Opening brace should be on a new line
Loading history...
196
        Craft::$app->getDeprecator()->log('Analytics::addCommerceProductDetailView()', '`Analytics::addCommerceProductDetailView()` is deprecated. Use `Analytics::addCommerceProductImpression()` instead.');
197
        InstantAnalytics::$plugin->commerce->addCommerceProductImpression($productVariant, $index, $listName);
198
    }
199
200
    /**
201
     * Add a commerce product list impression.
202
     *
203
     * @param array $products
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
204
     * @param $listName
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
205
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
206
    public function addCommerceProductListImpression(array $products, $listName) {
0 ignored issues
show
Coding Style introduced by
Opening brace should be on a new line
Loading history...
207
        InstantAnalytics::$plugin->commerce->addCommerceProductListImpression($products, $listName);
208
    }
209
210
    /**
211
     * Set the measurement id.
212
     *
213
     * @param string $measurementId
0 ignored issues
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
Coding Style introduced by
Missing parameter comment
Loading history...
214
     * @return $this
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
215
     */
216
    public function setMeasurementId(string $measurementId): self
217
    {
218
        $this->service()?->setMeasurementId($measurementId);
219
        return $this;
220
    }
221
222
    /**
223
     * Set the API secret.
224
     *
225
     * @param string $apiSecret
0 ignored issues
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
Coding Style introduced by
Missing parameter comment
Loading history...
226
     * @return $this
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
227
     */
228
    public function setApiSecret(string $apiSecret): self
229
    {
230
        $this->service()?->setApiSecret($apiSecret);
231
        return $this;
232
    }
233
234
    public function __call(string $methodName, array $arguments): ?self
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __call()
Loading history...
235
    {
236
        $knownProperties = [
237
            'allowGoogleSignals' => 'allow_google_signals',
238
            'allowAdPersonalizationSignals' => 'allow_ad_personalization_signals',
239
            'campaignContent' => 'campaign_content',
240
            'campaignId' => 'campaign_id',
241
            'campaignMedium' => 'campaign_medium',
242
            'campaignName' => 'campaign_name',
243
            'campaignSource' => 'campaign_source',
244
            'campaignTerm' => 'campaign_term',
245
            'campaign' => 'campaign',
246
            'clientId' => 'client_id',
247
            'contentGroup' => 'content_group',
248
            'cookieDomain' => 'cookie_domain',
249
            'cookieExpires' => 'cookie_expires',
250
            'cookieFlags' => 'cookie_flags',
251
            'cookiePath' => 'cookie_path',
252
            'cookiePrefix' => 'cookie_prefix',
253
            'cookieUpdate' => 'cookie_update',
254
            'language' => 'language',
255
            'pageLocation' => 'page_location',
256
            'pageReferrer' => 'page_referrer',
257
            'pageTitle' => 'page_title',
258
            'sendPageView' => 'send_page_view',
259
            'screenResolution' => 'screen_resolution',
260
            'userId' => 'user_id'
261
        ];
262
263
        if (str_starts_with($methodName, 'set')) {
264
            $methodName = lcfirst(substr($methodName, 3));
265
266
            $service = $this->service();
267
            if ($service && !empty($knownProperties[$methodName])) {
268
                $service->setAdditionalQueryParam($knownProperties[$methodName], $arguments[0]);
269
270
                return $this;
271
            }
272
273
        }
274
275
        return null;
276
    }
277
278
    protected function request(): BaseRequest
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function request()
Loading history...
279
    {
280
        if ($this->_request === null) {
281
            $this->_request = new BaseRequest();
282
            $this->_request->setClientId(AnalyticsHelper::getClientId());
0 ignored issues
show
Bug introduced by
The method setClientId() does not exist on null. ( Ignorable by Annotation )

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

282
            $this->_request->/** @scrutinizer ignore-call */ 
283
                             setClientId(AnalyticsHelper::getClientId());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
283
        }
284
285
        return $this->_request;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->_request could return the type null which is incompatible with the type-hinted return Br33f\Ga4\MeasurementPro...Dto\Request\BaseRequest. Consider adding an additional type-check to rule them out.
Loading history...
286
    }
287
288
    /**
289
     * Init the service used to send events
290
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
291
    public function init(): void
292
    {
293
        $this->service();
294
        $this->request();
295
    }
296
297
    protected function service(): ?Service
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function service()
Loading history...
298
    {
299
        if ($this->_service === null) {
300
            $settings = InstantAnalytics::$settings;
301
            $apiSecret = App::parseEnv($settings->googleAnalyticsMeasurementApiSecret);
302
            $measurementId = App::parseEnv($settings->googleAnalyticsMeasurementId);
303
304
            if (empty($apiSecret) || empty($measurementId)) {
305
                InstantAnalytics::$plugin->logAnalyticsEvent(
306
                    'API secret or measurement ID not set up for Instant Analytics',
307
                    [],
308
                    __METHOD__
309
                );
310
                $this->_service = false;
311
312
                return null;
313
            }
314
            $this->_service = new Service($apiSecret, $measurementId);
315
316
            $ga4Client = new HttpClient();
317
            $ga4Client->setClient(Craft::createGuzzleClient());
318
            $this->_service->setHttpClient($ga4Client);
319
320
            $request = Craft::$app->getRequest();
321
            try {
322
                $session = Craft::$app->getSession();
323
            } catch (MissingComponentException $exception) {
324
                $session = null;
325
            }
326
327
            $this->setPageReferrer($request->getReferrer());
328
329
            // Load any campaign values from session or request
330
            $campaignParams = [
331
                'utm_source' => 'CampaignSource',
332
                'utm_medium' => 'CampaignMedium',
333
                'utm_campaign' => 'CampaignName',
334
                'utm_content' => 'CampaignContent',
335
                'utm_term' => 'CampaignTerm',
336
            ];
337
338
            // Load them up for GA4
339
            foreach ($campaignParams as $key => $method) {
340
                $value = $request->getParam($key) ?? $session->get($key) ?? null;
341
                $method = 'set' . $method;
342
343
                $this->$method($value);
344
345
                if ($session && $value) {
346
                    $session->set($key, $value);
347
                }
348
349
            }
350
351
            // If SEOmatic is installed, set the affiliation as well
352
            if (InstantAnalytics::$seomaticPlugin && Seomatic::$settings->renderEnabled && Seomatic::$plugin->metaContainers->metaSiteVars !== null) {
353
                $siteName = Seomatic::$plugin->metaContainers->metaSiteVars->siteName;
354
                $this->setAffiliation($siteName);
355
            }
356
357
        }
358
359
        if ($this->_service === false) {
360
            return null;
361
        }
362
363
        return $this->_service;
364
    }
365
}
366