Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
n/a
0 / 0
n/a
0 / 0
CRAP
n/a
0 / 0
Select
n/a
0 / 0
n/a
0 / 0
36
n/a
0 / 0
 createPdoConnection
n/a
0 / 0
n/a
0 / 0
2
 setReadConnection
n/a
0 / 0
n/a
0 / 0
1
 getReadConnection
n/a
0 / 0
n/a
0 / 0
5
 hasReadConnection
n/a
0 / 0
n/a
0 / 0
2
 closeReadConnection
n/a
0 / 0
n/a
0 / 0
1
 setWriteConnection
n/a
0 / 0
n/a
0 / 0
1
 getWriteConnection
n/a
0 / 0
n/a
0 / 0
8
 hasWriteConnection
n/a
0 / 0
n/a
0 / 0
2
 closeWriteConnection
n/a
0 / 0
n/a
0 / 0
1
 setQueryCache
n/a
0 / 0
n/a
0 / 0
1
 setProfiling
n/a
0 / 0
n/a
0 / 0
1
 setCriticalReadSession
n/a
0 / 0
n/a
0 / 0
1
 setTransaction
n/a
0 / 0
n/a
0 / 0
1
 writeRollback
n/a
0 / 0
n/a
0 / 0
3
 writeCommit
n/a
0 / 0
n/a
0 / 0
4
 writeCommitWithStartLock
n/a
0 / 0
n/a
0 / 0
2
1<?php
2
3namespace BO\Zmsdb\Connection;
4
5/**
6 *
7 * @codeCoverageIgnore
8 *
9 * @SuppressWarnings(TooManyFields)
10 * Handle read and write connections
11 */
12class Select
13{
14    /**
15     * @var Bool $enableProfiling
16     */
17    public static $enableProfiling = false;
18
19    /**
20     * @var String $readSourceName PDO connection string
21     */
22    public static $readSourceName = null;
23
24    /**
25     * @var String $writeSourceName PDO connection string
26     */
27    public static $writeSourceName = null;
28
29    /**
30     * @var String $dbname_zms
31     */
32    public static $dbname_zms = 'zmsbo';
33
34    /**
35     * @var String $username Login
36     */
37    public static $username = null;
38
39    /**
40     * @var String $password Credential
41     */
42    public static $password = null;
43
44    /**
45     * @var Array $pdoOptions compatible to the 4th PDO::__construct parameter
46     */
47    public static $pdoOptions = [];
48
49    /**
50     * @var String $connectionTimezone
51     *
52     */
53    public static $connectionTimezone = ' UTC';
54
55    /**
56     * @var Bool $enableWsrepSyncWait
57     */
58    public static $enableWsrepSyncWait = false;
59
60    /**
61     * @var Bool $enableWsrepSyncWait
62     */
63    public static $galeraConnection = false;
64
65    /**
66     * @var PdoInterface $readConnection for read only requests
67     */
68    protected static $readConnection = null;
69
70    /**
71     * @var PdoInterface $writeConnection for write only requests
72     */
73    protected static $writeConnection = null;
74
75    /**
76     * @var \Aura\Sql\Profiler $readProfiler for read only requests
77     */
78    protected static $readProfiler = null;
79
80    /**
81     * @var \Aura\Sql\Profiler $writeProfiler for write only requests
82     */
83    protected static $writeProfiler = null;
84
85    /**
86     * @var Bool $useTransaction
87     *
88     */
89    protected static $useTransaction = false;
90
91    /**
92     * @var Bool $useProfiling
93     *
94     */
95    protected static $useProfiling = false;
96
97    /**
98     * @var Bool $useQueryCache
99     *
100     */
101    protected static $useQueryCache = true;
102
103    /**
104     * Create a PDO compatible object
105     *
106     * @param  String $dataSourceName compatible with PDO
107     * @return PdoInterface
108     */
109    protected static function createPdoConnection($dataSourceName)
110    {
111        try {
112            $pdoOptions = array_merge([
113                ], self::$pdoOptions);
114            $pdo = new Pdo($dataSourceName, self::$username, self::$password, $pdoOptions);
115            $pdo->exec('SET NAMES "UTF8";');
116            //$timezone = date_default_timezone_get();
117            //$pdo->prepare('SET time_zone = ?;')->execute([$timezone]);
118            $pdo->exec('SET SESSION sql_mode = "STRICT_ALL_TABLES";');
119            $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
120        } catch (\Exception $exception) {
121            // Extend exception message with connection information
122            $connectInfo = $dataSourceName;
123            throw new \BO\Zmsdb\Exception\Pdo\PDOFailed(
124                $connectInfo . $exception->getMessage(),
125                (int)$exception->getCode(),
126                $exception
127            );
128        }
129        return $pdo;
130    }
131
132    /**
133     * Set the read connection.
134     * Usually this function is only required to set mockups for testing
135     *
136     * @param PdoInterface $connection
137     */
138    public static function setReadConnection(PdoInterface $connection)
139    {
140        self::$readConnection = $connection;
141    }
142
143    /**
144     * Create or return a connection for reading data
145     *
146     * @return PdoInterface
147     */
148    public static function getReadConnection()
149    {
150        if (null === self::$readConnection) {
151            self::$readConnection = self::createPdoConnection(self::$readSourceName);
152            self::$readProfiler = new \Aura\Sql\Profiler\Profiler();
153            self::$readProfiler->setActive(self::$enableProfiling);
154            self::$readConnection->setProfiler(self::$readProfiler);
155            //self::$readConnection->exec('SET SESSION TRANSACTION READ ONLY');
156            if (!self::$useQueryCache) {
157                try {
158                    self::$readConnection->exec('SET SESSION query_cache_type = 0;');
159                } catch (\Exception $exception) {
160                    // ignore, query cache might be disabled
161                }
162            }
163            if (self::$useProfiling) {
164                self::$readConnection->exec('SET profiling = 1;');
165            }
166        }
167        return self::$readConnection;
168    }
169
170    /**
171     * Test if a read connection is established
172     *
173     */
174    public static function hasReadConnection()
175    {
176        return (null === self::$readConnection) ? false : true;
177    }
178
179    /**
180     * Close a connection for reading data
181     *
182     */
183    public static function closeReadConnection()
184    {
185        self::$readConnection = null;
186    }
187
188    /**
189     * Set the write connection.
190     * Usually this function is only required to set mockups for testing
191     *
192     * @param  PdoInterface $connection
193     * @return self
194     */
195    public static function setWriteConnection(PdoInterface $connection)
196    {
197        self::$writeConnection = $connection;
198    }
199
200    /**
201     * Create or return a connection for writing data
202     *
203     * @return PdoInterface
204     */
205    public static function getWriteConnection()
206    {
207        if (null === self::$writeConnection) {
208            self::$writeConnection = self::createPdoConnection(self::$writeSourceName);
209            self::$writeProfiler = new \Aura\Sql\Profiler\Profiler();
210            self::$writeProfiler->setActive(self::$enableProfiling);
211            self::$writeConnection->setProfiler(self::$writeProfiler);
212            if (self::$useTransaction) {
213                self::$writeConnection->exec('SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED');
214                self::$writeConnection->exec('SET SESSION innodb_lock_wait_timeout=15');
215                self::$writeConnection->beginTransaction();
216            }
217            if (!self::$useQueryCache) {
218                try {
219                    self::$writeConnection->exec('SET SESSION query_cache_type = 0;');
220                } catch (\Exception $exception) {
221                    // ignore, query cache might be disabled
222                }
223            }
224            if (self::$useProfiling) {
225                self::$writeConnection->exec('SET profiling = 1;');
226            }
227            if (self::$galeraConnection && self::$enableWsrepSyncWait) {
228                self::$writeConnection->exec(
229                    'SET SESSION wsrep_sync_wait = (
230                        SELECT CAST(value AS INT) FROM config WHERE name = "setting__wsrepsync"
231                    );'
232                );
233            }
234            // On writing, use the same host to avoid racing/transaction conditions
235            self::$readConnection = self::$writeConnection;
236        }
237        return self::$writeConnection;
238    }
239
240    /**
241     * Test if a write connection is established
242     *
243     */
244    public static function hasWriteConnection()
245    {
246        return (null === self::$writeConnection) ? false : true;
247    }
248
249    /**
250     * Close a connection for writing data
251     *
252     */
253    public static function closeWriteConnection()
254    {
255        self::$writeConnection = null;
256    }
257
258    /**
259     * Set query cache
260     *
261     * @param Bool $useQueryCache
262     *
263     */
264    public static function setQueryCache($useQueryCache = true)
265    {
266        static::$useQueryCache = $useQueryCache;
267    }
268
269    /**
270     * Set profiling
271     *
272     * @param Bool $useProfiling
273     *
274     */
275    public static function setProfiling($useProfiling = true)
276    {
277        static::$useProfiling = $useProfiling;
278    }
279
280    /**
281     * Set cluster wide causality checks, needed for critical reads across different nodes
282     * @param Bool $wsrepStatus Set to true for critical reads
283     */
284    public static function setCriticalReadSession($wsrepStatus = true)
285    {
286        static::$enableWsrepSyncWait = $wsrepStatus;
287        static::getWriteConnection();
288    }
289
290    /**
291     * Set transaction
292     *
293     * @param Bool $useTransaction
294     *
295     */
296    public static function setTransaction($useTransaction = true)
297    {
298        static::$useTransaction = $useTransaction;
299    }
300
301    /**
302     * Rollback transaction if started
303     *
304     */
305    public static function writeRollback()
306    {
307        if (self::$useTransaction && self::getWriteConnection()->inTransaction()) {
308            return self::getWriteConnection()->rollBack();
309        }
310        return null;
311    }
312
313    /**
314     * Commit transaction if started
315     *
316     */
317    public static function writeCommit()
318    {
319        if (self::$useTransaction && null !== self::$writeConnection && self::getWriteConnection()->inTransaction()) {
320            $status = self::getWriteConnection()->commit();
321            self::$writeConnection->beginTransaction();
322            return $status;
323        }
324        return null;
325    }
326
327    public static function writeCommitWithStartLock()
328    {
329        return self::writeCommit() && (new \BO\Zmsdb\Config())->readProperty('status__calculateSlotsLastRun', true);
330    }
331}