Skip to content

Commit f34facf

Browse files
committed
add fix and test
1 parent 30c1a96 commit f34facf

File tree

2 files changed

+145
-4
lines changed

2 files changed

+145
-4
lines changed

src/PhpSpreadsheet/Writer/Xlsx/Drawing.php

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,9 @@ class Drawing extends WriterPart
2323
*/
2424
public function writeDrawings(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $worksheet, bool $includeCharts = false): string
2525
{
26-
// Check if we have stored drawing XML (pass-through for unsupported elements)
27-
$unparsedLoadedData = $worksheet->getParentOrThrow()->getUnparsedLoadedData();
28-
if (isset($unparsedLoadedData['sheets'][$worksheet->getCodeName()]['Drawings'])) {
29-
return reset($unparsedLoadedData['sheets'][$worksheet->getCodeName()]['Drawings']);
26+
// Try to use pass-through drawing XML if available
27+
if ($passThroughXml = $this->getPassThroughDrawingXml($worksheet)) {
28+
return $passThroughXml;
3029
}
3130

3231
// Create XML writer
@@ -598,4 +597,34 @@ private static function writeAttributeIf(XMLWriter $objWriter, ?bool $condition,
598597
$objWriter->writeAttribute($attr, $val);
599598
}
600599
}
600+
601+
/**
602+
* Get pass-through drawing XML if available and no drawings have been modified.
603+
*/
604+
private function getPassThroughDrawingXml(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $worksheet): ?string
605+
{
606+
// Only use pass-through if no drawings have been added/modified programmatically
607+
if (count($worksheet->getDrawingCollection()) !== 0) {
608+
return null;
609+
}
610+
611+
$unparsedLoadedData = $worksheet->getParentOrThrow()->getUnparsedLoadedData();
612+
if (!isset($unparsedLoadedData['sheets']) || !is_array($unparsedLoadedData['sheets'])) {
613+
return null;
614+
}
615+
616+
$codeName = $worksheet->getCodeName();
617+
if (!isset($unparsedLoadedData['sheets'][$codeName]) || !is_array($unparsedLoadedData['sheets'][$codeName])) {
618+
return null;
619+
}
620+
621+
$sheetData = $unparsedLoadedData['sheets'][$codeName];
622+
if (!isset($sheetData['Drawings']) || !is_array($sheetData['Drawings'])) {
623+
return null;
624+
}
625+
626+
$firstDrawing = reset($sheetData['Drawings']);
627+
628+
return is_string($firstDrawing) ? $firstDrawing : null;
629+
}
601630
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpOffice\PhpSpreadsheetTests\Writer\Xlsx;
6+
7+
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
8+
use PhpOffice\PhpSpreadsheet\Worksheet\Drawing;
9+
use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional;
10+
11+
class DrawingPassThroughTest extends AbstractFunctional
12+
{
13+
private const DIRECTORY = 'tests/data/Writer/XLSX/';
14+
private const TEMPLATE = self::DIRECTORY . 'issue.3843a.template.xlsx';
15+
private const IMAGE = self::DIRECTORY . 'issue.3843a.jpg';
16+
17+
/**
18+
* Test that unsupported drawing elements (shapes, textboxes) are preserved
19+
* when pass-through is enabled and no drawings are modified.
20+
*/
21+
public function testDrawingPassThroughPreservesUnsupportedElements(): void
22+
{
23+
// Load with pass-through enabled
24+
$reader = new XlsxReader();
25+
$reader->setEnableDrawingPassThrough(true);
26+
$spreadsheet = $reader->load(self::TEMPLATE);
27+
28+
$sheet = $spreadsheet->getActiveSheet();
29+
30+
// Verify that drawing collection is empty (unsupported elements not parsed)
31+
$drawings = $sheet->getDrawingCollection();
32+
self::assertCount(0, $drawings, 'Drawing collection should be empty for unsupported elements');
33+
34+
// Verify that unparsed data contains the original drawing XML
35+
$unparsedData = $spreadsheet->getUnparsedLoadedData();
36+
$codeName = $sheet->getCodeName();
37+
self::assertArrayHasKey('sheets', $unparsedData);
38+
self::assertIsArray($unparsedData['sheets']);
39+
self::assertArrayHasKey($codeName, $unparsedData['sheets']);
40+
self::assertIsArray($unparsedData['sheets'][$codeName]);
41+
self::assertArrayHasKey('Drawings', $unparsedData['sheets'][$codeName]);
42+
43+
// Save and reload
44+
$reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx');
45+
$spreadsheet->disconnectWorksheets();
46+
47+
// Verify that the drawing XML is still present after reload
48+
$reloadedUnparsedData = $reloadedSpreadsheet->getUnparsedLoadedData();
49+
$reloadedCodeName = $reloadedSpreadsheet->getActiveSheet()->getCodeName();
50+
self::assertArrayHasKey('sheets', $reloadedUnparsedData);
51+
self::assertIsArray($reloadedUnparsedData['sheets']);
52+
self::assertArrayHasKey($reloadedCodeName, $reloadedUnparsedData['sheets']);
53+
self::assertIsArray($reloadedUnparsedData['sheets'][$reloadedCodeName]);
54+
self::assertArrayHasKey('Drawings', $reloadedUnparsedData['sheets'][$reloadedCodeName]);
55+
56+
$reloadedSpreadsheet->disconnectWorksheets();
57+
}
58+
59+
/**
60+
* Test that pass-through is NOT used when drawings are added programmatically.
61+
*/
62+
public function testDrawingPassThroughDisabledWhenDrawingsAdded(): void
63+
{
64+
// Load without pass-through (doesn't matter since we add drawings)
65+
$reader = new XlsxReader();
66+
$reader->setEnableDrawingPassThrough(false);
67+
$spreadsheet = $reader->load(self::TEMPLATE);
68+
69+
$sheet = $spreadsheet->getActiveSheet();
70+
71+
// Add a drawing programmatically
72+
$drawing = new Drawing();
73+
$drawing->setName('TestDrawing');
74+
$drawing->setPath(self::IMAGE);
75+
$drawing->setCoordinates('A1');
76+
$drawing->setWorksheet($sheet);
77+
78+
// Verify that drawing collection now has 1 element
79+
$drawings = $sheet->getDrawingCollection();
80+
self::assertCount(1, $drawings, 'Drawing collection should contain the added drawing');
81+
82+
// Save and reload
83+
$reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx');
84+
$spreadsheet->disconnectWorksheets();
85+
86+
// Verify that the new drawing is present after reload
87+
$reloadedDrawings = $reloadedSpreadsheet->getActiveSheet()->getDrawingCollection();
88+
self::assertCount(1, $reloadedDrawings, 'Reloaded spreadsheet should contain the added drawing');
89+
$firstDrawing = $reloadedDrawings[0] ?? null;
90+
self::assertNotNull($firstDrawing);
91+
self::assertSame('TestDrawing', $firstDrawing->getName());
92+
93+
$reloadedSpreadsheet->disconnectWorksheets();
94+
}
95+
96+
public function testDrawingPassThroughGetterSetter(): void
97+
{
98+
$reader = new XlsxReader();
99+
100+
// Default should be false
101+
self::assertFalse($reader->getEnableDrawingPassThrough());
102+
103+
// Enable pass-through
104+
$result = $reader->setEnableDrawingPassThrough(true);
105+
self::assertInstanceOf(XlsxReader::class, $result);
106+
self::assertTrue($reader->getEnableDrawingPassThrough());
107+
108+
// Disable pass-through
109+
$reader->setEnableDrawingPassThrough(false);
110+
self::assertFalse($reader->getEnableDrawingPassThrough());
111+
}
112+
}

0 commit comments

Comments
 (0)