diff --git a/CHANGELOG.md b/CHANGELOG.md index ba74ff7ae4..82289a0bbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### 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) ### Changed diff --git a/docs/topics/reading-and-writing-to-file.md b/docs/topics/reading-and-writing-to-file.md index e5c2afd9b8..cb1e0e77b9 100644 --- a/docs/topics/reading-and-writing-to-file.md +++ b/docs/topics/reading-and-writing-to-file.md @@ -1,8 +1,7 @@ # Reading and writing to file As you already know from the [architecture](./architecture.md#readers-and-writers), -reading and writing to a -persisted storage is not possible using the base PhpSpreadsheet classes. +reading and writing to a persisted storage is not possible using the base PhpSpreadsheet classes. For this purpose, PhpSpreadsheet provides readers and writers, which are implementations of `\PhpOffice\PhpSpreadsheet\Reader\IReader` and `\PhpOffice\PhpSpreadsheet\Writer\IWriter`. @@ -892,8 +891,7 @@ class My_Custom_TCPDF_Writer extends \PhpOffice\PhpSpreadsheet\Writer\Pdf\Tcpdf #### Writing a spreadsheet -Once you have identified the Renderer that you wish to use for PDF -generation, you can write a .pdf file using the following code: +Once you have identified the Renderer that you wish to use for PDF generation, you can write a .pdf file using the following code: ```php $writer = new \PhpOffice\PhpSpreadsheet\Writer\Pdf\Mpdf($spreadsheet); @@ -905,8 +903,7 @@ first worksheet by default. #### Write all worksheets -PDF files can contain one or more worksheets. If you want to write all -sheets into a single PDF file, use the following code: +PDF files can contain one or more worksheets. If you want to write all sheets into a single PDF file, use the following code: ```php $writer->writeAllSheets(); @@ -1020,3 +1017,64 @@ $spreadhseet = $reader->loadFromString($secondHtmlString, $spreadsheet); $writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, '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 | + diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 4ee0a9efd3..4d4f719336 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -6245,11 +6245,6 @@ parameters: count: 1 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\\.$#" count: 1 diff --git a/src/PhpSpreadsheet/IOFactory.php b/src/PhpSpreadsheet/IOFactory.php index 06006edc2e..6ed1fd82f2 100644 --- a/src/PhpSpreadsheet/IOFactory.php +++ b/src/PhpSpreadsheet/IOFactory.php @@ -75,15 +75,15 @@ public static function createReader($readerType) /** * 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 */ - 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); } /** diff --git a/src/PhpSpreadsheet/Reader/BaseReader.php b/src/PhpSpreadsheet/Reader/BaseReader.php index 8034813239..1f18484ff7 100644 --- a/src/PhpSpreadsheet/Reader/BaseReader.php +++ b/src/PhpSpreadsheet/Reader/BaseReader.php @@ -137,6 +137,13 @@ public function getSecurityScanner() return $this->securityScanner; } + protected function processFlags(int $flags): void + { + if (((bool) ($flags & self::LOAD_WITH_CHARTS)) === true) { + $this->setIncludeCharts(true); + } + } + /** * Open file for reading. * diff --git a/src/PhpSpreadsheet/Reader/Csv.php b/src/PhpSpreadsheet/Reader/Csv.php index b7bc0d49b4..f06de635af 100644 --- a/src/PhpSpreadsheet/Reader/Csv.php +++ b/src/PhpSpreadsheet/Reader/Csv.php @@ -236,12 +236,12 @@ public function listWorksheetInfo(string $pFilename): array /** * Loads Spreadsheet from file. * - * @param string $pFilename - * * @return Spreadsheet */ - public function load($pFilename) + public function load(string $pFilename, int $flags = 0) { + $this->processFlags($flags); + // Create new Spreadsheet $spreadsheet = new Spreadsheet(); diff --git a/src/PhpSpreadsheet/Reader/Gnumeric.php b/src/PhpSpreadsheet/Reader/Gnumeric.php index 85bae6f8c8..64c27366dd 100644 --- a/src/PhpSpreadsheet/Reader/Gnumeric.php +++ b/src/PhpSpreadsheet/Reader/Gnumeric.php @@ -235,12 +235,12 @@ private static function testSimpleXml($value): SimpleXMLElement /** * Loads Spreadsheet from file. * - * @param string $pFilename - * * @return Spreadsheet */ - public function load($pFilename) + public function load(string $pFilename, int $flags = 0) { + $this->processFlags($flags); + // Create new Spreadsheet $spreadsheet = new Spreadsheet(); $spreadsheet->removeSheetByIndex(0); diff --git a/src/PhpSpreadsheet/Reader/Html.php b/src/PhpSpreadsheet/Reader/Html.php index b7faac878c..6e6155c230 100644 --- a/src/PhpSpreadsheet/Reader/Html.php +++ b/src/PhpSpreadsheet/Reader/Html.php @@ -204,12 +204,12 @@ private static function containsTags($data) /** * Loads Spreadsheet from file. * - * @param string $pFilename - * * @return Spreadsheet */ - public function load($pFilename) + public function load(string $pFilename, int $flags = 0) { + $this->processFlags($flags); + // Create new Spreadsheet $spreadsheet = new Spreadsheet(); diff --git a/src/PhpSpreadsheet/Reader/IReader.php b/src/PhpSpreadsheet/Reader/IReader.php index a8bd360659..6a57f4a059 100644 --- a/src/PhpSpreadsheet/Reader/IReader.php +++ b/src/PhpSpreadsheet/Reader/IReader.php @@ -4,6 +4,8 @@ interface IReader { + public const LOAD_WITH_CHARTS = 1; + /** * IReader constructor. */ @@ -125,9 +127,7 @@ public function setReadFilter(IReadFilter $pValue); /** * Loads PhpSpreadsheet from file. * - * @param string $pFilename - * * @return \PhpOffice\PhpSpreadsheet\Spreadsheet */ - public function load($pFilename); + public function load(string $pFilename, int $flags = 0); } diff --git a/src/PhpSpreadsheet/Reader/Ods.php b/src/PhpSpreadsheet/Reader/Ods.php index 760aa10d08..b39fffedf4 100644 --- a/src/PhpSpreadsheet/Reader/Ods.php +++ b/src/PhpSpreadsheet/Reader/Ods.php @@ -231,12 +231,12 @@ public function listWorksheetInfo($pFilename) /** * Loads PhpSpreadsheet from file. * - * @param string $pFilename - * * @return Spreadsheet */ - public function load($pFilename) + public function load(string $pFilename, int $flags = 0) { + $this->processFlags($flags); + // Create new Spreadsheet $spreadsheet = new Spreadsheet(); diff --git a/src/PhpSpreadsheet/Reader/Slk.php b/src/PhpSpreadsheet/Reader/Slk.php index c7b6fc82d0..b58fdcba9c 100644 --- a/src/PhpSpreadsheet/Reader/Slk.php +++ b/src/PhpSpreadsheet/Reader/Slk.php @@ -197,12 +197,12 @@ public function listWorksheetInfo($pFilename) /** * Loads PhpSpreadsheet from file. * - * @param string $pFilename - * * @return Spreadsheet */ - public function load($pFilename) + public function load(string $pFilename, int $flags = 0) { + $this->processFlags($flags); + // Create new Spreadsheet $spreadsheet = new Spreadsheet(); diff --git a/src/PhpSpreadsheet/Reader/Xls.php b/src/PhpSpreadsheet/Reader/Xls.php index bfdd558304..a8c097f7e5 100644 --- a/src/PhpSpreadsheet/Reader/Xls.php +++ b/src/PhpSpreadsheet/Reader/Xls.php @@ -622,12 +622,12 @@ public function listWorksheetInfo($pFilename) /** * Loads PhpSpreadsheet from file. * - * @param string $pFilename - * * @return Spreadsheet */ - public function load($pFilename) + public function load(string $pFilename, int $flags = 0) { + $this->processFlags($flags); + // Read the OLE file $this->loadOLE($pFilename); diff --git a/src/PhpSpreadsheet/Reader/Xlsx.php b/src/PhpSpreadsheet/Reader/Xlsx.php index 82e4e82d02..8adb3bc8cf 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx.php +++ b/src/PhpSpreadsheet/Reader/Xlsx.php @@ -310,13 +310,12 @@ private function getFromZipArchive(ZipArchive $archive, $fileName = '') /** * Loads Spreadsheet from file. * - * @param string $pFilename - * * @return Spreadsheet */ - public function load($pFilename) + public function load(string $pFilename, int $flags = 0) { File::assertFile($pFilename); + $this->processFlags($flags); // Initialisations $excel = new Spreadsheet(); diff --git a/src/PhpSpreadsheet/Reader/Xml.php b/src/PhpSpreadsheet/Reader/Xml.php index 4ef4efe7b5..f63bc79870 100644 --- a/src/PhpSpreadsheet/Reader/Xml.php +++ b/src/PhpSpreadsheet/Reader/Xml.php @@ -236,18 +236,18 @@ public function listWorksheetInfo($filename) /** * Loads Spreadsheet from file. * - * @param string $filename - * * @return Spreadsheet */ - public function load($filename) + public function load(string $pFilename, int $flags = 0) { + $this->processFlags($flags); + // Create new Spreadsheet $spreadsheet = new Spreadsheet(); $spreadsheet->removeSheetByIndex(0); // Load into this instance - return $this->loadIntoExisting($filename, $spreadsheet); + return $this->loadIntoExisting($pFilename, $spreadsheet); } /** diff --git a/src/PhpSpreadsheet/Writer/BaseWriter.php b/src/PhpSpreadsheet/Writer/BaseWriter.php index afda5c433e..3b03cfc37e 100644 --- a/src/PhpSpreadsheet/Writer/BaseWriter.php +++ b/src/PhpSpreadsheet/Writer/BaseWriter.php @@ -6,7 +6,7 @@ abstract class BaseWriter implements IWriter { /** * 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 */ @@ -94,6 +94,13 @@ public function getDiskCachingDirectory() return $this->diskCachingDirectory; } + protected function processFlags(int $flags): void + { + if (((bool) ($flags & self::SAVE_WITH_CHARTS)) === true) { + $this->setIncludeCharts(true); + } + } + /** * Open file handle. * diff --git a/src/PhpSpreadsheet/Writer/Csv.php b/src/PhpSpreadsheet/Writer/Csv.php index 188a83a803..79e8e5f1e3 100644 --- a/src/PhpSpreadsheet/Writer/Csv.php +++ b/src/PhpSpreadsheet/Writer/Csv.php @@ -86,8 +86,10 @@ public function __construct(Spreadsheet $spreadsheet) * * @param resource|string $pFilename */ - public function save($pFilename): void + public function save($pFilename, int $flags = 0): void { + $this->processFlags($flags); + // Fetch sheet $sheet = $this->spreadsheet->getSheet($this->sheetIndex); diff --git a/src/PhpSpreadsheet/Writer/Html.php b/src/PhpSpreadsheet/Writer/Html.php index b694d4ef9d..76c5e72287 100644 --- a/src/PhpSpreadsheet/Writer/Html.php +++ b/src/PhpSpreadsheet/Writer/Html.php @@ -153,8 +153,10 @@ public function __construct(Spreadsheet $spreadsheet) * * @param resource|string $pFilename */ - public function save($pFilename): void + public function save($pFilename, int $flags = 0): void { + $this->processFlags($flags); + // Open file $this->openFileHandle($pFilename); diff --git a/src/PhpSpreadsheet/Writer/IWriter.php b/src/PhpSpreadsheet/Writer/IWriter.php index 5129d65583..a0361f7421 100644 --- a/src/PhpSpreadsheet/Writer/IWriter.php +++ b/src/PhpSpreadsheet/Writer/IWriter.php @@ -6,6 +6,8 @@ interface IWriter { + public const SAVE_WITH_CHARTS = 1; + /** * IWriter constructor. */ @@ -59,7 +61,7 @@ public function setPreCalculateFormulas($pValue); * * @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? diff --git a/src/PhpSpreadsheet/Writer/Ods.php b/src/PhpSpreadsheet/Writer/Ods.php index f07ade9a58..141a411950 100644 --- a/src/PhpSpreadsheet/Writer/Ods.php +++ b/src/PhpSpreadsheet/Writer/Ods.php @@ -115,12 +115,14 @@ public function getWriterPartThumbnails(): Thumbnails * * @param resource|string $pFilename */ - public function save($pFilename): void + public function save($pFilename, int $flags = 0): void { if (!$this->spreadSheet) { throw new WriterException('PhpSpreadsheet object unassigned.'); } + $this->processFlags($flags); + // garbage collect $this->spreadSheet->garbageCollect(); diff --git a/src/PhpSpreadsheet/Writer/Pdf/Dompdf.php b/src/PhpSpreadsheet/Writer/Pdf/Dompdf.php index 87e8eeb5f6..313b34e805 100644 --- a/src/PhpSpreadsheet/Writer/Pdf/Dompdf.php +++ b/src/PhpSpreadsheet/Writer/Pdf/Dompdf.php @@ -22,7 +22,7 @@ protected function createExternalWriterInstance() * * @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); diff --git a/src/PhpSpreadsheet/Writer/Pdf/Mpdf.php b/src/PhpSpreadsheet/Writer/Pdf/Mpdf.php index 56ac693066..0db164b63e 100644 --- a/src/PhpSpreadsheet/Writer/Pdf/Mpdf.php +++ b/src/PhpSpreadsheet/Writer/Pdf/Mpdf.php @@ -24,7 +24,7 @@ protected function createExternalWriterInstance($config) * * @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); diff --git a/src/PhpSpreadsheet/Writer/Pdf/Tcpdf.php b/src/PhpSpreadsheet/Writer/Pdf/Tcpdf.php index 56e917e3f2..76f983a045 100644 --- a/src/PhpSpreadsheet/Writer/Pdf/Tcpdf.php +++ b/src/PhpSpreadsheet/Writer/Pdf/Tcpdf.php @@ -38,7 +38,7 @@ protected function createExternalWriterInstance($orientation, $unit, $paperSize) * * @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); diff --git a/src/PhpSpreadsheet/Writer/Xls.php b/src/PhpSpreadsheet/Writer/Xls.php index 624dc41419..fa7827551f 100644 --- a/src/PhpSpreadsheet/Writer/Xls.php +++ b/src/PhpSpreadsheet/Writer/Xls.php @@ -119,8 +119,10 @@ public function __construct(Spreadsheet $spreadsheet) * * @param resource|string $pFilename */ - public function save($pFilename): void + public function save($pFilename, int $flags = 0): void { + $this->processFlags($flags); + // garbage collect $this->spreadsheet->garbageCollect(); diff --git a/src/PhpSpreadsheet/Writer/Xlsx.php b/src/PhpSpreadsheet/Writer/Xlsx.php index 27ceb55901..6f43989fd2 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx.php +++ b/src/PhpSpreadsheet/Writer/Xlsx.php @@ -286,8 +286,10 @@ public function getWriterPartWorksheet(): Worksheet * * @param resource|string $pFilename */ - public function save($pFilename): void + public function save($pFilename, int $flags = 0): void { + $this->processFlags($flags); + // garbage collect $this->pathNames = []; $this->spreadSheet->garbageCollect(); diff --git a/tests/PhpSpreadsheetTests/Reader/SheetsXlsxChartTest.php b/tests/PhpSpreadsheetTests/Reader/SheetsXlsxChartTest.php index c4dc328d2d..9c478c4a7e 100644 --- a/tests/PhpSpreadsheetTests/Reader/SheetsXlsxChartTest.php +++ b/tests/PhpSpreadsheetTests/Reader/SheetsXlsxChartTest.php @@ -4,6 +4,7 @@ use PhpOffice\PhpSpreadsheet\Chart\DataSeries; use PhpOffice\PhpSpreadsheet\IOFactory; +use PhpOffice\PhpSpreadsheet\Reader\IReader; use PHPUnit\Framework\TestCase; class SheetsXlsxChartTest extends TestCase @@ -11,8 +12,8 @@ class SheetsXlsxChartTest extends TestCase public function testLoadSheetsXlsxChart(): void { $filename = 'tests/data/Reader/XLSX/sheetsChartsTest.xlsx'; - $reader = IOFactory::createReader('Xlsx')->setIncludeCharts(true); - $spreadsheet = $reader->load($filename); + $reader = IOFactory::createReader('Xlsx'); + $spreadsheet = $reader->load($filename, IReader::LOAD_WITH_CHARTS); $worksheet = $spreadsheet->getActiveSheet(); $charts = $worksheet->getChartCollection();