Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Autoinject all admin variables #8116

Merged
merged 1 commit into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
51 changes: 51 additions & 0 deletions src/Controller/CRUDController.php
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ public function listAction(Request $request): Response
$exportFormats = $exporter->getAvailableFormats($this->admin);
}

/**
* @psalm-suppress DeprecatedMethod
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A NEXT_MAJOR replace with render() should be added (?)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The NEXT_MAJOR comment is pedantic because the annotation should provide enough information

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When we had to resolve all the 4.x NEXT_MAJOR some of them were not obvious, so there is never too much comment.

@psalm-suppress just tell to ignore the deprecation but does not explain how to solve it.

At least

NEXT_MAJOR: Remplace this method by `$this->render`

above renderWithExtraParams definition might be more useful than remove this method.

*/
return $this->renderWithExtraParams($template, [
'action' => 'list',
'form' => $formView,
Expand Down Expand Up @@ -262,6 +265,9 @@ public function deleteAction(Request $request): Response

$template = $this->templateRegistry->getTemplate('delete');

/**
* @psalm-suppress DeprecatedMethod
*/
return $this->renderWithExtraParams($template, [
'object' => $object,
'action' => 'delete',
Expand Down Expand Up @@ -371,6 +377,9 @@ public function editAction(Request $request): Response

$template = $this->templateRegistry->getTemplate($templateKey);

/**
* @psalm-suppress DeprecatedMethod
*/
return $this->renderWithExtraParams($template, [
'action' => 'edit',
'form' => $formView,
Expand Down Expand Up @@ -491,6 +500,9 @@ public function batchAction(Request $request): Response

$template = $batchAction['template'] ?? $this->templateRegistry->getTemplate('batch_confirmation');

/**
* @psalm-suppress DeprecatedMethod
*/
return $this->renderWithExtraParams($template, [
'action' => 'list',
'action_label' => $actionLabel,
Expand Down Expand Up @@ -544,6 +556,9 @@ public function createAction(Request $request): Response
$class = new \ReflectionClass($this->admin->hasActiveSubClass() ? $this->admin->getActiveSubClass() : $this->admin->getClass());

if ($class->isAbstract()) {
/**
* @psalm-suppress DeprecatedMethod
*/
return $this->renderWithExtraParams(
'@SonataAdmin/CRUD/select_subclass.html.twig',
[
Expand Down Expand Up @@ -632,6 +647,9 @@ public function createAction(Request $request): Response

$template = $this->templateRegistry->getTemplate($templateKey);

/**
* @psalm-suppress DeprecatedMethod
*/
return $this->renderWithExtraParams($template, [
'action' => 'create',
'form' => $formView,
Expand Down Expand Up @@ -664,6 +682,9 @@ public function showAction(Request $request): Response

$template = $this->templateRegistry->getTemplate('show');

/**
* @psalm-suppress DeprecatedMethod
*/
return $this->renderWithExtraParams($template, [
'action' => 'show',
'object' => $object,
Expand Down Expand Up @@ -702,6 +723,9 @@ public function historyAction(Request $request): Response

$template = $this->templateRegistry->getTemplate('history');

/**
* @psalm-suppress DeprecatedMethod
*/
return $this->renderWithExtraParams($template, [
'action' => 'history',
'object' => $object,
Expand Down Expand Up @@ -753,6 +777,9 @@ public function historyViewRevisionAction(Request $request, string $revision): R

$template = $this->templateRegistry->getTemplate('show');

/**
* @psalm-suppress DeprecatedMethod
*/
return $this->renderWithExtraParams($template, [
'action' => 'show',
'object' => $object,
Expand Down Expand Up @@ -813,6 +840,9 @@ public function historyCompareRevisionsAction(Request $request, string $baseRevi

$template = $this->templateRegistry->getTemplate('show_compare');

/**
* @psalm-suppress DeprecatedMethod
*/
return $this->renderWithExtraParams($template, [
'action' => 'show',
'object' => $baseObject,
Expand Down Expand Up @@ -921,6 +951,9 @@ public function aclAction(Request $request): Response

$template = $this->templateRegistry->getTemplate('acl');

/**
* @psalm-suppress DeprecatedMethod
*/
return $this->renderWithExtraParams($template, [
'action' => 'acl',
'permissions' => $adminObjectAclData->getUserPermissions(),
Expand Down Expand Up @@ -961,20 +994,34 @@ final public function configureAdmin(Request $request): void
*
* @param string $view The view name
* @param array<string, mixed> $parameters An array of parameters to pass to the view
*
* @deprecated since sonata-project/admin-bundle version 4.x
*
* NEXT_MAJOR: Remove this method
*/
final protected function renderWithExtraParams(string $view, array $parameters = [], ?Response $response = null): Response
{
/**
* @psalm-suppress DeprecatedMethod
*/
return $this->render($view, $this->addRenderExtraParams($parameters), $response);
}

/**
* @param array<string, mixed> $parameters
*
* @return array<string, mixed>
*
* @deprecated since sonata-project/admin-bundle version 4.x
*
* NEXT_MAJOR: Remove this method
*/
protected function addRenderExtraParams(array $parameters = []): array
{
$parameters['admin'] ??= $this->admin;
/**
* @psalm-suppress DeprecatedMethod
*/
$parameters['base_template'] ??= $this->getBaseTemplate();

return $parameters;
Expand Down Expand Up @@ -1020,6 +1067,10 @@ protected function getLogger(): LoggerInterface
* Returns the base template name.
*
* @return string The template name
*
* @deprecated since sonata-project/admin-bundle version 4.x
*
* NEXT_MAJOR: Remove this method
*/
protected function getBaseTemplate(): string
{
Expand Down
83 changes: 83 additions & 0 deletions src/EventListener/AdminEventListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Sonata Project package.
*
* (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Sonata\AdminBundle\EventListener;

use Sonata\AdminBundle\Request\AdminFetcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\KernelEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Twig\Environment;

/**
* @author Christian Gripp <mail@core23.de>
*/
final class AdminEventListener implements EventSubscriberInterface
{
public function __construct(private Environment $twig, private AdminFetcherInterface $adminFetcher)
{
}

public static function getSubscribedEvents(): array
{
return [
KernelEvents::REQUEST => [['onKernelRequest', -50]],
];
}

public function onKernelRequest(KernelEvent $event): void
{
$request = $event->getRequest();

try {
$admin = $this->adminFetcher->get($request);
} catch (\InvalidArgumentException) {
return;
}

$this->addVariable('admin', $admin);

$templateRegistry = $admin->getTemplateRegistry();

if ($this->isXmlHttpRequest($request)) {
$baseTemplate = $templateRegistry->getTemplate('ajax');
} else {
$baseTemplate = $templateRegistry->getTemplate('layout');
}

$this->addVariable('base_template', $baseTemplate);
}

/**
* Returns true if the request is a XMLHttpRequest.
*
* @return bool True if the request is an XMLHttpRequest, false otherwise
*/
private function isXmlHttpRequest(Request $request): bool
{
if ($request->isXmlHttpRequest()) {
return true;
}

return null !== $request->attributes->get('_xml_http_request');
}

private function addVariable(string $name, mixed $value): void
{
try {
$this->twig->addGlobal($name, $value);
VincentLanglet marked this conversation as resolved.
Show resolved Hide resolved
} catch (\LogicException) {
}
}
}
8 changes: 8 additions & 0 deletions src/Resources/config/event_listener.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,19 @@

namespace Symfony\Component\DependencyInjection\Loader\Configurator;

use Sonata\AdminBundle\EventListener\AdminEventListener;
use Sonata\AdminBundle\EventListener\ConfigureCRUDControllerListener;

return static function (ContainerConfigurator $containerConfigurator): void {
$containerConfigurator->services()

->set('sonata.admin.event_listener.admin_event', AdminEventListener::class)
->tag('kernel.event_subscriber')
->args([
new ReferenceConfigurator('twig'),
new ReferenceConfigurator('sonata.admin.request.fetcher'),
])

->set('sonata.admin.event_listener.configure_crud_controller', ConfigureCRUDControllerListener::class)
->tag('kernel.event_subscriber');
};
107 changes: 107 additions & 0 deletions tests/EventListener/AdminEventListenerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Sonata Project package.
*
* (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Sonata\AdminBundle\Tests\EventListener;

use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Sonata\AdminBundle\Admin\AdminInterface;
use Sonata\AdminBundle\EventListener\AdminEventListener;
use Sonata\AdminBundle\Request\AdminFetcherInterface;
use Sonata\AdminBundle\Templating\MutableTemplateRegistryInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\KernelEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\KernelEvents;
use Twig\Environment;
use Twig\Loader\ArrayLoader;

final class AdminEventListenerTest extends TestCase
{
private Environment $twig;

/**
* @var AdminFetcherInterface&MockObject
*/
private AdminFetcherInterface $adminFetcher;

private AdminEventListener $listener;

protected function setUp(): void
{
$this->twig = new Environment(new ArrayLoader([
]));
$this->adminFetcher = $this->createMock(AdminFetcherInterface::class);

$this->listener = new AdminEventListener(
$this->twig,
$this->adminFetcher
);
}

public function testGetSubscribedEvents(): void
{
static::assertSame([
KernelEvents::REQUEST => [['onKernelRequest', -50]],
], AdminEventListener::getSubscribedEvents());
}

public function testOnKernelRequest(): void
{
$request = new Request();

$event = new KernelEvent(self::createStub(HttpKernelInterface::class), $request, HttpKernelInterface::MAIN_REQUEST);

$admin = self::createStub(AdminInterface::class);

$this->adminFetcher->method('get')->willReturn($admin);

$templateRegistry = $this->createMock(MutableTemplateRegistryInterface::class);
$templateRegistry->expects(static::once())->method('getTemplate')->with('layout')
->willReturn('layout.html.twig');

$admin->method('getTemplateRegistry')->willReturn($templateRegistry);

$this->listener->onKernelRequest($event);

$global = $this->twig->getGlobals();

static::assertSame($admin, $global['admin']);
static::assertSame('layout.html.twig', $global['base_template']);
}

public function testOnAjaxKernelRequest(): void
{
$request = new Request();
$request->attributes->set('_xml_http_request', true);

$event = new KernelEvent(self::createStub(HttpKernelInterface::class), $request, HttpKernelInterface::MAIN_REQUEST);

$admin = self::createStub(AdminInterface::class);

$this->adminFetcher->method('get')->willReturn($admin);

$templateRegistry = $this->createMock(MutableTemplateRegistryInterface::class);
$templateRegistry->expects(static::once())->method('getTemplate')->with('ajax')
->willReturn('ajax.html.twig');

$admin->method('getTemplateRegistry')->willReturn($templateRegistry);

$this->listener->onKernelRequest($event);

$global = $this->twig->getGlobals();

static::assertSame($admin, $global['admin']);
static::assertSame('ajax.html.twig', $global['base_template']);
}
}