1: <?php namespace Laravel;
2:
3: use Symfony\Component\HttpFoundation\ResponseHeaderBag;
4: use Symfony\Component\HttpFoundation\LaravelResponse as FoundationResponse;
5:
6: class Response {
7:
8: /**
9: * The content of the response.
10: *
11: * @var mixed
12: */
13: public $content;
14:
15: /**
16: * The Symfony HttpFoundation Response instance.
17: *
18: * @var HttpFoundation\Response
19: */
20: public $foundation;
21:
22: /**
23: * Create a new response instance.
24: *
25: * @param mixed $content
26: * @param int $status
27: * @param array $headers
28: * @return void
29: */
30: public function __construct($content, $status = 200, $headers = array())
31: {
32: $this->content = $content;
33:
34: $this->foundation = new FoundationResponse('', $status, $headers);
35: }
36:
37: /**
38: * Create a new response instance.
39: *
40: * <code>
41: * // Create a response instance with string content
42: * return Response::make(json_encode($user));
43: *
44: * // Create a response instance with a given status
45: * return Response::make('Not Found', 404);
46: *
47: * // Create a response with some custom headers
48: * return Response::make(json_encode($user), 200, array('header' => 'value'));
49: * </code>
50: *
51: * @param mixed $content
52: * @param int $status
53: * @param array $headers
54: * @return Response
55: */
56: public static function make($content, $status = 200, $headers = array())
57: {
58: return new static($content, $status, $headers);
59: }
60:
61: /**
62: * Create a new response instance containing a view.
63: *
64: * <code>
65: * // Create a response instance with a view
66: * return Response::view('home.index');
67: *
68: * // Create a response instance with a view and data
69: * return Response::view('home.index', array('name' => 'Taylor'));
70: * </code>
71: *
72: * @param string $view
73: * @param array $data
74: * @return Response
75: */
76: public static function view($view, $data = array())
77: {
78: return new static(View::make($view, $data));
79: }
80:
81: /**
82: * Create a new JSON response.
83: *
84: * <code>
85: * // Create a response instance with JSON
86: * return Response::json($data, 200, array('header' => 'value'));
87: * </code>
88: *
89: * @param mixed $data
90: * @param int $status
91: * @param array $headers
92: * @param int $json_options
93: * @return Response
94: */
95: public static function json($data, $status = 200, $headers = array(), $json_options = 0)
96: {
97: $headers['Content-Type'] = 'application/json; charset=utf-8';
98:
99: return new static(json_encode($data, $json_options), $status, $headers);
100: }
101:
102:
103: /**
104: * Create a new JSONP response.
105: *
106: * <code>
107: * // Create a response instance with JSONP
108: * return Response::jsonp('myFunctionCall', $data, 200, array('header' => 'value'));
109: * </code>
110: *
111: * @param mixed $data
112: * @param int $status
113: * @param array $headers
114: * @return Response
115: */
116: public static function jsonp($callback, $data, $status = 200, $headers = array())
117: {
118: $headers['Content-Type'] = 'application/javascript; charset=utf-8';
119:
120: return new static($callback.'('.json_encode($data).');', $status, $headers);
121: }
122:
123: /**
124: * Create a new response of JSON'd Eloquent models.
125: *
126: * <code>
127: * // Create a new response instance with Eloquent models
128: * return Response::eloquent($data, 200, array('header' => 'value'));
129: * </code>
130: *
131: * @param Eloquent|array $data
132: * @param int $status
133: * @param array $headers
134: * @return Response
135: */
136: public static function eloquent($data, $status = 200, $headers = array())
137: {
138: $headers['Content-Type'] = 'application/json; charset=utf-8';
139:
140: return new static(eloquent_to_json($data), $status, $headers);
141: }
142:
143: /**
144: * Create a new error response instance.
145: *
146: * The response status code will be set using the specified code.
147: *
148: * The specified error should match a view in your views/error directory.
149: *
150: * <code>
151: * // Create a 404 response
152: * return Response::error('404');
153: *
154: * // Create a 404 response with data
155: * return Response::error('404', array('message' => 'Not Found'));
156: * </code>
157: *
158: * @param int $code
159: * @param array $data
160: * @return Response
161: */
162: public static function error($code, $data = array())
163: {
164: return new static(View::make('error.'.$code, $data), $code);
165: }
166:
167: /**
168: * Create a new download response instance.
169: *
170: * <code>
171: * // Create a download response to a given file
172: * return Response::download('path/to/file.jpg');
173: *
174: * // Create a download response with a given file name
175: * return Response::download('path/to/file.jpg', 'your_file.jpg');
176: * </code>
177: *
178: * @param string $path
179: * @param string $name
180: * @param array $headers
181: * @return Response
182: */
183: public static function download($path, $name = null, $headers = array())
184: {
185: if (is_null($name)) $name = basename($path);
186:
187: // We'll set some sensible default headers, but merge the array given to
188: // us so that the developer has the chance to override any of these
189: // default headers with header values of their own liking.
190: $headers = array_merge(array(
191: 'Content-Description' => 'File Transfer',
192: 'Content-Type' => File::mime(File::extension($path)),
193: 'Content-Transfer-Encoding' => 'binary',
194: 'Expires' => 0,
195: 'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0',
196: 'Pragma' => 'public',
197: 'Content-Length' => File::size($path),
198: ), $headers);
199:
200: // Once we create the response, we need to set the content disposition
201: // header on the response based on the file's name. We'll pass this
202: // off to the HttpFoundation and let it create the header text.
203: $response = new static(File::get($path), 200, $headers);
204:
205: // If the Content-Disposition header has already been set by the
206: // merge above, then do not override it with out generated one.
207: if (!isset($headers['Content-Disposition'])) {
208: $d = $response->disposition($name);
209: $response = $response->header('Content-Disposition', $d);
210: }
211:
212: return $response;
213: }
214:
215: /**
216: * Create the proper Content-Disposition header.
217: *
218: * @param string $file
219: * @return string
220: */
221: public function disposition($file)
222: {
223: $type = ResponseHeaderBag::DISPOSITION_ATTACHMENT;
224:
225: return $this->foundation->headers->makeDisposition($type, $file);
226: }
227:
228: /**
229: * Prepare a response from the given value.
230: *
231: * @param mixed $response
232: * @return Response
233: */
234: public static function prepare($response)
235: {
236: // We will need to force the response to be a string before closing
237: // the session since the developer may be utilizing the session
238: // within the view, and we can't age it until rendering.
239: if ( ! $response instanceof Response)
240: {
241: $response = new static($response);
242: }
243:
244: return $response;
245: }
246:
247: /**
248: * Send the headers and content of the response to the browser.
249: *
250: * @return void
251: */
252: public function send()
253: {
254: $this->cookies();
255:
256: $this->foundation->prepare(Request::foundation());
257:
258: $this->foundation->send();
259: }
260:
261: /**
262: * Convert the content of the Response to a string and return it.
263: *
264: * @return string
265: */
266: public function render()
267: {
268: // If the content is a stringable object, we'll go ahead and call
269: // the toString method so that we can get the string content of
270: // the content object. Otherwise we'll just cast to string.
271: if (str_object($this->content))
272: {
273: $this->content = $this->content->__toString();
274: }
275: else
276: {
277: $this->content = (string) $this->content;
278: }
279:
280: // Once we obtain the string content, we can set the content on
281: // the HttpFoundation's Response instance in preparation for
282: // sending it back to client browser when all is finished.
283: $this->foundation->setContent($this->content);
284:
285: return $this->content;
286: }
287:
288: /**
289: * Send all of the response headers to the browser.
290: *
291: * @return void
292: */
293: public function send_headers()
294: {
295: $this->foundation->prepare(Request::foundation());
296:
297: $this->foundation->sendHeaders();
298: }
299:
300: /**
301: * Set the cookies on the HttpFoundation Response.
302: *
303: * @return void
304: */
305: protected function cookies()
306: {
307: $ref = new \ReflectionClass('Symfony\Component\HttpFoundation\Cookie');
308:
309: // All of the cookies for the response are actually stored on the
310: // Cookie class until we're ready to send the response back to
311: // the browser. This allows our cookies to be set easily.
312: foreach (Cookie::$jar as $name => $cookie)
313: {
314: $config = array_values($cookie);
315:
316: $this->headers()->setCookie($ref->newInstanceArgs($config));
317: }
318: }
319:
320: /**
321: * Add a header to the array of response headers.
322: *
323: * @param string $name
324: * @param string $value
325: * @return Response
326: */
327: public function header($name, $value)
328: {
329: $this->foundation->headers->set($name, $value);
330:
331: return $this;
332: }
333:
334: /**
335: * Get the HttpFoundation Response headers.
336: *
337: * @return ResponseParameterBag
338: */
339: public function headers()
340: {
341: return $this->foundation->headers;
342: }
343:
344: /**
345: * Get / set the response status code.
346: *
347: * @param int $status
348: * @return mixed
349: */
350: public function status($status = null)
351: {
352: if (is_null($status))
353: {
354: return $this->foundation->getStatusCode();
355: }
356: else
357: {
358: $this->foundation->setStatusCode($status);
359:
360: return $this;
361: }
362: }
363:
364: /**
365: * Render the response when cast to string
366: *
367: * @return string
368: */
369: public function __toString()
370: {
371: return $this->render();
372: }
373:
374: }
375: