2 declare(strict_types = 1);
20 use Psr\Http\Message\ServerRequestInterface;
213 $formIdentifier = $this->formDefinition->getIdentifier();
214 if (isset($arguments[$formIdentifier])) {
255 $sessionIdentifierFromRequest = $this->request->getInternalArgument(
'__session');
256 $this->formSession = GeneralUtility::makeInstance(FormSession::class, $sessionIdentifierFromRequest);
268 $serializedFormStateWithHmac = $this->request->getInternalArgument(
'__state');
270 $this->formState = GeneralUtility::makeInstance(FormState::class);
273 $serializedFormState = $this->hashService->validateAndStripHmac($serializedFormStateWithHmac);
274 }
catch (InvalidHashException | InvalidArgumentForHashGenerationException $e) {
275 throw new BadRequestException(
'The HMAC of the form state could not be validated.', 1581862823);
277 $this->formState = unserialize(base64_decode($serializedFormState));
283 foreach (
$GLOBALS[
'TYPO3_CONF_VARS'][
'SC_OPTIONS'][
'ext/form'][
'afterFormStateInitialized'] ?? [] as $className) {
284 $hookObj = GeneralUtility::makeInstance($className);
286 $hookObj->afterFormStateInitialized($this);
299 if (!$this->formState->isFormSubmitted() || !$this->canProcessFormSubmission()) {
300 $this->currentPage = $this->formDefinition->getPageByIndex(0);
301 $renderingOptions = $this->currentPage->getRenderingOptions();
303 if (!$this->currentPage->isEnabled()) {
304 throw new FormException(
'Disabling the first page is not allowed', 1527186844);
307 foreach (
$GLOBALS[
'TYPO3_CONF_VARS'][
'SC_OPTIONS'][
'ext/form'][
'afterInitializeCurrentPage'] ?? [] as $className) {
308 $hookObj = GeneralUtility::makeInstance($className);
309 if (method_exists($hookObj,
'afterInitializeCurrentPage')) {
310 $this->currentPage = $hookObj->afterInitializeCurrentPage(
314 $this->request->getArguments()
321 $this->lastDisplayedPage = $this->formDefinition->getPageByIndex($this->formState->getLastDisplayedPageIndex());
322 $currentPageIndex = (int)$this->request->getInternalArgument(
'__currentPage');
325 if ($currentPageIndex < $this->lastDisplayedPage->getIndex()) {
326 $currentPageIndex = $this->lastDisplayedPage->getIndex();
329 if ($currentPageIndex > $this->lastDisplayedPage->getIndex() + 1) {
330 $currentPageIndex = $this->lastDisplayedPage->getIndex() + 1;
334 if ($currentPageIndex >= count($this->formDefinition->getPages())) {
336 $this->currentPage =
null;
338 $this->currentPage = $this->formDefinition->getPageByIndex($currentPageIndex);
339 $renderingOptions = $this->currentPage->getRenderingOptions();
341 if (!$this->currentPage->isEnabled()) {
342 if ($currentPageIndex === 0) {
343 throw new FormException(
'Disabling the first page is not allowed', 1527186845);
354 foreach (
$GLOBALS[
'TYPO3_CONF_VARS'][
'SC_OPTIONS'][
'ext/form'][
'afterInitializeCurrentPage'] ?? [] as $className) {
355 $hookObj = GeneralUtility::makeInstance($className);
356 if (method_exists($hookObj,
'afterInitializeCurrentPage')) {
357 $this->currentPage = $hookObj->afterInitializeCurrentPage(
360 $this->lastDisplayedPage,
361 $this->request->getArguments()
372 $renderingOptions = $this->formDefinition->getRenderingOptions();
373 if (!isset($renderingOptions[
'honeypot'][
'enable']) || $renderingOptions[
'honeypot'][
'enable'] ===
false || TYPO3_MODE ===
'BE') {
380 $elementsCount = count($this->lastDisplayedPage->getElements());
381 if ($elementsCount === 0) {
386 if ($honeypotNameFromSession) {
387 $honeypotElement = $this->lastDisplayedPage->createElement($honeypotNameFromSession, $renderingOptions[
'honeypot'][
'formElementToUse']);
388 $validator = $this->objectManager->get(EmptyValidator::class);
399 $renderingOptions = $this->formDefinition->getRenderingOptions();
400 if (!isset($renderingOptions[
'honeypot'][
'enable']) || $renderingOptions[
'honeypot'][
'enable'] ===
false || TYPO3_MODE ===
'BE') {
407 $elementsCount = count($this->currentPage->getElements());
408 if ($elementsCount === 0) {
414 if ($honeypotNameFromSession) {
415 $honeypotElement = $this->formDefinition->getElementByIdentifier($honeypotNameFromSession);
416 if ($honeypotElement instanceof FormElementInterface) {
417 $this->lastDisplayedPage->removeElement($honeypotElement);
422 $elementsCount = count($this->currentPage->getElements());
423 $randomElementNumber = mt_rand(0, $elementsCount - 1);
424 $honeypotName = substr(str_shuffle(
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'), 0, mt_rand(5, 26));
426 $referenceElement = $this->currentPage->getElements()[$randomElementNumber];
427 $honeypotElement = $this->currentPage->createElement($honeypotName, $renderingOptions[
'honeypot'][
'formElementToUse']);
428 $validator = $this->objectManager->get(EmptyValidator::class);
431 if (mt_rand(0, 1) === 1) {
432 $this->currentPage->moveElementAfter($honeypotElement, $referenceElement);
434 $this->currentPage->moveElementBefore($honeypotElement, $referenceElement);
449 self::HONEYPOT_NAME_SESSION_IDENTIFIER . $this->
getIdentifier() . $page->getIdentifier()
454 self::HONEYPOT_NAME_SESSION_IDENTIFIER . $this->
getIdentifier() . $page->getIdentifier()
457 return $honeypotNameFromSession;
469 self::HONEYPOT_NAME_SESSION_IDENTIFIER . $this->
getIdentifier() . $page->getIdentifier(),
475 self::HONEYPOT_NAME_SESSION_IDENTIFIER . $this->
getIdentifier() . $page->getIdentifier(),
488 return (
bool)GeneralUtility::makeInstance(Context::class)
489 ->getPropertyFromAspect(
'frontend.user',
'isLoggedIn',
false);
498 $renderables = array_merge([$this->formDefinition], $this->formDefinition->getRenderablesRecursively());
499 foreach ($renderables as $renderable) {
500 if ($renderable instanceof VariableRenderableInterface) {
501 $variants = $renderable->getVariants();
502 foreach ($variants as $variant) {
503 if ($variant->conditionMatches($conditionResolver)) {
518 return $this->currentPage ===
null;
528 return $this->lastDisplayedPage ===
null;
549 $contentObject = $this->configurationManager->getContentObject();
550 return $contentObject ===
null
562 if ($result->hasErrors() && !$this->userWentBackToPreviousStep()) {
564 $this->request->setOriginalRequestMappingResults($result);
585 $result = $this->objectManager->get(Result::class);
586 $requestArguments = $this->request->getArguments();
588 $propertyPathsForWhichPropertyMappingShouldHappen = [];
589 $registerPropertyPaths =
function ($propertyPath) use (&$propertyPathsForWhichPropertyMappingShouldHappen) {
590 $propertyPathParts = explode(
'.', $propertyPath);
591 $accumulatedPropertyPathParts = [];
592 foreach ($propertyPathParts as $propertyPathPart) {
593 $accumulatedPropertyPathParts[] = $propertyPathPart;
594 $temporaryPropertyPath = implode(
'.', $accumulatedPropertyPathParts);
595 $propertyPathsForWhichPropertyMappingShouldHappen[$temporaryPropertyPath] = $temporaryPropertyPath;
601 foreach (
$GLOBALS[
'TYPO3_CONF_VARS'][
'SC_OPTIONS'][
'ext/form'][
'afterSubmit'] ?? [] as $className) {
602 $hookObj = GeneralUtility::makeInstance($className);
603 if (method_exists($hookObj,
'afterSubmit')) {
604 $value = $hookObj->afterSubmit(
613 foreach ($page->getElementsRecursively() as $element) {
614 if (!$element->isEnabled()) {
620 }
catch (MissingArrayPathException $exception) {
624 foreach (
$GLOBALS[
'TYPO3_CONF_VARS'][
'SC_OPTIONS'][
'ext/form'][
'afterSubmit'] ?? [] as $className) {
625 $hookObj = GeneralUtility::makeInstance($className);
626 if (method_exists($hookObj,
'afterSubmit')) {
627 $value = $hookObj->afterSubmit(
636 $this->formState->setFormValue($element->getIdentifier(), $value);
637 $registerPropertyPaths($element->getIdentifier());
641 usort($propertyPathsForWhichPropertyMappingShouldHappen,
function ($a, $b) {
642 return substr_count($b,
'.') - substr_count($a,
'.');
645 $processingRules = $this->formDefinition->getProcessingRules();
647 foreach ($propertyPathsForWhichPropertyMappingShouldHappen as $propertyPath) {
648 if (isset($processingRules[$propertyPath])) {
649 $processingRule = $processingRules[$propertyPath];
650 $value = $this->formState->getFormValue($propertyPath);
652 $value = $processingRule->process($value);
654 throw new PropertyMappingException(
655 'Failed to process FormValue at "' . $propertyPath .
'" from "' . gettype($value) .
'" to "' . $processingRule->getDataType() .
'"',
660 $result->forProperty($this->
getIdentifier() .
'.' . $propertyPath)->merge($processingRule->getProcessingMessages());
661 $this->formState->setFormValue($propertyPath, $value);
678 $this->currentPage = $this->formDefinition->getPageByIndex($pageIndex);
694 $this->formState->setLastDisplayedPageIndex($this->currentPage->getIndex());
696 if ($this->formDefinition->getRendererClassName() ===
'') {
697 throw new RenderingException(sprintf(
'The form definition "%s" does not have a rendererClassName set.', $this->formDefinition->getIdentifier()), 1326095912);
699 $rendererClassName = $this->formDefinition->getRendererClassName();
700 $renderer = $this->objectManager->get($rendererClassName);
701 if (!($renderer instanceof RendererInterface)) {
702 throw new RenderingException(sprintf(
'The renderer "%s" des not implement RendererInterface', $rendererClassName), 1326096024);
707 $renderer->setControllerContext($controllerContext);
708 $renderer->setFormRuntime($this);
709 return $renderer->render();
719 $finisherContext = $this->objectManager->get(
720 FinisherContext::class,
726 $originalContent = $this->response->getContent();
727 $this->response->setContent(
null);
728 foreach ($this->formDefinition->getFinishers() as $finisher) {
729 $this->currentFinisher = $finisher;
732 $finisherOutput = $finisher->execute($finisherContext);
733 if (is_string($finisherOutput) && !empty($finisherOutput)) {
736 $output .= $this->response->getContent();
737 $this->response->setContent(
null);
740 if ($finisherContext->isCancelled()) {
744 $this->response->setContent($originalContent);
754 return $this->formDefinition->getIdentifier();
823 $previousPageIndex = $this->currentPage->getIndex() - 1;
824 if ($this->formDefinition->hasPageWithIndex($previousPageIndex)) {
825 return $this->formDefinition->getPageByIndex($previousPageIndex);
837 $nextPageIndex = $this->currentPage->getIndex() + 1;
838 if ($this->formDefinition->hasPageWithIndex($nextPageIndex)) {
839 return $this->formDefinition->getPageByIndex($nextPageIndex);
852 $previousPage =
null;
853 $previousPageIndex = $this->currentPage->getIndex() - 1;
854 while ($previousPageIndex >= 0) {
855 if ($this->formDefinition->hasPageWithIndex($previousPageIndex)) {
856 $previousPage = $this->formDefinition->getPageByIndex($previousPageIndex);
858 if ($previousPage->isEnabled()) {
862 $previousPage =
null;
863 $previousPageIndex--;
865 $previousPage =
null;
870 return $previousPage;
882 $pageCount = count($this->formDefinition->getPages());
883 $nextPageIndex = $this->currentPage->getIndex() + 1;
885 while ($nextPageIndex < $pageCount) {
886 if ($this->formDefinition->hasPageWithIndex($nextPageIndex)) {
887 $nextPage = $this->formDefinition->getPageByIndex($nextPageIndex);
888 $renderingOptions = $nextPage->getRenderingOptions();
890 !isset($renderingOptions[
'enabled'])
891 || (
bool)$renderingOptions[
'enabled']
911 $uriBuilder = $this->objectManager->get(UriBuilder::class);
912 $uriBuilder->setRequest($this->request);
913 $controllerContext = $this->objectManager->get(ControllerContext::class);
914 $controllerContext->setRequest($this->request);
915 $controllerContext->setResponse($this->response);
916 $controllerContext->setArguments($this->objectManager->get(Arguments::class, []));
917 $controllerContext->setUriBuilder($uriBuilder);
918 return $controllerContext;
930 return $this->formDefinition->getType();
944 if (is_callable([$this,
'get' . ucfirst($identifier)])) {
947 if (is_callable([$this,
'has' . ucfirst($identifier)])) {
950 if (is_callable([$this,
'is' . ucfirst($identifier)])) {
953 if (property_exists($this, $identifier)) {
954 $propertyReflection = new \ReflectionProperty($this, $identifier);
955 return $propertyReflection->isPublic();
971 $getterMethodName =
'get' . ucfirst($identifier);
972 if (is_callable([$this, $getterMethodName])) {
973 return $this->{$getterMethodName}();
983 public function offsetSet($identifier, $value)
985 $this->formState->setFormValue($identifier, $value);
994 $this->formState->setFormValue($identifier,
null);
1005 $formValue = $this->formState->getFormValue($identifier);
1006 if ($formValue !==
null) {
1009 return $this->formDefinition->getElementDefaultValueByIdentifier($identifier);
1017 return $this->formDefinition->getPages();
1036 return $this->formDefinition->getRenderingOptions();
1047 return $this->formDefinition->getRendererClassName();
1057 return $this->formDefinition->getLabel();
1067 return $this->formDefinition->getTemplateName();
1110 $GLOBALS[
'TYPO3_REQUEST'] instanceof ServerRequestInterface
1111 &&
$GLOBALS[
'TYPO3_REQUEST']->getAttribute(
'language') instanceof SiteLanguage
1113 $this->currentSiteLanguage =
$GLOBALS[
'TYPO3_REQUEST']->getAttribute(
'language');
1116 $languageId = (int)GeneralUtility::makeInstance(Context::class)->getPropertyFromAspect(
'language',
'id', 0);
1118 if (TYPO3_MODE ===
'FE') {
1122 $fakeSiteConfiguration = [
1125 'languageId' => $languageId,
1127 'navigationTitle' =>
'',
1128 'typo3Language' =>
'',
1138 $this->currentSiteLanguage = GeneralUtility::makeInstance(Site::class,
'form-dummy', $pageId, $fakeSiteConfiguration)
1139 ->getLanguageById($languageId);
1158 $formValues = array_replace_recursive(
1164 $finisherIdentifier =
'';
1169 $finisherIdentifier = (new \ReflectionClass($this->
getCurrentFinisher()))->getShortName();
1170 $finisherIdentifier = preg_replace(
'/Finisher$/',
'', $finisherIdentifier);
1174 return GeneralUtility::makeInstance(
1179 'formRuntime' => $this,
1180 'formValues' => $formValues,
1181 'stepIdentifier' => $page->getIdentifier(),
1182 'stepType' => $page->getType(),
1183 'finisherIdentifier' => $finisherIdentifier,
1185 $GLOBALS[
'TYPO3_REQUEST'] ?? GeneralUtility::makeInstance(ServerRequest::class)