TYPO3CMS  8
 All Classes Namespaces Files Functions Variables Pages
NodeFactory.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Backend\Form;
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
18 
23 {
29  protected $nodeTypes = [
30  'flex' => Container\FlexFormEntryContainer::class,
31  'flexFormContainerContainer' => Container\FlexFormContainerContainer::class,
32  'flexFormElementContainer' => Container\FlexFormElementContainer::class,
33  'flexFormNoTabsContainer' => Container\FlexFormNoTabsContainer::class,
34  'flexFormSectionContainer' => Container\FlexFormSectionContainer::class,
35  'flexFormTabsContainer' => Container\FlexFormTabsContainer::class,
36  'fullRecordContainer' => Container\FullRecordContainer::class,
37  'inline' => Container\InlineControlContainer::class,
38  'inlineRecordContainer' => Container\InlineRecordContainer::class,
39  'listOfFieldsContainer' => Container\ListOfFieldsContainer::class,
40  'noTabsContainer' => Container\NoTabsContainer::class,
41  'outerWrapContainer' => Container\OuterWrapContainer::class,
42  'paletteAndSingleContainer' => Container\PaletteAndSingleContainer::class,
43  'singleFieldContainer' => Container\SingleFieldContainer::class,
44  'soloFieldContainer' => Container\SoloFieldContainer::class,
45  'tabsContainer' => Container\TabsContainer::class,
46 
47  'check' => Element\CheckboxElement::class,
48  'group' => Element\GroupElement::class,
49  'input' => Element\InputTextElement::class,
50  'hidden' => Element\InputHiddenElement::class,
51  // rsaInput is defined with a fallback so extensions can use it even if ext:rsaauth is not loaded
52  'rsaInput' => Element\InputTextElement::class,
53  'imageManipulation' => Element\ImageManipulationElement::class,
54  'none' => Element\NoneElement::class,
55  'radio' => Element\RadioElement::class,
56  'selectCheckBox' => Element\SelectCheckBoxElement::class,
57  'selectMultipleSideBySide' => Element\SelectMultipleSideBySideElement::class,
58  'selectTree' => Element\SelectTreeElement::class,
59  'selectSingle' => Element\SelectSingleElement::class,
60  'selectSingleBox' => Element\SelectSingleBoxElement::class,
61  'colorpicker' => Element\InputColorPickerElement::class,
62  // t3editor is defined with a fallback so extensions can use it even if ext:t3editor is not loaded
63  't3editor' => Element\TextElement::class,
64  'text' => Element\TextElement::class,
65  'unknown' => Element\UnknownElement::class,
66  'user' => Element\UserElement::class,
67  ];
68 
75  protected $nodeResolver = [];
76 
80  public function __construct()
81  {
83  $this->initializeNodeResolver();
84  }
85 
93  public function create(array $data)
94  {
95  if (empty($data['renderType'])) {
96  throw new Exception(
97  'Missing "renderType" in TCA of field "[' . $data['tableName'] . '][' . $data['fieldName'] . ']".',
98  1431452406
99  );
100  }
101  $type = $data['renderType'];
102 
103  $className = isset($this->nodeTypes[$type]) ? $this->nodeTypes[$type] : $this->nodeTypes['unknown'];
104 
105  if (!empty($this->nodeResolver[$type])) {
106  // Resolver with highest priority is called first. If it returns with a new class name,
107  // it will be taken and loop is aborted, otherwise resolver with next lower priority is called.
108  foreach ($this->nodeResolver[$type] as $priority => $resolverClassName) {
110  $resolver = $this->instantiate($resolverClassName, $data);
111  if (!$resolver instanceof NodeResolverInterface) {
112  throw new Exception(
113  'Node resolver for type ' . $type . ' at priority ' . $priority . ' must implement NodeResolverInterface',
114  1433157422
115  );
116  }
117  // Resolver classes do NOT receive the name of the already resolved class. Single
118  // resolvers should not have dependencies to each other or the default implementation,
119  // so they also shouldn't know the output of a different resolving class.
120  // Additionally, the globalOptions array is NOT given by reference here, changing config is a
121  // task of container classes alone and must not be abused here.
122  $newClassName = $resolver->resolve();
123  if ($newClassName !== null) {
124  $className = $newClassName;
125  break;
126  }
127  }
128  }
129 
131  $nodeInstance = $this->instantiate($className, $data);
132  if (!$nodeInstance instanceof NodeInterface) {
133  throw new Exception('Node of type ' . get_class($nodeInstance) . ' must implement NodeInterface', 1431872546);
134  }
135  return $nodeInstance;
136  }
137 
146  {
147  // List of additional or override nodes
148  $registeredTypeOverrides = $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'];
149  // Sanitize input array
150  $registeredPrioritiesForNodeNames = [];
151  foreach ($registeredTypeOverrides as $override) {
152  if (!isset($override['nodeName']) || !isset($override['class']) || !isset($override['priority'])) {
153  throw new Exception(
154  'Key class, nodeName or priority missing for an entry in $GLOBALS[\'TYPO3_CONF_VARS\'][\'SYS\'][\'formEngine\'][\'nodeRegistry\']',
155  1432207533
156  );
157  }
158  if ($override['priority'] < 0 || $override['priority'] > 100) {
159  throw new Exception(
160  'Priority of element ' . $override['nodeName'] . ' with class ' . $override['class'] . ' is ' . $override['priority'] . ', but must between 0 and 100',
161  1432223531
162  );
163  }
164  if (isset($registeredPrioritiesForNodeNames[$override['nodeName']][$override['priority']])) {
165  throw new Exception(
166  'Element ' . $override['nodeName'] . ' already has an override registered with priority ' . $override['priority'],
167  1432223893
168  );
169  }
170  $registeredPrioritiesForNodeNames[$override['nodeName']][$override['priority']] = '';
171  }
172  // Add element with highest priority to registry
173  $highestPriority = [];
174  foreach ($registeredTypeOverrides as $override) {
175  if (!isset($highestPriority[$override['nodeName']]) || $override['priority'] > $highestPriority[$override['nodeName']]) {
176  $highestPriority[$override['nodeName']] = $override['priority'];
177  $this->nodeTypes[$override['nodeName']] = $override['class'];
178  }
179  }
180  }
181 
188  protected function initializeNodeResolver()
189  {
190  // List of node resolver
191  $registeredNodeResolvers = $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeResolver'];
192  $resolversByType = [];
193  foreach ($registeredNodeResolvers as $nodeResolver) {
194  if (!isset($nodeResolver['nodeName']) || !isset($nodeResolver['class']) || !isset($nodeResolver['priority'])) {
195  throw new Exception(
196  'Key class, nodeName or priority missing for an entry in $GLOBALS[\'TYPO3_CONF_VARS\'][\'SYS\'][\'formEngine\'][\'nodeResolver\']',
197  1433155522
198  );
199  }
200  if ($nodeResolver['priority'] < 0 || $nodeResolver['priority'] > 100) {
201  throw new Exception(
202  'Priority of element ' . $nodeResolver['nodeName'] . ' with class ' . $nodeResolver['class'] . ' is ' . $nodeResolver['priority'] . ', but must between 0 and 100',
203  1433155563
204  );
205  }
206  if (isset($resolversByType[$nodeResolver['nodeName']][$nodeResolver['priority']])) {
207  throw new Exception(
208  'Element ' . $nodeResolver['nodeName'] . ' already has a resolver registered with priority ' . $nodeResolver['priority'],
209  1433155705
210  );
211  }
212  $resolversByType[$nodeResolver['nodeName']][$nodeResolver['priority']] = $nodeResolver['class'];
213  }
214  $sortedResolversByType = [];
215  foreach ($resolversByType as $nodeName => $prioritiesAndClasses) {
216  krsort($prioritiesAndClasses);
217  $sortedResolversByType[$nodeName] = $prioritiesAndClasses;
218  }
219  $this->nodeResolver = $sortedResolversByType;
220  }
221 
229  protected function instantiate($className, array $data)
230  {
231  return GeneralUtility::makeInstance($className, $this, $data);
232  }
233 }
instantiate($className, array $data)
if(TYPO3_MODE=== 'BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
static makeInstance($className,...$constructorArguments)