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

Easyadmin Breadcrumbs Laravel Package

alshenetsky/easyadmin-breadcrumbs

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the package:

    composer require alshenetsky/easyadmin-breadcrumbs
    

    Ensure your project meets the requirements: EasyAdmin 4.5+, PHP 8.0+, and Symfony 5.4+.

  2. Create a breadcrumb class for your first CRUD action (e.g., UserIndexBreadcrumb):

    // src/Controller/Admin/Breadcrumb/UserIndexBreadcrumb.php
    namespace App\Controller\Admin\Breadcrumb;
    
    use Alshenetsky\EasyAdminBreadcrumbs\Breadcrumb\AbstractBreadcrumb;
    use Alshenetsky\EasyAdminBreadcrumbs\Breadcrumb\BreadcrumbType;
    use App\Entity\User;
    
    class UserIndexBreadcrumb extends AbstractBreadcrumb
    {
        public function getType(): BreadcrumbType { return BreadcrumbType::INDEX; }
        public function getEntityFqdn(): string { return User::class; }
        public function getName(): string { return 'Users'; }
    }
    
  3. Override EasyAdmin’s layout to render breadcrumbs:

    {# templates/bundles/EasyAdminBundle/layout.html.twig #}
    {% extends '@EasyAdmin/layout.html.twig' %}
    {% block content_header_wrapper %}
        {{ breadcrumbs() }}
        {{ parent() }}
    {% endblock %}
    
  4. Clear cache and test:

    php bin/console cache:clear
    

First Use Case

Add breadcrumbs to a list view (e.g., /admin/user). The UserIndexBreadcrumb class above will automatically render a "Users" breadcrumb when the index action of the User CRUD is accessed.


Implementation Patterns

Core Workflow

  1. Define Breadcrumb Hierarchy:

    • Create a class for each breadcrumb level (e.g., UserIndexBreadcrumb, UserEditBreadcrumb).
    • Use getParent() to link child breadcrumbs to their parents.
    • Example:
      class UserEditBreadcrumb extends AbstractBreadcrumb
      {
          public function getParent(): ?string { return UserIndexBreadcrumb::class; }
          // ...
      }
      
  2. Gather and Provide Data:

    • Use gather() to extract data from AdminContext (e.g., filters, entity IDs).
    • Use provide() to pass data up the hierarchy for parent breadcrumbs.
    • Example:
      public function gather(AdminContext $context): BreadcrumbData
      {
          return parent::gather($context)
              ->set('userId', $context->getEntity()->getId());
      }
      
      public function provide(BreadcrumbData $data): BreadcrumbData
      {
          return parent::provide($data)
              ->set('userId', $data->get('userId'));
      }
      
  3. Configure Dynamic Content:

    • Use configure() to set names, URLs, or filters dynamically.
    • Example:
      public function configure(BreadcrumbData $data): void
      {
          $this->setName('Editing User #'.$data->get('userId'))
               ->setUrl($this->getDefaultUrl()->setEntityId($data->get('userId')));
      }
      
  4. Handle Edge Cases:

    • Use supports() to conditionally render breadcrumbs (e.g., based on filters).
    • Example:
      public function supports(AdminContext $context): bool
      {
          return $context->getRequest()->query->has('active');
      }
      
  5. Nested CRUD Navigation:

    • For cross-CRUD navigation (e.g., UserEditBreadcrumbOrderIndexBreadcrumb), pass filter data via provide().
    • Example:
      class OrderIndexBreadcrumb extends AbstractBreadcrumb
      {
          public function gather(AdminContext $context): BreadcrumbData
          {
              return parent::gather($context)
                  ->set('userId', $context->getRequest()->get('filters')['user']['value']);
          }
      
          public function configure(BreadcrumbData $data): void
          {
              $this->setName('Orders for User #'.$data->get('userId'))
                   ->setFilters(['user' => ['value' => $data->get('userId')]]);
          }
      }
      

Integration Tips

  • Reuse Breadcrumb Logic: Extend AbstractBreadcrumb to avoid boilerplate.
  • Leverage getEntityReference(): Fetch entities efficiently without lazy-loading issues:
    $user = $this->getEntityReference(User::class, $data->get('userId'));
    
  • Customize URLs: Override getDefaultUrl() or use setUrl() for non-standard routes.
  • Symfony Events: Trigger breadcrumb-related events (e.g., easyadmin.breadcrumb.gather) for custom logic.

Gotchas and Tips

Pitfalls

  1. Broken Hierarchy:

    • Issue: Parent breadcrumbs fail if provide() doesn’t match gather() keys.
    • Fix: Ensure provide() returns the exact keys the parent expects (e.g., userId).
    • Debug: Use dump($data->all()) in configure() to inspect passed data.
  2. Filter Reset Issues:

    • Issue: Resetting filters (e.g., clearing userId) breaks breadcrumbs.
    • Fix: Throw BreadcrumbNotApplicableException in gather()/provide():
      public function gather(AdminContext $context): BreadcrumbData
      {
          $userId = $context->getRequest()->get('filters', [])['userId']['value'] ?? throw new BreadcrumbNotApplicableException();
          return parent::gather($context)->set('userId', $userId);
      }
      
  3. Entity Not Found:

    • Issue: getEntityReference() fails if the entity ID is invalid.
    • Fix: Validate IDs in configure() or use try-catch:
      try {
          $user = $this->getEntityReference(User::class, $id);
      } catch (\Exception) {
          $this->setName('Editing User (ID: '.$id.')');
      }
      
  4. Circular Dependencies:

    • Issue: A breadcrumb’s parent depends on it (e.g., ABA).
    • Fix: Avoid circular getParent() references. Use a flat hierarchy or middleware to resolve dependencies.
  5. Twig Template Overrides:

    • Issue: {{ breadcrumbs() }} doesn’t render.
    • Fix: Ensure the template path is correct (templates/bundles/EasyAdminBundle/layout.html.twig) and the block is extended properly.

Debugging Tips

  • Log Breadcrumb Data: Add debug logs in gather()/configure():
    $this->logger->debug('Breadcrumb data:', $data->all());
    
  • Check AdminContext: Verify the current route matches getType()/getEntityFqdn():
    dump($context->getCrud()->getEntityFqcn(), $context->getRequest()->get('_route'));
    
  • Test Incrementally: Add breadcrumbs one level at a time to isolate issues.

Extension Points

  1. Custom Breadcrumb Types:

    • Extend BreadcrumbType enum for non-CRUD actions (e.g., CUSTOM_ACTION).
    • Example:
      enum BreadcrumbType { INDEX; EDIT; CUSTOM_ACTION; }
      
  2. Dynamic Parent Resolution:

    • Override getParent() to resolve parents dynamically (e.g., based on route parameters):
      public function getParent(): ?string
      {
          return match ($this->getEntityFqdn()) {
              User::class => UserIndexBreadcrumb::class,
              default => null,
          };
      }
      
  3. Breadcrumb Twig Extensions:

    • Extend the breadcrumbs() function to customize rendering:
      {% macro breadcrumbs() %}
          <nav aria-label="Breadcrumbs">
              {% for breadcrumb in breadcrumbs %}
                  <a href="{{ breadcrumb.url }}">{{ breadcrumb.name }}</a>
              {% endfor %}
          </nav>
      {% endmacro %}
      
  4. Event Listeners:

    • Listen to easyadmin.breadcrumb.gather to modify data globally:
      // src/EventListener/BreadcrumbListener.php
      public function onGather(BreadcrumbGatherEvent $event)
      {
          $event->setData($event->getData()->set('customKey', 'value'));
      }
      
  5. Performance:

    • Avoid heavy operations in gather()/configure(). Use lazy-loading for entities:
      $user = $this->getEntityManager()->getRepository(User::class)->find($id);
      
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.
besmartand-pro/php-quality-config
sentix/ai-chatbot
terminal42/code-quality-tools
codifyo/ts-generator-bundle
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity