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