Symfony form not honoring set defaults - php

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.

Related

How to make referenced column sortable in drupal 7 view

I have one view in Drupal 7, which displays user information like (Name, address, Status, etc..). I have one column in this (Table)view as "Published event". Basically events are created by users do I want to make this column sortable. I have attached image for more reference.
I tried with applying relationship but no success.
table settings
my handler code is like below :
$handler->display->display_options['sorts']['event_count_published'] ['id'] = 'event_count_published';
$handler->display->display_options['sorts']['event_count_published'] ['table'] = 'search_api_index_user_search_index';
$handler->display->display_options['sorts']['event_count_published'] ['field'] = 'event_count_published';
$handler->display->display_options['sorts']['event_count_published'] ['order'] = 'DESC';
'mail' => array(
'sortable' => 1,
'default_sort_order' => 'asc',
'align' => '',
'separator' => '',
'empty_column' => 0,
),
'event_count_published' => array(
'align' => '',
'separator' => '',
'empty_column' => 0,
'sortable' => 1,
),
above code is in "tcd_reporting.views_default.inc" file, if I put 'sortable => 1', it still does not provide sorting
field is created by below code:
$properties['event_count_published'] = array(
'label' => t('Published Events'),
'description' => t('Number of published events authored by user.'),
'type' => 'integer',
'getter callback' => 'tcd_event_content_type_count_published_get',
'computed' => TRUE,
'entity views field' => TRUE,
);
[Introduction] Which function is responsible for 'click sort' in views?
Click sort -this checkbox from your second screen- in views table settings is function which is enabled only for fields which have properly defined handlers. As you may know each field in views have few handlers (for displaying, filtering, sorting). And for click sort to be possible on specified column its field handler must have two functions defined: click_sortable and click_sort. First one just need to return true, while second need to properly implements sorting on view. For example see handler: [views_module_path]/handlers/views_handler_field.inc.
Your case:
It seems that your column "Published event" have defined handler which does not have click_sortable and click_sort functions (or click_sortable simply returns false).
Possible fix:
Find place where you defined your view source (it depends on how you informed views about it, if I understand its something like "User info" - maybe in hook_entity_info function or hook_views_data function), check what handler is assigned to your "Published event" field and change it.
It's hard to tell where you need to look as it depends on your implementation.
I suggest you to try create hook_views_data_alter function and dpm() it for start. Later you can alter it like that:
mymodule_views_data_alter(&$data) {
$data['some_view_info']['published_event']['field']['handler'] = 'views_handler_field_numeric';
}
Edit 1
First could you tell where this code is? Is it inside handler class, or maybe some views hook? Views gives you a lot of flexibility but this make them hard to understand, and I'm not sure what exactly you achieve and how.
Assuming your field works properly you can try to simply enable click sort.
Example: I created hook_views_data_alter function to see content of views data
function mymodule_views_data_alter(&$data) {
dpm($data,'d');
}
You might need to clear cache to see dpm of *_alter hooks.
Inside dpm'ed array I found "users" for generic example, and its field name looks like this:
I suggest you to try alter your field with click_sortable = TRUE and see what happens. If this wont help please provide more information about your field, how you created it, how it looks in hook_views_data_alter and which handlers it has defined.
Edit 2
Ok, so you have your views exported to code into views_default file. But this only allows you to export view you created from database to code, so it is basically a reflection of what you done in views web editor (eg. page yourwebsite.com/admin/structure/views/view/your_view_name/edit). What you need to do is to change behavior of one of your fields so it became sortable (add click_sortable and click_sort functions in handler class) or change handler of this field to one with sorting option (change field handler to other one like views_handler_field_numeric). If you don't have experience in creating handlers and this is one of generic handlers i suggest you to go back to my Edit 1, examine your dpm, and try to alter $data array to find solution.
Edit 3
Little explanation to prevent confusion. When creating new view you select collection on which this particular view base on (simpliest example - it may be MySQL table, and view will use SQL queries to retrieve data from it). By digging down we have:
Collection - eg. User which is database table user, it is what you select as source when creating new view.
Field - eg. mail which is database column mail, this fields you add to your view.
Field handler - eg. views_handler_field_numeric, this is class name of handler to use by specified field
Now, if you don't created your own handler then your field "Published event" have one of generic views handler. You shouldn't ever change code of contributed modules - especially so widely used as views handlers. That's why my suggestion to add functions click_sortable and click_sort is incorrect. Instead you should change handler responsible for field "Published event".
Best way is to define proper handler in place where you define your field "Published event". If it's somehow impossible the only way I can think of is hook_views_data_alter see docs for more info and examples. I suppose you should try to redefine handler of your field to generic numeric handler views_handler_field_numeric as it should have full sorting functionallity, or try to add click_sortable property to field array as you can see in first image of my post, but I can't provide you fully tested example.

Symfony 2 Passing Default Date

I am quite new to Symfony 2.7. I am facing a problem with Symfony form.
Inside my form i have a form field as follows
Builder->add('passDate', 'hidden')
->add('issueDate','hidden')
Inside my controller function, i need to pass some fix value to database. So here is my form action
$entity->setIssueDate('1950/01/01');
$entity->setPassDate('1950/01/01');
But when i submit it, it show me the error as that these form fields are required, although i set as default date as 1950/01/01. Please help me. Thank you
You can either remove the NotBlank symfomy validator mapping from the two fields or use the empty_data option which will populate default values if the hidden fields weren't filled via JavaScript like this:
$builder->add('passDate', 'hidden', array(
'data' => null,
'empty_data' => '1950/01/01'
)

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']);
},
)

Yii2 and float field with default value NULL

In the official documentation example "Country" database. I decided to add new field (Property) for the country, namely, area. I added a field named to the MySQL database's table named country with the name area with the following structure:
`area` float DEFAULT NULL
The new field's values in the database takes the default value 0 and in the view it displayed as 0.00 like the following screen shot shows:
In the update form, I added an input field for area like the following:
// In views/country/_form.php, I added the following line to the form:
<?= $form->field($model, 'area')->textInput() ?>
//In models/Country.php, I did not set any validation rules for area field.
public function attributeLabels()
{
return [
'code' => 'Code',
'name' => 'Name',
'population' => 'Population',
'area' => 'Area in KM<sup>2</sup>'
];
}
Now all fields in update view, are updated successfully, except the new field area. It, simply, does not updated at all without any error messages. Why?
Also, as the screen shot shows, in the view area label is printed out correctly, however, in the update view it shows as its HTML entity i.e Area in KM<sup>2</sup>. Why?
In another aspect, I did not like the presentation of area for non defined area country by 0.00, so I decidd to make it to be N/A so I have made the following callback method in models/Country.php:
public function afterFind()
{
if ($this->area == NULL){
$this->area = 'N/A';
}
return true;
}
However, the above solution generates error in the action view:
'N/A' is not a numeric value.
So, I replaced N/A with NULL and the view action works fine and assigned non defined area countries with (not set) in the view instead of 0.00. The last question here, is there any way to make the view printout N\A for non defined area countries? The action view uses DetailView::widget
Now all fields in update view, are updated successfully, except the
new field area. It, simply, does not updated at all without any error
messages. Why?
Because it's not safe attribute. You said that it's not presented in the rules. If you don't want validate it, but want to be able to massively assign it, you should explicitly specify it in the validation rules like so:
['area', 'safe'],
Read more about model safe attributes in official documentation.
Also, as the screen shot shows, in the view area label is printed out
correctly, however, in the update view it shows as its HTML entity i.e
Area in KM<sup>2</sup>. Why?
That's how attribute label renders in DetailView:
https://github.com/yiisoft/yii2/blob/master/framework/widgets/DetailView.php#L206
And in Html::activeLabel() which is used by ActiveForm's field():
https://github.com/yiisoft/yii2/blob/master/framework/helpers/BaseHtml.php#L1048
If it's not specified explicitly and automatically taken from attributeLabels(), encoding applies regargless of the options.
As as a workaround in ActiveForm I recommend passing it like this:
<?= $form->field($model, 'area')->label('Area in KM<sup>2</sup>') ?>
I think it's not a big deal to copy such content, because it's not code logic and rarely changed. And even if it will change, it's very easy to replace it with global search in your editor. If you highly against that, maybe it's better to declare it additionally in your model.
If you want, you can create issue on Github about that. Maybe I missed something but I didn't find a way to disable encoding for labels in ActiveForm.
And another workaround is to simply replace html by text representation, something like square km. It's a bit longer, but does not have this problems with encoding.
The last question here, is there any way to make the view printout N\A
for non defined area countries?
I think what you doing in afterFind() is not good because you replace the actual model value with display value. It can be used somewhere else, for example in update process and lead to some bugs.
You can do it at least with two options in your view.
1) If the null values are presented only in area, or you want to display N\A for other attributes null values too, you can simply replace default null representation like so:
use Yii;
...
Yii::$app->formatter->nullDisplay = 'N\A';
You should place this code before rendering DetailView Read more in official documentation.
2) Otherwise just extend defition of attribute area in DetailView attributes section:
[
'attribute' => 'area',
'value' => $model->area === null ? 'N\A' : $model->area,
],
You can validate Float type validation by defining rule in model Like...
....other rules....
[['area'],'integer', 'integerOnly' => false,],
...other rule...

CakePHP Model::save allowed partially blank data during record insertion

I was investigating CakePHP (2.3.4) Model::save method to insert new records and ran into a little snag:
//Two fields provided, email field intended to fail validation
$data = array('Member' => array(
'username' => 'hello',
'email' => 'world'
));
$this->Member->create();
var_dump($this->Member->save($data, true));
The above save() will return false and no data will be written to the database. However if I change the data to:
//One field provided, intended to pass validation
$data = array('Member' => array(
'username' => 'hello'
));
then save() will attempt to write a new record to database with a blank email field. I realize that skipping validation for unspecified fields might be a useful behavior during updates, but is there a CakePHP recommended way to handle partially empty data sets when creating new records? Thanks a lot.
Edit:
Thanks to Sam Delaney for the tip. In case anybody else gets stumped, this did the trick: CakePHP Data Validation: field 'required' key
This key accepts either a boolean, or create or update. Setting this key to true will make the field always required. While setting it to create or update will make the field required only for update or create operations. If ‘required’ is evaluated to true, the field must be present in the data array. For example, if the validation rule has been defined as follows:
I had originally baked the model and forgotten that required => true was left out of the validation rule. Setting it to true or 'create' would've avoided me blank records getting inserted due to gibberish data array.
IMHO what you've experienced is the desired behavior. Consider that you have the same two fields within a form and the user provides a value for only username. Both username and email field are submitted even though email is empty. Then on the server, you try to save the record only to find out that it has failed validation which you feedback to the user. On the other hand, perhaps in your system it is perfectly possible to create a user without requiring an email (for example root access account), CakePHP's validation implementation allows both of these scenarios.
If this flexibility isn't what you desire, just set the required attribute for your validation rule as true:
public $validate = array(
'email' => array(
'rule' => 'email',
'required' => true
)
);
This will satisfy your all or nothing requirement.

Categories