Repo for the search and displace core module including the interface to select files and search and displace operations to run on them. https://searchanddisplace.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

182 lines
5.4 KiB

  1. <?php
  2. namespace App\SearchDisplace;
  3. use App\SearchDisplace\Documents\DocumentFile;
  4. use Illuminate\Support\Facades\Storage;
  5. use App\SearchDisplace\Convertor\Convertor;
  6. use DOMDocument;
  7. class SearchAndDisplaceXML
  8. {
  9. protected $file;
  10. protected $searchers;
  11. protected $storage;
  12. protected $searchOnly;
  13. protected $markedStyleCreated;
  14. public function __construct($file, $searchers, $searchOnly)
  15. {
  16. $this->fileDirectory = $file;
  17. $this->searchers = $searchers;
  18. $this->storage = Storage::disk('local');
  19. $this->searchOnly = $searchOnly;
  20. $this->markedStyleCreated = false;
  21. }
  22. public function execute()
  23. {
  24. $sdXML = $this->applySD();
  25. $pathinfo = pathinfo($sdXML);
  26. $this->convertSearchDisplacedXMLToHTML($sdXML);
  27. DocumentFile::updateImagesPath($pathinfo['dirname'] . '/document_sdapplied.html', $this->fileDirectory);
  28. return $pathinfo['filename'];
  29. }
  30. /**
  31. * Convert (Search displaced) XML to HTML for browser preview
  32. *
  33. * @return void
  34. */
  35. protected function convertSearchDisplacedXMLToHTML($file)
  36. {
  37. Convertor::convert('html', $file);
  38. }
  39. /**
  40. * Read XML document and send text contents to SD
  41. *
  42. * @return void
  43. */
  44. protected function applySD()
  45. {
  46. $dom = new \DOMDocument();
  47. $filePath = $this->storage->path("contracts/$this->fileDirectory");
  48. $dom->load($filePath . "/document.xml");
  49. foreach($dom->getElementsByTagName('p') as $p) {
  50. if(count($p->childNodes) > 0 && isset($p->parentNode->tagName) && $p->parentNode->tagName !== "table:table-cell") {
  51. foreach($p->childNodes as $child) {
  52. if(isset($child->tagName) && $child->tagName === "text:span") {
  53. $content = trim($child->textContent);
  54. if($content == '') {
  55. continue;
  56. }
  57. $this->replace($content, $child, $dom);
  58. }
  59. }
  60. } else {
  61. $content = trim($p->textContent);
  62. if($content == '') {
  63. continue;
  64. }
  65. $this->replace($content, $p, $dom);
  66. }
  67. }
  68. $dom->save($filePath . "/document_sdapplied.xml");
  69. return $filePath . "/document_sdapplied.xml";
  70. }
  71. /**
  72. * Apply SD on document's paragraph
  73. *
  74. * @param string $content paragraph content
  75. * @param $element DOM element
  76. *
  77. * @return void
  78. */
  79. protected function replace($content, $element, $dom)
  80. {
  81. $search = new SearchAndDisplace(
  82. stripslashes($content),
  83. [
  84. 'searchers' => $this->searchers,
  85. ],
  86. $this->searchOnly,
  87. true
  88. );
  89. $changed = $search->execute();
  90. if($changed) {
  91. if($this->searchOnly) {
  92. $content = $element->textContent;
  93. $indexes = $changed;
  94. } else {
  95. $content = $changed['content'];
  96. $indexes = $changed['indexes'];
  97. }
  98. foreach(array_keys($indexes) as $searcher) {
  99. if(empty($indexes[$searcher])) {
  100. continue;
  101. }
  102. foreach($indexes[$searcher] as $change) {
  103. $first = substr($content, 0, $change['start']);
  104. $changed = substr($content, $change['start'], $change['end'] - $change['start'] + 1);
  105. $last = substr($content, $change['end'] + 1);
  106. $element->textContent = $first;
  107. $changed = $dom->createElement("text:span", $changed);
  108. $last = $dom->createElement("text:span", $last);
  109. //text:style-name="mark"
  110. $changed->setAttribute('text:style-name', 'mark');
  111. $element->appendChild($changed);
  112. $element->appendChild($last);
  113. }
  114. }
  115. if(!$this->markedStyleCreated) {
  116. $this->createMarkedStyle($dom);
  117. }
  118. $this->markedStyleCreated = true;
  119. }
  120. }
  121. /**
  122. * Create marked style for browser preview
  123. *
  124. */
  125. private function createMarkedStyle($dom)
  126. {
  127. $style = $dom->createElement("style:style");
  128. $style->setAttribute("style:name", 'mark');
  129. $style->setAttribute("style:family", 'text');
  130. $child = $dom->createElement('style:text-properties');
  131. $child->setAttribute("officeooo:rsid", '0014890a');
  132. $child->setAttribute("fo:background-color", '#ffff00');
  133. $style->appendChild($child);
  134. $dom->getElementsByTagName('automatic-styles')->item(0)->appendChild($style);
  135. }
  136. /**
  137. * Remove marked style used in browser and convert XML file to original file type
  138. *
  139. * @param $type file type
  140. * @param $file absolute file path
  141. *
  142. * @return string $path
  143. */
  144. public static function prepareForDownload($type, $file)
  145. {
  146. // remove marked style from XML
  147. $dom = new DOMDocument();
  148. $dom->load($file);
  149. $style = $dom->getElementsByTagName('automatic-styles')->item(0);
  150. $style->removeChild($style->lastChild);
  151. $dom->save($file);
  152. return Convertor::convert($type, $file, true);
  153. }
  154. }