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 $config = json_decode($row['config'], true); 98 $this->columns[$row['colref']] = 99 new Column( 100 $row['sort'], 101 new $class($config, $row['label'], $row['ismulti'], $row['tid']), 102 $row['colref'], 103 $row['enabled'], 104 $table 105 ); 106 107 if($row['sort'] > $this->maxsort) $this->maxsort = $row['sort']; 108 } 109 } 110 111 /** 112 * Cleans any unwanted stuff from table names 113 * 114 * @param string $table 115 * @return string 116 */ 117 static public function cleanTableName($table) { 118 $table = strtolower($table); 119 $table = preg_replace('/[^a-z0-9_]+/', '', $table); 120 $table = preg_replace('/^[0-9_]+/', '', $table); 121 $table = trim($table); 122 return $table; 123 } 124 125 /** 126 * @return string 127 */ 128 public function getChksum() { 129 return $this->chksum; 130 } 131 132 /** 133 * @return int 134 */ 135 public function getId() { 136 return $this->id; 137 } 138 139 /** 140 * Returns a list of columns in this schema 141 * 142 * @param bool $withDisabled if false, disabled columns will not be returned 143 * @return Column[] 144 */ 145 public function getColumns($withDisabled = true) { 146 if(!$withDisabled) { 147 return array_filter( 148 $this->columns, 149 function (Column $col) { 150 return $col->isEnabled(); 151 } 152 ); 153 } 154 155 return $this->columns; 156 } 157 158 /** 159 * Find a column in the schema by its label 160 * 161 * Only enabled columns are returned! 162 * 163 * @param $name 164 * @return bool|Column 165 */ 166 public function findColumn($name) { 167 foreach($this->columns as $col) { 168 if($col->isEnabled() && utf8_strtolower($col->getLabel()) == utf8_strtolower($name)) { 169 return $col; 170 } 171 } 172 return false; 173 } 174 175 /** 176 * @return string 177 */ 178 public function getTable() { 179 return $this->table; 180 } 181 182 /** 183 * @return int the highest sort number used in this schema 184 */ 185 public function getMaxsort() { 186 return $this->maxsort; 187 } 188 189} 190