Форма EntityType SYmfony добавляется как Entity вместо int

Я здесь, потому что не могу найти решение своей проблемы. У меня есть форма в 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;

Если вам нужен только идентификатор, вам не следует использовать EntityType, так как это всегда преобразует id в сущность, а затем возвращает сущность. Вместо этого вы можете использовать ChoiceType, так как это не выполняет автоматическое преобразование. Но уверены ли вы, что ваши сущности настроены правильно? Я ожидаю, что Group будет иметь свойство $client, которое содержит объект Client, а затем ORM выполнит преобразование объекта Client в id_client при сохранении его в базе данных.

Marleen 22.11.2022 11:24

Если у $id_client есть отношение, почему вы хотите сохранить int вместо объекта Client? Вы смешиваете концепции, если вы хотите сохранить сущность-клиент, у вас должен быть ``` private ?Client $id_client = null; ``` тогда вы можете использовать EntityType в форме, иначе используйте ChoiceType в форме без определения атрибута класса.

alexcm 22.11.2022 12:22

Здесь вы упускаете несколько концепций symfony и доктрины. Я очень рекомендую вам прочитать документацию Symfony. После 2 лет разработки в Symfony я все еще использую его каждый день, и мне это нравится. Это потрясающе!

Jonathan 22.11.2022 14:16
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
1
3
105
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

В своей сущности не называйте свойства с помощью 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» вместо «Клиент-клиент»? --> Я не знаю, я храню их в отношении типов и заканчиваю этим... так что я не знаю. Это произошло со всеми моими родственниками во всех моих Сущностях. Должен ли я перезапустить и снова создать новые объекты с отношением и посмотреть, что у меня есть?

mco 22.11.2022 14:43

Я предлагаю вам создавать свои сущности с помощью команды makephp bin/console make entity. Если 1Client имеет nGroups, отношение OneToMany верно. Вы действительно хотите использовать здесь поле формы EntityType.

Jonathan 22.11.2022 14:48

Не принимайте эту тему (идентификаторы или отношение объекта) как необязательный выбор. Многие функции зависят от правильного выполнения этого (например, проверка, поля форм, миграции, репозитории и везде, где вы используете эти объекты в своих контроллерах).

Jonathan 22.11.2022 14:52

простое решение - использовать тип выбора, таким образом, вам не нужно отношение, и когда вы отправляете, у вас будет идентификатор клиента. Если загрузить форму для редактирования (загружая объект, он покажет выбранное значение из отправки)

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 22.11.2022 14:48

Можете ли вы аргументировать свой совет против простых запросов? в документации написано, что их можно использовать @Jonathan

benkov 23.11.2022 07:03

Ну, во-первых, если схема вашей таблицы изменится, метод доктрины findBy() все равно сможет извлекать, скажем, новые связанные таблицы или дополнительные столбцы. Простые запросы, с другой стороны, словно высечены в камне. Вы можете использовать их, но за годы мне никогда не приходилось, потому что всегда можно использовать репозиторий для извлечения данных и позволить доктрине делать все (динамические) вещи за вас. Кроме того, FormType-класс — это не то место, где вы извлекаете свои данные, за исключением свойства choice_query-элемента. Документация дает много примеров того, как получить данные в форме, если это необходимо.

Jonathan 23.11.2022 08:42

В конце концов, это действительно помогает вам, и вы получаете выгоду от использования предлагаемых методов. И вам понравится :)

Jonathan 23.11.2022 08:43

Другие вопросы по теме