An open API service indexing awesome lists of open source software.

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.

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


```
# 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


  • team

  • about


```

### 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


```

# Credits

- [Tobias Strub](https://www.tobento.ch)
- [All Contributors](../../contributors)