Я здесь, потому что не могу найти решение своей проблемы. У меня есть форма в Symfony 6, и одно из значений — id_client и относится к другому объекту, клиенту (отношение ManyToOne).
Я протестировал несколько методов, чтобы сделать поле выбранным для всех клиентов (я показываю имя клиента). И каждый из них работает, но когда я отправляю форму, это значение добавляется как весь объект, а не только идентификатор. Это проблема, потому что я заканчиваю на этом:
Expected argument of type "int", "App\\Entity\\Client" given at property path "id_client".
В моей форме это выглядит так:
<?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,
]);
}
}
Веточка:
<section class = "container my-3">
<div class = "row">
<div class = "col">
{{ form_start(form) }}
{{ form_row(form.name) }}
{{ form_row(form.can_display) }}
{{ form_row(form.id_client) }}
<button class = "btn btn-primary my-3">{{ button_label|default('Save') }}</button>
{{ form_end(form) }}
</div>
</div>
</section>
Контроллер (у меня такой же результат, если оставить как было в начале):
#[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,
]);
}
Моя сущность:
#[ORM\Column]
private ?int $id_client = null;
Если у $id_client есть отношение, почему вы хотите сохранить int вместо объекта Client? Вы смешиваете концепции, если вы хотите сохранить сущность-клиент, у вас должен быть ``` private ?Client $id_client = null; ``` тогда вы можете использовать EntityType в форме, иначе используйте ChoiceType в форме без определения атрибута класса.
Здесь вы упускаете несколько концепций symfony и доктрины. Я очень рекомендую вам прочитать документацию Symfony. После 2 лет разработки в Symfony я все еще использую его каждый день, и мне это нравится. Это потрясающе!






В своей сущности не называйте свойства с помощью id_*. Свойство-клиент в объекте группы (?) должно называться $client, а не $id_client.
Затем в своей форме назовите это поле точно так же, как свойство в Group-Entity. Doctrine (как и должен делать DBAL) делает это за кулисами, связывая объект с фактическим идентификатором для вас.
Group1Type.php
->add('client', EntityType::class, [
'class' => Client::class,
// ...
])
И ваша Группа-Сущность (или Группа1?)
class Group
{
// ...
#[ORM\ManyToOne(targetEntity: Client::class, inversedBy: 'groups')]
#[ORM\JoinColumn(nullable: false)]
private $client;
// ...
}
Совершенно нормально и правильно, что форма сама отправляет и обрабатывает объект-экземпляр выбранного клиента. Вы почти никогда не обрабатываете значения
$id. Это одна из особенностей учения!
См. документацию Symfony для получения дополнительной информации о том, как использовать
EntityTypeполя.
Примечание. Судя по названию, которое вы дали, я подозреваю, что у вас неправильное отношение, может быть, оно должно быть
OneToMany? (Можете ли вы рассказать нам, как связаныGroupиClient? У 1 группы несколько клиентов или наоборот?)
Примечание: в редких случаях, когда вам действительно нужно число, связанное с сущностью (например, текстовый ввод, где пользователь может ввести номер клиента, который затем преобразуется в реальную сущность клиента), вы можете использовать
DataTransformerдля перевода таких значений. Но это не то, что вы хотите здесь!
Спасибо за ваши ответы Джонатан, Алекс и Марлин. - Когда я поставил ChoiceType вместо ENtityType, я получил тот же результат. - Для моих отношений каждый клиент может иметь несколько групп - Почему у меня есть «int id_client» вместо «Клиент-клиент»? --> Я не знаю, я храню их в отношении типов и заканчиваю этим... так что я не знаю. Это произошло со всеми моими родственниками во всех моих Сущностях. Должен ли я перезапустить и снова создать новые объекты с отношением и посмотреть, что у меня есть?
Я предлагаю вам создавать свои сущности с помощью команды makephp bin/console make entity. Если 1Client имеет nGroups, отношение OneToMany верно. Вы действительно хотите использовать здесь поле формы EntityType.
Не принимайте эту тему (идентификаторы или отношение объекта) как необязательный выбор. Многие функции зависят от правильного выполнения этого (например, проверка, поля форм, миграции, репозитории и везде, где вы используете эти объекты в своих контроллерах).
простое решение - использовать тип выбора, таким образом, вам не нужно отношение, и когда вы отправляете, у вас будет идентификатор клиента. Если загрузить форму для редактирования (загружая объект, он покажет выбранное значение из отправки)
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();
}
он создаст раскрывающееся меню, где значением является идентификатор, а параметром является имя клиента.
Я настоятельно рекомендую не использовать простые запросы! Это решение очень плохое. Пожалуйста, обратитесь к документации, где все указано правильно.
Можете ли вы аргументировать свой совет против простых запросов? в документации написано, что их можно использовать @Jonathan
Ну, во-первых, если схема вашей таблицы изменится, метод доктрины findBy() все равно сможет извлекать, скажем, новые связанные таблицы или дополнительные столбцы. Простые запросы, с другой стороны, словно высечены в камне. Вы можете использовать их, но за годы мне никогда не приходилось, потому что всегда можно использовать репозиторий для извлечения данных и позволить доктрине делать все (динамические) вещи за вас. Кроме того, FormType-класс — это не то место, где вы извлекаете свои данные, за исключением свойства choice_query-элемента. Документация дает много примеров того, как получить данные в форме, если это необходимо.
В конце концов, это действительно помогает вам, и вы получаете выгоду от использования предлагаемых методов. И вам понравится :)
Если вам нужен только идентификатор, вам не следует использовать
EntityType, так как это всегда преобразуетidв сущность, а затем возвращает сущность. Вместо этого вы можете использоватьChoiceType, так как это не выполняет автоматическое преобразование. Но уверены ли вы, что ваши сущности настроены правильно? Я ожидаю, чтоGroupбудет иметь свойство$client, которое содержит объектClient, а затем ORM выполнит преобразование объектаClientвid_clientпри сохранении его в базе данных.