1
0

提交代码

This commit is contained in:
2020-08-06 14:50:07 +08:00
parent 9d0d5f4be9
commit d7a848c824
11299 changed files with 1321854 additions and 0 deletions

20
vendor/maatwebsite/excel/.styleci.yml vendored Normal file
View File

@@ -0,0 +1,20 @@
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"

View File

@@ -0,0 +1,46 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at patrick@maatwebsite.nl. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

View File

@@ -0,0 +1,3 @@
# Contributing
Find the contributing guide at: https://docs.laravel-excel.com/3.1/getting-started/contributing

21
vendor/maatwebsite/excel/LICENSE vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) Maatwebsite
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.

98
vendor/maatwebsite/excel/README.md vendored Normal file
View File

@@ -0,0 +1,98 @@
![banner](https://user-images.githubusercontent.com/7728097/57463977-2263fc80-727c-11e9-833d-669d816fb7fb.jpg)
<p align="center">
<a href="https://travis-ci.org/Maatwebsite/Laravel-Excel">
<img src="https://travis-ci.org/Maatwebsite/Laravel-Excel.svg?branch=3.1" alt="Build Status">
</a>
<a href="https://styleci.io/repos/14259390">
<img src="https://styleci.io/repos/14259390/shield?branch=3.1" alt="StyleCI">
</a>
<a href="https://packagist.org/packages/maatwebsite/excel">
<img src="https://poser.pugx.org/maatwebsite/excel/v/stable.png" alt="Latest Stable Version">
</a>
<a href="https://packagist.org/packages/maatwebsite/excel">
<img src="https://poser.pugx.org/maatwebsite/excel/downloads.png" alt="Total Downloads">
</a>
<a href="https://packagist.org/packages/maatwebsite/excel">
<img src="https://poser.pugx.org/maatwebsite/excel/license.png" alt="License">
</a>
</p>
<h3 align="center">Supercharged Excel exports and imports</h3>
<p align="center">
A simple, but elegant <a href="https://laravel.com" target="_blank">Laravel<a/> wrapper around <a href="https://phpspreadsheet.readthedocs.io/" target="_blank">PhpSpreadsheet</a>
exports and imports.
</p>
<h4 align="center">
<a href="https://docs.laravel-excel.com/3.1/exports/">Quickstart</a>
<span> · </span>
<a href="https://docs.laravel-excel.com/3.1/getting-started/">Documentation</a>
<span> · </span>
<a href="https://course.laravel-excel.com">Video Course</a>
<span> · </span>
<a href="https://github.com/Maatwebsite/Laravel-Nova-Excel">Nova</a>
<span> · </span>
<a href="https://medium.com/maatwebsite/laravel-excel/home">Blog</a>
<span> · </span>
<a href="https://docs.laravel-excel.com/3.1/getting-started/contributing.html">Contributing</a>
<span> · </span>
<a href="https://docs.laravel-excel.com/3.1/getting-started/support.html">Support</a>
</h4>
## ✨ Features
- **Easily export collections to Excel.** Supercharge your Laravel collections and export them directly to an Excel or CSV document. Exporting has never been so easy.
- **Supercharged exports.** Export queries with automatic chunking for better performance. You provide us the query, we handle the performance. Exporting even larger datasets? No worries, Laravel Excel has your back. You can queue your exports so all of this happens in the background.
- **Supercharged imports.** Import workbooks and worksheets to Eloquent models with chunk reading and batch inserts! Have large files? You can queue every chunk of a file! Your entire import will happen in the background.
- **Export Blade views.** Want to have a custom layout in your spreadsheet? Use a HTML table in a Blade view and export that to Excel.
## 🎓 Learning Laravel Excel
You can find the full documentation of Laravel Excel [on the website](https://docs.laravel-excel.com).
We welcome suggestions for improving our docs. The documentation repository can be found at [https://github.com/Maatwebsite/laravel-excel-docs](https://github.com/Maatwebsite/laravel-excel-docs).
Some articles and tutorials can be found on our blog: https://medium.com/maatwebsite/laravel-excel/home
## 🎥 Video Course
![1_bzlh2ituv5x7yu2wenhxxw](https://user-images.githubusercontent.com/7728097/53638298-188f9e80-3c26-11e9-82c8-baf057271013.jpeg)
We are currently building a video course called "Advanced Laravel Excel". In this video course well build a small application with real-life, complex imports and exports that go beyond simple user imports and exports. Well go step-by-step and tackle implementing Laravel Excel in a performant way.
If you sign up now, youll get notified when the course launches and get it for the early bird price of $69 instead of ~~$99~~.
https://course.laravel-excel.com
## :mailbox_with_mail: License & Postcardware
![1_5nblgs68uarg0wxxejozdq](https://user-images.githubusercontent.com/7728097/53638144-9e5f1a00-3c25-11e9-9f4a-fc71c9d94562.jpg)
Laravel Excel is completely free (MIT license) to use, however the package is licensed as Postcardware. This means that if it makes it to your production environment, we would very much appreciate receiving a postcard from your hometown.
**Maatwebsite**
Markt 2
6231 LS Meerssen
The Netherlands
More about the license can be found at: [https://docs.laravel-excel.com/3.1/getting-started/license.html](https://docs.laravel-excel.com/3.1/getting-started/license.html)
## :wrench: Supported Versions
Versions will be supported for a limited amount of time.
| Version | Laravel Version | Php Version | Support |
|---- |----|----|----|
| 2.1 | <=5.6 | <=7.0 | Unsupported since 15-5-2018 |
| 3.0 | ^5.5 | ^7.0 | Unsupported since 31-12-2018 |
| 3.1 | ^5.5\|^6.0 | ^7.1 | New features |

15
vendor/maatwebsite/excel/SECURITY.md vendored Normal file
View File

@@ -0,0 +1,15 @@
# 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@maatwebsite.nl. All security vulnerabilities will be promptly addressed.

58
vendor/maatwebsite/excel/composer.json vendored Normal file
View File

@@ -0,0 +1,58 @@
{
"name": "maatwebsite/excel",
"description": "Supercharged Excel exports and imports in Laravel",
"license": "MIT",
"keywords": [
"laravel",
"php",
"phpspreadsheet",
"phpexcel",
"excel",
"csv",
"export",
"import",
"batch"
],
"authors": [
{
"name": "Patrick Brouwers",
"email": "patrick@maatwebsite.nl"
}
],
"require": {
"ext-json": "*",
"php": "^7.0",
"phpoffice/phpspreadsheet": "^1.6",
"illuminate/support": "5.5.*|5.6.*|5.7.*|5.8.*|^6.0",
"opis/closure": "^3.1"
},
"require-dev": {
"orchestra/testbench": "^4.0",
"phpunit/phpunit": "^8.0",
"mockery/mockery": "^1.1",
"orchestra/database": "^4.0",
"predis/predis": "^1.1"
},
"autoload": {
"psr-4": {
"Maatwebsite\\Excel\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Maatwebsite\\Excel\\Tests\\": "tests/"
}
},
"extra": {
"laravel": {
"providers": [
"Maatwebsite\\Excel\\ExcelServiceProvider"
],
"aliases": {
"Excel": "Maatwebsite\\Excel\\Facades\\Excel"
}
}
},
"minimum-stability": "dev",
"prefer-stable": true
}

View File

@@ -0,0 +1,185 @@
<?php
use Maatwebsite\Excel\Excel;
return [
'exports' => [
/*
|--------------------------------------------------------------------------
| Chunk size
|--------------------------------------------------------------------------
|
| When using FromQuery, the query is automatically chunked.
| Here you can specify how big the chunk should be.
|
*/
'chunk_size' => 1000,
/*
|--------------------------------------------------------------------------
| Pre-calculate formulas during export
|--------------------------------------------------------------------------
*/
'pre_calculate_formulas' => false,
/*
|--------------------------------------------------------------------------
| CSV Settings
|--------------------------------------------------------------------------
|
| Configure e.g. delimiter, enclosure and line ending for CSV exports.
|
*/
'csv' => [
'delimiter' => ',',
'enclosure' => '"',
'line_ending' => PHP_EOL,
'use_bom' => false,
'include_separator_line' => false,
'excel_compatibility' => false,
],
],
'imports' => [
'read_only' => true,
'heading_row' => [
/*
|--------------------------------------------------------------------------
| Heading Row Formatter
|--------------------------------------------------------------------------
|
| Configure the heading row formatter.
| Available options: none|slug|custom
|
*/
'formatter' => 'slug',
],
/*
|--------------------------------------------------------------------------
| CSV Settings
|--------------------------------------------------------------------------
|
| Configure e.g. delimiter, enclosure and line ending for CSV imports.
|
*/
'csv' => [
'delimiter' => ',',
'enclosure' => '"',
'escape_character' => '\\',
'contiguous' => false,
'input_encoding' => 'UTF-8',
],
],
/*
|--------------------------------------------------------------------------
| Extension detector
|--------------------------------------------------------------------------
|
| Configure here which writer type should be used when
| the package needs to guess the correct type
| based on the extension alone.
|
*/
'extension_detector' => [
'xlsx' => Excel::XLSX,
'xlsm' => Excel::XLSX,
'xltx' => Excel::XLSX,
'xltm' => Excel::XLSX,
'xls' => Excel::XLS,
'xlt' => Excel::XLS,
'ods' => Excel::ODS,
'ots' => Excel::ODS,
'slk' => Excel::SLK,
'xml' => Excel::XML,
'gnumeric' => Excel::GNUMERIC,
'htm' => Excel::HTML,
'html' => Excel::HTML,
'csv' => Excel::CSV,
'tsv' => Excel::TSV,
/*
|--------------------------------------------------------------------------
| PDF Extension
|--------------------------------------------------------------------------
|
| Configure here which Pdf driver should be used by default.
| Available options: Excel::MPDF | Excel::TCPDF | Excel::DOMPDF
|
*/
'pdf' => Excel::DOMPDF,
],
'value_binder' => [
/*
|--------------------------------------------------------------------------
| Default Value Binder
|--------------------------------------------------------------------------
|
| PhpSpreadsheet offers a way to hook into the process of a value being
| written to a cell. In there some assumptions are made on how the
| value should be formatted. If you want to change those defaults,
| you can implement your own default value binder.
|
*/
'default' => Maatwebsite\Excel\DefaultValueBinder::class,
],
'transactions' => [
/*
|--------------------------------------------------------------------------
| Transaction Handler
|--------------------------------------------------------------------------
|
| By default the import is wrapped in a transaction. This is useful
| for when an import may fail and you want to retry it. With the
| transactions, the previous import gets rolled-back.
|
| You can disable the transaction handler by setting this to null.
| Or you can choose a custom made transaction handler here.
|
| Supported handlers: null|db
|
*/
'handler' => 'db',
],
'temporary_files' => [
/*
|--------------------------------------------------------------------------
| Local Temporary Path
|--------------------------------------------------------------------------
|
| When exporting and importing files, we use a temporary file, before
| storing reading or downloading. Here you can customize that path.
|
*/
'local_path' => sys_get_temp_dir(),
/*
|--------------------------------------------------------------------------
| Remote Temporary Disk
|--------------------------------------------------------------------------
|
| When dealing with a multi server setup with queues in which you
| cannot rely on having a shared local temporary path, you might
| want to store the temporary file on a shared disk. During the
| queue executing, we'll retrieve the temporary file from that
| location instead. When left to null, it will always use
| the local path. This setting only has effect when using
| in conjunction with queued imports and exports.
|
*/
'remote_disk' => null,
],
];

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
bootstrap="vendor/autoload.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
>
<php>
<env name="APP_KEY" value="base64:6igsHe3RYC88h3Wje3VzSNqPwUr7Z5ru+NZw/9qwY5M=" />
<env name="DB_HOST" value="127.0.0.1"/>
<env name="DB_PORT" value="3306"/>
<env name="DB_DATABASE" value="laravel_excel"/>
<env name="DB_USERNAME" value="root"/>
<env name="DB_PASSWORD" value=""/>
</php>
<testsuites>
<testsuite name="Package Test Suite">
<directory suffix="Test.php">./tests/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory suffix=".php">./src</directory>
</whitelist>
</filter>
</phpunit>

77
vendor/maatwebsite/excel/src/Cell.php vendored Normal file
View File

@@ -0,0 +1,77 @@
<?php
namespace Maatwebsite\Excel;
use PhpOffice\PhpSpreadsheet\RichText\RichText;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use PhpOffice\PhpSpreadsheet\Cell\Cell as 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
*
* @throws \PhpOffice\PhpSpreadsheet\Exception
* @return Cell
*/
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) {
$value = $this->cell->getCalculatedValue();
} 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 $value;
}
}

View File

@@ -0,0 +1,85 @@
<?php
namespace Maatwebsite\Excel;
use Throwable;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Jobs\ReadChunk;
use Maatwebsite\Excel\Jobs\QueueImport;
use Maatwebsite\Excel\Concerns\WithLimit;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Events\BeforeImport;
use Maatwebsite\Excel\Files\TemporaryFile;
use Maatwebsite\Excel\Jobs\AfterImportJob;
use Illuminate\Contracts\Queue\ShouldQueue;
use Maatwebsite\Excel\Concerns\WithProgressBar;
use Maatwebsite\Excel\Concerns\WithChunkReading;
use Maatwebsite\Excel\Imports\HeadingRowExtractor;
class ChunkReader
{
/**
* @param WithChunkReading $import
* @param Reader $reader
* @param TemporaryFile $temporaryFile
*
* @return \Illuminate\Foundation\Bus\PendingDispatch|null
*/
public function read(WithChunkReading $import, Reader $reader, TemporaryFile $temporaryFile)
{
if ($import instanceof WithEvents && isset($import->registerEvents()[BeforeImport::class])) {
$reader->beforeImport($import);
}
$chunkSize = $import->chunkSize();
$totalRows = $reader->getTotalRows();
$worksheets = $reader->getWorksheets($import);
if ($import instanceof WithProgressBar) {
$import->getConsoleOutput()->progressStart(array_sum($totalRows));
}
$jobs = new Collection();
foreach ($worksheets as $name => $sheetImport) {
$startRow = HeadingRowExtractor::determineStartRow($sheetImport);
$totalRows[$name] = $sheetImport instanceof WithLimit ? $sheetImport->limit() : $totalRows[$name];
for ($currentRow = $startRow; $currentRow <= $totalRows[$name]; $currentRow += $chunkSize) {
$jobs->push(new ReadChunk(
$import,
$reader->getPhpSpreadsheetReader(),
$temporaryFile,
$name,
$sheetImport,
$currentRow,
$chunkSize
));
}
}
$jobs->push(new AfterImportJob($import, $reader));
if ($import instanceof ShouldQueue) {
return QueueImport::withChain($jobs->toArray())->dispatch();
}
$jobs->each(function ($job) {
try {
dispatch_now($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;
}
}

View File

@@ -0,0 +1,105 @@
<?php
namespace Maatwebsite\Excel\Concerns;
use Maatwebsite\Excel\Exporter;
use Illuminate\Foundation\Bus\PendingDispatch;
use Maatwebsite\Excel\Exceptions\NoFilenameGivenException;
use Maatwebsite\Excel\Exceptions\NoFilePathGivenException;
trait Exportable
{
/**
* @param string $fileName
* @param string|null $writerType
* @param array $headers
*
* @throws NoFilenameGivenException
* @return \Illuminate\Http\Response|\Symfony\Component\HttpFoundation\BinaryFileResponse
*/
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
*
* @throws NoFilePathGivenException
* @return bool|PendingDispatch
*/
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
*
* @throws NoFilePathGivenException
* @return PendingDispatch
*/
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 ?? []
);
}
/**
* Create an HTTP response that represents the object.
*
* @param \Illuminate\Http\Request $request
*
* @throws NoFilenameGivenException
* @return \Illuminate\Http\Response
*/
public function toResponse($request)
{
return $this->download();
}
/**
* @return Exporter
*/
private function getExporter(): Exporter
{
return app(Exporter::class);
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace Maatwebsite\Excel\Concerns;
interface FromArray
{
/**
* @return array
*/
public function array(): array;
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Maatwebsite\Excel\Concerns;
use Illuminate\Support\Collection;
interface FromCollection
{
/**
* @return Collection
*/
public function collection();
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Maatwebsite\Excel\Concerns;
use Iterator;
interface FromIterator
{
/**
* @return Iterator
*/
public function iterator(): Iterator;
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Maatwebsite\Excel\Concerns;
use Illuminate\Database\Query\Builder;
interface FromQuery
{
/**
* @return Builder
*/
public function query();
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Maatwebsite\Excel\Concerns;
use Illuminate\Contracts\View\View;
interface FromView
{
/**
* @return View
*/
public function view(): View;
}

View File

@@ -0,0 +1,149 @@
<?php
namespace Maatwebsite\Excel\Concerns;
use InvalidArgumentException;
use Maatwebsite\Excel\Importer;
use Illuminate\Support\Collection;
use Illuminate\Console\OutputStyle;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\PendingDispatch;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Maatwebsite\Excel\Exceptions\NoFilePathGivenException;
trait Importable
{
/**
* @var OutputStyle|null
*/
protected $output;
/**
* @param string|UploadedFile|null $filePath
* @param string|null $disk
* @param string|null $readerType
*
* @throws NoFilePathGivenException
* @return Importer|PendingDispatch
*/
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
*
* @throws NoFilePathGivenException
* @return array
*/
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
*
* @throws NoFilePathGivenException
* @return Collection
*/
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
*
* @throws NoFilePathGivenException
* @throws InvalidArgumentException
* @return PendingDispatch
*/
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) {
throw new InvalidArgumentException(
'Importable has no OutputStyle. Declare one by using ->withOutput($this->output).'
);
}
return $this->output;
}
/**
* @param UploadedFile|string|null $filePath
*
* @throws NoFilePathGivenException
* @return UploadedFile|string
*/
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);
}
}

View File

@@ -0,0 +1,69 @@
<?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';
/**
* @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);
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Maatwebsite\Excel\Concerns;
use Maatwebsite\Excel\Row;
interface OnEachRow
{
/**
* @param Row $row
*/
public function onRow(Row $row);
}

View File

@@ -0,0 +1,52 @@
<?php
namespace Maatwebsite\Excel\Concerns;
use Maatwebsite\Excel\Events\AfterSheet;
use Maatwebsite\Excel\Events\AfterImport;
use Maatwebsite\Excel\Events\BeforeSheet;
use Maatwebsite\Excel\Events\BeforeExport;
use Maatwebsite\Excel\Events\BeforeImport;
use Maatwebsite\Excel\Events\ImportFailed;
use Maatwebsite\Excel\Events\BeforeWriting;
trait RegistersEventListeners
{
/**
* @return array
*/
public function registerEvents(): array
{
$listeners = [];
if (method_exists($this, 'beforeExport')) {
$listeners[BeforeExport::class] = [static::class, 'beforeExport'];
}
if (method_exists($this, 'beforeWriting')) {
$listeners[BeforeWriting::class] = [static::class, 'beforeWriting'];
}
if (method_exists($this, 'beforeImport')) {
$listeners[BeforeImport::class] = [static::class, 'beforeImport'];
}
if (method_exists($this, 'afterImport')) {
$listeners[AfterImport::class] = [static::class, 'afterImport'];
}
if (method_exists($this, 'importFailed')) {
$listeners[ImportFailed::class] = [static::class, 'importFailed'];
}
if (method_exists($this, 'beforeSheet')) {
$listeners[BeforeSheet::class] = [static::class, 'beforeSheet'];
}
if (method_exists($this, 'afterSheet')) {
$listeners[AfterSheet::class] = [static::class, 'afterSheet'];
}
return $listeners;
}
}

View File

@@ -0,0 +1,7 @@
<?php
namespace Maatwebsite\Excel\Concerns;
interface ShouldAutoSize
{
}

View File

@@ -0,0 +1,31 @@
<?php
namespace Maatwebsite\Excel\Concerns;
use Throwable;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Validators\Failure;
trait SkipsErrors
{
/**
* @var Failure[]
*/
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);
}
}

View File

@@ -0,0 +1,30 @@
<?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);
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Maatwebsite\Excel\Concerns;
use Throwable;
interface SkipsOnError
{
/**
* @param Throwable $e
*/
public function onError(Throwable $e);
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Maatwebsite\Excel\Concerns;
use Maatwebsite\Excel\Validators\Failure;
interface SkipsOnFailure
{
/**
* @param Failure[] $failures
*/
public function onFailure(Failure ...$failures);
}

View File

@@ -0,0 +1,11 @@
<?php
namespace Maatwebsite\Excel\Concerns;
interface SkipsUnknownSheets
{
/**
* @param string|int $sheetName
*/
public function onUnknownSheet($sheetName);
}

View File

@@ -0,0 +1,11 @@
<?php
namespace Maatwebsite\Excel\Concerns;
interface ToArray
{
/**
* @param array $array
*/
public function array(array $array);
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Maatwebsite\Excel\Concerns;
use Illuminate\Support\Collection;
interface ToCollection
{
/**
* @param Collection $collection
*/
public function collection(Collection $collection);
}

View File

@@ -0,0 +1,15 @@
<?php
namespace Maatwebsite\Excel\Concerns;
use Illuminate\Database\Eloquent\Model;
interface ToModel
{
/**
* @param array $row
*
* @return Model|Model[]|null
*/
public function model(array $row);
}

View File

@@ -0,0 +1,11 @@
<?php
namespace Maatwebsite\Excel\Concerns;
interface WithBatchInserts
{
/**
* @return int
*/
public function batchSize(): int;
}

View File

@@ -0,0 +1,7 @@
<?php
namespace Maatwebsite\Excel\Concerns;
interface WithCalculatedFormulas
{
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Maatwebsite\Excel\Concerns;
use PhpOffice\PhpSpreadsheet\Chart\Chart;
interface WithCharts
{
/**
* @return Chart|Chart[]
*/
public function charts();
}

View File

@@ -0,0 +1,11 @@
<?php
namespace Maatwebsite\Excel\Concerns;
interface WithChunkReading
{
/**
* @return int
*/
public function chunkSize(): int;
}

View File

@@ -0,0 +1,11 @@
<?php
namespace Maatwebsite\Excel\Concerns;
interface WithColumnFormatting
{
/**
* @return array
*/
public function columnFormats(): array;
}

View File

@@ -0,0 +1,38 @@
<?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;
}

View File

@@ -0,0 +1,11 @@
<?php
namespace Maatwebsite\Excel\Concerns;
interface WithCustomChunkSize
{
/**
* @return int
*/
public function chunkSize(): int;
}

View File

@@ -0,0 +1,11 @@
<?php
namespace Maatwebsite\Excel\Concerns;
interface WithCustomCsvSettings
{
/**
* @return array
*/
public function getCsvSettings(): array;
}

View File

@@ -0,0 +1,17 @@
<?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;
}

View File

@@ -0,0 +1,11 @@
<?php
namespace Maatwebsite\Excel\Concerns;
interface WithCustomStartCell
{
/**
* @return string
*/
public function startCell(): string;
}

View File

@@ -0,0 +1,9 @@
<?php
namespace Maatwebsite\Excel\Concerns;
use PhpOffice\PhpSpreadsheet\Cell\IValueBinder;
interface WithCustomValueBinder extends IValueBinder
{
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Maatwebsite\Excel\Concerns;
use PhpOffice\PhpSpreadsheet\Worksheet\BaseDrawing;
interface WithDrawings
{
/**
* @return BaseDrawing|BaseDrawing[]
*/
public function drawings();
}

View File

@@ -0,0 +1,11 @@
<?php
namespace Maatwebsite\Excel\Concerns;
interface WithEvents
{
/**
* @return array
*/
public function registerEvents(): array;
}

View File

@@ -0,0 +1,7 @@
<?php
namespace Maatwebsite\Excel\Concerns;
interface WithHeadingRow
{
}

View File

@@ -0,0 +1,11 @@
<?php
namespace Maatwebsite\Excel\Concerns;
interface WithHeadings
{
/**
* @return array
*/
public function headings(): array;
}

View File

@@ -0,0 +1,11 @@
<?php
namespace Maatwebsite\Excel\Concerns;
interface WithLimit
{
/**
* @return int
*/
public function limit(): int;
}

View File

@@ -0,0 +1,11 @@
<?php
namespace Maatwebsite\Excel\Concerns;
interface WithMappedCells
{
/**
* @return array
*/
public function mapping(): array;
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Maatwebsite\Excel\Concerns;
interface WithMapping
{
/**
* @param mixed $row
*
* @return array
*/
public function map($row): array;
}

View File

@@ -0,0 +1,11 @@
<?php
namespace Maatwebsite\Excel\Concerns;
interface WithMultipleSheets
{
/**
* @return array
*/
public function sheets(): array;
}

View File

@@ -0,0 +1,7 @@
<?php
namespace Maatwebsite\Excel\Concerns;
interface WithPreCalculateFormulas
{
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Maatwebsite\Excel\Concerns;
use Illuminate\Console\OutputStyle;
interface WithProgressBar
{
/**
* @return OutputStyle
*/
public function getConsoleOutput(): OutputStyle;
}

View File

@@ -0,0 +1,11 @@
<?php
namespace Maatwebsite\Excel\Concerns;
interface WithStartRow
{
/**
* @return int
*/
public function startRow(): int;
}

View File

@@ -0,0 +1,7 @@
<?php
namespace Maatwebsite\Excel\Concerns;
interface WithStrictNullComparison
{
}

View File

@@ -0,0 +1,11 @@
<?php
namespace Maatwebsite\Excel\Concerns;
interface WithTitle
{
/**
* @return string
*/
public function title(): string;
}

View File

@@ -0,0 +1,11 @@
<?php
namespace Maatwebsite\Excel\Concerns;
interface WithValidation
{
/**
* @return array
*/
public function rules(): array;
}

View File

@@ -0,0 +1,97 @@
<?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')) {
$stub = '/stubs/export.query-model.stub';
} elseif ($this->option('model')) {
$stub = '/stubs/export.model.stub';
} elseif ($this->option('query')) {
$stub = '/stubs/export.query.stub';
}
$stub = $stub ?? '/stubs/export.plain.stub';
return __DIR__ . $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.'],
];
}
}

View File

@@ -0,0 +1,93 @@
<?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()
{
if ($this->option('model')) {
$stub = '/stubs/import.model.stub';
}
$stub = $stub ?? '/stubs/import.collection.stub';
return __DIR__ . $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.'],
['query', '', InputOption::VALUE_NONE, 'Generate an import for a query.'],
];
}
}

View File

@@ -0,0 +1,48 @@
<?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 = trim(str_replace('/', '\\', $model), '\\');
if (!Str::startsWith($model, $rootNamespace = $this->laravel->getNamespace())) {
$model = $rootNamespace . $model;
}
return $model;
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace DummyNamespace;
use DummyFullModelClass;
use Maatwebsite\Excel\Concerns\FromCollection;
class DummyClass implements FromCollection
{
/**
* @return \Illuminate\Support\Collection
*/
public function collection()
{
return DummyModelClass::all();
}
}

View File

@@ -0,0 +1,16 @@
<?php
namespace DummyNamespace;
use Maatwebsite\Excel\Concerns\FromCollection;
class DummyClass implements FromCollection
{
/**
* @return \Illuminate\Support\Collection
*/
public function collection()
{
//
}
}

View File

@@ -0,0 +1,17 @@
<?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();
}
}

View File

@@ -0,0 +1,16 @@
<?php
namespace DummyNamespace;
use Maatwebsite\Excel\Concerns\FromQuery;
class DummyClass implements FromQuery
{
/**
* @return \Illuminate\Database\Query\Builder
*/
public function query()
{
//
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace DummyNamespace;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\ToCollection;
class DummyClass implements ToCollection
{
/**
* @param Collection $collection
*/
public function collection(Collection $collection)
{
//
}
}

View File

@@ -0,0 +1,21 @@
<?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([
//
]);
}
}

View File

@@ -0,0 +1,24 @@
<?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);
}
}

View File

@@ -0,0 +1,36 @@
<?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();
}

View File

@@ -0,0 +1,52 @@
<?php
namespace Maatwebsite\Excel\Events;
use Maatwebsite\Excel\Reader;
class AfterImport extends Event
{
/**
* @var Reader
*/
public $reader;
/**
* @var object
*/
private $importable;
/**
* @param Reader $reader
* @param object $importable
*/
public function __construct(Reader $reader, $importable)
{
$this->reader = $reader;
$this->importable = $importable;
}
/**
* @return Reader
*/
public function getReader(): Reader
{
return $this->reader;
}
/**
* @return object
*/
public function getConcernable()
{
return $this->importable;
}
/**
* @return mixed
*/
public function getDelegate()
{
return $this->reader;
}
}

View File

@@ -0,0 +1,52 @@
<?php
namespace Maatwebsite\Excel\Events;
use Maatwebsite\Excel\Sheet;
class AfterSheet extends Event
{
/**
* @var Sheet
*/
public $sheet;
/**
* @var object
*/
private $exportable;
/**
* @param Sheet $sheet
* @param object $exportable
*/
public function __construct(Sheet $sheet, $exportable)
{
$this->sheet = $sheet;
$this->exportable = $exportable;
}
/**
* @return Sheet
*/
public function getSheet(): Sheet
{
return $this->sheet;
}
/**
* @return object
*/
public function getConcernable()
{
return $this->exportable;
}
/**
* @return mixed
*/
public function getDelegate()
{
return $this->sheet;
}
}

View File

@@ -0,0 +1,52 @@
<?php
namespace Maatwebsite\Excel\Events;
use Maatwebsite\Excel\Writer;
class BeforeExport 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;
$this->exportable = $exportable;
}
/**
* @return Writer
*/
public function getWriter(): Writer
{
return $this->writer;
}
/**
* @return object
*/
public function getConcernable()
{
return $this->exportable;
}
/**
* @return mixed
*/
public function getDelegate()
{
return $this->writer;
}
}

View File

@@ -0,0 +1,52 @@
<?php
namespace Maatwebsite\Excel\Events;
use Maatwebsite\Excel\Reader;
class BeforeImport extends Event
{
/**
* @var Reader
*/
public $reader;
/**
* @var object
*/
private $importable;
/**
* @param Reader $reader
* @param object $importable
*/
public function __construct(Reader $reader, $importable)
{
$this->reader = $reader;
$this->importable = $importable;
}
/**
* @return Reader
*/
public function getReader(): Reader
{
return $this->reader;
}
/**
* @return object
*/
public function getConcernable()
{
return $this->importable;
}
/**
* @return mixed
*/
public function getDelegate()
{
return $this->reader;
}
}

View File

@@ -0,0 +1,52 @@
<?php
namespace Maatwebsite\Excel\Events;
use Maatwebsite\Excel\Sheet;
class BeforeSheet extends Event
{
/**
* @var Sheet
*/
public $sheet;
/**
* @var object
*/
private $exportable;
/**
* @param Sheet $sheet
* @param object $exportable
*/
public function __construct(Sheet $sheet, $exportable)
{
$this->sheet = $sheet;
$this->exportable = $exportable;
}
/**
* @return Sheet
*/
public function getSheet(): Sheet
{
return $this->sheet;
}
/**
* @return object
*/
public function getConcernable()
{
return $this->exportable;
}
/**
* @return mixed
*/
public function getDelegate()
{
return $this->sheet;
}
}

View File

@@ -0,0 +1,52 @@
<?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;
$this->exportable = $exportable;
}
/**
* @return Writer
*/
public function getWriter(): Writer
{
return $this->writer;
}
/**
* @return object
*/
public function getConcernable()
{
return $this->exportable;
}
/**
* @return mixed
*/
public function getDelegate()
{
return $this->writer;
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace Maatwebsite\Excel\Events;
abstract class Event
{
/**
* @return object
*/
abstract public function getConcernable();
/**
* @return mixed
*/
abstract public function getDelegate();
/**
* @param string $concern
*
* @return bool
*/
public function appliesToConcern(string $concern): bool
{
return $this->getConcernable() instanceof $concern;
}
}

View File

@@ -0,0 +1,29 @@
<?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;
}
}

197
vendor/maatwebsite/excel/src/Excel.php vendored Normal file
View File

@@ -0,0 +1,197 @@
<?php
namespace Maatwebsite\Excel;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Files\Filesystem;
use Maatwebsite\Excel\Files\TemporaryFile;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\PendingDispatch;
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 = [])
{
return response()->download(
$this->export($export, $fileName, $writerType)->getLocalPath(),
$fileName,
$headers
)->deleteFileAfterSend(true);
}
/**
* {@inheritdoc}
*/
public function store($export, string $filePath, string $diskName = null, string $writerType = null, $diskOptions = [])
{
if ($export instanceof ShouldQueue) {
return $this->queue($export, $filePath, $diskName, $writerType, $diskOptions);
}
$temporaryFile = $this->export($export, $filePath, $writerType);
$exported = $this->filesystem->disk($diskName, $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
*
* @throws \PhpOffice\PhpSpreadsheet\Exception
* @return TemporaryFile
*/
protected function export($export, string $fileName, string $writerType = null): TemporaryFile
{
$writerType = FileTypeDetector::detectStrict($fileName, $writerType);
return $this->writer->export($export, $writerType);
}
}

View File

@@ -0,0 +1,94 @@
<?php
namespace Maatwebsite\Excel;
use Illuminate\Support\Collection;
use Illuminate\Support\ServiceProvider;
use Maatwebsite\Excel\Files\Filesystem;
use Maatwebsite\Excel\Mixins\StoreCollection;
use Maatwebsite\Excel\Console\ExportMakeCommand;
use Maatwebsite\Excel\Console\ImportMakeCommand;
use Maatwebsite\Excel\Mixins\DownloadCollection;
use Maatwebsite\Excel\Files\TemporaryFileFactory;
use Laravel\Lumen\Application as LumenApplication;
use Maatwebsite\Excel\Transactions\TransactionHandler;
use Maatwebsite\Excel\Transactions\TransactionManager;
class ExcelServiceProvider extends ServiceProvider
{
/**
* {@inheritdoc}
*/
public function boot()
{
if ($this->app->runningInConsole()) {
if ($this->app instanceof LumenApplication) {
$this->app->configure('excel');
} else {
$this->publishes([
$this->getConfigFile() => config_path('excel.php'),
], 'config');
}
}
}
/**
* {@inheritdoc}
*/
public function register()
{
$this->mergeConfigFrom(
$this->getConfigFile(),
'excel'
);
$this->app->bind(TransactionManager::class, function () {
return new TransactionManager($this->app);
});
$this->app->bind(TransactionHandler::class, function () {
return $this->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 () {
return new Filesystem($this->app->make('filesystem'));
});
$this->app->bind('excel', function () {
return new Excel(
$this->app->make(Writer::class),
$this->app->make(QueuedWriter::class),
$this->app->make(Reader::class),
$this->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 DownloadCollection);
Collection::mixin(new StoreCollection);
$this->commands([
ExportMakeCommand::class,
ImportMakeCommand::class,
]);
}
/**
* @return string
*/
protected function getConfigFile(): string
{
return __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'excel.php';
}
}

View File

@@ -0,0 +1,16 @@
<?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.');
}
}

View File

@@ -0,0 +1,9 @@
<?php
namespace Maatwebsite\Excel\Exceptions;
use Throwable;
interface LaravelExcelException extends Throwable
{
}

View File

@@ -0,0 +1,38 @@
<?php
namespace Maatwebsite\Excel\Exceptions;
use Throwable;
use InvalidArgumentException;
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.');
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace Maatwebsite\Excel\Exceptions;
use Throwable;
use InvalidArgumentException;
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);
}
}

View File

@@ -0,0 +1,22 @@
<?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);
}
}

View File

@@ -0,0 +1,41 @@
<?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();
}
}

View File

@@ -0,0 +1,27 @@
<?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}.");
}
}

View File

@@ -0,0 +1,22 @@
<?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);
}
}

View File

@@ -0,0 +1,53 @@
<?php
namespace Maatwebsite\Excel;
use Illuminate\Foundation\Bus\PendingDispatch;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
interface Exporter
{
/**
* @param object $export
* @param string|null $fileName
* @param string $writerType
* @param array $headers
*
* @throws \PhpOffice\PhpSpreadsheet\Exception
* @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
* @return BinaryFileResponse
*/
public function download($export, string $fileName, string $writerType = null, array $headers = []);
/**
* @param object $export
* @param string $filePath
* @param string|null $disk
* @param string $writerType
* @param mixed $diskOptions
*
* @throws \PhpOffice\PhpSpreadsheet\Exception
* @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
* @return bool
*/
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 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);
}

View File

@@ -0,0 +1,48 @@
<?php
namespace Maatwebsite\Excel\Facades;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Facade;
use Maatwebsite\Excel\Fakes\ExcelFake;
use Maatwebsite\Excel\Excel as BaseExcel;
use Illuminate\Foundation\Bus\PendingDispatch;
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 BaseExcel import(object $import, string $filePath, string $disk = null, string $readerType = null)
* @method static array toArray(object $import, string $filePath, string $disk = null, string $readerType = null)
* @method static Collection toCollection(object $import, string $filePath, string $disk = null, string $readerType = null)
* @method static PendingDispatch queueImport(object $import, string $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 $disk = null, callable $callback = null)
* @method static void assertQueued(string $filePath, string $disk = null, callable $callback = null)
* @method static void assertImported(string $filePath, string $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';
}
}

View File

@@ -0,0 +1,67 @@
<?php
namespace Maatwebsite\Excel\Factories;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Reader\Csv;
use Maatwebsite\Excel\Files\TemporaryFile;
use PhpOffice\PhpSpreadsheet\Reader\IReader;
use PhpOffice\PhpSpreadsheet\Reader\Exception;
use Maatwebsite\Excel\Concerns\MapsCsvSettings;
use Maatwebsite\Excel\Concerns\WithCustomCsvSettings;
use Maatwebsite\Excel\Exceptions\NoTypeDetectedException;
class ReaderFactory
{
use MapsCsvSettings;
/**
* @param object $import
* @param TemporaryFile $file
* @param string $readerType
*
* @throws Exception
* @return IReader
*/
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 ($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);
}
return $reader;
}
/**
* @param TemporaryFile $temporaryFile
*
* @throws NoTypeDetectedException
* @return string
*/
private static function identify(TemporaryFile $temporaryFile): string
{
try {
return IOFactory::identify($temporaryFile->getLocalPath());
} catch (Exception $e) {
throw new NoTypeDetectedException(null, null, $e);
}
}
}

View File

@@ -0,0 +1,86 @@
<?php
namespace Maatwebsite\Excel\Factories;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Writer\Csv;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Html;
use Maatwebsite\Excel\Concerns\WithCharts;
use PhpOffice\PhpSpreadsheet\Writer\IWriter;
use Maatwebsite\Excel\Concerns\MapsCsvSettings;
use Maatwebsite\Excel\Concerns\WithMultipleSheets;
use Maatwebsite\Excel\Concerns\WithCustomCsvSettings;
use Maatwebsite\Excel\Concerns\WithPreCalculateFormulas;
class WriterFactory
{
use MapsCsvSettings;
/**
* @param string $writerType
* @param Spreadsheet $spreadsheet
* @param object $export
*
* @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
* @return IWriter
*/
public static function make(string $writerType, Spreadsheet $spreadsheet, $export): IWriter
{
$writer = IOFactory::createWriter($spreadsheet, $writerType);
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->setLineEnding(static::$lineEnding);
$writer->setUseBOM(static::$useBom);
$writer->setIncludeSeparatorLine(static::$includeSeparatorLine);
$writer->setExcelCompatibility(static::$excelCompatibility);
}
// 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;
}
}

View File

@@ -0,0 +1,342 @@
<?php
namespace Maatwebsite\Excel\Fakes;
use Illuminate\Bus\Queueable;
use Maatwebsite\Excel\Reader;
use PHPUnit\Framework\Assert;
use Maatwebsite\Excel\Exporter;
use Maatwebsite\Excel\Importer;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Queue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\PendingDispatch;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
class ExcelFake implements Exporter, Importer
{
/**
* @var array
*/
protected $downloads = [];
/**
* @var array
*/
protected $stored = [];
/**
* @var array
*/
protected $queued = [];
/**
* @var array
*/
protected $imported = [];
/**
* @var bool
*/
protected $matchByRegex = false;
/**
* {@inheritdoc}
*/
public function download($export, string $fileName, string $writerType = null, array $headers = [])
{
$this->downloads[$fileName] = $export;
return new BinaryFileResponse(__DIR__ . '/fake_file');
}
/**
* {@inheritdoc}
*/
public function store($export, string $filePath, string $disk = null, string $writerType = null, $diskOptions = [])
{
if ($export instanceof ShouldQueue) {
return $this->queue($export, $filePath, $disk, $writerType);
}
$this->stored[$disk ?? '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;
return new PendingDispatch(new class {
use Queueable;
public function handle()
{
//
}
});
}
/**
* @param object $export
* @param string $writerType
*
* @return string
*/
public function raw($export, string $writerType)
{
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;
return new PendingDispatch(new class {
use Queueable;
public function handle()
{
//
}
});
}
/**
* 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."
);
}
/**
* @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 $results[0];
}
Assert::assertArrayHasKey($key, $disk, $message);
return $key;
}
}

View File

View File

@@ -0,0 +1,99 @@
<?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);
}
}

View File

@@ -0,0 +1,36 @@
<?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
);
}
}

View File

@@ -0,0 +1,69 @@
<?php
namespace Maatwebsite\Excel\Files;
class LocalTemporaryFile extends TemporaryFile
{
/**
* @var string
*/
private $filePath;
/**
* @param string $filePath
*/
public function __construct(string $filePath)
{
touch($filePath);
$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
{
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);
}
}

View File

@@ -0,0 +1,131 @@
<?php
namespace Maatwebsite\Excel\Files;
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 exists(): bool
{
return $this->disk()->exists($this->filename);
}
/**
* @return bool
*/
public function delete(): bool
{
$this->localTemporaryFile->delete();
return $this->disk()->delete($this->filename);
}
/**
* @return TemporaryFile
*/
public function sync(): TemporaryFile
{
if (!$this->localTemporaryFile->exists()) {
touch($this->localTemporaryFile->getLocalPath());
}
$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);
}
}

View File

@@ -0,0 +1,71 @@
<?php
namespace Maatwebsite\Excel\Files;
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 {
$readStream = app('filesystem')->disk($disk)->readStream($filePath);
}
$this->put($readStream);
if (is_resource($readStream)) {
fclose($readStream);
}
return $this->sync();
}
}

View File

@@ -0,0 +1,84 @@
<?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();
}
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) && !is_dir($concurrentDirectory)) {
throw new \RuntimeException(sprintf('Directory "%s" was not created', $concurrentDirectory));
}
return new LocalTemporaryFile(
$this->temporaryPath . DIRECTORY_SEPARATOR . ($fileName ?: $this->generateFilename($fileExtension))
);
}
/**
* @return RemoteTemporaryFile
*/
private function makeRemote(): RemoteTemporaryFile
{
$filename = $this->generateFilename();
return new RemoteTemporaryFile(
$this->temporaryDisk,
$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 : '');
}
}

View File

@@ -0,0 +1,56 @@
<?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));
}
}

View File

@@ -0,0 +1,64 @@
<?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;
}
}
/**
* 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);
}
}

View File

@@ -0,0 +1,53 @@
<?php
namespace Maatwebsite\Excel;
use Maatwebsite\Excel\Concerns\WithLimit;
use Maatwebsite\Excel\Concerns\Importable;
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);
}
}

View File

@@ -0,0 +1,33 @@
<?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'));
}
}

Some files were not shown because too many files have changed in this diff Show More