Add config for db-schema:1.0 + Updated src + Update notice

This commit is contained in:
xdrm-brackets 2017-09-09 15:55:32 +02:00
parent cca6d23c46
commit 61b74d5bcf
3 changed files with 175 additions and 108 deletions

View File

@ -35,7 +35,7 @@ The aim of this package is to make your life easier working with database creati
Features:
- Manage multiple databases (according to the database-driver)
- Push a json configuration to a database (mysql)
- (todo) Pull a database schema to a json file
- Pull a database schema to a json file
2 - Usage
----
@ -66,25 +66,42 @@ use \dbschema\core\dBuilder;
```php
// loads the default schema
dBuilder::parse();
$dbuilder = dBuilder::load();
// loads the custom schema
dBuilder::parse('custom');
$dbuilder = dBuilder::load('custom');
```
> ### 2) Push the loaded schema to the database
```php
// push to the default database
dBuilder::push();
$dbuilder->push();
// push a custom database
dBuilder::push('custom-db');
$dbuilder->push('custom-db');
```
Note: In the first line, it will use the database-driver default configuration. In the second line, it will use the database-driver `custom` configuration.
> ### 3) Pull a configuration from a database
```php
// pulls into the default schema (default database-driver config)
$dbuilder = dBuilder::pull();
// pulls into the custom schema
$dbuilder = dBuilder::pull('custom');
// pulls into the default schema ('custom-db' database-driver config)
$dbuilder = dBuilder::pull(null, 'custom-db');
// pulls into the custom schema ('custom-db' database-driver config)
$dbuilder = dBuilder::pull('custom', 'custom-db);
```
3 - configuration
----
@ -136,31 +153,4 @@ Note: In the first line, it will use the database-driver default configuration.
## (2) Field types
### Default types
|Type|Example|Description|
|---|---|---|
|`bool`|`true`|Boolean (true or false)|
|`boolean`|`true`|Boolean (true or false)|
|`bit`|`true`|Boolean (true or false)|
|`char`|`a`|Any character|
|`int`|`10`|Positive integer number between `0` and `2147483647`|
|`integer`|`10`|Positive integer number between `0` and `2147483647`|
|`number`|`10`|Positive integer number between `0` and `2147483647`|
|`float`|`-10.2`, `23.4`|Any real number|
|`double`|`-10.2`, `23.4`|Any real number|
|`decimal`|`-10.2`, `23.4`|Any real number|
|`real`|`-10.2`, `23.4`|Any real number|
|`time`|`12:23,32`|Time|
|`date`|`12-08-2017`|Date|
|`datetime`|`12-08-2017 12:23,32`|Datetime|
|`timestamp`|`1504954629`|Timestamp|
### Complex types
|Type|Description|
|---|---|
|`varchar(a)`|Text of a maximum length of `a`|
|`double(a,b)`|Decimal number with a size of `a` and a decimal size of `b`|
|`float(a,b)`|Decimal number with a size of `a` and a decimal size of `b`|
|`decimal(a,b)`|Decimal number with a size of `a` and a decimal size of `b`|
|`real(a,b)`|Decimal number with a size of `a` and a decimal size of `b`|
You must use the default MySQL field types.

View File

@ -0,0 +1,18 @@
{
"default": {
"user": {
"id_user": { "type": "int", "primary": true, "auto_increment": true },
"username": { "type": "varchar(30)", "unique": true, "null": false },
"description": { "type": "text", "default": null }
},
"article": {
"id_article": { "type": "int", "primary": true, "auto_increment": true },
"#id_writer": { "type": "int", "ref": [ "user", "id_user" ] },
"title": { "type": "varchar(50)", "null": false },
"body": { "type": "text", "null": false }
}
}
}

View File

@ -9,20 +9,33 @@
// Constantes
private static function config_path(){ return __ROOT__.'/config/dbschema.json'; }
private static function config_path(){ return __ROOT__.'/config/db-schema.json'; }
// Private attributes
private static $raw = null;
private $raw = null;
/* [0] Constructor
*
* @raw<array> Creates an instance from a json
*
=========================================================*/
private function __construct($raw=[]){
$this->raw = $raw;
}
/* [1] Builds a local schema from the json file
*
* @return status False on error
* @label<String> The database label
*
* @return instance<dBuilder> dBuilder instance -> NULL on error
*
=========================================================*/
public static function parse(){
public static function load($label=null){
/* [1] Extract config file
=========================================================*/
@ -30,22 +43,28 @@
/* (1) Check if file exists */
if( !file_exists($conf) )
return false;
return null;
/* (2) Try to read file */
self::$raw = file_get_contents($conf);
$RAW = file_get_contents($conf);
if( self::$raw === false )
return false;
if( $RAW === false )
return null;
/* (3) Try to parse JSON */
self::$raw = json_decode(self::$raw, true);
$RAW = json_decode($RAW, true);
if( is_null(self::$raw) )
return false;
if( is_null($RAW) )
return null;
/* (4) Add 'constrain' flag according to '#' before column name */
foreach(self::$raw as &$table){
/* (4) If label does not exist -> abort */
is_null($label) && ($label = 'default');
if( !isset($RAW[$label]) )
return null;
/* (5) Add 'constraint' flag according to '#' before column name */
foreach($RAW[$label] as &$table){
foreach($table as $column_name=>$column){
if( $column_name[0] == '#' ){
@ -60,7 +79,7 @@
return true;
return new self($RAW[$label]);
}
@ -69,20 +88,22 @@
/* [2] Populates a database
*
* @label<String> DatabaseDriver label
* @dblabel<String> DatabaseDriver label
*
* @return status False on error
=========================================================*/
public static function push($label=null){
public function push($ddlabel=null){
$PDO = DatabaseDriver::getPDO($label);
/* [0] Initialize useful variables
=========================================================*/
$PDO = DatabaseDriver::getPDO($ddlabel);
$QUERY = '';
$foreign_keys = []; // global foreign keys
/* [1] For each table create an entry
=========================================================*/
foreach(self::$raw as $table_name=>$table){
foreach($this->raw as $table_name=>$table){
/* (1) Initialise variables
---------------------------------------------------------*/
@ -114,12 +135,8 @@
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) Add corresponding SQL type to the query */
$QUERY .= $column['type'];
/* (2.2) Manage inline constraints (not null, auto_increment)
@ -147,12 +164,12 @@
$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]]) ){
if( isset($this->raw[$fk[0]]) && isset($this->raw[$fk[0]][$fk[1]]) ){
// {2} Check if the type matches //
$refSQLType = self::checkType(self::$raw[$fk[0]][$fk[1]]['type']);
$refType = $this->raw[$fk[0]][$fk[1]]['type'];
if( $refSQLType == $SQLType )
if( $refType == $column['type'] )
$foreign_keys[] = [ $table_name, $column_name, $fk[0], $fk[1] ];
}
@ -233,76 +250,118 @@
/* [3] Checks if a given type is correct
/* [3] Fills a config file from a database
*
* @type<Mixed> The human-readable type
* @label<String> The database label
* @dblabel<String> DatabaseDriver label
*
* @return SQLType<String> The corresponding SQL type
* FALSE on error
* @return instance<dBuilder> dBuilder instance -> NULL on error
*
=========================================================*/
private static function checkType($type){
/* [1] Check complex types
public static function pull($label=null, $ddlabel=null){
/* [1] Get basic information (tables)
=========================================================*/
/* (1) Varchar
---------------------------------------------------------*/
if( preg_match("@^varchar\((\d+)\)$@", $type, $match) )
return "VARCHAR(${match[1]})";
/* (1) Initialize raw data */
$RAW = [];
/* (2) Double
---------------------------------------------------------*/
if( preg_match("@^(?:double|float|decimal|real)\((\d+), ?(\d+)\)$@", $type, $match) )
return "DOUBLE(${match[1]},${match[2]})";
/* (2) Get database name */
$db_name = DatabaseDriver::get()->getConfig()['dbname'];
/* (3) Get the table list */
$tabList = DatabaseDriver::getPDO($ddlabel)->query("SHOW TABLES");
$tabList = $tabList->fetchAll();
/* (4) Populate raw data */
foreach($tabList as $field){
$table_name = $field['Tables_in_'.$db_name];
$RAW[$table_name] = [];
}
/* [2] Check simple types
/* [2] Get each tables' columns
=========================================================*/
/* (1) Boolean
---------------------------------------------------------*/
if( $type == 'bool' || $type == 'boolean' || $type == 'bit' )
return 'BIT';
foreach($RAW as $table_name=>&$table){
/* (2) Character
---------------------------------------------------------*/
if( $type == 'char' || $type == 'byte' )
return 'CHAR';
/* (1) Get column list */
$colList = DatabaseDriver::getPDO($ddlabel)->query("SHOW COLUMNS FROM $table_name");
$colList = $colList->fetchAll();
/* (3) Integer
---------------------------------------------------------*/
if( $type == 'int' || $type == 'integer' || $type == 'number' )
return 'INT';
/* (2) Add each column to $table array */
foreach($colList as $column){
/* (4) Float
---------------------------------------------------------*/
if( $type == 'float' || $type == 'double' || $type == 'decimal' || $type == 'real' )
return 'DOUBLE';
/* (2.1) Foreign key management */
$col_name = ($column['Key'] == 'MUL') ? '#'.$column['Field'] : $column['Field'];
/* (5) Text
---------------------------------------------------------*/
if( $type == 'text' )
return 'TEXT';
/* (2.2) Fill basic data*/
$table[$col_name] = [
'type' => $column['Type']
];
/* (6) Date & time
---------------------------------------------------------*/
if( $type == 'date' )
return 'DATE';
// {2.2.1} PRIMARY KEY //
if( $column['Key'] == 'PRI' )
$table[$col_name]['primary'] = true;
if( $type == 'time' )
return 'TIME';
// {2.2.2} NOT NULL //
if( $column['Null'] == 'NO' )
$table[$col_name]['null'] = false;
if( $type == 'datetime' )
return 'DATETIME';
// {2.2.3} AUTO_INCREMENT //
if( $column['Extra'] == 'auto_increment' )
$table[$col_name]['auto_increment'] = true;
if( $type == 'timestamp' )
return 'TIMESTAMP';
}
/* (3) Get each tables' constraints */
// {3.1} Get table constraints //
$conList = DatabaseDriver::getPDO($ddlabel)->query("SHOW CREATE TABLE $table_name");
$conList = $conList->fetch()['Create Table'];
$conLines = explode("\n", $conList);
return false;
// {3.2} For each column -> get constraints //
foreach($conLines as $i=>$line)
if( preg_match('/CONSTRAINT `.+` FOREIGN KEY \(`(.+)`\) REFERENCES `(.+)` \(`(.+)`\)+/i', $line, $m) )
if( isset($table['#'.$m[1]]) )
$table['#'.$m[1]]['ref'] = [ $m[2], $m[3] ];
}
/* [3] Extract config file
=========================================================*/
$conf = self::config_path();
/* (1) Check if file exists */
if( !file_exists($conf) )
return 1;
/* (2) Try to read file */
$OUTDATED = file_get_contents($conf);
if( $OUTDATED === false )
return 2;
/* (3) Try to parse JSON */
$OUTDATED = json_decode($OUTDATED, true);
if( is_null($OUTDATED) )
return 3;
/* [4] Adds pulled schema + writes
=========================================================*/
/* (1) Set $label to default if missing */
is_null($label) && ($label = 'default');
/* (2) Adds pulled conf to conf */
var_dump($RAW);
$OUTDATED[$label] = $RAW;
/* (3) Writes down new config */
file_put_contents(self::config_path(), json_encode($OUTDATED, JSON_PRETTY_PRINT) );
return self::load($label);
}
}