|
|
<?php
namespace App\SearchDisplace;
use App\SearchDisplace\Documents\DocumentFile; use Illuminate\Support\Facades\Storage; use App\SearchDisplace\Convertor\Convertor; use DOMDocument; use DOMNode; use DOMText;
class SearchAndDisplaceXML { protected $file; protected $searchers; protected $storage; protected $searchOnly; protected $markedStyleCreated;
public function __construct($file, $searchers, $searchOnly) { $this->fileDirectory = $file; $this->searchers = $searchers; $this->storage = Storage::disk('local'); $this->searchOnly = $searchOnly; $this->markedStyleCreated = false; }
public function execute() { $sdXML = $this->applySD(); $pathinfo = pathinfo($sdXML);
$this->convertSearchDisplacedXMLToHTML($sdXML);
DocumentFile::updateImagesPath($pathinfo['dirname'] . '/document_sdapplied.html', $this->fileDirectory);
return $pathinfo['filename']; }
/** * Convert (Search displaced) XML to HTML for browser preview * * @return void */ protected function convertSearchDisplacedXMLToHTML($file) { Convertor::convert('html', $file); }
/** * Read XML document and send text contents to SD * * @return void */ protected function applySD() { $dom = new \DOMDocument(); $filePath = $this->storage->path("contracts/$this->fileDirectory"); $dom->load($filePath . "/document.xml");
foreach($dom->getElementsByTagName('p') as $p) { if( !$p instanceof DOMText && count($p->childNodes) > 0 && isset($p->parentNode->tagName) && $p->parentNode->tagName !== "table:table-cell" ) { $replacements = []; foreach($p->childNodes as $child) { if (in_array($child, $replacements)) { continue; }
if (!$child instanceof DOMText) { continue; }
$replacements = array_merge($replacements, $this->replace($child, $dom)); } } }
$dom->save($filePath . "/document_sdapplied.xml");
return $filePath . "/document_sdapplied.xml"; }
/** * Apply SD on document's paragraph * * @param DOMNode $element DOM element * @param DOMDocument $dom The document * * @return array */ protected function replace(DOMText &$element, DOMDocument &$dom) { /** @var string $content */ $content = $element->textContent ?? $element->nodeValue;
$search = new SearchAndDisplace( stripslashes($content), [ 'searchers' => $this->searchers, ], $this->searchOnly, true );
$changed = $search->execute();
$replacementNodes = [];
if($changed) { if($this->searchOnly) { $content = $element->textContent; $indexes = $changed; } else { $content = $changed['content']; $indexes = $changed['indexes']; }
foreach($indexes as $searcher => $changes) { if(empty($changes)) { continue; }
foreach($changes as $change) { $firstContent = substr($content, 0, $change['start']); $changedContent = substr($content, $change['start'], $change['end'] - $change['start'] + 1); $lastContent = substr($content, $change['end'] + 1);
// $firstNode = $dom->createElement("text:span", $firstContent);
$element->textContent = $firstContent;
$changedNode = $dom->createElement("text:span", $changedContent); $changedNode->setAttribute('text:style-name', 'mark');
$lastNode = $dom->createElement("text:span", $lastContent);
// Add the changed and last nodes after the current (element) node
// $element->parentNode->insertBefore($firstNode, $element->nextSibling);
# element->parentNode->insertBefore(... $element->nextSibling) inserts a new node before the node AFTER this one
# So we need to add the `last` node first, and then the `changed` node BEFORE the last.
$element->parentNode->insertBefore($lastNode, $element->nextSibling); $element->parentNode->insertBefore($changedNode, $element->nextSibling);
$replacementNodes[] = $changedNode; $replacementNodes[] = $lastNode; } }
if(!$this->markedStyleCreated) { $this->createMarkedStyle($dom); } $this->markedStyleCreated = true; }
return $replacementNodes; }
/** * Create marked style for browser preview * */ private function createMarkedStyle($dom) { $style = $dom->createElement("style:style"); $style->setAttribute("style:name", 'mark'); $style->setAttribute("style:family", 'text');
$child = $dom->createElement('style:text-properties'); $child->setAttribute("officeooo:rsid", '0014890a'); $child->setAttribute("fo:background-color", '#ffff00');
$style->appendChild($child);
$dom->getElementsByTagName('automatic-styles')->item(0)->appendChild($style); }
/** * Remove marked style used in browser and convert XML file to original file type * * @param $type file type * @param $file absolute file path * * @return string $path */ public static function prepareForDownload($type, $file) { // remove marked style from XML
$dom = new DOMDocument(); $dom->load($file); $style = $dom->getElementsByTagName('automatic-styles')->item(0); $style->removeChild($style->lastChild); $dom->save($file);
return Convertor::convert($type, $file, true); } }
|