VichUploader图像以嵌入式形式上传(Symfony 3)



如何将正在运行的图像上传表单成功嵌入到具有一对一关系的分类表单中?

Stackoverflow上的第一篇文章,所以请温柔一点(我是法国人......^^)

我有一个Symfony 3.3项目,运行得很好。我使用 VichUploaderBundle 进行上传,使用 LiipImagine 进行渲染。目前,单个图像文件上传没有问题! 我有一个上传测试页面,我显示一个图像文件上传表单,我上传文件...它通过控制器,一切都很好。文件上传并移动到目录中,页面显示新图像,以及所有过滤器。伟大!

我真正的问题出现在将表单嵌入另一个表单中时

我想将我的"图像表单"嵌入到分类表单中。我首先在这个分类表单中创建字段mainImage。分类的关系是一对一的,当然它有级联="持久"和"删除"。

但是在验证时,没有触发任何内容,我在image_name上收到以下错误:

--- 执行"插入到vehicle_ad"(创建位置、更新位置、发布位置、发布位置、朋友优先级、 朋友优先级开始,购买日期,卖出价格,货币,里程表类型, 当前里程表, 能源, 变速箱, 主颜色, 昵称, 描述, creator_id、vehicle_brand_id、vehicle_model_id、main_image_id、 vehicle_id) 值 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'带参数 ["2018-01-23 17:15:39", "2018-01-23 17:15:39", 0, 空, 0, 空, 空, 2650, "欧元", "公里", 17340, 空

, 空, 空, 空, 空, 1, 3, 1, 空, 空]:SQLSTATE[23000]:完整性约束冲突:1048 Le champ

'main_image_id' ne peut être vide (null)

文件为空,未触发上传器命名器...几天后我就被困住了。我做了很多研究...因此,任何帮助将不胜感激。

我尝试尽可能清楚地给出我的代码。一、什么是OK(单张图片上传):

图像类

<?php

namespace GacMediasBundleEntity;

use DoctrineORMMapping as ORM;
use SymfonyComponentValidatorConstraints as Assert;
use SymfonyComponentHttpFoundationFileFile;
use VichUploaderBundleMappingAnnotation as Vich;

/**
* Image
*
* @ORMTable(name="image")
* @ORMEntity(repositoryClass="GacMediasBundleRepositoryImageRepository")
* @VichUploadable
*/
class Image
{
/**
* @var int
*
* @ORMColumn(name="id", type="integer")
* @ORMId
* @ORMGeneratedValue(strategy="AUTO")
*/
private $id;

/* ----------------------------------------------------------------------
---------   Connection with other entities
------------------------------------------------------------------------- */

/**
* @ORMManyToOne(targetEntity="GacUserBundleEntityUser", inversedBy="images")
* @ORMJoinColumn(nullable=false)
*/
private $creator;

/**
* @ORMManyToOne(targetEntity="GacAdsBundleEntityVehicleAd", inversedBy="images")
* @ORMJoinColumn(nullable=true)
*/
private $vehicleAd;

// -------------------------------------------------------------------------------

/**
* @var string
*
* @ORMColumn(name="imageName", type="string", length=255)
*/
private $imageName;

/**
* @VichUploadableField(mapping="users_images", fileNameProperty="imageName")
* @var File
*/
private $imageFile;

/**
* @var DateTime
*
* @ORMColumn(name="createdAt", type="datetime")
* @AssertDateTime()
*/
private $createdAt;

/**
* @var DateTime
*
* @ORMColumn(name="updatedAt", type="datetime")
* @AssertDateTime()
*/
private $updatedAt;

/**
* @var DateTime
*
* @ORMColumn(name="hiddenAt", type="datetime", nullable=true)
* @AssertDateTime()
*/
private $hiddenAt;


public function __construct($thisuser)
{
$this->creator = $thisuser;
$this->createdAt = new Datetime();
$this->updatedAt = new Datetime();
}

/**
* Get id
*
* @return int
*/
public function getId()
{
return $this->id;
}

/**
* Set creator
*
* @param GacUserBundleEntityUser $creator
*
* @return Image
*/
public function setCreator(GacUserBundleEntityUser $creator)
{
$this->creator = $creator;

return $this;
}

/**
* Get creator
*
* @return GacUserBundleEntityUser
*/
public function getCreator()
{
return $this->creator;
}

/**
* Set imageName
*
* @param string $imageName
*
* @return Image
*/
public function setImageName($imageName)
{
$this->imageName = $imageName;

return $this;
}

/**
* Get imageName
*
* @return string
*/
public function getImageName()
{
return $this->imageName;
}

public function setImageFile(File $image = null)
{
$this->imageFile = $image;

// VERY IMPORTANT:
// It is required that at least one field changes if you are using Doctrine,
// otherwise the event listeners won't be called and the file is lost
if ($image) {
$this->updatedAt = new DateTime();
}
}

/**
* Get imageFile
*/
public function getImageFile()
{
return $this->imageFile;
}

/**
* Set createdAt
*
* @param DateTime $createdAt
*
* @return Image
*/
public function setCreatedAt($createdAt)
{
$this->createdAt = $createdAt;

return $this;
}

/**
* Get createdAt
*
* @return DateTime
*/
public function getCreatedAt()
{
return $this->createdAt;
}

/**
* Set updatedAt
*
* @param DateTime $updatedAt
*
* @return Image
*/
public function setUpdatedAt($updatedAt)
{
$this->updatedAt = $updatedAt;

return $this;
}

/**
* Get updatedAt
*
* @return DateTime
*/
public function getUpdatedAt()
{
return $this->updatedAt;
}

/**
* Set hiddenAt
*
* @param DateTime $hiddenAt
*
* @return Image
*/
public function setHiddenAt($hiddenAt)
{
$this->hiddenAt = $hiddenAt;

return $this;
}

/**
* Get hiddenAt
*
* @return DateTime
*/
public function getHiddenAt()
{
return $this->hiddenAt;
}

/**
* Set vehicleAd
*
* @param GacAdsBundleEntityVehicleAd $vehicleAd
*
* @return Image
*/
public function setVehicleAd(GacAdsBundleEntityVehicleAd $vehicleAd = null)
{
$this->vehicleAd = $vehicleAd;

return $this;
}

/**
* Get vehicleAd
*
* @return GacAdsBundleEntityVehicleAd
*/
public function getVehicleAd()
{
return $this->vehicleAd;
}
}

然后相关的图像形式:

<?php

namespace GacMediasBundleForm;

use SymfonyComponentFormAbstractType;
use SymfonyComponentFormFormBuilderInterface;
use SymfonyComponentOptionsResolverOptionsResolver;
use VichUploaderBundleFormTypeVichImageType;

class ImageType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('imageFile',       VichImageType::class, [
'label' => false,
'required' => false,
'allow_delete' => false,
]);
}

/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'GacMediasBundleEntityImage'
));
}

/**
* {@inheritdoc}
*/
public function getBlockPrefix()
{
//return 'gac_mediasbundle_image';
return 'ImageType';
}


}

和控制器

{% extends 'medias/layout.html.twig' %}

{% block bundle_content %}

<div class="jumbotron text-center">
<h1>Testing user's images UPLOAD</h1>
</div>

<p>-----------------</p>
{{ form_start(form) }}
{{ form_errors(form) }}
{{ form_row(form) }}
<button type="submit">Upload</button>
{{ form_end(form) }}
<p>-----------------</p>

{% for picture in pictures %}
<div class="row">
<div class="media">
<div class="media-left media-middle">
<img class="media-object" src="{{ picture.imageName | imagine_filter('tiny_test') }}" alt="{{ 'GearsAndCoffee-'~picture.imageName }}" /><br/>
</div>
<div class="media-body">
<h4 class="media-heading">Filter name :</h4>
<em>tiny_test</em>
</div>
</div>
<div class="media">
<div class="media-left media-middle">
<a href="{{ asset('uploads/images/'~picture.imageName) }}" />
<img class="media-object" src="{{ picture.imageName | imagine_filter('std_display') }}" alt="{{ 'GearsAndCoffee-'~picture.imageName }}" /><br/>
</a>
</div>
<div class="media-body">
<h4 class="media-heading">Filter name :</h4>
<em>std_display</em>
</div>
</div>
<p>
<a href="{{ path('gac_medias_updatetest', {'id': picture.id}) }}"><strong>UPDATE IMAGE</strong></a>
</p>
<p>
<a href="{{ path('gac_medias_removetest', {'id': picture.id}) }}"><strong>DELETE IMAGE</strong></a>
</p>
</div>
<p>-----------------</p>
{% endfor %}

{% endblock bundle_content %}

作为信息,VichUploader 捆绑包配置:

vich_uploader:
db_driver: orm
#templating: true
#twig:       true               
#form:       true
mappings:
users_images:
uri_prefix:         '%app.path.users_images%'
upload_destination: '%kernel.root_dir%/../web/uploads/images'
namer:              vich_uploader.namer_uniqid
inject_on_load:     true
delete_on_update:   true
delete_on_remove:   true

现在我的应用程序上没有运行的代码:

分类类

<?php

namespace GacAdsBundleEntity;

use DoctrineORMMapping as ORM;
use SymfonyComponentValidatorConstraints as Assert;
use DoctrineCommonCollectionsArrayCollection;

/**
* VehicleAd
*
* @ORMTable(name="vehicle_ad")
* @ORMEntity(repositoryClass="GacAdsBundleRepositoryVehicleAdRepository")
* @ORMHasLifecycleCallbacks
*/
class VehicleAd
{
/**
* @var int
*
* @ORMColumn(name="id", type="integer")
* @ORMId
* @ORMGeneratedValue(strategy="AUTO")
*/
private $id;

/* ----------------------------------------------------------------------
---------   Connection with other entities
------------------------------------------------------------------------- */

/**
* @ORMManyToOne(targetEntity="GacUserBundleEntityUser")
* @ORMJoinColumn(nullable=false)
*/
private $creator;

/**
* @ORMManyToOne(targetEntity="GacVehiclesBundleEntityVehicleBrand")
* @ORMJoinColumn(nullable=false)
*/
private $vehicleBrand;

/**
* @ORMManyToOne(targetEntity="GacVehiclesBundleEntityVehicleModel")
* @ORMJoinColumn(nullable=false)
*/
private $vehicleModel;

/**
* @ORMOneToOne(targetEntity="GacMediasBundleEntityImage", cascade={"persist", "remove"})
* @ORMJoinColumn(nullable=false)
*/
private $mainImage;

// -------------------------------------------------------------------------------

// ---------------- General status and dates for the AD -------------

/**
* @var DateTime
*
* @ORMColumn(name="createdAt", type="datetime")
* @AssertDateTime()
*/
private $createdAt;

/**
* @var DateTime
*
* @ORMColumn(name="updatedAt", type="datetime")
* @AssertDateTime()
*/
private $updatedAt;

// ---------------------- AD main content -----------------------

/**
* @var string
*
* @ORMColumn(name="description", type="text", nullable=true)
* @AssertType("string")
*/
private $description;


// ************************* FUNCTIONS ***************************

public function __construct($thisuser)
{
$this->creator = $thisuser;
$this->createdAt = new Datetime();
$this->updatedAt = new Datetime();
}

/**
* Change updatedAt field just before ORM update
*
* @ORMPreUpdate
*/
public function changeUpdatedAt()
{
$this->updatedAt = new Datetime();
}

/**
* Get id
*
* @return int
*/
public function getId()
{
return $this->id;
}

/**
* Set createdAt
*
* @param DateTime $createdAt
*
* @return VehicleAd
*/
public function setCreatedAt($createdAt)
{
$this->createdAt = $createdAt;

return $this;
}

/**
* Get createdAt
*
* @return DateTime
*/
public function getCreatedAt()
{
return $this->createdAt;
}

/**
* Set updatedAt
*
* @param DateTime $updatedAt
*
* @return VehicleAd
*/
public function setUpdatedAt($updatedAt)
{
$this->updatedAt = $updatedAt;

return $this;
}

/**
* Get updatedAt
*
* @return DateTime
*/
public function getUpdatedAt()
{
return $this->updatedAt;
}

/**
* Set creator
*
* @param GacUserBundleEntityUser $creator
*
* @return VehicleAd
*/
public function setCreator(GacUserBundleEntityUser $creator)
{
$this->creator = $creator;

return $this;
}

/**
* Get creator
*
* @return GacUserBundleEntityUser
*/
public function getCreator()
{
return $this->creator;
}

/**
* Set description
*
* @param string $description
*
* @return VehicleAd
*/
public function setDescription($description)
{
$this->description = $description;

return $this;
}

/**
* Get description
*
* @return string
*/
public function getDescription()
{
return $this->description;
}

/**
* Set vehicleBrand
*
* @param GacVehiclesBundleEntityVehicleBrand $vehicleBrand
*
* @return VehicleAd
*/
public function setVehicleBrand(GacVehiclesBundleEntityVehicleBrand $vehicleBrand)
{
$this->vehicleBrand = $vehicleBrand;

return $this;
}

/**
* Get vehicleBrand
*
* @return GacVehiclesBundleEntityVehicleBrand
*/
public function getVehicleBrand()
{
return $this->vehicleBrand;
}

/**
* Set vehicleModel
*
* @param GacVehiclesBundleEntityVehicleModel $vehicleModel
*
* @return VehicleAd
*/
public function setVehicleModel(GacVehiclesBundleEntityVehicleModel $vehicleModel)
{
$linkedBrand = $vehicleModel->getModelBrand();

$this->vehicleBrand = $linkedBrand;
$this->vehicleModel = $vehicleModel;

return $this;
}

/**
* Get vehicleModel
*
* @return GacVehiclesBundleEntityVehicleModel
*/
public function getVehicleModel()
{
return $this->vehicleModel;
}

/**
* Set mainImage
*
* @param GacMediasBundleEntityImage $mainImage
*
* @return VehicleAd
*/
public function setMainImage(GacMediasBundleEntityImage $mainImage)
{
$this->mainImage = $mainImage;

return $this;
}

/**
* Get mainImage
*
* @return GacMediasBundleEntityImage
*/
public function getMainImage()
{
return $this->mainImage;
}
}

当然是最大的,我的分类表格!

<?php

namespace GacAdsBundleForm;

use SymfonyComponentFormAbstractType;
use SymfonyComponentFormFormInterface;
use SymfonyComponentFormFormBuilderInterface;
use SymfonyComponentFormFormEvent;
use SymfonyComponentFormFormEvents;
use SymfonyComponentOptionsResolverOptionsResolver;
use SymfonyBridgeDoctrineFormTypeEntityType;
use SymfonyComponentFormExtensionCoreTypeChoiceType;
use SymfonyComponentFormExtensionCoreTypeTextType;
use SymfonyComponentFormExtensionCoreTypeTextareaType;
use SymfonyComponentFormExtensionCoreTypeCheckboxType;
use SymfonyComponentFormExtensionCoreTypeIntegerType;
use SymfonyComponentFormExtensionCoreTypeDateType;
use SymfonyComponentFormExtensionCoreTypeCollectionType;
use GacMediasBundleFormImageType;
use GacVehiclesBundleEntityVehicleBrand;
use GacVehiclesBundleEntityVehicleModel;

class VehicleAdType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$globalDatas = $options['globalDatas'];

$builder->add('vehicleBrand', EntityType::class, array(
'class' => 'GacVehiclesBundle:VehicleBrand',
'choice_label' => 'brandName',
'placeholder' => 'Please select a brand :',
))
->add('vehicleModel', EntityType::class, array(
'class' => 'GacVehiclesBundle:VehicleModel',
'choice_label' => 'modelName',
))
->add('description', TextareaType::class, array('required' => false));

$builder->add('mainImage', ImageType::class);

$formModifier = function (FormInterface $form, VehicleBrand $vehicleBrand = null) {
$models = null === $vehicleBrand ? array() : $vehicleBrand->getVehicleModels();

$form->add('vehicleModel', EntityType::class, array(
'class' => 'GacVehiclesBundle:VehicleModel',
'choice_label' => 'modelName',
'choices' => $models,
));
};

$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($formModifier) {
// this would be your entity, i.e. Brand
$data = $event->getData();

$formModifier($event->getForm(), $data->getVehicleBrand());
}
);

$builder->get('vehicleBrand')->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) use ($formModifier) {
$vehicleBrand = $event->getForm()->getData();
$formModifier($event->getForm()->getParent(), $vehicleBrand);
}
);
}

/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'GacAdsBundleEntityVehicleAd',
'globalDatas' => null,
));
}

/**
* {@inheritdoc}
*/
public function getBlockPrefix()
{
return 'gac_adsbundle_vehiclead';
}


}

分类创建控制器

<?php

namespace GacAdsBundleController;

use SymfonyBundleFrameworkBundleControllerController;
use SymfonyComponentSecurityCoreExceptionAccessDeniedException;
use SymfonyComponentHttpKernelExceptionNotFoundHttpException;
use SymfonyComponentHttpFoundationRequest;
use SymfonyComponentHttpFoundationResponse;
use GacMediasBundleEntityImage;
use GacMediasBundleFormImageType;
use GacAdsBundleEntityVehicleAd;
use GacAdsBundleFormVehicleAdType;
use GacVehiclesBundleEntityVehicle;
use GacVehiclesBundleFormVehicleType;
use GacVehiclesBundleEntityVehicleModel;
use GacVehiclesBundleEntityVehicleBrand;

class ManageController extends Controller
{  
public function sellvehicleAction(Request $request)
{
$this->denyAccessUnlessGranted('ROLE_USER');
$thisuser = $this->get('security.token_storage')->getToken()->getUser();
$em = $this->getDoctrine()->getManager();

// Create new ad and load a "mainImage"
$classified = new VehicleAd($thisuser);
$oneImage = new Image($thisuser);
$classified->setMainImage($oneImage);

$globalDatas = $this->container->get('gac_general.globaldatas');  // Always pass globalDatas VAR to any created form in the application
$form = $this->createForm(VehicleAdType::class, $classified, array(
'globalDatas' => $globalDatas,
));

$form->handleRequest($request);
if ($request->isMethod('POST') && $form->isValid()) {
$em->persist($classified);
$em->flush();

$id = $classified->getId();

return $this->redirectToRoute('gac_ads_previewvehiclead', array('id' => $id));
}

return $this->render('ads/manage/sellvehicle.html.twig', array(
'form' => $form->createView()
));
}
}

最后是我的分类形式的观点

{% extends 'ads/layout.html.twig' %}

{% block bundle_content %}
<form action="{{ path('gac_ads_sellvehicle') }}" method="post">

<div class="row justify-content-center">
<div class="col-md-8">
{{ form_errors(form) }}
<div class="card mb-3">
<div class="card-body">
<p class="text-primary"><strong>{{ 'mandatory informations'|trans|capitalize }} :</strong></p>
{{ form_row(form.vehicleBrand, {'label': 'Vehicle Brand :'}) }}
{{ form_row(form.vehicleModel, {'label': 'Vehicle Model :'}) }}
</div>
</div>

<div class="card mb-3">
<div class="card-body">
<p class="text-primary">{{ 'image'|trans|capitalize }} :</p>
<div id="toto">
{{ form_row(form.mainImage.imageFile) }}
</div>
</div>
</div>

<div class="card mb-3">
<div class="card-body">
<p class="text-primary">{{ 'other parameters'|trans|capitalize }} ({{ 'optional'|trans }}) :</p>
<p class="text-primary">{{ 'tell us a few words about your vehicle'|trans|capitalize }} ({{ 'optional'|trans }}) :</p>
{{ form_row(form.description, {'label': 'Description :'}) }}
</div>
</div>
</div>
<div class="col-md-4">
<div class="card mb-3">
<div class="card-body">
{{ form_rest(form) }}
</div>
</div>
<button type="submit" class="btn btn-block btn-primary">{{ 'preview your ad'|capitalize }}</button>
</div>
</div>
</form>
{% endblock bundle_content %}

我必须说,在问之前,我自己做了很多搜索(测试......)和大量的谷歌搜索。我知道Vich上传器有一些棘手的事情,但我管理了一切,因为...它适用于一个文件。

所以问题是:你能帮我让我的上传和我的表单在嵌入另一个表单时工作吗?

多谢!

问候

尝试以"分类"形式执行此操作:...add('description', textAreaType::class) ->add('mainImage', ImageType::class);也许,使用两次表单生成器实例"$builder"会导致问题。无论如何:见这里 公式 Imbriqués.我这样做了,它非常适合使用 vich 的嵌入式表单

相关内容

  • 没有找到相关文章

最新更新