Symfony FormEvents get errors - symfony

I call to form every route, so instead of all the time to do :
$form = $this->get('form.factory')->createNamed(UserType:class);
$form->handleRequest($request);
I call it from twig UserRegister.html.twig:
{{ render(controller('AppBundle:Security:register')) }}
and the twig:
{% if form.vars['errors'] is not empty %}
{{ form_errors(form) }}
{% endif %}
{{ form_start(form) }}
{{ form_end(form)
on the control it's:
public function registerAction(Request $request)
{
$form = $this->get('form.factory')->createNamed('register', UserType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($form->getData());
$em->flush();
$em->clear();
return $this->redirectToRoute('app.homepage');
}
return $this->render('#site_forms/UserRegister.html.twig', ['form' => $form->createView()]);
}
So what's the big problem?
on error it will show only the form!
the error should return this current page!

It seems you are rendering only form's twig on !isValid() case. Maybe it comes from here?
you could use $this->redirectToRoute($request->get('_route') to always redirect to current page.

Related

Symfony 4.4 object not found by the #ParamConverter annotation

I know there are lots of similar topics already.
What I tried:
checking my routes (php bin/console router:match url)
Overriding the ParamConverter "App\Entity\User object not found by the #ParamConverter annotation"
Understanding #ParamConverter & #security annotations
And more solutions that didn't work for me.
Here is not working fragment of the controller:
/**
* Edit action.
*
* #param Request $request HTTP request
* #param User $user User entity
* #param UserPasswordEncoderInterface $passwordEncoder Password encoder
*
* #return Response HTTP response
*
* #throws ORMException
* #throws OptimisticLockException
*
* #Route(
* "/{id}/password",
* methods={"GET", "PUT"},
* requirements={"id": "[1-9]\d*"},
* name="app_password",
* )
*/
public function editPasswordUser(Request $request, User $user, UserPasswordEncoderInterface $passwordEncoder): Response
{
if (($this->getUser() == $user) || (is_array($this->getUser()->getRoles()) && in_array(
'ROLE_ADMIN',
$this->getUser()->getRoles()
))) {
$role = $user->getRoles();
$form = $this->createForm(NewPasswordType::class, $user, ['method' => 'PUT']);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$user->setPassword(
$passwordEncoder->encodePassword(
$user,
$user->getPassword()
)
);
$user->setUpdatedAt(new DateTime());
$this->userService->save($user);
$this->addFlash('success', 'message_updated_successfully');
return $this->redirectToRoute('detail_show');
}
return $this->render(
'security/password.html.twig',
[
'form' => $form->createView(),
'user' => $user,
'role' => $role,
]
);
} else {
return $this->redirectToRoute('detail_show');
}
}
Twig file:
{% extends 'base.html.twig' %}
{% block title %}
{{ 'title.user_editpasswd'|trans({'%id%': user.id|default('')}) }}
{% endblock %}
{% block body %}
<h1>{{ 'title.user_editpasswd'|trans({'%id%': user.id|default('')}) }}</h1>
{{ form_start(form, { method: 'PUT', action: url('app_password', {id: user.id}) }) }}
{{ form_widget(form) }}
<div class="form-group row float-sm-right">
<input type="submit" value="{{ 'action.save'|trans }}" class="btn btn-primary" />
</div>
<div>
{% if role[0] == 'ROLE_ADMIN' %}
<a href="{{ url('user_view', {id: user.id} ) }}" title="{{ 'action.back_to_view'|trans }}">
{{ 'action.back_to_view'|trans }}
</a>
{% endif %}
</div>
<div>
{% if role[0] == 'ROLE_ADMIN' %}
<a href="{{ url('user_index') }}" title="{{ 'action.index'|trans }}">
{{ 'action.index'|trans }}
</a>
{% endif %}
</div>
{{ form_end(form) }}
{% endblock %}
My app is almost finished, and that's the first and only time I have such an error.
Change argument type in controller action from User to \Symfony\Component\Security\Core\User\UserInterface and everything should work. Current user is registered in a container by this service id.

Symfony3.4 Form errors rendered twice

I have a form with author and message fields and NotBlank() validation on both.
In twig, I do this:
{{ form_start(form) }}
{{ form_errors(form.author) }}
{{ form_label(form.author) }}
{{ form_widget(form.author) }}
{{ form_errors(form.message) }}
{{ form_label(form.message) }}
{{ form_widget(form.message) }}
{{ form_end(form) }}
If I press Save button with empty fields I EXPECT to see this:
But I get this:
Somehow the bottom error message comes from the {{ form_label(...) }} I say this, because if I comment the labels out and use static HTML for labels, the output is like on first picture.
I would prefer not to use static HTML for labels, but I don't understand where the second error messages came from.
Below my code:
Form
class TestFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('author', TextType::class, ['required' => false, 'constraints' => [new NotBlank()]])
->add('message', TextType::class, ['required' => false, 'constraints' => [new NotBlank()]])
->add('save', SubmitType::class)
;
}
}
Controller
class TestController extends Controller
{
/**
* #Route("/testing", name="test")
* #param Request $request
* #return RedirectResponse|Response
*/
public function index(Request $request)
{
$form = $this->createForm(TestFormType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid())
{
return $this->redirectToRoute('test');
}
return $this->render('test/index.html.twig', [
'form' => $form->createView(),
]);
}
}
Template
{% extends 'base.html.twig' %}
{% block title %}Hello TestController!{% endblock %}
{% block body %}
<p>This is a test...</p>
{{ form_start(form) }}
{{ form_errors(form.author) }}
{{ form_label(form.author) }}
{{ form_widget(form.author) }}
{{ form_errors(form.message) }}
{{ form_label(form.message) }}
{{ form_widget(form.message) }}
{{ form_end(form) }}
{% endblock %}
For bootstrap theme error block is integrated in label.
So you need either to remove form_errors block in your template or to override form_label block.
You can use form_row (as #Adrien suggests in commentaries) as there is no form_errors call
You've explicitly added form_errors whereas error message already rendered via form_label. either you can remove form_errors or form_label.

Symfony form submit button not working

I'm trying to submit a form which is supposed to deactivate several documents. When hitting the "Submit" button nothing happens.
Here is my twig file:
{% block content %}
{{ form_start(form) }}
{{ form(form.documentlist) }}
{{ form_end(form) }}
<p>
<div class="row">
<button type="submit">Submit</button>
</div>
{% endblock content %}
{% block javascripts %}
{{ parent() }}
<script src="{{ asset('js/bootstrap-multiselect.js') }}"></script>
<script>
makeMultiselectDropdown('#{{ form.vars.name }}_documentlist', 'Select Document');
</script>
<script type="text/javascript">
$(document).ready(function() {
$('#{{ form.vars.name }}_documentlist').change(function() {
var docId = $('#{{ form.vars.name }}_documentlist').val();
$.ajax({
type: "POST",
data: {'id': docId},
});
});
});
</script>
{% endblock %}
and my Controller function:
/**
* #Route("/document/bulkdeactivate", name="documentBundle_document_bulkDeactivate")
* #Template()
*/
public function bulkDeactivateAction(Request $request) {
$em = $this->getDoctrine()->getManager();
$selected_documents = $request->request->all();
$form = $this->createForm(DocumentDeactivationType::class);
$form->handleRequest($request);
if ($form->isValid() && $form->isSubmitted()) {
foreach($selected_documents as $document) {
$documentR = json_decode(json_encode($document), true);
dump($documentR);
for($i=0; $i<count($documentR); $i++){
$doc = $em->getRepository('DocumentBundle:Document')->findOneById($documentR[$i]);
dump($doc);
$document->setActive(false);
$em->persist($document);
$em->flush();
}
}
$this->addFlash(
'success',
'The document has been deactivated!'
);
return $this->redirectToRoute('documentBundle_document_list');
}
return $this->render('DocumentBundle:Panels:ActivationPanel.html.twig', array(
'form' => $form->createView(),
));
}
I looked in the console while hitting "Submit" and it says
Uncaught TypeError: Cannot set property 'href' of null
at window.onload (bulkdeactivate:257)
which is the line that renders the twig template. I don't know if this has anything to do with my problem, just wanted to let you know as much as I know!
Any help would be appreciated!

Show the thumbnails instead of the name of img with Symfony2 formbuilder

I am making the form which allow a user to select a img.
Symfony2.8 with sonataMediaBundle/
$form = $this->createFormBuilder($form)
->add('media',EntityType::class,array(
'expanded' => true,
'class' => "Application\Sonata\MediaBundle\Entity\Media"
}))
->add('save', SubmitType::class, array('label' => 'Create Post'))
->getForm();
in twig
{{form_widget(form.media)}}
However it shows the radio buttons with only the name of img.
○AAA.jpg ○BBB.jpg ○CCC.jpg ○DDD.jpg ('○' is radio button)
It is not good design for users.
I want to show the thumbnail of imgs here.
Is there good way to do this?
The easiest way i can imagine is to actually check the radio button with javascript.
Your Controller :
//src/AppBundle/Controller/YourController.php
public function yourAction()
{
$em = $this->getDoctrine()->getManager();
$medias = $em->getRepository('AppBundle:Media')->findAll();
$entity = new YourEntity();
$form = $this->createForm(YourEntityType::class, $entity);
if ($form->isSubmitted() && $form->isValid()) {
//... your logic
}
return $this->render('AppBundle::template.html.twig', array(
'form' => $form->createView(),
'medias' => $medias
));
}
Then in your twig file
{% for media in medias %}
<img class="to-select" src="{{ media.pathToThumbnail }}" data-id="{{ media.id }}" />
{% endfor %}
{{ form_start(form) }}
<!-- assuming you are using bootstrap -->
<div class="hidden">{{ form_widget(form.media) }}</div>
{{ form_widget(form.submit) }}
{{ form_end(form) }}
{% block javascripts %}
<script>
//assuming you use jquery
$('.to-select').click(function () {
var id = '#form_name_media_' + $(this).data('id');
var media = $(id);
if (media.is(':checked')) {
media.prop('checked', false);
} else {
media.prop('checked', true);
}
});
</script>
{% endblock javascripts %}

Symfony2 form in base.html.twig

I am new to Symfony2 and I am just trying some stuff to learn Symfony2.
Currently, I have a few controllers which can perfrom some simple tasks. A simple crud controller for example.
Al my pages extend a base.html.twig file and insert their block into it. Now I want to add a login part to my base file, because I want to be able to login at every page. I was thinking to use the formbuilder for this, but this is php code which can not be in a html.twig file. I have absolutly no idea how to handle this. Can someone push me in the right direction of give my some working example?
Thanking in advance
Actions:
public function loginFormAction(Request $request){
// create a task and give it some dummy data for this example
$message = "";
$account = new Account();
$account->setEmail('login#login.nl');
$form = $this->createFormBuilder($account)
->add('email', 'text')
->add('wachtwoord', 'text')
->add('login', 'submit')
->getForm();
$form->handleRequest($request);
if ($_POST != null && $_POST['form']['email'] != null) {
$repository = $this->getDoctrine()->getRepository('AcmeBlogBundle:Account');
$email =$_POST['form']['email'];
$wachtwoord =$_POST['form']['wachtwoord'];
$foundAccount = $repository->findOneByemail($email);
if (!$foundAccount) {
$message = "Ingevuld email en wachtwoord komen niet overeen.";
}else if($foundAccount->getWachtwoord() == $wachtwoord){
$session = $request->getSession();
$session->set('name', $foundAccount->getVoornaam() . " " . $foundAccount->getAchternaam());
$session->set('email', $foundAccount->getEmail());
//return $this->redirect($this->generateUrl('melding', array('melding' => 'mooiman')));
//return $this->render('AcmeBlogBundle:Account:melding.html.twig', array('melding' => 'Hallo, '.$foundAccount->getVoornaam() . " " . $foundAccount->getAchternaam()));
$message = 'Hallo, '.$foundAccount->getVoornaam() . " " . $foundAccount->getAchternaam();
$form = $this->createFormBuilder()
->add('logout', 'submit')
->getForm();
return $this->render('AcmeBlogBundle:Account:login.html.twig', array('form'=> $form->createView(), 'message' => $message));
}else{
$message = "Ingevuld email en wachtwoord komen niet overeen.";
}
}
return $this->render('AcmeBlogBundle:Account:login.html.twig', array('form'=> $form->createView(), 'message' => $message));
}
public function logoutFormAction(Request $request){
// create a task and give it some dummy data for this example
$session = $request->getSession();
$message = 'Hallo, '.$session->get('name');
$form = $this->createFormBuilder()
->add('logout', 'submit')
->getForm();
$form->handleRequest($request);
if ($_POST != null) {
$account = new Account();
$account->setEmail('login#login.nl');
$form = $this->createFormBuilder($account)
->add('email', 'text')
->add('wachtwoord', 'text')
->add('login', 'submit')
->getForm();
$session->set('name', null);
$session->set('email', null);
$message = "U bent nu uitgelogd";
}
return $this->render('AcmeBlogBundle:Account:login.html.twig', array('form'=> $form->createView(), 'message' => $message));
}
Base.html.twig:
{% if(app.session.get('name') == null) %}
{{ render(controller('AcmeBlogBundle:Account:loginForm')) }}
{% else %}
{{ render(controller('AcmeBlogBundle:Account:logoutForm')) }}
{% endif %}
You can include whole output of other controller/action in template. Just include this in your taplate:
<div id="sidebar">
{{ render(controller('YourBundle:User:login')) }}
</div>
This will inject whole output of YourBundle/UserController/loginAction to the #sidebar div. Remember that YourBundle/UserController/loginAction template can't extend other twig templates and hould be simple.
You can read more about embedding controllers here http://symfony.com/doc/current/book/templating.html#embedding-controllers
[EXAMPLE]:
An form action:
/**
* #Route("/contact", name="contact")
*/
public function contactAction(Request $request){
$form = $this->createFormBuilder()
->setAction($this->generateUrl('contact'))
->add('email', 'email', array(
'constraints' => array(
new \Symfony\Component\Validator\Constraints\Email()
)
))
->add('add', 'submit')
->getForm()
;
if ($request->getMethod() == 'POST') {
$form->handleRequest($request);
if ($form->isValid()) {
//do whatever you want and redirect
return $this->redirect($this->generateUrl('homepage'));
}else{
// this must be a full page (extending from base tamplate)
// that show form and errors
return $this->render(
'YourBundle:ControllerName:contact_faild.html.twig',
array('form' => $form->createView())
);
}
}
return $this->render(
'YourBundle:ControllerName:contact.html.twig',
array('form' => $form->createView())
);
}
There must be action URL in form "->setAction($this->generateUrl('contact'))" because form should be handled on separate request.
Next a form template (YourBundle:ControllerName:contact.html.twig):
{{ form(form) }}
Then we need an extra template for showing form errors when something went wrong. That should extend base template and probably override place where form appear in the first time
A form with errors tempalte (YourBundle:ControllerName:contact_faild.html.twig):
{% extends '::base.html.twig' %}
{% block sidebar -%}
{{ form(form) }}
{% endblock sidebar %}
And base teplate:
(...)
{% block sidebar %}
<div id="sidebar">
{{ render(controller('ClickAdUserBundle:User:contact')) }}
</div>
{% endblock %}
(...)
read this
you will find some html/twig code, put that in a "login.html.twig" and include it where you want
If you're completly new to Symfony2 i can suggest the symfony2 symblock tutorial
You'll work with Doctrine 2, creating Forms and design them, Twig Layouts and all the other stuff while creating a little blog.
Taken from the example, you would create the form in your controller like this
// src/Blogger/BlogBundle/Controller/PageController.php
public function contactAction()
{
$enquiry = new Enquiry(); //This creates an Instance of the Entity you need for the form
$form = $this->createForm(new EnquiryType(), $enquiry);
$request = $this->getRequest();
if ($request->getMethod() == 'POST') {
$form->bindRequest($request);
if ($form->isValid()) {
// Perform some action, such as sending an email
// Redirect - This is important to prevent users re-posting
// the form if they refresh the page
return $this->redirect($this->generateUrl('BloggerBlogBundle_contact'));
}
}
return $this->render('BloggerBlogBundle:Page:contact.html.twig', array(
'form' => $form->createView()
));
}
and the form as .html.twig would look like this
{# src/Blogger/BlogBundle/Resources/views/Page/contact.html.twig #}
{% extends 'BloggerBlogBundle::layout.html.twig' %}
{% block title %}Contact{% endblock%}
{% block body %}
<header>
<h1>Contact symblog</h1>
</header>
<p>Want to contact symblog?</p>
<form action="{{ path('BloggerBlogBundle_contact') }}" method="post" {{ form_enctype(form) }} class="blogger">
{{ form_errors(form) }}
{{ form_row(form.name) }}
{{ form_row(form.email) }}
{{ form_row(form.subject) }}
{{ form_row(form.body) }}
{{ form_rest(form) }}
<input type="submit" value="Submit" />
</form>
{% endblock %}
I hardly suggest working through this tutorial to have a nice start with symfony2

Resources