ExportCodegen.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. <?php
  2. /**
  3. * Set of functions used to build NHibernate dumps of tables
  4. */
  5. declare(strict_types=1);
  6. namespace PhpMyAdmin\Plugins\Export;
  7. use PhpMyAdmin\Plugins\Export\Helpers\TableProperty;
  8. use PhpMyAdmin\Plugins\ExportPlugin;
  9. use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup;
  10. use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyRootGroup;
  11. use PhpMyAdmin\Properties\Options\Items\HiddenPropertyItem;
  12. use PhpMyAdmin\Properties\Options\Items\SelectPropertyItem;
  13. use PhpMyAdmin\Properties\Plugins\ExportPluginProperties;
  14. use PhpMyAdmin\Util;
  15. use function implode;
  16. use function preg_match;
  17. use function preg_replace;
  18. use function sprintf;
  19. use function ucfirst;
  20. /**
  21. * Handles the export for the CodeGen class
  22. */
  23. class ExportCodegen extends ExportPlugin
  24. {
  25. /**
  26. * CodeGen Formats
  27. *
  28. * @var array
  29. */
  30. private $cgFormats;
  31. private const HANDLER_NHIBERNATE_CS = 0;
  32. private const HANDLER_NHIBERNATE_XML = 1;
  33. public function __construct()
  34. {
  35. parent::__construct();
  36. // initialize the specific export CodeGen variables
  37. $this->initSpecificVariables();
  38. $this->setProperties();
  39. }
  40. /**
  41. * Initialize the local variables that are used for export CodeGen
  42. *
  43. * @return void
  44. */
  45. protected function initSpecificVariables()
  46. {
  47. $this->setCgFormats([
  48. self::HANDLER_NHIBERNATE_CS => 'NHibernate C# DO',
  49. self::HANDLER_NHIBERNATE_XML => 'NHibernate XML',
  50. ]);
  51. }
  52. /**
  53. * Sets the export CodeGen properties
  54. *
  55. * @return void
  56. */
  57. protected function setProperties()
  58. {
  59. $exportPluginProperties = new ExportPluginProperties();
  60. $exportPluginProperties->setText('CodeGen');
  61. $exportPluginProperties->setExtension('cs');
  62. $exportPluginProperties->setMimeType('text/cs');
  63. $exportPluginProperties->setOptionsText(__('Options'));
  64. // create the root group that will be the options field for
  65. // $exportPluginProperties
  66. // this will be shown as "Format specific options"
  67. $exportSpecificOptions = new OptionsPropertyRootGroup(
  68. 'Format Specific Options'
  69. );
  70. // general options main group
  71. $generalOptions = new OptionsPropertyMainGroup('general_opts');
  72. // create primary items and add them to the group
  73. $leaf = new HiddenPropertyItem('structure_or_data');
  74. $generalOptions->addProperty($leaf);
  75. $leaf = new SelectPropertyItem(
  76. 'format',
  77. __('Format:')
  78. );
  79. $leaf->setValues($this->getCgFormats());
  80. $generalOptions->addProperty($leaf);
  81. // add the main group to the root group
  82. $exportSpecificOptions->addProperty($generalOptions);
  83. // set the options for the export plugin property item
  84. $exportPluginProperties->setOptions($exportSpecificOptions);
  85. $this->properties = $exportPluginProperties;
  86. }
  87. /**
  88. * Outputs export header
  89. *
  90. * @return bool Whether it succeeded
  91. */
  92. public function exportHeader()
  93. {
  94. return true;
  95. }
  96. /**
  97. * Outputs export footer
  98. *
  99. * @return bool Whether it succeeded
  100. */
  101. public function exportFooter()
  102. {
  103. return true;
  104. }
  105. /**
  106. * Outputs database header
  107. *
  108. * @param string $db Database name
  109. * @param string $db_alias Aliases of db
  110. *
  111. * @return bool Whether it succeeded
  112. */
  113. public function exportDBHeader($db, $db_alias = '')
  114. {
  115. return true;
  116. }
  117. /**
  118. * Outputs database footer
  119. *
  120. * @param string $db Database name
  121. *
  122. * @return bool Whether it succeeded
  123. */
  124. public function exportDBFooter($db)
  125. {
  126. return true;
  127. }
  128. /**
  129. * Outputs CREATE DATABASE statement
  130. *
  131. * @param string $db Database name
  132. * @param string $export_type 'server', 'database', 'table'
  133. * @param string $db_alias Aliases of db
  134. *
  135. * @return bool Whether it succeeded
  136. */
  137. public function exportDBCreate($db, $export_type, $db_alias = '')
  138. {
  139. return true;
  140. }
  141. /**
  142. * Outputs the content of a table in NHibernate format
  143. *
  144. * @param string $db database name
  145. * @param string $table table name
  146. * @param string $crlf the end of line sequence
  147. * @param string $error_url the url to go back in case of error
  148. * @param string $sql_query SQL query for obtaining data
  149. * @param array $aliases Aliases of db/table/columns
  150. *
  151. * @return bool Whether it succeeded
  152. */
  153. public function exportData(
  154. $db,
  155. $table,
  156. $crlf,
  157. $error_url,
  158. $sql_query,
  159. array $aliases = []
  160. ) {
  161. $format = (int) $GLOBALS['codegen_format'];
  162. if ($format === self::HANDLER_NHIBERNATE_CS) {
  163. return $this->export->outputHandler($this->handleNHibernateCSBody($db, $table, $crlf, $aliases));
  164. }
  165. if ($format === self::HANDLER_NHIBERNATE_XML) {
  166. return $this->export->outputHandler($this->handleNHibernateXMLBody($db, $table, $crlf, $aliases));
  167. }
  168. return $this->export->outputHandler(sprintf('%s is not supported.', $format));
  169. }
  170. /**
  171. * Used to make identifiers (from table or database names)
  172. *
  173. * @param string $str name to be converted
  174. * @param bool $ucfirst whether to make the first character uppercase
  175. *
  176. * @return string identifier
  177. */
  178. public static function cgMakeIdentifier($str, $ucfirst = true)
  179. {
  180. // remove unsafe characters
  181. $str = (string) preg_replace('/[^\p{L}\p{Nl}_]/u', '', $str);
  182. // make sure first character is a letter or _
  183. if (! preg_match('/^\pL/u', $str)) {
  184. $str = '_' . $str;
  185. }
  186. if ($ucfirst) {
  187. $str = ucfirst($str);
  188. }
  189. return $str;
  190. }
  191. /**
  192. * C# Handler
  193. *
  194. * @param string $db database name
  195. * @param string $table table name
  196. * @param string $crlf line separator
  197. * @param array $aliases Aliases of db/table/columns
  198. *
  199. * @return string containing C# code lines, separated by "\n"
  200. */
  201. private function handleNHibernateCSBody($db, $table, $crlf, array $aliases = [])
  202. {
  203. global $dbi;
  204. $db_alias = $db;
  205. $table_alias = $table;
  206. $this->initAlias($aliases, $db_alias, $table_alias);
  207. $lines = [];
  208. $result = $dbi->query(
  209. sprintf(
  210. 'DESC %s.%s',
  211. Util::backquote($db),
  212. Util::backquote($table)
  213. )
  214. );
  215. if ($result) {
  216. /** @var TableProperty[] $tableProperties */
  217. $tableProperties = [];
  218. while ($row = $dbi->fetchRow($result)) {
  219. $col_as = $this->getAlias($aliases, $row[0], 'col', $db, $table);
  220. if (! empty($col_as)) {
  221. $row[0] = $col_as;
  222. }
  223. $tableProperties[] = new TableProperty($row);
  224. }
  225. $dbi->freeResult($result);
  226. $lines[] = 'using System;';
  227. $lines[] = 'using System.Collections;';
  228. $lines[] = 'using System.Collections.Generic;';
  229. $lines[] = 'using System.Text;';
  230. $lines[] = 'namespace ' . self::cgMakeIdentifier($db_alias);
  231. $lines[] = '{';
  232. $lines[] = ' #region '
  233. . self::cgMakeIdentifier($table_alias);
  234. $lines[] = ' public class '
  235. . self::cgMakeIdentifier($table_alias);
  236. $lines[] = ' {';
  237. $lines[] = ' #region Member Variables';
  238. foreach ($tableProperties as $tableProperty) {
  239. $lines[] = $tableProperty->formatCs(
  240. ' protected #dotNetPrimitiveType# _#name#;'
  241. );
  242. }
  243. $lines[] = ' #endregion';
  244. $lines[] = ' #region Constructors';
  245. $lines[] = ' public '
  246. . self::cgMakeIdentifier($table_alias) . '() { }';
  247. $temp = [];
  248. foreach ($tableProperties as $tableProperty) {
  249. if ($tableProperty->isPK()) {
  250. continue;
  251. }
  252. $temp[] = $tableProperty->formatCs(
  253. '#dotNetPrimitiveType# #name#'
  254. );
  255. }
  256. $lines[] = ' public '
  257. . self::cgMakeIdentifier($table_alias)
  258. . '('
  259. . implode(', ', $temp)
  260. . ')';
  261. $lines[] = ' {';
  262. foreach ($tableProperties as $tableProperty) {
  263. if ($tableProperty->isPK()) {
  264. continue;
  265. }
  266. $lines[] = $tableProperty->formatCs(
  267. ' this._#name#=#name#;'
  268. );
  269. }
  270. $lines[] = ' }';
  271. $lines[] = ' #endregion';
  272. $lines[] = ' #region Public Properties';
  273. foreach ($tableProperties as $tableProperty) {
  274. $lines[] = $tableProperty->formatCs(
  275. ' public virtual #dotNetPrimitiveType# #ucfirstName#'
  276. . "\n"
  277. . ' {' . "\n"
  278. . ' get {return _#name#;}' . "\n"
  279. . ' set {_#name#=value;}' . "\n"
  280. . ' }'
  281. );
  282. }
  283. $lines[] = ' #endregion';
  284. $lines[] = ' }';
  285. $lines[] = ' #endregion';
  286. $lines[] = '}';
  287. }
  288. return implode($crlf, $lines);
  289. }
  290. /**
  291. * XML Handler
  292. *
  293. * @param string $db database name
  294. * @param string $table table name
  295. * @param string $crlf line separator
  296. * @param array $aliases Aliases of db/table/columns
  297. *
  298. * @return string containing XML code lines, separated by "\n"
  299. */
  300. private function handleNHibernateXMLBody(
  301. $db,
  302. $table,
  303. $crlf,
  304. array $aliases = []
  305. ) {
  306. global $dbi;
  307. $db_alias = $db;
  308. $table_alias = $table;
  309. $this->initAlias($aliases, $db_alias, $table_alias);
  310. $lines = [];
  311. $lines[] = '<?xml version="1.0" encoding="utf-8" ?' . '>';
  312. $lines[] = '<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" '
  313. . 'namespace="' . self::cgMakeIdentifier($db_alias) . '" '
  314. . 'assembly="' . self::cgMakeIdentifier($db_alias) . '">';
  315. $lines[] = ' <class '
  316. . 'name="' . self::cgMakeIdentifier($table_alias) . '" '
  317. . 'table="' . self::cgMakeIdentifier($table_alias) . '">';
  318. $result = $dbi->query(
  319. sprintf(
  320. 'DESC %s.%s',
  321. Util::backquote($db),
  322. Util::backquote($table)
  323. )
  324. );
  325. if ($result) {
  326. while ($row = $dbi->fetchRow($result)) {
  327. $col_as = $this->getAlias($aliases, $row[0], 'col', $db, $table);
  328. if (! empty($col_as)) {
  329. $row[0] = $col_as;
  330. }
  331. $tableProperty = new TableProperty($row);
  332. if ($tableProperty->isPK()) {
  333. $lines[] = $tableProperty->formatXml(
  334. ' <id name="#ucfirstName#" type="#dotNetObjectType#"'
  335. . ' unsaved-value="0">' . "\n"
  336. . ' <column name="#name#" sql-type="#type#"'
  337. . ' not-null="#notNull#" unique="#unique#"'
  338. . ' index="PRIMARY"/>' . "\n"
  339. . ' <generator class="native" />' . "\n"
  340. . ' </id>'
  341. );
  342. } else {
  343. $lines[] = $tableProperty->formatXml(
  344. ' <property name="#ucfirstName#"'
  345. . ' type="#dotNetObjectType#">' . "\n"
  346. . ' <column name="#name#" sql-type="#type#"'
  347. . ' not-null="#notNull#" #indexName#/>' . "\n"
  348. . ' </property>'
  349. );
  350. }
  351. }
  352. $dbi->freeResult($result);
  353. }
  354. $lines[] = ' </class>';
  355. $lines[] = '</hibernate-mapping>';
  356. return implode($crlf, $lines);
  357. }
  358. /**
  359. * Getter for CodeGen formats
  360. *
  361. * @return array
  362. */
  363. private function getCgFormats()
  364. {
  365. return $this->cgFormats;
  366. }
  367. /**
  368. * Setter for CodeGen formats
  369. *
  370. * @param array $CG_FORMATS contains CodeGen Formats
  371. *
  372. * @return void
  373. */
  374. private function setCgFormats(array $CG_FORMATS)
  375. {
  376. $this->cgFormats = $CG_FORMATS;
  377. }
  378. }