При использовании EntityType для отображения выбора невозможно сохранить объект из формы Symfony

У меня есть два связанных объекта в моем проекте symfony, которые хранятся с помощью Doctrine. Одной сущностью является «Рекламодатель», у которой есть идентификатор и имя. Другой объект, который вызывает проблему, предназначен для «Отчета», который имеет собственный идентификатор вместе с полем «advertiser_id».

При добавлении отчета для рекламодателя в форме Symfony я использую EntityType для поля рекламодателя_id, чтобы отображать выбранных рекламодателей. Эта часть работает отлично, но когда я пытаюсь отправить форму, я получаю сообщение об ошибке, потому что она передает объект Advertiser вместо идентификатора рекламодателя в поле Advertisingr_id.

Вот что у меня есть в конструкторе моей формы:

$builder
    ->add('advertiser_id', EntityType::class, [
        'class'        => Advertiser::class,
        'query_builder' => $this->advertiserRepository->findAllNotDeletedUnpaginated(),
        'choice_label' => 'name',

    ])
    ->add('submit', SubmitType::class, [
        'label' => 'Submit',
    ])
;

Когда я отправляю форму, я получаю эту ошибку: Задан ожидаемый аргумент типа "целое число", "App\Entity\Advertiser".

Любая идея о том, как я могу заставить symfony пытаться сохранить только идентификатор выбранного рекламодателя, а не передавать всего рекламодателя?

UPDATE: Now that I've refactored it so that the advertiser is a related entity to report, I'm trying to figure out how to make the advertiser a hidden field and getting nowhere.

Я пробовал код, упомянутый ранее iirxs, с преобразователем обратного вызова - изменением «advertiser_id» на «advertiser», но мне не повезло с этим. Я читал сообщения, подобные этому Symfony hiddenType, использующий data_class для объекта вместо трансформатора, но у меня возникли проблемы с получением значения для «рекламодателя» так, как они получают $options['selected_course'] в этом примере.

Когда я пытаюсь (в целях тестирования) жестко запрограммировать значение 1 для рекламодателя, а затем помещаю его в форму, форма отображается, но при отправке я получаю сообщение об ошибке:

    $advertiser=1;

    $builder
        ->add('advertiser', HiddenType::class,['data' => $advertiser, 'data_class' => null])

Ошибка, которую я получаю при отправке формы: Ожидаемый аргумент типа "App\Entity\Advertiser or null", задана "строка".

Извините, что избил дохлую лошадь по этому поводу. Кажется, что это должно быть таким обычным/простым делом, но мне трудно найти, как сделать это скрытым полем. Благодарим за любую идею!

Не могли бы вы проверить advertiser_id определение этого поля в вашем объекте. Если он определен как целое число, вы должны изменить его.

Mert Öksüz 12.02.2019 06:29

Вы можете поделиться здесь своим файлом сущности Report.php? Вы указали тип поля как ManyToOne в аннотациях?

Nodir Rashidov 12.02.2019 07:23

Есть ли причина, по которой вы хотите передать в форму идентификатор, а не сущность? (symfony на самом деле делает за вас работу по сериализации/десериализации EntityType)

Erwan Haquet 12.02.2019 09:17
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Symfony Station Communiqué - 17 февраля 2023 г
Symfony Station Communiqué - 17 февраля 2023 г
Это коммюнике первоначально появилось на Symfony Station , вашем источнике передовых новостей Symfony, PHP и кибербезопасности.
Управление ответами api для исключений на Symfony с помощью KernelEvents
Управление ответами api для исключений на Symfony с помощью KernelEvents
Много раз при создании api нам нужно возвращать клиентам разные ответы в зависимости от возникшего исключения.
1
3
2 152
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Проблема в том, что вы неправильно определили ассоциацию с сущностью "Рекламодатель" в сущности отчета. Вы должны были определить такую ​​ассоциацию:

// inside Report.php class

/**
 * @ORM\ManyToOne(targetEntity = "App\Entity\Advertiser")
 */
private $advertiser;

вместо определения поля, содержащего внешний ключ advertiser_id. Doctrine достаточно умна, чтобы самостоятельно сопоставить поле рекламодателя с внешним ключом advertiser_id в вашей базе данных, поэтому было бы лучше использовать сопоставление ассоциации. Вы можете найти больше в документация.

Однако, если вам действительно нужно использовать только целое число для хранения advertiser_id в виде целого числа по вашим собственным причинам, вам следует использовать Преобразователь данных Symfony для преобразования сущности рекламодателя в целое число, подобное этому:

$advertiserRepository = $this->advertiserRepository;
$builder->get('advertiser_id')
        ->addModelTransformer(new CallbackTransformer(
            function ($advertiserAsInteger) use ($advertiserRepository) {
                // transform the integer to an entity object
                return $advertiserRepository->find($advertiserAsInteger);
            },
            function ($advertiserAsEntity) {
                // transform the entity back to an integer
                return $advertiserAsEntity->getId();
            }
        ))
    ;

В приведенном выше коде я использовал CallbackTransformer для реализации преобразования, но вы также можете использовать для этого класс преобразователя. Вы также можете найти больше об этом в документация по преобразователям данных.

Спасибо, iirxs! Я собираюсь реорганизовать свою сущность в соответствии с вашим первым предложением.

Erich 12.02.2019 15:50

Я провел рефакторинг приложения, чтобы рекламодатель был связан с отчетом. Сейчас пытаюсь отрендерить форму для отчета и пытаюсь понять как отобразить рекламодателя в форме. Я попробовал базовый «-> add('advertiser')» в конструкторе, но это дает мне эту ошибку: Catchable Fatal Error: Object of class App\Entity\Advertiser не может быть преобразован в строку. Будем признательны за любые мысли или ссылки о том, как правильно отображать форму, когда есть связанный объект!

Erich 12.02.2019 23:32

Вы добавили поле рекламодателя в свою форму как EntityType?

iiirxs 13.02.2019 12:33

Еще раз спасибо, iirxs! Изменение построителя, чтобы включить это, сработало! ->add('рекламодатель', EntityType::class, array( 'class' => Advertiser::class, 'choice_label' => 'name', ))

Erich 13.02.2019 15:44

Я хотел добавить к части ответа @iiirxs пользовательский тип, который я только что реализовал на основе предложения преобразователя модели.

Этот тип расширяет встроенный EntityType, поэтому во многих случаях вы можете заменить EntityType на EntityReferenceType и вместо этого сопоставить идентификатор.

Это полезно, если форма не сопоставляется непосредственно с сущностью, например, с использованием шаблона команды, поэтому вы предпочитаете идентификатор.

use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\CallbackTransformer;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\PropertyAccess\PropertyAccess;

class EntityReferenceType extends AbstractType
{
    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'id_property' => 'id'
        ]);
    }

    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder->addModelTransformer(
            new CallbackTransformer(
                function ($entityIdentifier) use ($options) {
                    if ($entityIdentifier === null) {
                        return null;
                    }
                    return $options['em']->getRepository($options['class'])->find($entityIdentifier);
                },
                function ($entity) use ($options) {
                    if ($entity === null) {
                        return null;
                    }
                    return PropertyAccess::createPropertyAccessor()->getValue($entity, $options['id_property']);
                }
            )
        );
    }


    public function getParent(): string
    {
        return EntityType::class;
    }
}

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