Skip to content

Commit 84374a5

Browse files
shaedrichProgi1984
authored andcommitted
Add support for comments to reader
1 parent d94b00c commit 84374a5

File tree

4 files changed

+225
-4
lines changed

4 files changed

+225
-4
lines changed

src/PhpWord/PhpWord.php

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
namespace PhpOffice\PhpWord;
1919

2020
use BadMethodCallException;
21+
use InvalidArgumentException;
22+
use PhpOffice\PhpWord\Element\AbstractElement;
2123
use PhpOffice\PhpWord\Element\Section;
2224
use PhpOffice\PhpWord\Exception\Exception;
2325

@@ -68,7 +70,14 @@ class PhpWord
6870
private $metadata = [];
6971

7072
/**
71-
* Create new instance.
73+
* Comment reference cache
74+
*
75+
* @var array
76+
*/
77+
private $commentReferenceCache = [];
78+
79+
/**
80+
* Create new instance
7281
*
7382
* Collections are created dynamically
7483
*/
@@ -325,4 +334,88 @@ public function save($filename, $format = 'Word2007', $download = false)
325334

326335
return true;
327336
}
337+
338+
/**
339+
* Create new section
340+
*
341+
* @deprecated 0.10.0
342+
*
343+
* @param array $settings
344+
*
345+
* @return \PhpOffice\PhpWord\Element\Section
346+
*
347+
* @codeCoverageIgnore
348+
*/
349+
public function createSection($settings = null)
350+
{
351+
return $this->addSection($settings);
352+
}
353+
354+
/**
355+
* Get document properties object
356+
*
357+
* @deprecated 0.12.0
358+
*
359+
* @return \PhpOffice\PhpWord\Metadata\DocInfo
360+
*
361+
* @codeCoverageIgnore
362+
*/
363+
public function getDocumentProperties()
364+
{
365+
return $this->getDocInfo();
366+
}
367+
368+
/**
369+
* Set document properties object
370+
*
371+
* @deprecated 0.12.0
372+
*
373+
* @param \PhpOffice\PhpWord\Metadata\DocInfo $documentProperties
374+
*
375+
* @return self
376+
*
377+
* @codeCoverageIgnore
378+
*/
379+
public function setDocumentProperties($documentProperties)
380+
{
381+
$this->metadata['Document'] = $documentProperties;
382+
383+
return $this;
384+
}
385+
386+
/**
387+
* Cache commentReference (as well as commentRangeStart and commentRangeEnd) for later use
388+
*
389+
* @param 'start'|'end' $type
390+
* @param string $id,
391+
* @param $element
392+
*
393+
* @return self
394+
*/
395+
public function cacheCommentReference(string $type, string $id, AbstractElement $element)
396+
{
397+
//dump('cacheCommentReference', func_get_args(), array_key_exists($id, $this->commentReferenceCache));
398+
if (!in_array($type, [ 'start', 'end' ])) {
399+
throw new InvalidArgumentException('Type must be "start" or "end"');
400+
}
401+
402+
if (!array_key_exists($id, $this->commentReferenceCache)) {
403+
$this->commentReferenceCache[$id] = (object)[
404+
"start" => null,
405+
"end" => null
406+
];
407+
}
408+
$this->commentReferenceCache[$id]->{$type} = $element;
409+
410+
return $this;
411+
}
412+
413+
public function getCommentReference(string $id)
414+
{
415+
if (!array_key_exists($id, $this->commentReferenceCache)) {
416+
//dd($this->commentReferenceCache);
417+
throw new InvalidArgumentException('Comment with id '.$id.' isn\'t referenced in document');
418+
}
419+
return $this->commentReferenceCache[$id];
420+
}
328421
}

src/PhpWord/Reader/Word2007/AbstractPart.php

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,11 @@ protected function readParagraph(XMLReader $xmlReader, DOMElement $domNode, $par
126126
// Paragraph style
127127
$paragraphStyle = null;
128128
$headingDepth = null;
129+
if ($xmlReader->elementExists('w:commentReference', $domNode) || $xmlReader->elementExists('w:commentRangeStart', $domNode) || $xmlReader->elementExists('w:commentRangeEnd', $domNode)) {
130+
$nodes = $xmlReader->getElements('w:commentReference|w:commentRangeStart|w:commentRangeEnd', $domNode);
131+
$node = current(iterator_to_array($nodes));
132+
$id = $node->attributes->getNamedItem('id')->value;
133+
}
129134
if ($xmlReader->elementExists('w:pPr', $domNode)) {
130135
$paragraphStyle = $this->readParagraphStyle($xmlReader, $domNode);
131136
$headingDepth = $this->getHeadingDepth($paragraphStyle);
@@ -182,7 +187,7 @@ protected function readParagraph(XMLReader $xmlReader, DOMElement $domNode, $par
182187
$parent->addTitle($textContent, $headingDepth);
183188
} else {
184189
// Text and TextRun
185-
$textRunContainers = $xmlReader->countElements('w:r|w:ins|w:del|w:hyperlink|w:smartTag', $domNode);
190+
$textRunContainers = $xmlReader->countElements('w:r|w:ins|w:del|w:hyperlink|w:smartTag|w:commentReference|w:commentRangeStart|w:commentRangeEnd', $domNode);
186191
if (0 === $textRunContainers) {
187192
$parent->addTextBreak(null, $paragraphStyle);
188193
} else {
@@ -230,7 +235,7 @@ private function getHeadingDepth(?array $paragraphStyle = null)
230235
*/
231236
protected function readRun(XMLReader $xmlReader, DOMElement $domNode, $parent, $docPart, $paragraphStyle = null): void
232237
{
233-
if (in_array($domNode->nodeName, ['w:ins', 'w:del', 'w:smartTag', 'w:hyperlink'])) {
238+
if (in_array($domNode->nodeName, array('w:ins', 'w:del', 'w:smartTag', 'w:hyperlink', 'w:commentReference'))) {
234239
$nodes = $xmlReader->getElements('*', $domNode);
235240
foreach ($nodes as $node) {
236241
$this->readRun($xmlReader, $node, $parent, $docPart, $paragraphStyle);
@@ -242,6 +247,15 @@ protected function readRun(XMLReader $xmlReader, DOMElement $domNode, $parent, $
242247
$this->readRunChild($xmlReader, $node, $parent, $docPart, $paragraphStyle, $fontStyle);
243248
}
244249
}
250+
251+
if($xmlReader->elementExists('.//*["commentReference"=local-name()]', $domNode)) {
252+
$curEl = iterator_to_array($xmlReader->getElements('.//*["commentReference"=local-name()]', $domNode))[0];
253+
$id = $curEl->attributes->getNamedItem('id')->value;
254+
//$path = './/*[("commentRangeStart"=local-name() or "commentRangeEnd"=local-name()) and @*[local-name()="id" and .="'.$id.'"]]';
255+
//$range = $xmlReader->getElements($path);
256+
$this->phpWord->cacheCommentReference('start', $id, $parent->getElement($parent->countElements() - 1));
257+
$this->phpWord->cacheCommentReference('end', $id, $parent->getElement($parent->countElements() - 1));
258+
}
245259
}
246260

247261
/**
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
<?php
2+
3+
namespace App\Library\PhpOffice\PhpWord\Reader\Word2007;
4+
5+
use DateTime;
6+
use PhpOffice\PhpWord\Element\Comment;
7+
use PhpOffice\PhpWord\PhpWord;
8+
use PhpOffice\PhpWord\Reader\Word2007\AbstractPart;
9+
use PhpOffice\PhpWord\Shared\XMLReader;
10+
11+
class Comments extends AbstractPart
12+
{
13+
/**
14+
* Collection name comments
15+
*
16+
* @var string
17+
*/
18+
protected $collection = 'comments';
19+
20+
/**
21+
* Read settings.xml.
22+
*
23+
* @param \PhpOffice\PhpWord\PhpWord $phpWord
24+
*/
25+
public function read(PhpWord $phpWord)
26+
{
27+
$xmlReader = new XMLReader();
28+
$xmlReader->getDomFromZip($this->docFile, $this->xmlFile);
29+
30+
//$xmlReader2 = new XMLReader();
31+
//$xmlReader2->getDomFromZip($this->docFile, 'word/document.xml');
32+
//dd($xmlReader2);
33+
34+
$comments = $phpWord->getComments();
35+
36+
$nodes = $xmlReader->getElements('*');
37+
if ($nodes->length > 0) {
38+
foreach ($nodes as $node) {
39+
$name = str_replace('w:', '', $node->nodeName);
40+
$value = $xmlReader->getAttribute('w:author', $node);
41+
$author = $xmlReader->getAttribute('w:author', $node);
42+
$date = $xmlReader->getAttribute('w:date', $node);
43+
$initials = $xmlReader->getAttribute('w:initials', $node);
44+
$id = $xmlReader->getAttribute('w:id', $node);
45+
$element = new Comment($author, new DateTime($date), $initials);//$this->getElement($phpWord, $id);
46+
//$element->set
47+
// $range = $xmlReader2->getElements('.//*[("commentRangeStart"=local-name() or "commentRangeEnd"=local-name()) and @*[local-name()="id" and .="'.$id.'"]]');
48+
try {
49+
unset($range);
50+
$range = $phpWord->getCommentReference($id);
51+
$range->start->setCommentRangeStart($element);
52+
$range->end->setCommentRangeEnd($element);
53+
} catch(\Exception $e) {
54+
//dd('range', [$element, $id, $node, $node->C14N(), $range ?? null, $e]);
55+
}
56+
//dd($startElement, $endElement, current(current($phpWord->getSections())->getElements()));
57+
//dump($element, $range);
58+
//dd($element, $node, $id, $node->C14N());
59+
$method = 'set' . $name;
60+
//dump([$element, $id, $name, $value, $author, $date, $initials, $method, $xmlReader->getElements('w:p/w:r/w:t', $node)]);
61+
//dd('dsf');
62+
$pNodes = $xmlReader->getElements('w:p/w:r', $node);
63+
foreach ($pNodes as $pNode) {
64+
//dump(['>', $xmlReader, $pNode, $node, $this->collection, '<']);
65+
$this->readRun($xmlReader, $pNode, $element, $this->collection);
66+
}
67+
68+
/*if (in_array($name, $this::$booleanProperties)) {
69+
if ($value == 'false') {
70+
$comments->$method(false);
71+
} else {
72+
$comments->$method(true);
73+
}
74+
} else*/if (method_exists($this, $method)) {
75+
$this->$method($xmlReader, $phpWord, $node);
76+
} elseif (method_exists($comments, $method)) {
77+
$comments->$method($value);
78+
} elseif (method_exists($phpWord, $method)) {
79+
$phpWord->$method($value);
80+
} elseif (method_exists($comments, 'addItem')) {
81+
$comments->addItem($element);
82+
}
83+
}
84+
}
85+
}
86+
87+
/**
88+
* Searches for the element with the given relationId
89+
*
90+
* @param PhpWord $phpWord
91+
* @param int $relationId
92+
* @return \PhpOffice\PhpWord\Element\AbstractContainer|null
93+
*/
94+
private function getElement(PhpWord $phpWord, $relationId)
95+
{
96+
$getMethod = "get{$this->collection}";
97+
//$getMethod = "getTrackChange";
98+
$collection = $phpWord->$getMethod();//->getItems();
99+
100+
//not found by key, looping to search by relationId
101+
foreach ($collection as $collectionElement) {
102+
if ($collectionElement->getRelationId() == $relationId) {
103+
return $collectionElement;
104+
}
105+
}
106+
107+
return null;
108+
}
109+
}

src/PhpWord/Reader/Word2007/Document.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class Document extends AbstractPart
3636
*
3737
* @var \PhpOffice\PhpWord\PhpWord
3838
*/
39-
private $phpWord;
39+
protected $phpWord;
4040

4141
/**
4242
* Read document.xml.
@@ -170,4 +170,9 @@ private function readWSectPrNode(XMLReader $xmlReader, DOMElement $node, Section
170170
$section->setStyle($style);
171171
$this->readHeaderFooter($style, $section);
172172
}
173+
174+
protected function cacheCommentReference(string $type, string $id, $element)
175+
{
176+
$this->phpWord->cacheCommentReference($type, $id, $element);
177+
}
173178
}

0 commit comments

Comments
 (0)