vd/vendor/dipper/excel/src/QueuedWriter.php
2019-01-15 18:06:37 +08:00

173 lines
4.7 KiB
PHP

<?php
namespace Dipper\Excel;
use Traversable;
use Dipper\Excel\Jobs\CloseSheet;
use Dipper\Excel\Jobs\QueueExport;
use Illuminate\Support\Collection;
use Dipper\Excel\Concerns\FromQuery;
use Dipper\Excel\Jobs\SerializedQuery;
use Dipper\Excel\Jobs\AppendDataToSheet;
use Dipper\Excel\Jobs\StoreQueuedExport;
use Dipper\Excel\Concerns\FromCollection;
use Dipper\Excel\Jobs\AppendQueryToSheet;
use Dipper\Excel\Jobs\AfterQueueExportJob;
use Dipper\Excel\Concerns\WithMultipleSheets;
use Dipper\Excel\Concerns\WithCustomChunkSize;
use Dipper\Excel\Concerns\WithCustomQuerySize;
class QueuedWriter
{
/**
* @var Writer
*/
protected $writer;
/**
* @var int
*/
protected $chunkSize;
/**
* @param Writer $writer
*/
public function __construct(Writer $writer)
{
$this->writer = $writer;
$this->chunkSize = config('excel.exports.chunk_size', 1000);
}
/**
* @param object $export
* @param string $filePath
* @param string|null $disk
* @param string|null $writerType
*
* @return \Dipper\Excel\Bus\PendingDispatch
*/
public function store($export, string $filePath, string $disk = null, string $writerType = null)
{
$tempFile = $this->writer->tempFile();
$jobs = $this->buildExportJobs($export, $tempFile, $writerType);
$jobs->push(new StoreQueuedExport($tempFile, $filePath, $disk));
$jobs->push(new AfterQueueExportJob($this->writer, $export, $filePath, $disk));
return QueueExport::withChain($jobs->toArray())->dispatch($export, $tempFile, $writerType);
}
/**
* @param object $export
* @param string $tempFile
* @param string $writerType
*
* @return Collection
*/
private function buildExportJobs($export, string $tempFile, string $writerType)
{
$sheetExports = [$export];
if ($export instanceof WithMultipleSheets) {
$sheetExports = $export->sheets();
}
$jobs = new Collection;
foreach ($sheetExports as $sheetIndex => $sheetExport) {
if ($sheetExport instanceof FromCollection) {
$jobs = $jobs->merge($this->exportCollection($sheetExport, $tempFile, $writerType, $sheetIndex));
} elseif ($sheetExport instanceof FromQuery) {
$jobs = $jobs->merge($this->exportQuery($sheetExport, $tempFile, $writerType, $sheetIndex));
}
$jobs->push(new CloseSheet($sheetExport, $tempFile, $writerType, $sheetIndex));
}
return $jobs;
}
/**
* @param FromCollection $export
* @param string $filePath
* @param string $writerType
* @param int $sheetIndex
*
* @return Collection
*/
private function exportCollection(
FromCollection $export,
string $filePath,
string $writerType,
int $sheetIndex
) {
return $export
->collection()
->chunk($this->getChunkSize($export))
->map(function ($rows) use ($writerType, $filePath, $sheetIndex, $export) {
if ($rows instanceof Traversable) {
$rows = iterator_to_array($rows);
}
return new AppendDataToSheet(
$export,
$filePath,
$writerType,
$sheetIndex,
$rows
);
});
}
/**
* @param FromQuery $export
* @param string $filePath
* @param string $writerType
* @param int $sheetIndex
*
* @return Collection
*/
private function exportQuery(
FromQuery $export,
string $filePath,
string $writerType,
int $sheetIndex
) {
$query = $export->query();
$count = $export instanceof WithCustomQuerySize ? $export->querySize() : (clone $query)->count();
$spins = ceil($count / $this->getChunkSize($export));
$jobs = new Collection();
for ($page = 1; $page <= $spins; $page++) {
$serializedQuery = new SerializedQuery(
(clone $query)->forPage($page, $this->getChunkSize($export))
);
$jobs->push(new AppendQueryToSheet(
$export,
$filePath,
$writerType,
$sheetIndex,
$serializedQuery
));
}
return $jobs;
}
/**
* @param object|WithCustomChunkSize $export
*
* @return int
*/
private function getChunkSize($export): int
{
if ($export instanceof WithCustomChunkSize) {
return $export->chunkSize();
}
return $this->chunkSize;
}
}