Custom sfValidatorFile and sfValidatedFile
By eNk` on Monday, April 5 2010, 10:56 - Symfony - Permalink
In this post I will show a way to customize the file upload with the forms framework. The forms framework provide the sfWidgetFormInputFile class to display a file input tag and the sfValidatorFile class which is the default class used to validate a file input field. As all validator classes sfValidatorFile check if the field value is ok according to the validation options, but instead of returning a "basic" value such as an integer or a string, this validator will return an instance of sfValidatedFile as a clean value.
In this exemple I will use an Image class and cutomize the ImageForm class.
Image:
columns:
title: { type: string(255) }
file: { type: string(255) }
The Image form class configured with a sfWidgetFormInputFile and a sfValidadorFile:
class ImageForm extends BaseImageForm
{
public function configure()
{
$this->setWidget('file', new sfWidgetFormInputFile());
$this->setValidator('file', new sfValidadorFile(array(
'path' => '/my/super/folder';
// ... other options ...
))));
}
}
By using the previous configuration, when we will save the form the image file will automaticaly be saved in /my/super/folder.
But let's say we need to save the image in several size, how to do it ? To do this the sfValidadorFile validator provide a 'validated_file_class' option to define your own sfValidtedFile class. So you can easly create a ImageValidatedFile class which extends from sfValidatedFile and override the sfValidatedFile::save() function to save the image as the way you want.
But let's go a little bit futher, it would be cool if we could pass the several size format to the ImageValidatedFile class from the form configuration function, so something like:
class ImageForm extends BaseImageForm
{
public function configure()
{
$this->setWidget('file', new sfWidgetFormInputFile());
$this->setValidator('file', new sfValidatorFile(array(
'path' => '/my/super/folder',
'resize_formats' => array(
'big' => array('width' => 800, 'height' => 600),
'thumb' => array('width' => 120, 'height' => 80) ))
));
}
}
As you can see in the following sfValidatorFile::doClean() function, the sfValidatorFile validator don't pass any options to the validated file class except the path option.
protected function doClean($value)
{
// ...
$class = $this->getOption('validated_file_class');
return new $class($value['name'], $mimeType, $value['tmp_name'], $value['size'], $this->getOption('path'));
}
So to pass some options to the validated file class we can create a custom ImageValidatorFile class which will use the ImageValidatedFile class by default. So the idea is to configure the ImageForm like this:
class ImageForm extends BaseImageForm
{
public function configure()
{
$this->setWidget('file', new sfWidgetFormInputFile());
$this->setValidator('file', new ImageValidatorFile(array(
'path' => '/my/super/folder',
// custom options I will define in ImageValidatorFile:
'preserve_ratio' => true,
'resize_formats' => array(
'big' => array('width' => 800, 'height' => 600),
'thumb' => array('width' => 120, 'height' => 80) ))
));
}
}
In the ImageValidatorFile class we just need to override the configure() and doClean() functions to set the validator options and pass the custom options to the validated file class:
class ImageValidatorFile extends sfValidatorFile
{
protected function configure($options = array(), $messages = array())
{
parent::configure($options, $messages);
$this->setOption('validated_file_class', 'ImageValidatedFile');
$this->setOption('required', false);
$this->addOption('preserve_ratio', true);
$this->addOption('resize_formats', array()));
}
protected function doClean($value)
{
$validatedFile = parent::doClean($value);
$validatedFile->setResizeFormats($this->getOption('resize_formats'));
$validatedFile->setPreserveRation($this->getOption('preserve_ratio'));
return $validatedFile;
}
}
And in the ImageValidatedFile we just need to override the save() function:
class ImageValidatedFile extends sfValidatedFile
{
private $resizeFormats = array();
private $preserveRatio = true;
public function setResizeFileFormats($value)
{
$this->resizeFormats = $value;
}
public function setPreserveRation($value)
{
$this->preserveRatio = (boolean) $value;
}
public function save($file = null, $fileMode = 0666, $create = true, $dirMode = 0777)
{
if(is_null($file))
{
$fileName = substr($this->originalName, 0, strpos($this->originalName, '.'));
$file = preg_replace('/\W+/', '-', $fileName);
$file = strtolower(trim($file, '-'));
$file .= $this->getExtension('.jpg');
}
if($create)
{
// create the folder where to save the files with $dirMode permissions.
}
if(!is_array($this->resizeFileFormats))
{
$this->resizeFileFormats = array();
}
// here I use sfImageTransformPlugin to resize the image
$img = new sfImage($this->tempName, $this->type);
foreach($this->resizeFormats as $formatName => $dimensions)
{
$img->resize($dimensions['width'], $this->preserveRatio ? null : $dimensions['height']);
$img->saveAs($this->path.'/'.$formatName.'/'.$file, $this->type);
}
return $file; // return the file's name
}
}
Comments
Thanks, very useful article. I used to override the 'save' method of the form class, but this is much more elegenat and DRY solution.
<A href="http://www.toptoys2trade.com/zhu-zh... ">zhu zhu pets</A>
<a href="http://www.toptoys2trade.com/a-sill... "> silly bandz</a>
<A href="http://www.toptoys2trade.com/power-... "> power balance</A>
<A href="http://www.toptoys2trade.com/animal... ">animal rubber bands</A>
<A href="http://www.toptoys2trade.com/baby-c... ">Baby Carriers</A>
<A href="http://www.toptoys2trade.com/pillow... ">Pillow Pets</A>
<A href="http://www.toptoys2trade.com/plush-... ">Plush Pencil Case</A>
<A href="http://www.golf-equipment2u.com ">golf equipments</A>
[url=http://www.b2chandbag.com/guess-han... ]guess handbags[/url]
[url=http://www.b2chandbag.com/d&g-h... ]d&g handbags[/url]
[url=http://www.b2chandbag.com/ ]prada handbags[/url]
[url=http://www.topcasualshoes.com/ ]ecco shoes[/url]