EasyAdminBundle icon indicating copy to clipboard operation
EasyAdminBundle copied to clipboard

Executing 'Delete' action twice on same entity before refresh result in exception

Open BastienRimbert opened this issue 3 years ago • 4 comments

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.4 but still occurs in v4.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.

BastienRimbert avatar Aug 12 '22 09:08 BastienRimbert

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"?

michaelKaefer avatar Aug 12 '22 21:08 michaelKaefer

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.

BastienRimbert avatar Aug 16 '22 07:08 BastienRimbert

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?

michaelKaefer avatar Aug 17 '22 16:08 michaelKaefer

I'll try to do so

BastienRimbert avatar Aug 17 '22 16:08 BastienRimbert