PageRenderTime 23ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/om/mysql/xpdomanager.class.php

https://github.com/Kleist/xPDO
PHP | 296 lines | 267 code | 2 blank | 27 comment | 0 complexity | 41549778e26609c967c7347f80738284 MD5 | raw file
Possible License(s): GPL-2.0
  1. <?php
  2. /*
  3. * Copyright 2006, 2007, 2008, 2009 by Jason Coward <xpdo@opengeek.com>
  4. *
  5. * This file is part of xPDO.
  6. *
  7. * xPDO is free software; you can redistribute it and/or modify it under the
  8. * terms of the GNU General Public License as published by the Free Software
  9. * Foundation; either version 2 of the License, or (at your option) any later
  10. * version.
  11. *
  12. * xPDO is distributed in the hope that it will be useful, but WITHOUT ANY
  13. * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  14. * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along with
  17. * xPDO; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
  18. * Suite 330, Boston, MA 02111-1307 USA
  19. */
  20. /**
  21. * The MySQL implementation of the xPDOManager class.
  22. *
  23. * @package xpdo
  24. * @subpackage om.mysql
  25. */
  26. /**
  27. * Include the parent {@link xPDOManager} class.
  28. */
  29. require_once (strtr(realpath(dirname(dirname(__FILE__))), '\\', '/') . '/xpdomanager.class.php');
  30. /**
  31. * Provides MySQL data source management for an xPDO instance.
  32. *
  33. * These are utility functions that only need to be loaded under special
  34. * circumstances, such as creating tables, adding indexes, altering table
  35. * structures, etc. xPDOManager class implementations are specific to a
  36. * database driver and this instance is implemented for MySQL.
  37. *
  38. * @package xpdo
  39. * @subpackage om.mysql
  40. */
  41. class xPDOManager_mysql extends xPDOManager {
  42. /**
  43. * Get a xPDOManager instance.
  44. *
  45. * @param object $xpdo A reference to a specific modDataSource instance.
  46. */
  47. function __construct(& $xpdo) {
  48. parent :: __construct($xpdo);
  49. $this->dbtypes['integer']= array('INT','INTEGER','TINYINT','BOOLEAN','SMALLINT','MEDIUMINT','BIGINT');
  50. $this->dbtypes['boolean']= array('BOOLEAN','BOOL');
  51. $this->dbtypes['float']= array('DECIMAL','DEC','NUMERIC','FLOAT','DOUBLE','DOUBLE PRECISION','REAL');
  52. $this->dbtypes['string']= array('CHAR','VARCHAR','BINARY','VARBINARY','TINYTEXT','TEXT','MEDIUMTEXT','LONGTEXT','ENUM','SET','TIME','YEAR');
  53. $this->dbtypes['timestamp']= array('TIMESTAMP');
  54. $this->dbtypes['datetime']= array('DATETIME');
  55. $this->dbtypes['date']= array('DATE');
  56. $this->dbtypes['binary']= array('TINYBLOB','BLOB','MEDIUMBLOB','LONGBLOB');
  57. $this->dbtypes['bit']= array('BIT');
  58. }
  59. /**
  60. * Creates the physical data container represented by a data source.
  61. *
  62. * @param array $dsnArray An array of xPDO configuration properties.
  63. * @param string $username Database username with privileges to create tables.
  64. * @param string $password Database user password.
  65. * @param array $containerOptions An array of options for controlling the creation of the container.
  66. * @return boolean True only if the database is created successfully.
  67. */
  68. public function createSourceContainer($dsnArray, $username= '', $password= '', $containerOptions= array ()) {
  69. $created= false;
  70. if (is_array($dsnArray)) {
  71. $sql= 'CREATE DATABASE `' . $dsnArray['dbname'] . '`';
  72. if (isset ($containerOptions['collation']) && isset ($containerOptions['charset'])) {
  73. $sql.= ' CHARACTER SET ' . $containerOptions['charset'];
  74. $sql.= ' COLLATE ' . $containerOptions['collation'];
  75. }
  76. if ($conn= mysql_connect($dsnArray['host'], $username, $password, true)) {
  77. if (!$rt= @ mysql_select_db($dsnArray['dbname'], $conn)) {
  78. @ mysql_query($sql, $conn);
  79. $errorNo= @ mysql_errno($conn);
  80. $created= $errorNo ? false : true;
  81. }
  82. }
  83. }
  84. return $created;
  85. }
  86. /**
  87. * Drops a physical data container, if it exists.
  88. *
  89. * @param string $dsn Represents the database connection string.
  90. * @param string $username Database username with privileges to drop tables.
  91. * @param string $password Database user password.
  92. * @return int Returns 1 on successful drop, 0 on failure, and -1 if the db
  93. * does not exist.
  94. */
  95. public function removeSourceContainer() {
  96. $removed= 0;
  97. if ($dsnArray= & $this->xpdo->config) {
  98. $sql= 'DROP DATABASE `' . $dsnArray['dbname'] . '`';
  99. if ($conn= @ mysql_connect($dsnArray['host'], $dsnArray['username'], $dsnArray['password'], true)) {
  100. if (@ mysql_select_db($dsnArray['dbname'], $conn)) {
  101. if (@ mysql_query($sql, $conn)) {
  102. $removed= 1;
  103. }
  104. } else {
  105. $removed= -1;
  106. }
  107. }
  108. }
  109. return $removed;
  110. }
  111. /**
  112. * Drops a table, if it exists.
  113. *
  114. * @param string $className The object table to drop.
  115. * @return int Returns 1 on successful drop, 0 on failure, and -1 if the table
  116. * does not exist.
  117. */
  118. public function removeObjectContainer($className) {
  119. $removed= 0;
  120. if ($instance= $this->xpdo->newObject($className)) {
  121. $sql= 'DROP TABLE ' . $this->xpdo->getTableName($className);
  122. $removed= $this->xpdo->exec($sql);
  123. if (!$removed && $this->xpdo->errorCode() !== '' && $this->xpdo->errorCode() !== PDO::ERR_NONE) {
  124. $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, 'Could not drop table ' . $className . "\nSQL: {$sql}\nERROR: " . print_r($this->xpdo->pdo->errorInfo(), true));
  125. } else {
  126. $removed= true;
  127. $this->xpdo->log(xPDO::LOG_LEVEL_INFO, 'Dropped table' . $className . "\nSQL: {$sql}\n");
  128. }
  129. }
  130. return $removed;
  131. }
  132. /**
  133. * Creates the container for a persistent data object. In this
  134. * implementation, a source container is a synonym for a MySQL database
  135. * table.
  136. *
  137. * @todo Add more robust index support.
  138. * @todo Add constraint support.
  139. *
  140. * @param string $className The class of object to create a source container
  141. * for.
  142. */
  143. public function createObjectContainer($className) {
  144. $created= false;
  145. if ($instance= $this->xpdo->newObject($className)) {
  146. $tableName= $this->xpdo->getTableName($className);
  147. $existsStmt = $this->xpdo->prepare("SELECT COUNT(*) FROM {$tableName}");
  148. $exists = $existsStmt->execute();
  149. if ($exists && $existsStmt->fetchAll()) {
  150. return true;
  151. }
  152. $tableMeta= $this->xpdo->getTableMeta($className);
  153. $tableType= isset($tableMeta['engine']) ? $tableMeta['engine'] : 'MyISAM';
  154. $numerics= array_merge($this->dbtypes['integer'], $this->dbtypes['boolean'], $this->dbtypes['float']);
  155. $datetimeStrings= array_merge($this->dbtypes['timestamp'], $this->dbtypes['datetime']);
  156. $dateStrings= $this->dbtypes['date'];
  157. $pk= $this->xpdo->getPK($className);
  158. $pktype= $this->xpdo->getPKType($className);
  159. $fulltextIndexes= array ();
  160. $uniqueIndexes= array ();
  161. $indexes= array ();
  162. $lobs= array ('TEXT', 'BLOB');
  163. $lobsPattern= '/(' . implode('|', $lobs) . ')/';
  164. $sql= 'CREATE TABLE ' . $tableName . ' (';
  165. $fieldMeta = $this->xpdo->getFieldMeta($className);
  166. while (list($key, $meta)= each($fieldMeta)) {
  167. $dbtype= strtoupper($meta['dbtype']);
  168. $precision= isset ($meta['precision']) ? '(' . $meta['precision'] . ')' : '';
  169. $notNull= !isset ($meta['null'])
  170. ? false
  171. : ($meta['null'] === 'false' || empty($meta['null']));
  172. $null= $notNull ? ' NOT NULL' : ' NULL';
  173. $extra= (isset ($meta['index']) && $meta['index'] == 'pk' && !is_array($pk) && $pktype == 'integer' && isset ($meta['generated']) && $meta['generated'] == 'native') ? ' AUTO_INCREMENT' : '';
  174. if (empty ($extra) && isset ($meta['extra'])) {
  175. $extra= ' ' . $meta['extra'];
  176. }
  177. $default= '';
  178. if (isset ($meta['default']) && !preg_match($lobsPattern, $dbtype)) {
  179. $defaultVal= $meta['default'];
  180. if (($defaultVal === null || strtoupper($defaultVal) === 'NULL') || (in_array($dbtype, $datetimeStrings) && $defaultVal === 'CURRENT_TIMESTAMP')) {
  181. $default= ' DEFAULT ' . $defaultVal;
  182. } else {
  183. $default= ' DEFAULT \'' . $defaultVal . '\'';
  184. }
  185. }
  186. $attributes= (isset ($meta['attributes'])) ? ' ' . $meta['attributes'] : '';
  187. if (strpos(strtolower($attributes), 'unsigned') !== false) {
  188. $sql .= '`' . $key . '` ' . $dbtype . $precision . $attributes . $null . $default . $extra . ',';
  189. } else {
  190. $sql .= '`' . $key . '` ' . $dbtype . $precision . $null . $default . $attributes . $extra . ',';
  191. }
  192. if (isset ($meta['index']) && $meta['index'] !== 'pk') {
  193. if ($meta['index'] === 'fulltext') {
  194. if (isset ($meta['indexgrp'])) {
  195. $fulltextIndexes[$meta['indexgrp']][]= $key;
  196. } else {
  197. $fulltextIndexes[$key]= $key;
  198. }
  199. }
  200. elseif ($meta['index'] === 'unique') {
  201. if (isset ($meta['indexgrp'])) {
  202. $uniqueIndexes[$meta['indexgrp']][]= $key;
  203. } else {
  204. $uniqueIndexes[$key]= $key;
  205. }
  206. }
  207. elseif ($meta['index'] === 'fk') {
  208. if (isset ($meta['indexgrp'])) {
  209. $indexes[$meta['indexgrp']][]= $key;
  210. } else {
  211. $indexes[$key]= $key;
  212. }
  213. } else {
  214. if (isset ($meta['indexgrp'])) {
  215. $indexes[$meta['indexgrp']][]= $key;
  216. } else {
  217. $indexes[$key]= $key;
  218. }
  219. }
  220. }
  221. }
  222. $sql= substr($sql, 0, strlen($sql) - 1);
  223. if (is_array($pk)) {
  224. $pkarray= array ();
  225. foreach ($pk as $k) {
  226. $pkarray[]= '`' . $k . '`';
  227. }
  228. $pk= implode(',', $pkarray);
  229. }
  230. elseif ($pk) {
  231. $pk= '`' . $pk . '`';
  232. }
  233. if ($pk)
  234. $sql .= ', PRIMARY KEY (' . $pk . ')';
  235. if (!empty ($indexes)) {
  236. foreach ($indexes as $indexkey => $index) {
  237. if (is_array($index)) {
  238. $indexset= array ();
  239. foreach ($index as $indexmember) {
  240. $indexset[]= "`{$indexmember}`";
  241. }
  242. $indexset= implode(',', $indexset);
  243. } else {
  244. $indexset= "`{$indexkey}`";
  245. }
  246. $sql .= ", INDEX `{$indexkey}` ({$indexset})";
  247. }
  248. }
  249. if (!empty ($uniqueIndexes)) {
  250. foreach ($uniqueIndexes as $indexkey => $index) {
  251. if (is_array($index)) {
  252. $indexset= array ();
  253. foreach ($index as $indexmember) {
  254. $indexset[]= "`{$indexmember}`";
  255. }
  256. $indexset= implode(',', $indexset);
  257. } else {
  258. $indexset= $indexkey;
  259. }
  260. $sql .= ", UNIQUE INDEX `{$indexkey}` ({$indexset})";
  261. }
  262. }
  263. if (!empty ($fulltextIndexes)) {
  264. foreach ($fulltextIndexes as $indexkey => $index) {
  265. if (is_array($index)) {
  266. $indexset= array ();
  267. foreach ($index as $indexmember) {
  268. $indexset[]= "`{$indexmember}`";
  269. }
  270. $indexset= implode(',', $indexset);
  271. } else {
  272. $indexset= $indexkey;
  273. }
  274. $sql .= ", FULLTEXT INDEX `{$indexkey}` ({$indexset})";
  275. }
  276. }
  277. $sql .= ") TYPE={$tableType}";
  278. $created= $this->xpdo->exec($sql);
  279. if (!$created && $this->xpdo->errorCode() !== '' && $this->xpdo->errorCode() !== PDO::ERR_NONE) {
  280. $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, 'Could not create table ' . $tableName . "\nSQL: {$sql}\nERROR: " . print_r($this->xpdo->errorInfo(), true));
  281. } else {
  282. $created= true;
  283. $this->xpdo->log(xPDO::LOG_LEVEL_INFO, 'Created table' . $tableName . "\nSQL: {$sql}\n");
  284. }
  285. }
  286. return $created;
  287. }
  288. }