Executing 'Delete' action twice on same entity before refresh result in exception
Describe the bug
Whenever you are able to delete a entity via action and you do the action twice before the request has been complete, an exception will occur since the involved entity has been deleted before executing the second request.
I haven't found a proper way to prevent that since it seems to be thrown before any code is executed from the CRUD Controller.
To Reproduce
The easiest way to reproduce this is to create a custom action which remove involved entity and double click it since the basic 'Delete' button has a prompt which makes it impossible except on heavy delete.
Additional context
- EasyAdmin version: I'm using
v4.2.4but still occurs inv4.3.4. - Exception thrown:
EntityNotFoundException - Message:
The "App\Entity\MyEntity" entity with "id = 3" does not exist in the database. The entity may have been deleted by mistake or by a "cascade={"remove"}" operation executed by Doctrine.
Trace log
Logs
at vendor/easycorp/easyadmin-bundle/src/Factory/EntityFactory.php:148
at EasyCorp\Bundle\EasyAdminBundle\Factory\EntityFactory->getEntityInstance('App\\Entity\\ErrorDetail', '3')
(vendor/easycorp/easyadmin-bundle/src/Factory/EntityFactory.php:110)
at EasyCorp\Bundle\EasyAdminBundle\Factory\EntityFactory->doCreate('App\\Entity\\ErrorDetail', '3', null)
(vendor/easycorp/easyadmin-bundle/src/Factory/EntityFactory.php:70)
at EasyCorp\Bundle\EasyAdminBundle\Factory\EntityFactory->create('App\\Entity\\ErrorDetail', '3', null)
(vendor/easycorp/easyadmin-bundle/src/Factory/AdminContextFactory.php:240)
at EasyCorp\Bundle\EasyAdminBundle\Factory\AdminContextFactory->getEntityDto(object(Request), object(CrudDto))
(vendor/easycorp/easyadmin-bundle/src/Factory/AdminContextFactory.php:61)
at EasyCorp\Bundle\EasyAdminBundle\Factory\AdminContextFactory->create(object(Request), object(DashboardController), object(ErrorDetailCrudController))
(vendor/easycorp/easyadmin-bundle/src/EventListener/AdminRouterSubscriber.php:84)
at EasyCorp\Bundle\EasyAdminBundle\EventListener\AdminRouterSubscriber->onKernelRequest(object(RequestEvent), 'kernel.request', object(TraceableEventDispatcher))
(vendor/symfony/event-dispatcher/Debug/WrappedListener.php:115)
at Symfony\Component\EventDispatcher\Debug\WrappedListener->__invoke(object(RequestEvent), 'kernel.request', object(TraceableEventDispatcher))
(vendor/symfony/event-dispatcher/EventDispatcher.php:230)
at Symfony\Component\EventDispatcher\EventDispatcher->callListeners(array(object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener)), 'kernel.request', object(RequestEvent))
(vendor/symfony/event-dispatcher/EventDispatcher.php:59)
at Symfony\Component\EventDispatcher\EventDispatcher->dispatch(object(RequestEvent), 'kernel.request')
(vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php:153)
at Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher->dispatch(object(RequestEvent), 'kernel.request')
(vendor/symfony/http-kernel/HttpKernel.php:128)
at Symfony\Component\HttpKernel\HttpKernel->handleRaw(object(Request), 1)
(vendor/symfony/http-kernel/HttpKernel.php:74)
at Symfony\Component\HttpKernel\HttpKernel->handle(object(Request), 1, true)
(vendor/symfony/http-kernel/Kernel.php:202)
at Symfony\Component\HttpKernel\Kernel->handle(object(Request))
(vendor/symfony/runtime/Runner/Symfony/HttpKernelRunner.php:35)
at Symfony\Component\Runtime\Runner\Symfony\HttpKernelRunner->run()
(vendor/autoload_runtime.php:29)
at require_once('/code/vendor/autoload_runtime.php')
(public/index.php:5)
Proposed solution
One solution would be to do something similar as to when you're adding a new entity, the buttons get disabled so you can't do that action again.
Do I understand correctly? The only way to reproduce this bug is to implement a custom action? If that's correct then it is no EA bug.
What do you mean by "heavy delete"?
Not really, it's possible to get the error to occur with just EA. The only thing that prevent you from seeing that error often is just the popup asking you to confirm, but if you are fast enough, or the entity you're trying to delete involve a long process and thus making it few seconds longs and you try to delete again, the error occurs.
It can be reproduced with:
class ProductCrudController extends AbstractCrudController
{
public static function getEntityFqcn(): string
{
return Product::class;
}
public function delete(AdminContext $context)
{
sleep(20);
return parent::delete($context);
}
}
@BastienRimbert Yes, seems it can be fixed by disabling the delete action after the deletion prompt model is accepted. Can you submit a PR?
I'll try to do so