Failed Conditions
Pull Request — master (#35)
by Mathieu
02:00
created

MasterSlavesConnection::checkSlaves()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 8
rs 9.4286
cc 3
eloc 4
nc 3
nop 1
1
<?php
2
3
namespace Ez\DbLinker\Driver\Connection;
4
5
use Closure;
6
use Exception;
7
use SplObjectStorage;
8
use Doctrine\DBAL\DriverManager;
9
use Doctrine\DBAL\Driver\Connection;
10
11
class MasterSlavesConnection implements Connection, ConnectionWrapper
0 ignored issues
show
Bug introduced by
There is at least one abstract method in this class. Maybe declare it as abstract, or implement the remaining methods: wrappedConnection, wrappedDriver
Loading history...
12
{
13
    use ConnectionWrapperTrait;
14
15
    private $master;
16
    private $slaves;
17
    private $currentConnectionParams;
18
    private $currentSlave;
19
20
    public function __construct(array $master, array $slaves)
21
    {
22
        $this->master = $master;
23
        $this->checkSlaves($slaves);
24
        $this->slaves = $slaves;
25
    }
26
27
    private function checkSlaves(array $slaves)
28
    {
29
        foreach ($slaves as $slave) {
30
            if ((int)$slave['weight'] < 0) {
31
                throw new Exception('Slave weight must be >= 0');
32
            }
33
        }
34
    }
35
36
    public function connectToMaster()
37
    {
38
        $this->currentConnectionParams = $this->master;
39
        $this->currentSlave = null;
40
        $this->wrappedConnection = null;
41
    }
42
43
    public function connectToSlave()
44
    {
45
        $this->currentConnectionParams = null;
46
        $this->currentSlave = null;
47
        $this->wrappedConnection = null;
48
    }
49
50
    public function isConnectedToMaster()
51
    {
52
        return $this->currentSlave === null && $this->currentConnectionParams !== null;
53
    }
54
55
    /**
56
     * @inherit
57
     */
58
    public function getCurrentConnection()
59
    {
60
        return $this->wrappedConnection();
61
    }
62
63
    protected function wrap()
64
    {
65
        if ($this->currentConnectionParams === null) {
66
            $this->currentSlave = $this->chooseASlave();
67
            $this->currentConnectionParams = $this->currentSlave ? $this->slaves[$this->currentSlave] : $this->master;
68
        }
69
        $connection = DriverManager::getConnection($this->currentConnectionParams);
70
        $this->wrappedConnection = $connection->getWrappedConnection();
71
        $this->wrappedDriver = $connection->getDriver();
72
    }
73
74
    private function chooseASlave()
75
    {
76
        $totalSlavesWeight = $this->totalSlavesWeight();
77
        if ($totalSlavesWeight < 1) {
78
            return null;
79
        }
80
        $weightTarget = mt_rand(1, $totalSlavesWeight);
81
        foreach ($this->slaves as $n => $slave) {
82
            $weightTarget -= $slave['weight'];
83
            if ($weightTarget <= 0) {
84
                return $n;
85
            }
86
        }
87
    }
88
89
    private function totalSlavesWeight()
90
    {
91
        $weight = 0;
92
        foreach ($this->slaves as $slave) {
93
            $weight += $slave['weight'];
94
        }
95
        return $weight;
96
    }
97
98
    public function disableCurrentSlave()
99
    {
100
        if ($this->currentSlave !== null) {
101
            array_splice($this->slaves, $this->currentSlave, 1);
102
            $this->currentSlave = null;
103
        }
104
        $this->currentConnectionParams = null;
105
        $this->wrappedConnection = null;
106
    }
107
108
    public function slaves()
109
    {
110
        return $this->slaves;
111
    }
112
113
    /**
114
     * Prepares a statement for execution and returns a Statement object.
115
     *
116
     * @param string $prepareString
117
     *
118
     * @return \Doctrine\DBAL\Driver\Statement
119
     */
120
    public function prepare($prepareString)
121
    {
122
        $this->connectToMaster();
123
        return $this->wrappedConnection()->prepare($prepareString);
124
    }
125
126
    /**
127
     * Executes an SQL statement, returning a result set as a Statement object.
128
     *
129
     * @return \Doctrine\DBAL\Driver\Statement
130
     */
131
    public function query()
132
    {
133
        return call_user_func_array([$this->wrappedConnection(), __FUNCTION__], func_get_args());
134
    }
135
136
    /**
137
     * Quotes a string for use in a query.
138
     *
139
     * @param string  $input
140
     * @param integer $type
141
     *
142
     * @return string
143
     */
144
    public function quote($input, $type = \PDO::PARAM_STR)
145
    {
146
        return $this->wrappedConnection()->quote($input, $type);
147
    }
148
149
    /**
150
     * Executes an SQL statement and return the number of affected rows.
151
     *
152
     * @param string $statement
153
     *
154
     * @return integer
155
     */
156
    public function exec($statement)
157
    {
158
        $this->connectToMaster();
159
        return $this->wrappedConnection()->exec($statement);
160
    }
161
162
    /**
163
     * Returns the ID of the last inserted row or sequence value.
164
     *
165
     * @param string|null $name
166
     *
167
     * @return string
168
     */
169
    public function lastInsertId($name = null)
170
    {
171
        return $this->wrappedConnection()->lastInsertId($name);
172
    }
173
174
    /**
175
     * Initiates a transaction.
176
     *
177
     * @return boolean TRUE on success or FALSE on failure.
178
     */
179
    public function beginTransaction()
180
    {
181
        $this->connectToMaster();
182
        return $this->wrappedConnection()->beginTransaction();
183
    }
184
185
    /**
186
     * Commits a transaction.
187
     *
188
     * @return boolean TRUE on success or FALSE on failure.
189
     */
190
    public function commit()
191
    {
192
        $this->connectToMaster();
193
        return $this->wrappedConnection()->commit();
194
    }
195
196
    /**
197
     * Rolls back the current transaction, as initiated by beginTransaction().
198
     *
199
     * @return boolean TRUE on success or FALSE on failure.
200
     */
201
    public function rollBack()
202
    {
203
        $this->connectToMaster();
204
        return $this->wrappedConnection()->rollBack();
205
    }
206
207
    /**
208
     * Returns the error code associated with the last operation on the database handle.
209
     *
210
     * @return string|null The error code, or null if no operation has been run on the database handle.
211
     */
212
    public function errorCode()
213
    {
214
        return $this->wrappedConnection()->errorCode();
215
    }
216
217
    /**
218
     * Returns extended error information associated with the last operation on the database handle.
219
     *
220
     * @return array
221
     */
222
    public function errorInfo()
223
    {
224
        return $this->wrappedConnection()->errorInfo();
225
    }
226
}
227