Skip to content

Commit

Permalink
Add support for comments to reader
Browse files Browse the repository at this point in the history
  • Loading branch information
shaedrich authored and Progi1984 committed Sep 13, 2023
1 parent d94b00c commit 84374a5
Show file tree
Hide file tree
Showing 4 changed files with 225 additions and 4 deletions.
95 changes: 94 additions & 1 deletion src/PhpWord/PhpWord.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
namespace PhpOffice\PhpWord;

use BadMethodCallException;
use InvalidArgumentException;
use PhpOffice\PhpWord\Element\AbstractElement;
use PhpOffice\PhpWord\Element\Section;
use PhpOffice\PhpWord\Exception\Exception;

Expand Down Expand Up @@ -68,7 +70,14 @@ class PhpWord
private $metadata = [];

/**
* Create new instance.
* Comment reference cache
*
* @var array
*/
private $commentReferenceCache = [];

/**
* Create new instance
*
* Collections are created dynamically
*/
Expand Down Expand Up @@ -325,4 +334,88 @@ public function save($filename, $format = 'Word2007', $download = false)

return true;
}

/**
* Create new section
*
* @deprecated 0.10.0
*
* @param array $settings
*
* @return \PhpOffice\PhpWord\Element\Section
*
* @codeCoverageIgnore
*/
public function createSection($settings = null)
{
return $this->addSection($settings);
}

/**
* Get document properties object
*
* @deprecated 0.12.0
*
* @return \PhpOffice\PhpWord\Metadata\DocInfo
*
* @codeCoverageIgnore
*/
public function getDocumentProperties()
{
return $this->getDocInfo();
}

/**
* Set document properties object
*
* @deprecated 0.12.0
*
* @param \PhpOffice\PhpWord\Metadata\DocInfo $documentProperties
*
* @return self
*
* @codeCoverageIgnore
*/
public function setDocumentProperties($documentProperties)
{
$this->metadata['Document'] = $documentProperties;

return $this;
}

/**
* Cache commentReference (as well as commentRangeStart and commentRangeEnd) for later use
*
* @param 'start'|'end' $type
* @param string $id,
* @param $element
*
* @return self
*/
public function cacheCommentReference(string $type, string $id, AbstractElement $element)
{
//dump('cacheCommentReference', func_get_args(), array_key_exists($id, $this->commentReferenceCache));
if (!in_array($type, [ 'start', 'end' ])) {
throw new InvalidArgumentException('Type must be "start" or "end"');
}

if (!array_key_exists($id, $this->commentReferenceCache)) {
$this->commentReferenceCache[$id] = (object)[
"start" => null,
"end" => null
];
}
$this->commentReferenceCache[$id]->{$type} = $element;

return $this;
}

public function getCommentReference(string $id)
{
if (!array_key_exists($id, $this->commentReferenceCache)) {
//dd($this->commentReferenceCache);
throw new InvalidArgumentException('Comment with id '.$id.' isn\'t referenced in document');
}
return $this->commentReferenceCache[$id];
}
}
18 changes: 16 additions & 2 deletions src/PhpWord/Reader/Word2007/AbstractPart.php
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,11 @@ protected function readParagraph(XMLReader $xmlReader, DOMElement $domNode, $par
// Paragraph style
$paragraphStyle = null;
$headingDepth = null;
if ($xmlReader->elementExists('w:commentReference', $domNode) || $xmlReader->elementExists('w:commentRangeStart', $domNode) || $xmlReader->elementExists('w:commentRangeEnd', $domNode)) {
$nodes = $xmlReader->getElements('w:commentReference|w:commentRangeStart|w:commentRangeEnd', $domNode);
$node = current(iterator_to_array($nodes));
$id = $node->attributes->getNamedItem('id')->value;
}
if ($xmlReader->elementExists('w:pPr', $domNode)) {
$paragraphStyle = $this->readParagraphStyle($xmlReader, $domNode);
$headingDepth = $this->getHeadingDepth($paragraphStyle);
Expand Down Expand Up @@ -182,7 +187,7 @@ protected function readParagraph(XMLReader $xmlReader, DOMElement $domNode, $par
$parent->addTitle($textContent, $headingDepth);
} else {
// Text and TextRun
$textRunContainers = $xmlReader->countElements('w:r|w:ins|w:del|w:hyperlink|w:smartTag', $domNode);
$textRunContainers = $xmlReader->countElements('w:r|w:ins|w:del|w:hyperlink|w:smartTag|w:commentReference|w:commentRangeStart|w:commentRangeEnd', $domNode);
if (0 === $textRunContainers) {
$parent->addTextBreak(null, $paragraphStyle);
} else {
Expand Down Expand Up @@ -230,7 +235,7 @@ private function getHeadingDepth(?array $paragraphStyle = null)
*/
protected function readRun(XMLReader $xmlReader, DOMElement $domNode, $parent, $docPart, $paragraphStyle = null): void
{
if (in_array($domNode->nodeName, ['w:ins', 'w:del', 'w:smartTag', 'w:hyperlink'])) {
if (in_array($domNode->nodeName, array('w:ins', 'w:del', 'w:smartTag', 'w:hyperlink', 'w:commentReference'))) {
$nodes = $xmlReader->getElements('*', $domNode);
foreach ($nodes as $node) {
$this->readRun($xmlReader, $node, $parent, $docPart, $paragraphStyle);
Expand All @@ -242,6 +247,15 @@ protected function readRun(XMLReader $xmlReader, DOMElement $domNode, $parent, $
$this->readRunChild($xmlReader, $node, $parent, $docPart, $paragraphStyle, $fontStyle);
}
}

if($xmlReader->elementExists('.//*["commentReference"=local-name()]', $domNode)) {
$curEl = iterator_to_array($xmlReader->getElements('.//*["commentReference"=local-name()]', $domNode))[0];
$id = $curEl->attributes->getNamedItem('id')->value;
//$path = './/*[("commentRangeStart"=local-name() or "commentRangeEnd"=local-name()) and @*[local-name()="id" and .="'.$id.'"]]';
//$range = $xmlReader->getElements($path);
$this->phpWord->cacheCommentReference('start', $id, $parent->getElement($parent->countElements() - 1));
$this->phpWord->cacheCommentReference('end', $id, $parent->getElement($parent->countElements() - 1));
}
}

/**
Expand Down
109 changes: 109 additions & 0 deletions src/PhpWord/Reader/Word2007/Comments.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<?php

namespace App\Library\PhpOffice\PhpWord\Reader\Word2007;

use DateTime;
use PhpOffice\PhpWord\Element\Comment;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Reader\Word2007\AbstractPart;
use PhpOffice\PhpWord\Shared\XMLReader;

class Comments extends AbstractPart
{
/**
* Collection name comments
*
* @var string
*/
protected $collection = 'comments';

/**
* Read settings.xml.
*
* @param \PhpOffice\PhpWord\PhpWord $phpWord
*/
public function read(PhpWord $phpWord)
{
$xmlReader = new XMLReader();
$xmlReader->getDomFromZip($this->docFile, $this->xmlFile);

//$xmlReader2 = new XMLReader();
//$xmlReader2->getDomFromZip($this->docFile, 'word/document.xml');
//dd($xmlReader2);

$comments = $phpWord->getComments();

$nodes = $xmlReader->getElements('*');
if ($nodes->length > 0) {
foreach ($nodes as $node) {
$name = str_replace('w:', '', $node->nodeName);
$value = $xmlReader->getAttribute('w:author', $node);
$author = $xmlReader->getAttribute('w:author', $node);
$date = $xmlReader->getAttribute('w:date', $node);
$initials = $xmlReader->getAttribute('w:initials', $node);
$id = $xmlReader->getAttribute('w:id', $node);
$element = new Comment($author, new DateTime($date), $initials);//$this->getElement($phpWord, $id);
//$element->set
// $range = $xmlReader2->getElements('.//*[("commentRangeStart"=local-name() or "commentRangeEnd"=local-name()) and @*[local-name()="id" and .="'.$id.'"]]');
try {
unset($range);
$range = $phpWord->getCommentReference($id);
$range->start->setCommentRangeStart($element);
$range->end->setCommentRangeEnd($element);
} catch(\Exception $e) {
//dd('range', [$element, $id, $node, $node->C14N(), $range ?? null, $e]);
}
//dd($startElement, $endElement, current(current($phpWord->getSections())->getElements()));
//dump($element, $range);
//dd($element, $node, $id, $node->C14N());
$method = 'set' . $name;
//dump([$element, $id, $name, $value, $author, $date, $initials, $method, $xmlReader->getElements('w:p/w:r/w:t', $node)]);
//dd('dsf');
$pNodes = $xmlReader->getElements('w:p/w:r', $node);
foreach ($pNodes as $pNode) {
//dump(['>', $xmlReader, $pNode, $node, $this->collection, '<']);
$this->readRun($xmlReader, $pNode, $element, $this->collection);
}

/*if (in_array($name, $this::$booleanProperties)) {
if ($value == 'false') {
$comments->$method(false);
} else {
$comments->$method(true);
}
} else*/if (method_exists($this, $method)) {
$this->$method($xmlReader, $phpWord, $node);
} elseif (method_exists($comments, $method)) {
$comments->$method($value);
} elseif (method_exists($phpWord, $method)) {
$phpWord->$method($value);
} elseif (method_exists($comments, 'addItem')) {
$comments->addItem($element);
}
}
}
}

/**
* Searches for the element with the given relationId
*
* @param PhpWord $phpWord
* @param int $relationId
* @return \PhpOffice\PhpWord\Element\AbstractContainer|null
*/
private function getElement(PhpWord $phpWord, $relationId)
{
$getMethod = "get{$this->collection}";
//$getMethod = "getTrackChange";
$collection = $phpWord->$getMethod();//->getItems();

//not found by key, looping to search by relationId
foreach ($collection as $collectionElement) {
if ($collectionElement->getRelationId() == $relationId) {
return $collectionElement;
}
}

return null;
}
}
7 changes: 6 additions & 1 deletion src/PhpWord/Reader/Word2007/Document.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class Document extends AbstractPart
*
* @var \PhpOffice\PhpWord\PhpWord
*/
private $phpWord;
protected $phpWord;

/**
* Read document.xml.
Expand Down Expand Up @@ -170,4 +170,9 @@ private function readWSectPrNode(XMLReader $xmlReader, DOMElement $node, Section
$section->setStyle($style);
$this->readHeaderFooter($style, $section);
}

protected function cacheCommentReference(string $type, string $id, $element)
{
$this->phpWord->cacheCommentReference($type, $id, $element);
}
}

0 comments on commit 84374a5

Please sign in to comment.