Zum Inhalt springen

Formularbeispiel

Live-Demo öffnen unter /documentation/examples/run/forms.

Dieses Beispiel zeigt benannte, serverseitig gerenderte Formulare im DotApp PHP Framework. Die Live-Seite ist reines HTML, sendet per POST an dieselbe URL und lädt dotapp.js nicht.

Einführung

Drei Formulare können denselben POST-Endpunkt nutzen, wenn jedes Formular ein Token {{ formName(Name) }} enthält. Der Controller ruft für jeden erwarteten Formularnamen $request->form(['POST'], 'Name', $ok, $err) auf und gibt die gerenderte Seite für das passende Formular zurück.

Wenn Sie neu bei DotApp sind, lesen Sie zuerst die Grundlagen zu Modulen und Routing:

Das Examples-Modul erstellen

Erstellen Sie das Modul Examples mit der DotApper CLI:

php dotapper.php --create-module=Examples

Das Live-Modul wird nur für die URLs des Beispiel-Runners aktiv. Halten Sie den Routenumfang in /app/modules/Examples/module.init.php explizit:

public function initializeRoutes()
{
    return ['/documentation/examples/run', '/documentation/examples/run/*'];
}

Den Forms-Controller erstellen

Erstellen Sie einen Controller namens Forms für das Modul Examples:

php dotapper.php --module=Examples --create-controller=Forms

Controller in DotApp 2.0 stellen öffentliche statische Aktionsmethoden bereit und werden über Modul-Controller-Zeichenketten wie 'Examples:Forms@index!' referenziert.

Routen konfigurieren

Definieren Sie ein Routenpaar für die URL mit und ohne Schrägstrich. Das Live-Modul verwendet einen kleinen Helfer, damit GET und POST konsistent bleiben:

public function initialize($dotApp)
{
    Config::module('Examples', 'prefix') ?? Config::module('Examples', 'prefix', '/documentation/examples/run');
    $p = rtrim((string) Config::module('Examples', 'prefix'), '/');

    $pair = function (string $path): array {
        $path = rtrim($path, '/');
        return [$path, $path . '/'];
    };

    Router::get($pair($p . '/forms'), 'Examples:Forms@index!', Router::STATIC_ROUTE);
    Router::post($pair($p . '/forms'), 'Examples:Forms@submit!', Router::STATIC_ROUTE);
}

Die GET-Aktion rendert die Formularseite. Die POST-Aktion prüft den übermittelten Formularnamen und gibt eine neue HTML-Antwort zurück.

Die View erstellen

Die Live-Demo verwendet eine eigenständige View unter /app/modules/Examples/views/forms.view.php. Die Datei ist ein vollständiges HTML-Dokument.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>{{ var: $title }} - DotApp PHP Framework 2.0</title>
  <link rel="stylesheet" href="/assets/modules/Examples/css/examples.css" />
</head>
<body class="ex-body">
  <main class="ex-main">
    <h1>Named forms</h1>
    <p>Three forms post to the same URL. This demo does not use dotapp.js.</p>

    {{ if $formNumber }}
      <div class="ex-status">Using form {{ var: $formNumber }}, you submitted the text: {{ var: $formText }}</div>
    {{ /if }}

    <form method="POST">
      <input type="text" name="textfrom1" placeholder="Enter text to display" />
      {{ formName(Form1) }}
      <button type="submit">{{ var: $btnName }}</button>
    </form>

    <form method="POST">
      <input type="text" name="textfromanother" placeholder="Enter text to display" />
      {{ formName(Form2) }}
      <button type="submit">{{ var: $btnName }}</button>
    </form>

    <form method="POST">
      <input type="text" name="textfromanother" placeholder="Enter text to display" />
      {{ formName(Form3) }}
      <button type="submit">{{ var: $btnName }}</button>
    </form>
  </main>
</body>
</html>

Die Tags {{ formName(Form1) }}, {{ formName(Form2) }} und {{ formName(Form3) }} müssen innerhalb der zugehörigen <form>-Tags stehen.

Formulare verarbeiten

Der Live-Controller gibt die HTML-Zeichenkette zurück. Jeder Aufruf von $request->form() enthält sowohl einen Erfolgs- als auch einen Fehler-Callback, sodass nicht passende Formularprüfungen sicher fortgesetzt werden können.

use Dotsystems\App\Parts\Logger;
use Dotsystems\App\Parts\Renderer;
use Dotsystems\App\Parts\Response;

class Forms extends \Dotsystems\App\Parts\Controller
{
    public static function index($request)
    {
        return self::formPage('', 0);
    }

    public static function submit($request)
    {
        $attempts = [
            1 => ['Form1', 'textfrom1'],
            2 => ['Form2', 'textfromanother'],
            3 => ['Form3', 'textfromanother'],
        ];

        foreach ($attempts as $num => $spec) {
            $html = $request->form(['POST'], $spec[0], function ($request) use ($num, $spec) {
                $text = (string) ($request->data()[$spec[1]] ?? '');
                return self::formPage($text, $num);
            }, function () {
                return null;
            });

            if (is_string($html) && $html !== '') {
                return $html;
            }
        }

        return self::formPage('', 0);
    }

    private static function formPage(string $text, int $formNumber)
    {
        return self::view('forms', [
            'title' => 'Named forms demo',
            'docsUrl' => '/documentation/examples/forms',
            'btnName' => 'Send',
            'formNumber' => $formNumber,
            'formText' => htmlspecialchars($text, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'),
        ]);
    }

    private static function view(string $name, array $vars)
    {
        $r = Renderer::new()->module('Examples')->setView($name, 'clean');
        foreach ($vars as $key => $value) {
            $r->setViewVar($key, $value);
        }

        $html = $r->renderView();
        if ($html === '') {
            Logger::use()->error('Examples view empty', ['view' => $name]);
            return new Response(500, 'Template error');
        }

        return $html;
    }
}

Renderer::new()->module('Examples')->setView('forms', 'clean') wählt die eigenständige View aus, bevor Variablen mit setViewVar() zugewiesen werden.

Rendering-Theorie

DotApp kann eine vollständige View direkt rendern oder eine View, die {{ content }} und ein Layout enthält. Dieses Live-Beispiel verwendet den direkten Ansatz mit eigenständiger View, weil die Demoseite in sich abgeschlossen ist.

$r = Renderer::new()->module('Examples')->setView('forms', 'clean');
$r->setViewVar('btnName', 'Send');
$html = $r->renderView();

Layout-Rendering kommt zum Einsatz, wenn ein gemeinsamer Wrapper nützlich ist. Diese Anleitung verwendet die eigenständige Seite forms.view.php.

Live-Demo

Probieren Sie die Live-Demo unter /documentation/examples/run/forms. Sie sendet drei benannte Formulare an einen Endpunkt und gibt die gerenderte Seite aus dem Controller zurück.