CacheService   A
last analyzed

Complexity

Total Complexity 11

Size/Duplication

Total Lines 115
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
wmc 11
lcom 1
cbo 3
dl 0
loc 115
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A registerInternalCache() 0 8 2
A registerDynamicCaches() 0 11 2
A registerDynamicCache() 0 15 2
A registerCacheInternal() 0 8 2
A getCache() 0 4 1
A getCacheManager() 0 9 2
1
<?php
2
/*
3
 * 2018 Romain CANON <[email protected]>
4
 *
5
 * This file is part of the TYPO3 Configuration Object project.
6
 * It is free software; you can redistribute it and/or modify it
7
 * under the terms of the GNU General Public License, either
8
 * version 3 of the License, or any later version.
9
 *
10
 * For the full copyright and license information, see:
11
 * http://www.gnu.org/licenses/gpl-3.0.html
12
 */
13
14
namespace Romm\ConfigurationObject\Core\Service;
15
16
use TYPO3\CMS\Core\Cache\Backend\FileBackend;
17
use TYPO3\CMS\Core\Cache\CacheManager;
18
use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
19
use TYPO3\CMS\Core\Cache\Frontend\VariableFrontend;
20
use TYPO3\CMS\Core\SingletonInterface;
21
use TYPO3\CMS\Core\Utility\GeneralUtility;
22
23
class CacheService implements SingletonInterface
24
{
25
    const CACHE_IDENTIFIER = 'cache_configuration_object';
26
    const CACHE_TAG_DYNAMIC_CACHE = 'dynamic-cache';
27
28
    /**
29
     * Options for the internal cache.
30
     *
31
     * @var array
32
     */
33
    protected $cacheOptions = [
34
        'backend'  => FileBackend::class,
35
        'frontend' => VariableFrontend::class,
36
        'groups'   => ['all', 'system']
37
    ];
38
39
    /**
40
     * @var CacheManager
41
     */
42
    protected $cacheManager;
43
44
    /**
45
     * Function called from `ext_localconf` file which will register the
46
     * internal cache earlier.
47
     *
48
     * @internal
49
     */
50
    public function registerInternalCache()
51
    {
52
        $cacheManager = $this->getCacheManager();
53
54
        if (false === $cacheManager->hasCache(self::CACHE_IDENTIFIER)) {
55
            $cacheManager->setCacheConfigurations([self::CACHE_IDENTIFIER => $this->cacheOptions]);
56
        }
57
    }
58
59
    /**
60
     * This function will take care of initializing all caches that were defined
61
     * previously  by the `CacheService` which allows dynamic caches to be used
62
     * for every configuration object type.
63
     *
64
     * @see \Romm\ConfigurationObject\Service\Items\Cache\CacheService::initialize()
65
     * @internal
66
     */
67
    public function registerDynamicCaches()
68
    {
69
        $dynamicCaches = $this->getCache()->getByTag(self::CACHE_TAG_DYNAMIC_CACHE);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface TYPO3\CMS\Core\Cache\Frontend\FrontendInterface as the method getByTag() does only exist in the following implementations of said interface: TYPO3\CMS\Core\Cache\Frontend\PhpFrontend, TYPO3\CMS\Core\Cache\Frontend\StringFrontend, TYPO3\CMS\Core\Cache\Frontend\VariableFrontend.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
70
71
        foreach ($dynamicCaches as $cacheData) {
72
            $identifier = $cacheData['identifier'];
73
            $options = $cacheData['options'];
74
75
            $this->registerCacheInternal($identifier, $options);
76
        }
77
    }
78
79
    /**
80
     * Registers a new dynamic cache: the cache will be added to the cache
81
     * manager after this function is executed. Its configuration will also be
82
     * remembered so the cache will be registered properly during the cache
83
     * framework initialization in further requests.
84
     *
85
     * @param string $identifier
86
     * @param array  $options
87
     */
88
    public function registerDynamicCache($identifier, array $options)
89
    {
90
        if (false === $this->getCache()->has($identifier)) {
91
            $this->getCache()->set(
92
                $identifier,
93
                [
94
                    'identifier' => $identifier,
95
                    'options'    => $options
96
                ],
97
                [self::CACHE_TAG_DYNAMIC_CACHE]
98
            );
99
        }
100
101
        $this->registerCacheInternal($identifier, $options);
102
    }
103
104
    /**
105
     * @param string $identifier
106
     * @param array  $options
107
     */
108
    protected function registerCacheInternal($identifier, array $options)
109
    {
110
        $cacheManager = $this->getCacheManager();
111
112
        if (false === $cacheManager->hasCache($identifier)) {
113
            $cacheManager->setCacheConfigurations([$identifier => $options]);
114
        }
115
    }
116
117
    /**
118
     * @return FrontendInterface
119
     */
120
    protected function getCache()
121
    {
122
        return $this->getCacheManager()->getCache(self::CACHE_IDENTIFIER);
123
    }
124
125
    /**
126
     * @return CacheManager
127
     */
128
    protected function getCacheManager()
129
    {
130
        if (null === $this->cacheManager) {
131
            /** @var CacheManager $cacheManager */
132
            $this->cacheManager = GeneralUtility::makeInstance(CacheManager::class);
133
        }
134
135
        return $this->cacheManager;
136
    }
137
}
138