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...
Related
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.
I'm using ActiveForm with Yii2 and by default it seems to generate default id's for fields if you don't set one, in the format of:
{action-name}-{field-name}
So for example if I had a field with the name of foo_bar used in an action of actionSettings then the id of this field would be generated as:
settings-foo_bar
I would prefer this to just be foo_bar.
Is this possible to change on a form by form basis?
Based on the answer provided by #Bizley I was investigating how the method calculated the name and found out there is another way to achieve this as well.
You can simply override the formName method of your respective model to return a blank value, such as:
public function formName() {
return '';
}
Whilst this has less overheads as you don't need to create a new class, it will also affect other things within your form such as the field names and also should not be used for forms which contain multiple different models as explained here.
Lastly, because this question was about changing how Yii formats the id, #Bizleys answer is the correct one; my solution is just another option of possibly achieving it another way.
ActiveField id is by default created based on the form's model name and field's name.
If you want to change it for the whole form override the method that does it:
protected function getInputId()
{
return $this->_inputId ?: Html::getInputId($this->model, $this->attribute);
}
and use this modified class in your form.
To generate a checkboxlist within Yii framework 2.0 I use the following line of code.
Html::checkboxList($model->choises, null, $arrayOption, ['separator' => '<br />',]);
I would like to have the last checkbox option with an input text field like others. Does Yii framework 2.0 provide any view helper to generate that?
Since I needed to approach this goal I have tried different solution and came up with an ideal solution which I would like to share here since no one yet could answer this question. The solution is for both radionList and checkboxList.
Just inject the $arrayOption with the following code snippet.
$arrayOption[0] = 'Others <input type="text" class="my-class-name" name="MyModel[my_other_option]">';
Add the following code into the rules function inside of the model class.
[
['my_other_option',], 'required' , 'when' => function($model) {
return $model->choises == '0';
},
],
By doing so, the validation will be failed when you selected the Other option but didn't fill in the input text field, named my_other_option.
I am having problem displaying values set by select elements created by FormHelper. I have searched the internet but doesn't seem to be able to find the answer. Here is the scene:
I have a questionnaire form that has many options. In the model I put those items into an array, say ($frequencyOptions) and when formhelper is used,
$this->Form->input('frequency',array("options"=> $frequencyOptions));
Currently, the option value is the array index, which looks like:
<option value="">(choose one)</option>
<option value="0">Rare</option>
<option value="1">Frequent</option>
<option value="2">Moderate</option>
Of course I know that if I set the key as well when constructing the $frequencyOptions variable like
$frequencyOptions = array("Rare" => "Rare", ...
I will be able to store the value in text.
However, since some of these options are very very long, I would prefer to save them in INT in the database.
Yet the challenge I have at this moment is how to display those fields in the "list" in the index page. When I use the form field to display in the view or edit action, it is okay because the select element will be used again. However, if I want to display it in plain text, how should I "translate" it?
One thing I can think of is to create these "conversion" methods in the Model, but I think calling model method in views is not a good practice in MVC.
Any idea?
I'd think adding a method to your Model would be the way to go. How about this:
// In your Model class
// Store the index-to-name map in the Model as well
var $frequencyOptions = array(...);
public function translateFrequency(&$data) {
foreach ($data as &$record) {
$index = $record['ModelName']['frequency'];
$record['ModelName']['frequency'] = $this->frequencyOptions[$index];
}
}
// In your Controller action:
$data = $this->ModelName->find(...);
$this->ModelName->translateFrequency($data);
And then it should display the human-readable value when passed to the index page. If preferred, the above method could be changed so it works on $this->data inside the Model.
Note: The method has to be changed if it should work for a single record data array as well.
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.