1<?php 2 3namespace plugin\struct\meta; 4 5/** 6 * Class Schema 7 * 8 * Represents the schema of a single data table and all its properties. It defines what can be stored in 9 * the represented data table and how those contents are formatted. 10 * 11 * It can be initialized with a timestamp to access the schema as it looked at that particular point in time. 12 * 13 * @package plugin\struct\meta 14 */ 15class Schema { 16 17 /** @var \helper_plugin_sqlite|null */ 18 protected $sqlite; 19 20 /** @var int The ID of this schema */ 21 protected $id = 0; 22 23 /** @var string name of the associated table */ 24 protected $table = ''; 25 26 /** 27 * @var string the current checksum of this schema 28 */ 29 protected $chksum = ''; 30 31 /** @var Column[] all the colums */ 32 protected $columns = array(); 33 34 /** @var int */ 35 protected $maxsort = 0; 36 37 /** @var int */ 38 protected $ts = 0; 39 40 /** 41 * Schema constructor 42 * 43 * @param string $table The table this schema is for 44 * @param int $ts The timestamp for when this schema was valid, 0 for current 45 */ 46 public function __construct($table, $ts = 0) { 47 /** @var \helper_plugin_struct_db $helper */ 48 $helper = plugin_load('helper', 'struct_db'); 49 $this->sqlite = $helper->getDB(); 50 if(!$this->sqlite) return; 51 52 $table = self::cleanTableName($table); 53 $this->table = $table; 54 $this->ts = $ts; 55 56 // load info about the schema itself 57 if($ts) { 58 $sql = "SELECT * 59 FROM schemas 60 WHERE tbl = ? 61 AND ts <= ? 62 ORDER BY ts DESC 63 LIMIT 1"; 64 $opt = array($table, $ts); 65 } else { 66 $sql = "SELECT * 67 FROM schemas 68 WHERE tbl = ? 69 ORDER BY ts DESC 70 LIMIT 1"; 71 $opt = array($table); 72 } 73 $res = $this->sqlite->query($sql, $opt); 74 if($this->sqlite->res2count($res)) { 75 $schema = $this->sqlite->res2arr($res); 76 $result = array_shift($schema); 77 $this->id = $result['id']; 78 $this->chksum = $result['chksum']; 79 80 } 81 $this->sqlite->res_close($res); 82 if(!$this->id) return; 83 84 // load existing columns 85 $sql = "SELECT SC.*, T.* 86 FROM schema_cols SC, 87 types T 88 WHERE SC.sid = ? 89 AND SC.tid = T.id 90 ORDER BY SC.sort"; 91 $res = $this->sqlite->query($sql, $this->id); 92 $rows = $this->sqlite->res2arr($res); 93 $this->sqlite->res_close($res); 94 95 foreach($rows as $row) { 96 $class = 'plugin\\struct\\types\\' . $row['class']; 97 if(!class_exists($class)) { 98 // This usually never happens, except during development 99 msg('Unknown type "'.hsc($row['class']).'" falling back to Text', -1); 100 $class = 'plugin\\struct\\types\\Text'; 101 } 102 103 $config = json_decode($row['config'], true); 104 $this->columns[$row['colref']] = 105 new Column( 106 $row['sort'], 107 new $class($config, $row['label'], $row['ismulti'], $row['tid']), 108 $row['colref'], 109 $row['enabled'], 110 $table 111 ); 112 113 if($row['sort'] > $this->maxsort) $this->maxsort = $row['sort']; 114 } 115 } 116 117 /** 118 * Cleans any unwanted stuff from table names 119 * 120 * @param string $table 121 * @return string 122 */ 123 static public function cleanTableName($table) { 124 $table = strtolower($table); 125 $table = preg_replace('/[^a-z0-9_]+/', '', $table); 126 $table = preg_replace('/^[0-9_]+/', '', $table); 127 $table = trim($table); 128 return $table; 129 } 130 131 /** 132 * @return string 133 */ 134 public function getChksum() { 135 return $this->chksum; 136 } 137 138 /** 139 * @return int 140 */ 141 public function getId() { 142 return $this->id; 143 } 144 145 /** 146 * Returns a list of columns in this schema 147 * 148 * @param bool $withDisabled if false, disabled columns will not be returned 149 * @return Column[] 150 */ 151 public function getColumns($withDisabled = true) { 152 if(!$withDisabled) { 153 return array_filter( 154 $this->columns, 155 function (Column $col) { 156 return $col->isEnabled(); 157 } 158 ); 159 } 160 161 return $this->columns; 162 } 163 164 /** 165 * Find a column in the schema by its label 166 * 167 * Only enabled columns are returned! 168 * 169 * @param $name 170 * @return bool|Column 171 */ 172 public function findColumn($name) { 173 foreach($this->columns as $col) { 174 if($col->isEnabled() && utf8_strtolower($col->getLabel()) == utf8_strtolower($name)) { 175 return $col; 176 } 177 } 178 return false; 179 } 180 181 /** 182 * @return string 183 */ 184 public function getTable() { 185 return $this->table; 186 } 187 188 /** 189 * @return int the highest sort number used in this schema 190 */ 191 public function getMaxsort() { 192 return $this->maxsort; 193 } 194 195} 196