Export Laravel Resource to CSV trait

William Vicary
May 25 · 2 min read

I was looking for a simple method of exporting a Laravel Resource to a CSV file, there is no native method of doing this however as you’ve already modelled how your data should look in an API it seems a little backward to re-model your data for exporting, it’s much nicer to re-use the Resource that you’ve already pre-defined.

I found the below to be reasonably elegant way of exporting a Laravel resource to CSV file as a trait on the Resource. This handles nested data by appending the parent key with an underscore affix and iterates hierarchically where needed. This solution makes use of an AnonymouseResourceCollection (the same approach laravel takes when you run Resource::collection($data); ).

Note: This relies on League\CSV (https://csv.thephpleague.com/) to generate the CSV file.

ExportTrait.php:

<?php

use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
use League\Csv\Writer;

trait ExportTrait
{
/**
* Exports a CSV from a provided resource collection
* @param mixed $resource
* @param string $filename
* @return int
* @throws \League\Csv\CannotInsertRecord
*/
public static function
exportCSV($resource, $filename = 'export.csv'): int
{
$resourceCollection = new AnonymousResourceCollection($resource, static::class);
$data = $resourceCollection->toArray(request());
$csv = Writer::createFromFileObject(new \SplTempFileObject());

$i = 0;
// Build the CSV
foreach
($data as $key => $datum) {
// Add the headers into the document
$row = self::assocToFlat($datum);
if ($i === 0) {
$csv->insertOne(array_keys($row));
}

$csv->insertOne($row);
$i++;
}

return $csv->output($filename);
}

/**
* Turns an associative array into a flat array, with hierarchical key names joined by underscore
* @param $dataRow
* @param string $prefixKey
* @return array
*/
private static function
assocToFlat($dataRow, $prefixKey = ''): array
{
$return = [];
foreach ($dataRow as $key => $item) {
if (!is_array($item)) {
$return[$prefixKey . $key] = $item;
continue;
}

$return = array_merge($return, self::assocToFlat($item, $prefixKey . $key . '_'));
}

return $return;
}
}

Add the trait to a resource you want to export:

<?php

namespace
App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;
use Support\Resource\ExportTrait;

class MyResource extends JsonResource
{
use ExportTrait;

/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function
toArray($request)
{
parent::toArray($request);
}
}

Then, when you have your data available, the following command will set the necessary download headers and export a CSV file based on your resource specification.

MyResource::export($data);

William Vicary

Written by

Technical Director of 3WhiteHats - Cornwall based Digital Marketing Agency consulting on SEO, PPC, Analytics and Website Strategies.