1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25:
26:
27:
28: 29: 30: 31: 32: 33: 34:
35: class Mage_CatalogIndex_Model_Resource_Indexer extends Mage_Core_Model_Resource_Db_Abstract
36: {
37: 38: 39: 40: 41:
42: protected $_insertData = array();
43:
44: 45: 46: 47: 48:
49: protected $_tableFields = array();
50:
51: 52: 53: 54: 55:
56: protected $_attributeCache = array();
57:
58: 59: 60: 61:
62: protected function _construct()
63: {
64: $this->_init('catalog/product', 'entity_id');
65: }
66:
67: 68: 69: 70: 71: 72:
73: protected function _loadAttribute($id)
74: {
75: if (!isset($this->_attributeCache[$id])) {
76: $this->_attributeCache[$id] = Mage::getModel('eav/entity_attribute')->load($id);
77: }
78:
79: return $this->_attributeCache[$id];
80: }
81:
82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92:
93: public function clear($eav = true, $price = true, $minimal = true, $finalPrice = true, $tierPrice = true,
94: $products = null, $store = null)
95: {
96: $suffix = '';
97: $priceSuffix = '';
98: $tables = array('eav'=>'catalogindex/eav', 'price'=>'catalogindex/price');
99: if (!is_null($products)) {
100: if ($products instanceof Mage_Catalog_Model_Product) {
101: $products = $products->getId();
102: } elseif ($products instanceof Mage_Catalog_Model_Product_Condition_Interface) {
103: $suffix = 'entity_id IN ('.$products->getIdsSelect($this->_getWriteAdapter())->__toString().')';
104: }
105: else if (!is_numeric($products) && !is_array($products)) {
106: Mage::throwException('Invalid products supplied for indexing');
107: }
108: if (empty($suffix)) {
109: $suffix = $this->_getWriteAdapter()->quoteInto('entity_id in (?)', $products);
110: }
111: }
112: if (!is_null($store)) {
113: $websiteIds = array();
114:
115: if ($store instanceof Mage_Core_Model_Store) {
116: $store = $store->getId();
117: $websiteIds[] = Mage::app()->getStore($store)->getWebsiteId();
118: } else if ($store instanceof Mage_Core_Model_Resource_Store_Collection) {
119: $store = $store->getAllIds();
120: foreach ($store as $one) {
121: $websiteIds[] = Mage::app()->getStore($one)->getWebsiteId();
122: }
123: } else if (is_array($store)) {
124: $resultStores = array();
125: foreach ($store as $s) {
126: if ($s instanceof Mage_Core_Model_Store) {
127: $resultStores[] = $s->getId();
128: $websiteIds[] = $s->getWebsiteId();
129: } elseif (is_numeric($s)) {
130: $websiteIds[] = Mage::app()->getStore($s)->getWebsiteId();
131: $resultStores[] = $s;
132: }
133: }
134: $store = $resultStores;
135: }
136:
137: if ($suffix) {
138: $suffix .= ' AND ';
139: }
140:
141: $priceSuffix = $suffix . $this->_getWriteAdapter()->quoteInto('website_id in (?)', $websiteIds);
142: $suffix .= $this->_getWriteAdapter()->quoteInto('store_id in (?)', $store);
143:
144: }
145:
146: if ($tierPrice) {
147: $tables['tierPrice'] = 'catalogindex/price';
148: $tierPrice = array(Mage::getSingleton('eav/entity_attribute')->getIdByCode(Mage_Catalog_Model_Product::ENTITY, 'tier_price'));
149: }
150: if ($finalPrice) {
151: $tables['finalPrice'] = 'catalogindex/price';
152: $tierPrice = array(Mage::getSingleton('eav/entity_attribute')->getIdByCode(Mage_Catalog_Model_Product::ENTITY, 'price'));
153: }
154: if ($minimal) {
155: $tables['minimal'] = 'catalogindex/minimal_price';
156: }
157:
158:
159: foreach ($tables as $variable=>$table) {
160: $variable = $$variable;
161: $suffixToInsert = $suffix;
162: if (in_array($table, $this->_getPriceTables())) {
163: $suffixToInsert = $priceSuffix;
164: }
165:
166: if ($variable === true) {
167: $query = "DELETE FROM {$this->getTable($table)} ";
168: if ($suffixToInsert) {
169: $query .= "WHERE {$suffixToInsert}";
170: }
171:
172: $this->_getWriteAdapter()->query($query);
173: } else if (is_array($variable) && count($variable)) {
174: $query = "DELETE FROM {$this->getTable($table)} WHERE ";
175: $query .= $this->_getWriteAdapter()->quoteInto("attribute_id in (?)", $variable);
176: if ($suffixToInsert) {
177: $query .= " AND {$suffixToInsert}";
178: }
179:
180: $this->_getWriteAdapter()->query($query);
181: }
182: }
183: }
184:
185: 186: 187: 188: 189:
190: protected function _getPriceTables()
191: {
192: return array('catalogindex/price', 'catalogindex/minimal_price');
193: }
194:
195: 196: 197: 198: 199: 200: 201: 202:
203: public function reindexTiers($products, $store, $forcedId = null)
204: {
205: $websiteId = $store->getWebsiteId();
206: $attribute = Mage::getSingleton('eav/entity_attribute')->getIdByCode(Mage_Catalog_Model_Product::ENTITY, 'tier_price');
207: $this->_beginInsert(
208: 'catalogindex/price',
209: array('entity_id', 'attribute_id', 'value', 'website_id', 'customer_group_id', 'qty')
210: );
211:
212: 213: 214: 215: 216: 217:
218: $products = Mage::getSingleton('catalogindex/retreiver')->assignProductTypes($products);
219: if (is_null($forcedId)) {
220: foreach ($products as $type=>$typeIds) {
221: $retreiver = Mage::getSingleton('catalogindex/retreiver')->getRetreiver($type);
222: if ($retreiver->areChildrenIndexable(Mage_CatalogIndex_Model_Retreiver::CHILDREN_FOR_TIERS)) {
223: foreach ($typeIds as $id) {
224: $children = $retreiver->getChildProductIds($store, $id);
225: if ($children) {
226: $this->reindexTiers($children, $store, $id);
227: }
228: }
229: }
230: }
231: }
232:
233: $attributeIndex = $this->getTierData($products, $store);
234: foreach ($attributeIndex as $index) {
235: $type = $index['type_id'];
236: $id = (is_null($forcedId) ? $index['entity_id'] : $forcedId);
237: if ($id && $index['value']) {
238: if ($index['all_groups'] == 1) {
239: foreach (Mage::getSingleton('catalogindex/retreiver')->getCustomerGroups() as $group) {
240: $this->_insert('catalogindex/price', array(
241: $id,
242: $attribute,
243: $index['value'],
244: $websiteId,
245: (int) $group->getId(),
246: (int) $index['qty']
247: ));
248: }
249: } else {
250: $this->_insert('catalogindex/price', array(
251: $id,
252: $attribute,
253: $index['value'],
254: $websiteId,
255: (int) $index['customer_group_id'],
256: (int) $index['qty']
257: ));
258: }
259: }
260: }
261: $this->_commitInsert('catalogindex/price');
262: return $this;
263: }
264:
265: 266: 267: 268: 269: 270: 271: 272:
273: public function reindexPrices($products, $attributeIds, $store)
274: {
275: $this->reindexAttributes($products, $attributeIds, $store, null, 'catalogindex/price', true);
276: return $this;
277: }
278:
279: 280: 281: 282: 283: 284: 285: 286:
287: public function reindexFinalPrices($products, $store, $forcedId = null)
288: {
289: $priceAttribute = Mage::getSingleton('eav/entity_attribute')->getIdByCode(Mage_Catalog_Model_Product::ENTITY, 'price');
290: $this->_beginInsert('catalogindex/price', array(
291: 'entity_id',
292: 'website_id',
293: 'customer_group_id',
294: 'value',
295: 'attribute_id',
296: 'tax_class_id'
297: ));
298:
299: $productTypes = Mage::getSingleton('catalogindex/retreiver')->assignProductTypes($products);
300: foreach ($productTypes as $type=>$products) {
301: $retreiver = Mage::getSingleton('catalogindex/retreiver')->getRetreiver($type);
302: foreach ($products as $product) {
303: if (is_null($forcedId)) {
304: if ($retreiver->areChildrenIndexable(Mage_CatalogIndex_Model_Retreiver::CHILDREN_FOR_PRICES)) {
305: $children = $retreiver->getChildProductIds($store, $product);
306: if ($children) {
307: $this->reindexFinalPrices($children, $store, $product);
308: }
309: }
310: }
311: foreach (Mage::getSingleton('catalogindex/retreiver')->getCustomerGroups() as $group) {
312: $finalPrice = $retreiver->getFinalPrice($product, $store, $group);
313: $taxClassId = $retreiver->getTaxClassId($product, $store);
314: $id = $product;
315: if (!is_null($forcedId)) {
316: $id = $forcedId;
317: }
318:
319: if (false !== $finalPrice && false !== $id && false !== $priceAttribute) {
320: $this->_insert('catalogindex/price', array(
321: $id,
322: $store->getWebsiteId(),
323: $group->getId(),
324: $finalPrice,
325: $priceAttribute,
326: $taxClassId
327: ));
328: }
329: }
330: }
331: }
332: $this->_commitInsert('catalogindex/price');
333: return $this;
334: }
335:
336: 337: 338: 339: 340: 341: 342:
343: public function reindexMinimalPrices($products, $store)
344: {
345: $this->_beginInsert('catalogindex/minimal_price', array(
346: 'website_id',
347: 'entity_id',
348: 'customer_group_id',
349: 'value',
350: 'tax_class_id'
351: ));
352: $this->clear(false, false, true, false, false, $products, $store);
353: $products = Mage::getSingleton('catalogindex/retreiver')->assignProductTypes($products);
354:
355: foreach ($products as $type=>$typeIds) {
356: $retreiver = Mage::getSingleton('catalogindex/retreiver')->getRetreiver($type);
357:
358: foreach ($typeIds as $id) {
359: $minimal = array();
360: if ($retreiver->areChildrenIndexable(Mage_CatalogIndex_Model_Retreiver::CHILDREN_FOR_PRICES)) {
361: $children = $retreiver->getChildProductIds($store, $id);
362: if ($children) {
363: $minimal = $this->getMinimalPrice(array($type=>$children), $store);
364: }
365: } else {
366: $minimal = $this->getMinimalPrice(array($type=>array($id)), $store);
367: }
368:
369: if (is_array($minimal)) {
370: foreach ($minimal as $price) {
371: if (!isset($price['tax_class_id'])) {
372: $price['tax_class_id'] = 0;
373: }
374: $this->_insert('catalogindex/minimal_price', array(
375: $store->getWebsiteId(),
376: $id,
377: $price['customer_group_id'],
378: $price['minimal_value'],
379: $price['tax_class_id']
380: ));
381: }
382: }
383: }
384: }
385:
386: $this->_commitInsert('catalogindex/minimal_price');
387: return $this;
388: }
389:
390: 391: 392: 393: 394: 395: 396: 397: 398: 399: 400:
401: public function reindexAttributes($products, $attributeIds, $store, $forcedId = null, $table = 'catalogindex/eav',
402: $storeIsWebsite = false)
403: {
404: $storeField = 'store_id';
405: $websiteId = null;
406: if ($storeIsWebsite) {
407: $storeField = 'website_id';
408: if ($store instanceof Mage_Core_Model_Store) {
409: $websiteId = $store->getWebsiteId();
410: } else {
411: $websiteId = Mage::app()->getStore($store)->getWebsiteId();
412: }
413: }
414:
415: $this->_beginInsert($table, array('entity_id', 'attribute_id', 'value', $storeField));
416:
417: $products = Mage::getSingleton('catalogindex/retreiver')->assignProductTypes($products);
418:
419: if (is_null($forcedId)) {
420: foreach ($products as $type=>$typeIds) {
421: $retreiver = Mage::getSingleton('catalogindex/retreiver')->getRetreiver($type);
422: if ($retreiver->areChildrenIndexable(Mage_CatalogIndex_Model_Retreiver::CHILDREN_FOR_ATTRIBUTES)) {
423: foreach ($typeIds as $id) {
424: $children = $retreiver->getChildProductIds($store, $id);
425: if ($children) {
426: $this->reindexAttributes($children, $attributeIds, $store, $id, $table, $storeIsWebsite);
427: }
428: }
429: }
430: }
431: }
432:
433: $attributeIndex = $this->getProductData($products, $attributeIds, $store);
434: foreach ($attributeIndex as $index) {
435: $type = $index['type_id'];
436: $id = (is_null($forcedId) ? $index['entity_id'] : $forcedId);
437:
438: if ($id && $index['attribute_id'] && isset($index['value'])) {
439: $attribute = $this->_loadAttribute($index['attribute_id']);
440: if ($attribute->getFrontendInput() == 'multiselect') {
441: $index['value'] = explode(',', $index['value']);
442: }
443:
444: if (is_array($index['value'])) {
445: foreach ($index['value'] as $value) {
446: $this->_insert($table, array(
447: $id,
448: $index['attribute_id'],
449: $value,
450: (is_null($websiteId) ? $store->getId() : $websiteId)
451: ));
452: }
453: } else {
454: $this->_insert($table, array(
455: $id,
456: $index['attribute_id'],
457: $index['value'],
458: (is_null($websiteId) ? $store->getId() : $websiteId)
459: ));
460: }
461: }
462: }
463:
464: $this->_commitInsert($table);
465: return $this;
466: }
467:
468: 469: 470: 471: 472: 473: 474:
475: public function getTierData($products, $store)
476: {
477: $result = array();
478: foreach ($products as $type=>$typeIds) {
479: $retreiver = Mage::getSingleton('catalogindex/retreiver')->getRetreiver($type);
480: $byType = $retreiver->getTierPrices($typeIds, $store);
481: if ($byType) {
482: $result = array_merge($result, $byType);
483: }
484: }
485: return $result;
486: }
487:
488: 489: 490: 491: 492: 493: 494:
495: public function getMinimalPrice($products, $store)
496: {
497: $result = array();
498: foreach ($products as $type=>$typeIds) {
499: $retreiver = Mage::getSingleton('catalogindex/retreiver')->getRetreiver($type);
500: $byType = $retreiver->getMinimalPrice($typeIds, $store);
501: if ($byType) {
502: $result = array_merge($result, $byType);
503: }
504: }
505: return $result;
506: }
507:
508: 509: 510: 511: 512: 513: 514: 515:
516: public function getProductData($products, $attributeIds, $store)
517: {
518: $result = array();
519: foreach ($products as $type=>$typeIds) {
520: $retreiver = Mage::getSingleton('catalogindex/retreiver')->getRetreiver($type);
521: $byType = $retreiver->getAttributeData($typeIds, $attributeIds, $store);
522: if ($byType) {
523: $result = array_merge($result, $byType);
524: }
525: }
526: return $result;
527: }
528:
529: 530: 531: 532: 533: 534: 535:
536: protected function _beginInsert($table, $fields)
537: {
538: $this->_tableFields[$table] = $fields;
539: return $this;
540: }
541:
542: 543: 544: 545: 546: 547: 548:
549: protected function _commitInsert($table, $forced = true)
550: {
551: if (isset($this->_insertData[$table]) && count($this->_insertData[$table]) && ($forced || count($this->_insertData[$table]) >= 100)) {
552: $query = 'REPLACE INTO ' . $this->getTable($table) . ' (' . implode(', ', $this->_tableFields[$table]) . ') VALUES ';
553: $separator = '';
554: foreach ($this->_insertData[$table] as $row) {
555: $rowString = $this->_getWriteAdapter()->quoteInto('(?)', $row);
556: $query .= $separator . $rowString;
557: $separator = ', ';
558: }
559: $this->_getWriteAdapter()->query($query);
560: $this->_insertData[$table] = array();
561: }
562: return $this;
563: }
564:
565: 566: 567: 568: 569: 570: 571:
572: protected function _insert($table, $data)
573: {
574: $this->_insertData[$table][] = $data;
575: $this->_commitInsert($table, false);
576: return $this;
577: }
578:
579: 580: 581: 582: 583: 584:
585: public function prepareCatalogProductFlatColumns(Varien_Object $object)
586: {
587: $columns = $object->getColumns();
588:
589: foreach (Mage::getSingleton('catalogindex/retreiver')->getCustomerGroups() as $group) {
590: $columnName = 'display_price_group_' . $group->getId();
591: $columns[$columnName] = array(
592: 'type' => 'decimal(12,4)',
593: 'unsigned' => false,
594: 'nullable' => true,
595: 'default' => null,
596: 'extra' => null,
597: 'comment' => $columnName . ' column'
598: );
599: }
600:
601: $object->setColumns($columns);
602:
603: return $this;
604: }
605:
606: 607: 608: 609: 610: 611:
612: public function prepareCatalogProductFlatIndexes(Varien_Object $object)
613: {
614: $indexes = $object->getIndexes();
615:
616: foreach (Mage::getSingleton('catalogindex/retreiver')->getCustomerGroups() as $group) {
617: $columnName = 'display_price_group_' . $group->getId();
618: $indexName = 'IDX_DISPLAY_PRICE_GROUP_' . $group->getId();
619: $indexes[$indexName] = array(
620: 'type' => 'index',
621: 'fields' => array($columnName)
622: );
623: }
624:
625: $object->setIndexes($indexes);
626:
627: return $this;
628: }
629:
630: 631: 632: 633: 634: 635: 636: 637:
638: public function updateCatalogProductFlat($storeId, $productIds = null, $tableName = null)
639: {
640: if (is_null($tableName)) {
641: $tableName = $this->getTable('catalog/product_flat') . '_' . $storeId;
642: }
643: $addChildData = Mage::helper('catalog/product_flat')->isAddChildData();
644:
645: $priceAttribute = Mage::getSingleton('eav/entity_attribute')
646: ->getIdByCode(Mage_Catalog_Model_Product::ENTITY, 'price');
647: $websiteId = Mage::app()->getStore($storeId)->getWebsiteId();
648:
649: foreach (Mage::getSingleton('catalogindex/retreiver')->getCustomerGroups() as $group) {
650: $columnName = 'display_price_group_' . $group->getId();
651:
652: 653: 654:
655: $select = $this->_getWriteAdapter()->select()
656: ->join(
657: array('p' => $this->getTable('catalogindex/price')),
658: "`e`.`entity_id`=`p`.`entity_id`"
659: . " AND `p`.`attribute_id`={$priceAttribute}"
660: . " AND `p`.`customer_group_id`={$group->getId()}"
661: . " AND `p`.`website_id`={$websiteId}",
662: array($columnName => 'value'));
663: if ($addChildData) {
664: $select->where('e.is_child=?', 0);
665: }
666:
667: if ($productIds instanceof Mage_Catalog_Model_Product_Condition_Interface) {
668: $select->where('e.entity_id IN ('.$productIds->getIdsSelect($this->_getWriteAdapter())->__toString().')');
669: } elseif (!is_null($productIds)) {
670: $select->where("e.entity_id IN(?)", $productIds);
671: }
672:
673: $sql = $select->crossUpdateFromSelect(array('e' => $tableName));
674: $this->_getWriteAdapter()->query($sql);
675:
676: if ($addChildData) {
677: 678: 679:
680: $select = $this->_getWriteAdapter()->select()
681: ->join(
682: array('p' => $this->getTable('catalogindex/price')),
683: "`e`.`child_id`=`p`.`entity_id`"
684: . " AND `p`.`attribute_id`={$priceAttribute}"
685: . " AND `p`.`customer_group_id`={$group->getId()}"
686: . " AND `p`.`website_id`={$websiteId}",
687: array($columnName => 'value'))
688: ->where('e.is_child=?', 1);
689:
690: if ($productIds instanceof Mage_Catalog_Model_Product_Condition_Interface) {
691: $select->where('e.child_id IN ('.$productIds->getIdsSelect($this->_getWriteAdapter())->__toString().')');
692: } elseif (!is_null($productIds)) {
693: $select->where("e.child_id IN(?)", $productIds);
694: }
695:
696: $sql = $select->crossUpdateFromSelect(array('e' => $tableName));
697: $this->_getWriteAdapter()->query($sql);
698: }
699:
700: }
701:
702: return $this;
703: }
704: }
705: