1<?php 2 3namespace dokuwiki\plugin\struct\meta; 4 5class CSVPageImporter extends CSVImporter 6{ 7 protected $importedPids = []; 8 9 /** @var bool[] */ 10 protected $createPage = []; 11 12 /** 13 * Import page schema only when the pid header is present. 14 */ 15 protected function readHeaders() 16 { 17 parent::readHeaders(); 18 if (!in_array('pid', $this->header)) 19 throw new StructException('There is no "pid" header in the CSV. Schema not imported.'); 20 } 21 22 /** 23 * Add the revision. 24 * 25 * @param string[] $values 26 */ 27 protected function saveLine($values) 28 { 29 //create new page revision 30 $pid = cleanID($values[0]); 31 if (isset($this->createPage[$pid])) { 32 $this->createPage($pid, $values); 33 } 34 // make sure this schema is assigned 35 /** @noinspection PhpUndefinedVariableInspection */ 36 Assignments::getInstance()->assignPageSchema( 37 $pid, 38 $this->schema->getTable() 39 ); 40 parent::saveLine($values); 41 } 42 43 /** 44 * Create a page from a namespace template and replace column-label-placeholders 45 * 46 * This is intended to use the same placeholders as bureaucracy in their most basic version 47 * (i.e. without default values, formatting, etc. ) 48 * 49 * @param string $pid 50 * @param array $line 51 */ 52 protected function createPage($pid, $line) 53 { 54 $text = pageTemplate($pid); 55 if (trim($text) === '') { 56 $pageParts = explode(':', $pid); 57 $pagename = end($pageParts); 58 $text = "====== $pagename ======\n"; 59 } 60 $keys = array_reduce( 61 $this->columns, 62 function ($keys, Column $col) { 63 if (!in_array($col->getLabel(), $keys, true)) { 64 return $keys; 65 } 66 $index = array_search($col->getLabel(), $keys, true); 67 $keys[$index] = $col->getFullQualifiedLabel(); 68 return $keys; 69 }, 70 $this->header 71 ); 72 73 $keysAt = array_map(static fn($key) => "@@$key@@", $keys); 74 $keysHash = array_map(static fn($key) => "##$key##", $keys); 75 $flatValues = array_map( 76 function ($value) { 77 if (is_array($value)) { 78 return implode(', ', $value); 79 } 80 return $value; 81 }, 82 $line 83 ); 84 $text = $this->evaluateIfNotEmptyTags($text, $keys, $flatValues); 85 $text = str_replace($keysAt, $flatValues, $text); 86 /** @noinspection CascadeStringReplacementInspection */ 87 $text = str_replace($keysHash, $flatValues, $text); 88 saveWikiText($pid, $text, 'Created by struct csv import'); 89 } 90 91 /** 92 * Replace conditional <ifnotempty fieldname></ifnotempty> tags 93 * 94 * @param string $text The template 95 * @param string[] $keys The array of qualified headers 96 * @param string[] $values The flat array of corresponding values 97 * 98 * @return string The template with the tags replaced 99 */ 100 protected function evaluateIfNotEmptyTags($text, $keys, $values) 101 { 102 return preg_replace_callback( 103 '/<ifnotempty (.+?)>([^<]*?)<\/ifnotempty>/', 104 function ($matches) use ($keys, $values) { 105 [, $blockKey, $textIfNotEmpty] = $matches; 106 $index = array_search($blockKey, $keys, true); 107 if ($index === false) { 108 msg('Import error: Key "' . hsc($blockKey) . '" not found!', -1); 109 return ''; 110 } 111 if (trim($values[$index]) === '') { 112 return ''; 113 } 114 return $textIfNotEmpty; 115 }, 116 $text 117 ); 118 } 119 120 /** 121 * Check if page id realy exists 122 * 123 * @param Column $col 124 * @param mixed $rawvalue 125 * @return bool 126 */ 127 protected function validateValue(Column $col, &$rawvalue) 128 { 129 //check if page id exists and schema is bound to the page 130 if ($col->getLabel() == 'pid') { 131 $pid = cleanID($rawvalue); 132 if (isset($this->importedPids[$pid])) { 133 $this->errors[] = 'Page "' . $pid . '" already imported. Skipping the row.'; 134 return false; 135 } 136 if (page_exists($pid)) { 137 $this->importedPids[$pid] = true; 138 return true; 139 } 140 global $INPUT; 141 if ($INPUT->bool('createPage')) { 142 $this->createPage[$pid] = true; 143 return true; 144 } 145 $this->errors[] = 'Page "' . $pid . '" does not exists. Skipping the row.'; 146 return false; 147 } 148 149 return parent::validateValue($col, $rawvalue); 150 } 151} 152