Zend_Form and Float number localization - php

I'm using Zend_Form for handling a form and I have a problem with localization.
I use following field declaration:
$this->addElement('text', 'area', array(
'label' => 'Area:',
'required' => true,
'filters' => array('StringTrim', 'NormalizedToLocalized')
));
The problem is, I use pl_PL locale and in this locale the decimal point separator is "," not ".". But database (MySQL) stores float with "." separator.
I added NormalizedToLocalized to convert e.g. 40.12 into 40,12 in my html form.
But when passing 40,12 in POST request I want Zend_Form to automatically convert back value 40,12 into 40.12 so that it can be passed to DB (I collect values from form using $form->getValues() method). By now it renders 40,12 successfully but in $form->getValues() I get localized, not not normalized value.
So my question is, whether it is possible to create different filter for rendering and getting value of field in Zend Framework.
Thanks in advance for your help!

The filters are not applied until the form is submitted so 'NormalizedToLocalized' will not have any effect until the form is posted. So if you want decimal points and not commas in your data for storage remove the filter (or use 'LocalizedToNormalized') from the form and apply the filter using Zend_Filter for any data you need to display.
If this field always expects a float type you can use a validator to enforce the value and then use the filter to enforce formating for the database.
$this->addElement('text', 'area', array(
'label' => 'Area:',
'required' => true,
'validators' => array('Float'),
'filters' => array('StringTrim', 'LocalizedToNormalized')
));

I'm not familiar with Zend Framework but looking on filter name, shouldn't it be 'LocalizedToNormalized' ?

Related

Selected option not set in EntityType::class formfield symfony3

I'm very new at working with a framework like symfony, but I must say that i am turning in to a fan quite fast. Unfortunately i'm totally stuck for the last few days in a row.
The Context
I'm trying to refactor my old-school php CMS to the symfony3 framework. A user can manage his pages by adding en editing them. Adding a new page to the database works like a charm. Editing a page is also working fine, except one small part of it. The form prefills al fields like it should and a post will edit the entity.
But... for some reason the selectbox won't pre-select with the selected templatetype. This list is build with use of the EntityType::class and fetches the available data from the database by using AppBundle:Templates.
A piece of the code i use for loading and building the form:
// Fetch selected page
$page = $this->getDoctrine()->getRepository('AppBundle:PageMan')->find($id);
// Generate form
$form = $this->createFormBuilder($page)
->add('templateId', EntityType::class, array(
'label' => 'Template type',
'class' => 'AppBundle:Templates',
'placeholder' => 'Kies een template',
'choice_label' => 'name',
'choice_value' => 'id',
'multiple' => false,
'expanded' => false,
'required' => true,
))->getForm();
The last few days i have tried every possibility i could think of and google. I've also checked the following:
templateId is filled with a value after loading the repository. When I change the field to a plain textfield, the value is shown.
AppBundle:Templates returns unique values (only two entity's in the database with id 1 and 2)
The selected="selected" attribute is set when posting (and not redirecting away)
Removing cashe doesn't solve the problem
At his moment i'm out of possible solutions, hope some one can help. It could be something so simple, but i'm just not seeing it anymore.
--Update--
Just found the following inconsistency in a vardump of the generated form. In the 'name'-object you see modelData, normData and viewData pre-filled. But 'templateId' misses content in viewData.
screenshot vardump formbuilder
In the documentation of symfony it states the folowing:
View Data - This is the format that's used to fill in the form fields themselves. It's also the format in which the user will submit the data. When you call Form::submit($data), the $data is in the "view" data format. Source
This could be a possible leed to a solution.
--Update 2--
Just hardcoded $this->viewData in \vendor\symfony\symfony\src\Symfony\Component\Form\Form.php to a hardcoded value that is present in the selectbox. This adds a value to the empty setting as mentioned in the the update above. Now the default value gets selected as it should. I'm going to follow this variable in the code. Hope to find the reason why it doesnt get prefilled.
Actually choice_value is callable, so you can make a function:
'choice_value' => function($page){
return strval( $page->getId() );
}
I think that might work in this case. Please try it.
Finally fixed my problem. Don't know if it's the official way, but in my case it works like a charm.
In my EntityType setting, i'm now passing 'data' => $page, as an extra object to the formbuilder. This results in viewData being filled with a value and that was what i needed to get a pre-selectid selectbox on pageload.
Here the final snippet:
->add('templateId', EntityType::class, array(
'label' => 'Template type',
'class' => TemplateMan::class,
'placeholder' => 'Kies een template',
'choice_label' => 'name',
'choice_value' => 'templateId',
'data' => $page,
'data_class' => null,
'multiple' => false,
'expanded' => false,
'required' => true,
))

Symfony2 Forms prevent changing entity's field

I'm looking for a way to bind entity to a form, but I need a specific field of it to be mapped (displayed), but not modified by the user submitting the form.
What I have checked so far:
Using disabled attribute - it's not being submitted and entity's field is set to null
Using HTML readonly attribute - it can still be modified by manipulating HTML
Using read_only field option - same as above
My field is a checkbox, but I'd prefer a generic solution for that kind of fields, because I'll have more of them in the future.
I would also like to avoid additional query.
Any ideas?
The 1st & 3th solutions are not good.
I had the same issue a while ago. This is what I did to solve it:
I used the 2nd solution, and since you have the entity in the application, you can simply override any value the user had changed by manipulating the HTML (whitch is a risk that should be handled).
or, you could draw a HTML checkbox that is not mapped (with random id and name), and it will be not mapped to you entity.
I think I have found the right solution to that problem. It's not very flexible, but converting it to extension should make it fairly easy to deal with. The basic version I created just now can be found here. A little explanation:
Make the field with option mapped set to false
create event handler function (setUnmappedField)
attach EventListener to both PRE_SET_DATA and SUBMIT events.
PRE_SET_DATA makes sure the field has a correct value when initially rendering the form.
SUBMIT makes sure the field's value is reverted back to the initial value even if user changed it before submitting the form.
Disabled and readonly attributes are here for UI/UX, it will work without these attributes as well.
Feel free to use it to build a form extension if you need one. I will probably build an extension to make it more flexible later, once I need it.
#EDIT
I just realised this can be done easier - leaving the field mapped! updated gist here. No need for PRE_SET_DATA listener and mapped=false
I suggest you do a combination of 1 and 2 . See below for sample
->add('trainings', 'entity', array(
'label'=> 'Upcoming training(s)',
'choice_label' => 'CompleteTitle',
'multiple' => 'true',
'expanded' => 'true',
'by_reference'=>false,
'class' => 'TrainingBundle:Trainings' ,
'query_builder' => function (EntityRepository $er) use ($options) {
return $er->getTrainingByParentId($options['parent_id']);
},
)
)
->add('PastTrainings', 'entity', array(
'label'=> 'Past trainings',
'choice_label' => 'CompleteTitle',
'multiple' => 'true','expanded' => 'false',
'disabled' => 'true',
'class' => 'TrainingBundle:Training' ,'mapped'=>false,
'query_builder' => function (EntityRepository $er) use ($options) {
return $er->getTrainingByParentId($options['parent_id']);
},
)

How to define a placeholder for an input of a stream field using stream API in pyrocms?

I am using community edition of Pyrocms, so cant really use the benefit of stream module that comes in pro edition. I am trying to work with Stream API.
I have defined a stream field's meta data as below:
$field = [
'name' => 'First Name',
'slug' => 'first_name',
'namespace' => 'users',
'type' => 'text',
'extra' => array(
'max_length' => 50,
'placeholder'=> 'Enter your first name' //NOT WORKING
),
'assign' => 'profiles',
'required' => true
]
$this->streams->fields->add_fields($fields);
In the above code, I have declared a key placeholder inside extra and have written its value. But when I later use this stream-field in the form by echoing out as
<?php echo $field['input']; ?>
Input field is rendered as expected and the validation is also working but the text for placeholder does not appear. Same is the case when I try to add extra class attributes when defining meta data for field. I have had a good look in pyrocms documentation. It says there is a way to define attributes for rendered input but have not shown how to do it. I tried adding it into extra also tried defining outside the extra but still I am not able to show up the extra attributes for the input fields. Also, when the type is set to choice, where should I put the default value for drop down menu or checkbox?
The field type 'text' doesn't have a parameter 'placeholder', only 'max_length' and 'default_value'.
So you could copy the text field type, rename the folder and the class, place it in addons/default/field_types and add this parameter to the field type - basically writing your own field type. It's really easy and I made a gist for you: https://gist.github.com/marcogrueter/02b5e70f02402d999059

symfony date validation localization

I have a simple form and I use jquery UI date-picker for birthday input.
and in the server side I use symfony validation with Date validation.
the problem is that the validation accepts only inputs with this format: YYYY-MM-DD
but in other locals like in UK the format is: DD/MM/YYYY
and the server gives error on it.
Do you have any suggestions?
I use the symfony form object with the inside validation,
so I would prefer not to force a format change manually.
As you can read from the documentation "date", the constraint dates performs validation only format "YYYY-MM-DD".
So you have two choices:
one (the simplest and most logical) is to set the format manually in the form field "format":
$builder->add('date', 'date', array(
'widget' => 'single_text',
'format' => 'dd-MM-yyyy',
));
in this way will be the form itself to reverse the date and pass the correct format to the validator (and the database).
The other is to create a constraint callback "callback", and creating your own logic for validation.
There would also be another way, even if it is inserted in the bonds of strings, and it is the constraint regex "regex".
In this way you will need to create a regular expression very precise (and complex).
For a problem as simple as the first solution is the most suitable!
EDIT:
jquery ui datepicker locks to an input type text, you do not need to create it manually.
As I wrote in the example, if you use the 'widget' => 'single_text' will produce an input type text!
You can set up a class to the date field in order to hook into that with jquery.
A short example:
form:
$builder->add('date', 'date', array(
'widget' => 'single_text',
'format' => 'dd-MM-yyyy',
'attr' => array(
'class' => 'your_class'),
));
javascript:
$(function() {
$( ".your_class" ).datepicker();
});

Symfony form not honoring set defaults

I have a pretty simple form with some fields from a doctrine model.
$this->widgetSchema['fields'] = new sfWidgetFormDoctrineChoice(array(
'model' => 'FieldModel',
'expanded' => true,
'multiple' => true,));
$this->validatorSchema['fields'] = new sfValidatorDoctrineChoice(array(
'model' => 'FieldModel',
'multiple' => true,));
The fields are rendered in the form as checkboxes and I'm able to check and save correctly. This 'fields'-field is converted to a json-structure and saved to the database as text. So far so good.
NOTE: The field 'fields' is stored as TEXT in the database, but the user should be able to select values from a list of checkboxes.
The problem arise when I want to have some of the checkboxes checked by default.
I tried to do:
$this->setDefault('fields', array('key1','key2','key3'));
Where 'keyX' correspond to the actual value of the primary key (string) for Field in the database.
If I do a
$this->getDefault('fields');
I get back exactly what I put in previously.
However, symfony is not outputing any of the checkboxes as checked. I have even tried to remove both the 'expanded' and 'multiple' options to the choice-widget so I get a simple SELECT-box and the provide only one value as default selected.
Setting default values for other widgets (text-inputs, choice, etc) work.
Btw; The Field-model is i18n. Don't know if that matters here, since both storing / retrieving works as expected.
Also; the form is rendered as part of another form by means of include_partial(). Can that sabotage anything? In the 'parent' form class:
$this->embedRelation('TheRelationThatBugsMe');
And then in the _form.php for the 'parent':
include_partial('the_relation_that_bugs_me/form', array('form' => $form['TheRelationThatBugsMe']));
Does anyone have an idea where I might have gone wrong, or at least can give me some pointers as to where I should start digging?
[UPDATE]
If I create a new field in the form 'fields2' (that does not exist as a field in the database) and use the exact same code to create widget, validator and set defaults, then the defaults are rendered correctly. How come it doesn't work setting defaults for a field mapped to a column in the database?
If you're calling setDefault before updateDefaultFromObject gets called in sfDoctrineForm, then the object's values will override form defaults if the object exists. updateDefaultsFromObject contains the relevant logic. You'll have to call setDefault later, or override the method.

Categories