Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.2.x will end 22 April 2024 (12 months).
  • Bug fixes for security issues in 4.2.x will end 7 October 2024 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.1.x is supported too.

Differences Between: [Versions 310 and 402] [Versions 311 and 402] [Versions 39 and 402] [Versions 400 and 402] [Versions 401 and 402]

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