跳到内容

仪表盘

编辑此页

仪表盘是后端的入口点,它们链接到一个或多个资源。仪表盘还显示一个主菜单来导航资源和已登录用户的信息。

假设你有一个简单的应用程序,其中包含三个 Doctrine 实体:用户、博客文章和类别。你的员工可以创建和编辑它们中的任何一个,但外部合作者只能创建博客文章。

你可以在 EasyAdmin 中按如下方式实现这一点

  • 创建三个 CRUD 控制器(例如 UserCrudControllerBlogPostCrudControllerCategoryCrudController);
  • 为你的员工创建一个仪表盘(例如 DashboardController),并链接到这三个资源;
  • 为你的外部合作者创建一个仪表盘(例如 ExternalDashboardController),并且仅链接到 BlogPostCrudController 资源。

从技术上讲,仪表盘是常规的 Symfony 控制器,因此你可以执行通常在控制器中执行的任何操作,例如注入服务和使用快捷方式,如 $this->render()$this->isGranted()

仪表盘控制器类必须实现 EasyCorp\Bundle\EasyAdminBundle\Contracts\Controller\DashboardControllerInterface,这确保了在仪表盘中定义了某些方法。除了实现接口之外,你还可以扩展 AbstractDashboardController 类。运行以下命令以快速生成仪表盘控制器

1
$ php bin/console make:admin:dashboard

如果你现在访问应用程序的 /admin URL,你将看到默认的 EasyAdmin 欢迎页面

EasyAdmin 4 Welcome Page

在本文的后面部分,你将学习如何自定义该页面。如果你没有看到欢迎页面,你可能需要配置后端的 URL,如下节所述。

漂亮的 Admin URL

4.14.0

对漂亮的 admin URL 的支持是在 EasyAdmin 4.14.0 中引入的。

EasyAdmin 后端定义了简洁且可预测的路由名称(例如 admin_product_indexadmin_category_detail),这些名称生成简短而漂亮的 URL(例如 /admin/product/admin/category/324)。

这要归功于你必须首先在应用程序中启用的 自定义 Symfony 路由加载器。为此,请创建此文件

1
2
3
4
# config/routes/easyadmin.yaml
easyadmin:
    resource: .
    type: easyadmin.routes

注意

easyadmin.routes 字符串也可以作为 PHP 常量 \EasyCorp\Bundle\EasyAdminBundle\Router\AdminRouteLoader::ROUTE_LOADER_TYPE 使用。

现在,使用以下 PHP 属性定义仪表盘类的主要路由(如果你还没有仪表盘,你可以运行命令 make:admin:dashboard 快速生成一个)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// src/Controller/Admin/DashboardController.php
namespace App\Controller\Admin;

use EasyCorp\Bundle\EasyAdminBundle\Attribute\AdminDashboard;
use EasyCorp\Bundle\EasyAdminBundle\Config\Dashboard;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractDashboardController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;

#[AdminDashboard(routePath: '/admin', routeName: 'admin')]
class DashboardController extends AbstractDashboardController
{
    public function index(): Response
    {
        return parent::index();
    }

    // ...
}

警告

仪表盘路由必须使用 #[AdminDashboard] 属性定义。Symfony 支持的其他任何配置路由的方式都将不起作用。

4.24.0

使用 #[AdminDashboard] 属性定义仪表盘路由的功能是在 EasyAdmin 4.24.0 中引入的。

EasyAdmin 使用 #[AdminDashboard] 属性的配置来创建仪表盘的主要路由。你可以通过运行以下命令来验证这一点

1
$ php bin/console debug:router

提示

如果你没有看到任何应该由 EasyAdmin 生成的路由,请删除应用程序的缓存以强制重新生成路由。

提示

如果你正在实现多语言仪表盘,请将 _locale 参数添加到路由(例如 /admin/{_locale})。

index() 方法由 EasyAdmin 调用以渲染你的仪表盘。由于 index() 是 Dashboard 接口的一部分,因此你无法向其添加参数来注入依赖项。相反,请将这些依赖项注入控制器的构造函数方法中。

仪表盘路由的名称应该简洁,因为它用作与此仪表盘关联的所有路由的前缀(例如,如果此路由名称是 my_private_backend,则生成的路由将类似于 my_private_backend_product_index)。此路由的路径也将被所有仪表盘路由使用(例如,如果路径是 /_secret/backend,则生成的路由路径将类似于 /_secret/backend/category/324)。

就是这样。稍后,当你开始添加 CRUD 控制器时,路由加载器将为每个控制器创建所有需要的路由。

index() 方法中定义路由

使用 #[AdminDashboard] 属性是定义仪表盘路由的推荐方法。但是,你也可以通过在 index() 方法上应用 #[Route] 属性来定义仪表盘路由

1
2
3
4
5
6
7
8
9
10
11
12
13
// ...
use Symfony\Component\Routing\Attribute\Route;

class DashboardController extends AbstractDashboardController
{
    #[Route('/admin', name: 'admin')]
    public function index(): Response
    {
        return parent::index();
    }

    // ...
}

警告

此替代方法在 EasyAdmin 4.x 版本中仍然有效,但它已被弃用,并且在 EasyAdmin 5.x 中将不起作用。建议尽快更新仪表盘类以使用 #[AdminDashboard] 属性。

旧式的 Admin URL

注意

如果你在应用程序中使用漂亮的 admin URL,则可以完全跳过本节。

警告

旧式的 admin URL 已被弃用,并且在 EasyAdmin 5.0 中将不再起作用。升级你的应用程序以使用漂亮的 URL

在引入漂亮的 admin URL之前,EasyAdmin 使用单个 Symfony 路由来服务所有仪表盘 URL。所需的信息使用查询字符串参数传递。如果你使用 make:admin:dashboard 命令生成了仪表盘,则路由是使用 Symfony 路由注解或 PHP 属性(如果项目需要 PHP 8 或更高版本)定义的。

唯一的要求是在名为 index() 的控制器方法中定义路由,该方法是 EasyAdmin 调用以渲染仪表盘的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// src/Controller/Admin/DashboardController.php
namespace App\Controller\Admin;

use EasyCorp\Bundle\EasyAdminBundle\Config\Dashboard;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractDashboardController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class DashboardController extends AbstractDashboardController
{
    /**
     * @Route("/admin")
     */
    public function index(): Response
    {
        return parent::index();
    }

    // ...
}

警告

在不使用漂亮的 URL的后端中,Route 注解/属性是配置仪表盘路由的唯一推荐方法。#[AdminDashboard] 属性不适用于传统的(丑陋的)URL。

注意

由于 index() 是 Dashboard 接口的一部分,因此你无法向其添加参数来注入依赖项。相反,请将这些依赖项注入控制器的构造函数方法中。

注意

如果你正在实现多语言仪表盘,请将 _locale 参数添加到路由(例如 /admin/{_locale})。

/admin URL 只是一个默认值,因此你可以更改它。如果你这样做,请不要忘记在你的 Symfony 安全配置中也更新此值,以限制对整个后端的访问

无需为此路由定义显式名称。Symfony 会自动生成路由名称,EasyAdmin 在运行时获取该值以生成所有 URL。但是,如果你在应用程序的其他部分生成指向仪表盘的 URL,则可以定义显式路由名称以简化你的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// src/Controller/Admin/DashboardController.php
namespace App\Controller\Admin;

use EasyCorp\Bundle\EasyAdminBundle\Config\Dashboard;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractDashboardController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class DashboardController extends AbstractDashboardController
{
    /**
     * @Route("/admin", name="some_route_name")
     */
    public function index(): Response
    {
        return parent::index();
    }

    // ...
}

如果你不使用注解,则必须在单独的文件中使用 YAML、XML 或 PHP 配置来配置仪表盘路由

1
2
3
4
5
6
# config/routes.yaml
dashboard:
    path: /admin
    controller: App\Controller\Admin\DashboardController::index

# ...

实际上,你无需处理此路由或应用程序中的查询字符串参数,因为 EasyAdmin 提供了一项服务来生成 admin URL

注意

使用单个路由来处理所有后端 URL 意味着生成的 URL 有点长且丑陋。这在许多情况下都可以,但如果你愿意,可以改用漂亮的 admin URL

仪表盘配置

仪表盘配置在 configureDashboard() 方法中定义(主菜单和用户菜单在它们自己的方法中配置,稍后会解释)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
namespace App\Controller\Admin;

use EasyCorp\Bundle\EasyAdminBundle\Attribute\AdminDashboard;
use EasyCorp\Bundle\EasyAdminBundle\Config\Dashboard;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractDashboardController;
use EasyCorp\Bundle\EasyAdminBundle\Dto\LocaleDto;

#[AdminDashboard(routePath: '/admin', routeName: 'admin')]
class DashboardController extends AbstractDashboardController
{
    // ...

    public function configureDashboard(): Dashboard
    {
        return Dashboard::new()
            // the name visible to end users
            ->setTitle('ACME Corp.')
            // you can include HTML contents too (e.g. to link to an image)
            ->setTitle('<img src="..."> ACME <span class="text-small">Corp.</span>')

            // by default EasyAdmin displays a black square as its default favicon;
            // use this method to display a custom favicon: the given path is passed
            // "as is" to the Twig asset() function:
            // <link rel="shortcut icon" href="{{ asset('...') }}">
            ->setFaviconPath('favicon.svg')

            // the domain used by default is 'messages'
            ->setTranslationDomain('my-custom-domain')

            // there's no need to define the "text direction" explicitly because
            // its default value is inferred dynamically from the user locale
            ->setTextDirection('ltr')

            // set this option if you prefer the page content to span the entire
            // browser width, instead of the default design which sets a max width
            ->renderContentMaximized()

            // set this option if you prefer the sidebar (which contains the main menu)
            // to be displayed as a narrow column instead of the default expanded design
            ->renderSidebarMinimized()

            // by default, users can select between a "light" and "dark" mode for the
            // backend interface. Call this method if you prefer to disable the "dark"
            // mode for any reason (e.g. if your interface customizations are not ready for it)
            ->disableDarkMode()

            // by default, the UI color scheme is 'auto', which means that the backend
            // will use the same mode (light/dark) as the operating system and will
            // change in sync when the OS mode changes.
            // Use this option to set which mode ('light', 'dark' or 'auto') will users see
            // by default in the backend (users can change it via the color scheme selector)
            ->setDefaultColorScheme('dark')
            // instead of magic strings, you can use constants as the value of
            // this option: EasyCorp\Bundle\EasyAdminBundle\Config\Option\ColorScheme::DARK

            // by default, all backend URLs are generated as absolute URLs. If you
            // need to generate relative URLs instead, call this method
            ->generateRelativeUrls()

            // set this option if you want to enable locale switching in dashboard.
            // IMPORTANT: this feature won't work unless you add the {_locale}
            // parameter in the admin dashboard URL (e.g. '/admin/{_locale}').
            // the name of each locale will be rendered in that locale
            // (in the following example you'll see: "English", "Polski")
            ->setLocales(['en', 'pl'])
            // to customize the labels of locales, pass a key => value array
            // (e.g. to display flags; although it's not a recommended practice,
            // because many languages/locales are not associated to a single country)
            ->setLocales([
                'en' => '🇬🇧 English',
                'pl' => '🇵🇱 Polski'
            ])
            // to further customize the locale option, pass an instance of
            // EasyCorp\Bundle\EasyAdminBundle\Config\Locale
            ->setLocales([
                'en', // locale without custom options
                Locale::new('pl', 'polski', 'far fa-language') // custom label and icon
            ])
        ;
    }
}

4.1.0

disableUrlSignatures() 仪表盘方法在 EasyAdmin 4.1.0 中已被弃用,因为后端 URL 不再包含签名。

自定义仪表盘内容

生成的仪表盘默认显示一个“欢迎页面”,其中包含一些有用的链接。在实际应用程序中,你需要自定义此页面以显示你自己的内容。

仪表盘通常显示带有统计信息的窗口小部件和图表。EasyAdmin 尚未提供创建这些小部件的任何方法。这在我们的未来功能列表中,但与此同时,你可以使用 Symfony UX Chart.js 捆绑包来创建这些图表并在你自己的 Twig 模板中渲染它们

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
use EasyCorp\Bundle\EasyAdminBundle\Attribute\AdminDashboard;
use EasyCorp\Bundle\EasyAdminBundle\Config\Dashboard;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractDashboardController;
use Symfony\UX\Chartjs\Builder\ChartBuilderInterface;
use Symfony\UX\Chartjs\Model\Chart;

#[AdminDashboard(routePath: '/admin', routeName: 'admin')]
class DashboardController extends AbstractDashboardController
{
    public function __construct(
        private ChartBuilderInterface $chartBuilder,
    ) {
    }

    // ... you'll also need to load some CSS/JavaScript assets to render
    // the charts; this is explained later in the chapter about Design

    public function index(): Response
    {
        $chart = $this->chartBuilder->createChart(Chart::TYPE_LINE);
        // ...set chart data and options somehow

        return $this->render('admin/my-dashboard.html.twig', [
            'chart' => $chart,
        ]);
    }
}

注意

由于 index()Dashboard 接口的一部分,因此你无法向其添加参数来注入依赖项(例如上面示例中的 ChartBuilderInterface)。相反,请在控制器构造函数中注入依赖项,或使用与接口中定义的方法名称不同的方法名称。

要在你的自定义仪表盘上使用 EasyAdmin 的内置布局(例如左侧的主菜单栏 - 在下一节中解释),请使你的模板扩展 `vendor/easycorp/easyadmin-bundle/src/Resources/views/layout.html.twig` 并覆盖一些块

1
2
3
4
5
6
{# templates/admin/my_dashboard.html.twig #}
{% extends '@EasyAdmin/layout.html.twig' %}

{% block main %}
    {# ... #}
{% endblock main %}

另一个流行的选择是完全避免仪表盘,而是重定向到后端人员最常见的任务。这需要生成 admin URLCRUD 控制器,这将在稍后详细解释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
use EasyCorp\Bundle\EasyAdminBundle\Attribute\AdminDashboard;
use EasyCorp\Bundle\EasyAdminBundle\Config\Dashboard;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractDashboardController;
use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator;

#[AdminDashboard(routePath: '/admin', routeName: 'admin')]
class DashboardController extends AbstractDashboardController
{
    // ...

    public function index(): Response
    {
        // when using pretty admin URLs, you can redirect directly to some route
        return $this->redirectToRoute('admin_post_index');

        // when using legacy admin URLs, use the URL generator to build the needed URL
        $adminUrlGenerator = $this->container->get(AdminUrlGenerator::class);

        // Option 1. Make your dashboard redirect to the same page for all users
        return $this->redirect($adminUrlGenerator->setController(OneOfYourCrudController::class)->generateUrl());

        // Option 2. Make your dashboard redirect to different pages depending on the user
        if ('jane' === $this->getUser()->getUsername()) {
            return $this->redirect('...');
        }
    }
}

主菜单从仪表盘链接到不同的CRUD 控制器。这是关联仪表盘和资源的唯一方法。出于安全原因,后端只能通过主菜单访问与仪表盘关联的资源。

主菜单是实现 EasyCorp\Bundle\EasyAdminBundle\Contracts\Menu\MenuItemInterface 的对象的集合,这些对象配置每个菜单项的外观和行为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
use App\Entity\BlogPost;
use App\Entity\Category;
use App\Entity\Comment;
use App\Entity\User;
use EasyCorp\Bundle\EasyAdminBundle\Attribute\AdminDashboard;
use EasyCorp\Bundle\EasyAdminBundle\Config\Dashboard;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractDashboardController;

#[AdminDashboard(routePath: '/admin', routeName: 'admin')]
class DashboardController extends AbstractDashboardController
{
    // ...

    public function configureMenuItems(): iterable
    {
        return [
            MenuItem::linkToDashboard('Dashboard', 'fa fa-home'),

            MenuItem::section('Blog'),
            MenuItem::linkToCrud('Categories', 'fa fa-tags', Category::class),
            MenuItem::linkToCrud('Blog Posts', 'fa fa-file-text', BlogPost::class),

            MenuItem::section('Users'),
            MenuItem::linkToCrud('Comments', 'fa fa-comment', Comment::class),
            MenuItem::linkToCrud('Users', 'fa fa-user', User::class),
        ];
    }
}

MenuItem::new() 的第一个参数是项目显示的标签,第二个参数是要显示的图标。图标名称遵循模式 icon_set:icon_name,与 Symfony UX Icons 中使用的模式相同。

注意

默认情况下,EasyAdmin 假定图标名称对应于 FontAwesome CSS 类。必要的 CSS 样式和 Web 字体也默认包含在内,因此你无需采取任何其他步骤即可使用 FontAwesome 图标。或者,你可以使用你自己的图标集而不是 FontAwesome。

所有菜单项都定义了以下方法来配置某些选项

  • setCssClass(string $cssClass),设置应用于菜单项的 <li> 父元素的 CSS 类;
  • setLinkRel(string $rel),设置菜单项链接的 rel HTML 属性(查看 “rel”属性的允许值);
  • setLinkTarget(string $target),设置菜单项链接的 target HTML 属性(默认 _self);
  • setPermission(string $permission),设置用户必须具有才能看到此菜单项的 Symfony 安全权限。阅读菜单安全参考以获取更多详细信息。
  • setHtmlAttribute(string $name, mixed $value),在渲染菜单项的 HTML 元素中设置自定义 HTML 属性。
  • setBadge($content, string $style='secondary', array $htmlAttributes = []),将给定的内容渲染为菜单项的徽章。它通常用于显示通知计数。第一个参数可以是任何可以在 Twig 模板中转换为字符串的值(数字、字符串、可字符串化 对象等)。第二个参数是预定义的 Bootstrap 样式之一(primarysecondarysuccessdangerwarninginfolightdark)或任意字符串内容,该内容将作为与徽章关联的 HTML 元素的 style 属性的值传递。第三个参数允许在渲染徽章的元素中设置自定义 HTML 属性。

其余选项取决于每个菜单项类型,如下节所述。

CRUD 菜单项

这是最常见的菜单项类型,它链接到某些 CRUD 控制器的某些操作。您必须传递与 CRUD 控制器关联的 Doctrine 实体的 FQCN (完全限定类名),而不是传递 CRUD 控制器的 FQCN。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
use App\Entity\Category;
use EasyCorp\Bundle\EasyAdminBundle\Config\MenuItem;

public function configureMenuItems(): iterable
{
    return [
        // ...

        // links to the 'index' action of the Category CRUD controller
        MenuItem::linkToCrud('Categories', 'fa fa-tags', Category::class),

        // links to a different CRUD action
        MenuItem::linkToCrud('Add Category', 'fa fa-tags', Category::class)
            ->setAction('new'),

        MenuItem::linkToCrud('Show Main Category', 'fa fa-tags', Category::class)
            ->setAction('detail')
            ->setEntityId(1),

        // if the same Doctrine entity is associated to more than one CRUD controller,
        // use the 'setController()' method to specify which controller to use
        MenuItem::linkToCrud('Categories', 'fa fa-tags', Category::class)
            ->setController(LegacyCategoryCrudController::class),

        // uses custom sorting options for the listing
        MenuItem::linkToCrud('Categories', 'fa fa-tags', Category::class)
            ->setDefaultSort(['createdAt' => 'DESC']),
    ];
}

仪表盘菜单项

它链接到当前仪表盘的首页。您可以使用“路由菜单项”(如下所述)实现相同的效果,但此项更简单,因为您不必指定路由名称(它会自动查找)。

1
2
3
4
5
6
7
8
9
use EasyCorp\Bundle\EasyAdminBundle\Config\MenuItem;

public function configureMenuItems(): iterable
{
    return [
        MenuItem::linkToDashboard('Home', 'fa fa-home'),
        // ...
    ];
}

路由菜单项

它链接到您的 Symfony 应用程序定义的任何路由。

1
2
3
4
5
6
7
8
9
10
use EasyCorp\Bundle\EasyAdminBundle\Config\MenuItem;

public function configureMenuItems(): iterable
{
    return [
        MenuItem::linkToRoute('The Label', 'fa ...', 'route_name'),
        MenuItem::linkToRoute('The Label', 'fa ...', 'route_name', ['routeParamName' => 'routeParamValue']),
        // ...
    ];
}

注意

阅读关于 在 EasyAdmin 中集成 Symfony 控制器/操作 的章节,以充分理解 linkToRoute() 生成的 URL。

URL 菜单项

它链接到相对或绝对 URL。

1
2
3
4
5
6
7
8
9
10
use EasyCorp\Bundle\EasyAdminBundle\Config\MenuItem;

public function configureMenuItems(): iterable
{
    return [
        MenuItem::linkToUrl('Visit public website', null, '/'),
        MenuItem::linkToUrl('Search in Google', 'fab fa-google', 'https://google.com'),
        // ...
    ];
}

为了避免将内部后端信息泄露给外部网站,EasyAdmin 会将 rel="noopener" 属性添加到所有 URL 菜单项,除非菜单项定义了自己的 rel 选项。

节菜单项

它在菜单项之间创建视觉分隔,并且可以选择显示一个标签,该标签充当下方菜单项的标题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
use EasyCorp\Bundle\EasyAdminBundle\Config\MenuItem;

public function configureMenuItems(): iterable
{
    return [
        // ...

        MenuItem::section(),
        // ...

        MenuItem::section('Blog'),
        // ...
    ];
}

注销菜单项

它链接到用户必须访问才能从应用程序注销的 URL。如果您知道注销路由名称,则可以使用“路由菜单项”实现相同的效果,但此项更方便,因为它会自动为当前安全防火墙查找注销 URL。

1
2
3
4
5
6
7
8
9
use EasyCorp\Bundle\EasyAdminBundle\Config\MenuItem;

public function configureMenuItems(): iterable
{
    return [
        // ...
        MenuItem::linkToLogout('Logout', 'fa fa-exit'),
    ];
}

注意

注销菜单项在某些身份验证方案(如 HTTP Basic)下不起作用,因为由于这些身份验证方案的工作方式,它们没有配置默认注销路径。

如果您遇到类似“无法找到当前防火墙 LogoutListener,请手动提供提供程序密钥。”的错误,您需要删除注销菜单项或向您的身份验证方案添加注销提供程序。

退出模拟菜单项

它链接到用户必须访问才能停止模拟其他用户的 URL。

1
2
3
4
5
6
7
8
9
use EasyCorp\Bundle\EasyAdminBundle\Config\MenuItem;

public function configureMenuItems(): iterable
{
    return [
        // ...
        MenuItem::linkToExitImpersonation('Stop impersonation', 'fa fa-exit'),
    ];
}

主菜单最多可以显示两级嵌套菜单。子菜单使用 subMenu() 菜单项类型定义。

1
2
3
4
5
6
7
8
9
10
11
12
13
use EasyCorp\Bundle\EasyAdminBundle\Config\MenuItem;

public function configureMenuItems(): iterable
{
    return [
        MenuItem::subMenu('Blog', 'fa fa-article')->setSubItems([
            MenuItem::linkToCrud('Categories', 'fa fa-tags', Category::class),
            MenuItem::linkToCrud('Posts', 'fa fa-file-text', BlogPost::class),
            MenuItem::linkToCrud('Comments', 'fa fa-comment', Comment::class),
        ]),
        // ...
    ];
}

注意

在子菜单中,父菜单项不能链接到任何资源、路由或 URL;它只能展开/折叠子菜单项。

复杂的主菜单

configureMenuItems() 的返回类型是 iterable,因此您不必总是返回数组。例如,如果您的主菜单需要复杂的逻辑来决定为每个用户显示哪些项目,则使用生成器返回菜单项会更方便。

1
2
3
4
5
6
7
8
9
10
11
12
public function configureMenuItems(): iterable
{
    yield MenuItem::linkToDashboard('Dashboard', 'fa fa-home');

    if ('... some complex expression ...') {
        yield MenuItem::section('Blog');
        yield MenuItem::linkToCrud('Categories', 'fa fa-tags', Category::class);
        yield MenuItem::linkToCrud('Blog Posts', 'fa fa-file-text', BlogPost::class);
    }

    // ...
}

用户菜单

当访问受保护的后端时,EasyAdmin 会显示登录到应用程序的用户的详细信息以及包含诸如“注销”(如果启用了 Symfony 的 注销功能)等选项的菜单。

用户名是通过调用当前用户对象上的 __toString() 方法的结果。用户头像是通用头像图标。使用 configureUserMenu() 方法配置此菜单的功能和项目。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
use EasyCorp\Bundle\EasyAdminBundle\Attribute\AdminDashboard;
use EasyCorp\Bundle\EasyAdminBundle\Config\MenuItem;
use EasyCorp\Bundle\EasyAdminBundle\Config\UserMenu;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractDashboardController;
use Symfony\Component\Security\Core\User\UserInterface;

#[AdminDashboard(routePath: '/admin', routeName: 'admin')]
class DashboardController extends AbstractDashboardController
{
    // ...

    public function configureUserMenu(UserInterface $user): UserMenu
    {
        // Usually it's better to call the parent method because that gives you a
        // user menu with some menu items already created ("sign out", "exit impersonation", etc.)
        // if you prefer to create the user menu from scratch, use: return UserMenu::new()->...
        return parent::configureUserMenu($user)
            // use the given $user object to get the user name
            ->setName($user->getFullName())
            // use this method if you don't want to display the name of the user
            ->displayUserName(false)

            // you can return an URL with the avatar image
            ->setAvatarUrl('https://...')
            ->setAvatarUrl($user->getProfileImageUrl())
            // use this method if you don't want to display the user image
            ->displayUserAvatar(false)
            // you can also pass an email address to use gravatar's service
            ->setGravatarEmail($user->getMainEmailAddress())

            // you can use any type of menu item, except submenus
            ->addMenuItems([
                MenuItem::linkToRoute('My Profile', 'fa fa-id-card', '...', ['...' => '...']),
                MenuItem::linkToRoute('Settings', 'fa fa-user-cog', '...', ['...' => '...']),
                MenuItem::section(),
                MenuItem::linkToLogout('Logout', 'fa fa-sign-out'),
            ]);
    }
}

Admin 上下文

EasyAdmin 在每个后端请求上自动初始化类型为 EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext 的变量。此对象实现了 上下文对象 设计模式,并存储后端不同部分常用的所有信息。

此上下文对象会自动注入到每个模板中,作为名为 ea(“EasyAdmin”的首字母)的变量。

1
2
3
4
5
<h1>{{ ea.dashboardTitle }}</h1>

{% for menuItem in ea.mainMenu.items %}
    {# ... #}
{% endfor %}

AdminContext 变量是在每个请求上动态创建的,因此您不能直接将其注入到您的服务中。相反,请使用 AdminContextProvider 服务来获取上下文变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
use EasyCorp\Bundle\EasyAdminBundle\Provider\AdminContextProvider;

final class SomeService
{
    private $adminContextProvider;

    public function __construct(AdminContextProvider $adminContextProvider)
    {
        $this->adminContextProvider = $adminContextProvider;
    }

    public function someMethod()
    {
        $context = $this->adminContextProvider->getContext();
    }

    // ...
}

在 EasyAdmin 的 CRUD 控制器集成到 EasyAdmin 的 Symfony 控制器中,在您想要注入上下文对象的任何参数中使用 AdminContext 类型提示。

1
2
3
4
5
6
7
8
9
10
use EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;

class SomeController extends AbstractController
{
    public function someMethod(AdminContext $context)
    {
        // ...
    }
}

翻译

后端界面使用 Symfony 翻译 功能进行完全翻译。EasyAdmin 自己的消息和内容使用 EasyAdminBundle 翻译域(感谢我们的社区慷慨地提供数十种语言的翻译)。

其余内容(例如,菜单项的标签、实体和字段名称等)默认使用 messages 翻译域。您可以使用 translationDomain() 方法更改此值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#[AdminDashboard(routePath: '/admin', routeName: 'admin')]
class DashboardController extends AbstractDashboardController
{
    // ...

    public function configureDashboard(): Dashboard
    {
        return Dashboard::new()
            // ...

            // the argument is the name of any valid Symfony translation domain
            ->setTranslationDomain('admin');
    }
}

在内部,EasyAdmin 通过 TranslatableMessage 对象管理翻译。这些对象被传递到模板,在模板中它们被翻译成用户语言环境。您还可以使用 TranslatableMessage 对象来定义后端中的任何文本内容(例如,某些字段的标签、某些页面的帮助内容等)。

1
2
3
4
5
6
7
8
9
10
use function Symfony\Component\Translation\t;
use Symfony\Component\Translation\TranslatableMessage;

// creating translatable messages using objects
TextField::new('firstName', new TranslatableMessage('Name'))
TextField::new('firstName', new TranslatableMessage('Name', ['parameter' => 'value'], 'admin'))

// creating translatable messages using the t() function shortcut
TextField::new('firstName', t('Name'))
TextField::new('firstName', t('Name', ['parameter' => 'value'], 'admin'))

提示

对于多语言后端,建议使用可翻译对象,因为 Symfony 可以自动提取所有这些对象以更新您的翻译文件。

后端使用 Symfony 应用程序中配置的语言。当语言环境为阿拉伯语 (ar)、波斯语 (fa) 或希伯来语 (he) 时,HTML 文本方向会自动设置为 rtl(从右到左)。否则,文本显示为 ltr(从左到右),但您可以显式配置此值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#[AdminDashboard(routePath: '/admin', routeName: 'admin')]
class DashboardController extends AbstractDashboardController
{
    // ...

    public function configureDashboard(): Dashboard
    {
        return Dashboard::new()
            // ...

            // most of the times there's no need to configure this explicitly
            // (default: 'rtl' or 'ltr' depending on the language)
            ->setTextDirection('rtl');
    }
}

提示

如果您希望后端使用与公共网站不同的语言,请将 {_locale} 参数添加到您的仪表盘路由,并使用 setLocales() 方法配置后端中可用的语言环境。

注意

存储在数据库中的内容(例如,博客文章的内容或产品的名称)未翻译。EasyAdmin 不支持将实体属性内容翻译成不同的语言。

页面模板

EasyAdmin 提供了几个页面模板,这些模板在您的仪表盘中添加自定义逻辑时非常有用。

登录表单模板

Twig 模板路径:@EasyAdmin/page/login.html.twig

它显示一个简单的用户名+密码登录表单,其样式与后端的其余部分匹配。该模板定义了许多配置选项,但大多数应用程序都可以依赖其默认值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;

class SecurityController extends AbstractController
{
    #[Route("/login", name="login")]
    public function login(AuthenticationUtils $authenticationUtils): Response
    {
        $error = $authenticationUtils->getLastAuthenticationError();
        $lastUsername = $authenticationUtils->getLastUsername();

        return $this->render('@EasyAdmin/page/login.html.twig', [
            // parameters usually defined in Symfony login forms
            'error' => $error,
            'last_username' => $lastUsername,

            // OPTIONAL parameters to customize the login form:

            // the translation_domain to use (define this option only if you are
            // rendering the login template in a regular Symfony controller; when
            // rendering it from an EasyAdmin Dashboard this is automatically set to
            // the same domain as the rest of the Dashboard)
            'translation_domain' => 'admin',

            // by default EasyAdmin displays a black square as its default favicon;
            // use this method to display a custom favicon: the given path is passed
            // "as is" to the Twig asset() function:
            // <link rel="shortcut icon" href="{{ asset('...') }}">
            'favicon_path' => '/favicon-admin.svg',

            // the title visible above the login form (define this option only if you are
            // rendering the login template in a regular Symfony controller; when rendering
            // it from an EasyAdmin Dashboard this is automatically set as the Dashboard title)
            'page_title' => 'ACME login',

            // the string used to generate the CSRF token. If you don't define
            // this parameter, the login form won't include a CSRF token
            'csrf_token_intention' => 'authenticate',

            // the URL users are redirected to after the login (default: '/admin')
            'target_path' => $this->generateUrl('admin_dashboard'),

            // the label displayed for the username form field (the |trans filter is applied to it)
            'username_label' => 'Your username',

            // the label displayed for the password form field (the |trans filter is applied to it)
            'password_label' => 'Your password',

            // the label displayed for the Sign In form button (the |trans filter is applied to it)
            'sign_in_label' => 'Log in',

            // the 'name' HTML attribute of the <input> used for the username field (default: '_username')
            'username_parameter' => 'my_custom_username_field',

            // the 'name' HTML attribute of the <input> used for the password field (default: '_password')
            'password_parameter' => 'my_custom_password_field',

            // whether to enable or not the "forgot password?" link (default: false)
            'forgot_password_enabled' => true,

            // the path (i.e. a relative or absolute URL) to visit when clicking the "forgot password?" link (default: '#')
            'forgot_password_path' => $this->generateUrl('...', ['...' => '...']),

            // the label displayed for the "forgot password?" link (the |trans filter is applied to it)
            'forgot_password_label' => 'Forgot your password?',

            // whether to enable or not the "remember me" checkbox (default: false)
            'remember_me_enabled' => true,

            // remember me name form field (default: '_remember_me')
            'remember_me_parameter' => 'custom_remember_me_param',

            // whether to check by default the "remember me" checkbox (default: false)
            'remember_me_checked' => true,

            // the label displayed for the remember me checkbox (the |trans filter is applied to it)
            'remember_me_label' => 'Remember me',
        ]);
    }
}

内容页面模板

Twig 模板路径:@EasyAdmin/page/content.html.twig

它显示一个类似于索引/详细信息/表单页面的简单页面,带有主标题、侧边栏菜单和中心内容部分。唯一的区别是内容部分完全为空,因此它对于显示您自己的内容和自定义表单,将 Symfony 操作集成到 EasyAdmin 中等非常有用。示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{# templates/admin/my-custom-page.html.twig #}
{% extends '@EasyAdmin/page/content.html.twig' %}

{% block content_title %}The Title of the Page{% endblock %}
{% block page_actions %}
    <a class="btn btn-primary" href="...">Some Action</a>
{% endblock %}

{% block main %}
    <table class="datagrid">
        <thead>
            <tr>
                <td>Some Column</td>
                <td>Another Column</td>
            </tr>
        </thead>
        <tbody>
            {% for data in my_own_data %}
                <tr>
                    <td>{{ data.someColumn }}</td>
                    <td>{{ data.anotherColumn }}</td>
                </tr>
            {% endfor %}
        </tbody>
    </table>
{% endblock %}
这项工作,包括代码示例,已根据 Creative Commons BY-SA 3.0 许可获得许可。
目录
    版本