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];
    40           Widget::REQUIRED => (bool)$column[
'required'],
    41           Widget::DEFAULT_VALUE => $default,
    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';
    53           $def[Widget::MAX] = (int)$column[
'length'];
    57             $def[
'type'] = $column[
'length'] > $this->charLimit ? 
'memo' : 
'char';
    58             $def[Widget::MAX] = (int)$column[
'length'];
    63             $def[
'type'] = 
'number';
    64             if(($scale = $column[
'scale']) !== null){
    65               $def[
'decimals'] = $scale;
    66               $def[Widget::MIN] = -($def[Widget::MAX] = pow(10,$column[
'precision'] - $scale) - pow(10,-$scale));
    72         $table[$column_name] = array_filter($def) + \Rsi\Record::select($def,[Widget::MIN,Widget::MAX]);
    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;
    81       $this->databaseStructureFilename,
    83       "//this database-structure file was auto-generated on " . date(
'Y-m-d H:i:s') . 
"\n" .
    84       "//it may be overwritten in the future -- changes will NOT be saved\n" .
    85       "//use '{$this->filename}' instead for adjustments\n\n" .
    86       preg_replace(
'/\\s+array \\(/',
' array(',
'return ' . var_export($structure,
true) . 
';'),
    89     if(count($collations) > 1){
    90       uasort($collations,
function($a,$b){
    91         if(($ac = count($a)) == ($bc = count($b))) 
return strcmp(array_shift($a),array_shift($b));
    92         return $ac < $bc ? 1 : -1;
    94       $default = \Rsi\Record::key($collations);
    95       array_shift($collations);
    96       $this->
component(
'log')->warning($warning = 
"Columns with collation other than '$default'",[
'collations' => $collations]);
    97       foreach($collations as $collation => $columns) $warning .= 
"\n- $collation: " . implode(
', ',$columns);
    98       $warnings[] = $warning;
   108     return \Rsi\Record::iget($this->def,$table);
   115   public function key($table){
   117     foreach($this->
table($table) as $column => $def) 
if($def[
'primary'] ?? 
false) $key[] = $column;
   127   public function column($table,$column,$extra = null){
   128     $def = array_merge(\
Rsi\Record::iget($this->
table($table),$column,[]),$extra ?: []);
   129     if(array_key_exists(null,$def)){
   130       $ref = \Rsi\Record::explode($def[null]);
   131       $column = array_pop($ref);
   132       $def += $this->
column($ref ? array_pop($ref) : $table,$column);
   135     foreach($def as $key => $value) 
if(substr($key,0,1) == 
'@'){
   137       $def[substr($key,1)] = call_user_func($value);
   148   public function value($table,$column,$key,$default = null){
   149     return \Rsi\Record::get($this->
column($table,$column),$key,$default);
   157   public function ref($table,$column){
   158     if($ref = \
Rsi\Record::iget($this->
table($table),[$column,null])){
   159       $column = array_pop($ref);
   160       return $this->
ref($ref ? array_pop($ref) : $table,$column) ?: $column;
   171     if($value !== null) 
switch($type){
   173       case 'number': 
return $value + 0;
   185     foreach($tables as $table) 
if($def = $this->
column($table,$column))
   186       return $this->
convert($def[
'type'] ?? null,$value);
   196     if($record) 
foreach($record as $column => &$value) $value = $this->
convertColumn($column,$value,$tables);
   207     if($value !== null) 
switch($type){
   209       case 'date': 
return is_numeric($value) ? $this->
component(
'db')->date($value) : $value;
   210       case 'datetime': 
return is_numeric($value) ? $this->
component(
'db')->dateTime($value) : $value;
   222     foreach($tables as $table) 
if($def = $this->
column($table,$column))
   223       return $this->
format($def[
'type'] ?? null,$value);
   233     if($record) 
foreach($record as $column => &$value) 
foreach($tables as $table) 
if($column = $this->
column($table,$column)){
   234       $value = $this->
format($column[
'type'] ?? null,$value);
   242     if($this->_def === null){
   244       if($this->databaseStructureFilename) $this->_def = array_replace_recursive($this->_def,require($this->databaseStructureFilename));
   245       if($this->filename) $this->_def = array_replace_recursive($this->_def,require($this->filename));
   250   public function __call($func_name,$params){
   251     return $this->
column($func_name,array_shift($params),array_shift($params));
 formatRecord($record, $tables)
Format a value from standard, internal format to database format. 
 
generateDatabaseStructure($table_trans=null)
Generate a definition file from the database structure. 
 
value($table, $column, $key, $default=null)
Definition value. 
 
__call($func_name, $params)
 
ref($table, $column)
Get the base (referenced) column. 
 
convertColumn($column, $value, $tables)
Convert a single column value from database format to standard, internal format. 
 
key($table)
Primary key columns. 
 
formatColumn($column, $value, $tables)
Convert a single column value from standard, internal format to database format. 
 
$databaseStructureFilename
 
column($table, $column, $extra=null)
Column definition. 
 
convertRecord($record, $tables)
Convert a record from database format to standard, internal format. 
 
format($type, $value)
Format a value from standard, internal format to database format. 
 
convert($type, $value)
Convert a single value from database format to standard, internal format. 
 
table($table)
Table definition (all columns). 
 
component($name)
Get a component (local or default).