Passed
Push — develop ( fc793b...3984b9 )
by Andrew
06:39
created

SeoProduct::installEventHandlers()   C

Complexity

Conditions 13
Paths 12

Size

Total Lines 85
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
eloc 30
nc 12
nop 0
dl 0
loc 85
rs 6.6166
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * SEOmatic plugin for Craft CMS 3.x
4
 *
5
 * A turnkey SEO implementation for Craft CMS that is comprehensive, powerful,
6
 * and flexible
7
 *
8
 * @link      https://nystudio107.com
9
 * @copyright Copyright (c) 2019 nystudio107
10
 */
11
12
namespace nystudio107\seomatic\seoelements;
13
14
use nystudio107\seomatic\Seomatic;
15
use nystudio107\seomatic\assetbundles\seomatic\SeomaticAsset;
16
use nystudio107\seomatic\base\SeoElementInterface;
17
use nystudio107\seomatic\helpers\ArrayHelper;
18
use nystudio107\seomatic\helpers\Config as ConfigHelper;
19
use nystudio107\seomatic\helpers\PluginTemplate;
20
use nystudio107\seomatic\models\MetaBundle;
21
22
use Craft;
23
use craft\base\ElementInterface;
24
use craft\base\Model;
25
use craft\elements\db\ElementQueryInterface;
26
use craft\models\Site;
27
28
use craft\commerce\Plugin as CommercePlugin;
0 ignored issues
show
Bug introduced by
The type craft\commerce\Plugin 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...
29
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...
30
use craft\commerce\events\ProductTypeEvent;
0 ignored issues
show
Bug introduced by
The type craft\commerce\events\ProductTypeEvent 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...
31
use craft\commerce\models\ProductType;
0 ignored issues
show
Bug introduced by
The type craft\commerce\models\ProductType 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...
32
use craft\commerce\services\ProductTypes;
0 ignored issues
show
Bug introduced by
The type craft\commerce\services\ProductTypes 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...
33
34
use yii\base\Event;
35
use yii\base\InvalidConfigException;
36
37
/**
38
 * @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...
39
 * @package   Seomatic
40
 * @since     3.2.0
0 ignored issues
show
Coding Style introduced by
The tag in position 3 should be the @author tag
Loading history...
41
 */
0 ignored issues
show
Coding Style introduced by
Missing @license tag in class comment
Loading history...
42
class SeoProduct implements SeoElementInterface
43
{
44
    // Constants
45
    // =========================================================================
46
47
    const META_BUNDLE_TYPE = 'product';
48
    const ELEMENT_CLASSES = [
49
        Product::class,
50
    ];
51
    const REQUIRED_PLUGIN_HANDLE = 'commerce';
52
    const CONFIG_FILE_PATH = 'productmeta/Bundle';
53
54
    // Public Static Methods
55
    // =========================================================================
56
57
    /**
58
     * Return the sourceBundleType for that this SeoElement handles
59
     *
60
     * @return string
61
     */
62
    public static function getMetaBundleType(): string
63
    {
64
        return self::META_BUNDLE_TYPE;
65
    }
66
67
    /**
68
     * Returns an array of the element classes that are handled by this SeoElement
69
     *
70
     * @return array
71
     */
72
    public static function getElementClasses(): array
73
    {
74
        return self::ELEMENT_CLASSES;
75
    }
76
77
    /**
78
     * Return the refHandle (e.g.: `entry` or `category`) for the SeoElement
79
     *
80
     * @return string
81
     */
82
    public static function getElementRefHandle(): string
83
    {
84
        return Product::refHandle();
85
    }
86
87
    /**
88
     * Return the handle to a required plugin for this SeoElement type
89
     *
90
     * @return null|string
91
     */
92
    public static function getRequiredPluginHandle()
93
    {
94
        return self::REQUIRED_PLUGIN_HANDLE;
95
    }
96
97
    /**
98
     * Install any event handlers for this SeoElement type
99
     */
100
    public static function installEventHandlers()
101
    {
102
        $request = Craft::$app->getRequest();
103
104
        // Install for all non-console requests
105
        if (!$request->getIsConsoleRequest()) {
106
            // Handler: ProductTypes::EVENT_AFTER_SAVE_PRODUCTTYPE
107
            Event::on(
108
                ProductTypes::class,
109
                ProductTypes::EVENT_AFTER_SAVE_PRODUCTTYPE,
110
                function (ProductTypeEvent $event) {
111
                    Craft::debug(
112
                        'ProductTypes::EVENT_AFTER_SAVE_PRODUCTTYPE',
113
                        __METHOD__
114
                    );
115
                    if ($event->productType !== null && $event->productType->id !== null) {
116
                        Seomatic::$plugin->metaBundles->invalidateMetaBundleById(
117
                            SeoProduct::getMetaBundleType(),
118
                            $event->productType->id,
119
                            $event->isNew
120
                        );
121
                        // Create the meta bundles for this Product Type if it's new
122
                        if ($event->isNew) {
123
                            SeoProduct::createContentMetaBundle($event->productType);
124
                            Seomatic::$plugin->sitemaps->submitSitemapIndex();
125
                        }
126
                    }
127
                }
128
            );
129
            /*
130
             * @TODO Sadly this event doesn't exist yet
131
            // Handler: ProductTypes::EVENT_AFTER_DELETE_PRODUCTTYPE
132
            Event::on(
133
                ProductTypes::class,
134
                ProductTypes::EVENT_AFTER_DELETE_PRODUCTTYPE,
135
                function (ProductTypeEvent $event) {
136
                    Craft::debug(
137
                        'ProductTypes::EVENT_AFTER_DELETE_PRODUCTTYPE',
138
                        __METHOD__
139
                    );
140
                    if ($event->productType !== null && $event->productType->id !== null) {
141
                        Seomatic::$plugin->metaBundles->invalidateMetaBundleById(
142
                            SeoProduct::getMetaBundleType(),
143
                            $event->productType->id,
144
                            false
145
                        );
146
                        // Delete the meta bundles for this Product Type
147
                        Seomatic::$plugin->metaBundles->deleteMetaBundleBySourceId(
148
                            SeoProduct::getMetaBundleType(),
149
                            $event->productType->id
150
                        );
151
                    }
152
                }
153
            );
154
            */
155
        }
156
157
        // Install only for non-console site requests
158
        if ($request->getIsSiteRequest() && !$request->getIsConsoleRequest()) {
159
        }
160
161
        // Install only for non-console Control Panel requests
162
        if ($request->getIsCpRequest() && !$request->getIsConsoleRequest()) {
163
            // Commerce Product Types sidebar
164
            $commerce = CommercePlugin::getInstance();
165
            if ($commerce !== null) {
166
                Seomatic::$view->hook('cp.commerce.product.edit.details', function (&$context) {
167
                    $html = '';
168
                    Seomatic::$view->registerAssetBundle(SeomaticAsset::class);
169
                    /** @var  $product Product */
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
The close comment tag must be the only content on the line
Loading history...
170
                    $product = $context['product'];
171
                    if ($product !== null && $product->uri !== null) {
172
                        Seomatic::$plugin->metaContainers->previewMetaContainers($product->uri, $product->siteId, true);
173
                        // Render our preview sidebar template
174
                        if (Seomatic::$settings->displayPreviewSidebar) {
175
                            $html .= PluginTemplate::renderPluginTemplate('_sidebars/product-preview.twig');
176
                        }
177
                        // Render our analysis sidebar template
178
// @TODO: This will be added an upcoming 'pro' edition
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected at least 24 spaces, found 0
Loading history...
Coding Style introduced by
This line of the multi-line function call does not seem to be indented correctly. Expected 20 spaces, but found 0.
Loading history...
179
//                if (Seomatic::$settings->displayAnalysisSidebar) {
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected at least 24 spaces, found 0
Loading history...
Coding Style introduced by
This line of the multi-line function call does not seem to be indented correctly. Expected 20 spaces, but found 0.
Loading history...
180
//                    $html .= PluginTemplate::renderPluginTemplate('_sidebars/product-analysis.twig');
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected at least 24 spaces, found 0
Loading history...
Coding Style introduced by
This line of the multi-line function call does not seem to be indented correctly. Expected 20 spaces, but found 0.
Loading history...
181
//                }
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected at least 24 spaces, found 0
Loading history...
Coding Style introduced by
This line of the multi-line function call does not seem to be indented correctly. Expected 20 spaces, but found 0.
Loading history...
182
                    }
183
184
                    return $html;
185
                });
186
            }
187
        }
188
    }
189
190
    /**
191
     * Return an ElementQuery for the sitemap elements for the given MetaBundle
192
     *
193
     * @param MetaBundle $metaBundle
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
194
     *
195
     * @return ElementQueryInterface
196
     */
197
    public static function sitemapElementsQuery(MetaBundle $metaBundle): ElementQueryInterface
198
    {
199
        $query = Product::find()
200
            ->type($metaBundle->sourceHandle)
201
            ->siteId($metaBundle->sourceSiteId)
202
            ->limit($metaBundle->metaSitemapVars->sitemapLimit)
203
            ->enabledForSite(true);
204
205
        return $query;
206
    }
207
208
    /**
209
     * Return an ElementInterface for the sitemap alt element for the given MetaBundle
210
     * and Element ID
211
     *
212
     * @param MetaBundle $metaBundle
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
213
     * @param int        $elementId
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
214
     * @param int        $siteId
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
215
     *
216
     * @return null|ElementInterface
217
     */
218
    public static function sitemapAltElement(
219
        MetaBundle $metaBundle,
220
        int $elementId,
221
        int $siteId
222
    ): ElementInterface {
223
        return Product::find()
224
            ->id($elementId)
225
            ->siteId($siteId)
226
            ->limit(1)
227
            ->enabledForSite(true)
228
            ->one();
229
    }
230
231
    /**
232
     * Return a preview URI for a given $sourceHandle and $siteId
233
     * This just returns the first element
234
     *
235
     * @param string    $sourceHandle
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 3 spaces after parameter type; 4 found
Loading history...
236
     * @param int|null  $siteId
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 1 spaces after parameter type; 2 found
Loading history...
237
     *
238
     * @return string|null
239
     */
240
    public static function previewUri(string $sourceHandle, $siteId)
241
    {
242
        $uri = null;
243
        $element = Product::find()
244
            ->type($sourceHandle)
245
            ->siteId($siteId)
246
            ->one();
247
        if ($element) {
248
            $uri = $element->uri;
249
        }
250
251
        return $uri;
252
    }
253
254
    /**
255
     * Return an array of FieldLayouts from the $sourceHandle
256
     *
257
     * @param string $sourceHandle
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
258
     *
259
     * @return array
260
     */
261
    public static function fieldLayouts(string $sourceHandle): array
262
    {
263
        $layouts = [];
264
        $commerce = CommercePlugin::getInstance();
265
        if ($commerce !== null) {
266
            $layoutId = null;
267
            try {
268
                $productType = $commerce->productTypes->getProductTypeByHandle($sourceHandle);
269
                if ($productType) {
270
                    $layoutId = $productType->getFieldLayoutId();
271
                }
272
            } catch (\Exception $e) {
273
                $layoutId = null;
274
            }
275
            if ($layoutId) {
276
                $layouts[] = Craft::$app->getFields()->getLayoutById($layoutId);
277
            }
278
        }
279
280
        return $layouts;
281
    }
282
283
    /**
284
     * Return the source model of the given $sourceId
285
     *
286
     * @param int $sourceId
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
287
     *
288
     * @return ProductType|null
289
     */
290
    public static function sourceModelFromId(int $sourceId)
291
    {
292
        $productType = null;
293
        $commerce = CommercePlugin::getInstance();
294
        if ($commerce !== null) {
295
            $productType = $commerce->productTypes->getProductTypeById($sourceId);
296
        }
297
298
        return $productType;
299
    }
300
301
    /**
302
     * Return the source model of the given $sourceId
303
     *
304
     * @param string $sourceHandle
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
305
     *
306
     * @return ProductType|null
307
     */
308
    public static function sourceModelFromHandle(string $sourceHandle)
309
    {
310
        $productType = null;
311
        $commerce = CommercePlugin::getInstance();
312
        if ($commerce !== null) {
313
            $productType = $commerce->productTypes->getProductTypeByHandle($sourceHandle);
314
        }
315
316
        return $productType;
317
    }
318
319
    /**
320
     * Return the most recently updated Element from a given source model
321
     *
322
     * @param Model $sourceModel
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
323
     * @param int   $sourceSiteId
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
324
     *
325
     * @return ElementInterface
326
     */
327
    public static function mostRecentElement(Model $sourceModel, int $sourceSiteId): ElementInterface
328
    {
329
        /** @var ProductType $sourceModel */
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
The close comment tag must be the only content on the line
Loading history...
330
        return Product::find()
331
            ->type($sourceModel->handle)
332
            ->siteId($sourceSiteId)
333
            ->limit(1)
334
            ->orderBy(['elements.dateUpdated' => SORT_DESC])
335
            ->one();
336
    }
337
338
    /**
339
     * Return the path to the config file directory
340
     *
341
     * @return string
342
     */
343
    public static function configFilePath(): string
344
    {
345
        return self::CONFIG_FILE_PATH;
346
    }
347
348
    /**
349
     * Return a meta bundle config array for the given $sourceModel
350
     *
351
     * @param Model $sourceModel
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
352
     *
353
     * @return array
354
     */
355
    public static function metaBundleConfig(Model $sourceModel): array
356
    {
357
        /** @var ProductType $sourceModel */
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
The close comment tag must be the only content on the line
Loading history...
358
        return ArrayHelper::merge(
359
            ConfigHelper::getConfigFromFile(self::configFilePath()),
360
            [
361
                'sourceId' => $sourceModel->id,
362
                'sourceName' => $sourceModel->name,
363
                'sourceHandle' => $sourceModel->handle,
364
            ]
365
        );
366
    }
367
368
    /**
369
     * Return the source id from the $element
370
     *
371
     * @param ElementInterface $element
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
372
     *
373
     * @return int|null
374
     */
375
    public static function sourceIdFromElement(ElementInterface $element)
376
    {
377
        /** @var Product $element */
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
The close comment tag must be the only content on the line
Loading history...
378
        return $element->typeId;
379
    }
380
381
    /**
382
     * Return the source handle from the $element
383
     *
384
     * @param ElementInterface $element
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
385
     *
386
     * @return string|null
387
     */
388
    public static function sourceHandleFromElement(ElementInterface $element)
389
    {
390
        $sourceHandle = '';
0 ignored issues
show
Unused Code introduced by
The assignment to $sourceHandle is dead and can be removed.
Loading history...
391
        /** @var Product $element */
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
The close comment tag must be the only content on the line
Loading history...
392
        try {
393
            $sourceHandle = $element->getType()->handle;
394
        } catch (InvalidConfigException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
395
        }
396
397
        return $sourceHandle;
398
    }
399
400
    /**
401
     * Create a MetaBundle in the db for each site, from the passed in $sourceModel
402
     *
403
     * @param Model $sourceModel
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
404
     */
405
    public static function createContentMetaBundle(Model $sourceModel)
406
    {
407
        /** @var ProductType $sourceModel */
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
The close comment tag must be the only content on the line
Loading history...
408
        $sites = Craft::$app->getSites()->getAllSites();
409
        /** @var Site $site */
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
The close comment tag must be the only content on the line
Loading history...
410
        foreach ($sites as $site) {
411
            $seoElement = self::class;
412
            /** @var SeoElementInterface $seoElement */
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
The close comment tag must be the only content on the line
Loading history...
413
            Seomatic::$plugin->metaBundles->createMetaBundleFromSeoElement($seoElement, $sourceModel, $site->id);
414
        }
415
    }
416
417
    /**
418
     * Create all the MetaBundles in the db for this Seo Element
419
     */
420
    public static function createAllContentMetaBundles()
421
    {
422
        $commerce = CommercePlugin::getInstance();
423
        if ($commerce !== null) {
424
            // Get all of the calendars with URLs
425
            $productTypes = $commerce->productTypes->getAllProductTypes();
426
            foreach ($productTypes as $productType) {
427
                self::createContentMetaBundle($productType);
428
            }
429
        }
430
    }
431
}
432