11fc2361fSSzymon Olewniczak<?php 21fc2361fSSzymon Olewniczak 31fc2361fSSzymon Olewniczaknamespace dokuwiki\plugin\struct\meta; 4*d6d97f60SAnna Dabrowska 51fc2361fSSzymon Olewniczakuse dokuwiki\plugin\struct\types\Page; 61fc2361fSSzymon Olewniczak 7*d6d97f60SAnna Dabrowskaclass CSVPageImporter extends CSVImporter 8*d6d97f60SAnna Dabrowska{ 9e53295c5SSzymon Olewniczak 10e53295c5SSzymon Olewniczak protected $importedPids = array(); 11e53295c5SSzymon Olewniczak 12ee52a3aaSMichael Große /** @var bool[] */ 1317dbef8aSMichael Große protected $createPage = []; 1417dbef8aSMichael Große 151fc2361fSSzymon Olewniczak /** 161fc2361fSSzymon Olewniczak * Import page schema only when the pid header is present. 171fc2361fSSzymon Olewniczak */ 18*d6d97f60SAnna Dabrowska protected function readHeaders() 19*d6d97f60SAnna Dabrowska { 201fc2361fSSzymon Olewniczak 211fc2361fSSzymon Olewniczak //add pid to struct 221fc2361fSSzymon Olewniczak $pageType = new Page(null, 'pid'); 2317dbef8aSMichael Große $this->columns[] = new Column(0, $pageType, 0, true, $this->schema->getTable()); 241fc2361fSSzymon Olewniczak 251fc2361fSSzymon Olewniczak parent::readHeaders(); 261fc2361fSSzymon Olewniczak 271fc2361fSSzymon Olewniczak if (!in_array('pid', $this->header)) throw new StructException('There is no "pid" header in the CSV. Schema not imported.'); 281fc2361fSSzymon Olewniczak } 291fc2361fSSzymon Olewniczak 301fc2361fSSzymon Olewniczak /** 311fc2361fSSzymon Olewniczak * Creates the insert string for the single value table 321fc2361fSSzymon Olewniczak * 331fc2361fSSzymon Olewniczak * @return string 341fc2361fSSzymon Olewniczak */ 35*d6d97f60SAnna Dabrowska protected function getSQLforAllValues() 36*d6d97f60SAnna Dabrowska { 371fc2361fSSzymon Olewniczak $colnames = array(); 381fc2361fSSzymon Olewniczak foreach ($this->columns as $i => $col) { 391fc2361fSSzymon Olewniczak $colnames[] = 'col' . $col->getColref(); 401fc2361fSSzymon Olewniczak } 411fc2361fSSzymon Olewniczak //replace first column with pid 421fc2361fSSzymon Olewniczak $colnames[0] = 'pid'; 431fc2361fSSzymon Olewniczak //insert rev at the end 441fc2361fSSzymon Olewniczak $colnames[] = 'rev'; 451fc2361fSSzymon Olewniczak 461fc2361fSSzymon Olewniczak $placeholds = join(', ', array_fill(0, count($colnames), '?')); 471fc2361fSSzymon Olewniczak $colnames = join(', ', $colnames); 481fc2361fSSzymon Olewniczak $table = $this->schema->getTable(); 491fc2361fSSzymon Olewniczak 50e53295c5SSzymon Olewniczak return "INSERT INTO data_$table ($colnames, latest) VALUES ($placeholds, 1)"; 511fc2361fSSzymon Olewniczak } 521fc2361fSSzymon Olewniczak 531fc2361fSSzymon Olewniczak /** 541fc2361fSSzymon Olewniczak * Add the revision. 551fc2361fSSzymon Olewniczak * 561fc2361fSSzymon Olewniczak * @param string[] $values 571fc2361fSSzymon Olewniczak * @param $line 581fc2361fSSzymon Olewniczak * @param string $single 591fc2361fSSzymon Olewniczak * @param string $multi 601fc2361fSSzymon Olewniczak */ 61*d6d97f60SAnna Dabrowska protected function saveLine($values, $line, $single, $multi) 62*d6d97f60SAnna Dabrowska { 63e53295c5SSzymon Olewniczak //create new page revision 6495ea798eSMichael Große $pid = cleanID($values[0]); 6517dbef8aSMichael Große if ($this->createPage[$pid]) { 6617dbef8aSMichael Große $this->createPage($pid, $line); 6717dbef8aSMichael Große } 68e53295c5SSzymon Olewniczak $helper = plugin_load('helper', 'struct'); 69e53295c5SSzymon Olewniczak $revision = $helper->createPageRevision($pid, 'CSV data imported'); 70e53295c5SSzymon Olewniczak p_get_metadata($pid); // reparse the metadata of the page top update the titles/rev/lasteditor table 71e53295c5SSzymon Olewniczak 72e53295c5SSzymon Olewniczak // make sure this schema is assigned 73e53295c5SSzymon Olewniczak /** @noinspection PhpUndefinedVariableInspection */ 74e53295c5SSzymon Olewniczak Assignments::getInstance()->assignPageSchema( 75e53295c5SSzymon Olewniczak $pid, 76e53295c5SSzymon Olewniczak $this->schema->getTable() 77e53295c5SSzymon Olewniczak ); 78e53295c5SSzymon Olewniczak 79e53295c5SSzymon Olewniczak //add page revision to values 80e53295c5SSzymon Olewniczak $values[] = $revision; 81e53295c5SSzymon Olewniczak 821fc2361fSSzymon Olewniczak parent::saveLine($values, $line, $single, $multi); 831fc2361fSSzymon Olewniczak } 841fc2361fSSzymon Olewniczak 851fc2361fSSzymon Olewniczak /** 8617dbef8aSMichael Große * Create a page from a namespace template and replace column-label-placeholders 8717dbef8aSMichael Große * 8817dbef8aSMichael Große * This is intended to use the same placeholders as bureaucracy in their most basic version 8917dbef8aSMichael Große * (i.e. without default values, formatting, etc. ) 9017dbef8aSMichael Große * 9117dbef8aSMichael Große * @param string $pid 9217dbef8aSMichael Große * @param array $line 9317dbef8aSMichael Große */ 9417dbef8aSMichael Große protected function createPage($pid, $line) 9517dbef8aSMichael Große { 9617dbef8aSMichael Große $text = pageTemplate($pid); 9717dbef8aSMichael Große if (trim($text) === '') { 9817dbef8aSMichael Große $pageParts = explode(':', $pid); 9917dbef8aSMichael Große $pagename = end($pageParts); 10017dbef8aSMichael Große $text = "====== $pagename ======\n"; 10117dbef8aSMichael Große } 102*d6d97f60SAnna Dabrowska $keys = array_reduce( 103*d6d97f60SAnna Dabrowska $this->columns, 104c09fb9e3SMichael Große function ($keys, Column $col) { 105c09fb9e3SMichael Große if (!in_array($col->getLabel(), $keys, true)) { 106c09fb9e3SMichael Große return $keys; 107c09fb9e3SMichael Große } 108c09fb9e3SMichael Große $index = array_search($col->getLabel(), $keys, true); 109c09fb9e3SMichael Große $keys[$index] = $col->getFullQualifiedLabel(); 110c09fb9e3SMichael Große return $keys; 111c09fb9e3SMichael Große }, 112c09fb9e3SMichael Große $this->header 113c09fb9e3SMichael Große ); 114c09fb9e3SMichael Große 115*d6d97f60SAnna Dabrowska $keysAt = array_map(function ($key) { 116*d6d97f60SAnna Dabrowska return "@@$key@@"; 117*d6d97f60SAnna Dabrowska }, $keys); 118*d6d97f60SAnna Dabrowska $keysHash = array_map(function ($key) { 119*d6d97f60SAnna Dabrowska return "##$key##"; 120*d6d97f60SAnna Dabrowska }, $keys); 12117dbef8aSMichael Große $flatValues = array_map( 12217dbef8aSMichael Große function ($value) { 12317dbef8aSMichael Große if (is_array($value)) { 12417dbef8aSMichael Große return implode(', ', $value); 12517dbef8aSMichael Große } 12617dbef8aSMichael Große return $value; 127*d6d97f60SAnna Dabrowska }, 128*d6d97f60SAnna Dabrowska $line 129*d6d97f60SAnna Dabrowska ); 13000043bffSMichael Große $text = $this->evaluateIfNotEmptyTags($text, $keys, $flatValues); 13117dbef8aSMichael Große $text = str_replace($keysAt, $flatValues, $text); 13217dbef8aSMichael Große /** @noinspection CascadeStringReplacementInspection */ 13317dbef8aSMichael Große $text = str_replace($keysHash, $flatValues, $text); 13417dbef8aSMichael Große saveWikiText($pid, $text, 'Created by struct csv import'); 13517dbef8aSMichael Große } 13617dbef8aSMichael Große 13717dbef8aSMichael Große /** 13800043bffSMichael Große * Replace conditional <ifnotempty fieldname></ifnotempty> tags 13900043bffSMichael Große * 14000043bffSMichael Große * @param string $text The template 14100043bffSMichael Große * @param string[] $keys The array of qualified headers 14200043bffSMichael Große * @param string[] $values The flat array of corresponding values 14300043bffSMichael Große * 14400043bffSMichael Große * @return string The template with the tags replaced 14500043bffSMichael Große */ 14600043bffSMichael Große protected function evaluateIfNotEmptyTags($text, $keys, $values) 14700043bffSMichael Große { 14800043bffSMichael Große return preg_replace_callback( 14900043bffSMichael Große '/<ifnotempty (.+?)>([^<]*?)<\/ifnotempty>/', 150*d6d97f60SAnna Dabrowska function ($matches) use ($keys, $values) { 15100043bffSMichael Große list (,$blockKey, $textIfNotEmpty) = $matches; 15200043bffSMichael Große $index = array_search($blockKey, $keys, true); 15300043bffSMichael Große if ($index === false) { 15400043bffSMichael Große msg('Import error: Key "' . hsc($blockKey) . '" not found!', -1); 15500043bffSMichael Große return ''; 15600043bffSMichael Große } 15700043bffSMichael Große if (trim($values[$index]) === '') { 15800043bffSMichael Große return ''; 15900043bffSMichael Große } 16000043bffSMichael Große return $textIfNotEmpty; 16100043bffSMichael Große }, 16200043bffSMichael Große $text 16300043bffSMichael Große ); 16400043bffSMichael Große } 16500043bffSMichael Große 16600043bffSMichael Große /** 1671fc2361fSSzymon Olewniczak * In the paga schemas primary key is a touple of (pid, rev) 1681fc2361fSSzymon Olewniczak * 1691fc2361fSSzymon Olewniczak * @param string[] $values 1701fc2361fSSzymon Olewniczak * @param string $single 1711fc2361fSSzymon Olewniczak * @return array(pid, rev) 1721fc2361fSSzymon Olewniczak */ 173*d6d97f60SAnna Dabrowska protected function insertIntoSingle($values, $single) 174*d6d97f60SAnna Dabrowska { 1751fc2361fSSzymon Olewniczak $pid = $values[0]; 1761fc2361fSSzymon Olewniczak $rev = $values[count($values) - 1]; 177e53295c5SSzymon Olewniczak 178e53295c5SSzymon Olewniczak //update latest 179e53295c5SSzymon Olewniczak $table = $this->schema->getTable(); 180e53295c5SSzymon Olewniczak $this->sqlite->query("UPDATE data_$table SET latest = 0 WHERE latest = 1 AND pid = ?", array($pid)); 181e53295c5SSzymon Olewniczak 182e53295c5SSzymon Olewniczak //insert into table 183e53295c5SSzymon Olewniczak parent::insertIntoSingle($values, $single); 184e53295c5SSzymon Olewniczak 1851fc2361fSSzymon Olewniczak //primary key is touple of (pid, rev) 1861fc2361fSSzymon Olewniczak return array($pid, $rev); 1871fc2361fSSzymon Olewniczak } 1881fc2361fSSzymon Olewniczak 1891fc2361fSSzymon Olewniczak /** 1901fc2361fSSzymon Olewniczak * Add pid and rev to insert query parameters 1911fc2361fSSzymon Olewniczak * 1921fc2361fSSzymon Olewniczak * @param string $multi 1931fc2361fSSzymon Olewniczak * @param string $pk 1941fc2361fSSzymon Olewniczak * @param string $column 1951fc2361fSSzymon Olewniczak * @param string $row 1961fc2361fSSzymon Olewniczak * @param string $value 1971fc2361fSSzymon Olewniczak */ 198*d6d97f60SAnna Dabrowska protected function insertIntoMulti($multi, $pk, $column, $row, $value) 199*d6d97f60SAnna Dabrowska { 2001fc2361fSSzymon Olewniczak list($pid, $rev) = $pk; 201e53295c5SSzymon Olewniczak 202e53295c5SSzymon Olewniczak //update latest 203e53295c5SSzymon Olewniczak $table = $this->schema->getTable(); 204e53295c5SSzymon Olewniczak $this->sqlite->query("UPDATE multi_$table SET latest = 0 WHERE latest = 1 AND pid = ?", array($pid)); 205e53295c5SSzymon Olewniczak 2061fc2361fSSzymon Olewniczak $this->sqlite->query($multi, array($pid, $rev, $column->getColref(), $row + 1, $value)); 2071fc2361fSSzymon Olewniczak } 2081fc2361fSSzymon Olewniczak 2091fc2361fSSzymon Olewniczak /** 2101fc2361fSSzymon Olewniczak * In page schemas we use REPLACE instead of INSERT to prevent ambiguity 2111fc2361fSSzymon Olewniczak * 2121fc2361fSSzymon Olewniczak * @return string 2131fc2361fSSzymon Olewniczak */ 214*d6d97f60SAnna Dabrowska protected function getSQLforMultiValue() 215*d6d97f60SAnna Dabrowska { 2161fc2361fSSzymon Olewniczak $table = $this->schema->getTable(); 2171fc2361fSSzymon Olewniczak /** @noinspection SqlResolve */ 218e53295c5SSzymon Olewniczak return "INSERT INTO multi_$table (pid, rev, colref, row, value, latest) VALUES (?,?,?,?,?,1)"; 2191fc2361fSSzymon Olewniczak } 2201fc2361fSSzymon Olewniczak 2211fc2361fSSzymon Olewniczak /** 2221fc2361fSSzymon Olewniczak * Check if page id realy exists 2231fc2361fSSzymon Olewniczak * 2241fc2361fSSzymon Olewniczak * @param Column $col 2251fc2361fSSzymon Olewniczak * @param mixed $rawvalue 2261fc2361fSSzymon Olewniczak * @return bool 2271fc2361fSSzymon Olewniczak */ 228*d6d97f60SAnna Dabrowska protected function validateValue(Column $col, &$rawvalue) 229*d6d97f60SAnna Dabrowska { 230e53295c5SSzymon Olewniczak //check if page id exists and schema is bounded to the page 2311fc2361fSSzymon Olewniczak if ($col->getLabel() == 'pid') { 232e53295c5SSzymon Olewniczak $pid = cleanID($rawvalue); 233e53295c5SSzymon Olewniczak if (isset($this->importedPids[$pid])) { 234e53295c5SSzymon Olewniczak $this->errors[] = 'Page "' . $pid . '" already imported. Skipping the row.'; 235e53295c5SSzymon Olewniczak return false; 236e53295c5SSzymon Olewniczak } 237e53295c5SSzymon Olewniczak if (page_exists($pid)) { 238e53295c5SSzymon Olewniczak $this->importedPids[$pid] = true; 2391fc2361fSSzymon Olewniczak return true; 2401fc2361fSSzymon Olewniczak } 24117dbef8aSMichael Große global $INPUT; 24217dbef8aSMichael Große if ($INPUT->bool('createPage')) { 24317dbef8aSMichael Große $this->createPage[$pid] = true; 24417dbef8aSMichael Große return true; 24517dbef8aSMichael Große } 246e53295c5SSzymon Olewniczak $this->errors[] = 'Page "' . $pid . '" does not exists. Skipping the row.'; 2471fc2361fSSzymon Olewniczak return false; 2481fc2361fSSzymon Olewniczak } 2491fc2361fSSzymon Olewniczak 2501fc2361fSSzymon Olewniczak return parent::validateValue($col, $rawvalue); 2511fc2361fSSzymon Olewniczak } 2521fc2361fSSzymon Olewniczak} 253