Reader writer flags (#2136)

* Use of passing flags with Readers to identify whether speacial features such as loading charts should be enabled; no need to instantiate a reader and manually enable it before loading any more.

This is in preparation for supporting new "boolean" Reaer/Writer features, such as pivot tables

* Use of passing flags with Writers to identify whether speacial features such as loading charts should be enabled; no need to instantiate a writer and manually enable it before loading any more.

* Update documentation with details of changes to the StringValueBinder
This commit is contained in:
Mark Baker 2021-06-04 13:45:32 +02:00 committed by GitHub
parent 488701b748
commit 19724e3217
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 136 additions and 55 deletions

View File

@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org).
### Added ### Added
- Support for passing flags in the Reader `load()` and Writer `save()`methods, and through the IOFactory, to set behaviours. [PR #2136](https://github.com/PHPOffice/PhpSpreadsheet/pull/2136)
- See [documentation](https://phpspreadsheet.readthedocs.io/en/latest/topics/reading-and-writing-to-file/) for details
- More flexibility in the StringValueBinder to determine what datatypes should be treated as strings [PR #2138](https://github.com/PHPOffice/PhpSpreadsheet/pull/2138) - More flexibility in the StringValueBinder to determine what datatypes should be treated as strings [PR #2138](https://github.com/PHPOffice/PhpSpreadsheet/pull/2138)
### Changed ### Changed

View File

@ -1,8 +1,7 @@
# Reading and writing to file # Reading and writing to file
As you already know from the [architecture](./architecture.md#readers-and-writers), As you already know from the [architecture](./architecture.md#readers-and-writers),
reading and writing to a reading and writing to a persisted storage is not possible using the base PhpSpreadsheet classes.
persisted storage is not possible using the base PhpSpreadsheet classes.
For this purpose, PhpSpreadsheet provides readers and writers, which are For this purpose, PhpSpreadsheet provides readers and writers, which are
implementations of `\PhpOffice\PhpSpreadsheet\Reader\IReader` and implementations of `\PhpOffice\PhpSpreadsheet\Reader\IReader` and
`\PhpOffice\PhpSpreadsheet\Writer\IWriter`. `\PhpOffice\PhpSpreadsheet\Writer\IWriter`.
@ -892,8 +891,7 @@ class My_Custom_TCPDF_Writer extends \PhpOffice\PhpSpreadsheet\Writer\Pdf\Tcpdf
#### Writing a spreadsheet #### Writing a spreadsheet
Once you have identified the Renderer that you wish to use for PDF Once you have identified the Renderer that you wish to use for PDF generation, you can write a .pdf file using the following code:
generation, you can write a .pdf file using the following code:
```php ```php
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Pdf\Mpdf($spreadsheet); $writer = new \PhpOffice\PhpSpreadsheet\Writer\Pdf\Mpdf($spreadsheet);
@ -905,8 +903,7 @@ first worksheet by default.
#### Write all worksheets #### Write all worksheets
PDF files can contain one or more worksheets. If you want to write all PDF files can contain one or more worksheets. If you want to write all sheets into a single PDF file, use the following code:
sheets into a single PDF file, use the following code:
```php ```php
$writer->writeAllSheets(); $writer->writeAllSheets();
@ -1020,3 +1017,64 @@ $spreadhseet = $reader->loadFromString($secondHtmlString, $spreadsheet);
$writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, 'Xls'); $writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, 'Xls');
$writer->save('write.xls'); $writer->save('write.xls');
``` ```
## Reader/Writer Flags
Some Readers and Writers support special "Feature Flags" that need to be explicitly enabled.
An example of this is Charts in a spreadsheet. By default, when you load a spreadsheet that contains Charts, the charts will not be loaded. If all you want to do is read the data in the spreadsheet, then loading charts is an overhead for both speed of loading and memory usage.
However, there are times when you may want to load any charts in the spreadsheet as well as the data. To do so, you need to tell the Reader explicitly to include Charts.
```php
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReaderForFile("05featuredemo.xlsx");
$reader->setIncludeCharts(true);
$reader->load("spreadsheetWithCharts.xlsx");
```
Alternatively, you can specify this in the call to load the spreadsheet:
```php
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReaderForFile("spreadsheetWithCharts.xlsx");
$reader->load("spreadsheetWithCharts.xlsx", $reader::LOAD_WITH_CHARTS);
```
If you wish to use the IOFactory `load()` method rather than instantiating a specific Reader, then you can still pass these flags.
```php
$spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load("spreadsheetWithCharts.xlsx", \PhpOffice\PhpSpreadsheet\Reader\IReader::LOAD_WITH_CHARTS);
```
Likewise, when saving a file using a Writer, loaded charts wil not be saved unless you explicitly tell the Writer to include them:
```php
$writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
$writer->setIncludeCharts(true);
$writer->save('mySavedFileWithCharts.xlsx');
```
As with the `load()` method, you can also pass flags in the `save()` method:
```php
$writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
$writer->save('mySavedFileWithCharts.xlsx', \PhpOffice\PhpSpreadsheet\Writer\IWriter::SAVE_WITH_CHARTS);
```
Currently, the only special "Feature Flag" that is supported in this way is the inclusion of Charts, and only for certain formats.
Readers | LOAD_WITH_CHARTS |
---------|------------------|
Xlsx | YES |
Xls | NO |
Xml | NO |
Ods | NO |
Gnumeric | NO |
Html | N/A |
Slk | N/A |
Csv | N/A |
Writers | SAVE_WITH_CHARTS |
--------|------------------|
Xlsx | YES |
Xls | NO |
Ods | NO |
Html | YES |
Pdf | YES |
Csv | N/A |

View File

@ -6245,11 +6245,6 @@ parameters:
count: 1 count: 1
path: src/PhpSpreadsheet/Writer/Html.php path: src/PhpSpreadsheet/Writer/Html.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\IWriter\\:\\:save\\(\\) has no return typehint specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Writer/IWriter.php
- -
message: "#^Negated boolean expression is always false\\.$#" message: "#^Negated boolean expression is always false\\.$#"
count: 1 count: 1

View File

@ -75,15 +75,15 @@ abstract class IOFactory
/** /**
* Loads Spreadsheet from file using automatic Reader\IReader resolution. * Loads Spreadsheet from file using automatic Reader\IReader resolution.
* *
* @param string $pFilename The name of the spreadsheet file * @param string $filename The name of the spreadsheet file
* *
* @return Spreadsheet * @return Spreadsheet
*/ */
public static function load($pFilename) public static function load(string $filename, int $flags = 0)
{ {
$reader = self::createReaderForFile($pFilename); $reader = self::createReaderForFile($filename);
return $reader->load($pFilename); return $reader->load($filename, $flags);
} }
/** /**

View File

@ -137,6 +137,13 @@ abstract class BaseReader implements IReader
return $this->securityScanner; return $this->securityScanner;
} }
protected function processFlags(int $flags): void
{
if (((bool) ($flags & self::LOAD_WITH_CHARTS)) === true) {
$this->setIncludeCharts(true);
}
}
/** /**
* Open file for reading. * Open file for reading.
* *

View File

@ -236,12 +236,12 @@ class Csv extends BaseReader
/** /**
* Loads Spreadsheet from file. * Loads Spreadsheet from file.
* *
* @param string $pFilename
*
* @return Spreadsheet * @return Spreadsheet
*/ */
public function load($pFilename) public function load(string $pFilename, int $flags = 0)
{ {
$this->processFlags($flags);
// Create new Spreadsheet // Create new Spreadsheet
$spreadsheet = new Spreadsheet(); $spreadsheet = new Spreadsheet();

View File

@ -235,12 +235,12 @@ class Gnumeric extends BaseReader
/** /**
* Loads Spreadsheet from file. * Loads Spreadsheet from file.
* *
* @param string $pFilename
*
* @return Spreadsheet * @return Spreadsheet
*/ */
public function load($pFilename) public function load(string $pFilename, int $flags = 0)
{ {
$this->processFlags($flags);
// Create new Spreadsheet // Create new Spreadsheet
$spreadsheet = new Spreadsheet(); $spreadsheet = new Spreadsheet();
$spreadsheet->removeSheetByIndex(0); $spreadsheet->removeSheetByIndex(0);

View File

@ -204,12 +204,12 @@ class Html extends BaseReader
/** /**
* Loads Spreadsheet from file. * Loads Spreadsheet from file.
* *
* @param string $pFilename
*
* @return Spreadsheet * @return Spreadsheet
*/ */
public function load($pFilename) public function load(string $pFilename, int $flags = 0)
{ {
$this->processFlags($flags);
// Create new Spreadsheet // Create new Spreadsheet
$spreadsheet = new Spreadsheet(); $spreadsheet = new Spreadsheet();

View File

@ -4,6 +4,8 @@ namespace PhpOffice\PhpSpreadsheet\Reader;
interface IReader interface IReader
{ {
public const LOAD_WITH_CHARTS = 1;
/** /**
* IReader constructor. * IReader constructor.
*/ */
@ -125,9 +127,7 @@ interface IReader
/** /**
* Loads PhpSpreadsheet from file. * Loads PhpSpreadsheet from file.
* *
* @param string $pFilename
*
* @return \PhpOffice\PhpSpreadsheet\Spreadsheet * @return \PhpOffice\PhpSpreadsheet\Spreadsheet
*/ */
public function load($pFilename); public function load(string $pFilename, int $flags = 0);
} }

View File

@ -231,12 +231,12 @@ class Ods extends BaseReader
/** /**
* Loads PhpSpreadsheet from file. * Loads PhpSpreadsheet from file.
* *
* @param string $pFilename
*
* @return Spreadsheet * @return Spreadsheet
*/ */
public function load($pFilename) public function load(string $pFilename, int $flags = 0)
{ {
$this->processFlags($flags);
// Create new Spreadsheet // Create new Spreadsheet
$spreadsheet = new Spreadsheet(); $spreadsheet = new Spreadsheet();

View File

@ -197,12 +197,12 @@ class Slk extends BaseReader
/** /**
* Loads PhpSpreadsheet from file. * Loads PhpSpreadsheet from file.
* *
* @param string $pFilename
*
* @return Spreadsheet * @return Spreadsheet
*/ */
public function load($pFilename) public function load(string $pFilename, int $flags = 0)
{ {
$this->processFlags($flags);
// Create new Spreadsheet // Create new Spreadsheet
$spreadsheet = new Spreadsheet(); $spreadsheet = new Spreadsheet();

View File

@ -622,12 +622,12 @@ class Xls extends BaseReader
/** /**
* Loads PhpSpreadsheet from file. * Loads PhpSpreadsheet from file.
* *
* @param string $pFilename
*
* @return Spreadsheet * @return Spreadsheet
*/ */
public function load($pFilename) public function load(string $pFilename, int $flags = 0)
{ {
$this->processFlags($flags);
// Read the OLE file // Read the OLE file
$this->loadOLE($pFilename); $this->loadOLE($pFilename);

View File

@ -310,13 +310,12 @@ class Xlsx extends BaseReader
/** /**
* Loads Spreadsheet from file. * Loads Spreadsheet from file.
* *
* @param string $pFilename
*
* @return Spreadsheet * @return Spreadsheet
*/ */
public function load($pFilename) public function load(string $pFilename, int $flags = 0)
{ {
File::assertFile($pFilename); File::assertFile($pFilename);
$this->processFlags($flags);
// Initialisations // Initialisations
$excel = new Spreadsheet(); $excel = new Spreadsheet();

View File

@ -236,18 +236,18 @@ class Xml extends BaseReader
/** /**
* Loads Spreadsheet from file. * Loads Spreadsheet from file.
* *
* @param string $filename
*
* @return Spreadsheet * @return Spreadsheet
*/ */
public function load($filename) public function load(string $pFilename, int $flags = 0)
{ {
$this->processFlags($flags);
// Create new Spreadsheet // Create new Spreadsheet
$spreadsheet = new Spreadsheet(); $spreadsheet = new Spreadsheet();
$spreadsheet->removeSheetByIndex(0); $spreadsheet->removeSheetByIndex(0);
// Load into this instance // Load into this instance
return $this->loadIntoExisting($filename, $spreadsheet); return $this->loadIntoExisting($pFilename, $spreadsheet);
} }
/** /**

View File

@ -6,7 +6,7 @@ abstract class BaseWriter implements IWriter
{ {
/** /**
* Write charts that are defined in the workbook? * Write charts that are defined in the workbook?
* Identifies whether the Writer should write definitions for any charts that exist in the PhpSpreadsheet object;. * Identifies whether the Writer should write definitions for any charts that exist in the PhpSpreadsheet object.
* *
* @var bool * @var bool
*/ */
@ -94,6 +94,13 @@ abstract class BaseWriter implements IWriter
return $this->diskCachingDirectory; return $this->diskCachingDirectory;
} }
protected function processFlags(int $flags): void
{
if (((bool) ($flags & self::SAVE_WITH_CHARTS)) === true) {
$this->setIncludeCharts(true);
}
}
/** /**
* Open file handle. * Open file handle.
* *

View File

@ -86,8 +86,10 @@ class Csv extends BaseWriter
* *
* @param resource|string $pFilename * @param resource|string $pFilename
*/ */
public function save($pFilename): void public function save($pFilename, int $flags = 0): void
{ {
$this->processFlags($flags);
// Fetch sheet // Fetch sheet
$sheet = $this->spreadsheet->getSheet($this->sheetIndex); $sheet = $this->spreadsheet->getSheet($this->sheetIndex);

View File

@ -153,8 +153,10 @@ class Html extends BaseWriter
* *
* @param resource|string $pFilename * @param resource|string $pFilename
*/ */
public function save($pFilename): void public function save($pFilename, int $flags = 0): void
{ {
$this->processFlags($flags);
// Open file // Open file
$this->openFileHandle($pFilename); $this->openFileHandle($pFilename);

View File

@ -6,6 +6,8 @@ use PhpOffice\PhpSpreadsheet\Spreadsheet;
interface IWriter interface IWriter
{ {
public const SAVE_WITH_CHARTS = 1;
/** /**
* IWriter constructor. * IWriter constructor.
*/ */
@ -59,7 +61,7 @@ interface IWriter
* *
* @param resource|string $pFilename Name of the file to save * @param resource|string $pFilename Name of the file to save
*/ */
public function save($pFilename); public function save($pFilename, int $flags = 0): void;
/** /**
* Get use disk caching where possible? * Get use disk caching where possible?

View File

@ -115,12 +115,14 @@ class Ods extends BaseWriter
* *
* @param resource|string $pFilename * @param resource|string $pFilename
*/ */
public function save($pFilename): void public function save($pFilename, int $flags = 0): void
{ {
if (!$this->spreadSheet) { if (!$this->spreadSheet) {
throw new WriterException('PhpSpreadsheet object unassigned.'); throw new WriterException('PhpSpreadsheet object unassigned.');
} }
$this->processFlags($flags);
// garbage collect // garbage collect
$this->spreadSheet->garbageCollect(); $this->spreadSheet->garbageCollect();

View File

@ -22,7 +22,7 @@ class Dompdf extends Pdf
* *
* @param string $pFilename Name of the file to save as * @param string $pFilename Name of the file to save as
*/ */
public function save($pFilename): void public function save($pFilename, int $flags = 0): void
{ {
$fileHandle = parent::prepareForSave($pFilename); $fileHandle = parent::prepareForSave($pFilename);

View File

@ -24,7 +24,7 @@ class Mpdf extends Pdf
* *
* @param string $pFilename Name of the file to save as * @param string $pFilename Name of the file to save as
*/ */
public function save($pFilename): void public function save($pFilename, int $flags = 0): void
{ {
$fileHandle = parent::prepareForSave($pFilename); $fileHandle = parent::prepareForSave($pFilename);

View File

@ -38,7 +38,7 @@ class Tcpdf extends Pdf
* *
* @param string $pFilename Name of the file to save as * @param string $pFilename Name of the file to save as
*/ */
public function save($pFilename): void public function save($pFilename, int $flags = 0): void
{ {
$fileHandle = parent::prepareForSave($pFilename); $fileHandle = parent::prepareForSave($pFilename);

View File

@ -119,8 +119,10 @@ class Xls extends BaseWriter
* *
* @param resource|string $pFilename * @param resource|string $pFilename
*/ */
public function save($pFilename): void public function save($pFilename, int $flags = 0): void
{ {
$this->processFlags($flags);
// garbage collect // garbage collect
$this->spreadsheet->garbageCollect(); $this->spreadsheet->garbageCollect();

View File

@ -286,8 +286,10 @@ class Xlsx extends BaseWriter
* *
* @param resource|string $pFilename * @param resource|string $pFilename
*/ */
public function save($pFilename): void public function save($pFilename, int $flags = 0): void
{ {
$this->processFlags($flags);
// garbage collect // garbage collect
$this->pathNames = []; $this->pathNames = [];
$this->spreadSheet->garbageCollect(); $this->spreadSheet->garbageCollect();

View File

@ -4,6 +4,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Reader;
use PhpOffice\PhpSpreadsheet\Chart\DataSeries; use PhpOffice\PhpSpreadsheet\Chart\DataSeries;
use PhpOffice\PhpSpreadsheet\IOFactory; use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Reader\IReader;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
class SheetsXlsxChartTest extends TestCase class SheetsXlsxChartTest extends TestCase
@ -11,8 +12,8 @@ class SheetsXlsxChartTest extends TestCase
public function testLoadSheetsXlsxChart(): void public function testLoadSheetsXlsxChart(): void
{ {
$filename = 'tests/data/Reader/XLSX/sheetsChartsTest.xlsx'; $filename = 'tests/data/Reader/XLSX/sheetsChartsTest.xlsx';
$reader = IOFactory::createReader('Xlsx')->setIncludeCharts(true); $reader = IOFactory::createReader('Xlsx');
$spreadsheet = $reader->load($filename); $spreadsheet = $reader->load($filename, IReader::LOAD_WITH_CHARTS);
$worksheet = $spreadsheet->getActiveSheet(); $worksheet = $spreadsheet->getActiveSheet();
$charts = $worksheet->getChartCollection(); $charts = $worksheet->getChartCollection();