xpdomanager.class.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. <?php
  2. /*
  3. * Copyright 2010-2015 by MODX, LLC.
  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 (dirname(__DIR__) . '/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. public function createSourceContainer($dsnArray = null, $username= null, $password= null, $containerOptions= array ()) {
  43. $created= false;
  44. if ($this->xpdo->getConnection(array(xPDO::OPT_CONN_MUTABLE => true))) {
  45. if ($dsnArray === null) $dsnArray = xPDO::parseDSN($this->xpdo->getOption('dsn'));
  46. if ($username === null) $username = $this->xpdo->getOption('username', null, '');
  47. if ($password === null) $password = $this->xpdo->getOption('password', null, '');
  48. if (is_array($dsnArray) && is_string($username) && is_string($password)) {
  49. $sql= 'CREATE DATABASE `' . $dsnArray['dbname'] . '`';
  50. if (isset ($containerOptions['collation']) && isset ($containerOptions['charset'])) {
  51. $sql.= ' CHARACTER SET ' . $containerOptions['charset'];
  52. $sql.= ' COLLATE ' . $containerOptions['collation'];
  53. }
  54. try {
  55. $pdo = new PDO("mysql:host={$dsnArray['host']}", $username, $password, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
  56. $result = $pdo->exec($sql);
  57. if ($result !== false) {
  58. $created = true;
  59. } else {
  60. $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Could not create source container:\n{$sql}\nresult = " . var_export($result, true));
  61. }
  62. } catch (PDOException $pe) {
  63. $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Could not connect to database server: " . $pe->getMessage());
  64. } catch (Exception $e) {
  65. $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Could not create source container: " . $e->getMessage());
  66. }
  67. }
  68. } else {
  69. $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Could not get writable connection", '', __METHOD__, __FILE__, __LINE__);
  70. }
  71. return $created;
  72. }
  73. public function removeSourceContainer($dsnArray = null, $username= null, $password= null) {
  74. $removed= false;
  75. if ($this->xpdo->getConnection(array(xPDO::OPT_CONN_MUTABLE => true))) {
  76. if ($dsnArray === null) $dsnArray = xPDO::parseDSN($this->xpdo->getOption('dsn'));
  77. if ($username === null) $username = $this->xpdo->getOption('username', null, '');
  78. if ($password === null) $password = $this->xpdo->getOption('password', null, '');
  79. if (is_array($dsnArray) && is_string($username) && is_string($password)) {
  80. $sql= 'DROP DATABASE IF EXISTS ' . $this->xpdo->escape($dsnArray['dbname']);
  81. try {
  82. $pdo = new PDO("mysql:host={$dsnArray['host']}", $username, $password, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
  83. $result = $pdo->exec($sql);
  84. if ($result !== false) {
  85. $removed = true;
  86. } else {
  87. $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Could not remove source container:\n{$sql}\nresult = " . var_export($result, true));
  88. }
  89. } catch (PDOException $pe) {
  90. $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Could not connect to database server: " . $pe->getMessage());
  91. } catch (Exception $e) {
  92. $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Could not remove source container: " . $e->getMessage());
  93. }
  94. }
  95. } else {
  96. $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Could not get writable connection", '', __METHOD__, __FILE__, __LINE__);
  97. }
  98. return $removed;
  99. }
  100. public function removeObjectContainer($className) {
  101. $removed= false;
  102. if ($this->xpdo->getConnection(array(xPDO::OPT_CONN_MUTABLE => true))) {
  103. $instance= $this->xpdo->newObject($className);
  104. if ($instance) {
  105. $sql= 'DROP TABLE ' . $this->xpdo->getTableName($className);
  106. $removed= $this->xpdo->exec($sql);
  107. if ($removed === false && $this->xpdo->errorCode() !== '' && $this->xpdo->errorCode() !== PDO::ERR_NONE) {
  108. $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, 'Could not drop table ' . $className . "\nSQL: {$sql}\nERROR: " . print_r($this->xpdo->pdo->errorInfo(), true));
  109. } else {
  110. $removed= true;
  111. $this->xpdo->log(xPDO::LOG_LEVEL_INFO, 'Dropped table' . $className . "\nSQL: {$sql}\n");
  112. }
  113. }
  114. } else {
  115. $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Could not get writable connection", '', __METHOD__, __FILE__, __LINE__);
  116. }
  117. return $removed;
  118. }
  119. public function createObjectContainer($className) {
  120. $created= false;
  121. if ($this->xpdo->getConnection(array(xPDO::OPT_CONN_MUTABLE => true))) {
  122. $instance= $this->xpdo->newObject($className);
  123. if ($instance) {
  124. $tableName= $this->xpdo->getTableName($className);
  125. $existsStmt = $this->xpdo->query("SELECT COUNT(*) FROM {$tableName}");
  126. if ($existsStmt && $existsStmt->fetchAll()) {
  127. return true;
  128. }
  129. $modelVersion= $this->xpdo->getModelVersion($className);
  130. $tableMeta= $this->xpdo->getTableMeta($className);
  131. $tableType= isset($tableMeta['engine']) ? $tableMeta['engine'] : 'InnoDB';
  132. $tableType= $this->xpdo->getOption(xPDO::OPT_OVERRIDE_TABLE_TYPE, null, $tableType);
  133. $legacyIndexes= version_compare($modelVersion, '1.1', '<');
  134. $fulltextIndexes= array ();
  135. $uniqueIndexes= array ();
  136. $stdIndexes= array ();
  137. $sql= 'CREATE TABLE ' . $tableName . ' (';
  138. $fieldMeta = $this->xpdo->getFieldMeta($className, true);
  139. $columns = array();
  140. foreach ($fieldMeta as $key => $meta) {
  141. $columns[] = $this->getColumnDef($className, $key, $meta);
  142. /* Legacy index support for pre-2.0.0-rc3 models */
  143. if ($legacyIndexes && isset ($meta['index']) && $meta['index'] !== 'pk') {
  144. if ($meta['index'] === 'fulltext') {
  145. if (isset ($meta['indexgrp'])) {
  146. $fulltextIndexes[$meta['indexgrp']][]= $key;
  147. } else {
  148. $fulltextIndexes[$key]= $key;
  149. }
  150. }
  151. elseif ($meta['index'] === 'unique') {
  152. if (isset ($meta['indexgrp'])) {
  153. $uniqueIndexes[$meta['indexgrp']][]= $key;
  154. } else {
  155. $uniqueIndexes[$key]= $key;
  156. }
  157. }
  158. elseif ($meta['index'] === 'fk') {
  159. if (isset ($meta['indexgrp'])) {
  160. $stdIndexes[$meta['indexgrp']][]= $key;
  161. } else {
  162. $stdIndexes[$key]= $key;
  163. }
  164. } else {
  165. if (isset ($meta['indexgrp'])) {
  166. $stdIndexes[$meta['indexgrp']][]= $key;
  167. } else {
  168. $stdIndexes[$key]= $key;
  169. }
  170. }
  171. }
  172. }
  173. $sql .= implode(', ', $columns);
  174. if (!$legacyIndexes) {
  175. $indexes = $this->xpdo->getIndexMeta($className);
  176. $tableConstraints = array();
  177. if (!empty ($indexes)) {
  178. foreach ($indexes as $indexkey => $indexdef) {
  179. $tableConstraints[] = $this->getIndexDef($className, $indexkey, $indexdef);
  180. }
  181. }
  182. } else {
  183. /* Legacy index support for schema model versions 1.0 */
  184. $pk= $this->xpdo->getPK($className);
  185. if (is_array($pk)) {
  186. $pkarray= array ();
  187. foreach ($pk as $k) {
  188. $pkarray[]= $this->xpdo->escape($k);
  189. }
  190. $pk= implode(',', $pkarray);
  191. }
  192. elseif ($pk) {
  193. $pk= $this->xpdo->escape($pk);
  194. }
  195. if ($pk) {
  196. $tableConstraints[]= "PRIMARY KEY ({$pk})";
  197. }
  198. if (!empty ($stdIndexes)) {
  199. foreach ($stdIndexes as $indexkey => $index) {
  200. if (is_array($index)) {
  201. $indexset= array ();
  202. foreach ($index as $indexmember) {
  203. $indexset[]= $this->xpdo->escape($indexmember);
  204. }
  205. $indexset= implode(',', $indexset);
  206. } else {
  207. $indexset= $this->xpdo->escape($indexkey);
  208. }
  209. $tableConstraints[]= "INDEX {$this->xpdo->escape($indexkey)} ({$indexset})";
  210. }
  211. }
  212. if (!empty ($uniqueIndexes)) {
  213. foreach ($uniqueIndexes as $indexkey => $index) {
  214. if (is_array($index)) {
  215. $indexset= array ();
  216. foreach ($index as $indexmember) {
  217. $indexset[]= $this->xpdo->escape($indexmember);
  218. }
  219. $indexset= implode(',', $indexset);
  220. } else {
  221. $indexset= $this->xpdo->escape($indexkey);
  222. }
  223. $tableConstraints[]= "UNIQUE INDEX {$this->xpdo->escape($indexkey)} ({$indexset})";
  224. }
  225. }
  226. if (!empty ($fulltextIndexes)) {
  227. foreach ($fulltextIndexes as $indexkey => $index) {
  228. if (is_array($index)) {
  229. $indexset= array ();
  230. foreach ($index as $indexmember) {
  231. $indexset[]= $this->xpdo->escape($indexmember);
  232. }
  233. $indexset= implode(',', $indexset);
  234. } else {
  235. $indexset= $this->xpdo->escape($indexkey);
  236. }
  237. $tableConstraints[]= "FULLTEXT INDEX {$this->xpdo->escape($indexkey)} ({$indexset})";
  238. }
  239. }
  240. }
  241. if (!empty($tableConstraints)) {
  242. $sql .= ', ' . implode(', ', $tableConstraints);
  243. }
  244. $sql .= ")";
  245. if (!empty($tableType)) {
  246. $sql .= " ENGINE={$tableType}";
  247. }
  248. $created= $this->xpdo->exec($sql);
  249. if ($created === false && $this->xpdo->errorCode() !== '' && $this->xpdo->errorCode() !== PDO::ERR_NONE) {
  250. $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, 'Could not create table ' . $tableName . "\nSQL: {$sql}\nERROR: " . print_r($this->xpdo->errorInfo(), true));
  251. } else {
  252. $created= true;
  253. $this->xpdo->log(xPDO::LOG_LEVEL_INFO, 'Created table ' . $tableName . "\nSQL: {$sql}\n");
  254. }
  255. }
  256. } else {
  257. $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Could not get writable connection", '', __METHOD__, __FILE__, __LINE__);
  258. }
  259. return $created;
  260. }
  261. public function alterObjectContainer($className, array $options = array()) {
  262. if ($this->xpdo->getConnection(array(xPDO::OPT_CONN_MUTABLE => true))) {
  263. // TODO: Implement alterObjectContainer() method.
  264. } else {
  265. $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Could not get writable connection", '', __METHOD__, __FILE__, __LINE__);
  266. }
  267. }
  268. public function addConstraint($class, $name, array $options = array()) {
  269. if ($this->xpdo->getConnection(array(xPDO::OPT_CONN_MUTABLE => true))) {
  270. // TODO: Implement addConstraint() method.
  271. } else {
  272. $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Could not get writable connection", '', __METHOD__, __FILE__, __LINE__);
  273. }
  274. }
  275. public function addField($class, $name, array $options = array()) {
  276. $result = false;
  277. if ($this->xpdo->getConnection(array(xPDO::OPT_CONN_MUTABLE => true))) {
  278. $className = $this->xpdo->loadClass($class);
  279. if ($className) {
  280. $meta = $this->xpdo->getFieldMeta($className, true);
  281. if (is_array($meta) && array_key_exists($name, $meta)) {
  282. $colDef = $this->getColumnDef($className, $name, $meta[$name]);
  283. if (!empty($colDef)) {
  284. $sql = "ALTER TABLE {$this->xpdo->getTableName($className)} ADD COLUMN {$colDef}";
  285. if (isset($options['first']) && !empty($options['first'])) {
  286. $sql .= " FIRST";
  287. } elseif (isset($options['after']) && array_key_exists($options['after'], $meta)) {
  288. $sql .= " AFTER {$this->xpdo->escape($options['after'])}";
  289. }
  290. if ($this->xpdo->exec($sql) !== false) {
  291. $result = true;
  292. } else {
  293. $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Error adding field {$class}->{$name}: " . print_r($this->xpdo->errorInfo(), true), '', __METHOD__, __FILE__, __LINE__);
  294. }
  295. } else {
  296. $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Error adding field {$class}->{$name}: Could not get column definition");
  297. }
  298. } else {
  299. $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Error adding field {$class}->{$name}: No metadata defined");
  300. }
  301. }
  302. } else {
  303. $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Could not get writable connection", '', __METHOD__, __FILE__, __LINE__);
  304. }
  305. return $result;
  306. }
  307. public function addIndex($class, $name, array $options = array()) {
  308. $result = false;
  309. if ($this->xpdo->getConnection(array(xPDO::OPT_CONN_MUTABLE => true))) {
  310. $className = $this->xpdo->loadClass($class);
  311. if ($className) {
  312. $meta = $this->xpdo->getIndexMeta($className);
  313. if (is_array($meta) && array_key_exists($name, $meta)) {
  314. $idxDef = $this->getIndexDef($className, $name, $meta[$name]);
  315. if (!empty($idxDef)) {
  316. $sql = "ALTER TABLE {$this->xpdo->getTableName($className)} ADD {$idxDef}";
  317. if ($this->xpdo->exec($sql) !== false) {
  318. $result = true;
  319. } else {
  320. $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Error adding index {$name} to {$class}: " . print_r($this->xpdo->errorInfo(), true), '', __METHOD__, __FILE__, __LINE__);
  321. }
  322. } else {
  323. $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Error adding index {$name} to {$class}: Could not get index definition");
  324. }
  325. } else {
  326. $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Error adding index {$name} to {$class}: No metadata defined");
  327. }
  328. }
  329. } else {
  330. $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Could not get writable connection", '', __METHOD__, __FILE__, __LINE__);
  331. }
  332. return $result;
  333. }
  334. public function alterField($class, $name, array $options = array()) {
  335. $result = false;
  336. if ($this->xpdo->getConnection(array(xPDO::OPT_CONN_MUTABLE => true))) {
  337. $className = $this->xpdo->loadClass($class);
  338. if ($className) {
  339. $meta = $this->xpdo->getFieldMeta($className, true);
  340. if (is_array($meta) && array_key_exists($name, $meta)) {
  341. $colDef = $this->getColumnDef($className, $name, $meta[$name]);
  342. if (!empty($colDef)) {
  343. $sql = "ALTER TABLE {$this->xpdo->getTableName($className)} MODIFY COLUMN {$colDef}";
  344. if (isset($options['first']) && !empty($options['first'])) {
  345. $sql .= " FIRST";
  346. } elseif (isset($options['after']) && array_key_exists($options['after'], $meta)) {
  347. $sql .= " AFTER {$this->xpdo->escape($options['after'])}";
  348. }
  349. if ($this->xpdo->exec($sql) !== false) {
  350. $result = true;
  351. } else {
  352. $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Error altering field {$class}->{$name}: " . print_r($this->xpdo->errorInfo(), true), '', __METHOD__, __FILE__, __LINE__);
  353. }
  354. } else {
  355. $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Error altering field {$class}->{$name}: Could not get column definition");
  356. }
  357. } else {
  358. $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Error altering field {$class}->{$name}: No metadata defined");
  359. }
  360. }
  361. } else {
  362. $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Could not get writable connection", '', __METHOD__, __FILE__, __LINE__);
  363. }
  364. return $result;
  365. }
  366. public function removeConstraint($class, $name, array $options = array()) {
  367. if ($this->xpdo->getConnection(array(xPDO::OPT_CONN_MUTABLE => true))) {
  368. // TODO: Implement removeConstraint() method.
  369. } else {
  370. $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Could not get writable connection", '', __METHOD__, __FILE__, __LINE__);
  371. }
  372. }
  373. public function removeField($class, $name, array $options = array()) {
  374. $result = false;
  375. if ($this->xpdo->getConnection(array(xPDO::OPT_CONN_MUTABLE => true))) {
  376. $className = $this->xpdo->loadClass($class);
  377. if ($className) {
  378. $sql = "ALTER TABLE {$this->xpdo->getTableName($className)} DROP COLUMN {$this->xpdo->escape($name)}";
  379. if ($this->xpdo->exec($sql) !== false) {
  380. $result = true;
  381. } else {
  382. $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Error removing field {$class}->{$name}: " . print_r($this->xpdo->errorInfo(), true), '', __METHOD__, __FILE__, __LINE__);
  383. }
  384. }
  385. } else {
  386. $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Could not get writable connection", '', __METHOD__, __FILE__, __LINE__);
  387. }
  388. return $result;
  389. }
  390. public function removeIndex($class, $name, array $options = array()) {
  391. $result = false;
  392. if ($this->xpdo->getConnection(array(xPDO::OPT_CONN_MUTABLE => true))) {
  393. $className = $this->xpdo->loadClass($class);
  394. if ($className) {
  395. $sql = "ALTER TABLE {$this->xpdo->getTableName($className)} DROP INDEX {$this->xpdo->escape($name)}";
  396. if ($this->xpdo->exec($sql) !== false) {
  397. $result = true;
  398. } else {
  399. $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Error removing index {$name} from {$class}: " . print_r($this->xpdo->errorInfo(), true), '', __METHOD__, __FILE__, __LINE__);
  400. }
  401. }
  402. } else {
  403. $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Could not get writable connection", '', __METHOD__, __FILE__, __LINE__);
  404. }
  405. return $result;
  406. }
  407. protected function getColumnDef($class, $name, $meta, array $options = array()) {
  408. $pk= $this->xpdo->getPK($class);
  409. $pktype= $this->xpdo->getPKType($class);
  410. $dbtype= strtoupper($meta['dbtype']);
  411. $lobs= array ('TEXT', 'BLOB');
  412. $lobsPattern= '/(' . implode('|', $lobs) . ')/';
  413. $datetimeStrings= array('timestamp', 'datetime');
  414. $precision= isset ($meta['precision']) ? '(' . $meta['precision'] . ')' : '';
  415. $notNull= !isset ($meta['null']) ? false : ($meta['null'] === 'false' || empty($meta['null']));
  416. $null= $notNull ? ' NOT NULL' : ' NULL';
  417. $extra= '';
  418. if (isset($meta['index']) && $meta['index'] == 'pk' && !is_array($pk) && $pktype == 'integer' && isset ($meta['generated']) && $meta['generated'] == 'native') {
  419. $extra= ' AUTO_INCREMENT';
  420. }
  421. if (empty ($extra) && isset ($meta['extra'])) {
  422. $extra= ' ' . $meta['extra'];
  423. }
  424. $default= '';
  425. if (isset ($meta['default']) && !preg_match($lobsPattern, $dbtype)) {
  426. $defaultVal= $meta['default'];
  427. if (($defaultVal === null || strtoupper($defaultVal) === 'NULL') || (in_array($this->xpdo->driver->getPhpType($dbtype), $datetimeStrings) && $defaultVal === 'CURRENT_TIMESTAMP')) {
  428. $default= ' DEFAULT ' . $defaultVal;
  429. } else {
  430. $default= ' DEFAULT \'' . $defaultVal . '\'';
  431. }
  432. }
  433. $attributes= (isset ($meta['attributes'])) ? ' ' . $meta['attributes'] : '';
  434. if (strpos(strtolower($attributes), 'unsigned') !== false) {
  435. $result = $this->xpdo->escape($name) . ' ' . $dbtype . $precision . $attributes . $null . $default . $extra;
  436. } else {
  437. $result = $this->xpdo->escape($name) . ' ' . $dbtype . $precision . $null . $default . $attributes . $extra;
  438. }
  439. return $result;
  440. }
  441. protected function getIndexDef($class, $name, $meta, array $options = array()) {
  442. $result = '';
  443. if (isset($meta['type']) && $meta['type'] == 'FULLTEXT') {
  444. $indexType = 'FULLTEXT';
  445. } else if ( ! empty($meta['primary'])) {
  446. $indexType = 'PRIMARY KEY';
  447. } else if ( ! empty($meta['unique'])) {
  448. $indexType = 'UNIQUE KEY';
  449. } else {
  450. $indexType = 'INDEX';
  451. }
  452. $index = $meta['columns'];
  453. if (is_array($index)) {
  454. $indexset= array ();
  455. foreach ($index as $indexmember => $indexmemberdetails) {
  456. $indexMemberDetails = $this->xpdo->escape($indexmember);
  457. if (isset($indexmemberdetails['length']) && !empty($indexmemberdetails['length'])) {
  458. $indexMemberDetails .= " ({$indexmemberdetails['length']})";
  459. }
  460. $indexset[]= $indexMemberDetails;
  461. }
  462. $indexset= implode(',', $indexset);
  463. if (!empty($indexset)) {
  464. switch ($indexType) {
  465. case 'PRIMARY KEY':
  466. $result= "{$indexType} ({$indexset})";
  467. break;
  468. default:
  469. $result= "{$indexType} {$this->xpdo->escape($name)} ({$indexset})";
  470. break;
  471. }
  472. }
  473. }
  474. return $result;
  475. }
  476. }