Issues (257)

src/services/SeoElements.php (5 issues)

1
<?php
2
/**
3
 * SEOmatic plugin for Craft CMS
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\services;
13
14
use Craft;
15
use craft\base\Component;
16
use craft\base\ElementInterface;
0 ignored issues
show
The type craft\base\ElementInterface 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\events\RegisterComponentTypesEvent;
18
use nystudio107\seomatic\base\GqlSeoElementInterface;
19
use nystudio107\seomatic\base\SeoElementInterface;
20
use nystudio107\seomatic\seoelements\SeoCampaign;
21
use nystudio107\seomatic\seoelements\SeoCategory;
22
use nystudio107\seomatic\seoelements\SeoDigitalProduct;
23
use nystudio107\seomatic\seoelements\SeoEntry;
24
use nystudio107\seomatic\seoelements\SeoEvent;
25
use nystudio107\seomatic\seoelements\SeoProduct;
26
use nystudio107\seomatic\seoelements\SeoShopifyProduct;
27
use nystudio107\seomatic\Seomatic;
28
29
/**
30
 * @author    nystudio107
31
 * @package   Seomatic
32
 * @since     3.2.0
33
 */
34
class SeoElements extends Component
35
{
36
    // Constants
37
    // =========================================================================
38
39
    /**
40
     * @event RegisterComponentTypesEvent The event that is triggered when
41
     *        registering SeoElement types
42
     *
43
     * SeoElement types must implement [[SeoElementInterface]]
44
     *
45
     * ```php
46
     * use nystudio107\seomatic\services\SeoElements;
47
     * use craft\events\RegisterComponentTypesEvent;
48
     * use yii\base\Event;
49
     *
50
     * Event::on(SeoElements::class,
51
     *     SeoElements::EVENT_REGISTER_SEO_ELEMENT_TYPES,
52
     *     function(RegisterComponentTypesEvent $event) {
53
     *         $event->types[] = MySeoElement::class;
54
     *     }
55
     * );
56
     * ```
57
     */
58
    public const EVENT_REGISTER_SEO_ELEMENT_TYPES = 'registerSeoElementTypes';
59
60
    public const DEFAULT_SEO_ELEMENT_TYPES = [
61
        SeoCampaign::class,
62
        SeoCategory::class,
63
        SeoDigitalProduct::class,
64
        SeoEntry::class,
65
        SeoEvent::class,
66
        SeoProduct::class,
67
        SeoShopifyProduct::class,
68
    ];
69
70
    // Protected Properties
71
    // =========================================================================
72
73
    /**
74
     * @var class-string<SeoElementInterface>[] indexed by [sourceType]
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<SeoElementInterface>[] at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<SeoElementInterface>[].
Loading history...
75
     */
76
    protected array $seoElements = [];
77
78
    // Public Methods
79
    // =========================================================================
80
81
    /**
82
     * @param null|string $metaBundleType
83
     *
84
     * @return class-string<SeoElementInterface>|null
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<SeoElementInterface>|null at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<SeoElementInterface>|null.
Loading history...
85
     */
86
    public function getSeoElementByMetaBundleType(?string $metaBundleType): ?string
87
    {
88
        if ($metaBundleType === null) {
89
            return null;
90
        }
91
        $seoElements = $this->getAllSeoElementTypes();
92
93
        return $seoElements[$metaBundleType] ?? null;
94
    }
95
96
    /**
97
     * Returns all available field type classes.
98
     *
99
     * @return class-string<SeoElementInterface>[] The available field type classes
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<SeoElementInterface>[] at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<SeoElementInterface>[].
Loading history...
100
     */
101
    public function getAllSeoElementTypes(bool $useCache = true): array
102
    {
103
        // Return the memoized version if available
104
        if ($useCache && !empty($this->seoElements)) {
105
            return $this->seoElements;
106
        }
107
        // Merge in the built-in types with the types defined in the config.php
108
        $seoElementTypes = array_unique(array_merge(
109
            SeoMatic::$plugin->getSettings()->defaultSeoElementTypes ?? [],
0 ignored issues
show
The method getSettings() 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

109
            SeoMatic::$plugin->/** @scrutinizer ignore-call */ 
110
                               getSettings()->defaultSeoElementTypes ?? [],

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...
110
            self::DEFAULT_SEO_ELEMENT_TYPES
111
        ), SORT_REGULAR);
112
        // Throw an event to allow other modules/plugins to define their own types
113
        $event = new RegisterComponentTypesEvent([
114
            'types' => $seoElementTypes,
115
        ]);
116
        $this->trigger(self::EVENT_REGISTER_SEO_ELEMENT_TYPES, $event);
117
        // Index the array by META_BUNDLE_TYPE
118
        /** @var class-string<SeoElementInterface> $seoElement */
119
        foreach ($event->types as $seoElement) {
120
            $requiredPlugin = $seoElement::getRequiredPluginHandle();
121
            if ($requiredPlugin === null || Craft::$app->getPlugins()->getPlugin($requiredPlugin)) {
122
                $this->seoElements[$seoElement::getMetaBundleType()] = $seoElement;
123
                $seoElement::installEventHandlers();
124
            }
125
        }
126
127
        return $this->seoElements;
128
    }
129
130
    /**
131
     * Return the Meta Bundle type for a given element
132
     *
133
     * @param ElementInterface $element
134
     *
135
     * @return string|null
136
     */
137
    public function getMetaBundleTypeFromElement(ElementInterface $element)
138
    {
139
        $seoElements = $this->getAllSeoElementTypes();
140
        /** @var SeoElementInterface $seoElement */
141
        foreach ($seoElements as $metaBundleType => $seoElement) {
142
            foreach ($seoElement::getElementClasses() as $elementClass) {
143
                if ($element instanceof $elementClass) {
144
                    return $metaBundleType;
145
                }
146
            }
147
        }
148
149
        return null;
150
    }
151
152
    /**
153
     * Returns all available known GQL interfaces used by SEO elements.
154
     *
155
     * @return string[] List of known GQL interface names.
156
     */
157
    public function getAllSeoElementGqlInterfaceNames(): array
158
    {
159
        $seoElements = $this->getAllSeoElementTypes();
160
        $interfaceNames = [];
161
162
        foreach ($seoElements as $seoElement) {
163
            if (is_subclass_of($seoElement, GqlSeoElementInterface::class)) {
164
                $interfaceNames[] = $seoElement::getGqlInterfaceTypeName();
165
            }
166
        }
167
168
        return $interfaceNames;
169
    }
170
}
171