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_Catalog_Model_Category extends Mage_Catalog_Model_Abstract
36: {
37: 38: 39: 40:
41: const ENTITY = 'catalog_category';
42: 43: 44:
45: const DM_PRODUCT = 'PRODUCTS';
46: const DM_PAGE = 'PAGE';
47: const DM_MIXED = 'PRODUCTS_AND_PAGE';
48: const TREE_ROOT_ID = 1;
49:
50: const CACHE_TAG = 'catalog_category';
51:
52: 53: 54: 55: 56:
57: protected $_eventPrefix = 'catalog_category';
58:
59: 60: 61: 62: 63:
64: protected $_eventObject = 'category';
65:
66: 67: 68:
69: protected $_cacheTag = self::CACHE_TAG;
70:
71: 72: 73: 74: 75:
76: protected static $_url;
77:
78: 79: 80: 81: 82:
83: protected static $_urlRewrite;
84:
85: 86: 87: 88: 89:
90: protected $_useFlatResource = false;
91:
92: 93: 94: 95: 96:
97: private $_designAttributes = array(
98: 'custom_design',
99: 'custom_design_from',
100: 'custom_design_to',
101: 'page_layout',
102: 'custom_layout_update',
103: 'custom_apply_to_products'
104: );
105:
106: 107: 108: 109: 110:
111: protected $_treeModel = null;
112:
113: 114: 115: 116:
117: protected function _construct()
118: {
119: if (Mage::helper('catalog/category_flat')->isEnabled()) {
120: $this->_init('catalog/category_flat');
121: $this->_useFlatResource = true;
122: } else {
123: $this->_init('catalog/category');
124: }
125: }
126:
127: 128: 129: 130: 131:
132: public function getUrlInstance()
133: {
134: if (!self::$_url) {
135: self::$_url = Mage::getModel('core/url');
136: }
137: return self::$_url;
138: }
139:
140: 141: 142: 143: 144:
145: public function getUrlRewrite()
146: {
147: if (!self::$_urlRewrite) {
148: self::$_urlRewrite = Mage::getModel('core/url_rewrite');
149: }
150: return self::$_urlRewrite;
151: }
152:
153: 154: 155: 156: 157:
158: public function getTreeModel()
159: {
160: return Mage::getResourceModel('catalog/category_tree');
161: }
162:
163: 164: 165: 166: 167:
168: public function getTreeModelInstance()
169: {
170: if (is_null($this->_treeModel)) {
171: $this->_treeModel = Mage::getResourceSingleton('catalog/category_tree');
172: }
173: return $this->_treeModel;
174: }
175:
176: 177: 178: 179: 180: 181: 182:
183: public function move($parentId, $afterCategoryId)
184: {
185: 186: 187: 188:
189: $parent = Mage::getModel('catalog/category')
190: ->setStoreId($this->getStoreId())
191: ->load($parentId);
192:
193: if (!$parent->getId()) {
194: Mage::throwException(
195: Mage::helper('catalog')->__('Category move operation is not possible: the new parent category was not found.')
196: );
197: }
198:
199: if (!$this->getId()) {
200: Mage::throwException(
201: Mage::helper('catalog')->__('Category move operation is not possible: the current category was not found.')
202: );
203: } elseif ($parent->getId() == $this->getId()) {
204: Mage::throwException(
205: Mage::helper('catalog')->__('Category move operation is not possible: parent category is equal to child category.')
206: );
207: }
208:
209: 210: 211:
212: $this->setMovedCategoryId($this->getId());
213:
214: $eventParams = array(
215: $this->_eventObject => $this,
216: 'parent' => $parent,
217: 'category_id' => $this->getId(),
218: 'prev_parent_id'=> $this->getParentId(),
219: 'parent_id' => $parentId
220: );
221: $moveComplete = false;
222:
223: $this->_getResource()->beginTransaction();
224: try {
225: 226: 227: 228:
229: Mage::dispatchEvent('catalog_category_tree_move_before', $eventParams);
230: Mage::dispatchEvent($this->_eventPrefix.'_move_before', $eventParams);
231:
232: $this->getResource()->changeParent($this, $parent, $afterCategoryId);
233:
234: Mage::dispatchEvent($this->_eventPrefix.'_move_after', $eventParams);
235: Mage::dispatchEvent('catalog_category_tree_move_after', $eventParams);
236: $this->_getResource()->commit();
237:
238:
239: $this->setAffectedCategoryIds(array($this->getId(), $this->getParentId(), $parentId));
240:
241: $moveComplete = true;
242: } catch (Exception $e) {
243: $this->_getResource()->rollBack();
244: throw $e;
245: }
246: if ($moveComplete) {
247: Mage::dispatchEvent('category_move', $eventParams);
248: Mage::getSingleton('index/indexer')->processEntityAction(
249: $this, self::ENTITY, Mage_Index_Model_Event::TYPE_SAVE
250: );
251: Mage::app()->cleanCache(array(self::CACHE_TAG));
252: }
253:
254: return $this;
255: }
256:
257: 258: 259: 260: 261:
262: public function getDefaultAttributeSetId()
263: {
264: return $this->getResource()->getEntityType()->getDefaultAttributeSetId();
265: }
266:
267: 268: 269: 270: 271:
272: public function getProductCollection()
273: {
274: $collection = Mage::getResourceModel('catalog/product_collection')
275: ->setStoreId($this->getStoreId())
276: ->addCategoryFilter($this);
277: return $collection;
278: }
279:
280: 281: 282: 283: 284: 285:
286: public function getAttributes($noDesignAttributes = false)
287: {
288: $result = $this->getResource()
289: ->loadAllAttributes($this)
290: ->getSortedAttributes();
291:
292: if ($noDesignAttributes){
293: foreach ($result as $k=>$a){
294: if (in_array($k, $this->_designAttributes)) {
295: unset($result[$k]);
296: }
297: }
298: }
299:
300: return $result;
301: }
302:
303: 304: 305: 306: 307: 308: 309:
310: public function getProductsPosition()
311: {
312: if (!$this->getId()) {
313: return array();
314: }
315:
316: $array = $this->getData('products_position');
317: if (is_null($array)) {
318: $array = $this->getResource()->getProductsPosition($this);
319: $this->setData('products_position', $array);
320: }
321: return $array;
322: }
323:
324: 325: 326: 327: 328:
329: public function getStoreIds()
330: {
331: if ($this->getInitialSetupFlag()) {
332: return array();
333: }
334:
335: if ($storeIds = $this->getData('store_ids')) {
336: return $storeIds;
337: }
338:
339: if (!$this->getId()) {
340: return array();
341: }
342:
343: $nodes = array();
344: foreach ($this->getPathIds() as $id) {
345: $nodes[] = $id;
346: }
347:
348: $storeIds = array();
349: $storeCollection = Mage::getModel('core/store')->getCollection()->loadByCategoryIds($nodes);
350: foreach ($storeCollection as $store) {
351: $storeIds[$store->getId()] = $store->getId();
352: }
353:
354: $entityStoreId = $this->getStoreId();
355: if (!in_array($entityStoreId, $storeIds)) {
356: array_unshift($storeIds, $entityStoreId);
357: }
358: if (!in_array(0, $storeIds)) {
359: array_unshift($storeIds, 0);
360: }
361:
362: $this->setData('store_ids', $storeIds);
363: return $storeIds;
364: }
365:
366: 367: 368: 369: 370:
371: public function getLayoutUpdateHandle()
372: {
373: $layout = 'catalog_category_';
374: if ($this->getIsAnchor()) {
375: $layout .= 'layered';
376: }
377: else {
378: $layout .= 'default';
379: }
380: return $layout;
381: }
382:
383: 384: 385: 386: 387: 388: 389:
390: public function getStoreId()
391: {
392: if ($this->hasData('store_id')) {
393: return $this->_getData('store_id');
394: }
395: return Mage::app()->getStore()->getId();
396: }
397:
398: 399: 400: 401: 402: 403:
404: public function setStoreId($storeId)
405: {
406: if (!is_numeric($storeId)) {
407: $storeId = Mage::app($storeId)->getStore()->getId();
408: }
409: $this->setData('store_id', $storeId);
410: $this->getResource()->setStoreId($storeId);
411: return $this;
412: }
413:
414: 415: 416: 417: 418:
419: public function getUrl()
420: {
421: $url = $this->_getData('url');
422: if (is_null($url)) {
423: Varien_Profiler::start('REWRITE: '.__METHOD__);
424:
425: if ($this->hasData('request_path') && $this->getRequestPath() != '') {
426: $this->setData('url', $this->getUrlInstance()->getDirectUrl($this->getRequestPath()));
427: Varien_Profiler::stop('REWRITE: '.__METHOD__);
428: return $this->getData('url');
429: }
430:
431: Varien_Profiler::stop('REWRITE: '.__METHOD__);
432:
433: $rewrite = $this->getUrlRewrite();
434: if ($this->getStoreId()) {
435: $rewrite->setStoreId($this->getStoreId());
436: }
437: $idPath = 'category/' . $this->getId();
438: $rewrite->loadByIdPath($idPath);
439:
440: if ($rewrite->getId()) {
441: $this->setData('url', $this->getUrlInstance()->getDirectUrl($rewrite->getRequestPath()));
442: Varien_Profiler::stop('REWRITE: '.__METHOD__);
443: return $this->getData('url');
444: }
445:
446: Varien_Profiler::stop('REWRITE: '.__METHOD__);
447:
448: $this->setData('url', $this->getCategoryIdUrl());
449: return $this->getData('url');
450: }
451: return $url;
452: }
453:
454: 455: 456: 457: 458:
459: public function getCategoryIdUrl()
460: {
461: Varien_Profiler::start('REGULAR: '.__METHOD__);
462: $urlKey = $this->getUrlKey() ? $this->getUrlKey() : $this->formatUrlKey($this->getName());
463: $url = $this->getUrlInstance()->getUrl('catalog/category/view', array(
464: 's'=>$urlKey,
465: 'id'=>$this->getId(),
466: ));
467: Varien_Profiler::stop('REGULAR: '.__METHOD__);
468: return $url;
469: }
470:
471: 472: 473: 474: 475: 476:
477: public function formatUrlKey($str)
478: {
479: $str = Mage::helper('core')->removeAccents($str);
480: $urlKey = preg_replace('#[^0-9a-z]+#i', '-', $str);
481: $urlKey = strtolower($urlKey);
482: $urlKey = trim($urlKey, '-');
483: return $urlKey;
484: }
485:
486: 487: 488: 489: 490:
491: public function getImageUrl()
492: {
493: $url = false;
494: if ($image = $this->getImage()) {
495: $url = Mage::getBaseUrl('media').'catalog/category/'.$image;
496: }
497: return $url;
498: }
499:
500: 501: 502: 503: 504:
505: public function getUrlPath()
506: {
507: $path = $this->getData('url_path');
508: if ($path) {
509: return $path;
510: }
511:
512: $path = $this->getUrlKey();
513:
514: if ($this->getParentId()) {
515: $parentPath = Mage::getModel('catalog/category')->load($this->getParentId())->getCategoryPath();
516: $path = $parentPath.'/'.$path;
517: }
518:
519: $this->setUrlPath($path);
520:
521: return $path;
522: }
523:
524: 525: 526: 527: 528:
529: public function getParentCategory()
530: {
531: if (!$this->hasData('parent_category')) {
532: $this->setData('parent_category', Mage::getModel('catalog/category')->load($this->getParentId()));
533: }
534: return $this->_getData('parent_category');
535: }
536:
537: 538: 539: 540: 541:
542: public function getParentId()
543: {
544: $parentIds = $this->getParentIds();
545: return intval(array_pop($parentIds));
546: }
547:
548: 549: 550: 551: 552:
553: public function getParentIds()
554: {
555: return array_diff($this->getPathIds(), array($this->getId()));
556: }
557:
558: 559: 560: 561: 562:
563: public function getCustomDesignDate()
564: {
565: $result = array();
566: $result['from'] = $this->getData('custom_design_from');
567: $result['to'] = $this->getData('custom_design_to');
568:
569: return $result;
570: }
571:
572: 573: 574: 575: 576:
577: public function getDesignAttributes()
578: {
579: $result = array();
580: foreach ($this->_designAttributes as $attrName) {
581: $result[] = $this->_getAttribute($attrName);
582: }
583: return $result;
584: }
585:
586: 587: 588: 589: 590: 591:
592: private function _getAttribute($attributeCode)
593: {
594: if (!$this->_useFlatResource) {
595: $attribute = $this->getResource()->getAttribute($attributeCode);
596: }
597: else {
598: $attribute = Mage::getSingleton('catalog/config')
599: ->getAttribute(self::ENTITY, $attributeCode);
600: }
601: return $attribute;
602: }
603:
604: 605: 606: 607: 608: 609:
610: public function getAllChildren($asArray = false)
611: {
612: $children = $this->getResource()->getAllChildren($this);
613: if ($asArray) {
614: return $children;
615: }
616: else {
617: return implode(',', $children);
618: }
619:
620:
621:
622:
623:
624:
625:
626:
627:
628:
629:
630:
631:
632:
633:
634:
635:
636: }
637:
638: 639: 640: 641: 642:
643: public function getChildren()
644: {
645: return implode(',', $this->getResource()->getChildren($this, false));
646: }
647:
648: 649: 650: 651: 652: 653:
654: public function getPathInStore()
655: {
656: $result = array();
657:
658: $path = array_reverse($this->getPathIds());
659: foreach ($path as $itemId) {
660: if ($itemId == Mage::app()->getStore()->getRootCategoryId()) {
661: break;
662: }
663: $result[] = $itemId;
664: }
665: return implode(',', $result);
666: }
667:
668: 669: 670: 671: 672: 673:
674: public function checkId($id)
675: {
676: return $this->_getResource()->checkId($id);
677: }
678:
679: 680: 681: 682: 683: 684:
685: public function getPathIds()
686: {
687: $ids = $this->getData('path_ids');
688: if (is_null($ids)) {
689: $ids = explode('/', $this->getPath());
690: $this->setData('path_ids', $ids);
691: }
692: return $ids;
693: }
694:
695: 696: 697: 698: 699:
700: public function getLevel()
701: {
702: if (!$this->hasLevel()) {
703: return count(explode('/', $this->getPath())) - 1;
704: }
705: return $this->getData('level');
706: }
707:
708: 709: 710: 711: 712: 713:
714: public function verifyIds(array $ids)
715: {
716: return $this->getResource()->verifyIds($ids);
717: }
718:
719: 720: 721: 722: 723:
724: public function hasChildren()
725: {
726: return $this->_getResource()->getChildrenAmount($this) > 0;
727: }
728:
729: 730: 731: 732: 733:
734: public function getRequestPath()
735: {
736: return $this->_getData('request_path');
737: }
738:
739: 740: 741: 742: 743:
744: public function getName()
745: {
746: return $this->_getData('name');
747: }
748:
749: 750: 751: 752: 753:
754: protected function _beforeDelete()
755: {
756: $this->_protectFromNonAdmin();
757: if ($this->getResource()->isForbiddenToDelete($this->getId())) {
758: Mage::throwException("Can't delete root category.");
759: }
760: return parent::_beforeDelete();
761: }
762:
763: 764: 765: 766: 767:
768: public function getAnchorsAbove()
769: {
770: $anchors = array();
771: $path = $this->getPathIds();
772:
773: if (in_array($this->getId(), $path)) {
774: unset($path[array_search($this->getId(), $path)]);
775: }
776:
777: if ($this->_useFlatResource) {
778: $anchors = $this->_getResource()->getAnchorsAbove($path, $this->getStoreId());
779: }
780: else {
781: if (!Mage::registry('_category_is_anchor_attribute')) {
782: $model = $this->_getAttribute('is_anchor');
783: Mage::register('_category_is_anchor_attribute', $model);
784: }
785:
786: if ($isAnchorAttribute = Mage::registry('_category_is_anchor_attribute')) {
787: $anchors = $this->getResource()->findWhereAttributeIs($path, $isAnchorAttribute, 1);
788: }
789: }
790: return $anchors;
791: }
792:
793: 794: 795: 796: 797:
798: public function getProductCount()
799: {
800: if (!$this->hasProductCount()) {
801: $count = $this->_getResource()->getProductCount($this);
802: $this->setData('product_count', $count);
803: }
804: return $this->getData('product_count');
805: }
806:
807: 808: 809: 810: 811: 812: 813: 814: 815: 816:
817: public function getCategories($parent, $recursionLevel = 0, $sorted=false, $asCollection=false, $toLoad=true)
818: {
819: $categories = $this->getResource()
820: ->getCategories($parent, $recursionLevel, $sorted, $asCollection, $toLoad);
821: return $categories;
822: }
823:
824: 825: 826: 827: 828:
829: public function getParentCategories()
830: {
831: return $this->getResource()->getParentCategories($this);
832: }
833:
834: 835: 836: 837: 838:
839: public function getChildrenCategories()
840: {
841: return $this->getResource()->getChildrenCategories($this);
842: }
843:
844: 845: 846: 847: 848:
849: public function getParentDesignCategory()
850: {
851: return $this->getResource()->getParentDesignCategory($this);
852: }
853:
854: 855: 856: 857: 858:
859: public function isInRootCategoryList()
860: {
861: return $this->getResource()->isInRootCategoryList($this);
862: }
863:
864: 865: 866: 867: 868:
869: public function getAvailableSortBy()
870: {
871: $available = $this->getData('available_sort_by');
872: if (empty($available)) {
873: return array();
874: }
875: if ($available && !is_array($available)) {
876: $available = explode(',', $available);
877: }
878: return $available;
879: }
880:
881: 882: 883: 884: 885: 886:
887: public function getAvailableSortByOptions() {
888: $availableSortBy = array();
889: $defaultSortBy = Mage::getSingleton('catalog/config')
890: ->getAttributeUsedForSortByArray();
891: if ($this->getAvailableSortBy()) {
892: foreach ($this->getAvailableSortBy() as $sortBy) {
893: if (isset($defaultSortBy[$sortBy])) {
894: $availableSortBy[$sortBy] = $defaultSortBy[$sortBy];
895: }
896: }
897: }
898:
899: if (!$availableSortBy) {
900: $availableSortBy = $defaultSortBy;
901: }
902:
903: return $availableSortBy;
904: }
905:
906: 907: 908: 909: 910:
911: public function getDefaultSortBy() {
912: if (!$sortBy = $this->getData('default_sort_by')) {
913: $sortBy = Mage::getSingleton('catalog/config')
914: ->getProductListDefaultSortBy($this->getStoreId());
915: }
916: $available = $this->getAvailableSortByOptions();
917: if (!isset($available[$sortBy])) {
918: $sortBy = array_keys($available);
919: $sortBy = $sortBy[0];
920: }
921:
922: return $sortBy;
923: }
924:
925: 926: 927: 928: 929: 930:
931: public function validate()
932: {
933: return $this->_getResource()->validate($this);
934: }
935:
936: 937: 938: 939: 940:
941: protected function _afterSave()
942: {
943: $result = parent::_afterSave();
944: Mage::getSingleton('index/indexer')->processEntityAction(
945: $this, self::ENTITY, Mage_Index_Model_Event::TYPE_SAVE
946: );
947: return $result;
948: }
949: }
950: