Completed
Push — feature/version-2 ( 2f0885...a1aace )
by Romain
02:05
created

ConfigurationFactory::injectSignalSlotDispatcher()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
/*
3
 * 2017 Romain CANON <[email protected]>
4
 *
5
 * This file is part of the TYPO3 FormZ 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\Formz\Configuration;
15
16
use Romm\ConfigurationObject\ConfigurationObjectFactory;
17
use Romm\ConfigurationObject\ConfigurationObjectInstance;
18
use Romm\Formz\Service\CacheService;
19
use Romm\Formz\Service\ContextService;
20
use Romm\Formz\Service\HashService;
21
use Romm\Formz\Service\Traits\ExtendedSelfInstantiateTrait;
22
use Romm\Formz\Service\TypoScriptService;
23
use TYPO3\CMS\Core\SingletonInterface;
24
use TYPO3\CMS\Extbase\SignalSlot\Dispatcher;
25
26
/**
27
 * This class is used to build and manage the whole FormZ configuration: from a
28
 * plain configuration array, it builds an entire tree object which will give
29
 * all the features from the `configuration_object` extension (parent
30
 * inheritance, array keys save, etc.).
31
 */
32
class ConfigurationFactory implements SingletonInterface
33
{
34
    use ExtendedSelfInstantiateTrait;
35
36
    const POST_CONFIGURATION_PROCESS_SIGNAL = 'postConfigurationProcess';
37
38
    /**
39
     * @var TypoScriptService
40
     */
41
    protected $typoScriptService;
42
43
    /**
44
     * @var Dispatcher
45
     */
46
    protected $signalSlotDispatcher;
47
48
    /**
49
     * @var ConfigurationObjectInstance[]
50
     */
51
    protected $instances = [];
52
53
    /**
54
     * @var array
55
     */
56
    protected $cacheIdentifiers = [];
57
58
    /**
59
     * Returns the global FormZ configuration.
60
     *
61
     * Two cache layers are used:
62
     *
63
     * - A local cache which will avoid fetching the configuration every time
64
     *   the current script needs it.
65
     * - A system cache, which will store the configuration instance when it has
66
     *   been built, improving performance for next scripts.
67
     *
68
     * @return ConfigurationObjectInstance
69
     */
70
    public function getFormzConfiguration()
71
    {
72
        $cacheIdentifier = $this->getCacheIdentifier();
73
74
        if (false === array_key_exists($cacheIdentifier, $this->instances)) {
75
            $this->instances[$cacheIdentifier] = $this->getFormzConfigurationFromCache($cacheIdentifier);
76
        }
77
78
        return $this->instances[$cacheIdentifier];
79
    }
80
81
    /**
82
     * Will fetch the configuration from cache, and build it if not found. It
83
     * wont be stored in cache if any error is found. This is done this way to
84
     * avoid the integrator to be forced to flush caches when errors are found.
85
     *
86
     * @param string $cacheIdentifier
87
     * @return ConfigurationObjectInstance
88
     */
89
    protected function getFormzConfigurationFromCache($cacheIdentifier)
90
    {
91
        $cacheInstance = CacheService::get()->getCacheInstance();
92
93
        if ($cacheInstance->has($cacheIdentifier)) {
94
            $instance = $cacheInstance->get($cacheIdentifier);
95
        } else {
96
            $instance = $this->buildFormzConfiguration();
97
98
            if (false === $instance->getValidationResult()->hasErrors()) {
99
                $cacheInstance->set($cacheIdentifier, $instance);
100
            }
101
        }
102
103
        return $instance;
104
    }
105
106
    /**
107
     * @see getFormzConfiguration()
108
     *
109
     * @return ConfigurationObjectInstance
110
     */
111
    protected function buildFormzConfiguration()
112
    {
113
        $configuration = $this->typoScriptService->getFormzConfiguration();
114
        $instance = ConfigurationObjectFactory::getInstance()
115
            ->get(Configuration::class, $configuration);
116
117
        /** @var Configuration $instanceObject */
118
        $instanceObject = $instance->getObject(true);
119
120
        $this->callPostConfigurationProcessSignal($instanceObject);
121
122
        $instanceObject->calculateHash();
123
124
        return $instance;
125
    }
126
127
    /**
128
     * If you need to modify the configuration object after it has been built
129
     * using the TypoScript configuration, you can connect a slot on the signal
130
     * below.
131
     *
132
     * Note that the signal will be dispatched only once, as the configuration
133
     * object is latter put in cache. Therefore, your slots will be called only
134
     * once too and need to be aware of it.
135
     *
136
     * Example (`ext_localconf.php`):
137
     *
138
     * $signalSlotDispatcher = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
139
     *     \TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class
140
     * );
141
     * $signalSlotDispatcher->connect(
142
     *     \Romm\Formz\Configuration\ConfigurationFactory::class,
143
     *     \Romm\Formz\Configuration\ConfigurationFactory::POST_CONFIGURATION_PROCESS_SIGNAL,
144
     *     function (\Romm\Formz\Configuration\Configuration $configuration) {
145
     *         $configuration->getView()->setPartialRootPath(
146
     *             50,
147
     *             'EXT:my_extension/Resources/Private/Partials/FormZ/'
148
     *         );
149
     *     }
150
     * );
151
     *
152
     * @param Configuration $configuration
153
     */
154
    protected function callPostConfigurationProcessSignal(Configuration $configuration)
155
    {
156
        $this->signalSlotDispatcher->dispatch(
157
            __CLASS__,
158
            self::POST_CONFIGURATION_PROCESS_SIGNAL,
159
            [$configuration]
160
        );
161
    }
162
163
    /**
164
     * @return string
165
     */
166
    protected function getCacheIdentifier()
167
    {
168
        $contextHash = ContextService::get()->getContextHash();
169
170
        if (false === array_key_exists($contextHash, $this->cacheIdentifiers)) {
171
            $configuration = $this->typoScriptService->getFormzConfiguration();
172
173
            $this->cacheIdentifiers[$contextHash] = 'formz-configuration-' . HashService::get()->getHash(serialize($configuration));
174
        }
175
176
        return $this->cacheIdentifiers[$contextHash];
177
    }
178
179
    /**
180
     * @param TypoScriptService $typoScriptService
181
     */
182
    public function injectTypoScriptService(TypoScriptService $typoScriptService)
183
    {
184
        $this->typoScriptService = $typoScriptService;
185
    }
186
187
    /**
188
     * @param Dispatcher $signalSlotDispatcher
189
     */
190
    public function injectSignalSlotDispatcher(Dispatcher $signalSlotDispatcher)
191
    {
192
        $this->signalSlotDispatcher = $signalSlotDispatcher;
193
    }
194
}
195