我在树枝上使用app.user。当我编写测试时,我有一个用户登录,它在控制器中工作正常。但是在twig中,当访问app.user时,它为null。
以下是我如何在测试单元中记录用户:
$user = new User;
$user->setRole('ROLE_ADMIN');
$user->setUsername('admin');
$firewallContext = 'main';
$token = new UsernamePasswordToken(serialize($user), null, $firewallContext, array('ROLE_ADMIN'));
$session->set('_security_'.$firewallContext, serialize($token));
$session->save();
$cookie = new Cookie($session->getName(), $session->getId());
$this->client->getCookieJar()->set($cookie);
我错过了什么让它在树枝上工作?
答案 0 :(得分:0)
我有一个类似的问题(正确登录)最终为我解决的是改变我登录的方式,这是我的授权客户,你可以根据你的目的调整它。 (symfony版本:2.8)
private function createAuthorizedClient()
{
$client = static::createClient();
$container = static::$kernel->getContainer();
$session = $container->get('session');
$token = new UsernamePasswordToken('john.doe', null, 'main', array('ROLE_ADMIN'));
$session->set('_security_main', serialize($token));
$session->save();
$client->getCookieJar()->set(new Cookie($session->getName(), $session->getId()));
return $client;
}
答案 1 :(得分:-1)
我无法告诉您如何在测试环境中设置Twig来提供app.user
,但是我已经做出了一种变通方法,几乎可以实现相同的功能。
简而言之:
get_user()
)。get_user()
:它检查它是否在APP_ENV == test中运行。如果是,则从UsernamePasswordToken
实例获取User实例,否则从当前Twig Environment
实例返回存储的用户。对于Symfony 4.3+,以下代码应该是开箱即用的,但未经测试。
以下扩展名在Twig模板中提供了get_user()
。
<?php
namespace App\TwigExtension;
use App\Entity\User;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Twig\Environment;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
class SecurityExtension extends AbstractExtension
{
protected $currentUser;
protected $session;
protected $twigEnvironment;
public function __construct(
Environment $twigEnvironment,
SessionInterface $session
) {
$this->session = $session;
$this->twigEnvironment = $twigEnvironment;
}
public function getUser(): User
{
if (null !== $this->currentUser) {
return $this->currentUser;
}
/*
* if env == test
*/
if ('test' == $_SERVER['APP_ENV']) {
$token = \unserialize($this->session->get('_security_main'));
if ($token instanceof UsernamePasswordToken && true === $token->isAuthenticated()) {
$this->currentUser = $token->getUser();
}
} else {
/*
* normal way
*/
$this->currentUser = $this->twigEnvironment->getGlobals()['app']->getToken()->getUser();
}
return $this->currentUser;
}
/**
* @return array
*/
public function getFunctions(): array
{
return [
new TwigFunction('get_user', [$this, 'getUser']),
];
}
}
在下面的完整测试示例中,如何调用控制器动作,该动作在后面使用Twig。
<?php
use App\Entity\User;
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\BrowserKit\Cookie;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
class OrderControllerTest extends WebTestCase
{
public function testEdit(): void
{
$client = static::createClient();
$user = new User();
// ... adapt it if you want
$this->authenticateClientInstance($client, $user);
// make the request
$crawler = $client->request('GET', '/admin/order/');
$response = $client->getResponse();
// check the response
$this->assertEquals(200, $response->getStatusCode());
}
protected function authenticateClientInstance(KernelBrowser $client, User $user): void
{
$session = $client->getContainer()->get('session');
$token = new UsernamePasswordToken($user, null, 'main', ['ROLE_USER']);
$session->set('_security_main', \serialize($token));
$session->save();
$cookie = new Cookie($session->getName(), $session->getId());
$client->getCookieJar()->set($cookie);
}
}
例如:
{% set user = get_user() %}
该解决方案被认为不是最佳方法。问题是,您需要使用许多Symfony组件,这些组件可能不适合与非Symfony组件一起使用。如果他们更改了API,您也可能会遇到问题。
我通过进一步测试确保了该方法的有效性,以确保其有效。您也应该这样做,以防Symfony 5.0+损坏。