C5-8.3: select form widget doesn't save selected value in DB

Permalink
I have an array of strings (font names), it's a $this-fonts public variable which works fine in the view and in the form. This array is populated with values in the controller's on_start():
foreach ($files as $filename => $path) {
    $this->fonts[pathinfo($path)['filename']] = $path;
$this->set('fonts', array_keys($this->fonts));

So for example, setting the font in view() and edit()
$this->set('font', array_keys($this->fonts)[1]);

shows the first array key in the view.php and form.php. No problem here.

I have a select input in the form which is populated with those array keys:
echo $form->select('font', $fonts, $font_selected);

But I can't get the selected font saved in the DB. If I simply do this:
$args['font'] = $args['font'];

it only saves the selected font index. But if I do this:
$args['font'] = array_keys($this->fonts)[(int)$args['font']];

or simply this:
$args['font'] = array_keys($this->fonts)[1];

it doesn't save anything, the DB field is empty.
$args['font'] = "test" // this DOES save the 'test' string though

I've also tried that in the validate($args):
$e->add(array_keys($this->fonts)[1]);

it returns an empty value with the error:
public function asArray() { $error = $this->error; if ($error->has()) { $o = array(); $o['error'] = true; $o['errors'] = array(); foreach ($error->getList() as $error) { $o['errors'][] = (string) $error; } return $o; } } }

If I cast that to string (string)array_keys($this->fonts)[1], it returns an empty value.

I'm out of clues. $this->fonts is set in the on_start(), available for view() and edit(), how come it's not working for save() or validate()?

How can I save the selected font text value, not the selected index?

linuxoid
 
rge replied on at Permalink Reply
How does your final array look like? The keys are the values that should get stored in the DB.

Example
array(
    '' => t('Blank'),
    'now' => t('Current Date/Time'),
),


I would suggest starting debugging in save method and see what values are available in $args.
public function save($args){}
linuxoid replied on at Permalink Reply
linuxoid
As I said, everything works fine in view and form. For example:

controller view():
$this->set('fonts', array_keys($this->fonts));

view.php:
<?php var_dump($fonts); ?>

result:
array(3) { [0]=> string(14) "Andika-Regular" [1]=> string(15) "Lobster-Regular" [2]=> string(19) "MarckScript-Regular" }

But array_keys($this->fonts) in save() is empty!

controller save():
$args['font'] = array_keys($this->fonts)[(int)$args['font']];

view.php:
<?php var_dump($font); ?>

result:
string(0) ""
linuxoid replied on at Permalink Reply
linuxoid
This saves the correct selected index:
$args['font_selected'] = (int)$args['font'];

So, something does get saved, however anything but the actual selected string
rge replied on at Permalink Reply
Since you want to save the selected font as a string. I suggest changing the code. Instead of using array_keys just provide the array as it is. When the array is passed to $form->select() the keys will be the option value and the value in the array is what is displayed to the user.
array('Andika-Regular' => 'path')


In the save method $args['font'] now should contain a string ( the font name).

The selected font in the form can be the $font variable.
$form->select('font', $fonts, $font);


If you need to store the path instead of the font name. You can change the array.
$this->fonts[$path] = pathinfo($path)['filename'];
linuxoid replied on at Permalink Reply
linuxoid
The array passed to the select is in the form 'filename => path' (please see the top of my 1st post), so I can't pass it to the select as that will fill it with paths, not filenames.
rge replied on at Permalink Reply
You only have to make sure the array keys contain the value that you would like to store in the database. Also, make sure that in the db.xml the correct type is set.

// keys are filled with the font name
foreach ($files as $filename => $path) {
  $filename = pathinfo($path)['filename'];
  $this->fonts[$filename] = $filename;
}
$this->set('fonts', $this->fonts);

<field name="font" type="string" size="255" />
linuxoid replied on at Permalink Reply
linuxoid
That's exactly what I verified in view and form. However exactly the same code which returns a string in view or form returns empty in the save.

in save():
$args['font'] = "test" // this saves the string
$args['font'] = array_keys($this->fonts)[1]; //this saves nothing

in view():
$this->set('font', array_keys($this->fonts)[1]); //this shows the 2nd filename from the array

db.xml:
<field name="font" type="string" size="100"/>
rge replied on at Permalink Reply
on_start is not triggered when a block is saved. You might want to create a function which you call on start and in the save to fill the fonts array.
linuxoid replied on at Permalink Reply
linuxoid
Isn't it? I thought it's triggered before everything loads. And I was also using a public class variable.

Yeah, you're right! I've taken building the array out of on_start() and now the selected value is saved.

Thanks a lot for pointing that out!
rge replied on at Permalink Reply
No problem. If you do it as I said in my earlier answer (store the value you want in the database in the array keys). You would not have to use the function since the value is directly available in $args.