FOSUserBundle Custom forms using Bootstrap - symfony

I'm using FOSUserBundle in my Symfony application. Everything work but i would like to know how to custom the render of the forms delivered by the bundle.
I have already succesfully custom the login form but i didn't find the way to custom for example the changePassword.html.twig.
I'have checked in ChangePasswordFormType.php to see if I can get the differents fields of the form but I must have missed something.
For example in my FOSUserBundle login.html.twig:
<form class="form-group-lg" action="{{ path("fos_user_security_check") }}" method="post">
<input type="hidden" name="_csrf_token" value="{{ csrf_token }}" />
<fieldset>
{% if error %}
<div class="row">
<div class="alert alert-danger" role="alert">{{ error|trans({}, 'FOSUserBundle') }}</div>
</div>
{% endif %}
<div class="row">
<div class="input-group">
<span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span>
<input class="form-control" for="username" placeholder="{{ 'security.login.username'|trans({}, 'FOSUserBundle') }}" type="text" id="username" name="_username" value="{{ last_username }}" required="required" />
</div>
</div>
<div class="row">
</div>
<br>
<div class="row">
<div class="input-group">
<span class="input-group-addon"><i class="glyphicon glyphicon-lock"></i></span>
<input class="form-control" for="password" placeholder="{{ 'security.login.password'|trans({}, 'FOSUserBundle') }}" type="password" id="password" name="_password" required="required" />
</div>
<p class="text-right"> <a href={{ path('fos_user_resetting_request') }}> Mot de passe oublié ?</a></p>
</div>
<div class="checkbox">
<label>
<input type="checkbox" for="remember_me"/>{{ 'security.login.remember_me'|trans({}, 'FOSUserBundle') }}
</label>
</div>
<input class="btn btn-lg btn-primary btn-block" type="submit" id="_submit" name="_submit" value="{{ 'security.login.submit'|trans({}, 'FOSUserBundle') }}" />
</fieldset>
</form>
I'm looking for using the same syntax as {{ 'security.login.username'|trans({}, 'FOSUserBundle') }} for the others template provided by FOSUserBundleto get boostrap theme on it.
If someone have already done that i would like to know how you've done this.
Thanks.

FOSUserBundle templates are located at : vendor/friendsofsymfony/user-bundle/Resources/views/
To override these templates, create the folder app/Resources/FOSUserBundle/views then, you create a template with the same name as the FOSUserBundle template you want to override.
For example to override the change passord template :
vendor/friendsofsymfony/user-bundle/Resources/views/ChangePassword/change_password.html.twig
You must create app/Resources/FOSUserBundle/views/ChangePassword/change_passord.html.twig

Related

Add css classes to Jinja template for form

I'm copying an HTML template into a flask app. It comes with its own style sheet and I've made it work with the static elements on the page. My issue is that the contact us form that I'm trying to create with Jinja templates is looking very basic. I need to figure out how to add the existing style templates to the form fields.
In the original template, this is what the form fields looked like:
<div class="form-group">
<input type="text" name="name" class="form-control" id="name" placeholder="Your Name" data-rule="minlen:4" data-msg="Please enter at least 4 chars" />
<div class="validation"></div>
</div>
<div class="form-group">
<input type="email" class="form-control" name="email" id="email" placeholder="Your Email" data-rule="email" data-msg="Please enter a valid email" />
<div class="validation"></div>
</div>
<div class="form-group">
<input type="text" class="form-control" name="subject" id="subject" placeholder="Subject" data-rule="minlen:4" data-msg="Please enter at least 8 chars of subject" />
<div class="validation"></div>
</div>
<div class="form-group">
<textarea class="form-control" name="message" rows="5" data-rule="required" data-msg="Please write something for us" placeholder="Message"></textarea>
<div class="validation"></div>
</div>
<div class="text-center"><button type="submit">Send Message</button></div>
In my new form, this is what I have:
<div class="form-group">
{{ form.name(class="form-control") }}
</div>
<div class="form-group">
{{ form.email.label }}
{{ form.email }}
</div>
<div class="form-group">
{{ form.subject.label }}
{{ form.subject }}
</div>
<div class="form-group">
{{ form.message.label }}
{{ form.message }}
</div>
{{ form.submit }}
As you can see, I've been trying to add the original css classes to the Jinja template by adding class="form-control" to the form name. I haven't figured out how to add the rest. I'd appreciate your help with this.
<div class="form-group">
{{ form.name(class="form-control") }}
</div>
<div class="form-group">
{{ form.email.label(class="yourclass") }}
{{ form.email(class="yourclass") }}
</div>
<div class="form-group">
{{ form.subject.label(class="yourclass") }}
{{ form.subject(class="yourclass") }}
</div>
<div class="form-group">
{{ form.message.label(class="yourclass") }}
{{ form.message(class="yourclass") }}
</div>
{{ form.submit(class="yourclass") }}
Try this

Invalid CSRF token when resetting password

I have a resetting password feature in my site, however, form is not working. When trying to set the password, a "Invalid CSRF token" is shown.
This my actual resetting password form:
<div class="login-form">
<form name="fos_user_resetting_form" method="post" action="{{ path('fos_user_resetting_reset', {'token': token}) }}" class="needs-validation" novalidate>
<div class="form-group">
<label for="fos_user_resetting_form_plainPassword_first" class="required">{{ 'form.password'|trans }}</label>
<div class="input-group">
<div class="input-group-addon"><i class="fa fa-key"></i></div>
<input type="password" class="form-control" id="fos_user_resetting_form_plainPassword_first" name="fos_user_resetting_form[plainPassword][first]" required="required" autocomplete="new-password" />
<div class="invalid-tooltip">Por favor, ingrese la nueva contraseña.</div>
</div>
</div>
<div class="form-group">
<label for="fos_user_resetting_form_plainPassword_second" class="required">{{ 'form.password_confirmation'|trans }}</label>
<div class="input-group">
<div class="input-group-addon"><i class="fa fa-key"></i></div>
<input type="password" class="form-control" id="fos_user_resetting_form_plainPassword_second" name="fos_user_resetting_form[plainPassword][second]" required="required" autocomplete="new-password" />
<div class="invalid-tooltip" id="confirm_password_error">Por favor, ingrese la nueva contraseña.</div>
</div>
</div>
<div>
<button type="submit" id="_submit" name="_submit" class="btn btn-success btn-flat m-b-30 m-t-30">{{ 'resetting.reset.submit'|trans }}</button>
</div>
</form>
</div>
I Know I need to add a _csrf_token hidden input to form, but, how?
I tried with
{% if csrf_token %}
<input type="hidden" name="_csrf_token" value="{{ csrf_token }}" />
{% endif %}
With:
{% if _token %}
<input type="hidden" name="_csrf_token" value="{{ _token }}" />
{% endif %}
With:
<input type="hidden" id="fos_user_resetting_form__token" name="fos_user_resetting_form[_token]" value="{{ _token }}" />
And other attempts... but none works. In all cases, twig error is shown with 'Variable "_token" does not exist.'
When using Symfony debug toolbar, I see clearly the variable is called "_token". I don't know what else to try.
EDIT: when seeing Symfony Profiler, this is shown. Variable "_token" does exist, but I don't find a way to use it in the view.
when using the default FOSUserBundle form, the value of _token is rendered. I could not find how it is actually rendered, since it uses {{ form_widget(form) }} and when I saw the corresponding Form Type, I did not see any clue about this.
Thanks
Jaime
Finally, it was easier than I thought.
I added simply {{ form_widget(form._token) }} where the token should be in the form. That way, the correct token value was rendered for the hidden input field.
Regards
Jaime
Have you tried the following? From How to Implement CSRF Protection
<input type="hidden" name="_csrf_token"
value="{{ csrf_token('authenticate') }}"
>
For anyone trying to add the csrf token without generating the whole form, you can use in your twig template {{ fos_csrf_provider.refreshToken('resetting') }}. Example :
<!-- Form -->
<form id="change-password-form" action="{{ path("user_resetting_reset",{'token': token}) }}" method="post" name="change-password-form">
<div class="form-group">
<input id="change_password_first_password" class="input form-control" required type="password" name="first" placeholder="{% trans %}New password{% endtrans %}">
</div>
<div class="form-group">
<input id="change_password_second_password" class="input form-control" required type="password" name="second" placeholder="{% trans %}Retype new password{% endtrans %}">
</div>
<input type="hidden" id="profile_token" name="_token" value="{{ fos_csrf_provider.refreshToken('resetting') }}" />
<button type="submit" class="btn btn-block ui-gradient-green shadow-md">Reset</button>
</form>
<!-- Form -->

Symfony Demo Application - where to find twigs?

I'm trying to orientate myself with Symfony framework by going through the "Symfony Demo application" and am trying to work my way through the interconnections. However in the below code snippet I can't find where this twig reference is getting defined value="{{ last_username }}":
\app\Resources\view\security\login.html.twig
{% extends 'base.html.twig' %}
{% block body_id 'login' %}
{% block main %}
{% if error %}
<div class="alert alert-danger">
{{ error.messageKey|trans(error.messageData) }}
</div>
{% endif %}
<div class="row">
<div class="col-sm-5">
<div class="well">
<form action="{{ path('security_login_check') }}" method="post">
<fieldset>
<legend><i class="fa fa-lock"></i> Secure Sign in</legend>
<div class="form-group">
<label for="username">Username</label>
<input type="text" id="username" name="_username" value="{{ last_username }}" class="form-control"/>
</div>
<div class="form-group">
<label for="password">Password:</label>
<input type="password" id="password" name="_password" class="form-control" />
</div>
<input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}"/>
<button type="submit" class="btn btn-primary">
<i class="fa fa-sign-in"></i> Sign in
</button>
</fieldset>
</form>
</div>
</div>
I have searched the whole demo application for last_username and it only appears in these four files:
\app\cache\dev\classes.php
\app\cache\prod\classes.php
\vendor\symfony\symfony\src\Symfony\Component\Security\Core\SecurityContextInterface.php
\vendor\symfony\symfony\src\Symfony\Component\Security\Core\Security.php
...all of which don't seem to offer anything helpful of defining last_username.
The last_username parameter is passed to the template via the SecurityController, which is defined in the src/AppBundle/Controller/SecurityController.php file.
One of the coolest features of the Symfony Demo application is that all pages include a Show code which shows you both the controller and the template used to create the page you are looking at. For example, in the case of the login page:

Sonata Admin : Forgotten Password

I am using Sonata Admin with SonataUser/FosUser bundles.
I want to integrate the "reset password" functionality from FosUser into Sonata. Is there a quick way to :
integrate the "forgot your password" link into the sonata login page ?
integrate the functionality with the "admin/" url prefix and the sonata html/twig layout ?
I have modified the admin login template to add the reset password link, you must extend the SonataUserBundle in order to use your custom template, follow the documentation.
The custom template must have the same name and the same directory as in SonataUserBundle. Here is the template I used :
Application\Sonata\UserBundle\Resources\views\Admin\Security\login.html.twig
{% extends base_template %}
{% block content %}
<div class="connection">
<form action="{{ path("sonata_user_admin_security_check") }}" method="post">
{% if error %}
<div class="alert alert-error">{{ error|trans({}, 'SonataUserBundle') }}</div>
{% endif %}
<input type="hidden" name="_csrf_token" value="{{ csrf_token }}" />
<div class="control-group">
<label for="username">{{ 'security.login.username'|trans({}, 'FOSUserBundle') }}</label>
<div class="controls">
<input type="text" id="username" name="_username" value="{{ last_username }}" class="big sonata-medium"/>
</div>
</div>
<div class="control-group">
<label for="password">{{ 'security.login.password'|trans({}, 'FOSUserBundle') }}</label>
<div class="controls">
<input type="password" id="password" name="_password" class="big sonata-medium" />
</div>
</div>
<div class="control-group">
<label for="remember_me">
<input type="checkbox" id="remember_me" name="_remember_me" value="on" />
{{ 'security.login.remember_me'|trans({}, 'FOSUserBundle') }}
</label>
</div>
<div class="control-group">
<a href="{{ path('fos_user_resetting_request') }}">
{{ 'forgotten_password'|trans({}, 'SonataUserBundle') }}
</a>
</div>
<div class="form-actions">
<input type="submit" class="btn btn-primary" id="_submit" name="_submit" value="{{ 'security.login.submit'|trans({}, 'FOSUserBundle') }}" />
</div>
</form>
</div>
{% endblock content %}

Django styling login forms and adding additional spans

I have two questions in form-styling.
For my login, I am using Django's default auth features and haven't written any views or forms manually.
urls.py
urlpatterns += patterns(
'django.contrib.auth.views',
url(r'^login/$','login',
{'template_name':'login.html'},
name='qna_login'),
url(r'^logout/$','logout',
{'next_page':'qna_home'},
name='qna_logout'),
)
login.html
{% extends "base.html" %}
{% block content%}
{% if form.errors %}
<p class="text-warning"> Your username and/or password didn't match </p>
{% endif%}
<form role="form" class="form-horizontal" method="post" action="{% url 'django.contrib.auth.views.login' %}">
<div class="form-group">
{% csrf_token %}
{{ form }}
<input type="submit" class="btn btn-primary" value="login" />
<input type="hidden" name="next" value="{{ next }}" />
</div>
</form>
{% endblock %}
How do I add bootstrap styling to it?
For new user registration, I have added some bootstrap specific styles, but need to add additional spans and replace the labels with Glyphicons.
forms.py
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
class Meta:
model = User
fields = ('username', 'email', 'password')
def __init__(self, *args, **kwargs):
super(UserForm,self).__init__(*args,**kwargs)
self.fields['username'].widget.attrs.update({'class':'form-control','placeholder':'Username'})
self.fields['email'].widget.attrs.update({'class':'form-control','placeholder':'Email'})
self.fields['password'].widget.attrs.update({'class':'form-control','placeholder':'Password'})
What I need to do is replace what is generated in the template, such as
<p><label for="id_username">Username:</label> <input class="form-control" id="id_username" maxlength="30" name="username" placeholder="Username" type="text" /> <span class="helptext">Required. 30 characters or fewer. Letters, numbers and #/./+/-/_ characters</span></p>
by a custom bootstrap addon and glyphicon, like
<div class="input-group">
<span class="input-group-addon" style="background-color:#b77b48; color:white"><span class="glyphicon glyphicon-user"></span></span>
<input type="text" class="form-control" placeholder="Username">
</div>
You can render each field individually instead of letting Django render the whole form with {{ form }}. You can write the template like this -
<form role="form" class="form-horizontal" method="post" action="{% url 'django.contrib.auth.views.login' %}">{% csrf_token %}
<div class="form-group">
{% for field in form %}
<div class="input-group">
<span class="input-group-addon" style="background-color:#b77b48; color:white"><span class="glyphicon glyphicon-user"></span></span>
<input class="form-control" id="{{ field.id_for_label }}" maxlength="30" name="{{ field.html_name }}" value="{{ field.value }}" type="text" />
{{ field.errors }}
</div>
{% endfor %}
<input type="submit" class="btn btn-primary" value="login" />
<input type="hidden" name="next" value="{{ next }}" />
</div>
</form>
As always, like everything else, Django documentation has everything.

Resources