create an update password in symfony2? - php

I have created an update password form and whenever I try to submit the data I got error like The class 'RetailMapping\Bundle\UserBundle\Form\Model\ChangePassword' was not found in the chain configured namespaces AppBundle\Entity, RetailMapping\Bundle\UserBundle\Entity, RetailMapping\Bundle\CatalogBundle\Entity, RetailMapping\Bundle\LocationBundle\Entity, RetailMapping\Bundle\ClassificationBundle\Entity, RetailMapping\Bundle\RetailOutletBundle\Entity, FOS\UserBundle\Model. What am I doing wrong in here? The error occurs when I try to save the data in the database.
Here are my codes.
This is my ChangePasswordType.php
<?php
namespace RetailMapping\Bundle\UserBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class ChangePasswordType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('oldPassword', 'password');
$builder->add('newPassword', 'repeated', array(
'type' => 'password',
'invalid_message' => 'The password fields must match.',
'required' => true,
'first_options' => array('label' => 'Password'),
'second_options' => array('label' => 'Repeat Password'),
));
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'RetailMapping\Bundle\UserBundle\Form\Model\ChangePassword',
));
}
/**
* #return string
*/
public function getName()
{
return 'retailmapping_bundle_userbundle_password_chnage';
}
}
This is my ChangePassword.php
<?php
namespace RetailMapping\Bundle\UserBundle\Form\Model;
use Symfony\Component\Security\Core\Validator\Constraints as SecurityAssert;
use Symfony\Component\Validator\Constraints as Assert;
class ChangePassword
{
/**
* #SecurityAssert\UserPassword(
* message = "Wrong value for your current password"
* )
*/
protected $oldPassword;
/**
* #Assert\Length(
* min = 6,
* minMessage = "Password should by at least 6 chars long"
* )
*/
protected $newPassword;
public function setOldPassword($oldPassword)
{
$this->oldPassword = $oldPassword;
}
public function getOldPassword()
{
return $this->oldPassword;
}
public function setNewPassword($newPassword)
{
$this->newPassword = $newPassword;
}
public function getNewPassword()
{
return $this->newPassword;
}
}
This is my UserController.php
<?php
namespace RetailMapping\Bundle\UserBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use RetailMapping\Bundle\UserBundle\Form\ChangePasswordType;
use Symfony\Component\HttpFoundation\Request;
use RetailMapping\Bundle\UserBundle\Form\Model\ChangePassword;
class UserController extends Controller
{
public function editPasswordAction(Request $request)
{
$form = $this->createForm(new ChangePasswordType(), new ChangePassword());
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$data = $form->getData();
$form->getData();
$em = $this->getDoctrine()->getManager();
$em->persist($data);
$em->flush();
dump($form->getData());
die;
}
return $this->render('User/editPassword.html.twig', [
'form' => $form->createView(),
]);
}
}

There's no mention of an Entity in the post you linked. Because you made the class an Entity, it's become a database table, and fields like id's are expected.
Double check the answer you tried to implement.

For making a password update form you need to make PasswordUpdateModel and PasswordUpdateType, after processing form you can assign it to UserEntity fields.
I hope this helps.

Related

Symfony 4 get current user in form type?

I want to know how I can recover the current user in my FormType (EntityType)?
Currently, I can only retrieve the list of registered users but not the current (connected) user.
My current FormType
<?php
namespace App\Form;
use App\Entity\User;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class OneNewCarType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add(
'author',
EntityType::class, [
'label' => 'Ville',
'class' => User::class,
'attr' => [
'class' => 'selectpicker'
],
'choice_label' => function ($author) {
return $author->getCity();
}
]
);
}
public function getBlockPrefix()
{
return 'oneNewCarType';
}
}
I know how to recover it directly in my controller. But, I do not know how to do it when one uses the stepper bundle CraueFormFlowBundle
This is my current controller
/**
* #Route("/classified/{id}/edit", name="classified_edit")
* #param CarVehicle $carVehicle
* #param ObjectManager $manager
* #param CreateVehicleFlow $createVehicleFlow
* #return RedirectResponse|Response
*/
public function edit(CarVehicle $carVehicle, ObjectManager $manager, CreateVehicleFlow $createVehicleFlow)
{
$flow = $createVehicleFlow;
$flow->bind($carVehicle);
$form = $flow->createForm();
if ($flow->isValid($form)) {
$flow->saveCurrentStepData($form);
if ($flow->nextStep()) {
$form = $flow->createForm();
} else {
$manager->persist($carVehicle);
$manager->flush();
$flow->reset();
$this->addFlash(
'success',
"Votre annonce <i>{$carVehicle->getId()}</i> a bien été mise à jour"
);
return $this->redirect($this->generateUrl('account_index'));
}
}
return $this->render('front/classified/edit_vehicle.html.twig', [
'form' => $form->createView(),
'flow' => $flow,
'carVehicle' => $carVehicle,
]);
}
Thanks for the help !
With Symfony\Component\Security\Core\Security you can get user where you want. Inject this into FormType and use $user = $this->security->getUser();
private Security $security;
public function __construct(Security $security)
{
$this->security = $security;
}
In Symfony 5, With use
Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface
you can get user where you want. Inject this into FormType and use
$user = $this->token->getToken()->getUser();
private $token;
public function __construct(TokenStorageInterface $token)
{
$this->token = $token;
}

Symfony2 UniqueEntity constraint SQL error instead of message

I'm stuck with creating a user registration form with Symfony2.
I'm trying to define an Unique constraint on the email attribute of my User class.
Acme\APPBundle\Entity\User.php
namespace Acme\APPBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* #ORM\Entity
* #ORM\Entity(repositoryClass="Acme\APPBundle\Entity\UserRepository")
* #ORM\Table("users")
* #UniqueEntity(
* fields={"email"},
* message="email already used"
* )
*/
class User implements UserInterface, \Serializable
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string", length=255, unique=true)
* #Assert\NotBlank()
* #Assert\Email()
*/
protected $email;
[...]
}
Acme\APPBundle\Form\Type\UserType.php
namespace Acme\APPBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class UserType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('email', 'email');
$builder->add('password', 'repeated', array(
'first_name' => 'password',
'second_name' => 'confirm',
'type' => 'password',
));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Acme\APPBundle\Entity\User',
'cascade_validation' => true,
));
}
public function getName()
{
return 'user';
}
}
I've added the constraint following the documentation but I still get an exception like :
An exception occured while executing 'INSERT INTO users ( ... )'
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry
It looks like my message value defined in annotations is ignored and the form validation is bypassed since it should fail before attempting to insert row in database.
Can you tell me what am I doing wrong ?
EDIT :
Following Matteo 'Ingannatore' G.'s advice I've noticed that my form is not properly validated.
I forgot to mention that I use a registration class that extends the user form. I've written my code after what is explained in the Symfony Cookbook.
Thus I have :
Acme\APPBundle\Form\Model\Registration.php
namespace Acme\APPBundle\Form\Model;
use Symfony\Component\Validator\Constraints as Assert;
use Acme\APPBundle\Entity\User;
class Registration
{
/**
* #Assert\Type(type="Acme\APPBundle\Entity\User")
*/
protected $user;
/**
* #Assert\NotBlank()
* #Assert\True()
*/
protected $termsAccepted;
public function setUser(User $user)
{
$this->user = $user;
}
public function getUser()
{
return $this->user;
}
public function getTermsAccepted()
{
return $this->termsAccepted;
}
public function setTermsAccepted($termsAccepted)
{
$this->termsAccepted = (Boolean) $termsAccepted;
}
}
Acme\APPBundle\Form\Type\RegistrationType.php
namespace Acme\APPBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class RegistrationType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('user', new UserType());
$builder->add('terms', 'checkbox', array('property_path' => 'termsAccepted'));
}
public function getName()
{
return 'registration';
}
}
Acme\APPBundle\Controller\AccountController.php
namespace Acme\APPBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
use Acme\AccountBundle\Form\Type\RegistrationType;
use Acme\AccountBundle\Form\Model\Registration;
class AccountController extends Controller
{
public function registerAction()
{
$form = $this->createForm(new RegistrationType(), new Registration());
return $this->render('AcmeAPPBundle:Account:register.html.twig', array('form' => $form->createView()));
}
public function createAction()
{
$em = $this->getDoctrine()->getEntityManager();
$form = $this->createForm(new RegistrationType(), new Registration());
$form->handleRequest($this->getRequest());
if ($form->isValid()) { // FIXME !!
$registration = $form->getData();
$em->persist($registration->getUser());
$em->flush();
return $this->redirect($this->generateUrl('home'));
}
return $this->render('AcmeAPPBundle:Account:register.html.twig', array('form' => $form->createView()));
}
}
I guess the error I get might be caused by the fact that the Registration Form is validated, but the User Form within isn't submitted to validation. Am I wrong ?
How can I simply change that behaviour ? I saw there is a cascade_validation option but it seems to be useless here.
I think it's strange that Symfony Cookbook provides both guides to create a user provider and create a registration form but does not explain how to get those work along.
I finally found what the acutal problem was.
The validation was processed only on the RegistrationType instance but not on the UserType within.
To make sure that the validation also checks the constraints for the user I added the following code to my RegistrationType class :
public function setDefaultOptions(Options ResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Acme\APPBundle\Form\Model\Registration',
'cascade_validation' => true,
));
}
What changes everything is the cascade_validation option that must be set to true for this class while this option is set on the UserType class in the CookBook example.
Also, don't forget to :
use Symfony\Component\OptionResolver\OptionsResolverInterface
in the file where you define the setDefaultOptions.

Error while persisting data into database in symfony2

I have created an update password form and whenever I try to submit the data I got error like The class XXX was not found in the chain configured namespaces. What am I doing wrong in here? The error occurs when I try to save the data in the database. I have tried the answer from implementing update password
Here are my codes.
This is my ChangePasswordType.php
<?php
namespace RetailMapping\Bundle\UserBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class ChangePasswordType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('oldPassword', 'password');
$builder->add('newPassword', 'repeated', array(
'type' => 'password',
'invalid_message' => 'The password fields must match.',
'required' => true,
'first_options' => array('label' => 'Password'),
'second_options' => array('label' => 'Repeat Password'),
));
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'RetailMapping\Bundle\UserBundle\Form\Model\ChangePassword',
));
}
/**
* #return string
*/
public function getName()
{
return 'retailmapping_bundle_userbundle_password_chnage';
}
}
This is my ChangePassword.php
<?php
namespace RetailMapping\Bundle\UserBundle\Form\Model;
use Symfony\Component\Security\Core\Validator\Constraints as SecurityAssert;
use Symfony\Component\Validator\Constraints as Assert;
class ChangePassword
{
/**
* #SecurityAssert\UserPassword(
* message = "Wrong value for your current password"
* )
*/
protected $oldPassword;
/**
* #Assert\Length(
* min = 6,
* minMessage = "Password should by at least 6 chars long"
* )
*/
protected $newPassword;
public function setOldPassword($oldPassword)
{
$this->oldPassword = $oldPassword;
}
public function getOldPassword()
{
return $this->oldPassword;
}
public function setNewPassword($newPassword)
{
$this->newPassword = $newPassword;
}
public function getNewPassword()
{
return $this->newPassword;
}
}
This is my UserController.php
<?php
namespace RetailMapping\Bundle\UserBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use RetailMapping\Bundle\UserBundle\Form\ChangePasswordType;
use Symfony\Component\HttpFoundation\Request;
use RetailMapping\Bundle\UserBundle\Form\Model\ChangePassword;
class UserController extends Controller
{
public function editPasswordAction(Request $request)
{
$form = $this->createForm(new ChangePasswordType(), new ChangePassword());
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$data = $form->getData();
$form->getData();
$em = $this->getDoctrine()->getManager();
$em->persist($data);
$em->flush();
dump($form->getData());
die;
}
return $this->render('User/editPassword.html.twig', [
'form' => $form->createView(),
]);
}
}
By default your entity is mapped to Entity namespace.
DoctrineExtension code on github
protected function getMappingObjectDefaultName()
{
return 'Entity';
}
You need to place your ChangePassword.php within Entity folder.
UPDATE:
Similar question - you can look at

Reduce the number of request in form Symfony2

I have a form type and an other form type include the first one in one of his fields.
The second form type is used to display a list of entities
The first form type:
<?php
namespace Test\GameBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Doctrine\ORM\EntityRepository;
class CityType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('nameEn')
->add('latitude')
->add('longitude')
->add('country','entity',array(
'class' => 'GeoQuizzGameBundle:Country',
'property' => 'nameEn',
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBuilder('c')
->orderBy('c.nameEn', 'ASC');
},
))
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Test\GameBundle\Entity\City'
));
}
/**
* #return string
*/
public function getName()
{
return 'test_gamebundle_city';
}
}
The second entity:
namespace Test\AdminBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Test\GameBundle\Form\CityType;
class CityListType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('cities','collection', array(
'type'=>new CityType(),
'allow_add' => true,
'by_reference' => false
))
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Test\AdminBundle\Entity\CityList'
));
}
/**
* #return string
*/
public function getName()
{
return 'test_adminbundle_citylist';
}
}
and the form creation in the controller:
public function listAction(Request $request)
{
$cityRepository = $this->getDoctrine()->getRepository("GeoQuizzGameBundle:City");
//get continents
$cities = $cityRepository->findBy(
array(),
array('nameEn' => 'ASC')
);
$cityList = new CityList();
foreach($cities as $city){
$cityList->addCity($city);
}
$form = $this->createForm(new CityListType(),$cityList);
$form->handleRequest($request);
if($form->isValid()){
$em = $this->getDoctrine()->getManager();
foreach ($cityList->getCities() as $city){
if(!$this->isCity($cities, $city)){
$em->persist($city);
}
}
$em->flush();
return $this->redirect($this->generateUrl('geo_quizz_admin_city_list'));
}
return $this->render('GeoQuizzAdminBundle:City:list.html.twig',array(
'form' => $form->createView()
));
}
I have 196 request for 124 fields because the country list is requery on each row, is there a solution to prevent it ?
I can do the query in the controller and pass my country array as argument of the form type, is it clean ?
You can use choice field type instead of entity. All you need to do is have choices parameter containing your list of countries.
$countryChoices is an associative array of countries which you can fetch once and use it in buildForm method. The way I would do that is making your form a service, and passing ObjectManager to contructor:
services.yml:
services:
your_form:
class: Test\GameBundle\Form\CityListType
arguments: [#doctrine.orm.entity_manager]
tags:
- { name: form.type, alias: yourFormAlias }
Your CityType class:
class CityType extends AbstractType
{
/**
* #param ObjectManager $objectManager
*/
public function __construct(ObjectManager $objectManager)
{
$this->objectManager = $objectManager;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$countryChoices = array();
//by using result cache your query would be performed only once
$countries = $this->objectManager
->getRepository('GeoQuizzGameBundle:Country')
->createQueryBuilder('c')
->orderBy('c.nameEn', 'ASC')
->getQuery()
->useResultCache(true)
->getResult();
foreach($countries as $country) {
$countryChoices[$country->getId()] = $country->getNameEn();
}
$builder
->add('country','choice',array(
'choices' => $countryChoices,
'label' => 'Country',
))
;
}
}
You will also need to start call your form like a service.

How to get symfony 2 forms to return entities from a dynamic value

Ok here is a quick overview of what I am trying to do. I have a "Client" entity with a relationship to a "ClientDomain" entity. I need to have a form that will show me a list of all the ClientDomains for a given client. In the controller I know what client i need to filter for but im unsure how to pass that information to the formBuilder.
Heres what i have so far:
//src/NameSpace/ClientBundle/Entity/Client.php
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
*/
class Client{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $client_id;
/**
* #ORM\Column(type="string")
*/
protected $name;
/**
* #ORM\OneToMany(targetEntity="ClientDomain", mappedBy="client")
*/
protected $domains;
...
}
And the form:
//src/LG/ClientBundle/Form/ClientDomainSelectionForm.php
namespace LG\ProjectBundle\Form\Projects;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class ClientDomainSelectionForm extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('client_domain', 'entity', array(
'class' => 'LG\ClientBundle\Entity\ClientDomain',
'query_builder'=> function(EntityRepository $er) {
return $er->createQueryBuilder('cd')
/* NEEDS TO FIND DOMAINS BY CLIENT X */
},
'property' => 'domain',
'label' => 'Domain: '
));
}
}
And then finally the controller:
//src/LG/ClientBundle/Controller/DomainSelectorController.php
namespace LG/ClientBundle/Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use LG\ClientBundle\Entity\Client;
use LG\ClientBundle\Entity\ClientDomain;
use LG\ClientBundle\Entity\ClientActiveDomain;
use LG\ClientBundle\Form\ClientDomainSelectionForm;
/**
* #Route("")
*/
class DomainSelectorController extends Controller{
/**
* #Route("/client/{client_slug}/select-domain", name="lg.client.clientdomainselection.selectclient")
* #Template
*/
public function selectDomainAction(Request $request, Client $client){
$activeDomain = new ClientActiveDomain();
$form = $this->createForm(new ClientDomainSelectionForm(), $activeDomain );
if ($request->isMethod('POST')) {
$form->bind($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getEntityManager();
$em->persist($activeDomain );
$em->flush();
return $this->redirect(/*huge long url*/);
}
}
return array(
'form' => $form->createView(),
);
}
}
As you can see I have access to the client entity in the controller im just not sure how to give that to the form builder so that it will only return domains for the current client.
I Have found the answer, you just need to add a constructor to the form and pass in the client from the controller like so:
//src/LG/ClientBundle/Form/ClientDomainSelectionForm.php
namespace LG\ProjectBundle\Form\Projects;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class ClientDomainSelectionForm extends AbstractType {
protected $client;
public function __construct(Client $client) {
$this->client = $client;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$client = $this->client;
$builder->add('client_domain', 'entity', array(
'class' => 'LG\ClientBundle\Entity\ClientDomain',
'query_builder'=> function(\Doctrine\ORM\EntityRepository $er) use ($client) {
return $er->createQueryBuilder('cd')
->where('cd.client = :client')
->orderBy('cd.domain', 'ASC')
->setParameter('client',$client->getClientId());
},
'property' => 'domain',
'label' => 'Domain: '
));
}
}
And Then in the controller:
//src/LG/ClientBundle/Controller/DomainSelectorController.php
...
public function selectDomainAction(Request $request, Client $client){
...
$form = $this->createForm(new ClientDomainSelectionForm($client), $activeDomain );
...
}
...

Categories