Completed
Push — unit-tests-validation ( c31383...82d287 )
by Romain
17:06
created

FormObjectFactory::getInstanceFromFormInstance()   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 2
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;
15
16
use Romm\Formz\Configuration\Configuration;
17
use Romm\Formz\Configuration\ConfigurationFactory;
18
use Romm\Formz\Core\Core;
19
use Romm\Formz\Exceptions\ClassNotFoundException;
20
use Romm\Formz\Service\CacheService;
21
use Romm\Formz\Service\TypoScriptService;
22
use TYPO3\CMS\Core\SingletonInterface;
23
use TYPO3\CMS\Core\Utility\GeneralUtility;
24
use TYPO3\CMS\Extbase\Reflection\ReflectionService;
25
26
/**
27
 * Factory class which will manage instances of `FormObject`.
28
 */
29
class FormObjectFactory implements SingletonInterface
30
{
31
    const IGNORE_PROPERTY = 'formz-ignore';
32
33
    /**
34
     * @var ConfigurationFactory
35
     */
36
    protected $configurationFactory;
37
38
    /**
39
     * @var TypoScriptService
40
     */
41
    protected $typoScriptService;
42
43
    /**
44
     * @var FormObject[]
45
     */
46
    protected $instances = [];
47
48
    /**
49
     * @var array
50
     */
51
    private static $ignoredProperties = ['validationData', 'uid', 'pid', '_localizedUid', '_languageUid', '_versionedUid'];
52
53
    /**
54
     * Will create an instance of `FormObject` based on a class which implements
55
     * the interface `FormInterface`.
56
     *
57
     * @param string $className
58
     * @param string $name
59
     * @return FormObject
60
     * @throws \Exception
61
     */
62
    public function getInstanceFromClassName($className, $name)
63
    {
64
        if (false === class_exists($className)
65
            || false === in_array(FormInterface::class, class_implements($className))
66
        ) {
67
            throw new ClassNotFoundException(
68
                'Invalid class name given: "' . $className . '"; the class must be an instance of "' . FormInterface::class . '".',
69
                1467191011
70
            );
71
        }
72
73
        $cacheIdentifier = CacheService::get()->getCacheIdentifier('form-object-', $className . '-' . $name);
74
75
        if (false === isset($this->instances[$cacheIdentifier])) {
76
            $cacheInstance = CacheService::get()->getCacheInstance();
77
78
            if ($cacheInstance->has($cacheIdentifier)) {
79
                $instance = $cacheInstance->get($cacheIdentifier);
80
            } else {
81
                $instance = $this->createInstance($className, $name);
82
                $cacheInstance->set($cacheIdentifier, $instance);
83
            }
84
85
            /** @var Configuration $formzConfigurationObject */
86
            $formzConfigurationObject = $this->configurationFactory
87
                ->getFormzConfiguration()
88
                ->getObject(true);
89
90
            if (false === $formzConfigurationObject->hasForm($instance->getClassName(), $instance->getName())) {
91
                $formzConfigurationObject->addForm($instance);
92
            }
93
94
            $this->instances[$cacheIdentifier] = $instance;
95
        }
96
97
        return $this->instances[$cacheIdentifier];
98
    }
99
100
    /**
101
     * @param FormInterface $form
102
     * @param string        $name
103
     * @return FormObject
104
     */
105
    public function getInstanceFromFormInstance(FormInterface $form, $name)
106
    {
107
        return $this->getInstanceFromClassName(get_class($form), $name);
108
    }
109
110
    /**
111
     * Creates and initializes a new `FormObject` instance.
112
     *
113
     * @param string $className
114
     * @param string $name
115
     * @return FormObject
116
     */
117
    protected function createInstance($className, $name)
118
    {
119
        /** @var FormObject $instance */
120
        $instance = Core::instantiate(FormObject::class, $className, $name);
121
122
        $this->insertObjectProperties($instance);
123
124
        $formConfiguration = $this->typoScriptService->getFormConfiguration($className);
125
        $instance->setConfigurationArray($formConfiguration);
126
127
        $instance->getHash();
128
129
        return $instance;
130
    }
131
132
    /**
133
     * Will insert all the accessible properties of the given instance.
134
     *
135
     * @param FormObject $instance
136
     */
137
    protected function insertObjectProperties(FormObject $instance)
138
    {
139
        $className = $instance->getClassName();
140
141
        /** @var ReflectionService $reflectionService */
142
        $reflectionService = GeneralUtility::makeInstance(ReflectionService::class);
143
        $reflectionProperties = $reflectionService->getClassPropertyNames($className);
144
145
        $classReflection = new \ReflectionClass($className);
146
        $publicProperties = $classReflection->getProperties(\ReflectionProperty::IS_PUBLIC);
147
148
        foreach ($reflectionProperties as $property) {
149
            if (false === in_array($property, self::$ignoredProperties)
150
                && false === $reflectionService->isPropertyTaggedWith($className, $property, self::IGNORE_PROPERTY)
151
                && ((true === in_array($property, $publicProperties))
152
                    || $reflectionService->hasMethod($className, 'get' . ucfirst($property))
153
                )
154
            ) {
155
                $instance->addProperty($property);
156
            }
157
        }
158
159
        unset($publicProperties);
160
    }
161
162
    /**
163
     * @param ConfigurationFactory $configurationFactory
164
     */
165
    public function injectConfigurationFactory(ConfigurationFactory $configurationFactory)
166
    {
167
        $this->configurationFactory = $configurationFactory;
168
    }
169
170
    /**
171
     * @param TypoScriptService $typoScriptService
172
     */
173
    public function injectTypoScriptService(TypoScriptService $typoScriptService)
174
    {
175
        $this->typoScriptService = $typoScriptService;
176
    }
177
}
178