Completed
Push — namespace-model ( 32fe71...476d0e )
by Sam
16:05
created

PjaxResponseNegotiator::setCallback()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 1
eloc 2
nc 1
nop 2
dl 0
loc 3
rs 10
1
<?php
2
3
4
namespace SilverStripe\Control;
5
6
7
8
use Convert;
9
use InvalidArgumentException;
10
use SilverStripe\Control\HTTPResponse;
11
use SilverStripe\Control\HTTPRequest;
12
use SilverStripe\Control\HTTPResponse_Exception;
13
14
15
16
/**
17
 * Handle the X-Pjax header that AJAX responses may provide, returning the
18
 * fragment, or, in the case of non-AJAX form submissions, redirecting back
19
 * to the submitter.
20
 *
21
 * X-Pjax ensures that users won't end up seeing the unstyled form HTML in
22
 * their browser.
23
 *
24
 * If a JS error prevents the Ajax overriding of form submissions from happening.
25
 *
26
 * It also provides better non-JS operation.
27
 *
28
 * Caution: This API is volatile, and might eventually be replaced by a generic
29
 * action helper system for controllers.
30
 *
31
 * @package framework
32
 * @subpackage control
33
 */
34
class PjaxResponseNegotiator {
35
36
	/**
37
	 * @var Array See {@link respond()}
38
	 */
39
	protected $callbacks = array(
40
		// TODO Using deprecated functionality, but don't want to duplicate Controller->redirectBack()
41
		'default' => array('SilverStripe\Control\Director', 'redirectBack'),
42
	);
43
44
	protected $response = null;
45
46
	/**
47
	 * Overriden fragments (if any). Otherwise uses fragments from the request.
48
	 */
49
	protected $fragmentOverride = null;
50
51
	/**
52
	 * @param RequestHandler $controller
0 ignored issues
show
Bug introduced by
There is no parameter named $controller. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
53
	 * @param SS_HTTPResponse An existing response to reuse (optional)
54
	 * @param Array $callbacks
55
	 */
56
	public function __construct($callbacks = array(), $response = null) {
57
		$this->callbacks = $callbacks;
58
		$this->response = $response;
59
	}
60
61
	public function getResponse() {
62
		if(!$this->response) $this->response = new HTTPResponse();
63
		return $this->response;
64
	}
65
66
	public function setResponse($response) {
67
		$this->response = $response;
68
	}
69
70
	/**
71
	 * Out of the box, the handler "CurrentForm" value, which will return the rendered form.
72
	 * Non-Ajax calls will redirect back.
73
	 *
74
	 * @param SS_HTTPRequest $request
75
	 * @param array $extraCallbacks List of anonymous functions or callables returning either a string
76
	 * or SS_HTTPResponse, keyed by their fragment identifier. The 'default' key can
77
	 * be used as a fallback for non-ajax responses.
78
	 * @param array $fragmentOverride Change the response fragments.
0 ignored issues
show
Bug introduced by
There is no parameter named $fragmentOverride. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
79
	 * @return SS_HTTPResponse
80
	 */
81
	public function respond(HTTPRequest $request, $extraCallbacks = array()) {
82
		// Prepare the default options and combine with the others
83
		$callbacks = array_merge($this->callbacks, $extraCallbacks);
84
		$response = $this->getResponse();
85
86
		$responseParts = array();
87
88
		if (isset($this->fragmentOverride)) {
89
			$fragments = $this->fragmentOverride;
90
		} elseif ($fragmentStr = $request->getHeader('X-Pjax')) {
91
			$fragments = explode(',', $fragmentStr);
92
		} else {
93
			if($request->isAjax()) {
94
				throw new HTTPResponse_Exception("Ajax requests to this URL require an X-Pjax header.", 400);
95
			}
96
			$response->setBody(call_user_func($callbacks['default']));
97
			return $response;
98
		}
99
100
		// Execute the fragment callbacks and build the response.
101
		foreach($fragments as $fragment) {
102
			if(isset($callbacks[$fragment])) {
103
				$res = call_user_func($callbacks[$fragment]);
104
				$responseParts[$fragment] = $res ? (string) $res : $res;
105
			} else {
106
				throw new HTTPResponse_Exception("X-Pjax = '$fragment' not supported for this URL.", 400);
107
			}
108
		}
109
		$response->setBody(Convert::raw2json($responseParts));
110
		$response->addHeader('Content-Type', 'text/json');
111
112
		return $response;
113
	}
114
115
	/**
116
	 * @param string   $fragment
117
	 * @param Callable $callback
118
	 */
119
	public function setCallback($fragment, $callback) {
120
		$this->callbacks[$fragment] = $callback;
121
	}
122
123
	/**
124
	 * Set up fragment overriding - will completely replace the incoming fragments.
125
	 *
126
	 * @param array $fragments Fragments to insert.
127
	 */
128
	public function setFragmentOverride($fragments) {
129
		if (!is_array($fragments)) throw new InvalidArgumentException();
130
131
		$this->fragmentOverride = $fragments;
132
133
		return $this;
134
	}
135
136
	/**
137
	 * @return array
138
	 */
139
	public function getFragmentOverride() {
140
		return $this->fragmentOverride;
141
	}
142
}
143