Skip to content

Commit

Permalink
Add preBatchAction to Admin Extension and add a pre_batch_action event
Browse files Browse the repository at this point in the history
This adds a preBatchAction() method to the AbstractAdminExtension and
AdminExtensionInterface (BC). This enables the AdminEventExtension to
dispatch a BatchActionEvent of type pre_batch_action. Both the extension
and the event provide points to hook into within your own code, just
like this is possible for pre/post persist/update/delete.

Fixes sonata-project#7516 "Implement an event for batch actions"
Relates to sonata-project#6550 "Delete Event isn't triggered in Batch delete"
  • Loading branch information
7ochem committed Nov 1, 2021
1 parent 1e469ee commit 6ff9656
Show file tree
Hide file tree
Showing 6 changed files with 191 additions and 0 deletions.
9 changes: 9 additions & 0 deletions src/Admin/AbstractAdminExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,15 @@ public function configureBatchActions(AdminInterface $admin, array $actions): ar
return $actions;
}

// NEXT_MAJOR: Remove the PHPDoc block as the interface will then specify the types
/**
* @param mixed[] $idx
* @phpstan-param AdminInterface<T> $admin
*/
public function preBatchAction(AdminInterface $admin, string $actionName, ProxyQueryInterface $query, array &$idx, bool $allElements = false): void
{
}

public function configureExportFields(AdminInterface $admin, array $fields): array
{
return $fields;
Expand Down
11 changes: 11 additions & 0 deletions src/Admin/AdminExtensionInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
/**
* @author Thomas Rabaix <[email protected]>
*
* NEXT_MAJOR: Uncomment the actual definition of below methods inside the interface and remove these annotations.
*
* @method void preBatchAction(AdminInterface $admin, string $actionName, ProxyQueryInterface $query, array &$idx, bool $allElements = false)
*
* @phpstan-template T of object
*/
interface AdminExtensionInterface
Expand Down Expand Up @@ -127,6 +131,13 @@ public function getAccessMapping(AdminInterface $admin): array;
*/
public function configureBatchActions(AdminInterface $admin, array $actions): array;

// NEXT_MAJOR: Uncomment the method definition
///**
// * @param mixed[] $idx
// * @phpstan-param AdminInterface<T> $admin
// */
//public function preBatchAction(AdminInterface $admin, string $actionName, ProxyQueryInterface $query, array &$idx, bool $allElements = false): void;

/**
* Get a chance to modify export fields.
*
Expand Down
7 changes: 7 additions & 0 deletions src/Controller/CRUDController.php
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,13 @@ public function batchAction(Request $request): Response
$query->setMaxResults(null);

$this->admin->preBatchAction($action, $query, $idx, $allElements);
foreach ($this->admin->getExtensions() as $extension) {
// NEXT_MAJOR: Remove the if-statement around the call to `$extension->preBatchAction()`
// @phpstan-ignore-next-line
if (method_exists($extension, 'preBatchAction')) {
$extension->preBatchAction($this->admin, $action, $query, $idx, $allElements);
}
}

if (\count($idx) > 0) {
$this->admin->getModelManager()->addIdentifiersToQuery($this->admin->getClass(), $query, $idx);
Expand Down
8 changes: 8 additions & 0 deletions src/Event/AdminEventExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -126,4 +126,12 @@ public function postRemove(AdminInterface $admin, object $object): void
'sonata.admin.event.persistence.post_remove'
);
}

public function preBatchAction(AdminInterface $admin, string $actionName, ProxyQueryInterface $query, array &$idx, bool $allElements = false): void
{
$this->eventDispatcher->dispatch(
new BatchActionEvent($admin, BatchActionEvent::TYPE_PRE_BATCH_ACTION, $actionName, $query, $idx, $allElements),
'sonata.admin.event.batch_action.pre_batch_action'
);
}
}
122 changes: 122 additions & 0 deletions src/Event/BatchActionEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Sonata Project package.
*
* (c) Thomas Rabaix <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Sonata\AdminBundle\Event;

use Sonata\AdminBundle\Admin\AdminInterface;
use Sonata\AdminBundle\Datagrid\ProxyQueryInterface;
use Symfony\Contracts\EventDispatcher\Event;

/**
* This event is sent by hook:
* - preBatchAction.
*
* You can register the listener to the event dispatcher by using:
* - sonata.admin.event.batch_action.pre_batch_action)
* - sonata.admin.event.batch_action.[admin_code].pre_batch_action (not implemented yet)
*
* @author Jochem Klaver <[email protected]>
*
* @phpstan-template T of object
*/
final class BatchActionEvent extends Event
{
public const TYPE_PRE_BATCH_ACTION = 'pre_batch_action';
public const TYPE_POST_BATCH_ACTION = 'post_batch_action'; // not implemented yet

/**
* @var AdminInterface<object>
* @phpstan-var AdminInterface<T>
*/
private $admin;

/**
* @var string
* @phpstan-var self::TYPE_*
*/
private $type;

/**
* @var string
*/
private $actionName;

/**
* @var ProxyQueryInterface
*/
private $proxyQuery;

/**
* @var mixed[]
*/
private $idx;

/**
* @var bool
*/
private $allElements;

/**
* @param mixed[] $idx
* @phpstan-param AdminInterface<T> $admin
* @phpstan-param self::TYPE_* $type
*/
public function __construct(AdminInterface $admin, string $type, string $actionName, ProxyQueryInterface $proxyQuery, array &$idx, bool $allElements = false)
{
$this->admin = $admin;
$this->type = $type;
$this->actionName = $actionName;
$this->proxyQuery = $proxyQuery;
$this->idx = &$idx;
$this->allElements = $allElements;
}

/**
* @phpstan-return AdminInterface<T>
*/
public function getAdmin(): AdminInterface
{
return $this->admin;
}

/**
* @phpstan-return self::TYPE_*
*/
public function getType(): string
{
return $this->type;
}

public function getActionName(): string
{
return $this->actionName;
}

public function getProxyQuery(): ProxyQueryInterface
{
return $this->proxyQuery;
}

/**
* @return mixed[]
*/
public function &getIdx(): array
{
return $this->idx;
}

public function isAllElements(): bool
{
return $this->allElements;
}
}
34 changes: 34 additions & 0 deletions tests/Event/AdminEventExtensionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Datagrid\ProxyQueryInterface;
use Sonata\AdminBundle\Event\AdminEventExtension;
use Sonata\AdminBundle\Event\BatchActionEvent;
use Sonata\AdminBundle\Event\ConfigureEvent;
use Sonata\AdminBundle\Event\ConfigureQueryEvent;
use Sonata\AdminBundle\Event\PersistenceEvent;
Expand Down Expand Up @@ -189,4 +190,37 @@ public function testPostRemove(): void
static::equalTo('sonata.admin.event.persistence.post_remove'),
])->postRemove($this->createMock(AdminInterface::class), new \stdClass());
}

public function testPreBatchAction(): void
{
$admin = $this->createMock(AdminInterface::class);
$proxyQuery = $this->createMock(ProxyQueryInterface::class);
$idx = [1, 2, 3];

$this->getExtension([
static::callback(
static function (Event $event) use (&$idx): bool {
if (!$event instanceof BatchActionEvent) {
return false;
}

if (BatchActionEvent::TYPE_PRE_BATCH_ACTION !== $event->getType()) {
return false;
}

if ('delete' !== $event->getActionName()) {
return false;
}

$idx[] = 4; // Test if this was passed by reference correctly everywhere
if ($event->getIdx() !== $idx) {
return false;
}

return true;
}
),
static::equalTo('sonata.admin.event.batch_action.pre_batch_action'),
])->preBatchAction($admin, 'delete', $proxyQuery, $idx, false);
}
}

0 comments on commit 6ff9656

Please sign in to comment.