‪TYPO3CMS  11.5
FormRuntime.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
18 /*
19  * Inspired by and partially taken from the Neos.Form package (www.neos.io)
20  */
21 
23 
24 use Psr\Container\ContainerInterface;
25 use Psr\Http\Message\ResponseInterface;
26 use Psr\Http\Message\ServerRequestInterface;
61 use ‪TYPO3\CMS\Form\Exception as FormException;
64 use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
66 
108 class ‪FormRuntime implements ‪RootRenderableInterface, \ArrayAccess
109 {
110  public const ‪HONEYPOT_NAME_SESSION_IDENTIFIER = 'tx_form_honeypot_name_';
111 
112  protected ContainerInterface ‪$container;
113  // @deprecated since v11, will be removed in v12
116  protected ?‪Request ‪$request = null;
117  protected ResponseInterface ‪$response;
120 
124  protected ‪$formState;
125 
132  protected ‪$formSession;
133 
144  protected ‪$currentPage;
145 
152  protected ‪$lastDisplayedPage;
153 
159  protected ‪$currentSiteLanguage;
160 
166  protected ‪$currentFinisher;
167 
168  public function ‪__construct(
169  ContainerInterface ‪$container,
173  ) {
174  $this->container = ‪$container;
175  // @deprecated since v11, will be removed in v12
176  $this->objectManager = ‪$objectManager;
177  $this->configurationManager = ‪$configurationManager;
178  $this->hashService = ‪$hashService;
179  $this->response = new ‪Response();
180  }
181 
183  {
184  $this->formDefinition = ‪$formDefinition;
185  }
186 
187  public function ‪setRequest(‪Request ‪$request)
188  {
189  $this->request = clone ‪$request;
190  }
191 
192  public function ‪initialize()
193  {
194  $arguments = $this->request->getArguments();
195  $formIdentifier = $this->formDefinition->getIdentifier();
196  if (isset($arguments[$formIdentifier])) {
197  $this->request->setArguments($arguments[$formIdentifier]);
198  }
199 
204  $this->‪processVariants();
207 
208  // Only validate and set form values within the form state
209  // if the current request is not the very first request
210  // and the current request can be processed (POST request and uncached).
211  if (!$this->‪isFirstRequest() && $this->‪canProcessFormSubmission()) {
213  }
214 
216  }
217 
221  protected function ‪initializeFormSessionFromRequest(): void
222  {
223  // Initialize the form session only if the current request can be processed
224  // (POST request and uncached) to ensure unique sessions for each form submitter.
225  if (!$this->‪canProcessFormSubmission()) {
226  return;
227  }
228 
229  $sessionIdentifierFromRequest = $this->request->getInternalArgument('__session');
230  $this->formSession = GeneralUtility::makeInstance(FormSession::class, $sessionIdentifierFromRequest);
231  }
232 
237  protected function ‪initializeFormStateFromRequest()
238  {
239  // Only try to reconstitute the form state if the current request
240  // is not the very first request and if the current request can
241  // be processed (POST request and uncached).
242  $serializedFormStateWithHmac = $this->request->getInternalArgument('__state');
243  if ($serializedFormStateWithHmac === null || !$this->‪canProcessFormSubmission()) {
244  $this->formState = GeneralUtility::makeInstance(FormState::class);
245  } else {
246  try {
247  $serializedFormState = $this->hashService->validateAndStripHmac($serializedFormStateWithHmac);
248  } catch (InvalidHashException | InvalidArgumentForHashGenerationException $e) {
249  throw new ‪BadRequestException('The HMAC of the form state could not be validated.', 1581862823);
250  }
251  $this->formState = unserialize(base64_decode($serializedFormState));
252  }
253  }
254 
255  protected function ‪triggerAfterFormStateInitialized(): void
256  {
257  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/form']['afterFormStateInitialized'] ?? [] as $className) {
258  $hookObj = GeneralUtility::makeInstance($className);
259  if ($hookObj instanceof AfterFormStateInitializedInterface) {
260  $hookObj->afterFormStateInitialized($this);
261  }
262  }
263  }
264 
268  protected function ‪initializeCurrentPageFromRequest()
269  {
270  // If there was no previous form submissions or if the current request
271  // can't be processed (no POST request and/or cached) then display the first
272  // form step
273  if (!$this->formState->isFormSubmitted() || !$this->canProcessFormSubmission()) {
274  $this->currentPage = $this->formDefinition->getPageByIndex(0);
275 
276  if (!$this->currentPage->isEnabled()) {
277  throw new FormException('Disabling the first page is not allowed', 1527186844);
278  }
279 
280  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/form']['afterInitializeCurrentPage'] ?? [] as $className) {
281  $hookObj = GeneralUtility::makeInstance($className);
282  if (method_exists($hookObj, 'afterInitializeCurrentPage')) {
283  $this->currentPage = $hookObj->afterInitializeCurrentPage(
284  $this,
285  $this->currentPage,
286  null,
287  $this->request->getArguments()
288  );
289  }
290  }
291  return;
292  }
293 
294  $this->lastDisplayedPage = $this->formDefinition->getPageByIndex($this->formState->getLastDisplayedPageIndex());
295  $currentPageIndex = (int)$this->request->getInternalArgument('__currentPage');
296 
297  if ($this->‪userWentBackToPreviousStep()) {
298  if ($currentPageIndex < $this->lastDisplayedPage->getIndex()) {
299  $currentPageIndex = $this->lastDisplayedPage->getIndex();
300  }
301  } else {
302  if ($currentPageIndex > $this->lastDisplayedPage->getIndex() + 1) {
303  $currentPageIndex = $this->lastDisplayedPage->getIndex() + 1;
304  }
305  }
306 
307  if ($currentPageIndex >= count($this->formDefinition->getPages())) {
308  // Last Page
309  $this->currentPage = null;
310  } else {
311  $this->currentPage = $this->formDefinition->getPageByIndex($currentPageIndex);
312 
313  if (!$this->currentPage->isEnabled()) {
314  if ($currentPageIndex === 0) {
315  throw new FormException('Disabling the first page is not allowed', 1527186845);
316  }
317 
318  if ($this->‪userWentBackToPreviousStep()) {
319  $this->currentPage = $this->‪getPreviousEnabledPage();
320  } else {
321  $this->currentPage = $this->‪getNextEnabledPage();
322  }
323  }
324  }
325 
326  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/form']['afterInitializeCurrentPage'] ?? [] as $className) {
327  $hookObj = GeneralUtility::makeInstance($className);
328  if (method_exists($hookObj, 'afterInitializeCurrentPage')) {
329  $this->currentPage = $hookObj->afterInitializeCurrentPage(
330  $this,
331  $this->currentPage,
332  $this->lastDisplayedPage,
333  $this->request->getArguments()
334  );
335  }
336  }
337  }
338 
342  protected function ‪initializeHoneypotFromRequest()
343  {
344  $renderingOptions = $this->formDefinition->getRenderingOptions();
345  if (!isset($renderingOptions['honeypot']['enable'])
346  || $renderingOptions['honeypot']['enable'] === false
347  || ((‪$GLOBALS['TYPO3_REQUEST'] ?? null) instanceof ServerRequestInterface
348  && ‪ApplicationType::fromRequest(‪$GLOBALS['TYPO3_REQUEST'])->isBackend())
349  ) {
350  return;
351  }
352 
353  ‪ArrayUtility::assertAllArrayKeysAreValid($renderingOptions['honeypot'], ['enable', 'formElementToUse']);
354 
355  if (!$this->‪isFirstRequest()) {
356  $elementsCount = count($this->lastDisplayedPage->getElements());
357  if ($elementsCount === 0) {
358  return;
359  }
360 
361  $honeypotNameFromSession = $this->‪getHoneypotNameFromSession($this->lastDisplayedPage);
362  if ($honeypotNameFromSession) {
363  $honeypotElement = $this->lastDisplayedPage->createElement($honeypotNameFromSession, $renderingOptions['honeypot']['formElementToUse']);
364  ‪$validator = GeneralUtility::makeInstance(EmptyValidator::class);
365  $honeypotElement->addValidator(‪$validator);
366  }
367  }
368  }
369 
373  protected function ‪renderHoneypot()
374  {
375  $renderingOptions = $this->formDefinition->getRenderingOptions();
376  if (!isset($renderingOptions['honeypot']['enable'])
377  || $this->currentPage === null
378  || $renderingOptions['honeypot']['enable'] === false
379  || ((‪$GLOBALS['TYPO3_REQUEST'] ?? null) instanceof ServerRequestInterface
380  && ‪ApplicationType::fromRequest(‪$GLOBALS['TYPO3_REQUEST'])->isBackend())
381  ) {
382  return;
383  }
384 
385  ‪ArrayUtility::assertAllArrayKeysAreValid($renderingOptions['honeypot'], ['enable', 'formElementToUse']);
386 
387  if (!$this->‪isAfterLastPage()) {
388  $elementsCount = count($this->currentPage->getElements());
389  if ($elementsCount === 0) {
390  return;
391  }
392 
393  if (!$this->‪isFirstRequest()) {
394  $honeypotNameFromSession = $this->‪getHoneypotNameFromSession($this->lastDisplayedPage);
395  if ($honeypotNameFromSession) {
396  $honeypotElement = $this->formDefinition->getElementByIdentifier($honeypotNameFromSession);
397  if ($honeypotElement instanceof FormElementInterface) {
398  $this->lastDisplayedPage->removeElement($honeypotElement);
399  }
400  }
401  }
402 
403  $elementsCount = count($this->currentPage->getElements());
404  $randomElementNumber = random_int(0, $elementsCount - 1);
405  $honeypotName = substr(str_shuffle('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'), 0, random_int(5, 26));
406 
407  $referenceElement = $this->currentPage->getElements()[$randomElementNumber];
408  $honeypotElement = $this->currentPage->createElement($honeypotName, $renderingOptions['honeypot']['formElementToUse']);
409  ‪$validator = GeneralUtility::makeInstance(EmptyValidator::class);
410 
411  $honeypotElement->addValidator(‪$validator);
412  if (random_int(0, 1) === 1) {
413  $this->currentPage->moveElementAfter($honeypotElement, $referenceElement);
414  } else {
415  $this->currentPage->moveElementBefore($honeypotElement, $referenceElement);
416  }
417  $this->‪setHoneypotNameInSession($this->currentPage, $honeypotName);
418  }
419  }
420 
425  protected function ‪getHoneypotNameFromSession(‪Page $page)
426  {
427  if ($this->‪isFrontendUserAuthenticated()) {
428  $honeypotNameFromSession = $this->‪getFrontendUser()->‪getKey(
429  'user',
430  self::HONEYPOT_NAME_SESSION_IDENTIFIER . $this->‪getIdentifier() . $page->‪getIdentifier()
431  );
432  } else {
433  $honeypotNameFromSession = $this->‪getFrontendUser()->‪getKey(
434  'ses',
435  self::HONEYPOT_NAME_SESSION_IDENTIFIER . $this->‪getIdentifier() . $page->‪getIdentifier()
436  );
437  }
438  return $honeypotNameFromSession;
439  }
440 
445  protected function ‪setHoneypotNameInSession(‪Page $page, string $honeypotName)
446  {
447  if ($this->‪isFrontendUserAuthenticated()) {
448  $this->‪getFrontendUser()->‪setKey(
449  'user',
450  self::HONEYPOT_NAME_SESSION_IDENTIFIER . $this->‪getIdentifier() . $page->‪getIdentifier(),
451  $honeypotName
452  );
453  } else {
454  $this->‪getFrontendUser()->‪setKey(
455  'ses',
456  self::HONEYPOT_NAME_SESSION_IDENTIFIER . $this->‪getIdentifier() . $page->‪getIdentifier(),
457  $honeypotName
458  );
459  }
460  }
461 
467  protected function ‪isFrontendUserAuthenticated(): bool
468  {
469  return (bool)GeneralUtility::makeInstance(Context::class)
470  ->getPropertyFromAspect('frontend.user', 'isLoggedIn', false);
471  }
472 
473  protected function ‪processVariants()
474  {
475  $conditionResolver = $this->‪getConditionResolver();
476 
477  $renderables = array_merge([$this->formDefinition], $this->formDefinition->getRenderablesRecursively());
478  foreach ($renderables as $renderable) {
479  if ($renderable instanceof ‪VariableRenderableInterface) {
480  $variants = $renderable->getVariants();
481  foreach ($variants as $variant) {
482  if ($variant->conditionMatches($conditionResolver)) {
483  $variant->apply();
484  }
485  }
486  }
487  }
488  }
489 
495  protected function ‪isAfterLastPage(): bool
496  {
497  return $this->currentPage === null;
498  }
499 
505  protected function ‪isFirstRequest(): bool
506  {
507  return $this->lastDisplayedPage === null;
508  }
509 
513  protected function ‪isPostRequest(): bool
514  {
515  return $this->‪getRequest()->‪getMethod() === 'POST';
516  }
517 
527  protected function ‪isRenderedCached(): bool
528  {
529  $contentObject = $this->configurationManager->getContentObject();
530  return $contentObject === null
531  ? true
532  // @todo this does not work when rendering a cached `FLUIDTEMPLATE` (not nested in `COA_INT`)
533  : $contentObject->getUserObjectType() === ContentObjectRenderer::OBJECTTYPE_USER;
534  }
535 
539  protected function ‪processSubmittedFormValues()
540  {
541  $result = $this->‪mapAndValidatePage($this->lastDisplayedPage);
542  if ($result->hasErrors() && !$this->userWentBackToPreviousStep()) {
543  $this->currentPage = ‪$this->lastDisplayedPage;
544  $this->request->setOriginalRequestMappingResults($result);
545  }
546  }
547 
553  protected function ‪userWentBackToPreviousStep(): bool
554  {
555  return !$this->‪isAfterLastPage() && !$this->‪isFirstRequest() && $this->currentPage->getIndex() < $this->lastDisplayedPage->getIndex();
556  }
557 
563  protected function ‪mapAndValidatePage(‪Page $page): ‪Result
564  {
565  $result = GeneralUtility::makeInstance(Result::class);
566  $requestArguments = $this->request->getArguments();
567 
568  $propertyPathsForWhichPropertyMappingShouldHappen = [];
569  $registerPropertyPaths = static function ($propertyPath) use (&$propertyPathsForWhichPropertyMappingShouldHappen) {
570  $propertyPathParts = explode('.', $propertyPath);
571  $accumulatedPropertyPathParts = [];
572  foreach ($propertyPathParts as $propertyPathPart) {
573  $accumulatedPropertyPathParts[] = $propertyPathPart;
574  $temporaryPropertyPath = implode('.', $accumulatedPropertyPathParts);
575  $propertyPathsForWhichPropertyMappingShouldHappen[$temporaryPropertyPath] = $temporaryPropertyPath;
576  }
577  };
578 
579  $value = null;
580 
581  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/form']['afterSubmit'] ?? [] as $className) {
582  $hookObj = GeneralUtility::makeInstance($className);
583  if (method_exists($hookObj, 'afterSubmit')) {
584  $value = $hookObj->afterSubmit(
585  $this,
586  $page,
587  $value,
588  $requestArguments
589  );
590  }
591  }
592 
593  foreach ($page->‪getElementsRecursively() as $element) {
594  if (!$element->isEnabled()) {
595  continue;
596  }
597 
598  try {
599  $value = ‪ArrayUtility::getValueByPath($requestArguments, $element->getIdentifier(), '.');
600  } catch (‪MissingArrayPathException $exception) {
601  $value = null;
602  }
603 
604  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/form']['afterSubmit'] ?? [] as $className) {
605  $hookObj = GeneralUtility::makeInstance($className);
606  if (method_exists($hookObj, 'afterSubmit')) {
607  $value = $hookObj->afterSubmit(
608  $this,
609  $element,
610  $value,
611  $requestArguments
612  );
613  }
614  }
615 
616  $this->formState->setFormValue($element->getIdentifier(), $value);
617  $registerPropertyPaths($element->getIdentifier());
618  }
619 
620  // The more parts the path has, the more early it is processed
621  usort($propertyPathsForWhichPropertyMappingShouldHappen, static function ($a, $b) {
622  return substr_count($b, '.') - substr_count($a, '.');
623  });
624 
625  $processingRules = $this->formDefinition->getProcessingRules();
626 
627  foreach ($propertyPathsForWhichPropertyMappingShouldHappen as $propertyPath) {
628  if (isset($processingRules[$propertyPath])) {
629  $processingRule = $processingRules[$propertyPath];
630  $value = $this->formState->getFormValue($propertyPath);
631  try {
632  $value = $processingRule->process($value);
633  } catch (‪PropertyException $exception) {
634  throw new ‪PropertyMappingException(
635  'Failed to process FormValue at "' . $propertyPath . '" from "' . gettype($value) . '" to "' . $processingRule->getDataType() . '"',
636  1480024933,
637  $exception
638  );
639  }
640  $result->forProperty($this->‪getIdentifier() . '.' . $propertyPath)->merge($processingRule->getProcessingMessages());
641  $this->formState->setFormValue($propertyPath, $value);
642  }
643  }
644 
645  return $result;
646  }
647 
656  public function ‪overrideCurrentPage(int $pageIndex)
657  {
658  $this->currentPage = $this->formDefinition->getPageByIndex($pageIndex);
659  }
660 
667  public function ‪render()
668  {
669  if ($this->‪isAfterLastPage()) {
670  return $this->‪invokeFinishers();
671  }
672  $this->‪processVariants();
673 
674  $this->formState->setLastDisplayedPageIndex($this->currentPage->getIndex());
675 
676  if ($this->formDefinition->getRendererClassName() === '') {
677  throw new RenderingException(sprintf('The form definition "%s" does not have a rendererClassName set.', $this->formDefinition->getIdentifier()), 1326095912);
678  }
679  $rendererClassName = $this->formDefinition->getRendererClassName();
680  if ($this->container->has($rendererClassName)) {
681  $renderer = $this->container->get($rendererClassName);
682  } else {
683  // @deprecated since v11, will be removed in v12.
684  $renderer = $this->objectManager->get($rendererClassName);
685  }
686  if (!($renderer instanceof RendererInterface)) {
687  throw new RenderingException(sprintf('The renderer "%s" des not implement RendererInterface', $rendererClassName), 1326096024);
688  }
689 
690  // @deprecated since v11, will be removed with v12.
691  $controllerContext = $this->‪getControllerContext();
692  $renderer->setControllerContext($controllerContext);
693 
694  $renderer->setFormRuntime($this);
695  return $renderer->render();
696  }
697 
703  protected function ‪invokeFinishers(): string
704  {
705  $finisherContext = GeneralUtility::makeInstance(
706  FinisherContext::class,
707  $this,
708  $this->‪getControllerContext(), // @deprecated since v11, will be removed with v12.
709  $this->request
710  );
711 
712  ‪$output = '';
713  $this->response->getBody()->rewind();
714  $originalContent = $this->response->getBody()->getContents();
715  $this->response->getBody()->write('');
716  foreach ($this->formDefinition->getFinishers() as $finisher) {
717  $this->currentFinisher = $finisher;
718  $this->‪processVariants();
719 
720  $finisherOutput = $finisher->execute($finisherContext);
721  if (is_string($finisherOutput) && !empty($finisherOutput)) {
722  ‪$output .= $finisherOutput;
723  } else {
724  $this->response->getBody()->rewind();
725  ‪$output .= $this->response->getBody()->getContents();
726  $this->response->getBody()->write('');
727  }
728 
729  if ($finisherContext->isCancelled()) {
730  break;
731  }
732  }
733  $this->response->getBody()->rewind();
734  $this->response->getBody()->write($originalContent);
735 
736  return ‪$output;
737  }
738 
742  public function ‪getIdentifier(): string
743  {
744  return $this->formDefinition->getIdentifier();
745  }
746 
755  public function ‪getRequest(): Request
756  {
757  return ‪$this->request;
758  }
759 
768  public function ‪getResponse(): ResponseInterface
769  {
770  return ‪$this->response;
771  }
772 
782  public function ‪canProcessFormSubmission(): bool
783  {
784  return $this->‪isPostRequest() && !$this->‪isRenderedCached();
785  }
786 
791  public function ‪getFormSession(): ?‪FormSession
792  {
793  return ‪$this->formSession;
794  }
795 
801  public function ‪getCurrentPage(): ?‪Page
802  {
803  return ‪$this->currentPage;
804  }
805 
811  public function ‪getPreviousPage(): ?‪Page
812  {
813  $previousPageIndex = $this->currentPage->‪getIndex() - 1;
814  if ($this->formDefinition->hasPageWithIndex($previousPageIndex)) {
815  return $this->formDefinition->getPageByIndex($previousPageIndex);
816  }
817  return null;
818  }
819 
825  public function ‪getNextPage(): ?‪Page
826  {
827  $nextPageIndex = $this->currentPage->‪getIndex() + 1;
828  if ($this->formDefinition->hasPageWithIndex($nextPageIndex)) {
829  return $this->formDefinition->getPageByIndex($nextPageIndex);
830  }
831  return null;
832  }
833 
840  public function ‪getPreviousEnabledPage(): ?‪Page
841  {
842  $previousPage = null;
843  $previousPageIndex = $this->currentPage->‪getIndex() - 1;
844  while ($previousPageIndex >= 0) {
845  if ($this->formDefinition->hasPageWithIndex($previousPageIndex)) {
846  $previousPage = $this->formDefinition->getPageByIndex($previousPageIndex);
847 
848  if ($previousPage->isEnabled()) {
849  break;
850  }
851 
852  $previousPage = null;
853  $previousPageIndex--;
854  } else {
855  $previousPage = null;
856  break;
857  }
858  }
859 
860  return $previousPage;
861  }
862 
869  public function ‪getNextEnabledPage(): ?Page
870  {
871  $nextPage = null;
872  $pageCount = count($this->formDefinition->getPages());
873  $nextPageIndex = $this->currentPage->getIndex() + 1;
874 
875  while ($nextPageIndex < $pageCount) {
876  if ($this->formDefinition->hasPageWithIndex($nextPageIndex)) {
877  $nextPage = $this->formDefinition->getPageByIndex($nextPageIndex);
878  $renderingOptions = $nextPage->getRenderingOptions();
879  if (
880  !isset($renderingOptions['enabled'])
881  || (bool)$renderingOptions['enabled']
882  ) {
883  break;
884  }
885  $nextPage = null;
886  $nextPageIndex++;
887  } else {
888  $nextPage = null;
889  break;
890  }
891  }
892 
893  return $nextPage;
894  }
895 
900  protected function ‪getControllerContext(): ‪ControllerContext
901  {
902  $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
903  $uriBuilder->setRequest($this->request);
904  $controllerContext = GeneralUtility::makeInstance(ControllerContext::class);
905  $controllerContext->setRequest($this->request);
906  $controllerContext->setArguments(GeneralUtility::makeInstance(Arguments::class));
907  $controllerContext->setUriBuilder($uriBuilder);
908  return $controllerContext;
909  }
910 
918  public function ‪getType(): string
919  {
920  return $this->formDefinition->getType();
921  }
922 
929  public function ‪offsetExists($identifier): bool
930  {
931  if ($this->‪getElementValue($identifier) !== null) {
932  return true;
933  }
934 
935  if (is_callable([$this, 'get' . ucfirst($identifier)])) {
936  return true;
937  }
938  if (is_callable([$this, 'has' . ucfirst($identifier)])) {
939  return true;
940  }
941  if (is_callable([$this, 'is' . ucfirst($identifier)])) {
942  return true;
943  }
944  if (property_exists($this, $identifier)) {
945  $propertyReflection = new \ReflectionProperty($this, $identifier);
946  return $propertyReflection->isPublic();
947  }
948 
949  return false;
950  }
951 
959  #[\ReturnTypeWillChange]
960  public function ‪offsetGet($identifier)
961  {
962  if ($this->‪getElementValue($identifier) !== null) {
963  return $this->‪getElementValue($identifier);
964  }
965  $getterMethodName = 'get' . ucfirst($identifier);
966  if (is_callable([$this, $getterMethodName])) {
967  return $this->{$getterMethodName}();
968  }
969  return null;
970  }
971 
978  public function ‪offsetSet($identifier, $value): void
979  {
980  $this->formState->setFormValue($identifier, $value);
981  }
982 
988  public function ‪offsetUnset($identifier): void
989  {
990  $this->formState->setFormValue($identifier, null);
991  }
992 
999  public function ‪getElementValue(string $identifier)
1000  {
1001  $formValue = $this->formState->getFormValue($identifier);
1002  if ($formValue !== null) {
1003  return $formValue;
1004  }
1005  return $this->formDefinition->getElementDefaultValueByIdentifier($identifier);
1006  }
1007 
1011  public function ‪getPages(): array
1012  {
1013  return $this->formDefinition->getPages();
1014  }
1015 
1020  public function ‪getFormState(): ?‪FormState
1021  {
1022  return ‪$this->formState;
1023  }
1030  public function ‪getRenderingOptions(): array
1031  {
1032  return $this->formDefinition->getRenderingOptions();
1033  }
1034 
1041  public function ‪getRendererClassName(): string
1042  {
1043  return $this->formDefinition->getRendererClassName();
1044  }
1051  public function ‪getLabel(): string
1052  {
1053  return $this->formDefinition->getLabel();
1054  }
1061  public function ‪getTemplateName(): string
1062  {
1063  return $this->formDefinition->getTemplateName();
1064  }
1071  public function ‪getFormDefinition(): ‪FormDefinition
1072  {
1073  return ‪$this->formDefinition;
1074  }
1081  public function ‪getCurrentSiteLanguage(): ?‪SiteLanguage
1082  {
1084  }
1085 
1095  {
1096  $this->currentSiteLanguage = ‪$currentSiteLanguage;
1097  }
1098 
1103  protected function ‪initializeCurrentSiteLanguage(): void
1104  {
1105  if (
1106  ‪$GLOBALS['TYPO3_REQUEST'] instanceof ServerRequestInterface
1107  && ‪$GLOBALS['TYPO3_REQUEST']->getAttribute('language') instanceof ‪SiteLanguage
1108  ) {
1109  $this->currentSiteLanguage = ‪$GLOBALS['TYPO3_REQUEST']->getAttribute('language');
1110  } else {
1111  $pageId = 0;
1112  $languageId = (int)GeneralUtility::makeInstance(Context::class)->getPropertyFromAspect('language', 'id', 0);
1113 
1114  if ($this->‪getTypoScriptFrontendController() !== null) {
1115  $pageId = $this->‪getTypoScriptFrontendController()->id;
1116  }
1117 
1118  $fakeSiteConfiguration = [
1119  'languages' => [
1120  [
1121  'languageId' => $languageId,
1122  'title' => 'Dummy',
1123  'navigationTitle' => '',
1124  'typo3Language' => '',
1125  'flag' => '',
1126  'locale' => '',
1127  'iso-639-1' => '',
1128  'hreflang' => '',
1129  'direction' => '',
1130  ],
1131  ],
1132  ];
1133 
1134  $this->currentSiteLanguage = GeneralUtility::makeInstance(Site::class, 'form-dummy', $pageId, $fakeSiteConfiguration)
1135  ->getLanguageById($languageId);
1136  }
1137  }
1144  public function ‪getCurrentFinisher(): ?‪FinisherInterface
1145  {
1147  }
1148 
1152  protected function ‪getConditionResolver(): ‪Resolver
1153  {
1154  $formValues = array_replace_recursive(
1155  $this->‪getFormState()->getFormValues(),
1156  $this->‪getRequest()->getArguments()
1157  );
1158  $page = $this->‪getCurrentPage() ?? $this->‪getFormDefinition()->‪getPageByIndex(0);
1159 
1160  $finisherIdentifier = '';
1161  if ($this->‪getCurrentFinisher() !== null) {
1162  if (method_exists($this->‪getCurrentFinisher(), 'getFinisherIdentifier')) {
1163  $finisherIdentifier = $this->‪getCurrentFinisher()->getFinisherIdentifier();
1164  } else {
1165  $finisherIdentifier = (new \ReflectionClass($this->‪getCurrentFinisher()))->getShortName();
1166  $finisherIdentifier = preg_replace('/Finisher$/', '', $finisherIdentifier);
1167  }
1168  }
1169 
1170  $contentObjectData = [];
1171  if ($this->configurationManager->getContentObject() instanceof ContentObjectRenderer) {
1172  $contentObjectData = $this->configurationManager->getContentObject()->data;
1173  }
1174 
1175  return GeneralUtility::makeInstance(
1176  Resolver::class,
1177  'form',
1178  [
1179  'formRuntime' => $this,
1180  'formValues' => $formValues,
1181  'stepIdentifier' => $page->‪getIdentifier(),
1182  'stepType' => $page->‪getType(),
1183  'finisherIdentifier' => $finisherIdentifier,
1184  'contentObject' => $contentObjectData,
1185  ],
1186  ‪$GLOBALS['TYPO3_REQUEST'] ?? GeneralUtility::makeInstance(ServerRequest::class)
1187  );
1188  }
1189 
1194  {
1195  return $this->‪getTypoScriptFrontendController()->fe_user;
1196  }
1197 
1202  {
1203  return ‪$GLOBALS['TSFE'] ?? null;
1204  }
1205 }
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\isAfterLastPage
‪bool isAfterLastPage()
Definition: FormRuntime.php:489
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\getPreviousPage
‪Page null getPreviousPage()
Definition: FormRuntime.php:805
‪TYPO3\CMS\Core\Http\ApplicationType\fromRequest
‪static static fromRequest(ServerRequestInterface $request)
Definition: ApplicationType.php:62
‪TYPO3\CMS\Form\Domain\Model\FormElements\AbstractSection\getElementsRecursively
‪FormElementInterface[] getElementsRecursively()
Definition: AbstractSection.php:76
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime
Definition: FormRuntime.php:109
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\overrideCurrentPage
‪overrideCurrentPage(int $pageIndex)
Definition: FormRuntime.php:650
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\HONEYPOT_NAME_SESSION_IDENTIFIER
‪const HONEYPOT_NAME_SESSION_IDENTIFIER
Definition: FormRuntime.php:110
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\$formState
‪FormState $formState
Definition: FormRuntime.php:123
‪TYPO3\CMS\Form\Mvc\Validation\EmptyValidator
Definition: EmptyValidator.php:28
‪TYPO3\CMS\Extbase\Property\Exception
Definition: DuplicateObjectException.php:18
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\getRenderingOptions
‪array getRenderingOptions()
Definition: FormRuntime.php:1024
‪TYPO3\CMS\Form\Domain\Finishers\FinisherInterface
Definition: FinisherInterface.php:31
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\isFirstRequest
‪bool isFirstRequest()
Definition: FormRuntime.php:499
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\getTypoScriptFrontendController
‪TypoScriptFrontendController null getTypoScriptFrontendController()
Definition: FormRuntime.php:1195
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\isPostRequest
‪bool isPostRequest()
Definition: FormRuntime.php:507
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\getFrontendUser
‪FrontendUserAuthentication getFrontendUser()
Definition: FormRuntime.php:1187
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\setRequest
‪setRequest(Request $request)
Definition: FormRuntime.php:181
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\getHoneypotNameFromSession
‪string null getHoneypotNameFromSession(Page $page)
Definition: FormRuntime.php:419
‪TYPO3\CMS\Form\Domain\Runtime\Exception\PropertyMappingException
Definition: PropertyMappingException.php:27
‪TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder
Definition: UriBuilder.php:41
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\initializeFormSessionFromRequest
‪initializeFormSessionFromRequest()
Definition: FormRuntime.php:215
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\initialize
‪initialize()
Definition: FormRuntime.php:186
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\getControllerContext
‪ControllerContext getControllerContext()
Definition: FormRuntime.php:894
‪TYPO3\CMS\Core\Utility\Exception\MissingArrayPathException
Definition: MissingArrayPathException.php:27
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\$lastDisplayedPage
‪Page $lastDisplayedPage
Definition: FormRuntime.php:148
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\getCurrentSiteLanguage
‪SiteLanguage getCurrentSiteLanguage()
Definition: FormRuntime.php:1075
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\isFrontendUserAuthenticated
‪bool isFrontendUserAuthenticated()
Definition: FormRuntime.php:461
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\$formSession
‪FormSession null $formSession
Definition: FormRuntime.php:130
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\$container
‪ContainerInterface $container
Definition: FormRuntime.php:112
‪TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext
Definition: ControllerContext.php:30
‪TYPO3\CMS\Form\Domain\Renderer\RendererInterface
Definition: RendererInterface.php:35
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\initializeHoneypotFromRequest
‪initializeHoneypotFromRequest()
Definition: FormRuntime.php:336
‪TYPO3\CMS\Form\Domain\Runtime\FormState
Definition: FormState.php:36
‪TYPO3\CMS\Extbase\Mvc\Controller\Arguments
Definition: Arguments.php:27
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\canProcessFormSubmission
‪bool canProcessFormSubmission()
Definition: FormRuntime.php:776
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\getNextEnabledPage
‪Page null getNextEnabledPage()
Definition: FormRuntime.php:863
‪TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface
Definition: ConfigurationManagerInterface.php:28
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\$request
‪Request $request
Definition: FormRuntime.php:116
‪TYPO3\CMS\Extbase\Security\Exception\InvalidArgumentForHashGenerationException
Definition: InvalidArgumentForHashGenerationException.php:25
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\invokeFinishers
‪string invokeFinishers()
Definition: FormRuntime.php:697
‪TYPO3\CMS\Core\Error\Http\BadRequestException
Definition: BadRequestException.php:24
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\offsetSet
‪offsetSet($identifier, $value)
Definition: FormRuntime.php:972
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\getNextPage
‪Page null getNextPage()
Definition: FormRuntime.php:819
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\__construct
‪__construct(ContainerInterface $container, ObjectManagerInterface $objectManager, ConfigurationManagerInterface $configurationManager, HashService $hashService)
Definition: FormRuntime.php:162
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\getRendererClassName
‪string getRendererClassName()
Definition: FormRuntime.php:1035
‪TYPO3\CMS\Extbase\Security\Cryptography\HashService
Definition: HashService.php:31
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\getConditionResolver
‪Resolver getConditionResolver()
Definition: FormRuntime.php:1146
‪TYPO3\CMS\Core\Http\ApplicationType
Definition: ApplicationType.php:52
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\$currentFinisher
‪FinisherInterface $currentFinisher
Definition: FormRuntime.php:160
‪TYPO3\CMS\Core\Context\Context
Definition: Context.php:53
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\Lifecycle\AfterFormStateInitializedInterface
Definition: AfterFormStateInitializedInterface.php:29
‪TYPO3\CMS\Extbase\Error\Result
Definition: Result.php:24
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\processSubmittedFormValues
‪processSubmittedFormValues()
Definition: FormRuntime.php:533
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\getLabel
‪string getLabel()
Definition: FormRuntime.php:1045
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\getType
‪string getType()
Definition: FormRuntime.php:912
‪TYPO3\CMS\Extbase\Object\ObjectManagerInterface
Definition: ObjectManagerInterface.php:29
‪TYPO3\CMS\Form\Domain\Model\FormElements\Page
Definition: Page.php:44
‪TYPO3\CMS\Core\Site\Entity\Site
Definition: Site.php:42
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\initializeFormStateFromRequest
‪initializeFormStateFromRequest()
Definition: FormRuntime.php:231
‪TYPO3\CMS\Form\Domain\Model\Renderable\AbstractRenderable\getIndex
‪int getIndex()
Definition: AbstractRenderable.php:376
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\getPages
‪array Page[] getPages()
Definition: FormRuntime.php:1005
‪TYPO3\CMS\Core\Site\Entity\SiteLanguage
Definition: SiteLanguage.php:26
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\FormSession
Definition: FormSession.php:31
‪TYPO3\CMS\Form\Domain\Runtime
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\getElementValue
‪mixed getElementValue(string $identifier)
Definition: FormRuntime.php:993
‪TYPO3\CMS\Extbase\Mvc\Request\getMethod
‪getMethod()
Definition: Request.php:609
‪TYPO3\CMS\Form\Domain\Model\Renderable\AbstractRenderable\getIdentifier
‪string getIdentifier()
Definition: AbstractRenderable.php:107
‪TYPO3\CMS\Core\Utility\ArrayUtility\getValueByPath
‪static mixed getValueByPath(array $array, $path, $delimiter='/')
Definition: ArrayUtility.php:180
‪TYPO3\CMS\Form\Exception
Definition: Exception.php:25
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\getFormState
‪FormState null getFormState()
Definition: FormRuntime.php:1014
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\triggerAfterFormStateInitialized
‪triggerAfterFormStateInitialized()
Definition: FormRuntime.php:249
‪TYPO3\CMS\Core\Http\Response
Definition: Response.php:30
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\initializeCurrentPageFromRequest
‪initializeCurrentPageFromRequest()
Definition: FormRuntime.php:262
‪TYPO3\CMS\Form\Domain\Model\FormElements\FormElementInterface
Definition: FormElementInterface.php:40
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\getCurrentPage
‪Page null getCurrentPage()
Definition: FormRuntime.php:795
‪TYPO3\CMS\Form\Domain\Model\Renderable\RootRenderableInterface
Definition: RootRenderableInterface.php:31
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\$response
‪ResponseInterface $response
Definition: FormRuntime.php:117
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\setCurrentSiteLanguage
‪setCurrentSiteLanguage(SiteLanguage $currentSiteLanguage)
Definition: FormRuntime.php:1088
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\setFormDefinition
‪setFormDefinition(FormDefinition $formDefinition)
Definition: FormRuntime.php:176
‪$validator
‪if(isset($args['d'])) $validator
Definition: validateRstFiles.php:218
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\getRequest
‪Request getRequest()
Definition: FormRuntime.php:749
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\getCurrentFinisher
‪FinisherInterface null getCurrentFinisher()
Definition: FormRuntime.php:1138
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\processVariants
‪processVariants()
Definition: FormRuntime.php:467
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\$currentPage
‪Page null $currentPage
Definition: FormRuntime.php:141
‪TYPO3\CMS\Core\Http\ServerRequest
Definition: ServerRequest.php:37
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\setHoneypotNameInSession
‪setHoneypotNameInSession(Page $page, string $honeypotName)
Definition: FormRuntime.php:439
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\renderHoneypot
‪renderHoneypot()
Definition: FormRuntime.php:367
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\$objectManager
‪ObjectManagerInterface $objectManager
Definition: FormRuntime.php:114
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\isRenderedCached
‪bool isRenderedCached()
Definition: FormRuntime.php:521
‪TYPO3\CMS\Extbase\Security\Exception\InvalidHashException
Definition: InvalidHashException.php:25
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\getResponse
‪ResponseInterface getResponse()
Definition: FormRuntime.php:762
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\getTemplateName
‪string getTemplateName()
Definition: FormRuntime.php:1055
‪TYPO3\CMS\Form\Domain\Finishers\FinisherContext
Definition: FinisherContext.php:38
‪$output
‪$output
Definition: annotationChecker.php:121
‪TYPO3\CMS\Form\Domain\Model\FormDefinition
Definition: FormDefinition.php:226
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\$formDefinition
‪FormDefinition $formDefinition
Definition: FormRuntime.php:115
‪TYPO3\CMS\Form\Domain\Model\Renderable\AbstractRenderable\getType
‪string getType()
Definition: AbstractRenderable.php:97
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\offsetExists
‪bool offsetExists($identifier)
Definition: FormRuntime.php:923
‪TYPO3\CMS\Form\Domain\Model\Renderable\VariableRenderableInterface
Definition: VariableRenderableInterface.php:29
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
Definition: TypoScriptFrontendController.php:104
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\getFormSession
‪FormSession null getFormSession()
Definition: FormRuntime.php:785
‪TYPO3\CMS\Core\ExpressionLanguage\Resolver
Definition: Resolver.php:28
‪TYPO3\CMS\Core\Utility\ArrayUtility
Definition: ArrayUtility.php:24
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\getFormDefinition
‪FormDefinition getFormDefinition()
Definition: FormRuntime.php:1065
‪TYPO3\CMS\Core\Utility\ArrayUtility\assertAllArrayKeysAreValid
‪static assertAllArrayKeysAreValid(array $arrayToTest, array $allowedArrayKeys)
Definition: ArrayUtility.php:33
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\initializeCurrentSiteLanguage
‪initializeCurrentSiteLanguage()
Definition: FormRuntime.php:1097
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\mapAndValidatePage
‪Result mapAndValidatePage(Page $page)
Definition: FormRuntime.php:557
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\$hashService
‪HashService $hashService
Definition: FormRuntime.php:118
‪TYPO3\CMS\Frontend\Authentication\FrontendUserAuthentication\setKey
‪setKey($type, $key, $data)
Definition: FrontendUserAuthentication.php:462
‪TYPO3\CMS\Form\Domain\Exception\RenderingException
Definition: RenderingException.php:29
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\userWentBackToPreviousStep
‪bool userWentBackToPreviousStep()
Definition: FormRuntime.php:547
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\offsetGet
‪mixed offsetGet($identifier)
Definition: FormRuntime.php:954
‪TYPO3\CMS\Frontend\Authentication\FrontendUserAuthentication
Definition: FrontendUserAuthentication.php:32
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\$currentSiteLanguage
‪SiteLanguage $currentSiteLanguage
Definition: FormRuntime.php:154
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\getIdentifier
‪string getIdentifier()
Definition: FormRuntime.php:736
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\$configurationManager
‪ConfigurationManagerInterface $configurationManager
Definition: FormRuntime.php:119
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:50
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\getPreviousEnabledPage
‪Page null getPreviousEnabledPage()
Definition: FormRuntime.php:834
‪TYPO3\CMS\Form\Domain\Model\FormDefinition\getPageByIndex
‪Page getPageByIndex(int $index)
Definition: FormDefinition.php:481
‪TYPO3\CMS\Extbase\Mvc\Request
Definition: Request.php:39
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\offsetUnset
‪offsetUnset($identifier)
Definition: FormRuntime.php:982
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\render
‪string null render()
Definition: FormRuntime.php:661
‪TYPO3\CMS\Frontend\Authentication\FrontendUserAuthentication\getKey
‪mixed getKey($type, $key)
Definition: FrontendUserAuthentication.php:434