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_CatalogInventory_Model_Resource_Indexer_Stock extends Mage_Catalog_Model_Resource_Product_Indexer_Abstract
36: {
37: 38: 39: 40: 41: 42:
43: protected $_indexers;
44:
45: 46: 47: 48: 49:
50: protected $_defaultIndexer = 'cataloginventory/indexer_stock_default';
51:
52: 53: 54: 55:
56: protected function _construct()
57: {
58: $this->_init('cataloginventory/stock_status', 'product_id');
59: }
60:
61: 62: 63: 64: 65: 66:
67: public function cataloginventoryStockItemSave(Mage_Index_Model_Event $event)
68: {
69: $data = $event->getNewData();
70: if (empty($data['product_id'])) {
71: return $this;
72: }
73:
74: $productId = $data['product_id'];
75: $this->reindexProducts($productId);
76:
77: return $this;
78: }
79:
80: 81: 82: 83: 84: 85:
86: public function reindexProducts($productIds)
87: {
88: $adapter = $this->_getWriteAdapter();
89: if (!is_array($productIds)) {
90: $productIds = array($productIds);
91: }
92: $parentIds = $this->getRelationsByChild($productIds);
93: if ($parentIds) {
94: $processIds = array_merge($parentIds, $productIds);
95: } else {
96: $processIds = $productIds;
97: }
98:
99:
100: $select = $adapter->select()
101: ->from($this->getTable('catalog/product'), array('entity_id', 'type_id'))
102: ->where('entity_id IN(?)', $processIds);
103: $pairs = $adapter->fetchPairs($select);
104:
105: $byType = array();
106: foreach ($pairs as $productId => $typeId) {
107: $byType[$typeId][$productId] = $productId;
108: }
109:
110: $adapter->beginTransaction();
111: try {
112: $indexers = $this->_getTypeIndexers();
113: foreach ($indexers as $indexer) {
114: if (isset($byType[$indexer->getTypeId()])) {
115: $indexer->reindexEntity($byType[$indexer->getTypeId()]);
116: }
117: }
118: } catch (Exception $e) {
119: $adapter->rollback();
120: throw $e;
121: }
122: $adapter->commit();
123:
124: return $this;
125: }
126:
127: 128: 129: 130: 131: 132:
133: public function catalogProductDelete(Mage_Index_Model_Event $event)
134: {
135: $data = $event->getNewData();
136: if (empty($data['reindex_stock_parent_ids'])) {
137: return $this;
138: }
139:
140: $adapter = $this->_getWriteAdapter();
141:
142: $parentIds = array();
143: foreach ($data['reindex_stock_parent_ids'] as $parentId => $parentType) {
144: $parentIds[$parentType][$parentId] = $parentId;
145: }
146:
147: $adapter->beginTransaction();
148: try {
149: foreach ($parentIds as $parentType => $entityIds) {
150: $this->_getIndexer($parentType)->reindexEntity($entityIds);
151: }
152: } catch (Exception $e) {
153: $adapter->rollback();
154: throw $e;
155: }
156:
157: $adapter->commit();
158:
159: return $this;
160: }
161:
162: 163: 164: 165: 166: 167:
168: public function catalogProductMassAction(Mage_Index_Model_Event $event)
169: {
170: $data = $event->getNewData();
171: if (empty($data['reindex_stock_product_ids'])) {
172: return $this;
173: }
174:
175: $adapter = $this->_getWriteAdapter();
176: $processIds = $data['reindex_stock_product_ids'];
177: $select = $adapter->select()
178: ->from($this->getTable('catalog/product'), 'COUNT(*)');
179: $pCount = $adapter->fetchOne($select);
180:
181:
182: if ($pCount * 0.3 < count($processIds)) {
183: return $this->reindexAll();
184: }
185:
186:
187: $select = $adapter->select()
188: ->from($this->getTable('catalog/product_relation'), 'COUNT(DISTINCT parent_id)')
189: ->where('child_id IN(?)', $processIds);
190: $aCount = $adapter->fetchOne($select);
191: $select = $adapter->select()
192: ->from($this->getTable('catalog/product_relation'), 'COUNT(DISTINCT child_id)')
193: ->where('parent_id IN(?)', $processIds);
194: $bCount = $adapter->fetchOne($select);
195:
196:
197: if ($pCount * 0.3 < count($processIds) + $aCount + $bCount) {
198: return $this->reindexAll();
199: }
200:
201:
202:
203: $parentIds = $this->getRelationsByChild($processIds);
204: if ($parentIds) {
205: $processIds = array_merge($processIds, $parentIds);
206: }
207:
208:
209: $select = $adapter->select()
210: ->from($this->getTable('catalog/product'), array('entity_id', 'type_id'))
211: ->where('entity_id IN(?)', $processIds);
212: $query = $select->query(Zend_Db::FETCH_ASSOC);
213: $byType = array();
214: while ($row = $query->fetch()) {
215: $byType[$row['type_id']][] = $row['entity_id'];
216: }
217:
218: $adapter->beginTransaction();
219: try {
220: $indexers = $this->_getTypeIndexers();
221: foreach ($indexers as $indexer) {
222: if (!empty($byType[$indexer->getTypeId()])) {
223: $indexer->reindexEntity($byType[$indexer->getTypeId()]);
224: }
225: }
226: } catch (Exception $e) {
227: $adapter->rollback();
228: throw $e;
229: }
230: $adapter->commit();
231:
232: return $this;
233: }
234:
235: 236: 237: 238: 239:
240: public function reindexAll()
241: {
242: $this->useIdxTable(true);
243: $this->beginTransaction();
244: try {
245: $this->clearTemporaryIndexTable();
246:
247: foreach ($this->_getTypeIndexers() as $indexer) {
248: $indexer->reindexAll();
249: }
250:
251: $this->syncData();
252: $this->commit();
253: } catch (Exception $e) {
254: $this->rollBack();
255: throw $e;
256: }
257: return $this;
258: }
259:
260: 261: 262: 263: 264:
265: protected function _getTypeIndexers()
266: {
267: if (is_null($this->_indexers)) {
268: $this->_indexers = array();
269: $types = Mage::getSingleton('catalog/product_type')->getTypesByPriority();
270: foreach ($types as $typeId => $typeInfo) {
271: if (isset($typeInfo['stock_indexer'])) {
272: $modelName = $typeInfo['stock_indexer'];
273: } else {
274: $modelName = $this->_defaultIndexer;
275: }
276: $isComposite = !empty($typeInfo['composite']);
277: $indexer = Mage::getResourceModel($modelName)
278: ->setTypeId($typeId)
279: ->setIsComposite($isComposite);
280:
281: $this->_indexers[$typeId] = $indexer;
282: }
283: }
284: return $this->_indexers;
285: }
286:
287: 288: 289: 290: 291: 292:
293: protected function _getIndexer($productTypeId)
294: {
295: $types = $this->_getTypeIndexers();
296: if (!isset($types[$productTypeId])) {
297: Mage::throwException(Mage::helper('catalog')->__('Unsupported product type "%s".', $productTypeId));
298: }
299: return $types[$productTypeId];
300: }
301:
302: 303: 304: 305: 306: 307: 308:
309: public function getProductParentsByChild($childId)
310: {
311: $write = $this->_getWriteAdapter();
312: $select = $write->select()
313: ->from(array('l' => $this->getTable('catalog/product_relation')), array('parent_id'))
314: ->join(
315: array('e' => $this->getTable('catalog/product')),
316: 'l.parent_id=e.entity_id',
317: array('e.type_id')
318: )
319: ->where('l.child_id = :child_id');
320: return $write->fetchPairs($select, array(':child_id' => $childId));
321: }
322:
323: 324: 325: 326: 327: 328:
329: public function getIdxTable($table = null)
330: {
331: if ($this->useIdxTable()) {
332: return $this->getTable('cataloginventory/stock_status_indexer_idx');
333: }
334: return $this->getTable('cataloginventory/stock_status_indexer_tmp');
335: }
336: }
337: