Helper::findInheritableBundle()   A
last analyzed

Complexity

Conditions 6
Paths 3

Size

Total Lines 14
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
eloc 6
dl 0
loc 14
c 0
b 0
f 0
ccs 0
cts 12
cp 0
rs 9.2222
cc 6
nc 3
nop 3
crap 42
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) 2017 nystudio107
10
 */
11
12
namespace nystudio107\seomatic\services;
13
14
use Craft;
15
use craft\base\Component;
16
use craft\elements\Asset;
17
use craft\elements\db\MatrixBlockQuery;
18
use craft\elements\db\TagQuery;
19
use craft\helpers\Template;
20
use craft\web\twig\variables\Paginate;
21
use nystudio107\seomatic\base\InheritableSettingsModel;
22
use nystudio107\seomatic\helpers\DynamicMeta as DynamicMetaHelper;
23
use nystudio107\seomatic\helpers\ImageTransform as ImageTransformHelper;
24
use nystudio107\seomatic\helpers\Schema as SchemaHelper;
25
use nystudio107\seomatic\helpers\Text as TextHelper;
26
use nystudio107\seomatic\helpers\UrlHelper;
27
use nystudio107\seomatic\models\MetaBundle;
28
use nystudio107\seomatic\Seomatic;
29
use yii\base\Exception;
30
use yii\base\InvalidConfigException;
31
32
/**
33
 * Helper functions for SEOmatic
34
 * An instance of the service is available via [[`Seomatic::$plugin->helper`|`seomatic.helper`]]
35
 *
36
 * @author    nystudio107
37
 * @package   Seomatic
38
 * @since     3.0.0
39
 */
40
class Helper extends Component
41
{
42
    // Constants
43
    // =========================================================================
44
45
    const TWITTER_TRANSFORM_MAP = [
46
        'summary' => 'twitter-summary',
47
        'summary_large_image' => 'twitter-large',
48
        'app' => 'twitter-large',
49
        'player' => 'twitter-large',
50
    ];
51
52
    // Public Methods
53
    // =========================================================================
54
55
    /**
56
     * Return a base URL to the $path, removing any language segments that may
57
     * be present, for files like robots.txt that must be served from the root
58
     *
59
     * @param $path
60
     * @return string
61
     * @throws Exception
62
     */
63
    public static function baseSiteUrl($path): string
64
    {
65
        $baseUrl = UrlHelper::hostInfo(UrlHelper::siteUrl($path));
66
67
        return rtrim($baseUrl, '/') . '/' . ltrim($path, '/');
68
    }
69
70
    /**
71
     * Sanitize user input by decoding any HTML Entities, URL decoding the text,
72
     * then removing any newlines, stripping tags, stripping Twig tags, and changing
73
     * single {}'s into ()'s
74
     *
75
     * @param $str
76
     * @return string
77
     */
78
    public static function sanitizeUserInput($str): string
79
    {
80
        return TextHelper::sanitizeUserInput($str);
81
    }
82
83
    /**
84
     * Return the appropriate Twitter Transform based on the current $metaGlobalVars->twitterCard
85
     *
86
     * @return string
87
     */
88
    public static function twitterTransform(): string
89
    {
90
        $transform = 'twitter-summary';
91
        $metaGlobalVars = Seomatic::$plugin->metaContainers->metaGlobalVars;
92
        if ($metaGlobalVars) {
93
            $transform = self::TWITTER_TRANSFORM_MAP[$metaGlobalVars->twitterCard] ?? $transform;
94
        }
95
96
        return $transform;
97
    }
98
99
    /**
100
     * Return the proper content for the `query-input` JSON-LD property
101
     *
102
     * @return string
103
     */
104
    public static function siteLinksQueryInput(): string
105
    {
106
        $result = '';
107
108
        $metaSiteVars = Seomatic::$plugin->metaContainers->metaSiteVars;
109
        if ($metaSiteVars && !empty($metaSiteVars->siteLinksQueryInput)) {
110
            $result = 'required name=' . $metaSiteVars->siteLinksQueryInput;
111
        }
112
113
        return $result;
114
    }
115
116
    /**
117
     * Return whether this is a preview request of any kind
118
     *
119
     * @return bool
120
     */
121
    public static function isPreview(): bool
122
    {
123
        $isPreview = false;
124
        $request = Craft::$app->getRequest();
125
        if (Seomatic::$craft32) {
126
            $isPreview = $request->getIsPreview();
127
        }
128
        $isLivePreview = $request->getIsLivePreview();
129
130
        return ($isPreview || $isLivePreview);
131
    }
132
133
    /**
134
     * Return the Same As Links info as an array or null
135
     *
136
     * @param string $handle
137
     * @return array|null
138
     */
139
    public static function sameAsByHandle(string $handle)
140
    {
141
        $result = null;
142
143
        $sameAs = Seomatic::$plugin->metaContainers->metaSiteVars->sameAsLinks;
144
        if (!empty($sameAs) && !empty($handle)) {
145
            foreach ($sameAs as $sameAsInfo) {
146
                if (!empty($sameAsInfo) && is_array($sameAsInfo) && !empty($sameAsInfo['handle'])) {
147
                    if ($sameAsInfo['handle'] === $handle) {
148
                        return $sameAsInfo;
149
                    }
150
                }
151
            }
152
        }
153
154
        return $result;
155
    }
156
157
    /**
158
     * Return the canonical URL for the request, with the query string stripped
159
     *
160
     * @return string
161
     */
162
    public static function safeCanonicalUrl(): string
163
    {
164
        $url = '';
0 ignored issues
show
Unused Code introduced by
The assignment to $url is dead and can be removed.
Loading history...
165
        try {
166
            $url = Craft::$app->getRequest()->getPathInfo();
167
        } catch (InvalidConfigException $e) {
168
            Craft::error($e->getMessage(), __METHOD__);
169
        }
170
171
        return DynamicMetaHelper::sanitizeUrl(UrlHelper::absoluteUrlWithProtocol($url));
172
    }
173
174
    /**
175
     * Return the site URL for a given URL. This gives SEOmatic a chance to override it
176
     *
177
     * @param string $path
178
     * @param array|string|null $params
179
     * @param string|null $scheme
180
     * @param int|null $siteId
181
     * @return string
182
     * @throws Exception if|null $siteId is invalid
183
     */
184
    public static function siteUrl(string $path = '', $params = null, string $scheme = null, int $siteId = null): string
0 ignored issues
show
Unused Code introduced by
The parameter $siteId is not used and could be removed. ( Ignorable by Annotation )

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

184
    public static function siteUrl(string $path = '', $params = null, string $scheme = null, /** @scrutinizer ignore-unused */ int $siteId = null): string

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $scheme is not used and could be removed. ( Ignorable by Annotation )

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

184
    public static function siteUrl(string $path = '', $params = null, /** @scrutinizer ignore-unused */ string $scheme = null, int $siteId = null): string

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $params is not used and could be removed. ( Ignorable by Annotation )

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

184
    public static function siteUrl(string $path = '', /** @scrutinizer ignore-unused */ $params = null, string $scheme = null, int $siteId = null): string

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
185
    {
186
        return UrlHelper::siteUrl($path);
187
    }
188
189
    /**
190
     * Paginate based on the passed in Paginate variable as returned from the
191
     * Twig {% paginate %} tag:
192
     * https://docs.craftcms.com/v3/templating/tags/paginate.html#the-pageInfo-variable
193
     *
194
     * @param Paginate $pageInfo
195
     */
196
    public static function paginate(Paginate $pageInfo)
197
    {
198
        DynamicMetaHelper::paginate($pageInfo);
199
    }
200
201
    /**
202
     * Truncates the string to a given length. If $substring is provided, and
203
     * truncating occurs, the string is further truncated so that the substring
204
     * may be appended without exceeding the desired length.
205
     *
206
     * @param string $string The string to truncate
207
     * @param int $length Desired length of the truncated string
208
     * @param string $substring The substring to append if it can fit
209
     *
210
     * @return string with the resulting $str after truncating
211
     */
212
    public static function truncate($string, $length, $substring = '…'): string
213
    {
214
        return TextHelper::truncate($string, $length, $substring);
215
    }
216
217
    /**
218
     * Truncates the string to a given length, while ensuring that it does not
219
     * split words. If $substring is provided, and truncating occurs, the
220
     * string is further truncated so that the substring may be appended without
221
     * exceeding the desired length.
222
     *
223
     * @param string $string The string to truncate
224
     * @param int $length Desired length of the truncated string
225
     * @param string $substring The substring to append if it can fit
226
     *
227
     * @return string with the resulting $str after truncating
228
     */
229
    public static function truncateOnWord($string, $length, $substring = '…'): string
230
    {
231
        return TextHelper::truncateOnWord($string, $length, $substring);
232
    }
233
234
    /**
235
     * Return a list of localized URLs that are in the current site's group
236
     * The current URI is used if $uri is null. Similarly, the current site is
237
     * used if $siteId is null.
238
     * The resulting array of arrays has `id`, `language`, `ogLanguage`,
239
     * `hreflangLanguage`, and `url` as keys.
240
     *
241
     * @param string|null $uri
242
     * @param int|null $siteId
243
     *
244
     * @return array
245
     */
246
    public static function getLocalizedUrls(string $uri = null, int $siteId = null): array
247
    {
248
        return DynamicMetaHelper::getLocalizedUrls($uri, $siteId);
249
    }
250
251
    /**
252
     * Allow setting the X-Robots-Tag and Link headers on static files as per:
253
     * https://moz.com/blog/how-to-advanced-relcanonical-http-headers
254
     *
255
     * @param        $url
256
     * @param string $robots
257
     * @param string $canonical
258
     * @param bool $inline
259
     *
260
     * @return \Twig\Markup
261
     * @throws \yii\base\Exception
262
     */
263
    public static function seoFileLink($url, $robots = '', $canonical = '', $inline = true): \Twig\Markup
264
    {
265
        // Get the file name
266
        $path = parse_url($url, PHP_URL_PATH);
267
        $fileName = pathinfo($path, PATHINFO_BASENAME);
268
        // Set some defaults
269
        $robots = empty($robots) ? 'all' : $robots;
270
        $canonical = empty($canonical) ? $url : $canonical;
271
        $inlineStr = $inline === true ? '1' : '0';
272
        // Compose the base64 encoded URL
273
        $seoFileLink = 'seomatic/seo-file-link/'
274
            . base64_encode($url)
275
            . '/'
276
            . base64_encode($robots)
277
            . '/'
278
            . base64_encode($canonical)
279
            . '/'
280
            . $inlineStr
281
            . '/'
282
            . $fileName;
0 ignored issues
show
Bug introduced by
Are you sure $fileName of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

282
            . /** @scrutinizer ignore-type */ $fileName;
Loading history...
283
284
        return Template::raw(UrlHelper::siteUrl($seoFileLink));
285
    }
286
287
    /**
288
     * Load the appropriate meta containers for the given $uri and optional
289
     * $siteId
290
     *
291
     * @param string $uri
292
     * @param int|null $siteId
293
     */
294
    public static function loadMetadataForUri(string $uri = '', int $siteId = null)
295
    {
296
        Seomatic::$plugin->metaContainers->loadMetaContainers($uri, $siteId);
297
    }
298
299
    /**
300
     * Get the URL to the $siteId's sitemap index
301
     *
302
     * @param int|null $siteId
303
     *
304
     * @return string
305
     */
306
    public static function sitemapIndexForSiteId(int $siteId = null): string
307
    {
308
        return Seomatic::$plugin->sitemaps->sitemapIndexUrlForSiteId($siteId);
309
    }
310
311
    /**
312
     * Return a sitemap for each site in the same site group
313
     *
314
     * @return string
315
     */
316
    public static function sitemapIndex(): string
317
    {
318
        return Seomatic::$plugin->sitemaps->sitemapIndex();
319
    }
320
321
    /**
322
     * Return a sitemap for each site in the same site group
323
     *
324
     * @return string
325
     * @deprecated use sitemapIndex() instead
326
     */
327
    public static function siteGroupSitemaps(): string
328
    {
329
        return Seomatic::$plugin->sitemaps->sitemapIndex();
330
    }
331
332
    /**
333
     * @param string $sourceType
334
     * @param string $sourceHandle
335
     * @param int|null $siteId
336
     *
337
     * @return string
338
     */
339
    public static function sitemapUrlForBundle(string $sourceType, string $sourceHandle, int $siteId = null, int $page = 0): string
340
    {
341
        return Seomatic::$plugin->sitemaps->sitemapUrlForBundle($sourceType, $sourceHandle, $siteId, $page);
342
    }
343
344
    /**
345
     * Extract plain old text from a field
346
     *
347
     * @param $field
348
     *
349
     * @return string
350
     */
351
    public static function extractTextFromField($field = null): string
352
    {
353
        return TextHelper::extractTextFromField($field);
354
    }
355
356
    /**
357
     * Extract concatenated text from all of the tags in the $tagElement and
358
     * return as a comma-delimited string
359
     *
360
     * @param TagQuery $tagQuery
361
     *
362
     * @return string
363
     */
364
    public static function extractTextFromTags($tagQuery = null): string
365
    {
366
        return TextHelper::extractTextFromTags($tagQuery);
367
    }
368
369
    /**
370
     * Extract text from all of the blocks in a matrix field, concatenating it
371
     * together.
372
     *
373
     * @param MatrixBlockQuery $matrixQuery
374
     * @param string $fieldHandle
375
     *
376
     * @return string
377
     */
378
    public static function extractTextFromMatrix($matrixQuery = null, $fieldHandle = ''): string
379
    {
380
        return TextHelper::extractTextFromMatrix($matrixQuery, $fieldHandle);
381
    }
382
383
    /**
384
     * Return the most important keywords extracted from the text as a comma-
385
     * delimited string
386
     *
387
     * @param string $text
388
     * @param int $limit
389
     * @param bool $useStopWords
390
     *
391
     * @return string
392
     */
393
    public static function extractKeywords($text = '', $limit = 15, $useStopWords = true): string
394
    {
395
        return TextHelper::extractKeywords($text, $limit, $useStopWords);
396
    }
397
398
    /**
399
     * Extract a summary consisting of the 3 most important sentences from the
400
     * text
401
     *
402
     * @param string $text
403
     * @param bool $useStopWords
404
     *
405
     * @return string
406
     */
407
    public static function extractSummary($text = '', $useStopWords = true): string
408
    {
409
        return TextHelper::extractSummary($text, $useStopWords);
410
    }
411
412
    /**
413
     * Return a period-delimited schema.org path from the $settings
414
     *
415
     * @param $settings
416
     *
417
     * @return string
418
     */
419
    public static function getEntityPath($settings): string
420
    {
421
        return SchemaHelper::getEntityPath($settings);
422
    }
423
424
    /**
425
     * Return a flattened, indented menu of the given $path
426
     *
427
     * @param string $path
428
     *
429
     * @return array
430
     */
431
    public static function getTypeMenu($path): array
432
    {
433
        return SchemaHelper::getTypeMenu($path);
434
    }
435
436
    /**
437
     * Return a single menu of schemas starting at $path
438
     *
439
     * @param string $path
440
     *
441
     * @return array
442
     */
443
    public static function getSingleTypeMenu($path): array
444
    {
445
        return SchemaHelper::getSingleTypeMenu($path);
446
    }
447
448
    /**
449
     * Transform the $asset for social media sites in $transformName and
450
     * optional $siteId
451
     *
452
     * @param int|Asset $asset the Asset or Asset ID
453
     * @param string $transformName the name of the transform to apply
454
     * @param int|null $siteId
455
     * @param string $transformMode
456
     *
457
     * @return string URL to the transformed image
458
     */
459
    public function socialTransform($asset, $transformName = '', $siteId = null, $transformMode = null): string
460
    {
461
        return ImageTransformHelper::socialTransform($asset, $transformName, $siteId, $transformMode);
462
    }
463
464
    /**
465
     * Get the width of the transformed social image for $transformName and
466
     * optional $siteId
467
     *
468
     * @param int|Asset $asset the Asset or Asset ID
469
     * @param string $transformName the name of the transform to apply
470
     * @param int|null $siteId
471
     * @param string $transformMode
472
     *
473
     * @return string URL to the transformed image
474
     */
475
    public function socialTransformWidth(
476
        $asset,
477
        $transformName = '',
478
        $siteId = null,
479
        $transformMode = null
480
    ): string {
481
        return ImageTransformHelper::socialTransformWidth($asset, $transformName, $siteId, $transformMode);
482
    }
483
484
    /**
485
     * Get the height of the transformed social image for $transformName and
486
     * optional $siteId
487
     *
488
     * @param int|Asset $asset the Asset or Asset ID
489
     * @param string $transformName the name of the transform to apply
490
     * @param int|null $siteId
491
     * @param string $transformMode
492
     *
493
     * @return string URL to the transformed image
494
     */
495
    public function socialTransformHeight(
496
        $asset,
497
        $transformName = '',
498
        $siteId = null,
499
        $transformMode = null
500
    ): string {
501
        return ImageTransformHelper::socialTransformHeight($asset, $transformName, $siteId, $transformMode);
502
    }
503
504
    /**
505
     * Return whether we are running Craft 3.1 or later
506
     *
507
     * @return bool
508
     */
509
    public function craft31(): bool
510
    {
511
        return Seomatic::$craft31;
512
    }
513
514
    /**
515
     * Return whether we are running Craft 3.2 or later
516
     *
517
     * @return bool
518
     */
519
    public function craft32(): bool
520
    {
521
        return Seomatic::$craft32;
522
    }
523
524
    /**
525
     * Return whether we are running Craft 3.3 or later
526
     *
527
     * @return bool
528
     */
529
    public function craft33(): bool
530
    {
531
        return Seomatic::$craft33;
532
    }
533
534
    /**
535
     * Given a list of meta bundles in order of descending distance, return the bundle that has inheritable value.
536
     *
537
     * @param array $inheritedValues
538
     * @param string $settingName
539
     * @param string $collectionName The name off the collection to search
540
     * @return MetaBundle|null
541
     * @since 3.4.0
542
     */
543
    public function findInheritableBundle(array $inheritedValues, string $settingName, string $collectionName = "metaGlobalVars")
544
    {
545
        if (in_array($collectionName, ['metaGlobalVars', 'metaSitemapVars'], true)) {
546
            foreach ($inheritedValues as $bundle) {
547
                /** @var $bundle MetaBundle */
548
                if (isset($bundle->{$collectionName}[$settingName])) {
549
                    if (is_bool($bundle->{$collectionName}[$settingName]) || !empty($bundle->{$collectionName}[$settingName])) {
550
                        return $bundle;
551
                    }
552
                }
553
            }
554
        }
555
556
        return null;
557
    }
558
559
    /**
560
     * Return true if a setting is inherited.
561
     *
562
     * @param InheritableSettingsModel $settingCollection
563
     * @param $settingName
564
     * @return bool
565
     * @since 3.4.0
566
     */
567
    public function isInherited(InheritableSettingsModel $settingCollection, $settingName)
568
    {
569
        $explicitInherit = array_key_exists($settingName, (array)$settingCollection->inherited);
570
        $explicitOverride = array_key_exists($settingName, (array)$settingCollection->overrides);
571
572
        if ($explicitInherit || $explicitOverride) {
573
            return $explicitInherit && !$explicitOverride;
574
        }
575
576
        return empty($settingCollection->{$settingName});
577
    }
578
}
579