I have two entities that are connected to each other by doctrine association many-to-one. I created a form collection but when i try to save something it hits me with an error.
The error that i'm getting:
Expected argument of type "Zenith\SurveyBundle\Entity\SurveyOption", "array" given
This is my first form the one that loads the collection.
class TestType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('option', CollectionType::class, [
'entry_type' => SurveyOptionType::class,
'allow_add' => true,
'allow_delete' => true,
'entry_options' => [
'label' => false,
],
])
->add('submit', SubmitType::class, [
'label' => 'Salveaza',
])
;
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => SurveyManager::class
]);
}
}
This is the form loaded by collection:
class SurveyOptionType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('isEnabled', CheckboxType::class, [
'label' => 'Chestionar Activ',
])
->add('headquarter', EntityType::class, [
'class' => HeadQuarterManager::class,
'multiple' => false,
'expanded' => false,
])
->add('userNumber', IntegerType::class, [
'attr' => [
'min' => '1',
'type' => 'number',
],
'label' => 'Numar Utilizatori',
])
;
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => SurveyOption::class
));
}
}
My Controller action:
public function newAction($surveyId, Request $request)
{
$surveyOption = new SurveyOption();
$em = $this->getDoctrine()->getManager();
$surveyRepository = $em->getRepository(SurveyManager::class);
$survey = $surveyRepository->findOneBy(['id' => $surveyId]);
$form = $this->createForm(TestType::class, $survey);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
}
return [
'surveyOption' => $surveyOption,
'form' => $form->createView(),
];
}
The question is useless.. because i'm a hurry and overburned .. i didn't notice few mistakes.. the forms where fine .. :-)
Related
I'm working on a Symfony project and I'm currently encountering a problem with a form that I want to pre-fill from a collection of objects.
The form field in question is of type EntityType::class. I would like to pre-select elements of this field from a collection that contains objects of the same type(Classe).
One of the solutions I found is to add a 'data' => $defaultClass property in the buildForm, which would contain the data to be inserted, and to pass this object in the parameters($options) on the formBuilder.
Unfortunately, the two objects of type Classe do not appear in the field once the form is generated even though the $options variable contains the objects.
Thanks in advance for your help. Here are the codes concerned :
SearchCourseData
<?php
namespace App\Data;
use App\Entity\Classe;
use App\Entity\Teacher;
use App\Entity\Location;
class SearchCourseData
{
/**
* #var integer
*/
public $page = 1;
/**
* #var Classe[]
*/
public $classe = [];
// Missing lines
/**
* #var String
*/
public $status;
}
Code SearchCourseForm
class SearchCourseForm extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$defaultClass = new Classe();
if (!empty($options['data']->classe)) {
$defaultClass = $options["data"]->classe;
}
$builder
->add('classe', EntityType::class, [
'class' => Classe::class,
'label' => false,
'required' => false,
'expanded' => false,
'multiple' => true,
'query_builder' => function (ClasseRepository $qb) {
return $qb->createQueryBuilder('a')->orderBy('a.title', 'ASC');
},
'choice_label' => function (Classe $atelier) {
return($atelier->getTitle());
},
'attr' => [
'placeholder' => 'Atelier',
'class' => 'select-classes'
],
'data' => $defaultClass,
])
>add('status', ChoiceType::class, [
'required' => true,
'choices' => [
'Disponible' => "Disponible",
'Brouillon' => "Brouillon",
'Archivé' => "Archivé"
],
'label' => false,
])
;
}
public function configureOptions(OptionsResolver $resolver) {
$resolver->setDefaults([
'data_class' => SearchCourseData::class,
'method' => 'GET',
'csrf_protection' => false
]);
}
public function getBlockPrefix() {
return '';
}
}
Code CourseController
/**
* #Route("/course")
*/
class CourseController extends AbstractController {
/**
* #Route("/",name="course")
*/
public function courseList(CourseRepository $courseRepository, Request $request) {
$data = new SearchCourseData();
$defaultClassB = $this->getDoctrine()->getRepository(Classe::class)->find(49);
$defaultClassA = $this->getDoctrine()->getRepository(Classe::class)->find(1);
$defaultClass[] = new ArrayCollection();
$defaultClass[0] = $defaultClassA;
$defaultClass[1] = $defaultClassB;
$data->classe = $defaultClass;
$form = $this->createForm(SearchCourseForm::class, $data);
}
}
#V-light is right you are setting a collection in an index of an array - then overwrite it...
$defaultClass[] = new ArrayCollection();
// === $defaultClass[0] = new ArrayCollection();
the correct and easiest way would be:
/**
* #Route("/course")
*/
class CourseController extends AbstractController {
/**
* #Route("/",name="course")
*/
public function courseList(CourseRepository $courseRepository, Request $request) {
$data = new SearchCourseData();
$data->classe = $this->getDoctrine()->getRepository(Classe::class)->findById([49, 1]);
$form = $this->createForm(SearchCourseForm::class, $data);
}
}
EDIT - the corrected form:
'data' of classe gets set by the ModelTransformer automaticly.
class SearchCourseForm extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('classe', EntityType::class, [
'class' => Classe::class,
'label' => false,
'required' => false,
'expanded' => false,
'multiple' => true,
'query_builder' => function (ClasseRepository $qb) {
return $qb->createQueryBuilder('a')->orderBy('a.title', 'ASC');
},
'choice_label' => function (Classe $atelier) {
return($atelier->getTitle());
},
'attr' => [
'placeholder' => 'Atelier',
'class' => 'select-classes'
],
])
>add('status', ChoiceType::class, [
'required' => true,
'choices' => [
'Disponible' => "Disponible",
'Brouillon' => "Brouillon",
'Archivé' => "Archivé"
],
'label' => false,
])
;
}
public function configureOptions(OptionsResolver $resolver) {
$resolver->setDefaults([
'data_class' => SearchCourseData::class,
'method' => 'GET',
'csrf_protection' => false
]);
}
}
I'm trying to build a Order functionality with Symfony 4.4 Forms
I have this, so far
class OrderProductForm extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('customer', EntityType::class, [
'class' => 'App\Entity\Customers',
'choice_label' => 'name',
'label' =>'order_form.name'
])
->add('products', CollectionType::class, [
'entry_type' => ProductQuantityType::class,
'label' => '',
])
->getForm();
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'App\Entity\Order',
));
}
}
and
class ProductQuantityType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('products', EntityType::class, [
'class' => 'App\Entity\Products',
'expanded' => true,
'multiple' => true,
'choice_label' => 'name',
'label' =>''
])
->add('qty', IntegerType::class, [
'label' =>'order_form.qty'
])
->getForm();
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => null,
));
}
}
That won't render Product Quantity because it has no data. Symfony manual does not say how to do it ... CollectionType
What I really want is to add a Quantity Field for each product and at the same time to add as many products as I want.
This is the doctrine structure
Only the relevant code is included
class Order
{
/**
* #ORM\ManyToOne(targetEntity=Customers::class, inversedBy="orders")
* #ORM\JoinColumn(nullable=false)
*/
private $customer;
}
class Customers
{
/**
* #ORM\OneToMany(targetEntity=Order::class, mappedBy="customer", orphanRemoval=true)
*/
private $orders;
}
Any thoughts on how I can move forward with this ?
Thanks !
I have two pages and would like to use one uploadType. When I edit, show the name in the textfield. In NewsController I give the data.
$ EditForm ['upload'] ['filename'] -> setData ($ upload);
This is working. But when i will show the uploadPage and set the data in the uploadType.
'data' => $ build-> getData ()
so is the news textfield empty.
UploadType:
class UploadType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$data = $builder->getData();
if($this->isFieldEnabled('directory',$options)) {
$builder ->add('directory', null, array(
'label' => 'upload.directory',
'required' => true,
)
);
}
$builder->add('name', FileType::class,array(
'label' => 'upload.choice',
'data_class' => null,
'attr' => array(
'class' => 'hidden'
)
));
if($this->isFieldEnabled('filename',$options)) {
$builder->add('filename', 'text',array(
'label' => 'upload.upload',
'data' => $data, //If set, don't show in the news textfield
'mapped' => false,
));
}
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
array(
'data_class' => 'Maiskolben\UploadBundle\Entity\Upload',
'translation_domain' => 'Maiskolben',
'disableFields' => [],
)
);
$resolver->setOptional([
'disableFields',
]);
}
private function isFieldEnabled($fieldName, $options)
{
if (isset($options['disableFields']) && !empty($options['disableFields'])) {
if (in_array($fieldName, $options['disableFields'])) {
return false;
}
}
return true;
}
}
NewsType:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title', TextType::class,array(
'label' => 'news.newsTitle',
))
->add('content','textarea',array(
'label' => 'news.content',
))
->add('upload', new UploadType(), array(
'label' => false,
'required' => false,
'disableFields' => array(
'directory',
)
));
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Maiskolben\NewsBundle\Entity\News',
'translation_domain' => 'Maiskolben',
));
}
}
NewsController:
public function editAction(Request $request, News $news)
{
$upload = $news->getUpload();
$editForm = $this->createForm(new NewsType, $news);
$editForm['upload']['filename']->setData($upload);
$editForm->handleRequest($request);
if ($editForm->isSubmitted() && $editForm->isValid()) {
$em = $this->getDoctrine()->getManager();
//....
I tryed with "addEventListener" in both site. All the same result.
I hope anyone can help me. :)
I have a very simple form (ModuleType.php) calling a collection (ModuleControleType.php).
This code works perfectly (add, modify and delete : no problem), but I want to customize the query for find Description (I just want to add a Where) in ModuleControleType.php.
I can do a query_builder with a field of type " Entity ", but not with a field " Collection " type.
ModuleType.php :
class ModuleType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('point', 'textarea', array(
'label' => 'Point(s) à observer',
'required' => false,
'attr' => array(
'rows' => 5
)
))
->add('controles', 'collection', array(
'label' => false,
'type' => new ModuleControleType(),
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false
))
;
}
ModuleControleType.php :
class ModuleControleType extends AbstractType
{
use Description;
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('description', 'textarea', array(
'label' => 'Description',
'required' => false,
'attr' => array(
'rows' => $rows
)
))
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AdministrationBundle\Entity\ModuleControle',
'intention' => $this->getName() . '_token'
));
}
/**
* #return string
*/
public function getName()
{
return 'administration_module_controle_form';
}
}
I have 2 entities:
TransactionDefaultParametersEntity
Parameter: widgetType
Parameter: defaultParameters (Has one to one relationship with DefaultParametersEntity)
DefaultParametersEntity
Parameter: checkIn
Parameter: checkOut
Parameter: currency
Parameter: adults
The controller provides a collection of TransactionDefaultParametersEntities, and for each I want a form displayed with all DefaultParameterEntity parameters as well as the widgetType parameter provided by the TransactionDefaultParametersEntity.
Currently I have a form type for each entity:
TransactionDefaultParametersFormType
class DefaultSettingsFormType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('defaultParameters', 'collection', ['type' => default_parameters', 'allow_add' => true]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\TransactionDefaultParametersEntity',
'create' => false
));
}
public function getName()
{
return 'transaction_default_parameters';
}
}
DefaultParametersFormType
class DefaultParametersFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('widgetType', 'choice', [
'choices' => [
'Default',
'Booking Engine',
'Informative'
],
'label' => 'Widget Type'
])
->add('checkIn', 'text', ['label' => 'Check In'])
->add('checkOut', 'text', ['label' => 'Check Out'])
->add('currency', 'text', ['label' => 'Currency'])
->add('adults', 'text', ['label' => 'adults']);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\DefaultParametersEntity',
));
}
public function getName()
{
return 'default_parameters';
}
}
And lastly in the controller:
// $transactionDefaultParametersCollection is a collection of TransactionDefaultParameterEntities
$form = $this->createFormBuilder($transactionDefaultParametersCollection)
->add('transactionDefaultParameters', 'transaction_default_settings')
->add('save', 'submit', array('label' => 'Save'))
->getForm();
$form->handleRequest($request);
if ($form->isValid()) {
// do something
}
return $this->render(
'settings/editDefaults.html.twig',
[
'form' => $form->createView()
]
);
If this wasn't clear please let me know :). Also if I could be pointed to an article that would be very helpful. I looked at how to embed a collection of forms but this was a different case than the example provided.