Skip to content

Commit 5a35822

Browse files
committed
WIP Limited Support for Form Controls (ListBox, Button, etc.)
Fix PHPOffice#2396. Fix PHPOffice#1770. I am starting this out in draft status, and will probably leave it that way for some time. I'm not sure where we want to go with this. It fixes some problems, but in a limited manner, and creates some others. I'm not sure the pain of the others is balanced considering the limitations of the fix. If enough interest is generated as a result of this ticket being out there, we can proceed; if not, it probably isn't worth it. This fix allows form control elements to be read in and written out. It does not allow you to add such elements, nor even to locate them or determine their properties (so you can't modify or delete them). Although it handles reading and writing of sheets containing both form controls and comments, it will probably create a corrupt spreadsheet if you try adding a new comment to a sheet with form controls - probably quite difficult to solve. Cloning the sheet probably won't work either - probably easier than the other. It is conceivable that we want to add a new property to the Xlsx Reader which turns the reading of form elements on or off (default=off), so that negative effects will be limited to those who have explictly opted in. The change in its current form does not implement such a property. Because of its limitations, the change isn't really testable. As in some other recent installs, I have added a sample to demonstrate that it works correctly.
1 parent 443175e commit 5a35822

File tree

7 files changed

+47
-6
lines changed

7 files changed

+47
-6
lines changed
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
use PhpOffice\PhpSpreadsheet\IOFactory;
4+
5+
require __DIR__ . '/../Header.php';
6+
7+
$helper->log('Start');
8+
9+
$inputFileType = 'Xlsx';
10+
$inputFileName = __DIR__ . '/sampleData/formscomments.xlsx';
11+
12+
$helper->log('Loading file ' . $inputFileName . ' using IOFactory with a defined reader type of ' . $inputFileType);
13+
$reader = IOFactory::createReader($inputFileType);
14+
$helper->log('Loading all WorkSheets');
15+
$reader->setLoadAllSheets();
16+
$spreadsheet = $reader->load($inputFileName);
17+
18+
// Save
19+
$helper->write($spreadsheet, __FILE__, ['Xlsx']);
20+
$spreadsheet->disconnectWorksheets();
21+
22+
$helper->log('end');

samples/Reader/22_Reader_issue1767.php

+1
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,6 @@
1717

1818
// Save
1919
$helper->write($spreadsheet, __FILE__);
20+
$spreadsheet->disconnectWorksheets();
2021

2122
$helper->log('end');
23.6 KB
Binary file not shown.

src/PhpSpreadsheet/Reader/Xlsx.php

+10
Original file line numberDiff line numberDiff line change
@@ -969,6 +969,7 @@ public function load(string $filename, int $flags = 0): Spreadsheet
969969

970970
// later we will remove from it real vmlComments
971971
$unparsedVmlDrawings = $vmlComments;
972+
$vmlDrawingContents = [];
972973

973974
// Loop through VML comments
974975
foreach ($vmlComments as $relName => $relPath) {
@@ -987,6 +988,7 @@ public function load(string $filename, int $flags = 0): Spreadsheet
987988
// Locate VML drawings image relations
988989
$drowingImages = [];
989990
$VMLDrawingsRelations = dirname($relPath) . '/_rels/' . basename($relPath) . '.rels';
991+
$vmlDrawingContents[$relName] = $this->securityScanner->scan($this->getFromZipArchive($zip, $relPath));
990992
if ($zip->locateName($VMLDrawingsRelations)) {
991993
$relsVMLDrawing = $this->loadZip($VMLDrawingsRelations, Namespaces::RELATIONSHIPS);
992994
foreach ($relsVMLDrawing->Relationship as $elex) {
@@ -1391,6 +1393,14 @@ public function load(string $filename, int $flags = 0): Spreadsheet
13911393
}
13921394
}
13931395
}
1396+
if ($xmlSheet->legacyDrawing && !$this->readDataOnly) {
1397+
foreach ($xmlSheet->legacyDrawing as $drawing) {
1398+
$drawingRelId = (string) self::getArrayItem(self::getAttributes($drawing, $xmlNamespaceBase), 'id');
1399+
if (isset($vmlDrawingContents[$drawingRelId])) {
1400+
$unparsedLoadedData['sheets'][$docSheet->getCodeName()]['legacyDrawing'] = $vmlDrawingContents[$drawingRelId];
1401+
}
1402+
}
1403+
}
13941404

13951405
// unparsed drawing AlternateContent
13961406
$xmlAltDrawing = $this->loadZip($fileDrawing, Namespaces::COMPATIBILITY);

src/PhpSpreadsheet/Writer/Xlsx.php

+9-4
Original file line numberDiff line numberDiff line change
@@ -439,14 +439,17 @@ public function save($filename, int $flags = 0): void
439439
}
440440

441441
// Add comment relationship parts
442-
if (count($this->spreadSheet->getSheet($i)->getComments()) > 0) {
442+
$legacy = $unparsedLoadedData['sheets'][$this->spreadSheet->getSheet($i)->getCodeName()]['legacyDrawing'] ?? null;
443+
if (count($this->spreadSheet->getSheet($i)->getComments()) > 0 || $legacy !== null) {
443444
// VML Comments relationships
444445
$zipContent['xl/drawings/_rels/vmlDrawing' . ($i + 1) . '.vml.rels'] = $this->getWriterPartRels()->writeVMLDrawingRelationships($this->spreadSheet->getSheet($i));
445446

446447
// VML Comments
447-
$zipContent['xl/drawings/vmlDrawing' . ($i + 1) . '.vml'] = $this->getWriterPartComments()->writeVMLComments($this->spreadSheet->getSheet($i));
448+
$zipContent['xl/drawings/vmlDrawing' . ($i + 1) . '.vml'] = $legacy ?? $this->getWriterPartComments()->writeVMLComments($this->spreadSheet->getSheet($i));
449+
}
448450

449-
// Comments
451+
// Comments
452+
if (count($this->spreadSheet->getSheet($i)->getComments()) > 0) {
450453
$zipContent['xl/comments' . ($i + 1) . '.xml'] = $this->getWriterPartComments()->writeComments($this->spreadSheet->getSheet($i));
451454

452455
// Media
@@ -461,7 +464,9 @@ public function save($filename, int $flags = 0): void
461464
// Add unparsed relationship parts
462465
if (isset($unparsedLoadedData['sheets'][$sheetCodeName]['vmlDrawings'])) {
463466
foreach ($unparsedLoadedData['sheets'][$sheetCodeName]['vmlDrawings'] as $vmlDrawing) {
464-
$zipContent[$vmlDrawing['filePath']] = $vmlDrawing['content'];
467+
if (!isset($zipContent[$vmlDrawing['filePath']])) {
468+
$zipContent[$vmlDrawing['filePath']] = $vmlDrawing['content'];
469+
}
465470
}
466471
}
467472

src/PhpSpreadsheet/Writer/Xlsx/Rels.php

+3-1
Original file line numberDiff line numberDiff line change
@@ -236,14 +236,16 @@ public function writeWorksheetRelationships(\PhpOffice\PhpSpreadsheet\Worksheet\
236236

237237
// Write comments relationship?
238238
$i = 1;
239-
if (count($worksheet->getComments()) > 0) {
239+
if (count($worksheet->getComments()) > 0 || isset($unparsedLoadedData['sheets'][$worksheet->getCodeName()]['legacyDrawing'])) {
240240
$this->writeRelationship(
241241
$objWriter,
242242
'_comments_vml' . $i,
243243
'http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing',
244244
'../drawings/vmlDrawing' . $worksheetId . '.vml'
245245
);
246+
}
246247

248+
if (count($worksheet->getComments()) > 0) {
247249
$this->writeRelationship(
248250
$objWriter,
249251
'_comments' . $i,

src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -1317,7 +1317,8 @@ private function writeDrawings(XMLWriter $objWriter, PhpspreadsheetWorksheet $wo
13171317
private function writeLegacyDrawing(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void
13181318
{
13191319
// If sheet contains comments, add the relationships
1320-
if (count($worksheet->getComments()) > 0) {
1320+
$unparsedLoadedData = $worksheet->getParent()->getUnparsedLoadedData();
1321+
if (count($worksheet->getComments()) > 0 || isset($unparsedLoadedData['sheets'][$worksheet->getCodeName()]['legacyDrawing'])) {
13211322
$objWriter->startElement('legacyDrawing');
13221323
$objWriter->writeAttribute('r:id', 'rId_comments_vml1');
13231324
$objWriter->endElement();

0 commit comments

Comments
 (0)