Symfony2 - Undefined property in entity for file upload - symfony

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();
}
}

Related

Symfony2 - 2.6 file uploads

I'm having a problem with file uploads on 2.6, which worked fine on the previous versions. I can't figure out what the problem is, there is no error and when I dump the post object I see a file name there but there is no file in the images folder.
My images folder is in myproject/web/images.
Using SonataAdmin to upload the file and again no errors there.
Can someone point out what I'm doing wrong or what's changed?
Edit: After perusing through the folders I noticed it created another web/images folder in /var/www/html.
Any idea how correct this? My project folder is in /var/www/html/myproject.
Tried adding 2 more /../../ but got an error: Unable to create the "/var/www/html/myproject/src/AppBundle/Entity/../../../../../../web/images/" directory. And removed 2 /../../ and still nothing.
Calling the file in twig with the following:
{% for photo in photos %}
<a href="{{ asset(['images/', photo.image]|join) }}">
<img src="{{ asset(['images/', photo.image]|join) }}" width="400" height="600" alt=""/>
</a>
{% endfor %}
Post entity
/**
* #var string
*
* #ORM\Column(name="file", type="string", length=255)
*/
private $image;
public $file;
/**
* Set image
*
* #param string $image
* #return Post
*/
public function setImage($image)
{
$this->image = $image;
return $this;
}
/**
* Get image
*
* #return string
*/
public function getImage()
{
return $this->image;
}
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);
$this->file = null;
}
/**
* #ORM\PostRemove()
*/
public function removeUpload()
{
if ($file = $this->getAbsolutePath()) {
unlink($file);
}
}
Your Entity Path is:
var/www/html/myproject/src/AppBundle/Entity/Post.php
and your getUploadRootDir method:
public function getUploadRootDir()
{
return __DIR__ . '/../../../../web/' . $this->getUploadDir();
}
Which will go back four times cause there are 4(../) which is taking you to out of your source directory.
use this to resolve this error:
public function getUploadRootDir()
{
return __DIR__ . '/../../../web/' . $this->getUploadDir();
}
Just Change your entity with this.
Instead of
public function getUploadDir()
{
return 'images/';
}
Replace This
public function getUploadDir()
{
return '/images';
}

Upload multiple files for each entity

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.

Finding out what changed via postUpdate listener in Symfony 2.1

I have a postUpdate listener and I'd like to know what the values were prior to the update and what the values for the DB entry were after the update. Is there a way to do this in Symfony 2.1? I've looked at what's stored in getUnitOfWork() but it's empty since the update has already taken place.
You can use this ansfer Symfony2 - Doctrine - no changeset in post update
/**
* #param LifecycleEventArgs $args
*/
public function postUpdate(LifecycleEventArgs $args)
{
$changeArray = $args->getEntityManager()->getUnitOfWork()->getEntityChangeSet($args->getObject());
}
Found the solution here. What I needed was actually part of preUpdate(). I needed to call getEntityChangeSet() on the LifecycleEventArgs.
My code:
public function preUpdate(Event\LifecycleEventArgs $eventArgs)
{
$changeArray = $eventArgs->getEntityChangeSet();
//do stuff with the change array
}
Your Entitiy:
/**
* Order
*
* #ORM\Table(name="order")
* #ORM\Entity()
* #ORM\EntityListeners(
* {"\EventListeners\OrderListener"}
* )
*/
class Order
{
...
Your listener:
class OrderListener
{
protected $needsFlush = false;
protected $fields = false;
public function preUpdate($entity, LifecycleEventArgs $eventArgs)
{
if (!$this->isCorrectObject($entity)) {
return null;
}
return $this->setFields($entity, $eventArgs);
}
public function postUpdate($entity, LifecycleEventArgs $eventArgs)
{
if (!$this->isCorrectObject($entity)) {
return null;
}
foreach ($this->fields as $field => $detail) {
echo $field. ' was ' . $detail[0]
. ' and is now ' . $detail[1];
//this is where you would save something
}
$eventArgs->getEntityManager()->flush();
return true;
}
public function setFields($entity, LifecycleEventArgs $eventArgs)
{
$this->fields = array_diff_key(
$eventArgs->getEntityChangeSet(),
[ 'modified'=>0 ]
);
return true;
}
public function isCorrectObject($entity)
{
return $entity instanceof Order;
}
}
You can find example in doctrine documentation.
class NeverAliceOnlyBobListener
{
public function preUpdate(PreUpdateEventArgs $eventArgs)
{
if ($eventArgs->getEntity() instanceof User) {
if ($eventArgs->hasChangedField('name') && $eventArgs->getNewValue('name') == 'Alice') {
$eventArgs->setNewValue('name', 'Bob');
}
}
}
}

how to get the path of a file upload and save in db using symfony2

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...

Generate file name on file upload that contains file's username

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;
}
}

Resources