Repository: symfony/symfony
File: src/Symfony/Bundle/SecurityBundle/Security.php (PHP)

Code before:
 * @final
 */
class Security extends LegacySecurity
{
    public const ACCESS_DENIED_ERROR = SecurityRequestAttributes::ACCESS_DENIED_ERROR;
    public const AUTHENTICATION_ERROR = SecurityRequestAttributes::AUTHENTICATION_ERROR;
    public const LAST_USERNAME = SecurityRequestAttributes::LAST_USERNAME;

    public function __construct(private readonly ContainerInterface $container, private readonly array $authenticators = [])
    {
        parent::__construct($container, false);
    }

    public function getFirewallConfig(Request $request): ?FirewallConfig
    {
        return $this->container->get('security.firewall.map')->getFirewallConfig($request);
    }

    /**
     * @param UserInterface $user              The user to authenticate
     * @param string|null   $authenticatorName The authenticator name (e.g. "form_login") or service id (e.g. SomeApiKeyAuthenticator::class) - required only if multiple authenticators are configured
     * @param string|null   $firewallName      The firewall name - required only if multiple firewalls are configured
     */
    public function login(UserInterface $user, string $authenticatorName = null, string $firewallName = null): void
    {
        if (!$request = $this->container->get('request_stack')->getCurrentRequest()) {
            throw new LogicException('Unable to login without a request context.');
        }
        $firewallName ??= $this->getFirewallConfig($request)?->getName();

        if (!$firewallName) {
            throw new LogicException('Unable to login as the current route is not covered by any firewall.');
        }

        $authenticator = $this->getAuthenticator($authenticatorName, $firewallName);

        $this->container->get('security.user_checker')->checkPreAuth($user);
        $this->container->get('security.authenticator.managers_locator')->get($firewallName)->authenticateUser($user, $authenticator, $request);
    }

    /**
     * Logout the current user by dispatching the LogoutEvent.
     *
     * @param bool $validateCsrfToken Whether to look for a valid CSRF token based on the `logout` listener configuration
     *
     * @return Response|null The LogoutEvent's Response if any
     *
     * @throws LogoutException When $validateCsrfToken is true and the CSRF token is not found or invalid
     */
    public function logout(bool $validateCsrfToken = true): ?Response
    {

Review comment (suggestion):
Let's be explicit that we expect null here. We should also do it in two lines so it is easier to read.

```suggestion
        $request = $this->container->get('request_stack')->getCurrentRequest();
        if (null === $request) {
```

Code after:
 * @final
 */
class Security extends LegacySecurity
{
    public const ACCESS_DENIED_ERROR = SecurityRequestAttributes::ACCESS_DENIED_ERROR;
    public const AUTHENTICATION_ERROR = SecurityRequestAttributes::AUTHENTICATION_ERROR;
    public const LAST_USERNAME = SecurityRequestAttributes::LAST_USERNAME;

    public function __construct(private readonly ContainerInterface $container, private readonly array $authenticators = [])
    {
        parent::__construct($container, false);
    }

    public function getFirewallConfig(Request $request): ?FirewallConfig
    {
        return $this->container->get('security.firewall.map')->getFirewallConfig($request);
    }

    /**
     * @param UserInterface $user              The user to authenticate
     * @param string|null   $authenticatorName The authenticator name (e.g. "form_login") or service id (e.g. SomeApiKeyAuthenticator::class) - required only if multiple authenticators are configured
     * @param string|null   $firewallName      The firewall name - required only if multiple firewalls are configured
     */
    public function login(UserInterface $user, string $authenticatorName = null, string $firewallName = null): void
    {
        $request = $this->container->get('request_stack')->getCurrentRequest();
        if (null === $request) {
            throw new LogicException('Unable to login without a request context.');
        }

        $firewallName ??= $this->getFirewallConfig($request)?->getName();

        if (!$firewallName) {
            throw new LogicException('Unable to login as the current route is not covered by any firewall.');
        }

        $authenticator = $this->getAuthenticator($authenticatorName, $firewallName);

        $this->container->get('security.user_checker')->checkPreAuth($user);
        $this->container->get('security.authenticator.managers_locator')->get($firewallName)->authenticateUser($user, $authenticator, $request);
    }

    /**
     * Logout the current user by dispatching the LogoutEvent.
     *
     * @param bool $validateCsrfToken Whether to look for a valid CSRF token based on the `logout` listener configuration
     *
     * @return Response|null The LogoutEvent's Response if any
     *
     * @throws LogoutException When $validateCsrfToken is true and the CSRF token is not found or invalid
     */