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_CatalogSearch_Model_Indexer_Fulltext extends Mage_Index_Model_Indexer_Abstract
36: {
37: 38: 39:
40: const EVENT_MATCH_RESULT_KEY = 'catalogsearch_fulltext_match_result';
41:
42: 43: 44: 45: 46:
47: protected $_searchableAttributes = null;
48:
49: 50: 51: 52: 53:
54: protected function _getResource()
55: {
56: return Mage::getResourceSingleton('catalogsearch/indexer_fulltext');
57: }
58:
59: 60: 61: 62: 63:
64: protected $_matchedEntities = array(
65: Mage_Catalog_Model_Product::ENTITY => array(
66: Mage_Index_Model_Event::TYPE_SAVE,
67: Mage_Index_Model_Event::TYPE_MASS_ACTION,
68: Mage_Index_Model_Event::TYPE_DELETE
69: ),
70: Mage_Catalog_Model_Resource_Eav_Attribute::ENTITY => array(
71: Mage_Index_Model_Event::TYPE_SAVE,
72: Mage_Index_Model_Event::TYPE_DELETE,
73: ),
74: Mage_Core_Model_Store::ENTITY => array(
75: Mage_Index_Model_Event::TYPE_SAVE,
76: Mage_Index_Model_Event::TYPE_DELETE
77: ),
78: Mage_Core_Model_Store_Group::ENTITY => array(
79: Mage_Index_Model_Event::TYPE_SAVE
80: ),
81: Mage_Core_Model_Config_Data::ENTITY => array(
82: Mage_Index_Model_Event::TYPE_SAVE
83: ),
84: Mage_Catalog_Model_Convert_Adapter_Product::ENTITY => array(
85: Mage_Index_Model_Event::TYPE_SAVE
86: ),
87: Mage_Catalog_Model_Category::ENTITY => array(
88: Mage_Index_Model_Event::TYPE_SAVE
89: )
90: );
91:
92: 93: 94: 95: 96:
97: protected $_relatedConfigSettings = array(
98: Mage_CatalogSearch_Model_Fulltext::XML_PATH_CATALOG_SEARCH_TYPE
99: );
100:
101: 102: 103: 104: 105:
106: protected function _getIndexer()
107: {
108: return Mage::getSingleton('catalogsearch/fulltext');
109: }
110:
111: 112: 113: 114: 115:
116: public function getName()
117: {
118: return Mage::helper('catalogsearch')->__('Catalog Search Index');
119: }
120:
121: 122: 123: 124: 125:
126: public function getDescription()
127: {
128: return Mage::helper('catalogsearch')->__('Rebuild Catalog product fulltext search index');
129: }
130:
131: 132: 133: 134: 135: 136: 137: 138:
139: public function matchEvent(Mage_Index_Model_Event $event)
140: {
141: $data = $event->getNewData();
142: if (isset($data[self::EVENT_MATCH_RESULT_KEY])) {
143: return $data[self::EVENT_MATCH_RESULT_KEY];
144: }
145:
146: $entity = $event->getEntity();
147: if ($entity == Mage_Catalog_Model_Resource_Eav_Attribute::ENTITY) {
148:
149: $attribute = $event->getDataObject();
150:
151: if (!$attribute) {
152: $result = false;
153: } elseif ($event->getType() == Mage_Index_Model_Event::TYPE_SAVE) {
154: $result = $attribute->dataHasChangedFor('is_searchable');
155: } elseif ($event->getType() == Mage_Index_Model_Event::TYPE_DELETE) {
156: $result = $attribute->getIsSearchable();
157: } else {
158: $result = false;
159: }
160: } else if ($entity == Mage_Core_Model_Store::ENTITY) {
161: if ($event->getType() == Mage_Index_Model_Event::TYPE_DELETE) {
162: $result = true;
163: } else {
164:
165: $store = $event->getDataObject();
166: if ($store && $store->isObjectNew()) {
167: $result = true;
168: } else {
169: $result = false;
170: }
171: }
172: } else if ($entity == Mage_Core_Model_Store_Group::ENTITY) {
173:
174: $storeGroup = $event->getDataObject();
175: if ($storeGroup && $storeGroup->dataHasChangedFor('website_id')) {
176: $result = true;
177: } else {
178: $result = false;
179: }
180: } else if ($entity == Mage_Core_Model_Config_Data::ENTITY) {
181: $data = $event->getDataObject();
182: if ($data && in_array($data->getPath(), $this->_relatedConfigSettings)) {
183: $result = $data->isValueChanged();
184: } else {
185: $result = false;
186: }
187: } else {
188: $result = parent::matchEvent($event);
189: }
190:
191: $event->addNewData(self::EVENT_MATCH_RESULT_KEY, $result);
192:
193: return $result;
194: }
195:
196: 197: 198: 199: 200:
201: protected function _registerEvent(Mage_Index_Model_Event $event)
202: {
203: $event->addNewData(self::EVENT_MATCH_RESULT_KEY, true);
204: switch ($event->getEntity()) {
205: case Mage_Catalog_Model_Product::ENTITY:
206: $this->_registerCatalogProductEvent($event);
207: break;
208:
209: case Mage_Catalog_Model_Convert_Adapter_Product::ENTITY:
210: $event->addNewData('catalogsearch_fulltext_reindex_all', true);
211: break;
212:
213: case Mage_Core_Model_Config_Data::ENTITY:
214: case Mage_Core_Model_Store::ENTITY:
215: case Mage_Catalog_Model_Resource_Eav_Attribute::ENTITY:
216: case Mage_Core_Model_Store_Group::ENTITY:
217: $event->addNewData('catalogsearch_fulltext_skip_call_event_handler', true);
218: $process = $event->getProcess();
219: $process->changeStatus(Mage_Index_Model_Process::STATUS_REQUIRE_REINDEX);
220: break;
221: case Mage_Catalog_Model_Category::ENTITY:
222: $this->_registerCatalogCategoryEvent($event);
223: break;
224: }
225: }
226:
227: 228: 229: 230: 231: 232:
233: protected function _registerCatalogCategoryEvent(Mage_Index_Model_Event $event)
234: {
235: switch ($event->getType()) {
236: case Mage_Index_Model_Event::TYPE_SAVE:
237:
238: $category = $event->getDataObject();
239: $productIds = $category->getAffectedProductIds();
240: if ($productIds) {
241: $event->addNewData('catalogsearch_category_update_product_ids', $productIds);
242: $event->addNewData('catalogsearch_category_update_category_ids', array($category->getId()));
243: } else {
244: $movedCategoryId = $category->getMovedCategoryId();
245: if ($movedCategoryId) {
246: $event->addNewData('catalogsearch_category_update_product_ids', array());
247: $event->addNewData('catalogsearch_category_update_category_ids', array($movedCategoryId));
248: }
249: }
250: break;
251: }
252:
253: return $this;
254: }
255:
256: 257: 258: 259: 260: 261:
262: protected function _registerCatalogProductEvent(Mage_Index_Model_Event $event)
263: {
264: switch ($event->getType()) {
265: case Mage_Index_Model_Event::TYPE_SAVE:
266:
267: $product = $event->getDataObject();
268:
269: $event->addNewData('catalogsearch_update_product_id', $product->getId());
270: break;
271: case Mage_Index_Model_Event::TYPE_DELETE:
272:
273: $product = $event->getDataObject();
274:
275: $event->addNewData('catalogsearch_delete_product_id', $product->getId());
276: break;
277: case Mage_Index_Model_Event::TYPE_MASS_ACTION:
278:
279: $actionObject = $event->getDataObject();
280:
281: $reindexData = array();
282: $rebuildIndex = false;
283:
284:
285: $attrData = $actionObject->getAttributesData();
286: if (isset($attrData['status'])) {
287: $rebuildIndex = true;
288: $reindexData['catalogsearch_status'] = $attrData['status'];
289: }
290:
291:
292: if ($actionObject->getWebsiteIds()) {
293: $rebuildIndex = true;
294: $reindexData['catalogsearch_website_ids'] = $actionObject->getWebsiteIds();
295: $reindexData['catalogsearch_action_type'] = $actionObject->getActionType();
296: }
297:
298: $searchableAttributes = array();
299: if (is_array($attrData)) {
300: $searchableAttributes = array_intersect($this->_getSearchableAttributes(), array_keys($attrData));
301: }
302:
303: if (count($searchableAttributes) > 0) {
304: $rebuildIndex = true;
305: $reindexData['catalogsearch_force_reindex'] = true;
306: }
307:
308:
309: if ($rebuildIndex) {
310: $reindexData['catalogsearch_product_ids'] = $actionObject->getProductIds();
311: foreach ($reindexData as $k => $v) {
312: $event->addNewData($k, $v);
313: }
314: }
315: break;
316: }
317:
318: return $this;
319: }
320:
321: 322: 323: 324: 325:
326: protected function _getSearchableAttributes()
327: {
328: if (is_null($this->_searchableAttributes)) {
329:
330: $attributeCollection = Mage::getResourceModel('catalog/product_attribute_collection');
331: $attributeCollection->addIsSearchableFilter();
332:
333: foreach ($attributeCollection as $attribute) {
334: $this->_searchableAttributes[] = $attribute->getAttributeCode();
335: }
336: }
337:
338: return $this->_searchableAttributes;
339: }
340:
341: 342: 343: 344: 345: 346:
347: protected function _isProductComposite($productId)
348: {
349: $product = Mage::getModel('catalog/product')->load($productId);
350: return $product->isComposite();
351: }
352:
353: 354: 355: 356: 357:
358: protected function _processEvent(Mage_Index_Model_Event $event)
359: {
360: $data = $event->getNewData();
361:
362: if (!empty($data['catalogsearch_fulltext_reindex_all'])) {
363: $this->reindexAll();
364: } else if (!empty($data['catalogsearch_delete_product_id'])) {
365: $productId = $data['catalogsearch_delete_product_id'];
366:
367: if (!$this->_isProductComposite($productId)) {
368: $parentIds = $this->_getResource()->getRelationsByChild($productId);
369: if (!empty($parentIds)) {
370: $this->_getIndexer()->rebuildIndex(null, $parentIds);
371: }
372: }
373:
374: $this->_getIndexer()->cleanIndex(null, $productId)
375: ->resetSearchResults();
376: } else if (!empty($data['catalogsearch_update_product_id'])) {
377: $productId = $data['catalogsearch_update_product_id'];
378: $productIds = array($productId);
379:
380: if (!$this->_isProductComposite($productId)) {
381: $parentIds = $this->_getResource()->getRelationsByChild($productId);
382: if (!empty($parentIds)) {
383: $productIds = array_merge($productIds, $parentIds);
384: }
385: }
386:
387: $this->_getIndexer()->rebuildIndex(null, $productIds)
388: ->resetSearchResults();
389: } else if (!empty($data['catalogsearch_product_ids'])) {
390:
391: $productIds = $data['catalogsearch_product_ids'];
392:
393: if (!empty($data['catalogsearch_website_ids'])) {
394: $websiteIds = $data['catalogsearch_website_ids'];
395: $actionType = $data['catalogsearch_action_type'];
396:
397: foreach ($websiteIds as $websiteId) {
398: foreach (Mage::app()->getWebsite($websiteId)->getStoreIds() as $storeId) {
399: if ($actionType == 'remove') {
400: $this->_getIndexer()
401: ->cleanIndex($storeId, $productIds)
402: ->resetSearchResults();
403: } else if ($actionType == 'add') {
404: $this->_getIndexer()
405: ->rebuildIndex($storeId, $productIds)
406: ->resetSearchResults();
407: }
408: }
409: }
410: }
411: if (isset($data['catalogsearch_status'])) {
412: $status = $data['catalogsearch_status'];
413: if ($status == Mage_Catalog_Model_Product_Status::STATUS_ENABLED) {
414: $this->_getIndexer()
415: ->rebuildIndex(null, $productIds)
416: ->resetSearchResults();
417: } else {
418: $this->_getIndexer()
419: ->cleanIndex(null, $productIds)
420: ->resetSearchResults();
421: }
422: }
423: if (isset($data['catalogsearch_force_reindex'])) {
424: $this->_getIndexer()
425: ->rebuildIndex(null, $productIds)
426: ->resetSearchResults();
427: }
428: } else if (isset($data['catalogsearch_category_update_product_ids'])) {
429: $productIds = $data['catalogsearch_category_update_product_ids'];
430: $categoryIds = $data['catalogsearch_category_update_category_ids'];
431:
432: $this->_getIndexer()
433: ->updateCategoryIndex($productIds, $categoryIds);
434: }
435: }
436:
437: 438: 439: 440:
441: public function reindexAll()
442: {
443: $resourceModel = $this->_getIndexer()->getResource();
444: $resourceModel->beginTransaction();
445: try {
446: $this->_getIndexer()->rebuildIndex();
447: $resourceModel->commit();
448: } catch (Exception $e) {
449: $resourceModel->rollBack();
450: throw $e;
451: }
452: }
453: }
454: