ResponseFactory::respond()   F
last analyzed

Complexity

Conditions 23
Paths 482

Size

Total Lines 71
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 34
CRAP Score 23.6176

Importance

Changes 0
Metric Value
cc 23
eloc 37
nc 482
nop 1
dl 0
loc 71
rs 0.7194
c 0
b 0
f 0
ccs 34
cts 38
cp 0.8947
crap 23.6176

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Elgg\Http;
4
5
use Elgg\Ajax\Service as AjaxService;
6
use Elgg\EventsService;
7
use Elgg\PluginHooksService;
8
use ElggEntity;
9
use InvalidArgumentException;
10
use InvalidParameterException;
11
use Symfony\Component\HttpFoundation\Cookie;
12
use Symfony\Component\HttpFoundation\RedirectResponse as SymfonyRedirectResponse;
13
use Symfony\Component\HttpFoundation\Response;
14
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
15
16
/**
17
 * WARNING: API IN FLUX. DO NOT USE DIRECTLY.
18
 *
19
 * @since 2.3
20
 * @access private
21
 */
22
class ResponseFactory {
23
24
	/**
25
	 * @var Request
26
	 */
27
	private $request;
28
29
	/**
30
	 * @var AjaxService
31
	 */
32
	private $ajax;
33
34
	/**
35
	 * @var PluginHooksService
36
	 */
37
	private $hooks;
38
39
	/**
40
	 * @var ResponseTransport
41
	 */
42
	private $transport;
43
44
	/**
45
	 * @var Response|bool
46
	 */
47
	private $response_sent = false;
48
49
	/**
50
	 * @var ResponseHeaderBag
51
	 */
52
	private $headers;
53
	
54
	/**
55
	 * @var EventsService
56
	 */
57
	private $events;
58
59
	/**
60
	 * Constructor
61
	 *
62
	 * @param Request            $request   HTTP request
63
	 * @param PluginHooksService $hooks     Plugin hooks service
64
	 * @param AjaxService        $ajax      AJAX service
65
	 * @param ResponseTransport  $transport Response transport
66
	 * @param EventsService      $events    Events service
67
	 */
68 284
	public function __construct(Request $request, PluginHooksService $hooks, AjaxService $ajax, ResponseTransport $transport, EventsService $events) {
69 284
		$this->request = $request;
70 284
		$this->hooks = $hooks;
71 284
		$this->ajax = $ajax;
72 284
		$this->transport = $transport;
73 284
		$this->events = $events;
74
		
75 284
		$this->headers = new ResponseHeaderBag();
76 284
	}
77
78
	/**
79
	 * Sets headers to apply to all responses being sent
80
	 *
81
	 * @param string $name    Header name
82
	 * @param string $value   Header value
83
	 * @param bool   $replace Replace existing headers
84
	 * @return void
85
	 */
86 35
	public function setHeader($name, $value, $replace = true) {
87 35
		$this->headers->set($name, $value, $replace);
88 35
	}
89
90
	/**
91
	 * Set a cookie, but allow plugins to customize it first.
92
	 *
93
	 * To customize all cookies, register for the 'init:cookie', 'all' event.
94
	 *
95
	 * @param \ElggCookie $cookie The cookie that is being set
96
	 * @return bool
97
	 */
98 2
	public function setCookie(\ElggCookie $cookie) {
99 2
		if (!$this->events->trigger('init:cookie', $cookie->name, $cookie)) {
0 ignored issues
show
Bug introduced by Jerôme Bakker
$cookie of type ElggCookie is incompatible with the type string expected by parameter $object of Elgg\EventsService::trigger(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

99
		if (!$this->events->trigger('init:cookie', $cookie->name, /** @scrutinizer ignore-type */ $cookie)) {
Loading history...
100
			return false;
101
		}
102
103 2
		$symfony_cookie = new Cookie(
104 2
			$cookie->name,
105 2
			$cookie->value,
106 2
			$cookie->expire,
107 2
			$cookie->path,
108 2
			$cookie->domain,
109 2
			$cookie->secure,
110 2
			$cookie->httpOnly
111
		);
112
113 2
		$this->headers->setCookie($symfony_cookie);
114 2
		return true;
115
	}
116
117
	/**
118
	 * Get headers set to apply to all responses
119
	 *
120
	 * @param bool $remove_existing Remove existing headers found in headers_list()
121
	 * @return ResponseHeaderBag
122
	 */
123 121
	public function getHeaders($remove_existing = true) {
124
		// Add headers that have already been set by underlying views
125
		// e.g. viewtype page shells set content-type headers
126 121
		$headers_list = headers_list();
127 121
		foreach ($headers_list as $header) {
128
			if (stripos($header, 'HTTP/1.1') !== false) {
129
				continue;
130
			}
131
132
			list($name, $value) = explode(':', $header, 2);
133
			$this->setHeader($name, ltrim($value), false);
134
			if ($remove_existing) {
135
				header_remove($name);
136
			}
137
		}
138
139 121
		return $this->headers;
140
	}
141
142
	/**
143
	 * Creates an HTTP response
144
	 *
145
	 * @param string  $content The response content
146
	 * @param integer $status  The response status code
147
	 * @param array   $headers An array of response headers
148
	 * @return Response
149
	 */
150 102
	public function prepareResponse($content = '', $status = 200, array $headers = []) {
151 102
		$header_bag = $this->getHeaders();
152 102
		$header_bag->add($headers);
153 102
		$response = new Response($content, $status, $header_bag->all());
154 102
		$response->prepare($this->request);
155 102
		return $response;
156
	}
157
158
	/**
159
	 * Creates a redirect response
160
	 *
161
	 * @param string  $url     URL to redirect to
162
	 * @param integer $status  The status code (302 by default)
163
	 * @param array   $headers An array of response headers (Location is always set to the given URL)
164
	 * @return SymfonyRedirectResponse
165
	 * @throws InvalidArgumentException
166
	 */
167 18
	public function prepareRedirectResponse($url, $status = 302, array $headers = []) {
168 18
		$header_bag = $this->getHeaders();
169 18
		$header_bag->add($headers);
170 18
		$response = new SymfonyRedirectResponse($url, $status, $header_bag->all());
171 17
		$response->prepare($this->request);
172 17
		return $response;
173
	}
174
175
	/**
176
	 * Send a response
177
	 *
178
	 * @param Response $response Response object
179
	 * @return Response|false
180
	 */
181 146
	public function send(Response $response) {
182
183 146
		if ($this->response_sent) {
184 35
			if ($this->response_sent !== $response) {
185 4
				_elgg_services()->logger->error('Unable to send the following response: ' . PHP_EOL
186 4
						. (string) $response . PHP_EOL
187 4
						. 'because another response has already been sent: ' . PHP_EOL
188 35
						. (string) $this->response_sent);
189
			}
190
		} else {
191 146
			if (!$this->events->triggerBefore('send', 'http_response', $response)) {
192
				return false;
193
			}
194
195 146
			$request = $this->request;
196 146
			$method = $request->getRealMethod() ? : 'GET';
197 146
			$path = $request->getElggPath();
198
199 146
			_elgg_services()->logger->notice("Responding to {$method} {$path}");
200 146
			if (!$this->transport->send($response)) {
201
				return false;
202
			}
203
204 146
			$this->events->triggerAfter('send', 'http_response', $response);
205 146
			$this->response_sent = $response;
206
		}
207
208 146
		return $this->response_sent;
0 ignored issues
show
Bug Best Practice introduced by Ismayil Khayredinov
The expression return $this->response_sent also could return the type true which is incompatible with the documented return type Symfony\Component\HttpFoundation\Response|false.
Loading history...
209
	}
210
211
	/**
212
	 * Returns a response that was sent to the client
213
	 *
214
	 * @return Response|false
215
	 */
216 138
	public function getSentResponse() {
217 138
		return $this->response_sent;
0 ignored issues
show
Bug Best Practice introduced by Ismayil Khayredinov
The expression return $this->response_sent also could return the type boolean which is incompatible with the documented return type Symfony\Component\HttpFoundation\Response|false.
Loading history...
218
	}
219
220
	/**
221
	 * Send HTTP response
222
	 *
223
	 * @param ResponseBuilder $response ResponseBuilder instance
224
	 *                                  An instance of an ErrorResponse, OkResponse or RedirectResponse
225
	 * @return Response
226
	 * @throws \InvalidParameterException
227
	 */
228 134
	public function respond(ResponseBuilder $response) {
229
230 134
		$response_type = $this->parseContext();
231 134
		$response = $this->hooks->trigger('response', $response_type, $response, $response);
232 134
		if (!$response instanceof ResponseBuilder) {
233
			throw new InvalidParameterException("Handlers for 'response','$response_type' plugin hook must "
234
			. "return an instanceof " . ResponseBuilder::class);
235
		}
236
237 134
		if ($response->isNotModified()) {
238
			return $this->send($this->prepareResponse('', ELGG_HTTP_NOT_MODIFIED));
239
		}
240
241 134
		$is_xhr = $this->request->isXmlHttpRequest();
242
243 134
		$is_action = false;
244 134
		if (0 === strpos($response_type, 'action:')) {
245 23
			$is_action = true;
246
		}
247
248 134
		if ($is_action && $response->getForwardURL() === null) {
0 ignored issues
show
introduced by Ismayil Khayredinov
The condition $response->getForwardURL() === null is always false.
Loading history...
249
			// actions must always set a redirect url
250
			$response->setForwardURL(REFERRER);
251
		}
252
253 134
		if ($response->getForwardURL() === REFERRER) {
0 ignored issues
show
introduced by Ismayil Khayredinov
The condition $response->getForwardURL() === Elgg\Http\REFERRER is always false.
Loading history...
254 19
			$response->setForwardURL($this->request->headers->get('Referer'));
255
		}
256
257 134
		if ($response->getForwardURL() !== null && !$is_xhr) {
258
			// non-xhr requests should issue a forward if redirect url is set
259
			// unless it's an error, in which case we serve an error page
260 18
			if ($this->isAction() || (!$response->isClientError() && !$response->isServerError())) {
261 13
				$response->setStatusCode(ELGG_HTTP_FOUND);
262
			}
263
		}
264
265 134
		if ($is_xhr && ($is_action || $this->ajax->isAjax2Request())) {
266 33
			if (!$this->ajax->isAjax2Request()) {
267
				// xhr actions using legacy ajax API should return 200 with wrapped data
268 6
				$response->setStatusCode(ELGG_HTTP_OK);
269
			}
270
271
			// Actions always respond with JSON on xhr calls
272 33
			$headers = $response->getHeaders();
273 33
			$headers['Content-Type'] = 'application/json; charset=UTF-8';
274 33
			$response->setHeaders($headers);
275
276 33
			if ($response->isOk()) {
277 26
				$response->setContent($this->wrapAjaxResponse($response->getContent(), $response->getForwardURL()));
278
			}
279
		}
280
281 134
		$content = $this->stringify($response->getContent());
282 134
		$status_code = $response->getStatusCode();
283 134
		$headers = $response->getHeaders();
284
285 134
		if ($response->isRedirection()) {
286 16
			$redirect_url = $response->getForwardURL();
287 16
			return $this->redirect($redirect_url, $status_code);
288
		}
289
290 121
		if ($this->ajax->isReady() && $response->isSuccessful()) {
291 20
			return $this->respondFromContent($content, $status_code, $headers);
292
		}
293
294 101
		if ($response->isClientError() || $response->isServerError() || $response instanceof ErrorResponse) {
295 20
			return $this->respondWithError($content, $status_code, $headers);
296
		}
297
298 81
		return $this->respondFromContent($content, $status_code, $headers);
299
	}
300
301
	/**
302
	 * Send error HTTP response
303
	 *
304
	 * @param string $error       Error message
305
	 * @param int    $status_code HTTP status code
306
	 * @param array  $headers     HTTP headers (will be discarded on AJAX requests)
307
	 * @return Response
308
	 * @throws \InvalidParameterException
309
	 */
310 20
	public function respondWithError($error, $status_code = ELGG_HTTP_BAD_REQUEST, array $headers = []) {
311 20
		if ($this->ajax->isReady()) {
312 7
			return $this->send($this->ajax->respondWithError($error, $status_code));
313
		}
314
315 13
		if ($this->isXhr()) {
316
			// xhr calls to non-actions (e.g. ajax/view or ajax/form) need to receive proper HTTP status code
317 5
			return $this->send($this->prepareResponse($error, $status_code, $headers));
318
		}
319
320 8
		$forward_url = $this->request->headers->get('Referer');
321
322 8
		if (!$this->isAction()) {
323
			$params = [
324 8
				'current_url' => current_page_url(),
325 8
				'forward_url' => $forward_url,
326
			];
327
			// For BC, let plugins serve their own error page
328
			// @see elgg_error_page_handler
329 8
			$forward_reason = (string) $status_code;
330
331 8
			$forward_url = $this->hooks->trigger('forward', $forward_reason, $params, $forward_url);
0 ignored issues
show
Unused Code introduced by Ismayil Khayredinov
The assignment to $forward_url is dead and can be removed.
Loading history...
332
333 8
			if ($this->response_sent) {
334
				// Response was sent from a forward hook
335
				return $this->response_sent;
0 ignored issues
show
Bug Best Practice introduced by Ismayil Khayredinov
The expression return $this->response_sent also could return the type true which is incompatible with the documented return type Symfony\Component\HttpFoundation\Response.
Loading history...
336
			}
337
338 8
			if (elgg_view_exists('resources/error')) {
339 7
				$params['type'] = $forward_reason;
340 7
				$params['params']['error'] = $error;
341 7
				$error_page = elgg_view_resource('error', $params);
342
			} else {
343 1
				$error_page = $error;
344
			}
345
346 8
			return $this->send($this->prepareResponse($error_page, $status_code));
0 ignored issues
show
Bug Best Practice introduced by Ismayil Khayredinov
The expression return $this->send($this...or_page, $status_code)) could also return false which is incompatible with the documented return type Symfony\Component\HttpFoundation\Response. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
347
		}
348
349
		$forward_url = elgg_normalize_url($forward_url);
350
		return $this->send($this->prepareRedirectResponse($forward_url));
351
	}
352
353
	/**
354
	 * Send OK response
355
	 *
356
	 * @param string $content     Response body
357
	 * @param int    $status_code HTTP status code
358
	 * @param array  $headers     HTTP headers (will be discarded for AJAX requests)
359
	 *
360
	 * @return Response|false
361
	 */
362 101
	public function respondFromContent($content = '', $status_code = ELGG_HTTP_OK, array $headers = []) {
363
364 101
		if ($this->ajax->isReady()) {
365 20
			$hook_type = $this->parseContext();
366
			// $this->ajax->setStatusCode($status_code);
367 20
			return $this->send($this->ajax->respondFromOutput($content, $hook_type));
368
		}
369
370 81
		return $this->send($this->prepareResponse($content, $status_code, $headers));
371
	}
372
373
	/**
374
	 * Wraps response content in an Ajax2 compatible format
375
	 *
376
	 * @param string $content     Response content
377
	 * @param string $forward_url Forward URL
378
	 * @return string
379
	 */
380 26
	public function wrapAjaxResponse($content = '', $forward_url = null) {
381
382 26
		if (!$this->ajax->isAjax2Request()) {
383 6
			return $this->wrapLegacyAjaxResponse($content, $forward_url);
384
		}
385
386 20
		$content = $this->stringify($content);
387
388 20
		if ($forward_url === REFERRER) {
0 ignored issues
show
introduced by Ismayil Khayredinov
The condition $forward_url === Elgg\Http\REFERRER is always false.
Loading history...
389
			$forward_url = $this->request->headers->get('Referer');
390
		}
391
392
		$params = [
393 20
			'value' => '',
394 20
			'current_url' => current_page_url(),
395 20
			'forward_url' => elgg_normalize_url($forward_url),
396
		];
397
398 20
		$params['value'] = $this->ajax->decodeJson($content);
399
400 20
		return $this->stringify($params);
401
	}
402
403
	/**
404
	 * Wraps content for compability with legacy Elgg ajax calls
405
	 *
406
	 * @param string $content     Response content
407
	 * @param string $forward_url Forward URL
408
	 * @return string
409
	 */
410 11
	public function wrapLegacyAjaxResponse($content = '', $forward_url = REFERRER) {
411
412 11
		$content = $this->stringify($content);
413
414 11
		if ($forward_url === REFERRER) {
415
			$forward_url = $this->request->headers->get('Referer');
416
		}
417
418
		// always pass the full structure to avoid boilerplate JS code.
419
		$params = [
420 11
			'output' => '',
421 11
			'status' => 0,
422
			'system_messages' => [
423
				'error' => [],
424
				'success' => []
425
			],
426 11
			'current_url' => current_page_url(),
427 11
			'forward_url' => elgg_normalize_url($forward_url),
428
		];
429
430 11
		$params['output'] = $this->ajax->decodeJson($content);
431
432
		// Grab any system messages so we can inject them via ajax too
433 11
		$system_messages = _elgg_services()->systemMessages->dumpRegister();
434
435 11
		if (isset($system_messages['success'])) {
436 2
			$params['system_messages']['success'] = $system_messages['success'];
437
		}
438
439 11
		if (isset($system_messages['error'])) {
440 3
			$params['system_messages']['error'] = $system_messages['error'];
441 3
			$params['status'] = -1;
442
		}
443
444 11
		$response_type = $this->parseContext();
445 11
		list($service, $name) = explode(':', $response_type);
446
		$context = [
447 11
			$service => $name,
448
		];
449 11
		$params = $this->hooks->trigger('output', 'ajax', $context, $params);
450
451 11
		return $this->stringify($params);
452
	}
453
454
	/**
455
	 * Prepares a redirect response
456
	 *
457
	 * @param string $forward_url Redirection URL
458
	 * @param mixed  $status_code HTTP status code or forward reason
459
	 * @return SymfonyRedirectResponse
460
	 * @throws InvalidParameterException
461
	 */
462 30
	public function redirect($forward_url = REFERRER, $status_code = ELGG_HTTP_FOUND) {
463
464 30
		if ($forward_url === REFERRER) {
465 3
			$forward_url = $this->request->headers->get('Referer');
466
		}
467
468 30
		$forward_url = elgg_normalize_url($forward_url);
469
470
		// allow plugins to rewrite redirection URL
471 30
		$current_page = current_page_url();
472
		$params = [
473 30
			'current_url' => $current_page,
474 30
			'forward_url' => $forward_url
475
		];
476
477 30
		$forward_reason = (string) $status_code;
478
479 30
		$forward_url = $this->hooks->trigger('forward', $forward_reason, $params, $forward_url);
480
481 30
		if ($this->response_sent) {
482
			// Response was sent from a forward hook
483
			// Clearing handlers to void infinite loops
484 1
			return $this->response_sent;
0 ignored issues
show
Bug Best Practice introduced by Ismayil Khayredinov
The expression return $this->response_sent returns the type true which is incompatible with the documented return type Symfony\Component\HttpFoundation\RedirectResponse.
Loading history...
485
		}
486
487 30
		if ($forward_url === REFERRER) {
488
			$forward_url = $this->request->headers->get('Referer');
489
		}
490
491 30
		if (!is_string($forward_url)) {
492
			throw new InvalidParameterException("'forward', '$forward_reason' hook must return a valid redirection URL");
493
		}
494
495 30
		$forward_url = elgg_normalize_url($forward_url);
496
497 30
		switch ($status_code) {
498 30
			case 'system':
499 30
			case 'csrf':
500
				$status_code = ELGG_HTTP_OK;
501
				break;
502 30
			case 'admin':
503 30
			case 'login':
504 30
			case 'member':
505 30
			case 'walled_garden':
506
			default :
507 30
				$status_code = (int) $status_code;
508 30
				if (!$status_code || $status_code < 100 || $status_code > 599) {
509
					$status_code = ELGG_HTTP_SEE_OTHER;
510
				}
511 30
				break;
512
		}
513
514 30
		if ($this->isXhr()) {
515 12
			if ($status_code < 100 || ($status_code >= 300 && $status_code <= 399) || $status_code > 599) {
516
				// We only want to preserve OK and error codes
517
				// Redirect responses should be converted to OK responses as this is an XHR request
518 9
				$status_code = ELGG_HTTP_OK;
519
			}
520 12
			$output = ob_get_clean();
521 12
			if (!$this->isAction() && !$this->ajax->isAjax2Request()) {
522
				// legacy ajax calls are always OK
523
				// actions are wrapped by ResponseFactory::respond()
524 5
				$status_code = ELGG_HTTP_OK;
525 5
				$output = $this->wrapLegacyAjaxResponse($output, $forward_url);
526
			}
527
528 12
			$response = new OkResponse($output, $status_code, $forward_url);
529 12
			$headers = $response->getHeaders();
530 12
			$headers['Content-Type'] = 'application/json; charset=UTF-8';
531 12
			$response->setHeaders($headers);
532 12
			return $this->respond($response);
533
		}
534
535 18
		if ($this->isAction()) {
536
			// actions should always redirect on non xhr-calls
537 7
			if (!is_int($status_code) || $status_code < 300 || $status_code > 399) {
0 ignored issues
show
introduced by Ismayil Khayredinov
The condition is_int($status_code) is always true.
Loading history...
538
				$status_code = ELGG_HTTP_SEE_OTHER;
539
			}
540
		}
541
542 18
		$response = new OkResponse('', $status_code, $forward_url);
543 18
		if ($response->isRedirection()) {
544 16
			return $this->send($this->prepareRedirectResponse($forward_url, $status_code));
0 ignored issues
show
Bug Best Practice introduced by Ismayil Khayredinov
The expression return $this->send($this...ard_url, $status_code)) returns the type false which is incompatible with the documented return type Symfony\Component\HttpFoundation\RedirectResponse.
Loading history...
545
		}
546 2
		return $this->respond($response);
547
	}
548
549
	/**
550
	 * Parses response type to be used as plugin hook type
551
	 * @return string
552
	 */
553 146
	public function parseContext() {
554
555 146
		$segments = $this->request->getUrlSegments();
556
557 146
		$identifier = array_shift($segments);
558 146
		switch ($identifier) {
559 146
			case 'ajax' :
560 21
				$page = array_shift($segments);
561 21
				if ($page === 'view') {
562 14
					$view = implode('/', $segments);
563 14
					return "view:$view";
564 7
				} else if ($page === 'form') {
565 5
					$form = implode('/', $segments);
566 5
					return "form:$form";
567
				}
568 2
				array_unshift($segments, $page);
569 2
				break;
570
571 125
			case 'action' :
572 27
				$action = implode('/', $segments);
573 27
				return "action:$action";
574
		}
575
576 101
		array_unshift($segments, $identifier);
577 101
		$path = implode('/', $segments);
578 101
		return "path:$path";
579
	}
580
581
	/**
582
	 * Check if the request is an XmlHttpRequest
583
	 * @return bool
584
	 */
585 43
	public function isXhr() {
586 43
		return $this->request->isXmlHttpRequest();
587
	}
588
589
	/**
590
	 * Check if the requested path is an action
591
	 * @return bool
592
	 */
593 37
	public function isAction() {
594 37
		if (0 === strpos($this->parseContext(), 'action:')) {
595 11
			return true;
596
		}
597 27
		return false;
598
	}
599
600
	/**
601
	 * Normalizes content into serializable data by walking through arrays
602
	 * and objectifying Elgg entities
603
	 *
604
	 * @param mixed $content Data to normalize
605
	 * @return mixed
606
	 */
607 134
	public function normalize($content = '') {
608 134
		if ($content instanceof ElggEntity) {
609
			$content = (array) $content->toObject();
610
		}
611 134
		if (is_array($content)) {
612 34
			foreach ($content as $key => $value) {
613 34
				$content[$key] = $this->normalize($value);
614
			}
615
		}
616 134
		return $content;
617
	}
618
619
	/**
620
	 * Stringify/serialize response data
621
	 *
622
	 * Casts objects implementing __toString method to strings
623
	 * Serializes non-scalar values to JSON
624
	 *
625
	 * @param mixed $content Content to serialize
626
	 * @return string
627
	 */
628 134
	public function stringify($content = '') {
629 134
		$content = $this->normalize($content);
630 134
		if (empty($content) || (is_object($content) && is_callable($content, '__toString'))) {
0 ignored issues
show
Bug introduced by Ismayil Khayredinov
'__toString' of type string is incompatible with the type boolean expected by parameter $syntax_only of is_callable(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

630
		if (empty($content) || (is_object($content) && is_callable($content, /** @scrutinizer ignore-type */ '__toString'))) {
Loading history...
631 73
			return (string) $content;
632
		}
633 71
		if (is_scalar($content)) {
634 68
			return $content;
635
		}
636 34
		return json_encode($content, ELGG_JSON_ENCODING);
637
	}
638
639
	/**
640
	 * Replaces response transport
641
	 *
642
	 * @param ResponseTransport $transport Transport interface
643
	 * @return void
644
	 */
645 24
	public function setTransport(ResponseTransport $transport) {
646 24
		$this->transport = $transport;
647 24
	}
648
}
649