Skip to content

Commit

Permalink
[SonataExtraBundle] delete batch object check base on patch
Browse files Browse the repository at this point in the history
  • Loading branch information
mpoiriert committed Apr 1, 2024
1 parent 32ffd53 commit 0f1925f
Show file tree
Hide file tree
Showing 15 changed files with 191 additions and 1 deletion.
3 changes: 3 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,9 @@
"target-directory": "vendor-bin"
},
"patches": {
"sonata-project/doctrine-orm-admin-bundle": {
"Batch model delete check": "https://github.com/mpoiriert/SonataDoctrineORMAdminBundle/commit/9f9768c99d63020e3b9168d4456edf2a3dc97cca.patch"
}
}
},
"scripts": {
Expand Down
13 changes: 13 additions & 0 deletions packages/sonata-extra-bundle/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Draw\Bundle\SonataExtraBundle\DependencyInjection;

use Draw\Bundle\SonataExtraBundle\Extension\AutoActionExtension;
use Sonata\DoctrineORMAdminBundle\Event\PreObjectDeleteBatchEvent;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
Expand All @@ -21,6 +22,7 @@ public function getConfigTreeBuilder(): TreeBuilder
->booleanNode('install_assets')->defaultTrue()->end()
->append($this->createAutoActionNode())
->append($this->createAutoHelpNode())
->append($this->createBatchDeleteCheckNode())
->append($this->createCanSecurityHandlerNode())
->append($this->createFixMenuDepthNode())
->append($this->createListFieldPriorityNode())
Expand All @@ -38,6 +40,17 @@ private function createAutoHelpNode(): ArrayNodeDefinition
->canBeEnabled();
}

private function createBatchDeleteCheckNode(): ArrayNodeDefinition
{
$node = new ArrayNodeDefinition('batch_delete_check');

class_exists(PreObjectDeleteBatchEvent::class)
? $node->canBeDisabled()
: $node->canBeEnabled();

return $node;
}

private function createNotifierNode(): ArrayNodeDefinition
{
$node = new ArrayNodeDefinition('notifier');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Draw\Bundle\SonataExtraBundle\Controller\AdminControllerInterface;
use Draw\Bundle\SonataExtraBundle\EventListener\AutoHelpListener;
use Draw\Bundle\SonataExtraBundle\EventListener\FixDepthMenuBuilderListener;
use Draw\Bundle\SonataExtraBundle\EventListener\PreObjectDeleteBatchEventEventListener;
use Draw\Bundle\SonataExtraBundle\EventListener\SessionTimeoutRequestListener;
use Draw\Bundle\SonataExtraBundle\Extension\AutoActionExtension;
use Draw\Bundle\SonataExtraBundle\Extension\ListFieldPriorityExtension;
Expand Down Expand Up @@ -46,6 +47,10 @@ public function load(array $configs, ContainerBuilder $container): void
$container->removeDefinition(AutoHelpListener::class);
}

if (!($config['batch_delete_check']['enabled'] ?? false)) {
$container->removeDefinition(PreObjectDeleteBatchEventEventListener::class);
}

if (!($config['fix_menu_depth']['enabled'] ?? false)) {
$container->removeDefinition(FixDepthMenuBuilderListener::class);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace Draw\Bundle\SonataExtraBundle\EventListener;

use Sonata\AdminBundle\Admin\Pool;
use Sonata\DoctrineORMAdminBundle\Event\PreObjectDeleteBatchEvent;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;

class PreObjectDeleteBatchEventEventListener
{
public function __construct(private Pool $pool)
{
}

#[AsEventListener]
public function handlePreObjectDeleteBatchEvent(PreObjectDeleteBatchEvent $event): void
{
$canDelete = $this->pool
->getAdminByClass($event->getClassName())
->hasAccess('delete', $event->getObject());

if (!$canDelete) {
$event->preventDelete();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ public function getDefaultConfiguration(): array
'auto_help' => [
'enabled' => false,
],
'batch_delete_check' => [
'enabled' => true,
],
'can_security_handler' => [
'enabled' => false,
'grant_by_default' => true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public function createExtension(): Extension
public function getConfiguration(): array
{
return [
...parent::getConfiguration(),
'auto_action' => [
'enabled' => true,
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public function createExtension(): Extension
public function getConfiguration(): array
{
return [
...parent::getConfiguration(),
'auto_help' => [
'enabled' => true,
],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace DependencyInjection;

use Draw\Bundle\SonataExtraBundle\DependencyInjection\DrawSonataExtraExtension;
use Draw\Bundle\SonataExtraBundle\EventListener\PreObjectDeleteBatchEventEventListener;
use Draw\Bundle\SonataExtraBundle\Tests\DependencyInjection\DrawSonataExtraExtensionTest;
use Symfony\Component\DependencyInjection\Extension\Extension;

class DrawSonataExtraExtensionBatchDeleteCheckEnabledTest extends DrawSonataExtraExtensionTest
{
public function createExtension(): Extension
{
return new DrawSonataExtraExtension();
}

public function getConfiguration(): array
{
return [
...parent::getConfiguration(),
'batch_delete_check' => [
'enabled' => true,
],
];
}

public static function provideTestHasServiceDefinition(): iterable
{
yield from parent::provideTestHasServiceDefinition();
yield [PreObjectDeleteBatchEventEventListener::class];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public function createExtension(): Extension
public function getConfiguration(): array
{
return [
...parent::getConfiguration(),
'can_security_handler' => [
'enabled' => true,
'prevent_delete_voter' => [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public function createExtension(): Extension
public function getConfiguration(): array
{
return [
...parent::getConfiguration(),
'fix_menu_depth' => [
'enabled' => true,
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public function createExtension(): Extension
public function getConfiguration(): array
{
return [
...parent::getConfiguration(),
'notifier' => [
'enabled' => true,
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public function createExtension(): Extension
public function getConfiguration(): array
{
return [
...parent::getConfiguration(),
'session_timeout' => [
'enabled' => true,
'delay' => 900,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,11 @@ public function createExtension(): Extension

public function getConfiguration(): array
{
return [];
return [
'batch_delete_check' => [
'enabled' => false,
],
];
}

public static function provideTestHasServiceDefinition(): iterable
Expand Down
11 changes: 11 additions & 0 deletions packages/sonata-extra-bundle/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"symfony/expression-language": "^6.4.0"
},
"require-dev": {
"cweagans/composer-patches": "^1.7",
"draw/tester": "^0.11",
"draw/security": "^0.11",
"phpunit/phpunit": "^9.0 || ^10.0",
Expand All @@ -24,9 +25,19 @@
"Draw\\Bundle\\SonataExtraBundle\\": ""
}
},
"config": {
"allow-plugins": {
"cweagans/composer-patches": true
}
},
"extra": {
"branch-alias": {
"dev-master": "0.11-dev"
},
"patches": {
"sonata-project/doctrine-orm-admin-bundle": {
"Batch model delete check": "https://github.com/mpoiriert/SonataDoctrineORMAdminBundle/commit/9f9768c99d63020e3b9168d4456edf2a3dc97cca.patch"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?php

namespace App\Tests\SonataExtraBundle\EventListener;

use App\Entity\User;
use App\Security\Voter\CannotDeleteSelfVoter;
use Doctrine\ORM\EntityManagerInterface;
use Draw\Bundle\SonataExtraBundle\EventListener\PreObjectDeleteBatchEventEventListener;
use Draw\Bundle\TesterBundle\PHPUnit\Extension\SetUpAutowire\AutowiredInterface;
use Draw\Bundle\TesterBundle\PHPUnit\Extension\SetUpAutowire\AutowireService;
use Sonata\DoctrineORMAdminBundle\Event\PreObjectDeleteBatchEvent;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\Security\Core\Authentication\Token\AbstractToken;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;

class PreObjectDeleteBatchEventEventListenerTest extends KernelTestCase implements AutowiredInterface
{
#[AutowireService]
private PreObjectDeleteBatchEventEventListener $object;

#[AutowireService]
private TokenStorageInterface $tokenStorage;

#[AutowireService]
private EntityManagerInterface $entityManager;

public function testHandlePreObjectDeleteBatchEventCannotDelete(): void
{
$user = $this->entityManager
->getRepository(User::class)
->findOneBy(['email' => '[email protected]']);

$this->connectUser($user);

$this->object->handlePreObjectDeleteBatchEvent(
$event = new PreObjectDeleteBatchEvent(
User::class,
$user
)
);

static::assertFalse(
$event->shouldDelete(),
CannotDeleteSelfVoter::class.' should prevent deletion of the user.'
);
}

public function testHandlePreObjectDeleteBatchEventCanDelete(): void
{
$user = $this->entityManager
->getRepository(User::class)
->findOneBy(['email' => '[email protected]']);

$this->connectUser($user);

$this->object->handlePreObjectDeleteBatchEvent(
$event = new PreObjectDeleteBatchEvent(
User::class,
new User()
)
);

static::assertTrue(
$event->shouldDelete()
);
}

private function connectUser(User $user): void
{
$this->tokenStorage
->setToken(
new class($user) extends AbstractToken {
public function __construct(User $user)
{
parent::__construct(['ROLE_SUPER_ADMIN']);

$this->setUser($user);
}

public function getCredentials()
{
return null;
}
}
);
}
}

0 comments on commit 0f1925f

Please sign in to comment.