‪TYPO3CMS  ‪main
NodeFactory.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the TYPO3 CMS project.
5  *
6  * It is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License, either version 2
8  * of the License, or any later version.
9  *
10  * For the full copyright and license information, please read the
11  * LICENSE.txt file that was distributed with this source code.
12  *
13  * The TYPO3 project - inspiring people to share!
14  */
15 
17 
20 
40 {
45  private array ‪$nodeResolver = [];
46 
50  private array ‪$nodeTypes = [
51  // Default container classes
52  'flex' => Container\FlexFormEntryContainer::class,
53  'flexFormContainerContainer' => Container\FlexFormContainerContainer::class,
54  'flexFormElementContainer' => Container\FlexFormElementContainer::class,
55  'flexFormNoTabsContainer' => Container\FlexFormNoTabsContainer::class,
56  'flexFormSectionContainer' => Container\FlexFormSectionContainer::class,
57  'flexFormTabsContainer' => Container\FlexFormTabsContainer::class,
58  'fullRecordContainer' => Container\FullRecordContainer::class,
59  'inline' => Container\InlineControlContainer::class,
60  'inlineRecordContainer' => Container\InlineRecordContainer::class,
61  ‪FilesControlContainer::NODE_TYPE_IDENTIFIER => Container\FilesControlContainer::class,
62  ‪Container\FileReferenceContainer::NODE_TYPE_IDENTIFIER => Container\FileReferenceContainer::class,
63  'siteLanguage' => Container\SiteLanguageContainer::class,
64  'listOfFieldsContainer' => Container\ListOfFieldsContainer::class,
65  'noTabsContainer' => Container\NoTabsContainer::class,
66  'outerWrapContainer' => Container\OuterWrapContainer::class,
67  'paletteAndSingleContainer' => Container\PaletteAndSingleContainer::class,
68  'singleFieldContainer' => Container\SingleFieldContainer::class,
69  'tabsContainer' => Container\TabsContainer::class,
70 
71  // Default single element classes
72  'check' => Element\CheckboxElement::class,
73  'checkboxToggle' => Element\CheckboxToggleElement::class,
74  'checkboxLabeledToggle' => Element\CheckboxLabeledToggleElement::class,
75  'email' => Element\EmailElement::class,
76  'group' => Element\GroupElement::class,
77  'folder' => Element\FolderElement::class,
78  'input' => Element\InputTextElement::class,
79  'number' => Element\NumberElement::class,
80  'datetime' => Element\DatetimeElement::class,
81  'link' => Element\LinkElement::class,
82  'password' => Element\PasswordElement::class,
83  'hidden' => Element\InputHiddenElement::class,
84  'imageManipulation' => Element\ImageManipulationElement::class,
85  'none' => Element\NoneElement::class,
86  'radio' => Element\RadioElement::class,
87  'selectCheckBox' => Element\SelectCheckBoxElement::class,
88  'selectMultipleSideBySide' => Element\SelectMultipleSideBySideElement::class,
89  'selectTree' => Element\SelectTreeElement::class,
90  'selectSingle' => Element\SelectSingleElement::class,
91  'selectSingleBox' => Element\SelectSingleBoxElement::class,
92  'color' => Element\ColorElement::class,
93  'codeEditor' => Element\CodeEditorElement::class,
94  'text' => Element\TextElement::class,
95  'textTable' => Element\TextTableElement::class,
96  'unknown' => Element\UnknownElement::class,
97  'user' => Element\UserElement::class,
98  // special renderType for type="user" on sys_file_storage is_public column
99  'userSysFileStorageIsPublic' => Element\UserSysFileStorageIsPublicElement::class,
100  'fileInfo' => Element\FileInfoElement::class,
101  'mfaInfo' => Element\MfaInfoElement::class,
102  'slug' => Element\InputSlugElement::class,
103  'language' => Element\SelectSingleElement::class,
104  'category' => Element\CategoryElement::class,
105  'passthrough' => Element\PassThroughElement::class,
106  'belayoutwizard' => Element\BackendLayoutWizardElement::class,
107  'json' => Element\JsonElement::class,
108  'uuid' => Element\UuidElement::class,
109 
110  // Default classes to enrich single elements
111  'fieldControl' => NodeExpansion\FieldControl::class,
112  'fieldInformation' => NodeExpansion\FieldInformation::class,
113  'fieldWizard' => NodeExpansion\FieldWizard::class,
114 
115  // Element information
116  'tcaDescription' => FieldInformation\TcaDescription::class,
117  'adminIsSystemMaintainer' => FieldInformation\AdminIsSystemMaintainer::class,
118  'backendLayoutFromParentPage' => FieldInformation\BackendLayoutFromParentPage::class,
119 
120  // Element wizards
121  'defaultLanguageDifferences' => FieldWizard\DefaultLanguageDifferences::class,
122  'localizationStateSelector' => FieldWizard\LocalizationStateSelector::class,
123  'otherLanguageContent' => FieldWizard\OtherLanguageContent::class,
124  'otherLanguageThumbnails' => FieldWizard\OtherLanguageThumbnails::class,
125  'recordsOverview' => FieldWizard\RecordsOverview::class,
126  'selectIcons' => FieldWizard\SelectIcons::class,
127  'tableList' => FieldWizard\TableList::class,
128 
129  // Element controls
130  'addRecord' => FieldControl\AddRecord::class,
131  'editPopup' => FieldControl\EditPopup::class,
132  'elementBrowser' => FieldControl\ElementBrowser::class,
133  'insertClipboard' => FieldControl\InsertClipboard::class,
134  'linkPopup' => FieldControl\LinkPopup::class,
135  'listModule' => FieldControl\ListModule::class,
136  'resetSelection' => FieldControl\ResetSelection::class,
137  'passwordGenerator' => FieldControl\PasswordGenerator::class,
138  ];
139 
143  public function ‪__construct()
144  {
146  $this->‪registerNodeResolvers();
147  }
148 
155  public function ‪create(array $data): ‪NodeInterface
156  {
157  if (empty($data['renderType'])) {
158  throw new ‪Exception(
159  'Missing "renderType" in TCA of field "[' . ($data['tableName'] ?? 'unknown') . '][' . ($data['fieldName'] ?? 'unknown') . ']".',
160  1431452406
161  );
162  }
163  $type = $data['renderType'];
164 
165  $className = $this->nodeTypes[$type] ?? $this->nodeTypes['unknown'];
166 
167  if (!empty($this->nodeResolver[$type])) {
168  // Resolver with the highest priority is called first. If it returns with a new class name,
169  // it will be taken and loop is aborted, otherwise resolver with next lower priority is called.
170  foreach ($this->nodeResolver[$type] as $priority => $resolverClassName) {
171  $resolver = $this->‪initializeNodeResolverClass($resolverClassName, $data);
172  // Resolver classes do NOT receive the name of the already resolved class. Single
173  // resolvers should not have dependencies to each other or the default implementation,
174  // so they also shouldn't know the output of a different resolving class.
175  // Additionally, the globalOptions array is NOT given by reference here, changing config is a
176  // task of container classes alone and must not be abused here.
177  $newClassName = $resolver->resolve();
178  if ($newClassName !== null) {
179  $className = $newClassName;
180  break;
181  }
182  }
183  }
184 
185  return $this->‪initializeNodeClass($className, $data);
186  }
187 
196  {
197  // List of additional or override nodes
198  $registeredTypeOverrides = ‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'];
199  // Sanitize input array
200  $registeredPrioritiesForNodeNames = [];
201  foreach ($registeredTypeOverrides as $override) {
202  if (!isset($override['nodeName']) || !isset($override['class']) || !isset($override['priority'])) {
203  throw new ‪Exception(
204  'Key class, nodeName or priority missing for an entry in $GLOBALS[\'TYPO3_CONF_VARS\'][\'SYS\'][\'formEngine\'][\'nodeRegistry\']',
205  1432207533
206  );
207  }
208  if ($override['priority'] < 0 || $override['priority'] > 100) {
209  throw new ‪Exception(
210  'Priority of element ' . $override['nodeName'] . ' with class ' . $override['class'] . ' is ' . $override['priority'] . ', but must between 0 and 100',
211  1432223531
212  );
213  }
214  if (isset($registeredPrioritiesForNodeNames[$override['nodeName']][$override['priority']])) {
215  throw new ‪Exception(
216  'Element ' . $override['nodeName'] . ' already has an override registered with priority ' . $override['priority'],
217  1432223893
218  );
219  }
220  $registeredPrioritiesForNodeNames[$override['nodeName']][$override['priority']] = '';
221  }
222  // Add element with the highest priority to registry
223  $highestPriority = [];
224  foreach ($registeredTypeOverrides as $override) {
225  if (!isset($highestPriority[$override['nodeName']]) || $override['priority'] > $highestPriority[$override['nodeName']]) {
226  $highestPriority[$override['nodeName']] = $override['priority'];
227  $this->nodeTypes[$override['nodeName']] = $override['class'];
228  }
229  }
230  }
231 
238  private function ‪registerNodeResolvers(): void
239  {
240  // List of node resolver
241  $registeredNodeResolvers = ‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeResolver'];
242  $resolversByType = [];
243  foreach ($registeredNodeResolvers as ‪$nodeResolver) {
244  if (!isset(‪$nodeResolver['nodeName']) || !isset(‪$nodeResolver['class']) || !isset(‪$nodeResolver['priority'])) {
245  throw new ‪Exception(
246  'Key class, nodeName or priority missing for an entry in $GLOBALS[\'TYPO3_CONF_VARS\'][\'SYS\'][\'formEngine\'][\'nodeResolver\']',
247  1433155522
248  );
249  }
250  if (‪$nodeResolver['priority'] < 0 || ‪$nodeResolver['priority'] > 100) {
251  throw new ‪Exception(
252  'Priority of element ' . ‪$nodeResolver['nodeName'] . ' with class ' . ‪$nodeResolver['class'] . ' is ' . ‪$nodeResolver['priority'] . ', but must between 0 and 100',
253  1433155563
254  );
255  }
256  if (isset($resolversByType[‪$nodeResolver['nodeName']][‪$nodeResolver['priority']])) {
257  throw new ‪Exception(
258  'Element ' . ‪$nodeResolver['nodeName'] . ' already has a resolver registered with priority ' . ‪$nodeResolver['priority'],
259  1433155705
260  );
261  }
262  $resolversByType[‪$nodeResolver['nodeName']][‪$nodeResolver['priority']] = ‪$nodeResolver['class'];
263  }
264  $sortedResolversByType = [];
265  foreach ($resolversByType as $nodeName => $prioritiesAndClasses) {
266  krsort($prioritiesAndClasses);
267  $sortedResolversByType[$nodeName] = $prioritiesAndClasses;
268  }
269  $this->nodeResolver = $sortedResolversByType;
270  }
271 
277  private function ‪initializeNodeClass(string $className, array $data): ‪NodeInterface
278  {
280  $node = GeneralUtility::makeInstance($className);
281  $node->setData($data);
282  return $node;
283  }
284 
290  private function ‪initializeNodeResolverClass(string $className, array $data): ‪NodeResolverInterface
291  {
293  $node = GeneralUtility::makeInstance($className);
294  $node->setData($data);
295  return $node;
296  }
297 }
‪TYPO3\CMS\Backend\Form
Definition: AbstractNode.php:18
‪TYPO3\CMS\Backend\Form\NodeFactory\initializeNodeResolverClass
‪initializeNodeResolverClass(string $className, array $data)
Definition: NodeFactory.php:290
‪TYPO3\CMS\Backend\Form\NodeFactory\$nodeResolver
‪array $nodeResolver
Definition: NodeFactory.php:45
‪TYPO3\CMS\Backend\Form\Exception
Definition: Exception.php:21
‪TYPO3\CMS\Backend\Form\NodeFactory\registerNodeResolvers
‪registerNodeResolvers()
Definition: NodeFactory.php:238
‪TYPO3\CMS\Backend\Form\Container\FilesControlContainer
Definition: FilesControlContainer.php:49
‪TYPO3\CMS\Backend\Form\NodeFactory\registerAdditionalNodeTypesFromConfiguration
‪registerAdditionalNodeTypesFromConfiguration()
Definition: NodeFactory.php:195
‪TYPO3\CMS\Backend\Form\NodeInterface
Definition: NodeInterface.php:22
‪TYPO3\CMS\Backend\Form\NodeFactory
Definition: NodeFactory.php:40
‪TYPO3\CMS\Backend\Form\NodeResolverInterface
Definition: NodeResolverInterface.php:22
‪TYPO3\CMS\Backend\Form\NodeFactory\create
‪create(array $data)
Definition: NodeFactory.php:155
‪TYPO3\CMS\Backend\Form\Container\FileReferenceContainer\NODE_TYPE_IDENTIFIER
‪const NODE_TYPE_IDENTIFIER
Definition: FileReferenceContainer.php:51
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Backend\Form\Container\FilesControlContainer\NODE_TYPE_IDENTIFIER
‪const NODE_TYPE_IDENTIFIER
Definition: FilesControlContainer.php:50
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Backend\Form\NodeFactory\$nodeTypes
‪array $nodeTypes
Definition: NodeFactory.php:50
‪TYPO3\CMS\Backend\Form\NodeFactory\initializeNodeClass
‪initializeNodeClass(string $className, array $data)
Definition: NodeFactory.php:277
‪TYPO3\CMS\Backend\Form\NodeFactory\__construct
‪__construct()
Definition: NodeFactory.php:143