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; 21*aeb8444cSAnna 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 /** 30*aeb8444cSAnna Dabrowska * @var string Name of single-value table 31*aeb8444cSAnna Dabrowska */ 32*aeb8444cSAnna Dabrowska protected $stable; 33*aeb8444cSAnna Dabrowska 34*aeb8444cSAnna Dabrowska /** 35*aeb8444cSAnna Dabrowska * @var string Name of multi-value table 36*aeb8444cSAnna Dabrowska */ 37*aeb8444cSAnna Dabrowska protected $mtable; 38*aeb8444cSAnna Dabrowska 39*aeb8444cSAnna Dabrowska /** 40*aeb8444cSAnna Dabrowska * @var array Column names for the single-value insert/update 41*aeb8444cSAnna Dabrowska */ 42*aeb8444cSAnna Dabrowska protected $singleCols; 43*aeb8444cSAnna Dabrowska 44*aeb8444cSAnna Dabrowska /** 45*aeb8444cSAnna Dabrowska * @var array Input values for the single-value insert/update 46*aeb8444cSAnna Dabrowska */ 47*aeb8444cSAnna Dabrowska protected $singleValues; 48*aeb8444cSAnna Dabrowska 49*aeb8444cSAnna Dabrowska /** 50*aeb8444cSAnna Dabrowska * @var array Input values for the multi-value inserts/updates 51*aeb8444cSAnna Dabrowska */ 52*aeb8444cSAnna Dabrowska protected $multiValues; 53*aeb8444cSAnna Dabrowska 54*aeb8444cSAnna Dabrowska 55*aeb8444cSAnna 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 60897aef42SAndreas Gohr * @param int $ts Time at which the data should be read or written, 0 for now 6186a40c1eSAnna Dabrowska * @param int $rid Row id, 0 for page type data, otherwise autoincrement 62*aeb8444cSAnna Dabrowska * @return AccessTableData|AccessTableLookup 63f411d872SAndreas Gohr */ 640ceefd5cSAnna Dabrowska public static function bySchema(Schema $schema, $pid, $ts = 0, $rid = 0) { 65*aeb8444cSAnna Dabrowska if (self::isTypePage($pid, $ts, $rid)) { 660ceefd5cSAnna Dabrowska return new AccessTableData($schema, $pid, $ts, $rid); 67f411d872SAndreas Gohr } 68*aeb8444cSAnna Dabrowska return new AccessTableLookup($schema, $pid, $ts, $rid); 69*aeb8444cSAnna 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 76897aef42SAndreas Gohr * @param int $ts Time at which the data should be read or written, 0 for now 7786a40c1eSAnna Dabrowska * @param int $rid Row id, 0 for page type data, otherwise autoincrement 78*aeb8444cSAnna 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 */ 154*aeb8444cSAnna Dabrowska public function saveData($data) 155*aeb8444cSAnna Dabrowska { 156*aeb8444cSAnna Dabrowska if (!$this->validateTypeData($data)) { 157*aeb8444cSAnna Dabrowska return false; 158*aeb8444cSAnna Dabrowska } 159*aeb8444cSAnna Dabrowska 160*aeb8444cSAnna Dabrowska $this->stable = 'data_' . $this->schema->getTable(); 161*aeb8444cSAnna Dabrowska $this->mtable = 'multi_' . $this->schema->getTable(); 162*aeb8444cSAnna Dabrowska 163*aeb8444cSAnna Dabrowska $colrefs = array_flip($this->labels); 164*aeb8444cSAnna Dabrowska 165*aeb8444cSAnna Dabrowska foreach ($data as $colname => $value) { 166*aeb8444cSAnna Dabrowska if(!isset($colrefs[$colname])) { 167*aeb8444cSAnna Dabrowska throw new StructException("Unknown column %s in schema.", hsc($colname)); 168*aeb8444cSAnna Dabrowska } 169*aeb8444cSAnna Dabrowska 170*aeb8444cSAnna Dabrowska $this->singleCols[] = 'col' . $colrefs[$colname]; 171*aeb8444cSAnna Dabrowska if (is_array($value)) { 172*aeb8444cSAnna Dabrowska foreach ($value as $index => $multivalue) { 173*aeb8444cSAnna Dabrowska $this->multiValues[] = [$colrefs[$colname], $index + 1, $multivalue]; 174*aeb8444cSAnna Dabrowska } 175*aeb8444cSAnna Dabrowska // copy first value to the single column 176*aeb8444cSAnna Dabrowska if(isset($value[0])) { 177*aeb8444cSAnna Dabrowska $this->singleValues[] = $value[0]; 178*aeb8444cSAnna Dabrowska } else { 179*aeb8444cSAnna Dabrowska $this->singleValues[] = null; 180*aeb8444cSAnna Dabrowska } 181*aeb8444cSAnna Dabrowska } else { 182*aeb8444cSAnna Dabrowska $this->singleValues[] = $value; 183*aeb8444cSAnna Dabrowska } 184*aeb8444cSAnna Dabrowska } 185*aeb8444cSAnna Dabrowska 186*aeb8444cSAnna Dabrowska $this->sqlite->query('BEGIN TRANSACTION'); 187*aeb8444cSAnna Dabrowska 188*aeb8444cSAnna Dabrowska $ok = $this->beforeSave(); 189*aeb8444cSAnna Dabrowska 190*aeb8444cSAnna Dabrowska // insert single values 191*aeb8444cSAnna Dabrowska $ok = $ok && $this->sqlite->query( 192*aeb8444cSAnna Dabrowska $this->getSingleSql(), 193*aeb8444cSAnna Dabrowska array_merge($this->getSingleNoninputValues(), $this->singleValues) 194*aeb8444cSAnna Dabrowska ); 195*aeb8444cSAnna Dabrowska 196*aeb8444cSAnna Dabrowska $ok = $ok && $this->afterSingleSave(); 197*aeb8444cSAnna Dabrowska 198*aeb8444cSAnna Dabrowska // insert multi values 199*aeb8444cSAnna Dabrowska if ($ok && $this->multiValues) { 200*aeb8444cSAnna Dabrowska $multisql = $this->getMultiSql(); 201*aeb8444cSAnna Dabrowska $multiNoninputValues = $this->getMultiNoninputValues(); 202*aeb8444cSAnna Dabrowska foreach ($this->multiValues as $value) { 203*aeb8444cSAnna Dabrowska $ok = $ok && $this->sqlite->query( 204*aeb8444cSAnna Dabrowska $multisql, 205*aeb8444cSAnna Dabrowska array_merge($multiNoninputValues, $value) 206*aeb8444cSAnna Dabrowska ); 207*aeb8444cSAnna Dabrowska } 208*aeb8444cSAnna Dabrowska } 209*aeb8444cSAnna Dabrowska 210*aeb8444cSAnna Dabrowska if (!$ok) { 211*aeb8444cSAnna Dabrowska $this->sqlite->query('ROLLBACK TRANSACTION'); 212*aeb8444cSAnna Dabrowska return false; 213*aeb8444cSAnna Dabrowska } 214*aeb8444cSAnna Dabrowska $this->sqlite->query('COMMIT TRANSACTION'); 215*aeb8444cSAnna Dabrowska return true; 216*aeb8444cSAnna Dabrowska } 217*aeb8444cSAnna Dabrowska 218*aeb8444cSAnna Dabrowska /** 219*aeb8444cSAnna Dabrowska * Check whether all required data is present 220*aeb8444cSAnna Dabrowska * 221*aeb8444cSAnna Dabrowska * @param array $data 222*aeb8444cSAnna Dabrowska * @return bool 223*aeb8444cSAnna Dabrowska */ 224*aeb8444cSAnna Dabrowska abstract protected function validateTypeData($data); 225*aeb8444cSAnna Dabrowska 226*aeb8444cSAnna Dabrowska /** 227*aeb8444cSAnna Dabrowska * Names of non-input columns to be inserted into SQL query 228*aeb8444cSAnna Dabrowska * 229*aeb8444cSAnna Dabrowska * @return array 230*aeb8444cSAnna Dabrowska */ 231*aeb8444cSAnna Dabrowska abstract protected function getSingleNoninputCols(); 232*aeb8444cSAnna Dabrowska 233*aeb8444cSAnna Dabrowska /** 234*aeb8444cSAnna Dabrowska * Values for non-input columns to be inserted into SQL query 235*aeb8444cSAnna Dabrowska * for single-value tables 236*aeb8444cSAnna Dabrowska * 237*aeb8444cSAnna Dabrowska * @return array 238*aeb8444cSAnna Dabrowska */ 239*aeb8444cSAnna Dabrowska abstract protected function getSingleNoninputValues(); 240*aeb8444cSAnna Dabrowska 241*aeb8444cSAnna Dabrowska /** 242*aeb8444cSAnna Dabrowska * String template for single-value table 243*aeb8444cSAnna Dabrowska * 244*aeb8444cSAnna Dabrowska * @return string 245*aeb8444cSAnna Dabrowska */ 246*aeb8444cSAnna Dabrowska protected function getSingleSql() 247*aeb8444cSAnna Dabrowska { 248*aeb8444cSAnna Dabrowska $cols = array_merge($this->getSingleNoninputCols(), $this->singleCols); 249*aeb8444cSAnna Dabrowska $cols = join(',', $cols); 250*aeb8444cSAnna Dabrowska $vals = array_merge($this->getSingleNoninputValues(), $this->singleValues); 251*aeb8444cSAnna Dabrowska 252*aeb8444cSAnna Dabrowska return "INSERT INTO $this->stable ($cols) VALUES (" . trim(str_repeat('?,', count($vals)),',') . ');'; 253*aeb8444cSAnna Dabrowska } 254*aeb8444cSAnna Dabrowska 255*aeb8444cSAnna Dabrowska /** 256*aeb8444cSAnna Dabrowska * Optional operations to be executed before saving data 257*aeb8444cSAnna Dabrowska * 258*aeb8444cSAnna Dabrowska * @return bool False if any of the operations failed and transaction should be rolled back 259*aeb8444cSAnna Dabrowska */ 260*aeb8444cSAnna Dabrowska protected function beforeSave() 261*aeb8444cSAnna Dabrowska { 262*aeb8444cSAnna Dabrowska return true; 263*aeb8444cSAnna Dabrowska } 264*aeb8444cSAnna Dabrowska 265*aeb8444cSAnna Dabrowska /** 266*aeb8444cSAnna Dabrowska * Optional operations to be executed after saving data to single-value table, 267*aeb8444cSAnna Dabrowska * before saving multivalues 268*aeb8444cSAnna Dabrowska * 269*aeb8444cSAnna Dabrowska * @return bool False if anything goes wrong and transaction should be rolled back 270*aeb8444cSAnna Dabrowska */ 271*aeb8444cSAnna Dabrowska protected function afterSingleSave() 272*aeb8444cSAnna Dabrowska { 273*aeb8444cSAnna Dabrowska return true; 274*aeb8444cSAnna Dabrowska } 275*aeb8444cSAnna Dabrowska 276*aeb8444cSAnna Dabrowska /** 277*aeb8444cSAnna Dabrowska * String template for multi-value table 278*aeb8444cSAnna Dabrowska * 279*aeb8444cSAnna Dabrowska * @return string 280*aeb8444cSAnna Dabrowska */ 281*aeb8444cSAnna Dabrowska abstract protected function getMultiSql(); 282*aeb8444cSAnna Dabrowska 283*aeb8444cSAnna Dabrowska /** 284*aeb8444cSAnna Dabrowska * Values for non-input columns to be inserted into SQL query 285*aeb8444cSAnna Dabrowska * for multi-value tables 286*aeb8444cSAnna Dabrowska * @return array 287*aeb8444cSAnna Dabrowska */ 288*aeb8444cSAnna Dabrowska abstract protected function getMultiNoninputValues(); 289*aeb8444cSAnna 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 489897aef42SAndreas Gohr * time and pid. When the current timestamp is 0, the newest revision is 490897aef42SAndreas Gohr * returned. Used in @see buildGetDataSQL() 491f411d872SAndreas Gohr * 492897aef42SAndreas Gohr * @return int 493f411d872SAndreas Gohr */ 494897aef42SAndreas Gohr abstract protected function getLastRevisionTimestamp(); 49587dc1344SAndreas Gohr 49687dc1344SAndreas Gohr /** 49787dc1344SAndreas Gohr * Check if the given data validates against the current types. 49887dc1344SAndreas Gohr * 49987dc1344SAndreas Gohr * @param array $data 50093ca6f4fSAndreas Gohr * @return AccessDataValidator 50187dc1344SAndreas Gohr */ 50287dc1344SAndreas Gohr public function getValidator($data) { 50393ca6f4fSAndreas Gohr return new AccessDataValidator($this, $data); 50487dc1344SAndreas Gohr } 505c73fba38SAnna Dabrowska 506c73fba38SAnna Dabrowska /** 507c73fba38SAnna Dabrowska * Returns true if data is of type "page" 508c73fba38SAnna Dabrowska * 509c73fba38SAnna Dabrowska * @param string $pid 510c73fba38SAnna Dabrowska * @param int $rev 511c73fba38SAnna Dabrowska * @param int $rid 512c73fba38SAnna Dabrowska * @return bool 513c73fba38SAnna Dabrowska */ 514c73fba38SAnna Dabrowska public static function isTypePage($pid, $rev, $rid) 515c73fba38SAnna Dabrowska { 516c73fba38SAnna Dabrowska return $rev > 0; 517c73fba38SAnna Dabrowska } 518c73fba38SAnna Dabrowska 519c73fba38SAnna Dabrowska /** 520c73fba38SAnna Dabrowska * Returns true if data is of type "lookup" 521c73fba38SAnna Dabrowska * 522c73fba38SAnna Dabrowska * @param string $pid 523c73fba38SAnna Dabrowska * @param int $rev 524c73fba38SAnna Dabrowska * @param int $rid 525c73fba38SAnna Dabrowska * @return bool 526c73fba38SAnna Dabrowska */ 527c73fba38SAnna Dabrowska public static function isTypeLookup($pid, $rev, $rid) 528c73fba38SAnna Dabrowska { 529c73fba38SAnna Dabrowska return $pid === ''; 530c73fba38SAnna Dabrowska } 531c73fba38SAnna Dabrowska 532c73fba38SAnna Dabrowska /** 533c73fba38SAnna Dabrowska * Returns true if data is of type "serial" 534c73fba38SAnna Dabrowska * 535c73fba38SAnna Dabrowska * @param string $pid 536c73fba38SAnna Dabrowska * @param int $rev 537c73fba38SAnna Dabrowska * @param int $rid 538c73fba38SAnna Dabrowska * @return bool 539c73fba38SAnna Dabrowska */ 540c73fba38SAnna Dabrowska public static function isTypeSerial($pid, $rev, $rid) 541c73fba38SAnna Dabrowska { 542c73fba38SAnna Dabrowska return $pid !== '' && $rev === 0; 543c73fba38SAnna Dabrowska } 544f411d872SAndreas Gohr} 545f411d872SAndreas Gohr 546f411d872SAndreas Gohr 547