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

eliashaeussler / typo3-warming / 19583324379

21 Nov 2025 08:58PM UTC coverage: 94.541% (-0.05%) from 94.592%
19583324379

Pull #1023

github

eliashaeussler
[FEATURE] Add support for TYPO3 v14.0
Pull Request #1023: [FEATURE] Add support for TYPO3 v14.0

2 of 3 new or added lines in 1 file covered. (66.67%)

1680 of 1777 relevant lines covered (94.54%)

12.27 hits per line

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

97.01
/Classes/Backend/ContextMenu/ItemProviders/CacheWarmupProvider.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\ContextMenu\ItemProviders;
25

26
use EliasHaeussler\Typo3Warming\Backend\Action;
27
use EliasHaeussler\Typo3Warming\Configuration;
28
use EliasHaeussler\Typo3Warming\Domain;
29
use TYPO3\CMS\Backend;
30
use TYPO3\CMS\Core;
31

32
/**
33
 * CacheWarmupProvider
34
 *
35
 * @author Elias Häußler <elias@haeussler.dev>
36
 * @license GPL-2.0-or-later
37
 */
38
final class CacheWarmupProvider extends Backend\ContextMenu\ItemProviders\PageProvider
39
{
40
    private const CONTEXTS = [
41
        Action\WarmupActionContext::Page,
42
        Action\WarmupActionContext::Site,
43
    ];
44

45
    /**
46
     * @var array<string, array{
47
     *     type: string
48
     * }|array{
49
     *     type: string,
50
     *     label: string,
51
     *     iconIdentifier: string,
52
     *     callbackAction: string,
53
     *     childItems?: array<string, array{
54
     *         label?: string,
55
     *         iconIdentifier?: string,
56
     *         callbackAction?: string,
57
     *     }>,
58
     * }>
59
     */
60
    protected $itemsConfiguration = [];
61

62
    /**
63
     * @var array<non-empty-string, array{Action\WarmupAction, Action\WarmupActionContext}>
64
     */
65
    private array $actions = [];
66

67
    public function __construct(
15✔
68
        private readonly Domain\Repository\SiteRepository $siteRepository,
69
        private readonly Configuration\Configuration $configuration,
70
        private readonly Action\WarmupActionsProvider $actionsProvider,
71
        Core\Schema\TcaSchemaFactory $tcaSchemaFactory,
72
        Backend\Routing\UriBuilder $uriBuilder,
73
    ) {
74
        if ((new Core\Information\Typo3Version())->getMajorVersion() >= 14) {
15✔
75
            /* @phpstan-ignore arguments.count */
NEW
76
            parent::__construct($tcaSchemaFactory, $uriBuilder);
×
77
        } else {
78
            // @todo Remove once support for TYPO3 v13 is dropped
79
            parent::__construct();
15✔
80
        }
81
    }
82

83
    protected function canRender(string $itemName, string $type): bool
10✔
84
    {
85
        if (\in_array($itemName, $this->disabledItems, true)) {
10✔
86
            return false;
×
87
        }
88

89
        return true;
10✔
90
    }
91

92
    /**
93
     * @param array<string, array<string, mixed>> $items
94
     * @return array<string, array<string, mixed>>
95
     */
96
    public function addItems(array $items): array
15✔
97
    {
98
        $this->initialize();
15✔
99

100
        $localItems = $this->prepareItems($this->itemsConfiguration);
15✔
101
        $items += $localItems;
15✔
102

103
        return $items;
15✔
104
    }
105

106
    protected function initialize(): void
15✔
107
    {
108
        parent::initialize();
15✔
109
        $this->initItems();
15✔
110
    }
111

112
    public function getPriority(): int
15✔
113
    {
114
        return 45;
15✔
115
    }
116

117
    private function initItems(): void
15✔
118
    {
119
        // Early return if cache warmup from page tree is disabled globally
120
        if (!$this->configuration->enabledInPageTree) {
15✔
121
            return;
1✔
122
        }
123

124
        $site = $this->getCurrentSite();
14✔
125

126
        // Early return if site cannot be resolved
127
        if ($site === null) {
14✔
128
            return;
3✔
129
        }
130

131
        $pageId = $this->getPreviewPid();
11✔
132
        $dividerAdded = false;
11✔
133

134
        foreach (self::CONTEXTS as $context) {
11✔
135
            $actions = $this->actionsProvider->provideActions($context, $pageId);
11✔
136

137
            // Skip invalid and unsupported actions
138
            if ($actions === null || $actions->siteLanguages === []) {
11✔
139
                continue;
140
            }
141

142
            $itemName = $context->value;
10✔
143

144
            // Skip non-renderable items
145
            if (!$this->canRender($itemName, 'item')) {
10✔
146
                continue;
147
            }
148

149
            $itemConfiguration = [
10✔
150
                'type' => 'submenu',
10✔
151
                'label' => $context->label(),
10✔
152
                'iconIdentifier' => $context->icon(),
10✔
153
                'childItems' => [],
10✔
154
            ];
10✔
155

156
            // Add actions as child elements to the current item
157
            foreach ($actions->getActions() as $action) {
10✔
158
                $childItemName = $itemName . '_' . $action->name;
10✔
159
                $itemConfiguration['childItems'][$childItemName] = [
10✔
160
                    'label' => $action->label,
10✔
161
                    'iconIdentifier' => $action->icon,
10✔
162
                    'callbackAction' => $context->callbackAction(),
10✔
163
                ];
10✔
164

165
                // Store action for further processing
166
                $this->actions[$childItemName] = [$action, $context];
10✔
167
            }
168

169
            // Add divider if not already added
170
            if (!$dividerAdded) {
10✔
171
                $this->itemsConfiguration['cacheWarmupDivider'] = [
10✔
172
                    'type' => 'divider',
10✔
173
                ];
10✔
174
                $dividerAdded = true;
10✔
175
            }
176

177
            // Add item configuration
178
            $this->itemsConfiguration[$itemName] = $itemConfiguration;
10✔
179
        }
180
    }
181

182
    /**
183
     * @return array<string, mixed>
184
     */
185
    protected function getAdditionalAttributes(string $itemName): array
10✔
186
    {
187
        $attributes = [
10✔
188
            'data-callback-module' => '@eliashaeussler/typo3-warming/backend/context-menu-action',
10✔
189
        ];
10✔
190

191
        // Early return if current item is not part of a submenu
192
        // within the configured context menu items
193
        if (!isset($this->actions[$itemName])) {
10✔
194
            return $attributes;
10✔
195
        }
196

197
        [$action, $context] = $this->actions[$itemName];
10✔
198

199
        // Add site identifier as data attribute
200
        if ($context === Action\WarmupActionContext::Site) {
10✔
201
            $attributes['data-site-identifier'] = $this->getCurrentSite()?->getIdentifier();
8✔
202
        }
203

204
        // Add action identifier (language ID or special item) as data attribute
205
        $attributes['data-action-identifier'] = $action->identifier;
10✔
206

207
        return $attributes;
10✔
208
    }
209

210
    private function getCurrentSite(): ?Core\Site\Entity\Site
14✔
211
    {
212
        if ($this->record === null) {
14✔
213
            return null;
1✔
214
        }
215

216
        /** @var non-negative-int $pageId */
217
        $pageId = $this->getPreviewPid();
13✔
218

219
        return $this->siteRepository->findOneByPageId($pageId);
13✔
220
    }
221
}
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