Portal Update Forum Request (#2068)
[openemr.git] / common / database / Connector.php
blob10e858108172be0df0226c8671624ccc3256811c
1 <?php
2 /**
3 * This singleton class provides a pooled Doctrine connection to consumers. All connection data
4 * is configurable via sqlconf.php.
6 * If needed, the instance can be used in a transactional context:
7 * <code>
8 * $database = \common\database\Connector::Instance();
9 * $entityManager = $database->entityManager;
10 * $entityManager->getConnection()->beginTransaction();
11 * try {
12 * // Entity work here...
13 * $entityManager->persist($someEntityToBePersisted);
14 * $entityManager->flush();
15 * $entityManager->getConnection()->commit();
16 * } catch (Exception $e) {
17 * $entityManager->getConnection()->rollBack();
18 * throw $e;
19 * }
20 * </code>
22 * Copyright (C) 2016 Matthew Vita <matthewvita48@gmail.com>
24 * LICENSE: This program is free software; you can redistribute it and/or
25 * modify it under the terms of the GNU General Public License
26 * as published by the Free Software Foundation; either version 2
27 * of the License, or (at your option) any later version.
28 * This program is distributed in the hope that it will be useful,
29 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 * GNU General Public License for more details.
32 * You should have received a copy of the GNU General Public License
33 * along with this program. If not, see <http://opensource.org/licenses/gpl-license.php>.
35 * @package OpenEMR
36 * @author Matthew Vita <matthewvita48@gmail.com>
37 * @link http://www.open-emr.org
40 namespace OpenEMR\Common\Database;
42 use \Doctrine\ORM\Tools\Setup;
43 use \Doctrine\ORM\EntityManager;
44 use OpenEMR\Common\Database\Auditor;
45 use OpenEMR\Common\Logging\Logger;
47 final class Connector
49 /**
50 * The pooled Doctrine connection.
52 public $entityManager;
54 /**
55 * Logger for noting connection/configuration information.
57 private $logger;
59 /**
60 * Default constructor.
62 private function __construct()
64 $this->logger = new Logger("\OpenEMR\Common\Database\Connector");
65 $this->createConnection();
68 /**
69 * The only public method for consumers to either create or gain access to the sole singleton
70 * instance of the class.
72 * @return Connector instance
74 public static function Instance()
76 static $singletonInstance = null;
77 if ($singletonInstance === null) {
78 $singletonInstance = new Connector();
80 if ($GLOBALS['debug_ssl_mysql_connection']) {
81 // below is to debug mysql ssl connection
82 error_log("CHECK SSL CIPHER IN DOCTRINE: " . print_r($singletonInstance->entityManager->getConnection()->query("SHOW STATUS LIKE 'Ssl_cipher';")->FetchAll(), true));
86 return $singletonInstance;
89 /**
90 * Creates the pooled Doctrine connection. All connection data is configurable via sqlconf.php.
91 * By default, the connection is pooled, in a nondev mode, and uses the pdo_mysql driver. Note
92 * that $GLOBALS["doctrine_connection_pooling"] and $GLOBALS["doctrine_dev_mode"] are used instead
93 * of $sqlconf[] because editing the sqlconf.php is not allowed (will mess up endusers trying to
94 * upgrade their install).
96 * @todo document throwables
98 private function createConnection()
100 global $sqlconf;
101 $entityPath = array(__DIR__ . "../entities");
103 $this->logger->trace("Connecting with " . ($GLOBALS["doctrine_connection_pooling"] ? "pooled" : "non-pooled") . " mode");
104 $connection = array(
105 'driver' => "pdo_mysql",
106 'host' => $sqlconf["host"],
107 'port' => $sqlconf["port"],
108 'user' => $sqlconf["login"],
109 'password' => $sqlconf["pass"],
110 'dbname' => $sqlconf["dbase"],
111 'pooled' => $GLOBALS["doctrine_connection_pooling"]
114 global $disable_utf8_flag;
116 $driverOptionsString = '';
118 if (!$disable_utf8_flag) {
119 $this->logger->trace("Enabling utf8");
120 $connection['charset'] = 'utf8';
121 $driverOptionsString = 'SET NAMES utf8';
124 $this->logger->trace("Clearing sql mode");
125 if (!empty($driverOptionsString)) {
126 $driverOptionsString .= ',sql_mode = \'\'';
127 } else {
128 $driverOptionsString = 'SET sql_mode = \'\'';
131 $this->logger->trace("Setting time zone");
132 $driverOptionsString .= ", time_zone = '" . (new \DateTime())->format("P") . "'";
134 // 1002 is the integer value of PDO::MYSQL_ATTR_INIT_COMMAND, which is
135 // executed when connecting to the MySQL server. Note if utf8 or sql
136 // mode commands fail, the connection will not be made.
137 $connection['driverOptions'] = array(
138 1002 => $driverOptionsString
141 // Set mysql to use ssl, if applicable.
142 // Can support basic encryption by including just the mysql-ca pem (this is mandatory for ssl)
143 // Can also support client based certificate if also include mysql-cert and mysql-key (this is optional for ssl)
144 if (file_exists($GLOBALS['OE_SITE_DIR'] . "/documents/certificates/mysql-ca")) {
145 $connection['driverOptions'][\PDO::MYSQL_ATTR_SSL_CA ] = $GLOBALS['OE_SITE_DIR'] . "/documents/certificates/mysql-ca";
146 if (file_exists($GLOBALS['OE_SITE_DIR'] . "/documents/certificates/mysql-key") &&
147 file_exists($GLOBALS['OE_SITE_DIR'] . "/documents/certificates/mysql-cert")) {
148 $connection['driverOptions'][\PDO::MYSQL_ATTR_SSL_KEY] = $GLOBALS['OE_SITE_DIR'] . "/documents/certificates/mysql-key";
149 $connection['driverOptions'][\PDO::MYSQL_ATTR_SSL_CERT] = $GLOBALS['OE_SITE_DIR'] . "/documents/certificates/mysql-cert";
153 $this->logger->trace("Wiring up Doctrine entities");
155 // Note that we need to turn on isDevMode or else it breaks if a user has redis extension installed in PHP, but doesn't have
156 // redis working from the localhost.
157 // TODO : support false for isDevMode and thus support caching (and prevent issue with redis described above)
158 $configuration = Setup::createAnnotationMetadataConfiguration($entityPath, true, null, null, false);
159 $configuration->setAutoGenerateProxyClasses(true);
161 $this->logger->trace("Creating connection");
162 $this->entityManager = EntityManager::create($connection, $configuration);
164 $this->logger->trace("Wiring up SQL auditor to store audit entries in `log` table");
165 $this->entityManager->getConfiguration()->setSQLLogger(new Auditor());