ExcelExport.php 2.81 KB
<?php

namespace App\Support;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Vtiful\Kernel\Excel;
use Vtiful\Kernel\Format;

abstract class ExcelExport
{
    /**
     * @var string
     */
    private string $fileName;

    /**
     * @var \Vtiful\Kernel\Excel
     */
    protected Excel $fileObject;

    /**
     * @var \Illuminate\Database\Eloquent\Builder
     */
    protected Builder $builder;

    private function __construct()
    {
        $this->fileName   = Str::random(32) . '.xlsx';
        $this->fileObject = (new Excel(['path' => storage_path('excels')]))->constMemory($this->fileName, NULL, false);
    }

    /**
     * @param string|NULL $name
     * @return \Symfony\Component\HttpFoundation\BinaryFileResponse
     */
    public function download(string $name = NULL): BinaryFileResponse
    {
        $this->handle();
        return response()->download($this->fileObject->output(), $name ?? $this->fileName)->deleteFileAfterSend();
    }

    /**
     * @param \Illuminate\Database\Eloquent\Builder $builder
     * @return \App\Support\ExcelExport
     */
    public static function withBuilder(Builder $builder): static
    {
        return (new static)->setBuilder($builder);
    }

    /**
     * @param \Illuminate\Database\Eloquent\Builder $builder
     * @return \App\Support\ExcelExport
     */
    private function setBuilder(Builder $builder): static
    {
        $this->builder = $builder;
        return $this;
    }

    /**
     * @param array  $header
     * @param string $range
     * @return \App\Support\ExcelExport
     */
    protected function setHeader(array $header, string $range = 'A1'): static
    {
        $format    = new Format($this->fileObject->getHandle());
        $headStyle = $format->align(Format::FORMAT_ALIGN_CENTER, Format::FORMAT_ALIGN_VERTICAL_CENTER)->background(0XF2F2F2)->bold()->toResource();
        tap($this->fileObject, static fn(Excel $row) => $row->header($header)->setRow($range, 22, $headStyle));
        return $this;
    }

    /**
     * @param array $ranges
     * @return \App\Support\ExcelExport
     */
    public function setColumns(array $ranges): static
    {
        Arr::map($ranges, fn($val, $key) => $this->fileObject->setColumn($key, $val));
        return $this;
    }

    /**
     * @return void
     */
    private function handle(): void
    {
        $this->beforeHandle();
        $this->builder->chunk(1000, fn(Collection $collection) => $this->fileObject->data($collection->map(fn($item) => $this->setData($item))->toArray()));
        $this->afterHandle();
    }

    abstract protected function setData($item): array;

    protected function beforeHandle(): void { }

    protected function afterHandle(): void { }
}