mirror of
https://github.com/PHPOffice/PhpSpreadsheet.git
synced 2026-09-16 13:06:31 +00:00
8af9963350
Fix #4324. Serialization was explicity forbidden by PR #3199. This was in response to several issues, and concern that the Spreadsheet object contained non-serializable properties. This PR restores the ability to serialize a spreadsheet. Json serialization remains unsupported. Fix #1757, closed in Nov. 2023 but just reopened. At the time, Cell property `formulaAttributes` was stored as a SimpleXmlElement. Dynamic arrays PR #3962 defined that property as `null|array<string, string>` in the doc block. However, it left the formal Php type for the property as `mixed`. This PR changes the formal type to `?array`. Fix #1741, closed in Dec. 2020 but just reopened. Calculation property `referenceHelper` was defined as static, and, since static properties don't take part in serialization, this caused a problem after unserialization. There are at least 3 trivial ways to deal with this - make it an instance property, reinitialize it when unserialized using a wakeup method, or remove the property altogether. This PR uses the last of those 3. Calculation does have other static properties. Almost all of these deal with locale. So serialize/unserialize might wind up using a default locale when non-default is desired (but not necessarily required). If that is a problem for end-users, it will be a new one, and I will work on a solution if and when the time comes. Static property `returnArrayAsType` is potentially problematic. However, instance property `instanceArrayReturnType` is the preferred method of handling this, and using that will avoid any problems. Issue #932 also dealt with serialization. I do not have the wherewithal to investigate that issue. If it is not solved by this and the earlier PR's, I will have to leave it to others to re-raise it. Spreadsheet `copy` is now simplified to use serialize followed by unserialize. Formal tests are added. In addition, I have made a number of informal tests on very complicated spreadsheets, and it has performed correctly for all of them.
97 lines
3.3 KiB
PHP
97 lines
3.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace PhpOffice\PhpSpreadsheetTests;
|
|
|
|
use PhpOffice\PhpSpreadsheet\Exception as SpreadsheetException;
|
|
use PhpOffice\PhpSpreadsheet\Helper\Sample;
|
|
use PhpOffice\PhpSpreadsheet\NamedRange;
|
|
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
|
use PHPUnit\Framework\Attributes;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
class SpreadsheetSerializeTest extends TestCase
|
|
{
|
|
private ?Spreadsheet $spreadsheet = null;
|
|
|
|
protected function tearDown(): void
|
|
{
|
|
if ($this->spreadsheet !== null) {
|
|
$this->spreadsheet->disconnectWorksheets();
|
|
$this->spreadsheet = null;
|
|
}
|
|
}
|
|
|
|
public function testSerialize(): void
|
|
{
|
|
$this->spreadsheet = new Spreadsheet();
|
|
$sheet = $this->spreadsheet->getActiveSheet();
|
|
$sheet->getCell('A1')->setValue(10);
|
|
|
|
$serialized = serialize($this->spreadsheet);
|
|
$newSpreadsheet = unserialize($serialized);
|
|
self::assertInstanceOf(Spreadsheet::class, $newSpreadsheet);
|
|
self::assertNotSame($this->spreadsheet, $newSpreadsheet);
|
|
$newSheet = $newSpreadsheet->getActiveSheet();
|
|
self::assertSame(10, $newSheet->getCell('A1')->getValue());
|
|
$newSpreadsheet->disconnectWorksheets();
|
|
}
|
|
|
|
public function testNotJsonEncodable(): void
|
|
{
|
|
$this->spreadsheet = new Spreadsheet();
|
|
|
|
$this->expectException(SpreadsheetException::class);
|
|
$this->expectExceptionMessage('Spreadsheet objects cannot be json encoded');
|
|
json_encode($this->spreadsheet);
|
|
}
|
|
|
|
/**
|
|
* These tests are a bit weird.
|
|
* If prepareSerialize and readSerialize are run in the same
|
|
* process, the latter's assertions will always succeed.
|
|
* So to demonstrate that the
|
|
* problem is solved, they need to run in separate processes.
|
|
* But then they can't share the file name. So we need to send
|
|
* the file to a semi-hard-coded destination.
|
|
*/
|
|
private static function getTempFileName(): string
|
|
{
|
|
$helper = new Sample();
|
|
|
|
return $helper->getTemporaryFolder() . '/spreadsheet.serialize.test.txt';
|
|
}
|
|
|
|
public function testPrepareSerialize(): void
|
|
{
|
|
$this->spreadsheet = new Spreadsheet();
|
|
$sheet = $this->spreadsheet->getActiveSheet();
|
|
$this->spreadsheet->addNamedRange(new NamedRange('summedcells', $sheet, '$A$1:$A$5'));
|
|
$sheet->setCellValue('A1', 1);
|
|
$sheet->setCellValue('A2', 2);
|
|
$sheet->setCellValue('A3', 3);
|
|
$sheet->setCellValue('A4', 4);
|
|
$sheet->setCellValue('A5', 5);
|
|
$sheet->setCellValue('C1', '=SUM(summedcells)');
|
|
$ser = serialize($this->spreadsheet);
|
|
$this->spreadsheet->disconnectWorksheets();
|
|
$outputFileName = self::getTempFileName();
|
|
self::assertNotFalse(
|
|
file_put_contents($outputFileName, $ser)
|
|
);
|
|
}
|
|
|
|
#[Attributes\RunInSeparateProcess]
|
|
public function testReadSerialize(): void
|
|
{
|
|
$inputFileName = self::getTempFileName();
|
|
$ser = (string) file_get_contents($inputFileName);
|
|
unlink($inputFileName);
|
|
$this->spreadsheet = unserialize($ser);
|
|
$sheet = $this->spreadsheet->getActiveSheet();
|
|
self::assertSame('=SUM(summedcells)', $sheet->getCell('C1')->getValue());
|
|
self::assertSame(15, $sheet->getCell('C1')->getCalculatedValue());
|
|
}
|
|
}
|