-
-
Save beberlei/978346 to your computer and use it in GitHub Desktop.
<?php | |
use Symfony\Component\HttpFoundation\File\File; | |
use Symfony\Component\HttpFoundation\File\UploadedFile; | |
/** | |
* @Entity | |
*/ | |
class Document | |
{ | |
/** @var File - not a persistent field! */ | |
private $file; | |
/** @var string | |
* @Column(type="string") | |
*/ | |
private $filePersistencePath; | |
/** @var string */ | |
protected static $uploadDirectory = null; | |
static public function setUploadDirectory($dir) | |
{ | |
self::$uploadDirectory = $dir; | |
} | |
static public function getUploadDirectory() | |
{ | |
if (self::$uploadDirectory === null) { | |
throw new \RuntimeException("Trying to access upload directory for profile files"); | |
} | |
return self::$uploadDirectory; | |
} | |
/** | |
* Assumes 'type' => 'file' | |
*/ | |
public function setFile(File $file) | |
{ | |
$this->file = $file; | |
} | |
public function getFile() | |
{ | |
return new File(self::getUploadDirectory() . "/" . $this->filePersistencePath); | |
} | |
public function getFilePersistencePath() | |
{ | |
return $this->filePersistencePath; | |
} | |
public function processFile() | |
{ | |
if (! ($this->file instanceof UploadedFile) ) { | |
return false; | |
} | |
$uploadFileMover = new UploadFileMover(); | |
$this->filePersistencePath = $uploadFileMover->moveUploadedFile($this->file, self::getUploadedDirectory()); | |
} | |
} |
<?php | |
class DocumentController extends Controller | |
{ | |
public function formAction() | |
{ | |
$document = new Document(); | |
$form = $this->container->get('form.factory')->create(new DocumentType(), $document); | |
$request = $this->container->get('request'); | |
if ($request->getMethod() == 'POST') { | |
if ($form->isValid()) { | |
$document->processFile(); | |
} | |
} | |
} | |
} |
<?php | |
class UploadFileMover | |
{ | |
public function moveUploadedFile(UploadedFile $file, $uploadBasePath) | |
{ | |
$originalName = $file->getOriginalName(); | |
// use filemtime() to have a more determenistic way to determine the subpath, otherwise its hard to test. | |
$relativePath = date('Y-m', filemtime($this->file->getPath())); | |
$targetFileName = $relativePath . DIRECTORY_SEPARATOR . $originalName; | |
$targetFilePath = $uploadBasePath . DIRECTORY_SEPARATOR . $targetFileName; | |
$ext = $this->file->getExtension(); | |
$i = 1; | |
while (file_exists($targetFilePath) && md5_file($file->getPath()) != md5_file($targetFilePath)) { | |
if ($ext) { | |
$prev = $i==1 ? "" : $i; | |
$targetFilePath = $targetFilePath . str_replace($prev . $ext, $i++ . $ext, $targetFilePath); | |
} else { | |
$targetFilePath = $targetFilePath . $i++; | |
} | |
} | |
$targetDir = $uploadBasePath . DIRECTORY_SEPARATOR . $relativePath; | |
if (!is_dir($targetDir)) { | |
$ret = mkdir($targetDir, umask(), true); | |
if (!$ret) { | |
throw new \RuntimeException("Could not create target directory to move temporary file into."); | |
} | |
} | |
$file->move($targetDir, basename($targetFilePath)); | |
return str_replace($uploadBasePath . DIRECTORY_SEPARATOR, "", $targetFilePath); | |
} | |
} |
Thanks, useful !
Thanks for this really nice approach.
What I like the most is the static uploads directory path which is set during the bundle bootup. This is a simple way to put this setting in the application parameters.
# app/config/config.yml
parameters:
uploads_directory: %kernel.root_dir%/../uploads
# MyBundle.php
// ...
public function boot()
{
Document::setUploadsDirectory($this->container->getParameter('uploads_directory'));
}
}
// ...
This can be useful for any kind of entity parameters and there are a lot of questions out there how to get values from the parameters.yml
from inside an entity.
@moesis, Read the Symfony2 forms documentation. You'll quickly figure out what the DocumentType class should contain :)
Hi,
is it by intention, using the $this->file object instead of the $file object in the moveUploadedFile method?
best regards.
The only problem i've had with this approach: defining different folders for each bundle.
Multiple bundles are always loaded so you can't define a variable upload directory for each bundle, the directory will always be overwritten by the last bundle loaded.
could you show me the template TWIG when you implements this form upload ?
I really really dont understand what this gist has anything to do with uploading a file in symfony?!?!
Why do I need an entity to upload a file in symfony?
The author definitively didnt understand symfony OR he only follows blindly some examples which he clearly doesnt grasp.
Good job! Keep up the noob work!
The entity is obviously needed to store/persist a reference of the uploaded asset. How else will you access the uploaded file in your code? If you do see another/better way, kindly post it instead of criticizing the author.
P.s. I needed to integrate symfony with a JS library to generate thumbnails of the uploaded images. This article helped me and might help some of you too! :)
in the bundle boot method.