Add 'db-schema' src package

This commit is contained in:
xdrm-brackets 2017-09-09 12:30:23 +02:00
parent 1738ba1ea1
commit 8e08f02718
1 changed files with 309 additions and 0 deletions

View File

@ -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;
}
}