Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CSV export in laravel 5 controller

So I have made a little ajax request to my reviewsController@export.

Now when I console.log() the data in my success method, the ajax response shows the correct data. However my CSV has not downloaded. So I have all the right info and have created the csv essentially.

I think this has possibly to do with setting the headers maybe?

public function export() {     header("Content-type: text/csv");     header("Content-Disposition: attachment; filename=file.csv");     header("Pragma: no-cache");     header("Expires: 0");      $reviews = Reviews::getReviewExport($this->hw->healthwatchID)->get();     $columns = array('ReviewID', 'Provider', 'Title', 'Review', 'Location', 'Created', 'Anonymous', 'Escalate', 'Rating', 'Name');      $file = fopen('php://output', 'w');     fputcsv($file, $columns);      foreach($reviews as $review) {         fputcsv($file, array($review->reviewID,$review->provider,$review->title,$review->review,$review->location,$review->review_created,$review->anon,$review->escalate,$review->rating,$review->name));     }     exit(); } 

Is there anything I am doing wrong here, or does Laravel have something to cater for this?

like image 986
Matthew Smart Avatar asked Sep 07 '15 14:09

Matthew Smart


2 Answers

Try this version out - this should allow you to get a nice output using Response::stream().

public function export() {     $headers = array(         "Content-type" => "text/csv",         "Content-Disposition" => "attachment; filename=file.csv",         "Pragma" => "no-cache",         "Cache-Control" => "must-revalidate, post-check=0, pre-check=0",         "Expires" => "0"     );      $reviews = Reviews::getReviewExport($this->hw->healthwatchID)->get();     $columns = array('ReviewID', 'Provider', 'Title', 'Review', 'Location', 'Created', 'Anonymous', 'Escalate', 'Rating', 'Name');      $callback = function() use ($reviews, $columns)     {         $file = fopen('php://output', 'w');         fputcsv($file, $columns);          foreach($reviews as $review) {             fputcsv($file, array($review->reviewID, $review->provider, $review->title, $review->review, $review->location, $review->review_created, $review->anon, $review->escalate, $review->rating, $review->name));         }         fclose($file);     };     return Response::stream($callback, 200, $headers); } 

(Adapted from this SO answer: Use Laravel to Download table as CSV)

Try using a regular link with target="_blank" rather than using JavaScript/AJAX. Because it's a file download opening in a new tab, the user experience shouldn't be too clunky.

like image 154
Nerdwood Avatar answered Oct 13 '22 18:10

Nerdwood


My approach in Laravel 5.7

/**  * @param array $columnNames  * @param array $rows  * @param string $fileName  * @return \Symfony\Component\HttpFoundation\StreamedResponse  */ public static function getCsv($columnNames, $rows, $fileName = 'file.csv') {     $headers = [         "Content-type" => "text/csv",         "Content-Disposition" => "attachment; filename=" . $fileName,         "Pragma" => "no-cache",         "Cache-Control" => "must-revalidate, post-check=0, pre-check=0",         "Expires" => "0"     ];     $callback = function() use ($columnNames, $rows ) {         $file = fopen('php://output', 'w');         fputcsv($file, $columnNames);         foreach ($rows as $row) {             fputcsv($file, $row);         }         fclose($file);     };     return response()->stream($callback, 200, $headers); }  public function someOtherControllerFunction() {     $rows = [['a','b','c'],[1,2,3]];//replace this with your own array of arrays     $columnNames = ['blah', 'yada', 'hmm'];//replace this with your own array of string column headers             return self::getCsv($columnNames, $rows); } 
like image 38
Ryan Avatar answered Oct 13 '22 19:10

Ryan