database.lib.php 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819
  1. <?php
  2. /* For licensing terms, see /license.txt */
  3. use Doctrine\Common\Annotations\AnnotationRegistry;
  4. use Doctrine\DBAL\Connection;
  5. use Doctrine\DBAL\Driver\Statement;
  6. use Doctrine\DBAL\Types\Type;
  7. use Doctrine\ORM\EntityManager;
  8. use Symfony\Component\Debug\ExceptionHandler;
  9. /**
  10. * Class Database.
  11. */
  12. class Database
  13. {
  14. public static $utcDateTimeClass;
  15. /**
  16. * @var EntityManager
  17. */
  18. private static $em;
  19. private static $connection;
  20. /**
  21. * @param EntityManager $em
  22. */
  23. public function setManager($em)
  24. {
  25. self::$em = $em;
  26. }
  27. /**
  28. * @param Connection $connection
  29. */
  30. public function setConnection(Connection $connection)
  31. {
  32. self::$connection = $connection;
  33. }
  34. /**
  35. * @return Connection
  36. */
  37. public function getConnection()
  38. {
  39. return self::$connection;
  40. }
  41. /**
  42. * @return EntityManager
  43. */
  44. public static function getManager()
  45. {
  46. return self::$em;
  47. }
  48. /**
  49. * Returns the name of the main database.
  50. *
  51. * @return string
  52. */
  53. public static function get_main_database()
  54. {
  55. return self::getManager()->getConnection()->getDatabase();
  56. }
  57. /**
  58. * Get main table.
  59. *
  60. * @param string $table
  61. *
  62. * @return string
  63. */
  64. public static function get_main_table($table)
  65. {
  66. return $table;
  67. }
  68. /**
  69. * Get course table.
  70. *
  71. * @param string $table
  72. *
  73. * @return string
  74. */
  75. public static function get_course_table($table)
  76. {
  77. return DB_COURSE_PREFIX.$table;
  78. }
  79. /**
  80. * Counts the number of rows in a table.
  81. *
  82. * @param string $table The table of which the rows should be counted
  83. *
  84. * @return int the number of rows in the given table
  85. *
  86. * @deprecated
  87. */
  88. public static function count_rows($table)
  89. {
  90. $obj = self::fetch_object(self::query("SELECT COUNT(*) AS n FROM $table"));
  91. return $obj->n;
  92. }
  93. /**
  94. * Returns the number of affected rows in the last database operation.
  95. *
  96. * @param Statement $result
  97. *
  98. * @return int
  99. */
  100. public static function affected_rows(Statement $result)
  101. {
  102. return $result->rowCount();
  103. }
  104. /**
  105. * @return string
  106. */
  107. public static function getUTCDateTimeTypeClass()
  108. {
  109. return isset(self::$utcDateTimeClass) ? self::$utcDateTimeClass : 'Application\DoctrineExtensions\DBAL\Types\UTCDateTimeType';
  110. }
  111. /**
  112. * Connect to the database sets the entity manager.
  113. *
  114. * @param array $params
  115. * @param string $sysPath
  116. * @param string $entityRootPath
  117. * @param bool $returnConnection
  118. * @param bool $returnManager
  119. *
  120. * @throws \Doctrine\ORM\ORMException
  121. *
  122. * @return
  123. */
  124. public function connect(
  125. $params = [],
  126. $sysPath = '',
  127. $entityRootPath = '',
  128. $returnConnection = false,
  129. $returnManager = false
  130. ) {
  131. $config = self::getDoctrineConfig($entityRootPath);
  132. $config->setAutoGenerateProxyClasses(true);
  133. $config->setEntityNamespaces(
  134. [
  135. 'ChamiloUserBundle' => 'Chamilo\UserBundle\Entity',
  136. 'ChamiloCoreBundle' => 'Chamilo\CoreBundle\Entity',
  137. 'ChamiloCourseBundle' => 'Chamilo\CourseBundle\Entity',
  138. 'ChamiloSkillBundle' => 'Chamilo\SkillBundle\Entity',
  139. 'ChamiloTicketBundle' => 'Chamilo\TicketBundle\Entity',
  140. 'ChamiloPluginBundle' => 'Chamilo\PluginBundle\Entity',
  141. ]
  142. );
  143. $params['charset'] = 'utf8';
  144. $entityManager = EntityManager::create($params, $config);
  145. $sysPath = !empty($sysPath) ? $sysPath : api_get_path(SYS_PATH);
  146. // Registering Constraints
  147. /*AnnotationRegistry::registerAutoloadNamespace(
  148. 'Symfony\Component',
  149. $sysPath."vendor/"
  150. );*/
  151. AnnotationRegistry::registerLoader(
  152. function ($class) use ($sysPath) {
  153. $file = str_replace("\\", DIRECTORY_SEPARATOR, $class).".php";
  154. $file = str_replace('Symfony/Component/Validator', '', $file);
  155. $file = str_replace('Symfony\Component\Validator', '', $file);
  156. $fileToInclude = $sysPath.'vendor/symfony/validator/'.$file;
  157. if (file_exists($fileToInclude)) {
  158. // file exists makes sure that the loader fails silently
  159. require_once $fileToInclude;
  160. return true;
  161. }
  162. $fileToInclude = $sysPath.'vendor/symfony/validator/Constraints/'.$file;
  163. if (file_exists($fileToInclude)) {
  164. // file exists makes sure that the loader fails silently
  165. require_once $fileToInclude;
  166. return true;
  167. }
  168. }
  169. );
  170. AnnotationRegistry::registerFile(
  171. $sysPath."vendor/symfony/doctrine-bridge/Validator/Constraints/UniqueEntity.php"
  172. );
  173. // Registering gedmo extensions
  174. AnnotationRegistry::registerAutoloadNamespace(
  175. 'Gedmo\Mapping\Annotation',
  176. $sysPath."vendor/gedmo/doctrine-extensions/lib"
  177. );
  178. Type::overrideType(
  179. Type::DATETIME,
  180. self::getUTCDateTimeTypeClass()
  181. );
  182. $listener = new \Gedmo\Timestampable\TimestampableListener();
  183. $entityManager->getEventManager()->addEventSubscriber($listener);
  184. $listener = new \Gedmo\Tree\TreeListener();
  185. $entityManager->getEventManager()->addEventSubscriber($listener);
  186. $listener = new \Gedmo\Sortable\SortableListener();
  187. $entityManager->getEventManager()->addEventSubscriber($listener);
  188. $connection = $entityManager->getConnection();
  189. $connection->executeQuery('SET sql_mode = "";');
  190. $connection->executeQuery('SET SESSION sql_mode = ""');
  191. if ($returnConnection) {
  192. return $connection;
  193. }
  194. if ($returnManager) {
  195. return $entityManager;
  196. }
  197. $this->setConnection($connection);
  198. $this->setManager($entityManager);
  199. }
  200. /**
  201. * Escape MySQL wildchars _ and % in LIKE search.
  202. *
  203. * @param string $text The string to escape
  204. *
  205. * @return string The escaped string
  206. */
  207. public static function escape_sql_wildcards($text)
  208. {
  209. $text = api_preg_replace("/_/", "\_", $text);
  210. $text = api_preg_replace("/%/", "\%", $text);
  211. return $text;
  212. }
  213. /**
  214. * Escapes a string to insert into the database as text.
  215. *
  216. * @param string $string
  217. *
  218. * @return string
  219. */
  220. public static function escape_string($string)
  221. {
  222. $string = self::getManager()->getConnection()->quote($string);
  223. // The quote method from PDO also adds quotes around the string, which
  224. // is not how the legacy mysql_real_escape_string() was used in
  225. // Chamilo, so we need to remove the quotes around. Using trim will
  226. // remove more than one quote if they are sequenced, generating
  227. // broken queries and SQL injection risks
  228. return substr($string, 1, -1);
  229. }
  230. /**
  231. * Gets the array from a SQL result (as returned by Database::query).
  232. *
  233. * @param Statement $result
  234. * @param string $option Optional: "ASSOC","NUM" or "BOTH"
  235. *
  236. * @return array|mixed
  237. */
  238. public static function fetch_array(Statement $result, $option = 'BOTH')
  239. {
  240. if ($result === false) {
  241. return [];
  242. }
  243. return $result->fetch(self::customOptionToDoctrineOption($option));
  244. }
  245. /**
  246. * Gets an associative array from a SQL result (as returned by Database::query).
  247. *
  248. * @param Statement $result
  249. *
  250. * @return array
  251. */
  252. public static function fetch_assoc(Statement $result)
  253. {
  254. return $result->fetch(PDO::FETCH_ASSOC);
  255. }
  256. /**
  257. * Gets the next row of the result of the SQL query
  258. * (as returned by Database::query) in an object form.
  259. *
  260. * @param Statement $result
  261. *
  262. * @return mixed
  263. */
  264. public static function fetch_object(Statement $result)
  265. {
  266. return $result->fetch(PDO::FETCH_OBJ);
  267. }
  268. /**
  269. * Gets the array from a SQL result (as returned by Database::query)
  270. * help achieving database independence.
  271. *
  272. * @param Statement $result
  273. *
  274. * @return mixed
  275. */
  276. public static function fetch_row(Statement $result)
  277. {
  278. if ($result === false) {
  279. return [];
  280. }
  281. return $result->fetch(PDO::FETCH_NUM);
  282. }
  283. /**
  284. * Frees all the memory associated with the provided result identifier.
  285. *
  286. * @return bool|null Returns TRUE on success or FALSE on failure.
  287. * Notes: Use this method if you are concerned about how much memory is being used for queries that return large result sets.
  288. * Anyway, all associated result memory is automatically freed at the end of the script's execution.
  289. */
  290. public static function free_result(Statement $result)
  291. {
  292. $result->closeCursor();
  293. }
  294. /**
  295. * Gets the ID of the last item inserted into the database.
  296. *
  297. * @return string
  298. */
  299. public static function insert_id()
  300. {
  301. return self::getManager()->getConnection()->lastInsertId();
  302. }
  303. /**
  304. * @param Statement $result
  305. *
  306. * @return int
  307. */
  308. public static function num_rows(Statement $result)
  309. {
  310. if ($result === false) {
  311. return 0;
  312. }
  313. return $result->rowCount();
  314. }
  315. /**
  316. * Acts as the relative *_result() function of most DB drivers and fetches a
  317. * specific line and a field.
  318. *
  319. * @param Statement $resource
  320. * @param int $row
  321. * @param string $field
  322. *
  323. * @return mixed
  324. */
  325. public static function result(Statement $resource, $row, $field = '')
  326. {
  327. if ($resource->rowCount() > 0) {
  328. $result = $resource->fetchAll(PDO::FETCH_BOTH);
  329. return $result[$row][$field];
  330. }
  331. return false;
  332. }
  333. /**
  334. * @param string $query
  335. *
  336. * @return Statement
  337. */
  338. public static function query($query)
  339. {
  340. $connection = self::getManager()->getConnection();
  341. $result = null;
  342. try {
  343. $result = $connection->executeQuery($query);
  344. } catch (Exception $e) {
  345. self::handleError($e);
  346. }
  347. return $result;
  348. }
  349. /**
  350. * @param Exception $e
  351. */
  352. public static function handleError($e)
  353. {
  354. $debug = api_get_setting('server_type') == 'test';
  355. if ($debug) {
  356. // We use Symfony exception handler for better error information
  357. $handler = new ExceptionHandler();
  358. $handler->handle($e);
  359. exit;
  360. } else {
  361. error_log($e->getMessage());
  362. api_not_allowed(false, get_lang('GeneralError'));
  363. exit;
  364. }
  365. }
  366. /**
  367. * @param string $option
  368. *
  369. * @return int
  370. */
  371. public static function customOptionToDoctrineOption($option)
  372. {
  373. switch ($option) {
  374. case 'ASSOC':
  375. return PDO::FETCH_ASSOC;
  376. break;
  377. case 'NUM':
  378. return PDO::FETCH_NUM;
  379. break;
  380. case 'BOTH':
  381. default:
  382. return PDO::FETCH_BOTH;
  383. break;
  384. }
  385. }
  386. /**
  387. * Stores a query result into an array.
  388. *
  389. * @author Olivier Brouckaert
  390. *
  391. * @param Statement $result - the return value of the query
  392. * @param string $option BOTH, ASSOC, or NUM
  393. *
  394. * @return array - the value returned by the query
  395. */
  396. public static function store_result(Statement $result, $option = 'BOTH')
  397. {
  398. return $result->fetchAll(self::customOptionToDoctrineOption($option));
  399. }
  400. /**
  401. * Database insert.
  402. *
  403. * @param string $table_name
  404. * @param array $attributes
  405. * @param bool $show_query
  406. *
  407. * @return false|int
  408. */
  409. public static function insert($table_name, $attributes, $show_query = false)
  410. {
  411. if (empty($attributes) || empty($table_name)) {
  412. return false;
  413. }
  414. $params = array_keys($attributes);
  415. if (!empty($params)) {
  416. $sql = 'INSERT INTO '.$table_name.' ('.implode(',', $params).')
  417. VALUES (:'.implode(', :', $params).')';
  418. $statement = self::getManager()->getConnection()->prepare($sql);
  419. $result = $statement->execute($attributes);
  420. if ($show_query) {
  421. var_dump($sql);
  422. error_log($sql);
  423. }
  424. if ($result) {
  425. return (int) self::getManager()->getConnection()->lastInsertId();
  426. }
  427. }
  428. return false;
  429. }
  430. /**
  431. * @param string $tableName use Database::get_main_table
  432. * @param array $attributes Values to updates
  433. * Example: $params['name'] = 'Julio'; $params['lastname'] = 'Montoya';
  434. * @param array $whereConditions where conditions i.e array('id = ?' =>'4')
  435. * @param bool $showQuery
  436. *
  437. * @return bool|int
  438. */
  439. public static function update(
  440. $tableName,
  441. $attributes,
  442. $whereConditions = [],
  443. $showQuery = false
  444. ) {
  445. if (!empty($tableName) && !empty($attributes)) {
  446. $updateSql = '';
  447. $count = 1;
  448. foreach ($attributes as $key => $value) {
  449. if ($showQuery) {
  450. echo $key.': '.$value.PHP_EOL;
  451. }
  452. $updateSql .= "$key = :$key ";
  453. if ($count < count($attributes)) {
  454. $updateSql .= ', ';
  455. }
  456. $count++;
  457. }
  458. if (!empty($updateSql)) {
  459. //Parsing and cleaning the where conditions
  460. $whereReturn = self::parse_where_conditions($whereConditions);
  461. $sql = "UPDATE $tableName SET $updateSql $whereReturn ";
  462. $statement = self::getManager()->getConnection()->prepare($sql);
  463. $result = $statement->execute($attributes);
  464. if ($showQuery) {
  465. var_dump($sql);
  466. var_dump($attributes);
  467. var_dump($whereConditions);
  468. }
  469. if ($result) {
  470. return $statement->rowCount();
  471. }
  472. }
  473. }
  474. return false;
  475. }
  476. /**
  477. * Experimental useful database finder.
  478. *
  479. * @todo lot of stuff to do here
  480. * @todo known issues, it doesn't work when using LIKE conditions
  481. *
  482. * @example array('where'=> array('course_code LIKE "?%"'))
  483. * @example array('where'=> array('type = ? AND category = ?' => array('setting', 'Plugins'))
  484. * @example array('where'=> array('name = "Julio" AND lastname = "montoya"'))
  485. *
  486. * @param mixed $columns array (or string if only one column)
  487. * @param string $table_name
  488. * @param array $conditions
  489. * @param string $type_result all|first|count
  490. * @param string $option
  491. * @param bool $debug
  492. *
  493. * @return array
  494. */
  495. public static function select(
  496. $columns,
  497. $table_name,
  498. $conditions = [],
  499. $type_result = 'all',
  500. $option = 'ASSOC',
  501. $debug = false
  502. ) {
  503. if ($type_result === 'count') {
  504. $conditions['LIMIT'] = null;
  505. $conditions['limit'] = null;
  506. }
  507. $conditions = self::parse_conditions($conditions);
  508. //@todo we could do a describe here to check the columns ...
  509. if (is_array($columns)) {
  510. $clean_columns = implode(',', $columns);
  511. } else {
  512. if ($columns === '*') {
  513. $clean_columns = '*';
  514. } else {
  515. $clean_columns = (string) $columns;
  516. }
  517. }
  518. if ($type_result === 'count') {
  519. $clean_columns = ' count(*) count ';
  520. }
  521. $sql = "SELECT $clean_columns FROM $table_name $conditions";
  522. if ($debug) {
  523. var_dump($sql);
  524. }
  525. $result = self::query($sql);
  526. if ($type_result === 'count') {
  527. $row = self::fetch_array($result, $option);
  528. if ($row) {
  529. return (int) $row['count'];
  530. }
  531. return 0;
  532. }
  533. $array = [];
  534. if ($type_result === 'all') {
  535. while ($row = self::fetch_array($result, $option)) {
  536. if (isset($row['id'])) {
  537. $array[$row['id']] = $row;
  538. } else {
  539. $array[] = $row;
  540. }
  541. }
  542. } else {
  543. $array = self::fetch_array($result, $option);
  544. }
  545. return $array;
  546. }
  547. /**
  548. * Parses WHERE/ORDER conditions i.e array('where'=>array('id = ?' =>'4'), 'order'=>'id DESC').
  549. *
  550. * @todo known issues, it doesn't work when using
  551. * LIKE conditions example: array('where'=>array('course_code LIKE "?%"'))
  552. *
  553. * @param array $conditions
  554. *
  555. * @return string Partial SQL string to add to longer query
  556. */
  557. public static function parse_conditions($conditions)
  558. {
  559. if (empty($conditions)) {
  560. return '';
  561. }
  562. $return_value = $where_return = '';
  563. foreach ($conditions as $type_condition => $condition_data) {
  564. if ($condition_data == false) {
  565. continue;
  566. }
  567. $type_condition = strtolower($type_condition);
  568. switch ($type_condition) {
  569. case 'where':
  570. foreach ($condition_data as $condition => $value_array) {
  571. if (is_array($value_array)) {
  572. $clean_values = [];
  573. foreach ($value_array as $item) {
  574. $item = self::escape_string($item);
  575. $clean_values[] = $item;
  576. }
  577. } else {
  578. $value_array = self::escape_string($value_array);
  579. $clean_values = $value_array;
  580. }
  581. if (!empty($condition) && $clean_values != '') {
  582. $condition = str_replace('%', "'@percentage@'", $condition); //replace "%"
  583. $condition = str_replace("'?'", "%s", $condition);
  584. $condition = str_replace("?", "%s", $condition);
  585. $condition = str_replace("@%s@", "@-@", $condition);
  586. $condition = str_replace("%s", "'%s'", $condition);
  587. $condition = str_replace("@-@", "@%s@", $condition);
  588. // Treat conditions as string
  589. $condition = vsprintf($condition, $clean_values);
  590. $condition = str_replace('@percentage@', '%', $condition); //replace "%"
  591. $where_return .= $condition;
  592. }
  593. }
  594. if (!empty($where_return)) {
  595. $return_value = " WHERE $where_return";
  596. }
  597. break;
  598. case 'order':
  599. $order_array = $condition_data;
  600. if (!empty($order_array)) {
  601. // 'order' => 'id desc, name desc'
  602. $order_array = self::escape_string($order_array, null, false);
  603. $new_order_array = explode(',', $order_array);
  604. $temp_value = [];
  605. foreach ($new_order_array as $element) {
  606. $element = explode(' ', $element);
  607. $element = array_filter($element);
  608. $element = array_values($element);
  609. if (!empty($element[1])) {
  610. $element[1] = strtolower($element[1]);
  611. $order = 'DESC';
  612. if (in_array($element[1], ['desc', 'asc'])) {
  613. $order = $element[1];
  614. }
  615. $temp_value[] = $element[0].' '.$order.' ';
  616. } else {
  617. //by default DESC
  618. $temp_value[] = $element[0].' DESC ';
  619. }
  620. }
  621. if (!empty($temp_value)) {
  622. $return_value .= ' ORDER BY '.implode(', ', $temp_value);
  623. }
  624. }
  625. break;
  626. case 'limit':
  627. $limit_array = explode(',', $condition_data);
  628. if (!empty($limit_array)) {
  629. if (count($limit_array) > 1) {
  630. $return_value .= ' LIMIT '.intval($limit_array[0]).' , '.intval($limit_array[1]);
  631. } else {
  632. $return_value .= ' LIMIT '.intval($limit_array[0]);
  633. }
  634. }
  635. break;
  636. }
  637. }
  638. return $return_value;
  639. }
  640. /**
  641. * @param array $conditions
  642. *
  643. * @return string
  644. */
  645. public static function parse_where_conditions($conditions)
  646. {
  647. return self::parse_conditions(['where' => $conditions]);
  648. }
  649. /**
  650. * @param string $table_name
  651. * @param array $where_conditions
  652. * @param bool $show_query
  653. *
  654. * @return int
  655. */
  656. public static function delete($table_name, $where_conditions, $show_query = false)
  657. {
  658. $where_return = self::parse_where_conditions($where_conditions);
  659. $sql = "DELETE FROM $table_name $where_return ";
  660. if ($show_query) {
  661. echo $sql;
  662. echo '<br />';
  663. }
  664. $result = self::query($sql);
  665. $affected_rows = self::affected_rows($result);
  666. //@todo should return affected_rows for
  667. return $affected_rows;
  668. }
  669. /**
  670. * Get Doctrine configuration.
  671. *
  672. * @param string $path
  673. *
  674. * @return \Doctrine\ORM\Configuration
  675. */
  676. public static function getDoctrineConfig($path)
  677. {
  678. $isDevMode = true; // Forces doctrine to use ArrayCache instead of apc/xcache/memcache/redis
  679. $isSimpleMode = false; // related to annotations @Entity
  680. $cache = null;
  681. $path = !empty($path) ? $path : api_get_path(SYS_PATH);
  682. $paths = [
  683. //$path.'src/Chamilo/ClassificationBundle/Entity',
  684. //$path.'src/Chamilo/MediaBundle/Entity',
  685. //$path.'src/Chamilo/PageBundle/Entity',
  686. $path.'src/Chamilo/CoreBundle/Entity',
  687. $path.'src/Chamilo/UserBundle/Entity',
  688. $path.'src/Chamilo/CourseBundle/Entity',
  689. $path.'src/Chamilo/TicketBundle/Entity',
  690. $path.'src/Chamilo/SkillBundle/Entity',
  691. $path.'src/Chamilo/PluginBundle/Entity',
  692. //$path.'vendor/sonata-project/user-bundle/Entity',
  693. //$path.'vendor/sonata-project/user-bundle/Model',
  694. //$path.'vendor/friendsofsymfony/user-bundle/FOS/UserBundle/Entity',
  695. ];
  696. $proxyDir = $path.'app/cache/';
  697. $config = \Doctrine\ORM\Tools\Setup::createAnnotationMetadataConfiguration(
  698. $paths,
  699. $isDevMode,
  700. $proxyDir,
  701. $cache,
  702. $isSimpleMode
  703. );
  704. return $config;
  705. }
  706. /**
  707. * @param string $table
  708. *
  709. * @return bool
  710. */
  711. public static function tableExists($table)
  712. {
  713. return self::getManager()->getConnection()->getSchemaManager()->tablesExist($table);
  714. }
  715. /**
  716. * @param string $table
  717. *
  718. * @return \Doctrine\DBAL\Schema\Column[]
  719. */
  720. public static function listTableColumns($table)
  721. {
  722. return self::getManager()->getConnection()->getSchemaManager()->listTableColumns($table);
  723. }
  724. }