I'm creating new invoice form, which includes select input with some constant values.
I've made it through services:
services.yml
parameters:
stawki_vat:
0: 0%
5: 5%
8: 8%
23: 23%
zw: zw.
services:
acme.form.type.stawki_vat:
class: Acme\FakturyBundle\Form\Type\StawkiVatType
arguments:
- "%stawki_vat%"
tags:
- { name: form.type, alias: stawki_vat }
StawkiVatType.php
class StawkiVatType extends AbstractType
{
private $stawkiVatChoices;
public function __construct(array $stawkiVatChoices) {
$this->stawkiVatChoices = $stawkiVatChoices;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'choices' => $this->stawkiVatChoices,
));
}
public function getParent()
{
return 'choice';
}
public function getName()
{
return 'stawki_vat';
}
}
TowarType.php
class TowarType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('nazwa_towar', null, array('label' => 'Nazwa towaru/usługi'))
->add('cena_netto', null, array(
'label' => 'Cena netto'
))
->add('vat', 'stawki_vat', array(
'attr' => array('class' => 'styled'),
'label' => 'Stawka VAT',
))
;
}
In form, everything works perfect.
But now, I want to get a value stored in database (key of stawki_vat) and show a value of stawki_vat array.
How to achieve this in simple way?
You need to pass your entity manager to your custom form type service. Presuming you are using Doctrine:
services.yml
services:
acme.form.type.stawki_vat:
class: Acme\FakturyBundle\Form\Type\StawkiVatType
arguments: ["#doctrine.orm.entity_manager","%stawki_vat%"]
StawkiVatType.php
class StawkiVatType extends AbstractType
{
private $stawkiVatChoices;
private $em;
public function __construct(EntityManager $em, array $stawkiVatChoices) {
$this->em = $em;
$this->stawkiVatChoices = $stawkiVatChoices;
}
// ...
Related
I have three classes (User, Professionel and Simple, where Professionel and Simple are the children of User). I use inheritance mapping like this:
#[ORM\Entity(repositoryClass: UserRepository::class)]
#[ORM\InheritanceType("JOINED")]
#[ORM\DiscriminatorColumn(name:"compte", type: "string")]
#[ORM\DiscriminatorMap(["professionnel"=>Professionel::class, "simple"=> Simple::class])]
class User implements UserInterface, PasswordAuthenticatedUserInterface
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private $id;
#[ORM\Column(type: 'string', length: 180, unique: true)]
#[Assert\NotBlank()]
#[Assert\Length(min:2, max:80)]
private $email;
#[ORM\Column(type: 'string', length: 50)]
private $typeCompte;
}
class Professionel extends User
{
private $nameProfessionel;
//getter setter
}
class Simple extends User
{
private $name;
//getter setter
}
I have generated formtype for each entity and extended SimpleType and ProfessionelType like this:
class SimpleType extends UserFormType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('name')
;
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Simple::class,
]);
}
}
class ProfessionelType extends UserFormType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('nameProfessionel');
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Professionel::class,
]);
}
}
What I want to do is whenever the user clicks on a radio button (Simple or Professionel), to only show the form that fits.
I have tried to build the form in the controller:
$types = [
'parentForm' => UserFormType::class,
'partForm' => SimpleType::class,
'proForm' => ProfessionelType::class,
];
$forms = [];
foreach ($types as $type1) {
$forms[] = $this->createForm($type1);
}
but I have this error :
Could not load type "App\Form\ChoiceType": class does not exist.
This is the first time I am working with EventListener of a form so I am struggling on how to inject EntityManager in it.
I have this formType called UserType and in this class I have an EventSubscriber AddDepartmentDegreeCourseFieldSubscriber which needs access to EntityManager
class UserType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addEventSubscriber(new AddProfileFieldSubscriber());
$builder->addEventSubscriber(new AddDepartmentDegreeCourseFieldSubscriber());
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\User'
));
}
}
This is my services.yml
app.department_course_degree_subscriber:
class: AppBundle\Form\EventListener\AddDepartmentDegreeCourseFieldSubscriber
arguments: ["#doctrine.orm.entity_manager"]
tags:
- { name: kernel.event_subscriber }
The error I get is as following
Catchable Fatal Error: Argument 1 passed to
AppBundle\Form\EventListener\AddDepartmentDegreeCourseFieldSubscriber::__construct()
must be an instance of Doctrine\ORM\EntityManager, none given, called
in /Users/shairyar/Sites/oxford-portal/src/AppBundle/Form/UserType.php
on line 21 and defined
I know what the error means but I thought the service i registered in services.yml should inject the EntityManager so why I am getting this error? What am i missing here? Any help will be really appreciated.
It's because, you pass new instance of AddDepartmentDegreeCourseFieldSubscriber when building form. You need to pass instance from service container.
use AppBundle\Form\EventListener\AddDepartmentDegreeCourseFieldSubscriber;
class UserType extends AbstractType
{
private $addDepartmentDegreeCourseFieldSubscriber;
public function __construct(AddDepartmentDegreeCourseFieldSubscriber $subscriber)
{
$this->addDepartmentDegreeCourseFieldSubscriber = $subscriber;
}
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addEventSubscriber($this->addDepartmentDegreeCourseFieldSubscriber);
}
}
# app/config/services.yml
services:
app.department_course_degree_subscriber:
class: AppBundle\Form\EventListener\AddDepartmentDegreeCourseFieldSubscriber
arguments: ["#doctrine.orm.entity_manager"]
tags:
- { name: kernel.event_subscriber }
app.form.type.my_user_form:
class: AppBundle\Form\UserType
arguments: [ "#app.department_course_degree_subscriber" ]
tags:
- { name: form.type }
tl;dr:
Is there any way to have the 'context' option auto-cascade through all form types ? It would NOT be leasable to pass it along manually in the form types like this:
$builder->add('organizer', 'organizer_type', array('context' => $options['context']));
Hello everybody,
I have written an extension to ALL Symfony form types:
class ContextExtension extends AbstractTypeExtension
{
protected $context;
public function __construct(SecurityContextInterface $context)
{
$this->context = $context->getToken()->getUser()->getContext();
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults([
'context' => $this->context
]);
$resolver->setAllowedTypes(['context' => 'GOC\Bundle\FrameworkBundle\Model\ContextInterface']);
}
/**
* Returns the name of the type being extended.
*
* #return string The name of the type being extended
*/
public function getExtendedType()
{
return 'form';
}
}
I have validated that it is registered and working (for the most part). I only face one problem. When I set my new option ('context') in a form type like this:
class EventType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add(
'eventgroup', 'eventgroup_type', array(
'context' => $context,
)
)
}
public function getName()
{
return 'event';
}
}
I receive the option in the event group form type and can work with it there:
class EventGroupType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$this->log($options['context']);
$builder
->add('name', 'text')
->add('comment', 'text')
->add('organizer', 'organizer_type')
;
}
public function getName()
{
return 'eventgroup_type';
}
}
However, it appears that the options does not cascade any further and is therefore not usable in the text or organizer type. Is there any way to have the 'context' option auto-cascade through all form types ? It would NOT be leasable to pass it along manually in the form types like this:
$builder->add('organizer', 'organizer_type', array('context' => $options['context']));
As it stands isValid() returns true on form submission regardless of whether the fields have been filled out or not. The objective is to get isValid() method to actually check the data. Any help would be much appreciated.
Form Entity:
namespace Bookboon\Premium\AppBundle\Entity;
class Form {
protected $email;
protected $id,
$type,
$voucher,
$subscription,
$affiliate;
public function getEmail(){
return $this->email;
}
public function setEmail($email){
$this->email = $email;
}
// The rest of the getters & setters have been omitted for ease of reading, but they look very similar to the above.
}
services.yml:
services:
form.builder:
class: Symfony\Component\Form\FormBuilder
arguments: ['SignUpForm', 'Bookboon\Premium\AppBundle\Entity\Form', #event_dispatcher, #form.factory]
premium.form.entity:
class: Bookboon\Premium\AppBundle\Entity\Form
arguments: [ ]
premium.form.sign_up:
class: Bookboon\Premium\AppBundle\Form\SignUpFormType
tags:
- { name: form.type, alias: SignUpForm }
premium.controller.signup:
class: Bookboon\Premium\AppBundle\Controller\SignUpController
arguments: [#templating, #form.builder, #premium.form.sign_up, #form.factory, #premium.form.entity ]
validation.yml:
Bookboon\Premium\AppBundle\Entity\Form:
properties:
email:
- NotBlank: ~
- NotNull: ~
SignUpController.php:
namespace Bookboon\Premium\AppBundle\Controller;
use Bookboon\Premium\AppBundle\Entity\Form;
use Bookboon\Premium\AppBundle\Form\SignUpFormType;
use Bookboon\Premium\AppBundle\Form\SignUpDetailsForm;
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Form\FormFactory;
class SignUpController implements DetectionController
{
private $_templating;
private $_formBuilder;
private $_form;
private $_formFactory;
private $_formData;
public function __construct(EngineInterface $templating, FormBuilder $formBuilder, SignUpFormType $signUpFormType, FormFactory $formFactory, Form $formData)
{
$this->_templating = $templating;
$this->_formBuilder = $formBuilder;
$this->_form = $signUpFormType;
$this->_formFactory = $formFactory;
$this->_formData = $formData;
}
public function signUpDetailsAction()
{
return $this->renderForm('SignUpDetailsForm', new SignUpDetailsForm(), 'details');
}
public function signUpAction(Request $request)
{
$form = $this->createForm($this->_form, $this->_formData);
$form->handleRequest($request);
if($request->getMethod() == 'POST'){
if($form->isValid()){
dump('Form Is Valid!');
}
return $this->renderForm($form->createView(), 'signup');
}
return $this->renderForm($form->createView(), 'signup');
}
public function renderForm($form, $type)
{
return $this->_templating->renderResponse( 'PremiumBundle:Connect:'.$type.'.html.twig', array('form'=>$form));
}
public function createForm($type, $data = null, array $options = array())
{
return $this->_formFactory->create($type, $data, $options);
}
}
SignUpFormType:
namespace Bookboon\Premium\AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Bookboon\Premium\AppBundle\Entity;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class SignUpFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('email', 'text', array('label'=>' ',
'attr' => array('placeholder'=>'Your email', 'class'=>'email')))
->add('save', 'submit', array( 'label'=>'Access Premium',
'attr'=>array('class'=>'btn btnProceed'),
'validation_groups' => true))
->add('facebook', 'submit', array( 'validation_groups' => false,
'attr' =>array('class'=>'btn btnFacebook cancel')))
->add('linkedin', 'submit', array( 'validation_groups' => false,
'attr' =>array('class'=>'btn btnLinkedIn cancel')))
->add('id', 'hidden')
->add('type', 'hidden')
->add('voucher', 'hidden');
}
public function getName()
{
return 'SignUpForm';
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Bookboon\Premium\AppBundle\Entity\Form',
));
}
}
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.