24 if(!$this->databaseStructureFilename)
throw new Exception(
'No database structure filename');
25 $table_names = $structure = $collations = $warnings = [];
26 $all_caps = !$table_trans && is_file($this->databaseStructureFilename);
27 if($all_caps)
foreach(array_keys($this->def) as $table_name)
28 if(strtoupper($table_names[strtolower($table_name)] = $table_name) != $table_name) $all_caps =
false;
29 if($all_caps) $table_trans = \Rsi\Str::TRANSFORM_UPPER;
31 foreach($db->tables() as $table_name){
33 foreach($db->columns($table_name) as $column_name => $column){
34 switch($default = $column[
'default']){
35 case 'NULL': $default =
null;
break;
37 if(preg_match(
'/^\'(.*)\'$/',$default,$match)) $default = $match[1];
42 'primary' => (
bool)$column[
'primary'],
43 'ref' => $column[
'ref']
45 $type = $column[
'type'];
46 if(substr($type,-3) ==
'int'){
47 $def[
'type'] =
'number';
48 $def[
Widget::MAX] = $max = pow(10,$column[
'precision']) - 1;
49 $def[
Widget::MIN] = $column[
'unsigned'] ? 0 : -$max;
51 elseif(substr($type,-4) ==
'text'){
52 $def[
'type'] =
'memo';
57 $def[
'type'] = $column[
'length'] > $this->charLimit ?
'memo' :
'char';
63 $def[
'type'] =
'number';
64 if(($scale = $column[
'scale']) !==
null){
65 $def[
'decimals'] = $scale;
73 if($collation = $column[
'collation']){
74 if(!array_key_exists($collation,$collations)) $collations[$collation] = [];
75 $collations[$collation][] = $table_name .
'.' . $column_name;
78 $structure[$table_names[strtolower($table_name)] ?? \Rsi\Str::transform($table_name,$table_trans)] = $table;
80 \Rsi\File::export($this->databaseStructureFilename,$structure,0666,\
Rsi\File::EXPORT_PRETTY_PRINT,
81 "This database-structure file was auto-generated on " . date(
'Y-m-d H:i:s') .
".\n" .
82 "It may be overwritten in the future -- changes will NOT be saved!\n" .
83 "Use '{$this->filename}' instead for adjustments."
85 if(count($collations) > 1){
86 uasort($collations,
function($a,$b){
87 if(($ac = count($a)) == ($bc = count($b)))
return strcmp(array_shift($a),array_shift($b));
88 return $ac < $bc ? 1 : -1;
90 $default = \Rsi\Record::key($collations);
91 array_shift($collations);
92 $this->
component(
'log')->warning($warning =
"Columns with collation other than '$default'",[
'collations' => $collations]);
93 foreach($collations as $collation => $columns) $warning .=
"\n- $collation: " . implode(
', ',$columns);
94 $warnings[] = $warning;
104 return \Rsi\Record::iget($this->def,$table);
111 public function key($table){
113 foreach($this->
table($table) as $column => $def)
if($def[
'primary'] ??
false) $key[] = $column;
123 public function column($table,$column,$extra =
null){
124 $def = array_merge(\
Rsi\Record::iget($this->
table($table),$column,[]),$extra ?: []);
125 if(array_key_exists(
null,$def)){
126 $ref = \Rsi\Record::explode($def[
null]);
127 $column = array_pop($ref);
128 $def += $this->
column($ref ? array_pop($ref) : $table,$column);
131 foreach($def as $key => $value)
if(substr($key,0,1) ==
'@'){
133 $def[substr($key,1)] = call_user_func($value);
144 public function value($table,$column,$key,$default =
null){
145 return \Rsi\Record::get($this->
column($table,$column),$key,$default);
153 public function ref($table,$column){
154 if($ref = \
Rsi\Record::iget($this->
table($table),[$column,
null])){
155 $column = array_pop($ref);
156 return $this->
ref($ref ? array_pop($ref) : $table,$column) ?: $column;
167 if($value !==
null)
switch($type){
169 case 'number':
return $value + 0;
170 case 'json':
return json_decode($value);
182 foreach($tables as $table)
if($def = $this->
column($table,$column))
183 return $this->
convert($def[
'type'] ??
null,$value);
193 if($record)
foreach($record as $column => &$value) $value = $this->
convertColumn($column,$value,$tables);
204 if($value !==
null)
switch($type){
206 case 'date':
return is_numeric($value) ? $this->
component(
'db')->date($value) : $value;
207 case 'datetime':
return is_numeric($value) ? $this->
component(
'db')->dateTime($value) : $value;
208 case 'json':
return json_encode($value);
220 foreach($tables as $table)
if($def = $this->
column($table,$column))
221 return $this->
format($def[
'type'] ??
null,$value);
231 if($record)
foreach($record as $column => &$value)
foreach($tables as $table)
if($column = $this->
column($table,$column)){
232 $value = $this->
format($column[
'type'] ??
null,$value);
240 if($this->_def ===
null){
242 if($this->databaseStructureFilename) $this->_def = array_replace_recursive($this->_def,require($this->databaseStructureFilename));
243 if($this->filename) $this->_def = array_replace_recursive($this->_def,require($this->filename));
248 public function __call($func_name,$params){
249 return $this->
column($func_name,array_shift($params),array_shift($params));