Skip to content

Commit cd509e7

Browse files
potofcoffeecodex
andauthored
Writer ODText: support native comments (#2922)
Serialize comments as native ODF annotations and cover each supported element writer. Co-authored-by: Codex <noreply@openai.com>
1 parent 440f6fc commit cd509e7

11 files changed

Lines changed: 199 additions & 3 deletions

File tree

docs/changes/1.x/1.5.0.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
- Added support for image alt text by [@jwoodhead](https://github.com/jwoodhead) in [#2873](https://github.com/PHPOffice/PHPWord/pull/2873)
77
- MPDF Writer : Make the mPDF temporary directory configurable via the `tempDir` PDF renderer option, defaulting to the system temporary directory by [@danielwirz](https://github.com/danielwirz) in [#2898](https://github.com/PHPOffice/PHPWord/pull/2898)
88
- GD extension is now optional by [@andrew-demb](https://github.com/andrew-demb) fixing [#2789] in [#2902](https://github.com/PHPOffice/PHPWord/pull/2902)
9+
- Writer ODText: Serialize comments as native ODF annotations by [@potofcoffee](https://github.com/potofcoffee) fixing [#2921](https://github.com/PHPOffice/PHPWord/issues/2921) in [#2922](https://github.com/PHPOffice/PHPWord/pull/2922)
910

1011
### Bug fixes
1112

docs/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ Below are the supported features for each file formats.
6262
| | Footer | :material-check: | | | | |
6363
| | Footnote | :material-check: | | | :material-check: | |
6464
| | Endnote | :material-check: | | | :material-check: | |
65-
| | Comments | :material-check: | | | | |
65+
| | Comments | :material-check: | :material-check: | | | |
6666
| **Graphs** | 2D basic graphs | :material-check: | | | | |
6767
| | 2D advanced graphs | | | | | |
6868
| | 3D graphs | :material-check: | | | | |

docs/usage/elements/comment.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,6 @@ $text->setCommentRangeStart($comment);
2121
$textrun->addText(' a test');
2222
```
2323

24-
If no end is set for a comment using the ``setCommentRangeEnd``, the comment will be ended automatically at the end of the element it is started on.
24+
If no end is set for a comment using the ``setCommentRangeEnd``, the comment will be ended automatically at the end of the element it is started on.
25+
26+
The ODF writer serializes comments as native ODF annotations, including the author, date, formatted content, and comment range.

src/PhpWord/Writer/ODText/Element/AbstractElement.php

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
namespace PhpOffice\PhpWord\Writer\ODText\Element;
2020

21+
use PhpOffice\PhpWord\Element\Comment;
2122
use PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement as Word2007AbstractElement;
2223

2324
/**
@@ -27,6 +28,53 @@
2728
*/
2829
abstract class AbstractElement extends Word2007AbstractElement
2930
{
31+
protected function writeCommentRangeStart(): void
32+
{
33+
if ($this->getElement()->getCommentsRangeStart() === null) {
34+
return;
35+
}
36+
37+
foreach ($this->getElement()->getCommentsRangeStart()->getItems() as $comment) {
38+
$this->getXmlWriter()->startElement('office:annotation');
39+
$this->getXmlWriter()->writeAttribute('office:name', $comment->getElementId());
40+
$this->getXmlWriter()->writeElement('dc:creator', $comment->getAuthor());
41+
if ($comment->getDate() !== null) {
42+
$this->getXmlWriter()->writeElement('dc:date', $comment->getDate()->format('Y-m-d\\TH:i:s\\Z'));
43+
}
44+
45+
$containerWriter = new Container($this->getXmlWriter(), $comment);
46+
$containerWriter->write();
47+
$this->getXmlWriter()->endElement();
48+
}
49+
}
50+
51+
protected function writeCommentRangeEnd(): void
52+
{
53+
$element = $this->getElement();
54+
$comments = $element->getCommentsRangeEnd();
55+
if ($comments !== null) {
56+
foreach ($comments->getItems() as $comment) {
57+
$this->writeCommentRangeEndElement($comment);
58+
}
59+
}
60+
61+
$comments = $element->getCommentsRangeStart();
62+
if ($comments !== null) {
63+
foreach ($comments->getItems() as $comment) {
64+
if ($comment->getEndElement() === null) {
65+
$this->writeCommentRangeEndElement($comment);
66+
}
67+
}
68+
}
69+
}
70+
71+
private function writeCommentRangeEndElement(Comment $comment): void
72+
{
73+
$this->getXmlWriter()->startElement('office:annotation-end');
74+
$this->getXmlWriter()->writeAttribute('office:name', $comment->getElementId());
75+
$this->getXmlWriter()->endElement();
76+
}
77+
3078
protected function replaceTabs($text, $xmlWriter): void
3179
{
3280
if (preg_match('/^ +/', $text, $matches)) {

src/PhpWord/Writer/ODText/Element/Image.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ public function write(): void
5151
$xmlWriter->writeAttribute('text:style-name', 'IM' . $mediaIndex);
5252
}
5353

54+
$this->writeCommentRangeStart();
5455
$xmlWriter->startElement('draw:frame');
5556
$xmlWriter->writeAttribute('draw:style-name', 'fr' . $mediaIndex);
5657
$xmlWriter->writeAttributeIf($this->withoutP, 'draw:text-style-name', 'IM' . $mediaIndex);
@@ -68,6 +69,7 @@ public function write(): void
6869
$xmlWriter->endElement(); // draw:image
6970

7071
$xmlWriter->endElement(); // draw:frame
72+
$this->writeCommentRangeEnd();
7173

7274
if (!$this->withoutP) {
7375
$xmlWriter->endElement(); // text:p

src/PhpWord/Writer/ODText/Element/Link.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,13 @@ public function write(): void
4040
$xmlWriter->startElement('text:p'); // text:p
4141
}
4242

43+
$this->writeCommentRangeStart();
4344
$xmlWriter->startElement('text:a');
4445
$xmlWriter->writeAttribute('xlink:type', 'simple');
4546
$xmlWriter->writeAttribute('xlink:href', ($element->isInternal() ? '#' : '') . $element->getSource());
4647
$this->writeText($element->getText());
4748
$xmlWriter->endElement(); // text:a
49+
$this->writeCommentRangeEnd();
4850

4951
if (!$this->withoutP) {
5052
$xmlWriter->endElement(); // text:p

src/PhpWord/Writer/ODText/Element/Ruby.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,12 @@ public function write(): void
5252
}
5353
}
5454

55+
$this->writeCommentRangeStart();
5556
$this->replaceTabs($element->getBaseTextRun()->getText(), $xmlWriter);
5657
$this->writeText(' (');
5758
$this->replaceTabs($element->getRubyTextRun()->getText(), $xmlWriter);
5859
$this->writeText(')');
60+
$this->writeCommentRangeEnd();
5961

6062
if (!$this->withoutP) {
6163
$xmlWriter->endElement(); // text:p

src/PhpWord/Writer/ODText/Element/Text.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ public function write(): void
5353
if (!$this->withoutP) {
5454
$xmlWriter->startElement('text:p'); // text:p
5555
}
56+
$this->writeCommentRangeStart();
5657
if ($element->getTrackChange() != null && $element->getTrackChange()->getChangeType() == TrackChange::DELETED) {
5758
$xmlWriter->startElement('text:change');
5859
$xmlWriter->writeAttribute('text:change-id', $element->getTrackChange()->getElementId());
@@ -84,6 +85,7 @@ public function write(): void
8485
$xmlWriter->endElement();
8586
}
8687
}
88+
$this->writeCommentRangeEnd();
8789
if (!$this->withoutP) {
8890
$xmlWriter->endElement(); // text:p
8991
}

src/PhpWord/Writer/ODText/Element/TextRun.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,12 @@ public function write(): void
4040
$pStyle = 'Normal';
4141
}
4242
$xmlWriter->writeAttribute('text:style-name', $pStyle);
43+
$this->writeCommentRangeStart();
4344

4445
$containerWriter = new Container($xmlWriter, $element);
4546
$containerWriter->write();
4647

48+
$this->writeCommentRangeEnd();
4749
$xmlWriter->endElement();
4850
}
4951
}

src/PhpWord/Writer/ODText/Element/Title.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ public function write(): void
5353
} else {
5454
$xmlWriter->writeAttribute('text:style-name', 'Title');
5555
}
56+
$this->writeCommentRangeStart();
5657
$text = $element->getText();
5758
if (is_string($text)) {
5859
$this->writeText($text);
@@ -61,6 +62,7 @@ public function write(): void
6162
$containerWriter = new Container($xmlWriter, $text);
6263
$containerWriter->write();
6364
}
65+
$this->writeCommentRangeEnd();
6466
$xmlWriter->endElement(); // text:span
6567
$xmlWriter->endElement(); // text:h
6668
}

0 commit comments

Comments
 (0)