PageRenderTime 26ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 0ms

/src/xPDO/Om/mysql/xPDOGenerator.php

https://github.com/opengeek/xpdo
PHP | 204 lines | 160 code | 8 blank | 36 comment | 13 complexity | 2aea4522610c464736a9a3764fa5e334 MD5 | raw file
  1. <?php
  2. /**
  3. * This file is part of the xPDO package.
  4. *
  5. * Copyright (c) Jason Coward <jason@opengeek.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace xPDO\Om\mysql;
  11. use xPDO\xPDO;
  12. use PDO;
  13. /**
  14. * An extension for generating {@link xPDOObject} class and map files for MySQL.
  15. *
  16. * A MySQL-specific extension to an {@link xPDOManager} instance that can
  17. * generate class stub and meta-data map files from a provided XML schema of a
  18. * database structure.
  19. *
  20. * @package xPDO\Om\mysql
  21. */
  22. class xPDOGenerator extends \xPDO\Om\xPDOGenerator {
  23. public function compile($path = '') {
  24. return false;
  25. }
  26. public function getIndex($index) {
  27. switch ($index) {
  28. case 'PRI':
  29. $index= 'pk';
  30. break;
  31. case 'UNI':
  32. $index= 'unique';
  33. break;
  34. case 'MUL':
  35. $index= 'index';
  36. break;
  37. default:
  38. break;
  39. }
  40. if (!empty ($index)) {
  41. $index= ' index="' . $index . '"';
  42. }
  43. return $index;
  44. }
  45. /**
  46. * Write an xPDO XML Schema from your database.
  47. *
  48. * @param string $schemaFile The name (including path) of the schemaFile you
  49. * want to write.
  50. * @param string $package Name of the package to generate the classes in.
  51. * @param string $baseClass The class which all classes in the package will
  52. * extend; by default this is set to {@link xPDOObject} and any
  53. * auto_increment fields with the column name 'id' will extend {@link
  54. * xPDOSimpleObject} automatically.
  55. * @param string $tablePrefix The table prefix for the current connection,
  56. * which will be removed from all of the generated class and table names.
  57. * Specify a prefix when creating a new {@link xPDO} instance to recreate
  58. * the tables with the same prefix, but still use the generic class names.
  59. * @param boolean $restrictPrefix Only reverse-engineer tables that have the
  60. * specified tablePrefix; if tablePrefix is empty, this is ignored.
  61. * @return boolean True on success, false on failure.
  62. */
  63. public function writeSchema($schemaFile, $package= '', $baseClass= '', $tablePrefix= '', $restrictPrefix= false) {
  64. if (empty ($package))
  65. $package= $this->manager->xpdo->package;
  66. if (empty ($baseClass))
  67. $baseClass= 'xPDO\Om\xPDOObject';
  68. if (empty ($tablePrefix))
  69. $tablePrefix= $this->manager->xpdo->config[xPDO::OPT_TABLE_PREFIX];
  70. $schemaVersion = xPDO::SCHEMA_VERSION;
  71. $xmlContent = array();
  72. $xmlContent[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
  73. $xmlContent[] = "<model package=\"{$package}\" baseClass=\"{$baseClass}\" platform=\"mysql\" defaultEngine=\"MyISAM\" version=\"{$schemaVersion}\">";
  74. //read list of tables
  75. $dbname= $this->manager->xpdo->escape($this->manager->xpdo->config['dbname']);
  76. $tableLike= ($tablePrefix && $restrictPrefix) ? " LIKE '{$tablePrefix}%'" : '';
  77. $tablesStmt= $this->manager->xpdo->prepare("SHOW TABLES FROM {$dbname}{$tableLike}");
  78. $tstart = microtime(true);
  79. $tablesStmt->execute();
  80. $this->manager->xpdo->queryTime += microtime(true) - $tstart;
  81. $this->manager->xpdo->executedQueries++;
  82. $tables= $tablesStmt->fetchAll(PDO::FETCH_NUM);
  83. if ($this->manager->xpdo->getDebug() === true) $this->manager->xpdo->log(xPDO::LOG_LEVEL_DEBUG, print_r($tables, true));
  84. foreach ($tables as $table) {
  85. $xmlObject= array();
  86. $xmlFields= array();
  87. $xmlIndices= array();
  88. if (!$tableName= $this->getTableName($table[0], $tablePrefix, $restrictPrefix)) {
  89. continue;
  90. }
  91. $class= $this->getClassName($tableName);
  92. $extends= $baseClass;
  93. $fieldsStmt= $this->manager->xpdo->query('SHOW COLUMNS FROM ' . $this->manager->xpdo->escape($table[0]));
  94. if ($fieldsStmt) {
  95. $fields= $fieldsStmt->fetchAll(PDO::FETCH_ASSOC);
  96. if ($this->manager->xpdo->getDebug() === true) $this->manager->xpdo->log(xPDO::LOG_LEVEL_DEBUG, print_r($fields, true));
  97. if (!empty($fields)) {
  98. foreach ($fields as $field) {
  99. $Field= '';
  100. $Type= '';
  101. $Null= '';
  102. $Key= '';
  103. $Default= '';
  104. $Extra= '';
  105. extract($field, EXTR_OVERWRITE);
  106. $Type= xPDO :: escSplit(' ', $Type, "'", 2);
  107. $precisionPos= strpos($Type[0], '(');
  108. $dbType= $precisionPos? substr($Type[0], 0, $precisionPos): $Type[0];
  109. $dbType= strtolower($dbType);
  110. $Precision= $precisionPos? substr($Type[0], $precisionPos + 1, strrpos($Type[0], ')') - ($precisionPos + 1)): '';
  111. if (!empty ($Precision)) {
  112. $Precision= ' precision="' . trim($Precision) . '"';
  113. }
  114. $attributes= '';
  115. if (isset ($Type[1]) && !empty ($Type[1])) {
  116. $attributes= ' attributes="' . trim($Type[1]) . '"';
  117. }
  118. $PhpType= $this->manager->xpdo->driver->getPhpType($dbType);
  119. $Null= ' null="' . (($Null === 'NO') ? 'false' : 'true') . '"';
  120. $Key= $this->getIndex($Key);
  121. $Default= $this->getDefault($Default);
  122. if (!empty ($Extra)) {
  123. if ($Extra === 'auto_increment') {
  124. if ($baseClass === 'xPDO\Om\xPDOObject' && $Field === 'id') {
  125. $extends= 'xPDO\Om\xPDOSimpleObject';
  126. continue;
  127. } else {
  128. $Extra= ' generated="native"';
  129. }
  130. } else {
  131. $Extra= ' extra="' . strtolower($Extra) . '"';
  132. }
  133. $Extra= ' ' . $Extra;
  134. }
  135. $xmlFields[] = "\t\t<field key=\"{$Field}\" dbtype=\"{$dbType}\"{$Precision}{$attributes} phptype=\"{$PhpType}\"{$Null}{$Default}{$Key}{$Extra} />";
  136. }
  137. } else {
  138. $this->manager->xpdo->log(xPDO::LOG_LEVEL_ERROR, 'No columns were found in table ' . $table[0]);
  139. }
  140. } else {
  141. $this->manager->xpdo->log(xPDO::LOG_LEVEL_ERROR, 'Error retrieving columns for table ' . $table[0]);
  142. }
  143. $whereClause= ($extends === 'xPDO\Om\xPDOSimpleObject' ? " WHERE `Key_name` != 'PRIMARY'" : '');
  144. $indexesStmt= $this->manager->xpdo->query('SHOW INDEXES FROM ' . $this->manager->xpdo->escape($table[0]) . $whereClause);
  145. if ($indexesStmt) {
  146. $indexes= $indexesStmt->fetchAll(PDO::FETCH_ASSOC);
  147. if ($this->manager->xpdo->getDebug() === true) $this->manager->xpdo->log(xPDO::LOG_LEVEL_DEBUG, "Indices for table {$table[0]}: " . print_r($indexes, true));
  148. if (!empty($indexes)) {
  149. $indices = array();
  150. foreach ($indexes as $index) {
  151. if (!array_key_exists($index['Key_name'], $indices)) $indices[$index['Key_name']] = array();
  152. $indices[$index['Key_name']][$index['Seq_in_index']] = $index;
  153. }
  154. foreach ($indices as $index) {
  155. $xmlIndexCols = array();
  156. if ($this->manager->xpdo->getDebug() === true) $this->manager->xpdo->log(xPDO::LOG_LEVEL_DEBUG, "Details of index: " . print_r($index, true));
  157. foreach ($index as $columnSeq => $column) {
  158. if ($columnSeq == 1) {
  159. $keyName = $column['Key_name'];
  160. $primary = $keyName == 'PRIMARY' ? 'true' : 'false';
  161. $unique = empty($column['Non_unique']) ? 'true' : 'false';
  162. $packed = empty($column['Packed']) ? 'false' : 'true';
  163. $type = $column['Index_type'];
  164. }
  165. $null = $column['Null'] == 'YES' ? 'true' : 'false';
  166. $xmlIndexCols[]= "\t\t\t<column key=\"{$column['Column_name']}\" length=\"{$column['Sub_part']}\" collation=\"{$column['Collation']}\" null=\"{$null}\" />";
  167. }
  168. $xmlIndices[]= "\t\t<index alias=\"{$keyName}\" name=\"{$keyName}\" primary=\"{$primary}\" unique=\"{$unique}\" type=\"{$type}\" >";
  169. $xmlIndices[]= implode("\n", $xmlIndexCols);
  170. $xmlIndices[]= "\t\t</index>";
  171. }
  172. } else {
  173. $this->manager->xpdo->log(xPDO::LOG_LEVEL_WARN, 'No indexes were found in table ' . $table[0]);
  174. }
  175. } else {
  176. $this->manager->xpdo->log(xPDO::LOG_LEVEL_ERROR, 'Error getting indexes for table ' . $table[0]);
  177. }
  178. $xmlObject[] = "\t<object class=\"{$class}\" table=\"{$tableName}\" extends=\"{$extends}\">";
  179. $xmlObject[] = implode("\n", $xmlFields);
  180. if (!empty($xmlIndices)) {
  181. $xmlObject[] = '';
  182. $xmlObject[] = implode("\n", $xmlIndices);
  183. }
  184. $xmlObject[] = "\t</object>";
  185. $xmlContent[] = implode("\n", $xmlObject);
  186. }
  187. $xmlContent[] = "</model>";
  188. if ($this->manager->xpdo->getDebug() === true) {
  189. $this->manager->xpdo->log(xPDO::LOG_LEVEL_DEBUG, implode("\n", $xmlContent));
  190. }
  191. $file= fopen($schemaFile, 'wb');
  192. $written= fwrite($file, implode("\n", $xmlContent));
  193. fclose($file);
  194. return true;
  195. }
  196. }