Skip to content

Commit a018245

Browse files
committed
Adding plainPassword validation and a few other things
1 parent 16d3b9b commit a018245

File tree

6 files changed

+86
-26
lines changed

6 files changed

+86
-26
lines changed

src/Maker/MakeRegistrationForm.php

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,16 @@
2727
use Symfony\Bundle\SecurityBundle\SecurityBundle;
2828
use Symfony\Bundle\TwigBundle\TwigBundle;
2929
use Symfony\Component\Console\Command\Command;
30-
use Symfony\Component\Console\Input\InputArgument;
3130
use Symfony\Component\Console\Input\InputInterface;
32-
use Symfony\Component\Console\Input\InputOption;
3331
use Symfony\Component\Form\AbstractType;
3432
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
3533
use Symfony\Component\Routing\RouterInterface;
36-
use Symfony\Component\Validator\Constraints\NotBlank;
3734
use Symfony\Component\Validator\Validation;
3835

3936
/**
4037
* @author Ryan Weaver <[email protected]>
38+
*
39+
* @internal
4140
*/
4241
final class MakeRegistrationForm extends AbstractMaker
4342
{
@@ -63,12 +62,6 @@ public function configureCommand(Command $command, InputConfiguration $inputConf
6362
{
6463
$command
6564
->setDescription('Creates a new registration form system')
66-
->addArgument('user-class', InputArgument::OPTIONAL, 'Full user class')
67-
->addArgument('username-field', InputArgument::OPTIONAL, 'Field on your User class used to login')
68-
->addArgument('password-field', InputArgument::OPTIONAL, 'Field on your User class that stores the hashed password')
69-
->addOption('auto-login-authenticator', null, InputOption::VALUE_REQUIRED, 'Authenticator class to use for logging in')
70-
->addOption('firewall-name', null, InputOption::VALUE_REQUIRED, 'Firewall key used for authentication')
71-
->addOption('redirect-route-name', null, InputOption::VALUE_REQUIRED, 'Route for redirecting if not authenticating')
7265
->setHelp(file_get_contents(__DIR__.'/../Resources/help/MakeRegistrationForm.txt'))
7366
;
7467

@@ -79,6 +72,16 @@ public function configureCommand(Command $command, InputConfiguration $inputConf
7972

8073
public function interact(InputInterface $input, ConsoleStyle $io, Command $command)
8174
{
75+
// initialize arguments & commands that are internal (i.e. meant only to be asked)
76+
$command
77+
->addArgument('user-class')
78+
->addArgument('username-field')
79+
->addArgument('password-field')
80+
->addOption('auto-login-authenticator')
81+
->addOption('firewall-name')
82+
->addOption('redirect-route-name')
83+
;
84+
8285
$interactiveSecurityHelper = new InteractiveSecurityHelper();
8386

8487
if (!$this->fileManager->fileExists($path = 'config/packages/security.yaml')) {
@@ -154,7 +157,7 @@ private function interactAuthenticatorQuestions(InputInterface $input, ConsoleSt
154157

155158
$input->setOption(
156159
'auto-login-authenticator',
157-
count($authenticatorClasses) === 1 ? $authenticatorClasses[0] : $io->choice(
160+
1 === \count($authenticatorClasses) ? $authenticatorClasses[0] : $io->choice(
158161
'Which authenticator\'s onAuthenticationSuccess() should be used after logging in?',
159162
$authenticatorClasses
160163
)
@@ -261,17 +264,31 @@ private function generateFormClass(ClassNameDetails $userClassDetails, Generator
261264
$usernameField => null,
262265
'plainPassword' => [
263266
'type' => PasswordType::class,
264-
'options' => [
265-
'mapped' => false,
266-
// TODO - NotBlank constraint
267-
]
267+
'options_code' => <<<EOF
268+
// instead of being set onto the object directly,
269+
// this is read and encoded in the controller
270+
'mapped' => false,
271+
'constraints' => [
272+
new NotBlank([
273+
'message' => 'Please enter a password',
274+
]),
275+
new Length([
276+
'min' => 6,
277+
'minMessage' => 'Your password should be at least {{ limit }} characters',
278+
]),
279+
],
280+
EOF
268281
],
269282
];
270283

271284
$this->formTypeRenderer->render(
272285
$formClassDetails,
273286
$formFields,
274-
$userClassDetails
287+
$userClassDetails,
288+
[
289+
'Symfony\Component\Validator\Constraints\NotBlank',
290+
'Symfony\Component\Validator\Constraints\Length',
291+
]
275292
);
276293

277294
return $formClassDetails;

src/Renderer/FormTypeRenderer.php

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
<?php
22

3+
/*
4+
* This file is part of the Symfony MakerBundle package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
312
namespace Symfony\Bundle\MakerBundle\Renderer;
413

514
use Symfony\Bundle\MakerBundle\Generator;
@@ -18,12 +27,12 @@ public function __construct(Generator $generator)
1827
$this->generator = $generator;
1928
}
2029

21-
public function render(ClassNameDetails $formClassDetails, array $formFields, ClassNameDetails $boundClassDetails = null)
30+
public function render(ClassNameDetails $formClassDetails, array $formFields, ClassNameDetails $boundClassDetails = null, array $constraintClasses = [])
2231
{
2332
$fieldTypeUseStatements = [];
2433
$fields = [];
2534
foreach ($formFields as $name => $fieldTypeOptions) {
26-
$fieldTypeOptions = $fieldTypeOptions ?? ['type' => null, 'options' => []];
35+
$fieldTypeOptions = $fieldTypeOptions ?? ['type' => null, 'options_code' => null];
2736

2837
if (isset($fieldTypeOptions['type'])) {
2938
$fieldTypeUseStatements[] = $fieldTypeOptions['type'];
@@ -40,7 +49,8 @@ public function render(ClassNameDetails $formClassDetails, array $formFields, Cl
4049
'bounded_full_class_name' => $boundClassDetails ? $boundClassDetails->getFullName() : null,
4150
'bounded_class_name' => $boundClassDetails ? $boundClassDetails->getShortName() : null,
4251
'form_fields' => $fields,
43-
'field_type_use_statements' => $fieldTypeUseStatements
52+
'field_type_use_statements' => $fieldTypeUseStatements,
53+
'constraint_use_statements' => $constraintClasses,
4454
]
4555
);
4656
}

src/Resources/skeleton/form/Type.tpl.php

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,23 @@
1111
<?php endforeach; ?>
1212
use Symfony\Component\Form\FormBuilderInterface;
1313
use Symfony\Component\OptionsResolver\OptionsResolver;
14+
<?php foreach ($constraint_use_statements as $className): ?>
15+
use <?= $className ?>;
16+
<?php endforeach; ?>
1417

1518
class <?= $class_name ?> extends AbstractType
1619
{
1720
public function buildForm(FormBuilderInterface $builder, array $options)
1821
{
1922
$builder
2023
<?php foreach ($form_fields as $form_field => $typeOptions): ?>
21-
<?php if (null === $typeOptions['type'] && empty($typeOptions['options'])): ?>
24+
<?php if (null === $typeOptions['type'] && !$typeOptions['options_code']): ?>
2225
->add('<?= $form_field ?>')
23-
<?php elseif (null !== $typeOptions['type'] && empty($typeOptions['options'])): ?>
26+
<?php elseif (null !== $typeOptions['type'] && !$typeOptions['options_code']): ?>
2427
->add('<?= $form_field ?>', <?= $typeOptions['type'] ?>::class)
2528
<?php else: ?>
2629
->add('<?= $form_field ?>', <?= $typeOptions['type'] ? ($typeOptions['type'].'::class') : 'null' ?>, [
27-
<?php foreach ($typeOptions['options'] as $key => $val): ?>
28-
'<?= $key; ?>' => <?= var_export($val, true) ?>,
29-
<?php endforeach; ?>
30+
<?= $typeOptions['options_code'] ?>
3031
])
3132
<?php endif; ?>
3233
<?php endforeach; ?>

tests/fixtures/MakeRegistrationFormEntity/tests/RegistrationFormTest.php

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
class RegistrationFormTest extends WebTestCase
1111
{
12-
public function testGeneratedEntity()
12+
public function testRegistrationSuccessful()
1313
{
1414
self::bootKernel();
1515
/** @var EntityManager $em */
@@ -31,4 +31,36 @@ public function testGeneratedEntity()
3131
$this->assertSame(200, $client->getResponse()->getStatusCode());
3232
$this->assertSame('Page Success', $client->getResponse()->getContent());
3333
}
34+
35+
public function testRegistrationValidationError()
36+
{
37+
self::bootKernel();
38+
/** @var EntityManager $em */
39+
$em = self::$kernel->getContainer()
40+
->get('doctrine')
41+
->getManager();
42+
$em->createQuery('DELETE FROM App\\Entity\\User u')
43+
->execute();
44+
$user = new User();
45+
$user->setEmail('[email protected]');
46+
$user->setPassword('abc-fake-encoded');
47+
$em->persist($user);
48+
$em->flush();
49+
50+
$client = static::createClient();
51+
$crawler = $client->request('GET', '/register');
52+
$form = $crawler->selectButton('Register')->form();
53+
$form['registration_form[email]'] = '[email protected]';
54+
$form['registration_form[password]'] = 'foo';
55+
$client->submit($form);
56+
57+
$this->assertSame(200, $client->getResponse()->getStatusCode());
58+
$this->assertContains(
59+
'Your password should be at least 6 characters',
60+
$client->getResponse()->getContent()
61+
);
62+
$client->followRedirect();
63+
$this->assertSame(200, $client->getResponse()->getStatusCode());
64+
$this->assertSame('Page Success', $client->getResponse()->getContent());
65+
}
3466
}

tests/fixtures/MakeRegistrationFormNoGuessing/src/Security/AuthenticatorFirst.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44

55
class AuthenticatorFirst
66
{
7-
}
7+
}

tests/fixtures/MakeRegistrationFormNoGuessing/src/Security/AuthenticatorSecond.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44

55
class AuthenticatorSecond
66
{
7-
}
7+
}

0 commit comments

Comments
 (0)