5
5
*/
6
6
namespace Magento \Catalog \Observer ;
7
7
8
+ use Magento \Catalog \Model \Category ;
9
+ use Magento \Framework \Data \Collection ;
10
+ use Magento \Framework \Data \Tree \Node ;
8
11
use Magento \Framework \Event \ObserverInterface ;
9
12
13
+ /**
14
+ * Observer that add Categories Tree to Topmenu
15
+ */
10
16
class AddCatalogToTopmenuItemsObserver implements ObserverInterface
11
17
{
12
18
/**
@@ -17,28 +23,38 @@ class AddCatalogToTopmenuItemsObserver implements ObserverInterface
17
23
protected $ catalogCategory ;
18
24
19
25
/**
20
- * @var \Magento\Catalog\Model\Indexer\Category\Flat\State
26
+ * @var \Magento\Catalog\Model\ResourceModel\Category\CollectionFactory
27
+ */
28
+ private $ collectionFactory ;
29
+
30
+ /**
31
+ * @var \Magento\Store\Model\StoreManagerInterface
21
32
*/
22
- protected $ categoryFlatState ;
33
+ private $ storeManager ;
23
34
24
35
/**
25
- * @var MenuCategoryData
36
+ * @var \Magento\Catalog\Model\Layer\Resolver
26
37
*/
27
- protected $ menuCategoryData ;
38
+ private $ layerResolver ;
28
39
29
40
/**
30
41
* @param \Magento\Catalog\Helper\Category $catalogCategory
31
42
* @param \Magento\Catalog\Model\Indexer\Category\Flat\State $categoryFlatState
32
- * @param \Magento\Catalog\Observer\MenuCategoryData $menuCategoryData
43
+ * @param \Magento\Catalog\Model\ResourceModel\Category\CollectionFactory $categoryCollectionFactory
44
+ * @param \Magento\Store\Model\StoreManagerInterface $storeManager
45
+ * @param \Magento\Catalog\Helper\Category $catalogCategory
46
+ * @param \Magento\Catalog\Model\Layer\Resolver $layerResolver
33
47
*/
34
48
public function __construct (
35
49
\Magento \Catalog \Helper \Category $ catalogCategory ,
36
- \Magento \Catalog \Model \Indexer \Category \Flat \State $ categoryFlatState ,
37
- \Magento \Catalog \Observer \MenuCategoryData $ menuCategoryData
50
+ \Magento \Catalog \Model \ResourceModel \Category \CollectionFactory $ categoryCollectionFactory ,
51
+ \Magento \Store \Model \StoreManagerInterface $ storeManager ,
52
+ \Magento \Catalog \Model \Layer \Resolver $ layerResolver
38
53
) {
39
54
$ this ->catalogCategory = $ catalogCategory ;
40
- $ this ->categoryFlatState = $ categoryFlatState ;
41
- $ this ->menuCategoryData = $ menuCategoryData ;
55
+ $ this ->collectionFactory = $ categoryCollectionFactory ;
56
+ $ this ->storeManager = $ storeManager ;
57
+ $ this ->layerResolver = $ layerResolver ;
42
58
}
43
59
44
60
/**
@@ -50,38 +66,96 @@ public function __construct(
50
66
public function execute (\Magento \Framework \Event \Observer $ observer )
51
67
{
52
68
$ block = $ observer ->getEvent ()->getBlock ();
53
- $ block ->addIdentity (\Magento \Catalog \Model \Category::CACHE_TAG );
54
- $ this ->_addCategoriesToMenu ($ this ->catalogCategory ->getStoreCategories (), $ observer ->getMenu (), $ block );
69
+ $ menuRootNode = $ observer ->getEvent ()->getMenu ();
70
+ $ block ->addIdentity (Category::CACHE_TAG );
71
+
72
+ $ rootId = $ this ->storeManager ->getStore ()->getRootCategoryId ();
73
+ $ storeId = $ this ->storeManager ->getStore ()->getId ();
74
+
75
+ /** @var \Magento\Catalog\Model\ResourceModel\Category\Collection $collection */
76
+ $ collection = $ this ->getCategoryTree ($ storeId , $ rootId );
77
+
78
+ $ currentCategory = $ this ->getCurrentCategory ();
79
+
80
+ $ mapping = [$ rootId => $ menuRootNode ]; // use nodes stack to avoid recursion
81
+ foreach ($ collection as $ category ) {
82
+ if (!isset ($ mapping [$ category ->getParentId ()])) {
83
+ continue ;
84
+ }
85
+ /** @var Node $parentCategoryNode */
86
+ $ parentCategoryNode = $ mapping [$ category ->getParentId ()];
87
+
88
+ $ categoryNode = new Node (
89
+ $ this ->getCategoryAsArray ($ category , $ currentCategory ),
90
+ 'id ' ,
91
+ $ parentCategoryNode ->getTree (),
92
+ $ parentCategoryNode
93
+ );
94
+ $ parentCategoryNode ->addChild ($ categoryNode );
95
+
96
+ $ mapping [$ category ->getId ()] = $ categoryNode ; //add node in stack
97
+
98
+ $ block ->addIdentity (Category::CACHE_TAG . '_ ' . $ category ->getId ());
99
+ }
55
100
}
56
101
57
102
/**
58
- * Recursively adds categories to top menu
103
+ * Get current Category from catalog layer
59
104
*
60
- * @param \Magento\Framework\Data\Tree\Node\Collection|array $categories
61
- * @param \Magento\Framework\Data\Tree\Node $parentCategoryNode
62
- * @param \Magento\Theme\Block\Html\Topmenu $block
63
- * @return void
105
+ * @return \Magento\Catalog\Model\Category
64
106
*/
65
- protected function _addCategoriesToMenu ( $ categories , $ parentCategoryNode , $ block )
107
+ private function getCurrentCategory ( )
66
108
{
67
- foreach ($ categories as $ category ) {
68
- if (!$ category ->getIsActive ()) {
69
- continue ;
70
- }
71
- $ block ->addIdentity (\Magento \Catalog \Model \Category::CACHE_TAG . '_ ' . $ category ->getId ());
109
+ $ catalogLayer = $ this ->layerResolver ->get ();
72
110
73
- $ tree = $ parentCategoryNode ->getTree ();
74
- $ categoryData = $ this ->menuCategoryData ->getMenuCategoryData ($ category );
75
- $ categoryNode = new \Magento \Framework \Data \Tree \Node ($ categoryData , 'id ' , $ tree , $ parentCategoryNode );
76
- $ parentCategoryNode ->addChild ($ categoryNode );
111
+ if (!$ catalogLayer ) {
112
+ return null ;
113
+ }
77
114
78
- if ($ this ->categoryFlatState ->isFlatEnabled () && $ category ->getUseFlatResource ()) {
79
- $ subcategories = (array )$ category ->getChildrenNodes ();
80
- } else {
81
- $ subcategories = $ category ->getChildren ();
82
- }
115
+ return $ catalogLayer ->getCurrentCategory ();
116
+ }
83
117
84
- $ this ->_addCategoriesToMenu ($ subcategories , $ categoryNode , $ block );
85
- }
118
+ /**
119
+ * Convert category to array
120
+ *
121
+ * @param \Magento\Catalog\Model\Category $category
122
+ * @param \Magento\Catalog\Model\Category $currentCategory
123
+ * @return array
124
+ */
125
+ private function getCategoryAsArray ($ category , $ currentCategory )
126
+ {
127
+ return [
128
+ 'name ' => $ category ->getName (),
129
+ 'id ' => 'category-node- ' . $ category ->getId (),
130
+ 'url ' => $ this ->catalogCategory ->getCategoryUrl ($ category ),
131
+ 'has_active ' => in_array ((string )$ category ->getId (), explode ('/ ' , $ currentCategory ->getPath ()), true ),
132
+ 'is_active ' => $ category ->getId () == $ currentCategory ->getId ()
133
+ ];
134
+ }
135
+
136
+ /**
137
+ * Get Category Tree
138
+ *
139
+ * @param int $storeId
140
+ * @param int $rootId
141
+ * @return \Magento\Catalog\Model\ResourceModel\Category\Collection
142
+ * @throws \Magento\Framework\Exception\LocalizedException
143
+ */
144
+ protected function getCategoryTree ($ storeId , $ rootId )
145
+ {
146
+ /** @var \Magento\Catalog\Model\ResourceModel\Category\Collection $collection */
147
+ $ collection = $ this ->collectionFactory ->create ();
148
+ $ collection ->setStoreId ($ storeId );
149
+ $ collection ->addAttributeToSelect ('name ' );
150
+ $ collection ->addFieldToFilter ('path ' , ['like ' => '1/ ' . $ rootId . '/% ' ]); //load only from store root
151
+ $ collection ->addAttributeToFilter ('include_in_menu ' , 1 );
152
+ $ collection ->addAttributeToFilter ('is_active ' , 1 );
153
+ $ collection ->addUrlRewriteToResult ();
154
+ $ collection ->addOrder ('level ' , Collection::SORT_ORDER_ASC );
155
+ $ collection ->addOrder ('position ' , Collection::SORT_ORDER_ASC );
156
+ $ collection ->addOrder ('parent_id ' , Collection::SORT_ORDER_ASC );
157
+ $ collection ->addOrder ('entity_id ' , Collection::SORT_ORDER_ASC );
158
+
159
+ return $ collection ;
86
160
}
87
161
}
0 commit comments