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

FluidTYPO3 / flux / 27757675993

18 Jun 2026 11:55AM UTC coverage: 89.162% (-3.5%) from 92.646%
27757675993

push

github

NamelessCoder
[TASK] Address last phpstan warnings

6228 of 6985 relevant lines covered (89.16%)

40.84 hits per line

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

95.0
/Classes/Utility/CompatibilityRegistry.php
1
<?php
2
namespace FluidTYPO3\Flux\Utility;
3

4
/*
5
 * This file is part of the FluidTYPO3/Flux project under GPLv2 or later.
6
 *
7
 * For the full copyright and license information, please read the
8
 * LICENSE.md file that was distributed with this source code.
9
 */
10

11
use TYPO3\CMS\Core\Utility\VersionNumberUtility;
12

13
/**
14
 * Compatibility Registry
15
 * ----------------------
16
 *
17
 * Utility class responsible for keeping and providing
18
 * arbitrary values (such as configuration defaults, class
19
 * names, feature flags etc.) based on the version of
20
 * TYPO3 being used, or based on arbitrary versions of
21
 * packages, extensions, PHP, PHP modules, binaries etc.
22
 *
23
 * Usage example
24
 * -------------
25
 *
26
 * Use \FluidTYPO3\Flux\Utility\CompatibilityRegistry;
27
 *
28
 * CompatibilityRegistry::register(
29
 *     'FluidTYPO3\\Flux\\Backend\\Preview',
30
 *     [
31
 *         '6.2.0' => 'FluidTYPO3\\Flux\\Backend\\LegacyPreview',
32
 *         '7.1.0' => 'FluidTYPO3\\Flux\\Backend\\Preview'
33
 *     )
34
 * );
35
 *
36
 * $classWhichApplies = CompatibilityRegistry::get(
37
 *     'FluidTYPO3\\Flux\\Backend\\Preview'
38
 * );
39
 *
40
 * Also supports reading a specific version's applied value:
41
 *
42
 * $legacyClassName = CompatibilityRegistry::get(
43
 *     'FluidTYPO3\\Flux\\Backend\\Preview',
44
 *     '7.1.0'
45
 * );
46
 *
47
 * And a default to be used if nothing can be resolved:
48
 *
49
 * $classOrDefault = CompatibilityRegistry::get(
50
 *     'FluidTYPO3\\Flux\\Backend\\Preview',
51
 *     NULL,
52
 *     'FluidTYPO3\\Flux\\Backend\\UnsupportedPreview'
53
 * );
54
 *
55
 * (note that `NULL` is passed as version which means we
56
 * attempt to resolve the currently running version's best
57
 * match. It is still possible to pass a specific version
58
 * number here).
59
 *
60
 * Another example - say you created a backend module and
61
 * need it to work with a custom stylesheet on multiple
62
 * versions of TYPO3 which are styled differently:
63
 *
64
 * CompatibilityRegistry::register(
65
 *     'MyExtension',
66
 *     '/mySpecialNameForTheStylesheet',
67
 *     [
68
 *         '6.2.0' => 'EXT:my_extension/.../Styles.6.2.0.css',
69
 *         '7.2.0' => 'EXT:my_extension/.../Styles.7.2.0.css',
70
 *         '7.5.0' => 'EXT:my_extension/.../Styles.7.5.0.css'
71
 *     )
72
 * );
73
 *
74
 * And to retrieve:
75
 *
76
 * $styleSheet = CompatibilityRegistry::get(
77
 *     'MyExtension/mySpecialNameForTheStylesheet'
78
 * );
79
 *
80
 * And to illustrate, if...:
81
 *
82
 * - TYPO3 is 6.2.* obviously the '6.2.0' entry is used
83
 * - TYPO3 is 7.1.0 the '6.2.0' is used because '7.2.' is too high
84
 * - TYPO3 is 7.4.0 the '7.2.0' is used
85
 * - TYPO3 is anything at or above 7.5.0 then '7.5.0' is used
86
 *
87
 * Feature Flags
88
 * -------------
89
 *
90
 * The Compatibility Registry can also handle feature
91
 * flags for you; returning the closest matching set of
92
 * or individual feature flag based on version:
93
 *
94
 * CompatibilityRegistry::registerFeatureFlags(
95
 *     'FluidTYPO3.Flux',
96
 *     [
97
 *         '6.2.0' => ['form', 'nestedContent', 'provider', 'preview'),
98
 *         '7.5.0' => ['form', 'nestedContent', 'provider', 'preview', 'formengine'),
99
 *         '7.6.0' => ['form', 'provider', 'preview', 'formengine')
100
 *     )
101
 * );
102
 *
103
 * And to retrieve:
104
 *
105
 * if (CompatibilityRegistry::hasFeatureFlag('FluidTYPO3.Flux', 'nestedContent')) {
106
 *     // Would only be true until TYPO3 version hits 7.6.0, then
107
 *     // no longer triggers.
108
 * }
109
 *
110
 * Deprecation
111
 * -----------
112
 *
113
 * Because usage of CompatibilityRegistry is a very clear
114
 * intention of *supporting deprecation*, there is a built-in
115
 * layer warning of deprecation when you *register* either
116
 * values or feature flags but *do not include a currently
117
 * supported TYPO3 version* (as far as Flux is aware). To
118
 * disable this deprecation reporting simply pass TRUE as
119
 * the last parameter for either of the register commands:
120
 *
121
 * CompatibilityRegistry::register('MyClass', [...), TRUE);
122
 * CompatibilityRegistry::registerFeatureFlag('MyExt', [...), TRUE);
123
 *
124
 * Doing so merely prevents the check for whether or not you
125
 * include a value or feature flag for a non-deprecated TYPO3.
126
 *
127
 * Extension versions as key
128
 * -------------------------
129
 *
130
 * It is possible to make a registered variable or feature
131
 * flag not depend on the TYPO3 version but instead the
132
 * version of any arbitrary package - like a composer
133
 * dependency or version of PHP. To utilise this slightly
134
 * off-standard registry behavior, *manually include the
135
 * version you are checking against when you retrieve the
136
 * values from the registry*.
137
 *
138
 * Say your extension depends on extension "comments"
139
 * (fictional) but "comments" may be installed in several
140
 * versions that can be supported without breaking, as
141
 * long as certain features are not enabled:
142
 *
143
 * CompatibilityRegistry::registerFeatureFlags(
144
 *     'MyExt',
145
 *     [
146
 *         '3.1.0' => ['falRelations'),
147
 *         '4.0.0' => ['falRelations', 'ajax')
148
 *     ),
149
 *     TRUE
150
 *     // Note: *always* pass true here; the versions we record
151
 *     // aren't for TYPO3 so we don't want deprecation warnings.
152
 * );
153
 *
154
 * $extensionVersion = ExtensionManagementUtility::getExtensionVersion('comments');
155
 * if (CompatibilityRegistry::hasFeatureFlag('MyExt', 'ajax', $extensionVersion) {
156
 *     // It's okay to use our fresh feature that depends on
157
 *     // the version of "comments" extension, not TYPO3 itself.
158
 * }
159
 *
160
 * Which naturally means that only if the "comments"
161
 * extension is installed in at least version 4.0.0 will
162
 * the "ajax" feature flag query be TRUE.
163
 */
164
abstract class CompatibilityRegistry
165
{
166
    public const string VERSION_DEFAULT = 'default';
167

168
    protected static array $registry = [];
169
    protected static array $featureFlags = [];
170
    protected static array $cache = [];
171

172
    public static function register(string $scope, array $versionedVariables): void
173
    {
174
        static::$registry[$scope] = $versionedVariables;
32✔
175
    }
176

177
    public static function registerFeatureFlags(string $scope, array $versionedFeatureFlags): void
178
    {
179
        static::$featureFlags[$scope] = $versionedFeatureFlags;
16✔
180
    }
181

182
    /**
183
     * @param mixed $default
184
     * @return mixed
185
     */
186
    public static function get(string $scope, string $version = self::VERSION_DEFAULT, $default = null)
187
    {
188
        return static::cache(static::$registry, 'registry', $scope, $version) ?? $default;
20✔
189
    }
190

191
    public static function hasFeatureFlag(string $scope, string $flag, string $version = self::VERSION_DEFAULT): bool
192
    {
193
        return in_array($flag, static::getFeatureFlags($scope, $version));
16✔
194
    }
195

196
    public static function getFeatureFlags(string $scope, string $version = self::VERSION_DEFAULT): array
197
    {
198
        return (array) static::cache(static::$featureFlags, 'featureFlags', $scope, $version);
16✔
199
    }
200

201
    /**
202
     * @return mixed
203
     */
204
    protected static function resolveVersionedValue(array &$versionedValues, string $version)
205
    {
206
        if ($version === self::VERSION_DEFAULT) {
28✔
207
            $version = VersionNumberUtility::getCurrentTypo3Version();
4✔
208
        }
209
        krsort($versionedValues);
28✔
210
        foreach ($versionedValues as $valueVersion => $value) {
28✔
211
            if (version_compare((string) $version, (string) $valueVersion, '>=')) {
28✔
212
                return $value;
20✔
213
            }
214
        }
215
        return null;
8✔
216
    }
217

218
    /**
219
     * @return mixed
220
     */
221
    protected static function cache(array &$source, string $prefix, string $scope, string $version)
222
    {
223
        $key = $prefix . '-' . $scope . '-' . $version;
36✔
224
        if (true === array_key_exists($key, static::$cache)) {
36✔
225
            return static::$cache[$key];
8✔
226
        } elseif (is_array($source[$scope] ?? null)) {
28✔
227
            $value = static::resolveVersionedValue($source[$scope], $version);
28✔
228
            static::$cache[$key] = $value;
28✔
229
            return $value;
28✔
230
        }
231
        return null;
×
232
    }
233
}
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

© 2026 Coveralls, Inc