1083afc55SAndreas Gohr<?php 2083afc55SAndreas Gohr 3ba766201SAndreas Gohrnamespace dokuwiki\plugin\struct\meta; 4d486d6d7SAndreas Gohr 5ba766201SAndreas Gohruse dokuwiki\plugin\struct\types\AbstractBaseType; 6083afc55SAndreas Gohr 745560cc7SAndreas Gohrif (!defined('JSON_PRETTY_PRINT')) define('JSON_PRETTY_PRINT', 0); // PHP 5.3 compatibility 845560cc7SAndreas Gohr 97182938bSAndreas Gohr/** 107182938bSAndreas Gohr * Class Schema 117182938bSAndreas Gohr * 127182938bSAndreas Gohr * Represents the schema of a single data table and all its properties. It defines what can be stored in 137182938bSAndreas Gohr * the represented data table and how those contents are formatted. 147182938bSAndreas Gohr * 157182938bSAndreas Gohr * It can be initialized with a timestamp to access the schema as it looked at that particular point in time. 167182938bSAndreas Gohr * 17ba766201SAndreas Gohr * @package dokuwiki\plugin\struct\meta 187182938bSAndreas Gohr */ 19*d6d97f60SAnna Dabrowskaclass Schema 20*d6d97f60SAnna Dabrowska{ 21f800af69SMichael Große use TranslationUtilities; 22f800af69SMichael Große 23083afc55SAndreas Gohr /** @var \helper_plugin_sqlite|null */ 24083afc55SAndreas Gohr protected $sqlite; 25083afc55SAndreas Gohr 26083afc55SAndreas Gohr /** @var int The ID of this schema */ 27083afc55SAndreas Gohr protected $id = 0; 28083afc55SAndreas Gohr 29fa7b96aaSMichael Grosse /** @var string the user who last edited this schema */ 30fa7b96aaSMichael Grosse protected $user = ''; 31fa7b96aaSMichael Grosse 32083afc55SAndreas Gohr /** @var string name of the associated table */ 33083afc55SAndreas Gohr protected $table = ''; 34083afc55SAndreas Gohr 35083afc55SAndreas Gohr /** 36083afc55SAndreas Gohr * @var string the current checksum of this schema 37083afc55SAndreas Gohr */ 38083afc55SAndreas Gohr protected $chksum = ''; 39083afc55SAndreas Gohr 401c502704SAndreas Gohr /** @var Column[] all the colums */ 41083afc55SAndreas Gohr protected $columns = array(); 42083afc55SAndreas Gohr 43083afc55SAndreas Gohr /** @var int */ 44083afc55SAndreas Gohr protected $maxsort = 0; 45083afc55SAndreas Gohr 46250c83c2SAndreas Gohr /** @var int */ 47250c83c2SAndreas Gohr protected $ts = 0; 48250c83c2SAndreas Gohr 49d486d6d7SAndreas Gohr /** @var string struct version info */ 50d486d6d7SAndreas Gohr protected $structversion = '?'; 51d486d6d7SAndreas Gohr 52127d6bacSMichael Große /** @var array config array with label translations */ 53127d6bacSMichael Große protected $config = array(); 54e2c90eebSAndreas Gohr 55083afc55SAndreas Gohr /** 56083afc55SAndreas Gohr * Schema constructor 577182938bSAndreas Gohr * 58083afc55SAndreas Gohr * @param string $table The table this schema is for 59083afc55SAndreas Gohr * @param int $ts The timestamp for when this schema was valid, 0 for current 60083afc55SAndreas Gohr */ 61*d6d97f60SAnna Dabrowska public function __construct($table, $ts = 0) 62*d6d97f60SAnna Dabrowska { 63127d6bacSMichael Große $baseconfig = array('allowed editors' => ''); 64127d6bacSMichael Große 65083afc55SAndreas Gohr /** @var \helper_plugin_struct_db $helper */ 66083afc55SAndreas Gohr $helper = plugin_load('helper', 'struct_db'); 67d486d6d7SAndreas Gohr $info = $helper->getInfo(); 68d486d6d7SAndreas Gohr $this->structversion = $info['date']; 69083afc55SAndreas Gohr $this->sqlite = $helper->getDB(); 70083afc55SAndreas Gohr $table = self::cleanTableName($table); 71083afc55SAndreas Gohr $this->table = $table; 72250c83c2SAndreas Gohr $this->ts = $ts; 73083afc55SAndreas Gohr 74083afc55SAndreas Gohr // load info about the schema itself 75083afc55SAndreas Gohr if ($ts) { 76083afc55SAndreas Gohr $sql = "SELECT * 77083afc55SAndreas Gohr FROM schemas 78083afc55SAndreas Gohr WHERE tbl = ? 79083afc55SAndreas Gohr AND ts <= ? 80083afc55SAndreas Gohr ORDER BY ts DESC 81083afc55SAndreas Gohr LIMIT 1"; 82083afc55SAndreas Gohr $opt = array($table, $ts); 83083afc55SAndreas Gohr } else { 84083afc55SAndreas Gohr $sql = "SELECT * 85083afc55SAndreas Gohr FROM schemas 86083afc55SAndreas Gohr WHERE tbl = ? 87083afc55SAndreas Gohr ORDER BY ts DESC 88083afc55SAndreas Gohr LIMIT 1"; 89083afc55SAndreas Gohr $opt = array($table); 90083afc55SAndreas Gohr } 91083afc55SAndreas Gohr $res = $this->sqlite->query($sql, $opt); 92127d6bacSMichael Große $config = array(); 93083afc55SAndreas Gohr if ($this->sqlite->res2count($res)) { 944e2abec0SMichael Große $schema = $this->sqlite->res2arr($res); 954e2abec0SMichael Große $result = array_shift($schema); 96083afc55SAndreas Gohr $this->id = $result['id']; 97fa7b96aaSMichael Grosse $this->user = $result['user']; 989007da58SMichael Große $this->chksum = isset($result['chksum']) ? $result['chksum'] : ''; 99587e314dSAndreas Gohr $this->ts = $result['ts']; 100127d6bacSMichael Große $config = json_decode($result['config'], true); 101083afc55SAndreas Gohr } 102083afc55SAndreas Gohr $this->sqlite->res_close($res); 103127d6bacSMichael Große $this->config = array_merge($baseconfig, $config); 104f800af69SMichael Große $this->initTransConfig(array('label')); 105083afc55SAndreas Gohr if (!$this->id) return; 106083afc55SAndreas Gohr 107083afc55SAndreas Gohr // load existing columns 108083afc55SAndreas Gohr $sql = "SELECT SC.*, T.* 109083afc55SAndreas Gohr FROM schema_cols SC, 110083afc55SAndreas Gohr types T 1111c502704SAndreas Gohr WHERE SC.sid = ? 1121c502704SAndreas Gohr AND SC.tid = T.id 113083afc55SAndreas Gohr ORDER BY SC.sort"; 1141c502704SAndreas Gohr $res = $this->sqlite->query($sql, $this->id); 115083afc55SAndreas Gohr $rows = $this->sqlite->res2arr($res); 116083afc55SAndreas Gohr $this->sqlite->res_close($res); 117083afc55SAndreas Gohr 118636c8abaSAndreas Gohr $typeclasses = Column::allTypes(); 119083afc55SAndreas Gohr foreach ($rows as $row) { 120328db41bSAndreas Gohr if ($row['class'] == 'Integer') { 121328db41bSAndreas Gohr $row['class'] = 'Decimal'; 122328db41bSAndreas Gohr } 123328db41bSAndreas Gohr 124636c8abaSAndreas Gohr $class = $typeclasses[$row['class']]; 12598eaa57dSAndreas Gohr if (!class_exists($class)) { 12698eaa57dSAndreas Gohr // This usually never happens, except during development 12798eaa57dSAndreas Gohr msg('Unknown type "' . hsc($row['class']) . '" falling back to Text', -1); 128ba766201SAndreas Gohr $class = 'dokuwiki\\plugin\\struct\\types\\Text'; 12998eaa57dSAndreas Gohr } 13098eaa57dSAndreas Gohr 131083afc55SAndreas Gohr $config = json_decode($row['config'], true); 132bbf3d6aaSAndreas Gohr /** @var AbstractBaseType $type */ 133bbf3d6aaSAndreas Gohr $type = new $class($config, $row['label'], $row['ismulti'], $row['tid']); 134bbf3d6aaSAndreas Gohr $column = new Column( 1351c502704SAndreas Gohr $row['sort'], 136bbf3d6aaSAndreas Gohr $type, 1371c502704SAndreas Gohr $row['colref'], 13863d51bbfSAndreas Gohr $row['enabled'], 13963d51bbfSAndreas Gohr $table 1401c502704SAndreas Gohr ); 141bbf3d6aaSAndreas Gohr $type->setContext($column); 1421c502704SAndreas Gohr 1437629557eSAndreas Gohr $this->columns[] = $column; 144083afc55SAndreas Gohr if ($row['sort'] > $this->maxsort) $this->maxsort = $row['sort']; 145083afc55SAndreas Gohr } 146083afc55SAndreas Gohr } 147083afc55SAndreas Gohr 148083afc55SAndreas Gohr /** 14967641668SAndreas Gohr * @return string identifer for debugging purposes 15067641668SAndreas Gohr */ 151*d6d97f60SAnna Dabrowska function __toString() 152*d6d97f60SAnna Dabrowska { 15367641668SAndreas Gohr return __CLASS__ . ' ' . $this->table . ' (' . $this->id . ') ' . ($this->islookup ? 'LOOKUP' : 'DATA'); 15467641668SAndreas Gohr } 15567641668SAndreas Gohr 15667641668SAndreas Gohr /** 157083afc55SAndreas Gohr * Cleans any unwanted stuff from table names 158083afc55SAndreas Gohr * 159083afc55SAndreas Gohr * @param string $table 160083afc55SAndreas Gohr * @return string 161083afc55SAndreas Gohr */ 162*d6d97f60SAnna Dabrowska public static function cleanTableName($table) 163*d6d97f60SAnna Dabrowska { 1642af472dcSAndreas Gohr $table = strtolower($table); 165083afc55SAndreas Gohr $table = preg_replace('/[^a-z0-9_]+/', '', $table); 166083afc55SAndreas Gohr $table = preg_replace('/^[0-9_]+/', '', $table); 167083afc55SAndreas Gohr $table = trim($table); 168083afc55SAndreas Gohr return $table; 169083afc55SAndreas Gohr } 170083afc55SAndreas Gohr 171127d6bacSMichael Große 172127d6bacSMichael Große /** 173097f4a53SAndreas Gohr * Gets a list of all available schemas 174097f4a53SAndreas Gohr * 1757c080d69SAndreas Gohr * @param string $filter either 'page' or 'lookup' 1767c080d69SAndreas Gohr * @return \string[] 177097f4a53SAndreas Gohr */ 178*d6d97f60SAnna Dabrowska public static function getAll($filter = '') 179*d6d97f60SAnna Dabrowska { 180097f4a53SAndreas Gohr /** @var \helper_plugin_struct_db $helper */ 181097f4a53SAndreas Gohr $helper = plugin_load('helper', 'struct_db'); 1827cbcfbdbSAndreas Gohr $db = $helper->getDB(false); 183097f4a53SAndreas Gohr if (!$db) return array(); 184097f4a53SAndreas Gohr 1857c080d69SAndreas Gohr if ($filter == 'page') { 1867c080d69SAndreas Gohr $where = 'islookup = 0'; 1877c080d69SAndreas Gohr } elseif ($filter == 'lookup') { 1887c080d69SAndreas Gohr $where = 'islookup = 1'; 1897c080d69SAndreas Gohr } else { 1907c080d69SAndreas Gohr $where = '1 = 1'; 1917c080d69SAndreas Gohr } 1927c080d69SAndreas Gohr 1937c080d69SAndreas Gohr $res = $db->query("SELECT DISTINCT tbl FROM schemas WHERE $where ORDER BY tbl"); 194097f4a53SAndreas Gohr $tables = $db->res2arr($res); 195097f4a53SAndreas Gohr $db->res_close($res); 196097f4a53SAndreas Gohr 197097f4a53SAndreas Gohr $result = array(); 198097f4a53SAndreas Gohr foreach ($tables as $row) { 199097f4a53SAndreas Gohr $result[] = $row['tbl']; 200097f4a53SAndreas Gohr } 201097f4a53SAndreas Gohr return $result; 202097f4a53SAndreas Gohr } 203097f4a53SAndreas Gohr 204097f4a53SAndreas Gohr /** 205d5a1a6dcSAndreas Gohr * Delete all data associated with this schema 206d5a1a6dcSAndreas Gohr * 207d5a1a6dcSAndreas Gohr * This is really all data ever! Be careful! 208d5a1a6dcSAndreas Gohr */ 209*d6d97f60SAnna Dabrowska public function delete() 210*d6d97f60SAnna Dabrowska { 211d5a1a6dcSAndreas Gohr if (!$this->id) throw new StructException('can not delete unsaved schema'); 212d5a1a6dcSAndreas Gohr 213d5a1a6dcSAndreas Gohr $this->sqlite->query('BEGIN TRANSACTION'); 214d5a1a6dcSAndreas Gohr 215d5a1a6dcSAndreas Gohr $sql = "DROP TABLE ?"; 216d5a1a6dcSAndreas Gohr $this->sqlite->query($sql, 'data_' . $this->table); 217d5a1a6dcSAndreas Gohr $this->sqlite->query($sql, 'multi_' . $this->table); 218d5a1a6dcSAndreas Gohr 219d5a1a6dcSAndreas Gohr $sql = "DELETE FROM schema_assignments WHERE tbl = ?"; 220d5a1a6dcSAndreas Gohr $this->sqlite->query($sql, $this->table); 221d5a1a6dcSAndreas Gohr 222d5a1a6dcSAndreas Gohr $sql = "DELETE FROM schema_assignments_patterns WHERE tbl = ?"; 223d5a1a6dcSAndreas Gohr $this->sqlite->query($sql, $this->table); 224d5a1a6dcSAndreas Gohr 225d5a1a6dcSAndreas Gohr $sql = "SELECT T.id 226d5a1a6dcSAndreas Gohr FROM types T, schema_cols SC, schemas S 227d5a1a6dcSAndreas Gohr WHERE T.id = SC.tid 228d5a1a6dcSAndreas Gohr AND SC.sid = S.id 229d5a1a6dcSAndreas Gohr AND S.tbl = ?"; 230d5a1a6dcSAndreas Gohr $sql = "DELETE FROM types WHERE id IN ($sql)"; 231d5a1a6dcSAndreas Gohr $this->sqlite->query($sql, $this->table); 232d5a1a6dcSAndreas Gohr 233d5a1a6dcSAndreas Gohr $sql = "SELECT id 234d5a1a6dcSAndreas Gohr FROM schemas 235d5a1a6dcSAndreas Gohr WHERE tbl = ?"; 236d5a1a6dcSAndreas Gohr $sql = "DELETE FROM schema_cols WHERE sid IN ($sql)"; 237d5a1a6dcSAndreas Gohr $this->sqlite->query($sql, $this->table); 238d5a1a6dcSAndreas Gohr 239d5a1a6dcSAndreas Gohr $sql = "DELETE FROM schemas WHERE tbl = ?"; 240d5a1a6dcSAndreas Gohr $this->sqlite->query($sql, $this->table); 241d5a1a6dcSAndreas Gohr 242d5a1a6dcSAndreas Gohr $this->sqlite->query('COMMIT TRANSACTION'); 243d5a1a6dcSAndreas Gohr $this->sqlite->query('VACUUM'); 244f9f13d8cSAndreas Gohr 245f9f13d8cSAndreas Gohr // a deleted schema should not be used anymore, but let's make sure it's somewhat sane anyway 246f9f13d8cSAndreas Gohr $this->id = 0; 247f9f13d8cSAndreas Gohr $this->chksum = ''; 248f9f13d8cSAndreas Gohr $this->columns = array(); 249f9f13d8cSAndreas Gohr $this->maxsort = 0; 250f9f13d8cSAndreas Gohr $this->ts = 0; 251d5a1a6dcSAndreas Gohr } 252d5a1a6dcSAndreas Gohr 25379c83e06SMichael Große 25479c83e06SMichael Große /** 25579c83e06SMichael Große * Clear all data of a schema, but retain the schema itself 25679c83e06SMichael Große */ 257*d6d97f60SAnna Dabrowska public function clear() 258*d6d97f60SAnna Dabrowska { 25979c83e06SMichael Große if (!$this->id) throw new StructException('can not clear data of unsaved schema'); 26079c83e06SMichael Große 26179c83e06SMichael Große $this->sqlite->query('BEGIN TRANSACTION'); 26279c83e06SMichael Große $sql = 'DELETE FROM ?'; 26379c83e06SMichael Große $this->sqlite->query($sql, 'data_' . $this->table); 26479c83e06SMichael Große $this->sqlite->query($sql, 'multi_' . $this->table); 26579c83e06SMichael Große $this->sqlite->query('COMMIT TRANSACTION'); 26679c83e06SMichael Große $this->sqlite->query('VACUUM'); 26779c83e06SMichael Große } 26879c83e06SMichael Große 269d5a1a6dcSAndreas Gohr /** 2701c502704SAndreas Gohr * @return string 2711c502704SAndreas Gohr */ 272*d6d97f60SAnna Dabrowska public function getChksum() 273*d6d97f60SAnna Dabrowska { 2741c502704SAndreas Gohr return $this->chksum; 2751c502704SAndreas Gohr } 2761c502704SAndreas Gohr 2771c502704SAndreas Gohr /** 2781c502704SAndreas Gohr * @return int 2791c502704SAndreas Gohr */ 280*d6d97f60SAnna Dabrowska public function getId() 281*d6d97f60SAnna Dabrowska { 2821c502704SAndreas Gohr return $this->id; 2831c502704SAndreas Gohr } 2841c502704SAndreas Gohr 2851c502704SAndreas Gohr /** 286587e314dSAndreas Gohr * @return int returns the timestamp this Schema was created at 287f411d872SAndreas Gohr */ 288*d6d97f60SAnna Dabrowska public function getTimeStamp() 289*d6d97f60SAnna Dabrowska { 290f411d872SAndreas Gohr return $this->ts; 291f411d872SAndreas Gohr } 292f411d872SAndreas Gohr 293f411d872SAndreas Gohr /** 294fa7b96aaSMichael Grosse * @return string 295fa7b96aaSMichael Grosse */ 296*d6d97f60SAnna Dabrowska public function getUser() 297*d6d97f60SAnna Dabrowska { 298fa7b96aaSMichael Grosse return $this->user; 299fa7b96aaSMichael Grosse } 300fa7b96aaSMichael Grosse 301*d6d97f60SAnna Dabrowska public function getConfig() 302*d6d97f60SAnna Dabrowska { 303127d6bacSMichael Große return $this->config; 304e2c90eebSAndreas Gohr } 305e2c90eebSAndreas Gohr 306fa7b96aaSMichael Grosse /** 307f800af69SMichael Große * Returns the translated label for this schema 308f800af69SMichael Große * 309f800af69SMichael Große * Uses the current language as determined by $conf['lang']. Falls back to english 310f800af69SMichael Große * and then to the Schema label 311f800af69SMichael Große * 312f800af69SMichael Große * @return string 313f800af69SMichael Große */ 314*d6d97f60SAnna Dabrowska public function getTranslatedLabel() 315*d6d97f60SAnna Dabrowska { 316f800af69SMichael Große return $this->getTranslatedKey('label', $this->table); 317f800af69SMichael Große } 318f800af69SMichael Große 319f800af69SMichael Große /** 3206ebbbb8eSAndreas Gohr * Checks if the current user may edit data in this schema 3216ebbbb8eSAndreas Gohr * 3226ebbbb8eSAndreas Gohr * @return bool 3236ebbbb8eSAndreas Gohr */ 324*d6d97f60SAnna Dabrowska public function isEditable() 325*d6d97f60SAnna Dabrowska { 3266ebbbb8eSAndreas Gohr global $USERINFO; 327127d6bacSMichael Große if ($this->config['allowed editors'] === '') return true; 3286ebbbb8eSAndreas Gohr if (blank($_SERVER['REMOTE_USER'])) return false; 3296ebbbb8eSAndreas Gohr if (auth_isadmin()) return true; 330127d6bacSMichael Große return auth_isMember($this->config['allowed editors'], $_SERVER['REMOTE_USER'], $USERINFO['grps']); 3316ebbbb8eSAndreas Gohr } 3326ebbbb8eSAndreas Gohr 3336ebbbb8eSAndreas Gohr /** 334ce206ec7SAndreas Gohr * Returns a list of columns in this schema 335ce206ec7SAndreas Gohr * 336ce206ec7SAndreas Gohr * @param bool $withDisabled if false, disabled columns will not be returned 337ce206ec7SAndreas Gohr * @return Column[] 3381c502704SAndreas Gohr */ 339*d6d97f60SAnna Dabrowska public function getColumns($withDisabled = true) 340*d6d97f60SAnna Dabrowska { 341ce206ec7SAndreas Gohr if (!$withDisabled) { 342ce206ec7SAndreas Gohr return array_filter( 343ce206ec7SAndreas Gohr $this->columns, 344ce206ec7SAndreas Gohr function (Column $col) { 345ce206ec7SAndreas Gohr return $col->isEnabled(); 346ce206ec7SAndreas Gohr } 347ce206ec7SAndreas Gohr ); 348ce206ec7SAndreas Gohr } 349ce206ec7SAndreas Gohr 3501c502704SAndreas Gohr return $this->columns; 3511c502704SAndreas Gohr } 3521c502704SAndreas Gohr 353ae697e1fSAndreas Gohr /** 3545742aea9SAndreas Gohr * Find a column in the schema by its label 3555742aea9SAndreas Gohr * 3565742aea9SAndreas Gohr * Only enabled columns are returned! 3575742aea9SAndreas Gohr * 3585742aea9SAndreas Gohr * @param $name 3595742aea9SAndreas Gohr * @return bool|Column 3605742aea9SAndreas Gohr */ 361*d6d97f60SAnna Dabrowska public function findColumn($name) 362*d6d97f60SAnna Dabrowska { 3635742aea9SAndreas Gohr foreach ($this->columns as $col) { 3645742aea9SAndreas Gohr if ($col->isEnabled() && utf8_strtolower($col->getLabel()) == utf8_strtolower($name)) { 3655742aea9SAndreas Gohr return $col; 3665742aea9SAndreas Gohr } 3675742aea9SAndreas Gohr } 3685742aea9SAndreas Gohr return false; 3695742aea9SAndreas Gohr } 3705742aea9SAndreas Gohr 3715742aea9SAndreas Gohr /** 372ae697e1fSAndreas Gohr * @return string 373ae697e1fSAndreas Gohr */ 374*d6d97f60SAnna Dabrowska public function getTable() 375*d6d97f60SAnna Dabrowska { 376ae697e1fSAndreas Gohr return $this->table; 377ae697e1fSAndreas Gohr } 3781c502704SAndreas Gohr 379ae697e1fSAndreas Gohr /** 380ae697e1fSAndreas Gohr * @return int the highest sort number used in this schema 381ae697e1fSAndreas Gohr */ 382*d6d97f60SAnna Dabrowska public function getMaxsort() 383*d6d97f60SAnna Dabrowska { 384ae697e1fSAndreas Gohr return $this->maxsort; 385ae697e1fSAndreas Gohr } 3861c502704SAndreas Gohr 387d486d6d7SAndreas Gohr /** 388d486d6d7SAndreas Gohr * @return string the JSON representing this schema 389d486d6d7SAndreas Gohr */ 390*d6d97f60SAnna Dabrowska public function toJSON() 391*d6d97f60SAnna Dabrowska { 392d486d6d7SAndreas Gohr $data = array( 393d486d6d7SAndreas Gohr 'structversion' => $this->structversion, 394d486d6d7SAndreas Gohr 'schema' => $this->getTable(), 395d486d6d7SAndreas Gohr 'id' => $this->getId(), 39645313413SMichael Grosse 'user' => $this->getUser(), 397127d6bacSMichael Große 'config' => $this->getConfig(), 398d486d6d7SAndreas Gohr 'columns' => array() 399d486d6d7SAndreas Gohr ); 400d486d6d7SAndreas Gohr 401d486d6d7SAndreas Gohr foreach ($this->columns as $column) { 402d486d6d7SAndreas Gohr $data['columns'][] = array( 403d486d6d7SAndreas Gohr 'colref' => $column->getColref(), 404d486d6d7SAndreas Gohr 'ismulti' => $column->isMulti(), 405d486d6d7SAndreas Gohr 'isenabled' => $column->isEnabled(), 406d486d6d7SAndreas Gohr 'sort' => $column->getSort(), 407d486d6d7SAndreas Gohr 'label' => $column->getLabel(), 408d486d6d7SAndreas Gohr 'class' => $column->getType()->getClass(), 409d486d6d7SAndreas Gohr 'config' => $column->getType()->getConfig(), 410d486d6d7SAndreas Gohr ); 411d486d6d7SAndreas Gohr } 412d486d6d7SAndreas Gohr 413d486d6d7SAndreas Gohr return json_encode($data, JSON_PRETTY_PRINT); 414d486d6d7SAndreas Gohr } 415083afc55SAndreas Gohr} 416