1f411d872SAndreas Gohr<?php 2f411d872SAndreas Gohr 3f411d872SAndreas Gohrnamespace dokuwiki\plugin\struct\meta; 4f411d872SAndreas Gohr 5c73fba38SAnna Dabrowska/** 6c73fba38SAnna Dabrowska * Class AccessTable 7c73fba38SAnna Dabrowska * 8c73fba38SAnna Dabrowska * Base class for data accessors 9c73fba38SAnna Dabrowska * 10c73fba38SAnna Dabrowska * @package dokuwiki\plugin\struct\meta 11c73fba38SAnna Dabrowska */ 12f411d872SAndreas Gohrabstract class AccessTable { 13f411d872SAndreas Gohr 14efe74305SAnna Dabrowska const DEFAULT_REV = 0; 15efe74305SAnna Dabrowska const DEFAULT_LATEST = 1; 16efe74305SAnna Dabrowska 17f411d872SAndreas Gohr /** @var Schema */ 18f411d872SAndreas Gohr protected $schema; 19f411d872SAndreas Gohr protected $pid; 200ceefd5cSAnna Dabrowska protected $rid; 21aeb8444cSAnna Dabrowska protected $labels = []; 22f411d872SAndreas Gohr protected $ts = 0; 23f411d872SAndreas Gohr /** @var \helper_plugin_sqlite */ 24f411d872SAndreas Gohr protected $sqlite; 25f411d872SAndreas Gohr 2690421550SAndreas Gohr // options on how to retrieve data 27f411d872SAndreas Gohr protected $opt_skipempty = false; 28f411d872SAndreas Gohr 29f411d872SAndreas Gohr /** 30aeb8444cSAnna Dabrowska * @var string Name of single-value table 31aeb8444cSAnna Dabrowska */ 32aeb8444cSAnna Dabrowska protected $stable; 33aeb8444cSAnna Dabrowska 34aeb8444cSAnna Dabrowska /** 35aeb8444cSAnna Dabrowska * @var string Name of multi-value table 36aeb8444cSAnna Dabrowska */ 37aeb8444cSAnna Dabrowska protected $mtable; 38aeb8444cSAnna Dabrowska 39aeb8444cSAnna Dabrowska /** 40aeb8444cSAnna Dabrowska * @var array Column names for the single-value insert/update 41aeb8444cSAnna Dabrowska */ 42aeb8444cSAnna Dabrowska protected $singleCols; 43aeb8444cSAnna Dabrowska 44aeb8444cSAnna Dabrowska /** 45aeb8444cSAnna Dabrowska * @var array Input values for the single-value insert/update 46aeb8444cSAnna Dabrowska */ 47aeb8444cSAnna Dabrowska protected $singleValues; 48aeb8444cSAnna Dabrowska 49aeb8444cSAnna Dabrowska /** 50aeb8444cSAnna Dabrowska * @var array Input values for the multi-value inserts/updates 51aeb8444cSAnna Dabrowska */ 52aeb8444cSAnna Dabrowska protected $multiValues; 53aeb8444cSAnna Dabrowska 54aeb8444cSAnna Dabrowska 55aeb8444cSAnna Dabrowska /** 56b9d35ff2SAnna Dabrowska * Factory method returning the appropriate data accessor (page, lookup or serial) 57f411d872SAndreas Gohr * 58f411d872SAndreas Gohr * @param Schema $schema schema to load 5986a40c1eSAnna Dabrowska * @param string $pid Page id to access 60*a14cf85dSAnna Dabrowska * @param int $ts Time at which the data should be read or written 6186a40c1eSAnna Dabrowska * @param int $rid Row id, 0 for page type data, otherwise autoincrement 62aeb8444cSAnna Dabrowska * @return AccessTableData|AccessTableLookup 63f411d872SAndreas Gohr */ 640ceefd5cSAnna Dabrowska public static function bySchema(Schema $schema, $pid, $ts = 0, $rid = 0) { 65aeb8444cSAnna Dabrowska if (self::isTypePage($pid, $ts, $rid)) { 660ceefd5cSAnna Dabrowska return new AccessTableData($schema, $pid, $ts, $rid); 67f411d872SAndreas Gohr } 68aeb8444cSAnna Dabrowska return new AccessTableLookup($schema, $pid, $ts, $rid); 69aeb8444cSAnna Dabrowska } 70f411d872SAndreas Gohr 71f411d872SAndreas Gohr /** 72c73fba38SAnna Dabrowska * Factory Method to access data 73f411d872SAndreas Gohr * 74f411d872SAndreas Gohr * @param string $tablename schema to load 7586a40c1eSAnna Dabrowska * @param string $pid Page id to access 76*a14cf85dSAnna Dabrowska * @param int $ts Time at which the data should be read or written 7786a40c1eSAnna Dabrowska * @param int $rid Row id, 0 for page type data, otherwise autoincrement 78aeb8444cSAnna Dabrowska * @return AccessTableData|AccessTableLookup 79f411d872SAndreas Gohr */ 800ceefd5cSAnna Dabrowska public static function byTableName($tablename, $pid, $ts = 0, $rid = 0) { 81f411d872SAndreas Gohr $schema = new Schema($tablename, $ts); 820ceefd5cSAnna Dabrowska return self::bySchema($schema, $pid, $ts, $rid); 83f411d872SAndreas Gohr } 84f411d872SAndreas Gohr 85f411d872SAndreas Gohr /** 86f411d872SAndreas Gohr * AccessTable constructor 87f411d872SAndreas Gohr * 88897aef42SAndreas Gohr * @param Schema $schema The schema valid at $ts 8986a40c1eSAnna Dabrowska * @param string $pid Page id 90897aef42SAndreas Gohr * @param int $ts Time at which the data should be read or written, 0 for now 910ceefd5cSAnna Dabrowska * @param int $rid Row id: 0 for pages, autoincremented for other types 92f411d872SAndreas Gohr */ 930ceefd5cSAnna Dabrowska public function __construct(Schema $schema, $pid, $ts = 0, $rid = 0) { 94f411d872SAndreas Gohr /** @var \helper_plugin_struct_db $helper */ 95f411d872SAndreas Gohr $helper = plugin_load('helper', 'struct_db'); 96f411d872SAndreas Gohr $this->sqlite = $helper->getDB(); 97f411d872SAndreas Gohr 98f411d872SAndreas Gohr if(!$schema->getId()) { 99f411d872SAndreas Gohr throw new StructException('Schema does not exist. Only data of existing schemas can be accessed'); 100f411d872SAndreas Gohr } 101f411d872SAndreas Gohr 102f411d872SAndreas Gohr $this->schema = $schema; 103f411d872SAndreas Gohr $this->pid = $pid; 1040ceefd5cSAnna Dabrowska $this->rid = $rid; 105897aef42SAndreas Gohr $this->setTimestamp($ts); 106f411d872SAndreas Gohr foreach($this->schema->getColumns() as $col) { 107f411d872SAndreas Gohr $this->labels[$col->getColref()] = $col->getType()->getLabel(); 108f411d872SAndreas Gohr } 109f411d872SAndreas Gohr } 110f411d872SAndreas Gohr 111f411d872SAndreas Gohr /** 112f411d872SAndreas Gohr * gives access to the schema 113f411d872SAndreas Gohr * 114f411d872SAndreas Gohr * @return Schema 115f411d872SAndreas Gohr */ 116f411d872SAndreas Gohr public function getSchema() { 117f411d872SAndreas Gohr return $this->schema; 118f411d872SAndreas Gohr } 119f411d872SAndreas Gohr 120f411d872SAndreas Gohr /** 121f107f479SAndreas Gohr * The current pid 122f107f479SAndreas Gohr * 12386a40c1eSAnna Dabrowska * @return string 124f107f479SAndreas Gohr */ 125f107f479SAndreas Gohr public function getPid() { 126f107f479SAndreas Gohr return $this->pid; 127f107f479SAndreas Gohr } 128f107f479SAndreas Gohr 129f107f479SAndreas Gohr /** 1300ceefd5cSAnna Dabrowska * The current rid 1310ceefd5cSAnna Dabrowska * 13286a40c1eSAnna Dabrowska * @return int 1330ceefd5cSAnna Dabrowska */ 1340ceefd5cSAnna Dabrowska public function getRid() { 1350ceefd5cSAnna Dabrowska return $this->rid; 1360ceefd5cSAnna Dabrowska } 1370ceefd5cSAnna Dabrowska 1380ceefd5cSAnna Dabrowska /** 139f411d872SAndreas Gohr * Should remove the current data, by either deleting or ovewriting it 140f411d872SAndreas Gohr * 141f411d872SAndreas Gohr * @return bool if the delete succeeded 142f411d872SAndreas Gohr */ 143f411d872SAndreas Gohr abstract public function clearData(); 144f411d872SAndreas Gohr 145f411d872SAndreas Gohr /** 146f411d872SAndreas Gohr * Save the data to the database. 147f411d872SAndreas Gohr * 148f411d872SAndreas Gohr * We differentiate between single-value-column and multi-value-column by the value to the respective column-name, 149f411d872SAndreas Gohr * i.e. depending on if that is a string or an array, respectively. 150f411d872SAndreas Gohr * 151f411d872SAndreas Gohr * @param array $data typelabel => value for single fields or typelabel => array(value, value, ...) for multi fields 152f411d872SAndreas Gohr * @return bool success of saving the data to the database 153f411d872SAndreas Gohr */ 154aeb8444cSAnna Dabrowska public function saveData($data) 155aeb8444cSAnna Dabrowska { 156aeb8444cSAnna Dabrowska if (!$this->validateTypeData($data)) { 157aeb8444cSAnna Dabrowska return false; 158aeb8444cSAnna Dabrowska } 159aeb8444cSAnna Dabrowska 160aeb8444cSAnna Dabrowska $this->stable = 'data_' . $this->schema->getTable(); 161aeb8444cSAnna Dabrowska $this->mtable = 'multi_' . $this->schema->getTable(); 162aeb8444cSAnna Dabrowska 163aeb8444cSAnna Dabrowska $colrefs = array_flip($this->labels); 164aeb8444cSAnna Dabrowska 165aeb8444cSAnna Dabrowska foreach ($data as $colname => $value) { 166aeb8444cSAnna Dabrowska if(!isset($colrefs[$colname])) { 167aeb8444cSAnna Dabrowska throw new StructException("Unknown column %s in schema.", hsc($colname)); 168aeb8444cSAnna Dabrowska } 169aeb8444cSAnna Dabrowska 170aeb8444cSAnna Dabrowska $this->singleCols[] = 'col' . $colrefs[$colname]; 171aeb8444cSAnna Dabrowska if (is_array($value)) { 172aeb8444cSAnna Dabrowska foreach ($value as $index => $multivalue) { 173aeb8444cSAnna Dabrowska $this->multiValues[] = [$colrefs[$colname], $index + 1, $multivalue]; 174aeb8444cSAnna Dabrowska } 175aeb8444cSAnna Dabrowska // copy first value to the single column 176aeb8444cSAnna Dabrowska if(isset($value[0])) { 177aeb8444cSAnna Dabrowska $this->singleValues[] = $value[0]; 178aeb8444cSAnna Dabrowska } else { 179aeb8444cSAnna Dabrowska $this->singleValues[] = null; 180aeb8444cSAnna Dabrowska } 181aeb8444cSAnna Dabrowska } else { 182aeb8444cSAnna Dabrowska $this->singleValues[] = $value; 183aeb8444cSAnna Dabrowska } 184aeb8444cSAnna Dabrowska } 185aeb8444cSAnna Dabrowska 186aeb8444cSAnna Dabrowska $this->sqlite->query('BEGIN TRANSACTION'); 187aeb8444cSAnna Dabrowska 188aeb8444cSAnna Dabrowska $ok = $this->beforeSave(); 189aeb8444cSAnna Dabrowska 190aeb8444cSAnna Dabrowska // insert single values 191aeb8444cSAnna Dabrowska $ok = $ok && $this->sqlite->query( 192aeb8444cSAnna Dabrowska $this->getSingleSql(), 193aeb8444cSAnna Dabrowska array_merge($this->getSingleNoninputValues(), $this->singleValues) 194aeb8444cSAnna Dabrowska ); 195aeb8444cSAnna Dabrowska 196aeb8444cSAnna Dabrowska $ok = $ok && $this->afterSingleSave(); 197aeb8444cSAnna Dabrowska 198aeb8444cSAnna Dabrowska // insert multi values 199aeb8444cSAnna Dabrowska if ($ok && $this->multiValues) { 200aeb8444cSAnna Dabrowska $multisql = $this->getMultiSql(); 201aeb8444cSAnna Dabrowska $multiNoninputValues = $this->getMultiNoninputValues(); 202aeb8444cSAnna Dabrowska foreach ($this->multiValues as $value) { 203aeb8444cSAnna Dabrowska $ok = $ok && $this->sqlite->query( 204aeb8444cSAnna Dabrowska $multisql, 205aeb8444cSAnna Dabrowska array_merge($multiNoninputValues, $value) 206aeb8444cSAnna Dabrowska ); 207aeb8444cSAnna Dabrowska } 208aeb8444cSAnna Dabrowska } 209aeb8444cSAnna Dabrowska 210aeb8444cSAnna Dabrowska if (!$ok) { 211aeb8444cSAnna Dabrowska $this->sqlite->query('ROLLBACK TRANSACTION'); 212aeb8444cSAnna Dabrowska return false; 213aeb8444cSAnna Dabrowska } 214aeb8444cSAnna Dabrowska $this->sqlite->query('COMMIT TRANSACTION'); 215aeb8444cSAnna Dabrowska return true; 216aeb8444cSAnna Dabrowska } 217aeb8444cSAnna Dabrowska 218aeb8444cSAnna Dabrowska /** 219aeb8444cSAnna Dabrowska * Check whether all required data is present 220aeb8444cSAnna Dabrowska * 221aeb8444cSAnna Dabrowska * @param array $data 222aeb8444cSAnna Dabrowska * @return bool 223aeb8444cSAnna Dabrowska */ 224aeb8444cSAnna Dabrowska abstract protected function validateTypeData($data); 225aeb8444cSAnna Dabrowska 226aeb8444cSAnna Dabrowska /** 227aeb8444cSAnna Dabrowska * Names of non-input columns to be inserted into SQL query 228aeb8444cSAnna Dabrowska * 229aeb8444cSAnna Dabrowska * @return array 230aeb8444cSAnna Dabrowska */ 231aeb8444cSAnna Dabrowska abstract protected function getSingleNoninputCols(); 232aeb8444cSAnna Dabrowska 233aeb8444cSAnna Dabrowska /** 234aeb8444cSAnna Dabrowska * Values for non-input columns to be inserted into SQL query 235aeb8444cSAnna Dabrowska * for single-value tables 236aeb8444cSAnna Dabrowska * 237aeb8444cSAnna Dabrowska * @return array 238aeb8444cSAnna Dabrowska */ 239aeb8444cSAnna Dabrowska abstract protected function getSingleNoninputValues(); 240aeb8444cSAnna Dabrowska 241aeb8444cSAnna Dabrowska /** 242aeb8444cSAnna Dabrowska * String template for single-value table 243aeb8444cSAnna Dabrowska * 244aeb8444cSAnna Dabrowska * @return string 245aeb8444cSAnna Dabrowska */ 246aeb8444cSAnna Dabrowska protected function getSingleSql() 247aeb8444cSAnna Dabrowska { 248aeb8444cSAnna Dabrowska $cols = array_merge($this->getSingleNoninputCols(), $this->singleCols); 249aeb8444cSAnna Dabrowska $cols = join(',', $cols); 250aeb8444cSAnna Dabrowska $vals = array_merge($this->getSingleNoninputValues(), $this->singleValues); 251aeb8444cSAnna Dabrowska 252aeb8444cSAnna Dabrowska return "INSERT INTO $this->stable ($cols) VALUES (" . trim(str_repeat('?,', count($vals)),',') . ');'; 253aeb8444cSAnna Dabrowska } 254aeb8444cSAnna Dabrowska 255aeb8444cSAnna Dabrowska /** 256aeb8444cSAnna Dabrowska * Optional operations to be executed before saving data 257aeb8444cSAnna Dabrowska * 258aeb8444cSAnna Dabrowska * @return bool False if any of the operations failed and transaction should be rolled back 259aeb8444cSAnna Dabrowska */ 260aeb8444cSAnna Dabrowska protected function beforeSave() 261aeb8444cSAnna Dabrowska { 262aeb8444cSAnna Dabrowska return true; 263aeb8444cSAnna Dabrowska } 264aeb8444cSAnna Dabrowska 265aeb8444cSAnna Dabrowska /** 266aeb8444cSAnna Dabrowska * Optional operations to be executed after saving data to single-value table, 267aeb8444cSAnna Dabrowska * before saving multivalues 268aeb8444cSAnna Dabrowska * 269aeb8444cSAnna Dabrowska * @return bool False if anything goes wrong and transaction should be rolled back 270aeb8444cSAnna Dabrowska */ 271aeb8444cSAnna Dabrowska protected function afterSingleSave() 272aeb8444cSAnna Dabrowska { 273aeb8444cSAnna Dabrowska return true; 274aeb8444cSAnna Dabrowska } 275aeb8444cSAnna Dabrowska 276aeb8444cSAnna Dabrowska /** 277aeb8444cSAnna Dabrowska * String template for multi-value table 278aeb8444cSAnna Dabrowska * 279aeb8444cSAnna Dabrowska * @return string 280aeb8444cSAnna Dabrowska */ 281aeb8444cSAnna Dabrowska abstract protected function getMultiSql(); 282aeb8444cSAnna Dabrowska 283aeb8444cSAnna Dabrowska /** 284aeb8444cSAnna Dabrowska * Values for non-input columns to be inserted into SQL query 285aeb8444cSAnna Dabrowska * for multi-value tables 286aeb8444cSAnna Dabrowska * @return array 287aeb8444cSAnna Dabrowska */ 288aeb8444cSAnna Dabrowska abstract protected function getMultiNoninputValues(); 289aeb8444cSAnna Dabrowska 290f411d872SAndreas Gohr 291f411d872SAndreas Gohr /** 292f411d872SAndreas Gohr * Should empty or invisible (inpage) fields be returned? 293f411d872SAndreas Gohr * 294f411d872SAndreas Gohr * Defaults to false 295f411d872SAndreas Gohr * 296f411d872SAndreas Gohr * @param null|bool $set new value, null to read only 297f411d872SAndreas Gohr * @return bool current value (after set) 298f411d872SAndreas Gohr */ 299f411d872SAndreas Gohr public function optionSkipEmpty($set = null) { 300f411d872SAndreas Gohr if(!is_null($set)) { 301f411d872SAndreas Gohr $this->opt_skipempty = $set; 302f411d872SAndreas Gohr } 303f411d872SAndreas Gohr return $this->opt_skipempty; 304f411d872SAndreas Gohr } 305f411d872SAndreas Gohr 306f411d872SAndreas Gohr /** 307f411d872SAndreas Gohr * Get the value of a single column 308f411d872SAndreas Gohr * 309f411d872SAndreas Gohr * @param Column $column 310f411d872SAndreas Gohr * @return Value|null 311f411d872SAndreas Gohr */ 312f411d872SAndreas Gohr public function getDataColumn($column) { 313f411d872SAndreas Gohr $data = $this->getData(); 314f411d872SAndreas Gohr foreach($data as $value) { 315f411d872SAndreas Gohr if($value->getColumn() == $column) { 316f411d872SAndreas Gohr return $value; 317f411d872SAndreas Gohr } 318f411d872SAndreas Gohr } 319f411d872SAndreas Gohr return null; 320f411d872SAndreas Gohr } 321f411d872SAndreas Gohr 322f411d872SAndreas Gohr /** 323f411d872SAndreas Gohr * returns the data saved for the page 324f411d872SAndreas Gohr * 325f411d872SAndreas Gohr * @return Value[] a list of values saved for the current page 326f411d872SAndreas Gohr */ 327f411d872SAndreas Gohr public function getData() { 328f411d872SAndreas Gohr $data = $this->getDataFromDB(); 329f411d872SAndreas Gohr $data = $this->consolidateData($data, false); 330f411d872SAndreas Gohr return $data; 331f411d872SAndreas Gohr } 332f411d872SAndreas Gohr 333f411d872SAndreas Gohr /** 334f411d872SAndreas Gohr * returns the data saved for the page as associative array 335f411d872SAndreas Gohr * 336f411d872SAndreas Gohr * The array returned is in the same format as used in @see saveData() 337f411d872SAndreas Gohr * 33890421550SAndreas Gohr * It always returns raw Values! 33990421550SAndreas Gohr * 340f411d872SAndreas Gohr * @return array 341f411d872SAndreas Gohr */ 342f411d872SAndreas Gohr public function getDataArray() { 343f411d872SAndreas Gohr $data = $this->getDataFromDB(); 344f411d872SAndreas Gohr $data = $this->consolidateData($data, true); 345f411d872SAndreas Gohr return $data; 346f411d872SAndreas Gohr } 347f411d872SAndreas Gohr 348f411d872SAndreas Gohr /** 349f411d872SAndreas Gohr * Return the data in pseudo syntax 350f411d872SAndreas Gohr */ 351f411d872SAndreas Gohr public function getDataPseudoSyntax() { 352f411d872SAndreas Gohr $result = ''; 353a0a1d14eSAndreas Gohr $data = $this->getData(); 354a0a1d14eSAndreas Gohr 355a0a1d14eSAndreas Gohr foreach($data as $value) { 356a0a1d14eSAndreas Gohr $key = $value->getColumn()->getFullQualifiedLabel(); 357a0a1d14eSAndreas Gohr $value = $value->getDisplayValue(); 358f411d872SAndreas Gohr if(is_array($value)) $value = join(', ', $value); 359f411d872SAndreas Gohr $result .= sprintf("% -20s : %s\n", $key, $value); 360f411d872SAndreas Gohr } 361f411d872SAndreas Gohr return $result; 362f411d872SAndreas Gohr } 363f411d872SAndreas Gohr 364f411d872SAndreas Gohr /** 365f411d872SAndreas Gohr * retrieve the data saved for the page from the database. Usually there is no need to call this function. 366f411d872SAndreas Gohr * Call @see SchemaData::getData instead. 367f411d872SAndreas Gohr */ 368f411d872SAndreas Gohr protected function getDataFromDB() { 369efe74305SAnna Dabrowska $idColumn = self::isTypePage($this->pid, $this->ts, $this->rid) ? 'pid' : 'rid'; 370efe74305SAnna Dabrowska list($sql, $opt) = $this->buildGetDataSQL($idColumn); 371f411d872SAndreas Gohr 372f411d872SAndreas Gohr $res = $this->sqlite->query($sql, $opt); 373f411d872SAndreas Gohr $data = $this->sqlite->res2arr($res); 3749c00b26cSAndreas Gohr $this->sqlite->res_close($res); 375f411d872SAndreas Gohr return $data; 376f411d872SAndreas Gohr } 377f411d872SAndreas Gohr 378f411d872SAndreas Gohr /** 379f411d872SAndreas Gohr * Creates a proper result array from the database data 380f411d872SAndreas Gohr * 381f411d872SAndreas Gohr * @param array $DBdata the data as it is retrieved from the database, i.e. by SchemaData::getDataFromDB 382f411d872SAndreas Gohr * @param bool $asarray return data as associative array (true) or as array of Values (false) 383f411d872SAndreas Gohr * @return array|Value[] 384f411d872SAndreas Gohr */ 385f411d872SAndreas Gohr protected function consolidateData($DBdata, $asarray = false) { 386f411d872SAndreas Gohr $data = array(); 387f411d872SAndreas Gohr 388f411d872SAndreas Gohr $sep = Search::CONCAT_SEPARATOR; 389f411d872SAndreas Gohr 390f411d872SAndreas Gohr foreach($this->schema->getColumns(false) as $col) { 391f411d872SAndreas Gohr 39290421550SAndreas Gohr // if no data saved yet, return empty strings 393f411d872SAndreas Gohr if($DBdata) { 394bab52340SAndreas Gohr $val = $DBdata[0]['out' . $col->getColref()]; 395f411d872SAndreas Gohr } else { 396f411d872SAndreas Gohr $val = ''; 397f411d872SAndreas Gohr } 398f411d872SAndreas Gohr 399f411d872SAndreas Gohr // multi val data is concatenated 400f411d872SAndreas Gohr if($col->isMulti()) { 401f411d872SAndreas Gohr $val = explode($sep, $val); 402f411d872SAndreas Gohr $val = array_filter($val); 403f411d872SAndreas Gohr } 404f411d872SAndreas Gohr 40590421550SAndreas Gohr $value = new Value($col, $val); 406f411d872SAndreas Gohr 40790421550SAndreas Gohr if($this->opt_skipempty && $value->isEmpty()) continue; 40890421550SAndreas Gohr if($this->opt_skipempty && !$col->isVisibleInPage()) continue; //FIXME is this a correct assumption? 40990421550SAndreas Gohr 41090421550SAndreas Gohr // for arrays, we return the raw value only 411f411d872SAndreas Gohr if($asarray) { 41290421550SAndreas Gohr $data[$col->getLabel()] = $value->getRawValue(); 413f411d872SAndreas Gohr } else { 4146e54daafSMichael Große $data[$col->getLabel()] = $value; 415f411d872SAndreas Gohr } 416f411d872SAndreas Gohr } 417f411d872SAndreas Gohr 418f411d872SAndreas Gohr return $data; 419f411d872SAndreas Gohr } 420f411d872SAndreas Gohr 421f411d872SAndreas Gohr /** 422f411d872SAndreas Gohr * Builds the SQL statement to select the data for this page and schema 423f411d872SAndreas Gohr * 424f411d872SAndreas Gohr * @return array Two fields: the SQL string and the parameters array 425f411d872SAndreas Gohr */ 4266fd73b4bSAnna Dabrowska protected function buildGetDataSQL($idColumn = 'pid') { 427f411d872SAndreas Gohr $sep = Search::CONCAT_SEPARATOR; 428f411d872SAndreas Gohr $stable = 'data_' . $this->schema->getTable(); 429f411d872SAndreas Gohr $mtable = 'multi_' . $this->schema->getTable(); 430f411d872SAndreas Gohr 431f411d872SAndreas Gohr $QB = new QueryBuilder(); 432f411d872SAndreas Gohr $QB->addTable($stable, 'DATA'); 4336fd73b4bSAnna Dabrowska $QB->addSelectColumn('DATA', $idColumn, strtoupper($idColumn)); 4346fd73b4bSAnna Dabrowska $QB->addGroupByStatement("DATA.$idColumn"); 435f411d872SAndreas Gohr 436f411d872SAndreas Gohr foreach($this->schema->getColumns(false) as $col) { 437f411d872SAndreas Gohr 438f411d872SAndreas Gohr $colref = $col->getColref(); 439f411d872SAndreas Gohr $colname = 'col' . $colref; 440bab52340SAndreas Gohr $outname = 'out' . $colref; 441f411d872SAndreas Gohr 442f411d872SAndreas Gohr if($col->getType()->isMulti()) { 443f411d872SAndreas Gohr $tn = 'M' . $colref; 444f411d872SAndreas Gohr $QB->addLeftJoin( 445f411d872SAndreas Gohr 'DATA', 446f411d872SAndreas Gohr $mtable, 447f411d872SAndreas Gohr $tn, 4486fd73b4bSAnna Dabrowska "DATA.$idColumn = $tn.$idColumn AND DATA.rev = $tn.rev AND $tn.colref = $colref" 449f411d872SAndreas Gohr ); 450bab52340SAndreas Gohr $col->getType()->select($QB, $tn, 'value', $outname); 451bab52340SAndreas Gohr $sel = $QB->getSelectStatement($outname); 452bab52340SAndreas Gohr $QB->addSelectStatement("GROUP_CONCAT($sel, '$sep')", $outname); 453f411d872SAndreas Gohr } else { 454bab52340SAndreas Gohr $col->getType()->select($QB, 'DATA', $colname, $outname); 455bab52340SAndreas Gohr $QB->addGroupByStatement($outname); 456f411d872SAndreas Gohr } 457f411d872SAndreas Gohr } 458f411d872SAndreas Gohr 4596fd73b4bSAnna Dabrowska $pl = $QB->addValue($this->{$idColumn}); 4606fd73b4bSAnna Dabrowska $QB->filters()->whereAnd("DATA.$idColumn = $pl"); 461897aef42SAndreas Gohr $pl = $QB->addValue($this->getLastRevisionTimestamp()); 462f411d872SAndreas Gohr $QB->filters()->whereAnd("DATA.rev = $pl"); 463f411d872SAndreas Gohr 464f411d872SAndreas Gohr return $QB->getSQL(); 465f411d872SAndreas Gohr } 466f411d872SAndreas Gohr 467f411d872SAndreas Gohr /** 46813eddb0fSAndreas Gohr * @param int $ts 46913eddb0fSAndreas Gohr */ 47013eddb0fSAndreas Gohr public function setTimestamp($ts) { 471897aef42SAndreas Gohr if($ts && $ts < $this->schema->getTimeStamp()) { 472897aef42SAndreas Gohr throw new StructException('Given timestamp is not valid for current Schema'); 473897aef42SAndreas Gohr } 474897aef42SAndreas Gohr 47513eddb0fSAndreas Gohr $this->ts = $ts; 47613eddb0fSAndreas Gohr } 47713eddb0fSAndreas Gohr 47813eddb0fSAndreas Gohr /** 47969f7ec8fSAnna Dabrowska * Returns the timestamp from the current data 48069f7ec8fSAnna Dabrowska * @return int 48169f7ec8fSAnna Dabrowska */ 48269f7ec8fSAnna Dabrowska public function getTimestamp() 48369f7ec8fSAnna Dabrowska { 48469f7ec8fSAnna Dabrowska return $this->ts; 48569f7ec8fSAnna Dabrowska } 48669f7ec8fSAnna Dabrowska 48769f7ec8fSAnna Dabrowska /** 488897aef42SAndreas Gohr * Return the last time an edit happened for this table for the currently set 489*a14cf85dSAnna Dabrowska * time and pid. Used in @see buildGetDataSQL() 490f411d872SAndreas Gohr * 491897aef42SAndreas Gohr * @return int 492f411d872SAndreas Gohr */ 493897aef42SAndreas Gohr abstract protected function getLastRevisionTimestamp(); 49487dc1344SAndreas Gohr 49587dc1344SAndreas Gohr /** 49687dc1344SAndreas Gohr * Check if the given data validates against the current types. 49787dc1344SAndreas Gohr * 49887dc1344SAndreas Gohr * @param array $data 49993ca6f4fSAndreas Gohr * @return AccessDataValidator 50087dc1344SAndreas Gohr */ 50187dc1344SAndreas Gohr public function getValidator($data) { 50293ca6f4fSAndreas Gohr return new AccessDataValidator($this, $data); 50387dc1344SAndreas Gohr } 504c73fba38SAnna Dabrowska 505c73fba38SAnna Dabrowska /** 506c73fba38SAnna Dabrowska * Returns true if data is of type "page" 507c73fba38SAnna Dabrowska * 508c73fba38SAnna Dabrowska * @param string $pid 509c73fba38SAnna Dabrowska * @param int $rev 510c73fba38SAnna Dabrowska * @param int $rid 511c73fba38SAnna Dabrowska * @return bool 512c73fba38SAnna Dabrowska */ 513c73fba38SAnna Dabrowska public static function isTypePage($pid, $rev, $rid) 514c73fba38SAnna Dabrowska { 515c73fba38SAnna Dabrowska return $rev > 0; 516c73fba38SAnna Dabrowska } 517c73fba38SAnna Dabrowska 518c73fba38SAnna Dabrowska /** 519c73fba38SAnna Dabrowska * Returns true if data is of type "lookup" 520c73fba38SAnna Dabrowska * 521c73fba38SAnna Dabrowska * @param string $pid 522c73fba38SAnna Dabrowska * @param int $rev 523c73fba38SAnna Dabrowska * @param int $rid 524c73fba38SAnna Dabrowska * @return bool 525c73fba38SAnna Dabrowska */ 526c73fba38SAnna Dabrowska public static function isTypeLookup($pid, $rev, $rid) 527c73fba38SAnna Dabrowska { 528c73fba38SAnna Dabrowska return $pid === ''; 529c73fba38SAnna Dabrowska } 530c73fba38SAnna Dabrowska 531c73fba38SAnna Dabrowska /** 532c73fba38SAnna Dabrowska * Returns true if data is of type "serial" 533c73fba38SAnna Dabrowska * 534c73fba38SAnna Dabrowska * @param string $pid 535c73fba38SAnna Dabrowska * @param int $rev 536c73fba38SAnna Dabrowska * @param int $rid 537c73fba38SAnna Dabrowska * @return bool 538c73fba38SAnna Dabrowska */ 539c73fba38SAnna Dabrowska public static function isTypeSerial($pid, $rev, $rid) 540c73fba38SAnna Dabrowska { 541c73fba38SAnna Dabrowska return $pid !== '' && $rev === 0; 542c73fba38SAnna Dabrowska } 543f411d872SAndreas Gohr} 544f411d872SAndreas Gohr 545f411d872SAndreas Gohr 546