Create a simply form and store data in file

Hello,

I’m trying to make a form but I’m little confused.
I use “User sign-up” and “Uploading files from frontend” cookbook to start.

I would like to make form to store simply a name and a score.

Later, I would like to return all the name with their score in table.

So i create a snippet score.php (because it’s reuse in differents page)

snippet/score.php
  <form action="" method="post" enctype="multipart/form-data">

    <div class="honeypot">
      <label for="website">Website <abbr title="required">*</abbr></label>
      <input type="website" id="website" name="website">
    </div>

    <div class="form-field">
      <label for="name">Nom</label>
      <input required name="name" type="text" maxlength="3">
      <label for="score">Score</label>
      <input required name="score" type="number" >
    </div>

    <input type="submit" name="submit" value="Submit" class="button">

  </form>

A controller

controllers/score.php

<?php

return function ($kirby) {
    var_dump($kirby);

  $errors   = [];
  $success = '';

  if ($kirby->request()->is('post') === true && get('submit')) {

    // check the honeypot
    if (empty(get('website')) === false) {
      go($page->url());
      exit();
    }

    $data = [
        'name' => get('name'),
        'score' => get('score'),
    ];

    $rules = [
        'name' => ['required', 'maxLength' => 3],
        'score' => ['required', 'integer'],
    ];

    $messages = [
        'name' => 'Your name must have at max 3 characters',
        'score' => 'Should be a number',
    ];

    if ($invalid = invalid($data, $rules, $messages)) {
        $errors = $invalid;

    } else {
        try {
            $score = page('score')->update([
                'name' => $data['name'],
                'score' => $data['score'],
            ]);
        } catch (Exception $e) {
            $errors[] = $e->getMessage();
        }
    }
  }

  return compact('alerts', 'success');
};

And a new content folder “score” and a new txt file “score.txt”

content/score/score.txt
Title: Score

Nothing append, it seem I don’t go to my controller.
Also, I think that my try in my controller isn’t correct, but I didn’t find the best method to update the file.

Can you give me some trails :slight_smile:

Thank you :slight_smile: have a nice day

I don’t know where you are using your form snippet, but since it doesn’t have an action attribute that points to the score page, it will only load the controller of the page where it is located, which might not be your score page.

Also, while you are using the $page variable, it is not passed as argument to the closure, so this variable will be undefined, so should be

return function ($kirby, $page) {

Sure you want a maximum length of 3 chars for the name? This should be minLength, right?

Hello,

I decided to backtrack a bit to go step by step.

I’m designing my new portfolio, and I’ve made an old-fashioned mini game (that’s why I’m limiting the name to 3 characters max). I would like to make a scoreboard, so I’m building a form to record players’ scores.

So I’m going to stabilize my form already, before I use it in other pages.

I’m stuck on the data recording, I don’t know which method to use.

If I use page(score)->save(), it will overwrite all my existing data.
If I use page(score)->update(), I get an error and nothing happens.

I have solved the errors that you pointed out to me, thanks you.

Nice afternoon :slight_smile:

To update page data, you need to authenticate: Permissions | Kirby CMS

$kirby->impersonate('kirby');
$page->update([
                'name' => $data['name'],
                'score' => $data['score'],
            ]);

Thanks, you help a lot,

I succeed with that

try {

            /* Autorisation d'update une page */
            $kirby->impersonate('kirby');
            /* Récupération du scoreboard */
            $scoreBoard = page('score')->Scoreboard()->yaml();

            /*Ajout du nouveau score au scoreboard */
            $newScore = array('name' => $data['name'], 'score' => $data['score'] );
            array_push($scoreBoard, $newScore);


            /* Mise à jour de la page gérant le scoreboard */
            $score = page('score')->update(array('Scoreboard' => $scoreBoard));
            
            return true;
            
        } ...

Now I try to send my form with the fetch method in JS to avoid any page reload.

Do you have any suggestions? Here is the beginning of my script

const formSubmit = document.getElementById('PM-score-form');

formSubmit.addEventListener('submit', async(e) => {
    e.preventDefault();

    let url    = `http://${window.location.hostname}/score.php`;

    console.log(url);
    
    try {
      const response    = await fetch(url);

      console.log(response);

    } catch (error) {
      console.log('Fetch error: ', error);
    }

  });

I have made some progress, here is my code

index.js

const formSubmit = document.getElementById('PM-score-form');

formSubmit.addEventListener('submit', async(e) => {
    e.preventDefault();

    let url    = `http://${window.location.hostname}/score`;
    let newScore = {
        'name' : document.getElementById('PM-score-name').value,
        'score' : document.getElementById('PM-score-number').value
      }
    
    try {
        const response    = await fetch(url, {
            method: "POST",
            body : new FormData(formSubmit)
        });
        console.log(response.json());

    } catch (error) {
      console.log('Fetch error: ', error);
    }

  });
  
controllers/score.php
<?php

return function ($kirby, $page) {

  $alerts   = [];
  $success = '';

  if ($kirby->request()->is('post') === true && get('submit')) {

    // check the honeypot
    if (empty(get('website')) === false) {
      go($page->url());
      exit();
    }

    $data = [
        'name' => get('name'),
        'score' => get('score'),
    ];

    $rules = [
        'name' => ['required', 'maxLength' => 3],
        'score' => ['required', 'integer'],
    ];

    $messages = [
        'name' => 'Le pseudo ne peut pas avoir plus de 3 caractères',
        'score' => 'Le score doit être un nombre',
    ];

    if ($invalid = invalid($data, $rules, $messages)) {
        $alerts = $invalid;
    }

    if (empty($alerts)) {
        try {

            /* Autorisation d'update une page */
            $kirby->impersonate('kirby');
            /* Récupération du scoreboard */
            $scoreBoard = page('score')->Scoreboard()->yaml();

            /*Ajout du nouveau score au scoreboard */
            $newScore = array('name' => $data['name'], 'score' => $data['score'] );
            array_push($scoreBoard, $newScore);


            /* Mise à jour de la page gérant le scoreboard */
            $score = page('score')->update(array('Scoreboard' => $scoreBoard));
            
        } catch (Exception $error) {
            $alerts[] = "Le score n'a pas pu être enregistré";
        }

        // no exception occurred, let's send a success message
        if (empty($alerts) === true) {
            $success = 'Le score a bien été enregistré';
            $data = [];
        }
        
    }
  }

  // return data to template
  return [
    'alerts' => $alerts ?? false,
    'data'    => $data ?? false,
    'success' => $success ?? false
    ];
};```

My form works when I am on the score.php page
But it doesn’t work when I’m on index.php and I call the form with.

Also, I don’t have any return :confused:

templates/index.php
<?php $form = page('score'); ?>
<?= $form->render() ?>

Any idea ?
Good night :slight_smile: