• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

eliashaeussler / typo3-warming / 18447366655

12 Oct 2025 05:42PM UTC coverage: 93.098% (+0.3%) from 92.803%
18447366655

push

github

web-flow
Merge pull request #993 from eliashaeussler/feature/actions

138 of 139 new or added lines in 6 files covered. (99.28%)

1 existing line in 1 file now uncovered.

1767 of 1898 relevant lines covered (93.1%)

12.47 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.96
/Classes/Backend/Action/WarmupActionsProvider.php
1
<?php
2

3
declare(strict_types=1);
4

5
/*
6
 * This file is part of the TYPO3 CMS extension "warming".
7
 *
8
 * Copyright (C) 2021-2025 Elias Häußler <elias@haeussler.dev>
9
 *
10
 * This program is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation, either version 2 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
 * GNU General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU General Public License
21
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22
 */
23

24
namespace EliasHaeussler\Typo3Warming\Backend\Action;
25

26
use EliasHaeussler\Typo3SitemapLocator;
27
use EliasHaeussler\Typo3Warming\Configuration;
28
use EliasHaeussler\Typo3Warming\Domain;
29
use EliasHaeussler\Typo3Warming\Security;
30
use Symfony\Component\DependencyInjection;
31
use TYPO3\CMS\Backend;
32
use TYPO3\CMS\Core;
33

34
/**
35
 * WarmupActionsProvider
36
 *
37
 * @author Elias Häußler <elias@haeussler.dev>
38
 * @license GPL-2.0-or-later
39
 */
40
final readonly class WarmupActionsProvider
41
{
42
    public function __construct(
30✔
43
        private Configuration\Configuration $configuration,
44
        private Security\WarmupPermissionGuard $permissionGuard,
45
        private Core\Site\SiteFinder $siteFinder,
46
        private Domain\Repository\SiteLanguageRepository $siteLanguageRepository,
47
        private Domain\Repository\SiteRepository $siteRepository,
48
        private Typo3SitemapLocator\Sitemap\SitemapLocator $sitemapLocator,
49
        #[DependencyInjection\Attribute\Autowire('@cache.runtime')]
50
        private Core\Cache\Frontend\FrontendInterface $runtimeCache,
51
    ) {}
30✔
52

53
    /**
54
     * @return ($context is WarmupActionContext::Page ? PageWarmupActions|null : SiteWarmupActions|null)
55
     */
56
    public function provideActions(WarmupActionContext $context, int $pageId): PageWarmupActions|SiteWarmupActions|null
13✔
57
    {
58
        return match ($context) {
59
            WarmupActionContext::Page => $this->providePageActions($pageId),
13✔
60
            WarmupActionContext::Site => $this->provideSiteActions($pageId),
13✔
61
        };
62
    }
63

64
    public function provideSiteActions(int $pageId): ?SiteWarmupActions
19✔
65
    {
66
        if (!$this->isValidPage($pageId)) {
19✔
67
            return null;
4✔
68
        }
69

70
        $site = $this->siteRepository->findOneByRootPageId($pageId);
16✔
71

72
        // Early return if no associated site could be found
73
        if ($site === null) {
16✔
74
            return null;
2✔
75
        }
76

77
        // Get all languages of current site that are available for the current backend user
78
        $siteLanguages = array_filter(
14✔
79
            $this->siteLanguageRepository->findAll($site),
14✔
80
            fn(Core\Site\Entity\SiteLanguage $siteLanguage): bool => $this->canWarmupCachesOfSite($site, $siteLanguage),
14✔
81
        );
14✔
82

83
        return new SiteWarmupActions($site, $siteLanguages);
14✔
84
    }
85

86
    public function providePageActions(int $pageId): ?PageWarmupActions
18✔
87
    {
88
        if (!$this->isValidPage($pageId)) {
18✔
89
            return null;
3✔
90
        }
91

92
        try {
93
            // We cannot use SiteRepository here because it checks for associated site permissions,
94
            // where we want to check page permissions only
95
            $site = $this->siteFinder->getSiteByPageId($pageId);
15✔
96
        } catch (Core\Exception\SiteNotFoundException) {
1✔
97
            // Early return if no associated site could be found
98
            return null;
1✔
99
        }
100

101
        // Get all languages of current site that are available for the current backend user
102
        $siteLanguages = array_filter(
14✔
103
            $site->getAllLanguages(),
14✔
104
            fn(Core\Site\Entity\SiteLanguage $siteLanguage): bool => $this->permissionGuard->canWarmupCacheOfPage(
14✔
105
                $pageId,
14✔
106
                new Security\Context\PermissionContext($siteLanguage->getLanguageId()),
14✔
107
            ),
14✔
108
        );
14✔
109

110
        return new PageWarmupActions($pageId, $siteLanguages);
14✔
111
    }
112

113
    /**
114
     * @phpstan-assert-if-true non-negative-int $pageId
115
     */
116
    private function isValidPage(int $pageId): bool
26✔
117
    {
118
        $cacheIdentifier = 'warming_warmupActionsProvider_isValidPage_' . $pageId;
26✔
119

120
        // Return validation result from cache, if available
121
        if ($this->runtimeCache->has($cacheIdentifier)) {
26✔
122
            return $this->runtimeCache->get($cacheIdentifier);
12✔
123
        }
124

125
        // Root page cannot be used for cache warmup since it is not accessible in Frontend
126
        if ($pageId === 0) {
26✔
127
            return false;
2✔
128
        }
129

130
        $record = Backend\Utility\BackendUtility::getRecordWSOL('pages', $pageId);
24✔
131

132
        // Early return if page does not exist
133
        if ($record === null) {
24✔
134
            return false;
2✔
135
        }
136

137
        $doktype = (int)($record['doktype'] ?? 0);
22✔
138
        $isValidPage = $doktype > 0 && \in_array($doktype, $this->configuration->supportedDoktypes, true);
22✔
139

140
        // Store page validation in cache to avoid further lookups
141
        $this->runtimeCache->set($cacheIdentifier, $isValidPage);
22✔
142

143
        return $isValidPage;
22✔
144
    }
145

146
    private function canWarmupCachesOfSite(Core\Site\Entity\Site $site, Core\Site\Entity\SiteLanguage $siteLanguage): bool
13✔
147
    {
148
        try {
149
            // Check if any sitemap exists
150
            foreach ($this->sitemapLocator->locateBySite($site, $siteLanguage) as $sitemap) {
13✔
151
                if ($this->sitemapLocator->isValidSitemap($sitemap)) {
13✔
152
                    return true;
10✔
153
                }
154
            }
NEW
155
        } catch (\Exception) {
×
156
            // Unable to locate any sitemaps
157
        }
158

159
        return false;
4✔
160
    }
161
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc