2 declare(strict_types = 1);
69 public function indexAction(
string $formPersistenceIdentifier,
string $prototypeName =
null)
72 $this->view->getModuleTemplate()->setModuleName($this->request->getPluginName() .
'_' . $this->request->getControllerName());
73 $this->view->getModuleTemplate()->setFlashMessageQueue($this->controllerContext->getFlashMessageQueue());
75 if (!$this->formPersistenceManager->isAllowedPersistencePath($formPersistenceIdentifier)) {
80 strpos($formPersistenceIdentifier,
'EXT:') === 0
81 && !$this->formSettings[
'persistenceManager'][
'allowSaveToExtensionPaths']
86 $configurationService = $this->objectManager->get(ConfigurationService::class);
87 $formDefinition = $this->formPersistenceManager->load($formPersistenceIdentifier);
89 if ($prototypeName ===
null) {
90 $prototypeName = $formDefinition[
'prototypeName'] ??
'standard';
94 $selectablePrototypeNames = $configurationService->getSelectablePrototypeNamesDefinedInFormEditorSetup();
95 if (!in_array($prototypeName, $selectablePrototypeNames,
true)) {
96 throw new Exception(sprintf(
'The prototype name "%s" is not configured within "formManager.selectablePrototypesConfiguration" ', $prototypeName), 1528625039);
100 $formDefinition[
'prototypeName'] = $prototypeName;
101 $this->prototypeConfiguration = $configurationService->getPrototypeConfiguration($prototypeName);
106 $formEditorAppInitialData = [
107 'formEditorDefinitions' => $formEditorDefinitions,
108 'formDefinition' => $formDefinition,
109 'formPersistenceIdentifier' => $formPersistenceIdentifier,
110 'prototypeName' => $prototypeName,
112 'formPageRenderer' => $this->controllerContext->getUriBuilder()->uriFor(
'renderFormPage'),
113 'saveForm' => $this->controllerContext->getUriBuilder()->uriFor(
'saveForm')
115 'additionalViewModelModules' => $this->prototypeConfiguration[
'formEditor'][
'dynamicRequireJsModules'][
'additionalViewModelModules'],
116 'maximumUndoSteps' => $this->prototypeConfiguration[
'formEditor'][
'maximumUndoSteps'],
119 $this->view->assign(
'formEditorAppInitialData', json_encode($formEditorAppInitialData));
120 $this->view->assign(
'stylesheets', $this->
resolveResourcePaths($this->prototypeConfiguration[
'formEditor'][
'stylesheets']));
122 $this->view->assign(
'dynamicRequireJsModules', $this->prototypeConfiguration[
'formEditor'][
'dynamicRequireJsModules']);
126 $popupWindowWidth = 700;
127 $popupWindowHeight = 750;
128 $popupWindowSize = \trim($this->
getBackendUser()->getTSConfig()[
'options.'][
'popupWindowSize'] ??
'');
129 if (!empty($popupWindowSize)) {
130 list($popupWindowWidth, $popupWindowHeight) = GeneralUtility::intExplode(
'x', $popupWindowSize);
132 $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
133 $addInlineSettings = [
135 'typo3WinBrowserUrl' => (string)
$uriBuilder->buildUriFromRoute(
'wizard_element_browser'),
139 'width' => $popupWindowWidth,
140 'height' => $popupWindowHeight
145 $addInlineSettings = array_replace_recursive(
147 $this->prototypeConfiguration[
'formEditor'][
'addInlineSettings']
149 $this->view->assign(
'addInlineSettings', $addInlineSettings);
160 $this->defaultViewObjectName = JsonView::class;
172 $formDefinition = $formDefinition->getArrayCopy();
174 foreach (
$GLOBALS[
'TYPO3_CONF_VARS'][
'SC_OPTIONS'][
'ext/form'][
'beforeFormSave'] ?? [] as $className) {
175 $hookObj = GeneralUtility::makeInstance($className);
176 if (method_exists($hookObj,
'beforeFormSave')) {
177 $formDefinition = $hookObj->beforeFormSave(
178 $formPersistenceIdentifier,
185 'status' =>
'success',
189 if (!$this->formPersistenceManager->isAllowedPersistencePath($formPersistenceIdentifier)) {
192 $this->formPersistenceManager->save($formPersistenceIdentifier, $formDefinition);
193 $configurationService = $this->objectManager->get(ConfigurationService::class);
194 $this->prototypeConfiguration = $configurationService->getPrototypeConfiguration($formDefinition[
'prototypeName']);
196 $response[
'formDefinition'] = $formDefinition;
200 'message' => $e->getMessage(),
201 'code' => $e->getCode(),
208 $this->view->setVariablesToRender([
225 $prototypeName = $prototypeName ?: $formDefinition[
'prototypeName'] ??
'standard';
226 $formDefinition = $formDefinition->getArrayCopy();
228 $formFactory = $this->objectManager->get(ArrayFormFactory::class);
229 $formDefinition = $formFactory->build($formDefinition, $prototypeName);
230 $formDefinition->setRenderingOption(
'previewMode',
true);
231 $form = $formDefinition->bind($this->request, $this->response);
233 $form->overrideCurrentPage($pageIndex);
235 return $form->render();
248 $fakeSiteConfiguration = [
251 'languageId' => $languageId,
253 'navigationTitle' =>
'',
254 'typo3Language' =>
'',
265 $currentSiteLanguage = GeneralUtility::makeInstance(Site::class,
'form-dummy', $pageId, $fakeSiteConfiguration)
266 ->getLanguageById($languageId);
267 return $currentSiteLanguage;
279 $formElementsByGroup = [];
281 foreach ($formElementsDefinition as $formElementName => $formElementConfiguration) {
282 if (!isset($formElementConfiguration[
'group'])) {
285 if (!isset($formElementsByGroup[$formElementConfiguration[
'group']])) {
286 $formElementsByGroup[$formElementConfiguration[
'group']] = [];
290 $formElementConfiguration,
291 $this->prototypeConfiguration[
'formEditor'][
'translationFile'] ??
null
294 $formElementsByGroup[$formElementConfiguration[
'group']][] = [
295 'key' => $formElementName,
296 'cssKey' => preg_replace(
'/[^a-z0-9]/',
'-', strtolower($formElementName)),
297 'label' => $formElementConfiguration[
'label'],
298 'sorting' => $formElementConfiguration[
'groupSorting'],
299 'iconIdentifier' => $formElementConfiguration[
'iconIdentifier'],
304 foreach ($this->prototypeConfiguration[
'formEditor'][
'formElementGroups'] ?? [] as $groupName => $groupConfiguration) {
305 if (!isset($formElementsByGroup[$groupName])) {
309 usort($formElementsByGroup[$groupName],
function ($a, $b) {
310 return $a[
'sorting'] - $b[
'sorting'];
312 unset($formElementsByGroup[$groupName][
'sorting']);
316 $this->prototypeConfiguration[
'formEditor'][
'translationFile'] ??
null
321 'elements' => $formElementsByGroup[$groupName],
322 'label' => $groupConfiguration[
'label'],
336 $formEditorDefinitions = [];
337 foreach ([$this->prototypeConfiguration, $this->prototypeConfiguration[
'formEditor']] as $configuration) {
338 foreach ($configuration as $firstLevelItemKey => $firstLevelItemValue) {
339 if (substr($firstLevelItemKey, -10) !==
'Definition') {
342 $reducedKey = substr($firstLevelItemKey, 0, -10);
343 foreach ($configuration[$firstLevelItemKey] as $formEditorDefinitionKey => $formEditorDefinitionValue) {
344 if (isset($formEditorDefinitionValue[
'formEditor'])) {
345 $formEditorDefinitionValue = array_intersect_key($formEditorDefinitionValue, array_flip([
'formEditor']));
346 $formEditorDefinitions[$reducedKey][$formEditorDefinitionKey] = $formEditorDefinitionValue[
'formEditor'];
348 $formEditorDefinitions[$reducedKey][$formEditorDefinitionKey] = $formEditorDefinitionValue;
355 $formEditorDefinitions,
356 $this->prototypeConfiguration[
'formEditor'][
'translationFile'] ??
null
358 return $formEditorDefinitions;
369 $buttonBar = $this->view->getModuleTemplate()->getDocHeaderComponent()->getButtonBar();
370 $getVars = $this->request->getArguments();
372 if (isset($getVars[
'action']) && $getVars[
'action'] ===
'index') {
373 $newPageButton = $buttonBar->makeInputButton()
374 ->setDataAttributes([
'action' =>
'formeditor-new-page',
'identifier' =>
'headerNewPage'])
375 ->setTitle($this->
getLanguageService()->sL(
'LLL:EXT:form/Resources/Private/Language/Database.xlf:formEditor.new_page_button'))
376 ->setName(
'formeditor-new-page')
377 ->setValue(
'new-page')
378 ->setClasses(
't3-form-element-new-page-button hidden')
379 ->setIcon($this->view->getModuleTemplate()->getIconFactory()->getIcon(
'actions-page-new',
Icon::SIZE_SMALL));
381 $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
383 $closeButton = $buttonBar->makeLinkButton()
384 ->setDataAttributes([
'identifier' =>
'closeButton'])
385 ->setHref((
string)
$uriBuilder->buildUriFromRoute(
'web_FormFormbuilder'))
386 ->setClasses(
't3-form-element-close-form-button hidden')
387 ->setTitle($this->
getLanguageService()->sL(
'LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:rm.closeDoc'))
388 ->setIcon($this->view->getModuleTemplate()->getIconFactory()->getIcon(
'actions-close',
Icon::SIZE_SMALL));
390 $saveButton = $buttonBar->makeInputButton()
391 ->setDataAttributes([
'identifier' =>
'saveButton'])
392 ->setTitle($this->
getLanguageService()->sL(
'LLL:EXT:form/Resources/Private/Language/Database.xlf:formEditor.save_button'))
393 ->setName(
'formeditor-save-form')
395 ->setClasses(
't3-form-element-save-form-button hidden')
396 ->setIcon($this->view->getModuleTemplate()->getIconFactory()->getIcon(
'actions-document-save',
Icon::SIZE_SMALL))
397 ->setShowLabelText(
true);
399 $formSettingsButton = $buttonBar->makeInputButton()
400 ->setDataAttributes([
'identifier' =>
'formSettingsButton'])
401 ->setTitle($this->
getLanguageService()->sL(
'LLL:EXT:form/Resources/Private/Language/Database.xlf:formEditor.form_settings_button'))
402 ->setName(
'formeditor-form-settings')
403 ->setValue(
'settings')
404 ->setClasses(
't3-form-element-form-settings-button hidden')
405 ->setIcon($this->view->getModuleTemplate()->getIconFactory()->getIcon(
'actions-system-extension-configure',
Icon::SIZE_SMALL))
406 ->setShowLabelText(
true);
408 $undoButton = $buttonBar->makeInputButton()
409 ->setDataAttributes([
'identifier' =>
'undoButton'])
410 ->setTitle($this->
getLanguageService()->sL(
'LLL:EXT:form/Resources/Private/Language/Database.xlf:formEditor.undo_button'))
411 ->setName(
'formeditor-undo-form')
413 ->setClasses(
't3-form-element-undo-form-button hidden disabled')
414 ->setIcon($this->view->getModuleTemplate()->getIconFactory()->getIcon(
'actions-edit-undo',
Icon::SIZE_SMALL));
416 $redoButton = $buttonBar->makeInputButton()
417 ->setDataAttributes([
'identifier' =>
'redoButton'])
418 ->setTitle($this->
getLanguageService()->sL(
'LLL:EXT:form/Resources/Private/Language/Database.xlf:formEditor.redo_button'))
419 ->setName(
'formeditor-redo-form')
421 ->setClasses(
't3-form-element-redo-form-button hidden disabled')
422 ->setIcon($this->view->getModuleTemplate()->getIconFactory()->getIcon(
'actions-edit-redo',
Icon::SIZE_SMALL));
441 $fluidConfiguration = $this->prototypeConfiguration[
'formEditor'][
'formEditorFluidConfiguration'] ??
null;
442 $formEditorPartials = $this->prototypeConfiguration[
'formEditor'][
'formEditorPartials'] ??
null;
444 if (!isset($fluidConfiguration[
'templatePathAndFilename'])) {
446 'The option templatePathAndFilename must be set.',
451 !isset($fluidConfiguration[
'layoutRootPaths'])
452 || !is_array($fluidConfiguration[
'layoutRootPaths'])
455 'The option layoutRootPaths must be set.',
460 !isset($fluidConfiguration[
'partialRootPaths'])
461 || !is_array($fluidConfiguration[
'partialRootPaths'])
464 'The option partialRootPaths must be set.',
471 $view = $this->objectManager->get(TemplateView::class);
473 $view->getRenderingContext()->getTemplatePaths()->fillFromConfigurationArray($fluidConfiguration);
474 $view->setTemplatePathAndFilename($fluidConfiguration[
'templatePathAndFilename']);
476 'insertRenderablesPanelConfiguration' => $insertRenderablesPanelConfiguration,
477 'formEditorPartials' => $formEditorPartials,
490 $multiValueProperties = [];
491 foreach ($this->prototypeConfiguration[
'formElementsDefinition'] as $type => $configuration) {
492 if (!isset($configuration[
'formEditor'][
'editors'])) {
495 foreach ($configuration[
'formEditor'][
'editors'] as $editorConfiguration) {
496 if ($editorConfiguration[
'templateName'] ===
'Inspector-PropertyGridEditor') {
497 $multiValueProperties[$type][] = $editorConfiguration[
'propertyPath'];
509 $formDefinition = $formDefinitionConversionService->addHmacData($formDefinition);
510 $formDefinition = $formDefinitionConversionService->migrateFinisherConfiguration($formDefinition);
512 return $formDefinition;
550 array $formDefinition,
551 array $multiValueProperties
554 foreach ($formDefinition as $key => $value) {
555 if (isset($value[
'type']) && array_key_exists($value[
'type'], $multiValueProperties)) {
556 $multiValuePropertiesForType = $multiValueProperties[$value[
'type']];
557 foreach ($multiValuePropertiesForType as $multiValueProperty) {
562 if (!is_array($multiValuePropertyData)) {
565 $newMultiValuePropertyData = [];
566 foreach ($multiValuePropertyData as $k => $v) {
567 $newMultiValuePropertyData[] = [
577 if (is_array($value)) {
593 foreach ($array as $key => $value) {
594 if (!is_array($value)) {
602 if (empty($array[$key])) {
615 return GeneralUtility::makeInstance(FormDefinitionConversionService::class);
645 return GeneralUtility::makeInstance(PageRenderer::class);