简体   繁体   中英

Symfony EasyAdminBundle 3 override the createIndexQueryBuilder()

It said on the EasyAdminBundle doc

For example, the index() action calls to a method named createIndexQueryBuilder() to create the Doctrine query builder used to get the results displayed on the index listing. If you want to customize that listing, it's better to override the createIndexQueryBuilder() method instead of the entire index() method.

So let's imagine I have in my user entity the field isDeleted set to true when the user is deleted. In the index page, I want to display only user with isDeleted = false. How to override the createIndexQueryBuilder() for this purpose?

Here is the method createIndexQueryBuilder


public function createIndexQueryBuilder(SearchDto $searchDto, EntityDto $entityDto, FieldCollection $fields, FilterCollection $filters): QueryBuilder
{
    return $this->get(EntityRepository::class)->createQueryBuilder($searchDto, $entityDto, $fields, $filters);
}

I tried to override it like this but it didn't work


public function createIndexQueryBuilder(SearchDto $searchDto, EntityDto $entityDto, FieldCollection $fields, FilterCollection $filters): QueryBuilder
{
    $response = $this->get(EntityRepository::class)->createQueryBuilder($searchDto, $entityDto, $fields, $filters);
    $response->where('isDeleted', true);
    return $response;
}

All you need is add entity. in where clause:)

public function createIndexQueryBuilder(SearchDto $searchDto, EntityDto $entityDto, FieldCollection $fields, FilterCollection $filters): QueryBuilder
{
    parent::createIndexQueryBuilder($searchDto, $entityDto, $fields, $filters);

    $response = $this->get(EntityRepository::class)->createQueryBuilder($searchDto, $entityDto, $fields, $filters);
    $response->where('entity.isDeleted = 1');

    return $response;
}

For everyone getting following QueryException using the accepted answer and finding this through search:

QueryException 
Too many parameters: the query defines 1 parameters and you bound 3

EasyAdmin v3.x inside your EntityCrudController:

  • use ->andWhere() function
  • use entity. as prefix (really, use "entity", do not replace by your entity-name)
public function createIndexQueryBuilder(SearchDto $searchDto, EntityDto $entityDto, FieldCollection $fields, FilterCollection $filters): QueryBuilder
{
    $response = $this->get(EntityRepository::class)->createQueryBuilder($searchDto, $entityDto, $fields, $filters);
    $response->andWhere('entity.isDeleted = 1');   
    return $response;
}

EasyAdmin4 solution

Note: The keyword (alias) entity is important

use Doctrine\ORM\QueryBuilder;

class ArticleCrudController extends AbstractCrudController
{
     ...

     public function configureFields(string $pageName): iterable
     {
          return [
                ...
                AssociationField::new('author')->setQueryBuilder(
                fn (QueryBuilder $queryBuilder) => $queryBuilder
                   ->leftJoin('entity.article', 'a')
                   ->andWhere('entity.isActive = 1')
                   ->andWhere('a.author is NULL')
                  ),
                ...
            ]
      }

      ...
}

Here is an exemple about how to replace the DQL FILTER in EasyAdmin v3.x

EasyAdmin v2.x DQL FILTER:

easy_admin:
  entities:
    User:
      class: App\Entity\User
      list:
        dql_filter: "entity.roles NOT LIKE '%%ROLE_SUPER_ADMIN%%'"

EasyAdmin v3.x inside UserCrudController:

public function createIndexQueryBuilder(SearchDto $searchDto, EntityDto $entityDto, FieldCollection $fields, FilterCollection $filters): QueryBuilder
{
    $response = $this->get(EntityRepository::class)->createQueryBuilder($searchDto, $entityDto, $fields, $filters);
    $response->where("entity.roles NOT LIKE '%%ROLE_SUPER_ADMIN%%'");

    return $response;
}

This worked for me with EasyAdmin 4.x

use EasyCorp\Bundle\EasyAdminBundle\Orm\EntityRepository;

class CampaignCrudController extends AbstractCrudController
{
    public function __construct(EntityRepository $entityRepository)
    {
        $this->entityRepository = $entityRepository;
    }

    public function createIndexQueryBuilder(SearchDto $searchDto, EntityDto $entityDto, FieldCollection $fields, FilterCollection $filters): ORMQueryBuilder
    {
        $response = $this->entityRepository->createQueryBuilder($searchDto, $entityDto, $fields, $filters);
        $response->andWhere('entity.user = :user')->setParameter('user', $this->getUser());

        return $response;
    }

With EasyAdmin 4, i've found this solution, because I was having an error with get(EntityRepository). Since you get "parent", you get already your Entity and Repository.

$response = parent::createIndexQueryBuilder($searchDto, $entityDto, $fields, $filters);
$response->andWhere('entity.status = :status')->setParameter('status', $status);

Here's another fictional example for EasyAdmin 3.x, adding a filter on entities loaded in an edit subfield. These entities are the target of a OneToMany relation (Showroom::gears), based on a join with the current Showroom entity's other attributes (Showroom::creator is the same Member entity as the owner of the Gear::inventory):

class ShowroomCrudController extends AbstractCrudController
{
    public static function getEntityFqcn(): string
    {
        return Showroom::class;
    }

    public function configureFields(string $pageName): iterable
    {
        
        return [
            IdField::new('id')->hideOnForm(),
            // relation to Member entity
            AssociationField::new('creator'),
            BooleanField::new('published')
                ->onlyOnForms()
                ->hideWhenCreating(),
            TextField::new('description'),
            AssociationField::new('gears')
                ->onlyOnForms()
                // we don't want to manage association between gears and the showroom upon showroom creation
                ->hideWhenCreating()
                ->setTemplatePath('admin/fields/inventory_gears.html.twig')
                // Only display gears that belong to the inventory of the showroom creator
                ->setQueryBuilder(
                    function (QueryBuilder $queryBuilder) {
                        // get current showroom instance
                        $currentShowroom = $this->getContext()->getEntity()->getInstance();
                        $creator = $currentShowroom->getCreator();
                        $memberId = $creator->getId();
                        // load the gears whose inventory owner is the showroom creator only
                        $queryBuilder->leftJoin('entity.inventory', 'i')
                            ->leftJoin('i.owner', 'm')
                            ->andWhere('m.id = :member_id')
                            ->setParameter('member_id', $memberId);    
                        return $queryBuilder;
                    }
                   ),
        ];
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM