Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
Topmenu.php
Go to the documentation of this file.
1 <?php
7 
13 
20 class Topmenu extends Template implements IdentityInterface
21 {
27  protected $identities = [];
28 
34  protected $_menu;
35 
39  private $nodeFactory;
40 
44  private $treeFactory;
45 
52  public function __construct(
53  Template\Context $context,
54  NodeFactory $nodeFactory,
55  TreeFactory $treeFactory,
56  array $data = []
57  ) {
58  parent::__construct($context, $data);
59  $this->nodeFactory = $nodeFactory;
60  $this->treeFactory = $treeFactory;
61  }
62 
69  protected function getCacheLifetime()
70  {
71  return parent::getCacheLifetime() ?: 3600;
72  }
73 
82  public function getHtml($outermostClass = '', $childrenWrapClass = '', $limit = 0)
83  {
84  $this->_eventManager->dispatch(
85  'page_block_html_topmenu_gethtml_before',
86  ['menu' => $this->getMenu(), 'block' => $this, 'request' => $this->getRequest()]
87  );
88 
89  $this->getMenu()->setOutermostClass($outermostClass);
90  $this->getMenu()->setChildrenWrapClass($childrenWrapClass);
91 
92  $html = $this->_getHtml($this->getMenu(), $childrenWrapClass, $limit);
93 
94  $transportObject = new \Magento\Framework\DataObject(['html' => $html]);
95  $this->_eventManager->dispatch(
96  'page_block_html_topmenu_gethtml_after',
97  ['menu' => $this->getMenu(), 'transportObject' => $transportObject]
98  );
99  $html = $transportObject->getHtml();
100  return $html;
101  }
102 
109  protected function _countItems($items)
110  {
111  $total = $items->count();
112  foreach ($items as $item) {
114  if ($item->hasChildren()) {
115  $total += $this->_countItems($item->getChildren());
116  }
117  }
118  return $total;
119  }
120 
130  protected function _columnBrake($items, $limit)
131  {
132  $total = $this->_countItems($items);
133  if ($total <= $limit) {
134  return;
135  }
136 
137  $result[] = ['total' => $total, 'max' => (int)ceil($total / ceil($total / $limit))];
138 
139  $count = 0;
140  $firstCol = true;
141 
142  foreach ($items as $item) {
143  $place = $this->_countItems($item->getChildren()) + 1;
144  $count += $place;
145 
146  if ($place >= $limit) {
147  $colbrake = !$firstCol;
148  $count = 0;
149  } elseif ($count >= $limit) {
150  $colbrake = !$firstCol;
151  $count = $place;
152  } else {
153  $colbrake = false;
154  }
155 
156  $result[] = ['place' => $place, 'colbrake' => $colbrake];
157 
158  $firstCol = false;
159  }
160 
161  return $result;
162  }
163 
173  protected function _addSubMenu($child, $childLevel, $childrenWrapClass, $limit)
174  {
175  $html = '';
176  if (!$child->hasChildren()) {
177  return $html;
178  }
179 
180  $colStops = [];
181  if ($childLevel == 0 && $limit) {
182  $colStops = $this->_columnBrake($child->getChildren(), $limit);
183  }
184 
185  $html .= '<ul class="level' . $childLevel . ' ' . $childrenWrapClass . '">';
186  $html .= $this->_getHtml($child, $childrenWrapClass, $limit, $colStops);
187  $html .= '</ul>';
188 
189  return $html;
190  }
191 
204  protected function _getHtml(
205  \Magento\Framework\Data\Tree\Node $menuTree,
206  $childrenWrapClass,
207  $limit,
208  array $colBrakes = []
209  ) {
210  $html = '';
211 
212  $children = $menuTree->getChildren();
213  $parentLevel = $menuTree->getLevel();
214  $childLevel = $parentLevel === null ? 0 : $parentLevel + 1;
215 
216  $counter = 1;
217  $itemPosition = 1;
218  $childrenCount = $children->count();
219 
220  $parentPositionClass = $menuTree->getPositionClass();
221  $itemPositionClassPrefix = $parentPositionClass ? $parentPositionClass . '-' : 'nav-';
222 
224  foreach ($children as $child) {
225  if ($childLevel === 0 && $child->getData('is_parent_active') === false) {
226  continue;
227  }
228  $child->setLevel($childLevel);
229  $child->setIsFirst($counter == 1);
230  $child->setIsLast($counter == $childrenCount);
231  $child->setPositionClass($itemPositionClassPrefix . $counter);
232 
233  $outermostClassCode = '';
234  $outermostClass = $menuTree->getOutermostClass();
235 
236  if ($childLevel == 0 && $outermostClass) {
237  $outermostClassCode = ' class="' . $outermostClass . '" ';
238  $currentClass = $child->getClass();
239 
240  if (empty($currentClass)) {
241  $child->setClass($outermostClass);
242  } else {
243  $child->setClass($currentClass . ' ' . $outermostClass);
244  }
245  }
246 
247  if (is_array($colBrakes) && count($colBrakes) && $colBrakes[$counter]['colbrake']) {
248  $html .= '</ul></li><li class="column"><ul>';
249  }
250 
251  $html .= '<li ' . $this->_getRenderedMenuItemAttributes($child) . '>';
252  $html .= '<a href="' . $child->getUrl() . '" ' . $outermostClassCode . '><span>' . $this->escapeHtml(
253  $child->getName()
254  ) . '</span></a>' . $this->_addSubMenu(
255  $child,
256  $childLevel,
257  $childrenWrapClass,
258  $limit
259  ) . '</li>';
260  $itemPosition++;
261  $counter++;
262  }
263 
264  if (is_array($colBrakes) && count($colBrakes) && $limit) {
265  $html = '<li class="column"><ul>' . $html . '</ul></li>';
266  }
267 
268  return $html;
269  }
270 
277  protected function _getRenderedMenuItemAttributes(\Magento\Framework\Data\Tree\Node $item)
278  {
279  $html = '';
280  $attributes = $this->_getMenuItemAttributes($item);
281  foreach ($attributes as $attributeName => $attributeValue) {
282  $html .= ' ' . $attributeName . '="' . str_replace('"', '\"', $attributeValue) . '"';
283  }
284  return $html;
285  }
286 
293  protected function _getMenuItemAttributes(\Magento\Framework\Data\Tree\Node $item)
294  {
295  $menuItemClasses = $this->_getMenuItemClasses($item);
296  return ['class' => implode(' ', $menuItemClasses)];
297  }
298 
305  protected function _getMenuItemClasses(\Magento\Framework\Data\Tree\Node $item)
306  {
307  $classes = [];
308 
309  $classes[] = 'level' . $item->getLevel();
310  $classes[] = $item->getPositionClass();
311 
312  if ($item->getIsCategory()) {
313  $classes[] = 'category-item';
314  }
315 
316  if ($item->getIsFirst()) {
317  $classes[] = 'first';
318  }
319 
320  if ($item->getIsActive()) {
321  $classes[] = 'active';
322  } elseif ($item->getHasActive()) {
323  $classes[] = 'has-active';
324  }
325 
326  if ($item->getIsLast()) {
327  $classes[] = 'last';
328  }
329 
330  if ($item->getClass()) {
331  $classes[] = $item->getClass();
332  }
333 
334  if ($item->hasChildren()) {
335  $classes[] = 'parent';
336  }
337 
338  return $classes;
339  }
340 
347  public function addIdentity($identity)
348  {
349  if (!in_array($identity, $this->identities)) {
350  $this->identities[] = $identity;
351  }
352  }
353 
359  public function getIdentities()
360  {
361  return $this->identities;
362  }
363 
370  public function getCacheKeyInfo()
371  {
372  $keyInfo = parent::getCacheKeyInfo();
373  $keyInfo[] = $this->getUrl('*/*/*', ['_current' => true, '_query' => '']);
374  return $keyInfo;
375  }
376 
383  protected function getCacheTags()
384  {
385  return array_merge(parent::getCacheTags(), $this->getIdentities());
386  }
387 
397  public function getMenu()
398  {
399  if (!$this->_menu) {
400  $this->_menu = $this->nodeFactory->create(
401  [
402  'data' => [],
403  'idField' => 'root',
404  'tree' => $this->treeFactory->create()
405  ]
406  );
407  }
408  return $this->_menu;
409  }
410 }
elseif(isset( $params[ 'redirect_parent']))
Definition: iframe.phtml:17
_addSubMenu($child, $childLevel, $childrenWrapClass, $limit)
Definition: Topmenu.php:173
_columnBrake($items, $limit)
Definition: Topmenu.php:130
__construct(Template\Context $context, NodeFactory $nodeFactory, TreeFactory $treeFactory, array $data=[])
Definition: Topmenu.php:52
$count
Definition: recent.phtml:13
_getRenderedMenuItemAttributes(\Magento\Framework\Data\Tree\Node $item)
Definition: Topmenu.php:277
_getMenuItemClasses(\Magento\Framework\Data\Tree\Node $item)
Definition: Topmenu.php:305
getHtml($outermostClass='', $childrenWrapClass='', $limit=0)
Definition: Topmenu.php:82
$attributes
Definition: matrix.phtml:13
$children
Definition: actions.phtml:11
_getMenuItemAttributes(\Magento\Framework\Data\Tree\Node $item)
Definition: Topmenu.php:293
$items