Issues (447)

src/services/Routes.php (176 issues)

1
<?php
2
/**
3
 * Route Map plugin for Craft CMS
4
 *
5
 * Returns a list of public routes for elements with URLs
6
 *
7
 * @link      https://nystudio107.com/
0 ignored issues
show
The tag in position 1 should be the @copyright tag
Loading history...
8
 * @copyright Copyright (c) 2017 nystudio107
0 ignored issues
show
@copyright tag must contain a year and the name of the copyright holder
Loading history...
9
 */
0 ignored issues
show
PHP version not specified
Loading history...
Missing @category tag in file comment
Loading history...
Missing @package tag in file comment
Loading history...
Missing @author tag in file comment
Loading history...
Missing @license tag in file comment
Loading history...
10
11
namespace nystudio107\routemap\services;
12
13
use Craft;
14
use craft\base\Component;
15
use craft\base\Element;
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\elements\Asset;
0 ignored issues
show
The type craft\elements\Asset 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\elements\Category;
19
use craft\elements\db\ElementQueryInterface;
20
use craft\elements\Entry;
21
use craft\fields\Assets as AssetsField;
22
use craft\fields\Matrix as MatrixField;
23
use nystudio107\routemap\helpers\Field as FieldHelper;
24
use yii\caching\TagDependency;
25
use function count;
26
use function in_array;
27
use function is_array;
28
use function is_int;
29
use function is_object;
30
use function is_string;
31
32
/**
0 ignored issues
show
Missing short description in doc comment
Loading history...
33
 * @author    nystudio107
0 ignored issues
show
The tag in position 1 should be the @package tag
Loading history...
Content of the @author tag must be in the form "Display Name <[email protected]>"
Loading history...
Tag value for @author tag indented incorrectly; expected 2 spaces but found 4
Loading history...
34
 * @package   RouteMap
0 ignored issues
show
Tag value for @package tag indented incorrectly; expected 1 spaces but found 3
Loading history...
35
 * @since     1.0.0
0 ignored issues
show
The tag in position 3 should be the @author tag
Loading history...
Tag value for @since tag indented incorrectly; expected 3 spaces but found 5
Loading history...
36
 */
0 ignored issues
show
Missing @category tag in class comment
Loading history...
Missing @license tag in class comment
Loading history...
Missing @link tag in class comment
Loading history...
37
class Routes extends Component
38
{
39
    // Constants
40
    // =========================================================================
41
    /**
0 ignored issues
show
Missing short description in doc comment
Loading history...
42
     * @var string
43
     */
44
    public const ROUTE_FORMAT_CRAFT = 'Craft';
45
46
    /**
0 ignored issues
show
Missing short description in doc comment
Loading history...
47
     * @var string
48
     */
49
    public const ROUTE_FORMAT_REACT = 'React';
50
51
    /**
0 ignored issues
show
Missing short description in doc comment
Loading history...
52
     * @var string
53
     */
54
    public const ROUTE_FORMAT_VUE = 'Vue';
55
56
    /**
0 ignored issues
show
Missing short description in doc comment
Loading history...
57
     * @var null
58
     */
59
    public const ROUTEMAP_CACHE_DURATION = null;
60
61
    /**
0 ignored issues
show
Missing short description in doc comment
Loading history...
62
     * @var int
63
     */
64
    public const DEVMODE_ROUTEMAP_CACHE_DURATION = 30;
65
66
    /**
0 ignored issues
show
Missing short description in doc comment
Loading history...
67
     * @var string
68
     */
69
    public const ROUTEMAP_CACHE_TAG = 'RouteMap';
70
71
    /**
0 ignored issues
show
Missing short description in doc comment
Loading history...
72
     * @var string
73
     */
74
    public const ROUTEMAP_SECTION_RULES = 'Sections';
75
76
    /**
0 ignored issues
show
Missing short description in doc comment
Loading history...
77
     * @var string
78
     */
79
    public const ROUTEMAP_CATEGORY_RULES = 'Categories';
80
81
    /**
0 ignored issues
show
Missing short description in doc comment
Loading history...
82
     * @var string
83
     */
84
    public const ROUTEMAP_ELEMENT_URLS = 'ElementUrls';
85
86
    /**
0 ignored issues
show
Missing short description in doc comment
Loading history...
87
     * @var string
88
     */
89
    public const ROUTEMAP_ASSET_URLS = 'AssetUrls';
90
91
    /**
0 ignored issues
show
Missing short description in doc comment
Loading history...
92
     * @var string
93
     */
94
    public const ROUTEMAP_ALL_URLS = 'AllUrls';
95
96
    // Public Methods
97
    // =========================================================================
98
    /**
99
     * Return the public URLs for all elements that have URLs
100
     *
101
     * @param array $criteria
0 ignored issues
show
Missing parameter comment
Loading history...
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
102
     * @param ?int $siteId
0 ignored issues
show
Missing parameter comment
Loading history...
Expected 2 spaces after parameter type; 1 found
Loading history...
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
103
     * @return array
0 ignored issues
show
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
104
     */
105
    public function getAllUrls(array $criteria = [], ?int $siteId = null): array
106
    {
107
        $urls = [];
108
        $elements = Craft::$app->getElements();
109
        $elementTypes = $elements->getAllElementTypes();
110
        foreach ($elementTypes as $elementType) {
111
            /** @noinspection SlowArrayOperationsInLoopInspection */
0 ignored issues
show
The open comment tag must be the only content on the line
Loading history...
Missing short description in doc comment
Loading history...
The close comment tag must be the only content on the line
Loading history...
112
            $urls = array_merge($urls, $this->getElementUrls($elementType, $criteria, $siteId));
113
        }
114
115
        return $urls;
116
    }
117
118
    /**
119
     * Return all the section route rules
120
     *
121
     * @param string $format 'Craft'|'React'|'Vue'
0 ignored issues
show
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
122
     * @param ?int $siteId
0 ignored issues
show
Missing parameter comment
Loading history...
Expected 3 spaces after parameter type; 1 found
Loading history...
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
123
     * @return array
0 ignored issues
show
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
124
     */
125
    public function getAllRouteRules(string $format = 'Craft', ?int $siteId = null): array
126
    {
127
        // Get all the sections
128
        $sections = $this->getAllSectionRouteRules($format, $siteId);
129
        $categories = $this->getAllCategoryRouteRules($format, $siteId);
130
        $rules = $this->getRouteRules($siteId);
131
132
        return [
133
            'sections' => $sections,
134
            'categories' => $categories,
135
            'rules' => $rules,
136
        ];
137
    }
138
139
    /**
140
     * Return the public URLs for a section
141
     *
142
     * @param string $section
0 ignored issues
show
Missing parameter comment
Loading history...
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
143
     * @param array $criteria
0 ignored issues
show
Missing parameter comment
Loading history...
Expected 2 spaces after parameter type; 1 found
Loading history...
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
144
     * @param ?int $siteId
0 ignored issues
show
Missing parameter comment
Loading history...
Expected 3 spaces after parameter type; 1 found
Loading history...
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
145
     * @return array
0 ignored issues
show
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
146
     */
147
    public function getSectionUrls(string $section, array $criteria = [], ?int $siteId = null): array
148
    {
149
        $criteria = array_merge([
0 ignored issues
show
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
150
            'section' => $section,
151
            'status' => 'enabled',
152
        ], $criteria);
0 ignored issues
show
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...
153
154
        return $this->getElementUrls(Entry::class, $criteria, $siteId);
155
    }
156
157
    /**
158
     * Return all the section route rules
159
     *
160
     * @param string $format 'Craft'|'React'|'Vue'
0 ignored issues
show
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
161
     * @param ?int $siteId
0 ignored issues
show
Missing parameter comment
Loading history...
Expected 3 spaces after parameter type; 1 found
Loading history...
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
162
     * @return array
0 ignored issues
show
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
163
     */
164
    public function getAllSectionRouteRules(string $format = 'Craft', ?int $siteId = null): array
165
    {
166
        $routeRules = [];
167
        // Get all the sections
168
        $sections = Craft::$app->getEntries()->getAllSections();
169
        foreach ($sections as $section) {
170
            $routes = $this->getSectionRouteRules($section->handle, $format, $siteId);
171
            if (!empty($routes)) {
172
                $routeRules[$section->handle] = $routes;
173
            }
174
        }
175
176
        return $routeRules;
177
    }
178
179
    /**
180
     * Return the route rules for a specific section
181
     *
182
     * @param string $section
0 ignored issues
show
Missing parameter comment
Loading history...
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
183
     * @param string $format 'Craft'|'React'|'Vue'
0 ignored issues
show
Expected 2 spaces after parameter name; 1 found
Loading history...
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
184
     * @param ?int $siteId
0 ignored issues
show
Missing parameter comment
Loading history...
Expected 3 spaces after parameter type; 1 found
Loading history...
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
185
     * @return array
0 ignored issues
show
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
186
     */
187
    public function getSectionRouteRules(string $section, string $format = 'Craft', ?int $siteId = null): array
188
    {
189
        $devMode = Craft::$app->getConfig()->getGeneral()->devMode;
190
        $cache = Craft::$app->getCache();
191
192
        // Set up our cache criteria
193
        $cacheKey = $this->getCacheKey($this::ROUTEMAP_SECTION_RULES, [$section, $format, $siteId]);
194
        $duration = $devMode ? $this::DEVMODE_ROUTEMAP_CACHE_DURATION : $this::ROUTEMAP_CACHE_DURATION;
195
        $dependency = new TagDependency([
0 ignored issues
show
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
196
            'tags' => [
197
                $this::ROUTEMAP_CACHE_TAG,
198
            ],
199
        ]);
0 ignored issues
show
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...
200
201
        // Just return the data if it's already cached
202
        return $cache->getOrSet($cacheKey, function() use ($section, $format, $siteId): array {
0 ignored issues
show
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
203
            Craft::info(
204
                'Route Map cache miss: ' . $section,
205
                __METHOD__
206
            );
207
            $resultingRoutes = [];
208
209
            $section = Craft::$app->getEntries()->getSectionByHandle($section);
210
            if ($section) {
211
                $sites = $section->getSiteSettings();
212
213
                foreach ($sites as $site) {
214
                    if ($site->hasUrls && ($siteId === null || (int)$site->siteId === $siteId)) {
215
                        // Get section data to return
216
                        $route = [
217
                            'handle' => $section->handle,
218
                            'siteId' => $site->siteId,
219
                            'type' => $section->type,
220
                            'url' => $site->uriFormat,
221
                            'template' => $site->template,
222
                        ];
223
224
                        // Normalize the routes based on the format
225
                        $resultingRoutes[$site->siteId] = $this->normalizeFormat($format, $route);
226
                    }
227
                }
228
            }
229
230
            // If there's only one siteId for this section, just return it
231
            if (count($resultingRoutes) === 1) {
232
                $resultingRoutes = reset($resultingRoutes);
233
            }
234
235
            return $resultingRoutes;
236
        }, $duration, $dependency);
0 ignored issues
show
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...
237
    }
238
239
    /**
240
     * Return the public URLs for a category
241
     *
242
     * @param string $category
0 ignored issues
show
Missing parameter comment
Loading history...
243
     * @param array $criteria
0 ignored issues
show
Missing parameter comment
Loading history...
Expected 2 spaces after parameter type; 1 found
Loading history...
244
     * @param ?int $siteId
0 ignored issues
show
Missing parameter comment
Loading history...
Expected 3 spaces after parameter type; 1 found
Loading history...
245
     *
246
     * @return array
247
     */
248
    public function getCategoryUrls(string $category, array $criteria = [], ?int $siteId = null): array
249
    {
250
        $criteria = array_merge([
0 ignored issues
show
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
251
            'group' => $category,
252
        ], $criteria);
0 ignored issues
show
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...
253
254
        return $this->getElementUrls(Category::class, $criteria, $siteId);
255
    }
256
257
    /**
258
     * Return all the cateogry group route rules
259
     *
260
     * @param string $format 'Craft'|'React'|'Vue'
0 ignored issues
show
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
261
     * @param ?int $siteId
0 ignored issues
show
Missing parameter comment
Loading history...
Expected 3 spaces after parameter type; 1 found
Loading history...
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
262
     * @return array
0 ignored issues
show
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
263
     */
264
    public function getAllCategoryRouteRules(string $format = 'Craft', ?int $siteId = null): array
265
    {
266
        $routeRules = [];
267
        // Get all the sections
268
        $groups = Craft::$app->getCategories()->getAllGroups();
269
        foreach ($groups as $group) {
270
            $routes = $this->getCategoryRouteRules($group->handle, $format, $siteId);
271
            if (!empty($routes)) {
272
                $routeRules[$group->handle] = $routes;
273
            }
274
        }
275
276
        return $routeRules;
277
    }
278
279
    /**
280
     * Return the route rules for a specific category
281
     *
282
     * @param int|string $category
0 ignored issues
show
Missing parameter comment
Loading history...
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
283
     * @param string $format 'Craft'|'React'|'Vue'
0 ignored issues
show
Expected 5 spaces after parameter type; 1 found
Loading history...
Expected 3 spaces after parameter name; 1 found
Loading history...
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
284
     * @param ?int $siteId
0 ignored issues
show
Missing parameter comment
Loading history...
Expected 7 spaces after parameter type; 1 found
Loading history...
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
285
     * @return array
0 ignored issues
show
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
286
     */
287
    public function getCategoryRouteRules(int|string $category, string $format = 'Craft', ?int $siteId = null): array
288
    {
289
        $devMode = Craft::$app->getConfig()->getGeneral()->devMode;
290
        $cache = Craft::$app->getCache();
291
292
        if (is_int($category)) {
293
            $categoryGroup = Craft::$app->getCategories()->getGroupById($category);
294
            if ($categoryGroup === null) {
295
                return [];
296
            }
297
298
            $handle = $categoryGroup->handle;
299
        } else {
300
            $handle = $category;
301
        }
302
303
        if ($handle === null) {
304
            return [];
305
        }
306
307
        // Set up our cache criteria
308
        $cacheKey = $this->getCacheKey($this::ROUTEMAP_CATEGORY_RULES, [$category, $handle, $format, $siteId]);
309
        $duration = $devMode ? $this::DEVMODE_ROUTEMAP_CACHE_DURATION : $this::ROUTEMAP_CACHE_DURATION;
310
        $dependency = new TagDependency([
0 ignored issues
show
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
311
            'tags' => [
312
                $this::ROUTEMAP_CACHE_TAG,
313
            ],
314
        ]);
0 ignored issues
show
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...
315
        // Just return the data if it's already cached
316
        return $cache->getOrSet($cacheKey, function() use ($category, $handle, $format, $siteId): array {
0 ignored issues
show
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
317
            Craft::info(
318
                'Route Map cache miss: ' . $category,
319
                __METHOD__
320
            );
321
            $resultingRoutes = [];
322
            $category = Craft::$app->getCategories()->getGroupByHandle($handle);
323
            if ($category) {
324
                $sites = $category->getSiteSettings();
325
326
                foreach ($sites as $site) {
327
                    if ($site->hasUrls && ($siteId === null || (int)$site->siteId === $siteId)) {
328
                        // Get section data to return
329
                        $route = [
330
                            'handle' => $category->handle,
331
                            'siteId' => $site->siteId,
332
                            'url' => $site->uriFormat,
333
                            'template' => $site->template,
334
                        ];
335
336
                        // Normalize the routes based on the format
337
                        $resultingRoutes[$site->siteId] = $this->normalizeFormat($format, $route);
338
                    }
339
                }
340
            }
341
342
            // If there's only one siteId for this section, just return it
343
            if (count($resultingRoutes) === 1) {
344
                $resultingRoutes = reset($resultingRoutes);
345
            }
346
347
            return $resultingRoutes;
348
        }, $duration, $dependency);
0 ignored issues
show
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...
349
    }
350
351
    /**
352
     * Get all the assets of the type $assetTypes that are used in the Entry
353
     * that matches the $url
354
     *
355
     * @param string $url
0 ignored issues
show
Missing parameter comment
Loading history...
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
356
     * @param array $assetTypes
0 ignored issues
show
Missing parameter comment
Loading history...
Expected 2 spaces after parameter type; 1 found
Loading history...
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
357
     * @param ?int $siteId
0 ignored issues
show
Missing parameter comment
Loading history...
Expected 3 spaces after parameter type; 1 found
Loading history...
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
358
     * @return array
0 ignored issues
show
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
359
     */
360
    public function getUrlAssetUrls(string $url, array $assetTypes = ['image'], ?int $siteId = null): array
361
    {
362
        $devMode = Craft::$app->getConfig()->getGeneral()->devMode;
363
        $cache = Craft::$app->getCache();
364
365
        // Extract a URI from the URL
366
        $uri = parse_url($url, PHP_URL_PATH);
367
        $uri = ltrim($uri, '/');
368
        // Set up our cache criteria
369
        $cacheKey = $this->getCacheKey($this::ROUTEMAP_ASSET_URLS, [$uri, $assetTypes, $siteId]);
370
        $duration = $devMode ? $this::DEVMODE_ROUTEMAP_CACHE_DURATION : $this::ROUTEMAP_CACHE_DURATION;
371
        $dependency = new TagDependency([
0 ignored issues
show
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
372
            'tags' => [
373
                $this::ROUTEMAP_CACHE_TAG,
374
            ],
375
        ]);
0 ignored issues
show
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...
376
377
        // Just return the data if it's already cached
378
        return $cache->getOrSet($cacheKey, function() use ($uri, $assetTypes, $siteId): array {
0 ignored issues
show
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
379
            Craft::info(
380
                'Route Map cache miss: ' . $uri,
381
                __METHOD__
382
            );
383
            $resultingAssetUrls = [];
384
385
            // Find the element that matches this URI
386
            /** @var ?Entry $element */
0 ignored issues
show
The open comment tag must be the only content on the line
Loading history...
Missing short description in doc comment
Loading history...
The close comment tag must be the only content on the line
Loading history...
387
            $element = Craft::$app->getElements()->getElementByUri($uri, $siteId, true);
388
            if ($element) {
389
                // Iterate any Assets fields for this entry
390
                $assetFields = FieldHelper::fieldsOfType($element, AssetsField::class);
391
                foreach ($assetFields as $assetField) {
392
                    /** @var Asset[] $assets */
0 ignored issues
show
The open comment tag must be the only content on the line
Loading history...
Missing short description in doc comment
Loading history...
The close comment tag must be the only content on the line
Loading history...
393
                    $assets = $element[$assetField]->all();
394
                    foreach ($assets as $asset) {
395
                        /** @var $asset Asset */
0 ignored issues
show
The open comment tag must be the only content on the line
Loading history...
Missing short description in doc comment
Loading history...
The close comment tag must be the only content on the line
Loading history...
396
                        if (in_array($asset->kind, $assetTypes, true)
397
                            && !in_array($asset->getUrl(), $resultingAssetUrls, true)) {
0 ignored issues
show
Closing parenthesis of a multi-line IF statement must be on a new line
Loading history...
398
                            $resultingAssetUrls[] = $asset->getUrl();
399
                        }
400
                    }
401
                }
402
403
                // Iterate through any Assets embedded in Matrix fields
404
                $matrixFields = FieldHelper::fieldsOfType($element, MatrixField::class);
405
                foreach ($matrixFields as $matrixField) {
406
                    /** @var Entry[] $matrixEntries */
0 ignored issues
show
The open comment tag must be the only content on the line
Loading history...
Missing short description in doc comment
Loading history...
The close comment tag must be the only content on the line
Loading history...
407
                    $matrixEntries = $element[$matrixField]->all();
408
                    foreach ($matrixEntries as $matrixEntry) {
409
                        $assetFields = FieldHelper::matrixFieldsOfType($matrixEntry, AssetsField::class);
410
                        foreach ($assetFields as $assetField) {
411
                            foreach ($matrixEntry[$assetField] as $asset) {
412
                                /** @var $asset Asset */
0 ignored issues
show
The open comment tag must be the only content on the line
Loading history...
Missing short description in doc comment
Loading history...
The close comment tag must be the only content on the line
Loading history...
413
                                if (in_array($asset->kind, $assetTypes, true)
414
                                    && !in_array($asset->getUrl(), $resultingAssetUrls, true)) {
0 ignored issues
show
Closing parenthesis of a multi-line IF statement must be on a new line
Loading history...
415
                                    $resultingAssetUrls[] = $asset->getUrl();
416
                                }
417
                            }
418
                        }
419
                    }
420
                }
421
            }
422
423
            return $resultingAssetUrls;
424
        }, $duration, $dependency);
0 ignored issues
show
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...
425
    }
426
427
    /**
428
     * Returns all the URLs for the given $elementType based on the passed in
429
     * $criteria and $siteId
430
     *
431
     * @param string|ElementInterface $elementType
0 ignored issues
show
Missing parameter comment
Loading history...
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
432
     * @param array $criteria
0 ignored issues
show
Missing parameter comment
Loading history...
Expected 19 spaces after parameter type; 1 found
Loading history...
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
433
     * @param ?int $siteId
0 ignored issues
show
Missing parameter comment
Loading history...
Expected 20 spaces after parameter type; 1 found
Loading history...
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
434
     * @return array
0 ignored issues
show
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
435
     */
436
    public function getElementUrls(string|ElementInterface $elementType, array $criteria = [], ?int $siteId = null): array
437
    {
438
        $devMode = Craft::$app->getConfig()->getGeneral()->devMode;
439
        $cache = Craft::$app->getCache();
440
441
        // Merge in the $criteria passed in
442
        $criteria = array_merge([
0 ignored issues
show
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
443
            'siteId' => $siteId,
444
            'limit' => null,
445
        ], $criteria);
0 ignored issues
show
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...
446
        // Set up our cache criteria
447
        /* @var ElementInterface $elementInterface */
448
        $elementInterface = is_object($elementType) ? $elementType : new $elementType();
449
        $cacheKey = $this->getCacheKey($this::ROUTEMAP_ELEMENT_URLS, [$elementInterface, $criteria, $siteId]);
450
        $duration = $devMode ? $this::DEVMODE_ROUTEMAP_CACHE_DURATION : $this::ROUTEMAP_CACHE_DURATION;
451
        $dependency = new TagDependency([
0 ignored issues
show
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
452
            'tags' => [
453
                $this::ROUTEMAP_CACHE_TAG,
454
            ],
455
        ]);
0 ignored issues
show
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...
456
457
        // Just return the data if it's already cached
458
        return $cache->getOrSet($cacheKey, function() use ($elementInterface, $criteria): array {
0 ignored issues
show
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
459
            Craft::info(
460
                'Route Map cache miss: ' . $elementInterface::class,
461
                __METHOD__
462
            );
463
            $resultingUrls = [];
464
465
            // Get all of the entries in the section
466
            $query = $this->getElementQuery($elementInterface, $criteria);
467
            $elements = $query->all();
468
469
            // Iterate through the elements and grab their URLs
470
            foreach ($elements as $element) {
471
                if ($element instanceof Element
472
                    && $element->uri !== null
473
                    && !in_array($element->uri, $resultingUrls, true)
474
                ) {
475
                    $uri = $this->normalizeUri($element->uri);
476
                    $resultingUrls[] = $uri;
477
                }
478
            }
479
480
            return $resultingUrls;
481
        }, $duration, $dependency);
0 ignored issues
show
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...
482
    }
483
484
    /**
485
     * Invalidate the RouteMap caches
486
     */
0 ignored issues
show
Missing @return tag in function comment
Loading history...
487
    public function invalidateCache(): void
488
    {
489
        $cache = Craft::$app->getCache();
490
        TagDependency::invalidate($cache, self::ROUTEMAP_CACHE_TAG);
491
        Craft::info(
492
            'Route Map cache cleared',
493
            __METHOD__
494
        );
495
    }
496
497
    /**
0 ignored issues
show
Parameter $siteId should have a doc-comment as per coding-style.
Loading history...
Parameter $includeGlobal should have a doc-comment as per coding-style.
Loading history...
498
     * Get all routes rules defined in the config/routes.php file and CMS
499
     *
500
     * @return array
0 ignored issues
show
Tag value for @return tag indented incorrectly; expected 3 spaces but found 1
Loading history...
501
     * @property ?int $siteId
502
     *
503
     * @property bool $includeGlobal - merge global routes with the site rules
504
     */
505
    public function getRouteRules(?int $siteId = null, bool $includeGlobal = true): array
506
    {
507
        $globalRules = [];
508
509
        $siteRoutes = $this->getDbRoutes($siteId);
510
511
        return array_merge(
512
            Craft::$app->getRoutes()->getConfigFileRoutes(),
513
            $globalRules,
514
            $siteRoutes
515
        );
516
    }
517
518
    // Protected Methods
519
    // =========================================================================
520
    /**
521
     * Query the database for db routes
522
     *
523
     * @param ?int $siteId
0 ignored issues
show
Missing parameter comment
Loading history...
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
524
     * @return array
0 ignored issues
show
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
525
     */
526
    protected function getDbRoutes(?int $siteId = null): array
527
    {
528
        return Craft::$app->getRoutes()->getProjectConfigRoutes();
529
    }
530
531
    /**
532
     * Normalize the routes based on the format
533
     *
534
     * @param string $format 'Craft'|'React'|'Vue'
0 ignored issues
show
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
535
     * @param array $route
0 ignored issues
show
Missing parameter comment
Loading history...
Expected 2 spaces after parameter type; 1 found
Loading history...
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
536
     * @return array
0 ignored issues
show
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
537
     */
538
    protected function normalizeFormat(string $format, array $route): array
539
    {
540
        // Normalize the URL
541
        $route['url'] = $this->normalizeUri($route['url']);
542
        // Transform the URLs depending on the format requested
543
        switch ($format) {
544
            // React & Vue routes have a leading / and {slug} -> :slug
545
            case $this::ROUTE_FORMAT_REACT:
0 ignored issues
show
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
546
            case $this::ROUTE_FORMAT_VUE:
0 ignored issues
show
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
547
                $matchRegEx = '`{(.*?)}`';
548
                $replaceRegEx = ':$1';
549
                $route['url'] = preg_replace($matchRegEx, $replaceRegEx, $route['url']);
550
                // Add a leading /
551
                $route['url'] = '/' . ltrim($route['url'], '/');
552
                break;
553
554
            // Craft-style URLs don't need to be changed
555
            case $this::ROUTE_FORMAT_CRAFT:
0 ignored issues
show
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
556
            default:
0 ignored issues
show
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
557
                // Do nothing
558
                break;
559
        }
560
561
        return $route;
562
    }
563
564
    /**
565
     * Normalize the URI
566
     *
567
     * @param string $url
0 ignored issues
show
Missing parameter comment
Loading history...
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
568
     * @return string
0 ignored issues
show
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
569
     */
570
    protected function normalizeUri(string $url): string
571
    {
572
        // Handle the special '__home__' URI
573
        if ($url === '__home__') {
574
            $url = '/';
575
        }
576
577
        return $url;
578
    }
579
580
    /**
0 ignored issues
show
Parameter $prefix should have a doc-comment as per coding-style.
Loading history...
Parameter $args should have a doc-comment as per coding-style.
Loading history...
581
     * Generate a cache key with the combination of the $prefix and an md5()
582
     * hashed version of the flattened $args array
583
     */
0 ignored issues
show
Missing @return tag in function comment
Loading history...
584
    protected function getCacheKey(string $prefix, array $args = []): string
585
    {
586
        $cacheKey = $prefix;
587
        $flattenedArgs = '';
588
        // If an array of $args is passed in, flatten it into a concatenated string
589
        if (!empty($args)) {
590
            foreach ($args as $arg) {
591
                if ((is_object($arg) || is_array($arg)) && !empty($arg)) {
592
                    $flattenedArgs .= http_build_query($arg);
593
                }
594
595
                if (is_string($arg)) {
596
                    $flattenedArgs .= $arg;
597
                }
598
            }
599
600
            // Make an md5 hash out of it
601
            $flattenedArgs = md5($flattenedArgs);
602
        }
603
604
        return $cacheKey . $flattenedArgs;
605
    }
606
607
    /**
608
     * Returns the element query based on $elementType and $criteria
609
     *
610
     * @param array $criteria
0 ignored issues
show
Missing parameter comment
Loading history...
Expected 12 spaces after parameter type; 1 found
Loading history...
Doc comment for parameter $criteria does not match actual variable name $elementType
Loading history...
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
611
     * @param ElementInterface $elementType
0 ignored issues
show
Missing parameter comment
Loading history...
Doc comment for parameter $elementType does not match actual variable name $criteria
Loading history...
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
612
     * @return ElementQueryInterface
0 ignored issues
show
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
613
     */
614
    protected function getElementQuery(ElementInterface $elementType, array $criteria): ElementQueryInterface
615
    {
616
        $query = $elementType::find();
617
        Craft::configure($query, $criteria);
618
619
        return $query;
620
    }
621
}
622