I'm here because I can't find a solution to my problem. I have a form in Symfony 6 and one of the value is id_client and reffer to another entity, Client (relation ManyToOne).
I tested few methods to make the field be a select choice of all the clients (I show the name of the client). And every of them works but when I submit the form this value is add as the whole entity and not just the id. This is a problem because I end with this:
Expected argument of type "int", "App\\Entity\\Client" given at property path "id_client".
In my form it looks like this:
<?php
namespace App\Form;
use App\Entity\Client;
use App\Entity\Group;
use App\Repository\ClientRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
class Group1Type extends AbstractType
{
private $clientRepository;
public function __construct(ClientRepository $clientRepository)
{
$this->clientRepository = $clientRepository;
$this->clients = $clientRepository->findAll();
}
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('name', TextType::class, [
'attr' => [
'class' => 'form-control'
],
'label' => 'Name: '
])
->add('can_display', CheckboxType::class, [
'label' => 'Can display : ',
'attr' => [
'class' => 'my-3 mx-2'
]
])
->add('id_client', EntityType::class, [
'class' => Client::class,
// 'choices' => $this->clientRepository->findAllNameAlphabetical(),
// 'query_builder' => function (ClientRepository $client) {
// return $client->findAllNameAlphabetical();
// },
'choice_label' => 'name',
'expanded' => false,
'multiple' => false,
'attr' => [
'class' => 'form-control'
]
])
;
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Group::class,
]);
}
}
The twig:
<section >
<div >
<div >
{{ form_start(form) }}
{{ form_row(form.name) }}
{{ form_row(form.can_display) }}
{{ form_row(form.id_client) }}
<button >{{ button_label|default('Save') }}</button>
{{ form_end(form) }}
</div>
</div>
</section>
The controller (I have the same result if I let it as it was at the beginning):
#[Route('/new', name: 'app_group_new', methods: ['GET', 'POST'])]
public function new(Request $request, GroupRepository $groupRepository): Response
{
$group = new Group();
$form = $this->createForm(Group1Type::class, $group);
$form->handleRequest($request);
// $group->id_client = $group->id_client->id;
if ($form->isSubmitted()) {
// dd('submit');
// if(gettype($group->id_client)=="Client"){
// dd($group);
if($form->isValid()){
dd('valid');
$groupRepository->save($group, true);
$this->addFlash('success', 'The creation went successfully.');
return $this->redirectToRoute('app_group_index', [], Response::HTTP_SEE_OTHER);
// }
}
}
return $this->renderForm('group/new.html.twig', [
'group' => $group,
'form' => $form,
]);
}
My entity:
#[ORM\Column]
private ?int $id_client = null;
CodePudding user response:
Welcome to SO!
In your entity, do not name properties with id
. The client-Property in the Group(?) Entity should be named $client
, not $id_client
.
Then, in your Form, name that field excactly like the property in the Group-Entity. Doctrine (as a DBAL should do) does that behind-the-scene relating of the object by the actual id for you.
Group1Type.php
->add('client', EntityType::class, [
'class' => Client::class,
// ...
])
And your Group-Entity (or Group1?)
class Group
{
// ...
#[ORM\ManyToOne(targetEntity: Client::class, inversedBy: 'groups')]
#[ORM\JoinColumn(nullable: false)]
private $client;
// ...
}
It is totallfy fine and correct that the Form it self submits and handles the Entity-Instance of the selected client. You almost never handle
$id
values. Thats one of the features of doctrine!
See the Symfony documentation for more information on how to use
EntityType
fields.
Note: From the naming you gave, I suspect you have the wrong relation, maybe it should be
OneToMany
? (Can you tell us howGroup
andClient
is related? Does 1 Group have multiple clients or vice versa?)
Sidenote: In rare cases, when you really need a Number related to an Entity (e.g. a textinput where user can enter a customer number which then translates to a real customer entity) you can use
DataTransformer
to translate such values. But this is not what you want here!
CodePudding user response:
simple solution is to use choice type, this way you dont need the relation and when you submit you will have the id of the client. If load the form for editing (loading the entity, it will show the selected value from the submit)
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('client', ChoiceType::class, [
'choices'=> $this->getClients(),
])
}
public function getClients(){
$conn = $this->getEntityManager()->getConnection();
$query = "SELECT `name`, `id` FROM `clients` order by `name`";
$stmt = $conn->executeQuery($query);
return $stmt->fetchAllKeyValue();
}
it will generate a dropdown menu where the value is the id, and the option is the client name