Last active
August 1, 2017 12:06
-
-
Save danharper/8597149 to your computer and use it in GitHub Desktop.
A Laravel Controller which allows you to display API/report data in multiple formats. For example, you may display a preview as HTML, and offer buttons to download as CSV and JSON.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// this is the base controller which parses output to HTML/CSV/JSON depending on the format in the URL | |
use Illuminate\Support\Collection; | |
class FormatController extends Controller { | |
protected $fileName = 'export'; | |
protected $view = 'reports.output'; | |
public function callAction($method, $params) | |
{ | |
$response = parent::callAction($method, $params); | |
// default JSON. you may wish to change this to be HTML instead | |
if ( ! isset($params['format'])) return $response; | |
if ($params['format'] == '.csv') | |
{ | |
return $this->asCsv($response); | |
} | |
if ($params['format'] == '.html') | |
{ | |
return $this->asHtml($response); | |
} | |
return $response; | |
} | |
protected function asCsv($response) | |
{ | |
$csv = ''; | |
if ($response && count($response)) | |
{ | |
ob_start(); | |
$handle = fopen('php://output', 'r+'); | |
$first = ($response instanceof Collection) ? $response->first() : reset($response); | |
fputcsv($handle, array_keys($first)); | |
foreach ($response as $r) | |
{ | |
fputcsv($handle, array_values($r)); | |
} | |
$csv = ob_get_clean(); | |
fclose($handle); | |
} | |
return Response::make($csv, 200, [ | |
'Content-Type' => 'text/csv', | |
'Content-Disposition' => 'attachment;filename='.$this->fileName.'.csv' | |
]); | |
} | |
protected function asHtml($response) | |
{ | |
$path = '/'.str_replace('.html', '', Request::path()); | |
$query = Request::getQueryString(); | |
$first = ($response instanceof Collection) ? $response->first() : reset($response); | |
return View::make($this->view) | |
->with('title', $this->fileName) | |
->with('headers', $first ? array_keys($first) : []) | |
->with('rows', $response) | |
->with('error', $first ? null : 'No data found for criteria.') | |
->with('urls', (object) [ | |
'csv' => $path.'.csv?'.$query, | |
'json' => $path.'.json?'.$query, | |
]); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// this is an example Report controller making use of the FormatController | |
// we just return a collection of models. | |
// also included is an example of a date range filter | |
use Carbon\Carbon; | |
class ReportController extends FormatController { | |
public function __construct() | |
{ | |
Carbon::setToStringFormat('d/m/y'); | |
} | |
public function getCompletedOrders() | |
{ | |
$this->fileName = 'Completed Orders'; | |
list($from, $to) = $this->getDateRange(); | |
return Order::where('status', Order::COMPLETE)->whereBetween('completed_at', [$from, $to])->get(); | |
} | |
protected function getDateRange() | |
{ | |
$from = Input::has('from') ? new Carbon(Input::get('from')) : null; | |
$to = Input::has('to') ? new Carbon(Input::get('to')) : null; | |
return [$from, $to]; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// an example route. the {format} piece is important | |
Route::get('reports/completed-orders{format}', 'ReportController@getCompletedOrders'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- | |
an example view which will work out-of-the-box with the FormatController. | |
just place this at "reports/output.blade.php" (as defined in the $view variable in FormatController) | |
--> | |
<!doctype html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<title>{{ $title }} Export</title> | |
</head> | |
<body> | |
<p><a href="/reports">« Back to Reports</a></p> | |
<h1>{{ $title }}</h1> | |
<p> | |
Export as: <a class="btn" href="{{ $urls->csv }}">CSV</a> <a class="btn" href="{{ $urls->json }}">JSON</a> | |
</p> | |
@if ($error) | |
<p class="error"> | |
{{ $error }} | |
</p> | |
@endif | |
<table> | |
<thead> | |
<tr> | |
@foreach ($headers as $header) | |
<th>{{ $header }}</th> | |
@endforeach | |
</tr> | |
</thead> | |
<tbody> | |
@foreach ($rows as $row) | |
<tr> | |
@foreach (array_values($row) as $value) | |
<td>{{ $value }}</td> | |
@endforeach | |
</tr> | |
@endforeach | |
</tbody> | |
</table> | |
</body> | |
</html> |
Care to make the equivalent that adhere's to the SOLID principles? I'm having trouble designing for Liskov as it states each implementation of the interface (Csv/Html) should return the same data type/structure.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
If you are getting array_keys() expects parameter 1 to be array, object given errors, add the toArray lines in FormatController.php