Friday
17
April
2009

Localizing and Normalizing with Zend_Filter

Sometimes you have to work with user-provided numbers or dates.
The problem with this data is, that when your users are using different locales, then you will have to normalize and localize the provided data to be able to work with them.

In past you had to convert the data manually or by using Zend_Locale.

$values = $form->getValues();
	
$values['firstnumber'] = Zend_Locale::getInteger($values['number']);
$values['secondnumber'] = Zend_Locale::getInteger($values['number']);

With Zend Framework 1.8 I added a filter which does this for you. Simply add the filter to your form

$element = new Zend_Form_Element_Text('firstnumber');
$element->addFilter('LocalizedToNormalized');

This filter can handle
* Numbers like Integer, Float, Real
* Dates
* Times

Numbers will be returned as string in the english/computer notation.
Dates and Times will be returned as array where every date part is seperated to a own key.

The german number 12.345,67
would become 12345.67

This comes handy, for example, when you want to store the provided data within a database because you should always use a normalized representation when you work with multiple locales.

Of course I added also a filter which does the reverse task… to localize a normalized value.

Let’s expect we have a normalized value from a internal source. To display it in a localized manner simply use Zend_Filter_NormalizedToLocalized.

$filter = new Zend_Filter_NormalizedToLocalized();
$date = array(
    'day' => 3,
    'month' => 10,
    'year' => 2009
);
	
print $filter->filter($date);

The benefits of this components are, that they can be used within every other component which allows the usage of filters. And both detect the type of the given value automatically. Of course this filter provides als several parameters which enables you to tweak what the components return. For details about the parameters take a look into the manual.

I hope you find them usefull.

Greetings
Thomas Weidner
I18N Team Leader, Zend Framework

Zend Framework Advisory Board Member
Zend Certified Engineer for Zend Framework

Back to top
Friday
17
April
2009

Recieving files with Zend_Form_Element_File

How to receive a file from Zend_Form_Element_File is often a difficult question.
When you have problems you should read below to get an idea of the handling and to prevent possible problems:

Let’s expect our form has a file element like this one:

$element = new Zend_Form_Element_File('file');
$element->setDestination('/MyDir');

In past, before ZF 1.8, when you wanted to get the uploaded file you had to call receive() afterwards like this…

if ($form->isValid($this->getPost())) {
    if (!$element->file->receive()) {
        print_r($element->file->getMessages());
    }
}

Now many people said, and I think they were right, that it would be a great idea to get the file when calling getValues(). So we added this new feature for ZF 1.8.

This means that that with ZF 1.8 this call is enough:

$values = $form->getValues();

Your file is already transferred… no need to call received afterwards.

But sometime it is wished to call received manually. You could, for example, wish to add a own filter based on a value which you get from your form. So calling getValues() now would mean that you can not add a filter afterwards… as the file is already transferred.

But also for this usecase a solution has been added. You can set a flag to the file element which prevents that the file itself will be received when you call getValues().

Take a look at the following file element:

$element = new Zend_Form_Element_File('file');
$element->setDestination('/MyDir')
        ->setValueDisabled(true);

Note the added call of setValueDiabled(). It tells the file element that it should not receive the file when you call getValues().

Now you can call getValues() and the file will not be received in the background. But this means, of course, that you have to call receive() manually. Otherwise your file will not be available after the script has been finished.

$values = $form->getValues();
	
if ($form->isValid($this->getPost())) {
    $element->file->addFilter('Rename', false, 'Filename_'.$values['id']);
    if (!$element->file->receive()) {
        print_r($element->file->getMessages());
    }
}

Remember, to have this working you need to call setValueDisabled() otherwise the file is transferred when calling getValues(). When you omit the call then your file will be transferred, due to getValues(), but it will not be renamed, because the rename filter was not available at the time, the file has been received.

Note, that using a filename based on a user input is always a security issue. Use a autoincremented number from your database for example, or be sure that you validate the user input before using it as new filename.

You should also note that I did not use another instance of Zend_File_Transfer…
The file element itself has already a instance available. When you really need to have the instance itself, then use getTransferAdapter() instead of creating a new instance. This is faster, uses less ressources and prevents possible problems with files already being transferred by the other instance.

Greetings
Thomas Weidner
I18N Team Leader, Zend Framework

Zend Framework Advisory Board Member
Zend Certified Engineer for Zend Framework

Back to top