1083afc55SAndreas Gohr<?php 2083afc55SAndreas Gohr 3083afc55SAndreas Gohrnamespace plugin\struct\meta; 4*d486d6d7SAndreas Gohr 5bbf3d6aaSAndreas Gohruse plugin\struct\types\AbstractBaseType; 6083afc55SAndreas Gohr 77182938bSAndreas Gohr/** 87182938bSAndreas Gohr * Class Schema 97182938bSAndreas Gohr * 107182938bSAndreas Gohr * Represents the schema of a single data table and all its properties. It defines what can be stored in 117182938bSAndreas Gohr * the represented data table and how those contents are formatted. 127182938bSAndreas Gohr * 137182938bSAndreas Gohr * It can be initialized with a timestamp to access the schema as it looked at that particular point in time. 147182938bSAndreas Gohr * 157182938bSAndreas Gohr * @package plugin\struct\meta 167182938bSAndreas Gohr */ 17083afc55SAndreas Gohrclass Schema { 18083afc55SAndreas Gohr 19083afc55SAndreas Gohr /** @var \helper_plugin_sqlite|null */ 20083afc55SAndreas Gohr protected $sqlite; 21083afc55SAndreas Gohr 22083afc55SAndreas Gohr /** @var int The ID of this schema */ 23083afc55SAndreas Gohr protected $id = 0; 24083afc55SAndreas Gohr 25083afc55SAndreas Gohr /** @var string name of the associated table */ 26083afc55SAndreas Gohr protected $table = ''; 27083afc55SAndreas Gohr 28083afc55SAndreas Gohr /** 29083afc55SAndreas Gohr * @var string the current checksum of this schema 30083afc55SAndreas Gohr */ 31083afc55SAndreas Gohr protected $chksum = ''; 32083afc55SAndreas Gohr 331c502704SAndreas Gohr /** @var Column[] all the colums */ 34083afc55SAndreas Gohr protected $columns = array(); 35083afc55SAndreas Gohr 36083afc55SAndreas Gohr /** @var int */ 37083afc55SAndreas Gohr protected $maxsort = 0; 38083afc55SAndreas Gohr 39250c83c2SAndreas Gohr /** @var int */ 40250c83c2SAndreas Gohr protected $ts = 0; 41250c83c2SAndreas Gohr 42*d486d6d7SAndreas Gohr /** @var string struct version info */ 43*d486d6d7SAndreas Gohr protected $structversion = '?'; 44*d486d6d7SAndreas Gohr 45083afc55SAndreas Gohr /** 46083afc55SAndreas Gohr * Schema constructor 477182938bSAndreas Gohr * 48083afc55SAndreas Gohr * @param string $table The table this schema is for 49083afc55SAndreas Gohr * @param int $ts The timestamp for when this schema was valid, 0 for current 50083afc55SAndreas Gohr */ 51083afc55SAndreas Gohr public function __construct($table, $ts = 0) { 52083afc55SAndreas Gohr /** @var \helper_plugin_struct_db $helper */ 53083afc55SAndreas Gohr $helper = plugin_load('helper', 'struct_db'); 54*d486d6d7SAndreas Gohr $info = $helper->getInfo(); 55*d486d6d7SAndreas Gohr $this->structversion = $info['date']; 56083afc55SAndreas Gohr $this->sqlite = $helper->getDB(); 57083afc55SAndreas Gohr if(!$this->sqlite) return; 58083afc55SAndreas Gohr 59083afc55SAndreas Gohr $table = self::cleanTableName($table); 60083afc55SAndreas Gohr $this->table = $table; 61250c83c2SAndreas Gohr $this->ts = $ts; 62083afc55SAndreas Gohr 63083afc55SAndreas Gohr // load info about the schema itself 64083afc55SAndreas Gohr if($ts) { 65083afc55SAndreas Gohr $sql = "SELECT * 66083afc55SAndreas Gohr FROM schemas 67083afc55SAndreas Gohr WHERE tbl = ? 68083afc55SAndreas Gohr AND ts <= ? 69083afc55SAndreas Gohr ORDER BY ts DESC 70083afc55SAndreas Gohr LIMIT 1"; 71083afc55SAndreas Gohr $opt = array($table, $ts); 72083afc55SAndreas Gohr } else { 73083afc55SAndreas Gohr $sql = "SELECT * 74083afc55SAndreas Gohr FROM schemas 75083afc55SAndreas Gohr WHERE tbl = ? 76083afc55SAndreas Gohr ORDER BY ts DESC 77083afc55SAndreas Gohr LIMIT 1"; 78083afc55SAndreas Gohr $opt = array($table); 79083afc55SAndreas Gohr } 80083afc55SAndreas Gohr $res = $this->sqlite->query($sql, $opt); 81083afc55SAndreas Gohr if($this->sqlite->res2count($res)) { 824e2abec0SMichael Große $schema = $this->sqlite->res2arr($res); 834e2abec0SMichael Große $result = array_shift($schema); 84083afc55SAndreas Gohr $this->id = $result['id']; 85083afc55SAndreas Gohr $this->chksum = $result['chksum']; 86083afc55SAndreas Gohr } 87083afc55SAndreas Gohr $this->sqlite->res_close($res); 88083afc55SAndreas Gohr if(!$this->id) return; 89083afc55SAndreas Gohr 90083afc55SAndreas Gohr // load existing columns 91083afc55SAndreas Gohr $sql = "SELECT SC.*, T.* 92083afc55SAndreas Gohr FROM schema_cols SC, 93083afc55SAndreas Gohr types T 941c502704SAndreas Gohr WHERE SC.sid = ? 951c502704SAndreas Gohr AND SC.tid = T.id 96083afc55SAndreas Gohr ORDER BY SC.sort"; 971c502704SAndreas Gohr $res = $this->sqlite->query($sql, $this->id); 98083afc55SAndreas Gohr $rows = $this->sqlite->res2arr($res); 99083afc55SAndreas Gohr $this->sqlite->res_close($res); 100083afc55SAndreas Gohr 101083afc55SAndreas Gohr foreach($rows as $row) { 1021c502704SAndreas Gohr $class = 'plugin\\struct\\types\\' . $row['class']; 10398eaa57dSAndreas Gohr if(!class_exists($class)) { 10498eaa57dSAndreas Gohr // This usually never happens, except during development 10598eaa57dSAndreas Gohr msg('Unknown type "' . hsc($row['class']) . '" falling back to Text', -1); 10698eaa57dSAndreas Gohr $class = 'plugin\\struct\\types\\Text'; 10798eaa57dSAndreas Gohr } 10898eaa57dSAndreas Gohr 109083afc55SAndreas Gohr $config = json_decode($row['config'], true); 110bbf3d6aaSAndreas Gohr /** @var AbstractBaseType $type */ 111bbf3d6aaSAndreas Gohr $type = new $class($config, $row['label'], $row['ismulti'], $row['tid']); 112bbf3d6aaSAndreas Gohr $column = new Column( 1131c502704SAndreas Gohr $row['sort'], 114bbf3d6aaSAndreas Gohr $type, 1151c502704SAndreas Gohr $row['colref'], 11663d51bbfSAndreas Gohr $row['enabled'], 11763d51bbfSAndreas Gohr $table 1181c502704SAndreas Gohr ); 119bbf3d6aaSAndreas Gohr $type->setContext($column); 1201c502704SAndreas Gohr 121bbf3d6aaSAndreas Gohr $this->columns[$row['colref']] = $column; 122083afc55SAndreas Gohr if($row['sort'] > $this->maxsort) $this->maxsort = $row['sort']; 123083afc55SAndreas Gohr } 124083afc55SAndreas Gohr } 125083afc55SAndreas Gohr 126083afc55SAndreas Gohr /** 127083afc55SAndreas Gohr * Cleans any unwanted stuff from table names 128083afc55SAndreas Gohr * 129083afc55SAndreas Gohr * @param string $table 130083afc55SAndreas Gohr * @return string 131083afc55SAndreas Gohr */ 132083afc55SAndreas Gohr static public function cleanTableName($table) { 1332af472dcSAndreas Gohr $table = strtolower($table); 134083afc55SAndreas Gohr $table = preg_replace('/[^a-z0-9_]+/', '', $table); 135083afc55SAndreas Gohr $table = preg_replace('/^[0-9_]+/', '', $table); 136083afc55SAndreas Gohr $table = trim($table); 137083afc55SAndreas Gohr return $table; 138083afc55SAndreas Gohr } 139083afc55SAndreas Gohr 140083afc55SAndreas Gohr /** 141097f4a53SAndreas Gohr * Gets a list of all available schemas 142097f4a53SAndreas Gohr * 143097f4a53SAndreas Gohr * @return string[] 144097f4a53SAndreas Gohr */ 145097f4a53SAndreas Gohr static public function getAll() { 146097f4a53SAndreas Gohr /** @var \helper_plugin_struct_db $helper */ 147097f4a53SAndreas Gohr $helper = plugin_load('helper', 'struct_db'); 148097f4a53SAndreas Gohr $db = $helper->getDB(); 149097f4a53SAndreas Gohr if(!$db) return array(); 150097f4a53SAndreas Gohr 151097f4a53SAndreas Gohr $res = $db->query("SELECT DISTINCT tbl FROM schemas ORDER BY tbl"); 152097f4a53SAndreas Gohr $tables = $db->res2arr($res); 153097f4a53SAndreas Gohr $db->res_close($res); 154097f4a53SAndreas Gohr 155097f4a53SAndreas Gohr $result = array(); 156097f4a53SAndreas Gohr foreach($tables as $row) { 157097f4a53SAndreas Gohr $result[] = $row['tbl']; 158097f4a53SAndreas Gohr } 159097f4a53SAndreas Gohr return $result; 160097f4a53SAndreas Gohr } 161097f4a53SAndreas Gohr 162097f4a53SAndreas Gohr /** 1631c502704SAndreas Gohr * @return string 1641c502704SAndreas Gohr */ 1651c502704SAndreas Gohr public function getChksum() { 1661c502704SAndreas Gohr return $this->chksum; 1671c502704SAndreas Gohr } 1681c502704SAndreas Gohr 1691c502704SAndreas Gohr /** 1701c502704SAndreas Gohr * @return int 1711c502704SAndreas Gohr */ 1721c502704SAndreas Gohr public function getId() { 1731c502704SAndreas Gohr return $this->id; 1741c502704SAndreas Gohr } 1751c502704SAndreas Gohr 1761c502704SAndreas Gohr /** 177ce206ec7SAndreas Gohr * Returns a list of columns in this schema 178ce206ec7SAndreas Gohr * 179ce206ec7SAndreas Gohr * @param bool $withDisabled if false, disabled columns will not be returned 180ce206ec7SAndreas Gohr * @return Column[] 1811c502704SAndreas Gohr */ 182ce206ec7SAndreas Gohr public function getColumns($withDisabled = true) { 183ce206ec7SAndreas Gohr if(!$withDisabled) { 184ce206ec7SAndreas Gohr return array_filter( 185ce206ec7SAndreas Gohr $this->columns, 186ce206ec7SAndreas Gohr function (Column $col) { 187ce206ec7SAndreas Gohr return $col->isEnabled(); 188ce206ec7SAndreas Gohr } 189ce206ec7SAndreas Gohr ); 190ce206ec7SAndreas Gohr } 191ce206ec7SAndreas Gohr 1921c502704SAndreas Gohr return $this->columns; 1931c502704SAndreas Gohr } 1941c502704SAndreas Gohr 195ae697e1fSAndreas Gohr /** 1965742aea9SAndreas Gohr * Find a column in the schema by its label 1975742aea9SAndreas Gohr * 1985742aea9SAndreas Gohr * Only enabled columns are returned! 1995742aea9SAndreas Gohr * 2005742aea9SAndreas Gohr * @param $name 2015742aea9SAndreas Gohr * @return bool|Column 2025742aea9SAndreas Gohr */ 2035742aea9SAndreas Gohr public function findColumn($name) { 2045742aea9SAndreas Gohr foreach($this->columns as $col) { 2055742aea9SAndreas Gohr if($col->isEnabled() && utf8_strtolower($col->getLabel()) == utf8_strtolower($name)) { 2065742aea9SAndreas Gohr return $col; 2075742aea9SAndreas Gohr } 2085742aea9SAndreas Gohr } 2095742aea9SAndreas Gohr return false; 2105742aea9SAndreas Gohr } 2115742aea9SAndreas Gohr 2125742aea9SAndreas Gohr /** 213ae697e1fSAndreas Gohr * @return string 214ae697e1fSAndreas Gohr */ 215ae697e1fSAndreas Gohr public function getTable() { 216ae697e1fSAndreas Gohr return $this->table; 217ae697e1fSAndreas Gohr } 2181c502704SAndreas Gohr 219ae697e1fSAndreas Gohr /** 220ae697e1fSAndreas Gohr * @return int the highest sort number used in this schema 221ae697e1fSAndreas Gohr */ 222ae697e1fSAndreas Gohr public function getMaxsort() { 223ae697e1fSAndreas Gohr return $this->maxsort; 224ae697e1fSAndreas Gohr } 2251c502704SAndreas Gohr 226*d486d6d7SAndreas Gohr /** 227*d486d6d7SAndreas Gohr * @return string the JSON representing this schema 228*d486d6d7SAndreas Gohr */ 229*d486d6d7SAndreas Gohr public function toJSON() { 230*d486d6d7SAndreas Gohr $data = array( 231*d486d6d7SAndreas Gohr 'structversion' => $this->structversion, 232*d486d6d7SAndreas Gohr 'schema' => $this->getTable(), 233*d486d6d7SAndreas Gohr 'id' => $this->getId(), 234*d486d6d7SAndreas Gohr 'columns' => array() 235*d486d6d7SAndreas Gohr ); 236*d486d6d7SAndreas Gohr 237*d486d6d7SAndreas Gohr foreach($this->columns as $column) { 238*d486d6d7SAndreas Gohr $data['columns'][] = array( 239*d486d6d7SAndreas Gohr 'colref' => $column->getColref(), 240*d486d6d7SAndreas Gohr 'ismulti' => $column->isMulti(), 241*d486d6d7SAndreas Gohr 'isenabled' => $column->isEnabled(), 242*d486d6d7SAndreas Gohr 'sort' => $column->getSort(), 243*d486d6d7SAndreas Gohr 'label' => $column->getLabel(), 244*d486d6d7SAndreas Gohr 'class' => $column->getType()->getClass(), 245*d486d6d7SAndreas Gohr 'config' => $column->getType()->getConfig(), 246*d486d6d7SAndreas Gohr ); 247*d486d6d7SAndreas Gohr } 248*d486d6d7SAndreas Gohr 249*d486d6d7SAndreas Gohr return json_encode($data, JSON_PRETTY_PRINT); 250*d486d6d7SAndreas Gohr } 251083afc55SAndreas Gohr} 252