How to create go back button after reload Symfony/twig - symfony

I use Symfony 4.4. I have a go back button in my Twig template.
{% if previousPageboolean == false %}
<a class="d-block text-decoration-none cursor px-4 pt-3" href="{{app.request.headers.get('referer')}}"><img src="{{ asset('build/images/back.svg')}}" class="height-19"></a>
{%else%}
<a class="d-block text-decoration-none cursor px-4 pt-3" href="{{referer}}"><img src="{{ asset('build/images/back.svg')}}" class="height-19"></a>
{% endif %}
But I have a problem. It works but in this template I have 2 forms. When I click the submit button of these buttons, flash messeges apper and reload the page. So when page reload the route of the go back button change and it is the own page.
Controller
/**
* #Route("/receta/{title}", name="recipe_show", methods={"GET"})
* #Route("/receta/{title}", name="recipe_show")
*/
public function show(Recipe $recipe,RecipeRepository $recipeRepository,ScoreRepository $scoreRepository,CommentRepository $commentRepository, Request $request): Response
{
$comment = new Comment();
$score = new Score();
$comment_form = $this->createForm(CommentType::class, $comment);
$comment_form->handleRequest($request);
$score_form = $this->createForm(ScoreType::class, $score);
$score_form->handleRequest($request);
$entityManager = $this->getDoctrine()->getManager();
$user = $this->getUser();
$referrer="";
$previousPageboolean =false;
if ($score_form->isSubmitted() && $score_form->isValid()) {
$previousPageboolean =true;
$referrer = $request->get('referrer');
$score_value = $score_form->get("score")->getData();
$isScore = $scoreRepository->findBy(array('user' => $user , 'recipe' => $recipe->getId()));
if($isScore == [] ){
$score->setScore($score_value);
$score->setRecipe($recipe);
$score->setUser($user);
$entityManager->persist($score);
$entityManager->flush();
$this->addFlash('success', '¡Puntuación registrada con exito!');
return $this->redirectToRoute($request->getUri(), [
'referrer' => $this->generateUrl($request->attributes->get('_route'),
array_merge(
$this->request->atrributes->get('_route_params'),
$this->request->query->all
),
),
]);
}else{
$this->addFlash('danger', 'Ya existe una puntuación registrada para esta receta con este usuario.');
return $this->redirect($request->getUri());
}
}
if ($comment_form->isSubmitted() && $comment_form->isValid()) {
$parentid = $comment_form->get("parent")->getData();
if($parentid != null){
$parent = $entityManager->getRepository(Comment::class)->find($parentid);
}
$comment->setVisible(1);
$comment->setParent($parent ?? null);
$comment->setUser($user);
$comment->setRecipe($recipe);
$comment->setCreatedAt(new DateTime());
$entityManager->persist($comment);
$entityManager->flush();
$this->addFlash('success', '¡Comentario registrado con exito!');
return $this->redirect($request->getUri());
}
$comments = $commentRepository->findCommentsByRecipe($recipe);
return $this->render('recipe/show/show.html.twig', [
'recipe' => $recipe,
'score_form' => $score_form->createView(),
'comment_form' => $comment_form->createView(),
'comments' => $comments,
'referrer' => $referrer,
'previousPageboolean' => $previousPageboolean
]);
}
It isn't a good idea to put the name of the route in the back button because the route needs the category parameter and a recipe can have more than one categories.
The recipe table haven't a category property because I have a recipes_categories table which have a M:M relationship between recipe table and category table.

Don't know if it has something to do with your problem but I think there's a typo in your controller: array_merge(
$this->request->atrributes->get('_route_params'),

One workaround I can think of is passing the refferer as a query parameter, and including it in the twig file.
In case you redirect to the current controller from twig:
Link to the current controller
In case you redirect using RedirectResponse:
return $this->redirectToRoute('some_path', [
...,
'referrer' => $this->generateUrl($request->attributes->get('_route'),
array_merge(
$request->atrributes->get('_route_params'),
$request->query->all
),
),
]);
Controller:
public function show(Request $request, ...)
{
...
$referrer = $request->get('referrer');
...
return $this->render('recipe/show/show.html.twig', [
...,
'referrer' => $referrer,
]);
twig:
<a class="d-block text-decoration-none cursor px-4 pt-3" href="{{referrer}}"><img src="{{ asset('build/images/back.svg')}}" class="height-19"></a>

Related

Symfony 4 - Dynamic Generation for Submitted Forms with Select2

I'm following the tutorial at http://symfony.com/doc/current/form/dynamic_form_modification.html#dynamic-generation-for-submitted-forms
I managed to reproduce the tutorial without worries, everything works well. However, when I apply "Select2" on my fields, it does not work anymore.
Form :
class TicketAdminForm extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('Client', EntityType::class, [
'class' => Clients::class,
'choice_label' => 'name',
'label' => "Client",
'placeholder' => '',
'attr' => ['data-provider' => 'select2'],
])
;
$formModifier = function (FormInterface $form, Clients $client = null) {
$entity = null === $client ? [] : $client->getEntities();
$form->add('entity', EntityType::class, [
'class' => 'App\Entity\Entity',
'placeholder' => '',
'choices' => $entity,
'label' => 'Entité',
'attr' => ['data-provider' => 'select2'],
]);
};
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($formModifier) {
// this would be your entity, i.e. Clients
$data = $event->getData();
$form = $event->getForm();
$formModifier($event->getForm(), $data->getClient());
}
);
$builder->get('Client')->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) use ($formModifier) {
// It's important here to fetch $event->getForm()->getData(), as
// $event->getData() will get you the client data (that is, the ID)
$client = $event->getForm()->getData();
// since we've added the listener to the child, we'll have to pass on
// the parent to the callback functions!
$formModifier($event->getForm()->getParent(), $client);
}
);
}
Twig :
{{ form_start(form, {'attr': {'class': 'form-horizontal'} }) }}
<div class="box-body">
{{ form_row(form.client) }}
{{ form_errors(form.client) }}
{{ form_row(form.entity) }}
{{ form_errors(form.entity) }}
</div>
<!-- /.box-body -->
<div class="box-footer">
<div class="col-md-offset-2 col-sm-8">
<button id="dropbutton" class="btn bg-ticketing btn-flat form-control" type="submit">
{{ 'Submit the ticket'|trans({}, 'TicketingBundle') }}
</button>
</div>
</div>
<!-- /.box-footer -->
{{ form_end(form) }}
</div>
<script>
var $client = $('#ticket_admin_form_client');
// When client gets selected ...
$client.change(function() {
console.log('dans change');
// ... retrieve the corresponding form.
var $form = $(this).closest('form');
// Simulate form data, but only include the selected client value.
var data = {};
data[$client.attr('name')] = $client.val();
// Submit data via AJAX to the form's action path.
$.ajax({
url : $form.attr('action'),
type: $form.attr('method'),
data : data,
success: function(html) {
// Replace current entity field ...
$('#ticket_admin_form_entity').replaceWith(
// ... with the returned one from the AJAX response.
$(html).find('#ticket_admin_form_entity')
);
// Entity field now displays the appropriate entities.
}
});
});
</script>
This code only works if I remove 'attr' => ['data-provider' => 'select2'] in form.
I tried :
$('#ticket_admin_form_client').on("select2:selecting", function(e) {
console.log('test');
});
but it does not work.
Do you have a solution to make it work with select2?
It's simple, in your ajax method add this :
$('#ticket_admin_form_entity').select2({});
Like this in method success by this :
// ...
$.ajax({
// ...
success: function(html) {
$('#ticket_admin_form_entity').replaceWith(
$(html).find('#ticket_admin_form_entity')
);
$('#ticket_admin_form_entity').select2({}); // Add this
}
// ...
;)

Symfony2 - Dynamic generated form not working while editing form

Based on documentation: http://symfony.com/doc/2.8/form/dynamic_form_modification.html#form-events-submitted-data
I prepared dynamic generated form. And everything works properly but only when I use form for adding new data (/new) when I use the same form for editing existing data - not working
Simple form for "Appointment". It should work like that: User select client and then second "select" is filling proper data - depends on each client from first select. And this works ok but only when I try add new Appointment. When I try edit no.
class AppointmentType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('client', EntityType::class, array(
'class' => 'SystemAdminBundle:Client',
'placeholder' => '',
));
$formModifier = function(\Symfony\Component\Form\FormInterface $form, Client $client)
{
$diseases = array();
if($client !== null) {
$diseases = $client->getDiseases();
}
$form->add('disease', EntityType::class, array(
'class' => 'SystemAdminBundle:Disease',
'placeholder' => '',
'choices' => $diseases,
));
};
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($formModifier) {
$data = $event->getData();
$formModifier($event->getForm(), $data->getClient());
}
);
$builder->get('client')->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) use ($formModifier) {
$client = $event->getForm()->getData();
$formModifier($event->getForm()->getParent(), $client);
}
);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'System\AdminBundle\Entity\Appointment'
));
}
}
Appointment controller - here is function for add new appointment and edit. For "new" my code works, for "edit" no.
public function newAction(Request $request)
{
$appointment = new Appointment();
$form = $this->createForm(AppointmentType::class, $appointment);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$data = $request->request->get('appointment');
if(array_key_exists('name', $data)) {
$em = $this->getDoctrine()->getManager();
$em->persist($appointment);
$em->flush();
return $this->redirectToRoute('appointment_show', array('id' => $appointment->getId()));
}
}
return $this->render('appointment/new.html.twig', array(
'appointment' => $appointment,
'form' => $form->createView(),
));
}
public function editAction(Request $request, Appointment $appointment)
{
$deleteForm = $this->createDeleteForm($appointment);
$appointment = new Appointment();
$editForm = $this->createForm('System\AdminBundle\Form\AppointmentType', $appointment);
$editForm->handleRequest($request);
if ($editForm->isSubmitted() && $editForm->isValid()) {
$data = $request->request->get('appointment');
if(array_key_exists('name', $data)) {
$em = $this->getDoctrine()->getManager();
$em->persist($appointment);
$em->flush();
return $this->redirectToRoute('appointment_show', array('id' => $appointment->getId()));
}
return $this->redirectToRoute('appointment_edit', array('id' => $appointment->getId()));
}
return $this->render('appointment/edit.html.twig', array(
'appointment' => $appointment,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
));
}
View for "new" appointment
{% block content %}
{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}
window.onload = function() {
var $sport = $('#appointment_client');
$sport.change(function() {
var $form = $(this).closest('form');
var data = {};
data[$sport.attr('name')] = $sport.val();
data['appointment[_token]'] = $('#appointment__token').val();
$.ajax({
url : $form.attr('action'),
type: $form.attr('method'),
data : data,
success: function(html) {
$('#appointment_disease').replaceWith(
$(html).find('#appointment_disease')
);
}
});
});
};
{% endblock %}
View for "edit" appointment - it's almost the same as for "new" appointment
{% block content %}
{{ form_start(edit_form) }}
{{ form_widget(edit_form) }}
{{ form_end(edit_form) }}
window.onload = function() {
var $sport = $('#appointment_client');
$sport.change(function() {
var $form = $(this).closest('form');
var data = {};
data[$sport.attr('name')] = $sport.val();
data['appointment[_token]'] = $('#appointment__token').val();
$.ajax({
url : $form.attr('action'),
type: $form.attr('method'),
data : data,
success: function(html) {
$('#appointment_disease').replaceWith(
$(html).find('#appointment_disease')
);
}
});
});
};
{% endblock %}
You create a new Appointment in your editAction and then persist it. You should take the one that's in your function parameters, handle the request and just flush, since your object is already persisted.
So remove these lines :
$appointment = new Appointment();
// ...
$em->persist($appointment);

isValid() method return false in symfony

I am using symfony3 with window 7 AND using custom form rending. like that
{{ form_start(form,{ 'attr': {'class': 'form-horizontal','role':'form','id':'form'} }) }}
---- form field here
{{ form_widget(form._token) }}
{{ form_end(form, {'render_rest': false}) }}
/**
* #Route("entity/entity/{id}", name="entity_entity",defaults={"id" = 0})
*/
public function entityAction(Request $request,$id){
$action = false;
$arr_XYZ_data = array();
$arr_XYZ_prepare_data = array();
$form_title = 'Add New XYZ';
$obj_XYZ = new XYZ();
$form = $this->createForm(XYZType::class, $obj_XYZ);
if($id!=0){
$obj_repo = $this->getDoctrine()->getRepository('AppBundle:XYZ');
$arr_XYZ_data = $obj_repo->find($id);
if($arr_XYZ_data){
$action = true;
$form_title = 'Update XYZ';
$arr_XYZ_data = $obj_repo->findXYZById($id);
$arr_XYZ_prepare_data = $this->_prepareData($arr_XYZ_data);
}
}
$form->handleRequest($request);
if (($form->isSubmitted())&&($form->isValid())) {
$obj_XYZ->setXYZId($id);
$str_hiddenfield_result = $form->get('extraformfield')->getData();
$arr_hiddenfield_result = explode('&',$str_hiddenfield_result);
$obj_XYZ->setDef($obj_XYZ->getDef()->getDefId());
$obj_XYZ->setAbc($arr_hiddenfield_result[3]);
$obj_XYZ->setAuthor(1); //ldap session value
$em = $this->getDoctrine()->getManager();
$em->persist($obj_XYZ);
$em->flush();
$this->addFlash('success', 'Your record has been added successfully!');
return $this->redirectToRoute('XYZ_index', array(), 301);
}else{
$form->getErrors();
}
}
above code does not print any error but unable to submit. so please anyone can suggest me how can i fix the issue.
how to get all error in string with corresponding each form field.
Just calling the getter will not print anything, you need to do it by yourself using another (printing) function.
return new \Symfony\Component\HttpFoundation\Response($form->getErrors());
It will render a string containing all errors.
Depending on the context (traditional, ajax, ...), you can just re-render the form like so:
return $this->render('YourBundle:YourView.html.twig', [
'form' => $form->createView(),
]);
The errors should be properly displayed.

Sonata Action with custom form

I have a custom action, based on the editAction from Sonata. Only the form is different.
public function customAction(){
$id = $this->get('request')->get($this->admin->getIdParameter());
$object = $this->admin->getObject($id);
if (!$object) {
throw new NotFoundHttpException(sprintf('unable to find the object with id : %s', $id));
}
if (false === $this->admin->isGranted('EDIT', $object)) {
throw new AccessDeniedException();
}
// On vérifie que l'annonce appartient bien à l'utilisateur connecté
if($this->getUser()->getId() !== $object->getUser()->getId()) {
throw new AccessDeniedException();
}
$em = $this->getDoctrine()->getManager();
$preparechoices = $em->getRepository('AcmeBundle:Entity')->findAll();
foreach($preparechoices as $c){
$choices[$c->getId()] = $c->getLibelle();
}
$form = $this->createFormBuilder(array('choix'=>1))
->add('choix','choice',array('choices'=>$choices))
->add('submit','submit')
->getForm();
$view = $form->createView();
$this->admin->setSubject($object);
$this->get('twig')->getExtension('form')->renderer->setTheme($view, $this->admin->getFormTheme());
return $this->render($this->admin->getTemplate('EDIT'), array(
'action' => 'edit',
'object' => $object,
'form' => $view,
));
}
But I got this error :
Impossible to access a key ("default") on a boolean variable ("")
The error come from this line in the twif file :
{{ form_helper.render_groups(admin, form, admin.formtabs['default'].groups, has_tab) }}
I can't find how to fix it, does anyone know ?
Thanks to Joshua, i was able to fix the error by adding this line:
$this->admin->setFormTabs(array('default'=>array('groups' => array())));
But now, i got a new error :
Impossible to access an attribute ("help") on a null variable
Form form_admin_fields.html.twig, this line, because sonata_admin.field_description is null :
{% if sonata_admin.field_description.help %}
title="{{ sonata_admin.admin.trans(sonata_admin.field_description.help, {}, sonata_admin.field_description.translationDomain)|raw }}"
{% endif %}
I don't know how to fix it, i tried several test, whitout success, in the form definition like :
$form = $this->createFormBuilder(array('choix'=>1))
->add('choix','choice',array('choices'=>$choices,'sonata_admin'=>array('field_description'=>array('help'=>'help_message'))))
->add('submit','submit')
->getForm();

pagerfanta used in a form with a search. symfony2

I'd like the paging link render by pagerfanta be submitted with the form data.
This is to consider the data entered in the search form.
A simple pagination link will not allow me to navigate in my search result.
Any help please ?
controller
/**
* #Route("/{page}/", name="admin_user",requirements={"page" = "\d+"}, defaults={"page" = 1})
* #Template()
*/
public function indexAction($page = 1)
{
$data = [];
$data['name'] = $this->getUser()->getName();
$form = $this->createForm('admin_user_search_type', null);
$request = $this->getRequest();
if ($request->getMethod() == 'POST') {
$form->bind($request);
$data = array_merge($data, $form->getData());
}
return $this->render('AABundle:User:index.html.twig', array(
'pager' => $this->getDoctrine()->getManager()->getRepoitory('AABundle:User')->search($data, 4, $page, $this->getUser()),
'form' => $form->createView(),
));
}
view.html.twig
{% if pager.haveToPaginate %}
{{ pagerfanta(pager, 'twitter_bootstrap3') }}
{% endif %}
The solution is to submit the form with Get methode instead of Post to be able to retrieve form data .Also we don't need to check whether is valid or not , while it is a search form .
The controller will be as it shown below:
**
* #Route("/{page}/", name="admin_user",requirements={"page" = "\d+"}, defaults={"page" = 1})
* #Template()
*/
public function indexAction($page = 1)
{
$data = [];
$data['name'] = $this->getUser()->getName();
$form = $this->createForm('admin_user_search_type', null);
$request = $this->getRequest();
$form->bind($request);
$data = array_merge($data, $form->getData());
return $this->render('AABundle:User:index.html.twig', array(
'pager' => $this->getDoctrine()->getManager()->getRepoitory('AABundle:User')->search($data, 4, $page, $this->getUser()),
'form' => $form->createView(),
));
}
the form.html.twig
<form name= "search" action="{{ path('admin_user') }}" novalidate method="get"{{ form_enctype(form) }}>
</form>

Resources