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.
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.
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).
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.
Related
I am using agile toolkit code for developing an application , i do have dropdown that get values from database, I want to show selected value from field 1 to field 2 without submit any thing.
$form->addField('field1', ['caption' => 'Field 1', 'DropDown', 'values'=> $arra1,'isMultiple' => true ,'readonly' => false, ['dropdownOptions' => ['fullTextSearch' => true]]]);
$form->addField('field2', ['caption' => 'Select Specfic Values', 'DropDown','model' => new view_values($db),'dependency' => function (view_values $model, $data)
{isset($data['field1']) ? $model->addCondition($model->fieldName()->id, 'like', '%' . $data['field1'] . '%') : null;}
,'isMultiple' => true ,'readonly' => false, ['dropdownOptions' => ['fullTextSearch' => true]]]);
issue is Fatal Error atk4\ui\Exception: Unable to add form field (), object: atk4\ui\FormField\DropDown () property: "dependency" value: {}. Looking for Help. maybe my logic is wrong.
I have managed to find a solution for 2 field multi selection scenario:
$values = new view_table($db);
$values->addCondition($db->dsql()->orExpr()->where($db->dsql()->
andExpr()->where('field_status','<>','1')));
$Array = array();
reset($Array);
foreach($values as $row){
$Array[$row['id']] = $row['field_1'].": ".$row['field_2'];
}
$fieldvalue_1 = $form->addField('fieldvalue_1', ['caption' => 'fieldvalue_1', 'DropDown', 'values'=> $Array,'isMultiple' => true ,'readonly' => $readonly, ['dropdownOptions' => ['fullTextSearch' => true]]]);
$fieldvalue_2 = $form->addField('fieldvalue_2', ['caption' => 'fieldvalue_2', 'DropDown', 'values'=> $Array,'isMultiple' => true ,'readonly' => $readonly, ['dropdownOptions' => ['fullTextSearch' => true]]])->set($_GET['val'] ?? 'No value');
$fieldvalue_1->js('change' ,new \atk4\ui\JsReload($fieldvalue_2,['val' => $fieldvalue_1->jsInput()->val()]));
I need to add a MailChimp subscriber to a specific grouping. I have no issue getting the subscriber subscribed, but can't seem to get them into a specific grouping.
This is what I have:
// ENTER INTO MAILCHIMP
$newsletter = $_POST['newsletter'];
$newsletter = 'yes';
if ($newsletter = "yes") {
$MailChimp = new \Drewm\MailChimp('api');
$result = $MailChimp->call('lists/subscribe',
array(
'id' => 'listnumber',
'email' => array('email'=> $_POST['usersEmail']),
'merge_vars' => array(
'FNAME'=>$_POST['usersName'], 'LNAME'=>$_POST['usersLastName'],
'groupings' => array(
'id' => 494281,
array(
'name'=>'KeepBoard',
'groups' => 'KeepBoardUsers'
)
)
),
'double_optin' => false,
'update_existing' => true,
'replace_interests' => false,
'send_welcome' => false
));
print_r($result);
}
Also I am not entirely sure where to grab the listing id. I can't seem to find documentation. I worked off the URL. But I don't think that is right because that is the id for all groupings.
For those that have this problem this was the issue. The groups have to be an array, even for a single group.
so, I want to make a new button in my CGridView. This is up & down arrow buttons which is will be used for sorting my articles. I've read a lot of how to make this kind of buttons. I already read the wiki of how to use this CGridView button also in this link.
And now I have this in my view :
array(
'header' => 'Action',
'class' => 'CButtonColumn',
'template' => '{moveup}{movedown}{view}{delete}',
'htmlOptions' => array('style' => 'width: 68px'),
'buttons' => array
(
'moveup' => array
(
'label' => 'Move Up',
'imageUrl' => Yii::app()->request->baseUrl . '/images/move_up.png',
'url' => 'Yii::app()->createUrl("KB/moveup", array("id"=>$data->KBID))',
'visible' => '$data->KBORDER == KB::model()->getMax()',
),
'movedown' => array
(
'label' => 'Move Down',
'imageUrl' => Yii::app()->request->baseUrl . '/images/move_down.png',
'url' => 'Yii::app()->createUrl("KB/movedown", array("id"=>$data->KBID))',
'visible' => '$data->KBORDER == KB::model()->getMin()',
),
),
),
and this one in my model :
public function getMax(){
$sql = 'SELECT MAX(KBORDER) FROM KB';
$max = Yii::app()->db->createCommand($sql);
$max->queryAll();
return $max;
}
public function getMin(){
$sql = 'SELECT MIN(KBORDER) FROM KB';
$min = Yii::app()->db->createCommand($sql);
$min->queryAll();
return $min;
}
All that codes running just fine. except for the visibility. I want to make the up button become invisible when it has the highest value of KBORDER or when it position is in the 1st place. And for the down button, it supposed to be invisible too when it has the lowest value of KBORDER or when it position is in the last place. but, when I put that code in my 'visible', all the buttons are invicible.
so my question is, how to make my request happen?
thanks in advance
First off, queryAll returns an array. Documentation. So you should probably use queryScalar, and you should return the result from the function, not the command object.
return $max->queryScalar();
You could also use a statistical query in Yii.
Secondly, you want to SHOW the button when it is not in the top or bottom respectivily, so you should negate the =
'visible' => '$data->KBORDER != KB::model()->getMax()',
and
'visible' => '$data->KBORDER != KB::model()->getMin()',
I have a working webService using NuSOAP. Now, I have to make a validation before returning the data requested. If everything is ok, I return it normally, otherwise I would like to return a String message explaining why I'm not giving the information requested. Problem is that I can't get to add two different types of return to RegisterFunction of NuSOAP. If I add a ComplexType as return, I can't return a String.
The function can't have two return-values. You should add the error-message-string to your complex type. If you don't wanna touch your complex type, then you should create another
complex type wich contains your datatype and a string.
Example - the complex type you have right now:
$server->wsdl->addComplexType('myData','complexType','struct','all','',
array( 'important' => array('name' => 'important','type' => 'xsd:string'),
'stuff' => array('name' => 'stuff','type' => 'xsd:string')
)
);
the extra complex type:
$server->wsdl->addComplexType('package','complexType','struct','all','',
array( 'data' => array('name' => 'data','type' => 'tns:myData'),
'errormsg' => array('name' => 'errormsg','type' => 'xsd:string')
)
);
registration of the function:
$server->register(
'getData',
array('validation'=>'xsd:string'),
array('return'=>'tns:package'),
$namespace,
false,
'rpc',
'encoded',
'description'
);
the function:
function GetData($validation)
{
if($validation == "thegoodguy") {
$result['data'] = array(
"important" => "a top secret information",
"stuff" => "another one"
);
$result['errormsg'] = null;
} else {
$result['data'] = null;
$result['errormsg'] = "permission denied!";
}
return $result;
}
That way the client could try to analyse the received data and if it is null then he
shows up the errormessage.
You first need to define a new type that describes an array of strings like so:
$server->wsdl->addComplexType(
'ArrayOfString',
'complexType',
'array',
'sequence',
'',
array(
'itemName' => array(
'name' => 'itemName',
'type' => 'xsd:string',
'minOccurs' => '0',
'maxOccurs' => 'unbounded'
)
)
);
Then you can use tns:ArrayOfString as the return type.
I need to create field that as option gets regex string.
So, i made PatternType field:
public function getDefaultOptions(array $options)
{
$defaultOptions = array(
'data' => null,
'data_class' => null,
'trim' => true,
'required' => true,
'read_only' => false,
'max_length' => null,
'pattern' => null,
'property_path' => null,
'by_reference' => true,
'error_bubbling' => false,
'regexp' => false,
'error_mapping' => array(),
'label' => null,
'attr' => array(),
'invalid_message' => 'This value is not valid',
'invalid_message_parameters' => array()
);
$class = isset($options['data_class']) ? $options['data_class'] : null;
// If no data class is set explicitly and an object is passed as data,
// use the class of that object as data class
if (!$class && isset($options['data']) && is_object($options['data'])) {
$defaultOptions['data_class'] = $class = get_class($options['data']);
}
if ($class) {
$defaultOptions['empty_data'] = function () use ($class) {
return new $class();
};
} else {
$defaultOptions['empty_data'] = '';
}
$patt = $options['regexp'];
unset($options['regexp']);
$defaultOptions['validation_constraint'] = new Regex(
array(
'pattern' => $patt,
'match' => true,
'message' => 'Niewłaściwy format'
)
);
var_dump($defaultOptions);
return $defaultOptions;
}
var_dump returns well formatted settings array, with regex object within - but when form is generated validation doesn't work - pass any value. Any idea why?
Why are you doing this? There is a regex validator already. Just use a normal text field with that validator.
In case you need a form without a model class to bind to, read the corresponding section.
Ok, I found what was wrong - you can only add validator constant to root form object (others symfony simply ignore). So it seems that what I need is simply get root form, add there validator_constant with validator_group option set. Then just assign field proper validator_group.