[/caption]
There are many lousy things about the file upload button. But one of the worst is that, unlike regular form elements, if you present the same file upload button back to the user with their previous selection filled out... it doesn't work. They have to browse for the file again. Which contrasts harshly with the way other input elements behave: as long as you present the user's input back to them as the new default, they don't have to enter it again. And if you're asking the user to correct three or four things in a large form, you really, really don't want to make them re-upload their resume on every single pass.
Now before you start hollering about security, let me say that I fully understand
why the upload button won't let you specify a default. In a word, it's dangerous. Black hat web developers could specify any file on the hard drive... perhaps a file that often contains passwords on most people's hard drives, for instance... and if the user didn't triple-check, the black hats would then be in possession of the user's personal information. Ouch.
What's more, even if this did work, the user would still be
uploading the file over and over. Which is slow. And when it isn't slow, it's expensive. One sure way to exhaust your bandwidth allocation and be invited to step up to an exciting new level of service from your web hosting provider.
So what do we do about this? We work around it... over and over. A common pattern is to accept the file provisionally even though the rest of the form didn't validate, perhaps saving an object in a database but marking it "incomplete" until the user finishes the job correctly.
Of course, doing anything over and over is Repeating Yourself, and around here we frown on that sort of thing. I knew I wanted a real and lasting fix for the problem.
Enter
Symfony 1.2 and its new approach to forms. Symfony 1.2's forms offer lovely abstractions like widgets and validators. A widget represents an input element, file elements included, while a validator is responsible for determing whether a value is acceptable. They are very simple and well-factored and completely independent of one another.
Or they were until I got hold of 'em.
Symfony's approach is to validate fields and then present the form again if it fails validation, redisplaying the same values to the user. But if one of those fields is a file input field, this fails pretty badly: the user has to select the file all over again.
My new widget, pkWidgetFormInputFilePersistent, and its partner in crime, pkValidatorFilePersistent, break a few rules for the sake of the common good. But like all superheroes, they bend the rules for a good cause. And they only do it when you're not looking.
By holding hands under the table, they are able to store the user's initial upload attempt in a temporary folder and pass forward just enough information to allow that file to be automatically reused if the user chooses not to replace the file on the next validation pass.
[caption id="attachment_408" align="alignnone" width="518" caption="File upload, first validation pass"]