Symfony bug with forms - php

I am experiencing the following form error in Symfony:
Neither the property "email" nor one of the methods "email()", "getemail()"/"isemail()"/"hasemail()" or "__call()" exist and have public access in class "Symfony\Component\Form\FormView".
This is what my form looks like:
My App\Form\LostPasswordType:
namespace App\Form;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use App\Entity\LostPassword;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\AbstractType;
class LostPasswordType extends AbstractType
{
public function builder(FormBuilderInterface $builder, array $options)
{
$builder
->setAction('/forgotpw')
->setMethod('POST')
->add('mail', EmailType::class, [
'required' => true,
'label' => false,
'attr' => [
'autofocus' => false,
'class' => 'span8',
'placeholder' => 'example#example.com'
]
])
->add('submit', SubmitType::class, [
'label' => 'Reset Password',
'attr' => ['class' => 'btn btn-primary btn-green']
])
;
}
public function configureOption(OptionsResolver $resolver)
{
$resolver->setDefaults(['data_class' => LostPassword::class]);
}
}
And this is my controller code:
$formReset = $this->createForm(
LostPasswordType::class,
$forgotpass,
array('csrf_protection' => false)
);
$formReset->handleRequest($request);
Does anyone know why I am receiving this error?

I fixed the problem by changing the method function name in form builder, it was mistake there.

Related

Symfony on click adding a form row

I'm trying to make a form with Symfony to be able to adding new row by clicking button. I can't use SubmitType class because after submit symfony can't add new row. ButtonType class doesn't have a basic function isClicked(). Here is my Form:
<?php
namespace App\Form;
use App\Entity\Team;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\Extension\Core\Type\ButtonType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
final class TeamFormType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('teamName', TextType::class, [
'label' => false,
'attr' => array(
'placeholder' => 'Wpisz Nazwe Drużyny'
)
])
->add('teamCity', TextType::class, [
'label' => false,
'attr' => array(
'placeholder' => 'Wpisz Nazwe Miasta'
)
])
->add('teamCoach', TextType::class, [
'label' => false,
'attr' => array(
'placeholder' => 'Wpisz Imie i Nazwisko Trenera'
)
]);
$builder->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event){
$form = $event->getForm();
for ($i = 1; $i <= 6; $i++) {
$name = 'zawodnik' . $i .'';
$form->add($name, TextType::class, [
'mapped' => false,
'label' => false,
'attr' => array(
'placeholder' => 'Imie i Nazwisko Zawodnika'
)
]);
}
$form->add('agreeTerms', CheckBoxType::class, [
'mapped' => false,
'required' => true,
'label' => 'Zaakceptuj regulamin'
])
->add('Submit', SubmitType::class, [
'label' => 'Wyślij Zgłoszenie'
])
->add('addRow', ButtonType::class, [
'label' => 'Dodaj zawodnika'
]);
});
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Team::class,
'csrf_protection' => true,
'csrf_field_name'=> '_token',
'csrf_token_id' => 'team_item'
]);
}
}
And Controller :
<?php
namespace App\Controller;
use App\Form\TeamFormType;
use Doctrine\DBAL\Types\TextType;
use Doctrine\ORM\EntityManagerInterface;
use http\Env\Request;
use http\Env\Response;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
class FormsController extends AbstractController
{
public function createTeamForm(Request $request, EntityManagerInterface $entityManager) :Response
{
$teamEntity = new Team();
$form = $this->createForm(TeamFormType::class);
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()) {
if($form->get('addRow')->isClicked()) {
$form->add('something', TextType::class, [
'label' => false,
'attr' => array(
'placeholder' => 'Imie i Nazwisko zawodnika.'
)
]);
}
$entityManager->persist($teamEntity);
$entityManager->flush();
$this->addFlash('success', 'Pomyślnie Utworzono Drużyne');
return $this->redirectToRoute('index');
}
}
}
Anyone have a idea to create button like that ?
I suggest you using Javascript and css, create your row and just hide it, then, onClick, let em appear with a JS function that modify the css sheet

How to use a custom type correctly in Symfony?

I am trying to use all the power of Symfony to build a site. I already have 2 years of experience in Symfony but for the first time, I am trying to use the concept of custom form type to create a specific registration form. I already have a registration form for basic users but now, I want to create another one for managers whom operate hotels.
I have already created a form type named RegistrationFormType and another one named HotelType. My thing is that I want to use both of these form types in one form. But I keep getting an exception which says
Neither the property "user" nor one of the methods "getUser()",
"user()", "isUser()", "hasUser()", "__get()" exist and have public
access in class "App\Entity\User"
I have followed whatever was said in the Symfony official documentation about custom form types.
I made this form type RegistrationHotelFormType which is made up of another form RegistrationFormType used elsewhere as a form for basic users to create accounts and HotelType generated by Symfony itself.
<?php
namespace App\Form;
use App\Entity\User;
use App\Form\HotelType;
use App\Form\RegistrationFormType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Validator\Constraints\IsTrue;
use Symfony\Component\Validator\Constraints\Regex;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Validator\Constraints\File;
class RegistrationHotelFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('user', RegistrationFormType::class, ['mapped' => false])
->add('hotel', HotelType::class, ['mapped' => false])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => User::class,
]);
}
}
This above use to work but in the Symfony documentation, I don't need to set a mapped parameter to false knowing that I want form values to be assigned to objects fields which are Hotel and User. How can I get this done? (https://symfony.com/doc/current/form/create_custom_field_type.html#creating-form-types-created-from-scratch).
RegistrationFormType:
<?php
namespace App\Form;
use App\Entity\User;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Validator\Constraints\IsTrue;
use Symfony\Component\Validator\Constraints\Regex;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Validator\Constraints\File;
class RegistrationFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('email', EmailType::class, ['error_bubbling'=>true, 'label' => 'Email', 'attr' => ['type'=>'text','class'=>'form-control', 'placeholder'=>'Email', 'aria-label'=>"Username", 'aria-describedby'=>"basic-addon1"]])
->add('plainPassword', RepeatedType::class, [
'type' => PasswordType::class,
'label' => 'Mot de passe',
'attr' => ['error_bubbling'=>true,
'type'=>'text',
'class'=>'form-control',
'placeholder'=>'Mot de passe',
'aria-label'=>"Username",
'aria-describedby'=>"basic-addon1"],
'mapped' => false,
'constraints' => [
new NotBlank([
'message' => 'Mot de passe requis',
]),
new Length([
'min' => 8,
'minMessage' => 'Le mot de passe doit avoir au moins {{ limit }} caractères',
// max length allowed by Symfony for security reasons
'max' => 128,
'maxMessage' => 'Le mot de passe ne doit pas dépasser {{ limit }} caractères',
]),
// new Regex([
// 'pattern' => '/^\S*(?=\S*[a-z])(?=\S*[A-Z])(?=\S*[\d])\S*$/',
// 'message' => 'Le mot de passe doit contenir au moins 1 lettre et 1 chiffre',
// ])
],
])
->add('firstname', TextType::class, ['error_bubbling'=>true, 'label' => 'Prénom', 'attr' => ['type'=>'text','class'=>'form-control', 'placeholder'=>'Prénom', 'aria-label'=>"Username", 'aria-describedby'=>"basic-addon1"]])
->add('surname', TextType::class, ['error_bubbling'=>true, 'label' => 'Nom', 'attr' => ['type'=>'text','class'=>'form-control', 'placeholder'=>'Nom', 'aria-label'=>"Username", 'aria-describedby'=>"basic-addon1"]])
->add('phoneNumber', TextType::class, ['error_bubbling'=>true, 'label' => 'Téléphone', 'attr' => ['type'=>'text','class'=>'form-control', 'placeholder'=>'Téléphone', 'aria-label'=>"Username", 'aria-describedby'=>"basic-addon1"]])
->add('city', TextType::class, ['error_bubbling'=>true, 'label' => 'Ville', 'attr' => ['type'=>'text','class'=>'form-control', 'placeholder'=>'Ville', 'aria-label'=>"Username", 'aria-describedby'=>"basic-addon1"]])
->add('termsAccepted', CheckboxType::class, [
'error_bubbling'=>true,
'mapped' => false,
'constraints' => new IsTrue(),
'attr' => ['type'=>"checkbox", 'class'=>"form-check-input"]
])
->add('resumePDF', FileType::class, [
'error_bubbling'=>true,
'label' => 'CV (Fichier PDF)',
'mapped' => false,
'required' => true,
'constraints' => [
new File([
'maxSize' => '1024k',
'mimeTypes' => [
'application/pdf',
'application/x-pdf',
],
'mimeTypesMessage' => 'Téléchargez un fichier PDF valide',
])
],
'attr' => ['type'=>"file", 'class'=>"custom-file-input"]
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => User::class,
]);
}
}
HotelType
<?php
namespace App\Form;
use App\Entity\Hotel;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class HotelType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('address');
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Hotel::class,
]);
}
}
RegistrationController.php
/**
* #Route("/inscription-hotel", name="app_register_hotel")
*/
public function registerHotel(Request $request, UserPasswordEncoderInterface $passwordEncoder, \Swift_Mailer $mailer): Response
{
$session = new Session();
// $session->start();
$user = new User();
$form = $this->createForm(RegistrationHotelFormType::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
}
return $this->render('registration/register-hotel.html.twig', [
'registrationForm' => $form->createView(),
]);
}
Thanks in advance for your help
Cerad diagnosed why the error is triggered (the second argument to createForm will be used and the form will try to access the user and hotel property on it), the simplest solution follows:
I would remove the data_class from the combined form, and just omit the second parameter to createForm in your controller. The return value of $form->getData() would be an array:
['user' => {User object}, 'hotel' => {Hotel object}]
(you can also provide a similarly structured array to your createForm call as the second parameter)
of course, you can create a new class that contains both the user and the hotel...

Symfony 4 - Multiple forms of same type with dynamic display fields

I would like to use my UserType form class to register a user and to edit the user profile. As I want to the admins to register a user while setting up their roles, I don't want the user to modify that options. So I would like to use 2 different forms but for the same type User.
Can I create 2 different buildForm() functions in one FormType class ?
Or do I need to create another type ?
Here is my UserType class (main purpose was to register a user) :
<?php
namespace App\Form;
use App\Entity\User;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\BirthdayType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
class UserType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('firstname', TextType::class)
->add('lastname', TextType::class)
->add('birthdate', BirthdayType::class, array(
'placeholder' => '-'))
->add('email', EmailType::class)
->add('username', TextType::class)
->add('plainPassword', RepeatedType::class, array(
'type' => PasswordType::class,
'first_options' => array('label' => 'password'),
'second_options' => array('label' => 'repeat-password'),
))
->add('roles', ChoiceType::class, [
'multiple' => true,
'expanded' => true, // render check-boxes
'choices' => [
'Administrateur' => 'ROLE_ADMIN',
'Direction' => 'ROLE_MANAGER',
'Comptabilite' => 'ROLE_ACCOUNTING',
'Commercial' => 'ROLE_MARKETING',
'Docteur' => 'ROLE_DOCTOR',
'Client' => 'ROLE_CLIENT',
],
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => User::class,
));
}
}
You can use a variable to dynamically add the roles to the formType
public function buildForm(FormBuilderInterface $builder, array $options)
{
$this->is_admin = $options['is_admin'];
// [...]
if ($this->is_admin)
$builder
->add('roles', ChoiceType::class, [
'multiple' => true,
'expanded' => true,
'choices' => [
'Administrateur' => 'ROLE_ADMIN',
'Direction' => 'ROLE_MANAGER',
'Comptabilite' => 'ROLE_ACCOUNTING',
'Commercial' => 'ROLE_MARKETING',
'Docteur' => 'ROLE_DOCTOR',
'Client' => 'ROLE_CLIENT',
],
])
// [...]
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
// [...]
'is_admin' => false,
]);
}
Then pass the variable like
$form = $this->createForm(UserType::class, $user, array(
'is_admin' => $this->isGranted('ROLE_ADMIN'),
);
you can easily handle this using array $optionsin controller set choices of roles and add them to $optionand in userType do something like this:
->add('roles', ChoiceType::class, [
'multiple' => true,
'expanded' => true, // render check-boxes
'choices' => $options['choices'],
])

A2LiX Translation on change language tab get language in form

I need language on change of A2LiX Translation tabs. If I click on "FR" then need to get Fr and on click of "NL" need Nl language in form builder ('Need Language Here').
For querybuilder in one field.
Is it possible to get the language in form type when tab change ?
My Form class MixCampaignTranslationType :
<?php
namespace BackEndBundle\Form;
use BackEndBundle\Validator\Constraints\CampaignSlugDuplicate;
use BackEndBundle\Validator\Constraints\MaxMixCampaign;
use Doctrine\ORM\EntityRepository;
use SurveyBundle\Entity\Survey;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\Type;
class MixCampaignTranslationType extends AbstractType
{
public $campaignId = null;
public function buildForm(FormBuilderInterface $builder, array $options)
{
if (null !== $options['campaignId']) {
$this->campaignId = $options['campaignId'];
}
$builder
->add('surveys', EntityType::class, [
'class' => Survey::class,
'required' => false,
'multiple' => true,
'mapped' => true,
'attr' => [
'class' => 'select2',
],
'constraints' => new MaxMixCampaign(),
])
->add('startDate', DateTimeType::class, [
'widget' => 'single_text',
'format' => 'yyyy-MM-dd',
'constraints' => new NotBlank(),
'attr' => [
'class' => 'datepicker',
],
])
->add('endDate', DateTimeType::class, [
'widget' => 'single_text',
'format' => 'yyyy-MM-dd',
'constraints' => new NotBlank(),
'attr' => [
'class' => 'datepicker',
],
])
->add('slug', TextType::class, [
'constraints' => [new NotBlank(), new Type('string'), new CampaignSlugDuplicate($this->campaignId, $options['locale'], 'mix')],
])
->add('isClosed');
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => 'SurveyBundle\Entity\MixCampaignTranslation',
'locale' => 'fr',
'campaignId' => null
]);
}
public function getName()
{
return 'back_end_bundle_mix_campaign_translation_type';
}
}
You can create your custom TranslationFormType and then pass the language of loop as current language, Please check as below.
/**
* #param \Symfony\Component\Form\FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addEventSubscriber($this->translationsListener);
$formsOptions = $this->translationForm->getFormsOptions($options);
foreach ($options['locales'] as $locale) {
if (isset($formsOptions[$locale])) {
$builder->add($locale, $options['form_type'], [
'currentLanguage' => $locale,
'campaignId' => $formsOptions[$locale]['campaignId']
]
);
}
}
}
and you can use currentLanguage to filter data in query_builder in your form_type.
Hope it will help you.

How do I render a field in an embedded form in twig?

I have a collection that I want to render in my twig template. However I keep getting this ContextErrorException from twig which insinuates, that it's not getting the form view of my form. In my controller I am passing the form as such ...
'formExperience' => $formExperience->createView()
Where formExperience form is shown bellow.
<?php
// Form/CareExperienceForm
namespace Caremonk\MainSiteBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Doctrine\Common\Collections\ArrayCollection;
use Caremonk\MainSiteBundle\Form\CareWorkExperienceForm;
class CareExperienceForm extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('experience','collection',array(
'type' => new CareWorkExperienceForm(),
'allow_add' => true,
'allow_delete' => true));
$builder->add('AddExperience','button', array(
'attr' => array(
'class'=>'experience'
)
));
$builder->add('SaveInfo','button', array(
'attr' => array(
'class' => 'save'
)
));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
// Do nothing for the time being
$resolver->setDefaults(array(
'data_class' => 'Caremonk\MainSiteBundle\Processors\CareExperienceProcessor'
));
}
public function getName()
{
return 'CareExperience';
}
}
I am trying to render the independent fields of the 'experience' object, the class is shown bellow:
<?php
// Form/CareExperienceForm
namespace Caremonk\MainSiteBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Doctrine\Common\Collections\ArrayCollection;
use Caremonk\MainSiteBundle\Entity\WorkExperience;
class CareWorkExperienceForm extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('companyClient','text',
array('required' => true,'label' => 'company / client name',
'attr'=> array(
'class'=>'care_giver_db_register-form-experience-company textbox',
'placeholder'=>'compnay name',
'field'=>'companyClient'),
'label_attr'=> array('class'=>'care_giver_db_register-form-experience-title-company')
));
$builder->add('position','text',
array('required' => true,'label' => 'position',
'attr'=> array(
'class'=>'care_giver_db_register-form-experience-position textbox',
'placeholder'=>'position held',
'field'=>'position'),
'label_attr'=> array('class'=>'care_giver_db_register-form-experience-title-position')
));
$builder->add('description','textarea',
array('required' => true,'label' => 'description',
'attr'=> array(
'class'=>'care_giver_db_register-form-experience-description textarea',
'placeholder'=>'test content',
'field'=>'description'),
'label_attr'=> array('class'=>'care_giver_db_register-form-experience-title-description')
));
$builder->add('startDate','date',
array('required' => true,'label' => 'start date',
'attr'=> array(
'class'=>'care_giver_db_register-form-experience-start date',
'field' => 'startDate'),
'label_attr'=> array('class'=>'care_giver_db_register-form-experience-title-start')
));
$builder->add('endDate','date',
array('required' => true,'label' => 'end date',
'attr'=> array(
'class'=>'care_giver_db_register-form-experience-end date',
'field'=>'endDate'),
'label_attr'=> array('class'=>'care_giver_db_register-form-experience-title-end')
));
$builder->add('currentlyWorkingHere','checkbox',
array('required' => true,'label' => 'i currently work here',
'attr'=> array(
'class'=>'care_giver_db_register-form-experience-current checkbox',
'p-true'=>'yes',
'p-false'=>'no',
'field'=>'currentlyWorkHere'),
'label_attr'=> array('class'=>'care_giver_db_register-form-experience-title-current')
));
$builder->add('ClearInfo','reset',array(
'attr' => array('class' => 'care_giver_db_register-form-experience-cancel-collection'
)
));
$builder->add('DeleteField','button', array(
'attr' => array('class' => 'care_giver_db_register-form-experience-delete-collection deleteForm'),
));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
// Do nothing for the time being
$resolver->setDefaults(array(
'data_class' => 'Caremonk\MainSiteBundle\Entity\WorkExperience'
));
}
public function getName()
{
return 'CareWorkExperience';
}
}
In my twig view, I am doing the following which is giving me errors:
{% for experience in workExperience.experience %}
{{ experience.companyClient }}
{% endfor %}
Symfony however complains of a context error exception which is thrown when it doesn't get the form view. For example its like passing the regular form without doing form->createView() in symfony. How can I render this?

Categories