diff --git a/app/Http/Controllers/SearchAndDisplaceController.php b/app/Http/Controllers/SearchAndDisplaceController.php index 03f0072..e075bc2 100644 --- a/app/Http/Controllers/SearchAndDisplaceController.php +++ b/app/Http/Controllers/SearchAndDisplaceController.php @@ -12,9 +12,9 @@ class SearchAndDisplaceController extends Controller public function __construct() { - $this->storage = Storage::disk('local'); + $this->storage = Storage::disk('local'); } - + public function show($id) { $handler = new DocumentFile(); diff --git a/app/SearchDisplace/Convertor/Convertor.php b/app/SearchDisplace/Convertor/Convertor.php index c18a460..7284861 100644 --- a/app/SearchDisplace/Convertor/Convertor.php +++ b/app/SearchDisplace/Convertor/Convertor.php @@ -3,6 +3,7 @@ namespace App\SearchDisplace\Convertor; use Symfony\Component\Process\Process; +use Symfony\Component\Process\Exception\ProcessFailedException; /** * Convert documents from formats supported by Libre Office @@ -13,7 +14,7 @@ class Convertor { * @param $to desired file format * @param $document absolute file path * @param $tmp - if true file will be saved to tmp directory for download - * + * * @return string $path to converted file */ public static function convert($to, $document, $tmp = false) @@ -27,9 +28,25 @@ class Convertor { $folder = storage_path('app/tmp/'); } - $process = new Process(['soffice', '--convert-to', $to, $original, '--outdir', $folder]); + $process = new Process( + [ + 'soffice', + '--convert-to', + $to, + $original, + '--outdir', + $folder + ], base_path(), + [ + 'HOME' => base_path() + ] + ); $process->run(); + if (!$process->isSuccessful()) { + throw new ProcessFailedException($process); + } + return $path['filename'] . '.' . $to; } } \ No newline at end of file diff --git a/app/SearchDisplace/SearchAndDisplaceXML.php b/app/SearchDisplace/SearchAndDisplaceXML.php index 068e1d5..353ac89 100644 --- a/app/SearchDisplace/SearchAndDisplaceXML.php +++ b/app/SearchDisplace/SearchAndDisplaceXML.php @@ -6,6 +6,8 @@ use App\SearchDisplace\Documents\DocumentFile; use Illuminate\Support\Facades\Storage; use App\SearchDisplace\Convertor\Convertor; use DOMDocument; +use DOMNode; +use DOMText; class SearchAndDisplaceXML { @@ -19,8 +21,8 @@ class SearchAndDisplaceXML { $this->fileDirectory = $file; $this->searchers = $searchers; - $this->storage = Storage::disk('local'); - $this->searchOnly = $searchOnly; + $this->storage = Storage::disk('local'); + $this->searchOnly = $searchOnly; $this->markedStyleCreated = false; } @@ -35,10 +37,10 @@ class SearchAndDisplaceXML return $pathinfo['filename']; } - + /** * Convert (Search displaced) XML to HTML for browser preview - * + * * @return void */ protected function convertSearchDisplacedXMLToHTML($file) @@ -48,7 +50,7 @@ class SearchAndDisplaceXML /** * Read XML document and send text contents to SD - * + * * @return void */ protected function applySD() @@ -58,24 +60,24 @@ class SearchAndDisplaceXML $dom->load($filePath . "/document.xml"); foreach($dom->getElementsByTagName('p') as $p) { - if(count($p->childNodes) > 0 && isset($p->parentNode->tagName) && $p->parentNode->tagName !== "table:table-cell") { + 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(isset($child->tagName) && $child->tagName === "text:span") { - $content = trim($child->textContent); - if($content == '') { - continue; - } + if (in_array($child, $replacements)) { + continue; + } - $this->replace($content, $child, $dom); + if (!$child instanceof DOMText) { + continue; } - } - } else { - $content = trim($p->textContent); - if($content == '') { - continue; - } - $this->replace($content, $p, $dom); + $replacements = array_merge($replacements, $this->replace($child, $dom)); + } } } @@ -86,14 +88,17 @@ class SearchAndDisplaceXML /** * Apply SD on document's paragraph - * - * @param string $content paragraph content - * @param $element DOM element - * - * @return void + * + * @param DOMNode $element DOM element + * @param DOMDocument $dom The document + * + * @return array */ - protected function replace($content, $element, $dom) + protected function replace(DOMText &$element, DOMDocument &$dom) { + /** @var string $content */ + $content = $element->textContent ?? $element->nodeValue; + $search = new SearchAndDisplace( stripslashes($content), [ @@ -105,6 +110,8 @@ class SearchAndDisplaceXML $changed = $search->execute(); + $replacementNodes = []; + if($changed) { if($this->searchOnly) { $content = $element->textContent; @@ -114,23 +121,35 @@ class SearchAndDisplaceXML $indexes = $changed['indexes']; } - foreach(array_keys($indexes) as $searcher) { - if(empty($indexes[$searcher])) { + foreach($indexes as $searcher => $changes) { + if(empty($changes)) { continue; } - foreach($indexes[$searcher] as $change) { - $first = substr($content, 0, $change['start']); - $changed = substr($content, $change['start'], $change['end'] - $change['start'] + 1); - $last = substr($content, $change['end'] + 1); - - $element->textContent = $first; - $changed = $dom->createElement("text:span", $changed); - $last = $dom->createElement("text:span", $last); - //text:style-name="mark" - $changed->setAttribute('text:style-name', 'mark'); - $element->appendChild($changed); - $element->appendChild($last); + 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; } } @@ -139,11 +158,13 @@ class SearchAndDisplaceXML } $this->markedStyleCreated = true; } + + return $replacementNodes; } /** * Create marked style for browser preview - * + * */ private function createMarkedStyle($dom) { @@ -162,10 +183,10 @@ class SearchAndDisplaceXML /** * 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) diff --git a/package-lock.json b/package-lock.json index 0dd09f1..d15ed5e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "search-and-displace-core", - "version": "1", + "version": "1.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "search-and-displace-core", - "version": "1", + "version": "1.0.0", "dependencies": { "@types/jquery": "^3.5.14", "@types/marked": "^2.0.3",