Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Menu Bundle Laravel Package

aropixel/menu-bundle

View on GitHub
Deep Wiki
Context7
## Getting Started

### Minimal Setup
1. **Installation**:
   ```bash
   composer require aropixel/menu-bundle

Ensure aropixel/admin-bundle is already installed.

  1. Configuration: Add to config/packages/aropixel_menu.yaml:

    aropixel_menu:
        menus:
            main:
                name: "Main Menu"
                depth: 3
    
  2. Database: Run migrations:

    php bin/console doctrine:migrations:migrate
    
  3. Routes: Include in config/routes.yaml:

    aropixel_menu:
        resource: '@AropixelMenuBundle/Resources/config/routes.yaml'
        prefix: /admin
    
  4. First Use Case: Access /admin/menu to manage the "Main Menu" via the drag-and-drop interface. Use built-in sources (e.g., pages, links) to populate the menu.


Implementation Patterns

Core Workflow

  1. Admin Management:

    • Use the drag-and-drop interface to structure menus (e.g., main, footer).
    • Leverage built-in sources (link, page, section) or extend with custom sources (e.g., ProductMenuSource).
  2. Frontend Rendering: Use Twig functions/filters in templates:

    {# Render a menu #}
    <nav>
        {% for item in get_menu('main') %}
            {% if item|is_section %}
                <div>{{ item.title }}</div>
            {% else %}
                <a href="{{ item|get_link }}" {{ item.newTab ? 'target="_blank"' : '' }}>
                    {{ item.title }}
                </a>
            {% endif %}
        {% endfor %}
    </nav>
    
  3. Custom Entity Integration: Extend the base Menu entity to add fields (e.g., newTab):

    #[ORM\Entity]
    class Menu extends BaseMenu {
        #[ORM\Column(type: 'boolean')]
        private bool $newTab = false;
    }
    

    Update config:

    aropixel_menu:
        entity: App\Entity\Menu
    
  4. Custom Data Sources: Implement MenuSourceInterface for dynamic content (e.g., products):

    class ProductMenuSource implements MenuSourceInterface {
        public function getAvailableItems(array $menuItems): array {
            return $this->productRepository->findAll()->map(fn($p) => [
                'value' => $p->getId(),
                'label' => $p->getName(),
                'type' => 'product',
            ]);
        }
        // ... other required methods
    }
    
  5. Nested Menus: Configure depth in YAML and iterate recursively in Twig:

    {% for item in get_menu('main') %}
        <li>
            <a href="{{ item|get_link }}">{{ item.title }}</a>
            {% if item.children|length > 0 %}
                <ul>
                    {% include 'menu/_nested.html.twig' with {'items': item.children} %}
                </ul>
            {% endif %}
        </li>
    {% endfor %}
    

Gotchas and Tips

Pitfalls

  1. Entity Configuration:

    • Forgetting to update aropixel_menu.entity in config after extending the base Menu entity will cause runtime errors.
    • Fix: Always verify the config after customizing entities.
  2. Source Registration:

    • Custom sources must implement all methods in MenuSourceInterface (e.g., resolveUrl(), getPayload()).
    • Fix: Use the provided skeleton and test incrementally.
  3. Stimulus Controller:

    • If using Symfony UX Stimulus, ensure the aropixel-menu controller is auto-loaded (no manual assets/controllers.json needed since v2.3).
    • Fix: Clear cache (php bin/console cache:clear) if the drag-and-drop UI fails to load.
  4. Nested Menus:

    • Depth > 2 may break if not configured in YAML (e.g., depth: 3).
    • Fix: Set depth explicitly for each menu.
  5. Page Source:

    • Requires aropixel/page-bundle (v2.0+). If missing, pages won’t appear in the selector.
    • Fix: Install the PageBundle or use link sources temporarily.
  6. Caching Issues:

    • Menus may appear stale after updates due to Symfony cache. Clear it after changes:
      php bin/console cache:clear
      

Debugging Tips

  1. Check Registered Sources: Dump available sources in a Twig template:

    {{ dump(app.container.get('aropixel_menu.source_chain').getSources()) }}
    
  2. Log Menu Data: Override the getMenuItems method in a custom MenuHandler to log queries:

    class CustomMenuHandler extends MenuHandler {
        public function getMenuItems(string $menuCode): array {
            $items = parent::getMenuItems($menuCode);
            \Log::info('Menu items for '.$menuCode, ['items' => $items]);
            return $items;
        }
    }
    
  3. Twig Filter Debugging: Test |get_link with {{ item|get_link|dump }} to verify URL resolution.

  4. Database Schema: If migrations fail, manually check the menu table structure. The bundle expects:

    • id, title, type, link, parent_id, lft, rgt (for nested sets).

Extension Points

  1. Custom Menu Handlers: Extend MenuHandler to modify menu logic (e.g., filtering items):

    class CustomMenuHandler extends MenuHandler {
        public function getMenuItems(string $menuCode): array {
            $items = parent::getMenuItems($menuCode);
            return array_filter($items, fn($item) => $item->isActive());
        }
    }
    

    Register as a service with the aropixel_menu.menu_handler tag.

  2. Override Twig Templates: Customize the admin UI by overriding templates in templates/AropixelMenuBundle/ (e.g., menu/edit.html.twig).

  3. Dynamic Menu Codes: Fetch menu codes dynamically via a service and inject them into the config:

    aropixel_menu:
        menus: '%menu_codes%'
    
    // config/services.yaml
    parameters:
        menu_codes: ['main', 'footer', '%env(MENU_CODE)%']
    
  4. Validation: Add custom validation to menu items via a Constraint and Validator:

    #[Assert\Callback]
    public function validate(ExecutionContextInterface $context) {
        if ($this->type === 'page' && empty($this->link)) {
            $context->buildViolation('Page link is required')->addViolation();
        }
    }
    
  5. Performance: For large menus, optimize queries by:

    • Adding indexes to parent_id and type columns.
    • Using DQL to fetch only active/published items:
      $qb->andWhere('m.published = :published')->setParameter('published', true);
      

Pro Tips

  1. Multi-Language Menus: Extend the Menu entity to support translations:

    #[ORM\Column(type: 'string', length: 255)]
    private ?string $titleEn = null;
    
    #[ORM\Column(type: 'string', length: 255)]
    private ?string $titleFr = null;
    

    Update getAvailableItems() in sources to filter by locale.

  2. Menu Previews: Add a preview field to the Menu entity and use it in the admin template:

    <img src="{{ item.previewUrl }}" alt="{{ item.title }}" width="50">
    
  3. Menu Events: Listen for menu updates via Symfony events (e.g., aropixel.menu.pre_save):

    // config/services.yaml
    App\EventListener\MenuUpdateListener:
        tags:
            - { name: kernel.event_listener, event: aropixel.menu.pre_save, method: onMenuUpdate }
    
  4. API Integration: Expose menus via API using Symfony’s JsonResponse:

    #[Route('/api/menus/{code}', name: 'api_menu_get', methods: ['GET'])]
    public function getMenu(string $code, MenuHandler $handler): JsonResponse {
        return new JsonResponse($handler->getMenuItems($code));
    }
    
  5. Testing: Use the MenuHandler in PHPUnit tests to verify menu structure:

    public function testMainMenuStructure() {
        $handler = $this->container->get(MenuHandler::class);
        $menu = $handler->getMenuItems('main');
        $this->assertCount(3, $menu);
        $this->assertEquals('Home',
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
emuniq/filament-browser-notifications
syriable/filament-translator
hungnm28/livewire-form
wenprise/eloquent
crudly/encrypted
fadion/bouncy
cuci/prototurk-sdk
gos/pubsub-router-bundle
cuci/prototurk-sdk-symfony
clementtalleu/easyadmin-markdown-bundle
codeflextech/permission-manager
karnoweb/livewire-datepicker
sayedenam/sayed-dashboard
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui