Completed
Push — development ( 83de77...1b606a )
by Romain
01:41
created

ConfigurationObjectFactory::convertToObject()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 26
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 26
rs 8.8571
c 0
b 0
f 0
cc 2
eloc 15
nc 2
nop 2
1
<?php
2
/*
3
 * 2017 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;
15
16
use Romm\ConfigurationObject\Core\Core;
17
use Romm\ConfigurationObject\Exceptions\ClassNotFoundException;
18
use Romm\ConfigurationObject\Exceptions\EntryNotFoundException;
19
use Romm\ConfigurationObject\Exceptions\WrongInheritanceException;
20
use Romm\ConfigurationObject\Service\DataTransferObject\GetConfigurationObjectDTO;
21
use Romm\ConfigurationObject\Service\Event\ConfigurationObjectAfterServiceEventInterface;
22
use Romm\ConfigurationObject\Service\Event\ConfigurationObjectBeforeServiceEventInterface;
23
use Romm\ConfigurationObject\Service\Event\ConfigurationObjectBeforeValidationServiceEventInterface;
24
use Romm\ConfigurationObject\Service\ServiceFactory;
25
use Romm\ConfigurationObject\Service\WrongServiceException;
26
use TYPO3\CMS\Core\SingletonInterface;
27
use TYPO3\CMS\Core\Utility\GeneralUtility;
28
29
/**
30
 * This class provides function to get a configuration object from a data array.
31
 *
32
 * Use as follow:
33
 *
34
 *  $confObject = \Romm\ConfigurationObject\ConfigurationObjectFactory::convert(
35
 *      \MyVendor\MyExtension\Configuration\MyConfiguration::class,
36
 *      $myConfigurationArray
37
 *  );
38
 *
39
 *  if (false === $confObject->getResult()->hasErrors()) {
40
 *      $confObject = $confObject->getObject();
41
 *  } else {
42
 *      $errors = $confObject->getResult()->getFlattenedErrors();
43
 *      // Whatever you want...
44
 *  }
45
 */
46
class ConfigurationObjectFactory implements SingletonInterface
47
{
48
49
    /**
50
     * @var ConfigurationObjectFactory
51
     */
52
    protected static $instance;
53
54
    /**
55
     * @var ServiceFactory[]
56
     */
57
    protected $configurationObjectServiceFactory = [];
58
59
    /**
60
     * @var int
61
     */
62
    protected $runningProcesses = 0;
63
64
    /**
65
     * Alias for:
66
     *
67
     * \Romm\ConfigurationObject\ConfigurationObjectFactory::getInstance()->get(...)
68
     *
69
     * @param string $className
70
     * @param array  $objectData
71
     * @return ConfigurationObjectInstance
72
     */
73
    public static function convert($className, array $objectData)
74
    {
75
        return self::getInstance()->get($className, $objectData);
76
    }
77
78
    /**
79
     * @return ConfigurationObjectFactory
80
     */
81
    public static function getInstance()
82
    {
83
        if (null === self::$instance) {
84
            self::$instance = GeneralUtility::makeInstance(self::class);
85
        }
86
87
        return self::$instance;
88
    }
89
90
    /**
91
     * Returns an instance of the given configuration object name. The object is
92
     * recursively filled with the given array data.
93
     *
94
     * @param    string $className  Name of the configuration object class. The class must implement `\Romm\ConfigurationObject\ConfigurationObjectInterface`.
95
     * @param    array  $objectData Data used to fill the object.
96
     * @return ConfigurationObjectInstance
97
     * @throws \Exception
98
     */
99
    public function get($className, array $objectData)
100
    {
101
        $this->runningProcesses++;
102
103
        try {
104
            $result = $this->convertToObject($className, $objectData);
105
106
            $this->runningProcesses--;
107
108
            return $result;
109
        } catch (\Exception $exception) {
110
            $this->runningProcesses--;
111
112
            throw $exception;
113
        }
114
    }
115
116
    /**
117
     * @return bool
118
     */
119
    public function isRunning()
120
    {
121
        return $this->runningProcesses > 0;
122
    }
123
124
    /**
125
     * @param string $className
126
     * @param array  $objectData
127
     * @return ConfigurationObjectInstance
128
     */
129
    protected function convertToObject($className, array $objectData)
130
    {
131
        $serviceFactory = $this->register($className);
132
133
        $dto = new GetConfigurationObjectDTO($className, $serviceFactory);
134
        $dto->setConfigurationObjectData($objectData);
135
        $serviceFactory->runServicesFromEvent(ConfigurationObjectBeforeServiceEventInterface::class, 'configurationObjectBefore', $dto);
136
137
        if (false === $dto->getResult() instanceof ConfigurationObjectInstance) {
138
            $mapper = $this->getConfigurationObjectMapper();
139
            $object = $mapper->convert($dto->getConfigurationObjectData(), $className);
140
141
            /** @var ConfigurationObjectInstance $result */
142
            $result = GeneralUtility::makeInstance(ConfigurationObjectInstance::class, $object, $mapper->getMessages());
143
144
            $dto->setResult($result);
145
        }
146
147
        $serviceFactory->runServicesFromEvent(ConfigurationObjectAfterServiceEventInterface::class, 'configurationObjectAfter', $dto);
148
        $serviceFactory->runServicesFromEvent(ConfigurationObjectBeforeValidationServiceEventInterface::class, 'configurationObjectBeforeValidation', $dto);
149
150
        $result = $dto->getResult();
151
        unset($dto);
152
153
        return $result;
154
    }
155
156
    /**
157
     * Any configuration object needs to be registered before it can be used.
158
     *
159
     * @param  string $className Class name of the wanted configuration object.
160
     * @return ServiceFactory
161
     * @throws ClassNotFoundException
162
     * @throws WrongInheritanceException
163
     * @throws WrongServiceException
164
     */
165
    protected function register($className)
166
    {
167
        if (false === isset($this->configurationObjectServiceFactory[$className])) {
168
            if (false === Core::get()->classExists($className)) {
169
                throw new ClassNotFoundException(
170
                    'Trying to get a non-existing configuration object: "' . $className . '".',
171
                    1448886437
172
                );
173
            }
174
175
            if (false === in_array(ConfigurationObjectInterface::class, class_implements($className))) {
176
                throw new WrongInheritanceException(
177
                    'The configuration object class: "' . $className . '" must implement "' . ConfigurationObjectInterface::class . '".',
178
                    1448886449
179
                );
180
            }
181
182
            /** @var ConfigurationObjectInterface $configurationObjectClassName */
183
            $configurationObjectClassName = $className;
184
            $serviceFactory = $configurationObjectClassName::getConfigurationObjectServices();
185
            if (false === $serviceFactory instanceof ServiceFactory) {
186
                throw new WrongServiceException(
187
                    'Service factory for configuration object class: "' . $className . '" must be an instance of "' . ServiceFactory::class . '".',
188
                    1448886479
189
                );
190
            }
191
192
            /** @var ServiceFactory $serviceFactory */
193
            $serviceFactory->initialize();
194
195
            $this->configurationObjectServiceFactory[$className] = $serviceFactory;
196
        }
197
198
        return $this->configurationObjectServiceFactory[$className];
199
    }
200
201
    /**
202
     * @return ConfigurationObjectMapper
203
     */
204
    protected function getConfigurationObjectMapper()
205
    {
206
        return Core::get()->getObjectManager()->get(ConfigurationObjectMapper::class);
207
    }
208
209
    /**
210
     * @param  string $className Name of the configuration object class.
211
     * @return ServiceFactory
212
     * @throws EntryNotFoundException
213
     * @internal
214
     */
215
    public function getConfigurationObjectServiceFactory($className)
216
    {
217
        if (true === isset($this->configurationObjectServiceFactory[$className])) {
218
            return $this->configurationObjectServiceFactory[$className];
219
        }
220
221
        throw new EntryNotFoundException(
222
            'Trying to access to an instance of "ConfigurationObjectServiceFactory" which is not registered for the class "' . $className . '".',
223
            1471278490
224
        );
225
    }
226
}
227