Symfony
02 / 02

Security, Events & Async Messaging

Security, Events & Async Messaging

Security & Voters

# config/packages/security.yaml
security:
  firewalls:
    main:
      lazy: true
      provider: app_user_provider
      form_login:
        login_path: app_login
  access_control:
    - { path: ^/admin, roles: ROLE_ADMIN }
    - { path: ^/account, roles: ROLE_USER }
<?php
// Fine-grained authorization beyond role checks
class PostVoter extends Voter
{
    protected function supports(string $attribute, mixed $subject): bool
    {
        return $attribute === 'EDIT' && $subject instanceof Post;
    }

    protected function voteOnAttribute(string $attribute, mixed $post, TokenInterface $token): bool
    {
        $user = $token->getUser();
        return $user instanceof User && $post->getAuthor() === $user;
    }
}

// In a controller:
$this->denyAccessUnlessGranted('EDIT', $post);

Events & Subscribers

<?php
// Subscriber — declares its own subscribed events, discovered via autoconfiguration
class MaintenanceModeSubscriber implements EventSubscriberInterface
{
    public static function getSubscribedEvents(): array
    {
        return [KernelEvents::REQUEST => 'onKernelRequest'];
    }

    public function onKernelRequest(RequestEvent $event): void
    {
        if (MaintenanceMode::isEnabled()) {
            $event->setResponse(new Response('Down for maintenance', 503));
        }
    }
}
// Implementing EventSubscriberInterface is enough — no services.yaml tagging needed.

Messenger (Async Jobs)

<?php
final class SendWelcomeEmail
{
    public function __construct(public readonly string $userId) {}
}

#[AsMessageHandler]
class SendWelcomeEmailHandler
{
    public function __invoke(SendWelcomeEmail $message): void
    {
        // runs on a worker, off the request cycle
        $this->mailer->send(...);
    }
}

// Dispatch from a controller — returns immediately, worker processes it later
$this->messageBus->dispatch(new SendWelcomeEmail($user->getId()));

// Run the worker:
// php bin/console messenger:consume async

Testing

<?php
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

class ArticleControllerTest extends WebTestCase
{
    public function testShowArticle(): void
    {
        $client = static::createClient();
        $client->request('GET', '/articles/1');

        $this->assertResponseIsSuccessful();
        $this->assertSelectorTextContains('h1', 'My Article');
    }
}

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free