philipp
philipp

Reputation: 16515

Symfony3—Test Service with authentification

I am trying to test a Service which preprocessed a form and finally saves it. Within the creating of that form:

$this->container->get('security.token_storage')->getToken()->getUser();

is called to get currently logged in user as a default value for a field.

Right now I am having this (extending Symfony\Bundle\FrameworkBundle\Test\WebTestCase):

private $pages;
private $formFactory;

protected function setUp()
{
  self::bootKernel();

  $client = self::$kernel->getContainer()->get('test.client');
  $client->setServerParameters([
    'HTTP_HOST'                   => 'ajax.localhost.dev:10190',
    'CONTENT_TYPE'              => 'application/json',
    'HTTP_X-Requested-With' => 'XMLHttpRequest',
    'HTTP_USER_AGENT'         => 'Symfony/2.0',
    'PHP_AUTH_USER'             => 'root',
    'PHP_AUTH_PW'               => '[email protected]'
  ]);

  $this->pages = self::$kernel->getContainer()->get('app.pages');
  $this->formFactory = self::$kernel->getContainer()->get('form.factory');
}

public function testNewPage() {
  $page = new Page();
  //shortened
  $form = $this->formFactory->create(PageType::class, $page);
}

But that gives me the error:

Call to a member function getUser() on null

What shows that there is no security token.

How can I come over that?

UPDATE

Thanks to the comments of @LBA I tried that code, with no luck:

$session = self::$kernel->getContainer()->get('session');
$token = new UsernamePasswordToken('root', 'root', 'main', ['ROLE_USER', 'ROLE_ROOT']);
$session->set('_security_main', serialize($token));
$session->save();

The part with setting a Cookie as described here is missing, since the $kernel has no method getCookieJar()

Upvotes: 1

Views: 51

Answers (1)

philipp
philipp

Reputation: 16515

I could finally make it work like so:

protected function setUp()
{
  self::bootKernel();

  $root = new User();
  $root->setUsername('root');
  $root->setPassword('root');
  $root->setEmail('[email protected]');

  $token = new UsernamePasswordToken($root, null, 'main', ['ROLE_USER', 'ROLE_ROOT']);

  self::$kernel->getContainer()
    ->get('security.token_storage')
    ->setToken($token);

  $this->pages = self::$kernel->getContainer()->get('app.pages');
  $this->formFactory = self::$kernel->getContainer()->get('form.factory');
}

BUT BUT BUT Even if it is possible to solve that problem, the real issue in this case is, to have that $this->container->get('security.token_storage')->getToken()->getUser(); call with the Form, since this breaks the form in a test case. The pattern to prevent such a thing from happening is dependency injection, what I have missed to apply on the form type.

So the better solution would be (in the Form extending AbstractType):

public function configureOptions(OptionsResolver $resolver)
{
  $this->setDefined(['user]);
}

And finally create the form like so (in Controller or TestCase)

Within a UnitTest:

$user = new User();

and in the controller:

$user = $this->container->get('security.token_storage')->getToken()->getUser();

$form = $this->formFactory->create(TheFormType::class, 
  <some data object>, 
  ['user' => $user]);

Upvotes: 1

Related Questions