Open maxkain opened 2 years ago
Hi,
I'm happy to know I'm not the only one to have this need. Indeed, the index query builder locked allowed entities and there is no way to create a query builder somewhere else to perform action on these entities.
@maxkain It's interesting, but this is a major change I think.
In my app, I created a QueryBuilderFactory
. It would be interesting to move the logic of the method createIndexQueryBuilder
to an independant service like the factory below to be able to create a query builder based on CRUD configuration.
<?php
namespace App\EasyAdmin\Factory;
use Doctrine\ORM\QueryBuilder;
use Doctrine\Persistence\ManagerRegistry;
use EasyCorp\Bundle\EasyAdminBundle\Collection\FieldCollection;
use EasyCorp\Bundle\EasyAdminBundle\Config\Action;
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
use EasyCorp\Bundle\EasyAdminBundle\Config\Option\EA;
use EasyCorp\Bundle\EasyAdminBundle\Factory\AdminContextFactory;
use EasyCorp\Bundle\EasyAdminBundle\Factory\ControllerFactory;
use EasyCorp\Bundle\EasyAdminBundle\Factory\EntityFactory;
use EasyCorp\Bundle\EasyAdminBundle\Factory\FilterFactory;
use EasyCorp\Bundle\EasyAdminBundle\Factory\FormFactory;
use EasyCorp\Bundle\EasyAdminBundle\Orm\EntityRepository;
use EasyCorp\Bundle\EasyAdminBundle\Provider\AdminContextProvider;
use LogicException;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
class QueryBuilderFactory
{
public function __construct(private ManagerRegistry $doctrine, private AdminContextFactory $adminContextFactory, private ControllerFactory $controllerFactory, private EntityFactory $entityFactory, private FormFactory $formFactory, private FilterFactory $filterFactory, private EventDispatcherInterface $eventDispatcher)
{
}
public function create(string $crudControllerFqcn, string $dashboardControllerFqcn, string $query = null, array $customSort = [], array $appliedFilters = []): QueryBuilder
{
$request = new Request([
EA::CRUD_ACTION => Action::INDEX,
EA::QUERY => $query,
EA::SORT => $customSort,
EA::FILTERS => $appliedFilters,
]);
$dashboardController = $this->controllerFactory->getDashboardControllerInstance($dashboardControllerFqcn, $request);
if (!$dashboardController) {
throw new LogicException(sprintf('The dashboard controller "%s" was not found.', $dashboardControllerFqcn));
}
$crudController = $this->controllerFactory->getCrudControllerInstance($crudControllerFqcn, Action::INDEX, $request);
if (!$crudController) {
throw new LogicException(sprintf('The CRUD controller "%s" was not found.', $crudControllerFqcn));
}
$adminContext = $this->adminContextFactory->create($request, $dashboardController, $crudController);
$request->attributes->set(EA::CONTEXT_REQUEST_ATTRIBUTE, $adminContext);
$requestStack = new RequestStack();
$requestStack->push($request);
$adminContextProvider = new AdminContextProvider($requestStack);
$entityRepository = new EntityRepository($adminContextProvider, $this->doctrine, $this->entityFactory, $this->formFactory, $this->eventDispatcher);
$fields = FieldCollection::new($crudController->configureFields(Crud::PAGE_INDEX));
$crudDto = $adminContext->getCrud();
if (!$crudDto) {
throw new LogicException('Missing CRUD DTO.');
}
$filters = $this->filterFactory->create($crudDto->getFiltersConfig(), $fields, $adminContext->getEntity());
$searchDto = $adminContext->getSearch();
if (!$searchDto) {
throw new LogicException('Missing Search DTO.');
}
return $entityRepository->createQueryBuilder($searchDto, $adminContext->getEntity(), $fields, $filters);
}
}
As you can see, I have to create a fake request to be able to create a fake admin context so as to get the CrudDto
of another entity than the current request. Pretty dirty 😢 But it works (for now) 😄
Some times is needed to calculate entities virtual fields on index page. But it's difficult to do now, the way is to decorate PaginatorFactory for each controller. But there is another way to do this feature in PaginatorFactory for easy using it for all contollers.
Usage in crud controller:
Abstract crud controller:
PaginatorFactory Decorator: