Completed
Push — master ( 4efe38...cf8f45 )
by Tim
03:03 queued 01:04
created

Loader::allowNonDoctrineAnnotations()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
dl 0
loc 24
ccs 0
cts 12
cp 0
rs 9.536
c 0
b 0
f 0
cc 3
nc 3
nop 0
crap 12
1
<?php
2
3
/**
4
 * Central Loader object.
5
 */
6
declare(strict_types=1);
7
8
namespace HDNET\Autoloader;
9
10
use Doctrine\Common\Annotations\AnnotationReader;
11
use HDNET\Autoloader\Utility\ReflectionUtility;
12
use TYPO3\CMS\Core\Cache\Backend\SimpleFileBackend;
13
use TYPO3\CMS\Core\Cache\CacheManager;
14
use TYPO3\CMS\Core\Cache\Frontend\PhpFrontend;
15
use TYPO3\CMS\Core\Configuration\ConfigurationManager;
16
use TYPO3\CMS\Core\Utility\GeneralUtility;
17
use TYPO3\CMS\Core\Utility\VersionNumberUtility;
18
19
/**
20
 * Central Loader object.
21
 */
22
class Loader implements SingletonInterface
23
{
24
    /**
25
     * The different implementations and the order of the execution.
26
     *
27
     * @var array
28
     */
29
    protected $implementations = [
30
        // class replacement
31
        'Xclass',
32
        'AlternativeImplementations',
33
        // additional functions
34
        'Hooks',
35
        'Slots',
36
        // smart object management
37
        'SmartObjects',
38
        'ContentObjects',
39
        'TcaFiles',
40
        'ExtensionTypoScriptSetup',
41
        'ContextSensitiveHelps',
42
        // non-critical
43
        'Plugins',
44
        'FlexForms',
45
        'CommandController',
46
        'StaticTyposcript',
47
        'ExtensionId',
48
        'TypeConverter',
49
        'BackendLayout',
50
        'SoapServer',
51
        'JsonServer',
52
        'LanguageOverride',
53
        'Icon',
54
        'Gridelement',
55
        'FluidNamespace',
56
    ];
57
58
    /**
59
     * The Extension key.
60
     *
61
     * @var string
62
     */
63
    protected $extensionKey;
64
65
    /**
66
     * The vendorName.
67
     *
68
     * @var string
69
     */
70
    protected $vendorName;
71
72
    /**
73
     * Set to tro, if there is no valid autoloader cache.
74
     *
75
     * @var bool
76
     */
77
    protected $disableFirstCall = false;
78
79
    /**
80
     * Default cache configuration.
81
     *
82
     * @var array
83
     */
84
    protected $cacheConfiguration = [
85
        'backend' => SimpleFileBackend::class,
86
        'frontend' => PhpFrontend::class,
87
        'groups' => [
88
            'system',
89
        ],
90
        'options' => [
91
            'defaultLifetime' => 0,
92
        ],
93
    ];
94
95
    /**
96
     * Build up the object.
97
     * If there is no valid cache in the LocalConfiguration add one.
98
     */
99
    public function __construct()
100
    {
101
        if (!isset($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['autoloader'])) {
102
            /** @var \TYPO3\CMS\Core\Configuration\ConfigurationManager $configurationManager */
103
            $configurationManager = GeneralUtility::makeInstance(ConfigurationManager::class);
104
            $configurationManager->setLocalConfigurationValueByPath(
105
                'SYS/caching/cacheConfigurations/autoloader',
106
                $this->cacheConfiguration
107
            );
108
            $this->disableFirstCall = true;
109
        }
110
    }
111
112
    /**
113
     * Call this method in the ext_tables.php file.
114
     *
115
     * @param string $vendorName
116
     * @param string $extensionKey
117
     * @param array  $implementations
118
     */
119
    public static function extTables($vendorName, $extensionKey, array $implementations = [])
120
    {
121
        self::allowNonDoctrineAnnotations();
122
        /** @var \HDNET\Autoloader\Loader $loader */
123
        $loader = GeneralUtility::makeInstance(self::class);
124
        $loader->loadExtTables($vendorName, $extensionKey, $implementations);
125
    }
126
127
    /**
128
     * Call this method in the ext_localconf.php file.
129
     *
130
     * @param string $vendorName
131
     * @param string $extensionKey
132
     * @param array  $implementations
133
     */
134
    public static function extLocalconf($vendorName, $extensionKey, array $implementations = [])
135
    {
136
        self::allowNonDoctrineAnnotations();
137
        /** @var \HDNET\Autoloader\Loader $loader */
138
        $loader = GeneralUtility::makeInstance(self::class);
139
        $loader->loadExtLocalconf($vendorName, $extensionKey, $implementations);
140
    }
141
142
    /**
143
     * Allow non Doctrine annotations
144
     */
145
    public static function allowNonDoctrineAnnotations()
146
    {
147
        static $done = false;
148
        if ($done) {
149
            return;
150
        }
151
        $done = true;
152
        $is9orHigher = VersionNumberUtility::convertVersionNumberToInteger(TYPO3_branch) >= VersionNumberUtility::convertVersionNumberToInteger('9.0');
153
        if ($is9orHigher) {
154
            AnnotationReader::addGlobalIgnoredName('signalClass');
155
            AnnotationReader::addGlobalIgnoredName('signalName');
156
            AnnotationReader::addGlobalIgnoredName('noHeader');
157
            AnnotationReader::addGlobalIgnoredName('wizardTab');
158
            AnnotationReader::addGlobalIgnoredName('db');
159
            AnnotationReader::addGlobalIgnoredName('recordType');
160
            AnnotationReader::addGlobalIgnoredName('parentClass');
161
            AnnotationReader::addGlobalIgnoredName('hook');
162
            AnnotationReader::addGlobalIgnoredName('plugin');
163
            AnnotationReader::addGlobalIgnoredName('noCache');
164
            AnnotationReader::addGlobalIgnoredName('enableRichText');
165
            AnnotationReader::addGlobalIgnoredName('parentClass');
166
            AnnotationReader::addGlobalIgnoredName('smartExclude');
167
        }
168
    }
169
170
    /**
171
     * Load the ext tables information.
172
     *
173
     * @param string $vendorName
174
     * @param string $extensionKey
175
     * @param array  $implementations
176
     */
177
    public function loadExtTables($vendorName, $extensionKey, array $implementations = [])
178
    {
179
        if ($this->disableFirstCall) {
180
            return;
181
        }
182
        $this->extensionKey = $extensionKey;
183
        $this->vendorName = $vendorName;
184
185
        $autoLoaderObjects = $this->buildAutoLoaderObjects($implementations);
186
        $information = $this->prepareAutoLoaderObjects($autoLoaderObjects, LoaderInterface::EXT_TABLES);
187
        foreach ($autoLoaderObjects as $object) {
188
            /** @var LoaderInterface $object */
189
            $informationArray = $information[\get_class($object)];
190
            if (\is_array($informationArray)) {
191
                $object->loadExtensionTables($this, $informationArray);
192
            }
193
        }
194
    }
195
196
    /**
197
     * Load the ext localconf information.
198
     *
199
     * @param string $vendorName
200
     * @param string $extensionKey
201
     * @param array  $implementations
202
     */
203
    public function loadExtLocalconf($vendorName, $extensionKey, array $implementations = [])
204
    {
205
        if ($this->disableFirstCall) {
206
            return;
207
        }
208
        $this->extensionKey = $extensionKey;
209
        $this->vendorName = $vendorName;
210
211
        $autoLoaderObjects = $this->buildAutoLoaderObjects($implementations);
212
        $information = $this->prepareAutoLoaderObjects($autoLoaderObjects, LoaderInterface::EXT_LOCAL_CONFIGURATION);
213
        foreach ($autoLoaderObjects as $object) {
214
            /** @var LoaderInterface $object */
215
            $informationArray = $information[\get_class($object)];
216
            if (\is_array($informationArray)) {
217
                $object->loadExtensionConfiguration($this, $informationArray);
218
            }
219
        }
220
    }
221
222
    /**
223
     * Get the extension key.
224
     *
225
     * @return string
226
     */
227
    public function getExtensionKey()
228
    {
229
        return $this->extensionKey;
230
    }
231
232
    /**
233
     * Get the vendor name.
234
     *
235
     * @return string
236
     */
237
    public function getVendorName()
238
    {
239
        return $this->vendorName;
240
    }
241
242
    /**
243
     * check if the class is loadable and is instantiable
244
     * (exists and is no interface or abstraction etc.).
245
     *
246
     * @param $class
247
     *
248
     * @return bool
249
     */
250
    public function isInstantiableClass($class)
251
    {
252
        return ReflectionUtility::isInstantiable($class);
253
    }
254
255
    /**
256
     * Build the Autoloader objects.
257
     *
258
     * @param array $objectNames
259
     *
260
     * @return array
261
     */
262
    protected function buildAutoLoaderObjects(array $objectNames = [])
263
    {
264
        static $objectCache = [];
265
        $objectNames = $this->getAutoLoaderNamesInRightOrder($objectNames);
266
        $objects = [];
267
        foreach ($objectNames as $autoLoaderObjectName) {
268
            if (!isset($objectCache[$autoLoaderObjectName])) {
269
                if (\class_exists('HDNET\\Autoloader\\Loader\\' . $autoLoaderObjectName)) {
270
                    $objectCache[$autoLoaderObjectName] = GeneralUtility::makeInstance('HDNET\\Autoloader\\Loader\\' . $autoLoaderObjectName);
271
                } else {
272
                    $objectCache[$autoLoaderObjectName] = GeneralUtility::makeInstance($autoLoaderObjectName);
273
                }
274
            }
275
            $objects[] = $objectCache[$autoLoaderObjectName];
276
        }
277
278
        return $objects;
279
    }
280
281
    /**
282
     * Get the Autoloader Names in the right order.
283
     *
284
     * @param array $objectNames
285
     *
286
     * @return array
287
     */
288
    protected function getAutoLoaderNamesInRightOrder(array $objectNames = [])
289
    {
290
        if (empty($objectNames)) {
291
            return $this->implementations;
292
        }
293
294
        // sort
295
        $names = [];
296
        foreach ($this->implementations as $className) {
297
            if (\in_array($className, $objectNames, true)) {
298
                $names[] = $className;
299
                unset($objectNames[\array_search($className, $objectNames, true)]);
300
            }
301
        }
302
303
        return \array_merge($names, $objectNames);
304
    }
305
306
    /**
307
     * Prepare the autoLoader information.
308
     *
309
     * @param array $objects
310
     * @param int   $type
311
     *
312
     * @return array
313
     */
314
    protected function prepareAutoLoaderObjects(array $objects, $type)
315
    {
316
        $cacheIdentifier = $this->getVendorName() . '_' . $this->getExtensionKey() . '_' . GeneralUtility::shortMD5(\serialize($objects)) . '_' . $type;
317
318
        /** @var $cache \TYPO3\CMS\Core\Cache\Frontend\PhpFrontend */
319
        $cache = $this->getCacheManager()
320
            ->getCache('autoloader');
321
        if ($cache->has($cacheIdentifier)) {
322
            return $cache->requireOnce($cacheIdentifier);
323
        }
324
325
        $return = $this->buildLoaderInformation($objects, $type);
326
        $cache->set($cacheIdentifier, 'return ' . \var_export($return, true) . ';');
327
328
        return $return;
329
    }
330
331
    /**
332
     * Build the loader information.
333
     *
334
     * @param $objects
335
     * @param $type
336
     *
337
     * @return array
338
     */
339
    protected function buildLoaderInformation($objects, $type)
340
    {
341
        $return = [];
342
        foreach ($objects as $object) {
343
            /* @var LoaderInterface $object */
344
            $return[\get_class($object)] = $object->prepareLoader($this, $type);
345
        }
346
347
        return $return;
348
    }
349
350
    /**
351
     * Get the cache manager.
352
     *
353
     * @return \TYPO3\CMS\Core\Cache\CacheManager
354
     */
355
    protected function getCacheManager()
356
    {
357
        return GeneralUtility::makeInstance(CacheManager::class);
358
    }
359
}
360