vd/vendor/dipper/excel/src/ChunkReader.php
2018-12-29 10:19:35 +08:00

131 lines
3.9 KiB
PHP

<?php
namespace Dipper\Excel;
use Illuminate\Support\Collection;
use Dipper\Excel\Jobs\ReadChunk;
use Dipper\Excel\Jobs\QueueImport;
use Illuminate\Contracts\Bus\Dispatcher;
use Dipper\Excel\Concerns\WithLimit;
use Illuminate\Contracts\Queue\ShouldQueue;
use PhpOffice\PhpSpreadsheet\Reader\IReader;
use Dipper\Excel\Concerns\WithProgressBar;
use Dipper\Excel\Concerns\WithChunkReading;
use Dipper\Excel\Concerns\WithMultipleSheets;
use Dipper\Excel\Imports\HeadingRowExtractor;
class ChunkReader
{
/**
* @param WithChunkReading $import
* @param IReader $reader
* @param string $file
*
* @return \Dipper\Excel\Bus\PendingDispatch|null
*/
public function read(WithChunkReading $import, IReader $reader, string $file)
{
$chunkSize = $import->chunkSize();
$totalRows = $this->getTotalRows($reader, $file);
$worksheets = $this->getWorksheets($import, $reader, $file);
if ($import instanceof WithProgressBar) {
$import->getConsoleOutput()->progressStart(array_sum($totalRows));
}
$jobs = new Collection();
foreach ($worksheets as $name => $sheetImport) {
$startRow = HeadingRowExtractor::determineStartRow($sheetImport);
$totalRows[$name] = $sheetImport instanceof WithLimit ? $import->limit() : $totalRows[$name];
for ($currentRow = $startRow; $currentRow <= $totalRows[$name]; $currentRow += $chunkSize) {
$jobs->push(new ReadChunk(
$reader,
$file,
$name,
$sheetImport,
$currentRow,
$chunkSize
));
}
}
if ($import instanceof ShouldQueue) {
return QueueImport::withChain($jobs->toArray())->dispatch();
}
$jobs->each(function (ReadChunk $job) {
app(Dispatcher::class)->dispatchNow($job);
});
if ($import instanceof WithProgressBar) {
$import->getConsoleOutput()->progressFinish();
}
unset($jobs);
return null;
}
/**
* @param WithChunkReading $import
* @param IReader $reader
* @param string $file
*
* @return array
*/
private function getWorksheets(WithChunkReading $import, IReader $reader, string $file): array
{
// Csv doesn't have worksheets.
if (!method_exists($reader, 'listWorksheetNames')) {
return ['Worksheet' => $import];
}
$worksheets = [];
$worksheetNames = $reader->listWorksheetNames($file);
if ($import instanceof WithMultipleSheets) {
$sheetImports = $import->sheets();
// Load specific sheets.
if (method_exists($reader, 'setLoadSheetsOnly')) {
$reader->setLoadSheetsOnly(array_keys($sheetImports));
}
foreach ($sheetImports as $index => $sheetImport) {
// Translate index to name.
if (is_numeric($index)) {
$index = $worksheetNames[$index] ?? $index;
}
// Specify with worksheet name should have which import.
$worksheets[$index] = $sheetImport;
}
} else {
// Each worksheet the same import class.
foreach ($worksheetNames as $name) {
$worksheets[$name] = $import;
}
}
return $worksheets;
}
/**
* @param IReader $reader
* @param string $file
*
* @return array
*/
private function getTotalRows(IReader $reader, string $file): array
{
$info = $reader->listWorksheetInfo($file);
$totalRows = [];
foreach ($info as $sheet) {
$totalRows[$sheet['worksheetName']] = $sheet['totalRows'];
}
return $totalRows;
}
}