My symfony app have this entity:
<?php
namespace App\Entity;
class Lead
{
private ?string $zipCode;
private ?string $city;
public function getZipCode(): ?string
{
return $this->zipCode;
}
public function setZipCode(string $zipCode): self
{
$this->zipCode = $zipCode;
return $this;
}
public function getCity(): ?string
{
return $this->city;
}
public function setCity(string $city): self
{
$this->city = $city;
return $this;
}
}
And the Form LeadType is :
$builder->add('zipCode', TextType::class, [
'attr' => [
'placeholder' => 'Ex : 44000',
'onchange' => 'cityChoices(this.value)',
]
])
->add('city', ChoiceType::class, [
'choices' => [],
'attr' => ['class' => 'form-control'],
'choice_attr' => function () {return ['style' => 'color: #010101;'];},
]);
When the user enters a zip code, the javascript function cityChoices() add the select options using an external api like:
My problem is in the controller that the form is invalid. Because the user has selected a city that was not offered in the choices of LeadType ('choices' => []).
Here is the error:
0 => Symfony\Component\Form\FormError {#3703 ▼
#messageTemplate: "The selected choice is invalid."
#messageParameters: array:1 [▼
"{{ value }}" => "Bar-le-Duc"
]
How to make the choice valid?
Completly #craight
I add to the form :
->addEventListener(FormEvents::PRE_SUBMIT, function(FormEvent$event){
$form = $event->getForm();
$city = $event->getData()['city'];
if($city){
$form->add('city', ChoiceType::class, ['choices' => [$city => $city]]);
}
})
When pre submit, I update choices and I put only the user select 'choices' => ['Bar-le-Duc' => 'Bar-le-Duc'],
The form becomes valid in the controller
Related
I am currently working on a symfony 6 project where I came across the following problem:
I have to entites "Article" and "ColorPalette". The relationship between the both of these is a ManyToMany Relationship.
Now I have a form for creating new Articles where I have to define between 1 and n colors for the article. The select field uses select2 which works perfectly fine for all relationships beside the many to many one. So when I want to submit the form I get the following error:
Entity of type "Doctrine\Common\Collections\ArrayCollection" passed to
the choice field must be managed. Maybe you forget to persist it in
the entity manager?
I was able to find out that this has something to do with the field for the colorPalette which is a ManyToMany Relation but I could not figure out how to solve the issue.
My Current Code:
Article Entity Code:
/**
* #ORM\Entity(repositoryClass=ArticleRepository::class)
*/
class Article
{
...other properties
/**
* #ORM\ManyToMany(targetEntity=ColorPalette::class, inversedBy="articles")
*/
private $colorPalette;
...other functions
/**
* #return Collection|ColorPalette[]
*/
public function getColorPalette(): Collection
{
return $this->colorPalette;
}
public function addColorPalette(ColorPalette $colorPalette): self
{
if (!$this->colorPalette->contains($colorPalette)) {
$this->colorPalette[] = $colorPalette;
}
return $this;
}
public function removeColorPalette(ColorPalette $colorPalette): self
{
$this->colorPalette->removeElement($colorPalette);
return $this;
}
}
ArticleType Code:
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('title',null, array(
'label' => "title"
))
->add('titleEnglish',null, array(
'label' => "english title"
))
->add('description',null, array(
'label' => "description"
))
->add('stock',null, array(
'label' => "stock"
))
->add('status',ChoiceType::class, [
'label' => "status",
'choices' => [
'Gesperrt' => 'Gesperrt',
'Verfuegbar' => 'Verfuegbar',
'Auslaufartikel' => 'Auslaufartikel',
'Vergriffen' => 'Vergriffen'
],
'attr' => [
'class' => 'dropdown'
]
])
->add('colorPalette', EntityType::class, [
'class' => ColorPalette::class,
'multiple' => true,
'choice_label' => 'title',
'choices' => [],
'attr' => [
'class' => 'dropdown'
],
'label' => 'colors',
])
;
// Add EventSubscribers for specific fields (here: colorPalette)
$builder->addEventSubscriber(new EntityFieldListener($this->colorPaletteRepository,$this->colorPaletteClass,"colorPalette","colorPalette","id","title","colors"));
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Article::class,
]);
}
EntityFieldListener Code:
class EntityFieldListener implements EventSubscriberInterface
{
public function __construct($repository="",$class="",$fieldName="",$table="",$identifier="",$choiceLabel="",$label="") {
$this->repository = $repository;
$this->class = $class;
$this->fieldName = $fieldName;
$this->table = $table;
$this->identifier = $identifier;
$this->choiceLabel = $choiceLabel;
$this->label = $label;
}
public static function getSubscribedEvents(): array {
return [
FormEvents::PRE_SET_DATA => 'onPreSetData',
FormEvents::PRE_SUBMIT => 'onPreSubmit',
];
}
//This Event is used to prepopulate the previous select options for all Select Fields in the corresponding form
public function onPreSetData(FormEvent $event, $test): void
{
// Get the parent form
$form = $event->getForm();
// Get the data for the choice field
$data = $event->getData();
if($data->getId() != null) {
// Get the Id of the currently selected Base Article for the query builder
$functionName = 'get'.ucfirst($this->fieldName);
$selected = $data->$functionName()->getId();
$form->add($this->fieldName, EntityType::class, array(
'class' => $this->class,
'choice_label' => $this->choiceLabel,
'label' => $this->label,
'attr' => [
'class' => 'dropdown'
],
'query_builder' => function () use ($selected){
return $this->repository->createQueryBuilder($this->table)
->where($this->table.'.'.$this->identifier.' = :'.$this->identifier)
->setParameter($this->identifier, $selected);
},
));
}
}
public function onPreSubmit(FormEvent $event) {
// Get the parent form
$form = $event->getForm();
// Get the data for the choice field
$data = $event->getData();
if(isset($data[$this->fieldName]) and $data[$this->fieldName]!=null){
$selected = $data[$this->fieldName];
$form->add($this->fieldName, EntityType::class, array(
'class' => $this->class,
'choice_label' => $this->choiceLabel,
'label' => $this->label,
'attr' => [
'class' => 'dropdown'
],
'query_builder' => function () use ($selected){
//If a parameter is an array then this should be used:
// if(is_array($selected)) {
// $query = $this->repository->createQueryBuilder($this->table);
// $searchQuery="";
// for($i = 0; $i < count($selected); $i++) {
// if($i < count($selected)-1) {
// $searchQuery .= $this->table.'.'.$this->identifier.' = '.$selected[$i].' OR ';
// }
// else {
// $searchQuery .= $this->table.'.'.$this->identifier.' = '.$selected[$i];
// }
// }
// $query->andWhere($searchQuery);
// return $query;
// }
return $this->repository->createQueryBuilder($this->table)
// ->where($this->table.'.id = :id')
->where($this->table.'.'.$this->identifier.' = :'.$this->identifier)
->setParameter($this->identifier, $selected);
},
));
}
}
}
Controller Code (Only the route for inserting new entries):
#[Route('/new', name: 'new', methods: ['GET', 'POST'])]
public function new(Request $request, EntityManagerInterface $entityManager): Response
{
$article = new Article();
$form = $this->createForm(ArticleType::class, $article);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
//insert the new article
$this->entityManager->persist($article);
$this->entityManager->flush();
return $this->redirectToRoute($this->routeName.'_index', [], Response::HTTP_SEE_OTHER);
}
return $this->renderForm($this->routeName.'/new.html.twig', [
$this->routeName => $article,
'form' => $form,
]);
}
JS-Code:
//Imports
import {createSelectPicker} from './components/Select2/SelectPicker';
//Document Ready Function
$(function() {
document.getElementById("page-content").style.visibility = "visible";
createSelectPicker({id:'#article_colorPalette',minimumInputLength:1,multiple:true,selectField:'colorPalette',url:url_from_twig_ajax});
} );
Do you have an Idea how to solve this?
I would appreciate any help. :)
I am using symfony 6 with everything updated to date.
I created a form type with which I intend to receive a url or an image and internally transform the image into a url that will indicate where it is stored on the server, or keep the given url. The idea is to be able to receive one or the other (url or file) and only return as data the new url.
Here is my code:
parent form
class EditProfileForm extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('imgProfile', ImageType::class, [
'required' => false,
'label' => "Profile Image",
'bucket' => 'tw-user-files',
'key' => $options["key"],
'constraints' => [
new File([
'maxSize' => '7M',
'mimeTypes' => [
'image/*'
],
'mimeTypesMessage' => 'That is not a valid image format',
])
],
'setter' => function (User &$user, string $data, FormInterface $form): void {
$user->setImgProfile($data);
}
])
;
}
}
ImageType
class ImageType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$bucketName = $options["bucket"];
$bucket = $this->flySystemS3->getBucket($bucketName);
$constraints = $options["constraints"];
$builder->add('url', UrlType::class, [
'error_bubbling' => false,
'required' => false,
])
->add('file', FileType::class, [
"error_bubbling" => false,
"multiple" => false,
'required' => false,
'attr' => [
'accept' => 'image/*'
],
'constraints' => $constraints
])
->addViewTransformer(new UrlOrFileToImage($bucket, $options["key"]));
}
}
Data tranformer
class UrlOrFileToImage implements DataTransformerInterface
{
public function transform($value)
{
return [
"url" => "",
"file" => null
];
}
public function reverseTransform($value)
{
if (!empty($value["url"])) {
return $value;
}
if (!empty($value["file"])) {
return $this->fileToImage($value["file"]);
}
return "#";
}
private function fileToImage(UploadedFile $file): string
{
$fileName = $this->uploadToServer();
return $fileName;
}
}
the situation is that when validating the parent form I get the error "The file could not be found.", this only happens when validating the parent form, the child form "ImageType" passes all validations and does not generate error.
I debugged it step by step and when I debug it, it passes correctly, the validation is correct and returns everything ok. So I think it is some validation that takes too long, and at the time of debugging gives it a chance to validate it, and when I let it run the code, the validation fails.
I have a CreditCard entity, on form screen there is a dropdown with user's Bank entities and I want to fill BankAccount dropdown according to selected bank dynamically, I have tried couple solutions from SO and added an event listener to my form but when I change the Bank dropdown I get "Integrity constraint violation: kart_adi (credit card name field on entity) cannot be null. I am using Symfony 6 with php 8.1.2
KrediKarti.php:
class KrediKarti
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private $id;
#[ORM\ManyToOne(targetEntity: Banka::class)]
#[ORM\JoinColumn(nullable: false)]
private $banka;
#[ORM\ManyToOne(targetEntity: BankaHesap::class, inversedBy: 'krediKartlari')]
#[ORM\JoinColumn(nullable: false)]
private $hesap;
#[ORM\Column(type: 'string', length: 255)]
private $kart_adi;
#[ORM\Column(type: 'string', length: 255)]
private $kart_no;
#[ORM\Column(type: 'integer')]
private $hesap_kesim_gunu;
#[ORM\Column(type: 'string', length: 255, nullable: true)]
private $aciklama;
#[ORM\Column(type: 'float')]
private $borc;
#[ORM\Column(type: 'float')]
private $alacak;
#[ORM\Column(type: 'datetime_immutable')]
private $created_at;
public function getId(): ?int
{
return $this->id;
}
public function getBanka(): ?Banka
{
return $this->banka;
}
public function setBanka(?Banka $banka): self
{
$this->banka = $banka;
return $this;
}
public function getHesap(): ?BankaHesap
{
return $this->hesap;
}
public function setHesap(?BankaHesap $hesap): self
{
$this->hesap = $hesap;
return $this;
}
public function getKartAdi(): ?string
{
return $this->kart_adi;
}
public function setKartAdi(string $kart_adi): self
{
$this->kart_adi = $kart_adi;
return $this;
}
public function getKartNo(): ?string
{
return $this->kart_no;
}
public function setKartNo(string $kart_no): self
{
$this->kart_no = $kart_no;
return $this;
}
public function getHesapKesimGunu(): ?int
{
return $this->hesap_kesim_gunu;
}
public function setHesapKesimGunu(int $hesap_kesim_gunu): self
{
$this->hesap_kesim_gunu = $hesap_kesim_gunu;
return $this;
}
public function getAciklama(): ?string
{
return $this->aciklama;
}
public function setAciklama(?string $aciklama): self
{
$this->aciklama = $aciklama;
return $this;
}
public function getBorc(): ?float
{
return $this->borc;
}
public function setBorc(float $borc): self
{
$this->borc = $borc;
return $this;
}
public function getAlacak(): ?float
{
return $this->alacak;
}
public function setAlacak(float $alacak): self
{
$this->alacak = $alacak;
return $this;
}
public function getCreatedAt(): ?\DateTimeImmutable
{
return $this->created_at;
}
public function setCreatedAt(\DateTimeImmutable $created_at): self
{
$this->created_at = $created_at;
return $this;
}
}
KrediKartiType.php:
$builder
->add('kart_adi',TextType::class,['label' => 'Kart Adı','required' => false, 'attr' =>['class' => 'form-control', 'placeholder' => 'Kart Adı']])
->add('kart_no',TextType::class,['label' => 'Kart No','required' => false, 'attr' =>['class' => 'form-control', 'placeholder' => 'Kart No']])
->add('hesap_kesim_gunu', NumberType::class, [
'label' => 'Hesap Kesim Tarihi', 'attr' =>['class' => 'form-control', 'placeholder' => 'Hesap Kesim Günü']
])
->add('aciklama',TextType::class,['label' => 'Açıklama','required' => false, 'attr' =>['class' => 'form-control', 'placeholder' => 'Açıklama']])
->add('borc', NumberType::class,
[
'label' => 'Borç', 'attr' =>['class' => 'form-control', 'placeholder' => "Borç",'value' => '0.00','style' => 'text-align: right']
])
->add('alacak', NumberType::class,
[
'label' => 'Alacak', 'attr' =>['class' => 'form-control', 'placeholder' => "Alacak",'value' => '0.00','style' => 'text-align: right']
])
->add('banka', EntityType::class, array(
'class' => Banka::class,
'choice_label'=> 'adi',
'placeholder' => 'Lütfen bankanızı seçiniz',
'attr' =>['class' => 'form-control']
))
;
$formModifier = function (FormInterface $form, Banka $banka = null) {
$banka_hesap = null === $banka ? [] : $banka->getBankaHesaplari();
$form->add('hesap', EntityType::class, [
'class' => BankaHesap::class,
'placeholder' => '',
'choices' => $banka_hesap,
]);
};
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($formModifier) {
$data = $event->getData();
$formModifier($event->getForm(), $data->getBanka());
}
);
$builder->get('banka')->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) use ($formModifier) {
$banka = $event->getForm()->getData();
$formModifier($event->getForm()->getParent(), $banka);
}
);
new.html.twig:
<script>
var $banka = $('#kredi_karti_banka');
var $token = $('#kredi_karti__token');
$banka.change(function() {
var $form = $(this).closest('form');
var data = {};
data[$banka.attr('name')] = $banka.val();
data[$token.attr('name')] = $token.val();
$.ajax({
url : $form.attr('action'),
type: $form.attr('method'),
data : data,
complete: function(html) {
// Replace current position field ...
$('#kredi_karti_hesap').replaceWith(
// ... with the returned one from the AJAX response.
$(html.responseText).find('#meetup_position')
);
// Position field now displays the appropriate positions.
}
});
});
</script>
I simply want to fetch bank accounts based on the selected bank on bank change.
You could add options to the form when you create it. So you can create an endpoint where you can create the form with the extra options which could be the bank id and then render only the select element you wish, in your case the bank_accounts select. You can call this endpoint on change event via JS to the banks select. Also you need to modify the KrediKartiType so that the bank_accounts select should take the values from a query builder. For Example:
class BankAccountsController extends AbstractController
{
#[Route('/bank-accounts-select', name: 'bank_accounts_select', methods: ['GET'])]
public function getBankAccountsSelect(Request $request): Response
{
$form = $this->createForm(
KrediKartiType::class,
null,
['bankId' => $request->query->get('bankId')]
);
return $this->render('_bank-accounts-select.html.twig', [
'form' => $form->createView(),
]);
}
}
The form type for the bank_accounts key can look like this:
->add('bank_accounts', EntityType::class, [
'class' => BankaHesap::class,
'query_builder' => function (BankaHesapRepository $bankaHesapRepository) use ($options) {
return $bankaHesapRepository->bankAccountsByBankId((int) $options['bankId']);
},
'label_attr' => ['class' => 'mb-0 d-block'],
])
The Repository method to get the bank accounts from bankId:
public function bankAccountsByBankId(?int $bankId): QueryBuilder
{
return $this->createQueryBuilder('bh')
->join('bh.bank', 'b')
->where('b.id = :bankId')
->setParameter('bankId', $bankId)
->orderBy('bh.name', 'ASC') // this is optional :)
;
}
You would also need the twig file which renders the select element _bank-accounts-select.html.twig:
{{ form_row(form.bank_accounts, {
attr: {
'class': 'mb-3 form-control'
}
}) }}
At last the Js part, where you need to call the endpoint bank-accounts-select, where you replace the select with the one you get from the endpoint:
$bankSelect.on('change', (event) => {
const bankId = event.target.value;
$.ajax({
url: BASE_URL+'/bank-accounts-select',
data: {
bankId: bankId,
},
success: function (html) {
const $bankAccountsSelect = REGION_SELECT_FROM_CLASS_NAME //replace this with your jQuery/Javascript selector;
$bankAccountsSelect.html($(html).find("option"));
$bankAccountsSelect.val("").trigger("change");
},
});
});
This should do it, And I suggest you use English language on your code ;)
I try to apply documentation https://symfony.com/doc/current/form/dynamic_form_modification.html but i have some troubles when I receive the result of the first select categoryLevel1Id to collect options in the second select categoryLevel2Id.
I'm new with Doctrine, and I think something escapes me.
With the following code, I have an exception:
Expected argument of type "int", "object" given at property path
"categoryLevel1Id"
$builder->add('categoryLevel1Id', EntityType::class, [
'class' => CategoryLevel1::class,
'label' => 'contrib.create.category_level1',
'placeholder' => 'contrib.create.category_level1_placeholder',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('c')
->andWhere("c.langId = ?1")
->andWhere("c.validated = ?2")
->setParameter(1, $this->langService->getLangIdByLang(locale_get_default()))
->setParameter(2, 1);
},
'choice_label' => 'title',
'choice_attr' => function($choice, $key, $value) {
return ['class' => 'text-dark'];
},
]);
With the following code, I have this exception:
Argument 2 passed to
App\Form\Front\Situ\CreateSituFormType::App\Form\Front\Situ{closure}()
must be an instance of App\Entity\CategoryLevel1 or null, int given,
called in ..\src\Form\Front\Situ\CreateSituFormType.php on line 147
$categories = $this->categoryLevel1Repository->findLocaleCategories();
$categoriesOptions = [];
foreach ($categories as $categorie) {
$categoriesOptions[] = [
$categorie['title'] => $categorie['id'],
];
}
$builder->add('categoryLevel1Id', ChoiceType::class, [
'choices' => call_user_func_array('array_merge', $categoriesOptions),
'label' => 'contrib.create.category_level1',
'label_attr' => ['class' => ''],
'placeholder' => 'contrib.create.category_level1_placeholder',
'choice_attr' => function($choice, $key, $value) {
return ['class' => 'text-dark'];
},
]);
I tried to call a CategoryLevel1Type::class instead but it didn't work when code came to $formModifier = function (FormInterface $form.. of course or I did'nt know adapt code!
This is my buildForm() with any __construct before:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title', TextType::class, [
'label' => 'contrib.create.title',
'attr' => [
'class' => 'mb-md-4',
'placeholder' => 'contrib.create.title_placeholder'
],
])
->add('description', TextareaType::class, [
'label' => 'contrib.create.description',
'attr' => [
'rows' => '5',
'placeholder' => 'contrib.create.description_placeholder',
],
])
;
// Check locale categories level 1
$categories = $this->categoryLevel1Repository->findLocaleCategories();
// If no category, create it and its subcategory
if (empty($categories)) {
$builder
->add('categoryLevel1Id', CreateCategoryLevel1Type::class, [
'label' => 'category.create.category_level1',
'label_attr' => ['class' => 'pt-0'],
])
->add('categoryLevel2Id', CreateCategoryLevel2Type::class, [
'label' => 'category.create.category_level2',
'label_attr' => ['class' => 'pt-0'],
])
;
} else {
$builder->add('categoryLevel1Id', EntityType::class, [
'class' => CategoryLevel1::class,
'label' => 'contrib.create.category_level1',
'placeholder' => 'contrib.create.category_level1_placeholder',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('c')
->andWhere("c.langId = ?1")
->andWhere("c.validated = ?2")
->setParameter(1, $this->langService->getLangIdByLang(locale_get_default()))
->setParameter(2, 1);
},
'choice_label' => 'title',
'choice_attr' => function($choice, $key, $value) {
return ['class' => 'text-dark'];
},
]);
$formModifier = function (FormInterface $form, CategoryLevel1 $categoryLevel1 = null) {
$categoriesLevel2 = null === $categoryLevel1 ? [] :
$categoryLevel1->getGategoriesLevel2();
$form->add('categoryLevel2Id', EntityType::class, [
'class' => 'App\Entity\CategoryLevel2',
'label' => 'contrib.create.category_level2',
'placeholder' => 'contrib.create.category_level2_placeholder',
'choices' => $categoriesLevel2,
]);
};
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($formModifier) {
// this would be your entity, i.e. SportMeetup
$data = $event->getData();
$formModifier($event->getForm(), $data->getCategoryLevel1Id());
}
);
$builder->get('categoryLevel1Id')->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) use ($formModifier) {
// It's important here to fetch $event->getForm()->getData(), as
// $event->getData() will get you the client data (that is, the ID)
$categoryLevel1 = $event->getForm()->getData();
// since we've added the listener to the child, we'll have to pass on
// the parent to the callback functions!
$formModifier($event->getForm()->getParent(), $categoryLevel1); // (Error code 2 here)
}
);
}
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Situ::class,
'translation_domain' => 'user_messages',
]);
}
Then Entities with Relations:
CategoryLevel1:
.../...
/*
* #ORM\OneToMany(targetEntity="App\Entity\CategoryLevel2", cascade={"persist", "remove"}, mappedBy="categoryLevel1Id")
*/
protected $categoriesLevel2;
/*
* #ORM\OneToMany(targetEntity=Situ::class, cascade={"persist", "remove"}, mappedBy="categoryLevel1")
*/
protected $situs;
public function __construct()
{
$this->categoriesLevel2 = new ArrayCollection();
$this->situs = new ArrayCollection();
}
.../...
public function getGategoriesLevel2()
{
return $this->categoriesLevel2;
}
public function addCategoryLevel2(CategoryLevel2 $categoryLevel2)
{
$this->categoriesLevel2->add($categoryLevel2);
$categoryLevel2->setCategoryLevel1($this);
}
public function getSitus()
{
return $this->situs;
}
public function addSitu(Situ $situ)
{
$this->situs->add($situ);
$situ->setCategoryLevel1($this);
}
CategoryLevel2:
.../...
/**
* #ORM\Column(type="integer")
* #ORM\ManyToOne(targetEntity="App\Entity\CategoryLevel1", inversedBy="categoriesLevel2")
*/
private $categoryLevel1Id;
/**
* #ORM\Column(type="boolean")
*/
private $validated;
/**
* #ORM\OneToMany(targetEntity=Situ::class, cascade={"persist", "remove"}, mappedBy="categoryLevel2")
*/
protected $situs;
public function __construct()
{
$this->situs = new ArrayCollection();
}
.../...
public function getSitus()
{
return $this->situs;
}
public function addSitu(Situ $situ)
{
$this->situs->add($situ);
$situ->setCategoyLevel2($this);
}
.../...
Situ :
.../...
/**
* #ORM\Column(type="integer")
*/
private $categoryLevel1Id;
/**
* #ORM\Column(type="integer")
*/
private $categoryLevel2Id;
/**
* #ORM\ManyToOne(targetEntity=CategoryLevel1::class, inversedBy="situs")
*/
protected $categoryLevel1;
/**
* #ORM\ManyToOne(targetEntity=CategoryLevel2::class, inversedBy="situs")
*/
protected $categoryLevel2;
.../...
Into SituController, nothing but :
public function createSitu(Request $request, User $user): Response
{
$situ = new Situ();
$form = $this->createForm(CreateSituFormType::class, $situ);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// TODO
}
return $this->render('front/situ/new.html.twig', [
'situ' => $situ,
'form' => $form->createView(),
]);
}
You probably got confused between these 2 entities (CategoryLevel2 and Situ):
In CategoryLevel2 it's a App\Entity\CategoryLevel1 type
while in Situ it's an integer type
You can't use EntityType::class in $builder->add('categoryLevel1Id', EntityType::class, [ because in your CreateSituFormType the field categoryLevel1Id is an integer and not an entity.
In your Situ entity you might change:
/**
* #ORM\Column(type="integer")
*/
private $categoryLevel1Id;
into:
/**
* #ORM\ManyToOne(targetEntity="App\Entity\CategoryLevel1")
*/
private $categoryLevel1Id;
to solve the problem.
Can I specify how the form field shold be mapped on data class?
Let's say I have form with check box and on my data entity the field is stored as string.
class FormType extends AbstractType {
public function configureOptions(OptionsResolver $resolver) {
$resolver->setDefaults([
'data_class' => DataEntity::class,
]);
}
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('issueType', CheckboxType::class, [
'label' => 'issueType',
]);
}
}
class DataEntity {
/** #var string Either PLASTIC or PAPER */
private $issueType;
public function getIssueType() {
return $this->issueType;
}
public function setIssueType($issueType) {
$this->issueType = $issueType;
}
}
Can I made the checkbox to be mapped as 'PLASTIC' if ture and 'PAPER' if false?
You can use data transformer to cast bolean to the string. See this tutorial: https://symfony.com/doc/current/form/data_transformers.html.
$builder->get('issueType')
->addModelTransformer(new CallbackTransformer(
function ($type) {
// your logic here
return $type;
},
function ($type) {
// your logic here
return $type;
}
));
try :
$builder->add('newsletter', 'choice', array(
'label' => 'Newsletter erhalten',
'attr' => array(
'class' => 'form-control',
),
'choices' => array(array('yes' => 'plastic'), array('no' => 'paper')),
'expanded' => true,
'multiple' => true,
'required' => false,
));
also check the answer here Symfony2 Change checkbox values from 0/1 to 'no'/'yes'