I've got a form with embedded file form (News and NewsFiles collection). On my localhost machine everything works fine: News and NewsFiles entities persists, files are uploaded.
But on production server post request is stopped when I try add file. Files are uploaded, entities don't exist in db, post request is stopped with status: 302 Found and it returns blank page instead of redirect to next page.
public function createAction(Request $request) {
$entity = new News();
$form = $this->createCreateForm($entity);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
// PROBLEM APPEARS HERE - WHEN TRY TO FLUSH
$em->flush();
$this->get('session')->getFlashBag()->add(
'success', 'Wykonano pomyślnie!'
);
return $this->redirect($this->generateUrl('website_admin_panel_news'));
}
return $this->render('WebsiteNewsBundle:News:new.html.twig', array(
'entity' => $entity,
'form' => $form->createView(),
));
}
There is no problem when I try to add only News entity (without files). The same is when I am editing entity.
LOGS:
logs
INFO - Matched route "news_update" (parameters: "_controller": "Website\NewsBundle\Controller\NewsController::updateAction", "id": "6", "_route": "news_update")
DEBUG - Read SecurityContext from the session
DEBUG - Reloading user from user provider.
DEBUG - Username "admin" was reloaded from user provider.
DEBUG - Write SecurityContext in the session
I think the problem is on the server side, I will write to the administrator but he isn't an expert so I need to suggest him what he has to change... Any ideas? May it be a problem of timeouts?
Edit:
I've got more information. The problem occurs in move() function. It's not a problem with timeouts because I've tried to send little file (1px - 539 byte) and it still doesn't do the job.
Here is my Entity to upload:
<?php
namespace Website\NewsBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
// use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\Validator\Constraints;
/**
*
*
* #ORM\Entity
* #ORM\HasLifecycleCallbacks
* #ORM\Table(name="NewsFiles")
*
*/
class NewsFile {
private $temp;
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*
*/
private $owner;
/**
*
*/
private $file;
/**
* #ORM\Column(type="string", length=255)
*
*/
private $name;
/**
* #ORM\Column(type="datetime")
*/
private $created_at;
/**
* #ORM\ManyToOne(targetEntity="News", inversedBy="newsFiles")
* #ORM\JoinColumn(name="news_id", referencedColumnName="id")
*/
protected $news;
/**
* #var string
*
* #ORM\Column(name="path", type="string", length=255)
*/
private $path;
/**
* #var string
*
* #ORM\Column(type="boolean", nullable=false)
*/
private $isMain;
/**
* Now we tell doctrine that before we persist or update we call the updatedTimestamps() function.
*
* #ORM\PrePersist
* #ORM\PreUpdate
*/
public function updatedTimestamps() {
if ($this->getCreated_At() == null) {
$this->setCreated_At(new \DateTime(date('Y-m-d H:i:s')));
}
}
public function setId($id) {
$this->id = $id;
}
public function getId() {
return $this->id;
}
public function setOwner($owner) {
$this->owner = $owner;
}
public function getOwner() {
return $this->owner;
}
public function setName($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
public function setPath($path) {
$this->path = $path;
}
public function getPath() {
return $this->path;
}
/**
* Set created_at
*
* #param string $created_at
* #return File
*/
public function setCreated_at($created_at) {
$this->created_at = $created_at;
return $this;
}
/**
* Get created_at
*
* #return string
*/
public function getCreated_at() {
return $this->created_at;
}
/**
* Sets file.
*
* #param UploadedFile $file
*/
public function setFile(UploadedFile $file = null) {
$this->file = $file;
// check if we have an old image path
if (isset($this->path)) {
// store the old name to delete after the update
$this->temp = $this->path;
$this->path = null;
} else {
$this->path = 'initial';
}
}
/**
* Get file.
*
* #return UploadedFile
*/
public function getFile() {
return $this->file;
}
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 path where uploaded documents should be saved
return __DIR__ . '/../../../../web/' . $this->getUploadDir();
}
protected function getUploadDir() {
return 'uploads/News/' . $this->getNews()->getId();
}
/**
* #ORM\PrePersist()
* #ORM\PreUpdate()
*/
public function preUpload() {
if (null !== $this->file) {
// zrób cokolwiek chcesz aby wygenerować unikalną nazwę
$this->setName(sha1(uniqid(mt_rand(), true)));
$this->setPath($this->getName() . '.' . $this->file->guessExtension());
}
}
/**
* #ORM\PostPersist()
* #ORM\PostUpdate()
*/
public function upload() {
// zmienna file może być pusta jeśli pole nie jest wymagane
if (null === $this->file) {
return;
}
// HERE HE CANCEL HIS WORK
$this->getFile()->move($this->getUploadRootDir(), $this->path);
// check if we have an old image
if (isset($this->temp)) {
echo "isset temp";
// delete the old image
unlink($this->getUploadRootDir() . '/' . $this->temp);
// clear the temp image path
$this->temp = null;
}
$this->file = null;
}
/**
* #ORM\PostRemove()
*/
public function removeUpload() {
if ($file = $this->getAbsolutePath()) {
unlink($file);
}
}
/**
* Set news
*
* #param string $news
* #return News
*/
public function setNews($news) {
$this->news = $news;
return $this;
}
/**
* Get news
*
* #return string
*/
public function getNews() {
return $this->news;
}
/**
* Set isMain
*
* #param string $isMain
* #return IsMain
*/
public function setIsMain($isMain) {
$this->isMain = $isMain;
return $this;
}
/**
* Get isMain
*
* #return string
*/
public function getIsMain() {
return $this->isMain;
}
}
Ok, I've discovered what's going on.
My prod server doesn't accept chmod function, it is locked. The Symfony2 file:
/vendor/symfony/symfony/src/Symfony/Component/HttpFoundation/File/UploadedFile.php
has move() function -> I've deleted chmod usage there and everythning works fine.
Here is move() function after modification:
public function move($directory, $name = null)
{
if ($this->isValid()) {
if ($this->test) {
return parent::move($directory, $name);
}
$target = $this->getTargetFile($directory, $name);
if (!#move_uploaded_file($this->getPathname(), $target)) {
$error = error_get_last();
throw new FileException(sprintf('Could not move the file "%s" to "%s" (%s)', $this->getPathname(), $target, strip_tags($error['message'])));
}
return $target;
}
throw new FileException($this->getErrorMessage());
}
Related
i'm trying to upload a picture but i don't know why i always got this error message.
Error: Call to a member function guessExtension() on a non-object
this means that the object i got is null, but why?
this is my input<input type="file" id="images_emp" name="images_emp" >.
now in the contrller i did this:
$pic = $request->files->get('images_emp');
$imagenom=$nom.$Cin.'.'.$pic->guessExtension();
$pic->move( $this->getParameter('Dossier_images'),imagenom);
$Employe->setImgsrc("/images/".$imagenom);
and in this is what the entity looks like.
/**
* #ORM\Column(type="string", nullable=true)
*
* #Assert\File(
* maxSize = "1024k",
* mimeTypes={ "application/png" ,"application/jpg","application/jpeg"},
* mimeTypesMessage = "Svp inserer une forme valide (png,jpg,jpeg)"
* )
*/private $imgsrc;
/**
* #return mixed
*/
public function getImgsrc()
{
return $this->imgsrc;
}
/**
* #param mixed $imgsrc
*/
public function setImgsrc($imgsrc)
{
$this->imgsrc = $imgsrc;
return $this;
}
how could i solve this problem.
i advice you to use the events in entity is very simple and good then get()
Entity Images
<?php
namespace ------------ ;
use Symfony\Component\HttpFoundation\File\UploadedFile;
/**
* Images
*
* #ORM\Table(name="images")
* #ORM\Entity(repositoryClass="---------")
* #ORM\HasLifecycleCallbacks
*/
class Slides
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="url", type="string", length=255)
*/
private $url;
/**
* #var string
* #ORM\Column(name="alt", type="string", length=255)
*/
private $alt;
private $file;
//This attribute is added to store the temporary file name
private $tempFilename;
public function __construct()
{
}
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set url
*
* #param string $url
*
* #return Images
*/
public function setUrl($url)
{
$this->url = $url;
return $this;
}
/**
* Get url
*
* #return string
*/
public function getUrl()
{
return $this->url;
}
public function getFile()
{
return $this->file;
}
public function setFile(UploadedFile $file = null)
{
$this->file = $file;
// We check if we already had a file for this entity
if (null !== $this->url) {
// The file extension is saved to be deleted later
$this->tempFilename = $this->url;
// Reset the values of the url and alt attributes
$this->url = null;
$this->alt = null;
} }
/**
* #ORM\PrePersist()
* #ORM\PreUpdate()
*/
public function preUpload()
{
// If there is no file (optional field), nothing is done
if (null === $this->file) {
return;
}
// The name of the file is its id, you just have to store its extension
// To make it clean, we should rename this attribute to "extension" instead of "url"
$this->url = $this->file->guessExtension();
// And we generate the alt attribute of the <img> tag, at the file name value on the user's PC
}
/**
* #ORM\PostPersist()
* #ORM\PostUpdate()
*/
public function upload()
{
//If there is no file (optional field), nothing is done
if (null === $this->file) {
return;
}
//If we had an old file, we delete it
if (null !== $this->tempFilename) {
$oldFile = $this->getUploadRootDir().'/'.$this->id.'.'.$this->tempFilename;
if (file_exists($oldFile)) {
unlink($oldFile);
}
}
// We move the file sent in the directory of your choice
$this->file->move(
$this->getUploadRootDir(), // Le répertoire de destination
$this->id.'.'.$this->url // Le nom du fichier à créer, ici « id.extension »
);
}
/**
* #ORM\PreRemove()
*/
public function preRemoveUpload()
{
// We temporarily save the file name because it depends on the id
$this->tempFilename = $this->getUploadRootDir().'/'.$this->id.'.'.$this->url;
}
/**
* #ORM\PostRemove()
*/
public function removeUpload()
{
// In PostRemove, we do not have access to the id, we use our saved name
if (file_exists($this->tempFilename)) {
// we delete the file
unlink($this->tempFilename);
}
}
public function getUploadDir()
{
// Returns the relative path to the image for a browser
return 'uploads';
}
protected function getUploadRootDir()
{
// We return the relative path to the image for our PHP code
return __DIR__.'/../../../../web/'.$this->getUploadDir();
}
public function getWebPath()
{
return $this->getUploadDir().'/'.$this->getId().'.'.$this->getUrl();
}
/**
* Set description
*
* #param string $alt
*
* #return Images
*/
public function setAlt($alt)
{
$this->alt = $alt;
return $this;
}
/**
* Get alt
*
* #return string
*/
public function getAlt()
{
return $this->alt
}
}
In controller
$images = new Images();
$form = $this->get('form.factory')->create(ImagesType::class, $images);
if ($request->isMethod('POST') && $form->handleRequest($request)->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($images);
$em->flush();
}
and you can find this solution in openclassroom more more detailed
I implemented a form for upload a file in a directory. I would use a multiple insert without manytomany relation.
This is my entity Document:
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\HttpFoundation\File\UploadedFile;
/**
* #ORM\Entity
*/
class Document
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
public $id;
/**
* #Assert\File(maxSize="6000000")
*/
private $file;
/**
* #ORM\Column(type="string", length=255)
* #Assert\NotBlank
*/
public $name;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
public $path;
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 path where uploaded
// documents should be saved
return __DIR__.'/../../../web/'.$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';
}
/**
* Sets file.
*
* #param UploadedFile $file
*/
public function setFile(UploadedFile $file = null)
{
$this->file = $file;
}
/**
* Get file.
*
* #return UploadedFile
*/
public function getFile()
{
return $this->file;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
*
* #return Document
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set path
*
* #param string $path
*
* #return Document
*/
public function setPath($path)
{
$this->path = $path;
return $this;
}
/**
* Get path
*
* #return string
*/
public function getPath()
{
return $this->path;
}
public function upload() {
// the file property can be empty if the field is not required
if (null === $this->getFile()) {
return;
}
// use the original file name here but you should
// sanitize it at least to avoid any security issues
// move takes the target directory and then the
// target filename to move to
$this->getFile()->move(
$this->getUploadRootDir(), $this->getFile()->getClientOriginalName()
);
// set the path property to the filename where you've saved the file
$this->path = $this->getUploadRootDir()."/".$this->getFile()->getClientOriginalName();
// clean up the file property as you won't need it anymore
$this->file = null;
}
}
And this is my controller:
public function uploadAction(Request $request) {
$document = new Document();
$form = $this->createFormBuilder($document)
->add('name')
->add('file',FileType::class,array(
"attr" => array(
"accept" => "image/*",
"multiple" => "multiple",
)
))
->add('save', SubmitType::class, array(
'label' => 'Salva',
'attr' => array('class' => 'btn btn-primary')
))
->getForm();
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$document->upload();
$em->persist($document);
$em->flush();
return $this->redirectToRoute('immovable_upload');
}
return $this->render('AppBundle:Immovable:upload.html.twig', array(
'form' => $form->createView(),
));
}
How to edit my code for insert more image?? It would be enough to have a repeater of the form so that it can only do multiple insertions??
I think you can try embed a collection of forms how described here http://symfony.com/doc/current/cookbook/form/form_collections.html .
And you can also use specific bundle https://github.com/glavweb/GlavwebUploaderBundle for your task.
Here is my form type:
class TestFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('thumbnail', 'hidden', array(
'label' => 'Thumbnail',
'label_attr' => array(
'class' => 'col-xs-2 control-label'
),
'required' => false,
'error_bubbling' => true,
'required' => false
));
$builder->add('thumbnail_data', 'file', array(
'error_bubbling' => true,
'required' => false
));
}
public function setDefaultOptions(\Symfony\Component\OptionsResolver\OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'X\LibraryBundle\Entity\Test',
'cascade_validation' => true,
'error_bubbling' => true,
));
}
public function getName()
{
return 'test';
}
}
Here is the entity, important part is the setThumbnailData($file) method, which stores the thumbnail file and sets the thumbnail path via the setThumbnail(string) method.
<?php
namespace X\LibraryBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Test
*
* #ORM\Table(name="test")
* #ORM\Entity(repositoryClass="X\LibraryBundle\Repository\TestRepository")
*/
class Test
{
/**
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="text", nullable=true)
*/
protected $thumbnail;
/**
* Set thumbnail
*
* #param string $thumbnail
* #return Test
*/
public function setThumbnail($thumbnail)
{
$this->thumbnail = $thumbnail;
return $this;
}
/**
* Get thumbnail
*
* #return string
*/
public function getThumbnail()
{
return $this->thumbnail;
}
/**
* This will save file to disk
* #param $file
*/
public function setThumbnailData($file) {
if($file !== null && $file !== false)
{
$fileName = $file->getClientOriginalName();
$baseDir = __DIR__ . '/../../../../../../../web/uploads/promotional_material/';
$dir = sha1(microtime());
while (is_dir($baseDir . $dir)) {
$dir = sha1(microtime());
}
mkdir($baseDir . $dir);
$this->setThumbnail('/uploads/promotional_material/' . $dir . '/' . $fileName);
$file->move($baseDir . $dir, $fileName);
}
}
public function getThumbnailData() {
return '';
}
}
Now the issue is, if the form runs into a validation error, the following twig lines produce different output, the correct value outputted from the second line, the other produces the original thumbnail path. So if I output the thumbnail input using {{ form_widget(form.thumbnail) }}, I get the original thumbnail path, not the one that should have changed via the setThumbnailData() method.
{{ dump(form.thumbnail.vars.data) }}
{{ dump(form.vars.data.thumbnail) }}
Is the issue caused by setting the thumbnail using the setThumbnailData() method? Not sure how to fix this other than hard coding the input in twig like so:
<input type="hidden" name="test[thumbnail]" value="{{ form.vars.value.thumbnail }}"/>
I cannot exactly solve your problem, because in my opinion you're doing it the wrong way. A data class is actually only responsibly for keeping your data, so your method set/getThumbnailData should look like this
<?php
// ...
private $thumbnailData;
public function setThumbnailData(UploadedFile $thumbnailData) {
$this->thumbnailData = $thumbnailData;
}
public function getThumbnailData() {
return $this->thumbnailData;
}
In your controller you have something like this:
<?php
// ...
public function formAction() {
$form = // ...
$form->handleRequest($request);
if($form->isValid()) {
$test = $form->getData();
/* #var $test Test */
$thumbnailUploader = $this->get('thumbnail_uploader');
/* #var $thumbnailUploader ThumbnailUploadService */
$file = $test->getThumbnailData();
$filename = $file->getClientOriginalName();
$thumbnailUploader->upload($filename, $file);
// ...
}
}
I recommend to move all logic which has nothing to do with forms or requests into services. Your service in this case can be more generic handle any symfony files with a given filename.
<?php
class ThumbnailUploadService {
/**
* #param $file Symfony\Component\HttpFoundation\File\File
*
*/
public function upload($filename, File $file) {
// ...
}
}
Also there is another way using callbacks. Here i give you a generic class to uploads image and generate the thumbnails. I hope this work for you. This class manage the files generated automatically when you create update o delete the entity.
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints as DoctrineAssert;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\Validator\Constraints as Assert;
use App\MyBundleBundle\Util\Util;
/**
* Image
*
* #ORM\Table(name="image")
* #ORM\Entity()
* #ORM\HasLifecycleCallbacks
*/
class Image
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string")
* #Assert\NotBlank()
*/
private $name;
private $temp;
/**
* #ORM\Column(type="string", length=255)
*/
protected $path;
/**
* #Assert\Image(maxSize="5M")
*/
private $file;
/**
* Sets file.
*
* #param UploadedFile $file
*/
public function setFile(UploadedFile $file = null)
{
$this->file= $file;
if (isset($this->path)) {
$this->temp = $this->path;
$this->path= null;
} else {
$this->path= 'initial';
}
}
/**
* Get file.
*
* #return UploadedFile
*/
public function getFile()
{
return $this->file;
}
/**
* #ORM\PrePersist()
* #ORM\PreUpdate()
*/
public function preUpload()
{
if (null !== $this->getFile()) {
// do whatever you want to generate a unique name
$filename = Util::getSlug($this->name) . uniqid() . '.' . $this->file->guessExtension();
$this->path = $filename;
}
}
/**
* #ORM\PostPersist()
* #ORM\PostUpdate()
*/
public function upload()
{
if (null === $this->getFile()) {
return;
}
$this->getFile()->move($this->getUploadRootDir(), $this->path);
if (isset($this->temp)) {
if (file_exists($this->getUploadRootDir() .'/'. $this->temp)) {
unlink($this->getUploadRootDir() . '/' . $this->temp);
}
$this->temp = null;
}
$this->file= null;
//create a dir to save de thumbnails
if (!file_exists($this->getUploadRootDir() . '/thumbnails')) {
mkdir($this->getUploadRootDir() . '/thumbnails');
}
//call a method in util class to generate the thumbnails
Util::redim($this->getUploadRootDir() . '/' . $this->path, $this->getUploadRootDir() . '/thumbnails/' . $this->path, 128, 128);
}
/**
* #ORM\PostRemove()
*/
public function removeUpload()
{
//This is to remove the files when the entity is delete
if ($file = $this->getAbsolutePath()) {
if (file_exists($file)) {
unlink($file);
$thumb = $this->getUploadRootDir() . '/thumbnails/' . $this->getPath();
if (file_exists($thumb)) {
unlink($thumb);
}
}
}
}
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()
{
return $this->getUploadDir();
}
protected function getUploadDir()
{
return 'uploads/image/';
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set nombre
*
* #param string $name
* #return Image
*/
public function setName($name)
{
$this->name= $name;
return $this;
}
/**
* Get nombre
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set path
*
* #param string $path
* #return Imagen
*/
public function setPath($path)
{
$this->path= $path;
return $this;
}
/**
* Get path
*
* #return string
*/
public function getPath()
{
return $this->path;
}
public function __toString()
{
return $this->getName();
}
}
I have the following form type:
class GalleryImageType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('thumb', new GalleryThumbnailImage(), array('label' => 'Thumbnail Image'))
->add('full', new GalleryFullSizeImage(), array('label' => 'Full Size Image'));
}
public function getName()
{
return 'galleryImage';
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array('data_class' => 'MajorProductions\SewingDiva\SiteBundle\Entity\GalleryImage'));
}
}
And the following entities:
/**
* #ORM\Entity
* #ORM\HasLifecycleCallbacks
* #ORM\Table(name="GalleryImage", indexes={#ORM\Index(name="id_idx", columns={"id"})})
*/
class GalleryImage
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\OneToOne(targetEntity="GalleryThumbnailImage", mappedBy="galleryImage")
*/
private $thumb;
/**
* #ORM\OneToOne(targetEntity="GalleryFullSizeImage", mappedBy="galleryImage")
*/
private $full;
/**
* #ORM\Column(name="lastModified", type="datetime", nullable=true)
*/
private $lastModified;
public function getId()
{
return $this->id;
}
public function setId($id)
{
$this->id = $id;
}
/**
* #return GalleryFullSizeImage
*/
public function getFull()
{
return $this->full;
}
/**
* #param GalleryFullSizeImage $full
*/
public function setFull(Full $full)
{
$this->full = $full;
}
/**
* #return GalleryThumbnailImage
*/
public function getThumb()
{
return $this->thumb;
}
/**
* #param GalleryThumbnailImage $thumb
*/
public function setThumb(Thumb $thumb)
{
$this->thumb = $thumb;
}
/**
* #return \DateTime
*/
public function getLastModified()
{
return $this->lastModified;
}
/**
* #param \DateTime $lastModified
*/
public function setLastModified(\DateTime $lastModified)
{
$this->lastModified = $lastModified;
}
}
// ----
/**
* #ORM\Entity
* #ORM\HasLifecycleCallbacks
* #ORM\Table(name="GalleryFullSizeImage", indexes={#ORM\Index(name="id_idx", columns={"id"})})
*/
class GalleryFullSizeImage
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\OneToOne(targetEntity="GalleryImage", inversedBy="full")
* #ORM\JoinColumn(name="galleryImageId", referencedColumnName="id", onDelete="SET NULL")
*/
private $galleryImage;
/**
* #ORM\Column(type="string", length=255)
*/
private $path;
/**
* #Assert\Image(maxSize="6000000")
*/
private $file;
private $tmp;
public function getId()
{
return $this->id;
}
public function setId($id)
{
$this->id = $id;
}
public function getGalleryImage()
{
return $this->galleryImage;
}
public function setGalleryImage(GalleryImage $galleryImage)
{
$this->galleryImage = $galleryImage;
}
public function getWebPath()
{
return null === $this->path ? null : $this->getUploadRootDir() . '/' . $this->path;
}
protected function getUploadRootDir()
{
// the absolute directory path where uploaded
// documents should be saved
return __DIR__ . '/../../../../web/' . $this->getUploadDir() . '/full';
}
protected function getUploadDir()
{
// get rid of the __DIR__ so it doesn't screw up
// when displaying uploaded doc/image in the view.
return 'uploads/gallery';
}
/**
* Sets file.
*
* #param UploadedFile $file
*/
public function setFile(UploadedFile $file = null)
{
$this->file = $file;
// check if we have an old image path
if (is_file($this->getAbsolutePath())) {
// store the old name to delete after the update
$this->tmp = $this->getAbsolutePath();
} else {
$this->path = 'initial';
}
}
/**
* Returns file
*
* #return mixed
*/
public function getFile()
{
return $this->file;
}
/**
* #ORM\PrePersist()
* #ORM\PreUpdate()
*/
public function preUpload()
{
if (null !== $this->getFile()) {
$this->path = $this->getFile()->guessExtension();
}
}
/**
* #ORM\PostPersist()
* #ORM\PostUpdate()
*/
public function upload()
{
if (null === $this->getFile()) {
return;
}
// check if we have an old image
if (isset($this->tmp)) {
// delete the old image
unlink($this->tmp);
// clear the temp image path
$this->tmp = null;
}
$this->getFile()->move(
$this->getUploadRootDir(),
$this->id . '.' . $this->getFile()->guessExtension()
);
$this->setFile(null);
$this->galleryImage->setLastModified(new \DateTime(null));
}
/**
* #ORM\PreRemove()
*/
public function storeFilenameForRemove()
{
$this->tmp = $this->getAbsolutePath();
}
/**
* #ORM\PostRemove()
*/
public function removeUpload()
{
if (isset($this->tmp)) {
unlink($this->tmp);
$this->galleryImage->setLastModified(new \DateTime(null));
}
}
public function getAbsolutePath()
{
return null === $this->path ? null : $this->getUploadRootDir() . '/' . $this->id . '.' . $this->path;
}
}
// ----
/**
* #ORM\Entity
* #ORM\HasLifecycleCallbacks
* #ORM\Table(name="GalleryThumbnailImage", indexes={#ORM\Index(name="id_idx", columns={"id"})})
*/
class GalleryThumbnailImage
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\OneToOne(targetEntity="GalleryImage", inversedBy="thumb")
* #ORM\JoinColumn(name="galleryImageId", referencedColumnName="id", onDelete="SET NULL")
*/
private $galleryImage;
/**
* #ORM\Column(type="string", length=255)
*/
private $path;
/**
* #Assert\Image(maxSize="6000000")
*/
private $file;
private $tmp;
public function getId()
{
return $this->id;
}
public function setId($id)
{
$this->id = $id;
}
public function getGalleryImage()
{
return $this->galleryImage;
}
public function setGalleryImage(GalleryImage $galleryImage)
{
$this->galleryImage = $galleryImage;
}
public function getWebPath()
{
return null === $this->path ? null : $this->getUploadRootDir() . '/' . $this->path;
}
protected function getUploadRootDir()
{
// the absolute directory path where uploaded
// documents should be saved
return __DIR__ . '/../../../../web/' . $this->getUploadDir() . '/thumbs';
}
protected function getUploadDir()
{
// get rid of the __DIR__ so it doesn't screw up
// when displaying uploaded doc/image in the view.
return 'uploads/gallery';
}
/**
* Sets file.
*
* #param UploadedFile $file
*/
public function setFile(UploadedFile $file = null)
{
$this->file = $file;
// check if we have an old image path
if (is_file($this->getAbsolutePath())) {
// store the old name to delete after the update
$this->tmp = $this->getAbsolutePath();
} else {
$this->path = 'initial';
}
}
/**
* Returns file
*
* #return mixed
*/
public function getFile()
{
return $this->file;
}
/**
* #ORM\PrePersist()
* #ORM\PreUpdate()
*/
public function preUpload()
{
if (null !== $this->getFile()) {
$this->path = $this->getFile()->guessExtension();
}
}
/**
* #ORM\PostPersist()
* #ORM\PostUpdate()
*/
public function upload()
{
if (null === $this->getFile()) {
return;
}
// check if we have an old image
if (isset($this->tmp)) {
// delete the old image
unlink($this->tmp);
// clear the temp image path
$this->tmp = null;
}
$this->getFile()->move(
$this->getUploadRootDir(),
$this->id . '.' . $this->getFile()->guessExtension()
);
$this->setFile(null);
$this->galleryImage->setLastModified(new \DateTime(null));
}
/**
* #ORM\PreRemove()
*/
public function storeFilenameForRemove()
{
$this->tmp = $this->getAbsolutePath();
}
/**
* #ORM\PostRemove()
*/
public function removeUpload()
{
if (isset($this->tmp)) {
unlink($this->tmp);
$this->galleryImage->setLastModified(new \DateTime(null));
}
}
public function getAbsolutePath()
{
return null === $this->path ? null : $this->getUploadRootDir() . '/' . $this->id . '.' . $this->path;
}
}
And when I attempt to view the form itself, I get the following error message from an UnexpectedTypeException:
Expected argument of type "string or Symfony\Component\Form\FormTypeInterface", "MajorProductions\SewingDiva\SiteBundle\Entity\GalleryThumbnailImage" given
So, it's choking on the FormBuilder addition of my GalleryThumbnailImage field, thinking it should be backed by a string rather than that object. I really don't know why it's doing that, however. Could it be because I used namespace aliases in GalleryImage (Thumb in place of GalleryThumbnailImage and Full in place of GalleryFullSizeImage)? Or am I missing something obvious?
EDIT: The problem remains even after creating form types for GalleryFullSizeImage and GalleryThumbnailImage:
namespace MajorProductions\SewingDiva\SiteBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class GalleryFullSizeImageType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('file', 'file');
}
public function getName()
{
return 'galleryFullSizeImage';
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array('data_class' => 'MajorProductions\SewingDiva\SiteBundle\Entity\GalleryFullSizeImage'));
}
}
// ----
namespace MajorProductions\SewingDiva\SiteBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class GalleryThumbnailImageType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('file', 'file');
}
public function getName()
{
return 'galleryThumbnailImage';
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array('data_class' => 'MajorProductions\SewingDiva\SiteBundle\Entity\GalleryThumbnailImage'));
}
}
Note that where // ---- is written in my code, that represents the end of one file and the beginning of another. Given the length of my entity code with all of the Doctrine annotations, I figured I'd save some vertical space by putting the code of individual classes in the same code blocks here.
You use:
$builder
->add('thumb', new GalleryThumbnailImage(), array('label' => 'Thumbnail Image'))
->add('full', new GalleryFullSizeImage(), array('label' => 'Full Size Image'));
Let's recall what the arguments of FormBuilder#add() are: public function add($child, $type = null, array $options = array()). Instead of $type, you seem to pass an entity. The classes you want to pass here are GalleryThumbnailImageType and GalleryFullSizeImageType. These classes do implement FormTypeInterface, so everything is ok!
The code you need to use:
$builder
->add('thumb', new GalleryThumbnailImageType(), array('label' => 'Thumbnail Image'))
->add('full', new GalleryFullSizeImageType(), array('label' => 'Full Size Image'));
I have a Document Entity and I want that the user of the website be able to download the files that have been uploaded.
I don't know how to do this (I tried with a downloadAction in my DocumentController but I have some errors).
Here is my Document entity :
<?php
namespace MyBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints as DoctrineAssert;
use Symfony\Component\HttpFoundation\File\UploadedFile;
/**
* MyBundle\Entity\Document
* #ORM\Table()
* #ORM\Entity()
* #ORM\HasLifecycleCallbacks
*/
class Document
{
public function __toString() {
return $this->document_type->getName();
}
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var date $endDate
*
* #ORM\Column(name="endDate", type="date")
*/
private $endDate;
/**
* #ORM\ManyToOne(targetEntity="DocumentType")
* #ORM\JoinColumn(name="document_type_id", referencedColumnName="id")
*/
private $document_type;
/**
* #ORM\Column(type="string", length="255", nullable="TRUE")
* #Assert\File(maxSize="6000000")
*/
public $file;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
public $path;
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 path where uploaded documents should be saved
return __DIR__.'/../../../../web/'.$this->getUploadDir();
}
protected function getUploadDir()
{
// get rid of the __DIR__ so it doesn't screw when displaying uploaded doc/image in the view.
return 'uploads/documents';
}
/**
* #ORM\PrePersist()
* #ORM\PreUpdate()
*/
public function preUpload()
{
if (null !== $this->file) {
// do whatever you want to generate a unique name
$this->path = uniqid().'.'.$this->file->guessExtension();
}
}
/**
* #ORM\PostPersist()
* #ORM\PostUpdate()
*/
public function upload()
{
if (null === $this->file) {
return;
}
$this->file->move($this->getUploadRootDir(), $this->path);
unset($this->file);
}
/**
* #ORM\PostRemove()
*/
public function removeUpload()
{
if ($file = $this->getAbsolutePath()) {
unlink($file);
}
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set endDate
*
* #param date $endDate
*/
public function setEndDate($endDate)
{
$this->endDate = $endDate;
}
/**
* Get endDate
*
* #return endDate
*/
public function getEndDate()
{
return $this->endDate;
}
/**
* Set document_type
*
* #param Was\RHBundle\Entity\DocumentType $documentType
*/
public function setDocumentType(MyBundle\Entity\DocumentType $documentType)
{
$this->document_type = $documentType;
}
/**
* Get document_type
*
* #return MyBundle\Entity\DocumentType
*/
public function getDocumentType()
{
return $this->document_type;
}
/**
* Set path
*
* #param string $path
*/
public function setPath($path)
{
$this->path = $path;
}
/**
* Get path
*
* #return string
*/
public function getPath()
{
return $this->path;
}
/**
* Set file
*
* #param string $file
*/
public function setFile($file)
{
$this->file = $file;
}
/**
* Get file
*
* #return string
*/
public function getFile()
{
return $this->file;
}
}
Now, here is my downloadAction in my DocumentController.php :
public function downloadAction($id)
{
$em = $this->getDoctrine()->getEntityManager();
$document = $em->getRepository('MyBundle:Document')->find($id);
if (!$document) {
throw $this->createNotFoundException('Unable to find the document');
}
$headers = array(
'Content-Type' => $document->getMimeType()
'Content-Disposition' => 'attachment; filename="'.$document->getDocumentType().'"'
);
$filename = $document->getUploadRootDir().'/'.$document->getDocumentType();
return new Response(file_get_contents($filename), 200, $headers);
}
I've got this error :
Call to undefined method MyBundle\Entity\Document::getMimeType()
I use IgorwFileServeBundle.
Here a sample I used on one of my project :
$em = $this->getDoctrine()->getEntityManager();
$file = $em->getRepository('MyBundle:File')->find($id);
$path = $file->getPath();
$mimeType = $file->getMimeType();
$folder = 'Public';
$factory = $this->get('igorw_file_serve.response_factory');
$response = $factory->create($folder.'/'.$path, $mimeType);
return $response;
I hope it can help
Here is the code from one of my project
public function downloadAction()
{
$items = $this->get('xxxx')->getXXX();
$response = $this->render('xxx:xxx:xxx.csv.twig', array('items' => $items));
$response->headers->set('Content-Type', 'text/csv');
$response->headers->set('Content-Disposition', 'attachment; filename=budget.csv');
return $response;
}
Add variable $mimeType to the Document entity
/**
* #ORM\Column()
* #Assert\NotBlank
*/
private $mimeType;
and getters and setters (or generate them)
public function setMimeType($mimeType) {
$this->mimeType = $mimeType;
return $this;
}
public function getMimeType() {
return $this->mimeType;
}
update the database schema
php app/console doctrine:schema:update --force
and add setMimeType to your setFile function
/**
* Set file
*
* #param string $file
*/
public function setFile($file)
{
$this->file = $file;
$this->setMimeType($this->getFile()->getMimeType());
}
Then your controller will work properly.