{"id":20300943,"url":"https://github.com/rinvex/laravel-menus","last_synced_at":"2025-04-11T13:33:18.739Z","repository":{"id":45090606,"uuid":"114586319","full_name":"rinvex/laravel-menus","owner":"rinvex","description":"Rinvex Menus is a simple menu builder package for Laravel, that supports hierarchical structure, ordering, and styling with full flexibility using presenters for easy styling and custom structure of menu rendering.","archived":false,"fork":false,"pushed_at":"2023-09-01T08:39:30.000Z","size":200,"stargazers_count":30,"open_issues_count":3,"forks_count":9,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-06-18T23:02:21.811Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rinvex.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-12-18T02:20:26.000Z","updated_at":"2024-04-30T19:40:01.000Z","dependencies_parsed_at":"2024-06-18T22:54:53.165Z","dependency_job_id":null,"html_url":"https://github.com/rinvex/laravel-menus","commit_stats":{"total_commits":135,"total_committers":6,"mean_commits":22.5,"dds":0.03703703703703709,"last_synced_commit":"233e849c0849a04994a78cc92eeff14b8d8671c5"},"previous_names":[],"tags_count":28,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rinvex%2Flaravel-menus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rinvex%2Flaravel-menus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rinvex%2Flaravel-menus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rinvex%2Flaravel-menus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rinvex","download_url":"https://codeload.github.com/rinvex/laravel-menus/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224651567,"owners_count":17347201,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-14T16:22:32.347Z","updated_at":"2024-11-14T16:22:33.102Z","avatar_url":"https://github.com/rinvex.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Rinvex Menus\n\n**Rinvex Menus** is a simple menu builder package for Laravel, that supports hierarchical structure, ordering, and styling with full flexibility using presenters for easy styling and custom structure of menu rendering.\n\n[![Packagist](https://img.shields.io/packagist/v/rinvex/laravel-menus.svg?label=Packagist\u0026style=flat-square)](https://packagist.org/packages/rinvex/laravel-menus)\n[![Scrutinizer Code Quality](https://img.shields.io/scrutinizer/g/rinvex/laravel-menus.svg?label=Scrutinizer\u0026style=flat-square)](https://scrutinizer-ci.com/g/rinvex/laravel-menus/)\n[![Travis](https://img.shields.io/travis/rinvex/laravel-menus.svg?label=TravisCI\u0026style=flat-square)](https://travis-ci.org/rinvex/laravel-menus)\n[![StyleCI](https://styleci.io/repos/114586319/shield)](https://styleci.io/repos/114586319)\n[![License](https://img.shields.io/packagist/l/rinvex/laravel-menus.svg?label=License\u0026style=flat-square)](https://github.com/rinvex/laravel-menus/blob/develop/LICENSE)\n\n\n## Credits notice\n\nThis package is a rewritten fork of [nWidart/laravel-menus](https://github.com/nWidart/laravel-menus), which itself is a fork of [pingpong-labs/menus](https://github.com/pingpong-labs/menus), original credits goes to them both. It's been widely rewritten to drop technical debt and remove legacy code, so be aware that the API is different and not compatible with the original package(s) for good. The main goals behind this fork was to:\n\n- Simplify menu registration\n- Clean code and enhance readability\n- Enable sorting order feature by default\n- Remove legacy code, and drop technical debt\n- Allow extensibility with minimum or no core changes\n- Enforce consistency and straighten API to be intuitive\n- New sidebar menu feature, to treat dropdowns differently\n- Integrate with Laravel [Authentication](https://laravel.com/docs/master/authentication) and [Authorization](https://laravel.com/docs/master/authorization) features to streamline hiding/displaying menus according to permissions\n\n\n## Installation\n\n1. Install the package via composer:\n    ```shell\n    composer require rinvex/laravel-menus\n    ```\n\n2. **Optionally** you can publish view files by running the following commands:\n    ```shell\n    php artisan vendor:publish --tag=\"rinvex-menus-views\"\n    ```\n\n3. Done!\n\n\n## Usage\n\n### Create new menu\n\nTo register a new menu, simply call `Menu::register()` method. It takes two parameters, the first one is the menu title and the second one is a callback for defining menu items. See the following example:\n\n```php\nuse Rinvex\\Menus\\Models\\MenuItem;\nuse Rinvex\\Menus\\Models\\MenuGenerator;\n\nMenu::register('frontend.sidebar', function(MenuGenerator $menu) {\n    // Add menu header\n    $menu-\u003eheader('Header Title');\n\n    // Add url menu item\n    $menu-\u003eurl('url/path', 'Menu Title #1');\n\n    // Add route menu item\n    $menu-\u003eroute(['route.name'], 'Menu Title #2');\n\n    // Add menu divider\n    $menu-\u003edivider();\n\n    // Add menu dropdown (it can have childs too)\n    $menu-\u003edropdown(function(MenuItem $dropdown) {\n        $dropdown-\u003eheader('Child Header Title');\n        $dropdown-\u003eurl('url/path', 'Child Menu Title #1');\n        $dropdown-\u003eroute(['route.name'], 'Child Menu Title #2');\n        $dropdown-\u003edivider();\n    }, 'Dropdown Title', 50, 'fa fa-arrows', ['data-attribute' =\u003e 'something']);\n});\n```\n\nAll the `url`, `route`, `header`, and `dropdown` methods has a standard API like: `$menu-\u003emethod('data', 'title', 'order', 'icon', 'linkAttributes', 'itemAttributes')` that's intutive and self explanatory. Only the first parameter is mandatory and different for each method, but the rest are all the same and optional. `header` accepts string title, `url`: string link, `route`: array with string route name and optionally route parameters, `dropdown`: callback for child items definition, other parameters are optional.\n\n\u003e **Notes:**\n\u003e - Menu items are ordered in ascending order by default. If you don't need sorting, just ignore the `order` parameter when defining your menus as it's optional anyway. That way menu items will be displayed in the order they've been added.\n\u003e - The `icon` parameter takes a css class name, like `fa fa-user` for fontawesome, and the `linkAttributes` parameter takes array of any additional HTML attributes you would like to add to your menu item.\n\u003e - You can create a multi-level menu items by creating child dropdown menus inside parent dropdown menus, and it has no limit, so you can create the structure you need as deep as you want.\n\u003e - You can create multiple menus with different names using the `Menu::register()` method, and call them in different places. Like if you want a topbar menu, and a sidebar menu ..etc\n\n\n### Modify existing menu\n\nTo modify an existing menu item that's already been added somewhere else in the code you can use the same registration method:\n\n```php\nMenu::register('frontend.sidebar', function(MenuGenerator $menu) {\n    // Add url menu item above the dropdown we created before\n    $menu-\u003eurl('different/path', 'Menu Title #3', 40);\n});\n```\n\nAs you can see, we just modified the `frontend.sidebar` menu, and added a new url menu item under the divider, above the dropdown. See, it's that simple!\n\nAlternatively you can get a handle of the menu you need to modify, and then use it as you prefer, like so:\n\n```php\n$sidebar = Menu::instance('frontend.sidebar');\n$sidebar-\u003eurl('new/url', 'Menu Title #4', 40);\n$sidebar-\u003eroute('some.new.route', 'Menu Title #5', 60);\n```\n\n#### Hide menus conditionally\n\nTo simply hide any of your menu items, you can use any of the following methods:\n\n```php\n$sidebar-\u003eurl('one/more/url', 'One more new item')-\u003ehideWhen(function () {\n    return true; // Any expression\n});\n```\n\nAs you can see, the `hideWhen` method takes a closure that returns true or false. If true returned the menu item will be hidden, otherwise it will be displayed, so you can put whatever logic here to be evaluated.\n\nAnd as a syntactic sugar, there's few more methods that makes life easier! See the `ifUser`, `ifGuest`, and `ifCan` methods:\n\n```php\n// Only display if logged condition is true\n$sidebar-\u003eurl('one/more/url', 'One more new item')-\u003eif(true);\n\n// Only display if logged in user (authenticated)\n$sidebar-\u003eurl('one/more/url', 'One more new item')-\u003eifUser();\n\n// Only display if guest not yet authenticated\n$sidebar-\u003eurl('one/more/url', 'One more new item')-\u003eifGuest();\n\n// Only display if logged in user has required ability (authorization)\n$sidebar-\u003eurl('one/more/url', 'One more new item')-\u003eifCan('do-some-ability');\n```\n\nSure, as you expected all these methods works smoothly and fully integrated with Laravel's default [Authentication](https://laravel.com/docs/master/authentication) and [Authorization](https://laravel.com/docs/master/authorization) features.\n\nTo make it easy to control menu hide states, you can chain all hide methods infinitely and all hide callbacks will be stacked and executed in order. It will stop execution with the first positive condition result. Example:\n\n```php\n// Only display if logged in user has required ability (authorization)\n$sidebar-\u003eurl('one/more/url', 'One more new item')-\u003eifUser()-\u003eifCan('do-some-ability')-\u003ehideWhen(function () {\n    return true; // Any expression\n});\n```\n\nThis example means that menu will only displayed for users, who has `do-some-ability` permission, and also when the `hideWhen` callback expression returns true.\n\n#### Activate menus conditionally\n\nTo activate menus conditionally based on route name, you can set the route prefix to match against. If the current route name contains that prefix, then the menu item will be activated automatically. That way we can activate parent menu items by accessing child pages. Example:\n\n```php\n$menu-\u003eroute(['route.name.example'], 'Menu Title #2')-\u003eactivateOnRoute('route.name');\n```\n\nNow when we access any route prefixed by `route.name`, our menu with the `route.name.example` route will be activated automatically.\n\nAlternatively, you can fully control when that menu item is beeing activated by adding your own logic within callback that resolve to boolean, as follows:\n\n```php\n$menu-\u003eroute(['route.name.example'], 'Menu Title #2')-\u003eactivateWhen(function () {\n    return true; // Any expression\n});\n```\n\n### Search for existing menu item\n\nYou can also search for a specific menu item, a dropdown for example using `findBy` and add child items to it directly. The `findBy` method can search inside your menus by any attribute and take two required parameters, the attribute name \u0026 value to search by, and optionaly you can pass a third parameter as a callback to define child items (a way to modify the dropdown in one go).\n\n```php\nMenu::register('frontend.sidebar', function(MenuGenerator $menu) {\n    $menu-\u003efindBy('title', 'Dropdown Title', function (MenuItem $dropdown) { // Seach items by title\n        $dropdown-\u003eroute(['the.newest.route'], 'Yet another menu item', 15, 'fa fa-building-o');\n    });\n});\n```\n\nIf you need to update a specific menu item, or for example you need to change the url or rename the title, that's totally achievable too using the same method above with one simple tweak:\n\n```php\nMenu::register('frontend.sidebar', function(MenuGenerator $menu) {\n    $menu-\u003efindBy('title', 'Yet another menu item', function (MenuItem $item) {\n        $item-\u003efill(['icon' =\u003e 'fa fa-business]);\n    });\n});\n```\n\nThis code search for a menu item titled 'Yet another menu item' and update only it's icon. The `fill` method accepts an array with any properties you'd like to update, and merge it with the originals, resulting an overridden menu item definition.\n\n\n### Menu presenters\n\nRendering menus is the easiest part, but let's discover first few interesting concepts utilized by this package, Presenters!\n\nPresenters are like layout drivers that defines the way your menus are rendered, and it could be different for each and every menu. Let's make it simple by explained example, if you have multiple sections in your project that uses different CSS frameworks, like vanilla bootstrap and AdminLTE, you can create two different presenters for both (fortunately these two already built in out-of-the-box, but you can build your own for any other framework). The way it work is by creating the presenter, register it with the package, and just use it's name. So in short, your menu definition never change even if you changed the whole layout or even shifted to another CSS framework, you just need to change your presenter.\n\nPresenters are used also to define the different layouts for your menu structure, that way you can use menus to build navbars, dropdowns, or even tabs. It's all yours and the same code. Just hook your presenter and you're ready to go. By default there's few presenters built in for you out-of-the-box:\n\n- `navbar` \\Rinvex\\Menus\\Presenters\\NavbarPresenter\n- `navbar-right` \\Rinvex\\Menus\\Presenters\\NavbarRightPresenter\n- `nav-pills` \\Rinvex\\Menus\\Presenters\\NavPillsPresenter\n- `nav-tab` \\Rinvex\\Menus\\Presenters\\NavTabPresenter\n- `sidebar` \\Rinvex\\Menus\\Presenters\\SidebarMenuPresenter\n- `navmenu` \\Rinvex\\Menus\\Presenters\\NavMenuPresenter\n- `adminlte` \\Rinvex\\Menus\\Presenters\\AdminltePresenter\n\nAll are based on Bootstrap except for AdminLTE, but you can build your own. You always use the alias, not the full class path.\n\n#### Create new presenter\n\nTo build your own presenter you need to:\n\n- Create a new PHP class that implements `\\Rinvex\\Menus\\Contracts\\PresenterContract`.\n- Register your presenter with the package: `app('rinvex.menus.presenters')-\u003eput('new-presenter', \\Your\\New\\Presenter\\ClassPresenter::class)`\n\nThat's it, your new presenter is ready to be used by it's name `new-presenter`. See `Rinvex\\Menus\\Presenters\\AdminltePresenter` source code for real example.\n\n#### View presenters\n\nIn addition to the class-based presenters explained above, you can use view-based presenters as well. Fortunately there's also built in bootstrap views to be used and you can create your own too.\n\nThere's nothing complex here to be explained, just think of view presenters as normal Laravel views, because it is really are, nothing special. The only difference is when you render the menus, you can set your prefered presenter. View-based presenters has precedence over class-based presenters if both supplied, but if none supplied it will fallback to the default class-based built-in presenters. By default there's few view-based presenters built in for you out-of-the-box:\n\n- `rinvex/menus::menu` Plain Menu\n- `rinvex/menus::default` Bootstrap Navbar (default)\n- `rinvex/menus::navbar-left` Bootstrap Navbar Left\n- `rinvex/menus::navbar-right` Bootstrap Navbar Right\n- `rinvex/menus::nav-tabs` Bootstrap Nav Tabs\n- `rinvex/menus::nav-tabs-justified` Bootstrap Nav Tabs Justified\n- `rinvex/menus::nav-pills` Bootstrap Nav Pills\n- `rinvex/menus::nav-pills-stacked` Bootstrap Nav Pills Stacked\n- `rinvex/menus::nav-pills-justified` Bootstrap Nav Pills Justified\n\n\n### Render existing menu\n\nTo render a menu you can use the `Menu::render()` method as follows:\n\n```php\nMenu::render('frontend.sidebar');\n```\n\nAs you will see in the method definition, there's three more optional parameters to be explained: `public function render(string $name, string $presenter = null, array $bindings = [], bool $specialSidebar = false)`. The `presenter` parameter specify how the menu is being rendered, the `bindings` is a simple way to search and replace title placeholders (more on this below), and the `specialSidebar` is a flag to treat sidebar dropdowns differently by displaying headers above each group instead of collapsible dropdowns (beta feature).\n\n#### Data binding\n\nWhen you define a new menu, you can put placeholders in titles, and then when rendering you can pass bindings to be replaced at runtime. Interesting, right? See the following example:\n\n```php\n// Define new menu item with title placeholder\n$sidebar = Menu::instance('frontend.sidebar');\n$sidebar-\u003eurl('very/new/url', 'Welcome {user}');\n\n// Render menu and bind data on runtime\nMenu::render('frontend.sidebar', null, ['user' =\u003e 'Omran']);\n```\n\nAs you can see we defined a new menu item with a `{user}` placeholder, and when we rendered the menu we passed the required data to be bound. It will do search/replace on runtime and so you can pass any dynamic data within menu item titles.\n\n#### Change default presenter\n\nYou can change default presenters either on menu definition or on menu rendering step, but it's always prefered to do so on runtime rendering to have a stable unchanged menu structure, while keeping layout related changes like presenters on the frontend layer.\n\nHere's how to change presenters both ways:\n\n```php\n// Change menu presenter on definition\n$sidebar = Menu::instance('frontend.sidebar');\n$sidebar-\u003esetView('view-name'); // Set view-based presenter\n$sidebar-\u003esetPresenter('presenter-name'); // Set class-based presenter\n\n// Change menu presenter on rendering\nMenu::render('frontend.sidebar', 'view-name'); // Set view-based presenter\nMenu::render('frontend.sidebar', 'presenter-name'); // Set class-based presenter\n```\n\nYou don't need to worry about how this package works and how does it know whether the supplied presenter is view-based or class-based, but keep in mind that view-based presenters has precedence over class-based presenters, so this package will search for existing view-presenter with the supplied name, if found it will be used and returned immediately, otherwise it will search secondly for class-based presenters with the supplied name.\n\n\n## Changelog\n\nRefer to the [Changelog](CHANGELOG.md) for a full history of the project.\n\n\n## Support\n\nThe following support channels are available at your fingertips:\n\n- [Chat on Slack](https://bit.ly/rinvex-slack)\n- [Help on Email](mailto:help@rinvex.com)\n- [Follow on Twitter](https://twitter.com/rinvex)\n\n\n## Contributing \u0026 Protocols\n\nThank you for considering contributing to this project! The contribution guide can be found in [CONTRIBUTING.md](CONTRIBUTING.md).\n\nBug reports, feature requests, and pull requests are very welcome.\n\n- [Versioning](CONTRIBUTING.md#versioning)\n- [Pull Requests](CONTRIBUTING.md#pull-requests)\n- [Coding Standards](CONTRIBUTING.md#coding-standards)\n- [Feature Requests](CONTRIBUTING.md#feature-requests)\n- [Git Flow](CONTRIBUTING.md#git-flow)\n\n\n## Security Vulnerabilities\n\nIf you discover a security vulnerability within this project, please send an e-mail to [help@rinvex.com](help@rinvex.com). All security vulnerabilities will be promptly addressed.\n\n\n## About Rinvex\n\nRinvex is a software solutions startup, specialized in integrated enterprise solutions for SMEs established in Alexandria, Egypt since June 2016. We believe that our drive The Value, The Reach, and The Impact is what differentiates us and unleash the endless possibilities of our philosophy through the power of software. We like to call it Innovation At The Speed Of Life. That’s how we do our share of advancing humanity.\n\n\n## License\n\nThis software is released under [The MIT License (MIT)](LICENSE).\n\n(c) 2016-2022 Rinvex LLC, Some rights reserved.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frinvex%2Flaravel-menus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frinvex%2Flaravel-menus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frinvex%2Flaravel-menus/lists"}