1<?php 2 3namespace dokuwiki\plugin\struct\meta; 4 5/** 6 * Class AccessTableSerial 7 * 8 * Load and (more importantly) save serial data 9 * 10 * @package dokuwiki\plugin\struct\meta 11 */ 12class AccessTableSerial extends AccessTable { 13 14 /** 15 * Remove the current data 16 */ 17 public function clearData() { 18 if(!$this->rid || !$this->pid) return; // no data 19 20 /** @noinspection SqlResolve */ 21 $sql = 'DELETE FROM ? WHERE pid = ? AND rid = ?'; 22 $this->sqlite->query($sql, 'data_'.$this->schema->getTable(), $this->pid, $this->rid); 23 $this->sqlite->query($sql, 'multi_'.$this->schema->getTable(), $this->pid, $this->rid); 24 } 25 26 /** 27 * Save the data to the database. 28 * 29 * We differentiate between single-value-column and multi-value-column by the value to the respective column-name, 30 * i.e. depending on if that is a string or an array, respectively. 31 * 32 * @param array $data typelabel => value for single fields or typelabel => array(value, value, ...) for multi fields 33 * @return bool success of saving the data to the database 34 * @todo this duplicates quite a bit code from AccessTableData - could we avoid that? 35 */ 36 public function saveData($data) { 37 $stable = 'data_' . $this->schema->getTable(); 38 $mtable = 'multi_' . $this->schema->getTable(); 39 40 // we do not store completely empty rows 41 $isempty = array_reduce($data, function ($isempty, $cell) { 42 return $isempty && ($cell === '' || $cell === array() || $cell === null); 43 }, true); 44 if($isempty) return false; 45 46 $singlecols = ['pid', 'rev', 'latest']; 47 $opt = [$this->pid, 0, 1]; 48 49 $colrefs = array_flip($this->labels); 50 $multiopts = array(); 51 foreach($data as $colname => $value) { 52 if(!isset($colrefs[$colname])) { 53 throw new StructException("Unknown column %s in schema.", hsc($colname)); 54 } 55 56 $singlecols[] = 'col' . $colrefs[$colname]; 57 if(is_array($value)) { 58 foreach($value as $index => $multivalue) { 59 $multiopts[] = array($colrefs[$colname], $index + 1, $multivalue,); 60 } 61 // copy first value to the single column 62 if(isset($value[0])) { 63 $opt[] = $value[0]; 64 } else { 65 $opt[] = null; 66 } 67 } else { 68 $opt[] = $value; 69 } 70 } 71 72 // FIXME select pid too 73 $ridSingle = "(SELECT (COALESCE(MAX(rid), 0 ) + 1) FROM $stable)"; 74 $ridMulti = "(SELECT (COALESCE(MAX(rid), 0 ) + 1) FROM $mtable)"; 75 76 $singlesql = "REPLACE INTO $stable (rid, " . join(',', $singlecols) . ") VALUES ($ridSingle, " . trim(str_repeat('?,', count($opt)), ',') . ")"; 77 /** @noinspection SqlResolve */ 78 $multisql = "REPLACE INTO $mtable (rid, colref, row, value) VALUES ($ridMulti,?,?,?,?)"; 79 80 $this->sqlite->query('BEGIN TRANSACTION'); 81 $ok = true; 82 83 // insert single values 84 $ok = $ok && $this->sqlite->query($singlesql, $opt); 85 86 // get new rid if this is a new insert 87 if($ok && !$this->rid) { 88 $res = $this->sqlite->query('SELECT last_insert_rowid()'); 89 $this->rid = $this->sqlite->res2single($res); 90 $this->sqlite->res_close($res); 91 if(!$this->rid) $ok = false; 92 } 93 94 // insert multi values 95 if($ok) foreach($multiopts as $multiopt) { 96 $multiopt = array_merge(array($this->rid,$this->pid), $multiopt); 97 $ok = $ok && $this->sqlite->query($multisql, $multiopt); 98 } 99 100 if(!$ok) { 101 $this->sqlite->query('ROLLBACK TRANSACTION'); 102 return false; 103 } 104 $this->sqlite->query('COMMIT TRANSACTION'); 105 return true; 106 } 107 108 protected function getLastRevisionTimestamp() { 109 return 0; 110 } 111 112} 113