Ian P. Christian's Personal Blog Random witterings from pookey

11Mar/103

Handling Uploaded file in symfony’s admin generator

When a file is uploaded using sfForm in the admin generator, by default the filename that's used is a random string, which can look bad in URLs. If you want to change this, it's not immediately obvious how - but it is incredibly simple.

I think this is perhaps just a badly documented feature; or if it is documented I've not ever seen the document, and it doesn't come up in my search results when I look. A page does document it on the wiki, however it's rather long winded - http://trac.symfony-project.org/wiki/HowToRenameFileAfterUpload. I found this by accident whilst looking in the sfDoctrinePlugin (the same feature exists in sfPropelPlugin) source code for something else, and here's the magic:

<?php
abstract class sfFormDoctrine extends sfFormObject
 
  ...
 
  protected function saveFile($field, $filename = null, sfValidatedFile $file = null)
  {
    if (!$this->validatorSchema[$field] instanceof sfValidatorFile)
    {
      throw new LogicException(sprintf('You cannot save the current file for field "%s" as the field is not a file.', $field));
    }
 
    if (null === $file)
    {
      $file = $this->getValue($field);
    }
 
    $method = sprintf('generate%sFilename', $this->camelize($field));
 
    if (null !== $filename)
    {
      return $file->save($filename);
    }
    else if (method_exists($this, $method))
    {
      return $file->save($this->$method($file));
    }
    else if (method_exists($this->getObject(), $method))
    {
      return $file->save($this->getObject()->$method($file));
    }
    else if (method_exists($this->getObject(), $method = sprintf('generate%sFilename', $field)))
    {
      // this non-camelized method name has been deprecated
      return $file->save($this->getObject()->$method($file));
    }
    else
    {
      return $file->save();
    }
  }

From this, you should realise that before saving a file, the admin generator will try looking in a number of places to find out if you've defined a method to provide a name, and if you haven't, it calls back to using a name generated by sfValidatedFile. One of the places you can see it checking is the form, so... try this:

class DownloadForm extends BaseDownloadForm
{
 
  ...
 
  public function generatePreviewImageFilename($validator)
  {
    echo "<pre>";
    var_dump($this->getValues());
    var_dump($validator);
    var_dump($this->getObject()->toArray());
    die();
  }
}

Yes - I'll admit the way I debug and play with code is very primitive using var_dump's and dies - but it works for me! This example assume there's a 'preview_image' property of my Download model, but it shows you what variables you have available to you to use to name your file. One think to note is that this is called before save() is called on your object, so if it's a new object, the Id won't be available. Other than that, you can name it anything you want. Don't forget it's worth ensuring you're not overwriting an existing file too.

Conclusion

Not every feature of symfony is documented, it would be near impossible to do so too. You could argue the documentation could be better (and I'm sure patches are welcome!) - but really, you will learn more about what you can do by getting your hands dirty and diving into the symfony source code

Filed under: geek, php, symfony Leave a comment
Comments (3) Trackbacks (3)
  1. *wow* Keep up writing these posts! Very useful indeed.

  2. Thanks.
    The documentation about uploads in admin-genetator is very poor indeed.

  3. Actually, this is documented in the Practical Symfony book, in the section “The Forms – Customizing the Job Form”, it’s a small note (page 122). Anyway, it’s good and appreciated that people post the solution for their problems.


Leave a comment