symfony FormBuilder Сгруппированный список: вывести связанные сущности из БД (группировка по Entity)

Примечание: проверено на Symfony 6.3

  • Пример: у статьи на сайте есть категория и подкатегория. Связь статей с категориями/подкатегориями "многие к одному" Связь категории и подкатегории "один ко многим".
  • Задача: в html форме на странице создания/редактирования статьи вывести список подкатегорий, сгруппированный по категориям.
  • Примечание: в моем случае у статьи может отсутствовать категория и подкатегория, у подкатегории - категория

Класс статьи:

// ...
#[ORM\Table(name: 'articles')]
class Article
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    // ...

    #[ORM\ManyToOne(inversedBy: 'articles')]
    private ?Category $category = null;

    #[ORM\ManyToOne(inversedBy: 'articles')]
    private ?Subcategory $subcategory = null;

    // ...

Класс категории:

// ...
#[ORM\Table(name: 'categories')]
class Category
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 255)]
    private ?string $name = null;

    // ...
 
    public function __toString() 
    {
        return $this->getName();
    }

    public function getName(): ?string
    {
        return $this->name;
    }

    // ...

Класс подкатегории:

// ...
#[ORM\Table(name: 'subcategories')]
class Subcategory
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 100)]
    private ?string $name = null;

    #[ORM\ManyToOne]
    private ?Category $category = null;

    // ...
    
    public function __toString() 
    {
        return $this->getName();
    }

    public function getName(): ?string
    {
        return $this->name;
    }

    public function getCategory(): ?Category
    {
        return $this->category;
    }

    // ...

Метод __toString() нужен для отображения названия подкатегории и категории в выпадающем списке.

Форма статьи:

// ...
use App\Entity\Subcategory;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;

class ArticleType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        
	$builder

            // ...

            ->add('subcategory', EntityType::class, ['label' => 'Подкатегория',
                'class' => Subcategory::class,
                'group_by' => fn($subcategory) => $subcategory->getCategory() ?? 'Без категории'])

            // ...

Если у подкатегории не может отсутствовать категория, то строку 16 можно заменить:

'group_by' => 'category'])

Источник

Документация по group_by