Skip to content

Commit

Permalink
Formula : Add Element (& Writer/Reader Word2007/ODText)
Browse files Browse the repository at this point in the history
  • Loading branch information
Progi1984 committed Sep 21, 2023
1 parent a836c32 commit 05f7973
Show file tree
Hide file tree
Showing 33 changed files with 628 additions and 68 deletions.
3 changes: 2 additions & 1 deletion composer.json
Expand Up @@ -68,7 +68,8 @@
"ext-dom": "*",
"ext-json": "*",
"ext-xml": "*",
"laminas/laminas-escaper": ">=2.6"
"laminas/laminas-escaper": ">=2.6",
"phpoffice/math": "dev-master"
},
"require-dev": {
"ext-zip": "*",
Expand Down
55 changes: 54 additions & 1 deletion composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/PhpWord/Element/AbstractContainer.php
Expand Up @@ -18,6 +18,7 @@
namespace PhpOffice\PhpWord\Element;

use BadMethodCallException;
use PhpOffice\Math\Math;
use ReflectionClass;

/**
Expand Down Expand Up @@ -47,6 +48,7 @@
* @method Chart addChart(string $type, array $categories, array $values, array $style = null, $seriesName = null)
* @method FormField addFormField(string $type, mixed $fStyle = null, mixed $pStyle = null)
* @method SDT addSDT(string $type)
* @method Formula addFormula(Math $math)
* @method \PhpOffice\PhpWord\Element\OLEObject addObject(string $source, mixed $style = null) deprecated, use addOLEObject instead
*
* @since 0.10.0
Expand Down Expand Up @@ -88,6 +90,7 @@ public function __call($function, $args)
'Footnote', 'Endnote', 'CheckBox', 'TextBox', 'Field',
'Line', 'Shape', 'Title', 'TOC', 'PageBreak',
'Chart', 'FormField', 'SDT', 'Comment',
'Formula',
];
$functions = [];
foreach ($elements as $element) {
Expand Down
53 changes: 53 additions & 0 deletions src/PhpWord/Element/Formula.php
@@ -0,0 +1,53 @@
<?php
/**
* This file is part of PHPWord - A pure PHP library for reading and writing
* word processing documents.
*
* PHPWord is free software distributed under the terms of the GNU Lesser
* General Public License version 3 as published by the Free Software Foundation.
*
* For the full copyright and license information, please read the LICENSE
* file that was distributed with this source code. For the full list of
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
*
* @see https://github.com/PHPOffice/PHPWord
*
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
*/

declare(strict_types=1);

namespace PhpOffice\PhpWord\Element;

use PhpOffice\Math\Math;

/**
* Formula element.
*/
class Formula extends AbstractElement
{
/**
* @var Math
*/
protected $math;

/**
* Create a new Formula Element.
*/
public function __construct(Math $math)
{
$this->setMath($math);
}

public function setMath(Math $math): self
{
$this->math = $math;

return $this;
}

public function getMath(): Math
{
return $this->math;
}
}
4 changes: 2 additions & 2 deletions src/PhpWord/Reader/ODText.php
Expand Up @@ -59,7 +59,7 @@ public function load($docFile)
* @param string $docFile
* @param string $xmlFile
*/
private function readPart(PhpWord $phpWord, $relationships, $partName, $docFile, $xmlFile): void
private function readPart(PhpWord $phpWord, array $relationships, string $partName, string $docFile, string $xmlFile): void
{
$partClass = "PhpOffice\\PhpWord\\Reader\\ODText\\{$partName}";
if (class_exists($partClass)) {
Expand All @@ -77,7 +77,7 @@ private function readPart(PhpWord $phpWord, $relationships, $partName, $docFile,
*
* @return array
*/
private function readRelationships($docFile)
private function readRelationships(string $docFile): array
{
$rels = [];
$xmlFile = 'META-INF/manifest.xml';
Expand Down
68 changes: 42 additions & 26 deletions src/PhpWord/Reader/ODText/Content.php
Expand Up @@ -18,6 +18,7 @@
namespace PhpOffice\PhpWord\Reader\ODText;

use DateTime;
use PhpOffice\Math\Reader\MathML;
use PhpOffice\PhpWord\Element\TrackChange;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Shared\XMLReader;
Expand Down Expand Up @@ -51,37 +52,52 @@ public function read(PhpWord $phpWord): void

break;
case 'text:p': // Paragraph
$children = $node->childNodes;
foreach ($children as $child) {
switch ($child->nodeName) {
case 'text:change-start':
$changeId = $child->getAttribute('text:change-id');
if (isset($trackedChanges[$changeId])) {
$changed = $trackedChanges[$changeId];
}
$element = $xmlReader->getElement('draw:frame/draw:object', $node);
if ($element) {
$mathFile = str_replace('./', '', $element->getAttribute('xlink:href')) . '/content.xml';

break;
case 'text:change-end':
unset($changed);
$xmlReaderObject = new XMLReader();
$mathElement = $xmlReaderObject->getDomFromZip($this->docFile, $mathFile);

break;
case 'text:change':
$changeId = $child->getAttribute('text:change-id');
if (isset($trackedChanges[$changeId])) {
$changed = $trackedChanges[$changeId];
}
$mathXML = $mathElement->saveXML($mathElement);

Check failure on line 62 in src/PhpWord/Reader/ODText/Content.php

View workflow job for this annotation

GitHub Actions / phpstan

Cannot call method saveXML() on DOMDocument|false.

Check failure on line 62 in src/PhpWord/Reader/ODText/Content.php

View workflow job for this annotation

GitHub Actions / phpstan

Cannot call method saveXML() on DOMDocument|false.

$reader = new MathML();
$math = $reader->read($mathXML);

Check failure on line 65 in src/PhpWord/Reader/ODText/Content.php

View workflow job for this annotation

GitHub Actions / phpstan

Parameter #1 $content of method PhpOffice\Math\Reader\MathML::read() expects string, string|false given.

Check failure on line 65 in src/PhpWord/Reader/ODText/Content.php

View workflow job for this annotation

GitHub Actions / phpstan

Parameter #1 $content of method PhpOffice\Math\Reader\MathML::read() expects string, string|false given.

$section->addFormula($math);
} else {
$children = $node->childNodes;
foreach ($children as $child) {
switch ($child->nodeName) {
case 'text:change-start':
$changeId = $child->getAttribute('text:change-id');
if (isset($trackedChanges[$changeId])) {
$changed = $trackedChanges[$changeId];
}

break;
case 'text:change-end':
unset($changed);

break;
break;
case 'text:change':
$changeId = $child->getAttribute('text:change-id');
if (isset($trackedChanges[$changeId])) {
$changed = $trackedChanges[$changeId];
}

break;
}
}
}

$element = $section->addText($node->nodeValue);
if (isset($changed) && is_array($changed)) {
$element->setTrackChange($changed['changed']);
if (isset($changed['textNodes'])) {
foreach ($changed['textNodes'] as $changedNode) {
$element = $section->addText($changedNode->nodeValue);
$element->setTrackChange($changed['changed']);
$element = $section->addText($node->nodeValue);
if (isset($changed) && is_array($changed)) {
$element->setTrackChange($changed['changed']);
if (isset($changed['textNodes'])) {
foreach ($changed['textNodes'] as $changedNode) {
$element = $section->addText($changedNode->nodeValue);
$element->setTrackChange($changed['changed']);
}
}
}
}
Expand Down
74 changes: 41 additions & 33 deletions src/PhpWord/Reader/Word2007/AbstractPart.php
Expand Up @@ -20,6 +20,7 @@
use DateTime;
use DOMElement;
use InvalidArgumentException;
use PhpOffice\Math\Reader\OfficeMathML;
use PhpOffice\PhpWord\ComplexType\TblWidth as TblWidthComplexType;
use PhpOffice\PhpWord\Element\AbstractContainer;
use PhpOffice\PhpWord\Element\AbstractElement;
Expand Down Expand Up @@ -189,25 +190,7 @@ protected function getCommentReference(string $id): array
protected function readParagraph(XMLReader $xmlReader, DOMElement $domNode, $parent, $docPart = 'document'): void
{
// 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));
if ($node) {
$attributeIdentifier = $node->attributes->getNamedItem('id');
if ($attributeIdentifier) {
$id = $attributeIdentifier->nodeValue;
}
}
}
if ($xmlReader->elementExists('w:pPr', $domNode)) {
$paragraphStyle = $this->readParagraphStyle($xmlReader, $domNode);
$headingDepth = $this->getHeadingDepth($paragraphStyle);
}
$paragraphStyle = $xmlReader->elementExists('w:pPr', $domNode) ? $this->readParagraphStyle($xmlReader, $domNode) : null;

// PreserveText
if ($xmlReader->elementExists('w:r/w:instrText', $domNode)) {
Expand All @@ -234,8 +217,26 @@ protected function readParagraph(XMLReader $xmlReader, DOMElement $domNode, $par
}
}
$parent->addPreserveText(htmlspecialchars($textContent, ENT_QUOTES, 'UTF-8'), $fontStyle, $paragraphStyle);
} elseif ($xmlReader->elementExists('w:pPr/w:numPr', $domNode)) {
// List item

return;
}

// Formula
$xmlReader->registerNamespace('m', 'http://schemas.openxmlformats.org/officeDocument/2006/math');
if ($xmlReader->elementExists('m:oMath', $domNode)) {
$mathElement = $xmlReader->getElement('m:oMath', $domNode);
$mathXML = $mathElement->ownerDocument->saveXML($mathElement);

$reader = new OfficeMathML();
$math = $reader->read($mathXML);

Check failure on line 231 in src/PhpWord/Reader/Word2007/AbstractPart.php

View workflow job for this annotation

GitHub Actions / phpstan

Parameter #1 $content of method PhpOffice\Math\Reader\OfficeMathML::read() expects string, string|false given.

Check failure on line 231 in src/PhpWord/Reader/Word2007/AbstractPart.php

View workflow job for this annotation

GitHub Actions / phpstan

Parameter #1 $content of method PhpOffice\Math\Reader\OfficeMathML::read() expects string, string|false given.

$parent->addFormula($math);

return;
}

// List item
if ($xmlReader->elementExists('w:pPr/w:numPr', $domNode)) {
$numId = $xmlReader->getAttribute('w:val', $domNode, 'w:pPr/w:numPr/w:numId');
$levelId = $xmlReader->getAttribute('w:val', $domNode, 'w:pPr/w:numPr/w:ilvl');
$nodes = $xmlReader->getElements('*', $domNode);
Expand All @@ -245,8 +246,13 @@ protected function readParagraph(XMLReader $xmlReader, DOMElement $domNode, $par
foreach ($nodes as $node) {
$this->readRun($xmlReader, $node, $listItemRun, $docPart, $paragraphStyle);
}
} elseif ($headingDepth !== null) {
// Heading or Title

return;
}

// Heading or Title
$headingDepth = $xmlReader->elementExists('w:pPr', $domNode) ? $this->getHeadingDepth($paragraphStyle) : null;
if ($headingDepth !== null) {
$textContent = null;
$nodes = $xmlReader->getElements('w:r|w:hyperlink', $domNode);
if ($nodes->length === 1) {
Expand All @@ -258,17 +264,19 @@ protected function readParagraph(XMLReader $xmlReader, DOMElement $domNode, $par
}
}
$parent->addTitle($textContent, $headingDepth);

return;
}

// Text and TextRun
$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 {
// Text and TextRun
$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 {
$nodes = $xmlReader->getElements('*', $domNode);
$paragraph = $parent->addTextRun($paragraphStyle);
foreach ($nodes as $node) {
$this->readRun($xmlReader, $node, $paragraph, $docPart, $paragraphStyle);
}
$nodes = $xmlReader->getElements('*', $domNode);
$paragraph = $parent->addTextRun($paragraphStyle);
foreach ($nodes as $node) {
$this->readRun($xmlReader, $node, $paragraph, $docPart, $paragraphStyle);
}
}
}
Expand Down

0 comments on commit 05f7973

Please sign in to comment.