1<?php 2/** 3 * webtrees: online genealogy 4 * Copyright (C) 2019 webtrees development team 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * (at your option) any later version. 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 */ 16declare(strict_types=1); 17 18namespace Fisharebest\Webtrees; 19 20/** 21 * System for generating menus. 22 */ 23class Menu 24{ 25 /** @var string The text to be displayed in the mneu */ 26 private $label; 27 28 /** @var string The target URL or href */ 29 private $link; 30 31 /** @var string The CSS class used to style this menu item */ 32 private $class; 33 34 /** @var string[] A list of optional HTML attributes, such as onclick or data-xxx */ 35 private $attrs; 36 37 /** @var Menu[] An optional list of sub-menus. */ 38 private $submenus; 39 40 /** 41 * Constructor for the menu class 42 * 43 * @param string $label The label for the menu item 44 * @param string $link The target URL 45 * @param string $class A CSS class 46 * @param string[] $attrs Optional attributes, such as onclick or data-xxx 47 * @param Menu[] $submenus Any submenus 48 */ 49 public function __construct($label, $link = '#', $class = '', array $attrs = [], array $submenus = []) 50 { 51 $this 52 ->setLabel($label) 53 ->setLink($link) 54 ->setClass($class) 55 ->setAttrs($attrs) 56 ->setSubmenus($submenus); 57 } 58 59 /** 60 * Render this menu using Bootstrap4 markup 61 * 62 * @return string 63 */ 64 public function bootstrap4(): string 65 { 66 if (!empty($this->submenus)) { 67 $submenus = ''; 68 foreach ($this->submenus as $submenu) { 69 $attrs = ''; 70 foreach ($submenu->attrs as $key => $value) { 71 $attrs .= ' ' . $key . '="' . e($value) . '"'; 72 } 73 74 $class = trim('dropdown-item ' . $submenu->class); 75 $submenus .= '<a class="' . $class . '" href="' . e($submenu->link) . '"' . $attrs . '>' . $submenu->label . '</a>'; 76 } 77 78 $class = trim('nav-item dropdown ' . $this->class); 79 80 return 81 '<li class="' . $class . '">' . 82 '<a href="#" class="nav-link dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">' . 83 $this->label . 84 '<span class="caret"></span></a>' . 85 '<div class="dropdown-menu" role="menu">' . 86 $submenus . 87 '</div>' . 88 '</li>'; 89 } 90 91 $attrs = ''; 92 foreach ($this->attrs as $key => $value) { 93 $attrs .= ' ' . $key . '="' . e($value) . '"'; 94 } 95 96 $class = trim('nav-item ' . $this->class); 97 98 return '<li class="' . $class . '"><a class="nav-link" href="' . e($this->link) . '"' . $attrs . '>' . $this->label . '</a></li>'; 99 } 100 101 /** 102 * Get the optional attributes. 103 * 104 * @return string[] 105 */ 106 public function getAttrs(): array 107 { 108 return $this->attrs; 109 } 110 111 /** 112 * Set the optional attributes. 113 * 114 * @param string[] $attrs 115 * 116 * @return $this 117 */ 118 public function setAttrs(array $attrs): self 119 { 120 $this->attrs = $attrs; 121 122 return $this; 123 } 124 125 /** 126 * Get the class. 127 * 128 * @return string 129 */ 130 public function getClass(): string 131 { 132 return $this->class; 133 } 134 135 /** 136 * Set the class. 137 * 138 * @param string $class 139 * 140 * @return $this 141 */ 142 public function setClass($class): self 143 { 144 $this->class = $class; 145 146 return $this; 147 } 148 149 /** 150 * Get the label. 151 * 152 * @return string 153 */ 154 public function getLabel(): string 155 { 156 return $this->label; 157 } 158 159 /** 160 * Set the label. 161 * 162 * @param string $label 163 * 164 * @return $this 165 */ 166 public function setLabel($label): self 167 { 168 $this->label = $label; 169 170 return $this; 171 } 172 173 /** 174 * Get the link. 175 * 176 * @return string 177 */ 178 public function getLink(): string 179 { 180 return $this->link; 181 } 182 183 /** 184 * Set the link. 185 * 186 * @param string $link 187 * 188 * @return $this 189 */ 190 public function setLink($link): self 191 { 192 $this->link = $link; 193 194 return $this; 195 } 196 197 /** 198 * Add a submenu to this menu 199 * 200 * @param Menu $menu 201 * 202 * @return $this 203 */ 204 public function addSubmenu($menu): self 205 { 206 $this->submenus[] = $menu; 207 208 return $this; 209 } 210 211 /** 212 * Render this menu as an HTML list 213 * 214 * @return string 215 */ 216 public function getMenuAsList(): string 217 { 218 $attrs = ''; 219 foreach ($this->attrs as $key => $value) { 220 $attrs .= ' ' . $key . '="' . e($value) . '"'; 221 } 222 if ($this->link) { 223 $link = ' href="' . e($this->link) . '"'; 224 } else { 225 $link = ''; 226 } 227 $html = '<a' . $link . $attrs . '>' . $this->label . '</a>'; 228 if (!empty($this->submenus)) { 229 $html .= '<ul>'; 230 foreach ($this->submenus as $submenu) { 231 $html .= $submenu->getMenuAsList(); 232 } 233 $html .= '</ul>'; 234 } 235 236 return '<li class="' . $this->class . '">' . $html . '</li>'; 237 } 238 239 /** 240 * Get the sub-menus. 241 * 242 * @return Menu[] 243 */ 244 public function getSubmenus(): array 245 { 246 return $this->submenus; 247 } 248 249 /** 250 * Set the sub-menus. 251 * 252 * @param Menu[] $submenus 253 * 254 * @return $this 255 */ 256 public function setSubmenus(array $submenus): self 257 { 258 $this->submenus = $submenus; 259 260 return $this; 261 } 262} 263