I'm encountering an error in my Symfony application related to accessing the $container property of Symfony\Bundle\FrameworkBundle\Controller\AbstractController. The error message I'm receiving is:

 
Error: Typed property Symfony\Bundle\FrameworkBundle\Controller\AbstractController::$container must not be accessed before initialization

D:\Development\omegofleet\vendor\symfony\framework-bundle\Controller\AbstractController.php:343
D:\Development\omegofleet\src\Controller\UserController.php:203
D:\Development\omegofleet\tests\UserTest.php:185

Here's an example of my controller class:

<?php

namespace App\Controller;

use App\Entity\Company;
use App\Entity\User;
use App\Repository\UserRepository;
use Doctrine\ORM\EntityManagerInterface;
use Firebase\JWT\JWT;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Csrf\TokenStorage\TokenStorageInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;

class UserController extends AbstractController
{
    private EntityManagerInterface $entityManager;
    private UserRepository $userRepository;
    private TokenStorageInterface $tokenStorage;

    public function __construct(EntityManagerInterface $entityManager, UserRepository $userRepository, TokenStorageInterface $tokenStorage)
    {
        $this->entityManager = $entityManager;
        $this->userRepository = $userRepository;
        $this->tokenStorage = $tokenStorage;
    }

    #[Route('/api/users/{id}', name: 'user_delete', methods: ['DELETE'])]
    public function delete(User $user): Response
    {
        $currentUser = $this->getUser();

        if (!$currentUser) {
            return $this->json(['error' => 'User not authenticated'], Response::HTTP_UNAUTHORIZED);
        }

        // Load user's role
        $userRole = $this->getUserRole($currentUser->getUsername());

        if (!in_array($userRole, ['ROLE_SUPER_ADMIN'])) {
            return $this->json(['error' => 'Access denied'], Response::HTTP_FORBIDDEN);
        }

And here's part of my usertest class:

#[AllowDynamicProperties] class UserTest extends WebTestCase
{

    protected function setUp(): void
    {

        parent::setUp(); // Ensure parent setUp method is called


        $this->entityManagerMock = Mockery::mock(EntityManagerInterface::class);
        $this->userRepositoryMock = Mockery::mock(UserRepository::class);
        $this->tokenStorageMock = Mockery::mock(TokenStorageInterface::class); // Add this line

    }
    public function tearDown(): void
    {
        parent::tearDown();
        Mockery::close();
    }

    public function testLoginSuccessful()
    {
        $mockRequest = Mockery::mock(Request::class);
        $mockRequest->allows('getContent')->andReturns(json_encode(['name' => 'john.doe']));


        $mockUser = $this->createMockUser('john.doe', 'ROLE_SUPER_ADMIN');


        $mockUserRepository = Mockery::mock(UserRepository::class);
        $mockUserRepository->allows('findOneBy')->with(['name' => 'john.doe'])->andReturns($mockUser);
        $this->entityManagerMock
            ->allows('getRepository')
            ->with(User::class)
            ->andReturns($mockUserRepository);

        $mockEntityManager = Mockery::mock(EntityManagerInterface::class);
        $mockEntityManager->allows('getRepository')->with(User::class)->andReturns($mockUserRepository);

        // Create mock UserController with required dependencies
        $mockController = Mockery::mock(UserController::class, [$this->entityManagerMock, $this->userRepositoryMock, $this->tokenStorageMock]) // Pass $this->tokenStorageMock here
        ->makePartial(); // Allow calling actual `generateToken`
//        $mockController->allows('generateToken')->with('john.doe')->andReturns('test_token');

        // Call the login method
        $response = $mockController->login($mockRequest);

        $this->assertInstanceOf(JsonResponse::class, $response);
        $responseData = json_decode($response->getContent(), true);
        $this->assertArrayHasKey('token', $responseData);
        $this->assertIsString($responseData['token']);

        // Decode and verify the JWT token
                $secretKey = $_ENV['JWT_SECRET'];
        $decodedToken = JWT::decode($responseData['token'], new Key($secretKey, 'HS256'));
        $this->assertEquals('john.doe', $decodedToken->name);

// Retrieve the role from the UserRepository
        $userRepositoryMock = Mockery::mock(UserRepository::class);
        $userRepositoryMock->allows('loadUserByRole')->with('john.doe')->andReturn('ROLE_USER_ADMIN');

// Mock the EntityManagerInterface
        $mockEntityManager = Mockery::mock(EntityManagerInterface::class);
        $mockEntityManager->allows('getRepository')->with(User::class)->andReturn($userRepositoryMock);

// Call the login method
        $response = $mockController->login($mockRequest);

// Assert the response
        $this->assertInstanceOf(JsonResponse::class, $response);
        $this->assertEquals(Response::HTTP_OK, $response->getStatusCode());
        return $response;

    }
  protected function createMockUser(string $name, string $role): User
    {
        $mockUser = new User();

        $mockUser->setName($name);
        $mockUser->setId(1);
        $mockUser->setRole($role);
        return $mockUser;
    }
    public function testDeleteAsSuperAdmin(): void
    {
        // Dummy login process
        $loginResponse = $this->testLoginSuccessful();
        $token = json_decode($loginResponse->getContent(), true)['token'];

        // Create a user using the createMockUser method
        $user = $this->createMockUser('Test User', 'ROLE_SUPER_ADMIN');
        $user->setId(1);

        $this->entityManagerMock
            ->allows('getRepository')
            ->with(User::class)
            ->andReturns($this->userRepositoryMock);
        // Create a DELETE request to delete the user
        $request = Request::create('/api/users/' . $user->getId(), 'DELETE');
        $request->headers->set('Authorization', 'Bearer ' . $token);

        // Mock EntityManager to remove the user
        $this->entityManagerMock->allows('remove')->with($user);
        $this->entityManagerMock->allows('flush');

        // Create an instance of UserController with mocked dependencies
        $controller = new UserController($this->entityManagerMock, $this->userRepositoryMock, $this->tokenStorageMock);

        // Expectation on the userRepositoryMock should be set before calling the delete method
        $this->userRepositoryMock
            ->allows('find')
            ->with($user->getId())
            ->andReturns($user);

        // Call the delete method with the fetched user object
        $response = $controller->delete($user);

        // Assert the response status code and content
        $this->assertEquals(Response::HTTP_OK, $response->getStatusCode());
        $this->assertJsonStringEqualsJsonString('{"message": "User deleted"}', $response->getContent());
    }

    protected function generateDummyToken(string $username): string
    {
        // Generate a dummy JWT token for testing purposes
        $payload = [
            'name' => $username,
            'exp' => time() + 3600 // Token expiration time (1 hour)
        ];
        $secretKey = 'dummy_secret_key'; // Replace with your actual secret key
        return JWT::encode($payload, $secretKey, 'HS256');
    }

And here is the line from AbstractController :

 protected function getUser(): ?UserInterface
    {
        if (!$this->container->has('security.token_storage')) {
            throw new \LogicException('The SecurityBundle is not registered in your application. Try running "composer require symfony/security-bundle".');
        }


and here is the service.yml :



# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration
parameters:

services:
  # default configuration for services in *this* file
  _defaults:
    autowire: true      # Automatically injects dependencies in your services.
    autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.

  # makes classes in src/ available to be used as services
  # this creates a service per class whose id is the fully-qualified class name
  App\:
    resource: '../src/'
    exclude:
      - '../src/DependencyInjection/'
      - '../src/Entity/'
      - '../src/Kernel.php'

Despite this setup, I'm still encountering the error. What could be causing this issue, and how can I resolve it?

Any insights or suggestions would be greatly appreciated. Thank you!

0

There are 0 best solutions below