You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Symfony最佳实践:如何让后台路由共享AdminController基础对象

Hey there! Let's work through this following Symfony's best practices, and first fix a critical issue in your current code before solving the global data problem.

First: Fix the forward() Misuse

Right now, you're using $this->forward() to get systemnotifications, but this method returns a Response object, not the actual notification data. That means your template is trying to use a Response instead of your notification entities/arrays—this is a bug waiting to happen.

Instead, refactor your notification logic into a reusable service:

  1. Create a SystemNotificationService to handle fetching notifications:
// src/Service/SystemNotificationService.php
namespace App\Service;

use Doctrine\ORM\EntityManagerInterface;
use App\Entity\SystemNotification; // Adjust to your actual entity class

class SystemNotificationService
{
    private $entityManager;

    public function __construct(EntityManagerInterface $entityManager)
    {
        $this->entityManager = $entityManager;
    }

    public function getUserNotifications(int $userId)
    {
        // Replace with your actual query logic
        return $this->entityManager
            ->getRepository(SystemNotification::class)
            ->findBy(['user' => $userId]);
    }
}
  1. Update your AdminController to use this service instead of forward():
class AdminController extends Controller {
    private $notificationService;

    // Inject the service via constructor
    public function __construct(SystemNotificationService $notificationService)
    {
        $this->notificationService = $notificationService;
    }

    /**
     * @Route("/admin", name="adminDashboard")
     */
    public function adminDashboard() {
        $loggedUserId = $this->getUser()->getId();
        $systemnotifications = $this->notificationService->getUserNotifications($loggedUserId);
        
        return $this->render('admin/index.html.twig', [
            'systemnotifications' => $systemnotifications
        ]);
    }
}

Great, now we're passing actual notification data to the template. Now let's solve the global availability issue.

Option 1: Create an Admin Base Controller (DRY & Explicit)

This is perfect if all your admin controllers need access to notifications. Create a parent controller that all admin controllers inherit from:

// src/Controller/AdminBaseController.php
namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use App\Service\SystemNotificationService;
use Symfony\Component\HttpFoundation\Response;

class AdminBaseController extends AbstractController
{
    private $notificationService;

    public function __construct(SystemNotificationService $notificationService)
    {
        $this->notificationService = $notificationService;
    }

    // Override the render method to automatically inject notifications
    protected function render(string $view, array $parameters = [], Response $response = null): Response
    {
        $loggedUserId = $this->getUser()->getId();
        $parameters['systemnotifications'] = $this->notificationService->getUserNotifications($loggedUserId);
        
        return parent::render($view, $parameters, $response);
    }
}

Now update your admin controllers to inherit from this base controller:

// AdminController
class AdminController extends AdminBaseController {
    /**
     * @Route("/admin", name="adminDashboard")
     */
    public function adminDashboard() {
        // No need to pass notifications—parent render does it automatically
        return $this->render('admin/index.html.twig');
    }
}

// TestController
class TestController extends AdminBaseController {
    /**
     * @Route("/admin/test", name="test")
     */
    public function test() {
        // Notifications are already available in the template
        return $this->render('admin/dashboard/index.html.twig');
    }
}

Option 2: Use a Kernel Event Subscriber (Global & Automatic)

If you want notifications to be available for all routes under /admin without modifying controllers, use an event subscriber to inject the data into Twig's global variables:

// src/EventSubscriber/AdminNotificationSubscriber.php
namespace App\EventSubscriber;

use App\Service\SystemNotificationService;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ControllerEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Twig\Environment;
use Symfony\Component\Security\Core\Security;

class AdminNotificationSubscriber implements EventSubscriberInterface
{
    private $twig;
    private $notificationService;
    private $security;

    public function __construct(Environment $twig, SystemNotificationService $notificationService, Security $security)
    {
        $this->twig = $twig;
        $this->notificationService = $notificationService;
        $this->security = $security;
    }

    public static function getSubscribedEvents()
    {
        return [
            KernelEvents::CONTROLLER => 'onKernelController',
        ];
    }

    public function onKernelController(ControllerEvent $event)
    {
        $request = $event->getRequest();
        
        // Only apply to routes starting with /admin
        if (strpos($request->getPathInfo(), '/admin') !== 0) {
            return;
        }

        $user = $this->security->getUser();
        if (!$user) {
            return; // Skip if no user is logged in
        }

        $notifications = $this->notificationService->getUserNotifications($user->getId());
        $this->twig->addGlobal('systemnotifications', $notifications);
    }
}

Symfony will automatically detect this subscriber (thanks to autoconfiguration), and all /admin routes will have systemnotifications available in their templates—no controller changes needed.

Option 3: Use a Twig Function (Lazy Loading)

If only some admin pages need notifications, create a Twig function to fetch them on demand:

// src/Twig/AdminNotificationExtension.php
namespace App\Twig;

use App\Service\SystemNotificationService;
use Symfony\Component\Security\Core\Security;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;

class AdminNotificationExtension extends AbstractExtension
{
    private $security;
    private $notificationService;

    public function __construct(Security $security, SystemNotificationService $notificationService)
    {
        $this->security = $security;
        $this->notificationService = $notificationService;
    }

    public function getFunctions(): array
    {
        return [
            new TwigFunction('get_admin_notifications', [$this, 'getNotifications']),
        ];
    }

    public function getNotifications()
    {
        $user = $this->security->getUser();
        if (!$user) {
            return [];
        }
        return $this->notificationService->getUserNotifications($user->getId());
    }
}

Then in your template, call the function wherever you need notifications:

{% for notification in get_admin_notifications() %}
    <!-- Display your notification content here -->
{% endfor %}

Which Option to Choose?

  • Base Controller: Best for consistency when all admin pages need notifications. Explicit and easy to debug.
  • Event Subscriber: Ideal if you want complete automation without touching controllers.
  • Twig Function: Perfect for lazy loading or when only specific pages need notifications.

All these approaches align with Symfony's best practices of separation of concerns and reusability.

内容的提问来源于stack exchange,提问作者flow

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 09:28:34