Commerce   F
last analyzed

Complexity

Total Complexity 75

Size/Duplication

Total Lines 500
Duplicated Lines 0 %

Importance

Changes 11
Bugs 1 Features 0
Metric Value
wmc 75
eloc 228
c 11
b 1
f 0
dl 0
loc 500
rs 2.4

11 Methods

Rating   Name   Duplication   Size   Complexity  
C addProductDataFromLineItem() 0 61 13
A addCommerceOrderToAnalytics() 0 22 5
A addCommerceProductImpression() 0 30 6
A addCommerceProductDetailView() 0 16 3
A addCommerceCheckoutStep() 0 26 5
A orderComplete() 0 21 3
A addToCart() 0 22 3
F getProductDataFromProduct() 0 98 21
A removeFromCart() 0 27 3
A getDataFromElements() 0 28 5
B pullDataFromField() 0 30 8

How to fix   Complexity   

Complex Class

Complex classes like Commerce often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Commerce, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Instant Analytics plugin for Craft CMS
4
 *
5
 * Instant Analytics brings full Google Analytics support to your Twig templates
6
 *
7
 * @link      https://nystudio107.com
0 ignored issues
show
Coding Style introduced by
The tag in position 1 should be the @copyright tag
Loading history...
8
 * @copyright Copyright (c) 2017 nystudio107
0 ignored issues
show
Coding Style introduced by
@copyright tag must contain a year and the name of the copyright holder
Loading history...
9
 */
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 @package tag in file comment
Loading history...
Coding Style introduced by
Missing @author tag in file comment
Loading history...
Coding Style introduced by
Missing @license tag in file comment
Loading history...
10
11
namespace nystudio107\instantanalytics\services;
12
13
use Craft;
14
use craft\base\Component;
15
use craft\commerce\base\Purchasable;
0 ignored issues
show
Bug introduced by
The type craft\commerce\base\Purchasable 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...
16
use craft\commerce\elements\Order;
0 ignored issues
show
Bug introduced by
The type craft\commerce\elements\Order 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...
17
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...
18
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...
19
use craft\commerce\models\LineItem;
0 ignored issues
show
Bug introduced by
The type craft\commerce\models\LineItem 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\elements\db\CategoryQuery;
21
use craft\elements\db\MatrixBlockQuery;
22
use craft\elements\db\TagQuery;
23
use nystudio107\instantanalytics\helpers\IAnalytics;
24
use nystudio107\instantanalytics\InstantAnalytics;
25
26
/**
27
 * Commerce Service
28
 *
29
 * @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...
30
 * @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...
31
 * @since     1.0.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...
32
 */
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...
33
class Commerce extends Component
34
{
35
    // Public Methods
36
    // =========================================================================
37
38
    /**
39
     * Send analytics information for the completed order
40
     *
41
     * @param Order $order the Product or Variant
42
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
43
    public function orderComplete($order = null)
44
    {
45
        if ($order) {
46
            $analytics = InstantAnalytics::$plugin->ia->eventAnalytics(
47
                'Commerce',
48
                'Purchase',
49
                $order->reference,
50
                $order->totalPrice
51
            );
52
53
            if ($analytics) {
54
                $this->addCommerceOrderToAnalytics($analytics, $order);
55
                // Don't forget to set the product action, in this case to PURCHASE
56
                $analytics->setProductActionToPurchase();
57
                $analytics->sendEvent();
58
59
                Craft::info(Craft::t(
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
60
                    'instant-analytics',
61
                    'orderComplete for `Commerce` - `Purchase` - `{reference}` - `{price}`',
62
                    ['reference' => $order->reference, 'price' => $order->totalPrice]
63
                ), __METHOD__);
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
64
            }
65
        }
66
    }
67
68
    /**
69
     * Send analytics information for the item added to the cart
70
     *
71
     * @param Order $order the Product or Variant
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Expected 4 spaces after parameter name; 1 found
Loading history...
72
     * @param LineItem $lineItem the line item that was added
73
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
74
    public function addToCart(
75
        /** @noinspection PhpUnusedParameterInspection */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
76
        $order = null, $lineItem = null
77
    )
78
    {
0 ignored issues
show
Coding Style introduced by
The closing parenthesis and the opening brace of a multi-line function declaration must be on the same line
Loading history...
79
        if ($lineItem) {
80
            $title = $lineItem->purchasable->title ?? $lineItem->description;
81
            $quantity = $lineItem->qty;
82
            $analytics = InstantAnalytics::$plugin->ia->eventAnalytics('Commerce', 'Add to Cart', $title, $quantity);
83
84
            if ($analytics) {
85
                $title = $this->addProductDataFromLineItem($analytics, $lineItem);
86
                $analytics->setEventLabel($title);
87
                // Don't forget to set the product action, in this case to ADD
88
                $analytics->setProductActionToAdd();
89
                $analytics->sendEvent();
90
91
                Craft::info(Craft::t(
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
92
                    'instant-analytics',
93
                    'addToCart for `Commerce` - `Add to Cart` - `{title}` - `{quantity}`',
94
                    ['title' => $title, 'quantity' => $quantity]
95
                ), __METHOD__);
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
96
            }
97
        }
98
    }
99
100
    /**
101
     * Send analytics information for the item removed from the cart
102
     *
103
     * @param Order|null $order
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 4 spaces after parameter type; 1 found
Loading history...
104
     * @param LineItem|null $lineItem
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
105
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
106
    public function removeFromCart(
107
        /** @noinspection PhpUnusedParameterInspection */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
108
        $order = null, $lineItem = null
109
    )
110
    {
0 ignored issues
show
Coding Style introduced by
The closing parenthesis and the opening brace of a multi-line function declaration must be on the same line
Loading history...
111
        if ($lineItem) {
112
            $title = $lineItem->purchasable->title ?? $lineItem->description;
113
            $quantity = $lineItem->qty;
114
            $analytics = InstantAnalytics::$plugin->ia->eventAnalytics(
115
                'Commerce',
116
                'Remove from Cart',
117
                $title,
118
                $quantity
119
            );
120
121
            if ($analytics) {
122
                $title = $this->addProductDataFromLineItem($analytics, $lineItem);
123
                $analytics->setEventLabel($title);
124
                // Don't forget to set the product action, in this case to ADD
125
                $analytics->setProductActionToRemove();
126
                $analytics->sendEvent();
127
128
                Craft::info(Craft::t(
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
129
                    'instant-analytics',
130
                    'removeFromCart for `Commerce` - `Remove to Cart` - `{title}` - `{quantity}`',
131
                    ['title' => $title, 'quantity' => $quantity]
132
                ), __METHOD__);
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
133
            }
134
        }
135
    }
136
137
138
    /**
139
     * Add a Craft Commerce OrderModel to an Analytics object
140
     *
141
     * @param IAnalytics $analytics the Analytics object
142
     * @param Order $order the Product or Variant
0 ignored issues
show
Coding Style introduced by
Expected 6 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Expected 5 spaces after parameter name; 1 found
Loading history...
143
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
144
    public function addCommerceOrderToAnalytics($analytics = null, $order = null)
145
    {
146
        if ($order && $analytics) {
147
            // First, include the transaction data
148
            $analytics->setTransactionId($order->reference)
149
                ->setCurrencyCode($order->paymentCurrency)
150
                ->setRevenue($order->totalPrice)
151
                ->setTax($order->getTotalTax())
152
                ->setShipping($order->getTotalShippingCost());
153
154
            // Coupon code?
155
            if ($order->couponCode) {
156
                $analytics->setCouponCode($order->couponCode);
157
            }
158
159
            // Add each line item in the transaction
160
            // Two cases - variant and non variant products
161
            $index = 1;
162
163
            foreach ($order->lineItems as $key => $lineItem) {
164
                $this->addProductDataFromLineItem($analytics, $lineItem, $index, '');
165
                $index++;
166
            }
167
        }
168
    }
169
170
    /**
171
     * Add a Craft Commerce LineItem to an Analytics object
172
     *
173
     * @param IAnalytics|null $analytics
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
174
     * @param LineItem|null $lineItem
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 3 spaces after parameter type; 1 found
Loading history...
175
     * @param int $index
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 13 spaces after parameter type; 1 found
Loading history...
176
     * @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...
177
     *
178
     * @return string the title of the product
179
     * @throws \yii\base\InvalidConfigException
180
     */
181
    public function addProductDataFromLineItem($analytics = null, $lineItem = null, $index = 0, $listName = ''): string
182
    {
183
        $result = '';
184
        if ($lineItem && $analytics) {
185
            $product = null;
186
            $purchasable = $lineItem->purchasable;
187
            //This is the same for both variant and non variant products
188
            $productData = [
189
                'name' => $purchasable->title ?? $lineItem->description,
190
                'sku' => $purchasable->sku ?? $lineItem->sku,
191
                'price' => $lineItem->salePrice,
192
                'quantity' => $lineItem->qty,
193
            ];
194
            // Handle this purchasable being a Variant
195
            if (is_a($purchasable, Variant::class)) {
196
                /** @var Variant $purchasable */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
197
                $product = $purchasable->getProduct();
198
                $variant = $purchasable;
199
                // Product with variants
200
                $productData['name'] = $product->title;
201
                $productData['variant'] = $variant->title;
202
                $productData['category'] = $product->getType();
203
            }
204
            // Handle this purchasable being a Product
205
            if (is_a($purchasable, Product::class)) {
206
                /** @var Product $purchasable */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
207
                $product = $purchasable;
208
                $productData['name'] = $product->title;
209
                $productData['variant'] = $product->title;
210
                $productData['category'] = $product->getType();
211
            }
212
            // Handle product lists
213
            if ($index) {
214
                $productData['position'] = $index;
215
            }
216
            if ($listName) {
217
                $productData['list'] = $listName;
218
            }
219
            // Add in any custom categories/brands that might be set
220
            if (InstantAnalytics::$settings && $product) {
221
                if (isset(InstantAnalytics::$settings['productCategoryField'])
222
                    && !empty(InstantAnalytics::$settings['productCategoryField'])) {
0 ignored issues
show
Coding Style introduced by
Closing parenthesis of a multi-line IF statement must be on a new line
Loading history...
223
                    $productData['category'] = $this->pullDataFromField(
224
                        $product,
225
                        InstantAnalytics::$settings['productCategoryField']
226
                    );
227
                }
228
                if (isset(InstantAnalytics::$settings['productBrandField'])
229
                    && !empty(InstantAnalytics::$settings['productBrandField'])) {
0 ignored issues
show
Coding Style introduced by
Closing parenthesis of a multi-line IF statement must be on a new line
Loading history...
230
                    $productData['brand'] = $this->pullDataFromField(
231
                        $product,
232
                        InstantAnalytics::$settings['productBrandField']
233
                    );
234
                }
235
            }
236
            $result = $productData['name'];
237
            //Add each product to the hit to be sent
238
            $analytics->addProduct($productData);
239
        }
240
241
        return $result;
242
    }
243
244
    /**
245
     * Add a product impression from a Craft Commerce Product or Variant
246
     *
247
     * @param IAnalytics $analytics the Analytics object
0 ignored issues
show
Coding Style introduced by
Expected 6 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Expected 6 spaces after parameter name; 1 found
Loading history...
248
     * @param Product|Variant $productVariant the Product or Variant
249
     * @param int $index Where the product appears in the
0 ignored issues
show
Coding Style introduced by
Expected 13 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Expected 10 spaces after parameter name; 1 found
Loading history...
250
     *                                        list
0 ignored issues
show
Coding Style introduced by
Parameter comment not aligned correctly; expected 19 spaces but found 40
Loading history...
251
     * @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...
252
     * @param int $listIndex
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 13 spaces after parameter type; 1 found
Loading history...
253
     *
254
     * @throws \yii\base\InvalidConfigException
255
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
256
    public function addCommerceProductImpression(
257
        $analytics = null,
258
        $productVariant = null,
259
        $index = 0,
260
        $listName = 'default',
261
        $listIndex = 1
262
    )
263
    {
0 ignored issues
show
Coding Style introduced by
The closing parenthesis and the opening brace of a multi-line function declaration must be on the same line
Loading history...
264
        if ($productVariant && $analytics) {
265
            $productData = $this->getProductDataFromProduct($productVariant);
266
267
            /**
268
             * As per: https://github.com/theiconic/php-ga-measurement-protocol/issues/26
269
             */
270
            if ($listName && $listIndex) {
271
                $analytics->setProductImpressionListName($listName, $listIndex);
272
            }
273
274
            if ($index) {
275
                $productData['position'] = $index;
276
            }
277
278
            //Add the product to the hit to be sent
279
            $analytics->addProductImpression($productData, $listIndex);
280
281
            Craft::info(Craft::t(
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
282
                'instant-analytics',
283
                'addCommerceProductImpression for `{sku}` - `{name}` - `{name}` - `{index}`',
284
                ['sku' => $productData['sku'], 'name' => $productData['name'], 'index' => $index]
285
            ), __METHOD__);
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
286
        }
287
    }
288
289
    /**
290
     * Add a product detail view from a Craft Commerce Product or Variant
291
     *
292
     * @param IAnalytics $analytics the Analytics object
0 ignored issues
show
Coding Style introduced by
Expected 6 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Expected 6 spaces after parameter name; 1 found
Loading history...
293
     * @param Product|Variant $productVariant the Product or Variant
294
     *
295
     * @throws \yii\base\InvalidConfigException
296
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
297
    public function addCommerceProductDetailView($analytics = null, $productVariant = null)
298
    {
299
        if ($productVariant && $analytics) {
300
            $productData = $this->getProductDataFromProduct($productVariant);
301
302
            // Don't forget to set the product action, in this case to DETAIL
303
            $analytics->setProductActionToDetail();
304
305
            //Add the product to the hit to be sent
306
            $analytics->addProduct($productData);
307
308
            Craft::info(Craft::t(
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
309
                'instant-analytics',
310
                'addCommerceProductDetailView for `{sku}` - `{name}`',
311
                ['sku' => $productData['sku'], 'name' => $productData['name']]
312
            ), __METHOD__);
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
313
        }
314
    }
315
316
    /**
317
     * Add a checkout step and option to an Analytics object
318
     *
319
     * @param IAnalytics $analytics the Analytics object
320
     * @param Order $order the Product or Variant
0 ignored issues
show
Coding Style introduced by
Expected 6 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Expected 5 spaces after parameter name; 1 found
Loading history...
321
     * @param int $step the checkout step
0 ignored issues
show
Coding Style introduced by
Expected 8 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Expected 6 spaces after parameter name; 1 found
Loading history...
322
     * @param string $option the checkout option
0 ignored issues
show
Coding Style introduced by
Expected 5 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Expected 4 spaces after parameter name; 1 found
Loading history...
323
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
324
    public function addCommerceCheckoutStep($analytics = null, $order = null, $step = 1, $option = '')
325
    {
326
        if ($order && $analytics) {
327
            // Add each line item in the transaction
328
            // Two cases - variant and non variant products
329
            $index = 1;
330
331
            foreach ($order->lineItems as $key => $lineItem) {
332
                $this->addProductDataFromLineItem($analytics, $lineItem, $index, '');
333
                $index++;
334
            }
335
336
            $analytics->setCheckoutStep($step);
337
338
            if ($option) {
339
                $analytics->setCheckoutStepOption($option);
340
            }
341
342
            // Don't forget to set the product action, in this case to CHECKOUT
343
            $analytics->setProductActionToCheckout();
344
345
            Craft::info(Craft::t(
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
346
                'instant-analytics',
347
                'addCommerceCheckoutStep step: `{step}` with option: `{option}`',
348
                ['step' => $step, 'option' => $option]
349
            ), __METHOD__);
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
350
        }
351
    }
352
353
    /**
354
     * Extract product data from a Craft Commerce Product or Variant
355
     *
356
     * @param Product|Variant $productVariant the Product or Variant
357
     *
358
     * @return array the product data
359
     * @throws \yii\base\InvalidConfigException
360
     */
361
    public function getProductDataFromProduct($productVariant = null): array
362
    {
363
        $result = [];
364
365
        // Extract the variant if it's a Product or Purchasable
366
        if ($productVariant && \is_object($productVariant)) {
367
            if (is_a($productVariant, Product::class)
368
                || is_a($productVariant, Purchasable::class)
369
            ) {
370
                $productType = property_exists($productVariant, 'typeId')
371
                    ? InstantAnalytics::$commercePlugin->getProductTypes()->getProductTypeById($productVariant->typeId)
0 ignored issues
show
Bug introduced by
The method getProductTypes() 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

371
                    ? InstantAnalytics::$commercePlugin->/** @scrutinizer ignore-call */ getProductTypes()->getProductTypeById($productVariant->typeId)

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...
372
                    : null;
373
374
                if ($productType && $productType->hasVariants) {
375
                    $productVariants = $productVariant->getVariants();
376
                    $productVariant = reset($productVariants);
377
                    $product = $productVariant->getProduct();
378
379
                    if ($product) {
380
                        $category = $product->getType()['name'];
381
                        $name = $product->title;
382
                        $variant = $productVariant->title;
383
                    } else {
384
                        $category = $productVariant->getType()['name'];
385
                        $name = $productVariant->title;
386
                        $variant = '';
387
                    }
388
                } else {
389
                    if (!empty($productVariant->defaultVariantId)) {
390
                        /** @var Variant $productVariant */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
391
                        $productVariant = InstantAnalytics::$commercePlugin->getVariants()->getVariantById(
392
                            $productVariant->defaultVariantId
393
                        );
394
                        $category = $productVariant->getProduct()->getType()['name'];
395
                        $name = $productVariant->title;
396
                        $variant = '';
397
                    } else {
398
                        if (isset($productVariant->product)) {
399
                            $category = $productVariant->product->getType()['name'];
400
                            $name = $productVariant->product->title;
401
                        } else {
402
                            $category = $productVariant->getType()['name'];
403
                            $name = $productVariant->title;
404
                        }
405
                        $variant = $productVariant->title;
406
                    }
407
                }
408
            }
409
410
            $productData = [
411
                'sku' => $productVariant->sku,
412
                'name' => $name,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $name does not seem to be defined for all execution paths leading up to this point.
Loading history...
413
                'price' => number_format($productVariant->price, 2, '.', ''),
414
                'category' => $category,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $category does not seem to be defined for all execution paths leading up to this point.
Loading history...
415
            ];
416
417
            if ($variant) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $variant does not seem to be defined for all execution paths leading up to this point.
Loading history...
418
                $productData['variant'] = $variant;
419
            }
420
421
            $isVariant = is_a($productVariant, Variant::class);
422
423
            if (InstantAnalytics::$settings) {
424
                if (isset(InstantAnalytics::$settings['productCategoryField'])
425
                    && !empty(InstantAnalytics::$settings['productCategoryField'])) {
0 ignored issues
show
Coding Style introduced by
Closing parenthesis of a multi-line IF statement must be on a new line
Loading history...
426
                    $productData['category'] = $this->pullDataFromField(
427
                        $productVariant,
428
                        InstantAnalytics::$settings['productCategoryField']
429
                    );
430
                    if (empty($productData['category']) && $isVariant) {
431
                        $productData['category'] = $this->pullDataFromField(
432
                            $productVariant->product,
433
                            InstantAnalytics::$settings['productCategoryField']
434
                        );
435
                    }
436
                }
437
                if (isset(InstantAnalytics::$settings['productBrandField'])
438
                    && !empty(InstantAnalytics::$settings['productBrandField'])) {
0 ignored issues
show
Coding Style introduced by
Closing parenthesis of a multi-line IF statement must be on a new line
Loading history...
439
                    $productData['brand'] = $this->pullDataFromField(
440
                        $productVariant,
441
                        InstantAnalytics::$settings['productBrandField'],
442
                        true
443
                    );
444
445
                    if (empty($productData['brand']) && $isVariant) {
446
                        $productData['brand'] = $this->pullDataFromField(
447
                            $productVariant,
448
                            InstantAnalytics::$settings['productBrandField'],
449
                            true
450
                        );
451
                    }
452
                }
453
            }
454
455
            $result = $productData;
456
        }
457
458
        return $result;
459
    }
460
461
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
462
     * @param Product|Variant|null $productVariant
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
463
     * @param string $fieldHandle
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 15 spaces after parameter type; 1 found
Loading history...
464
     * @param bool $isBrand
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 17 spaces after parameter type; 1 found
Loading history...
465
     *
466
     * @return string
467
     */
468
    protected function pullDataFromField($productVariant, $fieldHandle, $isBrand = false): string
469
    {
470
        $result = '';
471
        if ($productVariant && $fieldHandle) {
472
            $srcField = $productVariant[$fieldHandle] ?? $productVariant->product[$fieldHandle] ?? null;
473
            // Handle eager loaded elements
474
            if (is_array($srcField)) {
475
                return $this->getDataFromElements($isBrand, $srcField);
476
            }
477
            // If the source field isn't an object, return nothing
478
            if (!is_object($srcField)) {
479
                return $result;
480
            }
481
            switch (\get_class($srcField)) {
482
                case MatrixBlockQuery::class:
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
483
                    break;
484
                case TagQuery::class:
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
485
                    break;
486
                case CategoryQuery::class:
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
487
                    $result = $this->getDataFromElements($isBrand, $srcField->all());
488
                    break;
489
490
491
                default:
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
492
                    $result = strip_tags($srcField);
0 ignored issues
show
Bug introduced by
$srcField of type object is incompatible with the type string expected by parameter $string of strip_tags(). ( Ignorable by Annotation )

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

492
                    $result = strip_tags(/** @scrutinizer ignore-type */ $srcField);
Loading history...
493
                    break;
494
            }
495
        }
496
497
        return $result;
498
    }
499
500
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
501
     * @param bool $isBrand
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 2 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...
502
     * @param array $elements
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...
503
     * @return string
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
504
     */
505
    protected function getDataFromElements(bool $isBrand, array $elements): string
506
    {
507
        $cats = [];
508
509
        if ($isBrand) {
510
            // Because we can only have one brand, we'll get
511
            // the very last category. This means if our
512
            // brand is a sub-category, we'll get the child
513
            // not the parent.
514
            foreach ($elements as $cat) {
515
                $cats = [$cat->title];
516
            }
517
        } else {
518
            // For every category, show its ancestors
519
            // delimited by a slash.
520
            foreach ($elements as $cat) {
521
                $name = $cat->title;
522
523
                while ($cat = $cat->parent) {
524
                    $name = $cat->title . '/' . $name;
525
                }
526
527
                $cats[] = $name;
528
            }
529
        }
530
531
        // Join separate categories with a pipe.
532
        return implode('|', $cats);
533
    }
534
}
535