Symfony3与PhpStorm.2016.3.2
我成功为一张图片制作文件上传器。但现在我需要让它“多重”
我将向您展示代码及其出现的错误,因为我无法上传多个文件。
这是控制器
public function newAction(Request $request)
{
$restaurant = new Restaurant();
$form = $this->createForm(RestaurantType::class, $restaurant);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
// file upload
if ($request->files->get('restaurant')['picture'] != null) {
$file = $request->files->get('restaurant')['picture'];
$targetDir = $this->getParameter('uploaded_restaurants');
$filename = $this->get('app.uploader')->upload($file, $targetDir);
$mediaRestaurant = null;
if ($restaurant->getId() != null) {
$mediaRestaurant = $this->getDoctrine()->getRepository('AppBundle:Media')->findPictureByRestaurant($restaurant);
}
if ($mediaRestaurant) {
$media = $mediaRestaurant;
$fs = new Filesystem();
try {
$fs->remove($this->get('kernel')->getRootDir().'/../web/uploads/restaurants/'.$media->getName());
} catch (IOException $e) {
echo "error";
}
} else {
$media = new Media();
$media->setCreatedAt(new \DateTime());
}
$originalName = $file->getClientOriginalName();
$media->setName($filename)
->setOriginalName($originalName)
->setType('img')
->setContext('restaurant_picture')
->setUpdatedAt(new \DateTime())
;
$media->setRestaurant($restaurant);
$em->persist($media);
}
$restaurant->setIsActivated(false);
$em->persist($restaurant);
$em->flush();
}
return $this->render('admin/restaurant/new.html.twig', array(
'restaurant' => $restaurant,
'form' => $form->createView(),
));
}
我的FormType(称为RestaurantType),我在其中添加了文件上传字段(当我将multiple
设置为false
时,它实际上仅适用于一张图片)
$builder
->add('picture', FileType::class, array(
'label' => 'Photos du restaurant',
'multiple' => true,
'required' => false,
'mapped' => false,
'attr' => array(
'accept' => '.jpg,.jpeg,.png'),
))
上传文件的服务
class FileUploader
{
/**
* @param UploadedFile $file
* @param $targetDir
* @return string
*/
public function upload(UploadedFile $file, $targetDir)
{
$fileName = md5(uniqid()).'.'.$file->guessExtension();
$file->move($targetDir, $fileName);
return $fileName;
}
}
MediaRepository中的queryBuilder
public function findPictureByRestaurant(Restaurant $restaurant)
{
return $this->createQueryBuilder('m')
->select('m')
->where('m.restaurant = :restaurant')
->setParameter('restaurant', $restaurant)
->andWhere('m.context = :restaurant_picture')
->setParameter('restaurant_picture', 'restaurant_picture')
->getQuery()
->getOneOrNullResult();
}
在我的show.html.twig中,您可以看到图片
{% if restaurant.medias != null and restaurant.medias.count > 0 and restaurant.medias[0].name != null %}
<img src="/uploads/restaurants/{{ restaurant.medias[0].name }}">
{% endif %}
我的config.yml上传文件
parameters:
locale: fr
uploaded_restaurants: "%kernel.root_dir%/../web/uploads/restaurants"
实体Restaurant
很长(抱歉)
/**
* Restaurant
*
* @ORM\Table(name="restaurant")
* @ORM\Entity(repositoryClass="AppBundle\Repository\RestaurantRepository")
*/
class Restaurant
{
/**
* @var FoodType
*
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\FoodType", inversedBy="restaurants")
* @ORM\JoinColumn(name="food_type_id", referencedColumnName="id")
*/
private $foodType;
/**
* @var City
*
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\City", inversedBy="restaurants")
* @ORM\JoinColumn(name="city_id", referencedColumnName="id")
*/
private $city;
/**
* @var ArrayCollection
*
* @ORM\OneToMany(targetEntity="AppBundle\Entity\Media", mappedBy="restaurant")
*/
private $medias;
/**
* @var ArrayCollection
*
* @ORM\OneToMany(targetEntity="AppBundle\Entity\Privatisation", mappedBy="restaurant")
*/
private $privatisations;
/**
* @var ArrayCollection
*
* @ORM\OneToMany(targetEntity="AppBundle\Entity\Retrocession", mappedBy="restaurant")
*/
private $retrocessions;
/**
* @var ArrayCollection
*
* @ORM\OneToMany(targetEntity="AppBundle\Entity\OpenedSlot", mappedBy="restaurant")
*/
private $openedSlots;
/**
* @var ArrayCollection
*
* @ORM\OneToMany(targetEntity="AppBundle\Entity\ExceptionSlot", mappedBy="restaurant")
*/
private $exceptionSlots;
/**
* @var ArrayCollection
*
* @ORM\OneToMany(targetEntity="AppBundle\Entity\Slot", mappedBy="restaurant")
*/
private $slots;
/**
* @var ArrayCollection
*
* @ORM\OneToMany(targetEntity="AppBundle\Entity\Chef", mappedBy="restaurant")
*/
private $chefs;
/**
* Constructor
*/
public function __construct()
{
$this->medias = new ArrayCollection();
$this->privatisations = new ArrayCollection();
$this->retrocessions = new ArrayCollection();
$this->openedSlots = new ArrayCollection();
$this->exceptionSlots = new ArrayCollection();
$this->slots = new ArrayCollection();
$this->chefs = new ArrayCollection();
}
/**
* @var int
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=120, unique=true)
* @Assert\Length(
* max = 120,
* maxMessage = "Ce champ ne peut pas dépasser {{ limit }} caractères."
* )
*/
private $name;
/**
* @var string
*
* @ORM\Column(name="slug", type="string", length=255, unique=true)
* @Gedmo\Slug(fields={"name"})
* @Assert\Length(
* max = 255,
* maxMessage = "Ce champ ne peut pas dépasser {{ limit }} caractères."
* )
*/
private $slug;
/**
* @var string
*
* @ORM\Column(name="description", type="text")
*/
private $description;
/**
* @var string
*
* @ORM\Column(name="webUrl", type="string", length=255, nullable=true)
* @Assert\Length(
* max = 255,
* maxMessage = "Ce champ ne peut pas dépasser {{ limit }} caractères."
* )
*/
private $webUrl;
/**
* @var string
*
* @ORM\Column(name="tripAdvisorUrl", type="string", length=255, nullable=true)
* @Assert\Length(
* max = 255,
* maxMessage = "Ce champ ne peut pas dépasser {{ limit }} caractères."
* )
*/
private $tripAdvisorUrl;
/**
* @var string
*
* @ORM\Column(name="facebookUrl", type="string", length=255, nullable=true)
* @Assert\Length(
* max = 255,
* maxMessage = "Ce champ ne peut pas dépasser {{ limit }} caractères."
* )
*/
private $facebookUrl;
/**
* @var string
*
* @ORM\Column(name="twitterUrl", type="string", length=255, nullable=true)
* @Assert\Length(
* max = 255,
* maxMessage = "Ce champ ne peut pas dépasser {{ limit }} caractères."
* )
*/
private $twitterUrl;
/**
* @var string
*
* @ORM\Column(name="instagramUrl", type="string", length=255, nullable=true)
* @Assert\Length(
* max = 255,
* maxMessage = "Ce champ ne peut pas dépasser {{ limit }} caractères."
* )
*/
private $instagramUrl;
/**
* @var string
*
* @ORM\Column(name="phone", type="string", length=20)
* @Assert\Regex(
* pattern="#^0[1-9]([-. ]?[0-9]{2}){4}$#",
* match=true,
* message="Numéro de téléphone invalide."
* )
*/
private $phone;
/**
* @var string
*
* @ORM\Column(name="phone2", type="string", length=20, nullable=true)
* @Assert\Regex(
* pattern="#^0[1-9]([-. ]?[0-9]{2}){4}$#",
* match=true,
* message="Numéro de téléphone invalide."
* )
*/
private $phone2;
/**
* @var string
*
* @ORM\Column(name="email", type="string", length=255)
* @Assert\Length(
* max = 255,
* maxMessage = "Ce champ ne peut pas dépasser {{ limit }} caractères."
* )
*/
private $email;
/**
* @var float
*
* @ORM\Column(name="latitude", type="float")
* @Assert\Regex(
* pattern="/^-?(?:\d+|\d*\.\d+)$/",
* match=true,
* )
*/
private $latitude;
/**
* @var float
*
* @ORM\Column(name="longitude", type="float")
* @Assert\Regex(
* pattern="/^-?(?:\d+|\d*\.\d+)$/",
* match=true,
* )
*/
private $longitude;
/**
* @var int
*
* @ORM\Column(name="stars", type="integer", nullable=true)
* @Assert\Regex(
* pattern="/^[0-9]+$/",
* match=true,
* message="Ceci n'est pas un chiffre."
* )
*/
private $stars;
/**
* @var int
*
* @ORM\Column(name="seatNumber", type="integer", nullable=true)
* @Assert\Regex(
* pattern="/^[0-9]+$/",
* match=true,
* )
*/
private $seatNumber;
/**
* @var float
*
* @ORM\Column(name="minPrice", type="float", nullable=true)
* @Assert\Regex(
* pattern="/^-?(?:\d+|\d*\.\d+)$/",
* match=true,
* )
*/
private $minPrice;
/**
* @var float
*
* @ORM\Column(name="maxPrice", type="float", nullable=true)
* @Assert\Regex(
* pattern="/^-?(?:\d+|\d*\.\d+)$/",
* match=true,
* )
*/
private $maxPrice;
/**
* @var string
*
* @ORM\Column(name="address", type="string", length=255)
* @Assert\Length(
* max = 255,
* maxMessage = "Ce champ ne peut pas dépasser {{ limit }} caractères."
* )
*/
private $address;
/**
* @var bool
*
* @ORM\Column(name="is_activated", type="boolean")
*/
private $isActivated = true;
/**
* Get id
*
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* @param string $name
*
* @return Restaurant
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Set slug
*
* @param string $slug
*
* @return Restaurant
*/
public function setSlug($slug)
{
$this->slug = $slug;
return $this;
}
/**
* Get slug
*
* @return string
*/
public function getSlug()
{
return $this->slug;
}
/**
* Set description
*
* @param string $description
*
* @return Restaurant
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* @return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set webUrl
*
* @param string $webUrl
*
* @return Restaurant
*/
public function setWebUrl($webUrl)
{
$this->webUrl = $webUrl;
return $this;
}
/**
* Get webUrl
*
* @return string
*/
public function getWebUrl()
{
return $this->webUrl;
}
/**
* Set tripAdvisorUrl
*
* @param string $tripAdvisorUrl
*
* @return Restaurant
*/
public function setTripAdvisorUrl($tripAdvisorUrl)
{
$this->tripAdvisorUrl = $tripAdvisorUrl;
return $this;
}
/**
* Get tripAdvisorUrl
*
* @return string
*/
public function getTripAdvisorUrl()
{
return $this->tripAdvisorUrl;
}
/**
* Set facebookUrl
*
* @param string $facebookUrl
*
* @return Restaurant
*/
public function setFacebookUrl($facebookUrl)
{
$this->facebookUrl = $facebookUrl;
return $this;
}
/**
* Get facebookUrl
*
* @return string
*/
public function getFacebookUrl()
{
return $this->facebookUrl;
}
/**
* Set twitterUrl
*
* @param string $twitterUrl
*
* @return Restaurant
*/
public function setTwitterUrl($twitterUrl)
{
$this->twitterUrl = $twitterUrl;
return $this;
}
/**
* Get twitterUrl
*
* @return string
*/
public function getTwitterUrl()
{
return $this->twitterUrl;
}
/**
* Set instagramUrl
*
* @param string $instagramUrl
*
* @return Restaurant
*/
public function setInstagramUrl($instagramUrl)
{
$this->instagramUrl = $instagramUrl;
return $this;
}
/**
* Get instagramUrl
*
* @return string
*/
public function getInstagramUrl()
{
return $this->instagramUrl;
}
/**
* Set phone
*
* @param string $phone
*
* @return Restaurant
*/
public function setPhone($phone)
{
$this->phone = $phone;
return $this;
}
/**
* Get phone
*
* @return string
*/
public function getPhone()
{
return $this->phone;
}
/**
* Set phone2
*
* @param string $phone2
*
* @return Restaurant
*/
public function setPhone2($phone2)
{
$this->phone2 = $phone2;
return $this;
}
/**
* Get phone2
*
* @return string
*/
public function getPhone2()
{
return $this->phone2;
}
/**
* Set email
*
* @param string $email
*
* @return Restaurant
*/
public function setEmail($email)
{
$this->email = $email;
return $this;
}
/**
* Get email
*
* @return string
*/
public function getEmail()
{
return $this->email;
}
/**
* Set latitude
*
* @param float $latitude
*
* @return Restaurant
*/
public function setLatitude($latitude)
{
$this->latitude = $latitude;
return $this;
}
/**
* Get latitude
*
* @return float
*/
public function getLatitude()
{
return $this->latitude;
}
/**
* Set longitude
*
* @param float $longitude
*
* @return Restaurant
*/
public function setLongitude($longitude)
{
$this->longitude = $longitude;
return $this;
}
/**
* Get longitude
*
* @return float
*/
public function getLongitude()
{
return $this->longitude;
}
/**
* Set stars
*
* @param integer $stars
*
* @return Restaurant
*/
public function setStars($stars)
{
$this->stars = $stars;
return $this;
}
/**
* Get stars
*
* @return int
*/
public function getStars()
{
return $this->stars;
}
/**
* Set seatNumber
*
* @param integer $seatNumber
*
* @return Restaurant
*/
public function setSeatNumber($seatNumber)
{
$this->seatNumber = $seatNumber;
return $this;
}
/**
* Get seatNumber
*
* @return int
*/
public function getSeatNumber()
{
return $this->seatNumber;
}
/**
* Set minPrice
*
* @param float $minPrice
*
* @return Restaurant
*/
public function setMinPrice($minPrice)
{
$this->minPrice = $minPrice;
return $this;
}
/**
* Get minPrice
*
* @return float
*/
public function getMinPrice()
{
return $this->minPrice;
}
/**
* Set maxPrice
*
* @param float $maxPrice
*
* @return Restaurant
*/
public function setMaxPrice($maxPrice)
{
$this->maxPrice = $maxPrice;
return $this;
}
/**
* Get maxPrice
*
* @return float
*/
public function getMaxPrice()
{
return $this->maxPrice;
}
/**
* Set address
*
* @param string $address
*
* @return Restaurant
*/
public function setAddress($address)
{
$this->address = $address;
return $this;
}
/**
* Get address
*
* @return string
*/
public function getAddress()
{
return $this->address;
}
/**
* Add media
*
* @param Media $media
*
* @return Restaurant
*/
public function addMedia(Media $media)
{
$this->medias[] = $media;
return $this;
}
/**
* Remove media
*
* @param Media $media
*/
public function removeMedia(Media $media)
{
$this->medias->removeElement($media);
}
/**
* Get medias
*
* @return ArrayCollection
*/
public function getMedias()
{
return $this->medias;
}
/**
* Set foodType
*
* @param FoodType $foodType
*
* @return Restaurant
*/
public function setFoodType(FoodType $foodType = null)
{
$this->foodType = $foodType;
return $this;
}
/**
* Get foodType
*
* @return FoodType
*/
public function getFoodType()
{
return $this->foodType;
}
/**
* Add privatisation
*
* @param Privatisation $privatisation
*
* @return Restaurant
*/
public function addPrivatisation(Privatisation $privatisation)
{
$this->privatisations[] = $privatisation;
return $this;
}
/**
* Remove privatisation
*
* @param Privatisation $privatisation
*/
public function removePrivatisation(Privatisation $privatisation)
{
$this->privatisations->removeElement($privatisation);
}
/**
* Get privatisations
*
* @return ArrayCollection
*/
public function getPrivatisations()
{
return $this->privatisations;
}
/**
* Add retrocession
*
* @param Retrocession $retrocession
*
* @return Restaurant
*/
public function addRetrocession(Retrocession $retrocession)
{
$this->retrocessions[] = $retrocession;
return $this;
}
/**
* Remove retrocession
*
* @param Retrocession $retrocession
*/
public function removeRetrocession(Retrocession $retrocession)
{
$this->retrocessions->removeElement($retrocession);
}
/**
* Get retrocessions
*
* @return ArrayCollection
*/
public function getRetrocessions()
{
return $this->retrocessions;
}
/**
* Add openedSlot
*
* @param OpenedSlot $openedSlot
*
* @return Restaurant
*/
public function addOpenedSlot(OpenedSlot $openedSlot)
{
$this->openedSlots[] = $openedSlot;
return $this;
}
/**
* Remove openedSlot
*
* @param OpenedSlot $openedSlot
*/
public function removeOpenedSlot(OpenedSlot $openedSlot)
{
$this->openedSlots->removeElement($openedSlot);
}
/**
* Get openedSlots
*
* @return ArrayCollection
*/
public function getOpenedSlots()
{
return $this->openedSlots;
}
/**
* Add exceptionSlot
*
* @param ExceptionSlot $exceptionSlot
*
* @return Restaurant
*/
public function addExceptionSlot(ExceptionSlot $exceptionSlot)
{
$this->exceptionSlots[] = $exceptionSlot;
return $this;
}
/**
* Remove exceptionSlot
*
* @param ExceptionSlot $exceptionSlot
*/
public function removeExceptionSlot(ExceptionSlot $exceptionSlot)
{
$this->exceptionSlots->removeElement($exceptionSlot);
}
/**
* Get exceptionSlots
*
* @return ArrayCollection
*/
public function getExceptionSlots()
{
return $this->exceptionSlots;
}
/**
* Add slot
*
* @param Slot $slot
*
* @return Restaurant
*/
public function addSlot(Slot $slot)
{
$this->slots[] = $slot;
return $this;
}
/**
* Remove slot
*
* @param Slot $slot
*/
public function removeSlot(Slot $slot)
{
$this->slots->removeElement($slot);
}
/**
* Get slots
*
* @return ArrayCollection
*/
public function getSlots()
{
return $this->slots;
}
/**
* Add chef
*
* @param Chef $chef
*
* @return Restaurant
*/
public function addChef(Chef $chef)
{
$this->chefs[] = $chef;
return $this;
}
/**
* Remove chef
*
* @param Chef $chef
*/
public function removeChef(Chef $chef)
{
$this->chefs->removeElement($chef);
}
/**
* Get chefs
*
* @return ArrayCollection
*/
public function getChefs()
{
return $this->chefs;
}
/**
* Set city
*
* @param City $city
*
* @return Restaurant
*/
public function setCity(City $city = null)
{
$this->city = $city;
return $this;
}
/**
* Get city
*
* @return City
*/
public function getCity()
{
return $this->city;
}
/**
* @return bool
*/
public function getIsActivated()
{
return $this->isActivated;
}
/**
* @param bool $isActivated
*/
public function setIsActivated($isActivated)
{
$this->isActivated = $isActivated;
}
}
以及我上传图片并点击submit
按钮
总结一下,当我在multiple
中设置false
到FormType
时,此代码仅适用于一张图片。但后来我被困在多文件上传中,我无法找到解决方法。有人知道如何处理我给你的代码吗?
谢谢
答案 0 :(得分:1)
由于您的文件定义接受多次上传,因此您需要修改控制器的上传部分:
// file upload
if ($request->files->get('restaurant')['picture'] != null) {
$files = $request->files->get('restaurant')['picture'];
foreach ($files as $file) {
$targetDir = $this->getParameter('uploaded_restaurants');
$filename = $this->get('app.uploader')->upload($file, $targetDir);
$mediaRestaurant = null;
if ($restaurant->getId() != null) {
$mediaRestaurant = $this->getDoctrine()->getRepository('AppBundle:Media')->findPictureByRestaurant($restaurant);
}
if ($mediaRestaurant) {
$media = $mediaRestaurant;
$fs = new Filesystem();
try {
$fs->remove($this->get('kernel')->getRootDir().'/../web/uploads/restaurants/'.$media->getName());
} catch (IOException $e) {
echo "error";
}
} else {
$media = new Media();
$media->setCreatedAt(new \DateTime());
}
$originalName = $file->getClientOriginalName();
$media->setName($filename)
->setOriginalName($originalName)
->setType('img')
->setContext('restaurant_picture')
->setUpdatedAt(new \DateTime())
;
$media->setRestaurant($restaurant);
$em->persist($media);
}
}
通知我已首先从表单上传的数据中获取所有文件,并在foreach循环中运行您的代码。
答案 1 :(得分:1)
你需要在upload方法中处理一个数组,因为它会从表单中获取,而不是单个的UploadedFile对象。
/**
* @param UploadedFile $file
* @param $targetDir
* @return array
*/
public function upload($files, $targetDir)
{
if(!is_array($files)) {
$files = (array) $files; // cast to array in case of a form that isn't multiple.
}
$filenames = [];
foreach($files as $file) {
$filenames[] = md5(uniqid()).'.'.$file->guessExtension();
$file->move($targetDir, $fileName);
}
return $filenames;
}
你需要改变获得返回filename
变量的任何内容,因为它现在是一个数组。
另一种方式,在我看来是一个更好的用户体验,就是使用CollectionType并为每个文件渲染一个文件输入框。这是一个简单的例子。
$builder->add('file_uploads', CollectionType::class, [
'entry_type' => FileType::class,
'entry_options' => [
'label' => 'Photos du restaurant',
'multiple' => true,
'required' => false,
'mapped' => false,
'attr' => [
'accept' => '.jpg,.jpeg,.png',
],
'allow_add' => true,
'allow_delete' => true,
],
'prototype' => true,
]);
然后,您需要在上传处理程序中处理生成的ArrayCollection。但这为用户提供了更好的界面。
我没有对此代码段进行测试,因此您可能需要调试或调整它以适应您正在进行的操作。