Skip to content

Commit

Permalink
Merge pull request #167 from core23/form-type
Browse files Browse the repository at this point in the history
Replace hardcoded forms with symfony forms
  • Loading branch information
core23 authored Dec 19, 2020
2 parents 39b5cdf + 566e07a commit 419fc02
Show file tree
Hide file tree
Showing 8 changed files with 219 additions and 59 deletions.
35 changes: 23 additions & 12 deletions src/Action/LoginAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@
namespace Nucleos\UserBundle\Action;

use Nucleos\UserBundle\Event\GetResponseLoginEvent;
use Nucleos\UserBundle\Form\Type\LoginFormType;
use Nucleos\UserBundle\NucleosUserEvents;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
use Twig\Environment;

Expand All @@ -37,18 +39,25 @@ final class LoginAction
private $eventDispatcher;

/**
* @var CsrfTokenManagerInterface|null
* @var FormFactoryInterface
*/
private $tokenManager;
private $formFactory;

/**
* @var RouterInterface
*/
private $router;

public function __construct(
Environment $twig,
EventDispatcherInterface $eventDispatcher,
CsrfTokenManagerInterface $tokenManager = null
FormFactoryInterface $formFactory,
RouterInterface $router
) {
$this->twig = $twig;
$this->eventDispatcher = $eventDispatcher;
$this->tokenManager = $tokenManager;
$this->formFactory = $formFactory;
$this->router = $router;
}

/**
Expand Down Expand Up @@ -82,21 +91,23 @@ public function __invoke(Request $request): Response
$error = null; // The value does not come from the security component.
}

$form = $this->formFactory->create(LoginFormType::class, null, [
'action' => $this->router->generate('nucleos_user_security_check'),
'method' => 'POST',
]);

// last username entered by the user
$lastUsername = (null === $session) ? '' : $session->get($lastUsernameKey);

return new Response($this->twig->render('@NucleosUser/Security/login.html.twig', [
'last_username' => $lastUsername,
'error' => $error,
'csrf_token' => $this->getCsrfToken(),
'form' => $form->createView(),
// TODO: Remove this fields with the next major release
'error' => null,
'csrf_token' => '',
]));
}

private function getCsrfToken(): ?string
{
return null !== $this->tokenManager ? $this->tokenManager->getToken('authenticate')->getValue() : null;
}

private function getSession(Request $request): ?SessionInterface
{
return $request->hasSession() ? $request->getSession() : null;
Expand Down
27 changes: 23 additions & 4 deletions src/Action/RequestResetAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@

namespace Nucleos\UserBundle\Action;

use Nucleos\UserBundle\Form\Type\RequestPasswordFormType;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\RouterInterface;
use Twig\Environment;

final class RequestResetAction
Expand All @@ -22,15 +25,31 @@ final class RequestResetAction
private $twig;

/**
* RequestAction constructor.
* @var FormFactoryInterface
*/
public function __construct(Environment $twig)
private $formFactory;

/**
* @var RouterInterface
*/
private $router;

public function __construct(Environment $twig, FormFactoryInterface $formFactory, RouterInterface $router)
{
$this->twig = $twig;
$this->twig = $twig;
$this->formFactory = $formFactory;
$this->router = $router;
}

public function __invoke(): Response
{
return new Response($this->twig->render('@NucleosUser/Resetting/request.html.twig'));
$form = $this->formFactory->create(RequestPasswordFormType::class, null, [
'action' => $this->router->generate('nucleos_user_resetting_send_email'),
'method' => 'POST',
]);

return new Response($this->twig->render('@NucleosUser/Resetting/request.html.twig', [
'form' => $form->createView(),
]));
}
}
102 changes: 102 additions & 0 deletions src/Form/Type/LoginFormType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<?php

/*
* This file is part of the NucleosUserBundle package.
*
* (c) Christian Gripp <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Nucleos\UserBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Security\Core\Security;

final class LoginFormType extends AbstractType
{
/**
* @var RequestStack
*/
private $requestStack;

public function __construct(RequestStack $requestStack)
{
$this->requestStack = $requestStack;
}

public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('_username', TextType::class, [
'label' => 'security.login.username',
'attr' => [
'autocomplete' => 'username',
],
])
->add('_password', PasswordType::class, [
'label' => 'security.login.password',
'attr' => [
'autocomplete' => 'password',
],
])
->add('_remember_me', CheckboxType::class, [
'label' => 'security.login.remember_me',
'required' => false,
'value' => 'on',
])
->add('_target_path', HiddenType::class)
->add('save', SubmitType::class, [
'label' => 'security.login.submit',
])
;

$request = $this->requestStack->getCurrentRequest();

$builder->addEventListener(FormEvents::PRE_SET_DATA, static function (FormEvent $event) use ($request): void {
if (null === $request) {
return;
}

$error = null;

if ($request->attributes->has(Security::AUTHENTICATION_ERROR)) {
$error = $request->attributes->get(Security::AUTHENTICATION_ERROR);
} else {
$error = $request->getSession()->get(Security::AUTHENTICATION_ERROR);
}

if (null !== $error) {
$event->getForm()->addError(new FormError($error->getMessage()));
}

$event->setData(array_replace((array) $event->getData(), [
'username' => $request->getSession()->get(Security::LAST_USERNAME),
]));
});
}

public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'translation_domain' => 'NucleosUserBundle',
]);
}

public function getBlockPrefix(): string
{
return '';
}
}
48 changes: 48 additions & 0 deletions src/Form/Type/RequestPasswordFormType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

/*
* This file is part of the NucleosUserBundle package.
*
* (c) Christian Gripp <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Nucleos\UserBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

final class RequestPasswordFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('username', TextType::class, [
'label' => 'resetting.request.username',
'attr' => [
'autocomplete' => 'username',
],
])
->add('save', SubmitType::class, [
'label' => 'resetting.request.submit',
])
;
}

public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'translation_domain' => 'NucleosUserBundle',
]);
}

public function getBlockPrefix(): string
{
return '';
}
}
6 changes: 6 additions & 0 deletions src/Resources/config/resetting.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use Nucleos\UserBundle\Action\SendEmailAction;
use Nucleos\UserBundle\EventListener\ResettingListener;
use Nucleos\UserBundle\Form\Model\Resetting;
use Nucleos\UserBundle\Form\Type\RequestPasswordFormType;
use Nucleos\UserBundle\Form\Type\ResettingFormType;
use Symfony\Component\DependencyInjection\Parameter;
use Symfony\Component\DependencyInjection\Reference;
Expand All @@ -30,6 +31,9 @@
Resetting::class,
])

->set(RequestPasswordFormType::class)
->tag('form.type')

->set(ResettingListener::class)
->tag('kernel.event_subscriber')
->args([
Expand All @@ -41,6 +45,8 @@
->public()
->args([
new Reference('twig'),
new Reference('form.factory'),
new Reference('router'),
])

->set(ResetAction::class)
Expand Down
11 changes: 9 additions & 2 deletions src/Resources/config/security.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@
use Nucleos\UserBundle\Action\LoginAction;
use Nucleos\UserBundle\Action\LogoutAction;
use Nucleos\UserBundle\EventListener\LastLoginListener;
use Nucleos\UserBundle\Form\Type\LoginFormType;
use Nucleos\UserBundle\Security\EmailProvider;
use Nucleos\UserBundle\Security\EmailUserProvider;
use Nucleos\UserBundle\Security\LoginManager;
use Nucleos\UserBundle\Security\LoginManagerInterface;
use Nucleos\UserBundle\Security\UserProvider;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Reference;

return static function (ContainerConfigurator $container): void {
Expand Down Expand Up @@ -59,12 +59,19 @@
new Reference('nucleos_user.user_manager'),
])

->set(LoginFormType::class)
->tag('form.type')
->args([
new Reference('request_stack'),
])

->set(LoginAction::class)
->public()
->args([
new Reference('twig'),
new Reference('event_dispatcher'),
new Reference('security.csrf.token_manager', ContainerInterface::NULL_ON_INVALID_REFERENCE),
new Reference('form.factory'),
new Reference('router'),
])

->set(LogoutAction::class)
Expand Down
15 changes: 4 additions & 11 deletions src/Resources/views/Resetting/request_content.html.twig
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
{% trans_default_domain 'NucleosUserBundle' %}

<form action="{{ path('nucleos_user_resetting_send_email') }}" method="POST" class="resetting-form">
<div class="form-group">
<label for="username">{{ 'resetting.request.username'|trans }}</label>
<input type="text" id="username" name="username" required="required" class="form-control" />
</div>
{{ form_errors(form) }}

<div>
<button type="submit" class="btn btn-primary">
{{ 'resetting.request.submit'|trans }}
</button>
</div>
</form>
{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}
Loading

0 comments on commit 419fc02

Please sign in to comment.