Add 'db-schema' src package
This commit is contained in:
parent
1738ba1ea1
commit
8e08f02718
|
@ -0,0 +1,309 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace dbschema\core;
|
||||||
|
|
||||||
|
use \database\core\DatabaseDriver;
|
||||||
|
|
||||||
|
|
||||||
|
class dBuilder{
|
||||||
|
|
||||||
|
|
||||||
|
// Constantes
|
||||||
|
private static function config_path(){ return __ROOT__.'/config/dbschema.json'; }
|
||||||
|
|
||||||
|
|
||||||
|
// Private attributes
|
||||||
|
private static $raw = null;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* [1] Builds a local schema from the json file
|
||||||
|
*
|
||||||
|
* @return status False on error
|
||||||
|
=========================================================*/
|
||||||
|
public static function parse(){
|
||||||
|
|
||||||
|
/* [1] Extract config file
|
||||||
|
=========================================================*/
|
||||||
|
$conf = self::config_path();
|
||||||
|
|
||||||
|
/* (1) Check if file exists */
|
||||||
|
if( !file_exists($conf) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* (2) Try to read file */
|
||||||
|
self::$raw = file_get_contents($conf);
|
||||||
|
|
||||||
|
if( self::$raw === false )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* (3) Try to parse JSON */
|
||||||
|
self::$raw = json_decode(self::$raw, true);
|
||||||
|
|
||||||
|
if( is_null(self::$raw) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* (4) Add 'constrain' flag according to '#' before column name */
|
||||||
|
foreach(self::$raw as &$table){
|
||||||
|
|
||||||
|
foreach($table as $column_name=>$column){
|
||||||
|
if( $column_name[0] == '#' ){
|
||||||
|
$table[$column_name]['foreign'] = true;
|
||||||
|
$table[substr($column_name,1)] = $table[$column_name];
|
||||||
|
unset($table[$column_name]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* [2] Populates a database
|
||||||
|
*
|
||||||
|
* @label<String> DatabaseDriver label
|
||||||
|
*
|
||||||
|
* @return status False on error
|
||||||
|
=========================================================*/
|
||||||
|
public static function push($label=null){
|
||||||
|
|
||||||
|
$PDO = DatabaseDriver::getPDO($label);
|
||||||
|
$QUERY = '';
|
||||||
|
$foreign_keys = []; // global foreign keys
|
||||||
|
|
||||||
|
|
||||||
|
/* [1] For each table create an entry
|
||||||
|
=========================================================*/
|
||||||
|
foreach(self::$raw as $table_name=>$table){
|
||||||
|
|
||||||
|
/* (1) Initialise variables
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
/* (1) The built query */
|
||||||
|
$QUERY .= "CREATE TABLE IF NOT EXISTS `$table_name`(\n";
|
||||||
|
|
||||||
|
/* (2) Constraints */
|
||||||
|
$constraints = [
|
||||||
|
'primary' => [],
|
||||||
|
'foreign_k' => [],
|
||||||
|
'unique' => [],
|
||||||
|
'default' => [],
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
/* (2) For each column create an entry
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
foreach($table as $column_name=>$column){
|
||||||
|
|
||||||
|
/* (1) Notify if foreign key */
|
||||||
|
$foreign = isset($column['foreign']) && $column['foreign'] == true;
|
||||||
|
|
||||||
|
/* (2) Append column name to query */
|
||||||
|
$QUERY .= "\t`$column_name` ";
|
||||||
|
|
||||||
|
|
||||||
|
/* (2.1) Manage column type
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
/* (1) If type missing, ignore this column */
|
||||||
|
if( !isset($column['type']) || !is_string($column['type']) )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* (2) If incorrect type, ignore column */
|
||||||
|
if( ($SQLType = self::checkType($column['type'])) == false )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* (3) Add corresponding SQL type to the query */
|
||||||
|
$QUERY .= "$SQLType";
|
||||||
|
|
||||||
|
|
||||||
|
/* (2.2) Manage inline constraints (not null, auto_increment)
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
/* (1) If 'null' set to FALSE, add NOT NULL constraint */
|
||||||
|
if( isset($column['null']) && $column['null'] == false )
|
||||||
|
$QUERY .= " NOT NULL";
|
||||||
|
|
||||||
|
/* (2) If 'auto_increment' set to TRUE, add AUTO_INCREMENT constraint */
|
||||||
|
if( isset($column['auto_increment']) && $column['auto_increment'] == true )
|
||||||
|
$QUERY .= " AUTO_INCREMENT";
|
||||||
|
|
||||||
|
/* (3) Append ',' column separator */
|
||||||
|
$QUERY .= ",\n";
|
||||||
|
|
||||||
|
|
||||||
|
/* (2.3) Manage global constraints (will be declared outside the CREATE TABLE)
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
/* (1) Primary key - if 'primary' == true */
|
||||||
|
if( isset($column['primary']) && $column['primary'] === true )
|
||||||
|
$constraints['primary'][] = $column_name;
|
||||||
|
|
||||||
|
/* (2) Foreign key - if foreign column && 'ref' == [table, column] */
|
||||||
|
if( $foreign && isset($column['ref']) && is_array($column['ref']) && sizeof($column['ref']) == 2 ){
|
||||||
|
$fk = $column['ref'];
|
||||||
|
|
||||||
|
// {1} Check if the 'ref' field exists in JSON structure //
|
||||||
|
if( isset(self::$raw[$fk[0]]) && isset(self::$raw[$fk[0]][$fk[1]]) ){
|
||||||
|
|
||||||
|
// {2} Check if the type matches //
|
||||||
|
$refSQLType = self::checkType(self::$raw[$fk[0]][$fk[1]]['type']);
|
||||||
|
|
||||||
|
if( $refSQLType == $SQLType )
|
||||||
|
$foreign_keys[] = [ $table_name, $column_name, $fk[0], $fk[1] ];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (3) Unique - if 'unique' == true */
|
||||||
|
if( isset($column['unique']) && $column['unique'] == true )
|
||||||
|
$constraints['unique'][] = $column_name;
|
||||||
|
|
||||||
|
/* (4) Default - if 'default' is set */
|
||||||
|
if( isset($column['default']) ){
|
||||||
|
|
||||||
|
// {4.1} If null -> use SQL constant (NULL) //
|
||||||
|
if( is_null($column['default']) )
|
||||||
|
$constraints['default'][$column_name] = "NULL";
|
||||||
|
|
||||||
|
// {4.2} If a string -> add surrounding quotes '' //
|
||||||
|
else if( is_string($column['default']) )
|
||||||
|
$constraints['default'][$column_name] = "'".$column['default']."'";
|
||||||
|
|
||||||
|
// {4.3} If boolean -> use SQL constants (TRUE,FALSE) //
|
||||||
|
else if( is_bool($column['default']) )
|
||||||
|
$constraints['default'][$column_name] = ($column['default']) ? 'TRUE' : 'FALSE';
|
||||||
|
|
||||||
|
// {4.4} Else (numeric) -> write as is //
|
||||||
|
else
|
||||||
|
$constraints['default'][$column_name] = $column['default'];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (3) Add global constraints
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
/* (1) Add primary keys -> combine all columns that are primary for each table*/
|
||||||
|
if( sizeof($constraints['primary']) > 0 )
|
||||||
|
$QUERY .= "CONSTRAINT pk_$table_name PRIMARY KEY(`".implode('`,`', $constraints['primary'])."`),\n";
|
||||||
|
|
||||||
|
|
||||||
|
/* (2) End CREATE TABLE statement + remove last ',' */
|
||||||
|
$querylen = strlen($QUERY);
|
||||||
|
$QUERY[$querylen-2] = ")";
|
||||||
|
$QUERY[$querylen-1] = ";";
|
||||||
|
$QUERY .= "\n";
|
||||||
|
|
||||||
|
/* (3) Add 'unique' constraints */
|
||||||
|
foreach($constraints['unique'] as $field)
|
||||||
|
$QUERY .= "ALTER TABLE `$table_name` ADD CONSTRAINT un_${table_name}_$field UNIQUE(`$field`);\n";
|
||||||
|
|
||||||
|
/* (4) Add 'default' constraint */
|
||||||
|
foreach($constraints['default'] as $field=>$val)
|
||||||
|
$QUERY .= "ALTER TABLE `$table_name` ALTER COLUMN `$field` SET DEFAULT $val;\n";
|
||||||
|
|
||||||
|
$QUERY .= "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (4) Add global foreign keys */
|
||||||
|
foreach($foreign_keys as $fk)
|
||||||
|
$QUERY .= "ALTER TABLE `${fk[0]}` ADD CONSTRAINT fk_${fk[0]}_${fk[1]} FOREIGN KEY (`${fk[1]}`) REFERENCES `${fk[2]}`(`${fk[3]}`);\n";
|
||||||
|
|
||||||
|
/* [2] Create the tables
|
||||||
|
=========================================================*/
|
||||||
|
/* (1) Try to execute */
|
||||||
|
try{
|
||||||
|
$PDO->exec($QUERY);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
|
||||||
|
/* (2) If error -> return FALSE */
|
||||||
|
}catch(\Exception $e){
|
||||||
|
var_dump('bla');
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* [3] Checks if a given type is correct
|
||||||
|
*
|
||||||
|
* @type<Mixed> The human-readable type
|
||||||
|
*
|
||||||
|
* @return SQLType<String> The corresponding SQL type
|
||||||
|
* FALSE on error
|
||||||
|
*
|
||||||
|
=========================================================*/
|
||||||
|
private static function checkType($type){
|
||||||
|
/* [1] Check complex types
|
||||||
|
=========================================================*/
|
||||||
|
/* (1) Varchar
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
if( preg_match("@^varchar\((\d+)\)$@", $type, $match) )
|
||||||
|
return "VARCHAR(${match[1]})";
|
||||||
|
|
||||||
|
/* (2) Double
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
if( preg_match("@^(?:double|float|decimal|real)\((\d+), ?(\d+)\)$@", $type, $match) )
|
||||||
|
return "DOUBLE(${match[1]},${match[2]})";
|
||||||
|
|
||||||
|
|
||||||
|
/* [2] Check simple types
|
||||||
|
=========================================================*/
|
||||||
|
/* (1) Boolean
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
if( $type == 'bool' || $type == 'boolean' || $type == 'bit' )
|
||||||
|
return 'BIT';
|
||||||
|
|
||||||
|
/* (2) Character
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
if( $type == 'char' || $type == 'byte' )
|
||||||
|
return 'CHAR';
|
||||||
|
|
||||||
|
/* (3) Integer
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
if( $type == 'int' || $type == 'integer' || $type == 'number' )
|
||||||
|
return 'INT';
|
||||||
|
|
||||||
|
/* (4) Float
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
if( $type == 'float' || $type == 'double' || $type == 'decimal' || $type == 'real' )
|
||||||
|
return 'DOUBLE';
|
||||||
|
|
||||||
|
/* (5) Text
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
if( $type == 'text' )
|
||||||
|
return 'TEXT';
|
||||||
|
|
||||||
|
/* (6) Date & time
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
if( $type == 'date' )
|
||||||
|
return 'DATE';
|
||||||
|
|
||||||
|
if( $type == 'time' )
|
||||||
|
return 'TIME';
|
||||||
|
|
||||||
|
if( $type == 'datetime' )
|
||||||
|
return 'DATETIME';
|
||||||
|
|
||||||
|
if( $type == 'timestamp' )
|
||||||
|
return 'TIMESTAMP';
|
||||||
|
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue