无法在编辑表单中加载,错误的表单视图数据实例

问题描述

我有一个模块,其中设置了以下实体:

  • 产品
    • 产品翻译
      • ContentBlock

我可以很好地添加新产品,但是当我对其进行编辑时,无法加载该表单。它给了我以下错误

该表单的视图数据应该是ContentBlockDataTransferObject类的实例,但是是ContentBlock类的实例。您可以通过将“ data_class”选项设置为null或添加一个将类ContentBlock的实例转换为ContentBlockDataTransferObject的实例的视图转换器来避免此错误

data_class设置为null似乎没有任何改变。

ProductType.PHP

<?PHP

namespace Backend\Modules\Products\Domain\Product;

use Backend\Core\Language\Language;
use Backend\Modules\MediaLibrary\Domain\MediaGroup\MediaGroupType;
use Backend\Modules\Products\Domain\Categories\Category;
use Backend\Modules\Products\Domain\Divisions\Division;
use Common\Form\CollectionType;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query\Expr\Join;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Common\Form\ImageType;
use Symfony\Component\Validator\Constraints\Valid;

final class ProductType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder,array $options): void
    {
        $builder->add(
            'categories',EntityType::class,[
                'class' => Category::class,'multiple' => true,'expanded' => true,'label' => 'lbl.Categories','query_builder' => function (EntityRepository $er) {
                    return $er->createqueryBuilder('i')
                        ->join('i.translations','t')
                        ->innerJoin(Division::class,'d',Join::WITH,'i.division = d')
                        ->addOrderBy('d.id','ASC')
                        ->addOrderBy('t.title','ASC');
                },]
        );
        $helpTextMessageMainImage = sprintf(
            Language::msg('HelpImageFieldWithMaxFileSize'),$this->getUploadMaxFileSize()
        );
        $helpTextMessageMainImage .= '<br><strong>' . Language::msg('MainImageHelp') . '</strong>';
        $builder->add(
            'mainImage',ImageType::class,[
                'image_class' => MainImage::class,'help_text_message' => $helpTextMessageMainImage,]
        );
        $builder->add(
            'translations',CollectionType::class,[
                'entry_type' => ProductTranslationType::class,'error_bubbling' => false,'constraints' => [new Valid()],]
        );
        $builder->add(
            'imagegallery',MediaGroupType::class,[
                'required' => false,]
        );
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults(['data_class' => ProductDataTransferObject::class]);
    }

    private function getUploadMaxFileSize(): ?string
    {
        $uploadMaxFileSize = ini_get('upload_max_filesize');
        if ($uploadMaxFileSize === false) {
            return null;
        }

        // reformat if defined as an integer
        if (is_numeric($uploadMaxFileSize)) {
            return $uploadMaxFileSize / 1024 . 'MB';
        }

        // reformat if specified in kB
        if (mb_strtoupper(mb_substr($uploadMaxFileSize,-1)) === 'K') {
            return mb_substr($uploadMaxFileSize,-1) . 'kB';
        }

        // reformat if specified in MB
        if (mb_strtoupper(mb_substr($uploadMaxFileSize,-1)) === 'M') {
            return $uploadMaxFileSize . 'B';
        }

        // reformat if specified in GB
        if (mb_strtoupper(mb_substr($uploadMaxFileSize,-1)) === 'G') {
            return $uploadMaxFileSize . 'B';
        }

        return $uploadMaxFileSize;
    }
}

ProductTranslationType.PHP

<?PHP

namespace Backend\Modules\Products\Domain\Product;

use Backend\Core\Engine\Model;
use Backend\Core\Language\Language;
use Backend\Form\Type\EditorType;
use Backend\Form\Type\MetaType;
use Backend\Modules\Products\Domain\ContentBlock\ContentBlockType;
use Backend\Modules\Products\Domain\Product\Command\CreateProduct;
use Backend\Modules\Products\Domain\Product\Command\UpdateProduct;
use Backend\Modules\Products\Domain\Product\ProductTranslation\ProductTranslationRepository;
use Common\Form\CollectionType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\TextType;

final class ProductTranslationType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder,array $options): void
    {
        $builder
            ->add(
                'title',TextType::class,[
                    'label' => 'lbl.Title',]
            )
            ->add(
                'contentBlocks',[
                    'entry_type' => ContentBlockType::class,'allow_delete' => true,'allow_add' => true,'allow_sequence' => false,'attr' => [
                        'class' => 'tab-pane tab-pane-collection','data-role' => 'products-content-blocks',],]
            )
            ->addEventListener(
                FormEvents::PRE_SET_DATA,function (FormEvent $event) {
                    /** @var CreateProduct|UpdateProduct $productFormData */
                    $productFormData = $event->getForm()->getParent()->getParent()->getData();

                    // Add Meta
                    $event->getForm()
                        ->add(
                            'Meta',MetaType::class,[
                                'detail_url' => Model::getUrlForBlock('Products','ProductDetail'),'base_field_name' => 'title','generate_url_callback_class' => ProductTranslationRepository::class,'generate_url_callback_method' => 'self::getUrl','generate_url_callback_parameters' => [
                                    $event->getData()->getLocale(),$productFormData->hasExistingProduct()
                                        ? $productFormData->getProductEntity()->getId() : null,]
                        );
                }
            );
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults(['data_class' => ProductTranslationDataTransferObject::class]);
    }
}

ContentBlockType.PHP

<?PHP

namespace Backend\Modules\Products\Domain\ContentBlock;

use Backend\Core\Engine\TemplateModifiers;
use Backend\Form\Type\EditorType;
use Common\Form\CollectionType;
use Common\Form\ImageType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\Valid;

final class ContentBlockType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder,array $options): void
    {
        $builder->add(
            'sequence',HiddenType::class,'attr' => [
                    'data-role' => 'sequence'
                ]
            ]
        );
        $builder->add(
            'type',ChoiceType::class,[
                'label' => 'lbl.Type','choices' => array_map(
                    function ($contentType) {
                        return new ContentType($contentType);
                    },ContentType::POSSIBLE_VALUES
                ),'choice_label' => function (ContentType $contentType) {
                    return TemplateModifiers::toLabel($contentType);
                },'choice_translation_domain' => false,'choice_value' => function (ContentType $contentType = null) {
                    return (string) $contentType;
                },'attr' => [
                    'data-role' => 'products-content-blocks-type',]
        );
        $builder->add(
            'text',EditorType::class,[
                'label' => 'lbl.Text','required' => false,'attr' => [
                    'class' => 'inputEditor','data-show' => 'type-text',]
        );
        $builder->add(
            'image',[
                'label' => 'lbl.Image','image_class' => Image::class,'show_remove_image' => false,]
        );
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults(['data_class' => ContentBlockDataTransferObject::class]);
    }
}

ProductAdd.PHP 操作

<?PHP

namespace Backend\Modules\Products\Actions;

use Backend\Core\Engine\Base\ActionAdd;
use Backend\Core\Language\Language;
use Backend\Core\Language\Locale;
use Backend\Modules\Products\Domain\Product\Command\CreateProduct;
use Backend\Modules\Products\Domain\Product\Command\CreateProductHandler;
use Backend\Modules\Products\Domain\Product\ProductType;
use Backend\Core\Engine\Model as BackendModel;
use Symfony\Component\Form\Form;
use Symfony\Component\Form\FormError;

final class ProductAdd extends ActionAdd
{
    public function execute(): void
    {
        parent::execute();

        $form = $this->getForm();

        if (!$form->isSubmitted() || !$form->isValid()) {
            $this->template->assign('activeTranslationTab','tab' . ucfirst(Locale::workingLocale()));
            $this->template->assign('locale',Locale::workingLocale());
            $this->template->assign('form',$form->createView());
            $this->template->assign('backLink',$this->getBackLink());
            $this->template->assign('imagegallery',$form->getData()->imagegallery);

            $this->parse();
            $this->display();

            return;
        }

        $this->handleForm($form);
    }

    private function handleForm(Form $form): void
    {
        /** @var CreateProduct $product */
        $product = $form->getData();

        // Handle the Product create
        $this->get('command_bus')->handle($product);

        $this->redirect(
            $this->getBackLink(
                [
                    'report' => 'added','var' => $product->translations[(string) Locale::workingLocale()]->title,]
            )
        );
    }

    private function getForm(): Form
    {
        $form = $this->createForm(ProductType::class,new CreateProduct());
        $form->handleRequest($this->getRequest());

        return $form;
    }

    private function getBackLink(array $parameters = []): string
    {
        return BackendModel::createUrlForAction(
            'ProductsIndex',null,$parameters
        );
    }
}

ProductEdit.PHP 操作

<?PHP

namespace Backend\Modules\Products\Actions;

use Backend\Core\Engine\Base\ActionEdit;
use Backend\Core\Language\Language;
use Backend\Core\Language\Locale;
use Backend\Form\Type\DeleteType;
use Backend\Modules\Products\Domain\Product\Command\UpdateProductHandler;
use Backend\Modules\Products\Domain\Product\Product;
use Backend\Modules\Products\Domain\Product\Command\UpdateProduct;
use Backend\Core\Engine\Model as BackendModel;
use Backend\Modules\Products\Domain\Product\ProductRepository;
use Backend\Modules\Products\Domain\Product\ProductType;
use Symfony\Component\Form\Form;
use Symfony\Component\Form\FormError;

final class ProductEdit extends ActionEdit
{
    public function execute(): void
    {
        parent::execute();

        /** @var Product $product */
        $product = $this->getProduct();

        /** @var Form $form */
        $form = $this->getForm($product);

        $deleteForm = $this->createForm(
            DeleteType::class,['id' => $product->getId()],[
                'module' => $this->getModule(),'action' => 'ProductDelete',]
        );

        $this->template->assign('deleteForm',$deleteForm->createView());

        if (!$form->isSubmitted() || !$form->isValid()) {
            $this->template->assign('activeTranslationTab',$form->createView());
            $this->template->assign('product',$product);
            $this->template->assign('imagegallery',$form->getData()->imagegallery);

            $this->parse();
            $this->display();

            return;
        }

        /** @var UpdateProduct $updateProduct */
        $updateProduct = $form->getData();

        // Handle the Product update
        $this->get('command_bus')->handle($updateProduct);

        $this->redirect(
            $this->getBackLink(
                [
                    'report' => 'edited','var' => $updateProduct->translations[(string)Locale::workingLocale()]->title,'highlight' => 'row-' . $updateProduct->getProductEntity()->getId(),]
            )
        );
    }

    private function getProduct(): Product
    {
        try {
            /** @return Product */
            return $this->get(ProductRepository::class)->findOneById($this->getRequest()->query->get('id'));
        } catch (\Exception $e) {
            $this->redirect(
                $this->getBackLink(
                    [
                        'error' => 'non-existing'
                    ]
                )
            );
        }
    }

    private function getBackLink(array $parameters = []): string
    {
        return BackendModel::createUrlForAction(
            'ProductsIndex',$parameters
        );
    }

    private function getForm(Product $product): Form
    {
        $form = $this->createForm(ProductType::class,new UpdateProduct($product));
        $form->handleRequest($this->getRequest());

        return $form;
    }

}

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)