У меня проблема, когда я пытаюсь загрузить более одного изображения в базу данных.
Я прочитал документы Symfony и могу загружать одно изображение за раз.
Я также прочитал
http://symfony.com/doc/current/cookbook/form/form_collections.html
До сих пор я полностью понимаю процесс загрузки ОДНОГО ИЗОБРАЖЕНИЯ, но что происходит, когда вам нужно загрузить более одного изображения?
Вот моя ситуация: у меня есть сущность Store и сущность StorePhoto, а Store содержит отношение OneToMany с StorePhoto (переменная commerce_photos) (я разрабатываю некую галерею изображений для магазина).
Идея состоит в том, чтобы загружать более одного изображения за раз, я имею в виду выбрать более одного файла и загрузить их.
Вот что я сделал
Мой магазин
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* @ORM\Entity
* @ORM\Table(name="store")
*
*/
class Store{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORM\Column(type="string", length=255)
*/
protected $name;
/**
* @ORM\OneToOne(targetEntity="StorePhoto")
*/
protected $photo;
/**
* @ORM\OneToMany(targetEntity="StorePhoto", mappedBy="store_photo")
*/
protected $commerce_photos;
public function __construct(){
$this->commerce_photos = new ArrayCollection();
}/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* @param string $name
* @return Store
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Add commerce_photos
*
* @param \AppBundle\Entity\StorePhoto $commercePhotos
* @return Store
*/
public function addCommercePhotos(\AppBundle\Entity\StorePhoto $commercePhotos)
{
$this->commerce_photos[] = $commercePhotos;
return $this;
}
/**
* Remove commerce_photos
*
* @param \AppBundle\Entity\StorePhoto $commercePhotos
*/
public function removeCommercePhotos(\AppBundle\Entity\StorePhoto $commercePhotos)
{
$this->commerce_photos->removeElement($commercePhotos);
}
/**
* Get commerce_photos
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getCommercePhotos()
{
return $this->commerce_photos;
}
}
Моя сущность StorePhoto
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\HttpFoundation\File\UploadedFile;/**
* @ORM\Entity
* @ORM\Table(name="store_photo")
*/
class StorePhoto{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORM\Column(type="string", length=255)
*/
protected $imageName;
/**
* @ORM\Column(type="string", length=255,nullable=false)
*/
protected $path;
/**
* @ORM\ManyToOne(targetEntity="Store", inversedBy="commerce_photos")
*/
protected $store_photo;
/**
* @Assert\Image
(mimeTypes = {"image/jpg", "image/jpeg", "image/gif", "image/png"},
mimeTypesMessage = "Solo acepta imagenes en formato JPG, GIF ou PNG.",
maxSize="5000k")
*/
private $imageFile;
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Get file.
*
* @return UploadedFile
*/
public function getImageFile()
{
return $this->imageFile;
}
/**
* Sets file.
*
* @param UploadedFile $imageFile
*/
public function setImageFile(UploadedFile $file = null)
{
$this->imageFile = $file;
}
/**
* Set imageName
*
* @param string $imageName
* @return StorePhoto
*/
public function setImageName($imageName)
{
$this->imageName = $imageName;
return $this;
}
/**
* Get imageName
*
* @return string
*/
public function getImageName()
{
return $this->imageName;
}
/**
* Set store_photo
*
* @param \AppBundle\Entity\Store $storePhoto
* @return StorePhoto
*/
public function setStorePhoto(\AppBundle\Entity\Store $storePhoto = null)
{
$this->store_photo = $storePhoto;
return $this;
}
/**
* Get store_photo
*
* @return \AppBundle\Entity\Store
*/
public function getStorePhoto()
{
return $this->store_photo;
}
public function getAbsolutePath()
{
return null === $this->path
? null
: $this->getUploadRootDir().'/'.$this->path;
}
public function getWebPath()
{
return null === $this->path
? null
: $this->getUploadDir().'/'.$this->path;
}
protected function getUploadRootDir()
{
//the absolute directory where uploaded documents should be saved
return __DIR__.'/../../../../web/images'.$this->getUploadDir();
}
protected function getUploadDir()
{
//get rid of the __DIR__ so it doesn't screw up
//when displaying uploaded doc/image in the view
return 'uploads/documents';
}
public function upload()
{
//the file property can be empty if the field is not required
if(null === $this->getImageFile())
{
return;
}
//use the original file name here but you should
//sanitaze it at least to avoid any security issues
//move takes the target directory and then the target filename to move to.
$this->getImageFile()->move(
$this->getUploadRootDir(), $this->getImageFile()->getClientOriginalName()
);
//set the path property to the filename where you've saved the file
$this->path = $this->getImageFile()->getClientOriginalName();
//clean up the file property as you won't need it anymore...
$this->imageFile = null;
}
}
Мой контроллер
<?php
namespace AppBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use AppBundle\Forms\Type\FileUploadType;
use Symfony\Component\HttpFoundation\Request;
use AppBundle\Entity\StorePhoto;
use AppBundle\Entity\Store;
use Symfony\Component\HttpFoundation\Response;
use AppBundle\Forms\Type\MultipleFileUploadType;class DefaultController extends Controller
{
public function multipleFileUploadAction(Request $request)
{
$store = new Store();
$store->setName('Test01');
$store->addCommercePhotos(new StorePhoto());
$form = $this->createForm(new MultipleFileUploadType(),$store);
$form->handleRequest($request);
if($form->isValid())
{
$em = $this->getDoctrine()->getManager();
$em->persist($store);
$em->flush();
return new Response('200 OK...');
}
return $this->render('Forms/FileUpload.html.twig',array('form'=>$form->createView()));}
}
Мои формы сейчас, FileUploadType и MultipleFileUploadType
<?php
namespace AppBundle\Forms\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class FileUploadType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('imageName', 'text');
$builder->add('imageFile', 'file',
array('multiple'=>'multiple'));
// $builder->add('Save', 'submit');
}
public function getName()
{
return "storePhoto";
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\StorePhoto',
));}
}
?>
<?php
namespace AppBundle\Forms\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use AppBundle\Forms\Type\FileUploadType;
class MultipleFileUploadType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name','text');
$builder->add('commerce_photos', 'collection',array(
'type' => new FileUploadType()));
$builder->add('Save', 'submit');
}
public function getName()
{
return "MultipleFileUpload";
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Store',
));
}
}
?>
Вот и весь код, я не знаю, что я здесь что-то упускаю.
Что мне нужно сделать, это отобразить диалоговое окно, выбрать несколько изображений и затем сохранить их.
В этом случае в контроллере я написал эту строку
$store = new Store();
$store->setName('Test01');
$store->addCommercePhotos(new StorePhoto());
В этом случае, когда я отрисовываю форму, она показывает мне диалоговое окно и позволяет мне выбрать только один файл.
Если я удаляю третью строку, addCommerce … Он показывает только ярлык commercePhotos.
Заранее спасибо!
Пока вы не установите значение для поля commerce_photos, Symfony будет распознавать его как пустое. Для пустого поля не будет отображаться элемент ввода. Так что вам нужно установить какое-нибудь фиктивное значение или визуализировать поле самостоятельно так:
{{ form_label(form.imageFile) }}
<input type="file" name="{{ form.imageFile.vars.fullName }}[]" class="file-upload" />
Квадратные скобки важны для того, чтобы Symfony обрабатывал несколько значений. Чтобы заставить форму принимать несколько файлов одновременно, вам может понадобиться такой jquery:
$('.file-upload').on('change', function (event) {
$(event.currentTarget).after('<input type="file" name="{{ form.imageFile.vars.fullName }}[]" class="file-upload" />');
});
Других решений пока нет …