https://github.com/tobento-ch/service-menu
A simple and fluent menu builder.
https://github.com/tobento-ch/service-menu
Last synced: about 2 months ago
JSON representation
A simple and fluent menu builder.
- Host: GitHub
- URL: https://github.com/tobento-ch/service-menu
- Owner: tobento-ch
- License: mit
- Created: 2021-06-14T17:13:46.000Z (about 4 years ago)
- Default Branch: 1.x
- Last Pushed: 2024-12-30T16:33:57.000Z (6 months ago)
- Last Synced: 2025-05-08T23:09:57.860Z (about 2 months ago)
- Language: PHP
- Size: 110 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Menu Service
With the Menu Service you can build menus easily.
## Table of Contents
- [Getting started](#getting-started)
- [Requirements](#requirements)
- [Highlights](#highlights)
- [Simple Example](#simple-example)
- [Documentation](#documentation)
- [Menu](#menu)
- [Creating menu items](#creating-menu-items)
- [Creating subitems](#creating-subitems)
- [Additional menu items](#additional-menu-items)
- [Icons](#icons)
- [Badges](#badges)
- [Sorting items](#sorting-items)
- [Iterating items](#iterating-items)
- [On specific item](#on-specific-item)
- [On parent items](#on-parent-items)
- [Active item](#active-item)
- [Get item(s)](#get-items)
- [Tags](#tags)
- [Escaping](#escaping)
- [Menus](#menus)
- [Examples](#examples)
- [Credits](#credits)
___# Getting started
Add the latest version of the Menu service project running this command.
```
composer require tobento/service-menu
```## Requirements
- PHP 8.0 or greater
## Highlights
- Framework-agnostic, will work with any project
- Decoupled design## Simple Example
Here is a simple example of how to use the Menu service.
```php
use Tobento\Service\Menu\Menu;
use Tobento\Service\Menu\Item;
use Tobento\Service\Menu\Link;$menu = (new Menu('footer'))
->add(new Item('about us'))
->add(new Link('/contact', 'contact'))
->add(new Item('team', null, 'about us'));$menu = new Menu('footer');
$menu->item('about us');
$menu->link('/contact', 'contact');
$menu->item('team')->parent('about us');
```Render the menu:
```php
= $menu->render() ?>// or just
= $menu ?>
```Both menus from above will produce the following output.
```html
- about us
- team
- contact
```
# Documentation
## Menu
### Creating menu items
Creating items with the add() method.
```php
use Tobento\Service\Menu\Menu;
use Tobento\Service\Menu\Item;
use Tobento\Service\Menu\Link;
use Tobento\Service\Menu\Html;
$menu = (new Menu('footer'))
->add(new Item('about us'))
->add(new Link('/contact', 'contact'))
->add(new Html('html')); // must be escaped!
```
Creating items with the build in methods.
```php
use Tobento\Service\Menu\Menu;
$menu = new Menu('footer');
$item = $menu->item('about us');
$linkItem = $menu->link('/contact', 'contact');
$htmlItem = $menu->html('html'); // must be escaped!
```
Creating items with the many() method.
```php
use Tobento\Service\Menu\Menu;
$items = [
[
'name' => 'about',
],
[
'name' => 'contact',
],
[
'name' => 'team',
'parent' => 'about',
],
];
$menu = (new Menu('footer'))->many($items, function($menu, $item) {
$menu->link('/'.$item['name'], $item['name'])
->parent($item['parent'] ?? null);
});
```
### Creating subitems
Creating subitems is done by defining the parent item by its id.
```php
use Tobento\Service\Menu\Menu;
use Tobento\Service\Menu\Item;
use Tobento\Service\Menu\Link;
$menu = (new Menu('footer'))
->add(new Item('about us'))
->add(new Item('team', parent: 'about us'));
$menu = new Menu('footer');
$menu->item('about us');
$menu->item('team')->parent('about us');
// or by defining an id
$menu = (new Menu('footer'))
->add(new Item('about us', id: 'about'))
->add(new Item('team', parent: 'about'));
$menu = new Menu('footer');
$menu->item('about us')->id('about');
$menu->item('team')->parent('about');
```
### Additional menu items
**Link To First Child**
The ```LinkToFirstChild``` menu item, links to the first child menu link if exists, otherwise it will not be rendered at all.
```php
use Tobento\Service\Menu\LinkToFirstChild;
use Tobento\Service\Menu\Menu;
$menu = new Menu('main');
$menu->add((new LinkToFirstChild($menu, 'Settings'))->id('settings'));
$menu->link('/locales', 'locales')->parent('settings');
```
### Icons
```php
use Tobento\Service\Menu\Menu;
$menu = new Menu('header');
$menu->link('/login', 'Login')->icon(name: 'login');
// you may define a position for all icons:
$menu->iconPosition('left');
```
**Creating Icons**
By default, icons will not be created at all.
A simple example how to create icons:
```php
use Tobento\Service\Menu\Str;
$menu->each(static function($item, $menu) {
if (!$item->getIcon()) {
return $item;
}
$html = '';
if ($menu->getIconPosition() === 'right') {
$item->tag()->append(html: $html);
} else {
$item->tag()->prepend(html: $html);
}
return $item;
});
```
**Creating Icons With The Icon Service**
You may use the menu icon factory to create icons using the [Icon Service](https://github.com/tobento-ch/service-icon).
```php
use Tobento\Service\Menu\MenuIconsFactory;
use Tobento\Service\Icon\IconsInterface;
$menuFactory = new MenuIconsFactory(
icons: $icons, // IconsInterface
);
$menu = $menuFactory->createMenu(name: 'header');
```
**Render Only Icons**
Use the ```onlyIcons``` method if you want to render the icons only:
```php
$menu->onlyIcons();
```
### Badges
Badges can be used to add additional information to a menu item:
```php
use Tobento\Service\Menu\Menu;
$menu = new Menu('header');
$menu->link('/invoices', 'Invoices')->badge(text: '10', attributes: ['title' => '10 new invoices']);
```
Will output:
```html
```
**Badge If**
You may use the ```badgeIf``` method which renders badges only if the given ```badge``` parameter value validates to ```true```.
```php
use Tobento\Service\Menu\Menu;
$invoiceCount = 10;
$menu = new Menu('header');
$menu->link('/invoices', 'Invoices')->badgeIf(
badge: $invoiceCount > 0, // bool
text: (string)$invoiceCount,
attributes: [],
);
```
### Sorting items
```php
use Tobento\Service\Menu\Menu;
$menu = new Menu('footer');
$menu->item('team');
$menu->item('about');
$menu->sort(fn ($a, $b) => $a->text() <=> $b->text());
```
### Iterating items
By using the filter method:
```php
use Tobento\Service\Menu\Menu;
$menu = new Menu('footer');
$menu->item('team');
$menu->item('about');
$menu->filter(fn($i) => $i->text() === 'team');
```
By using the each method having access to data tree and tags:
```php
use Tobento\Service\Menu\Menu;
$menu = new Menu('footer');
$menu->item('team');
$menu->item('about');
$menu->each(function($item, $menu) {
$parentTag = $item->parentTag();
$itemTag = $item->itemTag();
$treeLevel = $item->getTreeLevel();
$treeId = $item->getTreeId();
$treeParent = $item->getTreeParent();
$treeParentItem = $item->getTreeParentItem();
$treeChildren = $item->getTreeChildren();
return $item;
});
```
### On specific item
```php
use Tobento\Service\Menu\Menu;
$menu = new Menu('footer');
$menu->item('team');
$menu->item('about');
$menu->on('team', function($item, $menu) {
$item->itemTag()->class('foo');
$item->parentTag()->class('bar');
return $item;
});
```
```html
```
### On parent items
```php
use Tobento\Service\Menu\Menu;
$menu = new Menu('footer');
$menu->item('team')->parent('about');
$menu->item('about');
$menu->item('contact');
$menu->onParents('team', function($item, $menu) {
$item->itemTag()->class('foo');
return $item;
});
```
```html
- about
- team
- contact
```
### Active item
```php
use Tobento\Service\Menu\Menu;
$menu = new Menu('footer');
$menu->item('team')->parent('about');
$menu->item('about');
$menu->item('contact');
$menu->item('form')->parent('contact');
// set the form item and all its parent items active.
$menu->active('form');
```
```html
- about
- team
- contact
- form
```
Render only active tree items:
```php
use Tobento\Service\Menu\Menu;
$menu = new Menu('footer');
$menu->item('team')->parent('about');
$menu->item('about');
$menu->item('contact');
$menu->item('form')->parent('contact');
// set the form item active.
$menu->active('form');
// do not render any inactive tree items.
$menu->subitems(false);
```
```html
- about
- contact
- form
```
Set the items active on the item itself:
```php
use Tobento\Service\Menu\Menu;
$menu = new Menu('footer');
$menu->item('team')->parent('about');
$menu->item('about');
$menu->item('contact')->active();
$menu->item('form')->parent('contact')->active();
// do no render any inactive tree items.
$menu->subitems(false);
```
```html
- about
- contact
- form
```
### Get item(s)
Note: Items tree data and tags are not available yet, except item tag.
Get single item:
```php
use Tobento\Service\Menu\Menu;
$menu = new Menu('footer');
$menu->item('team');
$menu->get('team')->itemTag()->class('active');
```
Get all items:
```php
use Tobento\Service\Menu\Menu;
$menu = new Menu('footer');
$menu->item('team');
$items = $menu->all();
```
### Tags
With tags you can manage the menu tags being rendered.
#### Menu Tags
```php
use Tobento\Service\Menu\Menu;
use Tobento\Service\Menu\Tag;
use Tobento\Service\Menu\NullTag;
$menu = new Menu('footer');
// add class foo to every ul tag.
$menu->tag('ul')->class('foo');
// add class foo only to every ul tag with depth level 1.
$menu->tag('ul')->level(1)->class('foo');
// add class foo to every li tag.
$menu->tag('li')->class('foo');
// add class foo and bar only to every li tag with depth level 2.
$menu->tag('li')->level(2)->class('foo')->class('bar');
// add any attribute with the attr() method.
$menu->tag('li')->attr('data-foo', '1');
// change every ul tag to ol tag.
$menu->tag('ul')->handle(fn() => new Tag('ol'));
// assign current level so that other
// level tag attributes get assigned.
$menu->tag('ul')->handle(fn(Tag $t) => (new Tag('ol'))->level($t->getLevel()));
// change every ul tag to div tag.
$menu->tag('ul')->handle(fn() => new Tag('div'));
// change every li tag to a null tag and prepend and append a character.
$menu->tag('li')->handle(fn() => (new NullTag())->prepend('[')->append(']'));
// get tag attributes.
$attributes = $menu->tag('li')->attributes();
// check if there are any attributes.
$empty = $attributes->empty();
// check if there is a specific attribute.
$hasClassAttr = $attributes->has('class');
// get any attribute.
$classAttr = $attributes->get('class');
// get any attribute.
$classAttr = $attributes->get('class');
// get all attributes.
$allAttributes = $attributes->all();
// set an attribute.
$attributes->set('data-foo', '1');
// add an attribute (merges).
$attributes->add('data-foo', '1');
// merge an attribute.
$attributes->merge('data-foo', '1');
```
#### Item Tags
```php
use Tobento\Service\Menu\Menu;
$menu = new Menu('footer');
$item = $menu->link('/contact', 'contact');
// The item tag.
$item->itemTag()->class('bar');
// The tag: link items have for instance its own tag. The a tag.
$item->tag()->class('foo');
// The parent tag is not yet available.
var_dump($item->parentTag()); // NULL
// Use each(), on(), onParents() methods if you need to manage the parent tag.
```
### Escaping
Html escaping is done for you on rendering the menu. Except on the Tag class you will need to do it by yourself:
```php
use Tobento\Service\Menu\Tag;
$tag = new Tag('a', htmlspecialchars('html', ENT_QUOTES, 'UTF-8'));
$tag->content(htmlspecialchars('html', ENT_QUOTES, 'UTF-8'));
$tag->append(htmlspecialchars('html', ENT_QUOTES, 'UTF-8'));
$tag->prepend(htmlspecialchars('html', ENT_QUOTES, 'UTF-8'));
```
## Menus
```php
use Tobento\Service\Menu\Menus;
use Tobento\Service\Menu\Menu;
// Create menus.
$menus = new Menus();
// Create menus with a custom menu factory.
$menus = new Menus(new CustomMenuFactory());
// Add a menu.
$menus->add(new Menu('main'));
// Get the main menu. If it does not exist, it returns null.
$menus->get('main');
// Get the main menu. If it does not exist, it creates a new one.
$menus->menu('main')
->item('about')
->order(1000);
```
## Examples
### Add active class to active item only
```php
use Tobento\Service\Menu\Menu;
$menu = new Menu('footer');
$menu->item('team')->parent('about');
$menu->item('about');
$menu->item('contact');
$menu->item('form')->parent('contact');
$menu->on('form', function($item, $menu) {
$item->itemTag()->class('active');
$item->parentTag()->class('active');
return $item;
});
```
```html
- about
- team
- contact
- form
```
### Add active class to active items
```php
use Tobento\Service\Menu\Menu;
$menu = new Menu('footer');
$menu->item('team')->parent('about');
$menu->item('about');
$menu->item('contact');
$menu->item('form')->parent('contact');
$menu->onParents('form', function($item, $menu) {
$item->itemTag()->class('active');
if ($item->getTreeLevel() > 0) {
$item->parentTag()->class('active');
}
$item->tag()->class('active');
return $item;
});
// do only render active tree.
$menu->active('form')
->subitems(false);
```
```html
- about
-
contact
- form
```
# Credits
- [Tobias Strub](https://www.tobento.ch)
- [All Contributors](../../contributors)