Коротко: EasyAdmin даёт быстрый CRUD-админ для Symfony из коробки; разбираем установку, Dashboard, CRUD-контроллер и подключение CKEditor.

EasyAdmin — бандл для быстрой админки в Symfony: из коробки даёт CRUD с простым нативным интерфейсом, что удобно в сжатые сроки. Разберём установку, создание дашборда и CRUD-контроллера, подключение CKEditor и типовые нюансы.

EasyAdmin Bundle предоставляет довольно простой CRUD с нативной визуализацией — это и делает его удобным под сжатые сроки.

Установка

composer require easycorp/easyadmin-bundle

Создание дашборда

Первым делом EasyAdmin предлагает создать главную страницу — так называемый Dashboard. Представим простое приложение с тремя сущностями: User, BlogPost и Category. Сотрудники компании могут создавать и редактировать любые из них, а внешние пользователи — только посты блога. В EasyAdmin это реализуется так:

  1. создать три CRUD-контроллера: UserCrudController, BlogPostCrudController, CategoryCrudController;
  2. создать DashboardController для сотрудников компании;
  3. создать ExternalDashboardController для внешних пользователей.

Технически все эти контроллеры сродни обычным контроллерам Symfony, поэтому в них доступны такие штуки, как $this->render() или $this->isGranted(). Классы дашбордов должны имплементировать EasyCorp\Bundle\EasyAdminBundle\Contracts\Controller\DashboardControllerInterface (он гарантирует наличие нужных методов) — либо расширять AbstractDashboardController и опираться на поведение по умолчанию.

Генерируем контроллер:

php bin/console make:admin:dashboard

Теперь на странице /admin появится приветственное окно.

EasyAdmin 4 Welcome Page

Настройка меню и главной страницы

Дальше организуем меню и страницы. Переопределим шаблон дашборда в templates/admin/my-dashboard.html.twig:

{# 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>
        </tbody>
    </table>
{% endblock %}

И выставим примерно дефолтные значения в контроллере src/Controller/Admin/DashboardController:

<?php

namespace App\Controller\Admin;

use App\Entity\BlogPost;
use App\Entity\Category;
use App\Entity\User;
use EasyCorp\Bundle\EasyAdminBundle\Config\Dashboard;
use EasyCorp\Bundle\EasyAdminBundle\Config\MenuItem;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractDashboardController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class DashboardController extends AbstractDashboardController
{
    #[Route('/admin', name: 'admin')]
    public function index(): Response
    {
        return $this->render('admin/my-dashboard.html.twig');
    }

    public function configureDashboard(): Dashboard
    {
        return Dashboard::new()
            ->setTitle('Otezvikentiy Tech');
    }

    public function configureMenuItems(): iterable
    {
        yield MenuItem::linkToDashboard('Dashboard', 'fa fa-home');
        yield MenuItem::linkToCrud('Users', 'fas fa-user', User::class);
        yield MenuItem::linkToCrud('Categories', 'fas fa-navicon', Category::class);
        yield MenuItem::linkToCrud('Blog Posts', 'fas fa-newspaper', BlogPost::class);
    }
}

Теперь админка примет примерно такой вид:

easy_admin_view_1

Подключение CKEditor

Чтобы удобно управлять сущностями, сразу установим CKEditor для EasyAdmin — это даст более приятный интерфейс для текстовых полей.

composer require friendsofsymfony/ckeditor-bundle

Убедимся, что загрузилась последняя версия CKEditor:

php bin/console ckeditor:install

И установим ассеты в папку public:

php bin/console assets:install public

Как сделать CRUD-контроллер?

Запускаем команду и следуем инструкциям:

php bin/console make:admin:crud

Команда создаст файл контроллера, который нужно донастроить. Сначала указываем, на какую сущность он ориентирован, через метод getEntityFqcn:

<?php

namespace App\Controller\Admin;

use App\Entity\BlogPost;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;


class ArticleCrudController extends AbstractCrudController
{
    public static function getEntityFqcn(): string
    {
        return BlogPost::class;
    }

    //...

}

Затем конфигурируем CRUD методом configureCrud:

    public function configureCrud(Crud $crud): Crud
    {
        return $crud
            ->setEntityLabelInSingular('...')
            ->setDateTimeFormat('Y-m-d H:i:s')
            ->setTimezone('Europe/Moscow')
            ->renderContentMaximized()
            ->setEntityLabelInSingular('BlogPost')
            ->setEntityLabelInPlural('BlogPosts')
            ->setEntityPermission('ROLE_ADMIN')
            ->setSearchFields(['title', 'content', 'slug'])
            ->setDefaultSort(['id' => 'DESC'])
            ->setPaginatorPageSize(20)
            ->setPaginatorRangeSize(4)
            ->setPaginatorUseOutputWalkers(true)
            ->setPaginatorFetchJoinCollection(true)
            ->addFormTheme('@FOSCKEditor/Form/ckeditor_widget.html.twig')
            ;
    }

Далее настраиваем поля сущности методом configureFields:

    public function configureFields(string $pageName): iterable
    {
        return [
            TextField::new('title'),
            TextField::new('slug'),
            ImageField::new('mainPicture')->setBasePath('images')->setUploadDir('public/images')->setRequired(false),
            AssociationField::new('author')->setQueryBuilder(fn (QueryBuilder $queryBuilder) => $queryBuilder->getEntityManager()->getRepository(User::class)->findAll()),
            AssociationField::new('category')->setQueryBuilder(fn (QueryBuilder $queryBuilder) => $queryBuilder->getEntityManager()->getRepository(Category::class)->findAll()),
            AssociationField::new('tags')->setQueryBuilder(fn (QueryBuilder $queryBuilder) => $queryBuilder->getEntityManager()->getRepository(Tag::class)->findAll())->setFormTypeOption('by_reference', false),
            TextareaField::new('content')->setFormType(CKEditorType::class),
        ];
    }

У каждого поля свои настройки — полный список полей и опций есть в официальной документации EasyAdmin.

CKEditor можно кастомизировать — и внешне, и функционально — через их сайт: выбрать самый полный пресет, нужные плагины и скачать оптимизированную сборку. Полученный zip-архив распаковать в public/bundles/fosckeditor/*, предварительно очистив папку.

В процессе могут возникать ошибки вида «система пытается привести сущность к строке» — тогда добавьте в эту сущность магический метод __toString(), например так:

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity()]
class BlogPost
{
    //...

    #[ORM\Column(length: 255, nullable: false)]
    private string $title;

    public function __toString(): string
    {
        return $this->title;
    }

    //...
}

Это базовая настройка EasyAdmin. Если нужно быстро поднять админку под проект или, наоборот, мигрировать с EasyAdmin на кастомное решение — помогу на консультации.