2

I have to modify a Zend form where some of the fields can contain decimals. Currently you can only enter your decimals using a point: 34.75)

What I'd like the users to be able is to write their decimals both with a comma or a point. The fields can contain either numbers like 34.75 and 34,75 (In this case, both have the same value). I don't want to modify any configuration on the server, so I need to do this in the code.

Right now the value of some fields is calculated in function of other fields; so when you enter a comma, it messes up the calculations. It's done in javascript, and I'll need to fix those calculations - but for now, I want to fix this issue in the php code when I retrieve the form.

I tried to find a solution on the Zend website, but I didn't find anything I've already read elsewhere with more examples. As you'll see in the code, I need to add either a filter or a validator to a zend_form_element_text. I cannot use a str_replace, as the element is a zend_form_element_text.

I have found this other question for reference.

Here is my resulting code:

$tabBilanFrais = array( 'txtFraisSecretariat' => array( 'nom' => 'Frais secrétariat', 'disabled' => true, "class"=>"calcul"),
                            'txtFraisRegion' => array( 'nom' => 'Frais région', 'disabled' => false),
                            'txtFraisSalle' => array( 'nom' => 'Salle', 'disabled' => false, "class"=>"calcul"),
                            'txtFraisPause' => array( 'nom' => 'Pauses', 'disabled' => false, "class"=>"calcul"),
                            'txtDivers' => array( 'nom' => 'Divers', 'disabled' => false, "class"=>"calcul"),
                            'txtTotalRegion' => array( 'nom' => 'Total région', 'disabled' => true, "class"=>"total"),
                            'txtIndemnisationAdherent' => array( 'nom' => 'Comm. ADH', 'disabled' => true, "class"=>"calcul"),
                            'txtIndemnisationPAP' => array( 'nom' => 'Comm. PAP', 'disabled' => true, "class"=>"calcul"),
                            'txtIndemnisationForNext' => array( 'nom' => 'Comm. ForNext', 'disabled' => true, "class"=>"calcul"),
                            'txtIndemnisationPROStages' => array( 'nom' => 'Comm. PROStages', 'disabled' => true, "class"=>"calcul"),
                            'txtRecettes' => array( 'nom' => 'Recettes', 'disabled' => true, "class"=>"totalMontant"),
                            'txtDepenses' => array( 'nom' => 'Dépenses', 'disabled' => true, "class"=>"totalMontant"),
                            'txtRecettesH' => array( 'nom' => 'Recettes', 'disabled' => false, "class"=>"hiddenTxt"),
                            'txtDepensesH' => array( 'nom' => 'Dépenses', 'disabled' => false, "class"=>"hiddenTxt")
                    );


$tabFormulaire = array() ;

foreach($tabBilanFrais as $id => $tabElement)
{
    if($tabElement['nom'] == 'Frais region' )
        $element = new Zend_Form_Element_Hidden($id, array("label" => $tabElement['nom'], "required" => false, 'decorators' => array("ViewHelper", "Errors", "Label"))) ;
    else{
        $element = new Zend_Form_Element_Text($id, array("label" => $tabElement['nom'], "required" => false, 'decorators' => array("ViewHelper", "Errors", "Label"))) ;
        //$element->addFilter('pregReplace', array('match' => '/,/', 'replace' => '.'));
        $element->addFilter('LocalizedToNormalized');
        $element->addValidator('float', true, array('locale' => 'fr_FR'));
        if(isset($tabElement['class']) && $tabElement['class']){
            $element->setAttrib('class', $tabElement['class']);
        }
    }

    if( $tabElement['disabled'])
        $element->setAttrib('disabled', 'disabled');



    $tabFormulaire[] = $element ;
}

The pregReplace isn't working. The validator is (comma becomes a .). I get an error message about the number not being a float.

Community
  • 1
  • 1

3 Answers3

2

You can always write your own validator. In case of float I faced the same problem like you:

class Yourlib_Validate_Float extends Zend_Validate_Abstract
{
    const INVALID   = 'floatInvalid';
    const NOT_FLOAT = 'notFloat';

    /**
     * @var array
     */
    protected $_messageTemplates = array(
        self::INVALID   => "Invalid type given. String, integer or float expected",
        self::NOT_FLOAT => "'%value%' does not appear to be a float",
    );

    public function isValid($value)
    {
        $this->_setValue($value);

        $value = str_replace(',', '.', $value);

        if (!is_string($value) && !is_int($value) && !is_numeric($value)) {
            $this->_error(self::INVALID);
            return false;
        }

        if (is_numeric($value)) {
            return true;
        }

        $this->_error(self::NOT_FLOAT);
        return false;
    }
}

And to add the validator:

$element->addValidator(new Yourlib_Validate_Float());

Please rename Yourlib to whatever suits you. And you need to register your "namespace" in the application.ini like this:

autoloadernamespaces.Yourlib = "Yourlib_"

Strictly speaking this validator is a numeric validator. It accepts all numeric values like ints and floats thru the check with is_numeric. Feel free to modify that.

bitWorking
  • 12,485
  • 1
  • 32
  • 38
  • Thank you for your answer. I should've been more clear on a point though. The fields probably retrieve strings (i don't really know about that), that's why it isn't recognized as a float I think. I have no idea what validator i should use to solve that. – user2583853 Jul 15 '13 at 19:01
  • @user2583853 yes, form values are always strings but the default float validator `Zend_Validate_Float` can't deal with `.` and `,`. It can only deal with one of these depending on the locale setting. Have a look at the source `Zend/Validate/Float.php` and you'll see that my validator is not very different.. – bitWorking Jul 15 '13 at 19:13
  • Oh okay, I'll give it a try when I get back to work and I'll let you know. Thanks. You'll have your +1 if it works ;) – user2583853 Jul 15 '13 at 19:49
0

Alright, here is the modified part of the code:

foreach($tabBilanFrais as $id => $tabElement)
        {
            if($tabElement['nom'] == 'Frais region' )
                $element = new Zend_Form_Element_Hidden($id, array("label" => $tabElement['nom'], "required" => false, 'decorators' => array("ViewHelper", "Errors", "Label"))) ;
            else{
                $element = new Zend_Form_Element_Text($id, array("label" => $tabElement['nom'], "required" => false, 'decorators' => array("ViewHelper", "Errors", "Label"))) ;
                $element->addFilter('pregReplace', array('match' => '/,/', 'replace' => '.'));
                $element->addFilter('LocalizedToNormalized');
                $element->addValidator(new Anper_Validate_Float(), true, array('locale' => 'fr_FR'));
                if(isset($tabElement['class']) && $tabElement['class']){
                    $element->setAttrib('class', $tabElement['class']);
                }
            }

            if( $tabElement['disabled'])
                $element->setAttrib('disabled', 'disabled');



            $tabFormulaire[] = $element ;
        }

But now I need the values of the fields in $element to have the comma replaced by a point before the element is added to $tabFormulaire. Currently numbers with a comma are truncated (124,5 becomes 124) when I validate the form and display the updated values. The pregreplace doesn't seem to work.

Edit: it seems I don't need the pregReplace. I used two echo in my isValid function for the custom validator: one before the str_replace and one after. When I write in one of the field a value with a comma, both the echo displays the number with a point. I assume it's the result of the filter LocalizedToNormalized. What I don't understand is why once the values are saved and displayed those with a comma are truncated despite the findings I just made.

Edit2: If I write for example 124 8, and use a pregReplace to do like there was no blank, the 8 isn't kept on save; despite the pregReplace working (tried with my previous echo).

0

Although @bitWorking's answer is 100% OK, from the view point of semantics, it's better to use a filter (since it's more of filtering rather than validating)

either NumberFormat filter or writing your own.

Dima Dz
  • 512
  • 1
  • 5
  • 17