See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401] [Versions 401 and 402] [Versions 401 and 403]
1 <?php 2 3 namespace PhpOffice\PhpSpreadsheet\Writer\Xlsx; 4 5 use PhpOffice\PhpSpreadsheet\Cell\Coordinate; 6 use PhpOffice\PhpSpreadsheet\Comment; 7 use PhpOffice\PhpSpreadsheet\Shared\XMLWriter; 8 9 class Comments extends WriterPart 10 { 11 /** 12 * Write comments to XML format. 13 * 14 * @return string XML Output 15 */ 16 public function writeComments(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $worksheet) 17 { 18 // Create XML writer 19 $objWriter = null; 20 if ($this->getParentWriter()->getUseDiskCaching()) { 21 $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); 22 } else { 23 $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); 24 } 25 26 // XML header 27 $objWriter->startDocument('1.0', 'UTF-8', 'yes'); 28 29 // Comments cache 30 $comments = $worksheet->getComments(); 31 32 // Authors cache 33 $authors = []; 34 $authorId = 0; 35 foreach ($comments as $comment) { 36 if (!isset($authors[$comment->getAuthor()])) { 37 $authors[$comment->getAuthor()] = $authorId++; 38 } 39 } 40 41 // comments 42 $objWriter->startElement('comments'); 43 $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/spreadsheetml/2006/main'); 44 45 // Loop through authors 46 $objWriter->startElement('authors'); 47 foreach ($authors as $author => $index) { 48 $objWriter->writeElement('author', $author); 49 } 50 $objWriter->endElement(); 51 52 // Loop through comments 53 $objWriter->startElement('commentList'); 54 foreach ($comments as $key => $value) { 55 $this->writeComment($objWriter, $key, $value, $authors); 56 } 57 $objWriter->endElement(); 58 59 $objWriter->endElement(); 60 61 // Return 62 return $objWriter->getData(); 63 } 64 65 /** 66 * Write comment to XML format. 67 * 68 * @param string $cellReference Cell reference 69 * @param Comment $comment Comment 70 * @param array $authors Array of authors 71 */ 72 private function writeComment(XMLWriter $objWriter, $cellReference, Comment $comment, array $authors): void 73 { 74 // comment 75 $objWriter->startElement('comment'); 76 $objWriter->writeAttribute('ref', $cellReference); 77 $objWriter->writeAttribute('authorId', $authors[$comment->getAuthor()]); 78 79 // text 80 $objWriter->startElement('text'); 81 $this->getParentWriter()->getWriterPartstringtable()->writeRichText($objWriter, $comment->getText()); 82 $objWriter->endElement(); 83 84 $objWriter->endElement(); 85 } 86 87 /** 88 * Write VML comments to XML format. 89 * 90 * @return string XML Output 91 */ 92 public function writeVMLComments(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $worksheet) 93 { 94 // Create XML writer 95 $objWriter = null; 96 if ($this->getParentWriter()->getUseDiskCaching()) { 97 $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); 98 } else { 99 $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); 100 } 101 102 // XML header 103 $objWriter->startDocument('1.0', 'UTF-8', 'yes'); 104 105 // Comments cache 106 $comments = $worksheet->getComments(); 107 108 // xml 109 $objWriter->startElement('xml'); 110 $objWriter->writeAttribute('xmlns:v', 'urn:schemas-microsoft-com:vml'); 111 $objWriter->writeAttribute('xmlns:o', 'urn:schemas-microsoft-com:office:office'); 112 $objWriter->writeAttribute('xmlns:x', 'urn:schemas-microsoft-com:office:excel'); 113 114 // o:shapelayout 115 $objWriter->startElement('o:shapelayout'); 116 $objWriter->writeAttribute('v:ext', 'edit'); 117 118 // o:idmap 119 $objWriter->startElement('o:idmap'); 120 $objWriter->writeAttribute('v:ext', 'edit'); 121 $objWriter->writeAttribute('data', '1'); 122 $objWriter->endElement(); 123 124 $objWriter->endElement(); 125 126 // v:shapetype 127 $objWriter->startElement('v:shapetype'); 128 $objWriter->writeAttribute('id', '_x0000_t202'); 129 $objWriter->writeAttribute('coordsize', '21600,21600'); 130 $objWriter->writeAttribute('o:spt', '202'); 131 $objWriter->writeAttribute('path', 'm,l,21600r21600,l21600,xe'); 132 133 // v:stroke 134 $objWriter->startElement('v:stroke'); 135 $objWriter->writeAttribute('joinstyle', 'miter'); 136 $objWriter->endElement(); 137 138 // v:path 139 $objWriter->startElement('v:path'); 140 $objWriter->writeAttribute('gradientshapeok', 't'); 141 $objWriter->writeAttribute('o:connecttype', 'rect'); 142 $objWriter->endElement(); 143 144 $objWriter->endElement(); 145 146 // Loop through comments 147 foreach ($comments as $key => $value) { 148 $this->writeVMLComment($objWriter, $key, $value); 149 } 150 151 $objWriter->endElement(); 152 153 // Return 154 return $objWriter->getData(); 155 } 156 157 /** 158 * Write VML comment to XML format. 159 * 160 * @param string $cellReference Cell reference, eg: 'A1' 161 * @param Comment $comment Comment 162 */ 163 private function writeVMLComment(XMLWriter $objWriter, $cellReference, Comment $comment): void 164 { 165 // Metadata 166 [$column, $row] = Coordinate::indexesFromString($cellReference); 167 $id = 1024 + $column + $row; 168 $id = substr("$id", 0, 4); 169 170 // v:shape 171 $objWriter->startElement('v:shape'); 172 $objWriter->writeAttribute('id', '_x0000_s' . $id); 173 $objWriter->writeAttribute('type', '#_x0000_t202'); 174 $objWriter->writeAttribute('style', 'position:absolute;margin-left:' . $comment->getMarginLeft() . ';margin-top:' . $comment->getMarginTop() . ';width:' . $comment->getWidth() . ';height:' . $comment->getHeight() . ';z-index:1;visibility:' . ($comment->getVisible() ? 'visible' : 'hidden')); 175 $objWriter->writeAttribute('fillcolor', '#' . $comment->getFillColor()->getRGB()); 176 $objWriter->writeAttribute('o:insetmode', 'auto'); 177 178 // v:fill 179 $objWriter->startElement('v:fill'); 180 $objWriter->writeAttribute('color2', '#' . $comment->getFillColor()->getRGB()); 181 if ($comment->hasBackgroundImage()) { 182 $bgImage = $comment->getBackgroundImage(); 183 $objWriter->writeAttribute('o:relid', 'rId' . $bgImage->getImageIndex()); 184 $objWriter->writeAttribute('o:title', $bgImage->getName()); 185 $objWriter->writeAttribute('type', 'frame'); 186 } 187 $objWriter->endElement(); 188 189 // v:shadow 190 $objWriter->startElement('v:shadow'); 191 $objWriter->writeAttribute('on', 't'); 192 $objWriter->writeAttribute('color', 'black'); 193 $objWriter->writeAttribute('obscured', 't'); 194 $objWriter->endElement(); 195 196 // v:path 197 $objWriter->startElement('v:path'); 198 $objWriter->writeAttribute('o:connecttype', 'none'); 199 $objWriter->endElement(); 200 201 // v:textbox 202 $objWriter->startElement('v:textbox'); 203 $objWriter->writeAttribute('style', 'mso-direction-alt:auto'); 204 205 // div 206 $objWriter->startElement('div'); 207 $objWriter->writeAttribute('style', 'text-align:left'); 208 $objWriter->endElement(); 209 210 $objWriter->endElement(); 211 212 // x:ClientData 213 $objWriter->startElement('x:ClientData'); 214 $objWriter->writeAttribute('ObjectType', 'Note'); 215 216 // x:MoveWithCells 217 $objWriter->writeElement('x:MoveWithCells', ''); 218 219 // x:SizeWithCells 220 $objWriter->writeElement('x:SizeWithCells', ''); 221 222 // x:AutoFill 223 $objWriter->writeElement('x:AutoFill', 'False'); 224 225 // x:Row 226 $objWriter->writeElement('x:Row', (string) ($row - 1)); 227 228 // x:Column 229 $objWriter->writeElement('x:Column', (string) ($column - 1)); 230 231 $objWriter->endElement(); 232 233 $objWriter->endElement(); 234 } 235 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body