Rajout de doctrine/orm
[zf2.biz/galerie.git] / vendor / doctrine / dbal / lib / Doctrine / DBAL / Driver / Mysqli / MysqliStatement.php
1 <?php
2 /*
3  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14  *
15  * This software consists of voluntary contributions made by many individuals
16  * and is licensed under the MIT license. For more information, see
17  * <http://www.doctrine-project.org>.
18  */
19
20 namespace Doctrine\DBAL\Driver\Mysqli;
21
22 use Doctrine\DBAL\Driver\Statement;
23 use PDO;
24
25 /**
26  * @author Kim Hemsø Rasmussen <kimhemsoe@gmail.com>
27  */
28 class MysqliStatement implements \IteratorAggregate, Statement
29 {
30     protected static $_paramTypeMap = array(
31         PDO::PARAM_STR => 's',
32         PDO::PARAM_BOOL => 'i',
33         PDO::PARAM_NULL => 's',
34         PDO::PARAM_INT => 'i',
35         PDO::PARAM_LOB => 's' // TODO Support LOB bigger then max package size.
36     );
37
38     protected $_conn;
39     protected $_stmt;
40
41     /**
42      * @var null|false|array
43      */
44     protected $_columnNames;
45
46     /**
47      * @var null|array
48      */
49     protected $_rowBindedValues;
50
51     /**
52      * @var array
53      */
54     protected $_bindedValues;
55
56     /**
57      * Contains ref values for bindValue()
58      *
59      * @var array
60      */
61     protected $_values = array();
62
63     protected $_defaultFetchMode = PDO::FETCH_BOTH;
64
65     public function __construct(\mysqli $conn, $prepareString)
66     {
67         $this->_conn = $conn;
68         $this->_stmt = $conn->prepare($prepareString);
69         if (false === $this->_stmt) {
70             throw new MysqliException($this->_conn->error, $this->_conn->errno);
71         }
72
73         $paramCount = $this->_stmt->param_count;
74         if (0 < $paramCount) {
75             // Index 0 is types
76             // Need to init the string else php think we are trying to access it as a array.
77             $bindedValues = array(0 => str_repeat('s', $paramCount));
78             $null = null;
79             for ($i = 1; $i < $paramCount; $i++) {
80                 $bindedValues[] =& $null;
81             }
82             $this->_bindedValues = $bindedValues;
83         }
84     }
85
86     /**
87      * {@inheritdoc}
88      */
89     public function bindParam($column, &$variable, $type = null, $length = null)
90     {
91         if (null === $type) {
92             $type = 's';
93         } else {
94             if (isset(self::$_paramTypeMap[$type])) {
95                 $type = self::$_paramTypeMap[$type];
96             } else {
97                 throw new MysqliException("Unkown type: '{$type}'");
98             }
99         }
100
101         $this->_bindedValues[$column] =& $variable;
102         $this->_bindedValues[0][$column - 1] = $type;
103         return true;
104     }
105
106     /**
107      * {@inheritdoc}
108      */
109     public function bindValue($param, $value, $type = null)
110     {
111         if (null === $type) {
112             $type = 's';
113         } else {
114             if (isset(self::$_paramTypeMap[$type])) {
115                 $type = self::$_paramTypeMap[$type];
116             } else {
117                 throw new MysqliException("Unknown type: '{$type}'");
118             }
119         }
120
121         $this->_values[$param] = $value;
122         $this->_bindedValues[$param] =& $this->_values[$param];
123         $this->_bindedValues[0][$param - 1] = $type;
124         return true;
125     }
126
127     /**
128      * {@inheritdoc}
129      */
130     public function execute($params = null)
131     {
132         if (null !== $this->_bindedValues) {
133             if (null !== $params) {
134                 if ( ! $this->_bindValues($params)) {
135                     throw new MysqliException($this->_stmt->error, $this->_stmt->errno);
136                 }
137             } else {
138                 if (!call_user_func_array(array($this->_stmt, 'bind_param'), $this->_bindedValues)) {
139                     throw new MysqliException($this->_stmt->error, $this->_stmt->errno);
140                 }
141             }
142         }
143
144         if ( ! $this->_stmt->execute()) {
145             throw new MysqliException($this->_stmt->error, $this->_stmt->errno);
146         }
147
148         if (null === $this->_columnNames) {
149             $meta = $this->_stmt->result_metadata();
150             if (false !== $meta) {
151                 $columnNames = array();
152                 foreach ($meta->fetch_fields() as $col) {
153                     $columnNames[] = $col->name;
154                 }
155                 $meta->free();
156
157                 $this->_columnNames = $columnNames;
158                 $this->_rowBindedValues = array_fill(0, count($columnNames), NULL);
159
160                 $refs = array();
161                 foreach ($this->_rowBindedValues as $key => &$value) {
162                     $refs[$key] =& $value;
163                 }
164
165                 if (!call_user_func_array(array($this->_stmt, 'bind_result'), $refs)) {
166                     throw new MysqliException($this->_stmt->error, $this->_stmt->errno);
167                 }
168             } else {
169                 $this->_columnNames = false;
170             }
171         }
172
173         // We have a result.
174         if (false !== $this->_columnNames) {
175             $this->_stmt->store_result();
176         }
177         return true;
178     }
179
180     /**
181      * Bind a array of values to bound parameters
182      *
183      * @param array $values
184      * @return boolean
185      */
186     private function _bindValues($values)
187     {
188         $params = array();
189         $types = str_repeat('s', count($values));
190         $params[0] = $types;
191
192         foreach ($values as &$v) {
193             $params[] =& $v;
194         }
195         return call_user_func_array(array($this->_stmt, 'bind_param'), $params);
196     }
197
198     /**
199      * @return boolean|array
200      */
201     private function _fetch()
202     {
203         $ret = $this->_stmt->fetch();
204
205         if (true === $ret) {
206             $values = array();
207             foreach ($this->_rowBindedValues as $v) {
208                 // Mysqli converts them to a scalar type it can fit in.
209                 $values[] = null === $v ? null : (string)$v;
210             }
211             return $values;
212         }
213         return $ret;
214     }
215
216     /**
217      * {@inheritdoc}
218      */
219     public function fetch($fetchMode = null)
220     {
221         $values = $this->_fetch();
222         if (null === $values) {
223             return null;
224         }
225
226         if (false === $values) {
227             throw new MysqliException($this->_stmt->error, $this->_stmt->errno);
228         }
229
230         $fetchMode = $fetchMode ?: $this->_defaultFetchMode;
231
232         switch ($fetchMode) {
233             case PDO::FETCH_NUM:
234                 return $values;
235
236             case PDO::FETCH_ASSOC:
237                 return array_combine($this->_columnNames, $values);
238
239             case PDO::FETCH_BOTH:
240                 $ret = array_combine($this->_columnNames, $values);
241                 $ret += $values;
242                 return $ret;
243
244             default:
245                 throw new MysqliException("Unknown fetch type '{$fetchMode}'");
246         }
247     }
248
249     /**
250      * {@inheritdoc}
251      */
252     public function fetchAll($fetchMode = null)
253     {
254         $fetchMode = $fetchMode ?: $this->_defaultFetchMode;
255
256         $rows = array();
257         if (PDO::FETCH_COLUMN == $fetchMode) {
258             while (($row = $this->fetchColumn()) !== false) {
259                 $rows[] = $row;
260             }
261         } else {
262             while (($row = $this->fetch($fetchMode)) !== null) {
263                 $rows[] = $row;
264             }
265         }
266
267         return $rows;
268     }
269
270     /**
271      * {@inheritdoc}
272      */
273     public function fetchColumn($columnIndex = 0)
274     {
275         $row = $this->fetch(PDO::FETCH_NUM);
276         if (null === $row) {
277             return false;
278         }
279         return $row[$columnIndex];
280     }
281
282     /**
283      * {@inheritdoc}
284      */
285     public function errorCode()
286     {
287         return $this->_stmt->errno;
288     }
289
290     /**
291      * {@inheritdoc}
292      */
293     public function errorInfo()
294     {
295         return $this->_stmt->error;
296     }
297
298     /**
299      * {@inheritdoc}
300      */
301     public function closeCursor()
302     {
303         $this->_stmt->free_result();
304         return true;
305     }
306
307     /**
308      * {@inheritdoc}
309      */
310     public function rowCount()
311     {
312         if (false === $this->_columnNames) {
313             return $this->_stmt->affected_rows;
314         }
315         return $this->_stmt->num_rows;
316     }
317
318     /**
319      * {@inheritdoc}
320      */
321     public function columnCount()
322     {
323         return $this->_stmt->field_count;
324     }
325
326     /**
327      * {@inheritdoc}
328      */
329     public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null)
330     {
331         $this->_defaultFetchMode = $fetchMode;
332     }
333
334     /**
335      * {@inheritdoc}
336      */
337     public function getIterator()
338     {
339         $data = $this->fetchAll();
340         return new \ArrayIterator($data);
341     }
342 }