Completed
Push — wip/steps ( 551eb2...b236f9 )
by Romain
03:12
created

FormObjectFactory::getStepService()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

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