Kirby-uniform: forms in controllers.php ≠ template.php

Oh, silly me sure :stuck_out_tongue:

I am not sure what your use case is, but the way i found pages and pulled into the panel was this:

$page->site()->index()->findBy('uid', $data->teasercontent())

This was inside one of my builder snippets, and the builder print contained a drop down (teasercontent) of all pages so i could create a teaser hero panel just by picking a page. youll probably wont some way similar to feed the page through that has the data you want to use.

My snippet call looks like this:

<?php
$sections = $page->builder()->toStructure();
foreach($sections as $section):
  $index = $sections->indexOf($section);
  $next = $index + 1;
?>
    <div class="builder-block" data-scroll-index="<?= $index ?>">
        <?php snippet('builder/' . $section->_fieldset(), array('data' => $section, 'nextpanel' => $next)) ?>
    </div>

<?php endforeach ?>

Just to show you can pass extra bits data through, the above is adding unique html ID’s to each builder entry on the page.

Also, i dont know if you are aware, but controllers only work on the page that controller belongs too. To have it work on any page, you need to rename the controller to site.php. For example, i have a newsletter signup form on every page. Rather then put the Uniform controller code in duplicated controllers, you can put in a controller called site.php. This might be contributing to your problem.

@jimbobrjames thanks for all the tips!

This is confusing me a lot.

I tried to get the correct path w/

$page->site()->index()->filterBy('intendedTemplate', 'registration-form');

and compared it using gettype() to the $page object of the template I am using kirby builder:

same path, same type (object).

But controllers.php was telling me I was getting a Null object.

So then I tried to use this

$page->site()->index()->findBy('uid', 'name-of-page');

which gives me an objectarray (?), and once I use it inside the Uniform controllers.php loop I get the same Offset Illegal Type error as in the beginning.

This makes me think the problem is not using $page or $page->site()-> etc after all?

I am also getting back to PHP after a while and am not very sharp lately… will keep pocking at it.

All of the $page->$buillder()->toStructure() as $section fields are not string but object.

:thinking:

That’s because unless I call them and they get printed, the way they are stored is in the object form? How do I convert them to being strings?

Its because its an object not a collection: Reading external JSON

tl;dr … create your own array from the collection data THEN do stuff with it:

$rules = array ();

$rules[] = array(
      'YourThing' => $data->whatever();
   );

Obviously i’ve made that up but hopefully you get the idea.

1 Like

I had to use value…ie… $page->title()->value()

1 Like

OK so I convert the kirby-builder object to an array.

$rules = $page->builder()->toStructure()->toArray();

  $rules = array();
    foreach($_POST as $key => $value) {
      $rules[$key] = esc($value);
  };

This is at last saving the filled out fields to a text.log, correctly!

Only, only the last field in the form, which is a type=number field, gets skipped over, and instead the csrf_token gets saved?

Maybe it’s due to esc($value)?

again… flakey PHP knowledge…but its a number isn’t it, not a string, and your treating it as a string? Shouldnt you first check the value is string or a number then treat it appropriately? If you changed that number field to a text field, i bet you get a value.

What does var_dump() tell you?

strval($value); converts an int to a string. Or this.

Try:

$rules = $page->builder()->toStructure()->toArray();

  $rules = array();
    foreach($_POST as $key => $value) {
      if (is_numeric($value)) {
      $rules[$key] = strval($value);
      } else {
      $rules[$key] = esc($value);
      }
 }
;

Strange thing: I already use a couple of field numbers in the form, and they work flawlessly.

Only this last one before the submit button gets completely ignored. Still looking into it and will post an update.

On the other side, this is the complete controller.php for the Uniform Plugin to work w/ Kirby Builder.

I added a custom action to save the form as a kirby subpage.

<?php

use Uniform\Form;

return function ($site, $pages, $page)
{
    date_default_timezone_set('Europe/Rome');
    
    $rules = $page->builder()->toStructure()->toArray();

    $rules = array();
    foreach($_POST as $key => $value) {
      if ($key != 'csrf_token' && $key != 'website') {
        $rules[$key] = esc($value);
      }
    };
    
    $form = new Form($rules);
    if (r::is('POST')) {

      $new_registrationform = $page->grandChildren()->filterBy('intendedTemplate', 'registration-form')->create(str::slug('reg' . '-' . date('Ymd:His')) , 'registration-form', $rules);

    }

    return compact('form');
};

Is the field that is getting ignored properly named? No typos in controller? No typos in the HTML?

Also, its a better idea to set timezone in php.ini if you have access to it.

Silly error, was using the same name for a field… now working ofc.


Last thing is to put error messages with Kirby Builder based on the selected field.

Whenever the form validation failed or anything else went wrong, the user would loose all the form data that was already entered. Of course we don’t want that so Uniform flashes all form data to the session in this case. The flashed data can be accessed through the old method to re-populate the form data as you can see in the example below:

@mzur How would I access

value="<?php echo $form->old('email'); ?>

if I am using Kirby Builder / a structure field?

Something like this, but needs to fetch the old('value') instead of the default one?

value="<?= $data->type() ?>" 

Where type is email, ‘text’, etc—the kind of field I am using.

I’d like to go step by step and fully setup your plugin w/ a panel-centric way of building the form, as I think it might come handy also for other people.

Any more help appreciated :smiley:

Don’t know about this last bit at the mo, but I think all this $page->site() stuff is completely unnecessary as is converting the structure to an array. To avoid an object as array key, all I think you have to do is to get the value:

$rules = [];
  foreach($page->builder()->toStructure() as $section) {
    $rules[$section->_fieldset()->value()] = $section->rules();
}
var_dump($rules);

(not tested)

1 Like

@texnixe’s code looks good. The structure field won’t return the actual string of the field content but an object. I didn’t think of that.

Regarding $form->old(): It’s all about the form field names. If you have a field with name $section->_fieldset()->value() then you get the old value with the same key:

<input name="<?php echo $section->_fieldset()->value() ?>" value="<?php echo $form->old($section->_fieldset()->value()) ?>">

I tested it and I get the same initial error:

Illegal Offset Type

Thank you @mzur!

Tested this as well w/ a structured field (no Kirby Builder) and I get this

Illegal offset type in isset or empty

on line 140 of site/plugins/uniform/vendor/mzur/kirby-form/src/Form.php

// Encode HTML entities for output
        return isset($data[$key]) ? $this->encodeField($data[$key]) : '';
    }

That’s the same error for both cases. What do you get with var_dump($section->_fieldset())? Also, try casting the key to a string with strval($section->_fieldset()).

This is what I get

array(1) { ["placeholder"]=> object(Field)#210 (3) { ["page"]=> string(19) "partecipa/iscriviti" ["key"]=> string(5) "rules" ["value"]=> NULL } }

I have only one _fieldset in the kirby builder, and a bunch of subfield to pick from in order to set the input type.

Also, when I merge the form array with another custom array made in the controller, and then I make a new Form($rules), only the added keys from the non-form array get added to the logfile, and not their values.

If I check the merged array before doing new Form I get everything, but after the new Form command only the keys from $info.

Is it Uniform specific or due to the new Form command?

$survey_num = page('survey')->children()->count() +1;
$info = array(
  'title' => 'Questionario #' . $survey_num,
  'date'  => date('Y-m-d, H:i:s'),
);

$rules = $page->inquiry()->toStructure()->toArray();
foreach($_POST as $key => $value) {
  if($key != 'csrf_token' && $key != 'website') {
    $rules[$key] = esc($value);
  }
};

$rules = a::merge($info, $rules);
a::show($rules);
$form = new Form($rules);