0) { $line = fgets($inf); if ($line === false) return true; $overwrite--; } $line = fgets($inf); return $line === false || $line === ""; } finally { fclose($inf); } } private static function get_ovsuf($file, $overwrite) { if (is_file($file)) { if ($overwrite) return " (OVERWRITE)"; else return ""; } else return " (NEW)"; } private static function write($line, $w, $tmpf) { $r = fwrite($w, $line); if ($r === false) { fclose($w); throw new Exception("$tmpf: erreur lors de l'écriture du fichier"); } } private static function write_lines($lines, $outf, $overwrite=true, $final_nl=true) { if (is_file($outf) && !$overwrite) { return false; } $dir = dirname($outf); if (!is_dir($dir)) { $r = mkdir($dir, 0777, true); if ($r === false) { throw new Exception("$dir: erreur lors de la création du répertoire"); } } $tmpf = "$outf.tmp"; $w = fopen($tmpf, "w+b"); if ($w === false) { throw new Exception("$tmpf: erreur d'ouverture du fichier"); } $first = true; foreach ($lines as $line) { if ($first) $first = false; else self::write("\n", $w, $tmpf); self::write($line, $w, $tmpf); } if ($final_nl) self::write("\n", $w, $tmpf); $r = fclose($w); if ($r === false) { throw new Exception("$tmpf: erreur lors de la fermeture du fichier"); } $r = rename($tmpf, $outf); if ($r === false) { throw new Exception("$outf: erreur lors du renommage du fichier"); } return true; } ### private static function is_update(string $method) { return str::starts_with("update", $method); } private static function get_index(string $method) { return str::without_prefix("update", $method); } private static function update_methods(array &$methods, string $class): void { $all_methods = get_class_methods($class); if ($all_methods === null) { throw new Exception("$class: classe introuvable"); } $prefix = str_replace("\\", "_", $class); foreach ($all_methods as $method) { if (!self::is_update($method)) continue; $index = self::get_index($method); $name = "${prefix}_$index"; $methods[$name] = [ "class" => $class, "name" => $method, "index" => $index, "method" => [$class, $method], "prefix" => $prefix, ]; } $merge_classes = []; $c = new ReflectionClass($class); $merges = $c->getConstant("MERGES"); if (base::nz($merges)) A::merge($merge_classes, $merges); $merge = $c->getConstant("MERGE"); if (base::nz($merge)) $merge_classes[] = $merge; foreach ($merge_classes as $class) { self::update_methods($methods, $class); } } private static function get_methods($class) { $methods = []; self::update_methods($methods, $class); ksort($methods, SORT_NATURAL); return $methods; } ### private static function parse_col($def): array { if (preg_match('/^([a-zA-Z0-9_]+)(?:\((\d+)\s*(?:,\s*(\d+))?\))?\s*(.*)\s*(?:--\s*(.*)\s*)?(?:--\s*(.*)\s*)?$/', $def, $ms)) { $size = base::vn(A::get($ms, 2)); if ($size !== null) $size = intval($size); $precision = base::vn(A::get($ms, 3)); if ($precision !== null) $precision = intval($precision); return [ "type" => A::get($ms, 1), "size" => $size, "precision" => $precision, "options" => base::vn(A::get($ms, 4)), "title" => base::vn(A::get($ms, 5)), "desc" => base::vn(A::get($ms, 6)), ]; } else { throw new ValueException("erreur de syntaxe: $def"); } } private static function is_multi_fkdef($def, &$ms) { return preg_match('/^\((.+)\)$/', $def, $ms); } private static function is_single_fkref($ref, &$ms) { return preg_match('/^([a-zA-Z0-9_]+)\(([a-zA-Z0-9_]+)\)$/', $ref, $ms); } private static $tables = []; private static function has_table($table) { return A::get(self::$tables, $table, false) !== false; } private static function has_col($table, $col) { return (self::has_table($table) && A::get(self::$tables[$table], $col, false) !== false); } private static function add_table($table, $suffix=null, $dbtrait=null, $name=null): ?array { if (self::has_table($table)) return null; if ($name === null) $name = $table; return self::$tables[$table] = [ "name" => $name, "suffix" => $suffix, "cols" => [], "pk" => null, "dbtrait" => $dbtrait, ]; } private static function set_table_pk($table, $pk) { self::add_table($table); self::$tables[$table]["pk"] = A::with($pk); } private static function add_col($table, $col, $def=null): array { self::add_table($table); if ($def !== null) { [ "type" => $type, "size" => $size, "precision" => $precision, "options" => $options, "title" => $title, "desc" => $desc, ] = self::parse_col($def); #XXX calculer le type du schema: bool si integer(1), integer si integer, etc. $pk_col = boolval(preg_match('/\bprimary\s+key\b/i', $options)); $auto_col = boolval(preg_match('/\bauto_increment\b/i', $options)); if (str::starts_with("datetime", $type)) { $hot_type = "date"; #XXX ajouter le support datetime } elseif (str::starts_with("date", $type)) { $hot_type = "date"; } elseif (str::starts_with("int", $type)) { $hot_type = "numeric"; } else { $hot_type = "text"; } $cinfos = [ "name" => $col, "def" => $def, "pk" => $pk_col, "auto" => $auto_col, "hot_type" => $hot_type, # "schema" => [ "name" => $col, "title" => $title, "desc" => $desc, "mysql" => [ "type" => $type, "size" => $size, "precision" => $precision, "options" => $options, "pk" => $pk_col, "auto" => $auto_col, ], "hot" => [ "type" => $hot_type, ], ], ]; } else { $cinfos = [ "name" => $col, ]; } return self::$tables[$table]["cols"][$col] = $cinfos; } private static function del_table($table) { unset(self::$tables[$table]); } private static function del_col($table, $col) { if (!self::has_table($table)) return; unset(self::$tables[$table]["cols"][$col]); } private static $views = []; private static function has_view($view) { return A::get(self::$views, $view, false) !== false; } private static function add_view($view, $tables, $dbtrait=null, $name=null) { if (self::has_view($view)) return; if ($name === null) $name = $view; self::$views[$view] = [ "name" => $name, "tables" => $tables, "dbtrait" => $dbtrait, ]; } private static function del_view($view) { unset(self::$views[$view]); } private static $t1links = []; private static $tmlinks = []; private static function add_t1link($scol, $stable, $dcol, $dtable) { self::$t1links[] = [$scol, $stable, $dcol, $dtable]; } private static function reset($options=null, $tables_only=false) { self::$tables = []; self::$views = []; self::$t1links = []; self::$tmlinks = []; if (!$tables_only) { self::$trace = A::get($options, "trace"); } } ### static function gensql($class, $options=null) { self::reset($options); $destdir = A::get($options, "destdir", "."); $overwrite = A::get($options, "overwrite"); $verbose = A::get($options, "verbose"); $prefix = A::get($options, "prefix"); self::trace("# gensql"); self::trace(" class: $class"); self::trace(" destdir: $destdir"); $methods = self::get_methods($class); foreach ($methods as $minfos) { self::reset(null, true); $update = func::call($minfos["method"]); # par défaut, ne pas écraser les fichiers qui sont en +prod $prod = A::get($update, "+prod"); $overwrite_sql = $overwrite === null? !$prod: $overwrite; self::trace(" ## $minfos[class]::$minfos[name]"); $lines = [ "-- -*- coding: utf-8 mode: sql -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8", "-- fichier autogénéré: toute modification locale risque d'être perdue", ]; $desc = A::get($update, "+desc"); if ($desc) $lines[] = "-- $desc"; foreach ($update as $uname => $uinfos) { # ignorer les directives de mise à jour: elles ont été traitées ci-dessus if (str::starts_with("+", $uname)) { if (!in_array($uname, self::UPDATE_DIRECTIVES)) { trigger_error("$uname: unknown update directive", E_USER_WARNING); } continue; } $type = A::get($uinfos, "+type", "table"); if ($type === "table") { # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ $table = $uname; $table_name = A::get($uinfos, "+name", $table); $cols = $uinfos; ##################################################################### # suppression de table if ($cols === null) { $lines[] = "drop table $table_name;"; self::del_table($table); continue; } # liste de champs "normale" if (!self::has_table($table)) { ################################################################### # nouvelle table $lines[] = ""; $desc = A::get($cols, "+desc"); if ($desc) $lines[] = "-- $desc"; $lines[] = "create table $table_name ("; $suffix = A::get($cols, "+suffix"); self::add_table($table, $suffix, null, $table_name); $first = true; foreach ($cols as $col => $def) { # les directives seront traitées plus tard if (str::starts_with("+", $col)) continue; $lines[] = ($first? " ": ",")."$col $def"; $cinfos = self::add_col($table, $col, $def); if ($cinfos["pk"]) self::set_table_pk($table, $col); $first = false; } foreach ($cols as $col => $value) { if (!str::starts_with("+", $col)) continue; switch ($col) { case "+primary key": $pk = A::with($value); self::set_table_pk($table, $pk); $pk = implode(", ", $pk); $lines[] = ",primary key ($pk)"; break; case "+foreign key": foreach (A::with($value) as $fk => $ref) { $ms = null; if (self::is_multi_fkdef($fk, $ms)) $fk = $ms[1]; $lines[] = ",foreign key ($fk) references $ref"; $ms = null; if (self::is_single_fkref($ref, $ms)) { self::add_t1link($fk, $table, $ms[2], $ms[1]); } } break; case "+index": foreach (A::with($value) as $name => $cols) { if (is_numeric($name)) $name = false; $cols = implode(", ", A::with($cols)); $lines[] = ",index $name($cols)"; } break; case "+unique index": foreach (A::with($value) as $name => $cols) { if (is_numeric($name)) $name = false; $cols = implode(", ", A::with($cols)); $lines[] = ",unique index $name($cols)"; } break; default: if (!in_array($col, self::TABLE_DIRECTIVES)) { trigger_error("$table: $col: unknown table directive", E_USER_WARNING); } break; } } $lines[] = ");"; } else { ################################################################### # maj d'une table existante $lines[] = ""; $desc = A::get($cols, "+desc"); if ($desc) $lines[] = "-- $desc"; foreach ($cols as $col => $def) { # les directives seront traitées plus tard if (!str::starts_with("+", $col)) { if ($def === null) { ## suppression d'un champ if (!self::has_col($table, $col)) { trigger_error("$table.$col: deleting a non-existent column", E_USER_WARNING); } $lines[] = "alter table table_name drop column $col;"; self::del_col($table, $col); } else { if (self::has_col($table, $col)) { ## maj d'un champ $lines[] = "alter table table_name change column $col $col $def;"; # NB: pour simplifier, ne pas tenir compte du fait que ce # nouveau champ pourrait maintenant être une clé primaire } else { ## ajout d'un champ $lines[] = "alter table table_name add column $col $def;"; self::add_col($table, $col, $def); # NB: pour simplifier, ne pas tenir compte du fait que ce # nouveau champ pourrait être une clé primaire } } } else { ## maj directive trigger_error("$table: $col: table directive update is not (yet) supported", E_USER_WARNING); } } } } elseif ($type === "view") { # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ $view = $uname; $view_name = A::get($uinfos, "+name", $view); $vinfos = $uinfos; ##################################################################### # suppression de vue if ($vinfos === null) { $lines[] = "drop view $view_name;"; self::del_view($view); continue; } # définition "normale" if (!self::has_view($view)) { ################################################################### # nouvelle vue $tables = A::get($vinfos, "+view_tables"); $def = A::get($vinfos, "+view_def"); if ($def === null) trigger_error("$view: missing +view_def", E_USER_WARNING); self::add_view($view, $tables, null, $view_name); $lines[] = ""; $desc = A::get($vinfos, "+desc"); if ($desc) $lines[] = "-- $desc"; $lines[] = "create view $view_name as"; $lines[] = $def; $lines[] = ";"; } else { ################################################################### # maj d'une vue existante trigger_error("$view: view update is not (yet) supported", E_USER_WARNING); } } else { trigger_error("$type: unknown type, expected table or view", E_USER_WARNING); } } if (self::$tables || self::$views) { $name = A::get($update, "+name", "update"); $index = $minfos["index"]; $outfname = "$index-$name.sql"; if ($prefix) $outfname = "$minfos[prefix]--$outfname"; $outf = "$destdir/$outfname"; $ovsuf = self::get_ovsuf($outf, $overwrite_sql); if ($ovsuf || $verbose) { self::trace(" sql output: $outfname$ovsuf"); self::write_lines($lines, "$outf", $overwrite_sql); } # les fichiers csv ne sont écrasés que s'ils n'ont pas de données # automatiquement $overwrite_csv_threshold = $overwrite_sql? 1: false; foreach (self::$tables as $table => $tinfos) { $table_name = $tinfos["name"]; $cols = array_keys($tinfos["cols"]); $lines = [implode(",", $cols)]; $index++; $outfname = "$index-$table_name.csv"; if ($prefix) $outfname = "$minfos[prefix]--$outfname"; $outf = "$destdir/$outfname"; $overwrite_csv = self::should_overwrite($outf, $overwrite_csv_threshold); $ovsuf = self::get_ovsuf($outf, $overwrite_csv); if ($ovsuf || $verbose) { self::trace(" csv output: $outfname$ovsuf"); self::write_lines($lines, "$outf", $overwrite_csv); } } } } } static function gendoc($class, $options=null) { self::reset($options); $destdir = A::get($options, "destdir", "."); $overwrite = A::get($options, "overwrite"); $verbose = A::get($options, "verbose"); # par défaut, écraser les fichiers lors de la génération de la doc if ($overwrite === null) $overwrite = true; self::trace("# gendoc"); self::trace(" class: $class"); self::trace(" destdir: $destdir"); $methods = self::get_methods($class); foreach ($methods as $minfos) { $update = func::call($minfos["method"]); foreach ($update as $uname => $uinfos) { # ignorer les directives de mise à jour: elles ont été traitées ci-dessus if (str::starts_with("+", $uname)) { if (!in_array($uname, self::UPDATE_DIRECTIVES)) { trigger_error("$uname: unknown update directive", E_USER_WARNING); } continue; } $type = A::get($uinfos, "+type", "table"); if ($type === "table") { # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ $table = $uname; $cols = $uinfos; ##################################################################### # suppression de table if ($cols === null) { self::del_table($table); continue; } # liste de champs "normale" if (!self::has_table($table)) { ################################################################### # nouvelle table self::add_table($table); foreach ($cols as $col => $value) { if (!str::starts_with("+", $col)) { self::add_col($table, $col); } else { switch ($col) { case "+foreign key": foreach (A::with($value) as $fk => $ref) { $ms = null; if (self::is_multi_fkdef($fk, $ms)) $fk = $ms[1]; if (self::is_single_fkref($ref, $ms)) { self::add_t1link($fk, $table, $ms[2], $ms[1]); } } break; default: if (!in_array($col, self::TABLE_DIRECTIVES)) { trigger_error("$table: $col: unknown table directive", E_USER_WARNING); } break; } } } } else { ################################################################### # maj d'une table existante foreach ($cols as $col => $def) { # les directives seront traitées plus tard if (!str::starts_with("+", $col)) { if ($def === null) { ## suppression d'un champ if (!self::has_col($table, $col)) { trigger_error("$table.$col: deleting a non-existent column", E_USER_WARNING); } self::del_col($table, $col); } else { if (!self::has_col($table, $col)) { self::add_col($table, $col); } } } else { ## maj directive trigger_error("$table: $col: table directive update is not (yet) supported", E_USER_WARNING); } } } } elseif ($type === "view") { # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ $view = $uname; $vinfos = $uinfos; ##################################################################### # suppression de vue if ($vinfos === null) { self::del_view($view); continue; } # définition "normale" if (!self::has_view($view)) { ################################################################### # nouvelle vue $tables = A::get($vinfos, "+view_tables", null); self::add_view($view, $tables); } else { ################################################################### # maj d'une vue existante trigger_error("$view: view update is not (yet) supported", E_USER_WARNING); } } else { trigger_error("$type: unknown type, expected table or view", E_USER_WARNING); } } } $lines = [ "# -*- coding: utf-8 mode: plantuml -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8", "# fichier autogénéré: toute modification locale risque d'être perdue", "", "##@startuml", "hide empty members", "hide empty methods", "hide circle", "!ifndef SHOW_DETAILS", "hide members", "!endif", ]; foreach (self::$tables as $table => $tinfos) { $lines[] = ""; $lines[] = "class $table {"; $cols = $tinfos["cols"]; foreach (array_keys($cols) as $col) { $lines[] = " $col"; } $lines[] = "}"; } foreach (self::$views as $view => $vinfos) { $lines[] = ""; $lines[] = "class $view {"; $tables = $vinfos["tables"]; foreach ($tables as $table) { $cols = self::$tables[$table]["cols"]; foreach (array_keys($cols) as $col) { $lines[] = " $col"; } } $lines[] = "}"; } $lines[] = ""; $lines[] = "##@enduml"; $outfname = "classes.iuml"; $outf = "$destdir/$outfname"; $ovsuf = self::get_ovsuf($outf, $overwrite); if ($ovsuf || $verbose) { self::trace(" puml output: $outfname$ovsuf"); self::write_lines($lines, $outf, $overwrite, true); } $lines = []; foreach (self::$tables as $table => $tinfos) { $lines[] = "'hide $table"; } $first = true; foreach (self::$t1links as $link) { if ($first) $lines[] = ""; list($scol, $stable, $dcol, $dtable) = $link; $lines[] = "$stable \"*\" -- \"1\" $dtable"; $first = false; } A::merge($lines, [ "~~~", "", "-*- coding: utf-8 mode: markdown -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8:noeol:binary", ]); $slines = [ "![Modèle simplifié](model-simple.png)", "~~~puml", "# output=model-simple.png", "!include classes.iuml", ]; A::merge($slines, $lines); $outfname = "model-simple.md"; $outf = "$destdir/$outfname"; $ovsuf = self::get_ovsuf($outf, $overwrite); if ($ovsuf || $verbose) { self::trace(" md output: $outfname$ovsuf"); self::write_lines($slines, $outf, $overwrite, false); } $dlines = [ "![Modèle détaillé](model-details.png)", "~~~puml", "# output=model-details.png", "!define SHOW_DETAILS", "!include classes.iuml", ]; A::merge($dlines, $lines); $outfname = "model-details.md"; $outf = "$destdir/$outfname"; $ovsuf = self::get_ovsuf($outf, $overwrite); if ($ovsuf || $verbose) { self::trace(" md output: $outfname$ovsuf"); self::write_lines($dlines, $outf, $overwrite, false); } } private static function add_vtables(&$lines, $cols) { $lines[] = ""; $lines[] = " const VTABLES_HEADERS = self::COLUMNS;"; foreach ($cols as $col => $cinfos) { $vcol = strtoupper($col)."_VCOL"; $lines[] = " const $vcol = ["; $lines[] = " \"data\" => \"$col\","; $lines[] = " \"type\" => \"$cinfos[hot_type]\","; if ($cinfos["hot_type"] == "date") { $lines[] = " \"dateFormat\" => \"DD/MM/YYYY\","; $lines[] = " \"correctFormat\" => true,"; } $lines[] = " ];"; } $lines[] = " const VTABLES_SCHEMA = ["; foreach (array_keys($cols) as $col) { $vcol = strtoupper($col)."_VCOL"; $lines[] = " self::$vcol,"; } $lines[] = " ];"; } private static function add_data_schema(&$lines, $cols) { $cols = array_keys($cols); $lines[] = ""; foreach ($cols as $col) { $dcol = strtoupper($col)."_DCOL"; $lines[] = " const $dcol = ["; $lines[] = " \"name\" => \"$col\","; $lines[] = " \"key\" => \"$col\","; $lines[] = " ];"; } $lines[] = " const DATA_SCHEMA = ["; foreach ($cols as $col) { $dcol = strtoupper($col)."_DCOL"; $lines[] = " self::$dcol,"; } $lines[] = " ];"; $lines[] = " const CSV_SCHEMA = self::DATA_SCHEMA;"; $lines[] = " const HTML_SCHEMA = self::DATA_SCHEMA;"; } private static function add_schema(array &$lines, array $cols, string $indent): void { $schema = []; foreach ($cols as $col) { $schema[$col["name"]] = $col["schema"]; } md::normalize_mschema($schema); $generator = new SrcGenerator($indent); $generator->genConst("SCHEMA", $schema); $generator->mergeInto($lines); } static function genclass($class, $options=null) { $c = new ReflectionClass($class); $force_dbtrait = $c->getConstant("DBTRAIT"); $default_dbtrait = $c->getConstant("DEFAULT_DBTRAIT"); self::reset($options); $destdir = A::get($options, "destdir", "."); $package = A::get($options, "package"); $baserow = A::get($options, "baserow"); $overwrite = A::get($options, "overwrite"); $verbose = A::get($options, "verbose"); if ($baserow === null) $baserow = AbstractRow::class; $pos = strrpos($class, "\\"); $default_package = $pos !== false? substr($class, 0, $pos): false; if ($package === null) $package = $default_package; elseif (substr($package, 0, 1) != "\\") $package = "$default_package\\$package"; else $package = substr($package, 1); # par défaut ne pas écraser les fichiers lors de la génération des classes if ($overwrite === null) $overwrite = false; # ne pas écraser les classes dont la définition est en +prod $no_overwrites = []; self::trace("# genclass"); self::trace(" class: $class"); self::trace(" destdir: $destdir"); $methods = self::get_methods($class); foreach ($methods as $minfos) { $update = func::call($minfos["method"]); $dbtrait = $force_dbtrait; if (!$dbtrait) $dbtrait = A::get($update, "+dbtrait"); if (!$dbtrait) $dbtrait = $default_dbtrait; $prod = A::get($update, "+prod"); foreach ($update as $uname => $uinfos) { # ignorer les directives de mise à jour: elles ont été traitées ci-dessus if (str::starts_with("+", $uname)) { if (!in_array($uname, self::UPDATE_DIRECTIVES)) { trigger_error("$uname: unknown update directive", E_USER_WARNING); } continue; } $type = A::get($uinfos, "+type", "table"); if ($type === "table") { # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ $table = $uname; $table_name = A::get($uinfos, "+name", $table); $cols = $uinfos; ####################################################################### # suppression de table if ($cols === null) { self::del_table($table); if ($prod) unset($no_overwrites[$table]); continue; } # liste de champs "normale" if (!self::has_table($table)) { ##################################################################### # nouvelle table $suffix = A::get($cols, "+suffix"); self::add_table($table, $suffix, $dbtrait, $table_name); if ($prod) $no_overwrites[$table] = true; foreach ($cols as $col => $value) { if (!str::starts_with("+", $col)) { $def = $value; $cinfos = self::add_col($table, $col, $def); if ($cinfos["pk"]) self::set_table_pk($table, $col); } else { switch ($col) { case "+primary key": $pk = A::with($value); self::set_table_pk($table, $pk); break; case "+foreign key": foreach (A::with($value) as $fk => $ref) { $ms = null; if (self::is_multi_fkdef($fk, $ms)) $fk = $ms[1]; if (self::is_single_fkref($ref, $ms)) { self::add_t1link($fk, $table, $ms[2], $ms[1]); } } break; default: if (!in_array($col, self::TABLE_DIRECTIVES)) { trigger_error("$table: $col: unknown table directive", E_USER_WARNING); } break; } } } } else { ##################################################################### # maj d'une table existante foreach ($cols as $col => $def) { # les directives seront traitées plus tard if (!str::starts_with("+", $col)) { if ($def === null) { ## suppression d'un champ if (!self::has_col($table, $col)) { trigger_error("$table.$col: deleting a non-existent column", E_USER_WARNING); } self::del_col($table, $col); } else { if (!self::has_col($table, $col)) { self::add_col($table, $col, $def); } } } else { ## maj directive trigger_error("$table: $col: table directive update is not (yet) supported", E_USER_WARNING); } } } } elseif ($type === "view") { # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ $view = $uname; $view_name = A::get($uinfos, "+name", $view); $vinfos = $uinfos; ##################################################################### # suppression de vue if ($vinfos === null) { self::del_view($view); if ($prod) unset($no_overwrites[$view]); continue; } # définition "normale" if (!self::has_view($view)) { ################################################################### # nouvelle vue $tables = A::get($vinfos, "+view_tables"); self::add_view($view, $tables, $dbtrait, $view_name); if ($prod) $no_overwrites[$view] = true; } else { ################################################################### # maj d'une vue existante trigger_error("$view: view update is not (yet) supported", E_USER_WARNING); } } else { trigger_error("$type: unknown type, expected table or view", E_USER_WARNING); } } } foreach (self::$tables as $table => $tinfos) { $class = str::upperw($table); $class = preg_replace('/[^a-zA-Z0-9]*/', "", $class); $suffix = $tinfos["suffix"]; $suffix = $suffix? "\"$suffix\"": "null"; $pk = $tinfos["pk"]; $pk_key = []; if ($pk !== null) { foreach ($pk as $key) { $pk_key[] = "\"$key\""; } } if (!$pk_key) { $pk_key = "false"; } elseif (\count($pk_key) == 1) { $pk_key = $pk_key[0]; } else { $pk_key = "[".implode(", ", $pk_key)."]"; } $pk_auto = false; $cols = $tinfos["cols"]; foreach ($cols as $cinfos) { if ($cinfos["auto"]) { $pk_auto = true; break; } } $pk_auto = $pk_auto? "true": "false"; $dbtrait = $tinfos["dbtrait"]; $table_name = $tinfos["name"]; ### $lines = [" $vinfos) { $class = str::upperw($view); $class = preg_replace('/[^a-zA-Z0-9]*/', "", $class); $cols = []; foreach ($vinfos["tables"] as $table) { $cols = array_merge($cols, self::$tables[$table]["cols"]); } $dbtrait = $tinfos["dbtrait"]; $view_name = $vinfos["name"]; ### $lines = ["