You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

LuGenerator.php 9.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. <?php
  2. namespace Luticate\Generator;
  3. use PDO;
  4. use Twig_Autoloader;
  5. use Twig_Environment;
  6. use Twig_Loader_Filesystem;
  7. class LuGenerator {
  8. private $_pdo;
  9. public function __construct($db_connection, $db_database, $db_host, $db_port, $db_username, $db_password)
  10. {
  11. $dsn = $db_connection . ":dbname=" . $db_database . ";host="
  12. . $db_host . ";port=" . $db_port;
  13. $this->_pdo = new PDO($dsn, $db_username, $db_password);
  14. }
  15. protected function printError($query, $message)
  16. {
  17. echo $message . "\n";
  18. var_dump($query->errorInfo());
  19. var_dump($this->_pdo->errorInfo());
  20. return null;
  21. }
  22. protected function buildTwigVars($vars)
  23. {
  24. foreach ($vars as $key => $value)
  25. {
  26. if (is_array($value))
  27. $vars[$key] = $this->buildTwigVars($value);
  28. else if (is_string($value))
  29. {
  30. $vars[$key] = array(
  31. "as_it" => $value,
  32. "camel_upper" => $this->snakeToCamelCase($value, true),
  33. "camel_lower" => $this->snakeToCamelCase($value, false)
  34. );
  35. }
  36. }
  37. return $vars;
  38. }
  39. protected function buildTwig($templateFile, $destFile, $vars)
  40. {
  41. $twig_vars = $this->buildTwigVars($vars);
  42. Twig_Autoloader::register();
  43. $loader = new Twig_Loader_Filesystem(__DIR__ );
  44. $twig = new Twig_Environment($loader, array());
  45. $template = $twig->loadTemplate($templateFile . '.twig');
  46. $content = $template->render($twig_vars);
  47. file_put_contents($destFile, $content);
  48. }
  49. public function getTables()
  50. {
  51. $tablesQuery = $this->_pdo->prepare("SELECT table_name
  52. FROM information_schema.tables
  53. WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema')");
  54. if ($tablesQuery->execute(array())) {
  55. $tables = $tablesQuery->fetchAll();
  56. echo "Found " . count($tables) . " tables\n";
  57. return $tables;
  58. }
  59. else
  60. return $this->printError($tablesQuery, "Failed to get tables");
  61. }
  62. public function getColumns($table_name)
  63. {
  64. $columnsQuery = $this->_pdo->prepare("SELECT column_name as name, data_type as data_type FROM information_schema.columns WHERE table_name = :table_name");
  65. if ($columnsQuery->execute(array(":table_name" => $table_name)))
  66. {
  67. $columns = $columnsQuery->fetchAll();
  68. echo "Found " . count($columns) . " columns in table " . $table_name . "\n";
  69. return $columns;
  70. }
  71. else
  72. return $this->printError($columnsQuery, "Failed to get columns from " . $table_name);
  73. }
  74. function snakeToCamelCase($string, $capitalizeFirstCharacter) {
  75. $str = preg_replace_callback("/_[a-zA-Z]/", function($matches)
  76. {
  77. return strtoupper($matches[0][1]);
  78. }, $string);
  79. if ($capitalizeFirstCharacter)
  80. $str[0] = strtoupper($str[0]);
  81. return $str;
  82. }
  83. public function sqlTypeToPhpType($type)
  84. {
  85. if ($type == "character" || $type == "character varying")
  86. return "string";
  87. return $type;
  88. }
  89. public function sqlTypesToPhpTypes($array)
  90. {
  91. foreach ($array as $key => $value)
  92. {
  93. $array[$key]["data_type"] = array(
  94. "sql" => $array[$key]["data_type"],
  95. "php" => $this->sqlTypeToPhpType($array[$key]["data_type"])
  96. );
  97. }
  98. return $array;
  99. }
  100. public function generateDbo($name, $columns, $file)
  101. {
  102. $vars = array(
  103. "dbo_name" => $name,
  104. "columns" => $columns
  105. );
  106. $this->buildTwig('dbo.php', $file, $vars);
  107. }
  108. public function generateModel($modelName, $dboName, $columns, $file)
  109. {
  110. $vars = array(
  111. "model_name" => $modelName,
  112. "dbo_name" => $dboName,
  113. "columns" => $columns
  114. );
  115. $this->buildTwig('model.php', $file, $vars);
  116. }
  117. public function getStoredProcedures()
  118. {
  119. $spQuery = $this->_pdo->prepare("SELECT r.routine_name AS sp_name, r.data_type AS data_type, proc.proretset AS proretset
  120. FROM information_schema.routines r
  121. LEFT JOIN pg_catalog.pg_proc proc ON proc.proname = r.routine_name
  122. WHERE r.specific_schema='public'");
  123. if ($spQuery->execute())
  124. {
  125. $sp = $spQuery->fetchAll();
  126. echo "Found " . count($sp) . " stored procedures\n";
  127. return $sp;
  128. }
  129. else
  130. return $this->printError($spQuery, "Failed to get stored procedures");
  131. }
  132. public function getStoredProceduresArguments($sp)
  133. {
  134. $sp_name = $sp["sp_name"];
  135. $spQuery = $this->_pdo->prepare("SELECT parameters.parameter_name as name, parameters.data_type, parameters.parameter_mode
  136. FROM information_schema.routines
  137. JOIN information_schema.parameters ON routines.specific_name=parameters.specific_name
  138. WHERE routines.specific_schema='public' AND routines.routine_name = :sp_name
  139. ORDER BY parameters.ordinal_position;");
  140. if ($spQuery->execute(array("sp_name" => $sp_name)))
  141. {
  142. $sp_ = $spQuery->fetchAll();
  143. $sps = array("in" => array(), "out" => array());
  144. foreach ($sp_ as $p)
  145. $sps[strtolower($p["parameter_mode"])][] = $p;
  146. $out_count = count($sps['out']);
  147. if ($out_count == 0)
  148. {
  149. $sps['out'][] = array(
  150. "name" => $sp_name,
  151. "data_type" => $sp["data_type"],
  152. "parameter_mode" => "OUT"
  153. );
  154. $out_count = 1;
  155. }
  156. echo "Found " . count($sps['in']) . " input arguments for stored procedure " . $sp_name . "\n";
  157. echo "Found " . $out_count . " output arguments for stored procedure " . $sp_name . "\n";
  158. return $sps;
  159. }
  160. else
  161. return $this->printError($spQuery, "Failed to get arguments for stored procedure " . $sp_name);
  162. }
  163. public function generateSp($sp, $args, $file)
  164. {
  165. $vars = array(
  166. "sp" => $sp,
  167. "args" => $args
  168. );
  169. $this->buildTwig('sp.php', $file, $vars);
  170. }
  171. public function generateDataAccess($dataAccessName, $modelName, $dboName, $file)
  172. {
  173. if (file_exists($file))
  174. return;
  175. $vars = array(
  176. "data_access_name" => $dataAccessName,
  177. "model_name" => $modelName,
  178. "dbo_name" => $dboName
  179. );
  180. $this->buildTwig('dataaccess.php', $file, $vars);
  181. }
  182. public function generateBusiness($businessName, $dataAccessName, $dboName, $file)
  183. {
  184. if (file_exists($file))
  185. return;
  186. $vars = array(
  187. "business_name" => $businessName,
  188. "data_access_name" => $dataAccessName,
  189. "dbo_name" => $dboName
  190. );
  191. $this->buildTwig('business.php', $file, $vars);
  192. }
  193. public function mkdir($dir, $dir_mode)
  194. {
  195. if (!file_exists($dir))
  196. mkdir($dir, $dir_mode, true);
  197. }
  198. public function run($dir_mode, $dbo_dir, $model_dir, $sp_dir, $manager_dir, $business_dir)
  199. {
  200. $dbo_dir .= "/";
  201. $model_dir .= "/";
  202. $sp_dir .= "/";
  203. $manager_dir .= "/";
  204. $business_dir .= "/";
  205. $this->mkdir($dbo_dir, $dir_mode);
  206. $this->mkdir($model_dir, $dir_mode);
  207. $this->mkdir($sp_dir, $dir_mode);
  208. $this->mkdir($manager_dir, $dir_mode);
  209. $this->mkdir($business_dir, $dir_mode);
  210. $tables = $this->getTables();
  211. if (!is_null($tables)) {
  212. foreach ($tables as $table) {
  213. $table_name = $table["table_name"];
  214. $columns = $this->getColumns($table_name);
  215. if (is_null($columns))
  216. continue;
  217. $columns = $this->sqlTypesToPhpTypes($columns);
  218. $baseName = $this->snakeToCamelCase($table_name, true);
  219. $modelName = $baseName;
  220. $dboName = $baseName . "Dbo";
  221. $dataAccessName = $baseName . "DataAccess";
  222. $businessName = $baseName . "Business";
  223. $this->generateDbo($dboName, $columns, $dbo_dir . $dboName . ".php");
  224. $this->generateModel($modelName, $dboName, $columns, $model_dir . $modelName . ".php");
  225. $this->generateDataAccess($dataAccessName, $modelName, $dboName, $manager_dir . $dataAccessName . ".php");
  226. $this->generateBusiness($businessName, $dataAccessName, $dboName, $business_dir . $businessName . ".php");
  227. }
  228. }
  229. $sps = $this->getStoredProcedures();
  230. if (!is_null($sps)) {
  231. foreach ($sps as $sp)
  232. {
  233. $sp_name = $sp["sp_name"];
  234. $args = $this->getStoredProceduresArguments($sp);
  235. if (is_null($args))
  236. continue;
  237. $args["in"] = $this->sqlTypesToPhpTypes($args["in"]);
  238. $args["out"] = $this->sqlTypesToPhpTypes($args["out"]);
  239. $sp_model_name = $this->snakeToCamelCase($sp_name, true);
  240. $this->generateSp($sp, $args, $sp_dir . $sp_model_name . ".php");
  241. }
  242. }
  243. }
  244. }