You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

180 lines
5.1 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. <?php namespace Majestic\Model;
  2. /**
  3. * @copyright NetMonsters <team@netmonsters.ru>
  4. * @link http://netmonsters.ru
  5. * @package Majestic
  6. * @subpackage db
  7. * @since 2010-02-19
  8. */
  9. /**
  10. * @property MySQLiDriver $driver
  11. * @property \MySQLi_Result $result
  12. */
  13. class MySQLiStatement extends DbStatement
  14. {
  15. protected $map = null;
  16. public function bindParam($param, &$value)
  17. {
  18. if ($this->map === null) {
  19. $this->mapPlaceholders();
  20. }
  21. if (is_array($this->map) && count($this->map) > 0) {
  22. if (!is_string($param) && !is_int($param)) {
  23. throw new \Majestic\Exception\GeneralException('Placeholder must be an integer or string');
  24. }
  25. if (is_object($value) && ! ($value instanceof DbExpr)) {
  26. throw new \Majestic\Exception\GeneralException('Objects excepts DbExpr not allowed.');
  27. }
  28. if (isset($this->map[$param])) {
  29. $this->params[$param] = &$value;
  30. return true;
  31. }
  32. }
  33. return false;
  34. }
  35. protected function mapPlaceholders()
  36. {
  37. $matches = array();
  38. if(preg_match_all('/(\?|:[A-z][A-z0-9_]*+)/u', $this->request, $matches, PREG_OFFSET_CAPTURE)) {
  39. $noname = 0;
  40. foreach ($matches[0] as $id=>$match) {
  41. $match[2] = $matches[1][$id][0];
  42. $name = ($match[2][0] === ':') ? ltrim($match[2], ':') : $noname++;
  43. $this->map[$name]['placeholder'] = $match[0];
  44. $this->map[$name]['offset'][] = $match[1];
  45. }
  46. }
  47. }
  48. protected function assemble()
  49. {
  50. if (empty($this->map)) {
  51. return $this->request;
  52. }
  53. $query = $this->request;
  54. $placeholders = array();
  55. foreach($this->map as $name => $place) {
  56. $value = $this->driver->quote($this->params[$name]);
  57. foreach ($place['offset'] as $offset) {
  58. $placeholders[$offset] = array('placeholder' => $place['placeholder'], 'value' => $value);
  59. }
  60. }
  61. ksort($placeholders);
  62. $increment = 0;
  63. foreach($placeholders as $current_offset => $placeholder) {
  64. $offset = $current_offset + $increment;
  65. $length = mb_strlen($placeholder['placeholder']);
  66. $query = mb_substr($query, 0, $offset) . $placeholder['value'] . mb_substr($query, $offset + $length);
  67. $increment = (($increment - $length) + mb_strlen($placeholder['value']));
  68. }
  69. return $query;
  70. }
  71. /**
  72. * Fetches single row
  73. *
  74. * @param mixed $style
  75. * @return mixed
  76. * @throws \Majestic\Exception\GeneralException
  77. */
  78. public function fetch($style = Db::FETCH_OBJ)
  79. {
  80. if (!$this->result) {
  81. return false;
  82. }
  83. switch ($style) {
  84. case Db::FETCH_OBJ:
  85. $row = $this->result->fetch_object();
  86. break;
  87. case Db::FETCH_NUM:
  88. $row = $this->result->fetch_array(MYSQLI_NUM);
  89. break;
  90. case Db::FETCH_ASSOC:
  91. $row = $this->result->fetch_assoc();
  92. break;
  93. case Db::FETCH_BOTH:
  94. $row = $this->result->fetch_array(MYSQLI_BOTH);
  95. break;
  96. default:
  97. throw new \Majestic\Exception\GeneralException('Invalid fetch mode "' . $style . '" specified');
  98. }
  99. return $row;
  100. }
  101. /**
  102. * @param string $class
  103. * @return object
  104. */
  105. public function fetchObject($class = 'stdClass')
  106. {
  107. return $this->result->fetch_object($class);
  108. }
  109. /**
  110. * @return array
  111. */
  112. public function fetchPairs()
  113. {
  114. $data = array();
  115. while ($row = $this->fetch(Db::FETCH_NUM)) {
  116. $data[$row[0]] = $row[1];
  117. }
  118. return $data;
  119. }
  120. public function close()
  121. {
  122. if ($this->result !== null) {
  123. $this->result->close();
  124. $this->result = null;
  125. }
  126. }
  127. public function affectedRows()
  128. {
  129. return $this->driver->getConnection()->affected_rows;
  130. }
  131. public function numRows()
  132. {
  133. if ($this->result) {
  134. return $this->result->num_rows;
  135. }
  136. return false;
  137. }
  138. public function getMysqliResult()
  139. {
  140. return $this->result;
  141. }
  142. protected function driverExecute($request)
  143. {
  144. /**
  145. * @var \MySQLi
  146. */
  147. $mysqli = $this->driver->getConnection();
  148. if (\Majestic\Config::get('PROFILER_DETAILS')) {
  149. $profiler = \Majestic\Util\Profiler\Profiler::getInstance()->profilerCommand('MySQL', $request);
  150. $result = $mysqli->query($request);
  151. $profiler->end();
  152. } else {
  153. $result = $mysqli->query($request);
  154. }
  155. if ($result === false) {
  156. $message = $mysqli->error . "\nQuery: \"" . $request . '"';
  157. throw new \Majestic\Exception\GeneralException($message, $mysqli->errno);
  158. }
  159. if ($result instanceof \MySQLi_Result) {
  160. $this->result = $result;
  161. }
  162. return true;
  163. }
  164. }