‪TYPO3CMS  ‪main
ActionControllerArgumentTest.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 
19 
20 use PHPUnit\Framework\Attributes\DataProvider;
21 use PHPUnit\Framework\Attributes\Test;
22 use Psr\Http\Message\ResponseInterface;
34 use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
38 
39 final class ‪ActionControllerArgumentTest extends FunctionalTestCase
40 {
41  private string ‪$pluginName = 'Pi1';
42  private string ‪$extensionName = 'ActionControllerArgumentTest';
43  private string ‪$pluginNamespacePrefix = 'tx_actioncontrollerargumenttest_pi1';
44 
45  protected array ‪$testExtensionsToLoad = [
46  'typo3/sysext/extbase/Tests/Functional/Mvc/Controller/Fixture/Extension/action_controller_argument_test',
47  ];
48 
50  {
51  return [
52  // regular models
53  'preset model' => [
54  'inputPresetModel',
55  ['preset' => (new ‪Model())->setValue('preset')],
56  'validateModel',
57  [
58  'form/model/value' => 'preset',
59  'validationResults/model' => [[]],
60  ],
61  ],
62  'preset DTO' => [
63  'inputPresetDto',
64  ['preset' => (new ‪ModelDto())->setValue('preset')],
65  'validateDto',
66  [
67  'form/dto/value' => 'preset',
68  'validationResults/dto' => [[]],
69  ],
70  ],
71  ];
72  }
73 
77  #[DataProvider('validationErrorReturnsToForwardedPreviousActionDataProvider')]
78  #[Test]
79  public function ‪validationErrorReturnsToForwardedPreviousAction(string $forwardTargetAction, array $forwardTargetArguments, string $validateAction, array $expectations): void
80  {
81  $inputRequest = $this->‪buildRequest('forward');
82 
83  // trigger action to forward to some `input*` action
84  $controller = $this->‪buildController();
85  $controller->declareForwardTargetAction($forwardTargetAction);
86  $controller->declareForwardTargetArguments($forwardTargetArguments);
87 
88  $inputResponse = $this->‪dispatch($controller, $inputRequest);
89 
90  $body = $inputResponse->getBody();
91  $body->rewind();
92  $inputDocument = $this->‪createDocument($body->getContents());
93  $parsedInputData = $this->‪parseDataFromResponseDocument($inputDocument);
94  self::assertNotEmpty($parsedInputData['form'] ?? null);
95  unset($inputRequest, $controller);
96 
97  $validateRequest = $this->‪buildRequest($validateAction, $parsedInputData['form']);
98 
99  // trigger `validate*` action with generated arguments from FormViewHelper (see template)
100  $controller = $this->‪buildController();
101 
102  // dispatch request to `validate*` action
103  $validateResponse = $this->‪dispatch($controller, $validateRequest);
104  $body = $validateResponse->getBody();
105  $body->rewind();
106  $validateDocument = $this->‪createDocument($body->getContents());
107  $parsedValidateData = $this->‪parseDataFromResponseDocument($validateDocument);
108  foreach ($expectations ?? [] as $bodyPath => $bodyValue) {
109  self::assertSame($bodyValue, ‪ArrayUtility::getValueByPath($parsedValidateData, $bodyPath));
110  }
111  }
112 
113  private function ‪dispatch(‪ArgumentTestController $controller, ‪RequestInterface $request): ResponseInterface
114  {
115  $isDispatched = false;
116  while (!$isDispatched) {
117  $response = $controller->‪processRequest($request);
118  if ($response instanceof ‪ForwardResponse) {
120  $controller = $this->‪buildController();
121  return $controller->‪processRequest($request);
122  }
123  $isDispatched = true;
124  }
125  return $response;
126  }
127 
132  private function ‪parseDataFromResponseDocument(\DOMDocument $document): array
133  {
134  $results = [];
135  $xpath = new \DOMXPath($document);
136 
137  $elements = $xpath->query('//div[@id="validationResults"]');
138  if ($elements->count() !== 0) {
139  $results['validationResults'] = json_decode(
140  trim($elements->item(0)->textContent),
141  true
142  );
143  }
144 
145  $elements = $xpath->query('//input[@type="text" or @type="hidden"]');
146  foreach ($elements as $element) {
147  if (!$element instanceof \DOMElement) {
148  continue;
149  }
150  $results['form'][$element->getAttribute('name')] = $element->getAttribute('value');
151  }
152  if (!empty($results['form'])) {
153  $results['form'] = $this->‪inflateFormValues($results['form']);
154  }
155  return $results;
156  }
157 
162  private function ‪inflateFormValues(array $formValues): array
163  {
164  $inflatedFormValues = [];
165  $normalizedFormPaths = array_map(
166  function (string $formName): string {
167  $formName = substr($formName, strlen($this->pluginNamespacePrefix));
168  $formName = str_replace('][', '/', trim($formName, '[]'));
169  return $formName;
170  },
171  array_keys($formValues)
172  );
173  $normalizedFormValues = array_combine($normalizedFormPaths, $formValues);
174  foreach ($normalizedFormValues as $formPath => $formValue) {
175  $inflatedFormValues = ‪ArrayUtility::setValueByPath($inflatedFormValues, $formPath, $formValue, '/');
176  }
177  return $inflatedFormValues;
178  }
179 
180  private function ‪createDocument(string $content): \DOMDocument
181  {
182  $document = new \DOMDocument();
183  $document->loadHTML(
184  $content,
185  LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD
186  | LIBXML_NOBLANKS | LIBXML_NOERROR | LIBXML_NONET | LIBXML_NOWARNING
187  );
188  $document->preserveWhiteSpace = false;
189  return $document;
190  }
191 
192  private function ‪buildRequest(string $actionName, array $arguments = null): ‪Request
193  {
194  $frontendTypoScript = new ‪FrontendTypoScript(new ‪RootNode(), [], [], []);
195  $frontendTypoScript->setSetupArray([]);
196  $serverRequest = (new ‪ServerRequest())
197  ->withAttribute('extbase', new ‪ExtbaseRequestParameters())
198  ->withAttribute('applicationType', ‪SystemEnvironmentBuilder::REQUESTTYPE_FE)
199  ->withAttribute('frontend.typoscript', $frontendTypoScript);
200  $request = new ‪Request($serverRequest);
201  $request = $request->withPluginName($this->pluginName);
202  $request = $request->withControllerExtensionName($this->extensionName);
203  $request = $request->withControllerName('ArgumentTest');
204  $request = $request->withFormat('html');
205  $request = $request->withControllerActionName($actionName);
206  $request = $request->withAttribute('currentContentObject', $this->get(ContentObjectRenderer::class));
207  if ($arguments !== null) {
208  $request = $request->withArguments($arguments);
209  }
210  return $request;
211  }
212 
214  {
215  return $this->get(ArgumentTestController::class);
216  }
217 }
‪TYPO3Tests\ActionControllerArgumentTest\Controller\ArgumentTestController
Definition: ArgumentTestController.php:31
‪TYPO3\CMS\Extbase\Mvc\Dispatcher
Definition: Dispatcher.php:36
‪TYPO3\CMS\Extbase\Tests\Functional\Mvc\Controller
Definition: ActionControllerArgumentTest.php:18
‪TYPO3\CMS\Extbase\Tests\Functional\Mvc\Controller\ActionControllerArgumentTest
Definition: ActionControllerArgumentTest.php:40
‪TYPO3\CMS\Core\Core\SystemEnvironmentBuilder
Definition: SystemEnvironmentBuilder.php:41
‪TYPO3\CMS\Extbase\Tests\Functional\Mvc\Controller\ActionControllerArgumentTest\buildRequest
‪buildRequest(string $actionName, array $arguments=null)
Definition: ActionControllerArgumentTest.php:192
‪TYPO3\CMS\Extbase\Tests\Functional\Mvc\Controller\ActionControllerArgumentTest\parseDataFromResponseDocument
‪parseDataFromResponseDocument(\DOMDocument $document)
Definition: ActionControllerArgumentTest.php:132
‪TYPO3\CMS\Extbase\Tests\Functional\Mvc\Controller\ActionControllerArgumentTest\$pluginName
‪string $pluginName
Definition: ActionControllerArgumentTest.php:41
‪TYPO3Tests\ActionControllerArgumentTest\Domain\Model\ModelDto
Definition: ModelDto.php:24
‪TYPO3\CMS\Extbase\Tests\Functional\Mvc\Controller\ActionControllerArgumentTest\validationErrorReturnsToForwardedPreviousActionDataProvider
‪static validationErrorReturnsToForwardedPreviousActionDataProvider()
Definition: ActionControllerArgumentTest.php:49
‪TYPO3\CMS\Extbase\Http\ForwardResponse
Definition: ForwardResponse.php:24
‪TYPO3\CMS\Extbase\Mvc\Controller\ActionController\processRequest
‪processRequest(RequestInterface $request)
Definition: ActionController.php:333
‪TYPO3\CMS\Extbase\Mvc\Dispatcher\buildRequestFromCurrentRequestAndForwardResponse
‪static buildRequestFromCurrentRequestAndForwardResponse(RequestInterface $currentRequest, ForwardResponse $forwardResponse)
Definition: Dispatcher.php:108
‪TYPO3\CMS\Extbase\Tests\Functional\Mvc\Controller\ActionControllerArgumentTest\$pluginNamespacePrefix
‪string $pluginNamespacePrefix
Definition: ActionControllerArgumentTest.php:43
‪TYPO3\CMS\Core\Utility\ArrayUtility\getValueByPath
‪static getValueByPath(array $array, array|string $path, string $delimiter='/')
Definition: ArrayUtility.php:176
‪TYPO3\CMS\Extbase\Tests\Functional\Mvc\Controller\ActionControllerArgumentTest\createDocument
‪createDocument(string $content)
Definition: ActionControllerArgumentTest.php:180
‪TYPO3\CMS\Extbase\Tests\Functional\Mvc\Controller\ActionControllerArgumentTest\inflateFormValues
‪inflateFormValues(array $formValues)
Definition: ActionControllerArgumentTest.php:162
‪TYPO3\CMS\Core\Http\ServerRequest
Definition: ServerRequest.php:39
‪TYPO3\CMS\Extbase\Tests\Functional\Mvc\Controller\ActionControllerArgumentTest\$testExtensionsToLoad
‪array $testExtensionsToLoad
Definition: ActionControllerArgumentTest.php:45
‪TYPO3\CMS\Extbase\Tests\Functional\Mvc\Controller\ActionControllerArgumentTest\validationErrorReturnsToForwardedPreviousAction
‪validationErrorReturnsToForwardedPreviousAction(string $forwardTargetAction, array $forwardTargetArguments, string $validateAction, array $expectations)
Definition: ActionControllerArgumentTest.php:79
‪TYPO3\CMS\Extbase\Mvc\RequestInterface
Definition: RequestInterface.php:24
‪TYPO3\CMS\Core\Utility\ArrayUtility
Definition: ArrayUtility.php:26
‪TYPO3\CMS\Core\TypoScript\AST\Node\RootNode
Definition: RootNode.php:26
‪TYPO3\CMS\Core\Utility\ArrayUtility\setValueByPath
‪static array setValueByPath(array $array, string|array|\ArrayAccess $path, mixed $value, string $delimiter='/')
Definition: ArrayUtility.php:261
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
Definition: ContentObjectRenderer.php:102
‪TYPO3\CMS\Extbase\Tests\Functional\Mvc\Controller\ActionControllerArgumentTest\$extensionName
‪string $extensionName
Definition: ActionControllerArgumentTest.php:42
‪TYPO3Tests\ActionControllerArgumentTest\Domain\Model\Model
Definition: Model.php:26
‪TYPO3\CMS\Extbase\Mvc\ExtbaseRequestParameters
Definition: ExtbaseRequestParameters.php:35
‪TYPO3\CMS\Core\TypoScript\FrontendTypoScript
Definition: FrontendTypoScript.php:30
‪TYPO3\CMS\Core\Core\SystemEnvironmentBuilder\REQUESTTYPE_FE
‪const REQUESTTYPE_FE
Definition: SystemEnvironmentBuilder.php:43
‪TYPO3\CMS\Extbase\Tests\Functional\Mvc\Controller\ActionControllerArgumentTest\buildController
‪buildController()
Definition: ActionControllerArgumentTest.php:213
‪TYPO3\CMS\Extbase\Mvc\Request
Definition: Request.php:35
‪TYPO3\CMS\Extbase\Tests\Functional\Mvc\Controller\ActionControllerArgumentTest\dispatch
‪dispatch(ArgumentTestController $controller, RequestInterface $request)
Definition: ActionControllerArgumentTest.php:113