Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

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  }