Skip to content

Commit

Permalink
[SoantaExtraBundle] Allow AdminAction to generate multiple actions "b…
Browse files Browse the repository at this point in the history
…uttons" (#298)

---------

Co-authored-by: Martin Poirier Théorêt <[email protected]>
  • Loading branch information
DumitracheAdrian and mpoiriert authored Oct 15, 2024
1 parent 82dffeb commit aa87229
Show file tree
Hide file tree
Showing 8 changed files with 236 additions and 18 deletions.
28 changes: 28 additions & 0 deletions app/src/Controller/Admin/SetPreferredLocaleAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

namespace App\Controller\Admin;

use App\Entity\User;
use Draw\Bundle\SonataExtraBundle\ActionableAdmin\ObjectActionExecutioner;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;

#[AsController]
class SetPreferredLocaleAction
{
public function __invoke(
Request $request,
ObjectActionExecutioner $objectActionExecutioner,
): Response {
return $objectActionExecutioner->execute(
static function (User $user) use ($request, $objectActionExecutioner): void {
$user->setPreferredLocale($request->get('_locale') ?? 'en');

$objectActionExecutioner->getAdmin()->update($user);
}
);
}
}
23 changes: 22 additions & 1 deletion app/src/Sonata/Admin/UserAdmin.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use App\Controller\Admin\AddRolesAminAction;
use App\Controller\Admin\MakeAdminAction;
use App\Controller\Admin\SetPreferredLocaleAction;
use App\Entity\Tag;
use App\Entity\User;
use Draw\Bundle\SonataExtraBundle\ActionableAdmin\ActionableAdminInterface;
Expand Down Expand Up @@ -108,6 +109,7 @@ protected function configureShowFields(ShowMapper $show): void
->add('childObject2')
->add('email')
->add('dateOfBirth')
->add('preferredLocale')
->add('roles', 'json')
->add('rolesList', 'list')
->add('static', 'static', ['virtual_field' => true, 'value' => 'Static value'])
Expand Down Expand Up @@ -213,13 +215,32 @@ protected function configureFormFields(FormMapper $form): void
public function getActions(): array
{
return [
'makeAdin' => (new AdminAction('makeAdmin', true))
'makeAdmin' => (new AdminAction('makeAdmin', true))
->setController(MakeAdminAction::class)
->setIcon('fa fa-user-plus')
->setBatchController(MakeAdminAction::class),
'addRoles' => (new AdminAction('addRoles', true))
->setController(AddRolesAminAction::class)
->setBatchController(AddRolesAminAction::class),
'setPreferredLocale' => (new AdminAction('setPreferredLocale', true))
->setIcon('fa fa-language')
->setController(SetPreferredLocaleAction::class)
->setRoutePattern(
\sprintf(
'%s/preferred-locale/{_locale}',
$this->getRouterIdParameter(),
)
)
->setActionsCallback(
static function (AdminAction $action): iterable {
foreach (['en', 'fr'] as $locale) {
yield (clone $action)
->setLabel(strtoupper($locale))
->setRouteParameters(['_locale' => $locale])
;
}
}
),
];
}
}
60 changes: 60 additions & 0 deletions packages/sonata-extra-bundle/ActionableAdmin/AdminAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Draw\Bundle\SonataExtraBundle\ActionableAdmin;

use Sonata\AdminBundle\Admin\AdminInterface;
use Symfony\Component\DependencyInjection\Attribute\Exclude;
use Symfony\Component\String\UnicodeString;

Expand All @@ -22,11 +23,20 @@ class AdminAction

private string $urlSuffix;

private ?string $routePattern = null;

private array $routeParameters = [];

private string $access;

private string|false|null $label;
private string|false|null $translationDomain = null;

/**
* @var callable
*/
private $actionsCallback;

public function __construct(
private string $name,
private bool $targetEntity,
Expand All @@ -44,6 +54,8 @@ public function __construct(
->replace('_', '-')
->toString()
;

$this->actionsCallback = fn () => [$this];
}

public function getName(): string
Expand Down Expand Up @@ -80,6 +92,18 @@ public function setUrlSuffix(string $urlSuffix): self
return $this;
}

public function getRoutePattern(): ?string
{
return $this->routePattern;
}

public function setRoutePattern(?string $routePattern): self
{
$this->routePattern = $routePattern;

return $this;
}

public function getLabel(): bool|string|null
{
return $this->label;
Expand Down Expand Up @@ -197,4 +221,40 @@ public function isForAction(string $action): bool
{
return $this->forActions[$action] ?? $this->forActions['_default'];
}

public function getActions(): iterable
{
return \call_user_func($this->actionsCallback, $this);
}

public function getActionsCallback(): callable
{
return $this->actionsCallback;
}

public function setActionsCallback(callable $actionsCallback): self
{
$this->actionsCallback = $actionsCallback;

return $this;
}

public function getRouteParameters(): array
{
return $this->routeParameters;
}

public function setRouteParameters(array $routeParameters): self
{
$this->routeParameters = $routeParameters;

return $this;
}

public function generateUrl(AdminInterface $admin, mixed $subject = null): string
{
return null !== $subject
? $admin->generateObjectUrl($this->name, $subject, $this->routeParameters)
: $admin->generateUrl($this->name, $this->routeParameters);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Draw\Bundle\SonataExtraBundle\ActionableAdmin\Extension;

use Draw\Bundle\SonataExtraBundle\ActionableAdmin\AdminAction;
use Draw\Bundle\SonataExtraBundle\ActionableAdmin\AdminActionLoader;
use Sonata\AdminBundle\Admin\AbstractAdminExtension;
use Sonata\AdminBundle\Admin\AdminInterface;
Expand Down Expand Up @@ -36,14 +37,10 @@ public function configureRoutes(AdminInterface $admin, RouteCollectionInterface
$defaults['_controller'] = $action->getController();
}

$pattern = $action->getTargetEntity()
? $admin->getRouterIdParameter().'/'.$action->getUrlSuffix()
: $action->getUrlSuffix();

$collection
->add(
$action->getName(),
$pattern,
$this->getRoutePattern($admin, $action),
defaults: $defaults
)
;
Expand Down Expand Up @@ -144,4 +141,15 @@ public function configureActionButtons(

return $list;
}

private function getRoutePattern(AdminInterface $admin, AdminAction $action): string
{
if (null !== $pattern = $action->getRoutePattern()) {
return $pattern;
}

return $action->getTargetEntity()
? \sprintf('%s/%s', $admin->getRouterIdParameter(), $action->getUrlSuffix())
: $action->getUrlSuffix();
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
{% for action in item.action.actions %}
<li>
<a class="sonata-action-element" href="{{ object is defined ? admin.generateObjectUrl(item.action.name, object) : admin.generateUrl(item.action.name) }}">
{% if item.action.icon %}
<i class="{{ item.action.icon }}" aria-hidden="true"></i>
<a class="sonata-action-element" href="{{ action.generateUrl(admin, object) }}">
{% if action.icon %}
<i class="{{ action.icon }}" aria-hidden="true"></i>
{% endif %}
{{ item.action|translate_label }}
{{ action|translate_label }}
</a>
</li>
</li>
{% endfor %}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
{% if admin.hasAccess(actions.action.name, object) %}
<a class="btn btn-sm btn-default" href="{{ admin.generateObjectUrl(actions.action.name, object) }}">
{% if actions.action.icon %}
<i class="{{ actions.action.icon }}" aria-hidden="true"></i>
{% endif %}
{{ actions.action|translate_label }}
</a>
{% endif %}
{% for action in actions.action.actions %}
<a class="btn btn-sm btn-default" href="{{ action.generateUrl(admin, object) }}">
{% if action.icon %}
<i class="{{ action.icon }}" aria-hidden="true"></i>
{% endif %}
{{ action|translate_label }}
</a>
{% endfor %}
{% endif %}
96 changes: 96 additions & 0 deletions packages/sonata-extra-bundle/Test/AdminTestHelperTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?php

declare(strict_types=1);

namespace Draw\Bundle\SonataExtraBundle\Test;

use Symfony\Bundle\FrameworkBundle\KernelBrowser;
use Symfony\Component\DomCrawler\Crawler;
use Symfony\Component\DomCrawler\Link;

trait AdminTestHelperTrait
{
protected function selectListObjectLink(
Crawler $crawler,
int|string $identifier,
string $action,
): Link {
return $crawler
->filter(\sprintf('.sonata-ba-list-field-actions[objectid="%s"]', $identifier))
->selectLink($action)
->link()
;
}

protected function selectMenuObjectLink(
Crawler $crawler,
string $action,
): Link {
return $crawler
->filter('ul.dropdown-menu')
->selectLink($action)
->link()
;
}

protected function submitBatchAction(
KernelBrowser $client,
array $indexes,
string $action,
string $button = 'OK',
): void {
$crawler = $client->submitForm(
$button,
[
'idx' => $indexes,
'action' => $action,
]
);

$client->submit(
$crawler->selectButton('Yes, execute')->form()
);
}

protected function appendDefaultFiltersToListUrl(string $listUrl): string
{
return \sprintf(
'%s%s%s',
$listUrl,
null === parse_url($listUrl, \PHP_URL_QUERY) ? '?' : '&',
http_build_query(
[
'filter' => [
'_page' => 1,
'_per_page' => 25,
],
]
)
);
}

protected function filterListByIdentifier(
KernelBrowser $client,
string $listUrl,
int|string $identifier,
string $identifierName = 'id',
): Crawler {
return $client->request(
'GET',
\sprintf(
'%s?%s',
$listUrl,
http_build_query(
[
'filter' => [
$identifierName => [
'type' => 3,
'value' => $identifier,
],
],
]
)
)
);
}
}
1 change: 1 addition & 0 deletions packages/sonata-extra-bundle/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"require": {
"php": ">=8.2",
"draw/dependency-injection": "^0.12",
"symfony/browser-kit": "^6.4.0",
"symfony/framework-bundle": "^6.4.0",
"symfony/expression-language": "^6.4.0",
"symfony/string": "^6.4.0"
Expand Down

0 comments on commit aa87229

Please sign in to comment.