FRED™  3.0
FRED™: Framework for Rapid and Easy Development
Def.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Rsi\Fred;
4 
6 
7 class Def extends Component{
8 
10  public $filename = null;
11 
12  public $boolTrue = 1;
13  public $boolFalse = 0;
14  public $charLimit = 128;
15 
16  protected $_def = null;
17 
18  /**
19  * Generate a definition file from the database structure.
20  * @param string $table_trans Transformation method to use for the table name.
21  * @see \\Rsi\\Str::transform()
22  */
23  public function generateDatabaseStructure($table_trans = null){
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;
30  $db = $this->component('db');
31  foreach($db->tables() as $table_name){
32  $table = [];
33  foreach($db->columns($table_name) as $column_name => $column){
34  switch($default = $column['default']){
35  case 'NULL': $default = null; break;
36  default:
37  if(preg_match('/^\'(.*)\'$/',$default,$match)) $default = $match[1];
38  }
39  $def = [
40  Widget::REQUIRED => (bool)$column['required'],
41  Widget::DEFAULT_VALUE => $default,
42  'primary' => (bool)$column['primary'],
43  'ref' => $column['ref']
44  ];
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;
50  }
51  elseif(substr($type,-4) == 'text'){
52  $def['type'] = 'memo';
53  $def[Widget::MAX] = (int)$column['length'];
54  }
55  else switch($type){
56  case 'varchar':
57  $def['type'] = $column['length'] > $this->charLimit ? 'memo' : 'char';
58  $def[Widget::MAX] = (int)$column['length'];
59  break;
60  case 'decimal':
61  case 'float':
62  case 'double':
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));
67  }
68  break;
69  default:
70  $def['type'] = $type;
71  }
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;
76  }
77  }
78  $structure[$table_names[strtolower($table_name)] ?? \Rsi\Str::transform($table_name,$table_trans)] = $table;
79  }
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."
84  );
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;
89  });
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;
95  }
96  return $warnings;
97  }
98  /**
99  * Table definition (all columns).
100  * @param string $table
101  * @return array Key = column, value = definition.
102  */
103  public function table($table){
104  return \Rsi\Record::iget($this->def,$table);
105  }
106  /**
107  * Primary key columns.
108  * @param string $table
109  * @return array
110  */
111  public function key($table){
112  $key = [];
113  foreach($this->table($table) as $column => $def) if($def['primary'] ?? false) $key[] = $column;
114  return $key;
115  }
116  /**
117  * Column definition.
118  * @param string $table Table name.
119  * @param string $column Column name.
120  * @param array $extra Extra properties to add to the definition.
121  * @return array Definition (including referenced definitions).
122  */
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);
129  unset($def[null]);
130  }
131  foreach($def as $key => $value) if(substr($key,0,1) == '@'){
132  unset($def[$key]);
133  $def[substr($key,1)] = call_user_func($value);
134  }
135  return $def;
136  }
137  /**
138  * Definition value.
139  * @param string $table Table name.
140  * @param string $column Column name.
141  * @param string $key Key of value.
142  * @param mixed $default Default value if the key is not present in the definition.
143  */
144  public function value($table,$column,$key,$default = null){
145  return \Rsi\Record::get($this->column($table,$column),$key,$default);
146  }
147  /**
148  * Get the base (referenced) column.
149  * @param string $table
150  * @param string $column
151  * @return string Base column name.
152  */
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;
157  }
158  return null;
159  }
160  /**
161  * Convert a single value from database format to standard, internal format.
162  * @param string $type Column type.
163  * @param mixed $value Value in database format.
164  * @return mixed Value in standard, internal format.
165  */
166  public function convert($type,$value){
167  if($value !== null) switch($type){
168  case 'bool': return $value == $this->boolTrue;
169  case 'number': return $value + 0;
170  case 'json': return json_decode($value);
171  }
172  return $value;
173  }
174  /**
175  * Convert a single column value from database format to standard, internal format.
176  * @param string $column Column name.
177  * @param mixed $value Value in database format.
178  * @param array $tables Tables for the column.
179  * @return mixed Value in standard, internal format.
180  */
181  public function convertColumn($column,$value,$tables){
182  foreach($tables as $table) if($def = $this->column($table,$column))
183  return $this->convert($def['type'] ?? null,$value);
184  return $value;
185  }
186  /**
187  * Convert a record from database format to standard, internal format.
188  * @param array $record Record in database format.
189  * @param array $tables Tables for the column.
190  * @return array Record in standard, internal format.
191  */
192  public function convertRecord($record,$tables){
193  if($record) foreach($record as $column => &$value) $value = $this->convertColumn($column,$value,$tables);
194  unset($value);
195  return $record;
196  }
197  /**
198  * Format a value from standard, internal format to database format.
199  * @param string $type Column type.
200  * @param mixed $value Value in standard, internal format.
201  * @return mixed Value in database format.
202  */
203  public function format($type,$value){
204  if($value !== null) switch($type){
205  case 'bool': return $value ? $this->boolTrue : $this->boolFalse;
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);
209  }
210  return $value;
211  }
212  /**
213  * Convert a single column value from standard, internal format to database format.
214  * @param string $column Column name.
215  * @param mixed $value Value in standard, internal format.
216  * @param array $tables Tables for the column.
217  * @return mixed Value in database format.
218  */
219  public function formatColumn($column,$value,$tables){
220  foreach($tables as $table) if($def = $this->column($table,$column))
221  return $this->format($def['type'] ?? null,$value);
222  return $value;
223  }
224  /**
225  * Format a value from standard, internal format to database format.
226  * @param array $record Record in standard, internal format.
227  * @param array $tables Tables for the column.
228  * @return array Record in database format.
229  */
230  public function formatRecord($record,$tables){
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);
233  break;
234  }
235  unset($value);
236  return $record;
237  }
238 
239  protected function getDef(){
240  if($this->_def === null){
241  $this->_def = [];
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));
244  }
245  return $this->_def;
246  }
247 
248  public function __call($func_name,$params){
249  return $this->column($func_name,array_shift($params),array_shift($params));
250  }
251 
252 }
Rsi\Fred\Def\key
key($table)
Primary key columns.
Definition: Def.php:111
Rsi
Rsi\Fred\Def\generateDatabaseStructure
generateDatabaseStructure($table_trans=null)
Generate a definition file from the database structure.
Definition: Def.php:23
Rsi\Fred\Def\convertColumn
convertColumn($column, $value, $tables)
Convert a single column value from database format to standard, internal format.
Definition: Def.php:181
Rsi\Fred\Controller\Widget\MAX
const MAX
Maximum value.
Definition: Widget.php:29
Rsi\Fred\Def\$boolTrue
$boolTrue
Definition: Def.php:12
Rsi\Fred\Controller\Widget\MIN
const MIN
Minimum value.
Definition: Widget.php:28
Rsi\Fred\Def\$_def
$_def
Definition: Def.php:16
Rsi\Fred\Def\$filename
$filename
Definition: Def.php:10
Rsi\Fred\Controller\Widget\REQUIRED
const REQUIRED
True for required. Set to self::VALID_FUNC to let the validation function handle this....
Definition: Widget.php:30
Rsi\Fred\Def\convert
convert($type, $value)
Convert a single value from database format to standard, internal format.
Definition: Def.php:166
Rsi\Fred\Def\$boolFalse
$boolFalse
Definition: Def.php:13
Rsi\Fred\Def
Definition: Def.php:7
Rsi\Fred\Def\convertRecord
convertRecord($record, $tables)
Convert a record from database format to standard, internal format.
Definition: Def.php:192
Rsi\Fred\Def\__call
__call($func_name, $params)
Definition: Def.php:248
Rsi\Fred\Component
Basic component class.
Definition: Component.php:8
Rsi\Fred\Def\$databaseStructureFilename
$databaseStructureFilename
Definition: Def.php:9
Rsi\Fred\Def\format
format($type, $value)
Format a value from standard, internal format to database format.
Definition: Def.php:203
Rsi\Fred\Controller\Widget\DEFAULT_VALUE
const DEFAULT_VALUE
Definition: Widget.php:13
Rsi\Fred\Component\component
component($name)
Get a component (local or default).
Definition: Component.php:81
Rsi\Fred\Def\table
table($table)
Table definition (all columns).
Definition: Def.php:103
Rsi\Fred\Controller\Widget
Definition: Char.php:3
Rsi\Fred\Def\value
value($table, $column, $key, $default=null)
Definition value.
Definition: Def.php:144
Rsi\Fred\Def\getDef
getDef()
Definition: Def.php:239
Rsi\Fred\Def\$charLimit
$charLimit
Definition: Def.php:14
Rsi\Fred\Def\column
column($table, $column, $extra=null)
Column definition.
Definition: Def.php:123
Rsi\Fred\Def\ref
ref($table, $column)
Get the base (referenced) column.
Definition: Def.php:153
Rsi\Fred\Def\formatRecord
formatRecord($record, $tables)
Format a value from standard, internal format to database format.
Definition: Def.php:230
Rsi\Fred\Def\formatColumn
formatColumn($column, $value, $tables)
Convert a single column value from standard, internal format to database format.
Definition: Def.php:219
Rsi\Fred\Exception
Definition: Exception.php:5
Rsi\Fred
Definition: Alive.php:3