Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
Database.php
Go to the documentation of this file.
1 <?php
34 
36 {
42  protected $_options = [
43  'adapter' => '',
44  'adapter_callback' => '',
45  'data_table' => '',
46  'data_table_callback' => '',
47  'tags_table' => '',
48  'tags_table_callback' => '',
49  'store_data' => true,
50  'infinite_loop_flag' => false,
51  ];
52 
56  protected $_connection = null;
57 
63  public function __construct($options = [])
64  {
65  parent::__construct($options);
66  if (empty($this->_options['adapter_callback'])) {
67  if (!$this->_options['adapter'] instanceof \Magento\Framework\DB\Adapter\AdapterInterface) {
69  'Option "adapter" should be declared and extend \Magento\Framework\DB\Adapter\AdapterInterface!'
70  );
71  }
72  }
73  if (empty($this->_options['data_table']) && empty($this->_options['data_table_callback'])) {
74  \Zend_Cache::throwException('Option "data_table" or "data_table_callback" should be declared!');
75  }
76  if (empty($this->_options['tags_table']) && empty($this->_options['tags_table_callback'])) {
77  \Zend_Cache::throwException('Option "tags_table" or "tags_table_callback" should be declared!');
78  }
79  }
80 
86  protected function _getConnection()
87  {
88  if (!$this->_connection) {
89  if (!empty($this->_options['adapter_callback'])) {
90  $connection = call_user_func($this->_options['adapter_callback']);
91  } else {
92  $connection = $this->_options['adapter'];
93  }
94  if (!$connection instanceof \Magento\Framework\DB\Adapter\AdapterInterface) {
96  'DB Adapter should be declared and extend \Magento\Framework\DB\Adapter\AdapterInterface'
97  );
98  } else {
99  $this->_connection = $connection;
100  }
101  }
102  return $this->_connection;
103  }
104 
110  protected function _getDataTable()
111  {
112  if (empty($this->_options['data_table'])) {
113  $this->setOption('data_table', call_user_func($this->_options['data_table_callback']));
114  if (empty($this->_options['data_table'])) {
115  \Zend_Cache::throwException('Failed to detect data_table option');
116  }
117  }
118  return $this->_options['data_table'];
119  }
120 
126  protected function _getTagsTable()
127  {
128  if (empty($this->_options['tags_table'])) {
129  $this->setOption('tags_table', call_user_func($this->_options['tags_table_callback']));
130  if (empty($this->_options['tags_table'])) {
131  \Zend_Cache::throwException('Failed to detect tags_table option');
132  }
133  }
134  return $this->_options['tags_table'];
135  }
136 
146  public function load($id, $doNotTestCacheValidity = false)
147  {
148  if ($this->_options['store_data'] && !$this->_options['infinite_loop_flag']) {
149  $this->_options['infinite_loop_flag'] = true;
150  $select = $this->_getConnection()->select()->from(
151  $this->_getDataTable(),
152  'data'
153  )->where('id=:cache_id');
154 
155  if (!$doNotTestCacheValidity) {
156  $select->where('expire_time=0 OR expire_time>?', time());
157  }
158  $result = $this->_getConnection()->fetchOne($select, ['cache_id' => $id]);
159  $this->_options['infinite_loop_flag'] = false;
160  return $result;
161  } else {
162  return false;
163  }
164  }
165 
172  public function test($id)
173  {
174  if ($this->_options['store_data'] && !$this->_options['infinite_loop_flag']) {
175  $this->_options['infinite_loop_flag'] = true;
176  $select = $this->_getConnection()->select()->from(
177  $this->_getDataTable(),
178  'update_time'
179  )->where(
180  'id=:cache_id'
181  )->where(
182  'expire_time=0 OR expire_time>?',
183  time()
184  );
185  $result = $this->_getConnection()->fetchOne($select, ['cache_id' => $id]);
186  $this->_options['infinite_loop_flag'] = false;
187  return $result;
188  } else {
189  return false;
190  }
191  }
192 
205  public function save($data, $id, $tags = [], $specificLifetime = false)
206  {
207  $result = false;
208  if (!$this->_options['infinite_loop_flag']) {
209  $this->_options['infinite_loop_flag'] = true;
210  $result = true;
211  if ($this->_options['store_data']) {
212  $connection = $this->_getConnection();
213  $dataTable = $this->_getDataTable();
214 
215  $lifetime = $this->getLifetime($specificLifetime);
216  $time = time();
217  $expire = $lifetime === 0 || $lifetime === null ? 0 : $time + $lifetime;
218 
219  $idCol = $connection->quoteIdentifier('id');
220  $dataCol = $connection->quoteIdentifier('data');
221  $createCol = $connection->quoteIdentifier('create_time');
222  $updateCol = $connection->quoteIdentifier('update_time');
223  $expireCol = $connection->quoteIdentifier('expire_time');
224 
225  $query = "INSERT INTO {$dataTable} ({$idCol}, {$dataCol}, {$createCol}, {$updateCol}, {$expireCol}) " .
226  "VALUES (?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE {$dataCol}=VALUES({$dataCol}), " .
227  "{$updateCol}=VALUES({$updateCol}), {$expireCol}=VALUES({$expireCol})";
228 
229  $result = $connection->query($query, [$id, $data, $time, $time, $expire])->rowCount();
230  }
231  if ($result) {
232  $result = $this->_saveTags($id, $tags);
233  }
234  $this->_options['infinite_loop_flag'] = false;
235  }
236  return $result;
237  }
238 
245  public function remove($id)
246  {
247  if ($this->_options['store_data'] && !$this->_options['infinite_loop_flag']) {
248  $this->_options['infinite_loop_flag'] = true;
249  $result = $this->_getConnection()->delete($this->_getDataTable(), ['id=?' => $id]);
250  $this->_options['infinite_loop_flag'] = false;
251  return $result;
252  }
253  return false;
254  }
255 
273  public function clean($mode = \Zend_Cache::CLEANING_MODE_ALL, $tags = [])
274  {
275  if (!$this->_options['infinite_loop_flag']) {
276  $this->_options['infinite_loop_flag'] = true;
277  $connection = $this->_getConnection();
278  switch ($mode) {
279  case \Zend_Cache::CLEANING_MODE_ALL:
280  $result = $this->cleanAll($connection);
281  break;
282  case \Zend_Cache::CLEANING_MODE_OLD:
283  $result = $this->cleanOld($connection);
284  break;
285  case \Zend_Cache::CLEANING_MODE_MATCHING_TAG:
286  case \Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG:
287  case \Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG:
288  $result = $this->_cleanByTags($mode, $tags);
289  break;
290  default:
291  \Zend_Cache::throwException('Invalid mode for clean() method');
292  break;
293  }
294  $this->_options['infinite_loop_flag'] = false;
295  }
296 
297  return $result;
298  }
299 
305  public function getIds()
306  {
307  if ($this->_options['store_data']) {
308  $select = $this->_getConnection()->select()->from($this->_getDataTable(), 'id');
309  return $this->_getConnection()->fetchCol($select);
310  } else {
311  return [];
312  }
313  }
314 
320  public function getTags()
321  {
322  $select = $this->_getConnection()->select()->from($this->_getTagsTable(), 'tag')->distinct(true);
323  return $this->_getConnection()->fetchCol($select);
324  }
325 
334  public function getIdsMatchingTags($tags = [])
335  {
336  $select = $this->_getConnection()->select()->from(
337  $this->_getTagsTable(),
338  'cache_id'
339  )->distinct(
340  true
341  )->where(
342  'tag IN(?)',
343  $tags
344  )->group(
345  'cache_id'
346  )->having(
347  'COUNT(cache_id)=' . count($tags)
348  );
349  return $this->_getConnection()->fetchCol($select);
350  }
351 
360  public function getIdsNotMatchingTags($tags = [])
361  {
362  return array_diff($this->getIds(), $this->getIdsMatchingAnyTags($tags));
363  }
364 
373  public function getIdsMatchingAnyTags($tags = [])
374  {
375  $select = $this->_getConnection()->select()->from(
376  $this->_getTagsTable(),
377  'cache_id'
378  )->distinct(
379  true
380  )->where(
381  'tag IN(?)',
382  $tags
383  );
384  return $this->_getConnection()->fetchCol($select);
385  }
386 
392  public function getFillingPercentage()
393  {
394  return 1;
395  }
396 
408  public function getMetadatas($id)
409  {
410  $select = $this->_getConnection()->select()->from($this->_getTagsTable(), 'tag')->where('cache_id=?', $id);
411  $tags = $this->_getConnection()->fetchCol($select);
412 
413  $select = $this->_getConnection()->select()->from($this->_getDataTable())->where('id=?', $id);
414  $data = $this->_getConnection()->fetchRow($select);
415  $res = false;
416  if ($data) {
417  $res = ['expire' => $data['expire_time'], 'mtime' => $data['update_time'], 'tags' => $tags];
418  }
419  return $res;
420  }
421 
429  public function touch($id, $extraLifetime)
430  {
431  if ($this->_options['store_data']) {
432  return $this->_getConnection()->update(
433  $this->_getDataTable(),
434  ['expire_time' => new \Zend_Db_Expr('expire_time+' . $extraLifetime)],
435  ['id=?' => $id, 'expire_time = 0 OR expire_time>' => time()]
436  );
437  } else {
438  return true;
439  }
440  }
441 
456  public function getCapabilities()
457  {
458  return [
459  'automatic_cleaning' => true,
460  'tags' => true,
461  'expired_read' => true,
462  'priority' => false,
463  'infinite_lifetime' => true,
464  'get_list' => true
465  ];
466  }
467 
475  protected function _saveTags($id, $tags)
476  {
477  if (!is_array($tags)) {
478  $tags = [$tags];
479  }
480  if (empty($tags)) {
481  return true;
482  }
483 
484  $connection = $this->_getConnection();
485  $tagsTable = $this->_getTagsTable();
486  $select = $connection->select()->from($tagsTable, 'tag')->where('cache_id=?', $id)->where('tag IN(?)', $tags);
487 
488  $existingTags = $connection->fetchCol($select);
489  $insertTags = array_diff($tags, $existingTags);
490  if (!empty($insertTags)) {
491  $query = 'INSERT IGNORE INTO ' . $tagsTable . ' (tag, cache_id) VALUES ';
492  $bind = [];
493  $lines = [];
494  foreach ($insertTags as $tag) {
495  $lines[] = '(?, ?)';
496  $bind[] = $tag;
497  $bind[] = $id;
498  }
499  $query .= implode(',', $lines);
500  $connection->query($query, $bind);
501  }
502  $result = true;
503  return $result;
504  }
505 
514  protected function _cleanByTags($mode, $tags)
515  {
516  if ($this->_options['store_data']) {
517  $connection = $this->_getConnection();
518  $select = $connection->select()->from($this->_getTagsTable(), 'cache_id');
519  switch ($mode) {
520  case \Zend_Cache::CLEANING_MODE_MATCHING_TAG:
521  $select->where('tag IN (?)', $tags)->group('cache_id')->having('COUNT(cache_id)=' . count($tags));
522  break;
523  case \Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG:
524  $select->where('tag NOT IN (?)', $tags);
525  break;
526  case \Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG:
527  $select->where('tag IN (?)', $tags);
528  break;
529  default:
530  \Zend_Cache::throwException('Invalid mode for _cleanByTags() method');
531  break;
532  }
533 
534  $result = true;
535  $ids = [];
536  $counter = 0;
537  $stmt = $connection->query($select);
538  while ($row = $stmt->fetch()) {
539  $ids[] = $row['cache_id'];
540  $counter++;
541  if ($counter > 100) {
542  $result = $result && $connection->delete($this->_getDataTable(), ['id IN (?)' => $ids]);
543  $ids = [];
544  $counter = 0;
545  }
546  }
547  if (!empty($ids)) {
548  $result = $result && $connection->delete($this->_getDataTable(), ['id IN (?)' => $ids]);
549  }
550  return $result;
551  } else {
552  return true;
553  }
554  }
555 
562  private function cleanAll(\Magento\Framework\DB\Adapter\AdapterInterface $connection)
563  {
564  if ($this->_options['store_data']) {
565  $result = $connection->query('TRUNCATE TABLE ' . $this->_getDataTable());
566  } else {
567  $result = true;
568  }
569  $result = $result && $connection->query('TRUNCATE TABLE ' . $this->_getTagsTable());
570  return $result;
571  }
572 
579  private function cleanOld(\Magento\Framework\DB\Adapter\AdapterInterface $connection)
580  {
581  if ($this->_options['store_data']) {
582  $result = $connection->delete(
583  $this->_getDataTable(),
584  ['expire_time> ?' => 0, 'expire_time<= ?' => time()]
585  );
586  return $result;
587  } else {
588  $result = true;
589  return $result;
590  }
591  }
592 }
$id
Definition: fieldset.phtml:14
setOption($name, $value)
Definition: Backend.php:101
save($data, $id, $tags=[], $specificLifetime=false)
Definition: Database.php:205
if($exist=($block->getProductCollection() && $block->getProductCollection() ->getSize())) $mode
Definition: grid.phtml:15
const CLEANING_MODE_ALL
Definition: Cache.php:72
static throwException($msg, Exception $e=null)
Definition: Cache.php:205
clean($mode=\Zend_Cache::CLEANING_MODE_ALL, $tags=[])
Definition: Database.php:273
load($id, $doNotTestCacheValidity=false)
Definition: Database.php:146
$connection
Definition: bulk.php:13
getLifetime($specificLifetime)
Definition: Backend.php:143