/home/mip/www/vendor/laravel-filemanager/files/folder-1/821668/maatwebsite.tar
excel/LICENSE 0000644 00000002044 15243417774 0006667 0 ustar 00 MIT License
Copyright (c) Spartner
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
excel/src/Excel.php 0000644 00000012045 15243417774 0010224 0 ustar 00 <?php
namespace Maatwebsite\Excel;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\PendingDispatch;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Files\Filesystem;
use Maatwebsite\Excel\Files\TemporaryFile;
use Maatwebsite\Excel\Helpers\FileTypeDetector;
class Excel implements Exporter, Importer
{
use RegistersCustomConcerns;
const XLSX = 'Xlsx';
const CSV = 'Csv';
const TSV = 'Csv';
const ODS = 'Ods';
const XLS = 'Xls';
const SLK = 'Slk';
const XML = 'Xml';
const GNUMERIC = 'Gnumeric';
const HTML = 'Html';
const MPDF = 'Mpdf';
const DOMPDF = 'Dompdf';
const TCPDF = 'Tcpdf';
/**
* @var Writer
*/
protected $writer;
/**
* @var QueuedWriter
*/
protected $queuedWriter;
/**
* @var Filesystem
*/
protected $filesystem;
/**
* @var Reader
*/
private $reader;
/**
* @param Writer $writer
* @param QueuedWriter $queuedWriter
* @param Reader $reader
* @param Filesystem $filesystem
*/
public function __construct(
Writer $writer,
QueuedWriter $queuedWriter,
Reader $reader,
Filesystem $filesystem
) {
$this->writer = $writer;
$this->reader = $reader;
$this->filesystem = $filesystem;
$this->queuedWriter = $queuedWriter;
}
/**
* {@inheritdoc}
*/
public function download($export, string $fileName, string $writerType = null, array $headers = [])
{
// Clear output buffer to prevent stuff being prepended to the Excel output.
if (ob_get_length() > 0) {
ob_end_clean();
ob_start();
}
return response()->download(
$this->export($export, $fileName, $writerType)->getLocalPath(),
$fileName,
$headers
)->deleteFileAfterSend(true);
}
/**
* {@inheritdoc}
*
* @param string|null $disk Fallback for usage with named properties
*/
public function store($export, string $filePath, string $diskName = null, string $writerType = null, $diskOptions = [], string $disk = null)
{
if ($export instanceof ShouldQueue) {
return $this->queue($export, $filePath, $diskName ?: $disk, $writerType, $diskOptions);
}
$temporaryFile = $this->export($export, $filePath, $writerType);
$exported = $this->filesystem->disk($diskName ?: $disk, $diskOptions)->copy(
$temporaryFile,
$filePath
);
$temporaryFile->delete();
return $exported;
}
/**
* {@inheritdoc}
*/
public function queue($export, string $filePath, string $disk = null, string $writerType = null, $diskOptions = [])
{
$writerType = FileTypeDetector::detectStrict($filePath, $writerType);
return $this->queuedWriter->store(
$export,
$filePath,
$disk,
$writerType,
$diskOptions
);
}
/**
* {@inheritdoc}
*/
public function raw($export, string $writerType)
{
$temporaryFile = $this->writer->export($export, $writerType);
$contents = $temporaryFile->contents();
$temporaryFile->delete();
return $contents;
}
/**
* {@inheritdoc}
*/
public function import($import, $filePath, string $disk = null, string $readerType = null)
{
$readerType = FileTypeDetector::detect($filePath, $readerType);
$response = $this->reader->read($import, $filePath, $readerType, $disk);
if ($response instanceof PendingDispatch) {
return $response;
}
return $this;
}
/**
* {@inheritdoc}
*/
public function toArray($import, $filePath, string $disk = null, string $readerType = null): array
{
$readerType = FileTypeDetector::detect($filePath, $readerType);
return $this->reader->toArray($import, $filePath, $readerType, $disk);
}
/**
* {@inheritdoc}
*/
public function toCollection($import, $filePath, string $disk = null, string $readerType = null): Collection
{
$readerType = FileTypeDetector::detect($filePath, $readerType);
return $this->reader->toCollection($import, $filePath, $readerType, $disk);
}
/**
* {@inheritdoc}
*/
public function queueImport(ShouldQueue $import, $filePath, string $disk = null, string $readerType = null)
{
return $this->import($import, $filePath, $disk, $readerType);
}
/**
* @param object $export
* @param string|null $fileName
* @param string $writerType
* @return TemporaryFile
*
* @throws \PhpOffice\PhpSpreadsheet\Exception
*/
protected function export($export, string $fileName, string $writerType = null): TemporaryFile
{
$writerType = FileTypeDetector::detectStrict($fileName, $writerType);
return $this->writer->export($export, $writerType);
}
}
excel/src/DelegatedMacroable.php 0000644 00000001324 15243417774 0012646 0 ustar 00 <?php
namespace Maatwebsite\Excel;
use Illuminate\Support\Traits\Macroable;
trait DelegatedMacroable
{
use Macroable {
__call as __callMacro;
}
/**
* Dynamically handle calls to the class.
*
* @param string $method
* @param array $parameters
* @return mixed
*/
public function __call($method, $parameters)
{
if (method_exists($this->getDelegate(), $method)) {
return call_user_func_array([$this->getDelegate(), $method], $parameters);
}
array_unshift($parameters, $this);
return $this->__callMacro($method, $parameters);
}
/**
* @return object
*/
abstract public function getDelegate();
}
excel/src/Validators/RowValidator.php 0000644 00000007715 15243417774 0013721 0 ustar 00 <?php
namespace Maatwebsite\Excel\Validators;
use Illuminate\Contracts\Validation\Factory;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException as IlluminateValidationException;
use Maatwebsite\Excel\Concerns\SkipsOnFailure;
use Maatwebsite\Excel\Concerns\WithValidation;
use Maatwebsite\Excel\Exceptions\RowSkippedException;
class RowValidator
{
/**
* @var Factory
*/
private $validator;
/**
* @param Factory $validator
*/
public function __construct(Factory $validator)
{
$this->validator = $validator;
}
/**
* @param array $rows
* @param WithValidation $import
*
* @throws ValidationException
* @throws RowSkippedException
*/
public function validate(array $rows, WithValidation $import)
{
$rules = $this->rules($import);
$messages = $this->messages($import);
$attributes = $this->attributes($import);
try {
$validator = $this->validator->make($rows, $rules, $messages, $attributes);
if (method_exists($import, 'withValidator')) {
$import->withValidator($validator);
}
$validator->validate();
} catch (IlluminateValidationException $e) {
$failures = [];
foreach ($e->errors() as $attribute => $messages) {
$row = strtok($attribute, '.');
$attributeName = strtok('');
$attributeName = $attributes['*.' . $attributeName] ?? $attributeName;
$failures[] = new Failure(
$row,
$attributeName,
str_replace($attribute, $attributeName, $messages),
$rows[$row] ?? []
);
}
if ($import instanceof SkipsOnFailure) {
$import->onFailure(...$failures);
throw new RowSkippedException(...$failures);
}
throw new ValidationException(
$e,
$failures
);
}
}
/**
* @param WithValidation $import
* @return array
*/
private function messages(WithValidation $import): array
{
return method_exists($import, 'customValidationMessages')
? $this->formatKey($import->customValidationMessages())
: [];
}
/**
* @param WithValidation $import
* @return array
*/
private function attributes(WithValidation $import): array
{
return method_exists($import, 'customValidationAttributes')
? $this->formatKey($import->customValidationAttributes())
: [];
}
/**
* @param WithValidation $import
* @return array
*/
private function rules(WithValidation $import): array
{
return $this->formatKey($import->rules());
}
/**
* @param array $elements
* @return array
*/
private function formatKey(array $elements): array
{
return collect($elements)->mapWithKeys(function ($rule, $attribute) {
$attribute = Str::startsWith($attribute, '*.') ? $attribute : '*.' . $attribute;
return [$attribute => $this->formatRule($rule)];
})->all();
}
/**
* @param string|object|callable|array $rules
* @return string|array
*/
private function formatRule($rules)
{
if (is_array($rules)) {
foreach ($rules as $rule) {
$formatted[] = $this->formatRule($rule);
}
return $formatted ?? [];
}
if (is_object($rules) || is_callable($rules)) {
return $rules;
}
if (Str::contains($rules, 'required_') && preg_match('/(.*?):(.*),(.*)/', $rules, $matches)) {
$column = Str::startsWith($matches[2], '*.') ? $matches[2] : '*.' . $matches[2];
return $matches[1] . ':' . $column . ',' . $matches[3];
}
return $rules;
}
}
excel/src/Validators/Failure.php 0000644 00000003466 15243417774 0012672 0 ustar 00 <?php
namespace Maatwebsite\Excel\Validators;
use Illuminate\Contracts\Support\Arrayable;
use JsonSerializable;
class Failure implements Arrayable, JsonSerializable
{
/**
* @var int
*/
protected $row;
/**
* @var string
*/
protected $attribute;
/**
* @var array
*/
protected $errors;
/**
* @var array
*/
private $values;
/**
* @param int $row
* @param string $attribute
* @param array $errors
* @param array $values
*/
public function __construct(int $row, string $attribute, array $errors, array $values = [])
{
$this->row = $row;
$this->attribute = $attribute;
$this->errors = $errors;
$this->values = $values;
}
/**
* @return int
*/
public function row(): int
{
return $this->row;
}
/**
* @return string
*/
public function attribute(): string
{
return $this->attribute;
}
/**
* @return array
*/
public function errors(): array
{
return $this->errors;
}
/**
* @return array
*/
public function values(): array
{
return $this->values;
}
/**
* @return array
*/
public function toArray()
{
return collect($this->errors)->map(function ($message) {
return __('There was an error on row :row. :message', ['row' => $this->row, 'message' => $message]);
})->all();
}
/**
* @return array
*/
#[\ReturnTypeWillChange]
public function jsonSerialize()
{
return [
'row' => $this->row(),
'attribute' => $this->attribute(),
'errors' => $this->errors(),
'values' => $this->values(),
];
}
}
excel/src/Validators/ValidationException.php 0000644 00000001546 15243417774 0015251 0 ustar 00 <?php
namespace Maatwebsite\Excel\Validators;
use Illuminate\Validation\ValidationException as IlluminateValidationException;
class ValidationException extends IlluminateValidationException
{
/**
* @var Failure[]
*/
protected $failures;
/**
* @param IlluminateValidationException $previous
* @param array $failures
*/
public function __construct(IlluminateValidationException $previous, array $failures)
{
parent::__construct($previous->validator, $previous->response, $previous->errorBag);
$this->failures = $failures;
}
/**
* @return string[]
*/
public function errors(): array
{
return collect($this->failures)->map->toArray()->all();
}
/**
* @return array
*/
public function failures(): array
{
return $this->failures;
}
}
excel/src/Writer.php 0000644 00000020051 15243417774 0010434 0 ustar 00 <?php
namespace Maatwebsite\Excel;
use Illuminate\Support\Arr;
use Maatwebsite\Excel\Concerns\WithBackgroundColor;
use Maatwebsite\Excel\Concerns\WithCustomValueBinder;
use Maatwebsite\Excel\Concerns\WithDefaultStyles;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Concerns\WithMultipleSheets;
use Maatwebsite\Excel\Concerns\WithProperties;
use Maatwebsite\Excel\Concerns\WithTitle;
use Maatwebsite\Excel\Events\BeforeExport;
use Maatwebsite\Excel\Events\BeforeWriting;
use Maatwebsite\Excel\Factories\WriterFactory;
use Maatwebsite\Excel\Files\RemoteTemporaryFile;
use Maatwebsite\Excel\Files\TemporaryFile;
use Maatwebsite\Excel\Files\TemporaryFileFactory;
use PhpOffice\PhpSpreadsheet\Cell\Cell;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Style\Color;
use PhpOffice\PhpSpreadsheet\Style\Fill;
/** @mixin Spreadsheet */
class Writer
{
use DelegatedMacroable, HasEventBus;
/**
* @var Spreadsheet
*/
protected $spreadsheet;
/**
* @var object
*/
protected $exportable;
/**
* @var TemporaryFileFactory
*/
protected $temporaryFileFactory;
/**
* @param TemporaryFileFactory $temporaryFileFactory
*/
public function __construct(TemporaryFileFactory $temporaryFileFactory)
{
$this->temporaryFileFactory = $temporaryFileFactory;
$this->setDefaultValueBinder();
}
/**
* @param object $export
* @param string $writerType
* @return TemporaryFile
*
* @throws \PhpOffice\PhpSpreadsheet\Exception
*/
public function export($export, string $writerType): TemporaryFile
{
$this->open($export);
$sheetExports = [$export];
if ($export instanceof WithMultipleSheets) {
$sheetExports = $export->sheets();
}
foreach ($sheetExports as $sheetExport) {
$this->addNewSheet()->export($sheetExport);
}
return $this->write($export, $this->temporaryFileFactory->makeLocal(null, strtolower($writerType)), $writerType);
}
/**
* @param object $export
* @return $this
*/
public function open($export)
{
$this->exportable = $export;
if ($export instanceof WithEvents) {
$this->registerListeners($export->registerEvents());
}
$this->exportable = $export;
$this->spreadsheet = new Spreadsheet;
$this->spreadsheet->disconnectWorksheets();
if ($export instanceof WithCustomValueBinder) {
Cell::setValueBinder($export);
}
$this->handleDocumentProperties($export);
if ($export instanceof WithBackgroundColor) {
$defaultStyle = $this->spreadsheet->getDefaultStyle();
$backgroundColor = $export->backgroundColor();
if (is_string($backgroundColor)) {
$defaultStyle->getFill()->setFillType(Fill::FILL_SOLID)->getStartColor()->setRGB($backgroundColor);
}
if (is_array($backgroundColor)) {
$defaultStyle->applyFromArray(['fill' => $backgroundColor]);
}
if ($backgroundColor instanceof Color) {
$defaultStyle->getFill()->setFillType(Fill::FILL_SOLID)->setStartColor($backgroundColor);
}
}
if ($export instanceof WithDefaultStyles) {
$defaultStyle = $this->spreadsheet->getDefaultStyle();
$styles = $export->defaultStyles($defaultStyle);
if (is_array($styles)) {
$defaultStyle->applyFromArray($styles);
}
}
$this->raise(new BeforeExport($this, $this->exportable));
return $this;
}
/**
* @param TemporaryFile $tempFile
* @param string $writerType
* @return Writer
*
* @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
*/
public function reopen(TemporaryFile $tempFile, string $writerType)
{
$reader = IOFactory::createReader($writerType);
$this->spreadsheet = $reader->load($tempFile->sync()->getLocalPath());
return $this;
}
/**
* @param object $export
* @param TemporaryFile $temporaryFile
* @param string $writerType
* @return TemporaryFile
*
* @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
* @throws \PhpOffice\PhpSpreadsheet\Exception
*/
public function write($export, TemporaryFile $temporaryFile, string $writerType): TemporaryFile
{
$this->exportable = $export;
$this->spreadsheet->setActiveSheetIndex(0);
$this->raise(new BeforeWriting($this, $this->exportable));
$writer = WriterFactory::make(
$writerType,
$this->spreadsheet,
$export
);
if ($temporaryFile instanceof RemoteTemporaryFile && !$temporaryFile->existsLocally()) {
$temporaryFile = resolve(TemporaryFileFactory::class)
->makeLocal(Arr::last(explode('/', $temporaryFile->getLocalPath())));
}
$writer->save(
$temporaryFile->getLocalPath()
);
if ($temporaryFile instanceof RemoteTemporaryFile) {
$temporaryFile->updateRemote();
$temporaryFile->deleteLocalCopy();
}
$this->clearListeners();
$this->spreadsheet->disconnectWorksheets();
unset($this->spreadsheet);
return $temporaryFile;
}
/**
* @param int|null $sheetIndex
* @return Sheet
*
* @throws \PhpOffice\PhpSpreadsheet\Exception
*/
public function addNewSheet(int $sheetIndex = null)
{
return new Sheet($this->spreadsheet->createSheet($sheetIndex));
}
/**
* @return Spreadsheet
*/
public function getDelegate()
{
return $this->spreadsheet;
}
/**
* @return $this
*/
public function setDefaultValueBinder()
{
Cell::setValueBinder(
app(config('excel.value_binder.default', DefaultValueBinder::class))
);
return $this;
}
/**
* @param int $sheetIndex
* @return Sheet
*
* @throws \PhpOffice\PhpSpreadsheet\Exception
*/
public function getSheetByIndex(int $sheetIndex)
{
return new Sheet($this->getDelegate()->getSheet($sheetIndex));
}
/**
* @param string $concern
* @return bool
*/
public function hasConcern($concern): bool
{
return $this->exportable instanceof $concern;
}
/**
* @param object $export
*/
protected function handleDocumentProperties($export)
{
$properties = config('excel.exports.properties', []);
if ($export instanceof WithProperties) {
$properties = array_merge($properties, $export->properties());
}
if ($export instanceof WithTitle) {
$properties = array_merge($properties, ['title' => $export->title()]);
}
$props = $this->spreadsheet->getProperties();
foreach (array_filter($properties) as $property => $value) {
switch ($property) {
case 'title':
$props->setTitle($value);
break;
case 'description':
$props->setDescription($value);
break;
case 'creator':
$props->setCreator($value);
break;
case 'lastModifiedBy':
$props->setLastModifiedBy($value);
break;
case 'subject':
$props->setSubject($value);
break;
case 'keywords':
$props->setKeywords($value);
break;
case 'category':
$props->setCategory($value);
break;
case 'manager':
$props->setManager($value);
break;
case 'company':
$props->setCompany($value);
break;
}
}
}
}
excel/src/Middleware/CellMiddleware.php 0000644 00000000323 15243417774 0014112 0 ustar 00 <?php
namespace Maatwebsite\Excel\Middleware;
abstract class CellMiddleware
{
/**
* @param mixed $value
* @return mixed
*/
abstract public function __invoke($value, callable $next);
}
excel/src/Middleware/ConvertEmptyCellValuesToNull.php 0000644 00000000474 15243417774 0017021 0 ustar 00 <?php
namespace Maatwebsite\Excel\Middleware;
class ConvertEmptyCellValuesToNull extends CellMiddleware
{
/**
* @param mixed $value
* @return mixed
*/
public function __invoke($value, callable $next)
{
return $next(
$value === '' ? null : $value
);
}
}
excel/src/Middleware/TrimCellValue.php 0000644 00000000774 15243417774 0013757 0 ustar 00 <?php
namespace Maatwebsite\Excel\Middleware;
class TrimCellValue extends CellMiddleware
{
/**
* @param mixed $value
* @return mixed
*/
public function __invoke($value, callable $next)
{
if (!is_string($value)) {
return $next($value);
}
// Remove whitespace, BOM and zero width spaces.
$cleaned = preg_replace('~^[\s\x{FEFF}\x{200B}]+|[\s\x{FEFF}\x{200B}]+$~u', '', $value) ?? trim($value);
return $next($cleaned);
}
}
excel/src/Transactions/TransactionManager.php 0000644 00000001251 15243417774 0015411 0 ustar 00 <?php
namespace Maatwebsite\Excel\Transactions;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Manager;
class TransactionManager extends Manager
{
/**
* @return string
*/
public function getDefaultDriver()
{
return config('excel.transactions.handler');
}
/**
* @return NullTransactionHandler
*/
public function createNullDriver()
{
return new NullTransactionHandler();
}
/**
* @return DbTransactionHandler
*/
public function createDbDriver()
{
return new DbTransactionHandler(
DB::connection(config('excel.transactions.db.connection'))
);
}
}
excel/src/Transactions/NullTransactionHandler.php 0000644 00000000422 15243417774 0016246 0 ustar 00 <?php
namespace Maatwebsite\Excel\Transactions;
class NullTransactionHandler implements TransactionHandler
{
/**
* @param callable $callback
* @return mixed
*/
public function __invoke(callable $callback)
{
return $callback();
}
}
excel/src/Transactions/TransactionHandler.php 0000644 00000000315 15243417774 0015414 0 ustar 00 <?php
namespace Maatwebsite\Excel\Transactions;
interface TransactionHandler
{
/**
* @param callable $callback
* @return mixed
*/
public function __invoke(callable $callback);
}
excel/src/Transactions/DbTransactionHandler.php 0000644 00000001176 15243417774 0015670 0 ustar 00 <?php
namespace Maatwebsite\Excel\Transactions;
use Illuminate\Database\ConnectionInterface;
class DbTransactionHandler implements TransactionHandler
{
/**
* @var ConnectionInterface
*/
private $connection;
/**
* @param ConnectionInterface $connection
*/
public function __construct(ConnectionInterface $connection)
{
$this->connection = $connection;
}
/**
* @param callable $callback
* @return mixed
*
* @throws \Throwable
*/
public function __invoke(callable $callback)
{
return $this->connection->transaction($callback);
}
}
excel/src/RegistersCustomConcerns.php 0000644 00000002145 15243417774 0014021 0 ustar 00 <?php
namespace Maatwebsite\Excel;
use Maatwebsite\Excel\Events\AfterSheet;
use Maatwebsite\Excel\Events\BeforeExport;
use Maatwebsite\Excel\Events\BeforeSheet;
use Maatwebsite\Excel\Events\BeforeWriting;
use Maatwebsite\Excel\Events\Event;
trait RegistersCustomConcerns
{
/**
* @var array
*/
private static $eventMap = [
BeforeWriting::class => Writer::class,
BeforeExport::class => Writer::class,
BeforeSheet::class => Sheet::class,
AfterSheet::class => Sheet::class,
];
/**
* @param string $concern
* @param callable $handler
* @param string $event
*/
public static function extend(string $concern, callable $handler, string $event = BeforeWriting::class)
{
/** @var HasEventBus $delegate */
$delegate = static::$eventMap[$event] ?? BeforeWriting::class;
$delegate::listen($event, function (Event $event) use ($concern, $handler) {
if ($event->appliesToConcern($concern)) {
$handler($event->getConcernable(), $event->getDelegate());
}
});
}
}
excel/src/Jobs/AppendQueryToSheet.php 0000644 00000005611 15243417774 0013613 0 ustar 00 <?php
namespace Maatwebsite\Excel\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Events\AfterChunk;
use Maatwebsite\Excel\Files\TemporaryFile;
use Maatwebsite\Excel\HasEventBus;
use Maatwebsite\Excel\Jobs\Middleware\LocalizeJob;
use Maatwebsite\Excel\Writer;
class AppendQueryToSheet implements ShouldQueue
{
use Queueable, Dispatchable, ProxyFailures, InteractsWithQueue, HasEventBus;
/**
* @var TemporaryFile
*/
public $temporaryFile;
/**
* @var string
*/
public $writerType;
/**
* @var int
*/
public $sheetIndex;
/**
* @var FromQuery
*/
public $sheetExport;
/**
* @var int
*/
public $page;
/**
* @var int
*/
public $chunkSize;
/**
* @param FromQuery $sheetExport
* @param TemporaryFile $temporaryFile
* @param string $writerType
* @param int $sheetIndex
* @param int $page
* @param int $chunkSize
*/
public function __construct(
FromQuery $sheetExport,
TemporaryFile $temporaryFile,
string $writerType,
int $sheetIndex,
int $page,
int $chunkSize
) {
$this->sheetExport = $sheetExport;
$this->temporaryFile = $temporaryFile;
$this->writerType = $writerType;
$this->sheetIndex = $sheetIndex;
$this->page = $page;
$this->chunkSize = $chunkSize;
}
/**
* Get the middleware the job should be dispatched through.
*
* @return array
*/
public function middleware()
{
return (method_exists($this->sheetExport, 'middleware')) ? $this->sheetExport->middleware() : [];
}
/**
* @param Writer $writer
*
* @throws \PhpOffice\PhpSpreadsheet\Exception
* @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
*/
public function handle(Writer $writer)
{
(new LocalizeJob($this->sheetExport))->handle($this, function () use ($writer) {
if ($this->sheetExport instanceof WithEvents) {
$this->registerListeners($this->sheetExport->registerEvents());
}
$writer = $writer->reopen($this->temporaryFile, $this->writerType);
$sheet = $writer->getSheetByIndex($this->sheetIndex);
$query = $this->sheetExport->query()->forPage($this->page, $this->chunkSize);
$sheet->appendRows($query->get(), $this->sheetExport);
$writer->write($this->sheetExport, $this->temporaryFile, $this->writerType);
$this->raise(new AfterChunk($sheet, $this->sheetExport, ($this->page - 1) * $this->chunkSize));
$this->clearListeners();
});
}
}
excel/src/Jobs/ReadChunk.php 0000644 00000014732 15243417774 0011732 0 ustar 00 <?php
namespace Maatwebsite\Excel\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Cache;
use Maatwebsite\Excel\Concerns\WithChunkReading;
use Maatwebsite\Excel\Concerns\WithCustomValueBinder;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Events\AfterChunk;
use Maatwebsite\Excel\Events\ImportFailed;
use Maatwebsite\Excel\Files\RemoteTemporaryFile;
use Maatwebsite\Excel\Files\TemporaryFile;
use Maatwebsite\Excel\Filters\ChunkReadFilter;
use Maatwebsite\Excel\HasEventBus;
use Maatwebsite\Excel\Imports\HeadingRowExtractor;
use Maatwebsite\Excel\Sheet;
use Maatwebsite\Excel\Transactions\TransactionHandler;
use PhpOffice\PhpSpreadsheet\Cell\Cell;
use PhpOffice\PhpSpreadsheet\Reader\IReader;
use Throwable;
class ReadChunk implements ShouldQueue
{
use Queueable, HasEventBus, InteractsWithQueue;
/**
* @var int
*/
public $timeout;
/**
* @var int
*/
public $tries;
/**
* @var int
*/
public $maxExceptions;
/**
* @var int
*/
public $backoff;
/**
* @var string
*/
public $queue;
/**
* @var string
*/
public $connection;
/**
* @var WithChunkReading
*/
private $import;
/**
* @var IReader
*/
private $reader;
/**
* @var TemporaryFile
*/
private $temporaryFile;
/**
* @var string
*/
private $sheetName;
/**
* @var object
*/
private $sheetImport;
/**
* @var int
*/
private $startRow;
/**
* @var int
*/
private $chunkSize;
/**
* @var string
*/
private $uniqueId;
/**
* @param WithChunkReading $import
* @param IReader $reader
* @param TemporaryFile $temporaryFile
* @param string $sheetName
* @param object $sheetImport
* @param int $startRow
* @param int $chunkSize
*/
public function __construct(WithChunkReading $import, IReader $reader, TemporaryFile $temporaryFile, string $sheetName, $sheetImport, int $startRow, int $chunkSize)
{
$this->import = $import;
$this->reader = $reader;
$this->temporaryFile = $temporaryFile;
$this->sheetName = $sheetName;
$this->sheetImport = $sheetImport;
$this->startRow = $startRow;
$this->chunkSize = $chunkSize;
$this->timeout = $import->timeout ?? null;
$this->tries = $import->tries ?? null;
$this->maxExceptions = $import->maxExceptions ?? null;
$this->backoff = method_exists($import, 'backoff') ? $import->backoff() : ($import->backoff ?? null);
$this->connection = property_exists($import, 'connection') ? $import->connection : null;
$this->queue = property_exists($import, 'queue') ? $import->queue : null;
}
public function getUniqueId(): string
{
if (!isset($this->uniqueId)) {
$this->uniqueId = uniqid();
Cache::set('laravel-excel/read-chunk/' . $this->uniqueId, true);
}
return $this->uniqueId;
}
public static function isComplete(string $id): bool
{
return !Cache::has('laravel-excel/read-chunk/' . $id);
}
/**
* Get the middleware the job should be dispatched through.
*
* @return array
*/
public function middleware()
{
return (method_exists($this->import, 'middleware')) ? $this->import->middleware() : [];
}
/**
* Determine the time at which the job should timeout.
*
* @return \DateTime
*/
public function retryUntil()
{
return (method_exists($this->import, 'retryUntil')) ? $this->import->retryUntil() : null;
}
/**
* @param TransactionHandler $transaction
*
* @throws \Maatwebsite\Excel\Exceptions\SheetNotFoundException
* @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
*/
public function handle(TransactionHandler $transaction)
{
if (method_exists($this->import, 'setChunkOffset')) {
$this->import->setChunkOffset($this->startRow);
}
if (method_exists($this->sheetImport, 'setChunkOffset')) {
$this->sheetImport->setChunkOffset($this->startRow);
}
if ($this->sheetImport instanceof WithCustomValueBinder) {
Cell::setValueBinder($this->sheetImport);
}
$headingRow = HeadingRowExtractor::headingRow($this->sheetImport);
$filter = new ChunkReadFilter(
$headingRow,
$this->startRow,
$this->chunkSize,
$this->sheetName
);
$this->reader->setReadFilter($filter);
$this->reader->setReadDataOnly(config('excel.imports.read_only', true));
$this->reader->setReadEmptyCells(!config('excel.imports.ignore_empty', false));
$spreadsheet = $this->reader->load(
$this->temporaryFile->sync()->getLocalPath()
);
$sheet = Sheet::byName(
$spreadsheet,
$this->sheetName
);
if ($sheet->getHighestRow() < $this->startRow) {
$sheet->disconnect();
$this->cleanUpTempFile();
return;
}
$transaction(function () use ($sheet) {
$sheet->import(
$this->sheetImport,
$this->startRow
);
$sheet->disconnect();
$this->cleanUpTempFile();
$sheet->raise(new AfterChunk($sheet, $this->import, $this->startRow));
});
}
/**
* @param Throwable $e
*/
public function failed(Throwable $e)
{
$this->cleanUpTempFile(true);
if ($this->import instanceof WithEvents) {
$this->registerListeners($this->import->registerEvents());
$this->raise(new ImportFailed($e));
if (method_exists($this->import, 'failed')) {
$this->import->failed($e);
}
}
}
private function cleanUpTempFile(bool $force = false): bool
{
if (!empty($this->uniqueId)) {
Cache::delete('laravel-excel/read-chunk/' . $this->uniqueId);
}
if (!$force && !config('excel.temporary_files.force_resync_remote')) {
return true;
}
if (!$this->temporaryFile instanceof RemoteTemporaryFile) {
return true;
}
return $this->temporaryFile->deleteLocalCopy();
}
}
excel/src/Jobs/Middleware/LocalizeJob.php 0000644 00000001740 15243417774 0014333 0 ustar 00 <?php
namespace Maatwebsite\Excel\Jobs\Middleware;
use Closure;
use Illuminate\Contracts\Translation\HasLocalePreference;
use Illuminate\Support\Traits\Localizable;
class LocalizeJob
{
use Localizable;
/**
* @var object
*/
private $localizable;
/**
* LocalizeJob constructor.
*
* @param object $localizable
*/
public function __construct($localizable)
{
$this->localizable = $localizable;
}
/**
* Handles the job.
*
* @param mixed $job
* @param Closure $next
* @return mixed
*/
public function handle($job, Closure $next)
{
$locale = value(function () {
if ($this->localizable instanceof HasLocalePreference) {
return $this->localizable->preferredLocale();
}
return null;
});
return $this->withLocale($locale, function () use ($next, $job) {
return $next($job);
});
}
}
excel/src/Jobs/ProxyFailures.php 0000644 00000000445 15243417774 0012676 0 ustar 00 <?php
namespace Maatwebsite\Excel\Jobs;
use Throwable;
trait ProxyFailures
{
/**
* @param Throwable $e
*/
public function failed(Throwable $e)
{
if (method_exists($this->sheetExport, 'failed')) {
$this->sheetExport->failed($e);
}
}
}
excel/src/Jobs/AppendPaginatedToSheet.php 0000644 00000005716 15243417774 0014410 0 ustar 00 <?php
namespace Maatwebsite\Excel\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Query\Builder;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Laravel\Scout\Builder as ScoutBuilder;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Files\TemporaryFile;
use Maatwebsite\Excel\Jobs\Middleware\LocalizeJob;
use Maatwebsite\Excel\Writer;
class AppendPaginatedToSheet implements ShouldQueue
{
use Queueable, Dispatchable, ProxyFailures, InteractsWithQueue;
/**
* @var TemporaryFile
*/
public $temporaryFile;
/**
* @var string
*/
public $writerType;
/**
* @var int
*/
public $sheetIndex;
/**
* @var FromQuery
*/
public $sheetExport;
/**
* @var int
*/
public $page;
/**
* @var int
*/
public $perPage;
/**
* @param FromQuery $sheetExport
* @param TemporaryFile $temporaryFile
* @param string $writerType
* @param int $sheetIndex
* @param int $page
* @param int $perPage
*/
public function __construct(
FromQuery $sheetExport,
TemporaryFile $temporaryFile,
string $writerType,
int $sheetIndex,
int $page,
int $perPage
) {
$this->sheetExport = $sheetExport;
$this->temporaryFile = $temporaryFile;
$this->writerType = $writerType;
$this->sheetIndex = $sheetIndex;
$this->page = $page;
$this->perPage = $perPage;
}
/**
* Get the middleware the job should be dispatched through.
*
* @return array
*/
public function middleware()
{
return (method_exists($this->sheetExport, 'middleware')) ? $this->sheetExport->middleware() : [];
}
/**
* @param Writer $writer
*
* @throws \PhpOffice\PhpSpreadsheet\Exception
* @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
*/
public function handle(Writer $writer)
{
(new LocalizeJob($this->sheetExport))->handle($this, function () use ($writer) {
$writer = $writer->reopen($this->temporaryFile, $this->writerType);
$sheet = $writer->getSheetByIndex($this->sheetIndex);
$sheet->appendRows($this->chunk($this->sheetExport->query()), $this->sheetExport);
$writer->write($this->sheetExport, $this->temporaryFile, $this->writerType);
});
}
/**
* @param Builder|Relation|EloquentBuilder|ScoutBuilder $query
*/
protected function chunk($query)
{
if ($query instanceof \Laravel\Scout\Builder) {
return $query->paginate($this->perPage, 'page', $this->page)->items();
}
// Fallback
return $query->forPage($this->page, $this->perPage)->get();
}
}
excel/src/Jobs/CloseSheet.php 0000644 00000003312 15243417774 0012114 0 ustar 00 <?php
namespace Maatwebsite\Excel\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Files\TemporaryFile;
use Maatwebsite\Excel\Writer;
class CloseSheet implements ShouldQueue
{
use Queueable, ProxyFailures;
/**
* @var object
*/
private $sheetExport;
/**
* @var string
*/
private $temporaryFile;
/**
* @var string
*/
private $writerType;
/**
* @var int
*/
private $sheetIndex;
/**
* @param object $sheetExport
* @param TemporaryFile $temporaryFile
* @param string $writerType
* @param int $sheetIndex
*/
public function __construct($sheetExport, TemporaryFile $temporaryFile, string $writerType, int $sheetIndex)
{
$this->sheetExport = $sheetExport;
$this->temporaryFile = $temporaryFile;
$this->writerType = $writerType;
$this->sheetIndex = $sheetIndex;
}
/**
* @param Writer $writer
*
* @throws \PhpOffice\PhpSpreadsheet\Exception
* @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
*/
public function handle(Writer $writer)
{
$writer = $writer->reopen(
$this->temporaryFile,
$this->writerType
);
$sheet = $writer->getSheetByIndex($this->sheetIndex);
if ($this->sheetExport instanceof WithEvents) {
$sheet->registerListeners($this->sheetExport->registerEvents());
}
$sheet->close($this->sheetExport);
$writer->write(
$this->sheetExport,
$this->temporaryFile,
$this->writerType
);
}
}
excel/src/Jobs/AfterImportJob.php 0000644 00000004415 15243417774 0012752 0 ustar 00 <?php
namespace Maatwebsite\Excel\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Events\ImportFailed;
use Maatwebsite\Excel\HasEventBus;
use Maatwebsite\Excel\Reader;
use Throwable;
class AfterImportJob implements ShouldQueue
{
use HasEventBus, InteractsWithQueue, Queueable;
/**
* @var WithEvents
*/
private $import;
/**
* @var Reader
*/
private $reader;
/**
* @var iterable
*/
private $dependencyIds = [];
private $interval = 60;
/**
* @param object $import
* @param Reader $reader
*/
public function __construct($import, Reader $reader)
{
$this->import = $import;
$this->reader = $reader;
}
public function setInterval(int $interval)
{
$this->interval = $interval;
}
public function setDependencies(Collection $jobs)
{
$this->dependencyIds = $jobs->map(function (ReadChunk $job) {
return $job->getUniqueId();
})->all();
}
public function handle()
{
foreach ($this->dependencyIds as $id) {
if (!ReadChunk::isComplete($id)) {
// Until there is no jobs left to run we put this job back into the queue every minute
// Note: this will do nothing in a SyncQueue but that's desired, because in a SyncQueue jobs run in order
$this->release($this->interval);
return;
}
}
if ($this->import instanceof ShouldQueue && $this->import instanceof WithEvents) {
$this->reader->clearListeners();
$this->reader->registerListeners($this->import->registerEvents());
}
$this->reader->afterImport($this->import);
}
/**
* @param Throwable $e
*/
public function failed(Throwable $e)
{
if ($this->import instanceof WithEvents) {
$this->registerListeners($this->import->registerEvents());
$this->raise(new ImportFailed($e));
if (method_exists($this->import, 'failed')) {
$this->import->failed($e);
}
}
}
}
excel/src/Jobs/QueueImport.php 0000644 00000001202 15243417774 0012331 0 ustar 00 <?php
namespace Maatwebsite\Excel\Jobs;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
class QueueImport implements ShouldQueue
{
use ExtendedQueueable, Dispatchable;
/**
* @var int
*/
public $tries;
/**
* @var int
*/
public $timeout;
/**
* @param ShouldQueue $import
*/
public function __construct(ShouldQueue $import = null)
{
if ($import) {
$this->timeout = $import->timeout ?? null;
$this->tries = $import->tries ?? null;
}
}
public function handle()
{
//
}
}
excel/src/Jobs/AppendViewToSheet.php 0000644 00000004105 15243417774 0013415 0 ustar 00 <?php
namespace Maatwebsite\Excel\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Maatwebsite\Excel\Concerns\FromView;
use Maatwebsite\Excel\Files\TemporaryFile;
use Maatwebsite\Excel\Jobs\Middleware\LocalizeJob;
use Maatwebsite\Excel\Writer;
class AppendViewToSheet implements ShouldQueue
{
use Queueable, Dispatchable, InteractsWithQueue;
/**
* @var TemporaryFile
*/
public $temporaryFile;
/**
* @var string
*/
public $writerType;
/**
* @var int
*/
public $sheetIndex;
/**
* @var FromView
*/
public $sheetExport;
/**
* @param FromView $sheetExport
* @param TemporaryFile $temporaryFile
* @param string $writerType
* @param int $sheetIndex
* @param array $data
*/
public function __construct(FromView $sheetExport, TemporaryFile $temporaryFile, string $writerType, int $sheetIndex)
{
$this->sheetExport = $sheetExport;
$this->temporaryFile = $temporaryFile;
$this->writerType = $writerType;
$this->sheetIndex = $sheetIndex;
}
/**
* Get the middleware the job should be dispatched through.
*
* @return array
*/
public function middleware()
{
return (method_exists($this->sheetExport, 'middleware')) ? $this->sheetExport->middleware() : [];
}
/**
* @param Writer $writer
*
* @throws \PhpOffice\PhpSpreadsheet\Exception
* @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
*/
public function handle(Writer $writer)
{
(new LocalizeJob($this->sheetExport))->handle($this, function () use ($writer) {
$writer = $writer->reopen($this->temporaryFile, $this->writerType);
$sheet = $writer->getSheetByIndex($this->sheetIndex);
$sheet->fromView($this->sheetExport, $this->sheetIndex);
$writer->write($this->sheetExport, $this->temporaryFile, $this->writerType);
});
}
}
excel/src/Jobs/StoreQueuedExport.php 0000644 00000002425 15243417774 0013531 0 ustar 00 <?php
namespace Maatwebsite\Excel\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Maatwebsite\Excel\Files\Filesystem;
use Maatwebsite\Excel\Files\TemporaryFile;
class StoreQueuedExport implements ShouldQueue
{
use Queueable;
/**
* @var string
*/
private $filePath;
/**
* @var string|null
*/
private $disk;
/**
* @var TemporaryFile
*/
private $temporaryFile;
/**
* @var array|string
*/
private $diskOptions;
/**
* @param TemporaryFile $temporaryFile
* @param string $filePath
* @param string|null $disk
* @param array|string $diskOptions
*/
public function __construct(TemporaryFile $temporaryFile, string $filePath, string $disk = null, $diskOptions = [])
{
$this->disk = $disk;
$this->filePath = $filePath;
$this->temporaryFile = $temporaryFile;
$this->diskOptions = $diskOptions;
}
/**
* @param Filesystem $filesystem
*/
public function handle(Filesystem $filesystem)
{
$filesystem->disk($this->disk, $this->diskOptions)->copy(
$this->temporaryFile,
$this->filePath
);
$this->temporaryFile->delete();
}
}
excel/src/Jobs/QueueExport.php 0000644 00000004774 15243417774 0012361 0 ustar 00 <?php
namespace Maatwebsite\Excel\Jobs;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Maatwebsite\Excel\Concerns\WithMultipleSheets;
use Maatwebsite\Excel\Exceptions\NoSheetsFoundException;
use Maatwebsite\Excel\Files\TemporaryFile;
use Maatwebsite\Excel\Jobs\Middleware\LocalizeJob;
use Maatwebsite\Excel\Writer;
use Throwable;
class QueueExport implements ShouldQueue
{
use ExtendedQueueable, Dispatchable;
/**
* @var object
*/
public $export;
/**
* @var string
*/
private $writerType;
/**
* @var TemporaryFile
*/
private $temporaryFile;
/**
* @param object $export
* @param TemporaryFile $temporaryFile
* @param string $writerType
*/
public function __construct($export, TemporaryFile $temporaryFile, string $writerType)
{
$this->export = $export;
$this->writerType = $writerType;
$this->temporaryFile = $temporaryFile;
}
/**
* Get the middleware the job should be dispatched through.
*
* @return array
*/
public function middleware()
{
return (method_exists($this->export, 'middleware')) ? $this->export->middleware() : [];
}
/**
* @param Writer $writer
*
* @throws \PhpOffice\PhpSpreadsheet\Exception
*/
public function handle(Writer $writer)
{
(new LocalizeJob($this->export))->handle($this, function () use ($writer) {
$writer->open($this->export);
$sheetExports = [$this->export];
if ($this->export instanceof WithMultipleSheets) {
$sheetExports = $this->export->sheets();
}
if (count($sheetExports) === 0) {
throw new NoSheetsFoundException('Your export did not return any sheet export instances, please make sure your sheets() method always at least returns one instance.');
}
// Pre-create the worksheets
foreach ($sheetExports as $sheetIndex => $sheetExport) {
$sheet = $writer->addNewSheet($sheetIndex);
$sheet->open($sheetExport);
}
// Write to temp file with empty sheets.
$writer->write($sheetExport, $this->temporaryFile, $this->writerType);
});
}
/**
* @param Throwable $e
*/
public function failed(Throwable $e)
{
if (method_exists($this->export, 'failed')) {
$this->export->failed($e);
}
}
}
excel/src/Jobs/ExtendedQueueable.php 0000644 00000000773 15243417774 0013457 0 ustar 00 <?php
namespace Maatwebsite\Excel\Jobs;
use Illuminate\Bus\Queueable;
trait ExtendedQueueable
{
use Queueable {
chain as originalChain;
}
/**
* @param $chain
* @return $this
*/
public function chain($chain)
{
collect($chain)->each(function ($job) {
$serialized = method_exists($this, 'serializeJob') ? $this->serializeJob($job) : serialize($job);
$this->chained[] = $serialized;
});
return $this;
}
}
excel/src/Jobs/AppendDataToSheet.php 0000644 00000004200 15243417774 0013350 0 ustar 00 <?php
namespace Maatwebsite\Excel\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Maatwebsite\Excel\Files\TemporaryFile;
use Maatwebsite\Excel\Jobs\Middleware\LocalizeJob;
use Maatwebsite\Excel\Writer;
class AppendDataToSheet implements ShouldQueue
{
use Queueable, Dispatchable, ProxyFailures, InteractsWithQueue;
/**
* @var array
*/
public $data = [];
/**
* @var string
*/
public $temporaryFile;
/**
* @var string
*/
public $writerType;
/**
* @var int
*/
public $sheetIndex;
/**
* @var object
*/
public $sheetExport;
/**
* @param object $sheetExport
* @param TemporaryFile $temporaryFile
* @param string $writerType
* @param int $sheetIndex
* @param array $data
*/
public function __construct($sheetExport, TemporaryFile $temporaryFile, string $writerType, int $sheetIndex, array $data)
{
$this->sheetExport = $sheetExport;
$this->data = $data;
$this->temporaryFile = $temporaryFile;
$this->writerType = $writerType;
$this->sheetIndex = $sheetIndex;
}
/**
* Get the middleware the job should be dispatched through.
*
* @return array
*/
public function middleware()
{
return (method_exists($this->sheetExport, 'middleware')) ? $this->sheetExport->middleware() : [];
}
/**
* @param Writer $writer
*
* @throws \PhpOffice\PhpSpreadsheet\Exception
* @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
*/
public function handle(Writer $writer)
{
(new LocalizeJob($this->sheetExport))->handle($this, function () use ($writer) {
$writer = $writer->reopen($this->temporaryFile, $this->writerType);
$sheet = $writer->getSheetByIndex($this->sheetIndex);
$sheet->appendRows($this->data, $this->sheetExport);
$writer->write($this->sheetExport, $this->temporaryFile, $this->writerType);
});
}
}
excel/src/Console/WithModelStub.php 0000644 00000003132 15243417774 0013315 0 ustar 00 <?php
namespace Maatwebsite\Excel\Console;
use Illuminate\Support\Str;
use InvalidArgumentException;
trait WithModelStub
{
/**
* Build the model replacement values.
*
* @param array $replace
* @return array
*/
protected function buildModelReplacements(array $replace): array
{
$modelClass = $this->parseModel($this->option('model'));
return array_merge($replace, [
'DummyFullModelClass' => $modelClass,
'DummyModelClass' => class_basename($modelClass),
]);
}
/**
* Get the fully-qualified model class name.
*
* @param string $model
* @return string
*/
protected function parseModel($model): string
{
if (preg_match('([^A-Za-z0-9_/\\\\])', $model)) {
throw new InvalidArgumentException('Model name contains invalid characters.');
}
$model = ltrim($model, '\\/');
$model = str_replace('/', '\\', $model);
$rootNamespace = $this->rootNamespace();
if (Str::startsWith($model, $rootNamespace)) {
return $model;
}
$model = is_dir(app_path('Models'))
? $rootNamespace . 'Models\\' . $model
: $rootNamespace . $model;
return $model;
}
/**
* Resolve the fully-qualified path to the stub.
*
* @param string $stub
* @return string
*/
protected function resolveStubPath($stub)
{
return file_exists($customPath = $this->laravel->basePath(trim($stub, '/')))
? $customPath
: __DIR__ . $stub;
}
}
excel/src/Console/stubs/export.query.stub 0000644 00000000352 15243417774 0014577 0 ustar 00 <?php
namespace DummyNamespace;
use Maatwebsite\Excel\Concerns\FromQuery;
class DummyClass implements FromQuery
{
/**
* @return \Illuminate\Database\Query\Builder
*/
public function query()
{
//
}
}
excel/src/Console/stubs/export.query-model.stub 0000644 00000000441 15243417774 0015674 0 ustar 00 <?php
namespace DummyNamespace;
use DummyFullModelClass;
use Maatwebsite\Excel\Concerns\FromQuery;
class DummyClass implements FromQuery
{
/**
* @return \Illuminate\Database\Query\Builder
*/
public function query()
{
return DummyModelClass::query();
}
}
excel/src/Console/stubs/import.collection.stub 0000644 00000000441 15243417774 0015555 0 ustar 00 <?php
namespace DummyNamespace;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\ToCollection;
class DummyClass implements ToCollection
{
/**
* @param Collection $collection
*/
public function collection(Collection $collection)
{
//
}
}
excel/src/Console/stubs/import.model.stub 0000644 00000000542 15243417774 0014524 0 ustar 00 <?php
namespace DummyNamespace;
use DummyFullModelClass;
use Maatwebsite\Excel\Concerns\ToModel;
class DummyClass implements ToModel
{
/**
* @param array $row
*
* @return \Illuminate\Database\Eloquent\Model|null
*/
public function model(array $row)
{
return new DummyModelClass([
//
]);
}
}
excel/src/Console/stubs/export.model.stub 0000644 00000000452 15243417774 0014533 0 ustar 00 <?php
namespace DummyNamespace;
use DummyFullModelClass;
use Maatwebsite\Excel\Concerns\FromCollection;
class DummyClass implements FromCollection
{
/**
* @return \Illuminate\Support\Collection
*/
public function collection()
{
return DummyModelClass::all();
}
}
excel/src/Console/stubs/export.plain.stub 0000644 00000000365 15243417774 0014541 0 ustar 00 <?php
namespace DummyNamespace;
use Maatwebsite\Excel\Concerns\FromCollection;
class DummyClass implements FromCollection
{
/**
* @return \Illuminate\Support\Collection
*/
public function collection()
{
//
}
}
excel/src/Console/ImportMakeCommand.php 0000755 00000003565 15243417774 0014147 0 ustar 00 <?php
namespace Maatwebsite\Excel\Console;
use Illuminate\Console\GeneratorCommand;
use Symfony\Component\Console\Input\InputOption;
class ImportMakeCommand extends GeneratorCommand
{
use WithModelStub;
/**
* The console command name.
*
* @var string
*/
protected $name = 'make:import';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a new import class';
/**
* The type of class being generated.
*
* @var string
*/
protected $type = 'Import';
/**
* Get the stub file for the generator.
*
* @return string
*/
protected function getStub()
{
return $this->option('model')
? $this->resolveStubPath('/stubs/import.model.stub')
: $this->resolveStubPath('/stubs/import.collection.stub');
}
/**
* Get the default namespace for the class.
*
* @param string $rootNamespace
* @return string
*/
protected function getDefaultNamespace($rootNamespace)
{
return $rootNamespace . '\Imports';
}
/**
* Build the class with the given name.
* Remove the base controller import if we are already in base namespace.
*
* @param string $name
* @return string
*/
protected function buildClass($name)
{
$replace = [];
if ($this->option('model')) {
$replace = $this->buildModelReplacements($replace);
}
return str_replace(
array_keys($replace), array_values($replace), parent::buildClass($name)
);
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [
['model', 'm', InputOption::VALUE_OPTIONAL, 'Generate an import for the given model.'],
];
}
}
excel/src/Console/ExportMakeCommand.php 0000755 00000004337 15243417774 0014154 0 ustar 00 <?php
namespace Maatwebsite\Excel\Console;
use Illuminate\Console\GeneratorCommand;
use Symfony\Component\Console\Input\InputOption;
class ExportMakeCommand extends GeneratorCommand
{
use WithModelStub;
/**
* The console command name.
*
* @var string
*/
protected $name = 'make:export';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a new export class';
/**
* The type of class being generated.
*
* @var string
*/
protected $type = 'Export';
/**
* Get the stub file for the generator.
*
* @return string
*/
protected function getStub()
{
if ($this->option('model') && $this->option('query')) {
return $this->resolveStubPath('/stubs/export.query-model.stub');
} elseif ($this->option('model')) {
return $this->resolveStubPath('/stubs/export.model.stub');
} elseif ($this->option('query')) {
return $this->resolveStubPath('/stubs/export.query.stub');
}
return $this->resolveStubPath('/stubs/export.plain.stub');
}
/**
* Get the default namespace for the class.
*
* @param string $rootNamespace
* @return string
*/
protected function getDefaultNamespace($rootNamespace)
{
return $rootNamespace . '\Exports';
}
/**
* Build the class with the given name.
* Remove the base controller import if we are already in base namespace.
*
* @param string $name
* @return string
*/
protected function buildClass($name)
{
$replace = [];
if ($this->option('model')) {
$replace = $this->buildModelReplacements($replace);
}
return str_replace(
array_keys($replace), array_values($replace), parent::buildClass($name)
);
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [
['model', 'm', InputOption::VALUE_OPTIONAL, 'Generate an export for the given model.'],
['query', '', InputOption::VALUE_NONE, 'Generate an export for a query.'],
];
}
}
excel/src/DefaultValueBinder.php 0000644 00000001075 15243417774 0012672 0 ustar 00 <?php
namespace Maatwebsite\Excel;
use PhpOffice\PhpSpreadsheet\Cell\Cell;
use PhpOffice\PhpSpreadsheet\Cell\DefaultValueBinder as PhpSpreadsheetDefaultValueBinder;
class DefaultValueBinder extends PhpSpreadsheetDefaultValueBinder
{
/**
* @param Cell $cell Cell to bind value to
* @param mixed $value Value to bind in cell
* @return bool
*/
public function bindValue(Cell $cell, $value)
{
if (is_array($value)) {
$value = \json_encode($value);
}
return parent::bindValue($cell, $value);
}
}
excel/src/Concerns/WithColumnLimit.php 0000644 00000000165 15243417774 0014026 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
interface WithColumnLimit
{
public function endColumn(): string;
}
excel/src/Concerns/FromArray.php 0000644 00000000217 15243417774 0012636 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
interface FromArray
{
/**
* @return array
*/
public function array(): array;
}
excel/src/Concerns/WithCharts.php 0000644 00000000275 15243417774 0013020 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
use PhpOffice\PhpSpreadsheet\Chart\Chart;
interface WithCharts
{
/**
* @return Chart|Chart[]
*/
public function charts();
}
excel/src/Concerns/WithCalculatedFormulas.php 0000644 00000000123 15243417774 0015336 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
interface WithCalculatedFormulas
{
}
excel/src/Concerns/SkipsOnFailure.php 0000644 00000000337 15243417774 0013635 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
use Maatwebsite\Excel\Validators\Failure;
interface SkipsOnFailure
{
/**
* @param Failure[] $failures
*/
public function onFailure(Failure ...$failures);
}
excel/src/Concerns/FromGenerator.php 0000644 00000000257 15243417774 0013512 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
use Generator;
interface FromGenerator
{
/**
* @return Generator
*/
public function generator(): Generator;
}
excel/src/Concerns/SkipsUnknownSheets.php 0000644 00000000265 15243417774 0014564 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
interface SkipsUnknownSheets
{
/**
* @param string|int $sheetName
*/
public function onUnknownSheet($sheetName);
}
excel/src/Concerns/FromCollection.php 0000644 00000000273 15243417774 0013655 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
use Illuminate\Support\Collection;
interface FromCollection
{
/**
* @return Collection
*/
public function collection();
}
excel/src/Concerns/WithConditionalSheets.php 0000644 00000001406 15243417774 0015210 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
trait WithConditionalSheets
{
/**
* @var array
*/
protected $conditionallySelectedSheets = [];
/**
* @param string|array $sheets
* @return $this
*/
public function onlySheets($sheets)
{
$this->conditionallySelectedSheets = is_array($sheets) ? $sheets : func_get_args();
return $this;
}
/**
* @return array
*/
public function sheets(): array
{
return \array_filter($this->conditionalSheets(), function ($name) {
return \in_array($name, $this->conditionallySelectedSheets, false);
}, ARRAY_FILTER_USE_KEY);
}
/**
* @return array
*/
abstract public function conditionalSheets(): array;
}
excel/src/Concerns/WithBackgroundColor.php 0000644 00000000324 15243417774 0014645 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
use PhpOffice\PhpSpreadsheet\Style\Color;
interface WithBackgroundColor
{
/**
* @return string|array|Color
*/
public function backgroundColor();
}
excel/src/Concerns/FromIterator.php 0000644 00000000252 15243417774 0013350 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
use Iterator;
interface FromIterator
{
/**
* @return Iterator
*/
public function iterator(): Iterator;
}
excel/src/Concerns/WithStrictNullComparison.php 0000644 00000000125 15243417774 0015724 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
interface WithStrictNullComparison
{
}
excel/src/Concerns/PersistRelations.php 0000644 00000000115 15243417774 0014243 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
interface PersistRelations
{
}
excel/src/Concerns/WithDrawings.php 0000644 00000000327 15243417774 0013350 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
use PhpOffice\PhpSpreadsheet\Worksheet\BaseDrawing;
interface WithDrawings
{
/**
* @return BaseDrawing|BaseDrawing[]
*/
public function drawings();
}
excel/src/Concerns/Exportable.php 0000644 00000006277 15243417774 0013055 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
use Illuminate\Foundation\Bus\PendingDispatch;
use Maatwebsite\Excel\Exceptions\NoFilenameGivenException;
use Maatwebsite\Excel\Exceptions\NoFilePathGivenException;
use Maatwebsite\Excel\Exporter;
trait Exportable
{
/**
* @param string $fileName
* @param string|null $writerType
* @param array $headers
* @return \Illuminate\Http\Response|\Symfony\Component\HttpFoundation\BinaryFileResponse
*
* @throws NoFilenameGivenException
*/
public function download(string $fileName = null, string $writerType = null, array $headers = null)
{
$headers = $headers ?? $this->headers ?? [];
$fileName = $fileName ?? $this->fileName ?? null;
$writerType = $writerType ?? $this->writerType ?? null;
if (null === $fileName) {
throw new NoFilenameGivenException();
}
return $this->getExporter()->download($this, $fileName, $writerType, $headers);
}
/**
* @param string $filePath
* @param string|null $disk
* @param string|null $writerType
* @param mixed $diskOptions
* @return bool|PendingDispatch
*
* @throws NoFilePathGivenException
*/
public function store(string $filePath = null, string $disk = null, string $writerType = null, $diskOptions = [])
{
$filePath = $filePath ?? $this->filePath ?? null;
if (null === $filePath) {
throw NoFilePathGivenException::export();
}
return $this->getExporter()->store(
$this,
$filePath,
$disk ?? $this->disk ?? null,
$writerType ?? $this->writerType ?? null,
$diskOptions ?: $this->diskOptions ?? []
);
}
/**
* @param string|null $filePath
* @param string|null $disk
* @param string|null $writerType
* @param mixed $diskOptions
* @return PendingDispatch
*
* @throws NoFilePathGivenException
*/
public function queue(string $filePath = null, string $disk = null, string $writerType = null, $diskOptions = [])
{
$filePath = $filePath ?? $this->filePath ?? null;
if (null === $filePath) {
throw NoFilePathGivenException::export();
}
return $this->getExporter()->queue(
$this,
$filePath,
$disk ?? $this->disk ?? null,
$writerType ?? $this->writerType ?? null,
$diskOptions ?: $this->diskOptions ?? []
);
}
/**
* @param string|null $writerType
* @return string
*/
public function raw($writerType = null)
{
$writerType = $writerType ?? $this->writerType ?? null;
return $this->getExporter()->raw($this, $writerType);
}
/**
* Create an HTTP response that represents the object.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*
* @throws NoFilenameGivenException
*/
public function toResponse($request)
{
return $this->download();
}
/**
* @return Exporter
*/
private function getExporter(): Exporter
{
return app(Exporter::class);
}
}
excel/src/Concerns/WithUpserts.php 0000644 00000000224 15243417774 0013233 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
interface WithUpserts
{
/**
* @return string|array
*/
public function uniqueBy();
}
excel/src/Concerns/WithFormatData.php 0000644 00000000113 15243417774 0013605 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
interface WithFormatData
{
}
excel/src/Concerns/FromQuery.php 0000644 00000000565 15243417774 0012673 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Query\Builder;
use Laravel\Scout\Builder as ScoutBuilder;
interface FromQuery
{
/**
* @return Builder|EloquentBuilder|Relation|ScoutBuilder
*/
public function query();
}
excel/src/Concerns/Importable.php 0000644 00000007504 15243417774 0013040 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
use Illuminate\Console\OutputStyle;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\PendingDispatch;
use Illuminate\Support\Collection;
use InvalidArgumentException;
use Maatwebsite\Excel\Exceptions\NoFilePathGivenException;
use Maatwebsite\Excel\Importer;
use Symfony\Component\Console\Input\StringInput;
use Symfony\Component\Console\Output\NullOutput;
use Symfony\Component\HttpFoundation\File\UploadedFile;
trait Importable
{
/**
* @var OutputStyle|null
*/
protected $output;
/**
* @param string|UploadedFile|null $filePath
* @param string|null $disk
* @param string|null $readerType
* @return Importer|PendingDispatch
*
* @throws NoFilePathGivenException
*/
public function import($filePath = null, string $disk = null, string $readerType = null)
{
$filePath = $this->getFilePath($filePath);
return $this->getImporter()->import(
$this,
$filePath,
$disk ?? $this->disk ?? null,
$readerType ?? $this->readerType ?? null
);
}
/**
* @param string|UploadedFile|null $filePath
* @param string|null $disk
* @param string|null $readerType
* @return array
*
* @throws NoFilePathGivenException
*/
public function toArray($filePath = null, string $disk = null, string $readerType = null): array
{
$filePath = $this->getFilePath($filePath);
return $this->getImporter()->toArray(
$this,
$filePath,
$disk ?? $this->disk ?? null,
$readerType ?? $this->readerType ?? null
);
}
/**
* @param string|UploadedFile|null $filePath
* @param string|null $disk
* @param string|null $readerType
* @return Collection
*
* @throws NoFilePathGivenException
*/
public function toCollection($filePath = null, string $disk = null, string $readerType = null): Collection
{
$filePath = $this->getFilePath($filePath);
return $this->getImporter()->toCollection(
$this,
$filePath,
$disk ?? $this->disk ?? null,
$readerType ?? $this->readerType ?? null
);
}
/**
* @param string|UploadedFile|null $filePath
* @param string|null $disk
* @param string|null $readerType
* @return PendingDispatch
*
* @throws NoFilePathGivenException
* @throws InvalidArgumentException
*/
public function queue($filePath = null, string $disk = null, string $readerType = null)
{
if (!$this instanceof ShouldQueue) {
throw new InvalidArgumentException('Importable should implement ShouldQueue to be queued.');
}
return $this->import($filePath, $disk, $readerType);
}
/**
* @param OutputStyle $output
* @return $this
*/
public function withOutput(OutputStyle $output)
{
$this->output = $output;
return $this;
}
/**
* @return OutputStyle
*/
public function getConsoleOutput(): OutputStyle
{
if (!$this->output instanceof OutputStyle) {
$this->output = new OutputStyle(new StringInput(''), new NullOutput());
}
return $this->output;
}
/**
* @param UploadedFile|string|null $filePath
* @return UploadedFile|string
*
* @throws NoFilePathGivenException
*/
private function getFilePath($filePath = null)
{
$filePath = $filePath ?? $this->filePath ?? null;
if (null === $filePath) {
throw NoFilePathGivenException::import();
}
return $filePath;
}
/**
* @return Importer
*/
private function getImporter(): Importer
{
return app(Importer::class);
}
}
excel/src/Concerns/WithHeadings.php 0000644 00000000225 15243417774 0013311 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
interface WithHeadings
{
/**
* @return array
*/
public function headings(): array;
}
excel/src/Concerns/WithProgressBar.php 0000644 00000000321 15243417774 0014015 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
use Illuminate\Console\OutputStyle;
interface WithProgressBar
{
/**
* @return OutputStyle
*/
public function getConsoleOutput(): OutputStyle;
}
excel/src/Concerns/RemembersRowNumber.php 0000644 00000000627 15243417774 0014523 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
trait RemembersRowNumber
{
/**
* @var int
*/
protected $rowNumber;
/**
* @param int $rowNumber
*/
public function rememberRowNumber(int $rowNumber)
{
$this->rowNumber = $rowNumber;
}
/**
* @return int|null
*/
public function getRowNumber()
{
return $this->rowNumber;
}
}
excel/src/Concerns/WithBatchInserts.php 0000644 00000000226 15243417774 0014161 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
interface WithBatchInserts
{
/**
* @return int
*/
public function batchSize(): int;
}
excel/src/Concerns/WithMappedCells.php 0000644 00000000227 15243417774 0013762 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
interface WithMappedCells
{
/**
* @return array
*/
public function mapping(): array;
}
excel/src/Concerns/SkipsOnError.php 0000644 00000000261 15243417774 0013333 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
use Throwable;
interface SkipsOnError
{
/**
* @param Throwable $e
*/
public function onError(Throwable $e);
}
excel/src/Concerns/WithMultipleSheets.php 0000644 00000000231 15243417774 0014533 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
interface WithMultipleSheets
{
/**
* @return array
*/
public function sheets(): array;
}
excel/src/Concerns/WithValidation.php 0000644 00000000224 15243417774 0013660 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
interface WithValidation
{
/**
* @return array
*/
public function rules(): array;
}
excel/src/Concerns/WithGroupedHeadingRow.php 0000644 00000000151 15243417774 0015142 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
interface WithGroupedHeadingRow extends WithHeadingRow
{
}
excel/src/Concerns/WithCustomCsvSettings.php 0000644 00000000244 15243417774 0015237 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
interface WithCustomCsvSettings
{
/**
* @return array
*/
public function getCsvSettings(): array;
}
excel/src/Concerns/WithProperties.php 0000644 00000000164 15243417774 0013725 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
interface WithProperties
{
public function properties(): array;
}
excel/src/Concerns/WithColumnWidths.php 0000644 00000000170 15243417774 0014206 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
interface WithColumnWidths
{
public function columnWidths(): array;
}
excel/src/Concerns/WithUpsertColumns.php 0000644 00000000230 15243417774 0014406 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
interface WithUpsertColumns
{
/**
* @return array
*/
public function upsertColumns();
}
excel/src/Concerns/ShouldAutoSize.php 0000644 00000000113 15243417774 0013651 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
interface ShouldAutoSize
{
}
excel/src/Concerns/WithChunkReading.php 0000644 00000000226 15243417774 0014132 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
interface WithChunkReading
{
/**
* @return int
*/
public function chunkSize(): int;
}
excel/src/Concerns/ShouldQueueWithoutChain.php 0000644 00000000225 15243417774 0015525 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
use Illuminate\Contracts\Queue\ShouldQueue;
interface ShouldQueueWithoutChain extends ShouldQueue
{
}
excel/src/Concerns/WithPreCalculateFormulas.php 0000644 00000000125 15243417774 0015643 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
interface WithPreCalculateFormulas
{
}
excel/src/Concerns/ToCollection.php 0000644 00000000334 15243417774 0013332 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
use Illuminate\Support\Collection;
interface ToCollection
{
/**
* @param Collection $collection
*/
public function collection(Collection $collection);
}
excel/src/Concerns/SkipsFailures.php 0000644 00000001055 15243417774 0013521 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Validators\Failure;
trait SkipsFailures
{
/**
* @var Failure[]
*/
protected $failures = [];
/**
* @param Failure ...$failures
*/
public function onFailure(Failure ...$failures)
{
$this->failures = array_merge($this->failures, $failures);
}
/**
* @return Failure[]|Collection
*/
public function failures(): Collection
{
return new Collection($this->failures);
}
}
excel/src/Concerns/WithStyles.php 0000644 00000000250 15243417774 0013050 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
interface WithStyles
{
public function styles(Worksheet $sheet);
}
excel/src/Concerns/SkipsEmptyRows.php 0000644 00000000113 15243417774 0013712 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
interface SkipsEmptyRows
{
}
excel/src/Concerns/WithLimit.php 0000644 00000000213 15243417774 0012642 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
interface WithLimit
{
/**
* @return int
*/
public function limit(): int;
}
excel/src/Concerns/OnEachRow.php 0000644 00000000260 15243417774 0012557 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
use Maatwebsite\Excel\Row;
interface OnEachRow
{
/**
* @param Row $row
*/
public function onRow(Row $row);
}
excel/src/Concerns/WithEvents.php 0000644 00000000231 15243417774 0013030 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
interface WithEvents
{
/**
* @return array
*/
public function registerEvents(): array;
}
excel/src/Concerns/WithCustomChunkSize.php 0000644 00000000231 15243417774 0014662 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
interface WithCustomChunkSize
{
/**
* @return int
*/
public function chunkSize(): int;
}
excel/src/Concerns/ToModel.php 0000644 00000000341 15243417774 0012275 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
use Illuminate\Database\Eloquent\Model;
interface ToModel
{
/**
* @param array $row
* @return Model|Model[]|null
*/
public function model(array $row);
}
excel/src/Concerns/ToArray.php 0000644 00000000232 15243417774 0012312 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
interface ToArray
{
/**
* @param array $array
*/
public function array(array $array);
}
excel/src/Concerns/HasReferencesToOtherSheets.php 0000644 00000000127 15243417774 0016132 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
interface HasReferencesToOtherSheets
{
}
excel/src/Concerns/SkipsErrors.php 0000644 00000000727 15243417774 0013230 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
use Illuminate\Support\Collection;
use Throwable;
trait SkipsErrors
{
/**
* @var Throwable[]
*/
protected $errors = [];
/**
* @param Throwable $e
*/
public function onError(Throwable $e)
{
$this->errors[] = $e;
}
/**
* @return Throwable[]|Collection
*/
public function errors(): Collection
{
return new Collection($this->errors);
}
}
excel/src/Concerns/WithMapping.php 0000644 00000000326 15243417774 0013164 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
/**
* @template RowType of mixed
*/
interface WithMapping
{
/**
* @param RowType $row
* @return array
*/
public function map($row): array;
}
excel/src/Concerns/WithStartRow.php 0000644 00000000221 15243417774 0013350 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
interface WithStartRow
{
/**
* @return int
*/
public function startRow(): int;
}
excel/src/Concerns/WithReadFilter.php 0000644 00000000327 15243417774 0013613 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
use PhpOffice\PhpSpreadsheet\Reader\IReadFilter;
interface WithReadFilter
{
/**
* @return IReadFilter
*/
public function readFilter(): IReadFilter;
}
excel/src/Concerns/WithCustomValueBinder.php 0000644 00000000230 15243417774 0015156 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
use PhpOffice\PhpSpreadsheet\Cell\IValueBinder;
interface WithCustomValueBinder extends IValueBinder
{
}
excel/src/Concerns/WithDefaultStyles.php 0000644 00000000333 15243417774 0014357 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
use PhpOffice\PhpSpreadsheet\Style\Style;
interface WithDefaultStyles
{
/**
* @return array|void
*/
public function defaultStyles(Style $defaultStyle);
}
excel/src/Concerns/WithColumnFormatting.php 0000644 00000000242 15243417774 0015056 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
interface WithColumnFormatting
{
/**
* @return array
*/
public function columnFormats(): array;
}
excel/src/Concerns/RegistersEventListeners.php 0000644 00000002565 15243417774 0015606 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
use Maatwebsite\Excel\Events\AfterBatch;
use Maatwebsite\Excel\Events\AfterChunk;
use Maatwebsite\Excel\Events\AfterImport;
use Maatwebsite\Excel\Events\AfterSheet;
use Maatwebsite\Excel\Events\BeforeExport;
use Maatwebsite\Excel\Events\BeforeImport;
use Maatwebsite\Excel\Events\BeforeSheet;
use Maatwebsite\Excel\Events\BeforeWriting;
use Maatwebsite\Excel\Events\ImportFailed;
trait RegistersEventListeners
{
/**
* @return array
*/
public function registerEvents(): array
{
$listenersClasses = [
BeforeExport::class => 'beforeExport',
BeforeWriting::class => 'beforeWriting',
BeforeImport::class => 'beforeImport',
AfterImport::class => 'afterImport',
AfterBatch::class => 'afterBatch',
AfterChunk::class => 'afterChunk',
ImportFailed::class => 'importFailed',
BeforeSheet::class => 'beforeSheet',
AfterSheet::class => 'afterSheet',
];
$listeners = [];
foreach ($listenersClasses as $class => $name) {
// Method names are case insensitive in php
if (method_exists($this, $name)) {
// Allow methods to not be static
$listeners[$class] = [$this, $name];
}
}
return $listeners;
}
}
excel/src/Concerns/WithTitle.php 0000644 00000000221 15243417774 0012644 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
interface WithTitle
{
/**
* @return string
*/
public function title(): string;
}
excel/src/Concerns/WithCustomStartCell.php 0000644 00000000237 15243417774 0014662 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
interface WithCustomStartCell
{
/**
* @return string
*/
public function startCell(): string;
}
excel/src/Concerns/WithHeadingRow.php 0000644 00000000113 15243417774 0013612 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
interface WithHeadingRow
{
}
excel/src/Concerns/RemembersChunkOffset.php 0000644 00000000651 15243417774 0015017 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
trait RemembersChunkOffset
{
/**
* @var int|null
*/
protected $chunkOffset;
/**
* @param int $chunkOffset
*/
public function setChunkOffset(int $chunkOffset)
{
$this->chunkOffset = $chunkOffset;
}
/**
* @return int|null
*/
public function getChunkOffset()
{
return $this->chunkOffset;
}
}
excel/src/Concerns/MapsCsvSettings.php 0000644 00000004215 15243417774 0014033 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
use Illuminate\Support\Arr;
trait MapsCsvSettings
{
/**
* @var string
*/
protected static $delimiter = ',';
/**
* @var string
*/
protected static $enclosure = '"';
/**
* @var string
*/
protected static $lineEnding = PHP_EOL;
/**
* @var bool
*/
protected static $useBom = false;
/**
* @var bool
*/
protected static $includeSeparatorLine = false;
/**
* @var bool
*/
protected static $excelCompatibility = false;
/**
* @var string
*/
protected static $escapeCharacter = '\\';
/**
* @var bool
*/
protected static $contiguous = false;
/**
* @var string
*/
protected static $inputEncoding = 'UTF-8';
/**
* @var string
*/
protected static $outputEncoding = '';
/**
* @var bool
*/
protected static $testAutoDetect = true;
/**
* @param array $config
*/
public static function applyCsvSettings(array $config)
{
static::$delimiter = Arr::get($config, 'delimiter', static::$delimiter);
static::$enclosure = Arr::get($config, 'enclosure', static::$enclosure);
static::$lineEnding = Arr::get($config, 'line_ending', static::$lineEnding);
static::$useBom = Arr::get($config, 'use_bom', static::$useBom);
static::$includeSeparatorLine = Arr::get($config, 'include_separator_line', static::$includeSeparatorLine);
static::$excelCompatibility = Arr::get($config, 'excel_compatibility', static::$excelCompatibility);
static::$escapeCharacter = Arr::get($config, 'escape_character', static::$escapeCharacter);
static::$contiguous = Arr::get($config, 'contiguous', static::$contiguous);
static::$inputEncoding = Arr::get($config, 'input_encoding', static::$inputEncoding);
static::$outputEncoding = Arr::get($config, 'output_encoding', static::$outputEncoding);
static::$testAutoDetect = Arr::get($config, 'test_auto_detect', static::$testAutoDetect);
}
}
excel/src/Concerns/WithCustomQuerySize.php 0000644 00000001245 15243417774 0014725 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
interface WithCustomQuerySize
{
/**
* Queued exportables are processed in chunks; each chunk being a job pushed to the queue by the QueuedWriter.
* In case of exportables that implement the FromQuery concern, the number of jobs is calculated by dividing the $query->count() by the chunk size.
* Depending on the implementation of the query() method (eg. When using a groupBy clause), this calculation might not be correct.
*
* When this is the case, you should use this method to provide a custom calculation of the query size.
*
* @return int
*/
public function querySize(): int;
}
excel/src/Concerns/FromView.php 0000644 00000000260 15243417774 0012470 0 ustar 00 <?php
namespace Maatwebsite\Excel\Concerns;
use Illuminate\Contracts\View\View;
interface FromView
{
/**
* @return View
*/
public function view(): View;
}
excel/src/Row.php 0000644 00000010175 15243417774 0007735 0 ustar 00 <?php
namespace Maatwebsite\Excel;
use ArrayAccess;
use Closure;
use Illuminate\Support\Collection;
use PhpOffice\PhpSpreadsheet\Worksheet\Row as SpreadsheetRow;
/** @mixin SpreadsheetRow */
class Row implements ArrayAccess
{
use DelegatedMacroable;
/**
* @var array
*/
protected $headingRow = [];
/**
* @var array
*/
protected $headerIsGrouped = [];
/**
* @var \Closure
*/
protected $preparationCallback;
/**
* @var SpreadsheetRow
*/
protected $row;
/**
* @var array|null
*/
protected $rowCache;
/**
* @var bool|null
*/
protected $rowCacheFormatData;
/**
* @var string|null
*/
protected $rowCacheEndColumn;
/**
* @param SpreadsheetRow $row
* @param array $headingRow
* @param array $headerIsGrouped
*/
public function __construct(SpreadsheetRow $row, array $headingRow = [], array $headerIsGrouped = [])
{
$this->row = $row;
$this->headingRow = $headingRow;
$this->headerIsGrouped = $headerIsGrouped;
}
/**
* @return SpreadsheetRow
*/
public function getDelegate(): SpreadsheetRow
{
return $this->row;
}
/**
* @param null $nullValue
* @param bool $calculateFormulas
* @param bool $formatData
* @param string|null $endColumn
* @return Collection
*/
public function toCollection($nullValue = null, $calculateFormulas = false, $formatData = true, ?string $endColumn = null): Collection
{
return new Collection($this->toArray($nullValue, $calculateFormulas, $formatData, $endColumn));
}
/**
* @param null $nullValue
* @param bool $calculateFormulas
* @param bool $formatData
* @param string|null $endColumn
* @return array
*/
public function toArray($nullValue = null, $calculateFormulas = false, $formatData = true, ?string $endColumn = null)
{
if (is_array($this->rowCache) && ($this->rowCacheFormatData === $formatData) && ($this->rowCacheEndColumn === $endColumn)) {
return $this->rowCache;
}
$cells = [];
$i = 0;
foreach ($this->row->getCellIterator('A', $endColumn) as $cell) {
$value = (new Cell($cell))->getValue($nullValue, $calculateFormulas, $formatData);
if (isset($this->headingRow[$i])) {
if (!$this->headerIsGrouped[$i]) {
$cells[$this->headingRow[$i]] = $value;
} else {
$cells[$this->headingRow[$i]][] = $value;
}
} else {
$cells[] = $value;
}
$i++;
}
if (isset($this->preparationCallback)) {
$cells = ($this->preparationCallback)($cells, $this->row->getRowIndex());
}
$this->rowCache = $cells;
$this->rowCacheFormatData = $formatData;
$this->rowCacheEndColumn = $endColumn;
return $cells;
}
/**
* @param bool $calculateFormulas
* @param string|null $endColumn
* @return bool
*/
public function isEmpty($calculateFormulas = false, ?string $endColumn = null): bool
{
return count(array_filter($this->toArray(null, $calculateFormulas, false, $endColumn))) === 0;
}
/**
* @return int
*/
public function getIndex(): int
{
return $this->row->getRowIndex();
}
#[\ReturnTypeWillChange]
public function offsetExists($offset)
{
return isset($this->toArray()[$offset]);
}
#[\ReturnTypeWillChange]
public function offsetGet($offset)
{
return $this->toArray()[$offset];
}
#[\ReturnTypeWillChange]
public function offsetSet($offset, $value)
{
//
}
#[\ReturnTypeWillChange]
public function offsetUnset($offset)
{
//
}
/**
* @param \Closure $preparationCallback
*
* @internal
*/
public function setPreparationCallback(Closure $preparationCallback = null)
{
$this->preparationCallback = $preparationCallback;
}
}
excel/src/Importer.php 0000644 00000003034 15243417774 0010763 0 ustar 00 <?php
namespace Maatwebsite\Excel;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Support\Collection;
interface Importer
{
/**
* @param object $import
* @param string|\Symfony\Component\HttpFoundation\File\UploadedFile $filePath
* @param string|null $disk
* @param string|null $readerType
* @return Reader|\Illuminate\Foundation\Bus\PendingDispatch
*/
public function import($import, $filePath, string $disk = null, string $readerType = null);
/**
* @param object $import
* @param string|\Symfony\Component\HttpFoundation\File\UploadedFile $filePath
* @param string|null $disk
* @param string|null $readerType
* @return array
*/
public function toArray($import, $filePath, string $disk = null, string $readerType = null): array;
/**
* @param object $import
* @param string|\Symfony\Component\HttpFoundation\File\UploadedFile $filePath
* @param string|null $disk
* @param string|null $readerType
* @return Collection
*/
public function toCollection($import, $filePath, string $disk = null, string $readerType = null): Collection;
/**
* @param ShouldQueue $import
* @param string|\Symfony\Component\HttpFoundation\File\UploadedFile $filePath
* @param string|null $disk
* @param string $readerType
* @return \Illuminate\Foundation\Bus\PendingDispatch
*/
public function queueImport(ShouldQueue $import, $filePath, string $disk = null, string $readerType = null);
}
excel/src/Helpers/FileTypeDetector.php 0000644 00000002455 15243417774 0014005 0 ustar 00 <?php
namespace Maatwebsite\Excel\Helpers;
use Maatwebsite\Excel\Exceptions\NoTypeDetectedException;
use Symfony\Component\HttpFoundation\File\UploadedFile;
class FileTypeDetector
{
/**
* @param $filePath
* @param string|null $type
* @return string|null
*
* @throws NoTypeDetectedException
*/
public static function detect($filePath, string $type = null)
{
if (null !== $type) {
return $type;
}
if (!$filePath instanceof UploadedFile) {
$pathInfo = pathinfo($filePath);
$extension = $pathInfo['extension'] ?? '';
} else {
$extension = $filePath->getClientOriginalExtension();
}
if (null === $type && trim($extension) === '') {
throw new NoTypeDetectedException();
}
return config('excel.extension_detector.' . strtolower($extension));
}
/**
* @param string $filePath
* @param string|null $type
* @return string
*
* @throws NoTypeDetectedException
*/
public static function detectStrict(string $filePath, string $type = null): string
{
$type = static::detect($filePath, $type);
if (!$type) {
throw new NoTypeDetectedException();
}
return $type;
}
}
excel/src/Helpers/CellHelper.php 0000644 00000000437 15243417774 0012607 0 ustar 00 <?php
namespace Maatwebsite\Excel\Helpers;
class CellHelper
{
/**
* @param string $coordinate
* @return string
*/
public static function getColumnFromCoordinate(string $coordinate): string
{
return preg_replace('/[0-9]/', '', $coordinate);
}
}
excel/src/Helpers/ArrayHelper.php 0000644 00000001170 15243417774 0013001 0 ustar 00 <?php
namespace Maatwebsite\Excel\Helpers;
class ArrayHelper
{
/**
* @param array $array
* @return array
*/
public static function ensureMultipleRows(array $array): array
{
if (static::hasMultipleRows($array)) {
return $array;
}
return [$array];
}
/**
* Only have multiple rows, if each
* element in the array is an array itself.
*
* @param array $array
* @return bool
*/
public static function hasMultipleRows(array $array): bool
{
return count($array) === count(array_filter($array, 'is_array'));
}
}
excel/src/Fakes/ExcelFake.php 0000644 00000024124 15243417774 0012045 0 ustar 00 <?php
namespace Maatwebsite\Excel\Fakes;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\PendingDispatch;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Queue;
use Maatwebsite\Excel\Exporter;
use Maatwebsite\Excel\Importer;
use Maatwebsite\Excel\Reader;
use PHPUnit\Framework\Assert;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\File\UploadedFile;
class ExcelFake implements Exporter, Importer
{
/**
* @var array
*/
protected $downloads = [];
/**
* @var array
*/
protected $stored = [];
/**
* @var array
*/
protected $queued = [];
/**
* @var array
*/
protected $raws = [];
/**
* @var array
*/
protected $imported = [];
/**
* @var bool
*/
protected $matchByRegex = false;
/**
* @var object|null
*/
protected $job;
/**
* {@inheritdoc}
*/
public function download($export, string $fileName, string $writerType = null, array $headers = [])
{
$this->downloads[$fileName] = $export;
return new BinaryFileResponse(__DIR__ . '/fake_file');
}
/**
* {@inheritdoc}
*
* @param string|null $diskName Fallback for usage with named properties
*/
public function store($export, string $filePath, string $disk = null, string $writerType = null, $diskOptions = [], string $diskName = null)
{
if ($export instanceof ShouldQueue) {
return $this->queue($export, $filePath, $disk ?: $diskName, $writerType);
}
$this->stored[$disk ?: $diskName ?: 'default'][$filePath] = $export;
return true;
}
/**
* {@inheritdoc}
*/
public function queue($export, string $filePath, string $disk = null, string $writerType = null, $diskOptions = [])
{
Queue::fake();
$this->stored[$disk ?? 'default'][$filePath] = $export;
$this->queued[$disk ?? 'default'][$filePath] = $export;
$this->job = new class
{
use Queueable;
public function handle()
{
//
}
};
Queue::push($this->job);
return new PendingDispatch($this->job);
}
/**
* @param object $export
* @param string $writerType
* @return string
*/
public function raw($export, string $writerType)
{
$this->raws[get_class($export)] = $export;
return 'RAW-CONTENTS';
}
/**
* @param object $import
* @param string|UploadedFile $file
* @param string|null $disk
* @param string|null $readerType
* @return Reader|PendingDispatch
*/
public function import($import, $file, string $disk = null, string $readerType = null)
{
if ($import instanceof ShouldQueue) {
return $this->queueImport($import, $file, $disk, $readerType);
}
$filePath = ($file instanceof UploadedFile) ? $file->getClientOriginalName() : $file;
$this->imported[$disk ?? 'default'][$filePath] = $import;
return $this;
}
/**
* @param object $import
* @param string|UploadedFile $file
* @param string|null $disk
* @param string|null $readerType
* @return array
*/
public function toArray($import, $file, string $disk = null, string $readerType = null): array
{
$filePath = ($file instanceof UploadedFile) ? $file->getFilename() : $file;
$this->imported[$disk ?? 'default'][$filePath] = $import;
return [];
}
/**
* @param object $import
* @param string|UploadedFile $file
* @param string|null $disk
* @param string|null $readerType
* @return Collection
*/
public function toCollection($import, $file, string $disk = null, string $readerType = null): Collection
{
$filePath = ($file instanceof UploadedFile) ? $file->getFilename() : $file;
$this->imported[$disk ?? 'default'][$filePath] = $import;
return new Collection();
}
/**
* @param ShouldQueue $import
* @param string|UploadedFile $file
* @param string|null $disk
* @param string $readerType
* @return PendingDispatch
*/
public function queueImport(ShouldQueue $import, $file, string $disk = null, string $readerType = null)
{
Queue::fake();
$filePath = ($file instanceof UploadedFile) ? $file->getFilename() : $file;
$this->queued[$disk ?? 'default'][$filePath] = $import;
$this->imported[$disk ?? 'default'][$filePath] = $import;
$this->job = new class
{
use Queueable;
public function handle()
{
//
}
};
Queue::push($this->job);
return new PendingDispatch($this->job);
}
/**
* When asserting downloaded, stored, queued or imported, use regular expression
* to look for a matching file path.
*
* @return void
*/
public function matchByRegex()
{
$this->matchByRegex = true;
}
/**
* When asserting downloaded, stored, queued or imported, use regular string
* comparison for matching file path.
*
* @return void
*/
public function doNotMatchByRegex()
{
$this->matchByRegex = false;
}
/**
* @param string $fileName
* @param callable|null $callback
*/
public function assertDownloaded(string $fileName, $callback = null)
{
$fileName = $this->assertArrayHasKey($fileName, $this->downloads, sprintf('%s is not downloaded', $fileName));
$callback = $callback ?: function () {
return true;
};
Assert::assertTrue(
$callback($this->downloads[$fileName]),
"The file [{$fileName}] was not downloaded with the expected data."
);
}
/**
* @param string $filePath
* @param string|callable|null $disk
* @param callable|null $callback
*/
public function assertStored(string $filePath, $disk = null, $callback = null)
{
if (is_callable($disk)) {
$callback = $disk;
$disk = null;
}
$disk = $disk ?? 'default';
$storedOnDisk = $this->stored[$disk] ?? [];
$filePath = $this->assertArrayHasKey(
$filePath,
$storedOnDisk,
sprintf('%s is not stored on disk %s', $filePath, $disk)
);
$callback = $callback ?: function () {
return true;
};
Assert::assertTrue(
$callback($storedOnDisk[$filePath]),
"The file [{$filePath}] was not stored with the expected data."
);
}
/**
* @param string $filePath
* @param string|callable|null $disk
* @param callable|null $callback
*/
public function assertQueued(string $filePath, $disk = null, $callback = null)
{
if (is_callable($disk)) {
$callback = $disk;
$disk = null;
}
$disk = $disk ?? 'default';
$queuedForDisk = $this->queued[$disk] ?? [];
$filePath = $this->assertArrayHasKey(
$filePath,
$queuedForDisk,
sprintf('%s is not queued for export on disk %s', $filePath, $disk)
);
$callback = $callback ?: function () {
return true;
};
Assert::assertTrue(
$callback($queuedForDisk[$filePath]),
"The file [{$filePath}] was not stored with the expected data."
);
}
public function assertQueuedWithChain($chain): void
{
Queue::assertPushedWithChain(get_class($this->job), $chain);
}
/**
* @param string $classname
* @param callable|null $callback
*/
public function assertExportedInRaw(string $classname, $callback = null)
{
Assert::assertArrayHasKey($classname, $this->raws, sprintf('%s is not exported in raw', $classname));
$callback = $callback ?: function () {
return true;
};
Assert::assertTrue(
$callback($this->raws[$classname]),
"The [{$classname}] export was not exported in raw with the expected data."
);
}
/**
* @param string $filePath
* @param string|callable|null $disk
* @param callable|null $callback
*/
public function assertImported(string $filePath, $disk = null, $callback = null)
{
if (is_callable($disk)) {
$callback = $disk;
$disk = null;
}
$disk = $disk ?? 'default';
$importedOnDisk = $this->imported[$disk] ?? [];
$filePath = $this->assertArrayHasKey(
$filePath,
$importedOnDisk,
sprintf('%s is not stored on disk %s', $filePath, $disk)
);
$callback = $callback ?: function () {
return true;
};
Assert::assertTrue(
$callback($importedOnDisk[$filePath]),
"The file [{$filePath}] was not imported with the expected data."
);
}
/**
* Asserts that an array has a specified key and returns the key if successful.
*
* @see matchByRegex for more information about file path matching
*
* @param string $key
* @param array $array
* @param string $message
* @return string
*
* @throws ExpectationFailedException
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws Exception
*/
protected function assertArrayHasKey(string $key, array $disk, string $message = ''): string
{
if ($this->matchByRegex) {
$files = array_keys($disk);
$results = preg_grep($key, $files);
Assert::assertGreaterThan(0, count($results), $message);
Assert::assertEquals(1, count($results), "More than one result matches the file name expression '$key'.");
return array_values($results)[0];
}
Assert::assertArrayHasKey($key, $disk, $message);
return $key;
}
}
excel/src/Fakes/fake_file 0000644 00000000000 15243417774 0011320 0 ustar 00 excel/src/HeadingRowImport.php 0000644 00000001670 15243417774 0012410 0 ustar 00 <?php
namespace Maatwebsite\Excel;
use Maatwebsite\Excel\Concerns\Importable;
use Maatwebsite\Excel\Concerns\WithLimit;
use Maatwebsite\Excel\Concerns\WithMapping;
use Maatwebsite\Excel\Concerns\WithStartRow;
use Maatwebsite\Excel\Imports\HeadingRowFormatter;
class HeadingRowImport implements WithStartRow, WithLimit, WithMapping
{
use Importable;
/**
* @var int
*/
private $headingRow;
/**
* @param int $headingRow
*/
public function __construct(int $headingRow = 1)
{
$this->headingRow = $headingRow;
}
/**
* @return int
*/
public function startRow(): int
{
return $this->headingRow;
}
/**
* @return int
*/
public function limit(): int
{
return 1;
}
/**
* @param mixed $row
* @return array
*/
public function map($row): array
{
return HeadingRowFormatter::format($row);
}
}
excel/src/Mixins/StoreQueryMacro.php 0000644 00000003565 15243417774 0013546 0 ustar 00 <?php
namespace Maatwebsite\Excel\Mixins;
use Illuminate\Database\Eloquent\Builder;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Sheet;
class StoreQueryMacro
{
public function __invoke()
{
return function (string $filePath, string $disk = null, string $writerType = null, $withHeadings = false) {
$export = new class($this, $withHeadings) implements FromQuery, WithHeadings
{
use Exportable;
/**
* @var bool
*/
private $withHeadings;
/**
* @var Builder
*/
private $query;
/**
* @param $query
* @param bool $withHeadings
*/
public function __construct($query, bool $withHeadings = false)
{
$this->query = $query;
$this->withHeadings = $withHeadings;
}
/**
* @return Builder
*/
public function query()
{
return $this->query;
}
/**
* @return array
*/
public function headings(): array
{
if (!$this->withHeadings) {
return [];
}
$firstRow = (clone $this->query)->first();
if ($firstRow) {
return array_keys(Sheet::mapArraybleRow($firstRow));
}
return [];
}
};
return $export->store($filePath, $disk, $writerType);
};
}
}
excel/src/Mixins/ImportMacro.php 0000644 00000002266 15243417774 0012673 0 ustar 00 <?php
namespace Maatwebsite\Excel\Mixins;
use Illuminate\Database\Eloquent\Model;
use Maatwebsite\Excel\Concerns\Importable;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
class ImportMacro
{
public function __invoke()
{
return function (string $filename, string $disk = null, string $readerType = null) {
$import = new class(get_class($this->getModel())) implements ToModel, WithHeadingRow
{
use Importable;
/**
* @var string
*/
private $model;
/**
* @param string $model
*/
public function __construct(string $model)
{
$this->model = $model;
}
/**
* @param array $row
* @return Model|Model[]|null
*/
public function model(array $row)
{
return (new $this->model)->fill($row);
}
};
return $import->import($filename, $disk, $readerType);
};
}
}
excel/src/Mixins/ImportAsMacro.php 0000644 00000002664 15243417774 0013161 0 ustar 00 <?php
namespace Maatwebsite\Excel\Mixins;
use Illuminate\Database\Eloquent\Model;
use Maatwebsite\Excel\Concerns\Importable;
use Maatwebsite\Excel\Concerns\ToModel;
class ImportAsMacro
{
public function __invoke()
{
return function (string $filename, callable $mapping, string $disk = null, string $readerType = null) {
$import = new class(get_class($this->getModel()), $mapping) implements ToModel
{
use Importable;
/**
* @var string
*/
private $model;
/**
* @var callable
*/
private $mapping;
/**
* @param string $model
* @param callable $mapping
*/
public function __construct(string $model, callable $mapping)
{
$this->model = $model;
$this->mapping = $mapping;
}
/**
* @param array $row
* @return Model|Model[]|null
*/
public function model(array $row)
{
return (new $this->model)->fill(
($this->mapping)($row)
);
}
};
return $import->import($filename, $disk, $readerType);
};
}
}
excel/src/Mixins/DownloadCollectionMixin.php 0000644 00000004206 15243417774 0015223 0 ustar 00 <?php
namespace Maatwebsite\Excel\Mixins;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Sheet;
class DownloadCollectionMixin
{
/**
* @return callable
*/
public function downloadExcel()
{
return function (string $fileName, string $writerType = null, $withHeadings = false, array $responseHeaders = []) {
$export = new class($this, $withHeadings) implements FromCollection, WithHeadings
{
use Exportable;
/**
* @var bool
*/
private $withHeadings;
/**
* @var Collection
*/
private $collection;
/**
* @param Collection $collection
* @param bool $withHeading
*/
public function __construct(Collection $collection, bool $withHeading = false)
{
$this->collection = $collection->toBase();
$this->withHeadings = $withHeading;
}
/**
* @return Collection
*/
public function collection()
{
return $this->collection;
}
/**
* @return array
*/
public function headings(): array
{
if (!$this->withHeadings) {
return [];
}
$firstRow = $this->collection->first();
if ($firstRow instanceof Arrayable || \is_object($firstRow)) {
return array_keys(Sheet::mapArraybleRow($firstRow));
}
return $this->collection->collapse()->keys()->all();
}
};
return $export->download($fileName, $writerType, $responseHeaders);
};
}
}
excel/src/Mixins/DownloadQueryMacro.php 0000644 00000003537 15243417774 0014220 0 ustar 00 <?php
namespace Maatwebsite\Excel\Mixins;
use Illuminate\Database\Eloquent\Builder;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Sheet;
class DownloadQueryMacro
{
public function __invoke()
{
return function (string $fileName, string $writerType = null, $withHeadings = false) {
$export = new class($this, $withHeadings) implements FromQuery, WithHeadings
{
use Exportable;
/**
* @var bool
*/
private $withHeadings;
/**
* @var Builder
*/
private $query;
/**
* @param $query
* @param bool $withHeadings
*/
public function __construct($query, bool $withHeadings = false)
{
$this->query = $query;
$this->withHeadings = $withHeadings;
}
/**
* @return Builder
*/
public function query()
{
return $this->query;
}
/**
* @return array
*/
public function headings(): array
{
if (!$this->withHeadings) {
return [];
}
$firstRow = (clone $this->query)->first();
if ($firstRow) {
return array_keys(Sheet::mapArraybleRow($firstRow));
}
return [];
}
};
return $export->download($fileName, $writerType);
};
}
}
excel/src/Mixins/StoreCollectionMixin.php 0000644 00000003660 15243417774 0014553 0 ustar 00 <?php
namespace Maatwebsite\Excel\Mixins;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;
class StoreCollectionMixin
{
/**
* @return callable
*/
public function storeExcel()
{
return function (string $filePath, string $disk = null, string $writerType = null, $withHeadings = false) {
$export = new class($this, $withHeadings) implements FromCollection, WithHeadings
{
use Exportable;
/**
* @var bool
*/
private $withHeadings;
/**
* @var Collection
*/
private $collection;
/**
* @param Collection $collection
* @param bool $withHeadings
*/
public function __construct(Collection $collection, bool $withHeadings = false)
{
$this->collection = $collection->toBase();
$this->withHeadings = $withHeadings;
}
/**
* @return Collection
*/
public function collection()
{
return $this->collection;
}
/**
* @return array
*/
public function headings(): array
{
if (!$this->withHeadings) {
return [];
}
return is_array($first = $this->collection->first())
? $this->collection->collapse()->keys()->all()
: array_keys($first->toArray());
}
};
return $export->store($filePath, $disk, $writerType);
};
}
}
excel/src/Reader.php 0000644 00000033452 15243417774 0010373 0 ustar 00 <?php
namespace Maatwebsite\Excel;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Support\Collection;
use InvalidArgumentException;
use Maatwebsite\Excel\Concerns\HasReferencesToOtherSheets;
use Maatwebsite\Excel\Concerns\SkipsUnknownSheets;
use Maatwebsite\Excel\Concerns\WithCalculatedFormulas;
use Maatwebsite\Excel\Concerns\WithChunkReading;
use Maatwebsite\Excel\Concerns\WithCustomValueBinder;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Concerns\WithFormatData;
use Maatwebsite\Excel\Concerns\WithMultipleSheets;
use Maatwebsite\Excel\Events\AfterImport;
use Maatwebsite\Excel\Events\BeforeImport;
use Maatwebsite\Excel\Events\ImportFailed;
use Maatwebsite\Excel\Exceptions\NoTypeDetectedException;
use Maatwebsite\Excel\Exceptions\SheetNotFoundException;
use Maatwebsite\Excel\Factories\ReaderFactory;
use Maatwebsite\Excel\Files\TemporaryFile;
use Maatwebsite\Excel\Files\TemporaryFileFactory;
use Maatwebsite\Excel\Transactions\TransactionHandler;
use PhpOffice\PhpSpreadsheet\Cell\Cell;
use PhpOffice\PhpSpreadsheet\Reader\Exception;
use PhpOffice\PhpSpreadsheet\Reader\IReader;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Throwable;
/** @mixin Spreadsheet */
class Reader
{
use DelegatedMacroable, HasEventBus;
/**
* @var Spreadsheet
*/
protected $spreadsheet;
/**
* @var object[]
*/
protected $sheetImports = [];
/**
* @var TemporaryFile
*/
protected $currentFile;
/**
* @var TemporaryFileFactory
*/
protected $temporaryFileFactory;
/**
* @var TransactionHandler
*/
protected $transaction;
/**
* @var IReader
*/
protected $reader;
/**
* @param TemporaryFileFactory $temporaryFileFactory
* @param TransactionHandler $transaction
*/
public function __construct(TemporaryFileFactory $temporaryFileFactory, TransactionHandler $transaction)
{
$this->setDefaultValueBinder();
$this->transaction = $transaction;
$this->temporaryFileFactory = $temporaryFileFactory;
}
public function __sleep()
{
return ['spreadsheet', 'sheetImports', 'currentFile', 'temporaryFileFactory', 'reader'];
}
public function __wakeup()
{
$this->transaction = app(TransactionHandler::class);
}
/**
* @param object $import
* @param string|UploadedFile $filePath
* @param string|null $readerType
* @param string|null $disk
* @return \Illuminate\Foundation\Bus\PendingDispatch|$this
*
* @throws NoTypeDetectedException
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
* @throws Exception
*/
public function read($import, $filePath, string $readerType = null, string $disk = null)
{
$this->reader = $this->getReader($import, $filePath, $readerType, $disk);
if ($import instanceof WithChunkReading) {
return app(ChunkReader::class)->read($import, $this, $this->currentFile);
}
try {
$this->loadSpreadsheet($import);
($this->transaction)(function () use ($import) {
$sheetsToDisconnect = [];
foreach ($this->sheetImports as $index => $sheetImport) {
if ($sheet = $this->getSheet($import, $sheetImport, $index)) {
$sheet->import($sheetImport, $sheet->getStartRow($sheetImport));
// when using WithCalculatedFormulas we need to keep the sheet until all sheets are imported
if (!($sheetImport instanceof HasReferencesToOtherSheets)) {
$sheet->disconnect();
} else {
$sheetsToDisconnect[] = $sheet;
}
}
}
foreach ($sheetsToDisconnect as $sheet) {
$sheet->disconnect();
}
});
$this->afterImport($import);
} catch (Throwable $e) {
$this->raise(new ImportFailed($e));
$this->garbageCollect();
throw $e;
}
return $this;
}
/**
* @param object $import
* @param string|UploadedFile $filePath
* @param string $readerType
* @param string|null $disk
* @return array
*
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
* @throws \PhpOffice\PhpSpreadsheet\Exception
* @throws NoTypeDetectedException
* @throws Exceptions\SheetNotFoundException
*/
public function toArray($import, $filePath, string $readerType = null, string $disk = null): array
{
$this->reader = $this->getReader($import, $filePath, $readerType, $disk);
$this->loadSpreadsheet($import);
$sheets = [];
$sheetsToDisconnect = [];
foreach ($this->sheetImports as $index => $sheetImport) {
$calculatesFormulas = $sheetImport instanceof WithCalculatedFormulas;
$formatData = $sheetImport instanceof WithFormatData;
if ($sheet = $this->getSheet($import, $sheetImport, $index)) {
$sheets[$index] = $sheet->toArray($sheetImport, $sheet->getStartRow($sheetImport), null, $calculatesFormulas, $formatData);
// when using WithCalculatedFormulas we need to keep the sheet until all sheets are imported
if (!($sheetImport instanceof HasReferencesToOtherSheets)) {
$sheet->disconnect();
} else {
$sheetsToDisconnect[] = $sheet;
}
}
}
foreach ($sheetsToDisconnect as $sheet) {
$sheet->disconnect();
}
$this->afterImport($import);
return $sheets;
}
/**
* @param object $import
* @param string|UploadedFile $filePath
* @param string $readerType
* @param string|null $disk
* @return Collection
*
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
* @throws \PhpOffice\PhpSpreadsheet\Exception
* @throws NoTypeDetectedException
* @throws Exceptions\SheetNotFoundException
*/
public function toCollection($import, $filePath, string $readerType = null, string $disk = null): Collection
{
$this->reader = $this->getReader($import, $filePath, $readerType, $disk);
$this->loadSpreadsheet($import);
$sheets = new Collection();
$sheetsToDisconnect = [];
foreach ($this->sheetImports as $index => $sheetImport) {
$calculatesFormulas = $sheetImport instanceof WithCalculatedFormulas;
$formatData = $sheetImport instanceof WithFormatData;
if ($sheet = $this->getSheet($import, $sheetImport, $index)) {
$sheets->put($index, $sheet->toCollection($sheetImport, $sheet->getStartRow($sheetImport), null, $calculatesFormulas, $formatData));
// when using WithCalculatedFormulas we need to keep the sheet until all sheets are imported
if (!($sheetImport instanceof HasReferencesToOtherSheets)) {
$sheet->disconnect();
} else {
$sheetsToDisconnect[] = $sheet;
}
}
}
foreach ($sheetsToDisconnect as $sheet) {
$sheet->disconnect();
}
$this->afterImport($import);
return $sheets;
}
/**
* @return Spreadsheet
*/
public function getDelegate()
{
return $this->spreadsheet;
}
/**
* @return $this
*/
public function setDefaultValueBinder(): self
{
Cell::setValueBinder(
app(config('excel.value_binder.default', DefaultValueBinder::class))
);
return $this;
}
/**
* @param object $import
*/
public function loadSpreadsheet($import)
{
$this->sheetImports = $this->buildSheetImports($import);
$this->readSpreadsheet();
// When no multiple sheets, use the main import object
// for each loaded sheet in the spreadsheet
if (!$import instanceof WithMultipleSheets) {
$this->sheetImports = array_fill(0, $this->spreadsheet->getSheetCount(), $import);
}
$this->beforeImport($import);
}
public function readSpreadsheet()
{
$this->spreadsheet = $this->reader->load(
$this->currentFile->getLocalPath()
);
}
/**
* @param object $import
*/
public function beforeImport($import)
{
$this->raise(new BeforeImport($this, $import));
}
/**
* @param object $import
*/
public function afterImport($import)
{
$this->raise(new AfterImport($this, $import));
$this->garbageCollect();
}
/**
* @return IReader
*/
public function getPhpSpreadsheetReader(): IReader
{
return $this->reader;
}
/**
* @param object $import
* @return array
*/
public function getWorksheets($import): array
{
// Csv doesn't have worksheets.
if (!method_exists($this->reader, 'listWorksheetNames')) {
return ['Worksheet' => $import];
}
$worksheets = [];
$worksheetNames = $this->reader->listWorksheetNames($this->currentFile->getLocalPath());
if ($import instanceof WithMultipleSheets) {
$sheetImports = $import->sheets();
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;
}
// Load specific sheets.
if (method_exists($this->reader, 'setLoadSheetsOnly')) {
$this->reader->setLoadSheetsOnly(
collect($worksheetNames)->intersect(array_keys($worksheets))->values()->all()
);
}
} else {
// Each worksheet the same import class.
foreach ($worksheetNames as $name) {
$worksheets[$name] = $import;
}
}
return $worksheets;
}
/**
* @return array
*/
public function getTotalRows(): array
{
$info = $this->reader->listWorksheetInfo($this->currentFile->getLocalPath());
$totalRows = [];
foreach ($info as $sheet) {
$totalRows[$sheet['worksheetName']] = $sheet['totalRows'];
}
return $totalRows;
}
/**
* @param $import
* @param $sheetImport
* @param $index
* @return Sheet|null
*
* @throws \PhpOffice\PhpSpreadsheet\Exception
* @throws SheetNotFoundException
*/
protected function getSheet($import, $sheetImport, $index)
{
try {
return Sheet::make($this->spreadsheet, $index);
} catch (SheetNotFoundException $e) {
if ($import instanceof SkipsUnknownSheets) {
$import->onUnknownSheet($index);
return null;
}
if ($sheetImport instanceof SkipsUnknownSheets) {
$sheetImport->onUnknownSheet($index);
return null;
}
throw $e;
}
}
/**
* @param object $import
* @return array
*/
private function buildSheetImports($import): array
{
$sheetImports = [];
if ($import instanceof WithMultipleSheets) {
$sheetImports = $import->sheets();
// When only sheet names are given and the reader has
// an option to load only the selected sheets.
if (
method_exists($this->reader, 'setLoadSheetsOnly')
&& count(array_filter(array_keys($sheetImports), 'is_numeric')) === 0
) {
$this->reader->setLoadSheetsOnly(array_keys($sheetImports));
}
}
return $sheetImports;
}
/**
* @param object $import
* @param string|UploadedFile $filePath
* @param string|null $readerType
* @param string $disk
* @return IReader
*
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
* @throws NoTypeDetectedException
* @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
* @throws InvalidArgumentException
*/
private function getReader($import, $filePath, string $readerType = null, string $disk = null): IReader
{
$shouldQueue = $import instanceof ShouldQueue;
if ($shouldQueue && !$import instanceof WithChunkReading) {
throw new InvalidArgumentException('ShouldQueue is only supported in combination with WithChunkReading.');
}
if ($import instanceof WithEvents) {
$this->registerListeners($import->registerEvents());
}
if ($import instanceof WithCustomValueBinder) {
Cell::setValueBinder($import);
}
$fileExtension = pathinfo($filePath, PATHINFO_EXTENSION);
$temporaryFile = $shouldQueue ? $this->temporaryFileFactory->make($fileExtension) : $this->temporaryFileFactory->makeLocal(null, $fileExtension);
$this->currentFile = $temporaryFile->copyFrom(
$filePath,
$disk
);
return ReaderFactory::make(
$import,
$this->currentFile,
$readerType
);
}
/**
* Garbage collect.
*/
private function garbageCollect()
{
$this->clearListeners();
$this->setDefaultValueBinder();
// Force garbage collecting
unset($this->sheetImports, $this->spreadsheet);
$this->currentFile->delete();
}
}
excel/src/Exporter.php 0000644 00000002675 15243417774 0011004 0 ustar 00 <?php
namespace Maatwebsite\Excel;
interface Exporter
{
/**
* @param object $export
* @param string|null $fileName
* @param string $writerType
* @param array $headers
* @return \Symfony\Component\HttpFoundation\BinaryFileResponse
*
* @throws \PhpOffice\PhpSpreadsheet\Exception
* @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
*/
public function download($export, string $fileName, string $writerType = null, array $headers = []);
/**
* @param object $export
* @param string $filePath
* @param string|null $diskName
* @param string $writerType
* @param mixed $diskOptions
* @return bool
*
* @throws \PhpOffice\PhpSpreadsheet\Exception
* @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
*/
public function store($export, string $filePath, string $disk = null, string $writerType = null, $diskOptions = []);
/**
* @param object $export
* @param string $filePath
* @param string|null $disk
* @param string $writerType
* @param mixed $diskOptions
* @return \Illuminate\Foundation\Bus\PendingDispatch
*/
public function queue($export, string $filePath, string $disk = null, string $writerType = null, $diskOptions = []);
/**
* @param object $export
* @param string $writerType
* @return string
*/
public function raw($export, string $writerType);
}
excel/src/Files/RemoteTemporaryFile.php 0000644 00000006064 15243417774 0014170 0 ustar 00 <?php
namespace Maatwebsite\Excel\Files;
use Illuminate\Support\Arr;
class RemoteTemporaryFile extends TemporaryFile
{
/**
* @var string
*/
private $disk;
/**
* @var Disk|null
*/
private $diskInstance;
/**
* @var string
*/
private $filename;
/**
* @var LocalTemporaryFile
*/
private $localTemporaryFile;
/**
* @param string $disk
* @param string $filename
* @param LocalTemporaryFile $localTemporaryFile
*/
public function __construct(string $disk, string $filename, LocalTemporaryFile $localTemporaryFile)
{
$this->disk = $disk;
$this->filename = $filename;
$this->localTemporaryFile = $localTemporaryFile;
$this->disk()->touch($filename);
}
public function __sleep()
{
return ['disk', 'filename', 'localTemporaryFile'];
}
/**
* @return string
*/
public function getLocalPath(): string
{
return $this->localTemporaryFile->getLocalPath();
}
/**
* @return bool
*/
public function existsLocally(): bool
{
return $this->localTemporaryFile->exists();
}
/**
* @return bool
*/
public function exists(): bool
{
return $this->disk()->exists($this->filename);
}
/**
* @return bool
*/
public function deleteLocalCopy(): bool
{
return $this->localTemporaryFile->delete();
}
/**
* @return bool
*/
public function delete(): bool
{
// we don't need to delete local copy as it's deleted at end of each chunk
if (!config('excel.temporary_files.force_resync_remote')) {
$this->deleteLocalCopy();
}
return $this->disk()->delete($this->filename);
}
/**
* @return TemporaryFile
*/
public function sync(): TemporaryFile
{
if (!$this->localTemporaryFile->exists()) {
$this->localTemporaryFile = resolve(TemporaryFileFactory::class)
->makeLocal(Arr::last(explode('/', $this->filename)));
}
$this->disk()->copy(
$this,
$this->localTemporaryFile->getLocalPath()
);
return $this;
}
/**
* Store on remote disk.
*/
public function updateRemote()
{
$this->disk()->copy(
$this->localTemporaryFile,
$this->filename
);
}
/**
* @return resource
*/
public function readStream()
{
return $this->disk()->readStream($this->filename);
}
/**
* @return string
*/
public function contents(): string
{
return $this->disk()->get($this->filename);
}
/**
* @param string|resource $contents
*/
public function put($contents)
{
$this->disk()->put($this->filename, $contents);
}
/**
* @return Disk
*/
public function disk(): Disk
{
return $this->diskInstance ?: $this->diskInstance = app(Filesystem::class)->disk($this->disk);
}
}
excel/src/Files/TemporaryFileFactory.php 0000644 00000004426 15243417774 0014344 0 ustar 00 <?php
namespace Maatwebsite\Excel\Files;
use Illuminate\Support\Str;
class TemporaryFileFactory
{
/**
* @var string|null
*/
private $temporaryPath;
/**
* @var string|null
*/
private $temporaryDisk;
/**
* @param string|null $temporaryPath
* @param string|null $temporaryDisk
*/
public function __construct(string $temporaryPath = null, string $temporaryDisk = null)
{
$this->temporaryPath = $temporaryPath;
$this->temporaryDisk = $temporaryDisk;
}
/**
* @param string|null $fileExtension
* @return TemporaryFile
*/
public function make(string $fileExtension = null): TemporaryFile
{
if (null !== $this->temporaryDisk) {
return $this->makeRemote($fileExtension);
}
return $this->makeLocal(null, $fileExtension);
}
/**
* @param string|null $fileName
* @param string|null $fileExtension
* @return LocalTemporaryFile
*/
public function makeLocal(string $fileName = null, string $fileExtension = null): LocalTemporaryFile
{
if (!file_exists($this->temporaryPath) && !mkdir($concurrentDirectory = $this->temporaryPath, config('excel.temporary_files.local_permissions.dir', 0777), true) && !is_dir($concurrentDirectory)) {
throw new \RuntimeException(sprintf('Directory "%s" was not created', $concurrentDirectory));
}
return new LocalTemporaryFile(
$this->temporaryPath . DIRECTORY_SEPARATOR . ($fileName ?: $this->generateFilename($fileExtension))
);
}
/**
* @param string|null $fileExtension
* @return RemoteTemporaryFile
*/
private function makeRemote(string $fileExtension = null): RemoteTemporaryFile
{
$filename = $this->generateFilename($fileExtension);
return new RemoteTemporaryFile(
$this->temporaryDisk,
config('excel.temporary_files.remote_prefix') . $filename,
$this->makeLocal($filename)
);
}
/**
* @param string|null $fileExtension
* @return string
*/
private function generateFilename(string $fileExtension = null): string
{
return 'laravel-excel-' . Str::random(32) . ($fileExtension ? '.' . $fileExtension : '');
}
}
excel/src/Files/TemporaryFile.php 0000644 00000003624 15243417774 0013013 0 ustar 00 <?php
namespace Maatwebsite\Excel\Files;
use Illuminate\Contracts\Filesystem\FileNotFoundException;
use Symfony\Component\HttpFoundation\File\UploadedFile;
abstract class TemporaryFile
{
/**
* @return string
*/
abstract public function getLocalPath(): string;
/**
* @return bool
*/
abstract public function exists(): bool;
/**
* @param @param string|resource $contents
*/
abstract public function put($contents);
/**
* @return bool
*/
abstract public function delete(): bool;
/**
* @return resource
*/
abstract public function readStream();
/**
* @return string
*/
abstract public function contents(): string;
/**
* @return TemporaryFile
*/
public function sync(): TemporaryFile
{
return $this;
}
/**
* @param string|UploadedFile $filePath
* @param string|null $disk
* @return TemporaryFile
*/
public function copyFrom($filePath, string $disk = null): TemporaryFile
{
if ($filePath instanceof UploadedFile) {
$readStream = fopen($filePath->getRealPath(), 'rb');
} elseif ($disk === null && realpath($filePath) !== false) {
$readStream = fopen($filePath, 'rb');
} else {
$diskInstance = app('filesystem')->disk($disk);
if (!$diskInstance->exists($filePath)) {
$logPath = '[' . $filePath . ']';
if ($disk) {
$logPath .= ' (' . $disk . ')';
}
throw new FileNotFoundException('File ' . $logPath . ' does not exist and can therefor not be imported.');
}
$readStream = $diskInstance->readStream($filePath);
}
$this->put($readStream);
if (is_resource($readStream)) {
fclose($readStream);
}
return $this->sync();
}
}
excel/src/Files/LocalTemporaryFile.php 0000644 00000002574 15243417774 0013771 0 ustar 00 <?php
namespace Maatwebsite\Excel\Files;
class LocalTemporaryFile extends TemporaryFile
{
/**
* @var string
*/
private $filePath;
/**
* @param string $filePath
*/
public function __construct(string $filePath)
{
touch($filePath);
if (($rights = config('excel.temporary_files.local_permissions.file', null)) !== null) {
chmod($filePath, $rights);
}
$this->filePath = realpath($filePath);
}
/**
* @return string
*/
public function getLocalPath(): string
{
return $this->filePath;
}
/**
* @return bool
*/
public function exists(): bool
{
return file_exists($this->filePath);
}
/**
* @return bool
*/
public function delete(): bool
{
if (@unlink($this->filePath) || !$this->exists()) {
return true;
}
return unlink($this->filePath);
}
/**
* @return resource
*/
public function readStream()
{
return fopen($this->getLocalPath(), 'rb+');
}
/**
* @return string
*/
public function contents(): string
{
return file_get_contents($this->filePath);
}
/**
* @param @param string|resource $contents
*/
public function put($contents)
{
file_put_contents($this->filePath, $contents);
}
}
excel/src/Files/Disk.php 0000644 00000004261 15243417774 0011121 0 ustar 00 <?php
namespace Maatwebsite\Excel\Files;
use Illuminate\Contracts\Filesystem\Filesystem as IlluminateFilesystem;
/**
* @method bool get(string $filename)
* @method resource readStream(string $filename)
* @method bool delete(string $filename)
* @method bool exists(string $filename)
*/
class Disk
{
/**
* @var IlluminateFilesystem
*/
protected $disk;
/**
* @var string|null
*/
protected $name;
/**
* @var array
*/
protected $diskOptions;
/**
* @param IlluminateFilesystem $disk
* @param string|null $name
* @param array $diskOptions
*/
public function __construct(IlluminateFilesystem $disk, string $name = null, array $diskOptions = [])
{
$this->disk = $disk;
$this->name = $name;
$this->diskOptions = $diskOptions;
}
/**
* @param string $name
* @param array $arguments
* @return mixed
*/
public function __call($name, $arguments)
{
return $this->disk->{$name}(...$arguments);
}
/**
* @param string $destination
* @param string|resource $contents
* @return bool
*/
public function put(string $destination, $contents): bool
{
return $this->disk->put($destination, $contents, $this->diskOptions);
}
/**
* @param TemporaryFile $source
* @param string $destination
* @return bool
*/
public function copy(TemporaryFile $source, string $destination): bool
{
$readStream = $source->readStream();
if (realpath($destination)) {
$tempStream = fopen($destination, 'rb+');
$success = stream_copy_to_stream($readStream, $tempStream) !== false;
if (is_resource($tempStream)) {
fclose($tempStream);
}
} else {
$success = $this->put($destination, $readStream);
}
if (is_resource($readStream)) {
fclose($readStream);
}
return $success;
}
/**
* @param string $filename
*/
public function touch(string $filename)
{
$this->disk->put($filename, '', $this->diskOptions);
}
}
excel/src/Files/Filesystem.php 0000644 00000001211 15243417774 0012343 0 ustar 00 <?php
namespace Maatwebsite\Excel\Files;
use Illuminate\Contracts\Filesystem\Factory;
class Filesystem
{
/**
* @var Factory
*/
private $filesystem;
/**
* @param Factory $filesystem
*/
public function __construct(Factory $filesystem)
{
$this->filesystem = $filesystem;
}
/**
* @param string|null $disk
* @param array $diskOptions
* @return Disk
*/
public function disk(string $disk = null, array $diskOptions = []): Disk
{
return new Disk(
$this->filesystem->disk($disk),
$disk,
$diskOptions
);
}
}
excel/src/QueuedWriter.php 0000644 00000016543 15243417774 0011620 0 ustar 00 <?php
namespace Maatwebsite\Excel;
use Illuminate\Foundation\Bus\PendingDispatch;
use Illuminate\Support\Collection;
use Illuminate\Support\LazyCollection;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\FromView;
use Maatwebsite\Excel\Concerns\WithCustomChunkSize;
use Maatwebsite\Excel\Concerns\WithCustomQuerySize;
use Maatwebsite\Excel\Concerns\WithMultipleSheets;
use Maatwebsite\Excel\Files\TemporaryFile;
use Maatwebsite\Excel\Files\TemporaryFileFactory;
use Maatwebsite\Excel\Jobs\AppendDataToSheet;
use Maatwebsite\Excel\Jobs\AppendPaginatedToSheet;
use Maatwebsite\Excel\Jobs\AppendQueryToSheet;
use Maatwebsite\Excel\Jobs\AppendViewToSheet;
use Maatwebsite\Excel\Jobs\CloseSheet;
use Maatwebsite\Excel\Jobs\QueueExport;
use Maatwebsite\Excel\Jobs\StoreQueuedExport;
use Traversable;
class QueuedWriter
{
/**
* @var Writer
*/
protected $writer;
/**
* @var int
*/
protected $chunkSize;
/**
* @var TemporaryFileFactory
*/
protected $temporaryFileFactory;
/**
* @param Writer $writer
* @param TemporaryFileFactory $temporaryFileFactory
*/
public function __construct(Writer $writer, TemporaryFileFactory $temporaryFileFactory)
{
$this->writer = $writer;
$this->chunkSize = config('excel.exports.chunk_size', 1000);
$this->temporaryFileFactory = $temporaryFileFactory;
}
/**
* @param object $export
* @param string $filePath
* @param string $disk
* @param string|null $writerType
* @param array|string $diskOptions
* @return \Illuminate\Foundation\Bus\PendingDispatch
*/
public function store($export, string $filePath, string $disk = null, string $writerType = null, $diskOptions = [])
{
$extension = pathinfo($filePath, PATHINFO_EXTENSION);
$temporaryFile = $this->temporaryFileFactory->make($extension);
$jobs = $this->buildExportJobs($export, $temporaryFile, $writerType);
$jobs->push(new StoreQueuedExport(
$temporaryFile,
$filePath,
$disk,
$diskOptions
));
return new PendingDispatch(
(new QueueExport($export, $temporaryFile, $writerType))->chain($jobs->toArray())
);
}
/**
* @param object $export
* @param TemporaryFile $temporaryFile
* @param string $writerType
* @return Collection
*/
private function buildExportJobs($export, TemporaryFile $temporaryFile, string $writerType): Collection
{
$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, $temporaryFile, $writerType, $sheetIndex));
} elseif ($sheetExport instanceof FromQuery) {
$jobs = $jobs->merge($this->exportQuery($sheetExport, $temporaryFile, $writerType, $sheetIndex));
} elseif ($sheetExport instanceof FromView) {
$jobs = $jobs->merge($this->exportView($sheetExport, $temporaryFile, $writerType, $sheetIndex));
}
$jobs->push(new CloseSheet($sheetExport, $temporaryFile, $writerType, $sheetIndex));
}
return $jobs;
}
/**
* @param FromCollection $export
* @param TemporaryFile $temporaryFile
* @param string $writerType
* @param int $sheetIndex
* @return Collection|LazyCollection
*/
private function exportCollection(
FromCollection $export,
TemporaryFile $temporaryFile,
string $writerType,
int $sheetIndex
) {
return $export
->collection()
->chunk($this->getChunkSize($export))
->map(function ($rows) use ($writerType, $temporaryFile, $sheetIndex, $export) {
if ($rows instanceof Traversable) {
$rows = iterator_to_array($rows);
}
return new AppendDataToSheet(
$export,
$temporaryFile,
$writerType,
$sheetIndex,
$rows
);
});
}
/**
* @param FromQuery $export
* @param TemporaryFile $temporaryFile
* @param string $writerType
* @param int $sheetIndex
* @return Collection
*/
private function exportQuery(
FromQuery $export,
TemporaryFile $temporaryFile,
string $writerType,
int $sheetIndex
): Collection {
$query = $export->query();
if ($query instanceof \Laravel\Scout\Builder) {
return $this->exportScout($export, $temporaryFile, $writerType, $sheetIndex);
}
$count = $export instanceof WithCustomQuerySize ? $export->querySize() : $query->count();
$spins = ceil($count / $this->getChunkSize($export));
$jobs = new Collection();
for ($page = 1; $page <= $spins; $page++) {
$jobs->push(new AppendQueryToSheet(
$export,
$temporaryFile,
$writerType,
$sheetIndex,
$page,
$this->getChunkSize($export)
));
}
return $jobs;
}
/**
* @param FromQuery $export
* @param TemporaryFile $temporaryFile
* @param string $writerType
* @param int $sheetIndex
* @return Collection
*/
private function exportScout(
FromQuery $export,
TemporaryFile $temporaryFile,
string $writerType,
int $sheetIndex
): Collection {
$jobs = new Collection();
$chunk = $export->query()->paginate($this->getChunkSize($export));
// Append first page
$jobs->push(new AppendDataToSheet(
$export,
$temporaryFile,
$writerType,
$sheetIndex,
$chunk->items()
));
// Append rest of pages
for ($page = 2; $page <= $chunk->lastPage(); $page++) {
$jobs->push(new AppendPaginatedToSheet(
$export,
$temporaryFile,
$writerType,
$sheetIndex,
$page,
$this->getChunkSize($export)
));
}
return $jobs;
}
/**
* @param FromView $export
* @param TemporaryFile $temporaryFile
* @param string $writerType
* @param int $sheetIndex
* @return Collection
*/
private function exportView(
FromView $export,
TemporaryFile $temporaryFile,
string $writerType,
int $sheetIndex
): Collection {
$jobs = new Collection();
$jobs->push(new AppendViewToSheet(
$export,
$temporaryFile,
$writerType,
$sheetIndex
));
return $jobs;
}
/**
* @param object|WithCustomChunkSize $export
* @return int
*/
private function getChunkSize($export): int
{
if ($export instanceof WithCustomChunkSize) {
return $export->chunkSize();
}
return $this->chunkSize;
}
}
excel/src/MappedReader.php 0000644 00000002622 15243417774 0011515 0 ustar 00 <?php
namespace Maatwebsite\Excel;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\ToArray;
use Maatwebsite\Excel\Concerns\ToCollection;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithCalculatedFormulas;
use Maatwebsite\Excel\Concerns\WithFormatData;
use Maatwebsite\Excel\Concerns\WithMappedCells;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
class MappedReader
{
/**
* @param WithMappedCells $import
* @param Worksheet $worksheet
*
* @throws \PhpOffice\PhpSpreadsheet\Exception
*/
public function map(WithMappedCells $import, Worksheet $worksheet)
{
$mapped = $import->mapping();
array_walk_recursive($mapped, function (&$coordinate) use ($import, $worksheet) {
$cell = Cell::make($worksheet, $coordinate);
$coordinate = $cell->getValue(
null,
$import instanceof WithCalculatedFormulas,
$import instanceof WithFormatData
);
});
if ($import instanceof ToModel) {
$model = $import->model($mapped);
if ($model) {
$model->saveOrFail();
}
}
if ($import instanceof ToCollection) {
$import->collection(new Collection($mapped));
}
if ($import instanceof ToArray) {
$import->array($mapped);
}
}
}
excel/src/Facades/Excel.php 0000644 00000004516 15243417774 0011556 0 ustar 00 <?php
namespace Maatwebsite\Excel\Facades;
use Illuminate\Foundation\Bus\PendingDispatch;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Facade;
use Maatwebsite\Excel\Excel as BaseExcel;
use Maatwebsite\Excel\Fakes\ExcelFake;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
/**
* @method static BinaryFileResponse download(object $export, string $fileName, string $writerType = null, array $headers = [])
* @method static bool store(object $export, string $filePath, string $disk = null, string $writerType = null, $diskOptions = [])
* @method static PendingDispatch queue(object $export, string $filePath, string $disk = null, string $writerType = null, $diskOptions = [])
* @method static string raw(object $export, string $writerType)
* @method static BaseExcel import(object $import, string|UploadedFile $filePath, string $disk = null, string $readerType = null)
* @method static array toArray(object $import, string|UploadedFile $filePath, string $disk = null, string $readerType = null)
* @method static Collection toCollection(object $import, string|UploadedFile $filePath, string $disk = null, string $readerType = null)
* @method static PendingDispatch queueImport(object $import, string|UploadedFile $filePath, string $disk = null, string $readerType = null)
* @method static void matchByRegex()
* @method static void doNotMatchByRegex()
* @method static void assertDownloaded(string $fileName, callable $callback = null)
* @method static void assertStored(string $filePath, string|callable $disk = null, callable $callback = null)
* @method static void assertQueued(string $filePath, string|callable $disk = null, callable $callback = null)
* @method static void assertQueuedWithChain(array $chain)
* @method static void assertExportedInRaw(string $classname, callable $callback = null)
* @method static void assertImported(string $filePath, string|callable $disk = null, callable $callback = null)
*/
class Excel extends Facade
{
/**
* Replace the bound instance with a fake.
*
* @return void
*/
public static function fake()
{
static::swap(new ExcelFake());
}
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'excel';
}
}
excel/src/ChunkReader.php 0000644 00000011017 15243417774 0011355 0 ustar 00 <?php
namespace Maatwebsite\Excel;
use Illuminate\Bus\Queueable;
use Illuminate\Container\Container;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\PendingDispatch;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\Jobs\SyncJob;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\ShouldQueueWithoutChain;
use Maatwebsite\Excel\Concerns\WithChunkReading;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Concerns\WithLimit;
use Maatwebsite\Excel\Concerns\WithProgressBar;
use Maatwebsite\Excel\Files\TemporaryFile;
use Maatwebsite\Excel\Imports\HeadingRowExtractor;
use Maatwebsite\Excel\Jobs\AfterImportJob;
use Maatwebsite\Excel\Jobs\QueueImport;
use Maatwebsite\Excel\Jobs\ReadChunk;
use Throwable;
class ChunkReader
{
/**
* @var Container
*/
protected $container;
public function __construct(Container $container)
{
$this->container = $container;
}
/**
* @param WithChunkReading $import
* @param Reader $reader
* @param TemporaryFile $temporaryFile
* @return PendingDispatch|Collection|null
*/
public function read(WithChunkReading $import, Reader $reader, TemporaryFile $temporaryFile)
{
if ($import instanceof WithEvents) {
$reader->beforeImport($import);
}
$chunkSize = $import->chunkSize();
$totalRows = $reader->getTotalRows();
$worksheets = $reader->getWorksheets($import);
$queue = property_exists($import, 'queue') ? $import->queue : null;
$delayCleanup = property_exists($import, 'cleanupInterval') ? $import->cleanupInterval : 60;
if ($import instanceof WithProgressBar) {
$import->getConsoleOutput()->progressStart(array_sum($totalRows));
}
$jobs = new Collection();
foreach ($worksheets as $name => $sheetImport) {
$startRow = HeadingRowExtractor::determineStartRow($sheetImport);
if ($sheetImport instanceof WithLimit) {
$limit = $sheetImport->limit();
if ($limit <= $totalRows[$name]) {
$totalRows[$name] = $sheetImport->limit();
}
}
for ($currentRow = $startRow; $currentRow <= $totalRows[$name]; $currentRow += $chunkSize) {
$jobs->push(new ReadChunk(
$import,
$reader->getPhpSpreadsheetReader(),
$temporaryFile,
$name,
$sheetImport,
$currentRow,
$chunkSize
));
}
}
$afterImportJob = new AfterImportJob($import, $reader);
if ($import instanceof ShouldQueueWithoutChain) {
$afterImportJob->setInterval($delayCleanup);
$afterImportJob->setDependencies($jobs);
$jobs->push($afterImportJob->delay($delayCleanup));
return $jobs->each(function ($job) use ($queue) {
dispatch($job->onQueue($queue));
});
}
$jobs->push($afterImportJob);
if ($import instanceof ShouldQueue) {
return new PendingDispatch(
(new QueueImport($import))->chain($jobs->toArray())
);
}
$jobs->each(function ($job) {
try {
function_exists('dispatch_now')
? dispatch_now($job)
: $this->dispatchNow($job);
} catch (Throwable $e) {
if (method_exists($job, 'failed')) {
$job->failed($e);
}
throw $e;
}
});
if ($import instanceof WithProgressBar) {
$import->getConsoleOutput()->progressFinish();
}
unset($jobs);
return null;
}
/**
* Dispatch a command to its appropriate handler in the current process without using the synchronous queue.
*
* @param object $command
* @param mixed $handler
* @return mixed
*/
protected function dispatchNow($command, $handler = null)
{
$uses = class_uses_recursive($command);
if (in_array(InteractsWithQueue::class, $uses) &&
in_array(Queueable::class, $uses) && !$command->job
) {
$command->setJob(new SyncJob($this->container, json_encode([]), 'sync', 'sync'));
}
$method = method_exists($command, 'handle') ? 'handle' : '__invoke';
return $this->container->call([$command, $method]);
}
}
excel/src/Imports/ModelImporter.php 0000644 00000010070 15243417774 0013377 0 ustar 00 <?php
namespace Maatwebsite\Excel\Imports;
use Maatwebsite\Excel\Concerns\SkipsEmptyRows;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithBatchInserts;
use Maatwebsite\Excel\Concerns\WithCalculatedFormulas;
use Maatwebsite\Excel\Concerns\WithColumnLimit;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Concerns\WithFormatData;
use Maatwebsite\Excel\Concerns\WithMapping;
use Maatwebsite\Excel\Concerns\WithProgressBar;
use Maatwebsite\Excel\Concerns\WithValidation;
use Maatwebsite\Excel\Events\AfterBatch;
use Maatwebsite\Excel\HasEventBus;
use Maatwebsite\Excel\Row;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
class ModelImporter
{
use HasEventBus;
/**
* @var ModelManager
*/
private $manager;
/**
* @param ModelManager $manager
*/
public function __construct(ModelManager $manager)
{
$this->manager = $manager;
}
/**
* @param Worksheet $worksheet
* @param ToModel $import
* @param int|null $startRow
* @param string|null $endColumn
*
* @throws \Maatwebsite\Excel\Validators\ValidationException
*/
public function import(Worksheet $worksheet, ToModel $import, int $startRow = 1)
{
if ($startRow > $worksheet->getHighestRow()) {
return;
}
if ($import instanceof WithEvents) {
$this->registerListeners($import->registerEvents());
}
$headingRow = HeadingRowExtractor::extract($worksheet, $import);
$headerIsGrouped = HeadingRowExtractor::extractGrouping($headingRow, $import);
$batchSize = $import instanceof WithBatchInserts ? $import->batchSize() : 1;
$endRow = EndRowFinder::find($import, $startRow, $worksheet->getHighestRow());
$progessBar = $import instanceof WithProgressBar;
$withMapping = $import instanceof WithMapping;
$withCalcFormulas = $import instanceof WithCalculatedFormulas;
$formatData = $import instanceof WithFormatData;
$withValidation = $import instanceof WithValidation && method_exists($import, 'prepareForValidation');
$endColumn = $import instanceof WithColumnLimit ? $import->endColumn() : null;
$this->manager->setRemembersRowNumber(method_exists($import, 'rememberRowNumber'));
$i = 0;
$batchStartRow = $startRow;
foreach ($worksheet->getRowIterator($startRow, $endRow) as $spreadSheetRow) {
$i++;
$row = new Row($spreadSheetRow, $headingRow, $headerIsGrouped);
if (!$import instanceof SkipsEmptyRows || !$row->isEmpty($withCalcFormulas)) {
$rowArray = $row->toArray(null, $withCalcFormulas, $formatData, $endColumn);
if ($import instanceof SkipsEmptyRows && method_exists($import, 'isEmptyWhen') && $import->isEmptyWhen($rowArray)) {
continue;
}
if ($withValidation) {
$rowArray = $import->prepareForValidation($rowArray, $row->getIndex());
}
if ($withMapping) {
$rowArray = $import->map($rowArray);
}
$this->manager->add(
$row->getIndex(),
$rowArray
);
// Flush each batch.
if (($i % $batchSize) === 0) {
$this->flush($import, $batchSize, $batchStartRow);
$batchStartRow += $i;
$i = 0;
if ($progessBar) {
$import->getConsoleOutput()->progressAdvance($batchSize);
}
}
}
}
if ($i > 0) {
// Flush left-overs.
$this->flush($import, $batchSize, $batchStartRow);
}
}
private function flush(ToModel $import, int $batchSize, int $startRow)
{
$this->manager->flush($import, $batchSize > 1);
$this->raise(new AfterBatch($this->manager, $import, $batchSize, $startRow));
}
}
excel/src/Imports/Persistence/CascadePersistManager.php 0000644 00000005477 15243417774 0017310 0 ustar 00 <?php
namespace Maatwebsite\Excel\Imports\Persistence;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Transactions\TransactionHandler;
/** @todo */
class CascadePersistManager
{
/**
* @var TransactionHandler
*/
private $transaction;
/**
* @param TransactionHandler $transaction
*/
public function __construct(TransactionHandler $transaction)
{
$this->transaction = $transaction;
}
/**
* @param Model $model
* @return bool
*/
public function persist(Model $model): bool
{
return ($this->transaction)(function () use ($model) {
return $this->save($model);
});
}
/**
* @param Model $model
* @return bool
*/
private function save(Model $model): bool
{
if (!$model->save()) {
return false;
}
foreach ($model->getRelations() as $relationName => $models) {
$models = array_filter(
$models instanceof Collection ? $models->all() : [$models]
);
$relation = $model->{$relationName}();
if ($relation instanceof BelongsTo) {
if (!$this->persistBelongsTo($relation, $models)) {
return false;
}
}
if ($relation instanceof BelongsToMany) {
if (!$this->persistBelongsToMany($relation, $models)) {
return false;
}
}
}
// We need to save the model again to
// make sure all updates are performed.
$model->save();
return true;
}
/**
* @param BelongsTo $relation
* @param array $models
* @return bool
*/
private function persistBelongsTo(BelongsTo $relation, array $models): bool
{
// With belongs to, we first need to save all relations,
// so we can use their foreign key to attach to the relation.
foreach ($models as $model) {
// Cascade any relations that this child model may have.
if (!$this->save($model)) {
return false;
}
$relation->associate($model);
}
return true;
}
/**
* @param BelongsToMany $relation
* @param array $models
* @return bool
*/
private function persistBelongsToMany(BelongsToMany $relation, array $models): bool
{
foreach ($models as $model) {
$relation->save($model);
// Cascade any relations that this child model may have.
if (!$this->save($model)) {
return false;
}
}
return true;
}
}
excel/src/Imports/HeadingRowFormatter.php 0000644 00000004475 15243417774 0014544 0 ustar 00 <?php
namespace Maatwebsite\Excel\Imports;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
use InvalidArgumentException;
class HeadingRowFormatter
{
/**
* @const string
*/
const FORMATTER_NONE = 'none';
/**
* @const string
*/
const FORMATTER_SLUG = 'slug';
/**
* @var string
*/
protected static $formatter;
/**
* @var callable[]
*/
protected static $customFormatters = [];
/**
* @var array
*/
protected static $defaultFormatters = [
self::FORMATTER_NONE,
self::FORMATTER_SLUG,
];
/**
* @param array $headings
* @return array
*/
public static function format(array $headings): array
{
return (new Collection($headings))->map(function ($value, $key) {
return static::callFormatter($value, $key);
})->toArray();
}
/**
* @param string $name
*/
public static function default(string $name = null)
{
if (null !== $name && !isset(static::$customFormatters[$name]) && !in_array($name, static::$defaultFormatters, true)) {
throw new InvalidArgumentException(sprintf('Formatter "%s" does not exist', $name));
}
static::$formatter = $name;
}
/**
* @param string $name
* @param callable $formatter
*/
public static function extend(string $name, callable $formatter)
{
static::$customFormatters[$name] = $formatter;
}
/**
* Reset the formatter.
*/
public static function reset()
{
static::default();
}
/**
* @param mixed $value
* @return mixed
*/
protected static function callFormatter($value, $key=null)
{
static::$formatter = static::$formatter ?? config('excel.imports.heading_row.formatter', self::FORMATTER_SLUG);
// Call custom formatter
if (isset(static::$customFormatters[static::$formatter])) {
$formatter = static::$customFormatters[static::$formatter];
return $formatter($value, $key);
}
if (empty($value)) {
return $key;
}
if (static::$formatter === self::FORMATTER_SLUG) {
return Str::slug($value, '_');
}
// No formatter (FORMATTER_NONE)
return $value;
}
}
excel/src/Imports/ModelManager.php 0000644 00000014257 15243417774 0013163 0 ustar 00 <?php
namespace Maatwebsite\Excel\Imports;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\PersistRelations;
use Maatwebsite\Excel\Concerns\SkipsOnError;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithUpsertColumns;
use Maatwebsite\Excel\Concerns\WithUpserts;
use Maatwebsite\Excel\Concerns\WithValidation;
use Maatwebsite\Excel\Exceptions\RowSkippedException;
use Maatwebsite\Excel\Imports\Persistence\CascadePersistManager;
use Maatwebsite\Excel\Validators\RowValidator;
use Maatwebsite\Excel\Validators\ValidationException;
use Throwable;
class ModelManager
{
/**
* @var array
*/
private $rows = [];
/**
* @var RowValidator
*/
private $validator;
/**
* @var bool
*/
private $remembersRowNumber = false;
/**
* @var CascadePersistManager
*/
private $cascade;
/**
* @param RowValidator $validator
*/
public function __construct(RowValidator $validator, CascadePersistManager $cascade)
{
$this->validator = $validator;
$this->cascade = $cascade;
}
/**
* @param int $row
* @param array $attributes
*/
public function add(int $row, array $attributes)
{
$this->rows[$row] = $attributes;
}
/**
* @param bool $remembersRowNumber
*/
public function setRemembersRowNumber(bool $remembersRowNumber)
{
$this->remembersRowNumber = $remembersRowNumber;
}
/**
* @param ToModel $import
* @param bool $massInsert
*
* @throws ValidationException
*/
public function flush(ToModel $import, bool $massInsert = false)
{
if ($import instanceof WithValidation) {
$this->validateRows($import);
}
if ($massInsert) {
$this->massFlush($import);
} else {
$this->singleFlush($import);
}
$this->rows = [];
}
/**
* @param ToModel $import
* @param array $attributes
* @param int|null $rowNumber
* @return Model[]|Collection
*/
public function toModels(ToModel $import, array $attributes, $rowNumber = null): Collection
{
if ($this->remembersRowNumber) {
$import->rememberRowNumber($rowNumber);
}
return Collection::wrap($import->model($attributes));
}
/**
* @param ToModel $import
*/
private function massFlush(ToModel $import)
{
$this->rows()
->flatMap(function (array $attributes, $index) use ($import) {
return $this->toModels($import, $attributes, $index);
})
->mapToGroups(function ($model) {
return [\get_class($model) => $this->prepare($model)->getAttributes()];
})
->each(function (Collection $models, string $model) use ($import) {
try {
/* @var Model $model */
if ($import instanceof WithUpserts) {
$model::query()->upsert(
$models->toArray(),
$import->uniqueBy(),
$import instanceof WithUpsertColumns ? $import->upsertColumns() : null
);
return;
}
$model::query()->insert($models->toArray());
} catch (Throwable $e) {
$this->handleException($import, $e);
}
});
}
/**
* @param ToModel $import
*/
private function singleFlush(ToModel $import)
{
$this
->rows()
->each(function (array $attributes, $index) use ($import) {
$this->toModels($import, $attributes, $index)->each(function (Model $model) use ($import) {
try {
if ($import instanceof WithUpserts) {
$model->upsert(
$model->getAttributes(),
$import->uniqueBy(),
$import instanceof WithUpsertColumns ? $import->upsertColumns() : null
);
return;
}
if ($import instanceof PersistRelations) {
$this->cascade->persist($model);
} else {
$model->saveOrFail();
}
} catch (Throwable $e) {
$this->handleException($import, $e);
}
});
});
}
/**
* @param Model $model
* @return Model
*/
private function prepare(Model $model): Model
{
if ($model->usesTimestamps()) {
$time = $model->freshTimestamp();
$updatedAtColumn = $model->getUpdatedAtColumn();
// If model has updated at column and not manually provided.
if ($updatedAtColumn && null === $model->{$updatedAtColumn}) {
$model->setUpdatedAt($time);
}
$createdAtColumn = $model->getCreatedAtColumn();
// If model has created at column and not manually provided.
if ($createdAtColumn && null === $model->{$createdAtColumn}) {
$model->setCreatedAt($time);
}
}
return $model;
}
/**
* @param WithValidation $import
*
* @throws ValidationException
*/
private function validateRows(WithValidation $import)
{
try {
$this->validator->validate($this->rows, $import);
} catch (RowSkippedException $e) {
foreach ($e->skippedRows() as $row) {
unset($this->rows[$row]);
}
}
}
/**
* @return Collection
*/
private function rows(): Collection
{
return new Collection($this->rows);
}
private function handleException(ToModel $import, Throwable $e): void
{
if (!$import instanceof SkipsOnError) {
throw $e;
}
$import->onError($e);
}
}
excel/src/Imports/EndRowFinder.php 0000644 00000001464 15243417774 0013152 0 ustar 00 <?php
namespace Maatwebsite\Excel\Imports;
use Maatwebsite\Excel\Concerns\WithLimit;
class EndRowFinder
{
/**
* @param object|WithLimit $import
* @param int $startRow
* @param int|null $highestRow
* @return int|null
*/
public static function find($import, int $startRow = null, int $highestRow = null)
{
if (!$import instanceof WithLimit) {
return null;
}
$limit = $import->limit();
if ($limit > $highestRow) {
return null;
}
// When no start row given,
// use the first row as start row.
$startRow = $startRow ?? 1;
// Subtract 1 row from the start row, so a limit
// of 1 row, will have the same start and end row.
return ($startRow - 1) + $limit;
}
}
excel/src/Imports/HeadingRowExtractor.php 0000644 00000004765 15243417774 0014556 0 ustar 00 <?php
namespace Maatwebsite\Excel\Imports;
use Maatwebsite\Excel\Concerns\WithColumnLimit;
use Maatwebsite\Excel\Concerns\WithGroupedHeadingRow;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Concerns\WithStartRow;
use Maatwebsite\Excel\Row;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
class HeadingRowExtractor
{
/**
* @const int
*/
const DEFAULT_HEADING_ROW = 1;
/**
* @param WithHeadingRow|mixed $importable
* @return int
*/
public static function headingRow($importable): int
{
return method_exists($importable, 'headingRow')
? $importable->headingRow()
: self::DEFAULT_HEADING_ROW;
}
/**
* @param WithHeadingRow|mixed $importable
* @return int
*/
public static function determineStartRow($importable): int
{
if ($importable instanceof WithStartRow) {
return $importable->startRow();
}
// The start row is the row after the heading row if we have one!
return $importable instanceof WithHeadingRow
? self::headingRow($importable) + 1
: self::DEFAULT_HEADING_ROW;
}
/**
* @param Worksheet $worksheet
* @param WithHeadingRow|mixed $importable
* @return array
*/
public static function extract(Worksheet $worksheet, $importable): array
{
if (!$importable instanceof WithHeadingRow) {
return [];
}
$headingRowNumber = self::headingRow($importable);
$rows = iterator_to_array($worksheet->getRowIterator($headingRowNumber, $headingRowNumber));
$headingRow = head($rows);
$endColumn = $importable instanceof WithColumnLimit ? $importable->endColumn() : null;
return HeadingRowFormatter::format((new Row($headingRow))->toArray(null, false, false, $endColumn));
}
/**
* @param array $headingRow
* @param WithGroupedHeadingRow|mixed $importable
* @return array
*/
public static function extractGrouping($headingRow, $importable)
{
$headerIsGrouped = array_fill(0, count($headingRow), false);
if (!$importable instanceof WithGroupedHeadingRow) {
return $headerIsGrouped;
}
array_walk($headerIsGrouped, function (&$value, $key) use ($headingRow) {
if (array_count_values($headingRow)[$headingRow[$key]] > 1) {
$value = true;
}
});
return $headerIsGrouped;
}
}
excel/src/HasEventBus.php 0000644 00000002515 15243417774 0011354 0 ustar 00 <?php
namespace Maatwebsite\Excel;
trait HasEventBus
{
/**
* @var array
*/
protected static $globalEvents = [];
/**
* @var array
*/
protected $events = [];
/**
* Register local event listeners.
*
* @param array $listeners
*/
public function registerListeners(array $listeners)
{
foreach ($listeners as $event => $listener) {
$this->events[$event][] = $listener;
}
}
public function clearListeners()
{
$this->events = [];
}
/**
* Register a global event listener.
*
* @param string $event
* @param callable $listener
*/
public static function listen(string $event, callable $listener)
{
static::$globalEvents[$event][] = $listener;
}
/**
* @param object $event
*/
public function raise($event)
{
foreach ($this->listeners($event) as $listener) {
$listener($event);
}
}
/**
* @param object $event
* @return callable[]
*/
public function listeners($event): array
{
$name = \get_class($event);
$localListeners = $this->events[$name] ?? [];
$globalListeners = static::$globalEvents[$name] ?? [];
return array_merge($globalListeners, $localListeners);
}
}
excel/src/Events/AfterImport.php 0000644 00000001174 15243417774 0012665 0 ustar 00 <?php
namespace Maatwebsite\Excel\Events;
use Maatwebsite\Excel\Reader;
class AfterImport extends Event
{
/**
* @var Reader
*/
public $reader;
/**
* @param Reader $reader
* @param object $importable
*/
public function __construct(Reader $reader, $importable)
{
$this->reader = $reader;
parent::__construct($importable);
}
/**
* @return Reader
*/
public function getReader(): Reader
{
return $this->reader;
}
/**
* @return mixed
*/
public function getDelegate()
{
return $this->reader;
}
}
excel/src/Events/AfterSheet.php 0000644 00000001156 15243417774 0012463 0 ustar 00 <?php
namespace Maatwebsite\Excel\Events;
use Maatwebsite\Excel\Sheet;
class AfterSheet extends Event
{
/**
* @var Sheet
*/
public $sheet;
/**
* @param Sheet $sheet
* @param object $exportable
*/
public function __construct(Sheet $sheet, $exportable)
{
$this->sheet = $sheet;
parent::__construct($exportable);
}
/**
* @return Sheet
*/
public function getSheet(): Sheet
{
return $this->sheet;
}
/**
* @return mixed
*/
public function getDelegate()
{
return $this->sheet;
}
}
excel/src/Events/BeforeWriting.php 0000644 00000001273 15243417774 0013177 0 ustar 00 <?php
namespace Maatwebsite\Excel\Events;
use Maatwebsite\Excel\Writer;
class BeforeWriting extends Event
{
/**
* @var Writer
*/
public $writer;
/**
* @var object
*/
private $exportable;
/**
* @param Writer $writer
* @param object $exportable
*/
public function __construct(Writer $writer, $exportable)
{
$this->writer = $writer;
parent::__construct($exportable);
}
/**
* @return Writer
*/
public function getWriter(): Writer
{
return $this->writer;
}
/**
* @return mixed
*/
public function getDelegate()
{
return $this->writer;
}
}
excel/src/Events/Event.php 0000644 00000001311 15243417774 0011503 0 ustar 00 <?php
namespace Maatwebsite\Excel\Events;
/**
* @internal
*/
abstract class Event
{
/**
* @var object
*/
protected $concernable;
/**
* @param object $concernable
*/
public function __construct($concernable)
{
$this->concernable = $concernable;
}
/**
* @return object
*/
public function getConcernable()
{
return $this->concernable;
}
/**
* @return mixed
*/
abstract public function getDelegate();
/**
* @param string $concern
* @return bool
*/
public function appliesToConcern(string $concern): bool
{
return $this->getConcernable() instanceof $concern;
}
}
excel/src/Events/BeforeImport.php 0000644 00000001175 15243417774 0013027 0 ustar 00 <?php
namespace Maatwebsite\Excel\Events;
use Maatwebsite\Excel\Reader;
class BeforeImport extends Event
{
/**
* @var Reader
*/
public $reader;
/**
* @param Reader $reader
* @param object $importable
*/
public function __construct(Reader $reader, $importable)
{
$this->reader = $reader;
parent::__construct($importable);
}
/**
* @return Reader
*/
public function getReader(): Reader
{
return $this->reader;
}
/**
* @return mixed
*/
public function getDelegate()
{
return $this->reader;
}
}
excel/src/Events/BeforeExport.php 0000644 00000001175 15243417774 0013036 0 ustar 00 <?php
namespace Maatwebsite\Excel\Events;
use Maatwebsite\Excel\Writer;
class BeforeExport extends Event
{
/**
* @var Writer
*/
public $writer;
/**
* @param Writer $writer
* @param object $exportable
*/
public function __construct(Writer $writer, $exportable)
{
$this->writer = $writer;
parent::__construct($exportable);
}
/**
* @return Writer
*/
public function getWriter(): Writer
{
return $this->writer;
}
/**
* @return mixed
*/
public function getDelegate()
{
return $this->writer;
}
}
excel/src/Events/ImportFailed.php 0000644 00000000604 15243417774 0013005 0 ustar 00 <?php
namespace Maatwebsite\Excel\Events;
use Throwable;
class ImportFailed
{
/**
* @var Throwable
*/
public $e;
/**
* @param Throwable $e
*/
public function __construct(Throwable $e)
{
$this->e = $e;
}
/**
* @return Throwable
*/
public function getException(): Throwable
{
return $this->e;
}
}
excel/src/Events/BeforeSheet.php 0000644 00000001160 15243417774 0012617 0 ustar 00 <?php
namespace Maatwebsite\Excel\Events;
use Maatwebsite\Excel\Sheet;
class BeforeSheet extends Event
{
/**
* @var Sheet
*/
public $sheet;
/**
* @param Sheet $sheet
* @param object $exportable
*/
public function __construct(Sheet $sheet, $exportable)
{
$this->sheet = $sheet;
parent::__construct($exportable);
}
/**
* @return Sheet
*/
public function getSheet(): Sheet
{
return $this->sheet;
}
/**
* @return mixed
*/
public function getDelegate()
{
return $this->sheet;
}
}
excel/src/Events/AfterChunk.php 0000644 00000001225 15243417774 0012460 0 ustar 00 <?php
namespace Maatwebsite\Excel\Events;
use Maatwebsite\Excel\Sheet;
class AfterChunk extends Event
{
/**
* @var Sheet
*/
private $sheet;
/**
* @var int
*/
private $startRow;
public function __construct(Sheet $sheet, $importable, int $startRow)
{
$this->sheet = $sheet;
$this->startRow = $startRow;
parent::__construct($importable);
}
public function getSheet(): Sheet
{
return $this->sheet;
}
public function getDelegate()
{
return $this->sheet;
}
public function getStartRow(): int
{
return $this->startRow;
}
}
excel/src/Events/AfterBatch.php 0000644 00000002105 15243417774 0012427 0 ustar 00 <?php
namespace Maatwebsite\Excel\Events;
use Maatwebsite\Excel\Imports\ModelManager;
class AfterBatch extends Event
{
/**
* @var ModelManager
*/
public $manager;
/**
* @var int
*/
private $batchSize;
/**
* @var int
*/
private $startRow;
/**
* @param ModelManager $manager
* @param object $importable
* @param int $batchSize
* @param int $startRow
*/
public function __construct(ModelManager $manager, $importable, int $batchSize, int $startRow)
{
$this->manager = $manager;
$this->batchSize = $batchSize;
$this->startRow = $startRow;
parent::__construct($importable);
}
public function getManager(): ModelManager
{
return $this->manager;
}
/**
* @return mixed
*/
public function getDelegate()
{
return $this->manager;
}
public function getBatchSize(): int
{
return $this->batchSize;
}
public function getStartRow(): int
{
return $this->startRow;
}
}
excel/src/Cache/BatchCache.php 0000644 00000007473 15243417774 0012145 0 ustar 00 <?php
namespace Maatwebsite\Excel\Cache;
use Illuminate\Support\Facades\Cache;
use Psr\SimpleCache\CacheInterface;
class BatchCache implements CacheInterface
{
/**
* @var CacheInterface
*/
protected $cache;
/**
* @var MemoryCache
*/
protected $memory;
/**
* @var null|int|\DateInterval|callable
*/
protected $defaultTTL = null;
/**
* @param CacheInterface $cache
* @param MemoryCache $memory
* @param null|int|\DateInterval|callable $defaultTTL
*/
public function __construct(
CacheInterface $cache,
MemoryCache $memory,
null|int|\DateInterval|callable $defaultTTL = null
) {
$this->cache = $cache;
$this->memory = $memory;
$this->defaultTTL = $defaultTTL;
}
public function __sleep()
{
return ['memory'];
}
public function __wakeup()
{
$this->cache = Cache::driver(
config('excel.cache.illuminate.store')
);
}
/**
* {@inheritdoc}
*/
public function get(string $key, mixed $default = null): mixed
{
if ($this->memory->has($key)) {
return $this->memory->get($key);
}
return $this->cache->get($key, $default);
}
/**
* {@inheritdoc}
*/
public function set(string $key, mixed $value, null|int|\DateInterval $ttl = null): bool
{
if (func_num_args() === 2) {
$ttl = value($this->defaultTTL);
}
$this->memory->set($key, $value, $ttl);
if ($this->memory->reachedMemoryLimit()) {
return $this->cache->setMultiple($this->memory->flush(), $ttl);
}
return true;
}
/**
* {@inheritdoc}
*/
public function delete(string $key): bool
{
if ($this->memory->has($key)) {
return $this->memory->delete($key);
}
return $this->cache->delete($key);
}
/**
* {@inheritdoc}
*/
public function clear(): bool
{
$this->memory->clear();
return $this->cache->clear();
}
/**
* {@inheritdoc}
*/
public function getMultiple(iterable $keys, mixed $default = null): iterable
{
// Check if all keys are still in memory
$memory = $this->memory->getMultiple($keys, $default);
$actualItemsInMemory = count(array_filter($memory));
if ($actualItemsInMemory === count($keys)) {
return $memory;
}
// Get all rows from cache if none is hold in memory.
if ($actualItemsInMemory === 0) {
return $this->cache->getMultiple($keys, $default);
}
// Add missing values from cache.
foreach ($this->cache->getMultiple($keys, $default) as $key => $value) {
if (null !== $value) {
$memory[$key] = $value;
}
}
return $memory;
}
/**
* {@inheritdoc}
*/
public function setMultiple(iterable $values, null|int|\DateInterval $ttl = null): bool
{
if (func_num_args() === 1) {
$ttl = value($this->defaultTTL);
}
$this->memory->setMultiple($values, $ttl);
if ($this->memory->reachedMemoryLimit()) {
return $this->cache->setMultiple($this->memory->flush(), $ttl);
}
return true;
}
/**
* {@inheritdoc}
*/
public function deleteMultiple(iterable $keys): bool
{
$keys = is_array($keys) ? $keys : iterator_to_array($keys);
$this->memory->deleteMultiple($keys);
return $this->cache->deleteMultiple($keys);
}
/**
* {@inheritdoc}
*/
public function has(string $key): bool
{
if ($this->memory->has($key)) {
return true;
}
return $this->cache->has($key);
}
}
excel/src/Cache/MemoryCache.php 0000644 00000005057 15243417774 0012370 0 ustar 00 <?php
namespace Maatwebsite\Excel\Cache;
use PhpOffice\PhpSpreadsheet\Cell\Cell;
use Psr\SimpleCache\CacheInterface;
class MemoryCache implements CacheInterface
{
/**
* @var int|null
*/
protected $memoryLimit;
/**
* @var array
*/
protected $cache = [];
/**
* @param int|null $memoryLimit
*/
public function __construct(int $memoryLimit = null)
{
$this->memoryLimit = $memoryLimit;
}
/**
* {@inheritdoc}
*/
public function clear(): bool
{
$this->cache = [];
return true;
}
/**
* {@inheritdoc}
*/
public function delete(string $key): bool
{
unset($this->cache[$key]);
return true;
}
/**
* {@inheritdoc}
*/
public function deleteMultiple($keys): bool
{
foreach ($keys as $key) {
$this->delete($key);
}
return true;
}
/**
* {@inheritdoc}
*/
public function get(string $key, mixed $default = null): mixed
{
if ($this->has($key)) {
return $this->cache[$key];
}
return $default;
}
/**
* {@inheritdoc}
*/
public function getMultiple(iterable $keys, mixed $default = null): iterable
{
$results = [];
foreach ($keys as $key) {
$results[$key] = $this->get($key, $default);
}
return $results;
}
/**
* {@inheritdoc}
*/
public function has($key): bool
{
return isset($this->cache[$key]);
}
/**
* {@inheritdoc}
*/
public function set(string $key, mixed $value, null|int|\DateInterval $ttl = null): bool
{
$this->cache[$key] = $value;
return true;
}
/**
* {@inheritdoc}
*/
public function setMultiple($values, $ttl = null): bool
{
foreach ($values as $key => $value) {
$this->set($key, $value);
}
return true;
}
/**
* @return bool
*/
public function reachedMemoryLimit(): bool
{
// When no limit is given, we'll never reach any limit.
if (null === $this->memoryLimit) {
return false;
}
return count($this->cache) >= $this->memoryLimit;
}
/**
* @return array
*/
public function flush(): array
{
$memory = $this->cache;
foreach ($memory as $cell) {
if ($cell instanceof Cell) {
$cell->detach();
}
}
$this->clear();
return $memory;
}
}
excel/src/Cache/CacheManager.php 0000644 00000004115 15243417774 0012464 0 ustar 00 <?php
namespace Maatwebsite\Excel\Cache;
use Composer\InstalledVersions;
use Composer\Semver\VersionParser;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Manager;
use Psr\SimpleCache\CacheInterface;
class CacheManager extends Manager
{
/**
* @const string
*/
public const DRIVER_BATCH = 'batch';
/**
* @const string
*/
public const DRIVER_MEMORY = 'memory';
/**
* @const string
*/
public const DRIVER_ILLUMINATE = 'illuminate';
/**
* Get the default driver name.
*
* @return string
*/
public function getDefaultDriver(): string
{
return config('excel.cache.driver', 'memory');
}
/**
* @return MemoryCache
*/
public function createMemoryDriver(): CacheInterface
{
if (!InstalledVersions::satisfies(new VersionParser, 'psr/simple-cache', '^3.0')) {
return new MemoryCacheDeprecated(
config('excel.cache.batch.memory_limit', 60000)
);
}
return new MemoryCache(
config('excel.cache.batch.memory_limit', 60000)
);
}
/**
* @return BatchCache
*/
public function createBatchDriver(): CacheInterface
{
if (!InstalledVersions::satisfies(new VersionParser, 'psr/simple-cache', '^3.0')) {
return new BatchCacheDeprecated(
$this->createIlluminateDriver(),
$this->createMemoryDriver(),
config('excel.cache.ttl')
);
}
return new BatchCache(
$this->createIlluminateDriver(),
$this->createMemoryDriver(),
config('excel.cache.ttl')
);
}
/**
* @return CacheInterface
*/
public function createIlluminateDriver(): CacheInterface
{
return Cache::driver(
config('excel.cache.illuminate.store')
);
}
public function flush()
{
$this->driver()->clear();
}
public function isInMemory(): bool
{
return $this->getDefaultDriver() === self::DRIVER_MEMORY;
}
}
excel/src/Cache/MemoryCacheDeprecated.php 0000644 00000004675 15243417774 0014356 0 ustar 00 <?php
namespace Maatwebsite\Excel\Cache;
use PhpOffice\PhpSpreadsheet\Cell\Cell;
use Psr\SimpleCache\CacheInterface;
class MemoryCacheDeprecated implements CacheInterface
{
/**
* @var int|null
*/
protected $memoryLimit;
/**
* @var array
*/
protected $cache = [];
/**
* @param int|null $memoryLimit
*/
public function __construct(int $memoryLimit = null)
{
$this->memoryLimit = $memoryLimit;
}
/**
* {@inheritdoc}
*/
public function clear()
{
$this->cache = [];
return true;
}
/**
* {@inheritdoc}
*/
public function delete($key)
{
unset($this->cache[$key]);
return true;
}
/**
* {@inheritdoc}
*/
public function deleteMultiple($keys)
{
foreach ($keys as $key) {
$this->delete($key);
}
return true;
}
/**
* {@inheritdoc}
*/
public function get($key, $default = null)
{
if ($this->has($key)) {
return $this->cache[$key];
}
return $default;
}
/**
* {@inheritdoc}
*/
public function getMultiple($keys, $default = null)
{
$results = [];
foreach ($keys as $key) {
$results[$key] = $this->get($key, $default);
}
return $results;
}
/**
* {@inheritdoc}
*/
public function has($key)
{
return isset($this->cache[$key]);
}
/**
* {@inheritdoc}
*/
public function set($key, $value, $ttl = null)
{
$this->cache[$key] = $value;
return true;
}
/**
* {@inheritdoc}
*/
public function setMultiple($values, $ttl = null)
{
foreach ($values as $key => $value) {
$this->set($key, $value);
}
return true;
}
/**
* @return bool
*/
public function reachedMemoryLimit(): bool
{
// When no limit is given, we'll never reach any limit.
if (null === $this->memoryLimit) {
return false;
}
return count($this->cache) >= $this->memoryLimit;
}
/**
* @return array
*/
public function flush(): array
{
$memory = $this->cache;
foreach ($memory as $cell) {
if ($cell instanceof Cell) {
$cell->detach();
}
}
$this->clear();
return $memory;
}
}
excel/src/Cache/BatchCacheDeprecated.php 0000644 00000007241 15243417774 0014117 0 ustar 00 <?php
namespace Maatwebsite\Excel\Cache;
use Illuminate\Support\Facades\Cache;
use Psr\SimpleCache\CacheInterface;
class BatchCacheDeprecated implements CacheInterface
{
/**
* @var CacheInterface
*/
protected $cache;
/**
* @var MemoryCacheDeprecated
*/
protected $memory;
/**
* @var null|int|\DateTimeInterface|callable
*/
protected $defaultTTL = null;
/**
* @param CacheInterface $cache
* @param MemoryCacheDeprecated $memory
* @param int|\DateTimeInterface|callable|null $defaultTTL
*/
public function __construct(
CacheInterface $cache,
MemoryCacheDeprecated $memory,
$defaultTTL = null
) {
$this->cache = $cache;
$this->memory = $memory;
$this->defaultTTL = $defaultTTL;
}
public function __sleep()
{
return ['memory'];
}
public function __wakeup()
{
$this->cache = Cache::driver(
config('excel.cache.illuminate.store')
);
}
/**
* {@inheritdoc}
*/
public function get($key, $default = null)
{
if ($this->memory->has($key)) {
return $this->memory->get($key);
}
return $this->cache->get($key, $default);
}
/**
* {@inheritdoc}
*/
public function set($key, $value, $ttl = null)
{
if (func_num_args() === 2) {
$ttl = value($this->defaultTTL);
}
$this->memory->set($key, $value, $ttl);
if ($this->memory->reachedMemoryLimit()) {
return $this->cache->setMultiple($this->memory->flush(), $ttl);
}
return true;
}
/**
* {@inheritdoc}
*/
public function delete($key)
{
if ($this->memory->has($key)) {
return $this->memory->delete($key);
}
return $this->cache->delete($key);
}
/**
* {@inheritdoc}
*/
public function clear()
{
$this->memory->clear();
return $this->cache->clear();
}
/**
* {@inheritdoc}
*/
public function getMultiple($keys, $default = null)
{
// Check if all keys are still in memory
$memory = $this->memory->getMultiple($keys, $default);
$actualItemsInMemory = count(array_filter($memory));
if ($actualItemsInMemory === count($keys)) {
return $memory;
}
// Get all rows from cache if none is hold in memory.
if ($actualItemsInMemory === 0) {
return $this->cache->getMultiple($keys, $default);
}
// Add missing values from cache.
foreach ($this->cache->getMultiple($keys, $default) as $key => $value) {
if (null !== $value) {
$memory[$key] = $value;
}
}
return $memory;
}
/**
* {@inheritdoc}
*/
public function setMultiple($values, $ttl = null)
{
if (func_num_args() === 1) {
$ttl = value($this->defaultTTL);
}
$this->memory->setMultiple($values, $ttl);
if ($this->memory->reachedMemoryLimit()) {
return $this->cache->setMultiple($this->memory->flush(), $ttl);
}
return true;
}
/**
* {@inheritdoc}
*/
public function deleteMultiple($keys)
{
$keys = is_array($keys) ? $keys : iterator_to_array($keys);
$this->memory->deleteMultiple($keys);
return $this->cache->deleteMultiple($keys);
}
/**
* {@inheritdoc}
*/
public function has($key)
{
if ($this->memory->has($key)) {
return true;
}
return $this->cache->has($key);
}
}
excel/src/Sheet.php 0000644 00000061670 15243417774 0010244 0 ustar 00 <?php
namespace Maatwebsite\Excel;
use Closure;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Support\Collection;
use Illuminate\Support\LazyCollection;
use Maatwebsite\Excel\Concerns\FromArray;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\FromGenerator;
use Maatwebsite\Excel\Concerns\FromIterator;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\FromView;
use Maatwebsite\Excel\Concerns\OnEachRow;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
use Maatwebsite\Excel\Concerns\SkipsEmptyRows;
use Maatwebsite\Excel\Concerns\ToArray;
use Maatwebsite\Excel\Concerns\ToCollection;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithCalculatedFormulas;
use Maatwebsite\Excel\Concerns\WithCharts;
use Maatwebsite\Excel\Concerns\WithChunkReading;
use Maatwebsite\Excel\Concerns\WithColumnFormatting;
use Maatwebsite\Excel\Concerns\WithColumnLimit;
use Maatwebsite\Excel\Concerns\WithColumnWidths;
use Maatwebsite\Excel\Concerns\WithCustomChunkSize;
use Maatwebsite\Excel\Concerns\WithCustomStartCell;
use Maatwebsite\Excel\Concerns\WithCustomValueBinder;
use Maatwebsite\Excel\Concerns\WithDrawings;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Concerns\WithFormatData;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithMappedCells;
use Maatwebsite\Excel\Concerns\WithMapping;
use Maatwebsite\Excel\Concerns\WithProgressBar;
use Maatwebsite\Excel\Concerns\WithStrictNullComparison;
use Maatwebsite\Excel\Concerns\WithStyles;
use Maatwebsite\Excel\Concerns\WithTitle;
use Maatwebsite\Excel\Concerns\WithValidation;
use Maatwebsite\Excel\Events\AfterSheet;
use Maatwebsite\Excel\Events\BeforeSheet;
use Maatwebsite\Excel\Exceptions\ConcernConflictException;
use Maatwebsite\Excel\Exceptions\RowSkippedException;
use Maatwebsite\Excel\Exceptions\SheetNotFoundException;
use Maatwebsite\Excel\Files\TemporaryFileFactory;
use Maatwebsite\Excel\Helpers\ArrayHelper;
use Maatwebsite\Excel\Helpers\CellHelper;
use Maatwebsite\Excel\Imports\EndRowFinder;
use Maatwebsite\Excel\Imports\HeadingRowExtractor;
use Maatwebsite\Excel\Imports\ModelImporter;
use Maatwebsite\Excel\Validators\RowValidator;
use PhpOffice\PhpSpreadsheet\Cell\Cell as SpreadsheetCell;
use PhpOffice\PhpSpreadsheet\Chart\Chart;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Reader\Html;
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\BaseDrawing;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
/** @mixin Worksheet */
class Sheet
{
use DelegatedMacroable, HasEventBus;
/**
* @var int
*/
protected $chunkSize;
/**
* @var TemporaryFileFactory
*/
protected $temporaryFileFactory;
/**
* @var object
*/
protected $exportable;
/**
* @var Worksheet
*/
private $worksheet;
/**
* @param Worksheet $worksheet
*/
public function __construct(Worksheet $worksheet)
{
$this->worksheet = $worksheet;
$this->chunkSize = config('excel.exports.chunk_size', 100);
$this->temporaryFileFactory = app(TemporaryFileFactory::class);
}
/**
* @param Spreadsheet $spreadsheet
* @param string|int $index
* @return Sheet
*
* @throws \PhpOffice\PhpSpreadsheet\Exception
* @throws SheetNotFoundException
*/
public static function make(Spreadsheet $spreadsheet, $index)
{
if (is_numeric($index)) {
return self::byIndex($spreadsheet, $index);
}
return self::byName($spreadsheet, $index);
}
/**
* @param Spreadsheet $spreadsheet
* @param int $index
* @return Sheet
*
* @throws \PhpOffice\PhpSpreadsheet\Exception
* @throws SheetNotFoundException
*/
public static function byIndex(Spreadsheet $spreadsheet, int $index): Sheet
{
if (!isset($spreadsheet->getAllSheets()[$index])) {
throw SheetNotFoundException::byIndex($index, $spreadsheet->getSheetCount());
}
return new static($spreadsheet->getSheet($index));
}
/**
* @param Spreadsheet $spreadsheet
* @param string $name
* @return Sheet
*
* @throws SheetNotFoundException
*/
public static function byName(Spreadsheet $spreadsheet, string $name): Sheet
{
if (!$spreadsheet->sheetNameExists($name)) {
throw SheetNotFoundException::byName($name);
}
return new static($spreadsheet->getSheetByName($name));
}
/**
* @param object $sheetExport
*
* @throws \PhpOffice\PhpSpreadsheet\Exception
*/
public function open($sheetExport)
{
$this->exportable = $sheetExport;
if ($sheetExport instanceof WithCustomValueBinder) {
SpreadsheetCell::setValueBinder($sheetExport);
}
if ($sheetExport instanceof WithEvents) {
$this->registerListeners($sheetExport->registerEvents());
}
$this->raise(new BeforeSheet($this, $this->exportable));
if ($sheetExport instanceof WithTitle) {
$title = $sheetExport->title();
$title = str_replace(['*', ':', '/', '\\', '?', '[', ']'], '', $title);
if (StringHelper::countCharacters($title) > Worksheet::SHEET_TITLE_MAXIMUM_LENGTH) {
$title = StringHelper::substring($title, 0, Worksheet::SHEET_TITLE_MAXIMUM_LENGTH);
}
$this->worksheet->setTitle($title);
}
if (($sheetExport instanceof FromQuery || $sheetExport instanceof FromCollection || $sheetExport instanceof FromArray) && $sheetExport instanceof FromView) {
throw ConcernConflictException::queryOrCollectionAndView();
}
if (!$sheetExport instanceof FromView && $sheetExport instanceof WithHeadings) {
if ($sheetExport instanceof WithCustomStartCell) {
$startCell = $sheetExport->startCell();
}
$this->append(
ArrayHelper::ensureMultipleRows($sheetExport->headings()),
$startCell ?? null,
$this->hasStrictNullComparison($sheetExport)
);
}
if ($sheetExport instanceof WithCharts) {
$this->addCharts($sheetExport->charts());
}
}
/**
* @param object $sheetExport
*
* @throws \PhpOffice\PhpSpreadsheet\Exception
* @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
*/
public function export($sheetExport)
{
$this->open($sheetExport);
if ($sheetExport instanceof FromView) {
$this->fromView($sheetExport);
} else {
if ($sheetExport instanceof FromQuery) {
$this->fromQuery($sheetExport, $this->worksheet);
}
if ($sheetExport instanceof FromCollection) {
$this->fromCollection($sheetExport);
}
if ($sheetExport instanceof FromArray) {
$this->fromArray($sheetExport);
}
if ($sheetExport instanceof FromIterator) {
$this->fromIterator($sheetExport);
}
if ($sheetExport instanceof FromGenerator) {
$this->fromGenerator($sheetExport);
}
}
$this->close($sheetExport);
}
/**
* @param object $import
* @param int $startRow
*/
public function import($import, int $startRow = 1)
{
if ($import instanceof WithEvents) {
$this->registerListeners($import->registerEvents());
}
$this->raise(new BeforeSheet($this, $import));
if ($import instanceof WithProgressBar && !$import instanceof WithChunkReading) {
$import->getConsoleOutput()->progressStart($this->worksheet->getHighestRow());
}
$calculatesFormulas = $import instanceof WithCalculatedFormulas;
$formatData = $import instanceof WithFormatData;
if ($import instanceof WithMappedCells) {
app(MappedReader::class)->map($import, $this->worksheet);
} else {
if ($import instanceof ToModel) {
app(ModelImporter::class)->import($this->worksheet, $import, $startRow);
}
if ($import instanceof ToCollection) {
$rows = $this->toCollection($import, $startRow, null, $calculatesFormulas, $formatData);
if ($import instanceof WithValidation) {
$rows = $this->validated($import, $startRow, $rows);
}
$import->collection($rows);
}
if ($import instanceof ToArray) {
$rows = $this->toArray($import, $startRow, null, $calculatesFormulas, $formatData);
if ($import instanceof WithValidation) {
$rows = $this->validated($import, $startRow, $rows);
}
$import->array($rows);
}
}
if ($import instanceof OnEachRow) {
$headingRow = HeadingRowExtractor::extract($this->worksheet, $import);
$headerIsGrouped = HeadingRowExtractor::extractGrouping($headingRow, $import);
$endColumn = $import instanceof WithColumnLimit ? $import->endColumn() : null;
$preparationCallback = $this->getPreparationCallback($import);
foreach ($this->worksheet->getRowIterator()->resetStart($startRow ?? 1) as $row) {
$sheetRow = new Row($row, $headingRow, $headerIsGrouped);
if ($import instanceof WithValidation) {
$sheetRow->setPreparationCallback($preparationCallback);
}
$rowArray = $sheetRow->toArray(null, $import instanceof WithCalculatedFormulas, $import instanceof WithFormatData, $endColumn);
$rowIsEmptyAccordingToImport = $import instanceof SkipsEmptyRows && method_exists($import, 'isEmptyWhen') && $import->isEmptyWhen($rowArray);
if (!$import instanceof SkipsEmptyRows || ($import instanceof SkipsEmptyRows && (!$rowIsEmptyAccordingToImport && !$sheetRow->isEmpty($calculatesFormulas)))) {
if ($import instanceof WithValidation) {
$toValidate = [$sheetRow->getIndex() => $rowArray];
try {
app(RowValidator::class)->validate($toValidate, $import);
$import->onRow($sheetRow);
} catch (RowSkippedException $e) {
}
} else {
$import->onRow($sheetRow);
}
}
if ($import instanceof WithProgressBar) {
$import->getConsoleOutput()->progressAdvance();
}
}
}
$this->raise(new AfterSheet($this, $import));
if ($import instanceof WithProgressBar && !$import instanceof WithChunkReading) {
$import->getConsoleOutput()->progressFinish();
}
}
/**
* @param object $import
* @param int|null $startRow
* @param null $nullValue
* @param bool $calculateFormulas
* @param bool $formatData
* @return array
*/
public function toArray($import, int $startRow = null, $nullValue = null, $calculateFormulas = false, $formatData = false)
{
if ($startRow > $this->worksheet->getHighestRow()) {
return [];
}
$endRow = EndRowFinder::find($import, $startRow, $this->worksheet->getHighestRow());
$headingRow = HeadingRowExtractor::extract($this->worksheet, $import);
$headerIsGrouped = HeadingRowExtractor::extractGrouping($headingRow, $import);
$endColumn = $import instanceof WithColumnLimit ? $import->endColumn() : null;
$rows = [];
foreach ($this->worksheet->getRowIterator($startRow, $endRow) as $index => $row) {
$row = new Row($row, $headingRow, $headerIsGrouped);
if ($import instanceof SkipsEmptyRows && $row->isEmpty($calculateFormulas, $endColumn)) {
continue;
}
$row = $row->toArray($nullValue, $calculateFormulas, $formatData, $endColumn);
if ($import && method_exists($import, 'isEmptyWhen') && $import->isEmptyWhen($row)) {
continue;
}
if ($import instanceof WithMapping) {
$row = $import->map($row);
}
if ($import instanceof WithValidation && method_exists($import, 'prepareForValidation')) {
$row = $import->prepareForValidation($row, $index);
}
$rows[] = $row;
if ($import instanceof WithProgressBar) {
$import->getConsoleOutput()->progressAdvance();
}
}
return $rows;
}
/**
* @param object $import
* @param int|null $startRow
* @param null $nullValue
* @param bool $calculateFormulas
* @param bool $formatData
* @return Collection
*/
public function toCollection($import, int $startRow = null, $nullValue = null, $calculateFormulas = false, $formatData = false): Collection
{
$rows = $this->toArray($import, $startRow, $nullValue, $calculateFormulas, $formatData);
return new Collection(array_map(function (array $row) {
return new Collection($row);
}, $rows));
}
/**
* @param object $sheetExport
*
* @throws \PhpOffice\PhpSpreadsheet\Exception
*/
public function close($sheetExport)
{
if ($sheetExport instanceof WithDrawings) {
$this->addDrawings($sheetExport->drawings());
}
$this->exportable = $sheetExport;
if ($sheetExport instanceof WithColumnFormatting) {
foreach ($sheetExport->columnFormats() as $column => $format) {
$this->formatColumn($column, $format);
}
}
if ($sheetExport instanceof ShouldAutoSize) {
$this->autoSize();
}
if ($sheetExport instanceof WithColumnWidths) {
foreach ($sheetExport->columnWidths() as $column => $width) {
$this->worksheet->getColumnDimension($column)->setAutoSize(false)->setWidth($width);
}
}
if ($sheetExport instanceof WithStyles) {
$styles = $sheetExport->styles($this->worksheet);
if (is_array($styles)) {
foreach ($styles as $coordinate => $coordinateStyles) {
if (is_numeric($coordinate)) {
$coordinate = 'A' . $coordinate . ':' . $this->worksheet->getHighestColumn($coordinate) . $coordinate;
}
$this->worksheet->getStyle($coordinate)->applyFromArray($coordinateStyles);
}
}
}
$this->raise(new AfterSheet($this, $this->exportable));
$this->clearListeners();
}
/**
* @param FromView $sheetExport
* @param int|null $sheetIndex
*
* @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
*/
public function fromView(FromView $sheetExport, $sheetIndex = null)
{
$temporaryFile = $this->temporaryFileFactory->makeLocal(null, 'html');
$temporaryFile->put($sheetExport->view()->render());
$spreadsheet = $this->worksheet->getParent();
/** @var Html $reader */
$reader = IOFactory::createReader('Html');
// If no sheetIndex given, insert content into the last sheet
$reader->setSheetIndex($sheetIndex ?? $spreadsheet->getSheetCount() - 1);
$reader->loadIntoExisting($temporaryFile->getLocalPath(), $spreadsheet);
$temporaryFile->delete();
}
/**
* @param FromQuery $sheetExport
* @param Worksheet $worksheet
*/
public function fromQuery(FromQuery $sheetExport, Worksheet $worksheet)
{
if ($sheetExport->query() instanceof \Laravel\Scout\Builder) {
$this->fromScout($sheetExport, $worksheet);
return;
}
$sheetExport->query()->chunk($this->getChunkSize($sheetExport), function ($chunk) use ($sheetExport) {
$this->appendRows($chunk, $sheetExport);
});
}
/**
* @param FromQuery $sheetExport
* @param Worksheet $worksheet
*/
public function fromScout(FromQuery $sheetExport, Worksheet $worksheet)
{
$scout = $sheetExport->query();
$chunkSize = $this->getChunkSize($sheetExport);
$chunk = $scout->paginate($chunkSize);
// Append first page
$this->appendRows($chunk->items(), $sheetExport);
// Append rest of pages
for ($page = 2; $page <= $chunk->lastPage(); $page++) {
$this->appendRows($scout->paginate($chunkSize, 'page', $page)->items(), $sheetExport);
}
}
/**
* @param FromCollection $sheetExport
*/
public function fromCollection(FromCollection $sheetExport)
{
$this->appendRows($sheetExport->collection()->all(), $sheetExport);
}
/**
* @param FromArray $sheetExport
*/
public function fromArray(FromArray $sheetExport)
{
$this->appendRows($sheetExport->array(), $sheetExport);
}
/**
* @param FromIterator $sheetExport
*/
public function fromIterator(FromIterator $sheetExport)
{
$iterator = class_exists(LazyCollection::class) ? new LazyCollection(function () use ($sheetExport) {
foreach ($sheetExport->iterator() as $row) {
yield $row;
}
}) : $sheetExport->iterator();
$this->appendRows($iterator, $sheetExport);
}
/**
* @param FromGenerator $sheetExport
*/
public function fromGenerator(FromGenerator $sheetExport)
{
$generator = class_exists(LazyCollection::class) ? new LazyCollection(function () use ($sheetExport) {
foreach ($sheetExport->generator() as $row) {
yield $row;
}
}) : $sheetExport->generator();
$this->appendRows($generator, $sheetExport);
}
/**
* @param array $rows
* @param string|null $startCell
* @param bool $strictNullComparison
*/
public function append(array $rows, string $startCell = null, bool $strictNullComparison = false)
{
if (!$startCell) {
$startCell = 'A1';
}
if ($this->hasRows()) {
$startCell = CellHelper::getColumnFromCoordinate($startCell) . ($this->worksheet->getHighestRow() + 1);
}
$this->worksheet->fromArray($rows, null, $startCell, $strictNullComparison);
}
public function autoSize()
{
foreach ($this->buildColumnRange('A', $this->worksheet->getHighestDataColumn()) as $col) {
$dimension = $this->worksheet->getColumnDimension($col);
// Only auto-size columns that have not have an explicit width.
if ($dimension->getWidth() == -1) {
$dimension->setAutoSize(true);
}
}
}
/**
* @param string $column
* @param string $format
*
* @throws \PhpOffice\PhpSpreadsheet\Exception
*/
public function formatColumn(string $column, string $format)
{
// If the column is a range, we wouldn't need to calculate the range.
if (stripos($column, ':') !== false) {
$this->worksheet
->getStyle($column)
->getNumberFormat()
->setFormatCode($format);
} else {
$this->worksheet
->getStyle($column . '1:' . $column . $this->worksheet->getHighestRow())
->getNumberFormat()
->setFormatCode($format);
}
}
/**
* @param int $chunkSize
* @return Sheet
*/
public function chunkSize(int $chunkSize)
{
$this->chunkSize = $chunkSize;
return $this;
}
/**
* @return Worksheet
*/
public function getDelegate()
{
return $this->worksheet;
}
/**
* @param Chart|Chart[] $charts
*/
public function addCharts($charts)
{
$charts = \is_array($charts) ? $charts : [$charts];
foreach ($charts as $chart) {
$this->worksheet->addChart($chart);
}
}
/**
* @param BaseDrawing|BaseDrawing[] $drawings
*/
public function addDrawings($drawings)
{
$drawings = \is_array($drawings) ? $drawings : [$drawings];
foreach ($drawings as $drawing) {
$drawing->setWorksheet($this->worksheet);
}
}
/**
* @param string $concern
* @return string
*/
public function hasConcern(string $concern): string
{
return $this->exportable instanceof $concern;
}
/**
* @param iterable $rows
* @param object $sheetExport
*/
public function appendRows($rows, $sheetExport)
{
if (method_exists($sheetExport, 'prepareRows')) {
$rows = $sheetExport->prepareRows($rows);
}
$rows = $rows instanceof LazyCollection ? $rows : new Collection($rows);
$rows->flatMap(function ($row) use ($sheetExport) {
if ($sheetExport instanceof WithMapping) {
$row = $sheetExport->map($row);
}
if ($sheetExport instanceof WithCustomValueBinder) {
SpreadsheetCell::setValueBinder($sheetExport);
}
return ArrayHelper::ensureMultipleRows(
static::mapArraybleRow($row)
);
})->chunk(1000)->each(function ($rows) use ($sheetExport) {
$this->append(
$rows->toArray(),
$sheetExport instanceof WithCustomStartCell ? $sheetExport->startCell() : null,
$this->hasStrictNullComparison($sheetExport)
);
});
}
/**
* @param mixed $row
* @return array
*/
public static function mapArraybleRow($row): array
{
// When dealing with eloquent models, we'll skip the relations
// as we won't be able to display them anyway.
if (is_object($row) && method_exists($row, 'attributesToArray')) {
return $row->attributesToArray();
}
if ($row instanceof Arrayable) {
return $row->toArray();
}
// Convert StdObjects to arrays
if (is_object($row)) {
return json_decode(json_encode($row), true);
}
return $row;
}
/**
* @param $sheetImport
* @return int
*/
public function getStartRow($sheetImport): int
{
return HeadingRowExtractor::determineStartRow($sheetImport);
}
/**
* Disconnect the sheet.
*/
public function disconnect()
{
$this->worksheet->disconnectCells();
unset($this->worksheet);
}
/**
* @return Collection|array
*/
protected function validated(WithValidation $import, int $startRow, $rows)
{
$toValidate = (new Collection($rows))->mapWithKeys(function ($row, $index) use ($startRow) {
return [($startRow + $index) => $row];
});
try {
app(RowValidator::class)->validate($toValidate->toArray(), $import);
} catch (RowSkippedException $e) {
foreach ($e->skippedRows() as $row) {
unset($rows[$row - $startRow]);
}
}
return $rows;
}
/**
* @param string $lower
* @param string $upper
* @return \Generator
*/
protected function buildColumnRange(string $lower, string $upper)
{
$upper++;
for ($i = $lower; $i !== $upper; $i++) {
yield $i;
}
}
/**
* @return bool
*/
private function hasRows(): bool
{
$startCell = 'A1';
if ($this->exportable instanceof WithCustomStartCell) {
$startCell = $this->exportable->startCell();
}
return $this->worksheet->cellExists($startCell);
}
/**
* @param object $sheetExport
* @return bool
*/
private function hasStrictNullComparison($sheetExport): bool
{
if ($sheetExport instanceof WithStrictNullComparison) {
return true;
}
return config('excel.exports.strict_null_comparison', false);
}
/**
* @param object|WithCustomChunkSize $export
* @return int
*/
private function getChunkSize($export): int
{
if ($export instanceof WithCustomChunkSize) {
return $export->chunkSize();
}
return $this->chunkSize;
}
/**
* @param object|WithValidation $import
* @return Closure|null
*/
private function getPreparationCallback($import)
{
if (!$import instanceof WithValidation || !method_exists($import, 'prepareForValidation')) {
return null;
}
return function (array $data, int $index) use ($import) {
return $import->prepareForValidation($data, $index);
};
}
}
excel/src/SettingsProvider.php 0000644 00000001077 15243417774 0012502 0 ustar 00 <?php
namespace Maatwebsite\Excel;
use Maatwebsite\Excel\Cache\CacheManager;
use PhpOffice\PhpSpreadsheet\Settings;
class SettingsProvider
{
/**
* @var CacheManager
*/
private $cache;
public function __construct(CacheManager $cache)
{
$this->cache = $cache;
}
/**
* Provide PhpSpreadsheet settings.
*/
public function provide()
{
$this->configureCellCaching();
}
protected function configureCellCaching()
{
Settings::setCache(
$this->cache->driver()
);
}
}
excel/src/Filters/LimitFilter.php 0000644 00000001355 15243417774 0013022 0 ustar 00 <?php
namespace Maatwebsite\Excel\Filters;
use PhpOffice\PhpSpreadsheet\Reader\IReadFilter;
class LimitFilter implements IReadFilter
{
/**
* @var int
*/
private $startRow;
/**
* @var int
*/
private $endRow;
/**
* @param int $startRow
* @param int $limit
*/
public function __construct(int $startRow, int $limit)
{
$this->startRow = $startRow;
$this->endRow = $startRow + $limit;
}
/**
* @param string $column
* @param int $row
* @param string $worksheetName
* @return bool
*/
public function readCell($column, $row, $worksheetName = '')
{
return $row >= $this->startRow && $row < $this->endRow;
}
}
excel/src/Filters/ChunkReadFilter.php 0000644 00000002455 15243417774 0013612 0 ustar 00 <?php
namespace Maatwebsite\Excel\Filters;
use PhpOffice\PhpSpreadsheet\Reader\IReadFilter;
class ChunkReadFilter implements IReadFilter
{
/**
* @var int
*/
private $headingRow;
/**
* @var int
*/
private $startRow;
/**
* @var int
*/
private $endRow;
/**
* @var string
*/
private $worksheetName;
/**
* @param int $headingRow
* @param int $startRow
* @param int $chunkSize
* @param string $worksheetName
*/
public function __construct(int $headingRow, int $startRow, int $chunkSize, string $worksheetName)
{
$this->headingRow = $headingRow;
$this->startRow = $startRow;
$this->endRow = $startRow + $chunkSize;
$this->worksheetName = $worksheetName;
}
/**
* @param string $column
* @param int $row
* @param string $worksheetName
* @return bool
*/
public function readCell($column, $row, $worksheetName = '')
{
// Only read the heading row, and the rows that are configured in $this->_startRow and $this->_endRow
return ($worksheetName === $this->worksheetName || $worksheetName === '')
&& ($row === $this->headingRow || ($row >= $this->startRow && $row < $this->endRow));
}
}
excel/src/Cell.php 0000644 00000004535 15243417774 0010050 0 ustar 00 <?php
namespace Maatwebsite\Excel;
use Illuminate\Pipeline\Pipeline;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Cell\Cell as SpreadsheetCell;
use PhpOffice\PhpSpreadsheet\RichText\RichText;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
/** @mixin SpreadsheetCell */
class Cell
{
use DelegatedMacroable;
/**
* @var SpreadsheetCell
*/
private $cell;
/**
* @param SpreadsheetCell $cell
*/
public function __construct(SpreadsheetCell $cell)
{
$this->cell = $cell;
}
/**
* @param Worksheet $worksheet
* @param string $coordinate
* @return Cell
*
* @throws \PhpOffice\PhpSpreadsheet\Exception
*/
public static function make(Worksheet $worksheet, string $coordinate)
{
return new static($worksheet->getCell($coordinate));
}
/**
* @return SpreadsheetCell
*/
public function getDelegate(): SpreadsheetCell
{
return $this->cell;
}
/**
* @param null $nullValue
* @param bool $calculateFormulas
* @param bool $formatData
* @return mixed
*/
public function getValue($nullValue = null, $calculateFormulas = false, $formatData = true)
{
$value = $nullValue;
if ($this->cell->getValue() !== null) {
if ($this->cell->getValue() instanceof RichText) {
$value = $this->cell->getValue()->getPlainText();
} elseif ($calculateFormulas) {
try {
$value = $this->cell->getCalculatedValue();
} catch (Exception $e) {
$value = $this->cell->getOldCalculatedValue();
}
} else {
$value = $this->cell->getValue();
}
if ($formatData) {
$style = $this->cell->getWorksheet()->getParent()->getCellXfByIndex($this->cell->getXfIndex());
$value = NumberFormat::toFormattedString(
$value,
($style && $style->getNumberFormat()) ? $style->getNumberFormat()->getFormatCode() : NumberFormat::FORMAT_GENERAL
);
}
}
return app(Pipeline::class)->send($value)->through(config('excel.imports.cells.middleware', []))->thenReturn();
}
}
excel/src/Exceptions/NoSheetsFoundException.php 0000644 00000000236 15243417774 0015707 0 ustar 00 <?php
namespace Maatwebsite\Excel\Exceptions;
use LogicException;
class NoSheetsFoundException extends LogicException implements LaravelExcelException
{
}
excel/src/Exceptions/UnreadableFileException.php 0000644 00000000742 15243417774 0016027 0 ustar 00 <?php
namespace Maatwebsite\Excel\Exceptions;
use Exception;
use Throwable;
class UnreadableFileException extends Exception implements LaravelExcelException
{
/**
* @param string $message
* @param int $code
* @param Throwable|null $previous
*/
public function __construct(
$message = 'File could not be read',
$code = 0,
Throwable $previous = null
) {
parent::__construct($message, $code, $previous);
}
}
excel/src/Exceptions/ConcernConflictException.php 0000644 00000000612 15243417774 0016232 0 ustar 00 <?php
namespace Maatwebsite\Excel\Exceptions;
use LogicException;
class ConcernConflictException extends LogicException implements LaravelExcelException
{
/**
* @return ConcernConflictException
*/
public static function queryOrCollectionAndView()
{
return new static('Cannot use FromQuery, FromArray or FromCollection and FromView on the same sheet.');
}
}
excel/src/Exceptions/LaravelExcelException.php 0000644 00000000166 15243417774 0015534 0 ustar 00 <?php
namespace Maatwebsite\Excel\Exceptions;
use Throwable;
interface LaravelExcelException extends Throwable
{
}
excel/src/Exceptions/NoFilenameGivenException.php 0000644 00000001050 15243417774 0016164 0 ustar 00 <?php
namespace Maatwebsite\Excel\Exceptions;
use InvalidArgumentException;
use Throwable;
class NoFilenameGivenException extends InvalidArgumentException implements LaravelExcelException
{
/**
* @param string $message
* @param int $code
* @param Throwable|null $previous
*/
public function __construct(
$message = 'A filename needs to be passed in order to download the export',
$code = 0,
Throwable $previous = null
) {
parent::__construct($message, $code, $previous);
}
}
excel/src/Exceptions/NoFilePathGivenException.php 0000644 00000001626 15243417774 0016151 0 ustar 00 <?php
namespace Maatwebsite\Excel\Exceptions;
use InvalidArgumentException;
use Throwable;
class NoFilePathGivenException extends InvalidArgumentException implements LaravelExcelException
{
/**
* @param string $message
* @param int $code
* @param Throwable|null $previous
*/
public function __construct(
$message = 'A filepath needs to be passed.',
$code = 0,
Throwable $previous = null
) {
parent::__construct($message, $code, $previous);
}
/**
* @return NoFilePathGivenException
*/
public static function import()
{
return new static('A filepath or UploadedFile needs to be passed to start the import.');
}
/**
* @return NoFilePathGivenException
*/
public static function export()
{
return new static('A filepath needs to be passed in order to store the export.');
}
}
excel/src/Exceptions/NoTypeDetectedException.php 0000644 00000001120 15243417774 0016034 0 ustar 00 <?php
namespace Maatwebsite\Excel\Exceptions;
use Exception;
use Throwable;
class NoTypeDetectedException extends Exception implements LaravelExcelException
{
/**
* @param string $message
* @param int $code
* @param Throwable|null $previous
*/
public function __construct(
$message = 'No ReaderType or WriterType could be detected. Make sure you either pass a valid extension to the filename or pass an explicit type.',
$code = 0,
Throwable $previous = null
) {
parent::__construct($message, $code, $previous);
}
}
excel/src/Exceptions/SheetNotFoundException.php 0000644 00000001331 15243417774 0015705 0 ustar 00 <?php
namespace Maatwebsite\Excel\Exceptions;
class SheetNotFoundException extends \Exception implements LaravelExcelException
{
/**
* @param string $name
* @return SheetNotFoundException
*/
public static function byName(string $name): SheetNotFoundException
{
return new static("Your requested sheet name [{$name}] is out of bounds.");
}
/**
* @param int $index
* @param int $sheetCount
* @return SheetNotFoundException
*/
public static function byIndex(int $index, int $sheetCount): SheetNotFoundException
{
return new static("Your requested sheet index: {$index} is out of bounds. The actual number of sheets is {$sheetCount}.");
}
}
excel/src/Exceptions/RowSkippedException.php 0000644 00000001343 15243417774 0015252 0 ustar 00 <?php
namespace Maatwebsite\Excel\Exceptions;
use Exception;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Validators\Failure;
class RowSkippedException extends Exception
{
/**
* @var Failure[]
*/
private $failures;
/**
* @param Failure ...$failures
*/
public function __construct(Failure ...$failures)
{
$this->failures = $failures;
parent::__construct();
}
/**
* @return Failure[]|Collection
*/
public function failures(): Collection
{
return new Collection($this->failures);
}
/**
* @return int[]
*/
public function skippedRows(): array
{
return $this->failures()->map->row()->all();
}
}
excel/src/Factories/WriterFactory.php 0000644 00000005465 15243417774 0013717 0 ustar 00 <?php
namespace Maatwebsite\Excel\Factories;
use Maatwebsite\Excel\Cache\CacheManager;
use Maatwebsite\Excel\Concerns\MapsCsvSettings;
use Maatwebsite\Excel\Concerns\WithCharts;
use Maatwebsite\Excel\Concerns\WithCustomCsvSettings;
use Maatwebsite\Excel\Concerns\WithMultipleSheets;
use Maatwebsite\Excel\Concerns\WithPreCalculateFormulas;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Csv;
use PhpOffice\PhpSpreadsheet\Writer\Html;
use PhpOffice\PhpSpreadsheet\Writer\IWriter;
class WriterFactory
{
use MapsCsvSettings;
/**
* @param string $writerType
* @param Spreadsheet $spreadsheet
* @param object $export
* @return IWriter
*
* @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
*/
public static function make(string $writerType, Spreadsheet $spreadsheet, $export): IWriter
{
$writer = IOFactory::createWriter($spreadsheet, $writerType);
$writer->setUseDiskCaching(
config('excel.cache.driver', CacheManager::DRIVER_MEMORY) !== CacheManager::DRIVER_MEMORY
);
if (static::includesCharts($export)) {
$writer->setIncludeCharts(true);
}
if ($writer instanceof Html && $export instanceof WithMultipleSheets) {
$writer->writeAllSheets();
}
if ($writer instanceof Csv) {
static::applyCsvSettings(config('excel.exports.csv', []));
if ($export instanceof WithCustomCsvSettings) {
static::applyCsvSettings($export->getCsvSettings());
}
$writer->setDelimiter(static::$delimiter);
$writer->setEnclosure(static::$enclosure);
$writer->setEnclosureRequired((bool) static::$enclosure);
$writer->setLineEnding(static::$lineEnding);
$writer->setUseBOM(static::$useBom);
$writer->setIncludeSeparatorLine(static::$includeSeparatorLine);
$writer->setExcelCompatibility(static::$excelCompatibility);
$writer->setOutputEncoding(static::$outputEncoding);
}
// Calculation settings
$writer->setPreCalculateFormulas(
$export instanceof WithPreCalculateFormulas
? true
: config('excel.exports.pre_calculate_formulas', false)
);
return $writer;
}
/**
* @param $export
* @return bool
*/
private static function includesCharts($export): bool
{
if ($export instanceof WithCharts) {
return true;
}
if ($export instanceof WithMultipleSheets) {
foreach ($export->sheets() as $sheet) {
if ($sheet instanceof WithCharts) {
return true;
}
}
}
return false;
}
}
excel/src/Factories/ReaderFactory.php 0000644 00000005415 15243417774 0013640 0 ustar 00 <?php
namespace Maatwebsite\Excel\Factories;
use Maatwebsite\Excel\Concerns\MapsCsvSettings;
use Maatwebsite\Excel\Concerns\WithCustomCsvSettings;
use Maatwebsite\Excel\Concerns\WithLimit;
use Maatwebsite\Excel\Concerns\WithReadFilter;
use Maatwebsite\Excel\Concerns\WithStartRow;
use Maatwebsite\Excel\Exceptions\NoTypeDetectedException;
use Maatwebsite\Excel\Files\TemporaryFile;
use Maatwebsite\Excel\Filters\LimitFilter;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Reader\Csv;
use PhpOffice\PhpSpreadsheet\Reader\Exception;
use PhpOffice\PhpSpreadsheet\Reader\IReader;
class ReaderFactory
{
use MapsCsvSettings;
/**
* @param object $import
* @param TemporaryFile $file
* @param string $readerType
* @return IReader
*
* @throws Exception
*/
public static function make($import, TemporaryFile $file, string $readerType = null): IReader
{
$reader = IOFactory::createReader(
$readerType ?: static::identify($file)
);
if (method_exists($reader, 'setReadDataOnly')) {
$reader->setReadDataOnly(config('excel.imports.read_only', true));
}
if (method_exists($reader, 'setReadEmptyCells')) {
$reader->setReadEmptyCells(!config('excel.imports.ignore_empty', false));
}
if ($reader instanceof Csv) {
static::applyCsvSettings(config('excel.imports.csv', []));
if ($import instanceof WithCustomCsvSettings) {
static::applyCsvSettings($import->getCsvSettings());
}
$reader->setDelimiter(static::$delimiter);
$reader->setEnclosure(static::$enclosure);
$reader->setEscapeCharacter(static::$escapeCharacter);
$reader->setContiguous(static::$contiguous);
$reader->setInputEncoding(static::$inputEncoding);
if (method_exists($reader, 'setTestAutoDetect')) {
$reader->setTestAutoDetect(static::$testAutoDetect);
}
}
if ($import instanceof WithReadFilter) {
$reader->setReadFilter($import->readFilter());
} elseif ($import instanceof WithLimit) {
$reader->setReadFilter(new LimitFilter(
$import instanceof WithStartRow ? $import->startRow() : 1,
$import->limit()
));
}
return $reader;
}
/**
* @param TemporaryFile $temporaryFile
* @return string
*
* @throws NoTypeDetectedException
*/
private static function identify(TemporaryFile $temporaryFile): string
{
try {
return IOFactory::identify($temporaryFile->getLocalPath());
} catch (Exception $e) {
throw new NoTypeDetectedException(null, null, $e);
}
}
}
excel/src/ExcelServiceProvider.php 0000644 00000010716 15243417774 0013263 0 ustar 00 <?php
namespace Maatwebsite\Excel;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;
use Illuminate\Support\ServiceProvider;
use Laravel\Lumen\Application as LumenApplication;
use Maatwebsite\Excel\Cache\CacheManager;
use Maatwebsite\Excel\Console\ExportMakeCommand;
use Maatwebsite\Excel\Console\ImportMakeCommand;
use Maatwebsite\Excel\Files\Filesystem;
use Maatwebsite\Excel\Files\TemporaryFileFactory;
use Maatwebsite\Excel\Mixins\DownloadCollectionMixin;
use Maatwebsite\Excel\Mixins\DownloadQueryMacro;
use Maatwebsite\Excel\Mixins\ImportAsMacro;
use Maatwebsite\Excel\Mixins\ImportMacro;
use Maatwebsite\Excel\Mixins\StoreCollectionMixin;
use Maatwebsite\Excel\Mixins\StoreQueryMacro;
use Maatwebsite\Excel\Transactions\TransactionHandler;
use Maatwebsite\Excel\Transactions\TransactionManager;
class ExcelServiceProvider extends ServiceProvider
{
/**
* {@inheritdoc}
*/
public function boot()
{
if ($this->app->runningInConsole()) {
$this->publishes([
__DIR__ . '/Console/stubs/export.model.stub' => base_path('stubs/export.model.stub'),
__DIR__ . '/Console/stubs/export.plain.stub' => base_path('stubs/export.plain.stub'),
__DIR__ . '/Console/stubs/export.query.stub' => base_path('stubs/export.query.stub'),
__DIR__ . '/Console/stubs/export.query-model.stub' => base_path('stubs/export.query-model.stub'),
__DIR__ . '/Console/stubs/import.collection.stub' => base_path('stubs/import.collection.stub'),
__DIR__ . '/Console/stubs/import.model.stub' => base_path('stubs/import.model.stub'),
], 'stubs');
if ($this->app instanceof LumenApplication) {
$this->app->configure('excel');
} else {
$this->publishes([
$this->getConfigFile() => config_path('excel.php'),
], 'config');
}
}
if ($this->app instanceof \Illuminate\Foundation\Application) {
// Laravel
$this->app->booted(function ($app) {
$app->make(SettingsProvider::class)->provide();
});
} else {
// Lumen
$this->app->make(SettingsProvider::class)->provide();
}
}
/**
* {@inheritdoc}
*/
public function register()
{
$this->mergeConfigFrom(
$this->getConfigFile(),
'excel'
);
$this->app->bind(CacheManager::class, function ($app) {
return new CacheManager($app);
});
$this->app->singleton(TransactionManager::class, function ($app) {
return new TransactionManager($app);
});
$this->app->bind(TransactionHandler::class, function ($app) {
return $app->make(TransactionManager::class)->driver();
});
$this->app->bind(TemporaryFileFactory::class, function () {
return new TemporaryFileFactory(
config('excel.temporary_files.local_path', config('excel.exports.temp_path', storage_path('framework/laravel-excel'))),
config('excel.temporary_files.remote_disk')
);
});
$this->app->bind(Filesystem::class, function ($app) {
return new Filesystem($app->make('filesystem'));
});
$this->app->bind('excel', function ($app) {
return new Excel(
$app->make(Writer::class),
$app->make(QueuedWriter::class),
$app->make(Reader::class),
$app->make(Filesystem::class)
);
});
$this->app->alias('excel', Excel::class);
$this->app->alias('excel', Exporter::class);
$this->app->alias('excel', Importer::class);
Collection::mixin(new DownloadCollectionMixin);
Collection::mixin(new StoreCollectionMixin);
Builder::macro('downloadExcel', (new DownloadQueryMacro)());
Builder::macro('storeExcel', (new StoreQueryMacro())());
Builder::macro('import', (new ImportMacro())());
Builder::macro('importAs', (new ImportAsMacro())());
$this->commands([
ExportMakeCommand::class,
ImportMakeCommand::class,
]);
}
/**
* @return string
*/
protected function getConfigFile(): string
{
return __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'excel.php';
}
}
excel/SECURITY.md 0000644 00000000672 15243417774 0007460 0 ustar 00 # Security Policy
**PLEASE DON'T DISCLOSE SECURITY-RELATED ISSUES PUBLICLY, [SEE BELOW](#reporting-a-vulnerability).**
## Supported Versions
Version | Security Fixes Until
--- | ---
3.1 | -
3.0 | 31-12-2018
2.1 | 15-5-2018
## Reporting a Vulnerability
If you discover a security vulnerability within Laravel Excel, please send an email to Patrick Brouwers at patrick@spartner.nl. All security vulnerabilities will be promptly addressed.
excel/.styleci.yml 0000644 00000000435 15243417774 0010141 0 ustar 00 preset: laravel
risky: false
enabled:
- align_double_arrow
- align_equals
- concat_with_spaces
- ordered_class_elements
disabled:
- concat_without_spaces
- not_operator_with_successor_space
- unalign_equals
finder:
not-name:
- "*.md"
not-path:
- ".github"