Completed
Push — feature/improve-form-definitio... ( 0cba0f...350a13 )
by Romain
02:18
created

FormObjectFactory::getGlobalConfiguration()   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 0
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\Form\FormObject;
15
16
use Romm\ConfigurationObject\ConfigurationObjectInterface;
17
use Romm\Formz\Configuration\Configuration;
18
use Romm\Formz\Configuration\ConfigurationFactory;
19
use Romm\Formz\Core\Core;
20
use Romm\Formz\Exceptions\ClassNotFoundException;
21
use Romm\Formz\Exceptions\DuplicateEntryException;
22
use Romm\Formz\Exceptions\EntryNotFoundException;
23
use Romm\Formz\Exceptions\InvalidArgumentTypeException;
24
use Romm\Formz\Exceptions\InvalidArgumentValueException;
25
use Romm\Formz\Form\FormInterface;
26
use Romm\Formz\Form\FormObject\Builder\DefaultFormObjectBuilder;
27
use Romm\Formz\Form\FormObject\Builder\FormObjectBuilderInterface;
28
use Romm\Formz\Service\CacheService;
29
use Romm\Formz\Service\StringService;
30
use Romm\Formz\Service\Traits\ExtendedSelfInstantiateTrait;
31
use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
32
use TYPO3\CMS\Core\SingletonInterface;
33
34
/**
35
 * Factory class that will manage form object instances.
36
 *
37
 * You can fetch a new instance by calling one of the following methods:
38
 * `getInstanceFromFormInstance()` or `getInstanceFromClassName()`
39
 *
40
 * @see \Romm\Formz\Form\FormObject\FormObject
41
 */
42
class FormObjectFactory implements SingletonInterface
43
{
44
    use ExtendedSelfInstantiateTrait;
45
46
    /**
47
     * @var FormObject[]
48
     */
49
    protected $instances = [];
50
51
    /**
52
     * @var FormObjectStatic[]
53
     */
54
    protected $static = [];
55
56
    /**
57
     * @var FormObjectProxy[]
58
     */
59
    protected $proxy = [];
60
61
    /**
62
     * Returns the form object for the given form instance. The form instance
63
     * must have been defined first in this factory, or an exception is thrown.
64
     *
65
     * @param FormInterface $form
66
     * @return FormObject
67
     * @throws EntryNotFoundException
68
     */
69
    public function getInstanceWithFormInstance(FormInterface $form)
70
    {
71
        if (false === $this->formInstanceWasRegistered($form)) {
72
            throw EntryNotFoundException::formObjectInstanceNotFound($form);
73
        }
74
75
        return $this->instances[spl_object_hash($form)];
76
    }
77
78
    /**
79
     * Checks that the given form instance was registered in this factory.
80
     *
81
     * @param FormInterface $form
82
     * @return bool
83
     */
84
    public function formInstanceWasRegistered(FormInterface $form)
85
    {
86
        return isset($this->instances[spl_object_hash($form)]);
87
    }
88
89
    /**
90
     * Registers a new form instance.
91
     *
92
     * @param FormInterface $form
93
     * @param string        $name
94
     * @throws DuplicateEntryException
95
     * @throws InvalidArgumentValueException
96
     */
97
    public function registerFormInstance(FormInterface $form, $name)
98
    {
99
        if (empty($name)) {
100
            throw InvalidArgumentValueException::formNameEmpty($form);
101
        }
102
103
        if ($this->formInstanceWasRegistered($form)) {
104
            throw DuplicateEntryException::formObjectInstanceAlreadyRegistered($form, $name);
105
        }
106
107
        $hash = spl_object_hash($form);
108
        $this->instances[$hash] = $this->getInstanceWithClassName(get_class($form), $name);
109
        $this->instances[$hash]->setForm($form);
110
    }
111
112
    /**
113
     * A shortcut function to register the given form instance (if it was not
114
     * already registered) and return the form object.
115
     *
116
     * @param FormInterface $form
117
     * @param string        $name
118
     * @return FormObject
119
     */
120
    public function registerAndGetFormInstance(FormInterface $form, $name)
121
    {
122
        if (false === $this->formInstanceWasRegistered($form)) {
123
            $this->registerFormInstance($form, $name);
124
        }
125
126
        return $this->getInstanceWithFormInstance($form);
127
    }
128
129
    /**
130
     * Will create an instance of `FormObject` based on a class that implements
131
     * the interface `FormInterface`.
132
     *
133
     * @param string $className
134
     * @param string $name
135
     * @return FormObject
136
     */
137
    public function getInstanceWithClassName($className, $name)
138
    {
139
        /** @var FormObject $formObject */
140
        $formObject = Core::instantiate(FormObject::class, $name, $this->getStaticInstance($className));
141
142
        return $formObject;
143
    }
144
145
    /**
146
     * Returns the proxy object for the given form object and form instance.
147
     *
148
     * Please use with caution, as this is a very low level function!
149
     *
150
     * @param FormInterface $form
151
     * @return FormObjectProxy
152
     */
153
    public function getProxy(FormInterface $form)
154
    {
155
        $hash = spl_object_hash($form);
156
157
        if (false === isset($this->proxy[$hash])) {
158
            $this->proxy[$hash] = $this->getNewProxyInstance($form);
159
        }
160
161
        return $this->proxy[$hash];
162
    }
163
164
    /**
165
     * @param string $className
166
     * @return FormObjectStatic
167
     * @throws ClassNotFoundException
168
     * @throws InvalidArgumentTypeException
169
     */
170
    protected function getStaticInstance($className)
171
    {
172
        if (false === class_exists($className)) {
173
            throw ClassNotFoundException::wrongFormClassName($className);
174
        }
175
176
        if (false === in_array(FormInterface::class, class_implements($className))) {
177
            throw InvalidArgumentTypeException::wrongFormType($className);
178
        }
179
180
        $cacheIdentifier = $this->getCacheIdentifier($className);
181
182
        if (false === isset($this->static[$cacheIdentifier])) {
183
            $cacheInstance = $this->getCacheInstance();
184
185
            if ($cacheInstance->has($cacheIdentifier)) {
186
                $static = $cacheInstance->get($cacheIdentifier);
187
            } else {
188
                $static = $this->buildStaticInstance($className);
189
                $static->getObjectHash();
190
191
                if (false === $static->getDefinitionValidationResult()->hasErrors()) {
192
                    $cacheInstance->set($cacheIdentifier, $static);
193
                }
194
            }
195
196
            $static->getDefinition()->attachParent($this->getRootConfiguration());
197
198
            $this->static[$cacheIdentifier] = $static;
199
        }
200
201
        return $this->static[$cacheIdentifier];
202
    }
203
204
    /**
205
     * @param string $className
206
     * @return string
207
     */
208
    protected function getCacheIdentifier($className)
209
    {
210
        $sanitizedClassName = StringService::get()->sanitizeString(str_replace('\\', '-', $className));
211
212
        return 'form-object-' . $sanitizedClassName;
213
    }
214
215
    /**
216
     * Wrapper for unit tests.
217
     *
218
     * @param string $className
219
     * @return FormObjectStatic
220
     */
221
    protected function buildStaticInstance($className)
222
    {
223
        /** @var FormObjectBuilderInterface $builder */
224
        $builder = Core::instantiate(DefaultFormObjectBuilder::class);
225
226
        return $builder->getStaticInstance($className);
227
    }
228
229
    /**
230
     * Wrapper for unit tests.
231
     *
232
     * @param FormInterface $form
233
     * @return FormObjectProxy
234
     */
235
    protected function getNewProxyInstance(FormInterface $form)
236
    {
237
        $formObject = $this->getInstanceWithFormInstance($form);
238
239
        /** @var FormObjectProxy $formObjectProxy */
240
        $formObjectProxy = Core::instantiate(FormObjectProxy::class, $formObject, $form);
241
242
        return $formObjectProxy;
243
    }
244
245
    /**
246
     * @return Configuration|ConfigurationObjectInterface
247
     */
248
    protected function getRootConfiguration()
249
    {
250
        return ConfigurationFactory::get()->getRootConfiguration()->getObject(true);
251
    }
252
253
    /**
254
     * @return FrontendInterface
255
     */
256
    protected function getCacheInstance()
257
    {
258
        return CacheService::get()->getCacheInstance();
259
    }
260
}
261