1
+ <?php
2
+ abstract class Controller_API extends OAuth2_Controller
3
+ {
4
+ /**
5
+ * @var Object Request Payload
6
+ */
7
+ protected $ _request_payload = NULL ;
8
+
9
+ /**
10
+ * @var Object Response Payload
11
+ */
12
+ protected $ _response_payload = NULL ;
13
+
14
+ /**
15
+ * @var array Response Metadata
16
+ */
17
+ protected $ _response_metadata = array ('error ' => FALSE );
18
+
19
+ /**
20
+ * @var array Response Links
21
+ */
22
+ protected $ _response_links = array ();
23
+
24
+ /**
25
+ * @var array Map of HTTP methods -> actions
26
+ */
27
+ protected $ _action_map = array
28
+ (
29
+ Http_Request::POST => 'post ' , // Typically Create..
30
+ Http_Request::GET => 'get ' ,
31
+ Http_Request::PUT => 'put ' , // Typically Update..
32
+ Http_Request::DELETE => 'delete ' ,
33
+ );
34
+
35
+ /**
36
+ * @var array List of HTTP methods which support body content
37
+ */
38
+ protected $ _methods_with_body_content = array
39
+ (
40
+ Http_Request::POST ,
41
+ Http_Request::PUT ,
42
+ );
43
+
44
+ /**
45
+ * @var array List of HTTP methods which may be cached
46
+ */
47
+ protected $ _cacheable_methods = array
48
+ (
49
+ Http_Request::GET ,
50
+ );
51
+
52
+ public function before ()
53
+ {
54
+ parent ::before ();
55
+
56
+ $ this ->_parse_request ();
57
+ }
58
+
59
+ public function after ()
60
+ {
61
+ $ this ->_prepare_response ();
62
+
63
+ parent ::after ();
64
+ }
65
+
66
+ /**
67
+ * Parse the request...
68
+ */
69
+ protected function _parse_request ()
70
+ {
71
+ // Override the method if needed.
72
+ $ this ->request ->method (Arr::get (
73
+ $ _SERVER ,
74
+ 'HTTP_X_HTTP_METHOD_OVERRIDE ' ,
75
+ $ this ->request ->method ()
76
+ ));
77
+
78
+ // Is that a valid method?
79
+ if ( ! isset ($ this ->_action_map [$ this ->request ->method ()]))
80
+ {
81
+ // TODO .. add to the if (maybe??) .. method_exists($this, 'action_'.$this->request->method())
82
+ throw new Http_Exception_405 ('The :method method is not supported. Supported methods are :allowed_methods ' , array (
83
+ ':method ' => $ method ,
84
+ ':allowed_methods ' => implode (', ' , array_keys ($ this ->_action_map )),
85
+ ));
86
+ }
87
+
88
+ // Are we be expecting body content as part of the request?
89
+ if (in_array ($ this ->request ->method (), $ this ->_methods_with_body_content ))
90
+ {
91
+ $ this ->_parse_request_body ();
92
+ }
93
+ }
94
+
95
+ /**
96
+ * @todo Support more than just JSON
97
+ */
98
+ protected function _parse_request_body ()
99
+ {
100
+ if ($ this ->request ->body () == '' )
101
+ return ;
102
+
103
+ try
104
+ {
105
+ $ this ->_request_payload = json_decode ($ this ->request ->body (), TRUE );
106
+
107
+ if ( ! is_array ($ this ->_request_payload ) AND ! is_object ($ this ->_request_payload ))
108
+ throw new Http_Exception_400 ('Invalid json supplied. \':json \'' , array (
109
+ ':json ' => $ this ->request ->body (),
110
+ ));
111
+ }
112
+ catch (Exception $ e )
113
+ {
114
+ throw new Http_Exception_400 ('Invalid json supplied. \':json \'' , array (
115
+ ':json ' => $ this ->request ->body (),
116
+ ));
117
+ }
118
+ }
119
+
120
+ protected function _prepare_response ()
121
+ {
122
+ // Should we prevent this request from being cached?
123
+ if ( ! in_array ($ this ->request ->method (), $ this ->_cacheable_methods ))
124
+ {
125
+ $ this ->response ->headers ('cache-control ' , 'no-cache, no-store, max-age=0, must-revalidate ' );
126
+ }
127
+
128
+ $ this ->_prepare_response_body ();
129
+ }
130
+
131
+ /**
132
+ * @todo Support more than just JSON
133
+ */
134
+ protected function _prepare_response_body ()
135
+ {
136
+ try
137
+ {
138
+ // Set the correct content-type header
139
+ $ this ->response ->headers ('Content-Type ' , 'application/json ' );
140
+
141
+ $ response = array (
142
+ 'metadata ' => $ this ->_response_metadata ,
143
+ 'links ' => $ this ->_response_links ,
144
+ 'payload ' => $ this ->_response_payload
145
+ );
146
+
147
+ // Format the reponse as JSON
148
+ $ this ->response ->body (json_encode ($ response ));
149
+ }
150
+ catch (Exception $ e )
151
+ {
152
+ Kohana::$ log ->add (Log::ERROR , 'Error while formatting response: ' .$ e ->getMessage ());
153
+ throw new Http_Exception_500 ('Error while formatting response ' );
154
+ }
155
+ }
156
+
157
+ /**
158
+ * Execute the API call..
159
+ */
160
+ public function action_index ()
161
+ {
162
+ // Get the basic verb based action..
163
+ $ action = $ this ->_action_map [$ this ->request ->method ()];
164
+
165
+ // If this is a custom action, lets make sure we use it.
166
+ if ($ this ->request ->param ('custom ' , FALSE ) !== FALSE )
167
+ {
168
+ $ action .= '_ ' .$ this ->request ->param ('custom ' );
169
+ }
170
+
171
+ // If we are acting on a collection, append _collection to the action name.
172
+ if ($ this ->request ->param ('id ' , FALSE ) === FALSE )
173
+ {
174
+ $ action .= '_collection ' ;
175
+ }
176
+
177
+ // Execute the request
178
+ if (method_exists ($ this , $ action ))
179
+ {
180
+ try
181
+ {
182
+ $ this ->_execute ($ action );
183
+ }
184
+ catch (Exception $ e )
185
+ {
186
+ $ this ->response ->status (500 );
187
+ $ this ->_response_payload = NULL ;
188
+ }
189
+ }
190
+ else
191
+ {
192
+ /**
193
+ * @todo .. HTTP_Exception_405 is more approperiate, sometimes.
194
+ * Need to figure out a way to decide which to send...
195
+ */
196
+ throw new HTTP_Exception_404 ('The requested URL :uri was not found on this server. ' , array (
197
+ ':uri ' => $ this ->request ->uri ()
198
+ ));
199
+ }
200
+ }
201
+
202
+ protected function _execute ($ action )
203
+ {
204
+ try
205
+ {
206
+ $ this ->{$ action }();
207
+ }
208
+ catch (Exception $ e )
209
+ {
210
+ $ this ->response ->status (500 );
211
+
212
+ $ this ->_response_metadata = array (
213
+ 'error ' => TRUE ,
214
+ 'type ' => 'error_exception ' ,
215
+ );
216
+
217
+ $ this ->_response_payload = array (
218
+ 'message ' => $ e ->getMessage (),
219
+ 'code ' => $ e ->getCode (),
220
+ );
221
+
222
+ $ this ->_response_links = NULL ;
223
+ }
224
+ }
225
+
226
+ protected function _generate_link ($ method , $ uri , $ parameters = NULL )
227
+ {
228
+ $ link = array (
229
+ 'method ' => $ method ,
230
+ 'url ' => $ uri ,
231
+ 'parameters ' => array (),
232
+ );
233
+
234
+ if ($ parameters !== NULL )
235
+ {
236
+ foreach ($ parameters as $ search => $ replace )
237
+ {
238
+ if (is_numeric ($ search ))
239
+ {
240
+ $ link ['parameters ' ][': ' .$ replace ] = $ replace ;
241
+ }
242
+ else
243
+ {
244
+ $ link ['parameters ' ][$ search ] = $ replace ;
245
+ }
246
+ }
247
+ }
248
+
249
+ return $ link ;
250
+ }
251
+ }
0 commit comments