This forum is in READ-ONLY mode.
You can look around, but if you want to ask a new question, please use Stack Overflow.

sfValidatedFile related components native behavior

Requests for new symfony features.

sfValidatedFile related components native behavior

by lightpriest » Tue Dec 15, 2009 3:52 pm

In my current project (V:1.4 branch, ORM: Doctrine), I'm using sfValidatorFile which must accept a "path" in its options.
This has an annoying behavior since I can't control the generated filename (supposed I want a constant one).

The object of sfValidatorFile is a field in the database so when the model's save is executed (in-turn) it executes the save method of sfValidatedFile.
Failing to find any doc about the options I could pass to sfValidatorFile, I've followed the code execution to find which options I could pass that would affect the sfValidatedFile behavior.

I then realized that one cannot force a constant filename for the file to be saved.
Code: Select all
// ../symfony/lib/plugins/sfDoctrinePlugin/lib/form/sfFormDoctrine.class.php
public function processValues($values) {
  ..
  ..
  if ($this->validatorSchema[$field] instanceof sfValidatorFile)
  {
    $values[$field] = $this->processUploadedFile($field, null, $valuesToProcess);
  }
  ..
  ..
}
..
..
..
protected function processUploadedFile($field, $filename = null, $values = null) { .. }

Looking at sfValidatedFile API I saw that it has a "isSaved" funcion.
Thinking this function is handled and used somehow in the sfFormDoctrine (so that it won't save the file twice) I created my own ModelForm::save function that saves that file before the form's save method is called only to find out that it is ignored completely and I always get a hashed filename.
Eventually I created my own validatedFile class that inherits from sfValidatedFile and had to implement the "isSaved" method myself.

Is it possible to add a 'filename' option to sfValidatorFile options array? Or to implement the isSaved method?

I didn't want to open a ticket in symfony's trac because I could just be looking in the wrong place.

I could submit a patch myself, but I'm not that active in this community (i.e. I'm not familiar with the idioms you guys work with) so I don't want to interfere with the great work :)~ :-)~ :smile:

Thanks, in advance.
lightpriest
Junior Member
 
Posts: 6
Joined: Mon Jan 26, 2009 10:48 am

Re: sfValidatedFile related components native behavior

by lightpriest » Wed Jan 06, 2010 11:51 am

I see people are viewing this thread.
In case you got here from some search engine, here's my way to work around this:

Luckily, sfValidatedFile supports saving a desired filename (rather then a generated one) so we just need to make it work.

First, I've created my own sfValidatedFile to override the save method.
Let's name it myValidatedFile and put it in project/lib/validator.
Code: Select all
// lib/validator/myValidatedFile.php
class myValidatedFile extends sfValidatedFile {
  private $savedFilename = null;

  // Override sfValidatedFile's save method
  public function save($file = null, $fileMode = 0666, $create = true, $dirMode = 0777) {
    // This makes sure we use only one savedFilename (it will be the first)
    if ($this->savedFilename === null) $this->savedFilename = $file;

    // Let the original save method do its magic :)
    return parent::save($this->savedFilename, $fileMode, $create, $dirMode);
  }
}


To our form we add a normal sfWidgetFormInputFile (or some other file upload widget) and a normal sfValidatorFile with the validated_file_class option:
Code: Select all
// lib/form/ArticleForm.class.php
  public function configure() {
    $this->widgetSchema['thumbnail'] = new sfWidgetFormInputFile();
    $this->validatorSchema['thumbnail'] = new sfValidatorFile(array(
      'path' => 'path/of/your/choice',
      'validated_file_class' => 'myValidatedFile'
    ));
  }


What we did now was just overriding sfValidatedFile with our own method.
Now let's make it work.
We'll need to override the ArticleForm save method so that we'd save the file before sfFormDoctrine saves it.
Code: Select all
// lib/form/ArticleForm.class.php
  public function save($con = null) {
    // Get the uploaded file
    $thumbnail = $this->getValue('thumbnail');

    // The form could be posted without uploading a file
    if ($thumbnail) {
      $thumbnail->save('article_thumb_'.date('Ymd').'.jpg');
    }

    return parent::save($con);
  }

A small explanation.

First, the user requests the form which is configured to use "myValidatedFile" class.
Then, when the user submits the form with a file, the ArticleForm::save method is called.
The ArticleForm::save method calls the validatedFile::save method (which is our method), and it passes along a filename.

The validated file class saves that file name to itself, and calls the original validatedFile::save method to really save the file.
When the real form save happens (in sfFormDoctrine), it calls our class' save method again. Because it remembers the desired filename we selected earlier, it calls sfValidatedFile::save with the filename we wanted.

EDIT: Ofcourse we could save all this work if there was a filename option :)~ :-)~ :smile:
lightpriest
Junior Member
 
Posts: 6
Joined: Mon Jan 26, 2009 10:48 am

Use an object property as part of the uploaded filename

by cocomiel » Thu Feb 11, 2010 10:06 am

Hey, thanks for the info. I've been looking to do this for a while now...

In addition to the above post if you want to use some part of the object you are inserting as part of the filename, you can.

Let's say we want to have the ID after the date:

Code: Select all
  public function save($con = null) {
    // Get the uploaded file
    $thumbnail = $this->getValue('thumbnail');

    // The form could be posted without uploading a file
    if ($thumbnail) {
      $thumbnail->save('article_thumb_'.date('Ymd'). '_id_' . $this->getObject()->getId() . '.jpg');
    }

    return parent::save($con);
  }


I'll add this to the Wiki in a couple of days as it seems to stump a lot of people.
cocomiel
Junior Member
 
Posts: 3
Joined: Sat Jan 30, 2010 9:06 am

Re: Use an object property as part of the uploaded filename

by jmiridis » Mon Mar 29, 2010 5:45 am

May be I'm missing something here and my post is obsolete, but please let me know if this is the case and where my thinking is wrong.

The sfFormDoctrine::saveFile() method looks for both a form-method and and object-method with the name: generate<field>Filename() and uses the returned string (of the method it finds first) as the filename to store uploaded file under. So I think the following options should resolve the problem as well.

Code: Select all
// ArticleForm.class.php

  public function generateThumbnailFilename(sfValidatedFile $file)
  {
    return 'article_thumb_'.date('Ymd').'.jpg';
  }


or

Code: Select all
// Article.class.php

  public function generateThumbnailFilename(sfValidatedFile $file)
  {
    return sprintf('article_thumb_%s_id_%d.jpg', date('Ymd'), $this->getId());
  }
jmiridis
Junior Member
 
Posts: 20
Joined: Sun Apr 12, 2009 5:32 pm