[TASK] Deprecate ArrayUtility::inArray()
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Http / AjaxRequestHandler.php
1 <?php
2 namespace TYPO3\CMS\Core\Http;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use Psr\Http\Message\ResponseInterface;
18 use TYPO3\CMS\Core\Utility\GeneralUtility;
19
20 /**
21 * Class to hold all the information about an AJAX call and send
22 * the right headers for the request type
23 * @deprecated since TYPO3 v8, will be removed in TYPO3 v9
24 */
25 class AjaxRequestHandler
26 {
27 /**
28 * @var string|NULL
29 */
30 protected $ajaxId = null;
31
32 /**
33 * @var string|NULL
34 */
35 protected $errorMessage = null;
36
37 /**
38 * @var bool
39 */
40 protected $isError = false;
41
42 /**
43 * @var array
44 */
45 protected $content = [];
46
47 /**
48 * @var string
49 */
50 protected $contentFormat = 'plain';
51
52 /**
53 * @var string
54 */
55 protected $javascriptCallbackWrap = '
56 <script type="text/javascript">
57 /*<![CDATA[*/
58 response = |;
59 /*]]>*/
60 </script>
61 ';
62
63 /**
64 * Sets the ID for the AJAX call
65 *
66 * @param string $ajaxId The AJAX id
67 */
68 public function __construct($ajaxId)
69 {
70 $this->ajaxId = $ajaxId;
71 }
72
73 /**
74 * Returns the ID for the AJAX call
75 *
76 * @return string The AJAX id
77 */
78 public function getAjaxID()
79 {
80 return $this->ajaxId;
81 }
82
83 /**
84 * Overwrites the existing content with the data supplied
85 *
86 * @param array $content The new content
87 * @return mixed The old content as array; if the new content was not an array, FALSE is returned
88 */
89 public function setContent($content)
90 {
91 $oldcontent = false;
92 if (is_array($content)) {
93 $oldcontent = $this->content;
94 $this->content = $content;
95 }
96 return $oldcontent;
97 }
98
99 /**
100 * Adds new content
101 *
102 * @param string $key The new content key where the content should be added in the content array
103 * @param string $content The new content to add
104 * @return mixed The old content; if the old content didn't exist before, FALSE is returned
105 */
106 public function addContent($key, $content)
107 {
108 $oldcontent = false;
109 if (array_key_exists($key, $this->content)) {
110 $oldcontent = $this->content[$key];
111 }
112 if (!isset($content) || empty($content)) {
113 unset($this->content[$key]);
114 } elseif (!isset($key) || empty($key)) {
115 $this->content[] = $content;
116 } else {
117 $this->content[$key] = $content;
118 }
119 return $oldcontent;
120 }
121
122 /**
123 * Returns the content for the ajax call
124 *
125 * @return mixed The content for a specific key or the whole content
126 */
127 public function getContent($key = '')
128 {
129 return $key && array_key_exists($key, $this->content) ? $this->content[$key] : $this->content;
130 }
131
132 /**
133 * Sets the content format for the ajax call
134 *
135 * @param string $format Can be one of 'plain' (default), 'xml', 'json', 'javascript', 'jsonbody' or 'jsonhead'
136 * @return void
137 */
138 public function setContentFormat($format)
139 {
140 if (in_array($format, ['plain', 'xml', 'json', 'jsonhead', 'jsonbody', 'javascript'], true)) {
141 $this->contentFormat = $format;
142 }
143 }
144
145 /**
146 * Specifies the wrap to be used if contentFormat is "javascript".
147 * The wrap used by default stores the results in a variable "response" and
148 * adds <script>-Tags around it.
149 *
150 * @param string $javascriptCallbackWrap The javascript callback wrap to be used
151 * @return void
152 */
153 public function setJavascriptCallbackWrap($javascriptCallbackWrap)
154 {
155 $this->javascriptCallbackWrap = $javascriptCallbackWrap;
156 }
157
158 /**
159 * Sets an error message and the error flag
160 *
161 * @param string $errorMsg The error message
162 * @return void
163 */
164 public function setError($errorMsg = '')
165 {
166 $this->errorMessage = $errorMsg;
167 $this->isError = true;
168 }
169
170 /**
171 * Checks whether an error occurred during the execution or not
172 *
173 * @return bool Whether this AJAX call had errors
174 */
175 public function isError()
176 {
177 return $this->isError;
178 }
179
180 /**
181 * Renders the AJAX call based on the $contentFormat variable and exits the request
182 *
183 * @return ResponseInterface|NULL
184 */
185 public function render()
186 {
187 if ($this->isError) {
188 return $this->renderAsError();
189 }
190 switch ($this->contentFormat) {
191 case 'jsonhead':
192 case 'jsonbody':
193 case 'json':
194 return $this->renderAsJSON();
195 break;
196 case 'javascript':
197 return $this->renderAsJavascript();
198 break;
199 case 'xml':
200 return $this->renderAsXML();
201 break;
202 default:
203 return $this->renderAsPlain();
204 }
205 }
206
207 /**
208 * Renders the AJAX call in XML error style to handle with JS
209 * the "responseXML" of the transport object will be filled with the error message then
210 *
211 * @return ResponseInterface
212 */
213 protected function renderAsError()
214 {
215 /** @var Response $response */
216 $response = GeneralUtility::makeInstance(Response::class);
217 $response = $response
218 ->withStatus(500, ' (AJAX)')
219 ->withHeader('Content-Type', 'text/xml; charset=utf-8')
220 ->withHeader('X-JSON', 'false');
221
222 $response->getBody()->write('<t3err>' . htmlspecialchars($this->errorMessage) . '</t3err>');
223 return $response;
224 }
225
226 /**
227 * Renders the AJAX call with text/html headers
228 * the content will be available in the "responseText" value of the transport object
229 *
230 * @return ResponseInterface
231 * @throws \InvalidArgumentException
232 */
233 protected function renderAsPlain()
234 {
235 /** @var Response $response */
236 $response = GeneralUtility::makeInstance(Response::class);
237 $response = $response
238 ->withHeader('Content-Type', 'text/html; charset=utf-8')
239 ->withHeader('X-JSON', 'true');
240
241 $response->getBody()->write(implode('', $this->content));
242 return $response;
243 }
244
245 /**
246 * Renders the AJAX call with text/xml headers
247 * the content will be available in the "responseXML" value of the transport object
248 *
249 * @return ResponseInterface
250 * @throws \InvalidArgumentException
251 */
252 protected function renderAsXML()
253 {
254 /** @var Response $response */
255 $response = GeneralUtility::makeInstance(Response::class);
256 $response = $response
257 ->withHeader('Content-Type', 'text/xml; charset=utf-8')
258 ->withHeader('X-JSON', 'true');
259
260 $response->getBody()->write(implode('', $this->content));
261 return $response;
262 }
263
264 /**
265 * Renders the AJAX call with JSON evaluated headers
266 * note that you need to have requestHeaders: {Accept: 'application/json'},
267 * in your AJAX options of your AJAX request object in JS
268 *
269 * the content will be available
270 * - in the second parameter of the onSuccess / onComplete callback
271 * - and in the xhr.responseText as a string (except when contentFormat = 'jsonhead')
272 * you can evaluate this in JS with xhr.responseText.evalJSON();
273 *
274 * @return ResponseInterface
275 * @throws \InvalidArgumentException
276 */
277 protected function renderAsJSON()
278 {
279 /** @var Response $response */
280 $response = GeneralUtility::makeInstance(Response::class);
281 $response = $response->withHeader('Content-Type', 'application/json; charset=utf-8');
282
283 $content = json_encode($this->content);
284 // Bring content in xhr.responseText except when in "json head only" mode
285 if ($this->contentFormat === 'jsonhead') {
286 $response = $response->withHeader('X-JSON', $content);
287 } else {
288 $response = $response->withHeader('X-JSON', 'true');
289 $response->getBody()->write($content);
290 }
291 return $response;
292 }
293
294 /**
295 * Renders the AJAX call as inline JSON inside a script tag. This is useful
296 * when an iframe is used as the AJAX transport.
297 *
298 * @return ResponseInterface
299 * @throws \InvalidArgumentException
300 */
301 protected function renderAsJavascript()
302 {
303 $response = GeneralUtility::makeInstance(Response::class);
304 $response = $response->withHeader('Content-Type', 'text/html; charset=utf-8');
305 $response->getBody()->write(str_replace('|', json_encode($this->content), $this->javascriptCallbackWrap));
306 return $response;
307 }
308 }