Skip to content

Getting started ​

Take authors and their books: Book::$author is a ManyToOne, and Author::$books its inverse OneToMany.

The target CRUD controller ​

The list is the book index, filtered on the author. The book CRUD controller needs a filter on author:

php
use EasyCorp\Bundle\EasyAdminBundle\Config\Filters;
use EasyCorp\Bundle\EasyAdminBundle\Filter\EntityFilter;

final class BookCrudController extends AbstractCrudController
{
    public function configureFilters(Filters $filters): Filters
    {
        return $filters->add(EntityFilter::new('author'));
    }
}

Everything else the list shows (its columns, page size, default sort and row actions) is the book index's own configuration.

The field ​

php
use Janalis\EasyAdminEmbeddedList\Field\EmbeddedListField;

final class AuthorCrudController extends AbstractCrudController
{
    public function configureFields(string $pageName): iterable
    {
        yield TextField::new('name');
        yield EmbeddedListField::new('books', 'Books');
    }
}

The field finds the book CRUD controller from the mapping's target entity and the filter from the mapping's other side (mappedBy or inversedBy). Edit an author: the form shows their books, paginated and sortable.

  • A new author has no list: there is nothing to filter on yet.
  • The field never writes the collection: saving the form leaves it as it is.
  • An unlabelled field spans the whole row; a labelled one takes the configured columns (col-md-7 col-xxl-6).

On index and detail pages ​

The field shows the size of the collection. Give it a relatedUrl custom option to link that number:

php
EmbeddedListField::new('books', 'Books')
    ->setCustomOption('relatedUrl', $this->urls->setController(BookCrudController::class)->generateUrl());

The template is @EasyAdminEmbeddedList/crud/field/embedded_list.html.twig. Replace it for every field in Configuration, or for one field with setTemplatePath().

Released under the MIT License.