PageRenderTime 48ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/main/lib/db/result.php

https://gitlab.com/alexprowars/bitrix
PHP | 328 lines | 166 code | 34 blank | 128 comment | 20 complexity | 06362f3b6050367040fe5a07b2564b60 MD5 | raw file
  1. <?php
  2. namespace Bitrix\Main\DB;
  3. /**
  4. * Class Result is the abstract base class for representing
  5. * database query result.
  6. * <p>
  7. * It has ability to transform raw data populated from
  8. * the database into useful associative arrays with
  9. * some fields unserialized and some presented as Datetime
  10. * objects or other changes.
  11. * <p>
  12. * It also supports query debugging by providing {@link \Bitrix\Main\Diag\SqlTracker}
  13. * with timing information.
  14. *
  15. * @package Bitrix\Main\DB
  16. */
  17. abstract class Result implements \IteratorAggregate
  18. {
  19. /** @var \Bitrix\Main\DB\Connection */
  20. protected $connection;
  21. /** @var resource */
  22. protected $resource;
  23. /** @var \Bitrix\Main\Diag\SqlTrackerQuery */
  24. protected $trackerQuery = null;
  25. /** @var callable[] */
  26. protected $converters = array();
  27. /** @var string[] */
  28. protected $serializedFields = array();
  29. /** @var string[] */
  30. protected $replacedAliases = array();
  31. /** @var callable[] */
  32. protected $fetchDataModifiers = array();
  33. /** @var int */
  34. protected $count;
  35. /**
  36. * @param resource $result Database-specific query result.
  37. * @param Connection $dbConnection Connection object.
  38. * @param \Bitrix\Main\Diag\SqlTrackerQuery $trackerQuery Helps to collect debug information.
  39. */
  40. public function __construct($result, Connection $dbConnection = null, \Bitrix\Main\Diag\SqlTrackerQuery $trackerQuery = null)
  41. {
  42. $this->resource = $result;
  43. $this->connection = $dbConnection;
  44. $this->trackerQuery = $trackerQuery;
  45. $resultFields = $this->getFields();
  46. if ($resultFields && $this->connection)
  47. {
  48. $helper = $this->connection->getSqlHelper();
  49. foreach ($resultFields as $key => $type)
  50. {
  51. $converter = $helper->getConverter($resultFields[$key]);
  52. if (is_callable($converter))
  53. {
  54. $this->converters[$key] = $converter;
  55. }
  56. }
  57. }
  58. }
  59. /**
  60. * Returns database-specific resource of this result.
  61. *
  62. * @return null|resource
  63. */
  64. public function getResource()
  65. {
  66. return $this->resource;
  67. }
  68. /**
  69. * Sets list of aliased columns.
  70. * This allows to overcome database limits on length of the column names.
  71. *
  72. * @param array[string]string $replacedAliases Aliases map from tech to human.
  73. *
  74. * @return void
  75. * @see \Bitrix\Main\Db\Result::addReplacedAliases
  76. */
  77. public function setReplacedAliases(array $replacedAliases)
  78. {
  79. $this->replacedAliases = $replacedAliases;
  80. }
  81. /**
  82. * Extends list of aliased columns.
  83. *
  84. * @param array[string]string $replacedAliases Aliases map from tech to human.
  85. *
  86. * @return void
  87. * @see \Bitrix\Main\Db\Result::setReplacedAliases
  88. */
  89. public function addReplacedAliases(array $replacedAliases)
  90. {
  91. $this->replacedAliases = array_merge($this->replacedAliases, $replacedAliases);
  92. }
  93. /**
  94. * Sets internal list of fields which will be unserialized on fetch.
  95. *
  96. * @param array $serializedFields List of fields.
  97. *
  98. * @return void
  99. */
  100. public function setSerializedFields(array $serializedFields)
  101. {
  102. $this->serializedFields = $serializedFields;
  103. }
  104. /**
  105. * Modifier should accept once fetched array as an argument, then modify by link or return new array:
  106. * - function (&$data) { $data['AGE'] -= 7; }
  107. * - function ($data) { $data['AGE'] -= 7; return $data; }
  108. *
  109. * @param callable $fetchDataModifier Valid callback.
  110. *
  111. * @return void
  112. * @throws \Bitrix\Main\ArgumentException
  113. */
  114. public function addFetchDataModifier($fetchDataModifier)
  115. {
  116. if (!is_callable($fetchDataModifier))
  117. {
  118. throw new \Bitrix\Main\ArgumentException('Data Modifier should be a callback');
  119. }
  120. $this->fetchDataModifiers[] = $fetchDataModifier;
  121. }
  122. /**
  123. * Fetches one row of the query result and returns it in the associative array of raw DB data or false on empty data.
  124. *
  125. * @return array|false
  126. */
  127. public function fetchRaw()
  128. {
  129. if ($this->trackerQuery != null)
  130. {
  131. $this->trackerQuery->restartQuery();
  132. }
  133. $data = $this->fetchRowInternal();
  134. if ($this->trackerQuery != null)
  135. {
  136. $this->trackerQuery->refinishQuery();
  137. }
  138. if (!$data)
  139. {
  140. return false;
  141. }
  142. return $data;
  143. }
  144. /**
  145. * Fetches one row of the query result and returns it in the associative array of converted data or false on empty data.
  146. *
  147. * @param \Bitrix\Main\Text\Converter $converter Optional converter to encode data on fetching.
  148. *
  149. * @return array|false
  150. */
  151. public function fetch(\Bitrix\Main\Text\Converter $converter = null)
  152. {
  153. $data = $this->fetchRaw();
  154. if (!$data)
  155. {
  156. return false;
  157. }
  158. if ($this->converters)
  159. {
  160. foreach ($this->converters as $field => $convertDataModifier)
  161. {
  162. $data[$field] = call_user_func_array($convertDataModifier, array($data[$field]));
  163. }
  164. }
  165. if ($this->serializedFields)
  166. {
  167. foreach ($this->serializedFields as $field)
  168. {
  169. if (isset($data[$field]))
  170. $data[$field] = unserialize($data[$field]);
  171. }
  172. }
  173. if ($this->replacedAliases)
  174. {
  175. foreach ($this->replacedAliases as $tech => $human)
  176. {
  177. $data[$human] = $data[$tech];
  178. unset($data[$tech]);
  179. }
  180. }
  181. if ($this->fetchDataModifiers)
  182. {
  183. foreach ($this->fetchDataModifiers as $fetchDataModifier)
  184. {
  185. $result = call_user_func_array($fetchDataModifier, array(&$data));
  186. if (is_array($result))
  187. {
  188. $data = $result;
  189. }
  190. }
  191. }
  192. if ($converter != null)
  193. {
  194. foreach ($data as $key => $val)
  195. {
  196. $data[$key] = $converter->encode(
  197. $val,
  198. (isset($data[$key."_TYPE"])? $data[$key."_TYPE"] : \Bitrix\Main\Text\Converter::TEXT)
  199. );
  200. }
  201. }
  202. return $data;
  203. }
  204. /**
  205. * Fetches all the rows of the query result and returns it in the array of associative arrays.
  206. * Returns an empty array if query has no data.
  207. *
  208. * @param \Bitrix\Main\Text\Converter $converter Optional converter to encode data on fetching.
  209. *
  210. * @return array
  211. */
  212. public function fetchAll(\Bitrix\Main\Text\Converter $converter = null)
  213. {
  214. $res = array();
  215. while ($ar = $this->fetch($converter))
  216. {
  217. $res[] = $ar;
  218. }
  219. return $res;
  220. }
  221. /**
  222. * Returns an array of fields according to columns in the result.
  223. *
  224. * @return \Bitrix\Main\ORM\Fields\ScalarField[]
  225. */
  226. abstract public function getFields();
  227. /**
  228. * Returns the number of rows in the result.
  229. *
  230. * @return int
  231. */
  232. abstract public function getSelectedRowsCount();
  233. /**
  234. * Returns next result row or false.
  235. *
  236. * @return array|false
  237. */
  238. abstract protected function fetchRowInternal();
  239. /**
  240. * Returns current query tracker.
  241. *
  242. * @return \Bitrix\Main\Diag\SqlTrackerQuery|null
  243. */
  244. public function getTrackerQuery()
  245. {
  246. return $this->trackerQuery;
  247. }
  248. /**
  249. * @return callable[]
  250. */
  251. public function getConverters()
  252. {
  253. return $this->converters;
  254. }
  255. /**
  256. * @param callable[] $converters
  257. */
  258. public function setConverters($converters)
  259. {
  260. $this->converters = $converters;
  261. }
  262. /**
  263. * Sets record count.
  264. * @param int $n
  265. */
  266. public function setCount($n)
  267. {
  268. $this->count = (int)$n;
  269. }
  270. /**
  271. * Returns record count. It's required to set record count explicitly before.
  272. * @return int
  273. * @throws \Bitrix\Main\ObjectPropertyException
  274. */
  275. public function getCount()
  276. {
  277. if($this->count !== null)
  278. {
  279. return $this->count;
  280. }
  281. throw new \Bitrix\Main\ObjectPropertyException("count");
  282. }
  283. /**
  284. * Retrieve an external iterator
  285. * @link http://php.net/manual/en/iteratoraggregate.getiterator.php
  286. * @return \Traversable An instance of an object implementing <b>Iterator</b> or
  287. * <b>Traversable</b>
  288. * @since 5.0.0
  289. */
  290. public function getIterator()
  291. {
  292. return new ResultIterator($this);
  293. }
  294. }