Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Actions/Export.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public function download($items, $values): BinaryFileResponse|bool
{
$fileType = Arr::get($values, 'file_type', 'xlsx');
$firstItem = $items->first();
$exporter = new EntriesExport($items, $values);
$exporter = new EntriesExport(collect($items)->lazy(), $values);

if ($firstItem instanceof User) {
$filename = 'users';
Expand Down
77 changes: 35 additions & 42 deletions src/Exports/EntriesExport.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

namespace Doefom\StatamicExport\Exports;

use Generator;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\FromCollection;
use Illuminate\Support\LazyCollection;
use Maatwebsite\Excel\Concerns\FromGenerator;
use Maatwebsite\Excel\Concerns\WithStyles;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use Statamic\Contracts\Assets\Asset as AssetContract;
Expand All @@ -14,35 +15,50 @@
use Statamic\Entries\Entry;
use Statamic\Fields\Field;

class EntriesExport implements FromCollection, WithStyles
class EntriesExport implements FromGenerator, WithStyles
{
public function __construct(public Collection $items, public array $config = []) {}
public function __construct(public Generator|LazyCollection $items, public array $config = []) {}

/**
* Get all keys from all items combined (unique). Then go through all keys and check for each item if the key
* exists and if it does store the value. Else, store an empty string.
*
* If headers should be included, prepend those to the result array.
*/
public function collection(): Collection
public function generator(): Generator
{
// Get all unique keys from all items
$keys = $this->getAllKeysCombined($this->items);

$result = [];
foreach ($keys as $key => $label) {
// Add the key to the collection if it doesn't exist
foreach ($this->items as $index => $item) {
$result[$index][$key] = $this->getItemValue($item, $key);
Sheet::class;
$excludedFields = Arr::get($this->config, 'excluded_fields', []);
$keysForBlueprint = [];

foreach ($this->items as $index => $item) {
$blueprint = $item->blueprint();

if (!in_array($blueprint->handle(), $keysForBlueprint)) {
$keysForBlueprint[$blueprint->handle()] = $blueprint
->fields()
->all()
->unique(fn (Field $field) => $field->handle())
->filter(fn (Field $field) => ! in_array($field->handle(), $excludedFields))
->filter(fn(Field $field) => ! $field->fieldtype() instanceof \Statamic\Fieldtypes\Hidden
&& ! $field->fieldtype() instanceof \Statamic\Fieldtypes\Revealer
&& ! $field->fieldtype() instanceof \Statamic\Fieldtypes\Html
&& ! $field->fieldtype() instanceof \Statamic\Fieldtypes\Spacer)
->mapWithKeys(fn ($field) => [$field->handle() => $field->display()]);
}
}

// Add the headers to the collection
if (Arr::get($this->config, 'headers', true)) {
$result = Arr::prepend($result, $keys->toArray());
}
// First row with headers
if ($index === 0 && Arr::get($this->config, 'headers', true)) {
yield $keysForBlueprint[$blueprint->handle()]->all();
}

$row = [];
foreach ($keysForBlueprint[$blueprint->handle()] as $key => $label) {
$row[$label] = $this->getItemValue($item, $key);
}

return collect($result);
yield $row;
}
}

private function getItemValue($item, $key): mixed
Expand Down Expand Up @@ -230,27 +246,4 @@ private function toString(mixed $value): string

return '';
}

protected function getAllKeysCombined(Collection $items): Collection
{
$excludedFields = Arr::get($this->config, 'excluded_fields', []);

return $items
// Map each item to its blueprint fields, handling both Entry and User types
->map(fn (mixed $item) => $item->blueprint()->fields()->all())
// Flatten the resulting collection to remove nested structures
->flatten()
// Remove duplicate fields
->unique(fn (Field $field) => $field->handle())
// Remove fields that are excluded by the user. If there are no excluded fields, this will have no effect.
->filter(fn (Field $field) => ! in_array($field->handle(), $excludedFields))
// Filter out fields that are instances of certain field types
->filter(function (Field $field) {
return ! $field->fieldtype() instanceof \Statamic\Fieldtypes\Hidden
&& ! $field->fieldtype() instanceof \Statamic\Fieldtypes\Revealer
&& ! $field->fieldtype() instanceof \Statamic\Fieldtypes\Html
&& ! $field->fieldtype() instanceof \Statamic\Fieldtypes\Spacer;
})
->mapWithKeys(fn ($field) => [$field->handle() => $field->display()]);
}
}
4 changes: 2 additions & 2 deletions src/Http/Controllers/ExportController.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,13 @@ public function export(ExportRequest $request)
$includeHeaders = $request->input('headers', true);

if ($request->input('type') === 'users') {
$items = User::all();
$items = User::query()->lazy();
$filename = 'users';
} else {
$collectionHandle = $request->input('collection_handle');
$items = Entry::query()
->where('collection', $collectionHandle)
->get();
->lazy();
$filename = $collectionHandle;
}

Expand Down