Skip to content

Commit 164989f

Browse files
committed
bug #985 [make:auth] fix security controller attributes (jrushlow)
This PR was merged into the 1.0-dev branch. Discussion ---------- [make:auth] fix security controller attributes fixes #981 Commits ------- cc71c7a [make:auth] fix security controller attributes
2 parents 5f37ba1 + cc71c7a commit 164989f

File tree

11 files changed

+205
-40
lines changed

11 files changed

+205
-40
lines changed

src/Maker/MakeAuthenticator.php

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,14 +60,17 @@ final class MakeAuthenticator extends AbstractMaker
6060

6161
private $doctrineHelper;
6262

63+
private $securityControllerBuilder;
64+
6365
private $useSecurity52 = false;
6466

65-
public function __construct(FileManager $fileManager, SecurityConfigUpdater $configUpdater, Generator $generator, DoctrineHelper $doctrineHelper)
67+
public function __construct(FileManager $fileManager, SecurityConfigUpdater $configUpdater, Generator $generator, DoctrineHelper $doctrineHelper, SecurityControllerBuilder $securityControllerBuilder)
6668
{
6769
$this->fileManager = $fileManager;
6870
$this->configUpdater = $configUpdater;
6971
$this->generator = $generator;
7072
$this->doctrineHelper = $doctrineHelper;
73+
$this->securityControllerBuilder = $securityControllerBuilder;
7174
}
7275

7376
public static function getCommandName(): string
@@ -323,10 +326,10 @@ private function generateFormLoginFiles(string $controllerClass, string $userNam
323326

324327
$manipulator = new ClassSourceManipulator($controllerSourceCode, true);
325328

326-
$securityControllerBuilder = new SecurityControllerBuilder();
327-
$securityControllerBuilder->addLoginMethod($manipulator);
329+
$this->securityControllerBuilder->addLoginMethod($manipulator);
330+
328331
if ($logoutSetup) {
329-
$securityControllerBuilder->addLogoutMethod($manipulator);
332+
$this->securityControllerBuilder->addLogoutMethod($manipulator);
330333
}
331334

332335
$this->generator->dumpFile($controllerPath, $manipulator->getSourceCode());

src/Resources/config/makers.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
<argument type="service" id="maker.security_config_updater" />
1313
<argument type="service" id="maker.generator" />
1414
<argument type="service" id="maker.doctrine_helper" />
15+
<argument type="service" id="maker.security_controller_builder" />
1516
<tag name="maker.command" />
1617
</service>
1718

src/Resources/config/services.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@
6868
<argument type="service" id="maker.generator" />
6969
</service>
7070

71+
<service id="maker.security_controller_builder" class="Symfony\Bundle\MakerBundle\Security\SecurityControllerBuilder">
72+
<argument type="service" id="maker.php_compat_util" />
73+
</service>
74+
7175
<service id="maker.php_compat_util" class="Symfony\Bundle\MakerBundle\Util\PhpCompatUtil">
7276
<argument type="service" id="maker.file_manager" />
7377
</service>

src/Security/SecurityControllerBuilder.php

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Bundle\MakerBundle\Security;
1313

1414
use Symfony\Bundle\MakerBundle\Util\ClassSourceManipulator;
15+
use Symfony\Bundle\MakerBundle\Util\PhpCompatUtil;
1516
use Symfony\Component\HttpFoundation\Response;
1617
use Symfony\Component\Routing\Annotation\Route;
1718
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
@@ -21,9 +22,28 @@
2122
*/
2223
final class SecurityControllerBuilder
2324
{
25+
private $phpCompatUtil;
26+
27+
public function __construct(PhpCompatUtil $phpCompatUtil)
28+
{
29+
$this->phpCompatUtil = $phpCompatUtil;
30+
}
31+
2432
public function addLoginMethod(ClassSourceManipulator $manipulator): void
2533
{
26-
$loginMethodBuilder = $manipulator->createMethodBuilder('login', 'Response', false, ['@Route("/login", name="app_login")']);
34+
$loginMethodBuilder = $manipulator->createMethodBuilder('login', 'Response', false);
35+
36+
// @legacy Refactor when annotations are no longer supported
37+
if ($this->phpCompatUtil->canUseAttributes()) {
38+
$loginMethodBuilder->addAttribute($manipulator->buildAttributeNode(Route::class, ['path' => '/login', 'name' => 'app_login']));
39+
} else {
40+
$loginMethodBuilder->setDocComment(<<< 'EOT'
41+
/**
42+
* @Route("/login", name="app_login")
43+
*/
44+
EOT
45+
);
46+
}
2747

2848
$manipulator->addUseStatementIfNecessary(Response::class);
2949
$manipulator->addUseStatementIfNecessary(Route::class);
@@ -66,7 +86,19 @@ public function addLoginMethod(ClassSourceManipulator $manipulator): void
6686

6787
public function addLogoutMethod(ClassSourceManipulator $manipulator): void
6888
{
69-
$logoutMethodBuilder = $manipulator->createMethodBuilder('logout', 'void', false, ['@Route("/logout", name="app_logout")']);
89+
$logoutMethodBuilder = $manipulator->createMethodBuilder('logout', 'void', false);
90+
91+
// @legacy Refactor when annotations are no longer supported
92+
if ($this->phpCompatUtil->canUseAttributes()) {
93+
$logoutMethodBuilder->addAttribute($manipulator->buildAttributeNode(Route::class, ['path' => '/logout', 'name' => 'app_logout']));
94+
} else {
95+
$logoutMethodBuilder->setDocComment(<<< 'EOT'
96+
/**
97+
* @Route("/logout", name="app_logout")
98+
*/
99+
EOT
100+
);
101+
}
70102

71103
$manipulator->addUseStatementIfNecessary(Route::class);
72104
$manipulator->addMethodBody($logoutMethodBuilder, <<<'CODE'

tests/Security/SecurityControllerBuilderTest.php

Lines changed: 74 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,46 +14,98 @@
1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Bundle\MakerBundle\Security\SecurityControllerBuilder;
1616
use Symfony\Bundle\MakerBundle\Util\ClassSourceManipulator;
17+
use Symfony\Bundle\MakerBundle\Util\PhpCompatUtil;
1718

1819
class SecurityControllerBuilderTest extends TestCase
1920
{
20-
public function testAddLoginMethod()
21+
private $expectedBasePath = __DIR__.'/fixtures/expected';
22+
23+
public function testLoginMethod(): void
2124
{
22-
$source = file_get_contents(__DIR__.'/fixtures/source/SecurityController.php');
23-
$expectedSource = file_get_contents(__DIR__.'/fixtures/expected/SecurityController_login.php');
25+
/* @legacy Can be dropped when PHP 7.x support is dropped in MakerBundle */
26+
$this->runMethodTest(
27+
'addLoginMethod',
28+
true,
29+
sprintf('%s/legacy_add_login_method/%s', $this->expectedBasePath, 'SecurityController_login.php')
30+
);
2431

25-
$manipulator = new ClassSourceManipulator($source);
32+
if ((\PHP_VERSION_ID >= 80000)) {
33+
$this->runMethodTest(
34+
'addLoginMethod',
35+
false,
36+
sprintf('%s/%s', $this->expectedBasePath, 'SecurityController_login.php')
37+
);
38+
}
39+
}
2640

27-
$securityControllerBuilder = new SecurityControllerBuilder();
28-
$securityControllerBuilder->addLoginMethod($manipulator);
41+
public function testLogoutMethod(): void
42+
{
43+
/* @legacy Can be dropped when PHP 7.x support is dropped in MakerBundle */
44+
$this->runMethodTest(
45+
'addLogoutMethod',
46+
true,
47+
sprintf('%s/legacy_add_logout_method/%s', $this->expectedBasePath, 'SecurityController_logout.php')
48+
);
2949

30-
$this->assertSame($expectedSource, $manipulator->getSourceCode());
50+
if ((\PHP_VERSION_ID >= 80000)) {
51+
$this->runMethodTest(
52+
'addLogoutMethod',
53+
false,
54+
sprintf('%s/%s', $this->expectedBasePath, 'SecurityController_logout.php')
55+
);
56+
}
3157
}
3258

33-
public function testLogoutMethod()
59+
public function testLoginAndLogoutMethod(): void
3460
{
35-
$source = file_get_contents(__DIR__.'/fixtures/source/SecurityController.php');
36-
$expectedSource = file_get_contents(__DIR__.'/fixtures/expected/SecurityController_logout.php');
61+
/** @legacy Can be dropped when PHP 7.x support is dropped in MakerBundle */
62+
$builder = $this->getSecurityControllerBuilder(true);
63+
$csm = $this->getClassSourceManipulator();
64+
65+
$builder->addLoginMethod($csm);
66+
$builder->addLogoutMethod($csm);
67+
68+
$this->assertStringEqualsFile(
69+
sprintf('%s/legacy_add_login_logout_method/%s', $this->expectedBasePath, 'SecurityController_login_logout.php'),
70+
$csm->getSourceCode()
71+
);
3772

38-
$manipulator = new ClassSourceManipulator($source);
73+
if ((\PHP_VERSION_ID >= 80000)) {
74+
$builder = $this->getSecurityControllerBuilder(false);
75+
$csm = $this->getClassSourceManipulator();
3976

40-
$securityControllerBuilder = new SecurityControllerBuilder();
41-
$securityControllerBuilder->addLogoutMethod($manipulator);
77+
$builder->addLoginMethod($csm);
78+
$builder->addLogoutMethod($csm);
4279

43-
$this->assertSame($expectedSource, $manipulator->getSourceCode());
80+
$this->assertStringEqualsFile(
81+
sprintf('%s/%s', $this->expectedBasePath, 'SecurityController_login_logout.php'),
82+
$csm->getSourceCode()
83+
);
84+
}
4485
}
4586

46-
public function testLoginAndLogoutMethod()
87+
private function runMethodTest(string $builderMethod, bool $isLegacyTest, string $expectedFilePath): void
4788
{
48-
$source = file_get_contents(__DIR__.'/fixtures/source/SecurityController.php');
49-
$expectedSource = file_get_contents(__DIR__.'/fixtures/expected/SecurityController_login_logout.php');
89+
$builder = $this->getSecurityControllerBuilder($isLegacyTest);
90+
$csm = $this->getClassSourceManipulator();
5091

51-
$manipulator = new ClassSourceManipulator($source);
92+
$builder->$builderMethod($csm);
93+
$this->assertStringEqualsFile($expectedFilePath, $csm->getSourceCode());
94+
}
5295

53-
$securityControllerBuilder = new SecurityControllerBuilder();
54-
$securityControllerBuilder->addLoginMethod($manipulator);
55-
$securityControllerBuilder->addLogoutMethod($manipulator);
96+
private function getClassSourceManipulator(): ClassSourceManipulator
97+
{
98+
return new ClassSourceManipulator(file_get_contents(__DIR__.'/fixtures/source/SecurityController.php'));
99+
}
100+
101+
private function getSecurityControllerBuilder(bool $isLegacyTest): SecurityControllerBuilder
102+
{
103+
$compatUtil = $this->createMock(PhpCompatUtil::class);
104+
$compatUtil
105+
->method('canUseAttributes')
106+
->willReturn(!$isLegacyTest)
107+
;
56108

57-
$this->assertSame($expectedSource, $manipulator->getSourceCode());
109+
return new SecurityControllerBuilder($compatUtil);
58110
}
59111
}

tests/Security/fixtures/expected/SecurityController_login.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@
99

1010
class SecurityController extends AbstractController
1111
{
12-
/**
13-
* @Route("/login", name="app_login")
14-
*/
12+
#[Route(path: '/login', name: 'app_login')]
1513
public function login(AuthenticationUtils $authenticationUtils): Response
1614
{
1715
// if ($this->getUser()) {

tests/Security/fixtures/expected/SecurityController_login_logout.php

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@
99

1010
class SecurityController extends AbstractController
1111
{
12-
/**
13-
* @Route("/login", name="app_login")
14-
*/
12+
#[Route(path: '/login', name: 'app_login')]
1513
public function login(AuthenticationUtils $authenticationUtils): Response
1614
{
1715
// if ($this->getUser()) {
@@ -26,9 +24,7 @@ public function login(AuthenticationUtils $authenticationUtils): Response
2624
return $this->render('security/login.html.twig', ['last_username' => $lastUsername, 'error' => $error]);
2725
}
2826

29-
/**
30-
* @Route("/logout", name="app_logout")
31-
*/
27+
#[Route(path: '/logout', name: 'app_logout')]
3228
public function logout(): void
3329
{
3430
throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');

tests/Security/fixtures/expected/SecurityController_logout.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@
77

88
class SecurityController extends AbstractController
99
{
10-
/**
11-
* @Route("/logout", name="app_logout")
12-
*/
10+
#[Route(path: '/logout', name: 'app_logout')]
1311
public function logout(): void
1412
{
1513
throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
namespace App\Controller;
4+
5+
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
6+
use Symfony\Component\HttpFoundation\Response;
7+
use Symfony\Component\Routing\Annotation\Route;
8+
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
9+
10+
class SecurityController extends AbstractController
11+
{
12+
/**
13+
* @Route("/login", name="app_login")
14+
*/
15+
public function login(AuthenticationUtils $authenticationUtils): Response
16+
{
17+
// if ($this->getUser()) {
18+
// return $this->redirectToRoute('target_path');
19+
// }
20+
21+
// get the login error if there is one
22+
$error = $authenticationUtils->getLastAuthenticationError();
23+
// last username entered by the user
24+
$lastUsername = $authenticationUtils->getLastUsername();
25+
26+
return $this->render('security/login.html.twig', ['last_username' => $lastUsername, 'error' => $error]);
27+
}
28+
29+
/**
30+
* @Route("/logout", name="app_logout")
31+
*/
32+
public function logout(): void
33+
{
34+
throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
35+
}
36+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace App\Controller;
4+
5+
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
6+
use Symfony\Component\HttpFoundation\Response;
7+
use Symfony\Component\Routing\Annotation\Route;
8+
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
9+
10+
class SecurityController extends AbstractController
11+
{
12+
/**
13+
* @Route("/login", name="app_login")
14+
*/
15+
public function login(AuthenticationUtils $authenticationUtils): Response
16+
{
17+
// if ($this->getUser()) {
18+
// return $this->redirectToRoute('target_path');
19+
// }
20+
21+
// get the login error if there is one
22+
$error = $authenticationUtils->getLastAuthenticationError();
23+
// last username entered by the user
24+
$lastUsername = $authenticationUtils->getLastUsername();
25+
26+
return $this->render('security/login.html.twig', ['last_username' => $lastUsername, 'error' => $error]);
27+
}
28+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
namespace App\Controller;
4+
5+
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
6+
use Symfony\Component\Routing\Annotation\Route;
7+
8+
class SecurityController extends AbstractController
9+
{
10+
/**
11+
* @Route("/logout", name="app_logout")
12+
*/
13+
public function logout(): void
14+
{
15+
throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
16+
}
17+
}

0 commit comments

Comments
 (0)