Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
DefaultPrice.php
Go to the documentation of this file.
1 <?php
7 
10 
24 {
30  protected $_typeId;
31 
37  protected $_isComposite = false;
38 
44  protected $moduleManager;
45 
51  protected $_eventManager = null;
52 
56  private $hasEntity = null;
57 
61  private $indexTableStructureFactory;
62 
66  private $priceModifiers = [];
67 
80  public function __construct(
81  \Magento\Framework\Model\ResourceModel\Db\Context $context,
82  \Magento\Framework\Indexer\Table\StrategyInterface $tableStrategy,
83  \Magento\Eav\Model\Config $eavConfig,
84  \Magento\Framework\Event\ManagerInterface $eventManager,
85  \Magento\Framework\Module\Manager $moduleManager,
86  $connectionName = null,
87  IndexTableStructureFactory $indexTableStructureFactory = null,
88  array $priceModifiers = []
89  ) {
90  $this->_eventManager = $eventManager;
91  $this->moduleManager = $moduleManager;
92  parent::__construct($context, $tableStrategy, $eavConfig, $connectionName);
93 
94  $this->indexTableStructureFactory = $indexTableStructureFactory ?:
95  \Magento\Framework\App\ObjectManager::getInstance()->get(IndexTableStructureFactory::class);
96  foreach ($priceModifiers as $priceModifier) {
97  if (!($priceModifier instanceof PriceModifierInterface)) {
98  throw new \InvalidArgumentException(
99  'Argument \'priceModifiers\' must be of the type ' . PriceModifierInterface::class . '[]'
100  );
101  }
102 
103  $this->priceModifiers[] = $priceModifier;
104  }
105  }
106 
112  public function getTableStrategy()
113  {
114  return $this->tableStrategy;
115  }
116 
122  protected function _construct()
123  {
124  $this->_init('catalog_product_index_price', 'entity_id');
125  }
126 
133  public function setTypeId($typeCode)
134  {
135  $this->_typeId = $typeCode;
136  return $this;
137  }
138 
145  public function getTypeId()
146  {
147  if ($this->_typeId === null) {
148  throw new \Magento\Framework\Exception\LocalizedException(
149  __('A product type is not defined for the indexer.')
150  );
151  }
152  return $this->_typeId;
153  }
154 
161  public function setIsComposite($flag)
162  {
163  $this->_isComposite = (bool)$flag;
164  return $this;
165  }
166 
173  public function getIsComposite()
174  {
175  return $this->_isComposite;
176  }
177 
184  public function reindexAll()
185  {
186  $this->tableStrategy->setUseIdxTable(true);
187  $this->beginTransaction();
188  try {
189  $this->reindex();
190  $this->commit();
191  } catch (\Exception $e) {
192  $this->rollBack();
193  throw $e;
194  }
195  return $this;
196  }
197 
204  public function reindexEntity($entityIds)
205  {
206  $this->reindex($entityIds);
207  return $this;
208  }
209 
214  protected function reindex($entityIds = null)
215  {
216  if ($this->hasEntity() || !empty($entityIds)) {
217  $this->_prepareFinalPriceData($entityIds);
218  $this->_applyCustomOption();
220  }
221  return $this;
222  }
223 
231  protected function _getDefaultFinalPriceTable()
232  {
233  return $this->tableStrategy->getTableName('catalog_product_index_price_final');
234  }
235 
243  protected function _prepareDefaultFinalPriceTable()
244  {
245  $this->getConnection()->delete($this->_getDefaultFinalPriceTable());
246  return $this;
247  }
248 
254  private function prepareFinalPriceTable()
255  {
257  $this->getConnection()->delete($tableName);
258 
259  $finalPriceTable = $this->indexTableStructureFactory->create([
260  'tableName' => $tableName,
261  'entityField' => 'entity_id',
262  'customerGroupField' => 'customer_group_id',
263  'websiteField' => 'website_id',
264  'taxClassField' => 'tax_class_id',
265  'originalPriceField' => 'orig_price',
266  'finalPriceField' => 'price',
267  'minPriceField' => 'min_price',
268  'maxPriceField' => 'max_price',
269  'tierPriceField' => 'tier_price',
270  ]);
271 
272  return $finalPriceTable;
273  }
274 
280  protected function _getWebsiteDateTable()
281  {
282  return $this->getTable('catalog_product_index_website');
283  }
284 
292  protected function _prepareFinalPriceData($entityIds = null)
293  {
294  return $this->prepareFinalPriceDataForType($entityIds, $this->getTypeId());
295  }
296 
305  protected function prepareFinalPriceDataForType($entityIds, $type)
306  {
307  $finalPriceTable = $this->prepareFinalPriceTable();
308 
309  $select = $this->getSelect($entityIds, $type);
310  $query = $select->insertFromSelect($finalPriceTable->getTableName(), [], false);
311  $this->getConnection()->query($query);
312 
313  $this->modifyPriceIndex($finalPriceTable);
314 
315  return $this;
316  }
317 
330  protected function getSelect($entityIds = null, $type = null)
331  {
332  $metadata = $this->getMetadataPool()->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class);
333  $linkField = $metadata->getLinkField();
334  $connection = $this->getConnection();
335  $select = $connection->select()->from(
336  ['e' => $this->getTable('catalog_product_entity')],
337  ['entity_id']
338  )->join(
339  ['cg' => $this->getTable('customer_group')],
340  '',
341  ['customer_group_id']
342  )->join(
343  ['cw' => $this->getTable('store_website')],
344  '',
345  ['website_id']
346  )->join(
347  ['cwd' => $this->_getWebsiteDateTable()],
348  'cw.website_id = cwd.website_id',
349  []
350  )->join(
351  ['csg' => $this->getTable('store_group')],
352  'csg.website_id = cw.website_id AND cw.default_group_id = csg.group_id',
353  []
354  )->join(
355  ['cs' => $this->getTable('store')],
356  'csg.default_store_id = cs.store_id AND cs.store_id != 0',
357  []
358  )->join(
359  ['pw' => $this->getTable('catalog_product_website')],
360  'pw.product_id = e.entity_id AND pw.website_id = cw.website_id',
361  []
362  )->joinLeft(
363  // we need this only for BCC in case someone expects table `tp` to be present in query
364  ['tp' => $this->getTable('catalog_product_index_tier_price')],
365  'tp.entity_id = e.entity_id AND tp.customer_group_id = cg.customer_group_id' .
366  ' AND tp.website_id = pw.website_id',
367  []
368  )->joinLeft(
369  // calculate tier price specified as Website = `All Websites` and Customer Group = `Specific Customer Group`
370  ['tier_price_1' => $this->getTable('catalog_product_entity_tier_price')],
371  'tier_price_1.' . $linkField . ' = e.' . $linkField . ' AND tier_price_1.all_groups = 0' .
372  ' AND tier_price_1.customer_group_id = cg.customer_group_id AND tier_price_1.qty = 1' .
373  ' AND tier_price_1.website_id = 0',
374  []
375  )->joinLeft(
376  // calculate tier price specified as Website = `Specific Website`
377  //and Customer Group = `Specific Customer Group`
378  ['tier_price_2' => $this->getTable('catalog_product_entity_tier_price')],
379  'tier_price_2.' . $linkField . ' = e.' . $linkField . ' AND tier_price_2.all_groups = 0' .
380  ' AND tier_price_2.customer_group_id = cg.customer_group_id AND tier_price_2.qty = 1' .
381  ' AND tier_price_2.website_id = cw.website_id',
382  []
383  )->joinLeft(
384  // calculate tier price specified as Website = `All Websites` and Customer Group = `ALL GROUPS`
385  ['tier_price_3' => $this->getTable('catalog_product_entity_tier_price')],
386  'tier_price_3.' . $linkField . ' = e.' . $linkField . ' AND tier_price_3.all_groups = 1' .
387  ' AND tier_price_3.customer_group_id = 0 AND tier_price_3.qty = 1 AND tier_price_3.website_id = 0',
388  []
389  )->joinLeft(
390  // calculate tier price specified as Website = `Specific Website` and Customer Group = `ALL GROUPS`
391  ['tier_price_4' => $this->getTable('catalog_product_entity_tier_price')],
392  'tier_price_4.' . $linkField . ' = e.' . $linkField . ' AND tier_price_4.all_groups = 1' .
393  ' AND tier_price_4.customer_group_id = 0 AND tier_price_4.qty = 1' .
394  ' AND tier_price_4.website_id = cw.website_id',
395  []
396  );
397 
398  if ($type !== null) {
399  $select->where('e.type_id = ?', $type);
400  }
401 
402  // add enable products limitation
403  $statusCond = $connection->quoteInto(
404  '=?',
405  \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED
406  );
407  $this->_addAttributeToSelect(
408  $select,
409  'status',
410  'e.' . $linkField,
411  'cs.store_id',
412  $statusCond,
413  true
414  );
415  if ($this->moduleManager->isEnabled('Magento_Tax')) {
416  $taxClassId = $this->_addAttributeToSelect(
417  $select,
418  'tax_class_id',
419  'e.' . $linkField,
420  'cs.store_id'
421  );
422  } else {
423  $taxClassId = new \Zend_Db_Expr('0');
424  }
425  $select->columns(['tax_class_id' => $taxClassId]);
426 
427  $price = $this->_addAttributeToSelect(
428  $select,
429  'price',
430  'e.' . $linkField,
431  'cs.store_id'
432  );
433  $specialPrice = $this->_addAttributeToSelect(
434  $select,
435  'special_price',
436  'e.' . $linkField,
437  'cs.store_id'
438  );
439  $specialFrom = $this->_addAttributeToSelect(
440  $select,
441  'special_from_date',
442  'e.' . $linkField,
443  'cs.store_id'
444  );
445  $specialTo = $this->_addAttributeToSelect(
446  $select,
447  'special_to_date',
448  'e.' . $linkField,
449  'cs.store_id'
450  );
451  $currentDate = 'cwd.website_date';
452 
453  $maxUnsignedBigint = '~0';
454  $specialFromDate = $connection->getDatePartSql($specialFrom);
455  $specialToDate = $connection->getDatePartSql($specialTo);
456  $specialFromExpr = "{$specialFrom} IS NULL OR {$specialFromDate} <= {$currentDate}";
457  $specialToExpr = "{$specialTo} IS NULL OR {$specialToDate} >= {$currentDate}";
458  $specialPriceExpr = $connection->getCheckSql(
459  "{$specialPrice} IS NOT NULL AND ({$specialFromExpr}) AND ({$specialToExpr})",
460  $specialPrice,
461  $maxUnsignedBigint
462  );
463  $tierPrice = $this->getTotalTierPriceExpression($price);
464  $tierPriceExpr = $connection->getIfNullSql($tierPrice, $maxUnsignedBigint);
465  $finalPrice = $connection->getLeastSql([
466  $price,
467  $specialPriceExpr,
468  $tierPriceExpr,
469  ]);
470 
471  $select->columns(
472  [
473  'orig_price' => $connection->getIfNullSql($price, 0),
474  'price' => $connection->getIfNullSql($finalPrice, 0),
475  'min_price' => $connection->getIfNullSql($finalPrice, 0),
476  'max_price' => $connection->getIfNullSql($finalPrice, 0),
477  'tier_price' => $tierPrice,
478  'base_tier' => $tierPrice,
479  ]
480  );
481 
482  if ($entityIds !== null) {
483  $select->where('e.entity_id IN(?)', $entityIds);
484  }
485 
489  $this->_eventManager->dispatch(
490  'prepare_catalog_product_index_select',
491  [
492  'select' => $select,
493  'entity_field' => new \Zend_Db_Expr('e.entity_id'),
494  'website_field' => new \Zend_Db_Expr('cw.website_id'),
495  'store_field' => new \Zend_Db_Expr('cs.store_id'),
496  ]
497  );
498 
499  return $select;
500  }
501 
507  protected function _getCustomOptionAggregateTable()
508  {
509  return $this->tableStrategy->getTableName('catalog_product_index_price_opt_agr');
510  }
511 
517  protected function _getCustomOptionPriceTable()
518  {
519  return $this->tableStrategy->getTableName('catalog_product_index_price_opt');
520  }
521 
528  {
529  $this->getConnection()->delete($this->_getCustomOptionAggregateTable());
530  return $this;
531  }
532 
538  protected function _prepareCustomOptionPriceTable()
539  {
540  $this->getConnection()->delete($this->_getCustomOptionPriceTable());
541  return $this;
542  }
543 
550  private function modifyPriceIndex(IndexTableStructure $finalPriceTable) : void
551  {
552  foreach ($this->priceModifiers as $priceModifier) {
553  $priceModifier->modifyPrice($finalPriceTable);
554  }
555  }
556 
563  protected function _applyCustomOption()
564  {
565  $connection = $this->getConnection();
566  $finalPriceTable = $this->_getDefaultFinalPriceTable();
567  $coaTable = $this->_getCustomOptionAggregateTable();
568  $copTable = $this->_getCustomOptionPriceTable();
569  $metadata = $this->getMetadataPool()->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class);
570 
573 
574  $select = $connection->select()->from(
575  ['i' => $finalPriceTable],
576  ['entity_id', 'customer_group_id', 'website_id']
577  )->join(
578  ['e' => $this->getTable('catalog_product_entity')],
579  'e.entity_id = i.entity_id',
580  []
581  )->join(
582  ['cw' => $this->getTable('store_website')],
583  'cw.website_id = i.website_id',
584  []
585  )->join(
586  ['csg' => $this->getTable('store_group')],
587  'csg.group_id = cw.default_group_id',
588  []
589  )->join(
590  ['cs' => $this->getTable('store')],
591  'cs.store_id = csg.default_store_id',
592  []
593  )->join(
594  ['o' => $this->getTable('catalog_product_option')],
595  'o.product_id = e.' . $metadata->getLinkField(),
596  ['option_id']
597  )->join(
598  ['ot' => $this->getTable('catalog_product_option_type_value')],
599  'ot.option_id = o.option_id',
600  []
601  )->join(
602  ['otpd' => $this->getTable('catalog_product_option_type_price')],
603  'otpd.option_type_id = ot.option_type_id AND otpd.store_id = 0',
604  []
605  )->joinLeft(
606  ['otps' => $this->getTable('catalog_product_option_type_price')],
607  'otps.option_type_id = otpd.option_type_id AND otpd.store_id = cs.store_id',
608  []
609  )->group(
610  ['i.entity_id', 'i.customer_group_id', 'i.website_id', 'o.option_id']
611  );
612 
613  $optPriceType = $connection->getCheckSql('otps.option_type_price_id > 0', 'otps.price_type', 'otpd.price_type');
614  $optPriceValue = $connection->getCheckSql('otps.option_type_price_id > 0', 'otps.price', 'otpd.price');
615  $minPriceRound = new \Zend_Db_Expr("ROUND(i.price * ({$optPriceValue} / 100), 4)");
616  $minPriceExpr = $connection->getCheckSql("{$optPriceType} = 'fixed'", $optPriceValue, $minPriceRound);
617  $minPriceMin = new \Zend_Db_Expr("MIN({$minPriceExpr})");
618  $minPrice = $connection->getCheckSql("MIN(o.is_require) = 1", $minPriceMin, '0');
619 
620  $tierPriceRound = new \Zend_Db_Expr("ROUND(i.base_tier * ({$optPriceValue} / 100), 4)");
621  $tierPriceExpr = $connection->getCheckSql("{$optPriceType} = 'fixed'", $optPriceValue, $tierPriceRound);
622  $tierPriceMin = new \Zend_Db_Expr("MIN({$tierPriceExpr})");
623  $tierPriceValue = $connection->getCheckSql("MIN(o.is_require) > 0", $tierPriceMin, 0);
624  $tierPrice = $connection->getCheckSql("MIN(i.base_tier) IS NOT NULL", $tierPriceValue, "NULL");
625 
626  $maxPriceRound = new \Zend_Db_Expr("ROUND(i.price * ({$optPriceValue} / 100), 4)");
627  $maxPriceExpr = $connection->getCheckSql("{$optPriceType} = 'fixed'", $optPriceValue, $maxPriceRound);
628  $maxPrice = $connection->getCheckSql(
629  "(MIN(o.type)='radio' OR MIN(o.type)='drop_down')",
630  "MAX({$maxPriceExpr})",
631  "SUM({$maxPriceExpr})"
632  );
633 
634  $select->columns(
635  [
636  'min_price' => $minPrice,
637  'max_price' => $maxPrice,
638  'tier_price' => $tierPrice,
639  ]
640  );
641 
642  $query = $select->insertFromSelect($coaTable);
643  $connection->query($query);
644 
645  $select = $connection->select()->from(
646  ['i' => $finalPriceTable],
647  ['entity_id', 'customer_group_id', 'website_id']
648  )->join(
649  ['e' => $this->getTable('catalog_product_entity')],
650  'e.entity_id = i.entity_id',
651  []
652  )->join(
653  ['cw' => $this->getTable('store_website')],
654  'cw.website_id = i.website_id',
655  []
656  )->join(
657  ['csg' => $this->getTable('store_group')],
658  'csg.group_id = cw.default_group_id',
659  []
660  )->join(
661  ['cs' => $this->getTable('store')],
662  'cs.store_id = csg.default_store_id',
663  []
664  )->join(
665  ['o' => $this->getTable('catalog_product_option')],
666  'o.product_id = e.' . $metadata->getLinkField(),
667  ['option_id']
668  )->join(
669  ['opd' => $this->getTable('catalog_product_option_price')],
670  'opd.option_id = o.option_id AND opd.store_id = 0',
671  []
672  )->joinLeft(
673  ['ops' => $this->getTable('catalog_product_option_price')],
674  'ops.option_id = opd.option_id AND ops.store_id = cs.store_id',
675  []
676  );
677 
678  $optPriceType = $connection->getCheckSql('ops.option_price_id > 0', 'ops.price_type', 'opd.price_type');
679  $optPriceValue = $connection->getCheckSql('ops.option_price_id > 0', 'ops.price', 'opd.price');
680 
681  $minPriceRound = new \Zend_Db_Expr("ROUND(i.price * ({$optPriceValue} / 100), 4)");
682  $priceExpr = $connection->getCheckSql("{$optPriceType} = 'fixed'", $optPriceValue, $minPriceRound);
683  $minPrice = $connection->getCheckSql("{$priceExpr} > 0 AND o.is_require = 1", $priceExpr, 0);
684 
685  $maxPrice = $priceExpr;
686 
687  $tierPriceRound = new \Zend_Db_Expr("ROUND(i.base_tier * ({$optPriceValue} / 100), 4)");
688  $tierPriceExpr = $connection->getCheckSql("{$optPriceType} = 'fixed'", $optPriceValue, $tierPriceRound);
689  $tierPriceValue = $connection->getCheckSql("{$tierPriceExpr} > 0 AND o.is_require = 1", $tierPriceExpr, 0);
690  $tierPrice = $connection->getCheckSql("i.base_tier IS NOT NULL", $tierPriceValue, "NULL");
691 
692  $select->columns(
693  [
694  'min_price' => $minPrice,
695  'max_price' => $maxPrice,
696  'tier_price' => $tierPrice,
697  ]
698  );
699 
700  $query = $select->insertFromSelect($coaTable);
701  $connection->query($query);
702 
703  $select = $connection->select()->from(
704  [$coaTable],
705  [
706  'entity_id',
707  'customer_group_id',
708  'website_id',
709  'min_price' => 'SUM(min_price)',
710  'max_price' => 'SUM(max_price)',
711  'tier_price' => 'SUM(tier_price)',
712  ]
713  )->group(
714  ['entity_id', 'customer_group_id', 'website_id']
715  );
716  $query = $select->insertFromSelect($copTable);
717  $connection->query($query);
718 
719  $table = ['i' => $finalPriceTable];
720  $select = $connection->select()->join(
721  ['io' => $copTable],
722  'i.entity_id = io.entity_id AND i.customer_group_id = io.customer_group_id' .
723  ' AND i.website_id = io.website_id',
724  []
725  );
726  $select->columns(
727  [
728  'min_price' => new \Zend_Db_Expr('i.min_price + io.min_price'),
729  'max_price' => new \Zend_Db_Expr('i.max_price + io.max_price'),
730  'tier_price' => $connection->getCheckSql(
731  'i.tier_price IS NOT NULL',
732  'i.tier_price + io.tier_price',
733  'NULL'
734  ),
735  ]
736  );
737  $query = $select->crossUpdateFromSelect($table);
738  $connection->query($query);
739 
740  $connection->delete($coaTable);
741  $connection->delete($copTable);
742 
743  return $this;
744  }
745 
752  protected function _movePriceDataToIndexTable($entityIds = null)
753  {
754  $columns = [
755  'entity_id' => 'entity_id',
756  'customer_group_id' => 'customer_group_id',
757  'website_id' => 'website_id',
758  'tax_class_id' => 'tax_class_id',
759  'price' => 'orig_price',
760  'final_price' => 'price',
761  'min_price' => 'min_price',
762  'max_price' => 'max_price',
763  'tier_price' => 'tier_price',
764  ];
765 
766  $connection = $this->getConnection();
768  $select = $connection->select()->from($table, $columns);
769 
770  if ($entityIds !== null) {
771  $select->where('entity_id in (?)', count($entityIds) > 0 ? $entityIds : 0);
772  }
773 
774  $query = $select->insertFromSelect($this->getIdxTable(), [], false);
775  $connection->query($query);
776 
777  $connection->delete($table);
778 
779  return $this;
780  }
781 
787  protected function _getTierPriceIndexTable()
788  {
789  return $this->getTable('catalog_product_index_tier_price');
790  }
791 
799  public function getIdxTable($table = null)
800  {
801  return $this->tableStrategy->getTableName('catalog_product_index_price');
802  }
803 
807  protected function hasEntity()
808  {
809  if ($this->hasEntity === null) {
810  $reader = $this->getConnection();
811 
812  $select = $reader->select()->from(
813  [$this->getTable('catalog_product_entity')],
814  ['count(entity_id)']
815  )->where(
816  'type_id=?',
817  $this->getTypeId()
818  );
819  $this->hasEntity = (int)$reader->fetchOne($select) > 0;
820  }
821 
822  return $this->hasEntity;
823  }
824 
829  private function getTotalTierPriceExpression(\Zend_Db_Expr $priceExpression)
830  {
831  $maxUnsignedBigint = '~0';
832 
833  return $this->getConnection()->getCheckSql(
834  implode(
835  ' AND ',
836  [
837  'tier_price_1.value_id is NULL',
838  'tier_price_2.value_id is NULL',
839  'tier_price_3.value_id is NULL',
840  'tier_price_4.value_id is NULL'
841  ]
842  ),
843  'NULL',
844  $this->getConnection()->getLeastSql([
845  $this->getConnection()->getIfNullSql(
846  $this->getTierPriceExpressionForTable('tier_price_1', $priceExpression),
847  $maxUnsignedBigint
848  ),
849  $this->getConnection()->getIfNullSql(
850  $this->getTierPriceExpressionForTable('tier_price_2', $priceExpression),
851  $maxUnsignedBigint
852  ),
853  $this->getConnection()->getIfNullSql(
854  $this->getTierPriceExpressionForTable('tier_price_3', $priceExpression),
855  $maxUnsignedBigint
856  ),
857  $this->getConnection()->getIfNullSql(
858  $this->getTierPriceExpressionForTable('tier_price_4', $priceExpression),
859  $maxUnsignedBigint
860  ),
861  ])
862  );
863  }
864 
870  private function getTierPriceExpressionForTable($tableAlias, \Zend_Db_Expr $priceExpression)
871  {
872  return $this->getConnection()->getCheckSql(
873  sprintf('%s.value = 0', $tableAlias),
874  sprintf(
875  'ROUND(%s * (1 - ROUND(%s.percentage_value * cwd.rate, 4) / 100), 4)',
876  $priceExpression,
877  $tableAlias
878  ),
879  sprintf('ROUND(%s.value * cwd.rate, 4)', $tableAlias)
880  );
881  }
882 }
$tableName
Definition: trigger.php:13
_addAttributeToSelect($select, $attrCode, $entity, $store, $condition=null, $required=false)
__()
Definition: __.php:13
$price
$columns
Definition: default.phtml:15
$type
Definition: item.phtml:13
__construct(\Magento\Framework\Model\ResourceModel\Db\Context $context, \Magento\Framework\Indexer\Table\StrategyInterface $tableStrategy, \Magento\Eav\Model\Config $eavConfig, \Magento\Framework\Event\ManagerInterface $eventManager, \Magento\Framework\Module\Manager $moduleManager, $connectionName=null, IndexTableStructureFactory $indexTableStructureFactory=null, array $priceModifiers=[])
$connection
Definition: bulk.php:13
$table
Definition: trigger.php:14