Failed Conditions
Pull Request — master (#35)
by Mathieu
04:35 queued 02:37
created

MasterSlavesConnection::wrappedDriver()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
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 7
rs 9.4286
cc 2
eloc 4
nc 2
nop 0
1
<?php
2
3
namespace Ez\DbLinker\Driver\Connection;
4
5
use Doctrine\DBAL\Driver\Connection;
6
use SplObjectStorage;
7
use Exception;
8
9
class MasterSlavesConnection implements Connection, ConnectionWrapper
10
{
11
    private $master;
12
    private $slavesWeights;
13
    private $connection;
14
    private $driver;
15
    private $currentConnectionFactory;
16
17
    public function __construct($master, SplObjectStorage $slavesWeights)
18
    {
19
        $this->master = $master;
20
        $this->checkSlavesWeights($slavesWeights);
21
        $this->slavesWeights = $slavesWeights;
22
    }
23
24
    private function checkSlavesWeights(SplObjectStorage $slavesWeights)
25
    {
26
        foreach ($slavesWeights as $slave) {
27
            if ((int)$slavesWeights[$slave] < 0) {
28
                throw new Exception('Slave weight must be >= 0');
29
            }
30
        }
31
    }
32
33
    public function connectToMaster()
34
    {
35
        $this->currentConnectionFactory = $this->master;
36
        $this->connection = null;
37
    }
38
39
    public function connectToSlave()
40
    {
41
        $this->currentConnectionFactory = null;
42
        $this->connection = null;
43
    }
44
45
    public function isConnectedToMaster()
46
    {
47
        return $this->currentConnectionFactory === $this->master;
48
    }
49
50
    private function connection()
51
    {
52
        if ($this->connection === null) {
53
            $this->wrap();
54
        }
55
        return $this->connection;
56
    }
57
58
    public function getCurrentConnection()
59
    {
60
        return $this->wrappedConnection();
61
    }
62
63
    public function wrappedConnection()
64
    {
65
        if ($this->connection === null) {
66
            $this->wrap();
67
        }
68
        return $this->connection;
69
    }
70
71
    public function wrappedDriver()
72
    {
73
        if ($this->driver === null) {
74
            $this->wrap();
75
        }
76
        return $this->driver;
77
    }
78
79
    private function wrap()
80
    {
81
        if ($this->currentConnectionFactory === null) {
82
            $this->currentConnectionFactory = $this->chooseASlave() ?: $this->master;
83
        }
84
        $factory = $this->currentConnectionFactory;
85
        $connection = $factory();
86
        $this->connection = $connection->getWrappedConnection();
87
        $this->driver = $connection->getDriver();
88
    }
89
90
    private function chooseASlave()
91
    {
92
        $totalSlavesWeight = $this->totalSlavesWeight();
93
        if ($totalSlavesWeight < 1) {
94
            return null;
95
        }
96
        $weightTarget = mt_rand(1, $totalSlavesWeight);
97
        foreach ($this->slavesWeights as $slave) {
98
            $weightTarget -= $this->slavesWeights[$slave];
99
            if ($weightTarget <= 0) {
100
                return $slave;
101
            }
102
        }
103
    }
104
105
    private function totalSlavesWeight()
106
    {
107
        $weight = 0;
108
        foreach ($this->slavesWeights as $slave) {
109
            $weight += $this->slavesWeights[$slave];
110
        }
111
        return $weight;
112
    }
113
114
    public function disableCurrentSlave()
115
    {
116
        $this->slavesWeights->detach($this->currentConnectionFactory);
117
        $this->currentConnectionFactory = null;
118
        $this->connection = null;
119
    }
120
121
    public function slaves()
122
    {
123
        return clone $this->slavesWeights;
124
    }
125
126
    /**
127
     * Prepares a statement for execution and returns a Statement object.
128
     *
129
     * @param string $prepareString
130
     *
131
     * @return \Doctrine\DBAL\Driver\Statement
132
     */
133
    public function prepare($prepareString)
134
    {
135
        $this->connectToMaster();
136
        return $this->wrappedConnection()->prepare($prepareString);
0 ignored issues
show
Bug introduced by
The method prepare cannot be called on $this->wrappedConnection() (of type null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
137
    }
138
139
    /**
140
     * Executes an SQL statement, returning a result set as a Statement object.
141
     *
142
     * @return \Doctrine\DBAL\Driver\Statement
143
     */
144
    public function query()
145
    {
146
        return call_user_func_array([$this->wrappedConnection(), __FUNCTION__], func_get_args());
147
    }
148
149
    /**
150
     * Quotes a string for use in a query.
151
     *
152
     * @param string  $input
153
     * @param integer $type
154
     *
155
     * @return string
156
     */
157
    public function quote($input, $type = \PDO::PARAM_STR)
158
    {
159
        return $this->wrappedConnection()->quote($input, $type);
0 ignored issues
show
Bug introduced by
The method quote cannot be called on $this->wrappedConnection() (of type null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
160
    }
161
162
    /**
163
     * Executes an SQL statement and return the number of affected rows.
164
     *
165
     * @param string $statement
166
     *
167
     * @return integer
168
     */
169
    public function exec($statement)
170
    {
171
        $this->connectToMaster();
172
        return $this->wrappedConnection()->exec($statement);
0 ignored issues
show
Bug introduced by
The method exec cannot be called on $this->wrappedConnection() (of type null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
173
    }
174
175
    /**
176
     * Returns the ID of the last inserted row or sequence value.
177
     *
178
     * @param string|null $name
179
     *
180
     * @return string
181
     */
182
    public function lastInsertId($name = null)
183
    {
184
        return $this->wrappedConnection()->lastInsertId($name);
0 ignored issues
show
Bug introduced by
The method lastInsertId cannot be called on $this->wrappedConnection() (of type null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
185
    }
186
187
    /**
188
     * Initiates a transaction.
189
     *
190
     * @return boolean TRUE on success or FALSE on failure.
191
     */
192
    public function beginTransaction()
193
    {
194
        $this->connectToMaster();
195
        return $this->wrappedConnection()->beginTransaction();
0 ignored issues
show
Bug introduced by
The method beginTransaction cannot be called on $this->wrappedConnection() (of type null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
196
    }
197
198
    /**
199
     * Commits a transaction.
200
     *
201
     * @return boolean TRUE on success or FALSE on failure.
202
     */
203
    public function commit()
204
    {
205
        $this->connectToMaster();
206
        return $this->wrappedConnection()->commit();
0 ignored issues
show
Bug introduced by
The method commit cannot be called on $this->wrappedConnection() (of type null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
207
    }
208
209
    /**
210
     * Rolls back the current transaction, as initiated by beginTransaction().
211
     *
212
     * @return boolean TRUE on success or FALSE on failure.
213
     */
214
    public function rollBack()
215
    {
216
        $this->connectToMaster();
217
        return $this->wrappedConnection()->rollBack();
0 ignored issues
show
Bug introduced by
The method rollBack cannot be called on $this->wrappedConnection() (of type null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
218
    }
219
220
    /**
221
     * Returns the error code associated with the last operation on the database handle.
222
     *
223
     * @return string|null The error code, or null if no operation has been run on the database handle.
224
     */
225
    public function errorCode()
226
    {
227
        return $this->wrappedConnection()->errorCode();
0 ignored issues
show
Bug introduced by
The method errorCode cannot be called on $this->wrappedConnection() (of type null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
228
    }
229
230
    /**
231
     * Returns extended error information associated with the last operation on the database handle.
232
     *
233
     * @return array
234
     */
235
    public function errorInfo()
236
    {
237
        return $this->wrappedConnection()->errorInfo();
0 ignored issues
show
Bug introduced by
The method errorInfo cannot be called on $this->wrappedConnection() (of type null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
238
    }
239
}
240