a7d854be98e02e6a07a9efe4e1f75fac6e940f2a
[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 TYPO3\CMS\Core\Utility\ArrayUtility;
18
19 /**
20 * Class to hold all the information about an AJAX call and send
21 * the right headers for the request type
22 */
23 class AjaxRequestHandler {
24
25 /**
26 * @var string|NULL
27 */
28 protected $ajaxId = NULL;
29
30 /**
31 * @var string|NULL
32 */
33 protected $errorMessage = NULL;
34
35 /**
36 * @var bool
37 */
38 protected $isError = FALSE;
39
40 /**
41 * @var array
42 */
43 protected $content = array();
44
45 /**
46 * @var string
47 */
48 protected $contentFormat = 'plain';
49
50 /**
51 * @var string
52 */
53 protected $javascriptCallbackWrap = '
54 <script type="text/javascript">
55 /*<![CDATA[*/
56 response = |;
57 /*]]>*/
58 </script>
59 ';
60
61 /**
62 * Sets the ID for the AJAX call
63 *
64 * @param string $ajaxId The AJAX id
65 */
66 public function __construct($ajaxId) {
67 $this->ajaxId = $ajaxId;
68 }
69
70 /**
71 * Returns the ID for the AJAX call
72 *
73 * @return string The AJAX id
74 */
75 public function getAjaxID() {
76 return $this->ajaxId;
77 }
78
79 /**
80 * Overwrites the existing content with the data supplied
81 *
82 * @param array $content The new content
83 * @return mixed The old content as array; if the new content was not an array, FALSE is returned
84 */
85 public function setContent($content) {
86 $oldcontent = FALSE;
87 if (is_array($content)) {
88 $oldcontent = $this->content;
89 $this->content = $content;
90 }
91 return $oldcontent;
92 }
93
94 /**
95 * Adds new content
96 *
97 * @param string $key The new content key where the content should be added in the content array
98 * @param string $content The new content to add
99 * @return mixed The old content; if the old content didn't exist before, FALSE is returned
100 */
101 public function addContent($key, $content) {
102 $oldcontent = FALSE;
103 if (array_key_exists($key, $this->content)) {
104 $oldcontent = $this->content[$key];
105 }
106 if (!isset($content) || empty($content)) {
107 unset($this->content[$key]);
108 } elseif (!isset($key) || empty($key)) {
109 $this->content[] = $content;
110 } else {
111 $this->content[$key] = $content;
112 }
113 return $oldcontent;
114 }
115
116 /**
117 * Returns the content for the ajax call
118 *
119 * @return mixed The content for a specific key or the whole content
120 */
121 public function getContent($key = '') {
122 return $key && array_key_exists($key, $this->content) ? $this->content[$key] : $this->content;
123 }
124
125 /**
126 * Sets the content format for the ajax call
127 *
128 * @param string $format Can be one of 'plain' (default), 'xml', 'json', 'javascript', 'jsonbody' or 'jsonhead'
129 * @return void
130 */
131 public function setContentFormat($format) {
132 if (ArrayUtility::inArray(array('plain', 'xml', 'json', 'jsonhead', 'jsonbody', 'javascript'), $format)) {
133 $this->contentFormat = $format;
134 }
135 }
136
137 /**
138 * Specifies the wrap to be used if contentFormat is "javascript".
139 * The wrap used by default stores the results in a variable "response" and
140 * adds <script>-Tags around it.
141 *
142 * @param string $javascriptCallbackWrap The javascript callback wrap to be used
143 * @return void
144 */
145 public function setJavascriptCallbackWrap($javascriptCallbackWrap) {
146 $this->javascriptCallbackWrap = $javascriptCallbackWrap;
147 }
148
149 /**
150 * Sets an error message and the error flag
151 *
152 * @param string $errorMsg The error message
153 * @return void
154 */
155 public function setError($errorMsg = '') {
156 $this->errorMessage = $errorMsg;
157 $this->isError = TRUE;
158 }
159
160 /**
161 * Checks whether an error occurred during the execution or not
162 *
163 * @return bool Whether this AJAX call had errors
164 */
165 public function isError() {
166 return $this->isError;
167 }
168
169 /**
170 * Renders the AJAX call based on the $contentFormat variable and exits the request
171 *
172 * @return void
173 */
174 public function render() {
175 if ($this->isError) {
176 $this->renderAsError();
177 die;
178 }
179 switch ($this->contentFormat) {
180 case 'jsonhead':
181 case 'jsonbody':
182 case 'json':
183 $this->renderAsJSON();
184 break;
185 case 'javascript':
186 $this->renderAsJavascript();
187 break;
188 case 'xml':
189 $this->renderAsXML();
190 break;
191 default:
192 $this->renderAsPlain();
193 }
194 die;
195 }
196
197 /**
198 * Renders the AJAX call in XML error style to handle with JS
199 * the "responseXML" of the transport object will be filled with the error message then
200 *
201 * @return void
202 */
203 protected function renderAsError() {
204 header(\TYPO3\CMS\Core\Utility\HttpUtility::HTTP_STATUS_500 . ' (AJAX)');
205 header('Content-type: text/xml; charset=utf-8');
206 header('X-JSON: false');
207 die('<t3err>' . htmlspecialchars($this->errorMessage) . '</t3err>');
208 }
209
210 /**
211 * Renders the AJAX call with text/html headers
212 * the content will be available in the "responseText" value of the transport object
213 *
214 * @return void
215 */
216 protected function renderAsPlain() {
217 header('Content-type: text/html; charset=utf-8');
218 header('X-JSON: true');
219 echo implode('', $this->content);
220 }
221
222 /**
223 * Renders the AJAX call with text/xml headers
224 * the content will be available in the "responseXML" value of the transport object
225 *
226 * @return void
227 */
228 protected function renderAsXML() {
229 header('Content-type: text/xml; charset=utf-8');
230 header('X-JSON: true');
231 echo implode('', $this->content);
232 }
233
234 /**
235 * Renders the AJAX call with JSON evaluated headers
236 * note that you need to have requestHeaders: {Accept: 'application/json'},
237 * in your AJAX options of your AJAX request object in JS
238 *
239 * the content will be available
240 * - in the second parameter of the onSuccess / onComplete callback
241 * - and in the xhr.responseText as a string (except when contentFormat = 'jsonhead')
242 * you can evaluate this in JS with xhr.responseText.evalJSON();
243 *
244 * @return void
245 */
246 protected function renderAsJSON() {
247 $content = json_encode($this->content);
248 header('Content-type: application/json; charset=utf-8');
249 // Bring content in xhr.responseText except when in "json head only" mode
250 if ($this->contentFormat === 'jsonhead') {
251 header('X-JSON: ' . $content);
252 } else {
253 header('X-JSON: true');
254 echo $content;
255 }
256 }
257
258 /**
259 * Renders the AJAX call as inline JSON inside a script tag. This is useful
260 * when an iframe is used as the AJAX transport.
261 *
262 * @return void
263 */
264 protected function renderAsJavascript() {
265 $content = str_replace('|', json_encode($this->content), $this->javascriptCallbackWrap);
266 header('Content-type: text/html; charset=utf-8');
267 echo $content;
268 }
269
270 }