1083afc55SAndreas Gohr<?php 2083afc55SAndreas Gohr 3083afc55SAndreas Gohrnamespace plugin\struct\meta; 4bbf3d6aaSAndreas Gohruse plugin\struct\types\AbstractBaseType; 5083afc55SAndreas Gohr 67182938bSAndreas Gohr/** 77182938bSAndreas Gohr * Class Schema 87182938bSAndreas Gohr * 97182938bSAndreas Gohr * Represents the schema of a single data table and all its properties. It defines what can be stored in 107182938bSAndreas Gohr * the represented data table and how those contents are formatted. 117182938bSAndreas Gohr * 127182938bSAndreas Gohr * It can be initialized with a timestamp to access the schema as it looked at that particular point in time. 137182938bSAndreas Gohr * 147182938bSAndreas Gohr * @package plugin\struct\meta 157182938bSAndreas Gohr */ 16083afc55SAndreas Gohrclass Schema { 17083afc55SAndreas Gohr 18083afc55SAndreas Gohr /** @var \helper_plugin_sqlite|null */ 19083afc55SAndreas Gohr protected $sqlite; 20083afc55SAndreas Gohr 21083afc55SAndreas Gohr /** @var int The ID of this schema */ 22083afc55SAndreas Gohr protected $id = 0; 23083afc55SAndreas Gohr 24083afc55SAndreas Gohr /** @var string name of the associated table */ 25083afc55SAndreas Gohr protected $table = ''; 26083afc55SAndreas Gohr 27083afc55SAndreas Gohr /** 28083afc55SAndreas Gohr * @var string the current checksum of this schema 29083afc55SAndreas Gohr */ 30083afc55SAndreas Gohr protected $chksum = ''; 31083afc55SAndreas Gohr 321c502704SAndreas Gohr /** @var Column[] all the colums */ 33083afc55SAndreas Gohr protected $columns = array(); 34083afc55SAndreas Gohr 35083afc55SAndreas Gohr /** @var int */ 36083afc55SAndreas Gohr protected $maxsort = 0; 37083afc55SAndreas Gohr 38250c83c2SAndreas Gohr /** @var int */ 39250c83c2SAndreas Gohr protected $ts = 0; 40250c83c2SAndreas Gohr 41083afc55SAndreas Gohr /** 42083afc55SAndreas Gohr * Schema constructor 437182938bSAndreas Gohr * 44083afc55SAndreas Gohr * @param string $table The table this schema is for 45083afc55SAndreas Gohr * @param int $ts The timestamp for when this schema was valid, 0 for current 46083afc55SAndreas Gohr */ 47083afc55SAndreas Gohr public function __construct($table, $ts = 0) { 48083afc55SAndreas Gohr /** @var \helper_plugin_struct_db $helper */ 49083afc55SAndreas Gohr $helper = plugin_load('helper', 'struct_db'); 50083afc55SAndreas Gohr $this->sqlite = $helper->getDB(); 51083afc55SAndreas Gohr if(!$this->sqlite) return; 52083afc55SAndreas Gohr 53083afc55SAndreas Gohr $table = self::cleanTableName($table); 54083afc55SAndreas Gohr $this->table = $table; 55250c83c2SAndreas Gohr $this->ts = $ts; 56083afc55SAndreas Gohr 57083afc55SAndreas Gohr // load info about the schema itself 58083afc55SAndreas Gohr if($ts) { 59083afc55SAndreas Gohr $sql = "SELECT * 60083afc55SAndreas Gohr FROM schemas 61083afc55SAndreas Gohr WHERE tbl = ? 62083afc55SAndreas Gohr AND ts <= ? 63083afc55SAndreas Gohr ORDER BY ts DESC 64083afc55SAndreas Gohr LIMIT 1"; 65083afc55SAndreas Gohr $opt = array($table, $ts); 66083afc55SAndreas Gohr } else { 67083afc55SAndreas Gohr $sql = "SELECT * 68083afc55SAndreas Gohr FROM schemas 69083afc55SAndreas Gohr WHERE tbl = ? 70083afc55SAndreas Gohr ORDER BY ts DESC 71083afc55SAndreas Gohr LIMIT 1"; 72083afc55SAndreas Gohr $opt = array($table); 73083afc55SAndreas Gohr } 74083afc55SAndreas Gohr $res = $this->sqlite->query($sql, $opt); 75083afc55SAndreas Gohr if($this->sqlite->res2count($res)) { 764e2abec0SMichael Große $schema = $this->sqlite->res2arr($res); 774e2abec0SMichael Große $result = array_shift($schema); 78083afc55SAndreas Gohr $this->id = $result['id']; 79083afc55SAndreas Gohr $this->chksum = $result['chksum']; 80083afc55SAndreas Gohr 81083afc55SAndreas Gohr } 82083afc55SAndreas Gohr $this->sqlite->res_close($res); 83083afc55SAndreas Gohr if(!$this->id) return; 84083afc55SAndreas Gohr 85083afc55SAndreas Gohr // load existing columns 86083afc55SAndreas Gohr $sql = "SELECT SC.*, T.* 87083afc55SAndreas Gohr FROM schema_cols SC, 88083afc55SAndreas Gohr types T 891c502704SAndreas Gohr WHERE SC.sid = ? 901c502704SAndreas Gohr AND SC.tid = T.id 91083afc55SAndreas Gohr ORDER BY SC.sort"; 921c502704SAndreas Gohr $res = $this->sqlite->query($sql, $this->id); 93083afc55SAndreas Gohr $rows = $this->sqlite->res2arr($res); 94083afc55SAndreas Gohr $this->sqlite->res_close($res); 95083afc55SAndreas Gohr 96083afc55SAndreas Gohr foreach($rows as $row) { 971c502704SAndreas Gohr $class = 'plugin\\struct\\types\\' . $row['class']; 9898eaa57dSAndreas Gohr if(!class_exists($class)) { 9998eaa57dSAndreas Gohr // This usually never happens, except during development 10098eaa57dSAndreas Gohr msg('Unknown type "'.hsc($row['class']).'" falling back to Text', -1); 10198eaa57dSAndreas Gohr $class = 'plugin\\struct\\types\\Text'; 10298eaa57dSAndreas Gohr } 10398eaa57dSAndreas Gohr 104083afc55SAndreas Gohr $config = json_decode($row['config'], true); 105bbf3d6aaSAndreas Gohr /** @var AbstractBaseType $type */ 106bbf3d6aaSAndreas Gohr $type = new $class($config, $row['label'], $row['ismulti'], $row['tid']); 107bbf3d6aaSAndreas Gohr $column = new Column( 1081c502704SAndreas Gohr $row['sort'], 109bbf3d6aaSAndreas Gohr $type, 1101c502704SAndreas Gohr $row['colref'], 11163d51bbfSAndreas Gohr $row['enabled'], 11263d51bbfSAndreas Gohr $table 1131c502704SAndreas Gohr ); 114bbf3d6aaSAndreas Gohr $type->setContext($column); 1151c502704SAndreas Gohr 116bbf3d6aaSAndreas Gohr $this->columns[$row['colref']] = $column; 117083afc55SAndreas Gohr if($row['sort'] > $this->maxsort) $this->maxsort = $row['sort']; 118083afc55SAndreas Gohr } 119083afc55SAndreas Gohr } 120083afc55SAndreas Gohr 121083afc55SAndreas Gohr /** 122083afc55SAndreas Gohr * Cleans any unwanted stuff from table names 123083afc55SAndreas Gohr * 124083afc55SAndreas Gohr * @param string $table 125083afc55SAndreas Gohr * @return string 126083afc55SAndreas Gohr */ 127083afc55SAndreas Gohr static public function cleanTableName($table) { 1282af472dcSAndreas Gohr $table = strtolower($table); 129083afc55SAndreas Gohr $table = preg_replace('/[^a-z0-9_]+/', '', $table); 130083afc55SAndreas Gohr $table = preg_replace('/^[0-9_]+/', '', $table); 131083afc55SAndreas Gohr $table = trim($table); 132083afc55SAndreas Gohr return $table; 133083afc55SAndreas Gohr } 134083afc55SAndreas Gohr 135083afc55SAndreas Gohr /** 136*097f4a53SAndreas Gohr * Gets a list of all available schemas 137*097f4a53SAndreas Gohr * 138*097f4a53SAndreas Gohr * @return string[] 139*097f4a53SAndreas Gohr */ 140*097f4a53SAndreas Gohr static public function getAll() { 141*097f4a53SAndreas Gohr /** @var \helper_plugin_struct_db $helper */ 142*097f4a53SAndreas Gohr $helper = plugin_load('helper', 'struct_db'); 143*097f4a53SAndreas Gohr $db = $helper->getDB(); 144*097f4a53SAndreas Gohr if(!$db) return array(); 145*097f4a53SAndreas Gohr 146*097f4a53SAndreas Gohr $res = $db->query("SELECT DISTINCT tbl FROM schemas ORDER BY tbl"); 147*097f4a53SAndreas Gohr $tables = $db->res2arr($res); 148*097f4a53SAndreas Gohr $db->res_close($res); 149*097f4a53SAndreas Gohr 150*097f4a53SAndreas Gohr $result = array(); 151*097f4a53SAndreas Gohr foreach($tables as $row) { 152*097f4a53SAndreas Gohr $result[] = $row['tbl']; 153*097f4a53SAndreas Gohr } 154*097f4a53SAndreas Gohr return $result; 155*097f4a53SAndreas Gohr } 156*097f4a53SAndreas Gohr 157*097f4a53SAndreas Gohr /** 1581c502704SAndreas Gohr * @return string 1591c502704SAndreas Gohr */ 1601c502704SAndreas Gohr public function getChksum() { 1611c502704SAndreas Gohr return $this->chksum; 1621c502704SAndreas Gohr } 1631c502704SAndreas Gohr 1641c502704SAndreas Gohr /** 1651c502704SAndreas Gohr * @return int 1661c502704SAndreas Gohr */ 1671c502704SAndreas Gohr public function getId() { 1681c502704SAndreas Gohr return $this->id; 1691c502704SAndreas Gohr } 1701c502704SAndreas Gohr 1711c502704SAndreas Gohr /** 172ce206ec7SAndreas Gohr * Returns a list of columns in this schema 173ce206ec7SAndreas Gohr * 174ce206ec7SAndreas Gohr * @param bool $withDisabled if false, disabled columns will not be returned 175ce206ec7SAndreas Gohr * @return Column[] 1761c502704SAndreas Gohr */ 177ce206ec7SAndreas Gohr public function getColumns($withDisabled = true) { 178ce206ec7SAndreas Gohr if(!$withDisabled) { 179ce206ec7SAndreas Gohr return array_filter( 180ce206ec7SAndreas Gohr $this->columns, 181ce206ec7SAndreas Gohr function (Column $col) { 182ce206ec7SAndreas Gohr return $col->isEnabled(); 183ce206ec7SAndreas Gohr } 184ce206ec7SAndreas Gohr ); 185ce206ec7SAndreas Gohr } 186ce206ec7SAndreas Gohr 1871c502704SAndreas Gohr return $this->columns; 1881c502704SAndreas Gohr } 1891c502704SAndreas Gohr 190ae697e1fSAndreas Gohr /** 1915742aea9SAndreas Gohr * Find a column in the schema by its label 1925742aea9SAndreas Gohr * 1935742aea9SAndreas Gohr * Only enabled columns are returned! 1945742aea9SAndreas Gohr * 1955742aea9SAndreas Gohr * @param $name 1965742aea9SAndreas Gohr * @return bool|Column 1975742aea9SAndreas Gohr */ 1985742aea9SAndreas Gohr public function findColumn($name) { 1995742aea9SAndreas Gohr foreach($this->columns as $col) { 2005742aea9SAndreas Gohr if($col->isEnabled() && utf8_strtolower($col->getLabel()) == utf8_strtolower($name)) { 2015742aea9SAndreas Gohr return $col; 2025742aea9SAndreas Gohr } 2035742aea9SAndreas Gohr } 2045742aea9SAndreas Gohr return false; 2055742aea9SAndreas Gohr } 2065742aea9SAndreas Gohr 2075742aea9SAndreas Gohr /** 208ae697e1fSAndreas Gohr * @return string 209ae697e1fSAndreas Gohr */ 210ae697e1fSAndreas Gohr public function getTable() { 211ae697e1fSAndreas Gohr return $this->table; 212ae697e1fSAndreas Gohr } 2131c502704SAndreas Gohr 214ae697e1fSAndreas Gohr /** 215ae697e1fSAndreas Gohr * @return int the highest sort number used in this schema 216ae697e1fSAndreas Gohr */ 217ae697e1fSAndreas Gohr public function getMaxsort() { 218ae697e1fSAndreas Gohr return $this->maxsort; 219ae697e1fSAndreas Gohr } 2201c502704SAndreas Gohr 221083afc55SAndreas Gohr} 222