Symfony2 FOSUserBundle merge resetPasswordform with custom form - php

I am trying to create a form by merging 2 form types as following.
Teacher Entity that has a one to one relation with User Entity.
I am using FOSUserBundle and i want to merge the ResettingFormType with my custom TeacherFormType, to end up with a form that both fields from my custom & fos reset password form.
1- Teacher Entity:
/**
* #var \User
*
* #ORM\OneToOne(targetEntity="ITJari\UserBundle\Entity\User", fetch="EAGER")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*
*/
private $user;
public function getUser() {
return $this->user;
}
public function setUser($user) {
$this->user = $user;
return $this;
}
2- Extending FOS Reset password:
namespace ITJari\SchoolBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class ResettingFormType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
}
public function getParent() {
return 'fos_user_resetting';
}
public function getName() {
return 'ragab';
}
}
3- Teacher Form Type
namespace ITJari\SchoolBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class TeacherFormType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
}
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array(
'data_class' => 'ITJari\SchoolBundle\Entity\Teacher',
));
}
public function getParent() {
return 'fos_user_resetting';
}
public function getName() {
return 'teacherform';
}
}
4- Inside controller:
$teacher = new \ITJari\SchoolBundle\Entity\Teacher();
$teacher->setUser($user);
$form = $this->createForm('teacherform', $teacher);
But i got the following error:
Neither the property "plainPassword" nor one of the methods "getPlainPassword()", "isPlainPassword()", "hasPlainPassword()", "__get()" exist and have public access in class "ITJari\SchoolBundle\Entity\Teacher".
500 Internal Server Error - NoSuchPropertyException

Related

Symfony3 form: View transformer error suggests using view transfomer

I wanted to create a simple HiddenEntityType, so that I can have hidden form fields that represent an entity. The simplest solution by far looked to be to employ a (view) transformer.
However I cannot see to get it to work.
Based on documentation here
...the forward transform needs to return something you can put into HTML, a string(e.g. the id of my entity) and the reverseTransform must transform an id into an entity.
With that in mind here is the simple class I made:
namespace AppBundle\Form\Type;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\CallbackTransformer;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class HiddenEntityType extends AbstractType
{
/**
* #var EntityManagerInterface
*/
private $entityManager;
/**
* Constructor
* #param EntityManagerInterface $entityManager
*/
public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}
/**
* #inheritDoc
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$repository = $this->entityManager->getRepository($builder->getDataClass());
$builder->addViewTransformer(new CallbackTransformer(
function ($entity) use($repository) { //Forward
dump('Forward');
dump($entity);
if (!is_null($entity)) return $entity->getId();
return $entity;
},
function ($id) use($repository) { //Reverse
dump('Reverse');
dump($id);
return $repository->find($id);
}
));
}
/**
* #inheritDoc
*/
public function getParent()
{
return 'hidden';
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => null,
]);
}
}
I receive the following illogical error:
An exception has been thrown during the rendering of a template ("The form's view data is expected to be an instance of class AppBundle\Entity\MyEntity, but is a(n) integer. You can avoid this error by setting the "data_class" option to null or by adding a view transformer that transforms a(n) integer to an instance of AppBundle\Entity\MyEntity.").
When creating the form, based on the dumps you see above, the forward transform is called twice - once with null and once with the AppBundle\Entity\MyEntity as its argument.
What might I be doing wrong?
Sy 3.3.6
PHP 7.1.8

The autoloader expected class

I created code for tags in symfony but I have this bug:
The autoloader expected class "Tag\TagBundle\Form\Types\TagsType" to be defined in file "/var/www/html/TagProject/vendor/composer/../../src/Tag/TagBundle/Form/Types/TagsType.php". The file was found but the class was not in it, the class name or namespace probably has a typo.
TagsType.php:
<?php
namespace Tag\TagBundle\Form\Types;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Tag\TagBundle\Form\DataTransformer\TagsTransformer;
use Symfony\Bridge\Doctrine\Form\DataTransformer\CollectionArrayTransformer;
use Symfony\Component\Form\FormBuilderInterface;
class TagsTypes extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options){
$builder
->addModelTransformer(new CollectionArrayTransformer(),true)
->addModelTransformer(new TagsTransformer(),true);
}
public function getParent(){
return TextType::class;
}
}
}
TagsTransformer.php:
<?php
namespace Tag\TagBundle\Form\DataTransformer;
use Symfony\Component\Form\DataTransformerInterface;
class tagsTransformer implements DataTransformerInterface {
public function transform($value){
dump($value);
return "";
}
public function reverseTransform($value){
}
}
PostType.php:
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Tag\TagBundle\Form\Types\TagsType;
class PostType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name')
->add('content')
->add('tags',TagsType::class);
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Post'
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'appbundle_post';
}
}
Your error is naming class.
You have TagsType.php is php file and your class name is TagsTypes:
You have to change class name:
class TagsTypes
to
class TagsType

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.

Calling class using service in Form

I have a question about service and Form in Symfony2,so I created my calss form and I hope to add a multiselect list of cities then I want to get list of cities from another class "city",so how I can call my class "city" in my form using "Service" to get a function "getcities" to return me a list of cities? (I dont use Doctrine here)...
Edit
namespace Acme\DemoBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class CityType extends AbstractType
{
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'choices' => array( /**
* Here I will call function getcities(return list of cities)
*/
)
));
}
public function getParent()
{
return 'choice';
}
public function getName()
{
return 'gender';
}
}
class City.php :
Class City {
/**
* here i will get list of cities
*/
public function getcities()
{
.....
return $Listcities;
}
}
So I would like to use "Service" to call function "getcities" in form?
The form objects are not container-aware...at least, they're not meant to be. That said, your controller should use the service to get the cities, and then it should pass that list into the form object either through a constructor or a method.
Controller:
class SomethingController
{
public function someAction()
{
...
$cities = $this->get("citiesService")->getCities();
$form = $this->createForm(new SomeType($cities), $someEntity);
...
}
}
Form:
class SomeType extends AbstractType
{
private $cities;
public function __construct($cities)
{
$this->cities = $cities;
}
public function buildForm(FormBuilder $builder, array $options)
{
// Now you have access to $this->cities, so you can use it to build the form
}
}
Do you can set City object as form data object?
so it can looks like that...
$form = $this->createForm(new SomeType(), new City());
class SomeType extends AbstractType
{
public buildForm(FormBuilderInterface $builder, array $options)
{
$formFactory = $builder->getFormFactory();
$builder->addEventListener(
FormsEvents::PRE_SET_DATA,
function (FormEvent $event) use ($formFactory) {
$event->getForm()->add(
$formFactory->createNamed(
'gender',
'choice',
null,
array(
'choices' => $event->getData()->getCites()
)
)
);
}
);
}
}

Form embedded for many to many & many to one in symfony2.

I have a problem when I try to embed a form in Symfony2 for many to many relations or many to one relations.
I have two entities called 'Address' and 'AddressType' and they are related as you can see on code below.
What I tried to do is when I created a form for Address, I embedded the form for AddressType. I've already tried embedding a collection of AddressType to Address form, but when I try to embed the result of this to Address it seems not to work.
Address Entity
namespace Webmuch\ProductBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
*/
class Address
{
protected $id;
protected $line1;
protected $line2;
protected $state;
protected $city;
protected $zip;
protected $country;
protected $phone;
/**
* #ORM\ManyToOne(targetEntity="AddressType")
* #ORM\JoinColumn(name="address_type_id", referencedColumnName="id")
*/
protected $type;
public function __construct()
{
$this->type = new ArrayCollection();
}
/**
* Set type
*
* #param Webmuch\ProductBundle\Entity\AddressType $type
*/
public function setType(\Webmuch\ProductBundle\Entity\AddressType $type)
{
$this->type = $type;
}
/**
* Get type
*
* #return Webmuch\ProductBundle\Entity\AddressType
*/
public function getType()
{
return $this->type;
}
}
AddressType Entity:
namespace Webmuch\ProductBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
*/
class AddressType
{
protected $id;
protected $title;
public function __construct()
{
$this->title = false;
}
}
In form section->
form
AddressType:
namespace Webmuch\AdminBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
class AddressType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('line1')
->add('line2')
->add('city')
->add('zip')
->add('country')
->add('phone')
->add('type','collection', array( 'type' => new AddressTypeType(),
'allow_add' => true,
'prototype' => true,
'by_reference' => false,
));
}
public function getDefaultOptions(array $options)
{
return array('data_class' => 'Webmuch\ProductBundle\Entity\Address');
}
public function getName()
{
return 'address';
}
}
AddressTypeType:
namespace Webmuch\AdminBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
class AddressTypeType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('title');
;
}
public function getDefaultOptions(array $options)
{
return array(
'data_class' => 'Webmuch\ProductBundle\Entity\AddressType',
);
}
public function getName()
{
return 'addresstypetype';
}
}
Controller Section->
namespace Webmuch\AdminBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Webmuch\ProductBundle\Entity\Address;
use Webmuch\AdminBundle\Form\AddressType;
/**
* Address controller.
*
* #Route("/cusadmin/address")
*/
class AddressController extends Controller
{
/**
* Displays a form to create a new Address entity.
*
* #Route("/new", name="admin_address_new")
* #Template()
*/
public function newAction()
{
$entity = new Address();
$form = $this->createForm(new AddressType(), $entity);
return array(
'entity' => $entity,
'form' => $form->createView()
);
}
}
I've spent the whole day stuck with this and I have tried a lot of things but I couldn't manage get it working.
Any help is appreciated!
Thanks
Edit form AddressType: nd write this code,may be this is help full....
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('line1')
->add('line2')
->add('city')
->add('zip')
->add('country')
->add('phone')
->add('type','entity', array('class'=>'WebmuchProductBundle:AddressType','property'=>'value','multiple'=>true
));

Categories