alshenetsky/easyadmin-breadcrumbs

一个允许您向EasyAdmin添加面包屑的包

安装: 100

依赖: 0

建议者: 0

安全: 0

星标: 8

关注者: 1

分支: 0

开放问题: 0

类型:symfony-bundle

1.1.9 2024-05-28 09:45 UTC

This package is auto-updated.

Last update: 2024-09-28 10:41:29 UTC


README

一个允许您向EasyAdmin添加面包屑的包

A bundle that allows you to add breadcrumbs to EasyAdmin

安装

此包需要EasyAdmin 4.5或更高版本,PHP 8.0或更高版本,以及Symfony 5.4或更高版本。在您的应用程序中安装它,请运行以下命令

$ composer require alshenetsky/easyadmin-breadcrumbs

文档

概念

众所周知,EasyAdmin没有在管理页面上放置面包屑的功能。管理区域的导航基于GET请求数据,封装在名为AdminContext的类中。控制器方法之间的转换是通过生成所需CRUD的URL实现的,如果需要,可以对其应用过滤器。因此,构建面包屑树变得很困难,因为您需要以某种方式存储控制器层次结构,而不会丢失过滤器和控制器之间的连接。

此包允许您重新创建这样的层次结构。您创建一个面包屑类,然后它又创建对父面包屑的引用,依此类推。

创建面包屑层次结构

此类必须实现BreadcrumbInterface。最简单的方法是继承AbstractBreadcrumb类,该类已经实现了此接口并包含有用的方法,减少了样板代码的数量

<?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';
    }
}

每个面包屑类将通过getType()getEntityFqdn()方法与当前URL进行匹配。因此,此示例中的面包屑将出现在UserController::index页面上。

方法getType()返回与EasyAdmin包中Crud::PAGE_*常量完美匹配的BreadcrumbType枚举。

此外,如果您需要更复杂的逻辑来决定是否在页面上显示面包屑,您还可以实现supports()方法

  public function supports(AdminContext $context): bool
    {
        return isset($context->getRequest()->get('filters')['parent']['value']);
    }

让我们更深入地了解导航树。在用户列表中,很可能会有一个用户编辑。让我们创建一个二级面包屑

<?php

namespace App\Controller\Admin\Breadcrumb;

use Alshenetsky\EasyAdminBreadcrumbs\Breadcrumb\AbstractBreadcrumb;
use Alshenetsky\EasyAdminBreadcrumbs\Breadcrumb\BreadcrumbData;
use Alshenetsky\EasyAdminBreadcrumbs\Breadcrumb\BreadcrumbType;

use EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext;

class UserEditBreadcrumb extends AbstractBreadcrumb
{

    public function getType(): BreadcrumbType
    {
        return BreadcrumbType::EDIT;
    }

    public function getEntityFqdn(): string
    {
        return User::class;
    }

    public function getParent(): ?string
    {
        return UserIndexBreadcrumb::class;
    }

    public function gather(AdminContext $context): BreadcrumbData
    {
        return parent::gather($context)
            ->set('userId', $context->getEntity()->getPrimaryKeyValue())
        ;
    }

    public function configure(BreadcrumbData $gatheredData): void
    {
        /** @var User $user */
        $user = $this->getEntityManager()
            ->getReference(
                User::class,
                $gatheredData->get('userId')
            )
        ;

        $this
            ->setName(sprintf('Editing user %s', $user->getName()))
            ->setEntityId($user->getId())
        ;
    }
}

您可能会看到一些之前不熟悉的方法。

  • 第一个是getParent()。它建立了子面包屑和父面包屑之间的链接。
  • 第二个是gather()。它从当前查询(只有当给定的面包屑定义为当前时)收集数据,并将其存储在BreadcrumbData类中,该类作为数据存储库。
  • 第三个是configure()。它接收BreadcrumbData对象(我们在gather()方法中生成的)。基于这些数据,我们可以配置此面包屑的名称和URL。这里的setEntityId()调用是一个辅助方法调用,允许我们将entityId键添加到URL生成器,并使用默认的URL生成逻辑。但我们可以通过调用setUrl()来完全覆盖此机制
           ->setName(sprintf('Editing user %s', $user->getName()))
           ->setUrl(
               $this
                   ->getDefaultUrl() // returns EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator instance with controller and action already provided
                   ->setEntityId($user->getId())
                   ->set('foo', 'bar')
           )

就是这样。现在我们有了两个级别的面包屑导航

用户 -> 编辑用户John Doe

现在更深入。假设在用户的编辑页面上有一个链接到用户的订单,这些订单在OrdersController中显示。假设在用户的编辑页面上有一个链接到用户的订单,这些订单在OrdersController中显示。您很可能在用户的编辑页面上创建一个自定义操作,并为其创建一个链接,该链接指向OrdersController::index,并设置一个过滤器('user' => ['comparison' => '=', 'value' => $user->getId()]])。很容易为下一级嵌套添加面包屑

用户 -> 编辑用户John Doe -> 用户订单

<?php

class OrdersIndexBreadcrumb extends AbstractBreadcrumb
{
    public function getType(): BreadcrumbType
    {
        return BreadcrumbType::INDEX;
    }

    public function getEntityFqdn(): string
    {
        return Order::class;
    }

    public function getParent(): ?string
    {
        return UserEditBreadcrumb::class;
    }

    public function gather(AdminContext $context): BreadcrumbData
    {
        // gather userId from request filters:
        return parent::gather($context)
            ->set('userId', $context->getRequest()->get('filters')['userId']['value'])
        ;
    }
    
     public function provide(BreadcrumbData $gatheredData): BreadcrumbData
    {
        // provide UserEditBreadcrumb with userId we gathered:
        return parent::provide($gatheredData)
            ->set('userId', $gatheredData->get('userId'))
        ;
    }

    public function configure(BreadcrumbData $gatheredData): void
    {
        $this
            ->setName('User orders')
            ->setFilters(['userId' => ['comparison' => '=', 'value' => $gatheredData->get('userId')]])
        ;
    }
}

您应该了解的最后一种方法是 provide()。它也接收在 gather() 中收集的 BreadcrumbData,但它返回另一个 BreadcrumbData 类,以便用其填充父级面包屑。您应该提供与父级面包屑需要的完全相同的键。

您看,在另一个页面(不同的上下文)中,只会对当前面包屑调用 gather() 方法,而父级面包屑通过 provide() 方法从链中获取其 BreadcrumbData。这就是面包屑层次结构形成的方式。您可以形成任意多的嵌套级别。

摘要

  • 使用 configure() 方法设置面包屑的 URL 和名称,来自 BreadcrumbData
  • 使用 gather() 方法从当前上下文(仅对当前面包屑)收集 BreadcrumbData
  • 使用 provide() 方法将 BreadcrumbData 发送到父级面包屑,使用与父级面包屑需要的完全相同的键。

异常处理

当显示子项列表时,使用 EasyAdmin 过滤器时,您可能会发现当您重置过滤器时,您会超出面包屑结构。为了避免遇到 500 错误,在任何 configuregatherprovide 方法中抛出 BreadcrumbNotApplicableException。这个错误将被正确处理,面包屑将不会渲染。

use \Alshenetsky\EasyAdminBreadcrumbs\Exception\BreadcrumbNotApplicableException;

public function gather(AdminContext $context): BreadcrumbData
{
  return parent::gather($context)
      ->set(
         'userId',
         $context->getRequest()->get('filters')['userId']['value'] ?? throw new BreadcrumbNotApplicableException() // the absence of a filter value means that the list of ALL orders is now displayed, not just the user's orders. In this case, breadcrumbs are not applicable.
      )
  ;
}

在页面上放置面包屑

  1. 通过创建文件 templates/bundles/EasyAdminBundle/layout.html.twig 来覆盖 EadyAdmin 的 layout.html twig 模板
  2. 例如,在 content_header_wrapper 块中放置 {{ breadcrumbs() }}
    {% extends '@!EasyAdmin/layout.html.twig' %}
    {% block content_header_wrapper %}
        {{ breadcrumbs()}}
        {{ parent() }}
    {% endblock %}
    

贡献

欢迎贡献!

待办事项列表

  • 添加测试
  • 添加静态分析工具
  • 配置 CI

许可证

本软件在 MIT 许可证 下发布