1083afc55SAndreas Gohr<?php 2083afc55SAndreas Gohr 3083afc55SAndreas Gohrnamespace plugin\struct\meta; 4083afc55SAndreas Gohr 5*1c502704SAndreas Gohruse dokuwiki\Form\Form; 6083afc55SAndreas Gohruse plugin\struct\types\AbstractBaseType; 7083afc55SAndreas Gohruse plugin\struct\types\Text; 8083afc55SAndreas Gohr 9083afc55SAndreas Gohrclass Schema { 10083afc55SAndreas Gohr 11083afc55SAndreas Gohr /** @var \helper_plugin_sqlite|null */ 12083afc55SAndreas Gohr protected $sqlite; 13083afc55SAndreas Gohr 14083afc55SAndreas Gohr /** @var int The ID of this schema */ 15083afc55SAndreas Gohr protected $id = 0; 16083afc55SAndreas Gohr 17083afc55SAndreas Gohr /** @var string name of the associated table */ 18083afc55SAndreas Gohr protected $table = ''; 19083afc55SAndreas Gohr 20083afc55SAndreas Gohr /** 21083afc55SAndreas Gohr * @var string the current checksum of this schema 22083afc55SAndreas Gohr */ 23083afc55SAndreas Gohr protected $chksum = ''; 24083afc55SAndreas Gohr 25*1c502704SAndreas Gohr /** @var Column[] all the colums */ 26083afc55SAndreas Gohr protected $columns = array(); 27083afc55SAndreas Gohr 28083afc55SAndreas Gohr /** @var int */ 29083afc55SAndreas Gohr protected $maxsort = 0; 30083afc55SAndreas Gohr 31083afc55SAndreas Gohr /** 32083afc55SAndreas Gohr * Schema constructor 33083afc55SAndreas Gohr * @param string $table The table this schema is for 34083afc55SAndreas Gohr * @param int $ts The timestamp for when this schema was valid, 0 for current 35083afc55SAndreas Gohr */ 36083afc55SAndreas Gohr public function __construct($table, $ts = 0) { 37083afc55SAndreas Gohr /** @var \helper_plugin_struct_db $helper */ 38083afc55SAndreas Gohr $helper = plugin_load('helper', 'struct_db'); 39083afc55SAndreas Gohr $this->sqlite = $helper->getDB(); 40083afc55SAndreas Gohr if(!$this->sqlite) return; 41083afc55SAndreas Gohr 42083afc55SAndreas Gohr $table = self::cleanTableName($table); 43083afc55SAndreas Gohr $this->table = $table; 44083afc55SAndreas Gohr 45083afc55SAndreas Gohr // load info about the schema itself 46083afc55SAndreas Gohr if($ts) { 47083afc55SAndreas Gohr $sql = "SELECT * 48083afc55SAndreas Gohr FROM schemas 49083afc55SAndreas Gohr WHERE tbl = ? 50083afc55SAndreas Gohr AND ts <= ? 51083afc55SAndreas Gohr ORDER BY ts DESC 52083afc55SAndreas Gohr LIMIT 1"; 53083afc55SAndreas Gohr $opt = array($table, $ts); 54083afc55SAndreas Gohr 55083afc55SAndreas Gohr } else { 56083afc55SAndreas Gohr $sql = "SELECT * 57083afc55SAndreas Gohr FROM schemas 58083afc55SAndreas Gohr WHERE tbl = ? 59083afc55SAndreas Gohr ORDER BY ts DESC 60083afc55SAndreas Gohr LIMIT 1"; 61083afc55SAndreas Gohr $opt = array($table); 62083afc55SAndreas Gohr } 63083afc55SAndreas Gohr $res = $this->sqlite->query($sql, $opt); 64083afc55SAndreas Gohr if($this->sqlite->res2count($res)) { 65*1c502704SAndreas Gohr $result = array_shift($this->sqlite->res2arr($res)); 66083afc55SAndreas Gohr $this->id = $result['id']; 67083afc55SAndreas Gohr $this->chksum = $result['chksum']; 68083afc55SAndreas Gohr 69083afc55SAndreas Gohr } 70083afc55SAndreas Gohr $this->sqlite->res_close($res); 71083afc55SAndreas Gohr if(!$this->id) return; 72083afc55SAndreas Gohr 73083afc55SAndreas Gohr // load existing columns 74083afc55SAndreas Gohr $sql = "SELECT SC.*, T.* 75083afc55SAndreas Gohr FROM schema_cols SC, 76083afc55SAndreas Gohr types T 77*1c502704SAndreas Gohr WHERE SC.sid = ? 78*1c502704SAndreas Gohr AND SC.tid = T.id 79083afc55SAndreas Gohr ORDER BY SC.sort"; 80*1c502704SAndreas Gohr $res = $this->sqlite->query($sql, $this->id); 81083afc55SAndreas Gohr $rows = $this->sqlite->res2arr($res); 82083afc55SAndreas Gohr $this->sqlite->res_close($res); 83083afc55SAndreas Gohr 84083afc55SAndreas Gohr foreach($rows as $row) { 85*1c502704SAndreas Gohr $class = 'plugin\\struct\\types\\' . $row['class']; 86083afc55SAndreas Gohr $config = json_decode($row['config'], true); 87*1c502704SAndreas Gohr $this->columns[$row['colref']] = 88*1c502704SAndreas Gohr new Column( 89*1c502704SAndreas Gohr $row['sort'], 90*1c502704SAndreas Gohr new $class($config, $row['label'], $row['ismulti']), 91*1c502704SAndreas Gohr $row['tid'], 92*1c502704SAndreas Gohr $row['colref'], 93*1c502704SAndreas Gohr $row['enabled'] 94*1c502704SAndreas Gohr ); 95*1c502704SAndreas Gohr 96083afc55SAndreas Gohr if($row['sort'] > $this->maxsort) $this->maxsort = $row['sort']; 97083afc55SAndreas Gohr } 98083afc55SAndreas Gohr } 99083afc55SAndreas Gohr 100083afc55SAndreas Gohr /** 101083afc55SAndreas Gohr * Cleans any unwanted stuff from table names 102083afc55SAndreas Gohr * 103083afc55SAndreas Gohr * @param string $table 104083afc55SAndreas Gohr * @return string 105083afc55SAndreas Gohr */ 106083afc55SAndreas Gohr static public function cleanTableName($table) { 107083afc55SAndreas Gohr $table = preg_replace('/[^a-z0-9_]+/', '', $table); 108083afc55SAndreas Gohr $table = preg_replace('/^[0-9_]+/', '', $table); 109083afc55SAndreas Gohr $table = trim($table); 110083afc55SAndreas Gohr return $table; 111083afc55SAndreas Gohr } 112083afc55SAndreas Gohr 113083afc55SAndreas Gohr /** 114*1c502704SAndreas Gohr * Returns the Admin Form to edit the schema 115083afc55SAndreas Gohr * 116083afc55SAndreas Gohr * @return string 117083afc55SAndreas Gohr */ 118083afc55SAndreas Gohr public function adminEditor() { 119*1c502704SAndreas Gohr $form = new Form(array('method' => 'POST')); 120*1c502704SAndreas Gohr $form->setHiddenField('do', 'admin'); 121*1c502704SAndreas Gohr $form->setHiddenField('page', 'struct'); 122*1c502704SAndreas Gohr $form->setHiddenField('table', $this->table); 123*1c502704SAndreas Gohr $form->setHiddenField('schema[id]', $this->id); 124083afc55SAndreas Gohr 125*1c502704SAndreas Gohr $form->addHTML('<table class="inline">'); 126*1c502704SAndreas Gohr $form->addHTML('<tr><th>Sort</th><th>Label</th><th>Multi-Input?</th><th>Configuration</th><th>Type</th></tr>'); // FIXME localize 127083afc55SAndreas Gohr 128083afc55SAndreas Gohr foreach($this->columns as $key => $obj) { 129*1c502704SAndreas Gohr $form->addHTML($this->adminColumn($key, $obj)); 130083afc55SAndreas Gohr } 131083afc55SAndreas Gohr 132083afc55SAndreas Gohr // FIXME new one needs to be added dynamically, this is just for testing 133*1c502704SAndreas Gohr $form->addHTML($this->adminColumn('new1', new Column($this->maxsort+10, new Text()), 'new')); 134083afc55SAndreas Gohr 135*1c502704SAndreas Gohr $form->addHTML('</table>'); 136*1c502704SAndreas Gohr $form->addButton('save', 'Save')->attr('type','submit'); 137*1c502704SAndreas Gohr return $form->toHTML(); 138083afc55SAndreas Gohr } 139083afc55SAndreas Gohr 140083afc55SAndreas Gohr /** 141083afc55SAndreas Gohr * Returns the HTML to edit a single column definition of the schema 142083afc55SAndreas Gohr * 143083afc55SAndreas Gohr * @param string $column_id 144*1c502704SAndreas Gohr * @param Column $col 145*1c502704SAndreas Gohr * @param string $key The key to use in the form 146083afc55SAndreas Gohr * @return string 147083afc55SAndreas Gohr * @todo this should probably be reused for adding new columns via AJAX later? 148083afc55SAndreas Gohr */ 149*1c502704SAndreas Gohr protected function adminColumn($column_id, Column $col, $key='cols') { 150*1c502704SAndreas Gohr $base = 'schema['.$key.'][' . $column_id . ']'; // base name for all fields 151083afc55SAndreas Gohr 152083afc55SAndreas Gohr $html = '<tr>'; 153083afc55SAndreas Gohr 154083afc55SAndreas Gohr $html .= '<td>'; 155*1c502704SAndreas Gohr $html .= '<input type="text" name="' . $base . '[sort]" value="' . hsc($col->getSort()) . '" size="3">'; 156083afc55SAndreas Gohr $html .= '</td>'; 157083afc55SAndreas Gohr 158083afc55SAndreas Gohr $html .= '<td>'; 159*1c502704SAndreas Gohr $html .= '<input type="text" name="' . $base . '[label]" value="' . hsc($col->getType()->getLabel()) . '">'; 160083afc55SAndreas Gohr $html .= '</td>'; 161083afc55SAndreas Gohr 162083afc55SAndreas Gohr $html .= '<td>'; 163*1c502704SAndreas Gohr $checked = $col->getType()->isMulti() ? 'checked="checked"' : ''; 164083afc55SAndreas Gohr $html .= '<input type="checkbox" name="' . $base . '[ismulti]" value="1" ' . $checked . '>'; 165083afc55SAndreas Gohr $html .= '</td>'; 166083afc55SAndreas Gohr 167083afc55SAndreas Gohr $html .= '<td>'; 168*1c502704SAndreas Gohr $config = json_encode($col->getType()->getConfig(), JSON_PRETTY_PRINT); 169083afc55SAndreas Gohr $html .= '<textarea name="' . $base . '[config]" cols="45" rows="10">' . hsc($config) . '</textarea>'; 170083afc55SAndreas Gohr $html .= '</td>'; 171083afc55SAndreas Gohr 172083afc55SAndreas Gohr $html .= '<td>'; 173*1c502704SAndreas Gohr $html .= '<input type="text" name="' . $base . '[class]" value="' . hsc($col->getType()->getClass()) . '">'; //FIXME this needs to be a dropdown 174083afc55SAndreas Gohr $html .= '</td>'; 175083afc55SAndreas Gohr 176083afc55SAndreas Gohr $html .= '</tr>'; 177083afc55SAndreas Gohr 178083afc55SAndreas Gohr return $html; 179083afc55SAndreas Gohr } 180083afc55SAndreas Gohr 181*1c502704SAndreas Gohr /** 182*1c502704SAndreas Gohr * @return string 183*1c502704SAndreas Gohr */ 184*1c502704SAndreas Gohr public function getChksum() { 185*1c502704SAndreas Gohr return $this->chksum; 186*1c502704SAndreas Gohr } 187*1c502704SAndreas Gohr 188*1c502704SAndreas Gohr /** 189*1c502704SAndreas Gohr * @return int 190*1c502704SAndreas Gohr */ 191*1c502704SAndreas Gohr public function getId() { 192*1c502704SAndreas Gohr return $this->id; 193*1c502704SAndreas Gohr } 194*1c502704SAndreas Gohr 195*1c502704SAndreas Gohr /** 196*1c502704SAndreas Gohr * @return \plugin\struct\meta\Column[] 197*1c502704SAndreas Gohr */ 198*1c502704SAndreas Gohr public function getColumns() { 199*1c502704SAndreas Gohr return $this->columns; 200*1c502704SAndreas Gohr } 201*1c502704SAndreas Gohr 202*1c502704SAndreas Gohr 203*1c502704SAndreas Gohr 204*1c502704SAndreas Gohr 205083afc55SAndreas Gohr} 206