how to create a customized form - symfony

I'm working in a project and I would like to create form and not using form_widget. I want to create my own form.
Here is my controller:
public function newAction()
{
$entity = new Etudiant();
$form = $this->createCreateForm($entity);
return $this->render('MyAppRevBundle:Etudiant:new.html.twig', array(
'entity' => $entity,
'form' => $form->createView(),
));
}
And my html page is:
{% extends '::base.html.twig' %}
{% block body -%}
<form action="{{ path('etudiant') }}" {{form_enctype(form)}} method="post" >
<label for="username" class="col-md-2 control_label">Login :</label>
<input type="text" id="username" name="_username" value="Thaer"required="required" />
<br>
<input type="submit"/>
{{ form_rest(form) }}
</form>
<ul class="record_actions">
<li>
<a href="{{ path('etudiant') }}">
return
</a>
</li>
</ul>
{% endblock %}

so i solved
so it should be
{% extends '::base.html.twig' %}
{% block body -%}
<form action="{{ path('etudiant') }}" {{form_enctype(form)}} method="post" >
<table>
<tr>
<td>Libelle: </td>
<td>{{ form_widget(form.libelle)}}
</tr>
</table>
< input type="submit" />
{{ form_rest(form) }}
</form>
<ul class="record_actions">
<li>
<a href="{{ path('etudiant') }}">
return
</a>
</li>
{% endblock %}

Related

How to modify Bootstrap 4 form validation information presentation in Django?

I am using Django and Bootstrap 4. I want to customize the way form validation information is displayed in a template I am using. When an error occurs in the current template, the invalid input element has a red outline and the error message is displayed as a pop-up. Also, the input elements that have been inputted correctly don't have a green outline, they just remain without an outline.
I'd like to do the following:
display the error message underneath the field when an error occurs
give the green outline to the fields whose input is correct
I tried multiple solutions, including:
this tutorial
this GitHub gist
the Stack Overflow answers from this question
None worked from my case.
My current code:
submit_job_listing.html (the template):
{% extends "base.html" %}
{% block title %} Submit a job {% endblock %}
{% block nav_item_post_a_job %}active{% endblock nav_item_post_a_job %}
{% block head %}
{{ job_listing_form.media.css }}
{% endblock %}
{% block content %}
<h1>Submit a job listing</h1>
<div class="container">
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="row text-center">
<h2> <b>Job listing information</b> </h2>
</div>
<br/>
{% for field in job_listing_form.visible_fields %}
<div class="form-group">
<div class="row">
<p>{{ field.label_tag }}</p>
</div>
<div class="row">
{% if field.help_text %}
<p class="form-text text-muted">{{ field.help_text }}</p>
{% endif %}
</div>
<div class="row">
{{ field }}
</div>
</div>
{% endfor %}
<br/>
<div class="row text-center">
<h2> <b>Employer information</b> </h2>
</div>
<br/>
{% for field in employer_form.visible_fields %}
<div class="form-group">
<div class="row">
<p>{{ field.label_tag }}</p>
</div>
<div class="row">
{% if field.help_text %}
<p class="form-text text-muted">{{ field.help_text }}</p>
{% endif %}
</div>
<div class="row">
{{ field }}
</div>
</div>
{% endfor %}
<input type="submit" value="Submit" class="btn btn-primary" />
</form>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
{{ job_listing_form.media.js }}
</div>
{% endblock %}
views.py (relevant parts):
def submitJobListing(request):
if request.method == "POST":
employer_form = EmployerForm(request.POST, request.FILES)
job_listing_form = JobListingForm(request.POST, request.FILES)
#check if employer with that name already exists
employer_name = str(request.POST.get("name", ""))
try:
employer_with_the_same_name = Employer.objects.get(name=employer_name)
except ObjectDoesNotExist:
employer_with_the_same_name = None
employer = None
if (employer_with_the_same_name != None):
employer = employer_with_the_same_name
if employer == None and employer_form.is_valid() and job_listing_form.is_valid():
employer = employer_form.save()
job_listing = job_listing_form.save(commit=False)
job_listing.employer = employer
job_listing.save()
job_listing_form.save_m2m()
return SimpleTemplateResponse("employers/successful_job_listing_submission.html")
else:
employer_form = EmployerForm()
job_listing_form = JobListingForm()
context = {
"employer_form": employer_form,
"job_listing_form": job_listing_form,
}
return render(request, 'employers/submit_job_listing.html', context)
forms.py (relevant parts):
class EmployerForm(forms.ModelForm):
name = forms.CharField(max_length=100)
#location = forms.CharField(widget=LocationWidget)
short_bio = forms.CharField(widget=forms.Textarea)
website = forms.URLField()
profile_picture = forms.ImageField()
def __init__(self, *args, **kwargs):
super(EmployerForm, self).__init__(*args, **kwargs)
for visible in self.visible_fields():
if isinstance(visible.field.widget, (forms.widgets.TextInput, forms.widgets.Textarea, forms.widgets.URLInput, LocationWidget)):
visible.field.widget.attrs['class'] = 'form-control'
if isinstance(visible.field.widget, forms.widgets.ClearableFileInput):
visible.field.widget.attrs['class'] = 'form-control-file'
class Meta:
model = Employer
fields = ["name", "short_bio", "website", "profile_picture"]
class JobListingForm(forms.ModelForm):
job_title = forms.CharField(max_length=100, help_text="What's the job title?")
job_description = forms.CharField(widget=forms.Textarea)
job_requirements = forms.CharField(widget=forms.Textarea)
what_we_offer = forms.CharField(widget=forms.Textarea)
location = forms.CharField(widget=LocationWidget)
remote = forms.BooleanField()
job_application_url = forms.URLField()
point_of_contact = forms.EmailField()
categories = forms.ModelMultipleChoiceField(
queryset=Category.objects.all(),
widget=forms.CheckboxSelectMultiple,
required=True)
def __init__(self, *args, **kwargs):
super(JobListingForm, self).__init__(*args, **kwargs)
for visible in self.visible_fields():
if isinstance(visible.field.widget, (forms.widgets.TextInput, forms.widgets.Textarea, forms.widgets.URLInput, forms.widgets.EmailInput, LocationWidget)):
visible.field.widget.attrs['class'] = 'form-control'
if isinstance(visible.field.widget, (forms.widgets.CheckboxInput, forms.widgets.CheckboxSelectMultiple)):
visible.field.widget.attrs['class'] = 'form-check'
class Meta:
model = JobListing
fields = ["job_title", "job_description", "job_requirements", "what_we_offer", "location", "remote", "job_application_url", "categories", "point_of_contact"]
Can someone tell me how can I achieve the effects that I want?
Update 1:
I tried adding the code that checks for field.errors, but it doesn't work.
This is the submit_job_listing.html template file:
{% extends "base.html" %}
{% load widget_tweaks %}
{% block title %} Submit a job {% endblock %}
{% comment %} https://stackoverflow.com/questions/50028673/changing-active-class-in-bootstrap-navbar-not-staying-in-inherited-django-templa {% endcomment %}
{% block nav_item_post_a_job %}active{% endblock nav_item_post_a_job %}
{% block head %}
{{ job_listing_form.media.css }}
<!---
<style>
input, select {width: 100%}
</style>
--->
{% endblock %}
{% block content %}
{% comment %}
https://simpleisbetterthancomplex.com/article/2017/08/19/how-to-render-django-form-manually.html
{% endcomment %}
<h1>Submit a job listing</h1>
<div class="container">
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="row text-center">
<h2> <b>Job listing information</b> </h2>
</div>
<br />
<div class="row text-center">
<p> <b>Note: Fields marked with an asterisk (*) are required</b> </p>
</div>
<br/>
{% for field in job_listing_form.visible_fields %}
<div class="form-group">
<div class="row">
<p>{{ field.label_tag }}{{ field.field.required|yesno:"*," }}</p>
</div>
<div class="row">
{% if field.help_text %}
<p class="form-text text-muted">{{ field.help_text }}</p>
{% endif %}
</div>
<div class="row">
{{ field }}
<p> {{ field.errors }} </p>
{% if field.errors %}
<div class="border-bottom-danger">
{{ field.errors }}
</div>
{% endif %}
</div>
</div>
{% endfor %}
<br/>
<div class="row text-center">
<h2> <b>Employer information</b> </h2>
</div>
<br />
<div class="row text-center">
<p> <b>Note: Fields marked with an asterisk (*) are required</b> </p>
</div>
<br/>
{% for field in employer_form.visible_fields %}
<div class="form-group">
<div class="row">
<p>{{ field.label_tag }}{{ field.field.required|yesno:"*," }}</p>
</div>
<div class="row">
{% if field.help_text %}
<p class="form-text text-muted">{{ field.help_text }}</p>
{% endif %}
</div>
<div class="row">
{{ field }}
</div>
</div>
{% endfor %}
<input type="submit" value="Submit" class="btn btn-primary" />
</form>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
{{ job_listing_form.media.js }}
</div>
{% endblock %}
When I just click the submit button without inputting anything, all the inputs have a red outline, but nothing gets printed out as field.errors. I don't know why is that. Why is that?
Did you tried debugging in the template ?
I did something like you want to achieve :
<form method="post"> {% csrf_token %}
{% for field in form %}
<div class="form-group">
{{ field }}
<label class="control-label" for="{{ field.id_for_label }}">{{ field.label }}</label>
{% if field.errors %}
<div class="border-bottom-danger">
{{ field.errors }}
</div>
{% endif %}
</div>
{% endfor %}
<button class="btn btn-block" type="submit">Submit</button>
</form>
Where :
{{ field }} is the input, where you are correctly adding visible.field.widget.attrs['class'] = 'form-control'
Then, errors you want (I guess) are stored in the field, so you could get its with {{ field.errors }} if it has some.
The difference between your code and mine is that I'm using field.errors instead if field.help_text, I hope it can help.
I suggest you to put breakpoint in your template, then analyze your form object. Then you can do whatever you want in your frontend.
If no error : Add class outline-green to your input wrapper (the <div class="row")
If error : Display the error within a div underneath your input
PS : If you want to outline the input, and not the row wrapper, you can do it through css (or better with Sass if you are using it):
.row.outline-green > input{
border: 1px solid green;
}
<div class="row outline-green">
{{ field }}
</div>
{% load widget_tweaks %}
<div class="col-12 col-md-6">
<div class="form-group">
<label for="{{ form.field1.id_for_label }}" class="text-capitalize">{{ form.field1.label|title }}{% if form.field1.field.required %}<span class="text-danger ml-1">*</span>{% endif %}</label>
{% if form.is_bound %}
{% if form.field1.errors %}
{% render_field form.name class="form-control is-invalid" %}
{% for error in form.field1.errors %}
<div class="invalid-feedback">
{{ error }}
</div>
{% endfor %}
{% else %}
{% render_field form.field1 class="form-control is-valid" %}
{% endif %}
{% else %}
{% render_field form.field1 class="form-control" %}
{% endif %}
{% if form.field1.help_text %}
<small class="form-text text-muted">{{ form.field1.help_text }}</small>
{% endif %}
</div>
</div>
</div>

Knp Paginator Bundle route error when using slug

I'd like to implement the Knp Pagination for a table.
It is a page where I edit documents, so my route looks like that:
#Route("/document/edit/{id}/") and depending on the document, there is a different ID.
There are several panels on the page and one of them contains a table of different agencies. For that table I used the knp_paginator:
/**
* #var $paginator \Knp\Component\Pager\Paginator
*/
$paginator = $this->get('knp_paginator');
$agencyTable = $paginator->paginate(
$docAgencies,
$request->query->getId('page', 1),
5
);
the $docAgencies is defined like that so it's no query, but that's the way I need to get the information!
$document = $em->getRepository('DocumentBundle:Document')->findOneByIdInContext($id, $currentuser);
$docAgencies = $document->getAgencies();
When first accessing the page, everything is fine and page one of the table is being shown, but as soon as I try to click on another page of the table I get an error:
Controller "DocumentBundle\Controller\Document\EditController::editAction()" requires that you provide a value for the "$id" argument (because there is no default value or because there is a non optional argument after this one).
and my route looks like this:
http://localhost/sp/web/app_dev.php/document/document/edit?page=3
so the id of the document was just deleted and there's nothing to be accessed.
I tried to add a /{page} to my route like it was recommended in other Stackoverflow questions but this doesn't seem to work for me either.
That's how I tried it:
* #Route("/document/edit/{id}/{pag}", name="documentBundle_edit", requirements={"id" = "\d+", "pag" = "\d+"}, defaults={"id" = 0, "pag":1})
the editAction:
public function editAction(Request $request, $id, $pag) {
..
and within the paginate function:
$paginator = $this->get('knp_paginator');
$agencyTable = $paginator->paginate(
$docAgencies,
$pag,
5
);
any ideas why this is not working?
update twig view
{% block content %}
{{ form_start(form) }}
<div class="row">
{% include 'Form/form_errors_banner.html.twig' %}
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-body">
<legend>{{ 'header.info'|trans }}</legend>
{% include 'DocumentBundle:Panels:DocumentInfo.html.twig' %}
</div>
</div>
<div class="panel panel-default">
<div class="panel-body">
<legend>{{ 'label.comments'|trans }}</legend>
{% include 'AppBundle::CommentTable.html.twig' with {
'entity': document,
'add_comments': true
} %}
</div>
</div>
</div>
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-body">
<legend>{{ 'label.distribution'|trans }}</legend>
<div id="upload_profile_no">
{% trans_default_domain 'AppBundle' %}
{# CONFIG #}
{% if deleteButton is not defined %}
{% set deleteButton = true %}
{% endif %}
{{ form_label(form.agencies) }}<br>
{{ form_widget(form.agencies) }} <br> <br>
<table class="footable">
{# header fields #}
<thead>
<tr>
<th data-field="iata">{{ 'label.iata'|trans }}</th>
<th data-field="name">{{ 'label.name'|trans }}</th>
<th data-field="city">{{ 'label.city'|trans }}</th>
<th data-field="country">{{ 'label.country'|trans }}</th>
{% if deleteButton %}<th data-field="delete"></th>{% endif %}
</tr>
</thead>
{% block tablebody %}
{# body fields #}
<tbody>
{% for agency in docAgencies %}
<tr>
<td data-title="iata" data-market="{{ agency.market.id }}">{{ agency.id }}</td>
<td data-title="name">{{ agency.account }}</td>
<td data-title="city">{{ agency.cityName }}</td>
<td data-title="country">{{ agency.market.id }}</td>
{% if deleteButton %}
<td data-title="delete">
<button class="btn btn-danger btn-xs btn-remove-row" type="button" data-index="{{ agency.id }}">
<span class="glyphicon glyphicon-minus"></span>
</button>
<button class="btn btn-primary btn-xs btn-undo-remove hidden" type="button" data-index="{{ agency.id }}">
<span class="glyphicon glyphicon-repeat"></span>
</button>
</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
{% endblock %}
</table>
{% if docAgencies.pageCount > 1 %}
<div class="navigation text-center">
{{ knp_pagination_render(docAgencies) }}
</div>
{% endif %}
</div>
<br>
<div class="row">
<div class="col-md-6">
{{ form_row(form.airlines, { 'attr': { 'class': 'form-inline'} }) }}
</div>
<div class="col-md-6">
{{ form_row(form.products, { 'attr': { 'class': 'form-inline'} }) }}
</div>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-body">
<legend>{{ 'label.attachments'|trans }}</legend>
{% set fileDomain = 'document' %}
{% include 'AppBundle::AttachmentConfig.html.twig' %}
{% include 'AppBundle::DisplayAttachments.html.twig' with {'entity': document} %}
{% include 'AppBundle::FileUpload.html.twig' %}
</div>
</div>
</div>
</div>
<div class="row">
{% include 'AppBundle::HelpSubmitButton.html.twig' %}
</div>
{{ form_end(form) }}
{% include 'DocumentBundle:Action/UploadProfile:modals.html.twig' %}
{% endblock content %}
the part for the pagination is the table with {% for agency in docAgencies %}
**update 2 **
my full controller:
class EditController extends Controller {
/**
* #Route("/document/edit", name="documentBundle_edit2")
* #Route("/document/edit/{id}/{pag}", name="documentBundle_edit", requirements={"id" = "\d+", "pag" = "\d+"}, defaults={"id" = 0, "pag" = 1})
* #Template()
*/
public function editAction(Request $request, $id, $pag) {
$currentuser = $this->container->get('security.token_storage')->getToken()->getUser();
$em = $this->getDoctrine()->getManager();
$document = $em->getRepository('DocumentBundle:Document')->findOneByIdInContext($id, $currentuser);
$allComments = $document->getComments();
$docAgencies = $document->getAgencies();
$statusRepository = $em->getRepository('DocumentBundle:Status');
if($this->get('security.authorization_checker')->isGranted('ROLE_DOCUMENT_EDIT') && $document->getStatus()->getName() == 'Effective' && $document->isActive()
|| $this->get('security.authorization_checker')->isGranted('ROLE_CONTRACT_ADMIN')){
/*
* GET DOCUMENT FROM DB
*/
/*
* CHECK Document
*/
if($document == null)
{
return $this->get('app.error_helper')->throwError('error.404');
}
$form = $this->createForm(DocumentEditType::class, $document);
/*
* CREATE PAGINATION FOR TABLES
*/
/**
* #var $paginator \Knp\Component\Pager\Paginator
*/
$paginator = $this->get('knp_paginator');
$agencyTable = $paginator->paginate(
$docAgencies,
$pag,
5
);
$agencyTable->setTemplate('DocumentBundle::table_pagination.html.twig');
$agencyTable->setUsedRoute('documentBundle_edit');
$agencyTable->setParam('id', $id);
$commentTable = $paginator->paginate(
$allComments,
$pag,
5
);
$commentTable->setTemplate('DocumentBundle::table_pagination.html.twig');
/*
* IF REQUEST IS VALID
*/
$form->handleRequest($request);
if ($form->isValid()) {
$effective = date_format($document->getEffective(), 'Y-m-d');
$expires = date_format($document->getExpires(), 'Y-m-d');
$now = date('Y-m-d');
if($now < $effective) {
$status = $statusRepository->findOneById('3');
} elseif ($now >= $expires) {
$status = $statusRepository->findOneById('2');
} else {
$status = $statusRepository->findOneById('1');
}
$document->setStatus($status);
$em->flush();
$this->addFlash(
'success',
'The document has been edited!'
);
return $this->redirectToRoute('documentBundle_document_list');
}
/*
* DISPLAY Document
*/
return $this->render('DocumentBundle:Document:edit.html.twig', Array(
'document' => $document,
'docAgencies' => $agencyTable,
'comments' => $commentTable,
'form' => $form->createView(),
));
} else {
/*
* THROW ERROR
* If the acting user is not allowed to perform this action
*/
return $this->redirectToRoute('documentBundle_view_document', array(
'id' => $id
));
}
}
}
table_pagination.html.twig
<nav>
<ul class="pagination">
{# Previous #}
{% if startPage == 1 %}
<li class="disabled">
<a href="#" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
{% else %}
<li>
<a href="{{ path(app.request.attributes.get('_route'), {'page': startPage - 1}) }} " aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
{% endif %}
{# Pages #}
{% if pageCount < 12 %}{# less than 12 Pages #}
{% for i in 1..pageCount %}
<li {% if startPage == i %}class="active"{% endif %}>{{i}}</li>
{% endfor %}
{% else %}
{% if startPage < 8 %}{# any current page before 7 #}
{# Pages #}
{% for i in 1..8 %}
<li {% if startPage == i %}class="active"{% endif %}>{{i}}</li>
{% endfor %}
<li class="disabled">...</li>
<li>{{pageCount - 1}}</li>
<li>{{pageCount}}</li>
{% else %}
{% if startPage > pageCount - 7 %}{# any current page in the last 7 #}
{# Pages #}
<li>1</li>
<li>2</li>
<li class="disabled">...</li>
{% for i in 7..0 %}
<li {% if startPage == pageCount - i %}class="active"{% endif %}>{{pageCount - i}}</li>
{% endfor %}
{% else %}{# any other Page #}
<li>1</li>
<li>2</li>
<li class="disabled">...</li>
<li>{{startPage - 2}}</li>
<li>{{startPage - 1}}</li>
<li class="active">{{startPage}}</li>
<li>{{startPage + 1}}</li>
<li>{{startPage + 2}}</li>
<li class="disabled">...</li>
<li>{{pageCount - 1}}</li>
<li>{{pageCount}}</li>
{% endif %}{# any current page in the last 7 #}
{% endif %}{# any current page before 8 #}
{% endif %}{# less than 12 Pages #}
{# Next #}
{% if startPage == pageCount %}
<li class="disabled">
<a href="#" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
{% else %}
<li>
<a href="{{ path(app.request.attributes.get('_route'), {'page': startPage + 1}) }} " aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
{% endif %}
</ul>
</nav>
**update including #ste 's help **
Edit Controller:
* #Route("/document/edit/{id}/{page}", name="documentBundle_edit", requirements={"id" = "\d+", "page" = "\d+"}, defaults={"page" = 1})
* #Template()
*/
public function editAction(Request $request, $id, $page) {
$em = $this->getDoctrine()->getManager();
$document = $em->getRepository('DocumentBundle:Document')->findOneByIdInContext($id, $currentuser);
$allComments = $document->getComments();
$docAgencies = $document->getAgencies();
/*
* CREATE PAGINATION FOR TABLES
*/
/**
* #var $paginator \Knp\Component\Pager\Paginator
*/
$paginator = $this->get('knp_paginator');
$agencyTable = $paginator->paginate(
$docAgencies,
$page,
5
);
$agencyTable->setTemplate('DocumentBundle::table_pagination.html.twig');
$commentTable = $paginator->paginate(
$allComments,
$page,
5
);
$commentTable->setTemplate('DocumentBundle::table_pagination.html.twig');
return $this->render('DocumentBundle:Document:edit.html.twig', Array(
'document' => $document,
'docAgencies' => $agencyTable,
'comments' => $commentTable,
'form' => $form->createView(),
));
}
the pagination template
{# Pagination to be included anywhere. Needs {page, pageCount} #}
<nav>
<ul class="pagination">
{# Previous #}
{% if startPage == 1 %}
<li class="disabled">
<a href="#" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
{% else %}
<li>
<a href="{{ path(route, query|merge({'page': startPage - 1})) }} " aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
{% endif %}
{# Pages #}
{% if pageCount < 12 %}{# less than 12 Pages #}
{% for i in 1..pageCount %}
<li {% if startPage == i %}class="active"{% endif %}>{{i}}</li>
{% endfor %}
{% else %}
{% if startPage < 8 %}{# any current page before 7 #}
{# Pages #}
{% for i in 1..8 %}
<li {% if startPage == i %}class="active"{% endif %}>{{i}}</li>
{% endfor %}
<li class="disabled">...</li>
<li>{{pageCount - 1}}</li>
<li>{{pageCount}}</li>
{% else %}
{% if startPage > pageCount - 7 %}{# any current page in the last 7 #}
{# Pages #}
<li>1</li>
<li>2</li>
<li class="disabled">...</li>
{% for i in 7..0 %}
<li {% if startPage == pageCount - i %}class="active"{% endif %}>{{pageCount - i}}</li>
{% endfor %}
{% else %}{# any other Page #}
<li>1</li>
<li>2</li>
<li class="disabled">...</li>
<li>{{startPage - 2}}</li>
<li>{{startPage - 1}}</li>
<li class="active">{{startPage}}</li>
<li>{{startPage + 1}}</li>
<li>{{startPage + 2}}</li>
<li class="disabled">...</li>
<li>{{pageCount - 1}}</li>
<li>{{pageCount}}</li>
{% endif %}{# any current page in the last 7 #}
{% endif %}{# any current page before 8 #}
{% endif %}{# less than 12 Pages #}
{# Next #}
{% if startPage == pageCount %}
<li class="disabled">
<a href="#" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
{% else %}
<li>
<a href="{{ path(route, query|merge({'page': startPage + 1})) }} " aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
{% endif %}
</ul>
</nav>
and this is how I add the pagination to my template:
{{ knp_pagination_render(docAgencies) }}
It seems that you have a problem in table_pagination.html.twig.
You should replace this:
{{ path(app.request.attributes.get('_route'), {'page': THE_PAGE_YOU_HAVE}) }}
with this:
{{ path(route, query|merge({'pag': THE_PAGE_YOU_HAVE})) }}
or this
{{ path(app.request.attributes.get('_route'), app.request.query.all|merge({'pag': THE_PAGE_YOU_HAVE})) }}
Let me know if it works.
Further, you should remove the default value for id in your route for editAction

Customize SonataAdminBundle base_edit_form.html.twig

I would like to show the map in the form generated by Sonata Admin Bundle
This is my formMapper,
class PlaceInfoAdmin extends Admin
{
public function configureFormFields(FormMapper $formMapper)
{
$formMapper
->with('General')
->add('lati')
->add('longi')
->add('name')
I am using ivory google map API.
Simplifying what I want to do,
put this code at the last of template used by PlaceInfoAdmin
{{ ivory_google_api([
data.map,
data.form.field.vars['autocomplete']
])}}
put this code between rendered the cide of longi and name.
{{ ivory_google_map(data.map) }}
Now I research the twig files and found out maybe form is rendered by base_edit_form.html.twig,
However where should I alter?? or How can I find this twig is called by PlaceInfoAdmin?? (not by another ****Admin class)
{% block form %}
{{ sonata_block_render_event('sonata.admin.edit.form.top', { 'admin': admin, 'object': object }) }}
{% set url = admin.id(object) is not null ? 'edit' : 'create' %}
{% if not admin.hasRoute(url)%}
<div>
{{ "form_not_available"|trans({}, "SonataAdminBundle") }}
</div>
{% else %}
<form
{% if sonata_admin.adminPool.getOption('form_type') == 'horizontal' %}class="form-horizontal"{% endif %}
role="form"
action="{% block sonata_form_action_url %}{{ admin.generateUrl(url, {'id': admin.id(object), 'uniqid': admin.uniqid, 'subclass': app.request.get('subclass')}) }}{% endblock %}"
{% if form.vars.multipart %} enctype="multipart/form-data"{% endif %}
method="POST"
{% if not sonata_admin.adminPool.getOption('html5_validate') %}novalidate="novalidate"{% endif %}
{% block sonata_form_attributes %}{% endblock %}
>
{{ include('SonataAdminBundle:Helper:render_form_dismissable_errors.html.twig') }}
{% block sonata_pre_fieldsets %}
<div class="row">
{% endblock %}
{% block sonata_tab_content %}
{% set has_tab = ((admin.formtabs|length == 1 and admin.formtabs|keys[0] != 'default') or admin.formtabs|length > 1 ) %}
<div class="col-md-12">
{% if has_tab %}
<div class="nav-tabs-custom">
<ul class="nav nav-tabs" role="tablist">
{% for name, form_tab in admin.formtabs %}
<li{% if loop.index == 1 %} class="active"{% endif %}><i class="fa fa-exclamation-circle has-errors hide" aria-hidden="true"></i> {{ name|trans({}, form_tab.translation_domain ?: admin.translationDomain) }}</li>
{% endfor %}
</ul>
<div class="tab-content">
{% for code, form_tab in admin.formtabs %}
<div class="tab-pane fade{% if loop.first %} in active{% endif %}" id="tab_{{ admin.uniqid }}_{{ loop.index }}">
<div class="box-body container-fluid">
<div class="sonata-ba-collapsed-fields">
{% if form_tab.description != false %}
<p>{{ form_tab.description|raw }}</p>
{% endif %}
{{ form_helper.render_groups(admin, form, form_tab['groups'], has_tab) }}
</div>
</div>
</div>
{% endfor %}
</div>
</div>
{% else %}
{{ form_helper.render_groups(admin, form, admin.formtabs['default'].groups, has_tab) }}
{% endif %}
</div>
{% endblock %}
{% block sonata_post_fieldsets %}
</div>
{% endblock %}
{{ form_rest(form) }}
{% block formactions %}
<div class="sonata-ba-form-actions well well-small form-actions">
{% block sonata_form_actions %}
{% if app.request.isxmlhttprequest %}
{% if admin.id(object) is not null %}
<button type="submit" class="btn btn-success" name="btn_update"><i class="fa fa-save" aria-hidden="true"></i> {{ 'btn_update'|trans({}, 'SonataAdminBundle') }}</button>
{% else %}
<button type="submit" class="btn btn-success" name="btn_create"><i class="fa fa-plus-circle" aria-hidden="true"></i> {{ 'btn_create'|trans({}, 'SonataAdminBundle') }}</button>
{% endif %}
{% else %}
{% if admin.supportsPreviewMode %}
<button class="btn btn-info persist-preview" name="btn_preview" type="submit">
<i class="fa fa-eye" aria-hidden="true"></i>
{{ 'btn_preview'|trans({}, 'SonataAdminBundle') }}
</button>
{% endif %}
{% if admin.id(object) is not null %}
<button type="submit" class="btn btn-success" name="btn_update_and_edit"><i class="fa fa-save" aria-hidden="true"></i> {{ 'btn_update_and_edit_again'|trans({}, 'SonataAdminBundle') }}</button>
{% if admin.hasroute('list') and admin.isGranted('LIST') %}
<button type="submit" class="btn btn-success" name="btn_update_and_list"><i class="fa fa-save"></i> <i class="fa fa-list" aria-hidden="true"></i> {{ 'btn_update_and_return_to_list'|trans({}, 'SonataAdminBundle') }}</button>
{% endif %}
{% if admin.hasroute('delete') and admin.isGranted('DELETE', object) %}
{{ 'delete_or'|trans({}, 'SonataAdminBundle') }}
<a class="btn btn-danger" href="{{ admin.generateObjectUrl('delete', object) }}"><i class="fa fa-minus-circle" aria-hidden="true"></i> {{ 'link_delete'|trans({}, 'SonataAdminBundle') }}</a>
{% endif %}
{% if admin.isAclEnabled() and admin.hasroute('acl') and admin.isGranted('MASTER', object) %}
<a class="btn btn-info" href="{{ admin.generateObjectUrl('acl', object) }}"><i class="fa fa-users" aria-hidden="true"></i> {{ 'link_edit_acl'|trans({}, 'SonataAdminBundle') }}</a>
{% endif %}
{% else %}
{% if admin.hasroute('edit') and admin.isGranted('EDIT') %}
<button class="btn btn-success" type="submit" name="btn_create_and_edit"><i class="fa fa-save" aria-hidden="true"></i> {{ 'btn_create_and_edit_again'|trans({}, 'SonataAdminBundle') }}</button>
{% endif %}
{% if admin.hasroute('list') and admin.isGranted('LIST') %}
<button type="submit" class="btn btn-success" name="btn_create_and_list"><i class="fa fa-save"></i> <i class="fa fa-list" aria-hidden="true"></i> {{ 'btn_create_and_return_to_list'|trans({}, 'SonataAdminBundle') }}</button>
{% endif %}
<button class="btn btn-success" type="submit" name="btn_create_and_create"><i class="fa fa-plus-circle" aria-hidden="true"></i> {{ 'btn_create_and_create_a_new_one'|trans({}, 'SonataAdminBundle') }}</button>
{% endif %}
{% endif %}
{% endblock %}
</div>
{% endblock formactions %}
</form>
{% endif%}
{{ sonata_block_render_event('sonata.admin.edit.form.bottom', { 'admin': admin, 'object': object }) }}
{% endblock %}
{% endblock %}
Ho
Create a template that extends base_edit.html.twig:
{% extends 'SonataAdminBundle:CRUD:base_edit.html.twig' %}
{% block form %}
{# your custom code #}
{{ parent() }}
{% endblock %}
Then to make sure only the admin you want uses that template pass it in the definition of your admin service with a setTemplate call:
librinfo_crm.admin.contact:
class: Librinfo\CRMBundle\Admin\ContactAdmin
arguments: [~, Librinfo\CRMBundle\Entity\Contact, SonataAdminBundle:CRUD]
tags:
- name: sonata.admin
manager_type: orm
group: Customers Relationship Management
label: librinfo.crm.contact_admin.label
label_translator_strategy: blast_core.label.strategy.librinfo
calls:
- [ setTemplate, [edit, LibrinfoCRMBundle:OrganismAdmin:edit.html.twig]]

Symfony2 getLastUsername() function not working

I'm creating my first Symfony2 login form and want to use the getLastUsername() function to set the value of the username textbox but when calling the function it simply returns an empty string.
This is my SecurityController.php file:
<?php
namespace AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
class SecurityController extends Controller
{
/**
* #Route("/login", name="login")
*/
public function loginAction(Request $request)
{
$authenticationUtils = $this->get('security.authentication_utils');
// get the login error if there is one
$error = $authenticationUtils->getLastAuthenticationError();
// last username entered by the user
$lastUsername = $authenticationUtils->getLastUsername();
return $this->render(
'security/login.html.twig',
array(
// last username entered by the user
'last_username' => $lastUsername,
'error' => $error,
)
);
}
/**
* #Route("/login_check", name="login_check")
*/
public function loginCheckAction()
{
}
}
?>
and my Twig template for the form:
{# app/Resources/views/security/login.html.twig #}
{% extends 'base.html.twig' %}
{% block stylesheets %}
{{ parent() }}
<link href="{{ asset('css/login.css') }}" rel="stylesheet" />
{% endblock %}
{% block javascripts %}
{{ parent() }}
<script src="{{ asset('js/login.js') }}"></script>
{% endblock %}
{% block body %}
<div id="container">
{% if error %}
<div class="alert alert-danger">{{ error.messageKey|trans(error.messageData, 'security') }}</div>
{% endif %}
<div id="loginbox">
<form id="loginform" action="{{ path('login_check') }}" method="post">
<p>Enter username and password to continue.</p>
<div class="input-group input-sm">
<span class="input-group-addon"><i class="fa fa-user"></i></span><input class="form-control" type="text" name="_username" id="username" placeholder="Username" value="{{ last_username }}" />
</div>
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-lock"></i></span><input class="form-control" type="password" name="_password" id="password" placeholder="Password" />
</div>
<div class="form-actions clearfix">
<div class="pull-left">
Create new account
</div>
<div class="pull-right">
Lost password?
</div>
<input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}" />
<input type="submit" class="btn btn-block btn-primary btn-default" value="Login" />
</div>
</form>
</div>
</div>
{% endblock %}
Everything works fine. Logged in and out many times but the las username isn't showing. Thought Symfony might be using cookies to save the last used username but it isn't creating any cookies, only the PHP session is saved in a cookie. Is it a problem in the cookie configurations or may be something else?
Thanks,

How do i keep my footer on the same line

I have a shoppify site and the footer it shows the "quick links" "follow us" and the "newsletter" but i want all of them to be on the same page but newsletter keeps going on the next line. here is the code.
<div class="clearfix">
{% if settings.enable_social_links %}
<h4>{{ settings.footer_social_title }}</h4>
{% if settings.twitter_link != '' %}Twitter{% endif %}
{% if settings.facebook_link != '' %}Facebook{% endif %}
{% if settings.youtube_link != '' %}YouTube{% endif %}
{% if settings.atom_link != '' %}Blog feed{% endif %}
{% if settings.instagram_link != '' %}Instagram{% endif %}
{% if settings.pinterest_link != '' %}Pinterest{% endif %}
{% if settings.vimeo_link != '' %}Vimeo{% endif %}
{% if settings.tumblr_link != '' %}Tumblr{% endif %}
{% if settings.google_link != '' %}Google+{% endif %}
{% endif %}
</div>
<div class="span4">
{% if settings.footer_display_newsletter %}
<div class="p30">
<h4>{{ settings.footer_newsletter_title }}</h4>
<form action="{{ settings.mailing_list_form_action }}" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" target="_blank">
<input type="email" value="" placeholder="Email Address" name="EMAIL" id="mail" /><input type="submit" class="btn newsletter" value="Subscribe" name="subscribe" id="subscribe" />
</form>
</div>
{% endif %}
</div>
</div>
To keep elements on the same line, make them inline-block.
.p30, .p30 * { display: inline-block }

Resources