Learn

Erfahren Sie mehr über Flight

Flight ist ein schnelles, einfaches, erweiterbares Framework für PHP. Es ist ziemlich vielseitig und kann für den Aufbau jeder Art von Webanwendung verwendet werden. Es wurde mit einfachen Bedienung im Sinn erstellt und so geschrieben, dass es leicht verständlich und anwendbar ist.

Wichtige Framework-Konzepte

Warum ein Framework?

Hier ist ein kurzer Artikel darüber, warum Sie ein Framework verwenden sollten. Es ist eine gute Idee, die Vorteile der Verwendung eines Frameworks zu verstehen, bevor Sie damit beginnen.

Zusätzlich wurde ein ausgezeichnetes Tutorial von @lubiana erstellt. Obwohl es nicht im Detail auf Flight eingeht, wird Ihnen dieser Leitfaden helfen, einige der wichtigsten Konzepte rund um ein Framework zu verstehen und warum sie vorteilhaft sind. Das Tutorial finden Sie hier.

Kernthemen

Autoloading

Erfahren Sie, wie Sie Ihre eigenen Klassen in Ihrer Anwendung automatisch laden können.

Routing

Erfahren Sie, wie Sie Routen für Ihre Webanwendung verwalten können. Dies beinhaltet auch das Gruppieren von Routen, Routenparameter und Middleware.

Middleware

Erfahren Sie, wie Sie Middleware verwenden können, um Anfragen und Antworten in Ihrer Anwendung zu filtern.

Anfragen

Erfahren Sie, wie Sie Anfragen und Antworten in Ihrer Anwendung verarbeiten können.

Antworten

Erfahren Sie, wie Sie Antworten an Ihre Benutzer senden können.

HTML-Vorlagen

Erfahren Sie, wie Sie den integrierten View-Engine verwenden können, um Ihre HTML-Vorlagen zu rendern.

Sicherheit

Erfahren Sie, wie Sie Ihre Anwendung vor gängigen Sicherheitsbedrohungen schützen können.

Konfiguration

Erfahren Sie, wie Sie das Framework für Ihre Anwendung konfigurieren können.

Erweiterung von Flight

Erfahren Sie, wie Sie das Framework erweitern können, indem Sie Ihre eigenen Methoden und Klassen hinzufügen.

Ereignisse und Filterung

Erfahren Sie, wie Sie das Ereignissystem verwenden können, um Hooks zu Ihren Methoden und internen Framework-Methoden hinzuzufügen.

Dependency Injection Container

Erfahren Sie, wie Sie Dependency Injection Container (DIC) verwenden können, um die Abhängigkeiten Ihrer Anwendung zu verwalten.

Framework-API

Erfahren Sie mehr über die Kernmethoden des Frameworks.

Migration zu v3

Die Abwärtskompatibilität wurde größtenteils beibehalten, aber es gibt einige Änderungen, auf die Sie achten sollten, wenn Sie von v2 auf v3 migrieren.

Problembehandlung

Es gibt einige häufige Probleme, auf die Sie bei der Verwendung von Flight stoßen können. Diese Seite wird Ihnen bei der Problembehandlung dieser Probleme helfen.

Learn/stopping

Anhalten

Sie können das Framework jederzeit durch Aufrufen der halt Methode stoppen:

Flight::halt();

Sie können auch einen optionalen HTTP-Statuscode und eine Nachricht angeben:

Flight::halt(200, 'Bin gleich wieder da...');

Das Aufrufen von halt verwirft jeglichen Antwortinhalt bis zu diesem Zeitpunkt. Wenn Sie das Framework anhalten und die aktuelle Antwort ausgeben möchten, verwenden Sie die stop Methode:

Flight::stop();

Learn/errorhandling

Fehlerbehandlung

Fehler und Ausnahmen

Alle Fehler und Ausnahmen werden von Flight abgefangen und an die error Methode übergeben. Das Standardverhalten besteht darin, eine generische HTTP 500 Interner Serverfehler Antwort mit einigen Fehlerinformationen zu senden.

Sie können dieses Verhalten nach Ihren eigenen Bedürfnissen überschreiben:

Flight::map('error', function (Throwable $error) {
  // Fehler behandeln
  echo $error->getTraceAsString();
});

Standardmäßig werden Fehler nicht im Webserver protokolliert. Sie können dies aktivieren, indem Sie die Konfiguration ändern:

Flight::set('flight.log_errors', true);

Nicht gefunden

Wenn eine URL nicht gefunden werden kann, ruft Flight die notFound Methode auf. Das Standardverhalten besteht darin, eine HTTP 404 Nicht gefunden Antwort mit einer einfachen Nachricht zu senden.

Sie können dieses Verhalten nach Ihren eigenen Bedürfnissen überschreiben:

Flight::map('notFound', function () {
  // Nicht gefunden behandeln
});

Learn/migrating_to_v3

Migration zu v3

Die Abwärtskompatibilität wurde größtenteils beibehalten, aber es gibt einige Änderungen, auf die Sie achten sollten, wenn Sie von v2 auf v3 migrieren.

Verhalten der Ausgabepufferung (3.5.0)

Ausgabepufferung ist der Prozess, bei dem die Ausgabe, die von einem PHP-Skript generiert wird, in einem Puffer (intern von PHP) gespeichert wird, bevor sie an den Client gesendet wird. Dadurch können Sie die Ausgabe modifizieren, bevor sie zum Client gesendet wird.

In einer MVC-Anwendung ist der Controller der "Manager" und er verwaltet, was die Ansicht tut. Das Generieren von Ausgaben außerhalb des Controllers (oder in Flights Fall manchmal eine anonyme Funktion) verstößt gegen das MVC-Muster. Diese Änderung soll mehr im Einklang mit dem MVC-Muster stehen und das Framework vorhersehbarer und einfacher zu verwenden machen.

In v2 wurde die Ausgabepufferung so gehandhabt, dass der eigene Ausgabepuffer nicht konsistent geschlossen wurde, was Unit Tests und Streaming erschwerte. Für die meisten Benutzer hat diese Änderung tatsächlich keine Auswirkungen. Wenn Sie jedoch Inhalte außerhalb von Aufrufbaren und Controllern (zum Beispiel in einem Hook) echoen, werden Sie wahrscheinlich auf Probleme stoßen. Das Echoen von Inhalten in Hooks und vor der tatsächlichen Ausführung des Frameworks hat möglicherweise in der Vergangenheit funktioniert, wird jedoch zukünftig nicht mehr funktionieren.

Wo Probleme auftreten könnten

// index.php
require 'vendor/autoload.php';

// Nur ein Beispiel
define('START_TIME', microtime(true));

function hello() {
    echo 'Hallo Welt';
}

Flight::map('hello', 'hello');
Flight::after('hello', function(){
    // Das wird tatsächlich funktionieren
    echo '<p>Diese Begrüßung wurde Ihnen vom Buchstaben "H" präsentiert</p>';
});

Flight::before('start', function(){
    // Dinge wie diese werden einen Fehler verursachen
    echo '<html><head><title>Meine Seite</title></head><body>';
});

Flight::route('/', function(){
    // Das ist eigentlich in Ordnung
    echo 'Hallo Welt';

    // Dies sollte auch in Ordnung sein
    Flight::hello();
});

Flight::after('start', function(){
    // Das wird einen Fehler verursachen
    echo '<div>Ihre Seite wurde in '.(microtime(true) - START_TIME).' Sekunden geladen</div></body></html>';
});

Aktivieren des v2-Renderingverhaltens

Können Sie Ihren alten Code so lassen, wie er ist, ohne eine Neuschreibung vorzunehmen, um ihn mit v3 zum Laufen zu bringen? Ja, das können Sie! Sie können das v2-Renderingverhalten aktivieren, indem Sie die Konfigurationsoption flight.v2.output_buffering auf true setzen. Dadurch können Sie weiterhin das alte Renderingverhalten nutzen, aber es wird empfohlen, es zukünftig zu korrigieren. In v4 des Frameworks wird dies entfernt.

// index.php
require 'vendor/autoload.php';

Flight::set('flight.v2.output_buffering', true);

Flight::before('start', function(){
    // Jetzt wird dies in Ordnung sein
    echo '<html><head><title>Meine Seite</title></head><body>';
});

// mehr Code 

Änderungen im Dispatcher (3.7.0)

Wenn Sie direkt statische Methoden für Dispatcher aufgerufen haben, wie z.B. Dispatcher::invokeMethod(), Dispatcher::execute(), usw., müssen Sie Ihren Code aktualisieren, um diese Methoden nicht mehr direkt aufzurufen. Dispatcher wurde in eine stärker objektorientierte Form umgewandelt, damit Dependency Injection Containers auf einfachere Weise verwendet werden können. Wenn Sie eine Methode ähnlich wie Dispatcher aufrufen müssen, können Sie manuell etwas wie $result = $class->$method(...$params); oder call_user_func_array() verwenden.

Learn/configuration

Konfiguration

Sie können bestimmte Verhaltensweisen von Flight anpassen, indem Sie Konfigurationswerte über die set Methode setzen.

Flight::set('flight.log_errors', true);

Verfügbare Konfigurationseinstellungen

Folgend finden Sie eine Liste aller verfügbaren Konfigurationseinstellungen:

Variablen

Flight erlaubt es Ihnen, Variablen zu speichern, damit sie überall in Ihrer Anwendung verwendet werden können.

// Speichern Sie Ihre Variable
Flight::set('id', 123);

// Anderswo in Ihrer Anwendung
$id = Flight::get('id');

Um zu überprüfen, ob eine Variable gesetzt wurde, können Sie Folgendes tun:

if (Flight::has('id')) {
  // Etwas tun
}

Sie können eine Variable löschen, indem Sie Folgendes tun:

// Löscht die id Variable
Flight::clear('id');

// Löscht alle Variablen
Flight::clear();

Flight verwendet auch Variablen für Konfigurationszwecke.

Flight::set('flight.log_errors', true);

Fehlerbehandlung

Fehler und Ausnahmen

Alle Fehler und Ausnahmen werden von Flight abgefangen und an die error Methode übergeben. Das Standardverhalten besteht darin, eine generische HTTP 500 Internal Server Error Antwort mit einigen Fehlerinformationen zu senden.

Sie können dieses Verhalten nach Ihren eigenen Bedürfnissen überschreiben:

Flight::map('error', function (Throwable $error) {
  // Fehler behandeln
  echo $error->getTraceAsString();
});

Standardmäßig werden Fehler nicht im Webserver protokolliert. Sie können dies aktivieren, indem Sie die Konfiguration ändern:

Flight::set('flight.log_errors', true);

Nicht gefunden

Wenn eine URL nicht gefunden werden kann, ruft Flight die notFound Methode auf. Das Standardverhalten besteht darin, eine HTTP 404 Not Found Antwort mit einer einfachen Nachricht zu senden.

Sie können dieses Verhalten nach Ihren eigenen Bedürfnissen überschreiben:

Flight::map('notFound', function () {
  // Nicht gefunden behandeln
});

Learn/security

Sicherheit

Sicherheit ist eine große Sache, wenn es um Webanwendungen geht. Sie möchten sicherstellen, dass Ihre Anwendung sicher ist und dass die Daten Ihrer Benutzer geschützt sind. Flight bietet eine Reihe von Funktionen, um Ihnen bei der Absicherung Ihrer Webanwendungen zu helfen.

Header

HTTP-Header sind einer der einfachsten Wege, um Ihre Webanwendungen zu sichern. Sie können Header verwenden, um Clickjacking, XSS und andere Angriffe zu verhindern. Es gibt mehrere Möglichkeiten, wie Sie diese Header zu Ihrer Anwendung hinzufügen können.

Zwei großartige Websites, um die Sicherheit Ihrer Header zu überprüfen, sind securityheaders.com und observatory.mozilla.org.

Manuell hinzufügen

Sie können diese Header manuell hinzufügen, indem Sie die header-Methode auf dem Flight\Response-Objekt verwenden.

// Setzen des X-Frame-Options-Headers, um Clickjacking zu verhindern
Flight::response()->header('X-Frame-Options', 'SAMEORIGIN');

// Setzen des Content-Security-Policy-Headers, um XSS zu verhindern
// Hinweis: Dieser Header kann sehr komplex werden, daher möchten Sie
// Beispiele im Internet für Ihre Anwendung konsultieren
Flight::response()->header("Content-Security-Policy", "default-src 'self'");

// Setzen des X-XSS-Protection-Headers, um XSS zu verhindern
Flight::response()->header('X-XSS-Protection', '1; mode=block');

// Setzen des X-Content-Type-Options-Headers, um MIME-Schnüffeln zu verhindern
Flight::response()->header('X-Content-Type-Options', 'nosniff');

// Setzen des Referrer-Policy-Headers, um zu steuern, wie viele Referrer-Informationen gesendet werden
Flight::response()->header('Referrer-Policy', 'no-referrer-when-downgrade');

// Setzen des Strict-Transport-Security-Headers, um HTTPS zu erzwingen
Flight::response()->header('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');

// Setzen des Permissions-Policy-Headers, um zu steuern, welche Funktionen und APIs verwendet werden können
Flight::response()->header('Permissions-Policy', 'geolocation=()');

Diese können am Anfang Ihrer bootstrap.php oder index.php-Dateien hinzugefügt werden.

Als Filter hinzufügen

Sie können sie auch in einem Filter/Hook wie folgt hinzufügen:

// Fügen Sie die Header in einem Filter hinzu
Flight::before('start', function() {
    Flight::response()->header('X-Frame-Options', 'SAMEORIGIN');
    Flight::response()->header("Content-Security-Policy", "default-src 'self'");
    Flight::response()->header('X-XSS-Protection', '1; mode=block');
    Flight::response()->header('X-Content-Type-Options', 'nosniff');
    Flight::response()->header('Referrer-Policy', 'no-referrer-when-downgrade');
    Flight::response()->header('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
    Flight::response()->header('Permissions-Policy', 'geolocation=()');
});

Als Middleware hinzufügen

Sie können sie auch als Middleware-Klasse hinzufügen. Dies ist eine gute Möglichkeit, Ihren Code sauber und organisiert zu halten.

// app/middleware/SecurityHeadersMiddleware.php

namespace app\middleware;

class SecurityHeadersMiddleware
{
    public function before(array $params): void
    {
        Flight::response()->header('X-Frame-Options', 'SAMEORIGIN');
        Flight::response()->header("Content-Security-Policy", "default-src 'self'");
        Flight::response()->header('X-XSS-Protection', '1; mode=block');
        Flight::response()->header('X-Content-Type-Options', 'nosniff');
        Flight::response()->header('Referrer-Policy', 'no-referrer-when-downgrade');
        Flight::response()->header('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
        Flight::response()->header('Permissions-Policy', 'geolocation=()');
    }
}

// index.php oder wo immer Sie Ihre Routen haben
// Übrigens fungiert diese leere Stringgruppe als globales Middleware für
// alle Routen. Natürlich könnten Sie dasselbe tun und es nur bestimmten Routen hinzufügen.
Flight::group('', function(Router $router) {
    $router->get('/users', [ 'UserController', 'getUsers' ]);
    // weitere Routen
}, [ new SecurityHeadersMiddleware() ]);

Cross Site Request Forgery (CSRF)

Cross Site Request Forgery (CSRF) ist ein Angriffstyp, bei dem eine bösartige Website den Browser eines Benutzers dazu bringen kann, eine Anfrage an Ihre Website zu senden. Dies kann verwendet werden, um Aktionen auf Ihrer Website ohne das Wissen des Benutzers durchzuführen. Flight bietet keinen integrierten CSRF-Schutzmechanismus, aber Sie können ganz einfach Ihren eigenen implementieren, indem Sie Middleware verwenden.

Einrichtung

Zunächst müssen Sie ein CSRF-Token generieren und es in der Sitzung des Benutzers speichern. Sie können dieses Token dann in Ihren Formularen verwenden und beim Absenden des Formulars überprüfen.

// Generieren eines CSRF-Tokens und Speichern in der Benutzersitzung
// (vorausgesetzt, Sie haben ein Session-Objekt erstellt und es an Flight angehängt)
// Sie müssen nur ein einziges Token pro Sitzung generieren (damit es
// über mehrere Tabs und Anfragen hinweg für denselben Benutzer funktioniert)
if(Flight::session()->get('csrf_token') === null) {
    Flight::session()->set('csrf_token', bin2hex(random_bytes(32)) );
}
<!-- Verwendung des CSRF-Tokens in Ihrem Formular -->
<form method="post">
    <input type="hidden" name="csrf_token" value="<?= Flight::session()->get('csrf_token') ?>">
    <!-- andere Formularfelder -->
</form>

Verwendung von Latte

Sie können auch eine benutzerdefinierte Funktion festlegen, um das CSRF-Token in Ihren Latte-Templates auszugeben.

// Festlegen einer benutzerdefinierten Funktion zum Ausgeben des CSRF-Tokens
// Hinweis: Die Ansicht wurde mit Latte als Ansichtsmaschine konfiguriert
Flight::view()->addFunction('csrf', function() {
    $csrfToken = Flight::session()->get('csrf_token');
    return new \Latte\Runtime\Html('<input type="hidden" name="csrf_token" value="' . $csrfToken . '">');
});

Und jetzt können Sie in Ihren Latte-Templates die csrf()-Funktion verwenden, um das CSRF-Token auszugeben.

<form method="post">
    {csrf()}
    <!-- andere Formularfelder -->
</form>

Kurz und bündig, nicht wahr?

Überprüfen des CSRF-Tokens

Sie können das CSRF-Token mithilfe von Event-Filtern überprüfen:

// Dieses Middleware überprüft, ob die Anfrage eine POST-Anfrage ist, und überprüft dann, ob das CSRF-Token gültig ist
Flight::before('start', function() {
    if(Flight::request()->method == 'POST') {

        // Erfassen des CSRF-Tokens aus den Formularwerten
        $token = Flight::request()->data->csrf_token;
        if($token !== Flight::session()->get('csrf_token')) {
            Flight::halt(403, 'Ungültiges CSRF-Token');
        }
    }
});

Oder Sie können eine Middleware-Klasse verwenden:

// app/middleware/CsrfMiddleware.php

namespace app\middleware;

class CsrfMiddleware
{
    public function before(array $params): void
    {
        if(Flight::request()->method == 'POST') {
            $token = Flight::request()->data->csrf_token;
            if($token !== Flight::session()->get('csrf_token')) {
                Flight::halt(403, 'Ungültiges CSRF-Token');
            }
        }
    }
}

// index.php oder wo immer Sie Ihre Routen haben
Flight::group('', function(Router $router) {
    $router->get('/users', [ 'UserController', 'getUsers' ]);
    // weitere Routen
}, [ new CsrfMiddleware() ]);

Cross Site Scripting (XSS)

Cross Site Scripting (XSS) ist ein Angriffstyp, bei dem eine bösartige Website Code in Ihre Website einschleusen kann. Die meisten dieser Möglichkeiten ergeben sich aus Formularwerten, die Ihre Endbenutzer ausfüllen werden. Sie sollten niemals auf die Ausgabe Ihrer Benutzer vertrauen! Gehen Sie immer davon aus, dass alle die besten Hacker der Welt sind. Sie können bösartiges JavaScript oder HTML in Ihre Seite einschleusen. Dieser Code kann verwendet werden, um Informationen von Ihren Benutzern zu stehlen oder Aktionen auf Ihrer Website durchzuführen. Mit der View-Klasse von Flight können Sie die Ausgabe einfach escapen, um XSS-Angriffe zu verhindern.

// Angenommen, der Benutzer ist clever und versucht, dies als seinen Namen zu verwenden
$name = '<script>alert("XSS")</script>';

// Dies wird die Ausgabe escapen
Flight::view()->set('name', $name);
// Dies wird ausgegeben: &lt;script&gt;alert(&quot;XSS&quot;)&lt;/script&gt;

// Wenn Sie etwas wie Latte als Ihre View-Klasse registriert haben, wird es dies auch automatisch escapen.
Flight::view()->render('template', ['name' => $name]);

SQL-Injection

SQL-Injection ist ein Angriffstyp, bei dem ein bösartiger Benutzer SQL-Code in Ihre Datenbank einschleusen kann. Dies kann verwendet werden, um Informationen aus Ihrer Datenbank zu stehlen oder Aktionen auf Ihrer Datenbank durchzuführen. Auch hier sollten Sie niemals auf Eingaben Ihrer Benutzer vertrauen! Gehen Sie immer davon aus, dass sie auf Blut aus sind. Sie können vorbereitete Anweisungen in Ihren PDO-Objekten verwenden, um SQL-Injection zu verhindern.

// Angenommen, dass Flight::db() als Ihr PDO-Objekt registriert ist
$anweisung = Flight::db()->prepare('SELECT * FROM users WHERE username = :username');
$anweisung->execute([':username' => $username]);
$benutzer = $anweisung->fetchAll();

// Wenn Sie die PdoWrapper-Klasse verwenden, kann dies einfach in einer Zeile erledigt werden
$benutzer = Flight::db()->fetchAll('SELECT * FROM users WHERE username = :username', [ 'username' => $username ]);

// Sie können das Gleiche mit einem PDO-Objekt mit ?-Platzhaltern tun
$anweisung = Flight::db()->fetchAll('SELECT * FROM users WHERE username = ?', [ $username ]);

// Versprechen Sie einfach, dass Sie niemals etwas wie dies tun werden...
$benutzer = Flight::db()->fetchAll("SELECT * FROM users WHERE username = '{$username}' LIMIT 5");
// denn was ist, wenn $benutzername = "' OR 1=1; -- ";
// Nachdem die Abfrage erstellt wurde, sieht sie so aus
// SELECT * FROM users WHERE username = '' OR 1=1; -- LIMIT 5
// Es sieht seltsam aus, aber es ist eine gültige Abfrage, die funktionieren wird. Tatsächlich ist es ein sehr verbreiteter SQL-Injection-Angriff, der alle Benutzer zurückgibt.

CORS

Cross-Origin Resource Sharing (CORS) ist ein Mechanismus, der es vielen Ressourcen (z. B. Schriften, JavaScript usw.) auf einer Webseite ermöglicht, von einer anderen Domain außerhalb der Domäne, von der die Ressource stammt, angefordert zu werden. Flight hat keine integrierte Funktionalität, aber dies kann einfach mit einem Hook behandelt werden, der vor dem Aufruf der Flight::start()-Methode ausgeführt wird.

// app/utils/CorsUtil.php

namespace app\utils;

class CorsUtil
{
    public function set(array $params): void
    {
        $anfrage = Flight::request();
        $antwort = Flight::response();
        if ($anfrage->getVar('HTTP_ORIGIN') !== '') {
            $this->allowOrigins();
            $antwort->header('Access-Control-Allow-Credentials', 'true');
            $antwort->header('Access-Control-Max-Age', '86400');
        }

        if ($anfrage->method === 'OPTIONS') {
            if ($anfrage->getVar('HTTP_ACCESS_CONTROL_REQUEST_METHOD') !== '') {
                $antwort->header(
                    'Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS, HEAD'
                );
            }
            if ($anfrage->getVar('HTTP_ACCESS_CONTROL_REQUEST_HEADERS') !== '') {
                $antwort->header(
                    "Access-Control-Allow-Headers",
                    $anfrage->getVar('HTTP_ACCESS_CONTROL_REQUEST_HEADERS')
                );
            }

            $antwort->status(200);
            $antwort->send();
            exit;
        }
    }

    private function allowOrigins(): void
    {
        // passen Sie Ihre erlaubten Hosts hier an.
        $erlaubt = [
            'capacitor://localhost',
            'ionic://localhost',
            'http://localhost',
            'http://localhost:4200',
            'http://localhost:8080',
            'http://localhost:8100',
        ];

        $anfrage = Flight::request();

        if (in_array($anfrage->getVar('HTTP_ORIGIN'), $erlaubt, true) === true) {
            $antwort = Flight::response();
            $antwort->header("Access-Control-Allow-Origin", $anfrage->getVar('HTTP_ORIGIN'));
        }
    }
}

// index.php oder wo immer Sie Ihre Routen haben
$CorsUtil = new CorsUtil();
Flight::before('start', [ $CorsUtil, 'setupCors' ]);

Fazit

Sicherheit ist wichtig und es ist wichtig sicherzustellen, dass Ihre Webanwendungen sicher sind. Flight bietet eine Reihe von Funktionen, um Ihnen bei der Absicherung Ihrer Webanwendungen zu helfen, aber es ist wichtig, immer wachsam zu sein und sicherzustellen, dass Sie alles tun, um die Daten Ihrer Benutzer sicher zu halten. Gehen Sie immer vom Schlimmsten aus und vertrauen Sie niemals den Eingaben Ihrer Benutzer. Escapen Sie immer die Ausgabe und verwenden Sie vorbereitete Anweisungen, um SQL-Injection zu verhindern. Verwenden Sie immer Middleware, um Ihre Routen vor CSRF- und CORS-Angriffen zu schützen. Wenn Sie all diese Dinge tun, sind Sie auf dem besten Weg, sichere Webanwendungen zu erstellen.

Learn/overriding

Überschreiben

Flight ermöglicht es Ihnen, seine Standardfunktionalität anzupassen, um Ihren eigenen Anforderungen gerecht zu werden, ohne dass Sie Code ändern müssen.

Zum Beispiel, wenn Flight eine URL nicht mit einer Route übereinstimmen kann, ruft es die notFound-Methode auf, die eine generische HTTP 404-Antwort sendet. Sie können dieses Verhalten überschreiben, indem Sie die map-Methode verwenden:

Flight::map('notFound', function() {
  // Benutzerdefinierte 404-Seite anzeigen
  include 'errors/404.html';
});

Flight ermöglicht es Ihnen auch, Kernkomponenten des Frameworks zu ersetzen. Zum Beispiel können Sie die Standard-Routerklasse durch Ihre eigene benutzerdefinierte Klasse ersetzen:

// Registrieren Sie Ihre benutzerdefinierte Klasse
Flight::register('router', MyRouter::class);

// Wenn Flight die Router-Instanz lädt, wird Ihre Klasse geladen
$myrouter = Flight::router();

Framework-Methoden wie map und register können jedoch nicht überschrieben werden. Sie erhalten einen Fehler, wenn Sie es zu versuchen.

Learn/routing

# Routing

> **Hinweis:** Möchten Sie mehr über Routing erfahren? Schauen Sie sich die ["warum ein Framework?"](/learn/why-frameworks) Seite für eine ausführlichere Erklärung an.

Die grundlegende Routenführung in Flight erfolgt durch das Zuordnen eines URL-Musters mit einer Callback-Funktion oder einem Array einer Klasse und Methode.

```php
Flight::route('/', function(){
    echo 'Hallo Welt!';
});

Routen werden in der Reihenfolge abgeglichen, in der sie definiert sind. Die erste passende Route für eine Anfrage wird aufgerufen.

Callbacks/Funktionen

Das Callback kann jedes Objekt sein, das aufrufbar ist. Sie können also eine reguläre Funktion verwenden:

function hallo(){
    echo 'Hallo Welt!';
}

Flight::route('/', 'hallo');

Klassen

Sie können auch eine statische Methode einer Klasse verwenden:

class Gruß {
    public static function hallo() {
        echo 'Hallo Welt!';
    }
}

Flight::route('/', [ 'Gruß','hallo' ]);

Oder indem Sie zuerst ein Objekt erstellen und dann die Methode aufrufen:


// Gruß.php
class Gruß
{
    public function __construct() {
        $this->name = 'Max Mustermann';
    }

    public function hallo() {
        echo "Hallo, {$this->name}!";
    }
}

// index.php
$gruß = new Gruß();

Flight::route('/', [ $gruß, 'hallo' ]);
// Sie können dies auch ohne zuerst das Objekt zu erstellen
// beachten: Keine Argumente werden in den Konstruktor eingefügt
Flight::route('/', [ 'Gruß', 'hallo' ]);

Abhängigkeitsinjektion über DIC (Dependency Injection Container)

Wenn Sie die Abhängigkeitsinjektion über einen Container verwenden möchten (PSR-11, PHP-DI, Dice usw.), ist der einzige Typ von Routen, bei dem dies möglich ist, entweder das direkte Erstellen des Objekts selbst und die Verwendung des Containers zum Erstellen Ihres Objekts oder Sie können Zeichenfolgen verwenden, um die Klasse zu definieren und Methode zum Aufruf. Sie können zur Dependency Injection-Seite gehen, um mehr Informationen zu erhalten.

Hier ist ein schnelles Beispiel:


use flight\database\PdoWrapper;

// Gruß.php
class Gruß
{
    protected PdoWrapper $pdoWrapper;
    public function __construct(PdoWrapper $pdoWrapper) {
        $this->pdoWrapper = $pdoWrapper;
    }

    public function hallo(int $id) {
        // etwas mit $this->pdoWrapper machen
        $name = $this->pdoWrapper->fetchField("SELECT name FROM users WHERE id = ?", [ $id ]);
        echo "Hallo, Welt! Mein Name ist {$name}!";
    }
}

// index.php

// Richten Sie den Container mit den erforderlichen Parametern ein
// Sehen Sie sich die Dependency Injection-Seite für weitere Informationen zu PSR-11 an
$dice = new \Dice\Dice();

// Vergessen Sie nicht, die Variable mit '$dice = ' neu zuzuweisen!!!!
$dice = $dice->addRule('flight\database\PdoWrapper', [
    'shared' => true,
    'constructParams' => [ 
        'mysql:host=localhost;dbname=test', 
        'root',
        'password'
    ]
]);

// Melden Sie den Container-Handler an
Flight::registerContainerHandler(function($class, $params) use ($dice) {
    return $dice->create($class, $params);
});

// Routen wie gewohnt
Flight::route('/hallo/@id', [ 'Gruß', 'hallo' ]);
// oder
Flight::route('/hallo/@id', 'Gruß->hallo');
// oder
Flight::route('/hallo/@id', 'Gruß::hallo');

Flight::start();

Methodenrouten

Standardmäßig werden Routenmuster gegen alle Anfragemethoden abgeglichen. Sie können auf spezifische Methoden reagieren, indem Sie einen Bezeichner vor der URL platzieren.

Flight::route('GET /', function () {
  echo 'Ich habe eine GET-Anfrage erhalten.';
});

Flight::route('POST /', function () {
  echo 'Ich habe eine POST-Anfrage erhalten.';
});

// Sie können Flight::get() nicht für Routen verwenden, da dies eine Methode ist
//    zum Abrufen von Variablen, keine Route erstellen.
// Flight::post('/', function() { /* Code */ });
// Flight::patch('/', function() { /* Code */ });
// Flight::put('/', function() { /* Code */ });
// Flight::delete('/', function() { /* Code */ });

Sie können auch mehrere Methoden zu einer einzelnen Callbackfunktion zuordnen, indem Sie einen |-Delimiter verwenden:

Flight::route('GET|POST /', function () {
  echo 'Ich habe entweder eine GET- oder POST-Anfrage erhalten.';
});

Außerdem können Sie auf das Router-Objekt zugreifen, das einige Hilfsmethoden für Sie bereitstellt:


$router = Flight::router();

// alle Methoden zuordnen
$router->map('/', function() {
    echo 'Hallo Welt!';
});

// GET-Anforderung
$router->get('/benutzer', function() {
    echo 'Benutzer';
});
// $router->post();
// $router->put();
// $router->delete();
// $router->patch();

Reguläre Ausdrücke

Sie können reguläre Ausdrücke in Ihren Routen verwenden:

Flight::route('/benutzer/[0-9]+', function () {
  // Dies passt zu /benutzer/1234
});

Obwohl diese Methode verfügbar ist, wird empfohlen, benannte Parameter oder benannte Parameter mit regulären Ausdrücken zu verwenden, da diese besser lesbar und einfacher zu pflegen sind.

Benannte Parameter

Sie können benannte Parameter in Ihren Routen angeben, die an Ihre Callback-Funktion übergeben werden.

Flight::route('/@name/@id', function (string $name, string $id) {
  echo "Hallo, $name ($id)!";
});

Sie können auch reguläre Ausdrücke mit Ihren benannten Parametern einschließen, indem Sie den :-Delimiter verwenden:

Flight::route('/@name/@id:[0-9]{3}', function (string $name, string $id) {
  // Dies passt zu /bob/123
  // Passt jedoch nicht zu /bob/12345
});

Hinweis: Das Übereinstimmen von Regex-Gruppen () mit benannten Parametern wird nicht unterstützt. :'(

Optionale Parameter

Sie können benannte Parameter angeben, die optional übereinstimmen, indem Sie Segmente in Klammern setzen.

Flight::route(
  '/blog(/@year(/@month(/@day)))',
  function(?string $year, ?string $month, ?string $day) {
    // Dies passt zu den folgenden URLs:
    // /blog/2012/12/10
    // /blog/2012/12
    // /blog/2012
    // /blog
  }
);

Nicht übereinstimmende optionale Parameter werden als NULL übergeben.

Platzhalter

Die Übereinstimmung erfolgt nur auf einzelnen URL-Segmenten. Wenn Sie mehrere übereinstimmen möchten Segmente können Sie den *-Platzhalter verwenden.

Flight::route('/blog/*', function () {
  // Dies passt zu /blog/2000/02/01
});

Um alle Anfragen an eine einzelne Callbackfunktion zu routen, können Sie folgendes tun:

Flight::route('*', function () {
  // Mach etwas
});

Weitergabe

Sie können die Ausführung an die nächste passende Route weitergeben, indem Sie true aus Ihrer Callback-Funktion zurückgeben.

Flight::route('/benutzer/@name', function (string $name) {
  // Überprüfen Sie eine Bedingung
  if ($name !== "Bob") {
    // Zur nächsten Route fortsetzen
    return true;
  }
});

Flight::route('/benutzer/*', function () {
  // Dies wird aufgerufen
});

Routenalias

Sie können einem Route einen Alias zuweisen, damit die URL später dynamisch in Ihrem Code generiert werden kann (beispielsweise in einem Template).

Flight::route('/benutzer/@id', function($id) { echo 'user:'.$id; }, false, 'user_view');

// später im Code irgendwo
Flight::getUrl('user_view', [ 'id' => 5 ]); // gibt '/benutzer/5' zurück

Dies ist besonders nützlich, wenn sich Ihre URL zufällig ändert. Im obigen Beispiel wurde Benutzer beispielsweise nach /admin/benutzer/@id verschoben. Dank der Aliasfunktion müssen Sie überall dort, wo Sie auf den Alias verweisen, keine Änderungen vornehmen, da der Alias nun /admin/benutzer/5 wie im Beispiel oben zurückgibt.

Routenalias funktionieren auch in Gruppen:

Flight::group('/benutzer', function() {
    Flight::route('/@id', function($id) { echo 'user:'.$id; }, false, 'user_view');
});

// später im Code irgendwo
Flight::getUrl('user_view', [ 'id' => 5 ]); // gibt '/benutzer/5' zurück

Routeninformationen

Wenn Sie die Übereinstimmungsinformationen der Route inspizieren möchten, können Sie anfordern, dass das Routenobjekt an Ihre Callback-Funktion übergeben wird, indem Sie true als dritten Parameter in die Routenmethode übergeben. Das Routenobjekt wird immer als letzter Parameter an Ihre Callback-Funktion übergeben.

Flight::route('/', function(\flight\net\Route $route) {
  // Array der mit übereinstimmenden HTTP-Methoden
  $route->methods;

  // Array der benannten Parameter
  $route->params;

  // Übereinstimmender regulärer Ausdruck
  $route->regex;

  // Enthält den Inhalt von '*' im URL-Muster
  $route->splat;

  // Zeigt den URL-Pfad an.... falls wirklich benötigt
  $route->pattern;

  // Zeigt an, welches Middleware für diese Route zugewiesen ist
  $route->middleware;

  // Zeigt den diesem Route zugewiesenen Alias an
  $route->alias;
}, true);

Routengruppierung

Es gibt möglicherweise Zeiten, in denen Sie zusammenhängende Routen gruppieren möchten (z. B. /api/v1). Dies können Sie durch Verwendung der Gruppen-Methode erreichen:

Flight::group('/api/v1', function () {
  Flight::route('/benutzer', function () {
    // Passt zu /api/v1/benutzer
  });

  Flight::route('/beiträge', function () {
    // Passt zu /api/v1/beiträge
  });
});

Sie können sogar Gruppen von Gruppen verschachteln:

Flight::group('/api', function () {
  Flight::group('/v1', function () {
    // Flight::get() holt Variablen, setzt keine Route! Siehe Objektkontext unten
    Flight::route('GET /benutzer', function () {
      // Passt zu GET /api/v1/benutzer
    });

    Flight::post('/beiträge', function () {
      // Passt zu POST /api/v1/beiträge
    });

    Flight::put('/beiträge/1', function () {
      // Passt zu PUT /api/v1/beiträge
    });
  });
  Flight::group('/v2', function () {

    // Flight::get() holt Variablen, setzt keine Route! Siehe Objektkontext unten
    Flight::route('GET /benutzer', function () {
      // Passt zu GET /api/v2/benutzer
    });
  });
});

Gruppierung mit Objektkontext

Sie können die Routengruppierung immer noch mit dem Engine-Objekt auf folgende Weise verwenden:

$app = new \flight\Engine();
$app->group('/api/v1', function (Router $router) {

  // Verwenden Sie die Variable $router
  $router->get('/benutzer', function () {
    // Passt zu GET /api/v1/benutzer
  });

  $router->post('/beiträge', function () {
    // Passt zu POST /api/v1/beiträge
  });
});

Streaming

Sie können jetzt Antworten an den Client streamen, indem Sie die streamWithHeaders()-Methode verwenden. Dies ist nützlich für das Senden großer Dateien, lang laufende Prozesse oder die Generierung großer Antworten. Das Streamen einer Route wird etwas anders behandelt als eine normale Route.

Hinweis: Das Streamen von Antworten ist nur verfügbar, wenn Sie flight.v2.output_buffering auf false gesetzt haben.

Stream mit manuellen Headern

Sie können eine Antwort an den Client streamen, indem Sie die stream()-Methode auf einer Route verwenden. Wenn Sie das tun, müssen Sie alle Methoden von Hand festlegen, bevor Sie etwas an den Client ausgeben. Dies geschieht mit der header()-PHP-Funktion oder der Flight::response()->setRealHeader()-Methode.

Flight::route('/@dateiname', function($dateiname) {

    // offensichtlich sollten Sie den Pfad und dergleichen bereinigen.
    $dateinameSicher = basename($dateiname);

    // Wenn Sie hier nach der Route zusätzliche Header setzen müssen
    // müssen Sie diese definieren, bevor etwas an den Client ausgegeben wird.
    // Sie müssen alle ein Aufruf der header() Funktion oder ein Aufruf von Flight::response()->setRealHeader()
    header('Content-Disposition: Anhang; filename="'.$dateinameSicher.'"');
    // oder
    Flight::response()->setRealHeader('Content-Disposition', 'Anhang; filename="'.$dateinameSicher.'"');

    $dateiDaten = file_get_contents('/some/path/to/files/'.$dateinameSicher);

    // Fehlerbehandlung usw.
    if(empty($fileData)) {
        Flight::halt(404, 'Datei nicht gefunden');
    }

    // manuell die Inhaltslänge setzen, wenn Sie möchten
    header('Inhaltslänge: '.filesize($filename));

    // Streamen der Daten an den Client
    echo $dateiDaten;

// Dies ist die magische Zeile hier
})->stream();

Stream mit Headern

Sie können auch die streamWithHeaders()-Methode verwenden, um die Header festzulegen, bevor Sie mit dem Streamen beginnen.

Flight::route('/benutzer-stream', function() {

    // Sie können hier beliebige zusätzliche Header hinzufügen
    // Sie müssen nur header() oder Flight::response()->setRealHeader() verwenden

    // wie auch immer Sie Ihre Daten abrufen, nur als Beispiel...
    $benutzer_stmt = Flight::db()->query("SELECT id, vorname, nachname FROM benutzer");

    echo '{';
    $benutzerZähler = count($users);
    while($benutzer = $benutzer_stmt->fetch(PDO::FETCH_ASSOC)) {
        echo json_encode($benutzer);
        if(--$benutzerZähler > 0) {
            echo ',';
        }

        // Hiermit senden Sie die Daten an den Client
        ob_flush();
    }
    echo '}';

// So setzen Sie die Header, bevor Sie mit dem Streamen beginnen.
})->streamWithHeaders([
    'Content-Type' => 'application/json',
    'Content-Disposition' => 'Anhang; filename="benutzer.json"',
    // optionaler Statuscode, standardmäßig 200
    'status' => 200
]);

Learn/variables

Variablen

Flight ermöglicht es Ihnen, Variablen zu speichern, damit sie überall in Ihrer Anwendung verwendet werden können.

// Speichern Sie Ihre Variable
Flight::set('id', 123);

// Anderswo in Ihrer Anwendung
$id = Flight::get('id');

Um zu überprüfen, ob eine Variable festgelegt wurde, können Sie Folgendes tun:

if (Flight::has('id')) {
  // Mach etwas
}

Sie können eine Variable löschen, indem Sie Folgendes tun:

// Löscht die id-Variable
Flight::clear('id');

// Löscht alle Variablen
Flight::clear();

Flight verwendet auch Variablen für Konfigurationszwecke.

Flight::set('flight.log_errors', true);

Learn/dependency_injection_container

Dependency Injection Container

Einführung

Der Dependency Injection Container (DIC) ist ein leistungsstolles Werkzeug, das es ermöglicht, die Abhängigkeiten Ihrer Anwendung zu verwalten. Es ist ein Schlüsselkonzept in modernen PHP-Frameworks und wird verwendet, um die Instanziierung und Konfiguration von Objekten zu verwalten. Einige Beispiele für DIC-Bibliotheken sind: Dice, Pimple, PHP-DI und league/container.

Ein DIC ist eine elegante Möglichkeit zu sagen, dass es Ihnen ermöglicht, Ihre Klassen an einem zentralen Ort zu erstellen und zu verwalten. Dies ist nützlich, wenn Sie dasselbe Objekt an mehrere Klassen übergeben müssen (wie Ihre Controller). Ein einfaches Beispiel könnte dies verständlicher machen.

Grundbeispiel

Der alte Weg, Dinge zu erledigen, könnte so aussehen:


require 'vendor/autoload.php';

// Klasse zur Verwaltung von Benutzern aus der Datenbank
class UserController {

    protected PDO $pdo;

    public function __construct(PDO $pdo) {
        $this->pdo = $pdo;
    }

    public function view(int $id) {
        $stmt = $this->pdo->prepare('SELECT * FROM users WHERE id = :id');
        $stmt->execute(['id' => $id]);

        print_r($stmt->fetch());
    }
}

$User = new UserController(new PDO('mysql:host=localhost;dbname=test', 'user', 'pass'));
Flight::route('/user/@id', [ $UserController, 'view' ]);

Flight::start();

Sie können im obigen Code sehen, dass wir ein neues PDO-Objekt erstellen und es an unsere UserController-Klasse übergeben. Dies ist in Ordnung für eine kleine Anwendung, aber wenn Ihre Anwendung wächst, werden Sie feststellen, dass Sie das gleiche PDO-Objekt an mehreren Stellen erstellen. Hier kommt ein DIC ins Spiel.

Hier ist das gleiche Beispiel unter Verwendung eines DICs (unter Verwendung von Dice):


require 'vendor/autoload.php';

// dieselbe Klasse wie oben. Nichts geändert
class UserController {

    protected PDO $pdo;

    public function __construct(PDO $pdo) {
        $this->pdo = $pdo;
    }

    public function view(int $id) {
        $stmt = $this->pdo->prepare('SELECT * FROM users WHERE id = :id');
        $stmt->execute(['id' => $id]);

        print_r($stmt->fetch());
    }
}

// erstelle einen neuen Container
$container = new \Dice\Dice;
// vergiss nicht, ihn wie unten erneut zuzuweisen!
$container = $container->addRule('PDO', [
    // shared bedeutet, dass jedes Mal dasselbe Objekt zurückgegeben wird
    'shared' => true,
    'constructParams' => ['mysql:host=localhost;dbname=test', 'user', 'pass' ]
]);

// Hiermit wird der Container-Handler registriert, damit Flight weiß, dass er ihn verwenden soll.
Flight::registerContainerHandler(function($class, $params) use ($container) {
    return $container->create($class, $params);
});

// jetzt können wir den Container verwenden, um unseren UserController zu erstellen
Flight::route('/user/@id', [ 'UserController', 'view' ]);
// oder alternativ können Sie die Route wie folgt definieren
Flight::route('/user/@id', 'UserController->view');
// oder
Flight::route('/user/@id', 'UserController::view');

Flight::start();

Sie denken vielleicht, dass viel zusätzlicher Code zum Beispiel hinzugefügt wurde. Die Magie entsteht, wenn Sie einen anderen Controller haben, der das PDO-Objekt benötigt.


// Wenn alle Ihre Controller einen Konstruktor haben, der ein PDO-Objekt benötigt
// wird dies automatisch für jede der untenstehenden Routen eingefügt!!!
Flight::route('/company/@id', 'CompanyController->view');
Flight::route('/organization/@id', 'OrganizationController->view');
Flight::route('/category/@id', 'CategoryController->view');
Flight::route('/settings', 'SettingsController->view');

Der zusätzliche Vorteil der Nutzung eines DICs besteht darin, dass Unittests wesentlich einfacher werden. Sie können ein Mock-Objekt erstellen und es an Ihre Klasse übergeben. Dies ist ein großer Vorteil, wenn Sie Tests für Ihre Anwendung schreiben!

PSR-11

Flight kann auch jeden PSR-11-kompatiblen Container verwenden. Dies bedeutet, dass Sie jeden Container verwenden können, der das PSR-11-Interface implementiert. Hier ist ein Beispiel für die Verwendung des PSR-11-Containers von League:


require 'vendor/autoload.php';

// dieselbe UserController-Klasse wie oben

$container = new \League\Container\Container();
$container->add(UserController::class)->addArgument(PdoWrapper::class);
$container->add(PdoWrapper::class)
    ->addArgument('mysql:host=localhost;dbname=test')
    ->addArgument('user')
    ->addArgument('pass');
Flight::registerContainerHandler($container);

Flight::route('/user', [ 'UserController', 'view' ]);

Flight::start();

Obwohl dies etwas ausführlicher ist als das vorherige Dice-Beispiel, erledigt es dennoch die Aufgabe mit denselben Vorteilen!

Eigener DIC-Handler

Sie können auch Ihren eigenen DIC-Handler erstellen. Dies ist nützlich, wenn Sie einen benutzerdefinierten Container haben, den Sie verwenden möchten, der nicht PSR-11 (Dice) ist. Sehen Sie sich das Grundbeispiel dafür an.

Darüber hinaus gibt es einige nützliche Standardeinstellungen, die Ihnen das Leben erleichtern, wenn Sie Flight verwenden.

Engine-Instanz

Wenn Sie die Engine-Instanz in Ihren Controllern/Middleware verwenden, so konfigurieren Sie diese:


// Irgendwo in Ihrer Startdatei
$engine = Flight::app();

$container = new \Dice\Dice;
$container = $container->addRule('*', [
    'substitutions' => [
        // Hier geben Sie die Instanz ein
        Engine::class => $engine
    ]
]);

$engine->registerContainerHandler(function($class, $params) use ($container) {
    return $container->create($class, $params);
});

// Nun können Sie die Engine-Instanz in Ihren Controllern/Middleware verwenden

class MyController {
    public function __construct(Engine $app) {
        $this->app = $app;
    }

    public function index() {
        $this->app->render('index');
    }
}

Hinzufügen anderer Klassen

Wenn Sie andere Klassen in den Container aufnehmen möchten, ist dies mit Dice einfach, da sie automatisch vom Container aufgelöst werden. Hier ist ein Beispiel:


$container = new \Dice\Dice;
// Wenn Sie nichts in Ihre Klasse injizieren müssen,
// müssen Sie nichts definieren!
Flight::registerContainerHandler(function($class, $params) use ($container) {
    return $container->create($class, $params);
});

class MyCustomClass {
    public function parseThing() {
        return 'thing';
    }
}

class UserController {

    protected MyCustomClass $MyCustomClass;

    public function __construct(MyCustomClass $MyCustomClass) {
        $this->MyCustomClass = $MyCustomClass;
    }

    public function index() {
        echo $this->MyCustomClass->parseThing();
    }
}

Flight::route('/user', 'UserController->index');

Learn/middleware

Routen Middleware

Flight unterstützt Routen- und Gruppenrouten-Middleware. Middleware ist eine Funktion, die vor (oder nach) dem Routenrückruf ausgeführt wird. Dies ist eine großartige Möglichkeit, API-Authentifizierungsprüfungen in Ihrem Code hinzuzufügen oder zu überprüfen, ob der Benutzer die Berechtigung zum Zugriff auf die Route hat.

Grundlegende Middleware

Hier ist ein grundlegendes Beispiel:

// Wenn Sie nur eine anonyme Funktion angeben, wird sie vor dem Routenrückruf ausgeführt.
// Es gibt keine "nachher"-Middleware-Funktionen, außer für Klassen (siehe unten)
Flight::route('/pfad', function() { echo 'Hier bin ich!'; })->addMiddleware(function() {
    echo 'Middleware zuerst!';
});

Flight::start();

// Dies gibt "Middleware zuerst! Hier bin ich!" aus

Es gibt einige sehr wichtige Hinweise zur Middleware, die Sie beachten sollten, bevor Sie sie verwenden:

Middleware-Klassen

Middleware kann auch als Klasse registriert werden. Wenn Sie die "nachher"-Funktionalität benötigen, müssen Sie eine Klasse verwenden.

class MyMiddleware {
    public function before($params) {
        echo 'Middleware zuerst!';
    }

    public function after($params) {
        echo 'Middleware zuletzt!';
    }
}

$MeineMiddleware = new MyMiddleware();
Flight::route('/pfad', function() { echo 'Hier bin ich! '; })->addMiddleware($MeineMiddleware); // auch ->addMiddleware([$MeineMiddleware, $MeineMiddleware2]);

Flight::start();

// Dies zeigt "Middleware zuerst! Hier bin ich! Middleware zuletzt!" an

Behandlung von Middleware-Fehlern

Angenommen, Sie haben eine Auth-Middleware und möchten den Benutzer auf eine Login-Seite umleiten, wenn er nicht authentifiziert ist. Sie haben ein paar Optionen zur Verfügung:

  1. Sie können false aus der Middleware-Funktion zurückgeben, und Flight gibt automatisch einen 403 Forbidden Fehler zurück, jedoch ohne Anpassung.
  2. Sie können den Benutzer durch Verwendung von Flight::redirect() auf eine Login-Seite umleiten.
  3. Sie können einen benutzerdefinierten Fehler innerhalb der Middleware erstellen und die Ausführung der Route anhalten.

Grundlegendes Beispiel

Hier ist ein einfaches return false; Beispiel:

class MyMiddleware {
    public function before($params) {
        if (isset($_SESSION['benutzer']) === false) {
            return false;
        }

        // da es wahr ist, geht einfach alles weiter
    }
}

Umleitungsbeispiel

Hier ist ein Beispiel, wie Sie den Benutzer auf eine Login-Seite umleiten:

class MyMiddleware {
    public function before($params) {
        if (isset($_SESSION['benutzer']) === false) {
            Flight::redirect('/login');
            exit;
        }
    }
}

Benutzerdefiniertes Fehlerbeispiel

Angenommen, Sie müssen einen JSON-Fehler auslösen, weil Sie eine API erstellen. Sie können das folgendermaßen tun:

class MyMiddleware {
    public function before($params) {
        $autorisation = Flight::request()->headers['Authorization'];
        if(empty($autorisation)) {
            Flight::json(['error' => 'Sie müssen angemeldet sein, um auf diese Seite zuzugreifen.'], 403);
            exit;
            // oder
            Flight::halt(403, json_encode(['error' => 'Sie müssen angemeldet sein, um auf diese Seite zuzugreifen.']);
        }
    }
}

Gruppierung von Middleware

Sie können eine Routengruppe hinzufügen, und dann wird jede Route in dieser Gruppe ebenfalls dieselbe Middleware haben. Dies ist nützlich, wenn Sie eine Gruppe von Routen beispielsweise durch eine Auth-Middleware gruppieren müssen, um den API-Schlüssel im Header zu überprüfen.


// am Ende der Gruppenmethode hinzugefügt
Flight::group('/api', function() {

    // Diese "leer" aussehende Route wird tatsächlich /api übereinstimmen
    Flight::route('', function() { echo 'api'; }, false, 'api');
    Flight::route('/benutzer', function() { echo 'benutzer'; }, false, 'benutzer');
    Flight::route('/benutzer/@id', function($id) { echo 'benutzer:'.$id; }, false, 'benutzer_ansicht');
}, [ new ApiAuthMiddleware() ]);

Wenn Sie eine globale Middleware auf alle Ihre Routen anwenden möchten, können Sie eine "leere" Gruppe hinzufügen:


// am Ende der Gruppenmethode hinzugefügt
Flight::group('', function() {
    Flight::route('/benutzer', function() { echo 'benutzer'; }, false, 'benutzer');
    Flight::route('/benutzer/@id', function($id) { echo 'benutzer:'.$id; }, false, 'benutzer_ansicht');
}, [ new ApiAuthMiddleware() ]);

Learn/filtering

Filtern

Flight ermöglicht es Ihnen, Methoden vor und nach ihrem Aufruf zu filtern. Es gibt keine vordefinierten Hooks, die Sie sich merken müssen. Sie können beliebige der Standardframework-Methoden sowie benutzerdefinierte Methoden filtern, die Sie zugeordnet haben.

Eine Filterfunktion sieht so aus:

function (array &$params, string &$output): bool {
  // Filtercode
}

Unter Verwendung der übergebenen Variablen können Sie die Eingabeparameter und/oder die Ausgabe manipulieren.

Sie können einen Filter vor einer Methode ausführen, indem Sie dies tun:

Flight::before('start', function (array &$params, string &$output): bool {
  // Etwas machen
});

Sie können einen Filter nach einer Methode ausführen, indem Sie dies tun:

Flight::after('start', function (array &$params, string &$output): bool {
  // Etwas machen
});

Sie können beliebig viele Filter zu einer Methode hinzufügen. Sie werden in der Reihenfolge aufgerufen, in der sie deklariert sind.

Hier ist ein Beispiel des Filtervorgangs:

// Eine benutzerdefinierte Methode zuordnen
Flight::map('hallo', function (string $name) {
  return "Hallo, $name!";
});

// Einen Vorfiler hinzufügen
Flight::before('hallo', function (array &$params, string &$output): bool {
  // Den Parameter manipulieren
  $params[0] = 'Fred';
  return true;
});

// Einen Nachfilter hinzufügen
Flight::after('hallo', function (array &$params, string &$output): bool {
  // Die Ausgabe manipulieren
  $output .= " Einen schönen Tag!";
  return true;
});

// Die benutzerdefinierte Methode aufrufen
echo Flight::hallo('Bob');

Dies sollte anzeigen:

Hallo Fred! Einen schönen Tag!

Wenn Sie mehrere Filter definiert haben, können Sie die Kette unterbrechen, indem Sie in einer Ihrer Filterfunktionen false zurückgeben:

Flight::before('start', function (array &$params, string &$output): bool {
  echo 'eins';
  return true;
});

Flight::before('start', function (array &$params, string &$output): bool {
  echo 'zwei';

  // Dies wird die Kette beenden
  return false;
});

// Dies wird nicht aufgerufen
Flight::before('start', function (array &$params, string &$output): bool {
  echo 'drei';
  return true;
});

Hinweis: Kernmethoden wie map und register können nicht gefiltert werden, da sie direkt aufgerufen und nicht dynamisch aufgerufen werden.

Learn/requests

Anfragen

Flight kapselt die HTTP-Anfrage in ein einzelnes Objekt, auf das zugegriffen werden kann, indem Folgendes getan wird:

$request = Flight::request();

Das Anfrageobjekt stellt die folgenden Eigenschaften bereit:

Sie können auf die Eigenschaften query, data, cookies und files als Arrays oder Objekte zugreifen.

Um beispielsweise einen Abfragezeichenfolgenparameter zu erhalten, können Sie Folgendes tun:

$id = Flight::request()->query['id'];

Oder Sie können Folgendes tun:

$id = Flight::request()->query->id;

ROHER Anfragekörper

Um den Roh-HTTP-Anfragekörper zu erhalten, beispielsweise beim Umgang mit PUT-Anfragen, können Sie Folgendes tun:

$body = Flight::request()->getBody();

JSON-Eingabe

Wenn Sie eine Anfrage mit dem Typ application/json und den Daten {"id": 123} senden, sind diese über die data-Eigenschaft verfügbar:

$id = Flight::request()->data->id;

Zugriff auf $_SERVER

Es gibt eine Abkürzung zum Zugriff auf das Array $_SERVER über die Methode getVar():


$host = Flight::request()->getVar['HTTP_HOST'];

Zugriff auf Anfrageheader

Sie können auf Anfrageheader mit der Methode getHeader() oder getHeaders() zugreifen:


// Möglicherweise benötigen Sie den Autorisierungsheader
$host = Flight::request()->getHeader('Authorization');

// Wenn Sie alle Header abrufen müssen
$headers = Flight::request()->getHeaders();

Learn/frameworkmethods

Methoden des Frameworks

Flight wurde entwickelt, um einfach zu bedienen und zu verstehen zu sein. Im Folgenden finden Sie die vollständige Liste der Methoden für das Framework. Es besteht aus Kernmethoden, die reguläre statische Methoden sind, und erweiterbaren Methoden, die zugeordnete Methoden sind, die gefiltert oder überschrieben werden können.

Kernmethoden

Flight::map(string $name, callable $callback, bool $pass_route = false) // Erstellt eine benutzerdefinierte Framework-Methode.
Flight::register(string $name, string $class, array $params = [], ?callable $callback = null) // Registriert eine Klasse bei einer Framework-Methode.
Flight::before(string $name, callable $callback) // Fügt einen Filter vor einer Framework-Methode hinzu.
Flight::after(string $name, callable $callback) // Fügt einen Filter nach einer Framework-Methode hinzu.
Flight::path(string $path) // Fügt einen Pfad zum Laden von Klassen hinzu.
Flight::get(string $key) // Ruft eine Variable ab.
Flight::set(string $key, mixed $value) // Legt eine Variable fest.
Flight::has(string $key) // Überprüft, ob eine Variable festgelegt ist.
Flight::clear(array|string $key = []) // Löscht eine Variable.
Flight::init() // Initialisiert das Framework auf die Standardeinstellungen.
Flight::app() // Ruft die Anwendungsobjektinstanz ab.

Erweiterbare Methoden

Flight::start() // Startet das Framework.
Flight::stop() // Stoppt das Framework und sendet eine Antwort.
Flight::halt(int $code = 200, string $message = '') // Stoppt das Framework mit einem optionalen Statuscode und einer Nachricht.
Flight::route(string $pattern, callable $callback, bool $pass_route = false) // Ordnet ein URL-Muster einer Rückruffunktion zu.
Flight::group(string $pattern, callable $callback) // Erstellt Gruppierung für URLs, Muster muss ein String sein.
Flight::redirect(string $url, int $code) // Leitet zu einer anderen URL um.
Flight::render(string $file, array $data, ?string $key = null) // Rendert eine Vorlagendatei.
Flight::error(Throwable $error) // Sendet eine HTTP 500-Antwort.
Flight::notFound() // Sendet eine HTTP 404-Antwort.
Flight::etag(string $id, string $type = 'string') // Führt ETag-HTTP-Caching durch.
Flight::lastModified(int $time) // Führt HTTP-Caching für zuletzt geändert durch.
Flight::json(mixed $data, int $code = 200, bool $encode = true, string $charset = 'utf8', int $option) // Sendet eine JSON-Antwort.
Flight::jsonp(mixed $data, string $param = 'jsonp', int $code = 200, bool $encode = true, string $charset = 'utf8', int $option) // Sendet eine JSONP-Antwort.

Alle benutzerdefinierten Methoden, die mit map und register hinzugefügt wurden, können auch gefiltert werden.

Learn/api

Methoden der Framework-API

Flight wurde entwickelt, um einfach zu bedienen und zu verstehen zu sein. Hier ist die vollständige Liste der Methoden für das Framework. Diese besteht aus Kernmethoden, die reguläre statische Methoden sind, und erweiterbaren Methoden, die zugeordnete Methoden sind, die gefiltert oder überschrieben werden können.

Kernmethoden

Diese Methoden sind wesentlich für das Framework und können nicht überschrieben werden.

Flight::map(string $name, callable $callback, bool $pass_route = false) // Erstellt eine benutzerdefinierte Framework-Methode.
Flight::register(string $name, string $class, array $params = [], ?callable $callback = null) // Registriert eine Klasse bei einer Framework-Methode.
Flight::unregister(string $name) // Entfernt eine Klasse von einer Framework-Methode.
Flight::before(string $name, callable $callback) // Fügt einen Filter vor einer Framework-Methode hinzu.
Flight::after(string $name, callable $callback) // Fügt einen Filter nach einer Framework-Methode hinzu.
Flight::path(string $path) // Fügt einen Pfad zum Laden von Klassen hinzu.
Flight::get(string $key) // Ruft eine Variable ab.
Flight::set(string $key, mixed $value) // Legt eine Variable fest.
Flight::has(string $key) // Überprüft, ob eine Variable festgelegt ist.
Flight::clear(array|string $key = []) // Löscht eine Variable.
Flight::init() // Initialisiert das Framework auf seine Standardwerte.
Flight::app() // Ruft die Objektinstanz der Anwendung ab
Flight::request() // Ruft die Objektinstanz der Anfrage ab
Flight::response() // Ruft die Objektinstanz der Antwort ab
Flight::router() // Ruft die Objektinstanz des Routers ab
Flight::view() // Ruft die Objektinstanz der Ansicht ab

Erweiterbare Methoden

Flight::start() // Startet das Framework.
Flight::stop() // Stoppt das Framework und sendet eine Antwort.
Flight::halt(int $code = 200, string $message = '') // Stoppt das Framework mit optionalen Statuscode und Nachricht.
Flight::route(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') // Ordnet ein URL-Muster einer Rückruffunktion zu.
Flight::post(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') // Ordnet ein URL-Muster für POST-Anfragen einer Rückruffunktion zu.
Flight::put(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') // Ordnet ein URL-Muster für PUT-Anfragen einer Rückruffunktion zu.
Flight::patch(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') // Ordnet ein URL-Muster für PATCH-Anfragen einer Rückruffunktion zu.
Flight::delete(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') // Ordnet ein URL-Muster für DELETE-Anfragen einer Rückruffunktion zu.
Flight::group(string $pattern, callable $callback) // Erstellt Gruppierungen für URLs, Muster muss ein String sein.
Flight::getUrl(string $name, array $params = []) // Generiert eine URL basierend auf einem Routen-Alias.
Flight::redirect(string $url, int $code) // Leitet zu einer anderen URL weiter.
Flight::render(string $file, array $data, ?string $key = null) // Rendert eine Vorlagendatei.
Flight::error(Throwable $error) // Sendet eine HTTP 500 Antwort.
Flight::notFound() // Sendet eine HTTP 404 Antwort.
Flight::etag(string $id, string $type = 'string') // Führt ETag-HTTP-Caching durch.
Flight::lastModified(int $time) // Führt HTTP-Caching für zuletzt geändert durch.
Flight::json(mixed $data, int $code = 200, bool $encode = true, string $charset = 'utf8', int $option) // Sendet eine JSON-Antwort.
Flight::jsonp(mixed $data, string $param = 'jsonp', int $code = 200, bool $encode = true, string $charset = 'utf8', int $option) // Sendet eine JSONP-Antwort.

Alle benutzerdefinierten Methoden, die mit map und register hinzugefügt wurden, können auch gefiltert werden.

Learn/why_frameworks

Warum ein Framework?

Einige Programmierer sind vehement gegen die Verwendung von Frameworks. Sie argumentieren, dass Frameworks aufgebläht, langsam und schwer zu erlernen sind. Sie sagen, dass Frameworks unnötig sind und dass man besseren Code ohne sie schreiben kann. Es gibt sicherlich einige gültige Punkte, die über die Nachteile der Verwendung von Frameworks gemacht werden können. Es gibt jedoch auch viele Vorteile bei der Verwendung von Frameworks.

Gründe für die Verwendung eines Frameworks

Hier sind ein paar Gründe, warum Sie in Betracht ziehen sollten, ein Framework zu verwenden:

Flight ist ein Micro-Framework. Das bedeutet, dass es klein und leichtgewichtig ist. Es bietet nicht so viele Funktionen wie größere Frameworks wie Laravel oder Symfony. Es bietet jedoch viele der Funktionen, die Sie benötigen, um Webanwendungen zu erstellen. Es ist auch einfach zu erlernen und zu verwenden. Dies macht es zu einer guten Wahl für den schnellen und einfachen Aufbau von Webanwendungen. Wenn Sie neu in der Verwendung von Frameworks sind, ist Flight ein großartiges Einsteiger-Framework, um damit zu beginnen. Es wird Ihnen helfen, die Vorteile der Verwendung von Frameworks kennenzulernen, ohne Sie mit zu viel Komplexität zu überfordern. Nachdem Sie etwas Erfahrung mit Flight gesammelt haben, wird es einfacher sein, auf komplexere Frameworks wie Laravel oder Symfony umzusteigen. Allerdings kann Flight immer noch eine erfolgreiche robuste Anwendung erstellen.

Was ist Routenführung?

Die Routenführung ist der Kern des Flight-Frameworks, aber was genau ist das? Routenführung ist der Prozess, bei dem eine URL genommen und einer spezifischen Funktion in Ihrem Code zugeordnet wird. So können Sie Ihre Website basierend auf der angeforderten URL verschiedene Dinge tun lassen. Zum Beispiel möchten Sie eventuell das Profil eines Benutzers anzeigen, wenn er /user/1234 besucht, aber eine Liste aller Benutzer anzeigen, wenn er /users besucht. All das geschieht durch Routenführung.

Es könnte so funktionieren:

Und warum ist das wichtig?

Ein ordnungsgemäß zentralisiertes Routenführungssystem kann tatsächlich Ihr Leben dramatisch erleichtern! Es könnte am Anfang schwer zu erkennen sein. Hier sind ein paar Gründe warum:

Sicherlich kennen Sie die methode-artige Art und Weise, eine Website zu erstellen. Sie könnten eine Datei namens index.php haben, die eine Menge von if-Anweisungen hat, um die URL zu überprüfen und dann basierend auf der URL eine spezifische Funktion auszuführen. Dies ist eine Form von Routenführung, aber sie ist nicht sehr organisiert und kann schnell außer Kontrolle geraten. Das Routenführungssystem von Flight ist eine viel organisierte und leistungsstarke Methode, um die Routen zu handhaben.

Dies?


// /user/view_profile.php?id=1234
if ($_GET['id']) {
    $id = $_GET['id'];
    viewUserProfile($id);
}

// /user/edit_profile.php?id=1234
if ($_GET['id']) {
    $id = $_GET['id'];
    editUserProfile($id);
}

// usw...

Oder dies?


// index.php
Flight::route('/user/@id', [ 'UserController', 'viewUserProfile' ]);
Flight::route('/user/@id/edit', [ 'UserController', 'editUserProfile' ]);

// Vielleicht in Ihrer app/controllers/UserController.php
class UserController {
    public function viewUserProfile($id) {
        // Tu etwas
    }

    public function editUserProfile($id) {
        // Tu etwas
    }
}

Hoffentlich können Sie langsam die Vorteile der Verwendung eines zentralisierten Routenführungssystems erkennen. Es ist viel einfacher zu verwalten und zu verstehen auf lange Sicht!

Anfragen und Antworten

Flight bietet eine einfache und bequeme Möglichkeit, Anfragen und Antworten zu handhaben. Dies ist der Kern dessen, was ein Web-Framework tut. Es nimmt eine Anfrage von einem Benutzerbrowser entgegen, verarbeitet sie und sendet dann eine Antwort zurück. Auf diese Weise können Sie Webanwendungen erstellen, die Dinge wie das Anzeigen eines Benutzerprofils, das Anmelden eines Benutzers oder das Posten eines neuen Blogbeitrags ermöglichen.

Anfragen

Eine Anfrage ist das, was der Browser eines Benutzers an Ihren Server sendet, wenn er Ihre Website besucht. Diese Anfrage enthält Informationen darüber, was der Benutzer tun möchte. Zum Beispiel könnte sie Informationen darüber enthalten, welche URL der Benutzer besuchen möchte, welche Daten der Benutzer an Ihren Server senden möchte oder welche Art von Daten der Benutzer von Ihrem Server erhalten möchte. Es ist wichtig zu wissen, dass eine Anfrage schreibgeschützt ist. Sie können die Anfrage nicht ändern, aber Sie können daraus lesen.

Flight bietet einen einfachen Weg, um Informationen über die Anfrage abzurufen. Sie können Informationen über die Anfrage mit der Methode Flight::request() abrufen. Diese Methode gibt ein Request-Objekt zurück, das Informationen über die Anfrage enthält. Sie können dieses Objekt verwenden, um Informationen über die Anfrage abzurufen, wie die URL, die Methode oder die Daten, die der Benutzer an Ihren Server gesendet hat.

Antworten

Eine Antwort ist das, was Ihr Server dem Browser eines Benutzers zurücksendet, wenn er Ihre Website besucht. Diese Antwort enthält Informationen darüber, was Ihr Server tun möchte. Zum Beispiel könnte sie Informationen darüber enthalten, welche Art von Daten Ihr Server dem Benutzer senden möchte, welche Art von Daten Ihr Server vom Benutzer erhalten möchte oder welche Art von Daten Ihr Server auf dem Computer des Benutzers speichern möchte.

Flight bietet eine einfache Möglichkeit, eine Antwort an den Browser eines Benutzers zu senden. Sie können eine Antwort mit der Methode Flight::response() senden. Diese Methode nimmt ein Response-Objekt als Argument und sendet die Antwort an den Browser des Benutzers. Sie können dieses Objekt verwenden, um eine Antwort an den Browser des Benutzers zu senden, wie HTML, JSON oder eine Datei. Flight hilft Ihnen, einige Teile der Antwort automatisch zu generieren, um die Dinge einfach zu machen, aber letztendlich haben Sie die Kontrolle darüber, was Sie dem Benutzer zurücksenden.

Learn/httpcaching

HTTP-Caching

Flight stellt eine eingebaute Unterstützung für das Caching auf HTTP-Ebene bereit. Wenn die Cache-Bedingung erfüllt ist, wird Flight eine HTTP 304 Not Modified-Antwort zurückgeben. Das nächste Mal, wenn der Client die gleiche Ressource anfordert, wird er aufgefordert, die lokal zwischengespeicherte Version zu verwenden.

Zuletzt geändert

Sie können die lastModified-Methode verwenden und einen UNIX-Zeitstempel übergeben, um das Datum und die Uhrzeit festzulegen, wann eine Seite zuletzt geändert wurde. Der Client wird weiterhin seinen Cache verwenden, bis der zuletzt geänderte Wert geändert wird.

Flight::route('/nachrichten', function () {
  Flight::lastModified(1234567890);
  echo 'Dieser Inhalt wird zwischengespeichert sein.';
});

ETag

Das Caching von ETag ist ähnlich wie Last-Modified, außer dass Sie eine beliebige ID für die Ressource angeben können:

Flight::route('/nachrichten', function () {
  Flight::etag('meine-eindeutige-id');
  echo 'Dieser Inhalt wird zwischengespeichert sein.';
});

Denken Sie daran, dass das Aufrufen von lastModified oder etag sowohl den Cache-Wert setzen als auch überprüfen wird. Wenn der Cache-Wert zwischen den Anfragen identisch ist, sendet Flight sofort eine HTTP 304-Antwort und stoppt die Verarbeitung.

Learn/responses

Antworten

Flight hilft Ihnen dabei, einen Teil der Antwortheader zu generieren, aber Sie haben die meiste Kontrolle darüber, was Sie an den Benutzer zurücksenden. Manchmal können Sie direkt auf das Response-Objekt zugreifen, aber meistens verwenden Sie die Flight-Instanz, um eine Antwort zu senden.

Senden einer einfachen Antwort

Flight verwendet ob_start(), um die Ausgabe zu puffern. Das bedeutet, Sie können echo oder print verwenden, um eine Antwort an den Benutzer zu senden und Flight wird dies erfassen und mit den entsprechenden Headern zurückschicken.


// Dies sendet "Hallo, Welt!" an den Browser des Benutzers
Flight::route('/', function() {
    echo "Hallo, Welt!";
});

// HTTP/1.1 200 OK
// Content-Type: text/html
//
// Hallo, Welt!

Alternativ können Sie auch die write() Methode aufrufen, um etwas zum Body hinzuzufügen.


// Dies sendet "Hallo, Welt!" an den Browser des Benutzers
Flight::route('/', function() {
    // ausführlich, aber manchmal sinnvoll, wenn Sie es brauchen
    Flight::response()->write("Hallo, Welt!");

    // Wenn Sie den Body, den Sie zu diesem Zeitpunkt festgelegt haben, abrufen möchten
    // können Sie das so tun
    $body = Flight::response()->getBody();
});

Statuscodes

Sie können den Statuscode der Antwort mit der status Methode festlegen:

Flight::route('/@id', function($id) {
    if($id == 123) {
        Flight::response()->status(200);
        echo "Hallo, Welt!";
    } else {
        Flight::response()->status(403);
        echo "Verboten";
    }
});

Wenn Sie den aktuellen Statuscode abrufen möchten, können Sie die status Methode ohne Argumente verwenden:

Flight::response()->status(); // 200

Ausführen eines Callbacks auf dem Antwort-Body

Sie können einen Callback auf dem Antwort-Body ausführen, indem Sie die addResponseBodyCallback Methode verwenden:

Flight::route('/benutzer', function() {
    $db = Flight::db();
    $benutzer = $db->fetchAll("SELECT * FROM benutzer");
    Flight::render('benutzer_tabelle', ['benutzer' => $benutzer]);
});

// Dies wird alle Antworten für jede Route komprimieren
Flight::response()->addResponseBodyCallback(function($body) {
    return gzencode($body, 9);
});

Sie können mehrere Callbacks hinzufügen, die in der Reihenfolge ausgeführt werden, in der sie hinzugefügt wurden. Da dies jeden callable akzeptieren kann, kann es ein Klassenarray [ $klasse, 'methode' ], ein Closure $strErsetzen = function($body) { str_replace('hallo', 'da', $body); }; oder einen Funktionsnamen 'minify' akzeptieren, wenn Sie beispielsweise eine Funktion zum Verkleinern Ihres HTML-Codes haben.

Hinweis: Routen-Callbacks funktionieren nicht, wenn Sie die flight.v2.output_buffering Konfigurationsoption verwenden.

Spezifisches Routen-Callback

Wenn Sie möchten, dass dies nur für eine bestimmte Route gilt, können Sie den Callback auch in die Route selbst einfügen:

Flight::route('/benutzer', function() {
    $db = Flight::db();
    $benutzer = $db->fetchAll("SELECT * FROM benutzer");
    Flight::render('benutzer_tabelle', ['benutzer' => $benutzer]);

    // Dies komprimiert nur die Antwort für diese Route
    Flight::response()->addResponseBodyCallback(function($body) {
        return gzencode($body, 9);
    });
});

Middleware-Option

Sie können auch Middleware verwenden, um den Callback über Middleware auf alle Routen anzuwenden:

// MinifyMiddleware.php
class MinifyMiddleware {
    public function before() {
        Flight::response()->addResponseBodyCallback(function($body) {
            // Dies ist ein 
            return $this->verkleinern($body);
        });
    }

    protected function verkleinern(string $body): string {
        // Body verkleinern
        return $body;
    }
}

// index.php
Flight::group('/benutzer', function() {
    Flight::route('', function() { /* ... */ });
    Flight::route('/@id', function($id) { /* ... */ });
}, [ new MinifyMiddleware() ]);

Festlegen eines Antwort-Headers

Sie können einen Header wie den Inhaltstyp der Antwort durch Verwendung der header Methode festlegen:


// Dies sendet "Hallo, Welt!" im Klartext an den Browser des Benutzers
Flight::route('/', function() {
    Flight::response()->header('Content-Type', 'text/plain');
    echo "Hallo, Welt!";
});

JSON

Flight bietet Unterstützung zum Senden von JSON- und JSONP-Antworten. Um eine JSON-Antwort zu senden, geben Sie einige Daten an, die in JSON kodiert werden sollen:

Flight::json(['id' => 123]);

JSON mit Statuscode

Sie können auch als zweites Argument einen Statuscode angeben:

Flight::json(['id' => 123], 201);

JSON mit Pretty Print

Sie können auch ein Argument an letzter Stelle übergeben, um das Pretty-Printing zu aktivieren:

Flight::json(['id' => 123], 200, true, 'utf-8', JSON_PRETTY_PRINT);

Wenn Sie die in Flight::json() übergebenen Optionen ändern und eine einfachere Syntax wünschen, können Sie die JSON-Methode einfach neu zuordnen:

Flight::map('json', function($daten, $code = 200, $optionen = 0) {
    Flight::_json($daten, $code, true, 'utf-8', $optionen);
}

// Und jetzt kann es so verwendet werden
Flight::json(['id' => 123], 200, JSON_PRETTY_PRINT);

JSON und Ausführung stoppen

Wenn Sie eine JSON-Antwort senden und die Ausführung stoppen möchten, können Sie die jsonHalt Methode verwenden. Dies ist nützlich für Fälle, in denen Sie möglicherweise eine Art Autorisierung überprüfen und wenn der Benutzer nicht autorisiert ist, können Sie sofort eine JSON-Antwort senden, den vorhandenen Body leeren und die Ausführung stoppen.

Flight::route('/benutzer', function() {
    $autorisiert = einigeAutorisierungsüberprüfung();
    // Überprüfen, ob der Benutzer autorisiert ist
    if($autorisiert === false) {
        Flight::jsonHalt(['fehler' => 'Unberechtigt'], 401);
    }

    // Mit dem Rest der Route fortfahren
});

JSONP

Für JSONP-Anfragen können Sie optional den Query-Parameter-Namen übergeben, den Sie verwenden, um Ihre Callback-Funktion zu definieren:

Flight::jsonp(['id' => 123], 'q');

Daher sollten Sie beim Senden einer GET-Anfrage mit ?q=my_func die Ausgabe erhalten:

my_func({"id":123});

Wenn Sie keinen Query-Parameter-Namen angeben, wird standardmäßig jsonp verwendet.

Weiterleitung zu einer anderen URL

Sie können die aktuelle Anfrage mit der redirect() Methode umleiten, indem Sie eine neue URL angeben:

Flight::redirect('/neuer/ort');

Standardmäßig sendet Flight einen HTTP 303 ("See Other")-Statuscode. Sie können optional auch einen benutzerdefinierten Code festlegen:

Flight::redirect('/neuer/ort', 401);

Stoppen

Sie können das Framework an jeder Stelle anhalten, indem Sie die halt Methode aufrufen:

Flight::halt();

Sie können auch optional einen HTTP-Statuscode und eine Nachricht angeben:

Flight::halt(200, 'Bin gleich wieder da...');

Durch den Aufruf von halt werden alle bisherigen Response-Inhalte verworfen. Wenn Sie das Framework anhalten und den aktuellen Response ausgeben möchten, verwenden Sie die stop Methode:

Flight::stop();

HTTP-Caching

Flight bietet integrierte Unterstützung für das Caching auf HTTP-Ebene. Wenn die Caching-Bedingung erfüllt ist, wird Flight eine HTTP 304 Not Modified-Antwort zurückgeben. Das nächste Mal, wenn der Client die Ressource erneut anfordert, wird er aufgefordert, seine lokal zwischengespeicherte Version zu verwenden.

Caching auf Routenebene

Wenn Sie Ihre gesamte Antwort zwischenspeichern möchten, können Sie die cache() Methode verwenden und die Zeit zum Zwischenspeichern angeben.


// Dadurch wird die Antwort für 5 Minuten zwischengespeichert
Flight::route('/neuigkeiten', function () {
  Flight::response()->cache(time() + 300);
  echo 'Dieser Inhalt wird zwischengespeichert.';
});

// Alternativ können Sie einen String verwenden, den Sie an die strtotime() Methode übergeben würden
Flight::route('/neuigkeiten', function () {
  Flight::response()->cache('+5 minutes');
  echo 'Dieser Inhalt wird zwischengespeichert.';
});

Geändert am

Sie können die lastModified Methode verwenden und einen UNIX-Zeitstempel übergeben, um das Datum und die Uhrzeit festzulegen, wann eine Seite zuletzt geändert wurde. Der Client wird weiterhin seinen Cache verwenden, bis der zuletzt geänderte Wert geändert wird.

Flight::route('/neuigkeiten', function () {
  Flight::lastModified(1234567890);
  echo 'Dieser Inhalt wird zwischengespeichert.';
});

ETag

ETag-Caching ist ähnlich wie Last-Modified, außer dass Sie eine beliebige ID für die Ressource angeben können:

Flight::route('/neuigkeiten', function () {
  Flight::etag('meine-eindeutige-id');
  echo 'Dieser Inhalt wird zwischengespeichert.';
});

Beachten Sie, dass der Aufruf von lastModified oder etag sowohl den Cache-Wert setzt als auch überprüft. Wenn der Cache-Wert zwischen den Anfragen gleich ist, sendet Flight sofort eine HTTP 304-Antwort und stoppt die Verarbeitung.

Learn/frameworkinstance

Framework-Instanz

Anstatt Flight als globale statische Klasse auszuführen, können Sie es optional als ein Objektinstanz ausführen.

require 'flight/autoload.php';

$app = Flight::app();

$app->route('/', function () {
  echo 'Hallo Welt!';
});

$app->start();

Also würden Sie anstelle des Aufrufs der statischen Methode die Instanzmethode mit demselben Namen am Engine-Objekt aufrufen.

Learn/redirects

Weiterleitungen

Sie können die aktuelle Anfrage umleiten, indem Sie die redirect Methode verwenden und eine neue URL übergeben:

Flight::redirect('/neuer/standort');

Standardmäßig sendet Flight einen HTTP-Statuscode 303. Sie können optional einen benutzerdefinierten Code setzen:

Flight::redirect('/neuer/standort', 401);

Learn/views

Ansichten

Flight bietet standardmäßig einige grundlegende Template-Funktionalitäten. Um ein Ansichts-Template anzuzeigen, rufen Sie die Methode render mit dem Namen der Template-Datei und optionalen Template-Daten auf:

Flight::render('hello.php', ['name' => 'Bob']);

Die übergebenen Template-Daten werden automatisch in das Template eingefügt und können wie eine lokale Variable referenziert werden. Template-Dateien sind einfach PHP-Dateien. Wenn der Inhalt der hello.php Template-Datei lautet:

Hallo, <?= $name ?>!

Die Ausgabe wäre:

Hallo, Bob!

Sie können auch manuell Ansichtsvariablen festlegen, indem Sie die Methode set verwenden:

Flight::view()->set('name', 'Bob');

Die Variable name ist nun in allen Ihren Ansichten verfügbar. Sie können also einfach Folgendes tun:

Flight::render('hello');

Beachten Sie, dass beim Festlegen des Namens des Templates in der Render-Methode die Dateierweiterung .php ausgelassen werden kann.

Standardmäßig sucht Flight nach einem views-Verzeichnis für Template-Dateien. Sie können einen alternativen Pfad für Ihre Templates festlegen, indem Sie die folgende Konfiguration setzen:

Flight::set('flight.views.path', '/pfad/zu/ansichten');

Layouts

Es ist üblich, dass Websites eine einzelne Layout-Template-Datei mit sich änderndem Inhalt haben. Um Inhalte zu rendern, die in einem Layout verwendet werden sollen, können Sie einen optionalen Parameter an die render-Methode übergeben.

Flight::render('header', ['heading' => 'Hallo'], 'headerContent');
Flight::render('body', ['body' => 'Welt'], 'bodyContent');

Ihre Ansicht wird dann gespeicherte Variablen namens headerContent und bodyContent haben. Sie können dann Ihr Layout rendern, indem Sie Folgendes tun:

Flight::render('layout', ['title' => 'Startseite']);

Wenn die Template-Dateien wie folgt aussehen:

header.php:

<h1><?= $heading ?></h1>

body.php:

<div><?= $body ?></div>

layout.php:

<html>
  <head>
    <title><?= $title ?></title>
  </head>
  <body>
    <?= $headerContent ?>
    <?= $bodyContent ?>
  </body>
</html>

Die Ausgabe wäre:

<html>
  <head>
    <title>Startseite</title>
  </head>
  <body>
    <h1>Hallo</h1>
    <div>Welt</div>
  </body>
</html>

Individuelle Ansichten

Flight ermöglicht es Ihnen, den Standard-View-Engine einfach durch Registrieren Ihrer eigenen View-Klasse auszutauschen. So verwenden Sie z. B. den Smarty Template-Engine für Ihre Ansichten:

// Smarty-Bibliothek laden
require './Smarty/libs/Smarty.class.php';

// Registrieren Sie Smarty als View-Klasse
// Geben Sie auch eine Rückruffunktion zum Konfigurieren von Smarty beim Laden an
Flight::register('view', Smarty::class, [], function (Smarty $smarty) {
  $smarty->setTemplateDir('./templates/');
  $smarty->setCompileDir('./templates_c/');
  $smarty->setConfigDir('./config/');
  $smarty->setCacheDir('./cache/');
});

// Template-Daten zuweisen
Flight::view()->assign('name', 'Bob');

// Template anzeigen
Flight::view()->display('hello.tpl');

Zu Ihrer Information sollten Sie auch die Standard-Rendermethode von Flight überschreiben:

Flight::map('render', function(string $template, array $data): void {
  Flight::view()->assign($data);
  Flight::view()->display($template);
});

Learn/templates

Ansichten

Flight bietet standardmäßig einige grundlegende Template-Funktionalitäten.

Wenn Sie komplexere Template-Anforderungen haben, finden Sie Beispiele für Smarty und Latte im Abschnitt Benutzerdefinierte Ansichten.

Um eine Ansichtsvorlage anzuzeigen, rufen Sie die render Methode mit dem Namen der Vorlagendatei und optionalen Vorlagedaten auf:

Flight::render('hello.php', ['name' => 'Bob']);

Die von Ihnen übergebenen Vorlagendaten werden automatisch in die Vorlage eingefügt und können wie eine lokale Variable referenziert werden. Vorlagendateien sind einfach PHP-Dateien. Wenn der Inhalt der hello.php Vorlagendatei folgendermaßen aussieht:

Hallo, <?= $name ?>!

Das Ergebnis wäre:

Hallo, Bob!

Sie können auch manuell Ansichtsvariablen festlegen, indem Sie die set Methode verwenden:

Flight::view()->set('name', 'Bob');

Die Variable name steht nun in allen Ihren Ansichten zur Verfügung. Sie können also einfach Folgendes tun:

Flight::render('hello');

Beachten Sie, dass Sie bei der Angabe des Namens der Vorlage in der render Methode die Dateierweiterung .php weglassen können.

Standardmäßig sucht Flight nach einem views-Verzeichnis für Vorlagendateien. Sie können einen alternativen Pfad für Ihre Vorlagen festlegen, indem Sie die folgende Konfiguration setzen:

Flight::set('flight.views.path', '/pfad/zur/vorlagen');

Layouts

Es ist üblich, dass Websites eine einzelne Layout-Vorlagendatei mit wechselndem Inhalt haben. Um Inhalte zu rendern, die in einem Layout verwendet werden sollen, können Sie einen optionalen Parameter an die render Methode übergeben.

Flight::render('header', ['heading' => 'Hallo'], 'headerContent');
Flight::render('body', ['body' => 'Welt'], 'bodyContent');

Ihre Ansicht wird dann gespeicherte Variablen namens headerContent und bodyContent haben. Sie können dann Ihr Layout rendern, indem Sie Folgendes tun:

Flight::render('layout', ['title' => 'Startseite']);

Wenn die Vorlagendateien wie folgt aussehen:

header.php:

<h1><?= $heading ?></h1>

body.php:

<div><?= $body ?></div>

layout.php:

<html>
  <head>
    <title><?= $title ?></title>
  </head>
  <body>
    <?= $headerContent ?>
    <?= $bodyContent ?>
  </body>
</html>

Das Ergebnis wäre:

<html>
  <head>
    <title>Startseite</title>
  </head>
  <body>
    <h1>Hallo</h1>
    <div>Welt</div>
  </body>
</html>

Benutzerdefinierte Ansichten

Flight ermöglicht es Ihnen, den Standard-View-Engine einfach zu ersetzen, indem Sie Ihre eigene View-Klasse registrieren.

Smarty

So verwenden Sie den Smarty Template-Motor für Ihre Ansichten:

// Smarty-Bibliothek laden
require './Smarty/libs/Smarty.class.php';

// Smarty als View-Klasse registrieren
// Geben Sie auch eine Rückruffunktion zur Konfiguration von Smarty beim Laden an
Flight::register('view', Smarty::class, [], function (Smarty $smarty) {
  $smarty->setTemplateDir('./templates/');
  $smarty->setCompileDir('./templates_c/');
  $smarty->setConfigDir('./config/');
  $smarty->setCacheDir('./cache/');
});

// Vorlagendaten zuweisen
Flight::view()->assign('name', 'Bob');

// Vorlage anzeigen
Flight::view()->display('hello.tpl');

Für Vollständigkeit sollten Sie auch die Standard-render Methode von Flight überschreiben:

Flight::map('render', function(string $template, array $data): void {
  Flight::view()->assign($data);
  Flight::view()->display($template);
});

Latte

So verwenden Sie den Latte Template-Motor für Ihre Ansichten:


// Latte als View-Klasse registrieren
// Geben Sie auch eine Rückruffunktion zur Konfiguration von Latte beim Laden an
Flight::register('view', Latte\Engine::class, [], function (Latte\Engine $latte) {
  // Hier werden die Latte Ihre Vorlagen zwischenspeichern, um die Geschwindigkeit zu erhöhen
    // Eine nette Eigenschaft von Latte ist, dass es automatisch Ihren Zwischenspeicher aktualisiert
    // wenn Sie Änderungen an Ihren Vorlagen vornehmen!
    $latte->setTempDirectory(__DIR__ . '/../cache/');

    // Sagen Sie Latte, wo das Stammverzeichnis für Ihre Ansichten sein wird.
    $latte->setLoader(new \Latte\Loaders\FileLoader(__DIR__ . '/../views/'));
});

// Und verpacken Sie es, damit Sie Flight::render() korrekt verwenden können
Flight::map('render', function(string $template, array $data): void {
  // Dies entspricht $latte_engine->render($template, $data);
  echo Flight::view()->render($template, $data);
});

Learn/extending

Erweiterung

Flight ist darauf ausgelegt, ein erweiterbares Framework zu sein. Das Framework wird mit einer Reihe von Standardmethoden und -komponenten geliefert, aber es ermöglicht Ihnen, Ihre eigenen Methoden zu mappen, Ihre eigenen Klassen zu registrieren oder sogar vorhandene Klassen und Methoden zu überschreiben.

Wenn Sie nach einem DIC (Dependency Injection Container) suchen, gehen Sie zur Seite des Dependency Injection Containers.

Methoden Zuordnen

Um Ihre eigene einfache benutzerdefinierte Methode zuzuordnen, verwenden Sie die map Funktion:

// Ordne deine Methode zu
Flight::map('hello', function (string $name) {
  echo "Hallo $name!";
});

// Rufen Sie Ihre benutzerdefinierte Methode auf
Flight::hello('Bob');

Dies wird häufiger verwendet, wenn Sie Variablen in Ihre Methode passen müssen, um einen erwarteten Wert zu erhalten. Die Verwendung der register() Methode wie unten ist eher für das Übergeben von Konfigurationen und das Aufrufen Ihrer vorab konfigurierten Klasse.

Klassen registrieren

Um Ihre eigene Klasse zu registrieren und zu konfigurieren, verwenden Sie die register Funktion:

// Registriere deine Klasse
Flight::register('user', User::class);

// Erhalte eine Instanz deiner Klasse
$user = Flight::user();

Die Registriermethode ermöglicht es Ihnen auch, Parameter an den Konstruktor Ihrer Klasse zu übergeben. Wenn Sie Ihre benutzerdefinierte Klasse laden, wird sie also vorinitialisiert. Sie können die Konstruktorparameter festlegen, indem Sie ein zusätzliches Array übergeben. Hier ist ein Beispiel zum Laden einer Datenbankverbindung:

// Klasse mit Konstruktorparametern registrieren
Flight::register('db', PDO::class, ['mysql:host=localhost;dbname=test', 'user', 'pass']);

// Erhalte eine Instanz deiner Klasse
// Dies wird ein Objekt mit den definierten Parametern erstellen
//
// new PDO('mysql:host=localhost;dbname=test','user','pass');
//
$db = Flight::db();

// und wenn Sie es später in Ihrem Code benötigen, rufen Sie einfach die gleiche Methode erneut auf
class SomeController {
  public function __construct() {
    $this->db = Flight::db();
  }
}

Wenn Sie einen zusätzlichen Rückrufparameter übergeben, wird dieser sofort nach dem Klassenkonstruktor ausgeführt. Dies ermöglicht es Ihnen, alle Einrichtungsverfahren für Ihr neues Objekt durchzuführen. Die Rückruffunktion nimmt einen Parameter entgegen, eine Instanz des neuen Objekts.

// Der Rückruf erhält das konstruierte Objekt
Flight::register(
  'db',
  PDO::class,
  ['mysql:host=localhost;dbname=test', 'user', 'pass'],
  function (PDO $db) {
    $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  }
);

Standardmäßig erhalten Sie jedes Mal, wenn Sie Ihre Klasse laden, eine gemeinsam genutzte Instanz. Um eine neue Instanz einer Klasse zu erhalten, geben Sie einfach false als Parameter ein:

// Gemeinsam genutzte Instanz der Klasse
$shared = Flight::db();

// Neue Instanz der Klasse
$new = Flight::db(false);

Beachten Sie, dass gemappte Methoden Vorrang vor registrierten Klassen haben. Wenn Sie beide mit demselben Namen deklarieren, wird nur die gemappte Methode aufgerufen.

Framework-Methoden überschreiben

Flight ermöglicht es Ihnen, seine Standardfunktionalität anzupassen, um Ihren eigenen Anforderungen gerecht zu werden, ohne dass Sie dabei Code ändern müssen.

Wenn Flight beispielsweise keine URL mit einer Route übereinstimmen kann, ruft es die notFound Methode auf, die eine generische HTTP 404 Antwort sendet. Sie können dieses Verhalten überschreiben, indem Sie die map Methode verwenden:

Flight::map('notFound', function() {
  // Zeige benutzerdefinierte 404 Seite an
  include 'errors/404.html';
});

Flight ermöglicht es auch, Kernkomponenten des Frameworks zu ersetzen. Zum Beispiel können Sie die Standard-Routerklasse durch Ihre eigene benutzerdefinierte Klasse ersetzen:

// Registriere deine benutzerdefinierte Klasse
Flight::register('router', MyRouter::class);

// Wenn Flight die Router-Instanz lädt, lädt es Ihre Klasse
$myrouter = Flight::router();

Framework-Methoden wie map und register können jedoch nicht überschrieben werden. Sie erhalten einen Fehler, wenn Sie dies versuchen.

Learn/json

# JSON

Flight bietet Unterstützung für das Senden von JSON- und JSONP-Antworten. Um eine JSON-Antwort zu senden, übergeben Sie einige Daten, die in JSON kodiert werden sollen:

```php
Flight::json(['id' => 123]);

Für JSONP-Anfragen können Sie optional den Abfrage-Parameter Namen angeben, den Sie verwenden, um Ihre Rückruffunktion zu definieren:

Flight::jsonp(['id' => 123], 'q');

Wenn Sie also eine GET-Anfrage mit ?q=my_func stellen, sollten Sie die Ausgabe erhalten:

my_func({"id":123});

Wenn Sie keinen Abfrageparameter Namen angeben, wird standardmäßig jsonp verwendet.

Learn/autoloading

Autoloaden

Autoloaden ist ein Konzept in PHP, bei dem Sie ein Verzeichnis oder Verzeichnisse zum Laden von Klassen angeben. Dies ist viel vorteilhafter als die Verwendung von require oder include zum Laden von Klassen. Es ist auch eine Anforderung für die Verwendung von Composer-Paketen.

Standardmäßig wird jede Flight-Klasse dank Composer automatisch für Sie autoloadet. Wenn Sie jedoch Ihre eigenen Klassen autoloaden möchten, können Sie die Methode Flight::path verwenden, um ein Verzeichnis zum Laden von Klassen anzugeben.

Grundbeispiel

Angenommen, wir haben einen Verzeichnisbaum wie folgt:

# Beispiel-Pfad
/home/user/projekt/mein-flight-projekt/
├── app
│   ├── cache
│   ├── config
│   ├── controllers - enthält die Controller für dieses Projekt
│   ├── translations
│   ├── UTILS - enthält Klassen nur für diese Anwendung (das ist absichtlich alles in Großbuchstaben für ein späteres Beispiel)
│   └── views
└── public
    └── css
    └── js
    └── index.php

Sie haben vielleicht bemerkt, dass dies die gleiche Dateistruktur wie diese Dokumentationsseite ist.

Sie können jedes zu ladende Verzeichnis wie folgt angeben:


/**
 * public/index.php
 */

// Fügen Sie einen Pfad zum Autoloader hinzu
Flight::path(__DIR__.'/../app/controllers/');
Flight::path(__DIR__.'/../app/utils/');

/**
 * app/controllers/MyController.php
 */

// kein Namespacing erforderlich

// Alle autoloadeten Klassen sollten Pascal Case sein (jedes Wort großgeschrieben, keine Leerzeichen)
// Ab Version 3.7.2 können Sie Pascal_Snake_Case für Ihre Klassennamen verwenden, indem Sie Loader::setV2ClassLoading(false); ausführen
class MyController {

    public function index() {
        // etwas tun
    }
}

Namensräume

Wenn Sie Namensräume haben, wird dies tatsächlich sehr einfach zu implementieren. Sie sollten die Methode Flight::path() verwenden, um das Stammverzeichnis (nicht das Dokument-Stammverzeichnis oder den public/-Ordner) Ihrer Anwendung anzugeben.


/**
 * public/index.php
 */

// Fügen Sie einen Pfad zum Autoloader hinzu
Flight::path(__DIR__.'/../');

So könnte Ihr Controller aussehen. Werfen Sie einen Blick auf das folgende Beispiel, achten Sie jedoch auf die Kommentare für wichtige Informationen.

/**
 * app/controllers/MyController.php
 */

// Namensräume sind erforderlich
// Namensräume entsprechen der Verzeichnisstruktur
// Namensräume müssen der Groß- und Kleinschreibung der Verzeichnisstruktur entsprechen
// Namensräume und Verzeichnisse dürfen keine Unterstriche enthalten (sofern Loader::setV2ClassLoading(false) nicht festgelegt ist)
namespace app\controllers;

// Alle autoloadeten Klassen sollten Pascal Case sein (jedes Wort großgeschrieben, keine Leerzeichen)
// Ab Version 3.7.2 können Sie Pascal_Snake_Case für Ihre Klassennamen verwenden, indem Sie Loader::setV2ClassLoading(false); ausführen
class MyController {

    public function index() {
        // etwas tun
    }
}

Und wenn Sie eine Klasse in Ihrem utils-Verzeichnis autoloaden möchten, würden Sie im Grunde dasselbe tun:


/**
 * app/UTILS/ArrayHelperUtil.php
 */

// Der Namensraum muss der Verzeichnisstruktur und der Groß- und Kleinschreibung entsprechen (beachten Sie das UTILS-Verzeichnis in Großbuchstaben
//     wie im obigen Dateibaum)
namespace app\UTILS;

class ArrayHelperUtil {

    public function changeArrayCase(array $array) {
        // etwas tun
    }
}

Unterstriche in Klassennamen

Ab Version 3.7.2 können Sie Pascal_Snake_Case für Ihre Klassennamen verwenden, indem Sie Loader::setV2ClassLoading(false); ausführen. Dadurch können Sie Unterstriche in Ihren Klassennamen verwenden. Dies wird nicht empfohlen, steht aber für diejenigen zur Verfügung, die es benötigen.


/**
 * public/index.php
 */

// Fügen Sie einen Pfad zum Autoloader hinzu
Flight::path(__DIR__.'/../app/controllers/');
Flight::path(__DIR__.'/../app/utils/');
Loader::setV2ClassLoading(false);

/**
 * app/controllers/My_Controller.php
 */

// kein Namespacing erforderlich

class My_Controller {

    public function index() {
        // etwas tun
    }
}

Learn/troubleshooting

Fehlerbehebung

Diese Seite wird Ihnen helfen, häufige Probleme zu beheben, auf die Sie stoßen können, wenn Sie Flight verwenden.

Häufige Probleme

404 Nicht gefunden oder unerwartetes Routenverhalten

Wenn Sie einen 404 Nicht gefunden Fehler sehen (aber Sie schwören beim Leben, dass er wirklich da ist und es sich nicht um einen Tippfehler handelt), könnte dies tatsächlich ein Problem damit sein, dass Sie einen Wert in Ihrem Routenendpunkt zurückgeben anstatt ihn einfach auszugeben. Der Grund dafür ist beabsichtigt, könnte aber einige Entwickler überraschen.


Flight::route('/hello', function(){
    // Dies könnte einen 404 Nicht gefunden Fehler verursachen
    return 'Hallo Welt';
});

// Was Sie wahrscheinlich wollen
Flight::route('/hello', function(){
    echo 'Hallo Welt';
});

Der Grund dafür liegt an einem speziellen Mechanismus, der in den Router eingebaut ist und die Rückgabenausgabe als Signal zum "Weiter zur nächsten Route" behandelt. Sie können das Verhalten im Abschnitt zur Routenführung nachlesen.

Install

Installation

Lade die Dateien herunter.

Wenn Sie Composer verwenden, können Sie den folgenden Befehl ausführen:

composer require flightphp/core

ODER Sie können die Dateien herunterladen direkt und sie in Ihr Webverzeichnis extrahieren.

Konfigurieren Sie Ihren Webserver.

Apache

Für Apache bearbeiten Sie Ihre .htaccess-Datei wie folgt:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]

Hinweis: Wenn Sie Flight in einem Unterverzeichnis verwenden müssen, fügen Sie die Zeile hinzu RewriteBase /subdir/ direkt nach RewriteEngine On hinzu.

Hinweis: Wenn Sie alle Serverdateien schützen möchten, wie z.B. eine db- oder env-Datei. Fügen Sie dies Ihrer .htaccess-Datei hinzu:

RewriteEngine On
RewriteRule ^(.*)$ index.php

Nginx

Für Nginx fügen Sie Folgendes zu Ihrer Serverdeklaration hinzu:

server {
  location / {
    try_files $uri $uri/ /index.php;
  }
}

Erstellen Sie Ihre index.php-Datei.

<?php

// Wenn Sie Composer verwenden, fordern Sie den Autoloader an.
require 'vendor/autoload.php';
// wenn Sie Composer nicht verwenden, laden Sie das Framework direkt
// require 'flight/Flight.php';

// Definieren Sie dann eine Route und weisen Sie eine Funktion zu, um die Anfrage zu bearbeiten.
Flight::route('/', function () {
  echo 'Hallo Welt!';
});

// Starten Sie schließlich das Framework.
Flight::start();

License

Die MIT Lizenz (MIT)

Copyright © 2023 @mikecao, @n0nag0n

Hiermit wird unentgeltlich die Erlaubnis erteilt, von jeder Person, die eine Kopie dieser Software und der zugehörigen Dokumentationsdateien (the "Software") erhält, diese Software ohne Einschränkungen zu nutzen, einschließlich, aber nicht beschränkt auf das Recht, sie zu verwenden, zu kopieren, zu modifizieren, zu fusionieren, zu veröffentlichen, zu verbreiten, unterzulizenzieren und/oder zu verkaufen Kopien der Software sowie Personen, denen die Software überlassen wird, dies unter den folgenden Bedingungen zu tun:

Der obige Urheberrechtsvermerk und dieser Genehmigungsvermerk sind in allen Kopien oder wesentlichen Teilen der Software einzubeziehen.

DIE SOFTWARE WIRD "WIE SIE IST" BEREITGESTELLT, OHNE JEGLICHE GEWÄHRLEISTUNG, AUSDRÜCKLICH ODER IMPLIZIERT, EINSCHLIESSLICH DER GEWÄHRLEISTUNG DER MARKTFÄHIGKEIT, DER EIGNUNG FÜR EINEN BESTIMMTEN ZWECK UND NICHTVERLETZUNG. UNTER KEINEN UMSTÄNDEN SIND DIE AUTOREN ODER URHEBERRECHTSINHABER HAFTBAR FÜR ANSPRÜCHE, SCHÄDEN ODER ANDERE HAFTUNG, OB IN EINER VERTRAGS- ODER DELIKTISCHE HANDLUNG, DIE AUS ODER IN VERBINDUNG MIT DER SOFTWARE ODER DER VERWENDUNG ODER ANDEREN GESCHÄFTEN IN DER SOFTWARE ENTSTEHEN.

About

Was ist Flight?

Flight ist ein schnelles, einfaches, erweiterbares Framework für PHP. Es ist ziemlich vielseitig und kann für den Aufbau beliebiger Arten von Webanwendungen verwendet werden. Es ist mit Einfachheit im Sinn aufgebaut und so geschrieben, dass es leicht zu verstehen und zu verwenden ist.

Flight ist ein großartiges Einsteiger-Framework für diejenigen, die neu in PHP sind und lernen möchten, wie man Webanwendungen erstellt. Es ist auch ein großartiges Framework für erfahrene Entwickler, die mehr Kontrolle über ihre Webanwendungen haben möchten. Es ist darauf ausgelegt, leicht eine RESTful API, eine einfache Webanwendung oder eine komplexe Webanwendung zu erstellen.

Schnellstart

<?php

// Wenn mit Composer installiert
require 'vendor/autoload.php';
// oder wenn manuell per Zip-Datei installiert
// require 'flight/Flight.php';

Flight::route('/', function() {
  echo 'Hallo Welt!';
});

Flight::route('/json', function() {
  Flight::json(['hallo' => 'Welt']);
});

Flight::start();

Einfach genug, oder? Erfahren Sie mehr über Flight in der Dokumentation!

Skelett/Vorlagen-App

Es gibt eine Beispiel-App, die Ihnen den Einstieg in das Flight Framework erleichtern kann. Gehen Sie zu flightphp/skeleton für Anweisungen zum Einstieg! Sie können auch die Beispiele Seite besuchen, um sich inspirieren zu lassen, was Sie mit Flight tun können.

Community

Wir sind auf Matrix! Chatten Sie mit uns unter #flight-php-framework:matrix.org.

Mitwirken

Es gibt zwei Möglichkeiten, wie Sie zu Flight beitragen können:

  1. Sie können zum Kernframework beitragen, indem Sie das Kern-Repository besuchen.
  2. Sie können zur Dokumentation beitragen. Diese Dokumentationswebsite wird auf Github gehostet. Wenn Sie einen Fehler bemerken oder etwas besser ausarbeiten möchten, können Sie es gerne korrigieren und einen Pull-Request einreichen! Wir bemühen uns, auf dem Laufenden zu bleiben, aber Aktualisierungen und Sprachübersetzungen sind willkommen.

Anforderungen

Flight erfordert PHP 7.4 oder höher.

Hinweis: PHP 7.4 wird unterstützt, weil zum Zeitpunkt des Schreibens (2024) PHP 7.4 die Standardversion für einige LTS-Linux-Distributionen ist. Ein erzwungener Wechsel zu PHP >8 würde für diese Benutzer viele Kopfschmerzen verursachen. Das Framework unterstützt auch PHP >8.

Lizenz

Flight wird unter der MIT Lizenz veröffentlicht.

Awesome-plugins/php_cookie

Cookies

overclokk/cookie ist eine einfache Bibliothek zum Verwalten von Cookies in Ihrer App.

Installation

Die Installation ist mit Composer einfach.

composer require overclokk/cookie

Verwendung

Die Verwendung ist so einfach wie das Registrieren einer neuen Methode in der Flight-Klasse.


use Overclokk\Cookie\Cookie;

/*
 * Setzen Sie dies in Ihrer Bootstrap- oder public/index.php-Datei
 */

Flight::register('cookie', Cookie::class);

/**
 * ExampleController.php
 */

class ExampleController {
    public function login() {
        // Setze ein Cookie

        // Sie möchten, dass dies falsch ist, damit Sie eine neue Instanz erhalten
        // verwenden Sie den folgenden Kommentar, wenn Sie eine Autovervollständigung wünschen
        /** @var \Overclokk\Cookie\Cookie $cookie */
        $cookie = Flight::cookie(false);
        $cookie->set(
            'stay_logged_in', // Name des Cookies
            '1', // der Wert, den Sie setzen möchten
            86400, // Anzahl der Sekunden, die das Cookie dauern soll
            '/', // Pfad, auf dem das Cookie verfügbar sein wird
            'example.com', // Domain, auf der das Cookie verfügbar sein wird
            true, // das Cookie wird nur über eine sichere HTTPS-Verbindung übertragen
            true // das Cookie ist nur über das HTTP-Protokoll verfügbar
        );

        // optional, wenn Sie die Standardwerte beibehalten und eine schnelle Möglichkeit haben möchten, ein Cookie lange zu setzen
        $cookie->forever('stay_logged_in', '1');
    }

    public function home() {
        // Überprüfen Sie, ob Sie das Cookie haben
        if (Flight::cookie()->has('stay_logged_in')) {
            // bringe sie z.B. in den Dashboard-Bereich.
            Flight::redirect('/dashboard');
        }
    }
}

Awesome-plugins/php_encryption

PHP-Verschlüsselung

defuse/php-encryption ist eine Bibliothek, die zum Verschlüsseln und Entschlüsseln von Daten verwendet werden kann. Das Einrichten und Starten ist ziemlich einfach, um mit der Verschlüsselung und Entschlüsselung von Daten zu beginnen. Sie haben ein großartiges Tutorial, das dabei hilft, die Grundlagen zur Verwendung der Bibliothek sowie wichtige Sicherheitsaspekte in Bezug auf Verschlüsselung zu erklären.

Installation

Die Installation ist einfach mit Composer.

composer require defuse/php-encryption

Einrichtung

Dann müssen Sie einen Verschlüsselungsschlüssel generieren.

vendor/bin/generate-defuse-key

Das wird einen Schlüssel ausgeben, den Sie sicher aufbewahren müssen. Sie könnten den Schlüssel in Ihrer app/config/config.php-Datei im Array am Ende der Datei aufbewahren. Auch wenn es nicht der perfekte Ort ist, ist es zumindest etwas.

Verwendung

Nun, da Sie die Bibliothek und einen Verschlüsselungsschlüssel haben, können Sie damit beginnen, Daten zu verschlüsseln und zu entschlüsseln.


use Defuse\Crypto\Crypto;
use Defuse\Crypto\Key;

/*
 * In Ihrer Bootstrap- oder public/index.php-Datei festlegen
 */

// Verschlüsselungsmethode
Flight::map('encrypt', function($rohdaten) {
    $verschlüsselungsschlüssel = /* $config['encryption_key'] oder ein file_get_contents davon, wo Sie den Schlüssel platziert haben */;
    return Crypto::encrypt($rohdaten, Key::loadFromAsciiSafeString($verschlüsselungsschlüssel));
});

// Entschlüsselungsmethode
Flight::map('decrypt', function($verschlüsselte_daten) {
    $verschlüsselungsschlüssel = /* $config['encryption_key'] oder ein file_get_contents davon, wo Sie den Schlüssel platziert haben */;
    try {
        $rohdaten = Crypto::decrypt($verschlüsselte_daten, Key::loadFromAsciiSafeString($verschlüsselungsschlüssel));
    } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
        // Ein Angriff! Entweder der falsche Schlüssel wurde geladen oder der Geheimtext hat sich seit seiner Erstellung geändert -- entweder in der Datenbank korrupt oder absichtlich von Eve modifiziert, um einen Angriff durchzuführen.

        // ... diesen Fall auf eine Art und Weise behandeln, die für Ihre Anwendung geeignet ist ...
    }
    return $rohdaten;
});

Flight::route('/encrypt', function() {
    $verschlüsselte_daten = Flight::encrypt('Das ist ein Geheimnis');
    echo $verschlüsselte_daten;
});

Flight::route('/decrypt', function() {
    $verschlüsselte_daten = '...'; // Verschlüsselte Daten von irgendwoher erhalten
    $entschlüsselte_daten = Flight::decrypt($verschlüsselte_daten);
    echo $entschlüsselte_daten;
});

Awesome-plugins/php_file_cache

Wruczek/PHP-File-Cache

Leichte, einfache und eigenständige PHP-In-File-Caching-Klasse

Vorteile

Installation

Installiere über Composer:

composer require wruczek/php-file-cache

Verwendung

Die Verwendung ist ziemlich einfach.

use Wruczek\PhpFileCache\PhpFileCache;

$app = Flight::app();

// Sie geben das Verzeichnis, in dem der Cache gespeichert wird, dem Konstruktor an
$app->register('cache', PhpFileCache::class, [ __DIR__ . '/../cache/' ], function(PhpFileCache $cache) {

    // Dies stellt sicher, dass der Cache nur im Produktionsmodus verwendet wird
    // UMGEBUNG ist eine Konstante, die in Ihrer Startdatei oder an anderer Stelle in Ihrer App festgelegt ist
    $cache->setDevMode(ENVIRONMENT === 'development');
});

Dann können Sie es in Ihrem Code wie folgt verwenden:


// Cache-Instanz abrufen
$cache = Flight::cache();
$data = $cache->refreshIfExpired('simple-cache-test', function () {
    return date("H:i:s"); // Daten zurückgeben, die zwischengespeichert werden sollen
}, 10); // 10 Sekunden

// oder
$data = $cache->retrieve('simple-cache-test');
if(empty($data)) {
    $data = date("H:i:s");
    $cache->store('simple-cache-test', $data, 10); // 10 Sekunden
}

Dokumentation

Besuchen Sie https://github.com/Wruczek/PHP-File-Cache für die vollständige Dokumentation und stellen Sie sicher, dass Sie den Beispiele Ordner ansehen.

Awesome-plugins/index

Tolle Plugins

Flight ist unglaublich erweiterbar. Es gibt eine Reihe von Plugins, die dazu verwendet werden können, Funktionalitäten Ihrer Flight-Anwendung hinzuzufügen. Einige werden offiziell vom Flight-Team unterstützt, während andere Mikro-/Lite-Bibliotheken sind, um Ihnen den Einstieg zu erleichtern.

Caching

Caching ist ein großartiger Weg, um Ihre Anwendung zu beschleunigen. Es gibt einige Caching-Bibliotheken, die mit Flight verwendet werden können.

Debugging

Debugging ist entscheidend, wenn Sie in Ihrer lokalen Umgebung entwickeln. Es gibt einige Plugins, die Ihr Debugging-Erlebnis verbessern können.

Datenbanken

Datenbanken sind das Herzstück vieler Anwendungen. So speichern und abrufen Sie Daten. Einige Datenbank-Bibliotheken sind einfach Wrapper zum Schreiben von Abfragen, während andere vollwertige ORMs sind.

Sitzung

Sitzungen sind nicht wirklich nützlich für APIs, aber beim Erstellen einer Webanwendung können Sitzungen wichtig sein, um Zustands- und Anmeldeinformationen zu speichern.

Templating

Templates sind für jede Webanwendung mit einer Benutzeroberfläche unerlässlich. Es gibt eine Reihe von Templating-Engines, die mit Flight verwendet werden können.

Mitwirken

Haben Sie ein Plugin, das Sie teilen möchten? Senden Sie einen Pull-Request, um es der Liste hinzuzufügen!

Awesome-plugins/pdo_wrapper

PdoWrapper PDO Helper Klasse

Flight wird mit einer Hilfsklasse für PDO geliefert. Es ermöglicht Ihnen, Ihre Datenbank leicht abzufragen mit all dem vorbereiteten / ausführen / fetchAll () Wahnsinn. Es vereinfacht erheblich, wie Sie können Ihre Datenbank abfragen. Jedes Zeilenergebnis wird als Flight Collection-Klasse zurückgegeben, die ermöglicht es Ihnen, auf Ihre Daten über Array-Syntax oder Objektsyntax zuzugreifen.

Registrieren der PDO Helper Klasse

// Registrieren Sie die PDO-Hilfsklasse
Flight::register('db', \flight\database\PdoWrapper::class, ['mysql:host=localhost;dbname=cool_db_name', 'user', 'pass', [
        PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'utf8mb4\'',
        PDO::ATTR_EMULATE_PREPARES => false,
        PDO::ATTR_STRINGIFY_FETCHES => false,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
    ]
]);

Verwendung

Dieses Objekt erweitert PDO, so dass alle normalen PDO-Methoden verfügbar sind. Die folgenden Methoden werden hinzugefügt, um das Abfragen der Datenbank zu erleichtern:

runQuery(string $sql, array $params = []): PDOStatement

Verwenden Sie dies für INSERTS, UPDATES oder wenn Sie planen, ein SELECT in einer Schleife zu verwenden

$db = Flight::db();
$statement = $db->runQuery("SELECT * FROM table WHERE something = ?", [ $something ]);
while($row = $statement->fetch()) {
    // ...
}

// Oder Schreiben in die Datenbank
$db->runQuery("INSERT INTO table (name) VALUES (?)", [ $name ]);
$db->runQuery("UPDATE table SET name = ? WHERE id = ?", [ $name, $id ]);

fetchField(string $sql, array $params = []): mixed

Holt das erste Feld aus der Abfrage

$db = Flight::db();
$count = $db->fetchField("SELECT COUNT(*) FROM table WHERE something = ?", [ $something ]);

fetchRow(string $sql, array $params = []): array

Holt eine Zeile aus der Abfrage

$db = Flight::db();
$row = $db->fetchRow("SELECT id, name FROM table WHERE id = ?", [ $id ]);
echo $row['name'];
// oder
echo $row->name;

fetchAll(string $sql, array $params = []): array

Holt alle Zeilen aus der Abfrage

$db = Flight::db();
$rows = $db->fetchAll("SELECT id, name FROM table WHERE something = ?", [ $something ]);
foreach($rows as $row) {
    echo $row['name'];
    // oder
    echo $row->name;
}

Hinweis zur IN() Syntax

Hierfür gibt es auch ein hilfreiches Wrapper für IN()-Anweisungen. Sie können einfach ein einzelnes Fragezeichen als Platzhalter für IN() übergeben und dann ein Array von Werten. Hier ist ein Beispiel dafür, wie das aussehen könnte:

$db = Flight::db();
$name = 'Bob';
$company_ids = [1,2,3,4,5];
$rows = $db->fetchAll("SELECT id, name FROM table WHERE name = ? AND company_id IN (?)", [ $name, $company_ids ]);

Vollständiges Beispiel

// Beispielroute und wie Sie diesen Wrapper verwenden würden
Flight::route('/benutzer', function () {
    // Holen Sie sich alle Benutzer
    $users = Flight::db()->fetchAll('SELECT * FROM users');

    // Streamen Sie alle Benutzer
    $statement = Flight::db()->runQuery('SELECT * FROM users');
    while ($user = $statement->fetch()) {
        echo $user['name'];
        // oder echo $user->name;
    }

    // Holen Sie sich einen einzelnen Benutzer
    $user = Flight::db()->fetchRow('SELECT * FROM users WHERE id = ?', [123]);

    // Holen Sie sich einen einzelnen Wert
    $count = Flight::db()->fetchField('SELECT COUNT(*) FROM users');

    // Besondere IN()-Syntax zur Unterstützung (stellen Sie sicher, dass IN großgeschrieben ist)
    $users = Flight::db()->fetchAll('SELECT * FROM users WHERE id IN (?)', [[1,2,3,4,5]]);
    // Sie könnten auch dies tun
    $users = Flight::db()->fetchAll('SELECT * FROM users WHERE id IN (?)', [ '1,2,3,4,5']);

    // Fügen Sie einen neuen Benutzer ein
    Flight::db()->runQuery("INSERT INTO users (name, email) VALUES (?, ?)", ['Bob', 'bob@example.com']);
    $insert_id = Flight::db()->lastInsertId();

    // Aktualisieren Sie einen Benutzer
    Flight::db()->runQuery("UPDATE users SET name = ? WHERE id = ?", ['Bob', 123]);

    // Löschen eines Benutzers
    Flight::db()->runQuery("DELETE FROM users WHERE id = ?", [123]);

    // Abrufen der Anzahl der betroffenen Zeilen
    $statement = Flight::db()->runQuery("UPDATE users SET name = ? WHERE name = ?", ['Bob', 'Sally']);
    $affected_rows = $statement->rowCount();

});

Awesome-plugins/session

Ghostff/Session

PHP-Sitzungsmanager (nicht blockierend, Flash, Segment, Sitzungsverschlüsselung). Verwendet PHP open_ssl für die optionale Verschlüsselung/Entschlüsselung von Sitzungsdaten. Unterstützt Datei, MySQL, Redis und Memcached.

Installation

Installiere es mit Composer.

composer require ghostff/session

Grundkonfiguration

Sie müssen nichts übergeben, um die Standardeinstellungen für Ihre Sitzung zu verwenden. Weitere Einstellungen findest du in der Github Readme.


use Ghostff\Session\Session;

require 'vendor/autoload.php';

$app = Flight::app();

$app->register('session', Session::class);

// Etwas, an das man sich erinnern sollte, ist, dass Sie Ihre Sitzung bei jedem Laden der Seite bestätigen müssen
// oder Sie müssen auto_commit in Ihrer Konfiguration ausführen.

Einfaches Beispiel

Hier ist ein einfaches Beispiel, wie du das verwenden könntest.

Flight::route('POST /login', function() {
    $session = Flight::session();

    // Führen Sie hier Ihre Anmelde-Logik aus
    // Passwort validieren, usw.

    // Wenn die Anmeldung erfolgreich ist
    $session->set('is_logged_in', true);
    $session->set('user', $user);

    // Jedes Mal, wenn Sie auf die Sitzung schreiben, müssen Sie sie bewusst bestätigen.
    $session->commit();
});

// Diese Überprüfung könnte in der Logik der eingeschränkten Seite sein oder mit Middleware umgeben sein.
Flight::route('/some-restricted-page', function() {
    $session = Flight::session();

    if(!$session->get('is_logged_in')) {
        Flight::redirect('/login');
    }

    // Führen Sie hier Ihre Logik für eingeschränkte Seiten aus
});

// Die Version mit Middleware
Flight::route('/some-restricted-page', function() {
    // Normale Seitenlogik
})->addMiddleware(function() {
    $session = Flight::session();

    if(!$session->get('is_logged_in')) {
        Flight::redirect('/login');
    }
});

Komplexeres Beispiel

Hier ist ein komplexeres Beispiel, wie du das verwenden könntest.


use Ghostff\Session\Session;

require 'vendor/autoload.php';

$app = Flight::app();

// Legen Sie einen benutzerdefinierten Pfad für Ihre Sitzungskonfigurationsdatei fest und geben Sie eine Zufallszeichenfolge für die Sitzungs-ID an
$app->register('session', Session::class, [ 'pfad/zur/session_config.php', bin2hex(random_bytes(32)) ], function(Session $session) {
        // oder Sie können manuell Konfigurationsoptionen überschreiben
        $session->updateConfiguration([
            // Wenn Sie Ihre Sitzungsdaten in einer Datenbank speichern möchten (gut, wenn Sie etwas wie "Melden Sie mich von allen Geräten ab" möchten)
            Session::CONFIG_DRIVER        => Ghostff\Session\Drivers\MySql::class,
            Session::CONFIG_ENCRYPT_DATA  => true,
            Session::CONFIG_SALT_KEY      => hash('sha256', 'mein-super-GEHEIME-salt'), // bitte ändern Sie dies in etwas anderes
            Session::CONFIG_AUTO_COMMIT   => true, // tun Sie dies nur, wenn es erforderlich ist oder es schwierig ist, Ihre Sitzung mit commit() zu bestätigen.
                                                   // zusätzlich könnten Sie Flight::after('start', function() { Flight::session()->commit(); }); ausführen
            Session::CONFIG_MYSQL_DS         => [
                'driver'    => 'mysql',             # Datenbanktreiber für PDO dns zB(mysql:host=...;dbname=...)
                'host'      => '127.0.0.1',         # Datenbankhost
                'db_name'   => 'meine_app-datenbank',   # Datenbankname
                'db_table'  => 'sitzungen',          # Datenbanktabelle
                'db_user'   => 'root',              # Datenbankbenutzername
                'db_pass'   => '',                  # Datenbankpasswort
                'persistent_conn'=> false,          # Vermeiden Sie den Overhead beim Herstellen einer neuen Verbindung jedes Mal, wenn ein Skript mit einer Datenbank kommunizieren muss, was zu einer schnelleren Webanwendung führt. FINDEN SIE DIE RÜCKSEITE SELBST HERAUS
            ]
        ]);
    }
);

Hilfe! Meine Sitzungsdaten bleiben nicht erhalten!

Hast du deine Sitzungsdaten gesetzt und sie bleiben nicht zwischen Anfragen erhalten? Du hast vielleicht vergessen, deine Sitzungsdaten zu bestätigen. Dies kannst du tun, indem du $session->commit() aufrufst, nachdem du deine Sitzungsdaten gesetzt hast.

Flight::route('POST /login', function() {
    $session = Flight::session();

    // Führen Sie hier Ihre Anmelde-Logik aus
    // Passwort validieren, usw.

    // Wenn die Anmeldung erfolgreich ist
    $session->set('is_logged_in', true);
    $session->set('user', $user);

    // Jedes Mal, wenn Sie auf die Sitzung schreiben, müssen Sie sie bewusst bestätigen.
    $session->commit();
});

Der andere Weg dies zu umgehen ist, wenn Sie Ihren Sitzungsdienst einrichten, müssen Sie auto_commit auf true in Ihrer Konfiguration setzen. Dies wird automatisch Ihre Sitzungsdaten nach jeder Anfrage bestätigen.


$app->register('session', Session::class, [ 'pfad/zur/session_config.php', bin2hex(random_bytes(32)) ], function(Session $session) {
        $session->updateConfiguration([
            Session::CONFIG_AUTO_COMMIT   => true,
        ]);
    }
);

Zusätzlich könnten Sie Flight::after('start', function() { Flight::session()->commit(); }); ausführen, um Ihre Sitzungsdaten nach jeder Anfrage zu bestätigen.

Dokumentation

Besuche die Github Readme für die vollständige Dokumentation. Die Konfigurationsoptionen sind im default_config.php selbst gut dokumentiert. Der Code ist einfach zu verstehen, wenn du das Paket selbst durchsuchen möchtest.

Awesome-plugins/runway

Startbahn

Startbahn ist eine CLI-Anwendung, die Ihnen hilft, Ihre Flight-Anwendungen zu verwalten. Sie kann Controller generieren, alle Routen anzeigen und mehr. Basierend auf der ausgezeichneten adhocore/php-cli Bibliothek.

Installation

Installieren Sie es mit Composer.

composer require flightphp/runway

Grundlegende Konfiguration

Beim ersten Start von Startbahn wird es Sie durch einen Einrichtungsprozess führen und eine .runway.json Konfigurationsdatei im Stammverzeichnis Ihres Projekts erstellen. Diese Datei enthält einige notwendige Konfigurationen, damit Startbahn ordnungsgemäß funktioniert.

Verwendung

Startbahn verfügt über mehrere Befehle, die Sie verwenden können, um Ihre Flight-Anwendung zu verwalten. Es gibt zwei einfache Möglichkeiten, Startbahn zu verwenden.

  1. Wenn Sie das Grundgerüstprojekt verwenden, können Sie php runway [Befehl] im Stammverzeichnis Ihres Projekts ausführen.
  2. Wenn Sie Startbahn als Paket installiert haben, können Sie vendor/bin/runway [Befehl] im Stammverzeichnis Ihres Projekts ausführen.

Für jeden Befehl können Sie die --help-Flagge angeben, um weitere Informationen zur Verwendung des Befehls zu erhalten.

php runway routes --help

Hier sind ein paar Beispiele:

Einen Controller generieren

Basierend auf der Konfiguration in Ihrer .runway.json Datei wird standardmäßig ein Controller für Sie im Verzeichnis app/controllers/ generiert.

php runway make:controller MeinController

Ein Active Record Model generieren

Basierend auf der Konfiguration in Ihrer .runway.json Datei wird standardmäßig ein Active Record Model für Sie im Verzeichnis app/records/ generiert.

php runway make:record benutzer

Wenn Sie beispielsweise die benutzer Tabelle mit dem folgenden Schema haben: id, name, email, erstellt_am, aktualisiert_am, wird eine Datei ähnlich der folgenden im app/records/BenutzerRecord.php erstellt:

<?php

declare(strict_types=1);

namespace app\records;

/**
 * ActiveRecord-Klasse für die Benutzertabelle.
 * @link https://docs.flightphp.com/awesome-plugins/active-record
 * 
 * @property int $id
 * @property string $name
 * @property string $email
 * @property string $created_at
 * @property string $updated_at
 */
class BenutzerRecord extends \flight\ActiveRecord
{
    /**
     * @var array $relations Legt die Beziehungen für das Modell fest
     *   https://docs.flightphp.com/awesome-plugins/active-record#relationships
     */
    protected array $relations = [];

    /**
     * Konstruktor
     * @param mixed $databaseConnection Die Verbindung zur Datenbank
     */
    public function __construct($databaseConnection)
    {
        parent::__construct($databaseConnection, 'benutzer');
    }
}

Alle Routen anzeigen

Dies zeigt alle Routen an, die derzeit bei Flight registriert sind.

php runway routes

Wenn Sie nur bestimmte Routen anzeigen möchten, können Sie eine Flagge angeben, um die Routen zu filtern.

# Zeige nur GET-Routen an
php runway routes --get

# Zeige nur POST-Routen an
php runway routes --post

# usw.

Anpassen von Startbahn

Wenn Sie ein Paket für Flight erstellen oder Ihre eigenen benutzerdefinierten Befehle in Ihr Projekt aufnehmen möchten, können Sie ein src/commands/, flight/commands/, app/commands/ oder commands/ Verzeichnis für Ihr Projekt/Paket erstellen.

Um einen Befehl zu erstellen, erweitern Sie einfach die Klasse AbstractBaseCommand und implementieren Sie mindestens eine __construct-Methode und eine execute-Methode.

<?php

declare(strict_types=1);

namespace flight\commands;

class BeispielBefehl extends AbstractBaseCommand
{
    /**
     * Konstruieren
     *
     * @param array<string,mixed> $config JSON-Konfiguration aus .runway-config.json
     */
    public function __construct(array $config)
    {
        parent::__construct('make:beispiel', 'Erstellt ein Beispiel für die Dokumentation', $config);
        $this->argument('<lustiges-gif>', 'Der Name des lustigen Gifs');
    }

    /**
     * Führt die Funktion aus
     *
     * @return void
     */
    public function execute(string $controller)
    {
        $io = $this->app()->io();

        $io->info('Beispiel wird erstellt...');

        // Hier etwas tun

        $io->ok('Beispiel erstellt!');
    }
}

Siehe die adhocore/php-cli Dokumentation für weitere Informationen darüber, wie Sie Ihre eigenen benutzerdefinierten Befehle in Ihre Flight-Anwendung integrieren können!

Awesome-plugins/tracy_extensions

Tracy Flight Panel-Erweiterungen

Dies ist ein Satz von Erweiterungen, um die Arbeit mit Flight etwas komfortabler zu gestalten.

Dies ist das Panel

Flight-Leiste

Und jedes Panel zeigt sehr hilfreiche Informationen über Ihre Anwendung an!

Flight-Daten Flight-Datenbank Flight-Anfrage

Installation

Führen Sie composer require flightphp/tracy-extensions --dev aus und los geht's!

Konfiguration

Es ist sehr wenig Konfiguration erforderlich, um dies zu starten. Sie müssen den Tracy-Debugger initialisieren, bevor Sie dies verwenden https://tracy.nette.org/en/guide:

<?php

use Tracy\Debugger;
use flight\debug\tracy\TracyExtensionLoader;

// Bootstrap-Code
require __DIR__ . '/vendor/autoload.php';

Debugger::enable();
// Möglicherweise müssen Sie Ihre Umgebung mit Debugger::enable(Debugger::DEVELOPMENT) angeben

// Wenn Sie Datenbankverbindungen in Ihrer App verwenden, gibt es
// einen erforderlichen PDO-Wrapper, der NUR IN DER ENTWICKLUNG verwendet werden sollte (bitte nicht in der Produktion!)
// Er hat dieselben Parameter wie eine reguläre PDO-Verbindung
$pdo = new PdoQueryCapture('sqlite:test.db', 'user', 'pass');
// oder wenn Sie dies an das Flight-Framework anhängen
Flight::register('db', PdoQueryCapture::class, ['sqlite:test.db', 'user', 'pass']);
// Jetzt werden bei jeder Abfrage die Zeit, die Abfrage und die Parameter erfasst

// Dies verbindet die Punkte
if(Debugger::$showBar === true) {
    // Dies muss false sein, damit Tracy tatsächlich gerendert werden kann :(
    Flight::set('flight.content_length', false);
    new TracyExtensionLoader(Flight::app());
}

// mehr Code

Flight::start();

Zusätzliche Konfiguration

Sitzungsdaten

Wenn Sie einen benutzerdefinierten Sitzungshandler haben (wie ghostff/session), können Sie beliebige Sitzungsdatenarrays an Tracy übergeben, und es gibt sie automatisch für Sie aus. Sie geben es mit dem session_data-Schlüssel im zweiten Parameter des Konstruktors von TracyExtensionLoader an.


use Ghostff\Session\Session;

require 'vendor/autoload.php';

$app = Flight::app();

$app->register('session', Session::class);

if(Debugger::$showBar === true) {
    // Dies muss false sein, damit Tracy tatsächlich gerendert werden kann :(
    Flight::set('flight.content_length', false);
    new TracyExtensionLoader(Flight::app(), [ 'session_data' => Flight::session()->getAll() ]);
}

// Routen und andere Dinge...

Flight::start();

Latte

Wenn Sie Latte in Ihrem Projekt installiert haben, können Sie das Latte-Panel verwenden, um Ihre Vorlagen zu analysieren. Sie können die Latte-Instanz mit dem latte-Schlüssel im zweiten Parameter des TracyExtensionLoader-Konstruktors übergeben.



use Latte\Engine;

require 'vendor/autoload.php';

$app = Flight::app();

$app->register('latte', Engine::class, [], function($latte) {
    $latte->setTempDirectory(__DIR__ . '/temp');

    // Hier fügen Sie das Latte-Panel zu Tracy hinzu
    $latte->addExtension(new Latte\Bridges\Tracy\TracyExtension);
});

if(Debugger::$showBar === true) {
    // Dies muss false sein, damit Tracy tatsächlich gerendert werden kann :(
    Flight::set('flight.content_length', false);
    new TracyExtensionLoader(Flight::app());
}

Awesome-plugins/tracy

Tracy

Tracy ist ein erstaunlicher Fehlerhandler, der mit Flight verwendet werden kann. Es verfügt über eine Reihe von Panels, die Ihnen bei der Fehlerbehebung Ihrer Anwendung helfen können. Es ist auch sehr einfach zu erweitern und eigene Panels hinzuzufügen. Das Flight-Team hat speziell für Flight-Projekte mit dem flightphp/tracy-extensions Plugin einige Panels erstellt.

Installation

Installiere es mit Composer. Und in der Tat möchten Sie dies ohne die Entwicklerversion installieren, da Tracy mit einem Produktionsfehlerbehandlungskomponente geliefert wird.

composer require tracy/tracy

Grundkonfiguration

Es gibt einige grundlegende Konfigurationsoptionen, um loszulegen. Weitere Informationen dazu finden Sie in der Tracy-Dokumentation.


require 'vendor/autoload.php';

use Tracy\Debugger;

// Aktiviere Tracy
Debugger::enable();
// Debugger::enable(Debugger::DEVELOPMENT) // Manchmal müssen Sie explizit sein (auch Debugger::PRODUCTION)
// Debugger::enable('23.75.345.200'); // Sie können auch ein Array von IP-Adressen bereitstellen

// Hier werden Fehler und Ausnahmen protokolliert. Stellen Sie sicher, dass dieses Verzeichnis vorhanden ist und beschreibbar ist.
Debugger::$logDirectory = __DIR__ . '/../log/';
Debugger::$strictMode = true; // alle Fehler anzeigen
// Debugger::$strictMode = E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED; // alle Fehler außer veralteten Hinweisen
if (Debugger::$showBar) {
    $app->set('flight.content_length', false); // Wenn die Debugger-Leiste sichtbar ist, kann die Inhaltslänge nicht von Flight festgelegt werden

    // Dies ist spezifisch für die Tracy-Erweiterung für Flight, wenn Sie diese eingeschlossen haben
    // Andernfalls kommentieren Sie dies aus.
    new TracyExtensionLoader($app);
}

Hilfreiche Tipps

Wenn Sie Ihren Code debuggen, gibt es einige sehr hilfreiche Funktionen, um Daten für Sie auszugeben.

Awesome-plugins/active_record

Flight Aktivdatensatz

Ein aktivdatensatz ordnet eine Datenbankeinheit einem PHP-Objekt zu. Einfach ausgedrückt, wenn Sie eine Benutzertabelle in Ihrer Datenbank haben, können Sie eine Zeile in dieser Tabelle in eine User-Klasse und ein $user-Objekt in Ihrem Code umwandeln. Siehe grundlegendes Beispiel.

Grundlegendes Beispiel

Angenommen, Sie haben die folgende Tabelle:

CREATE TABLE users (
    id INTEGER PRIMARY KEY, 
    name TEXT, 
    password TEXT 
);

Sie können jetzt eine neue Klasse einrichten, um diese Tabelle zu repräsentieren:

/**
 * Eine Aktivdatensatzklasse ist in der Regel im Singular
 * 
 * Es wird dringend empfohlen, die Eigenschaften der Tabelle als Kommentare hier hinzuzufügen
 * 
 * @property int    $id
 * @property string $name
 * @property string $password
 */ 
class Benutzer erstreckt sich flight\ActiveRecord {
    public Funktion __construct($datenbank_verbindung)
    {
        // Sie können es auf diese Weise einstellen
        Elternteil::__construct($datenbank_verbindung, 'users');
        // oder auf diese Weise
        Elternteil::__construct($datenbank_verbindung, null, [ 'table' => 'users']);
    }
}

Nun lass die Magie passieren!

// für sqlite
$database_verbindung = neue PDO('sqlite:test.db'); // das dient nur als Beispiel, wahrscheinlich würden Sie eine echte Datenbankverbindung verwenden

// für mysql
$database_verbindung = neue PDO('mysql:host=localhost;dbname=test_db&charset=utf8bm4', 'benutzername', 'passwort');

// oder mysqli
$database_verbindung = neue mysqli('localhost', 'benutzername', 'passwort', 'test_db');
// oder mysqli mit nicht objektbasierter Erstellung
$database_verbindung = mysqli_connect('localhost', 'benutzername', 'passwort', 'test_db');

$benutzer = neue Benutzer($database_verbindung);
$benutzer->name = 'Bobby Tables';
$benutzer->password = password_hash('ein cooles Passwort');
$benutzer->einfügen();
// oder $benutzer->speichern();

echo $benutzer->id; // 1

$benutzer->name = 'Joseph Mamma';
$benutzer->password = password_hash('nochmal ein cooles Passwort!!!');
$benutzer->einfügen();
// Hier kann $benutzer->speichern() nicht verwendet werden, da es denkt, es handle sich um ein Update!

echo $benutzer->id; // 2

Und es war so einfach, einen neuen Benutzer hinzuzufügen! Jetzt, da es eine Benutzerzeile in der Datenbank gibt, wie holen Sie sie heraus?

$benutzer->find(1); // Suche nach id = 1 in der Datenbank und gib sie zurück.
echo $benutzer->name; // 'Bobby Tables'

Und wenn Sie alle Benutzer finden möchten?

$benutzer = $benutzer->findAll();

Was ist mit einer bestimmten Bedingung?

$benutzer = $benutzer->like('name', '%mamma%')->findAll();

Siehst du, wie viel Spaß das macht? Lass uns es installieren und loslegen!

Installation

Einfach mit Composer installieren

composer require flightphp/active-record 

Verwendung

Dies kann als eigenständige Bibliothek oder mit dem Flight PHP Framework verwendet werden. Ganz wie Sie möchten.

Eigenständig

Stellen Sie einfach sicher, dass Sie eine PDO-Verbindung an den Konstruktor übergeben.

$pdo_verbindung = neue PDO('sqlite:test.db'); // das ist nur ein Beispiel, Sie würden wahrscheinlich eine echte Datenbankverbindung verwenden

$Benutzer = neue Benutzer($pdo_verbindung);

Flight PHP Framework

Wenn Sie das Flight PHP Framework verwenden, können Sie die ActiveRecord-Klasse als Dienst registrieren (müssen Sie jedoch ehrlich gesagt nicht).

Flight::register('benutzer', 'Benutzer', [ $pdo_verbindung ]);

// dann können Sie es in einem Controller, einer Funktion usw. so verwenden

Flight::benutzer()->find(1);

CRUD-Funktionen

find($id = null) : boolean|ActiveRecord

Suchen Sie einen Datensatz und weisen Sie ihn dem aktuellen Objekt zu. Wenn Sie eine $id von irgendeiner Art übergeben, wird eine Abfrage auf dem Primärschlüssel mit diesem Wert durchgeführt. Wenn nichts übergeben wird, wird einfach der erste Datensatz in der Tabelle gefunden.

Zusätzlich können Sie ihm andere Hilfsmethoden übergeben, um Ihre Tabelle abzufragen.

// suchen Sie einen Datensatz mit einigen Bedingungen im Voraus
$benutzer->notNull('password')->orderBy('id DESC')->find();

// finden Sie einen Datensatz mit einer bestimmten id
$id = 123;
$benutzer->find($id);

findAll(): array<int,ActiveRecord>

Finden Sie alle Datensätze in der von Ihnen angegebenen Tabelle.

$benutzer->findAll();

isHydrated(): boolean (v0.4.0)

Gibt true zurück, wenn der aktuelle Datensatz geholt wurde (aus der Datenbank abgerufen).

$benutzer->find(1);
// wenn ein Datensatz mit Daten gefunden wird...
$benutzer->isHydrated(); // true

insert(): boolean|ActiveRecord

Fügt den aktuellen Datensatz in die Datenbank ein.

$benutzer = neue Benutzer($pdo_verbindung);
$benutzer->name = 'demo';
$benutzer->password = md5('demo');
$benutzer->einfügen();
Textbasierte Primärschlüssel

Wenn Sie einen textbasierten Primärschlüssel haben (wie z.B. eine UUID), können Sie den Primärschlüsselwert vor dem Einfügen auf zwei Arten festlegen.

$benutzer = neue Benutzer($pdo_verbindung, [ 'primaryKey' => 'uuid' ]);
$benutzer->uuid = 'some-uuid';
$benutzer->name = 'demo';
$benutzer->password = md5('demo');
$benutzer->einfügen(); // oder $benutzer->speichern();

oder Sie können den Primärschlüssel automatisch für Sie generieren lassen durch Ereignisse.

class Benutzer erstreckt flight\ActiveRecord {
    public Funktion __construct($datenbank_verbindung)
    {
        Elternteil::__construct($datenbank_verbindung, 'users', [ 'primaryKey' => 'uuid' ]);
        // Sie können den Primärschlüssel auch auf diese Weise setzen, anstatt des obigen Arrays.
        $this->primaryKey = 'uuid';
    }

    protected Funktion beforeInsert(self $self) {
        $self->uuid = uniqid(); // oder wie auch immer Sie Ihre eindeutigen IDs generieren müssen
    }
}

Wenn Sie den Primärschlüssel vor dem Einfügen nicht setzen, wird der rowid eingestellt und die Datenbank generiert ihn für Sie, aber er wird nicht persistiert, weil dieses Feld in Ihrer Tabelle möglicherweise nicht existiert. Deshalb wird empfohlen, das Ereignis zu verwenden, um dies automatisch für Sie zu übernehmen.

update(): boolean|ActiveRecord

Aktualisiert den aktuellen Datensatz in der Datenbank.

$benutzer->greaterThan('id', 0)->orderBy('id desc')->find();
$benutzer->email = 'test@example.com';
$benutzer->update();

save(): boolean|ActiveRecord

Fügt den aktuellen Datensatz in die Datenbank ein oder aktualisiert ihn. Wenn der Datensatz eine id hat, wird er aktualisiert, sonst wird er eingefügt.

$benutzer = neue Benutzer($pdo_verbindung);
$benutzer->name = 'demo';
$benutzer->password = md5('demo');
$benutzer->save();

Hinweis: Wenn Sie Beziehungen in der Klasse definiert haben, werden diese Beziehungen rekursiv gespeichert, wenn sie definiert, instanziert und schmutzige Daten zum Aktualisieren haben. (v0.4.0 und höher)

delete(): boolean

Löscht den aktuellen Datensatz aus der Datenbank.

$benutzer->gt('id', 0)->orderBy('id desc')->find();
$benutzer->delete();

Sie können auch mehrere Datensätze löschen, indem Sie zuerst eine Abfrage ausführen.

$benutzer->like('name', 'Bob%')->delete();

dirty(array $dirty = []): ActiveRecord

Schmutzige Daten beziehen sich auf die Daten, die in einem Datensatz geändert wurden.

$benutzer->greaterThan('id', 0)->orderBy('id desc')->find();

// bisher ist nichts "schmutzig".

$benutzer->email = 'test@example.com'; // jetzt wird die E-Mail-Adresse als "schmutzig" betrachtet, da sie geändert wurde.
$benutzer->update();
// jetzt gibt es keine schmutzigen Daten mehr, weil sie aktualisiert und in der Datenbank gespeichert wurden

$benutzer->password = password_hash()'neuespasswort'); // jetzt ist dies schmutzig
$benutzer->schmutzig(); // Wenn nichts übergeben wird, werden alle schmutzigen Einträge gelöscht.
$benutzer->update(); // nichts wird aktualisiert, da nichts als schmutzig erfasst wurde.

$benutzer->dirty([ 'name' => 'etwas', 'password' => password_hash('ein anderes Passwort') ]);
$benutzer->update(); // sowohl Name als auch Passwort werden aktualisiert.

copyFrom(array $data): ActiveRecord (v0.4.0)

Dies ist ein Alias für die Methode dirty(). Es ist etwas klarer, was Sie tun.

$benutzer->copyFrom([ 'name' => 'etwas', 'password' => password_hash('ein anderes Passwort') ]);
$benutzer->update(); // sowohl Name als auch Passwort werden aktualisiert.

isDirty(): boolean (v0.4.0)

Gibt true zurück, wenn der aktuelle Datensatz geändert wurde.

$benutzer->greaterThan('id', 0)->orderBy('id desc')->find();
$benutzer->email = 'test@email.com';
$benutzer->isDirty(); // true

reset(bool $include_query_data = true): ActiveRecord

Setzt den aktuellen Datensatz auf seinen Ausgangszustand zurück. Dies ist sehr nützlich bei Schleifenverhalten. Wenn Sie true übergeben, werden auch die Abfragedaten zurückgesetzt, die zum Finden des aktuellen Objekts verwendet wurden (Standardverhalten).

$benutzer = $benutzer->greaterThan('id', 0)->orderBy('id desc')->find();
$user_company = new UserCompany($pdo_verbindung);

foreach($benutzer as $benutzer) {
    $user_company->reset(); // mit einem sauberen Blatt beginnen
    $user_company->user_id = $benutzer->id;
    $user_company->company_id = $some_company_id;
    $user_company->insert();
}

getBuiltSql(): string (v0.4.1)

Nachdem Sie eine Methode find(), findAll(), insert(), update() oder save() ausgeführt haben, können Sie den generierten SQL abrufen und ihn zu Debugging-Zwecken verwenden.

SQL-Abfragemethoden

select(string $field1 [, string $field2 ... ])

Sie können nur einige der Spalten in einer Tabelle auswählen, wenn Sie möchten (es ist leistungsfähiger bei wirklich breiten Tabellen mit vielen Spalten)

$benutzer->select('id', 'name')->find();

from(string $table)

Sie können technisch auch eine andere Tabelle wählen! Warum zum Teufel nicht?!

$benutzer->select('id', 'name')->from('benutzer')->find();

join(string $table_name, string $join_condition)

Sie können auch zu einer anderen Tabelle in der Datenbank verknüpfen.

$benutzer->join('kontakte', 'kontakte.user_id = benutzer.id')->find();

where(string $where_conditions)

Sie können benutzerdefinierte WHERE-Argumente festlegen (Sie können in dieser WHERE-Anweisung keine Parameter festlegen)

$benutzer->where('id=1 UND name="demo"')->find();

Sicherheitshinweis - Sie könnten versucht sein, etwas wie $benutzer->where("id = '{$id}' UND name = '{$name}'")->find(); zu tun. Bitte TUN SIE DAS NICHT!!! Dies ist anfällig für sogenannte SQL-Injection-Angriffe. Es gibt viele Artikel online, bitte googeln Sie "SQL-Injection-Angriffe php" und Sie werden viele Artikel zu diesem Thema finden. Der richtige Umgang damit in dieser Bibliothek besteht darin, anstelle dieser where()-Methode etwas wie $benutzer->eq('id', $id)->eq('name', $name)->find(); zu verwenden. Wenn Sie dies unbedingt tun müssen, verfügt die PDO-Bibliothek über $pdo->quote($var), um dies für Sie zu escapen. Erst nach Verwendung von quote() können Sie es in einer where()-Anweisung verwenden.

group(string $group_by_statement)/groupBy(string $group_by_statement)

Gruppieren Sie Ihre Ergebnisse nach einer bestimmten Bedingung.

$benutzer->select('COUNT(*) as count')->groupBy('name')->findAll();

order(string $order_by_statement)/orderBy(string $order_by_statement)

Sortieren Sie die zurückgegebene Abfrage auf eine bestimmte Weise.

$benutzer->orderBy('name DESC')->find();

limit(string $limit)/limit(int $offset, int $limit)

Beschränken Sie die Anzahl der zurückgegebenen Datensätze. Wenn ein zweites Int übergeben wird, wird es wie in SQL versetzt, limitiert.

$benutzer->orderby('name DESC')->limit(0, 10)->findAll();

WHERE-Bedingungen

equal(string $field, mixed $value) / eq(string $field, mixed $value)

Dort field = $value

$benutzer->eq('id', 1)->find();

notEqual(string $field, mixed $value) / ne(string $field, mixed $value)

Dort field <> $value

$benutzer->ne('id', 1)->find();

isNull(string $field)

Dort field IS NULL

$benutzer->isNull('id')->find();

isNotNull(string $field) / notNull(string $field)

Dort field IS NOT NULL

$benutzer->isNotNull('id')->find();

greaterThan(string $field, mixed $value) / gt(string $field, mixed $value)

Dort field > $value

$benutzer->gt('id', 1)->find();

lessThan(string $field, mixed $value) / lt(string $field, mixed $value)

Dort field < $value

$benutzer->lt('id', 1)->find();

greaterThanOrEqual(string $field, mixed $value) / ge(string $field, mixed $value) / gte(string $field, mixed $value)

Dort field >= $value

$benutzer->ge('id', 1)->find();

lessThanOrEqual(string $field, mixed $value) / le(string $field, mixed $value) / lte(string $field, mixed $value)

Dort field <= $value

$benutzer->le('id', 1)->find();

like(string $field, mixed $value) / notLike(string $field, mixed $value)

Dort field LIKE $value oder field NOT LIKE $value

$benutzer->like('name', 'de')->find();

in(string $field, array $values) / notIn(string $field, array $values)

Dort field IN($value) oder field NOT IN($value)

$benutzer->in('id', [1, 2])->find();

between(string $field, array $values)

Dort field BETWEEN $value AND $value1

$benutzer->between('id', [1, 2])->find();

Beziehungen

Sie können mehrere Arten von Beziehungen mit dieser Bibliothek festlegen. Sie können Eins-zu-viele- und Eins-zu-eins-Beziehungen zwischen Tabellen festlegen. Dafür ist eine kleine Vorbereitung in der Klasse erforderlich.

Das Festlegen des $relations-Arrays ist nicht schwer, aber das korrekte Syntaxieren kann verwirrend sein.

geschütztes Array $relations = [
    // Sie können den Schlüssel nach Belieben benennen. Der Name des ActiveRecords ist wahrscheinlich gut. Z.B.: user, contact, client
    'benutzer' => [
        // erforderlich
        // self::HAS_MANY, self::HAS_ONE, self::BELONGS_TO
        self::HAS_ONE, // dies ist der Beziehungstyp

        // erforderlich
    'Some_Class', // dies ist die "andere" ActiveRecord-Klasse, auf die verwiesen wird

        // erforderlich
        // je nach Beziehungstyp
        // self::HAS_ONE = der Fremdschlüssel, der auf den Verbund verweist
        // self::HAS_MANY = der Fremdschlüssel, der auf den Verbund verweist
        // self::BELONGS_TO = der lokale Schlüssel, der auf den Verbund verweist
        'lokal_oder_fremd_schlüssel',
        // nur zur Info, das verbindet sich auch nur mit dem Primärschlüssel des "anderen" Modells

        // optional
        [ 'eq' => [ 'client_id', 5 ], 'select' => 'COUNT(*) as count', 'limit' 5 ], // zusätzliche Bedingungen, die Sie bei der Verbindung der Beziehung möchten
        // $record->eq('client_id', 5)->select('COUNT(*) as count')->limit(5))

        // optional
        'rück_reference_name' // dies ist, wenn Sie diese Beziehung zurück auf sich selbst beziehen möchten, z.B. $benutzer->contact->user;
    ];
]
class User extends ActiveRecord{
    geschütztes Array $relations = [
        'kontakte' => [ self::HAS_MANY, Kontakt::class, 'user_id' ],
        'contact' => [ self::HAS_ONE, Kontakt::class, 'user_id' ],
    ];

    public Funktion __construct($datenbank_verbindung)
    {
        Elternteil::__construct($datenbank_verbindung, 'benutzer');
    }
}

class Contact extends ActiveRecord{
    geschütztes Array $relations = [
        'user' => [ self::BELONGS_TO, User::class, 'user_id' ],
        'user_with_backref' => [ self::BELONGS_TO, User::class, 'user_id', [], 'contact' ],
    ];
    public Funktion __construct($datenbank_verbindung)
    {
        Elternteil::__construct($datenbank_verbindung, 'kontakte');
    }
}

Jetzt haben wir die Verweise eingerichtet, damit wir sie sehr einfach verwenden können!

$benutzer = neue Benutzer($pdo_verbindung);

// finde den neuesten Benutzer.
$benutzer->notNull('id')->orderBy('id desc')->finde();

// erhalte Kontakte, indem du die Beziehung verwendest:
foreach($benutzer->kontakte as $kontakt) {
    echo $kontakt->id;
}

// oder wir können den umgekehrten Weg gehen.
$kontakt = neue Kontakt();

// finde einen Kontakt
$contact->finde();

// erhalte den Benutzer durch Verwendung der Beziehung:
echo $kontakt->user->name; // das ist der Benutzername

Ziemlich cool, oder?

Einrichten benutzerdefinierter Daten

Manchmal müssen Sie Ihrem ActiveRecord etwas Einzigartiges wie eine benutzerdefinierte Berechnung anhängen, die möglicherweise einfacher wäre, diese an das Objekt anzuhängen, das dann an ein Template übergeben wird.

setCustomData(string $field, mixed $value)

Sie hängen die benutzerdefinierten Daten mit der Methode setCustomData() an.

$benutzer->setCustomData('page_view_count', $page_view_count);

Und dann verweisen Sie einfach darauf wie auf eine normale Objekteigenschaft.

echo $benutzer->page_view_count;

Ereignisse

Eine weitere super coole Funktion dieser Bibliothek sind Ereignisse. Ereignisse werden zu bestimmten Zeiten basierend auf bestimmten von Ihnen aufgerufenen Methoden ausgelöst. Sie sind sehr, sehr hilfreich, um Daten automatisch für Sie einzurichten.

onConstruct(ActiveRecord $ActiveRecord, array &config)

Dies ist wirklich hilfreich, wenn Sie eine Standardverbindung oder so etwas setzen müssen.

// index.php oder bootstrap.php
Flight::register('db', 'PDO', [ 'sqlite:test.db' ]);

//
//
//

// User.php
class User extends flight\ActiveRecord {

    geschützte Funktion onConstruct(self $self, array &$config) { // vergessen Sie nicht die & Referenz
        // Sie könnten dies tun, um die Verbindung automatisch einzustellen
        $config['connection'] = Flight::db();
        // oder dies
        $self->transformAndPersistConnection(Flight::db());

        // Sie können auch den Tabellennamen auf diese Weise festlegen.
        $config['table'] = 'users';
    } 
}

beforeFind(ActiveRecord $ActiveRecord)

Dies ist wahrscheinlich nur nützlich, wenn Sie jedes Mal eine Abfragebearbeitung benötigen.

class User extends flight\ActiveRecord {

    publik Funktion __construct($datenbank_verbindung)
    {
        Elternteil::__construct($datenbank_verbindung, 'benutzer');
    }

    geschützte Funktion beforeFind(self $self) {
        // immer id >= 0 ausführen, wenn das Ihr Ding ist
        $self->gte('id', 0); 
    } 
}

afterFind(ActiveRecord $ActiveRecord)

Dies ist wahrscheinlich nützlicher, wenn Sie jedes Mal eine Logik ausführen müssen, wenn dieser Datensatz abgerufen wird. Müssen Sie etwas entschlüsseln? Müssen Sie jedes Mal eine benutzerdefinierte Zählabfrage ausführen (nicht leistungsfähig, aber was auch immer)?

class User extends flight\ActiveRecord {

    publik Funktion __construct($datenbank_verbindung)
    {
        Elternteil::__construct($datenbank_verbindung, 'benutzer');
    }

    geschützte Funktion afterFind(self $self) {
        // Etwas entschlüsseln
        $self->secret = yourDecryptFunction($self->secret, $some_key);

        // Speichern von etwas Benutzerdefiniertem wie einer Abfrage???
        $self->setCustomData('view_count', $self->select('COUNT(*) count')->from('user_views')->eq('user_id', $self->id)['count']; 
    } 
}

beforeFindAll(ActiveRecord $ActiveRecord)

Dies ist wahrscheinlich nur nützlich, wenn Sie jedes Mal eine Abfragebearbeitung benötigen.

class User extends flight\ActiveRecord {

    publik Funktion __construct($datenbank_verbindung)
    {
        Elternteil::__construct($datenbank_verbindung, 'benutzer');
    }

    geschützte Funktion beforeFindAll(self $self) {
        // immer id >= 0 ausführen, wenn das Ihr Ding ist
        $self->gte('id', 0); 
    } 
}

afterFindAll(array<int,ActiveRecord> $results)

Ähnlich wie afterFind() können Sie dies nun für alle Datensätze ausführen!

class User extends flight\ActiveRecord {

    publik Funktion __construct($datenbank_verbindung)
    {
        Elternteil::__construct($datenbank_verbindung, 'benutzer');
    }

    geschützte Funktion afterFindAll(Array $results) {

        foreach($results as $self) {
            // Mach coole Sachen wie nachFind()
        }
    } 
}

beforeInsert(ActiveRecord $ActiveRecord)

Wirklich hilfreich, wenn Sie jedes Mal Standardwerte setzen müssen.

class User extends flight\ActiveRecord {

    publik Funktion __construct($datenbank_verbindung)
    {
        Elternteil::__construct($datenbank_verbindung, 'benutzer');
    }

    geschützte Funktion beforeInsert(self $self) {
        // Setze einige vernünftige Standardwerte
        if(!$self->created_date) {
            $self->created_date = gmdate('Y-m-d');
        }

        if(!$self->password) {
            $self->password = password_hash((string) microtime(true));
        }
    } 
}

afterInsert(ActiveRecord $ActiveRecord)

Vielleicht haben Sie einen Use-Case zum Ändern von Daten, nachdem sie eingefügt wurden?

class User extends flight\ActiveRecord {

    publik Funktion __construct($datenbank_verbindung)
    {
        Elternteil::__construct($datenbank_verbindung, 'benutzer');
    }

    geschützte Funktion afterInsert(self $self) {
        // Sie können...
        Flight::cache()->set('most_recent_insert_id', $self->id);
        // oder was auch immer....
    } 
}

beforeUpdate(ActiveRecord $ActiveRecord)

Wirklich hilfreich, wenn Sie jedes Mal Standardwerte beim Aktualisieren setzen müssen.

class User extends flight\ActiveRecord {

    publik Funktion __construct($datenbank_verbindung)
    {
        Elternteil::__construct($datenbank_verbindung, 'benutzer');
    }

    geschützte Funktion beforeInsert(self $self) {
        // Setzen Sie einige vernünftige Standardwerte
        if(!$self->updated_date) {
            $self->updated_date = gmdate('Y-m-d');
        }
    } 
}

afterUpdate(ActiveRecord $ActiveRecord)

Vielleicht haben Sie einen Use-Case für die Änderung von Daten, nachdem sie aktualisiert wurden?

class User extends flight\ActiveRecord {

    publik Funktion __construct($datenbank_verbindung)
    {
        Elternteil::__construct($datenbank_verbindung, 'benutzer');
    }

    geschützte Funktion afterInsert(self $self) {
        // Machen Sie, was Sie wollen
        Flight::cache()->set('most_recently_updated_user_id', $self->id);
        // oder so weiter....
    } 
}

beforeSave(ActiveRecord $ActiveRecord)/afterSave(ActiveRecord $ActiveRecord)

Dies ist nützlich, wenn Sie Ereignisse auslösen möchten, wenn Einfügungen oder Aktualisierungen erfolgen. Ich erspare Ihnen die lange Erklärung, aber ich bin mir sicher, Sie können erraten, was es ist.

class User extends flight\ActiveRecord {

    publik Funktion __construct($datenbank_verbindung)
    {
        Elternteil::__construct($datenbank_verbindung, 'benutzer');
    }

    geschützte Funktion beforeSave(self $self) {
        $self->last_updated = gmdate('Y-m-d H:i:s');
    } 
}

beforeDelete(ActiveRecord $ActiveRecord)/afterDelete(ActiveRecord $ActiveRecord)

Nicht sicher, was Sie hier tun möchten, aber keine Urteile hier! Los geht's!

class User extends flight\ActiveRecord {

    publik Funktion __construct($datenbank_verbindung)
    {
        Elternteil::__construct($datenbank_verbindung, 'benutzer');
    }

    geschützte Funktion beforeDelete(self $self) {
        echo 'Er war ein tapferer Soldat... :cry-face:';
    } 
}

Datenbankverbindungsverwaltung

Wenn Sie diese Bibliothek verwenden, können Sie die Datenbankverbindung auf mehrere Arten festlegen. Sie können die Verbindung im Konstruktor festlegen, Sie können sie über eine Konfigurationsvariable $config['connection'] festlegen oder Sie können sie über setDatabaseConnection() festlegen (v0.4.1).

$pdo_verbindung = new PDO('sqlite:test.db'); // zum Beispiel
$benutzer = neue Benutzer($pdo_verbindung);
// oder
$benutzer = neue Benutzer(null, [ 'connection' => $pdo_verbindung ]);
// oder
$benutzer = neue Benutzer();
$benutzer->setDatabaseConnection($pdo_verbindung);

Wenn Sie die Datenbankverbindung aktualisieren müssen, zum Beispiel, wenn Sie ein lang laufendes CLI-Skript ausführen und die Verbindung von Zeit zu Zeit aktualisieren müssen, können Sie die Verbindung mit $your_record->setDatabaseConnection($pdo_verbindung) erneut setzen.

Beitragender

Bitte tun Sie das. :D

Setup

Wenn Sie beitragen, stellen Sie sicher, dass Sie composer test-coverage ausführen, um eine Testabdeckung von 100% zu erhalten (dies ist keine echte Einheitstestabdeckung, sondern eher Integrationstests).

Stellen Sie außerdem sicher, dass Sie composer beautify und composer phpcs ausführen, um eventuelle Linting-Fehler zu beheben.

Lizenz

MIT

Awesome-plugins/latte

Latte

Latte ist eine voll ausgestattete Template-Engine, die sehr einfach zu bedienen ist und sich näher an einer PHP-Syntax anfühlt als Twig oder Smarty. Es ist auch sehr einfach zu erweitern und eigene Filter und Funktionen hinzuzufügen.

Installation

Installation mit Composer.

composer require latte/latte

Grundlegende Konfiguration

Es gibt einige grundlegende Konfigurationsoptionen, um loszulegen. Weitere Informationen dazu finden Sie in der Latte-Dokumentation.


use Latte\Engine as LatteEngine;

require 'vendor/autoload.php';

$app = Flight::app();

$app->register('latte', LatteEngine::class, [], function(LatteEngine $latte) use ($app) {

    // Hier werden Latte Ihre Templates zwischenspeichern, um die Leistung zu steigern
    // Eine coole Sache an Latte ist, dass es Ihren Cache automatisch aktualisiert,
    // wenn Sie Änderungen an Ihren Templates vornehmen!
    $latte->setTempDirectory(__DIR__ . '/../cache/');

    // Teilen Sie Latte mit, wo sich das Stammverzeichnis Ihrer Ansichten befindet.
    $latte->setLoader(new \Latte\Loaders\FileLoader($app->get('flight.views.path')));
});

Einfaches Layout-Beispiel

Hier ist ein einfaches Beispiel für eine Layout-Datei. Diese Datei wird verwendet, um alle anderen Ansichten zu umschließen.

<!-- app/views/layout.latte -->
<!doctype html>
<html lang="de">
    <head>
        <title>{$title ? $title . ' - '}Meine App</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <header>
            <nav>
                <!-- Ihre Navigations-Elemente hier -->
            </nav>
        </header>
        <div id="content">
            <!-- Hier passiert die Magie -->
            {block content}{/block}
        </div>
        <div id="footer">
            &copy; Urheberrecht
        </div>
    </body>
</html>

Und jetzt haben wir Ihre Datei, die innerhalb dieses Inhaltsblocks gerendert wird:

<!-- app/views/home.latte -->
<!-- Dies teilt Latte mit, dass diese Datei "innerhalb" der layout.latte Datei ist -->
{extends layout.latte}

<!-- Dies ist der Inhalt, der innerhalb des Layouts im Inhaltsblock gerendert wird -->
{block content}
    <h1>Startseite</h1>
    <p>Willkommen in meiner App!</p>
{/block}

Dann, wenn Sie dies in Ihrer Funktion oder Ihrem Controller rendern, würden Sie etwas Ähnliches tun:

// einfacher Route
Flight::route('/', function () {
    Flight::latte()->render('home.latte', [
        'title' => 'Startseite'
    ]);
});

// oder wenn Sie einen Controller verwenden
Flight::route('/', [HomeController::class, 'index']);

// HomeController.php
class HomeController
{
    public function index()
    {
        Flight::latte()->render('home.latte', [
            'title' => 'Startseite'
        ]);
    }
}

Besuchen Sie die Latte-Dokumentation für weitere Informationen darüber, wie Sie Latte optimal nutzen können!

Awesome-plugins/awesome_plugins

Erstaunliche Plugins

Flight ist unglaublich erweiterbar. Es gibt eine Reihe von Plugins, die verwendet werden können, um Funktionalitäten zu Ihrer Flight-Anwendung hinzuzufügen. Einige werden offiziell vom Flight-Team unterstützt, andere sind Mikro-/Lite-Bibliotheken, die Ihnen beim Einstieg helfen.

Caching

Caching ist eine großartige Möglichkeit, um Ihre Anwendung zu beschleunigen. Es gibt eine Reihe von Caching-Bibliotheken, die mit Flight verwendet werden können.

CLI

CLI-Anwendungen sind eine großartige Möglichkeit, mit Ihrer Anwendung zu interagieren. Sie können sie verwenden, um Controller zu generieren, alle Routen anzuzeigen und mehr.

Cookies

Cookies sind eine großartige Möglichkeit, kleine Datenstücke auf der Client-Seite zu speichern. Sie können verwendet werden, um Benutzereinstellungen, Anwendungseinstellungen und mehr zu speichern.

Debugging

Debugging ist entscheidend, wenn Sie in Ihrer lokalen Umgebung entwickeln. Es gibt einige Plugins, die Ihr Debugging-Erlebnis verbessern können.

Datenbanken

Datenbanken sind der Kern vieler Anwendungen. So speichern und abrufen Sie Daten. Einige Datenbank-Bibliotheken sind einfach Wrapper, um Abfragen zu schreiben, andere sind vollwertige ORMs.

Verschlüsselung

Verschlüsselung ist entscheidend für jede Anwendung, die sensible Daten speichert. Das Verschlüsseln und Entschlüsseln der Daten ist nicht besonders schwierig, aber das ordnungsgemäße Speichern des Verschlüsselungsschlüssels kann schwierig sein. Das Wichtigste ist, Ihren Verschlüsselungsschlüssel niemals in einem öffentlichen Verzeichnis zu speichern oder ihn Ihrem Code-Repository zu übermitteln.

Sitzung

Sitzungen sind für APIs nicht wirklich nützlich, aber für den Aufbau einer Webanwendung können Sitzungen entscheidend sein, um den Zustand und die Anmeldeinformationen zu speichern.

Templating

Templating ist für jede Webanwendung mit einer Benutzeroberfläche unerlässlich. Es gibt eine Reihe von Templating-Engines, die mit Flight verwendet werden können.

Mitarbeit

Hast du ein Plugin, das du teilen möchtest? Reichen Sie einen Pull-Request ein, um es zur Liste hinzuzufügen!

Examples

Brauchen Sie einen schnellen Start?

Sie haben zwei Möglichkeiten, um mit Flight zu starten:

Brauchen Sie etwas Inspiration?

Obwohl diese nicht offiziell von dem Flight Team gesponsert werden, könnten sie Ihnen Ideen geben, wie Sie Ihre eigenen Projekte strukturieren können, die mit Flight erstellt wurden!

Möchten Sie Ihr eigenes Beispiel teilen?

Wenn Sie ein Projekt haben, das Sie teilen möchten, reichen Sie bitte einen Pull-Request ein, um es zu dieser Liste hinzuzufügen!