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