I am using doctrine2 with symfony2.
This is my entity to upload the file.
First, it call the setFile() and put the path to $this->temp,
then,preUpload is called ,upload called.
It is OK for uploading onefile for each entity,however, I would like to upload multiple files for each entity.
How can I handle this ?
Do you have any samples for this purpose?
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
public $path = "nophoto.jpeg";
/**
* #Assert\File(maxSize="6000000")
*/
private $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->temp = $this->getAbsolutePath();
} else {
$this->path = 'initial';
}
}
/**
* #ORM\PrePersist()
* #ORM\PreUpdate()
*/
public function preUpload()
{
if (null !== $this->getFile()) {
$this->path = $this->getId().'.'.$this->getFile()->guessExtension();
}
/**
* #ORM\PostPersist()
* #ORM\PostUpdate()
*/
public function upload()
{
if (null === $this->getFile1()) {return;}
if (isset($this->temp)) {
// delete the old image
unlink($this->temp);
// clear the temp image path
$this->temp = null;
}
// you must throw an exception here if the file cannot be moved
// so that the entity is not persisted to the database
// which the UploadedFile move() method does
$this->getFile()->move(
$this->getUploadRootDir(),
$this->getId().'.'.$this->getFile()->guessExtension()
);
$this->setFile(null);
}
public function getAbsolutePath()
{
return null === $this->path
? null
: $this->getUploadRootDir().'/'.$this->getId().'.'.$this->path;
}
public function getFile1()
{
return $this->file;
}
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';
}
You need new entity which will represent uploaded file with many-to-one (or many-to-many) association to your entity. This is most universal approach.
Alternatively you can store file names in array but that will complicate your validation and forms.
Related
Could you help me resolve this issue?
I tried this tutorial: Symfony Upload
It works fine(stored to the database path to img), but don't store or move image to the folder.
Entity:
<?php
namespace DbBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\HttpFoundation\File\UploadedFile;
/**
* #ORM\Entity
* #ORM\HasLifecycleCallbacks
*/
class File
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
public $id;
/**
* #ORM\Column(type="string", length=255)
* #Assert\NotBlank
*/
public $name;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
public $path;
/**
* #Assert\File(maxSize="6000000")
*/
private $file;
private $temp;
/**
* 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';
}
}
/**
* #ORM\PrePersist()
* #ORM\PreUpdate()
*/
public function preUpload()
{
if (null !== $this->getFile()) {
// do whatever you want to generate a unique name
$filename = sha1(uniqid(mt_rand(), true));
$this->path = $filename.'.'.$this->getFile()->guessExtension();
}
}
/**
* Get file.
*
* #return UploadedFile
*/
public function getFile()
{
return $this->file;
}
/**
* #ORM\PostPersist()
* #ORM\PostUpdate()
*/
public function upload()
{
if (null === $this->getFile()) {
return;
}
// if there is an error when moving the file, an exception will
// be automatically thrown by move(). This will properly prevent
// the entity from being persisted to the database on error
$this->getFile()->move($this->getUploadRootDir(), $this->path);
// check if we have an old image
if (isset($this->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()
{
$file = $this->getAbsolutePath();
if ($file) {
unlink($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()
{
// get rid of the __DIR__ so it doesn't screw up
// when displaying uploaded doc/image in the view.
return 'uploads/documents';
}
}
Controller:
public function uploadAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$document = new File();
$form = $this->createFormBuilder($document)
->add('name')
->add('file')
->getForm();
$form->handleRequest($request);
if ($form->isValid()) {
$em->persist($document);
$em->flush();
return $this->redirectToRoute('web_portal_file');
}
return $this->render('WebPortalBundle:Default:file.html.twig',array('file_form' => $form->createView()));
}
EDIT: Twig:
<form action="{{ path('web_portal_file') }}" method="post" {{ form_enctype(file_form) }}>
{{ form_widget(file_form.file) }}
{{ form_rest(file_form) }}
<input type="submit"/>
</form>
I don't know what to do to make this work. Every time path is saved to the database, but folder is empty ...
Remember to upload files will be put in the form tag data encryption: PHP method uploads
In Symfony2, with Twig would be:
form class="" action="" method="post" {{ form_enctype(file_form) }}
{{ form_widget(file_form) }}
/form
The problem may be here. On Controller. When you are persisting the entity you call the upload() method
if($form->isValid()) {
$em->persist($document);
$em->flush();
return $this->redirectToRoute('web_portal_file');
}
In CookBook says:
The previous controller will automatically persist the Document entity with the submitted name, but it will do nothing about the file and the path property will be blank.
An easy way to handle the file upload is to move it just before the entity is persisted and then set the path property accordingly. Start by calling a new upload() method on the Document class, which you'll create in a moment to handle the file upload:
Now
if($form->isValid()) {
$document->upload();
$em->persist($document);
$em->flush();
return $this->redirectToRoute('web_portal_file');
}
The following code works:
protected function getUploadRootDir() {
// the absolute directory path where uploaded
// documents should be saved
return __DIR__ . '/../../../web/' . $this->getUploadDir();
}
I am getting the following error when trying to upload a file, it's odd because I've used the same code on other projects without any problems/errors.
What am I missing here?
Notice: Undefined property: Acme\DemoBundle\Entity\Article::$file in /var/www/html/InsideFight/src/Acme/DempBundle/Entity/Article.php line 277
The problem line is:
if (null !== $this->file) {
I do not have any file upload code in my controller it's being handled in the entity.
Entity
public $file;
public function getUploadDir()
{
return 'images/';
}
public function getUploadRootDir()
{
return __DIR__ . '/../../../../web/' . $this->getUploadDir();
}
public function getWebPath()
{
return null === $this->image ? null : $this->getUploadDir() . '/' . $this->image;
}
public function getAbsolutePath()
{
return null === $this->image ? null : $this->getUploadRootDir() . '/' . $this->image;
}
/**
* #ORM\PrePersist()
* #ORM\PreUpdate()
*/
public function preUpload()
{
if (null !== $this->file) {
$this->image = uniqid() . '.' . $this->file->guessExtension();
}
}
/**
* #ORM\PostPersist()
* #ORM\PostUpdate()
*/
public function upload()
{
if (null === $this->file) {
return;
}
// If there is an error when moving the file, an exception will
// be automatically thrown by move(). This will properly prevent
// the entity from being persisted to the database on error
$this->file->move($this->getUploadRootDir(), $this->image);
unset($this->file);
}
/**
* #ORM\PostRemove()
*/
public function removeUpload()
{
if ($file = $this->getAbsolutePath()) {
unlink($file);
}
}
Thats because you do unset($this->file);. Change it to $this->file = null.
Include the following namespace.
use Symfony\Component\HttpFoundation\File\UploadedFile;
Make the file variable private and create a temp file variable.
private $file;
private $tempFile
Then create getter and setter methods for $file.
public function getFile()
{
return $this->file;
}
public function setFile(UploadedFile $file = null)
{
$this->file = $file;
if (isset($this->image)) {
// store the old name to delete after the update
$this->tempfile = $this->image;
$this->image = null;
} else {
$this->image = 'initial';
}
}
Then, modify preUpload and upload functions.
public function upload()
{
if (null === $this->getFile()) {
return;
}
// if there is an error when moving the file, an exception will
// be automatically thrown by move(). This will properly prevent
// the entity from being persisted to the database on error
$this->getFile()->move($this->getUploadRootDir(), $this->image);
// check if we have an old image
if (isset($this->tempFile)) {
// delete the old image
unlink($this->getUploadRootDir() . '/' . $this->tempFile);
// clear the temp image path
$this->tempFile = null;
}
$this->file = null;
}
public function preUpload()
{
if (null !== $this->getFile()) {
// generate a unique name
$filename = uniqid();
$this->image = $filename . '.' . $this->getFile()->guessExtension();
}
}
I have created a file uploads page. In my controller I want to get the uploaded path of the view and add it in the database for a particular id. For that I want the path of the file ans send it to the repository. The problem when I am using in my controller
if ($request->getMethod() == 'POST')
{
$form->bind($request);
$file = $form["file"]->getData();
/* here it is giving the path like /tmp/phpkR4kgD */
$em = $this->getDoctrine()->getManager();
$user->upload();
}
this is my entity
/**
* Sets file.
*
* #param UploadedFile $file
*/
public function setFile(UploadedFile $file = null)
{
$this->file = $file;
}
public function upload()
{
if (null === $this->file)
{
return;
}
$this->file->move($this->getUploadRootDir(), $this->file->getClientOriginalName());
$this->path = $this->file->getClientOriginalName();
$this->file = null;
}
/**
* Get file.
*
* #return UploadedFile
*/
public function getFile()
{
return $this->file;
}
public function getAbsolutePath()
{
return null === $this->path
? null
: $this->getUploadRootDir() . DIRECTORY_SEPARATOR . $this->path;
}
public function getWebPath()
{
return null === $this->path
? null
: $this->getUploadDir() . DIRECTORY_SEPARATOR . $this->path;
}
protected function getUploadRootDir()
{
return __DIR__ . '/../../../../web/'. $this->getUploadDir();
}
protected function getUploadDir()
{
return 'uploads/';
}
I have created my uploads folder in web folder of symfony
while calling upload() method from it takes the temporary path to entity.
In entity it will get the orginal path $this->path = $this->file->getClientOriginalName();
so use return statement which returns the original path to controller from there you can save it in database...
i used the following code in the controller inorder to get the filenames of the uploaded files
My controller is
class uploadController extends Controller
{
public function uploadAction(Request $request)
{
$id= $_GET['id'];
$user = new attachments();
$form = $this->createFormBuilder($user)->add('files','file',array("data_class" => null,"attr"=>array("multiple" =>"multiple",)))->getForm();
$formView = $form->createView();
$formView->getChild('files')->set('full_name','files[]');
if ($request->getMethod() == 'POST')
{
$em = $this->getDoctrine()->getManager();
$data = $form["files"]->getData();
}
}
when i print the $data it is not giving the filenames of uploaded files it is returning the null values
my entity is:
use Symfony\Component\HttpFoundation\File\UploadedFile;
class attachments
{
private $id;
/**
* #var integer
* #ORM\Column(name="user", type="integer", nullable=false)
* #ORM\ManyToOne(targetEntity="users", inversedBy="annotations")
*/
protected $userId;
/**
* #var string
*
* #Assert\File(maxSize="6000000")
* #ORM\Column(name="files", type="array", length=255, nullable=true)
*/
public $files=array();
public function __construct()
{
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set userId
*
* #param integer $userId
* #return attachments
*/
public function setUserId($userId)
{
$this->userId = $userId;
return $this;
}
/**
* Set files
* #param object $files
*
* #return attachments
*/
public function setFiles($files)
{
$this->files = $files;
}
/**
* Get files
*
* #return object
*/
public function getFiles()
{
return $this->files;
}
public function uploadFiles()
{
// the files property can be empty if the field is not required
if (null === $this->files)
{
return;
}
else
{
$this->files->move($this->getUploadRootDir(), $this->files->getClientOriginalName());
}
$this->setFiles($this->files->getClientOriginalName());
}
/**
* Get userId
*
* #return integer
*/
public function getUserId()
{
return $this->userId;
}
public function getAbsolutePath()
{
return null === $this->path
? null
: $this->getUploadRootDir() . DIRECTORY_SEPARATOR . $this->path;
}
public function getWebPath()
{
return null === $this->path
? null
: $this->getUploadDir() . DIRECTORY_SEPARATOR . $this->path;
}
protected function getUploadRootDir()
{
return __DIR__ . '/../../../../web/'. $this->getUploadDir();
}
protected function getUploadDir()
{
return 'uploads/';
}
}
Uploaded Files in Symfony2 are of type Symfony/Component/HttpFoundation/File/UploadedFile.
You can get the original client name ( php will rename files when putting them into php_upload_tmp_dir ) with:
$file->getClientOriginalName();
... move the file to a new location with:
$file->move('path/to/your_file', 'new_name.jpg');
You can not use the assert File Constraint for an array.
* #Assert\File(maxSize="6000000")
*/
protected $files = array();
Therefore you need the All constraint.
Furthermore you can't just call the move method on an array or collection... you will have to loop over the collection/array.
$this->files->move('..') // this is never going to work...
Use an array collection and create a property for your uploaded files if thats what you want.
protected $files;
protected $uploadedFiles;
public function __construct()
{
$this->files = new ArrayCollection;
$this->uploadedFiles = new Array();
}
If you want to transform your Doctrine Collection of UploadedFile entities into an Array do the following:
$collection = $entity->getFiles();
$array = $collection->toArray();
But whatever you're trying to do ... better use OOP instead of arrays like you're attempting here.
I want to have the filename looks like: Username-OriginalFileName.
My first solution was to use the preUpload callback in my File Entity as described in Symfony cookbook here
/**
* #Assert\File(maxSize="6000000")
*/
public $FILE_file;
public $path;
public function getPath()
{
return $this->path;
}
public function setPath($path)
{
return $this->path=$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()
{
return __DIR__.'/../../../../web/'.$this->getUploadDir();
}
protected function getUploadDir()
{
return 'uploads/files';
}
/**
* #ORM\PrePersist()
* #ORM\PreUpdate()
*/
public function preUpload()
{
if (null !== $this->FILE_file) {
$username=$this->get('security.context')->getToken()->getUser()->getUsername();
$this->path = $username.'-'.$this->path;
}
}
/**
* #ORM\PostPersist()
* #ORM\PostUpdate()
*/
public function upload()
{
// the file property can be empty if the field is not required
if (null === $this->FILE_file) {
return;
}
$this->FILE_file->move($this->getUploadRootDir(), $this->FILE_file->getClientOriginalName());
$this->path = $this->FILE_file->getClientOriginalName();
$this->FILE_file = null;
}
But it seems that I can't get the container from the Entity.
So I've tried to do this in my File Controller:
$filename=$username.'-'.$file->path;
$file->setPath($filename);
$file->setFILEFormat($ext);
...
$em1->persist($file);
$em1->flush();
$file->upload();
$content=$file->getContent();
getContent is a function that opens the file and stores its content in an array of strings. For some reason the file is persisted and uploaded with its OriginalName from the upload form not with $filename. What am I doing wrong?
isnt there any relation between the file an the user?
else you could do something like:
File Entity:
/**
*
* #ORM/ManyToOne(targetEntity="User" …)
*/
private $user;
public function preUpload()
{
if (null !== $this->FILE_file) {
$this->path = $this->user->getUsername().'-'.$this->path;
}
}