I'm having a problem.
I'm using ZF2, and getting an error here.
$inputFilter->add($factory->createInput(array(
'name' => 'dataInicial',
'required' => true,
'validators' => array(
array(
'name' => 'NotEmpty',
'options' => array(
'messages' => array(
\Zend\Validator\NotEmpty::IS_EMPTY => 'A data do feriado deve ser preenchida.'
)
)
),
array(
'name' => 'callback',
'options' => array(
'messages' => array(
\Zend\Validator\Callback::INVALID_CALLBACK => 'Data no formato inválido.'
),
'callback' => function ($value, $context = array()) {
$dataInicial = \DateTime::createFromFormat('d/m/Y', $value);
return $dataInicial->format('d/m/Y');
}
)
)
)
)));
I'm getting this error:
DateTime::__construct(): Failed to parse time string (25/12/2014) at position 0 (2): Unexpected character
When I execute the same code in pure php, without zend, it works ok.
echo DateTime::createFromFormat('d/m/Y', '25/12/2014')->format('d/m/Y');
Maybe someone knows what's causing the error? Sorry for my english
Don't know what kind of database backend and relationship mapping but the issue is related to how the date is being stored I imagine, most likely like: Y/m/d
If you saving and getting this error then it's because you need the date in this format. If you are hydrating you may also need a date strategy to deal with hydration like:
// InputFilter.php
class yourInputFilter()
{
$hydrator->getHydrator()->addStrategy('my_attribute', new MyDateHydrationStrategy());
$this->add( array(
'name' => 'registration_starts',
'type' => 'Zend\Form\Element\DateTime',
'options' => array (
'format'=>'Y/m/d',
)
));
}
// YourForm.php
class YourForm Extends ....
{
$dateTime = new Element\DateTime('youDate');
$dateTime->setLabel('Date')
->setOptions(array(
'format' => 'Y-m-d\TH:iP'
));
}
// Strategy.php
class myDateTimeStrategy implements StrategyInterface
{
public function hydrate($value)
{
if (is_string($value)) {
$value = new DateTime($value);
}
// Could return in a different format, probably can't though because of when you need to edit
// return $value->format("m-d-Y")
return $value;
}
}
You will also need to change js settings if you using a datetime widget picker:
Which will be something like:
$('.datepicker').datepicker('format', 'yyyy/mm/dd');
Depending on which one you using.
Related
Im currently getting my hands dirty with some subclassing object oriented php. I would like to use an array to create some form fields, and these fields are separated into classes based on their type. This means that I have a main class called "form_field", and then have a bunch of subclasses called "form_field_type" (ex. "form_field_select"). The idea is that each subclass "knows" how to best generate their HTML in a display method.
So lets say that i write an array like this:
$fields = array(
array(
'name' => 'field1',
'type' => 'text',
'label' => 'label1',
'description' => 'desc1',
'required' => true,
),
array(
'name' => 'field2',
'type' => 'select',
'label' => 'label1',
'description' => 'desc1',
'options' => array(
'option1' => 'Cat',
'option2' => 'Dog',
),
'ui' => 'select2',
'allow_null' => false,
)
);
I would then like to create a loop that instantiates the correct class based on the type:
foreach ($fields as $field) {
$type = $field['type'];
$new_field = // instantiate the correct field class here based on type
$new_field->display();
}
What would be the best approach here? I would like to avoid doing something like:
if ($type == 'text') {
$new_field = new form_field_text();
} else if ($type == 'select') {
$new_field = new form_field_select();
} // etc...
This just feels inefficient, and i feel like there must be a better way? Is there a good pattern that is generally used in this situation, or am I going about solving this the wrong way?
Try something like this...
foreach ($fields as $field) {
$type = $field['type'];
// instantiate the correct field class here based on type
$classname = 'form_field_' .$type;
if (!class_exists($classname)) { //continue or throw new Exception }
// functional
$new_field = new $classname();
// object oriented
$class = new ReflectionClass($classname);
$new_field = $class->newInstance();
$new_field->display();
}
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.
So I created a input filter (see below) but I have to test 24 fields to make sure they are all valid (only 1 listed below to keep this simple). In this case, the input is coming from an e-mail server, not a user, so I need accept the input, and not send an error back. However, I still need to check the data to ensure no one is messing with the headers / fields trying to mess everything up.
So my question is, how can I sent a default value for each input? For example blow, if the mailbox is length 0, something is wrong, so I just want to set the value to be something like 'InvalidMailbox' so I can still store this in the database,
public function getInputFilter()
{
if (!$this->inputFilter) {
$inputFilter = new InputFilter();
$factory = new InputFactory();
$inputFilter->add($factory->createInput(array(
'name' => 'mailbox',
'required' => true,
'filters' => array(
array('name' => 'StripTags'),
array('name' => 'StripNewLines'),
array('name' => 'StringToLower'),
array('name' => 'StringTrim'),
),
'validators' => array(
array(
'name' => 'StringLength',
'options' => array(
'encoding' => 'UTF-8',
'min' => 1,
'max' => 200,
),
),
),
)));
$this->inputFilter = $inputFilter;
}
return $this->inputFilter;
}
Calling it...
$mail = new SMail();
$inputFilter = $mail->getInputFilter;
$inputFilter->setData($data);
if ($inputFilter->isValid()) {
//echo "The form is valid\n";
} else {
// Maybe set the default here?
// but with 24 different fields, how can I know which one caused the error?
//echo "The form is not valid\n";
}
Okay, sorry that i didn't get the quest right first time. Going by the Source of the BaseInputFilter, there is a function called getInvalidInput(), so my assumption is, that you can do the following:
$defaultData = array(
'elementName' => 'Default Value'
);
$returnData = array();
if (false === $inputFilter->isValid()) {
$falseInputs = $inputFilter->getInvalidInput();
foreach ($falseInputs as $input) {
$returnData[$input->getName()] = $defaultData[$input->getName()];
}
}
$goodInputs = $inputFilter->getValidInput();
$finalData = array_merge($goodInputs, returnData);
This however is no tested code. I'm not sure if $input->getName() is available. You may need to adjust that part accordingly. I'm quite certain though that this should be able to get you started, hopefully ;)
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.