I followed this tutorial to add a captcha to my form.
First I install it using
composer require captcha-com/symfony-captcha-bundle:"4.*"
After I Install it, I got an error on a file called captcha.html.twig
Error:
captcha Unexpected "spaceless" tag (expecting closing tag for the
"block" tag defined near line 2).
So I changed {% spaceless %} to {% apply spaceless %}
And the error is gone.
But My captcha bot always returns True (even when I don't even fill it.
Here is the ->add() function of my form:
->add('captchaCode', CaptchaType::class, [
'captchaConfig' => 'ExampleCaptchaUserRegistration',
'constraints' => [
new ValidCaptcha([
'message' => 'Invalid captcha, please try again',
]),
],]);
Code of Routes.yaml :
captcha_routing:
resource: "#CaptchaBundle/Resources/config/routing.yml"
Code of captcha.php :
<?php
// app/config/packages/captcha.php
if (!class_exists('CaptchaConfiguration')) { return; }
// BotDetect PHP Captcha configuration options
return [
// Captcha configuration for example form
'ExampleCaptchaUserRegistration' => [
'UserInputID' => 'captchaCode',
'ImageWidth' => 250,
'ImageHeight' => 50,
],
];
Captcha field on the User.php entity:
protected $captchaCode;
public function getCaptchaCode()
{
return $this->captchaCode;
}
public function setCaptchaCode($captchaCode)
{
$this->captchaCode = $captchaCode;
}
Code in the View (twig)
<span class="txt1 p-b-11">
Are You a Robot?
</span>
<div class="wrap-input100 m-b-36">
{{ form_widget(form.captchaCode, {'attr': {'class': 'input100'} }) }}
<span class="focus-input100"></span>
</div>
<div class="error">{{ form_errors(form.captchaCode) }} </div>
Controlleur function:
/**
* #Route("/register", name="user_register", methods={"GET","POST"})
*/
public function register(Request $request,UserPasswordEncoderInterface $encoder): Response
{
$user = new User();
$form = $this->createForm(UserType::class, $user, ['validation_groups' => ['register'], ]);
$form ->remove("description");
$form ->remove("phone");
$form ->remove("website");
$form ->remove("facebook");
$form ->remove("picture");
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$hash = $encoder->encodePassword($user,$user->getPassword());
$user->setPassword($hash);
// defaults values (user can edit them later)
$user->setDescription("Apparently, this User prefers to keep an air of mystery about them.");
$user->setPhone(null);
$user->setPicture("default.png");
$user->setWebsite(null);
$user->setFacebook(null);
$user->setRoles(["ROLE_USER"]);
// end default values
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($user);
$entityManager->flush();
return $this->redirectToRoute('user_login');
}
return $this->render('authentication/register.html.twig', [
'user' => $user,
'form' => $form->createView(),
]);
}
Related
I have an edit page of my user object, so when the user have role admin and he is the connected user he doesn't have access to change his own role admin so I disabled the input of role when the user try to access the page to modify his own information, but before the form isSubmitted() I remove the disabled character from the input of role to access the content of the input in the action and check with a condition if this user try to change his password and display an error message
the edit action :
#[Route('/edit/{id}', name: 'app_user_edit', methods: ['GET', 'POST'])]
public function edit(Request $request, User $user, UserRepository $userRepository): Response
{
$session = $this->requestStack->getSession();
$session->set('key' ,$user->getId());
$form = $this->createForm(UserType::class, $user);
$form->handleRequest($request);
//dd($form->isValid());
if ($form->isSubmitted() && $form->isValid() ) {
if (in_array('ROLE_ADMIN',$user->getRoles()) && $user === $this->getUser()) {
if($user->getRoles() != ['ROLE_ADMIN','ROLE_USER']) {
$session = $request->getSession();
$session->getFlashBag()->add('error', 'You cannot change your role!');
} else{
$userRepository->add($user);
return $this->redirectToRoute('app_user_index', [], Response::HTTP_SEE_OTHER);
}}
}
return $this->renderForm('user/edit.html.twig', [
'user' => $user,
'form' => $form,
]);
}
the message in twig page
{% for message in app.flashes('error') %}
<div class="alert alert-success">
{{ message }}
</div>
{% endfor %}
The requestStack services is made to retrieve the request in a services. But you can't attach information in to it. If you wan't to add flashMessages to the request you can use the build in addFlash() method of your AbstractController.
I have showUsersAction()-method inside the Defaultcontroller which should render a form where it should be possible to select a user from a list, press a submit-button and then redirects to a route /showItems/{userId} where the items of a user are shown.
I know that it would be possible to do that easy with a link, but I want to make use of ChoiceType:
First I copied an example of ChoiceType from the Symfony documentation with a minimal change:
/**
* #Route("/showUsers", name="showUsers")
*/
public function showUsersAction(){
$users = $this->getDoctrine()->getManager()->getRepository('AppBundle:User')->findAll();
$form = $this->createFormBuilder()
->setMethod('POST')
->add('user', ChoiceType::class, [
'choices' => $users,
'choice_label' => function($user) {
/** #var User $user */
return strtoupper($user->getUsername());//here is the problem
},
'choice_attr' => function($user) {
return ['class' => 'user_'.strtolower($user->getUsername())];
},
])
->getForm();
return $this->render('default/showUsers.html.twig',
array('users' => $users, 'form' => $form->createView()));
}
I am sure $users gives an array with objects of the class User. When I execute the route in the browser I get following error message:
Error: Call to a member function getUsername() on a non-object
in src\AppBundle\Controller\DefaultController.php at line 50
Line 50 is the commented line return strtoupper($user->getUsername());
What is the problem and how can I solve?
And how can I get the selected User after I submitted via a submit button to the same route?
EDIT: (because of possible duplication)
Of course I know that the method getUsername() can not be called, because $user is a non-object, which should not be related to the Symfony documentation. So my question relates to a Symfony special solution which has absolutly nothing to do with 100 of other problems where the Error is the same.
Use entity type instead. Here is a link to documentation. It's a child type of a choice type, with exactly same functionality, and also every option returns an entity object.
Because I had trouble with setting up the entity type field too, I decided to post my solution for the whole action function and the twig file here:
action method:
/**
* #Route("/showUsers", name="showUsers")
*/
public function showUsersAction(Request $request){
// gets array of all users in the database
$users = $this->getDoctrine()->getManager()->getRepository('AppBundle:User')->findAll();
$form = $this->createFormBuilder()
->setMethod('POST')
->add('users', EntityType::class, array(
'class' => 'AppBundle:User',
'choices' => $users,
// This combination of 'expanded' and 'multiple' implements radio buttons
'expanded' => true,
'multiple' => false,
'choice_label' => function ($user) {
return $user->__toString();
}
))
// Adds a submit button to the form.
// The 'attr' option adds a class to the html rendered form
->add('selected', SubmitType::class, array('label' => 'Show User Items', 'attr' => array('class' => 'button')))
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// gets the selected user
$selectedUser = $form["users"]->getData();
// redirects to route 'showItems' with the id of the selected user
return $this->redirectToRoute('showItems', array('userId' => $selectedUser->getId()));
}
// renders 'default/showUsers.html.twig' with the form as an argument
return $this->render('default/showUsers.html.twig', array('form' => $form->createView()));
}
twig file:
{#
// app/Resources/views/default/showUsers.html.twig
Description:
twig file that implements a form in which one of all users can get
selected via radio button to show the items of the user after a click
on the submit button.
#author goulashsoup
#}
{% extends 'base.html.twig' %}
{% block title %}Users{% endblock %}
{% block body %}
<div class="users">
{{ form_start(form) }}
{% for user in form.users %}
{{ form_widget(user) }}
{{ form_label(user) }}
<br>
{% endfor %}
<br>
{{ form_end(form) }}
</div>
{% endblock %}
I have on my form template new.html.twig a select where all the elements of an entity are loaded ($categories).
Controller
public function newAction(Request $request){
$entity = new Playlist();
$form = $this->createCreateForm($entity);
$em = $this->getDoctrine()->getManager();
$categories = $em->getRepository('PublicartelAppBundle:Category')->getAllCategories();**
return $this->render('PublicartelAppBundle:Playlist:new.html.twig', array(
'categories' => $categories,
'entity' => $entity,
'form' => $form->createView(),
));
}
Select filter that serves to make a search.
Select in my twig template that displays all categories obtained from the query.
new.html.twig
<div class="form-group">
<label for="publicartel_appbundle_category_name">Search for category: </label>
<select id='selectCategory' class="form-control select2">
{% for category in categories %}
<option>
{{ category.name }}
</option>
{% endfor %}
</select>
</div>
JS in my twig template that detects changes in select option to make a new query and retrieve records from the selected option.
JS code
$('#selectCategory').on('change', function () {
var optionSelect = $(this).val();
$.post("{{path('playlist_category') }}", {category: optionSelect},
function (filterContent) {
for (var content in filterContent.category_result) {
for (var name in filterContent.category_result[content]) {
var result = filterContent.category_result[content][name];
console.log(result);
$('#playlist_content_name').append('<option>' + result + '</option>');
}
}
}, 'json');
});
The result of the new query is done in the playlist_category route is assigned to another select this in my twig template with the append method.
<div class="form-group">
<label for="publicartel_appbundle_area_name">Content</label>
{{ form_widget(form.items.vars.prototype.content, { 'id': 'playlist_content_name', 'full_name': '', required: false, 'attr': {'class': 'form-control select2'}}) }}
</div>
This select load other options, but the other select is used to filter options to prevent all options be loaded.
My problem is that when I try to send the form with any of the options obtained from the search, I get an error that the variable categories does not exist in my template twig new.html.twig.
Then, as the method createAction, also conducts a rendering of the template new.html.twig also add the variable $ categories there.
Controller
public function createAction(Request $request){
$entity = new Playlist();
$form = $this->createCreateForm($entity);
$form->handleRequest($request);
$em = $this->getDoctrine()->getManager();
if ($form->isValid()) {
// $em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('playlist_show', array(
'id' => $entity->getId())));
}
$categories = $em->getRepository('PublicartelAppBundle:Category')->getAllCategories();
return $this->render('PublicartelAppBundle:Playlist:new.html.twig', array(
'categories' => $categories,
'entity' => $entity,
'form' => $form->createView(),
));
}
But when complete the form, having chosen an option of select which return the search, instead of addressing the playlist_show route, directs me to the path /create with the form new.html.twig.
I can't retrieve data from my form, I tried differents ways but no result. My repository :
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('min_price', 'text', array('mapped' => false, 'label' => 'De la :', 'attr'=>
array(
'placeholder'=>'Pretul minim',
'class'=>'form-control')))
->add('max_price', 'text', array('mapped' => false, 'label' => 'Pina la :' , 'attr'=>
array(
'placeholder'=>'Pretul maxim',
'class'=>'form-control')))
)
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
parent::setDefaultOptions($resolver);
$resolver->setDefaults(array(
// avoid to pass the csrf token in the url (but it's not protected anymore)
'csrf_protection' => false,
));
}
public function getName()
{
return '';
}
My controller :
public function showCategoryAction($id, $page, Request $request){
$em = $this->getDoctrine()->getManager();
$repositoryProduct = $em->getRepository('ShopDesktopBundle:Product');
$category = $em->getRepository('ShopDesktopBundle:Category')->findOneById($id);
if (!$category) {
throw $this->createNotFoundException('Category not found.');
}
$aFilter = array();
$entity = new Product();
$form = $this->createForm(new ProductType(), $entity,array(
'action' => $this->generateUrl('show_product_category',array("id" => $id, "name" => $category->getCategoryLink(), "page" => $page )), //Your url to generate
'method' => 'GET'
));
$form->handleRequest($request);
$aFilter['iMinPrice'] = $form["min_price"]->getData();
$aFilter['iMaxPrice'] = $form["max_price"]->getData();
print_r($aFilter);
//Searchs products
$aProducts = $repositoryProduct->getProductsOrderByDateDesc($id,null,$aFilter);
if (!$aProducts) {
throw $this->createNotFoundException('Products not found.');
}
//Create pagination
$paginator = $this->get('knp_paginator');
$pagination = $paginator->paginate(
$aProducts,
$page,
3
);
//Send data to view
return $this->render('ShopDesktopBundle:Category:category.html.twig',array(
'category' => $category,
'pagination' => $pagination,
'form' => $form->createView()
));
}
My view :
<form action="{{ path('show_product_category',{ 'id':category.getId(), 'name':category.getCategoryLink() }) }}" method="get" {{ form_enctype(form) }}>
<div class="accordion-group">
<div class="accordion-heading">
<a class="accordion-toggle" data-toggle="collapse" data-parent="" href="#toggleOne">
<em class="icon-minus icon-fixed-width"></em>Pret
</a>
</div>
<div id="toggleOne" class="accordion-body collapse in">
<div class="accordion-inner">
{{ form_widget(form) }}
</div>
</div>
</div>
<input type="submit" class="btn btn-primary marg-left-20" value="Cautare"/>
</form>
The view :
show_product_category:
path: /{id}/{name}/{page}
defaults: { _controller: ShopDesktopBundle:Category:showCategory, page: 1}
requirements:
id: \d+
page: \d+
_method: GET|POST
So the problem is that I can't retrieve data from thi form. For all situations $aFilter is empty. If for example I put in the view in form POST method the filter is with data from form. My url look like this :
?min_price=10&max_price=50.
Help me please. Thx in advance.Exist a solution??
I would not set the form method as GET, just do not specify a method and it will default to POST, which is the usual way to submit a form.
Then handle the form submission in your Controller when the method is POST - like this:
if ($request->isMethod('POST')) {
$form->handleRequest($request);
if ($form->isValid() {
$aFilter['iMinPrice'] = $form->get('min_price')->getData();
$aFilter['iMaxPrice'] = $form->get('max_price')->getData();
}
}
More information on how to handle form submissions in Symfony2 here.
If you really need the form method to be GET, you should be able to get the query string parameters from the request:
$aFilter['iMinPrice'] = $request->query->get('min_price');
$aFilter['iMaxPrice'] = $request->query->get('max_price');
I've been trying to create a simple form in symfony but each time I try to submit I get the following error:
ERROR: The CSRF token is invalid. Please try to resubmit the form.
After surfing on the Internet and reducing the code to almost empty. I still get that error. Most of the people who I've seen asking for that solved the error using the following twig code
{{ form_rest(form) }}
The problem is that I'm using it, it's like when I bind the request it doesn't do it correctly. I don't know what else can I do.
This is my small twig template:
<div><h2>Insert new activity</h2></div>
<div>
<form id="new-activity" action="{{ path('create') }}" method="post" {{ form_enctype(form) }}>
{{ form_rest(form) }}
<p>
<button type="submit">Submit</button>
</p>
</form>
</div>
As you can see it is pretty small code. This is my form render code:
/**
* Displays a form to create a new Activity entity.
*
* #Route("/new", name="sucr_new")
* #Template()
*/
public function newAction() {
$initialConfig = new SucrConfiguration();
$finalConfig = new SucrConfiguration();
$activity = new SucrActivity();
$data = array("activity" =>$activity,
"initialConfig" => $initialConfig,
"finalConfig" => $finalConfig);
$form = $this->createForm(new ActivityType(), $data);
return array(
'data' => $data,
'form' => $form->createView()
);
}
And this is the code that should handle the submition:
/**
* Displays a form to create a new Activity entity.
*
* #Route("/create", name="create")
* #Method("post")
* #Template("EusocSucrBundle:Sucr:new.html.twig")
*/
public function createAction() {
$initialConfig = new SucrConfiguration();
$finalConfig = new SucrConfiguration();
$activity = new SucrActivity();
$data = array("activity" =>$activity,
"initialConfig" => $initialConfig,
"finalConfig" => $finalConfig);
$form = $this->createForm(new ActivityType(), $data);
if ($this->getRequest()->getMethod() == 'POST') {
$form->bindRequest($this->getRequest());
if ($form->isValid()) {
return $this->redirect($this->generateUrl('sucr_show', array('id' => 1)));
}
var_dump($form->getErrorsAsString());
}
return array(
'data' => $data,
'form' => $form->createView()
);
}
Also note that I can see the hidden token in my browser.
Any ideas?