Learn

Lernen Sie Flight kennen

Flight ist ein schnelles, einfaches, erweiterbares Framework für PHP. Es ist sehr vielseitig und kann zum Erstellen jeder Art von Webanwendung verwendet werden. Es wurde mit dem Ziel der Einfachheit entwickelt und ist so geschrieben, dass es leicht zu verstehen und zu verwenden 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 eines verwenden.

Darüber hinaus wurde ein ausgezeichnetes Tutorial von @lubiana erstellt. Obwohl es nicht im Detail auf Flight eingeht, wird Ihnen dieser Leitfaden helfen, einige der wichtigen Konzepte rund um ein Framework zu verstehen und warum sie vorteilhaft sind. Sie finden das Tutorial hier.

Flight im Vergleich zu anderen Frameworks

Wenn Sie von einem anderen Framework wie Laravel, Slim, Fat-Free oder Symfony zu Flight migrieren, hilft Ihnen diese Seite, die Unterschiede zwischen den beiden zu verstehen.

Kern Themen

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. Dies umfasst auch das Gruppieren von Routen, Routenparameter und Middleware.

Middleware

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

Requests

Erfahren Sie, wie Sie Anfragen und Antworten in Ihrer Anwendung behandeln.

Responses

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

Events

Erfahren Sie, wie Sie das Event-System verwenden, um benutzerdefinierte Events in Ihre Anwendung hinzuzufügen.

HTML-Vorlagen

Erfahren Sie, wie Sie die integrierte View-Engine verwenden, 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.

Flight erweitern

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

Events und Filterung

Erfahren Sie, wie Sie das Event-System verwenden, um Hooks zu Ihren Methoden und internen Framework-Methoden hinzuzufügen.

Dependency Injection Container

Erfahren Sie, wie Sie Abhängigkeitsinjektionscontainer (DIC) verwenden, um die Abhängigkeiten Ihrer Anwendung zu verwalten.

Framework API

Erfahren Sie mehr über die Kernmethoden des Frameworks.

Migration zu v3

Die Rückwärtskompatibilität wurde größtenteils beibehalten, es gibt jedoch einige Änderungen, über die Sie sich beim Migrieren von v2 zu v3 im Klaren sein sollten.

Fehlerbehebung

Es gibt einige häufige Probleme, auf die Sie stoßen können, wenn Sie Flight verwenden. Diese Seite hilft Ihnen, diese Probleme zu beheben.

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/flight_vs_laravel

Flight vs Laravel

Was ist Laravel?

Laravel ist ein Framework mit vielen Funktionen und einer erstaunlichen, auf Entwickler ausgerichteten Entwicklungsumgebung, aber auf Kosten von Leistung und Komplexität. Das Ziel von Laravel ist es, dass Entwickler auf höchstem Produktivitätsniveau arbeiten und alltägliche Aufgaben einfach erledigen können. Laravel ist eine großartige Wahl für Entwickler, die eine umfassende Enterprise-Webanwendung erstellen möchten. Dies geht jedoch mit bestimmten Kompromissen einher, insbesondere in Bezug auf Leistung und Komplexität. Die Grundlagen von Laravel zu lernen kann einfach sein, aber die Beherrschung des Frameworks kann einige Zeit in Anspruch nehmen.

Es gibt auch so viele Laravel-Module, dass Entwickler oft das Gefühl haben, dass der einzige Weg, Probleme zu lösen, darin besteht, diese Module zu nutzen, während Sie tatsächlich einfach eine andere Bibliothek verwenden oder Ihren eigenen Code schreiben könnten.

Vor- und Nachteile im Vergleich zu Flight

Nachteile im Vergleich zu Flight

Learn/migrating_to_v3

Migration zu v3

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

Verhalten beim Output-Puffer (3.5.0)

Output buffering ist der Prozess, bei dem die Ausgabe, die von einem PHP-Skript generiert wird, in einem Puffer (intern zu PHP) gespeichert wird, bevor sie an den Client gesendet wird. Dies ermöglicht es Ihnen, die Ausgabe zu ändern, bevor sie an den 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 im Fall von Flights manchmal einer anonymen Funktion) bricht 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 auf eine Weise behandelt, bei der der eigene Ausgabepuffer nicht konsistent geschlossen wurde, was Unit-Tests und Streaming erschwert hat. Für die Mehrheit der Benutzer dürfte sich diese Änderung tatsächlich nicht auf Sie auswirken. Wenn Sie jedoch Inhalte außerhalb von Funktionsaufrufen und Controllern ausgeben (zum Beispiel in einem Hook), werden Sie wahrscheinlich Probleme haben. Das Ausgeben von Inhalten in Hooks und vor der tatsächlichen Ausführung des Frameworks hat möglicherweise in der Vergangenheit funktioniert, wird aber zukünftig nicht mehr funktionieren.

Wo Sie Probleme haben könnten

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

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

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

Flight::map('hello', 'hello');
Flight::after('hello', function(){
    // Dies wird tatsächlich in Ordnung sein
    echo '<p>Dieser Hallo-Welt-Satz 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 tatsächlich in Ordnung
    echo 'Hallo Welt';

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

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

Aktivieren des v2-Rendering-Verhaltens

Können Sie Ihren alten Code weiterhin 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-Rendering-Verhalten aktivieren, indem Sie die Konfigurationsoption flight.v2.output_buffering auf true setzen. Dadurch können Sie weiterhin das alte Rendering-Verhalten verwenden, 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(){
    // Nun wird das in Ordnung sein
    echo '<html><head><title>Meine Seite</title></head><body>';
});

// mehr Code 

Dispatcher-Änderungen (3.7.0)

Wenn Sie bisher direkt statische Methoden für Dispatcher wie Dispatcher::invokeMethod(), Dispatcher::execute() usw. aufgerufen haben, müssen Sie Ihren Code aktualisieren, um diese Methoden nicht mehr direkt aufzurufen. Dispatcher wurde in eine mehr objektorientierte Form umgewandelt, sodass Dependency Injection Container auf eine 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.

Änderungen an halt() stop() redirect() und error() (3.10.0)

Das Standardverhalten vor 3.10.0 bestand darin, sowohl die Header als auch den Antworttext zu löschen. Dies wurde geändert, um nur den Antworttext zu löschen. Wenn Sie auch die Header löschen müssen, können Sie Flight::response()->clear() verwenden.

Learn/security

Sicherheit

Sicherheit ist ein großes Thema, 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 zu helfen, Ihre Webanwendungen abzusichern.

Header

HTTP-Header sind eine der einfachsten Möglichkeiten, um Ihre Webanwendungen abzusichern. 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 Methode header auf dem Objekt Flight\Response verwenden.

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

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

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

// Setzen Sie den X-Content-Type-Options-Header, um MIME-Sniffing zu verhindern
Flight::response()->header('X-Content-Type-Options', 'nosniff');

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

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

// Setzen Sie den Permissions-Policy-Header, 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 auch immer Sie Ihre Routen haben
// FYI, diese leere Zeichenfolge agiert als globale Middleware für
// alle Routen. Natürlich könnten Sie das Gleiche tun und es nur
// zu 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 eine Art von Angriff, bei dem eine böswillige 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 Ihr eigenes durch die Verwendung von Middleware implementieren.

Einrichtung

Zuerst müssen Sie ein CSRF-Token generieren und es in der Sitzung des Benutzers speichern. Sie können dann dieses Token in Ihren Formularen verwenden und überprüfen, wenn das Formular abgesendet wird.

// Generieren Sie ein CSRF-Token und speichern Sie es in der Sitzung des Benutzers
// (vorausgesetzt, Sie haben ein Sitzungsobjekt erstellt und es an Flight angehängt)
// siehe die Sitzungsdokumentation für weitere Informationen
Flight::register('session', \Ghostff\Session\Session::class);

// Sie müssen nur ein einzelnes Token pro Sitzung generieren (damit es funktioniert 
// über mehrere Tabs und Anfragen für denselben Benutzer)
if(Flight::session()->get('csrf_token') === null) {
    Flight::session()->set('csrf_token', bin2hex(random_bytes(32)) );
}
<!-- Verwenden Sie das CSRF-Token in Ihrem Formular -->
<form method="post">
    <input type="hidden" name="csrf_token" value="<?= Flight::session()->get('csrf_token') ?>">
    <!-- andere Formularfelder -->
</form>

Mit Latte

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

// Setzen Sie eine benutzerdefinierte Funktion, um das CSRF-Token auszugeben
// Hinweis: Die Ansicht wurde mit Latte als Ansicht-Engine 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 in Ihren Latte-Vorlagen können Sie die Funktion csrf() verwenden, um das CSRF-Token auszugeben.

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

Kurz und einfach, richtig?

Überprüfen des CSRF-Tokens

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

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

        // Erfassen Sie das CSRF-Token aus den Formularwerten
        $token = Flight::request()->data->csrf_token;
        if($token !== Flight::session()->get('csrf_token')) {
            Flight::halt(403, 'Ungültiges CSRF-Token');
            // oder für eine JSON-Antwort
            Flight::jsonHalt(['error' => 'Ungültiges CSRF-Token'], 403);
        }
    }
});

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 auch 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 eine Art von Angriff, bei dem eine böswillige Website Code in Ihre Website injizieren kann. Die meisten dieser Möglichkeiten stammen von Formularwerten, die Ihre Endbenutzer ausfüllen werden. Sie sollten nie den Ausgang Ihrer Benutzer vertrauen! Immer davon ausgehen, dass alle von ihnen die besten Hacker der Welt sind. Sie können böswilliges JavaScript oder HTML in Ihre Seite injizieren. Dieser Code kann verwendet werden, um Informationen von Ihren Benutzern zu stehlen oder Aktionen auf Ihrer Website auszuführen. Mit der Ansichtsklasse von Flight können Sie Ausgaben leicht 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 ausgeben: &lt;script&gt;alert(&quot;XSS&quot;)&lt;/script&gt;

// Wenn Sie etwas wie Latte verwenden, das als Ihre Ansichtsklasse registriert ist, wird dies auch automatisch escaped.
Flight::view()->render('template', ['name' => $name]);

SQL-Injektion

SQL-Injektion ist eine Art von Angriff, bei dem ein böswilliger Benutzer SQL-Code in Ihre Datenbank injizieren kann. Dies kann verwendet werden, um Informationen aus Ihrer Datenbank zu stehlen oder Aktionen in Ihrer Datenbank auszuführen. Auch hier sollten Sie nie Eingaben von Ihren Benutzern vertrauen! Immer davon ausgehen, dass sie es auf Blut abgesehen haben. Sie können vorbereitete Anweisungen in Ihren PDO-Objekten verwenden, um SQL-Injektionen zu verhindern.

// Vorausgesetzt, Sie haben Flight::db() als Ihr PDO-Objekt registriert
$statement = Flight::db()->prepare('SELECT * FROM users WHERE username = :username');
$statement->execute([':username' => $username]);
$users = $statement->fetchAll();

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

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

// Versprechen Sie einfach, dass Sie niemals so etwas tun werden...
$users = Flight::db()->fetchAll("SELECT * FROM users WHERE username = '{$username}' LIMIT 5");
// denn was ist, wenn $username = "' 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 funktioniert. Tatsächlich,
// es ist ein sehr häufiger SQL-Injektionsangriff, der alle Benutzer zurückgibt.

CORS

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

// app/utils/CorsUtil.php

namespace app\utils;

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

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

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

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

        $request = Flight::request();

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

// index.php oder wo auch immer Sie Ihre Routen haben
$CorsUtil = new CorsUtil();

// Dies muss vor dem start ausgeführt werden.
Flight::before('start', [ $CorsUtil, 'setupCors' ]);

Fehlermanagement

Verbergen Sie sensible Fehlermeldungen in der Produktion, um das Leaken von Informationen an Angreifer zu vermeiden.

// In Ihrer bootstrap.php oder index.php

// im flightphp/skeleton, befindet sich dies in app/config/config.php
$environment = ENVIRONMENT;
if ($environment === 'production') {
    ini_set('display_errors', 0); // Fehleranzeige deaktivieren
    ini_set('log_errors', 1);     // Fehler stattdessen protokollieren
    ini_set('error_log', '/path/to/error.log');
}

// In Ihren Routen oder Controllern
// Verwenden Sie Flight::halt() für kontrollierte Fehlermeldungen
Flight::halt(403, 'Zugriff verweigert');

Eingabesäuberung

Vertrauen Sie niemals Benutzereingaben. Säubern Sie sie, bevor Sie sie verarbeiten, um zu verhindern, dass böswillige Daten eindringen.


// Angenommen, eine $_POST-Anfrage mit $_POST['input'] und $_POST['email']

// Bereinigen einer String-Eingabe
$clean_input = filter_var(Flight::request()->data->input, FILTER_SANITIZE_STRING);
// Bereinigen einer E-Mail
$clean_email = filter_var(Flight::request()->data->email, FILTER_SANITIZE_EMAIL);

Passwort Hashing

Speichern Sie Passwörter sicher und überprüfen Sie sie sicher mit den integrierten Funktionen von PHP.

$password = Flight::request()->data->password;
// Hashen Sie ein Passwort bei der Speicherung (z. B. während der Registrierung)
$hashed_password = password_hash($password, PASSWORD_DEFAULT);

// Überprüfen Sie ein Passwort (z. B. während des Logins)
if (password_verify($password, $stored_hash)) {
    // Passwort stimmt überein
}

Rate Limiting

Schützen Sie sich vor Brute-Force-Angriffen, indem Sie die Anforderungsraten mit einem Cache begrenzen.

// Vorausgesetzt, Sie haben flightphp/cache installiert und registriert
// Verwendung von flightphp/cache in einer Middleware
Flight::before('start', function() {
    $cache = Flight::cache();
    $ip = Flight::request()->ip;
    $key = "rate_limit_{$ip}";
    $attempts = (int) $cache->retrieve($key);

    if ($attempts >= 10) {
        Flight::halt(429, 'Zu viele Anfragen');
    }

    $cache->set($key, $attempts + 1, 60); // Reset nach 60 Sekunden
});

Fazit

Sicherheit ist ein großes Thema, und es ist wichtig, sicherzustellen, dass Ihre Webanwendungen sicher sind. Flight bietet eine Reihe von Funktionen, um Ihnen zu helfen, Ihre Webanwendungen abzusichern, aber es ist wichtig, immer wachsam zu sein und sicherzustellen, dass Sie alles tun, um die Daten Ihrer Benutzer zu schützen. Gehen Sie immer vom Schlimmsten aus und vertrauen Sie niemals Eingaben von Ihren Benutzern. Escapen Sie immer Ausgaben und verwenden Sie vorbereitete Anweisungen, um SQL-Injektionen 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/routing

Routing

Hinweis: Möchten Sie mehr über das Routing erfahren? Schauen Sie sich die "Warum ein Framework?" Seite für eine tiefere Erklärung an.

Das grundlegende Routing in Flight erfolgt durch das Abgleichen eines URL-Musters mit einer Callback-Funktion oder einem Array aus einer Klasse und einer Methode.

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

Routen werden in der Reihenfolge abgeglichen, in der sie definiert sind. Die erste Route, die mit einer Anfrage übereinstimmt, wird aufgerufen.

Callbacks/Funktionen

Der Callback kann jedes aufrufbare Objekt sein. Sie können also eine normale Funktion verwenden:

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

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

Klassen

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

class Greeting {
    public static function hello() {
        echo 'Hallo Welt!';
    }
}

Flight::route('/', [ 'Greeting','hello' ]);

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


// Greeting.php
class Greeting
{
    public function __construct() {
        $this->name = 'John Doe';
    }

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

// index.php
$greeting = new Greeting();

Flight::route('/', [ $greeting, 'hello' ]);
// Sie können dies auch tun, ohne das Objekt zuerst zu erstellen
// Hinweis: Es werden keine Argumente in den Konstruktor injiziert
Flight::route('/', [ 'Greeting', 'hello' ]);
// Zusätzlich können Sie diese kürzere Syntax verwenden
Flight::route('/', 'Greeting->hello');
// oder
Flight::route('/', Greeting::class.'->hello');

Abhängigkeitsinjektion über DIC (Dependency Injection Container)

Wenn Sie die Abhängigkeitsinjektion über einen Container (PSR-11, PHP-DI, Dice usw.) verwenden möchten, ist die einzige Art von Routen, wo dies verfügbar ist, entweder durch die direkte Erstellung des Objekts selbst und die Verwendung des Containers zur Erstellung Ihres Objekts oder indem Sie Strings verwenden, um die Klasse und methode zu definieren, die aufgerufen werden sollen. Sie können zur Abhängigkeitsinjektion Seite gehen für weitere Informationen.

Hier ist ein schnelles Beispiel:


use flight\database\PdoWrapper;

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

    public function hello(int $id) {
        // Mach etwas mit $this->pdoWrapper
        $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 benötigten Parametern ein
// Siehe die Seite zur Abhängigkeitsinjektion für weitere Informationen zu PSR-11
$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'
    ]
]);

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

// Routen wie gewohnt
Flight::route('/hello/@id', [ 'Greeting', 'hello' ]);
// oder
Flight::route('/hello/@id', 'Greeting->hello');
// oder
Flight::route('/hello/@id', 'Greeting::hello');

Flight::start();

Methoden-Routing

Standardmäßig werden Routenmuster mit allen Anfrage-Methoden abgeglichen. Sie können auf spezifische Methoden reagieren, indem Sie einen Bezeichner vor die URL setzen.

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() für Routen nicht verwenden, da dies eine Methode ist 
//    um Variablen zu erhalten, nicht um eine Route zu erstellen.
// Flight::post('/', function() { /* code */ });
// Flight::patch('/', function() { /* code */ });
// Flight::put('/', function() { /* code */ });
// Flight::delete('/', function() { /* code */ });

Sie können auch mehrere Methoden auf einen einzigen Callback abbilden, indem Sie ein | Trennzeichen verwenden:

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

Zusätzlich können Sie das Router-Objekt abrufen, das einige Hilfsmethoden für Sie hat:


$router = Flight::router();

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

// GET-Anfrage
$router->get('/users', 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('/user/[0-9]+', function () {
  // Dies wird /user/1234 abgleichen
});

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

Benannte Parameter

Sie können benannte Parameter in Ihren Routen angeben, die an Ihre Callback-Funktion übergeben werden. Das dient mehr der Lesbarkeit der Route als allem anderen. Bitte sehen Sie den Abschnitt unten über wichtige Vorbehalte.

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 das : Trennzeichen verwenden:

Flight::route('/@name/@id:[0-9]{3}', function (string $name, string $id) {
  // Dies wird /bob/123 abgleichen
  // Wird aber nicht abgleichen mit /bob/12345
});

Hinweis: Das Abgleichen von Regex-Gruppen () mit Positionsparametern wird nicht unterstützt. :'(

Wichtiger Vorbehalt

Obwohl im obigen Beispiel scheint, dass @name direkt an die Variable $name gebunden ist, ist dem nicht so. Die Reihenfolge der Parameter in der Callback-Funktion bestimmt, was an sie übergeben wird. Wenn Sie also die Reihenfolge der Parameter in der Callback-Funktion wechseln, würden sich auch die Variablen ändern. Hier ist ein Beispiel:

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

Und wenn Sie zur folgenden URL gehen: /bob/123, wäre die Ausgabe Hallo, 123 (bob)!. Bitte seien Sie vorsichtig, wenn Sie Ihre Routen und Callback-Funktionen einrichten.

Optionale Parameter

Sie können benannte Parameter angeben, die optional für die Übereinstimmung sind, indem Sie Segmente in Klammern setzen.

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

Alle optionalen Parameter, die nicht übereinstimmen, werden als NULL übergeben.

Wildcards

Die Übereinstimmung erfolgt nur auf einzelnen URL-Segmenten. Wenn Sie mehrere Segmente abgleichen möchten, können Sie das * Wildcard verwenden.

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

Um alle Anfragen an einen einzigen Callback zu routen, können Sie Folgendes tun:

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

Übergabe

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

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

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

Route-Aliasing

Sie können einer Route ein Alias zuweisen, damit die URL später dynamisch in Ihrem Code generiert werden kann (wie zum Beispiel in einer Vorlage).

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

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

Dies ist besonders hilfreich, wenn sich Ihre URL ändert. Im obigen Beispiel, nehmen wir an, dass Benutzer nach /admin/users/@id verschoben wurden. Mit dem Alias müssen Sie nicht überall, wo Sie auf den Alias verweisen, Änderungen vornehmen, weil der Alias jetzt /admin/users/5 zurückgibt, wie im obigen Beispiel.

Route-Aliasing funktioniert auch in Gruppen:

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

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

Routeninfo

Wenn Sie die übereinstimmenden Routeninformationen inspizieren möchten, können Sie anfordern, dass das Routenobjekt an Ihre Callback-Funktion übergeben wird, indem Sie true als drittes Parameter in der Routenmethode übergeben. Das Routenobjekt wird immer das letzte Parameter sein, das an Ihre Callback-Funktion übergeben wird.

Flight::route('/', function(\flight\net\Route $route) {
  // Array der HTTP-Methoden, die abgeglichen wurden
  $route->methods;

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

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

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

  // Zeigt den URL-Pfad an.... wenn Sie es wirklich benötigen
  $route->pattern;

  // Zeigt, welches Middleware zugewiesen ist
  $route->middleware;

  // Zeigt den Alias an, der dieser Route zugewiesen ist
  $route->alias;
}, true);

Routen Gruppierung

Es kann Zeiten geben, in denen Sie verwandte Routen zusammen gruppieren möchten (wie /api/v1). Sie können dies tun, indem Sie die group Methode verwenden:

Flight::group('/api/v1', function () {
  Flight::route('/users', function () {
    // Entspricht /api/v1/users
  });

  Flight::route('/posts', function () {
    // Entspricht /api/v1/posts
  });
});

Sie können sogar Gruppen von Gruppen verschachteln:

Flight::group('/api', function () {
  Flight::group('/v1', function () {
    // Flight::get() erhält Variablen, es setzt keine Route! Siehe Objektkontext unten
    Flight::route('GET /users', function () {
      // Entspricht GET /api/v1/users
    });

    Flight::post('/posts', function () {
      // Entspricht POST /api/v1/posts
    });

    Flight::put('/posts/1', function () {
      // Entspricht PUT /api/v1/posts
    });
  });
  Flight::group('/v2', function () {

    // Flight::get() erhält Variablen, es setzt keine Route! Siehe Objektkontext unten
    Flight::route('GET /users', function () {
      // Entspricht GET /api/v2/users
    });
  });
});

Gruppierung mit Objektkontext

Sie können die Routen-Gruppierung auch mit dem Engine-Objekt in folgender Weise verwenden:

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

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

  $router->post('/posts', function () {
    // Entspricht POST /api/v1/posts
  });
});

Ressourcen-Routing

Sie können eine Reihe von Routen für eine Ressource mit der Methode resource erstellen. Dies erstellt eine Reihe von Routen für eine Ressource, die den RESTful-Konventionen folgt.

Um eine Ressource zu erstellen, tun Sie Folgendes:

Flight::resource('/users', UsersController::class);

Und was im Hintergrund passieren wird, ist, dass die folgenden Routen erstellt werden:

[
      'index' => 'GET ',
      'create' => 'GET /create',
      'store' => 'POST ',
      'show' => 'GET /@id',
      'edit' => 'GET /@id/edit',
      'update' => 'PUT /@id',
      'destroy' => 'DELETE /@id'
]

Und Ihr Controller wird so aussehen:

class UsersController
{
    public function index(): void
    {
    }

    public function show(string $id): void
    {
    }

    public function create(): void
    {
    }

    public function store(): void
    {
    }

    public function edit(string $id): void
    {
    }

    public function update(string $id): void
    {
    }

    public function destroy(string $id): void
    {
    }
}

Hinweis: Sie können die neu hinzugefügten Routen mit runway anzeigen, indem Sie php runway routes ausführen.

Anpassen von Ressourcenrouten

Es gibt einige Optionen zur Konfiguration der Ressourcenrouten.

Alias-Basis

Sie können die aliasBase konfigurieren. Standardmäßig ist der Alias der letzte Teil der angegebenen URL. Zum Beispiel würde /users/ in einem aliasBase von users resultieren. Wenn diese Routen erstellt werden, sind die Aliase users.index, users.create usw. Wenn Sie den Alias ändern möchten, setzen Sie aliasBase auf den Wert, den Sie möchten.

Flight::resource('/users', UsersController::class, [ 'aliasBase' => 'user' ]);

Nur und Ausgeschlossen

Sie können auch angeben, welche Routen Sie erstellen möchten, indem Sie die Optionen only und except verwenden.

Flight::resource('/users', UsersController::class, [ 'only' => [ 'index', 'show' ] ]);
Flight::resource('/users', UsersController::class, [ 'except' => [ 'create', 'store', 'edit', 'update', 'destroy' ] ]);

Dies sind im Grunde Optionen zum Whitelisting und Blacklisting, damit Sie angeben können, welche Routen Sie erstellen möchten.

Middleware

Sie können auch Middleware angeben, die für jede der durch die Methode resource erstellten Routen ausgeführt wird.

Flight::resource('/users', UsersController::class, [ 'middleware' => [ MyAuthMiddleware::class ] ]);

Streaming

Sie können jetzt Antworten an den Client senden, indem Sie die Methode streamWithHeaders() verwenden. Das ist nützlich, um große Dateien, lang laufende Prozesse oder große Antworten zu senden. Das Streamen einer Route wird etwas anders behandelt als eine reguläre Route.

Hinweis: Streaming-Antworten sind 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 Methode stream() für eine Route verwenden. Wenn Sie das tun, müssen Sie alle Methoden manuell setzen, bevor Sie irgendetwas an den Client ausgeben. Dies geschieht mit der PHP-Funktion header() oder der Methode Flight::response()->setRealHeader().

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

    // Offensichtlich würden Sie den Pfad und dergleichen sanieren.
    $fileNameSafe = basename($filename);

    // Wenn Sie hier nach der Ausführung der Route zusätzliche Header setzen möchten
    // müssen Sie sie definieren, bevor etwas ausgegeben wird.
    // Sie müssen alle einen rohen Aufruf der `header()` Funktion oder 
    // einen Aufruf von `Flight::response()->setRealHeader()` sein.
    header('Content-Disposition: attachment; filename="'.$fileNameSafe.'"');
    // oder
    Flight::response()->setRealHeader('Content-Disposition', 'attachment; filename="'.$fileNameSafe.'"');

    $fileData = file_get_contents('/some/path/to/files/'.$fileNameSafe);

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

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

    // Streamen Sie die Daten an den Client
    echo $fileData;

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

Stream mit Headern

Sie können auch die Methode streamWithHeaders() verwenden, um die Header zu setzen, bevor Sie mit dem Streaming beginnen.

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

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

    // Wie auch immer Sie Ihre Daten abrufen, nur als Beispiel...
    $users_stmt = Flight::db()->query("SELECT id, first_name, last_name FROM users");

    echo '{';
    $user_count = count($users);
    while($user = $users_stmt->fetch(PDO::FETCH_ASSOC)) {
        echo json_encode($user);
        if(--$user_count > 0) {
            echo ',';
        }

        // Dies ist erforderlich, um die Daten an den Client zu senden
        ob_flush();
    }
    echo '}';

// So setzen Sie die Header, bevor Sie mit dem Streaming beginnen.
})->streamWithHeaders([
    'Content-Type' => 'application/json',
    'Content-Disposition' => 'attachment; filename="users.json"',
    // optionaler Statuscode, Standardwert ist 200
    'status' => 200
]);

Learn/flight_vs_symfony

Flight vs Symfony

Was ist Symfony?

Symfony ist eine Reihe von wiederverwendbaren PHP-Komponenten und ein PHP-Framework für Webprojekte.

Das Standardfundament, auf dem die besten PHP-Anwendungen aufgebaut sind. Wählen Sie eine der 50 eigenständigen Komponenten für Ihre eigenen Anwendungen aus.

Beschleunigen Sie die Erstellung und Wartung Ihrer PHP-Webanwendungen. Beenden Sie wiederholende Codieraufgaben und genießen Sie die Kontrolle über Ihren Code.

Vor- und Nachteile im Vergleich zu Flight

Vorteile im Vergleich zu Flight

Nachteile im Vergleich zu Flight

Learn/flight_vs_another_framework

Vergleich von Flight mit einem anderen Framework

Wenn Sie von einem anderen Framework wie Laravel, Slim, Fat-Free oder Symfony zu Flight migrieren, hilft Ihnen diese Seite, die Unterschiede zwischen den beiden zu verstehen.

Laravel

Laravel ist ein funktionsreiches Framework mit allen Extras und einem erstaunlichen, auf Entwickler ausgerichteten Ökosystem, aber zu einem Preis in Leistung und Komplexität.

Sehen Sie den Vergleich zwischen Laravel und Flight.

Slim

Slim ist ein Micro-Framework, das Flight ähnelt. Es ist darauf ausgelegt, leichtgewichtig und einfach zu bedienen zu sein, kann aber etwas komplexer sein als Flight.

Sehen Sie den Vergleich zwischen Slim und Flight.

Fat-Free

Fat-Free ist ein Full-Stack-Framework in einem viel kleineren Paket. Obwohl es alle Werkzeuge im Werkzeugkasten hat, hat es eine Datenarchitektur, die einige Projekte komplexer machen kann, als sie sein müssen.

Sehen Sie den Vergleich zwischen Fat-Free und Flight.

Symfony

Symfony ist ein modulares Enterprise-Level-Framework, das darauf ausgelegt ist, flexibel und skalierbar zu sein. Für kleinere Projekte oder neuere Entwickler kann Symfony etwas überwältigend sein.

Sehen Sie den Vergleich zwischen Symfony und Flight.

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 validieren, ob der Benutzer die Berechtigung hat, auf die Route zuzugreifen.

## Grundlegende Middleware

Hier ist ein grundlegendes Beispiel:

```php
// Wenn Sie nur eine anonyme Funktion bereitstellen, wird sie vor dem Routenrückruf ausgeführt. Es gibt keine "nach" Middleware-Funktionen außer 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 kennen sollten, bevor Sie sie verwenden:

Middleware-Klassen

Middleware kann auch als Klasse registriert werden. Wenn Sie die "nach" 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!';
    }
}

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

Flight::start();

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

Behandlung von Middleware-Fehlern

Angenommen, Sie haben eine Authentifizierungs-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 error zurück, aber ohne Anpassung.
  2. Sie können den Benutzer mit Flight::redirect() auf eine Login-Seite umleiten.
  3. Sie können einen benutzerdefinierten Fehler innerhalb der Middleware erstellen und die Ausführung der Route stoppen.

Grundlegendes Beispiel

Hier ist ein einfaches Beispiel mit return false;:

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

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

Umleitungsbeispiel

Hier ist ein Beispiel, um den Benutzer auf eine Login-Seite umzuleiten:

class MyMiddleware {
    public function before($params) {
        if (isset($_SESSION['user']) === 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 so machen:

class MyMiddleware {
    public function before($params) {
        $authorization = Flight::request()->headers['Authorization'];
        if(empty($authorization)) {
            Flight::jsonHalt(['error' => 'Sie müssen angemeldet sein, um auf diese Seite zuzugreifen.'], 403);
            // oder
            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 auch dieselbe Middleware haben. Dies ist nützlich, wenn Sie beispielsweise eine Reihe von Routen nach einer Auth-Middleware gruppieren müssen, um den API-Schlüssel im Header zu überprüfen.


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

    // Diese "leer" aussehende Route passt tatsächlich zu /api
    Flight::route('', function() { echo 'api'; }, false, 'api');
    // Dies passt zu /api/benutzer
    Flight::route('/users', function() { echo 'Benutzer'; }, false, 'benutzer');
    // Dies passt zu /api/benutzer/1234
    Flight::route('/users/@id', function($id) { echo 'Benutzer:'.$id; }, false, 'user_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 Gruppierungsmethode
Flight::group('', function() {

    // Dies ist immer noch /benutzer
    Flight::route('/users', function() { echo 'Benutzer'; }, false, 'benutzer');
    // Und das ist immer noch /benutzer/1234
    Flight::route('/users/@id', function($id) { echo 'Benutzer:'.$id; }, false, 'user_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, das aufgerufen werden kann durch:

$request = Flight::request();

Typische Anwendungsfälle

Wenn Sie mit einer Anfrage in einer Webanwendung arbeiten, möchten Sie in der Regel einen Header, oder ein $_GET oder $_POST Parameter extrahieren, oder vielleicht sogar den rohen Anfrageinhalt. Flight bietet eine einfache Schnittstelle, um all diese Dinge zu tun.

Hier ist ein Beispiel, wie man einen Abfragezeichenfolgenparameter erhält:

Flight::route('/search', function(){
    $keyword = Flight::request()->query['keyword'];
    echo "Sie suchen nach: $keyword";
    // Abfrage einer Datenbank oder etwas anderem mit dem $keyword
});

Hier ist ein Beispiel für ein Formular mit einer POST-Methode:

Flight::route('POST /submit', function(){
    $name = Flight::request()->data['name'];
    $email = Flight::request()->data['email'];
    echo "Sie haben eingereicht: $name, $email";
    // in eine Datenbank oder etwas anderes mit $name und $email speichern
});

Eigenschaften des Anfrageobjekts

Das Anfrageobjekt bietet die folgenden Eigenschaften:

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

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

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

Oder Sie können tun:

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

RAW Anfrageinhalt

Um den rohen HTTP-Anfrageinhalt zu erhalten, beispielsweise bei PUT-Anfragen, können Sie tun:

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

JSON-Eingabe

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

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

$_GET

Sie können auf das $_GET-Array über die query-Eigenschaft zugreifen:

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

$_POST

Sie können auf das $_POST-Array über die data-Eigenschaft zugreifen:

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

$_COOKIE

Sie können auf das $_COOKIE-Array über die cookies-Eigenschaft zugreifen:

$myCookieValue = Flight::request()->cookies['myCookieName'];

$_SERVER

Es gibt eine Abkürzung, um auf das $_SERVER-Array über die getVar()-Methode zuzugreifen:


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

Hochgeladene Dateien über $_FILES zugreifen

Sie können auf hochgeladene Dateien über die files-Eigenschaft zugreifen:

$uploadedFile = Flight::request()->files['myFile'];

Verarbeitung von Datei-Uploads

Sie können Datei-Uploads mithilfe des Frameworks mit einigen Hilfsmethoden verarbeiten. Es reduziert sich im Grunde darauf, die Dateidaten aus der Anfrage zu extrahieren und sie an einen neuen Speicherort zu verschieben.

Flight::route('POST /upload', function(){
    // Wenn Sie ein Eingabefeld wie <input type="file" name="myFile"> hatten
    $uploadedFileData = Flight::request()->getUploadedFiles();
    $uploadedFile = $uploadedFileData['myFile'];
    $uploadedFile->moveTo('/path/to/uploads/' . $uploadedFile->getClientFilename());
});

Wenn Sie mehrere Dateien hochgeladen haben, können Sie sie durchlaufen:

Flight::route('POST /upload', function(){
    // Wenn Sie ein Eingabefeld wie <input type="file" name="myFiles[]"> hatten
    $uploadedFiles = Flight::request()->getUploadedFiles()['myFiles'];
    foreach ($uploadedFiles as $uploadedFile) {
        $uploadedFile->moveTo('/path/to/uploads/' . $uploadedFile->getClientFilename());
    }
});

Sicherheitsnotiz: Validieren und sanitieren Sie immer die Benutzereingaben, insbesondere bei Datei-Uploads. Überprüfen Sie immer die Art der Dateierweiterungen, die Sie zulassen möchten, aber Sie sollten auch die "magischen Bytes" der Datei validieren, um sicherzustellen, dass es sich tatsächlich um den Dateityp handelt, den der Benutzer angibt. Es gibt Artikel und Bibliotheken, die Ihnen dabei helfen können.

Anfrage-Header

Sie können auf Anfrage-Header mithilfe der getHeader()- oder getHeaders()-Methode zugreifen:


// Vielleicht benötigen Sie den Authorization-Header
$host = Flight::request()->getHeader('Authorization');
// oder
$host = Flight::request()->header('Authorization');

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

Anfrageinhalt

Sie können auf den rohen Anfrageinhalt über die getBody()-Methode zugreifen:

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

Anfrage-Methode

Sie können auf die Anfrage-Methode über die method-Eigenschaft oder die getMethod()-Methode zugreifen:

$method = Flight::request()->method; // ruft tatsächlich getMethod() auf
$method = Flight::request()->getMethod();

Hinweis: Die getMethod()-Methode ruft zuerst die Methode aus $_SERVER['REQUEST_METHOD'] ab, dann kann sie durch $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] überschrieben werden, wenn sie vorhanden ist, oder durch $_REQUEST['_method'], wenn sie vorhanden ist.

Anfrage-URLs

Es gibt eine Reihe von Hilfsmethoden, um Teile einer URL zu Ihrem Vorteil zusammenzufügen.

Vollständige URL

Sie können die vollständige Anforderungs-URL über die getFullUrl()-Methode abrufen:

$url = Flight::request()->getFullUrl();
// https://example.com/some/path?foo=bar

Basis-URL

Sie können die Basis-URL über die getBaseUrl()-Methode abrufen:

$url = Flight::request()->getBaseUrl();
// Hinweis, kein abschließender Schrägstrich.
// https://example.com

Abfrageanalyse

Sie können eine URL an die parseQuery()-Methode übergeben, um die Abfragezeichenfolge in ein assoziatives Array zu analysieren:

$query = Flight::request()->parseQuery('https://example.com/some/path?foo=bar');
// ['foo' => 'bar']

Learn/api

Framework API Methoden

Flight wurde entwickelt, um einfach zu verwenden und zu verstehen zu sein. Die folgende Liste enthält die vollständige Menge an Methoden für das Framework. Es besteht aus Kernmethoden, die reguläre statische Methoden sind, und erweiterbaren Methoden, die gemappte Methoden sind, die gefiltert oder überschrieben werden können.

Kernmethoden

Diese Methoden sind grundlegend 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 für eine Framework-Methode.
Flight::unregister(string $name) // Löscht die Registrierung einer Klasse für eine 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 für das automatische Laden von Klassen hinzu.
Flight::get(string $key) // Holt eine Variable, die von Flight::set() gesetzt wurde.
Flight::set(string $key, mixed $value) // Setzt eine Variable innerhalb der Flight-Engine.
Flight::has(string $key) // Überprüft, ob eine Variable gesetzt ist.
Flight::clear(array|string $key = []) // Löscht eine Variable.
Flight::init() // Initialisiert das Framework mit den Standard Einstellungen.
Flight::app() // Holt die Instanz des Anwendungsobjekts.
Flight::request() // Holt die Instanz des Anfrageobjekts.
Flight::response() // Holt die Instanz des Antwortobjekts.
Flight::router() // Holt die Instanz des Router-Objekts.
Flight::view() // Holt die Instanz des View-Objekts.

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, string $alias = '') // Mapped ein URL-Muster zu einem Callback.
Flight::post(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') // Mapped ein POST-Anfrage-URL-Muster zu einem Callback.
Flight::put(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') // Mapped ein PUT-Anfrage-URL-Muster zu einem Callback.
Flight::patch(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') // Mapped ein PATCH-Anfrage-URL-Muster zu einem Callback.
Flight::delete(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') // Mapped ein DELETE-Anfrage-URL-Muster zu einem Callback.
Flight::group(string $pattern, callable $callback) // Erstellt Gruppierungen für URLs, das Muster muss ein String sein.
Flight::getUrl(string $name, array $params = []) // Generiert eine URL basierend auf einem Routenalias.
Flight::redirect(string $url, int $code) // Leitet zu einer anderen URL um.
Flight::download(string $filePath) // Lädt eine Datei herunter.
Flight::render(string $file, array $data, ?string $key = null) // Rendert eine Template-Datei.
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 das letzte modifizierte HTTP-Caching 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.
Flight::jsonHalt(mixed $data, int $code = 200, bool $encode = true, string $charset = 'utf8', int $option) // Sendet eine JSON-Antwort und stoppt das Framework.
Flight::onEvent(string $event, callable $callback) // Registriert einen Ereignis-Listener.
Flight::triggerEvent(string $event, ...$args) // Löst ein Ereignis aus.

Alle benutzerdefinierten Methoden, die mit map und register hinzugefügt werden, können ebenfalls gefiltert werden. Für Beispiele, wie man diese Methoden mapped, siehe den Extending Flight Leitfaden.

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 überzeugende Argumente gegen die Verwendung von Frameworks vorzubringen. Allerdings gibt es 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 Mikro-Framework. Das bedeutet, dass es klein und leichtgewichtig ist. Es bietet nicht so viele Funktionen wie größere Frameworks wie Laravel oder Symfony. Allerdings bietet es viele der Funktionen, die Sie benötigen, um Webanwendungen zu erstellen. Es ist auch einfach zu erlernen und zu verwenden. Das macht es zu einer guten Wahl, um Webanwendungen schnell und einfach zu erstellen. Wenn Sie neu in der Welt der Frameworks sind, ist Flight ein großartiges Anfänger-Framework, mit dem Sie beginnen können. Es hilft Ihnen, 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, Flight kann jedoch immer noch eine erfolgreiche robuste Anwendung ermöglichen.

Was ist Routing?

Routing ist der Kern des Flight Frameworks, aber was genau ist das? Routing ist der Prozess, bei dem eine URL genommen und mit einer bestimmten Funktion in Ihrem Code abgeglichen wird. So können Sie Ihre Website basierend auf der angeforderten URL unterschiedliche Dinge tun lassen. Zum Beispiel möchten Sie möglicherweise das Profil eines Benutzers anzeigen, wenn er /user/1234 besucht, aber eine Liste aller Benutzer anzeigen, wenn er /users besucht. All dies geschieht durch Routing.

Es könnte etwa so funktionieren:

Und warum ist das wichtig?

Eine ordnungsgemäß zentralisierte Routerung kann tatsächlich Ihr Leben dramatisch vereinfachen! Es kann nur anfangs schwer zu erkennen sein. Hier sind ein paar Gründe:

Sie sind sicherlich vertraut mit dem Script für Script-Weg, eine Website zu erstellen. Sie könnten eine Datei namens index.php haben, die eine Reihe von if-Anweisungen enthält, um die URL zu überprüfen und dann eine bestimmte Funktion auf der Grundlage der URL auszuführen. Dies ist eine Form der Routenführung, aber sie ist nicht sehr organisiert und kann schnell außer Kontrolle geraten. Flights Routensystem ist eine viel organisiertere und leistungsfähigere Art, die Routenführung zu handhaben.

Dies hier?


// /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);
}

// etc...

Oder das hier?


// index.php
Flight::route('/user/@id', [ 'BenutzerController', 'BenutzerprofilAnzeigen' ]);
Flight::route('/user/@id/edit', [ 'BenutzerController', 'BenutzerprofilBearbeiten' ]);

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

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

Hoffentlich erkennen Sie langsam die Vorteile der Verwendung eines zentralisierten Routingsystems. Es ist viel einfacher zu verwalten und zu verstehen auf lange Sicht!

Anfragen und Antworten

Flight bietet eine einfache und unkomplizierte Möglichkeit, Anfragen und Antworten zu bearbeiten. Dies ist der Kern dessen, was ein Web-Framework macht. Es nimmt eine Anfrage von einem Benutzerbrowser entgegen, verarbeitet sie und sendet dann eine Antwort zurück. So können Sie Webanwendungen erstellen, die Dinge wie das Anzeigen eines Benutzerprofils, das Einloggen eines Benutzers oder das Posten eines neuen Blogposts 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 eine einfache Möglichkeit, Informationen zur Anfrage abzurufen. Sie können über die Methode Flight::request() Informationen zur Anfrage abrufen. Diese Methode gibt ein Request-Objekt zurück, das Informationen zur Anfrage enthält. Mit diesem Objekt können Sie Informationen zur Anfrage abrufen, wie die URL, die Methode oder die Daten, die der Benutzer an Ihren Server gesendet hat.

Antworten

Eine Antwort ist das, was Ihr Server an den 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 es Informationen darüber enthalten, welche Art von Daten Ihr Server an den Benutzer senden möchte, welche Art von Daten Ihr Server von dem 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 z. B. HTML, JSON oder eine Datei. Flight hilft Ihnen dabei, einige Teile der Antwort automatisch zu generieren, um die Dinge zu vereinfachen, 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, einen Teil der Antwort-Header zu generieren, aber Sie haben die meiste Kontrolle darüber, was Sie an den Benutzer zurücksenden. Manchmal können Sie das Response-Objekt direkt aufrufen, 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, dass Sie echo oder print verwenden können, um eine Antwort an den Benutzer zu senden, und Flight wird sie erfassen und mit den entsprechenden Headern zurücksenden.


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

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

Alternativ können Sie die Methode write() aufrufen, um den Body zu ergänzen.


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

    // wenn Sie den Body abrufen möchten, den Sie an diesem Punkt festgelegt haben
    // können Sie dies so tun
    $body = Flight::response()->getBody();
});

Statuscodes

Sie können den Statuscode der Antwort festlegen, indem Sie die Methode status verwenden:

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 Methode status ohne Argumente verwenden:

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

Festlegen eines Antwort-Body

Sie können den Antwort-Body mit der Methode write festlegen. Wenn Sie jedoch etwas ausgeben (echo oder print), wird es erfasst und als Antwort-Body über die Ausgabe-Pufferung gesendet.

Flight::route('/', function() {
    Flight::response()->write("Hallo, Welt!");
});

// gleichwertig mit

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

Löschen eines Antwort-Bodys

Wenn Sie den Antwort-Body löschen möchten, können Sie die Methode clearBody verwenden:

Flight::route('/', function() {
    if($someCondition) {
        Flight::response()->write("Hallo, Welt!");
    } else {
        Flight::response()->clearBody();
    }
});

Ausführen eines Callbacks auf dem Antwort-Body

Sie können einen Callback auf dem Antwort-Body mit der Methode addResponseBodyCallback ausführen:

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

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

Sie können mehrere Callbacks hinzufügen, und sie werden in der Reihenfolge ausgeführt, in der sie hinzugefügt wurden. Da dies jede aufrufbare Funktion akzeptieren kann, kann es ein Klassenarray [ $class, 'method' ], eine Closure $strReplace = function($body) { str_replace('hi', 'there', $body); }; oder einen Funktionsnamen 'minify' akzeptieren, wenn Sie beispielsweise eine Funktion hätten, um Ihren HTML-Code zu minimieren.

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

Spezifischer Routen-Callback

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

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

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

Middleware-Option

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

// MinifyMiddleware.php
class MinifyMiddleware {
    public function before() {
        // Wenden Sie den Callback hier auf das response() Objekt an.
        Flight::response()->addResponseBodyCallback(function($body) {
            return $this->minify($body);
        });
    }

    protected function minify(string $body): string {
        // Minimieren Sie den Body auf irgendeine Weise
        return $body;
    }
}

// index.php
Flight::group('/users', 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 festlegen, indem Sie die Methode header verwenden:


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

JSON

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

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

Hinweis: Standardmäßig sendet Flight einen Content-Type: application/json Header mit der Antwort. Er wird auch die Konstanten JSON_THROW_ON_ERROR und JSON_UNESCAPED_SLASHES beim Codieren des JSON verwenden.

JSON mit Statuscode

Sie können auch einen Statuscode als zweiten Parameter übergeben:

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

JSON mit schöner Ausgabe

Sie können auch ein Argument in der letzten Position übergeben, um eine schöne Ausgabe zu aktivieren:

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

Wenn Sie die Optionen, die Sie an Flight::json() übergeben, ändern und eine einfachere Syntax wünschen, können Sie die JSON-Methode einfach umbenennen:

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

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

JSON und Ausführung anhalten (v3.10.0)

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

Flight::route('/users', function() {
    $authorized = someAuthorizationCheck();
    // Überprüfen, ob der Benutzer autorisiert ist
    if($authorized === false) {
        Flight::jsonHalt(['error' => 'Nicht autorisiert'], 401);
    }

    // Fahren Sie mit dem Rest der Route fort
});

Vor v3.10.0 müssten Sie etwas in dieser Art tun:

Flight::route('/users', function() {
    $authorized = someAuthorizationCheck();
    // Überprüfen, ob der Benutzer autorisiert ist
    if($authorized === false) {
        Flight::halt(401, json_encode(['error' => 'Nicht autorisiert']));
    }

    // Fahren Sie mit dem Rest der Route fort
});

JSONP

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

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

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

my_func({"id":123});

Wenn Sie keinen Abfrageparameternamen übergeben, wird standardmäßig jsonp verwendet.

Weiterleitung zu einer anderen URL

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

Flight::redirect('/new/location');

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

Flight::redirect('/new/location', 401);

Stopp

Sie können das Framework jederzeit stoppen, indem Sie die Methode halt aufrufen:

Flight::halt();

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

Flight::halt(200, 'Gleich zurück...');

Wenn Sie halt aufrufen, werden alle Antwortinhalte bis zu diesem Punkt verworfen. Wenn Sie das Framework stoppen und die aktuelle Antwort ausgeben möchten, verwenden Sie die Methode stop:

Flight::stop();

Antworten-Daten löschen

Sie können den Antwort-Body und die Header löschen, indem Sie die Methode clear() verwenden. Dies wird alle Header, die der Antwort zugeordnet sind, löschen, den Antwort-Body löschen und den Statuscode auf 200 setzen.

Flight::response()->clear();

Nur den Antwort-Body löschen

Wenn Sie nur den Antwort-Body löschen möchten, können Sie die Methode clearBody() verwenden:

// Dies wird weiterhin alle Header beibehalten, die im response() Objekt festgelegt sind.
Flight::response()->clearBody();

HTTP-Caching

Flight bietet integrierte Unterstützung für HTTP-Level-Caching. Wenn die Cache-Bedingung erfüllt ist, gibt Flight eine HTTP 304 Not Modified Antwort zurück. Beim nächsten Mal, wenn der Client dieselbe Ressource anfordert, wird er aufgefordert, seine lokal zwischengespeicherte Version zu verwenden.

Routing-Level-Caching

Wenn Sie Ihre gesamte Antwort zwischenspeichern möchten, können Sie die Methode cache() verwenden und die Cache-Zeit übergeben.


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

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

Last-Modified

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

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

ETag

Caching mit ETag ähnelt Last-Modified, mit dem Unterschied, dass Sie jede ID angeben können, die Sie für die Ressource möchten:

Flight::route('/news', function () {
  Flight::etag('my-unique-id');
  echo 'Dieser Inhalt wird zwischengespeichert.';
});

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

Eine Datei herunterladen (v3.12.0)

Es gibt eine Hilfsmethode, um eine Datei herunterzuladen. Sie können die Methode download verwenden und den Pfad übergeben.

Flight::route('/download', function () {
  Flight::download('/path/to/file.txt');
});

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/events

Ereignissystem in Flight PHP (v3.15.0+)

Flight PHP führt ein leichtgewichtiges und intuitives Ereignissystem ein, mit dem Sie benutzerdefinierte Ereignisse in Ihrer Anwendung registrieren und auslösen können. Mit der Ergänzung von Flight::onEvent() und Flight::triggerEvent() können Sie nun in Schlüsselereignisse im Lebenszyklus Ihrer App eintauchen oder Ihre eigenen Ereignisse definieren, um Ihren Code modularer und erweiterbarer zu gestalten. Diese Methoden sind Teil von Flight's mapbaren Methoden, was bedeutet, dass Sie deren Verhalten nach Ihren Bedürfnissen anpassen können.

Dieser Leitfaden behandelt alles, was Sie wissen müssen, um mit Ereignissen zu beginnen, einschließlich ihrer Wertigkeit, ihrer Nutzung und praktischer Beispiele, um Anfängern ihre Leistungsfähigkeit zu verdeutlichen.

Warum Ereignisse verwenden?

Ereignisse ermöglichen es Ihnen, verschiedene Teile Ihrer Anwendung zu trennen, sodass sie nicht zu stark voneinander abhängen. Diese Trennung—oft als Entkopplung bezeichnet—macht es einfacher, Ihren Code zu aktualisieren, zu erweitern oder zu debuggen. Anstatt alles in einem großen Block zu schreiben, können Sie Ihre Logik in kleinere, unabhängige Teile aufteilen, die auf spezifische Aktionen (Ereignisse) reagieren.

Stellen Sie sich vor, Sie bauen eine Blog-App:

Ohne Ereignisse würden Sie das alles in eine Funktion quetschen. Mit Ereignissen können Sie es aufteilen: Ein Teil speichert den Kommentar, ein anderer löst ein Ereignis wie 'comment.posted' aus, und separate Listener kümmern sich um die E-Mail und das Protokollieren. Dadurch bleibt Ihr Code sauberer und Sie können Funktionen (wie Benachrichtigungen) hinzufügen oder entfernen, ohne die Kernlogik zu berühren.

Häufige Anwendungen

Registrieren von Ereignis-Listenern

Um auf ein Ereignis zu hören, verwenden Sie Flight::onEvent(). Diese Methode ermöglicht es Ihnen zu definieren, was passieren soll, wenn ein Ereignis eintritt.

Syntax

Flight::onEvent(string $event, callable $callback): void

Wie es funktioniert

Sie "abonnieren" ein Ereignis, indem Sie Flight mitteilen, was zu tun ist, wenn es eintritt. Der Callback kann Argumente akzeptieren, die vom Ereignisauslöser übergeben werden.

Das Ereignissystem von Flight ist synchron, was bedeutet, dass jeder Ereignis-Listener nacheinander ausgeführt wird, einer nach dem anderen. Wenn Sie ein Ereignis auslösen, laufen alle registrierten Listener für dieses Ereignis bis zur Vollständigkeit, bevor Ihr Code fortfährt. Dies ist wichtig zu verstehen, da es sich von asynchronen Ereignissystemen unterscheidet, bei denen Listener parallel oder zu einem späteren Zeitpunkt ausgeführt werden können.

Einfaches Beispiel

Flight::onEvent('user.login', function ($username) {
    echo "Willkommen zurück, $username!";
});

Hier wird bei Auslösung des Ereignisses 'user.login' der Benutzer namentlich begrüßt.

Wichtige Punkte

Auslösen von Ereignissen

Um ein Ereignis auszulösen, verwenden Sie Flight::triggerEvent(). Dies teilt Flight mit, alle für dieses Ereignis registrierten Listener auszuführen und alle Daten, die Sie bereitstellen, weiterzuleiten.

Syntax

Flight::triggerEvent(string $event, ...$args): void

Einfaches Beispiel

$username = 'alice';
Flight::triggerEvent('user.login', $username);

Dies löst das Ereignis 'user.login' aus und sendet 'alice' an den zuvor definierten Listener, der ausgeben wird: Willkommen zurück, alice!.

Wichtige Punkte

Registrieren von Ereignis-Listenern

...

Weitere Listener stoppen: Wenn ein Listener false zurückgibt, werden keine zusätzlichen Listener für dieses Ereignis ausgeführt. Dies ermöglicht es Ihnen, die Ereigniskette basierend auf bestimmten Bedingungen zu stoppen. Denken Sie daran, dass die Reihenfolge der Listener wichtig ist, da der erste, der false zurückgibt, den Rest am Ausführen hindert.

Beispiel:

Flight::onEvent('user.login', function ($username) {
    if (isBanned($username)) {
        logoutUser($username);
        return false; // Stoppt nachfolgende Listener
    }
});
Flight::onEvent('user.login', function ($username) {
    sendWelcomeEmail($username); // diese wird niemals gesendet
});

Überschreiben von Ereignismethoden

Flight::onEvent() und Flight::triggerEvent() sind verfügbar, um erweitert zu werden, was bedeutet, dass Sie neu definieren können, wie sie funktionieren. Dies ist großartig für fortgeschrittene Benutzer, die das Ereignissystem anpassen möchten, z.B. durch Hinzufügen von Protokollierung oder Ändern der Art und Weise, wie Ereignisse ausgelöst werden.

Beispiel: Anpassen von onEvent

Flight::map('onEvent', function (string $event, callable $callback) {
    // Protokolliere jede Ereignisregistrierung
    error_log("Neuer Ereignis-Listener hinzugefügt für: $event");
    // Rufe das Standardverhalten auf (vorausgesetzt, es gibt ein internes Ereignissystem)
    Flight::_onEvent($event, $callback);
});

Jetzt wird jedes Mal, wenn Sie ein Ereignis registrieren, dies protokolliert, bevor es fortfährt.

Warum überschreiben?

Wo Sie Ihre Ereignisse platzieren sollten

Als Anfänger fragen Sie sich vielleicht: Wo registriere ich all diese Ereignisse in meiner App? Die Einfachheit von Flight bedeutet, dass es keine strenge Regel gibt—Sie können sie überall dort platzieren, wo es für Ihr Projekt sinnvoll ist. Allerdings hilft eine organisierte Struktur, Ihren Code zu pflegen, wenn Ihre App wächst. Hier sind einige praktische Optionen und Best Practices, die auf die leichte Natur von Flight zugeschnitten sind:

Option 1: In Ihrem Haupt-index.php

Für kleine Apps oder schnelle Prototypen können Sie Ereignisse direkt in Ihrer index.php-Datei neben Ihren Routen registrieren. Dies hält alles an einem Ort, was in Ordnung ist, wenn Einfachheit Ihre Priorität ist.

require 'vendor/autoload.php';

// Ereignisse registrieren
Flight::onEvent('user.login', function ($username) {
    error_log("$username hat sich um " . date('Y-m-d H:i:s') . " angemeldet");
});

// Routen definieren
Flight::route('/login', function () {
    $username = 'bob';
    Flight::triggerEvent('user.login', $username);
    echo "Angemeldet!";
});

Flight::start();

Option 2: Eine separate events.php-Datei

Für eine etwas größere App sollten Sie in Betracht ziehen, die Ereignisregistrierungen in eine separate Datei wie app/config/events.php zu verschieben. Binden Sie diese Datei in Ihre index.php vor Ihren Routen ein. Dies ahmt nach, wie Routen oft in Flight-Projekten in app/config/routes.php organisiert sind.

// app/config/events.php
Flight::onEvent('user.login', function ($username) {
    error_log("$username hat sich um " . date('Y-m-d H:i:s') . " angemeldet");
});

Flight::onEvent('user.registered', function ($email, $name) {
    echo "E-Mail gesendet an $email: Willkommen, $name!";
});
// index.php
require 'vendor/autoload.php';
require 'app/config/events.php';

Flight::route('/login', function () {
    $username = 'bob';
    Flight::triggerEvent('user.login', $username);
    echo "Angemeldet!";
});

Flight::start();

Option 3: Nahe dem Ort, wo sie ausgelöst werden

Ein weiterer Ansatz besteht darin, Ereignisse in der Nähe von dort zu registrieren, wo sie ausgelöst werden, z. B. innerhalb eines Controllers oder einer Routen-Definition. Dies funktioniert gut, wenn ein Ereignis spezifisch für einen Teil Ihrer App ist.

Flight::route('/signup', function () {
    // Ereignis hier registrieren
    Flight::onEvent('user.registered', function ($email) {
        echo "Willkommens-E-Mail gesendet an $email!";
    });

    $email = 'jane@example.com';
    Flight::triggerEvent('user.registered', $email);
    echo "Angemeldet!";
});

Best Practice für Flight

Tipp: Gruppieren nach Zweck

In events.php gruppieren Sie verwandte Ereignisse (z.B. alle benutzerbezogenen Ereignisse zusammen) mit Kommentaren zur Klarheit:

// app/config/events.php
// Benutzerereignisse
Flight::onEvent('user.login', function ($username) {
    error_log("$username hat sich angemeldet");
});
Flight::onEvent('user.registered', function ($email) {
    echo "Willkommen bei $email!";
});

// Seitenereignisse
Flight::onEvent('page.updated', function ($pageId) {
    unset($_SESSION['pages'][$pageId]);
});

Diese Struktur skalierbar und bleibt für Anfänger freundlich.

Beispiele für Anfänger

Lassen Sie uns einige reale Szenarien durchgehen, um zu zeigen, wie Ereignisse funktionieren und warum sie hilfreich sind.

Beispiel 1: Protokollierung einer Benutzeranmeldung

// Schritt 1: Listener registrieren
Flight::onEvent('user.login', function ($username) {
    $time = date('Y-m-d H:i:s');
    error_log("$username hat sich um $time angemeldet");
});

// Schritt 2: Auslösen in Ihrer App
Flight::route('/login', function () {
    $username = 'bob'; // Angenommen, dies kommt von einem Formular
    Flight::triggerEvent('user.login', $username);
    echo "Hallo, $username!";
});

Warum es nützlich ist: Der Anmeldecode muss nichts über das Protokollieren wissen—er löst einfach das Ereignis aus. Später können Sie mehr Zuhörer hinzufügen (z.B. eine Willkommens-E-Mail senden), ohne die Route zu ändern.

Beispiel 2: Benachrichtigen über neue Benutzer

// Listener für neue Registrierungen
Flight::onEvent('user.registered', function ($email, $name) {
    // Simulation des Sendens einer E-Mail
    echo "E-Mail gesendet an $email: Willkommen, $name!";
});

// Auslösen, wenn jemand sich anmeldet
Flight::route('/signup', function () {
    $email = 'jane@example.com';
    $name = 'Jane';
    Flight::triggerEvent('user.registered', $email, $name);
    echo "Danke für Ihre Anmeldung!";
});

Warum es nützlich ist: Die Anmeldelogik konzentriert sich auf das Erstellen des Benutzers, während das Ereignis sich um die Benachrichtigungen kümmert. Später könnten Sie mehr Listener hinzufügen (z.B. das Protokollieren der Anmeldung).

Beispiel 3: Leeren eines Caches

// Listener zum Leeren eines Caches
Flight::onEvent('page.updated', function ($pageId) {
    unset($_SESSION['pages'][$pageId]); // Leeren des Sitzungs-caches, falls zutreffend
    echo "Cache für Seite $pageId gelöscht.";
});

// Auslösen, wenn eine Seite bearbeitet wird
Flight::route('/edit-page/(@id)', function ($pageId) {
    // Angenommen, wir haben die Seite aktualisiert
    Flight::triggerEvent('page.updated', $pageId);
    echo "Seite $pageId aktualisiert.";
});

Warum es nützlich ist: Der Bearbeitungscode kümmert sich nicht um das Caching—er signalisiert einfach das Update. Andere Teile der App können nach Bedarf reagieren.

Best Practices

Das Ereignissystem in Flight PHP, mit Flight::onEvent() und Flight::triggerEvent(), bietet Ihnen eine einfache und dennoch leistungsstarke Möglichkeit, flexible Anwendungen zu erstellen. Indem Sie verschiedenen Teilen Ihrer App erlauben, über Ereignisse miteinander zu kommunizieren, können Sie Ihren Code organisiert, wiederverwendbar und leicht erweiterbar halten. Ob Sie Aktionen protokollieren, Benachrichtigungen senden oder Updates verwalten, Ereignisse helfen Ihnen, dies zu tun, ohne Ihre Logik zu verkomplizieren. Darüber hinaus haben Sie mit der Möglichkeit, diese Methoden zu überschreiben, die Freiheit, das System an Ihre Bedürfnisse anzupassen. Beginnen Sie klein mit einem einzelnen Ereignis und beobachten Sie, wie es die Struktur Ihrer App transformiert!

Eingebaute Ereignisse

Flight PHP verfügt über einige eingebaute Ereignisse, die Sie verwenden können, um in den Lebenszyklus des Frameworks einzugreifen. Diese Ereignisse werden an bestimmten Punkten im Anfrage-/Antwortzyklus ausgelöst, sodass Sie benutzerdefinierte Logik ausführen können, wenn bestimmte Aktionen auftreten.

Liste der eingebauten Ereignisse

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

HTML-Ansichten und Vorlagen

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

Flight ermöglicht es Ihnen, die standardmäßige Ansichtsengine einfach auszutauschen, indem Sie Ihre eigene Ansichts-Klasse registrieren. Scrollen Sie nach unten, um Beispiele für die Verwendung von Smarty, Latte, Blade und mehr zu sehen!

Eingebaute Ansichtsengine

Um eine Ansichts-Vorlage anzuzeigen, rufen Sie die Methode render mit dem Namen der Vorlagendatei und optionalen Vorlagendaten auf:

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

Die Vorlagendaten, die Sie übergeben, werden automatisch in die Vorlage injiziert und können wie eine lokale Variable referenziert werden. Vorlagendateien sind einfach PHP-Dateien. Wenn der Inhalt der Datei hello.php ist:

Hello, <?= $name ?>!

Wäre die Ausgabe:

Hello, 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 all Ihren Ansichten verfügbar. Sie können also einfach Folgendes tun:

Flight::render('hello');

Beachten Sie, dass Sie beim Festlegen des Namens der Vorlage in der Methode render die Endung .php weglassen können.

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

Flight::set('flight.views.path', '/path/to/views');

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 Methode render übergeben.

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

Ihre Ansicht hat dann die gespeicherten Variablen headerContent und bodyContent. Sie können dann Ihr Layout wie folgt rendern:

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

Wenn die Vorlagendateien so aussehen:

header.php:

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

body.php:

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

layout.php:

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

Wäre die Ausgabe:

<html>
  <head>
    <title>Home Page</title>
  </head>
  <body>
    <h1>Hello</h1>
    <div>World</div>
  </body>
</html>

Smarty

So würden Sie die Smarty Template-Engine für Ihre Ansichten verwenden:

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

// Smarty als Ansichts-Klasse registrieren
// Außerdem eine Callback-Funktion übergeben, um Smarty beim Laden zu konfigurieren
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');

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

Zur Vollständigkeit sollten Sie auch die standardmäßige Render-Methode von Flight überschreiben:

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

Latte

So würden Sie die Latte Template-Engine für Ihre Ansichten verwenden:

// Latte als Ansichts-Klasse registrieren
// Außerdem eine Callback-Funktion übergeben, um Latte beim Laden zu konfigurieren
Flight::register('view', Latte\Engine::class, [], function (Latte\Engine $latte) {
  // Hier wird Latte Ihre Vorlagen cachen, um die Dinge zu beschleunigen
    // Eine nette Sache an Latte ist, dass es Ihren Cache automatisch aktualisiert,
    // wenn Sie Änderungen an Ihren Vorlagen vornehmen!
    $latte->setTempDirectory(__DIR__ . '/../cache/');

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

// Und schließen Sie es ab, damit Sie Flight::render() korrekt verwenden können
Flight::map('render', function(string $template, array $data): void {
  // Das ist wie $latte_engine->render($template, $data);
  echo Flight::view()->render($template, $data);
});

Blade

So würden Sie die Blade Template-Engine für Ihre Ansichten verwenden:

Zuerst müssen Sie die BladeOne-Bibliothek über Composer installieren:

composer require eftec/bladeone

Dann können Sie BladeOne als Ansichts-Klasse in Flight konfigurieren:

<?php
// BladeOne-Bibliothek laden
use eftec\bladeone\BladeOne;

// BladeOne als Ansichts-Klasse registrieren
// Außerdem eine Callback-Funktion übergeben, um BladeOne beim Laden zu konfigurieren
Flight::register('view', BladeOne::class, [], function (BladeOne $blade) {
  $views = __DIR__ . '/../views';
  $cache = __DIR__ . '/../cache';

  $blade->setPath($views);
  $blade->setCompiledPath($cache);
});

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

// Die Vorlage anzeigen
echo Flight::view()->run('hello', []);

Zur Vollständigkeit sollten Sie auch die standardmäßige Render-Methode von Flight überschreiben:

<?php
Flight::map('render', function(string $template, array $data): void {
  echo Flight::view()->run($template, $data);
});

In diesem Beispiel könnte die hello.blade.php-Vorlagendatei so aussehen:

<?php
Hello, {{ $name }}!

Die Ausgabe wäre:

Hello, Bob!

Indem Sie diese Schritte befolgen, können Sie die Blade-Template-Engine mit Flight integrieren und sie zum Rendern Ihrer Ansichten verwenden.

Learn/flight_vs_fat_free

Flight vs Fat-Free

Was ist Fat-Free?

Fat-Free (zärtlich bekannt als F3) ist ein leistungsstarkes und dennoch einfach zu bedienendes PHP-Mikro-Framework, das entwickelt wurde, um Ihnen zu helfen, dynamische und robuste Webanwendungen schnell zu erstellen!

Flight vergleicht sich in vielerlei Hinsicht mit Fat-Free und ist wahrscheinlich der engste Verwandte in Bezug auf Funktionen und Einfachheit. Fat-Free hat viele Funktionen, die Flight nicht hat, aber auch viele Funktionen, die Flight besitzt. Fat-Free beginnt, sein Alter zu zeigen und ist nicht mehr so beliebt wie früher.

Aktualisierungen werden seltener und die Community ist nicht mehr so aktiv wie zuvor. Der Code ist einfach genug, aber manchmal kann der Mangel an Syntaxdisziplin das Lesen und Verstehen erschweren. Es funktioniert für PHP 8.3, aber der Code selbst sieht immer noch aus, als würde er in PHP 5.3 existieren.

Vorzüge im Vergleich zu Flight

Nachteile im Vergleich zu Flight

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/flight_vs_slim

Flug vs. Schlank

Was ist Schlank?

Slim ist ein PHP-Mikrorahmenwerk, das Ihnen hilft, schnell einfache, aber leistungsstarke Webanwendungen und APIs zu erstellen.

Eine Menge der Inspiration für einige der v3-Funktionen von Flug kam tatsächlich von Schlank. Das Gruppieren von Routen und das Ausführen von Middleware in einer bestimmten Reihenfolge sind zwei Funktionen, die von Schlank inspiriert wurden. Schlank v3 wurde mit Blick auf Einfachheit entwickelt, aber es gab gemischte Bewertungen bezüglich v4.

Vorteile im Vergleich zu Flug

Nachteile im Vergleich zu Flug

Learn/autoloading

Autoloading

Autoloading ist ein Konzept in PHP, bei dem Sie ein Verzeichnis oder Verzeichnisse angeben, aus denen Klassen geladen werden sollen. Dies ist weitaus vorteilhafter als die Verwendung von require oder include, um Klassen zu laden. Es ist auch eine Voraussetzung für die Verwendung von Composer-Paketen.

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

Grundbeispiel

Angenommen, wir haben einen Verzeichnisbaum wie folgt:

# Beispiel-Pfad
/home/user/project/my-flight-project/
├── app
│   ├── cache
│   ├── config
│   ├── controllers - enthält die Controller für dieses Projekt
│   ├── translations
│   ├── UTILS - enthält Klassen nur für diese Anwendung (dies ist alles großgeschrieben, um später ein Beispiel zu geben)
│   └── views
└── public
    └── css
    └── js
    └── index.php

Sie haben möglicherweise festgestellt, dass dies die gleiche Dateistruktur wie diese Dokumentationsseite ist.

Sie können jedes Verzeichnis wie folgt zum Laden 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
 */

// keine Namensräume erforderlich

// Alle automatisch geladenen Klassen sollten Pascal-Fall 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 machen
    }
}

Namensräume

Wenn Sie Namensräume haben, wird es tatsächlich sehr einfach, dies zu implementieren. Verwenden Sie die Flight::path()-Methode, um das Stammverzeichnis (nicht das Dokumentenstammverzeichnis 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. Schauen Sie sich das folgende Beispiel an, aber achten Sie 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 gleichen Groß- und Kleinschreibung wie die Verzeichnisstruktur folgen
// Namensräume und Verzeichnisse dürfen keine Unterstriche enthalten (sofern Loader::setV2ClassLoading(false) nicht festgelegt ist)
namespace app\controllers;

// Alle automatisch geladenen Klassen sollten Pascal-Fall 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 machen
    }
}

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


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

// Der Namensraum muss der Verzeichnisstruktur und Groß- und Kleinschreibung entsprechen (beachten Sie, dass das UTILS-Verzeichnis alle großgeschrieben ist
//     wie im obigen Dateibaum)
namespace app\UTILS;

class ArrayHelperUtil {

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

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
 */

// keine Namensräume erforderlich

class My_Controller {

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

Learn/troubleshooting

Fehlerbehebung

Diese Seite hilft Ihnen bei der Fehlerbehebung von häufig auftretenden Problemen, auf die Sie bei der Verwendung von Flight stoßen könnten.

Häufige Probleme

404 Nicht gefunden oder unerwartetes Routenverhalten

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

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

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

Der Grund dafür liegt in einem speziellen Mechanismus, der in den Router eingebaut ist und die Rückgabewerte als Anweisung für "zur nächsten Route gehen" behandelt. Das Verhalten ist im Routing Abschnitt dokumentiert.

Klasse nicht gefunden (Autoloading funktioniert nicht)

Dafür könnte es einige Gründe geben, warum dies nicht passiert. Unten sind einige Beispiele aufgeführt, aber stellen Sie sicher, dass Sie auch den Autoloading Abschnitt überprüfen.

Falscher Dateiname

Am häufigsten ist, dass der Klassenname nicht mit dem Dateinamen übereinstimmt.

Wenn Sie eine Klasse namens MeineKlasse haben, sollte die Datei MeineKlasse.php genannt werden. Wenn Sie eine Klasse namens MeineKlasse haben und die Datei meineklasse.php genannt wird, kann der Autoloader sie nicht finden.

Falscher Namespace

Wenn Sie Namespaces verwenden, sollte der Namespace mit der Verzeichnisstruktur übereinstimmen.

// Code

// Wenn Ihr MyController im app/controllers Verzeichnis ist und benannt ist
// dann funktioniert dies nicht.
Flight::route('/hallo', 'MeinController->hallo');

// Sie müssen eine dieser Optionen auswählen
Flight::route('/hallo', 'app\controllers\MeinController->hallo');
// oder wenn Sie eine Verwendungserklärung oben haben

use app\controllers\MeinController;

Flight::route('/hallo', [ MeinController::class, 'hallo' ]);
// kann auch geschrieben werden
Flight::route('/hallo', MeinController::class.'->hallo');
// auch...
Flight::route('/hallo', [ 'app\controllers\MeinController', 'hallo' ]);

path() nicht definiert

Im Skelett-App ist dies im config.php File definiert, aber damit Ihre Klassen gefunden werden, müssen Sie sicherstellen, dass die path() Methode definiert ist (wahrscheinlich zum Stammverzeichnis Ihres Verzeichnisses), bevor Sie versuchen, sie zu verwenden.

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

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();

Guides/blog

Erstellen eines einfachen Blogs mit Flight PHP

Diese Anleitung führt Sie durch die Erstellung eines einfachen Blogs mit dem Flight PHP-Framework. Sie richten ein Projekt ein, definieren Routen, verwalten Beiträge mit JSON und rendern sie mit der Latte-Template-Engine – alles zeigt die Einfachheit und Flexibilität von Flight. Am Ende haben Sie einen funktionalen Blog mit einer Startseite, individuellen Beitragsseiten und einem Erstellungsformular.

Voraussetzungen

Schritt 1: Richten Sie Ihr Projekt ein

Beginnen Sie damit, ein neues Projektverzeichnis zu erstellen und Flight über Composer zu installieren.

  1. Verzeichnis erstellen:

    mkdir flight-blog
    cd flight-blog
  2. Flight installieren:

    composer require flightphp/core
  3. Ein öffentliches Verzeichnis erstellen: Flight verwendet einen einzigen Einstiegspunkt (index.php). Erstellen Sie einen public/-Ordner dafür:

    mkdir public
  4. Basis index.php: Erstellen Sie public/index.php mit einer einfachen „Hallo Welt“-Route:

    <?php
    require '../vendor/autoload.php';
    
    Flight::route('/', function () {
       echo 'Hallo, Flight!';
    });
    
    Flight::start();
  5. Den integrierten Server ausführen: Testen Sie Ihre Einrichtung mit dem Entwicklungsserver von PHP:

    php -S localhost:8000 -t public/

    Besuchen Sie http://localhost:8000, um „Hallo, Flight!“ zu sehen.

Schritt 2: Organisieren Sie Ihre Projektstruktur

Für eine saubere Einrichtung strukturieren Sie Ihr Projekt wie folgt:

flight-blog/
├── app/
│   ├── config/
│   └── views/
├── data/
├── public/
│   └── index.php
├── vendor/
└── composer.json

Schritt 3: Installieren und Konfigurieren von Latte

Latte ist eine leichtgewichtige Template-Engine, die gut mit Flight integriert.

  1. Latte installieren:

    composer require latte/latte
  2. Latte in Flight konfigurieren: Aktualisieren Sie public/index.php, um Latte als Ansicht-Engine zu registrieren:

    <?php
    require '../vendor/autoload.php';
    
    use Latte\Engine;
    
    Flight::register('view', Engine::class, [], function ($latte) {
       $latte->setTempDirectory(__DIR__ . '/../cache/');
       $latte->setLoader(new \Latte\Loaders\FileLoader(__DIR__ . '/../app/views/'));
    });
    
    Flight::route('/', function () {
       Flight::view()->render('home.latte', ['title' => 'Mein Blog']);
    });
    
    Flight::start();
  3. Eine Layout-Vorlage erstellen: In app/views/layout.latte:

    <!DOCTYPE html>
    <html>
    <head>
    <title>{$title}</title>
    </head>
    <body>
    <header>
        <h1>Mein Blog</h1>
        <nav>
            <a href="/">Startseite</a> | 
            <a href="/create">Beitrag erstellen</a>
        </nav>
    </header>
    <main>
        {block content}{/block}
    </main>
    <footer>
        <p>&copy; {date('Y')} Flight Blog</p>
    </footer>
    </body>
    </html>
  4. Eine Startvorlage erstellen: In app/views/home.latte:

    {extends 'layout.latte'}
    
    {block content}
        <h2>{$title}</h2>
        <ul>
        {foreach $posts as $post}
            <li><a href="/post/{$post['slug']}">{$post['title']}</a></li>
        {/foreach}
        </ul>
    {/block}

    Starten Sie den Server neu, wenn Sie ihn verlassen haben und besuchen Sie http://localhost:8000, um die gerenderte Seite zu sehen.

  5. Eine Datendatei erstellen:

Verwenden Sie eine JSON-Datei, um eine Datenbank zur Vereinfachung zu simulieren.

In data/posts.json:

[
    {
        "slug": "first-post",
        "title": "Mein erster Beitrag",
        "content": "Dies ist mein allererster Blogbeitrag mit Flight PHP!"
    }
]

Schritt 4: Routen definieren

Trennen Sie Ihre Routen in eine Konfigurationsdatei für eine bessere Organisation.

  1. Erstellen Sie routes.php: In app/config/routes.php:
    
    <?php
    Flight::route('/', function () {
    Flight::view()->render('home.latte', ['title' => 'Mein Blog']);
    });

Flight::route('/post/@slug', function ($slug) { Flight::view()->render('post.latte', ['title' => 'Beitrag: ' . $slug, 'slug' => $slug]); });

Flight::route('GET /create', function () { Flight::view()->render('create.latte', ['title' => 'Beitrag erstellen']); });


2. **Aktualisieren Sie `index.php`**:
Integrieren Sie die Routen-Datei:
```php
<?php
require '../vendor/autoload.php';

use Latte\Engine;

Flight::register('view', Engine::class, [], function ($latte) {
    $latte->setTempDirectory(__DIR__ . '/../cache/');
    $latte->setLoader(new \Latte\Loaders\FileLoader(__DIR__ . '/../app/views/'));
});

require '../app/config/routes.php';

Flight::start();

Schritt 5: Blog-Beiträge speichern und abrufen

Fügen Sie die Methoden zum Laden und Speichern von Beiträgen hinzu.

  1. Eine Posts-Methode hinzufügen: In index.php, fügen Sie eine Methode hinzu, um Beiträge zu laden:

    Flight::map('posts', function () {
    $file = __DIR__ . '/../data/posts.json';
    return json_decode(file_get_contents($file), true);
    });
  2. Routen aktualisieren: Ändern Sie app/config/routes.php, um Beiträge zu verwenden:

    
    <?php
    Flight::route('/', function () {
    $posts = Flight::posts();
    Flight::view()->render('home.latte', [
        'title' => 'Mein Blog',
        'posts' => $posts
    ]);
    });

Flight::route('/post/@slug', function ($slug) { $posts = Flight::posts(); $post = array_filter($posts, fn($p) => $p['slug'] === $slug); $post = reset($post) ?: null; if (!$post) { Flight::notFound(); return; } Flight::view()->render('post.latte', [ 'title' => $post['title'], 'post' => $post ]); });

Flight::route('GET /create', function () { Flight::view()->render('create.latte', ['title' => 'Beitrag erstellen']); });


## Schritt 6: Vorlagen erstellen

Aktualisieren Sie Ihre Vorlagen, um Beiträge anzuzeigen.

1. **Beitragsseite (`app/views/post.latte`)**:
```html
{extends 'layout.latte'}

    {block content}
        <h2>{$post['title']}</h2>
        <div class="post-content">
            <p>{$post['content']}</p>
        </div>
    {/block}

Schritt 7: Beitragserstellung hinzufügen

Behandeln Sie die Formularübermittlung zum Hinzufügen neuer Beiträge.

  1. Erstellungsformular (app/views/create.latte):

    {extends 'layout.latte'}
    
    {block content}
        <h2>{$title}</h2>
        <form method="POST" action="/create">
            <div class="form-group">
                <label for="title">Titel:</label>
                <input type="text" name="title" id="title" required>
            </div>
            <div class="form-group">
                <label for="content">Inhalt:</label>
                <textarea name="content" id="content" required></textarea>
            </div>
            <button type="submit">Beitrag speichern</button>
        </form>
    {/block}
  2. POST-Route hinzufügen: In app/config/routes.php:

    Flight::route('POST /create', function () {
    $request = Flight::request();
    $title = $request->data['title'];
    $content = $request->data['content'];
    $slug = strtolower(str_replace(' ', '-', $title));
    
    $posts = Flight::posts();
    $posts[] = ['slug' => $slug, 'title' => $title, 'content' => $content];
    file_put_contents(__DIR__ . '/../../data/posts.json', json_encode($posts, JSON_PRETTY_PRINT));
    
    Flight::redirect('/');
    });
  3. Testen Sie es:

    • Besuchen Sie http://localhost:8000/create.
    • Reichen Sie einen neuen Beitrag ein (z. B. „Zweiter Beitrag“ mit etwas Inhalt).
    • Überprüfen Sie die Startseite, um zu sehen, dass er aufgeführt ist.

Schritt 8: Mit Fehlerbehandlung verbessern

Überschreiben Sie die notFound-Methode für ein besseres 404-Erlebnis.

In index.php:

Flight::map('notFound', function () {
    Flight::view()->render('404.latte', ['title' => 'Seite nicht gefunden']);
});

Erstellen Sie app/views/404.latte:

{extends 'layout.latte'}

{block content}
    <h2>404 - {$title}</h2>
    <p>Entschuldigung, diese Seite existiert nicht!</p>
{/block}

Nächste Schritte

Fazit

Sie haben einen einfachen Blog mit Flight PHP erstellt! Diese Anleitung zeigt die grundlegenden Funktionen wie Routing, das Rendern von Vorlagen mit Latte und die Handhabung von Formularübermittlungen – und das alles, während es leichtgewichtig bleibt. Erkunden Sie die Dokumentation von Flight für weitere fortgeschrittene Funktionen, um Ihren Blog weiter auszubauen!

License

Die MIT-Lizenz (MIT)

Urheberrecht © 2024 @mikecao, @n0nag0n

Hiermit wird unentgeltlich jeder Person, die eine Kopie der Software und der zugehörigen Dokumentationsdateien (die "Software") erhält, die Erlaubnis erteilt, uneingeschränkt mit der Software zu handeln, einschließlich und ohne Einschränkung der Rechte zur Nutzung, Veränderung, Zusammenführung, Veröffentlichung, Verbreitung, Unterlizenzierung und/oder Verkauf von Kopien der Software, und Personen, denen die Software überlassen wird, zu gestatten, dies zu tun, unter den folgenden Bedingungen:

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

DIE SOFTWARE WIRD "WIE BESEHEN" BEREITGESTELLT, OHNE JEGLICHE GARANTIE, AUSDRÜCKLICH ODER IMPLIZIERT, EINSCHLIEßLICH DER GARANTIE DER MARKTFÄHIGKEIT, DER EIGNUNG FÜR EINEN BESTIMMTEN ZWECK UND DER NICHTVERLETZUNG. IN KEINEM FALL HAFTEN DIE AUTOREN ODER COPYRIGHT-INHABER FÜR ANSPRÜCHE, SCHÄDEN ODER ANDERE HAFTUNGEN, OB IN EINER VERTRAGS- ODER DELIKTSKLAGE, DIE AUS ODER IN VERBINDUNG MIT DER SOFTWARE ODER DER VERWENDUNG ODER ANDEREN GESCHÄFTEN MIT DER SOFTWARE ENTSTEHEN.

About

Was ist Flight?

Flight ist ein schnelles, einfaches, erweiterbares Framework für PHP. Es ist ziemlich vielseitig und kann zum Erstellen jeder Art von Webanwendung verwendet werden. Es wurde mit dem Fokus auf Einfachheit entwickelt und ist 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 tolles Framework für erfahrene Entwickler, die mehr Kontrolle über ihre Webanwendungen wünschen. Es wurde entwickelt, um einfach eine RESTful API, eine einfache Webanwendung oder eine komplexe Webanwendung zu erstellen.

Schnellstart

Zuerst installieren Sie es mit Composer

composer require flightphp/core

oder Sie können ein Zip der Repo hier herunterladen. Dann hätten Sie eine grundlegende index.php-Datei wie die folgende:

<?php

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

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

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

Flight::start();

Das ist es! Sie haben eine grundlegende Flight-Anwendung. Sie können diese Datei jetzt mit php -S localhost:8000 ausführen und http://localhost:8000 in Ihrem Browser besuchen, um die Ausgabe zu sehen.

Ist es schnell?

Ja! Flight ist schnell. Es ist eines der schnellsten PHP-Frameworks, die verfügbar sind. Sie können alle Benchmarks bei TechEmpower sehen.

Sehen Sie sich den Benchmark unten mit einigen anderen beliebten PHP-Frameworks an.

Framework Plaintext Reqs/sec JSON Reqs/sec
Flight 190,421 182,491
Yii 145,749 131,434
Fat-Free 139,238 133,952
Slim 89,588 87,348
Phalcon 95,911 87,675
Symfony 65,053 63,237
Lumen 40,572 39,700
Laravel 26,657 26,901
CodeIgniter 20,628 19,901

Skeleton/Boilerplate App

Es gibt eine Beispielanwendung, die Ihnen helfen kann, mit dem Flight Framework zu beginnen. Gehen Sie zu flightphp/skeleton für Anweisungen, wie Sie starten können! Sie können auch die Beispiele-Seite besuchen, um Inspiration für einige der Dinge zu erhalten, die Sie mit Flight tun können.

Community

Wir sind im Matrix Chat

Matrix

Und Discord

Mitwirken

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

  1. Sie können zum Kern-Framework 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 versuchen, bei den Dingen auf dem Laufenden zu bleiben, aber Updates und Übersetzungen sind willkommen.

Anforderungen

Flight erfordert PHP 7.4 oder höher.

Hinweis: PHP 7.4 wird unterstützt, weil zum aktuellen Zeitpunkt des Schreibens (2024) PHP 7.4 die Standardversion für einige LTS-Linux-Distributionen ist. Ein Zwangswechsel auf PHP >8 würde vielen Nutzern Kopfschmerzen bereiten. 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

flightphp/cache

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

Vorteile

Diese Dokumentationsseite verwendet diese Bibliothek, um jede der Seiten zu cachen!

Klicken Sie hier, um den Code zu sehen.

Installation

Installation über Composer:

composer require flightphp/cache

Verwendung

Die Verwendung ist ziemlich unkompliziert. Dies speichert eine Cache-Datei im Cache-Verzeichnis.

use flight\Cache;

$app = Flight::app();

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

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

Dann können Sie es in Ihrem Code so verwenden:


// Erhalte Cache-Instanz
$cache = Flight::cache();
$data = $cache->refreshIfExpired('simple-cache-test', function () {
    return date("H:i:s"); // gibt die zu cachenden Daten zurück
}, 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/flightphp/cache für die vollständige Dokumentation und stellen Sie sicher, dass Sie den Beispiele Ordner sehen.

Awesome-plugins/permissions

FlightPHP/Berechtigungen

Dies ist ein Berechtigungsmodul, das in Ihren Projekten verwendet werden kann, wenn Sie mehrere Rollen in Ihrer App haben und jede Rolle eine etwas andere Funktionalität hat. Mit diesem Modul können Sie Berechtigungen für jede Rolle definieren und dann überprüfen, ob der aktuelle Benutzer die Berechtigung hat, auf eine bestimmte Seite zuzugreifen oder eine bestimmte Aktion auszuführen.

Klicken Sie hier für das Repository auf GitHub.

Installation

Führen Sie composer require flightphp/permissions aus und los geht's!

Verwendung

Zuerst müssen Sie Ihre Berechtigungen einrichten, dann teilen Sie Ihrer App mit, was die Berechtigungen bedeuten. Letztendlich prüfen Sie Ihre Berechtigungen mit $Permissions->has(), ->can() oder is(). has() und can() haben die gleiche Funktionalität, sind jedoch unterschiedlich benannt, um Ihren Code leichter lesbar zu machen.

Grundbeispiel

Angenommen, Sie haben in Ihrer Anwendung eine Funktion, die überprüft, ob ein Benutzer angemeldet ist. Sie können ein Berechtigungsobjekt wie folgt erstellen:

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

// etwas Code

// dann haben Sie wahrscheinlich etwas, das Ihnen mitteilt, was die aktuelle Rolle der Person ist
// wahrscheinlich haben Sie etwas, bei dem Sie die aktuelle Rolle abrufen
// aus einer Session-Variablen, die dies definiert
// nachdem sich jemand angemeldet hat, andernfalls haben sie die Rolle 'Gast' oder 'Öffentlich'.
$current_role = 'admin';

// Berechtigungen einrichten
$permission = new \flight\Permission($current_role);
$permission->defineRule('eingeloggt', function($current_role) {
    return $current_role !== 'gast';
});

// Sie werden dieses Objekt wahrscheinlich in Flight persistieren wollen
Flight::set('berechtigung', $permission);

Dann in einem Controller irgendwo haben Sie möglicherweise so etwas.

<?php

// irgendein Controller
class EinController {
    public function eineAktion() {
        $permission = Flight::get('berechtigung');
        if ($permission->has('eingeloggt')) {
            // etwas machen
        } else {
            // etwas anderes machen
        }
    }
}

Sie können dies auch verwenden, um zu verfolgen, ob sie Berechtigungen haben, um in Ihrer Anwendung etwas zu tun. Zum Beispiel, wenn Sie eine Möglichkeit haben, dass Benutzer Beiträge in Ihrer Software interagieren können, können Sie überprüfen, ob sie Berechtigungen haben, bestimmte Aktionen auszuführen.

$current_role = 'admin';

// Berechtigungen einrichten
$permission = new \flight\Permission($current_role);
$permission->defineRule('beitrag', function($current_role) {
    if($current_role === 'admin') {
        $permissions = ['erstellen', 'lesen', 'aktualisieren', 'löschen'];
    } else if($current_role === 'editor') {
        $permissions = ['erstellen', 'lesen', 'aktualisieren'];
    } else if($current_role === 'autor') {
        $permissions = ['erstellen', 'lesen'];
    } else if($current_role === 'mitwirkender') {
        $permissions = ['erstellen'];
    } else {
        $permissions = [];
    }
    return $permissions;
});
Flight::set('berechtigung', $permission);

Dann irgendwo in einem Controller...

class BeitragController {
    public function erstellen() {
        $permission = Flight::get('berechtigung');
        if ($permission->can('beitrag.erstellen')) {
            // etwas machen
        } else {
            // etwas anderes machen
        }
    }
}

Abhängigkeiten injizieren

Sie können Abhängigkeiten in den Closure einfügen, die die Berechtigungen definieren. Dies ist nützlich, wenn Sie eine Art Schalter, ID oder einen anderen Datenpunkt haben, gegen den Sie prüfen möchten. Das Gleiche gilt für Klassen->Methoden-Aufrufe, außer dass Sie die Argumente in der Methode definieren.

Closures

$Permission->defineRule('bestellung', function(string $current_role, MyDependency $MyDependency = null) {
    // ... code
});

// in Ihrer Controllerdatei
public function bestellungErstellen() {
    $MyDependency = Flight::myDependency();
    $permission = Flight::get('berechtigung');
    if ($permission->can('bestellung.erstellen', $MyDependency)) {
        // etwas machen
    } else {
        // etwas anderes machen
    }
}

Klassen

namespace MeinApp;

class Berechtigungen {

    public function bestellung(string $current_role, MyDependency $MyDependency = null) {
        // ... code
    }
}

Verknüpfung zum Setzen von Berechtigungen mit Klassen

Sie können auch Klassen verwenden, um Ihre Berechtigungen zu definieren. Dies ist nützlich, wenn Sie viele Berechtigungen haben und Ihren Code sauber halten möchten. Sie können etwas Ähnliches wie folgt tun:

<?php

// Startcode
$Berechtigungen = new \flight\Permission($current_role);
$Berechtigungen->defineRule('bestellung', 'MeinApp\Berechtigungen->bestellung');

// myapp/Berechtigungen.php
namespace MeinApp;

class Berechtigungen {

    public function bestellung(string $current_role, int $benutzer_id) {
        // Annehmen, dass Sie dies im Voraus eingerichtet haben
        /** @var \flight\database\PdoWrapper $db */
        $db = Flight::db();
        $erlaubte_berechtigungen = [ 'lesen' ]; // jeder kann eine Bestellung einsehen
        if($current_role === 'manager') {
            $erlaubte_berechtigungen[] = 'erstellen'; // Manager können Bestellungen erstellen
        }
        $ein_anderer_spezieller_schalter_aus_db = $db->fetchField('SELECT ein_anderer_spezieller_schalter FROM einstellungen WHERE id = ?', [ $benutzer_id ]);
        if($ein_anderer_spezieller_schalter_aus_db) {
            $erlaubte_berechtigungen[] = 'aktualisieren'; // Wenn der Benutzer einen speziellen Schalter hat, kann er Bestellungen aktualisieren
        }
        if($current_role === 'admin') {
            $erlaubte_berechtigungen[] = 'löschen'; // Admins können Bestellungen löschen
        }
        return $erlaubte_berechtigungen;
    }
}

Der interessante Teil ist, dass es auch eine Abkürzung gibt, die Sie verwenden können (die auch zwischengespeichert werden kann!!!), bei der Sie der Berechtigungsklasse einfach sagen, alle Methoden in einer Klasse in Berechtigungen zu kartieren. Also, wenn Sie eine Methode namens bestellung() und eine Methode namens unternehmen() haben, werden diese automatisch zugeordnet, sodass Sie einfach $Berechtigungen->has('bestellung.lesen') oder $Berechtigungen->has('unternehmen.lesen') ausführen können und es funktioniert. Das Definieren davon ist sehr schwierig, bleiben Sie also bei mir hier. Sie müssen nur dies tun:

Erstellen Sie die Berechtigungsklasse, die Sie zusammenfassen möchten.

class MeineBerechtigungen {
    public function bestellung(string $current_role, int $bestellungs_id = 0): array {
        // Code zur Bestimmung von Berechtigungen
        return $berechtigungen_array;
    }

    public function unternehmen(string $current_role, int $unternehmen_id): array {
        // Code zur Bestimmung von Berechtigungen
        return $berechtigungen_array;
    }
}

Dann machen Sie die Berechtigungen mit Hilfe dieser Bibliothek auffindbar.

$Berechtigungen = new \flight\Permission($current_role);
$Berechtigungen->defineRulesFromClassMethods(MeineApp\Berechtigungen::class);
Flight::set('berechtigungen', $Berechtigungen);

Rufen Sie schließlich die Berechtigung in Ihrem Code auf, um zu überprüfen, ob der Benutzer berechtigt ist, eine bestimmte Berechtigung auszuführen.

class EinController {
    public function bestellungErstellen() {
        if(Flight::get('berechtigungen')->can('bestellung.erstellen') === false) {
            die('Sie können keine Bestellung erstellen. Entschuldigung!');
        }
    }
}

Zwischenspeicherung

Um die Zwischenspeicherung zu aktivieren, sehen Sie sich die einfache wruczak/phpfilecache Bibliothek an. Ein Beispiel zur Aktivierung finden Sie unten.


// dieses $app kann Teil Ihres Codes sein oder
// Sie können einfach null übergeben und es wird
// aus Flight::app() im Konstruktor abgerufen
$app = Flight::app();

// Derzeit akzeptiert es dies als Dateipuffer. Andere können in Zukunft leicht hinzugefügt werden.
$Cache = new Wruczek\PhpFileCache\PhpFileCache;

$Berechtigungen = new \flight\Permission($current_role, $app, $Cache);
$Berechtigungen->defineRulesFromClassMethods(MeineApp\Berechtigungen::class, 3600); // 3600 gibt an, wie viele Sekunden diese Zwischenspeicherung gültig ist. Lassen Sie dies weg, um die Zwischenspeicherung nicht zu verwenden

Awesome-plugins/simple_job_queue

Einfache Job-Warteschlange

Die einfache Job-Warteschlange ist eine Bibliothek, die verwendet werden kann, um Jobs asynchron zu verarbeiten. Sie kann mit beanstalkd, MySQL/MariaDB, SQLite und PostgreSQL verwendet werden.

Installation

composer require n0nag0n/simple-job-queue

Verwendung

Damit dies funktioniert, benötigen Sie eine Möglichkeit, Jobs zur Warteschlange hinzuzufügen, und eine Möglichkeit, die Jobs zu verarbeiten (einen Worker). Im Folgenden finden Sie Beispiele, wie man einen Job zur Warteschlange hinzufügt und wie man den Job verarbeitet.

Hinzufügen zu Flight

Das Hinzufügen dieses Codes zu Flight ist einfach und erfolgt mit der Methode register(). Unten finden Sie ein Beispiel, wie Sie dies zu Flight hinzufügen.

<?php
require 'vendor/autoload.php';

// Ändern Sie ['mysql'] in ['beanstalkd'], wenn Sie beanstalkd verwenden möchten
Flight::register('queue', n0nag0n\Job_Queue::class, ['mysql'], function($Job_Queue) {
    // Wenn Sie bereits eine PDO-Verbindung zu Flight::db() haben;
    $Job_Queue->addQueueConnection(Flight::db());

    // Oder wenn Sie beanstalkd/Pheanstalk verwenden
    $pheanstalk = Pheanstalk\Pheanstalk::create('127.0.0.1');
    $Job_Queue->addQueueConnection($pheanstalk);
});

Einen neuen Job hinzufügen

Wenn Sie einen Job hinzufügen, müssen Sie eine Pipeline (Warteschlange) angeben. Dies ist vergleichbar mit einem Kanal in RabbitMQ oder einem Tube in beanstalkd.

<?php
Flight::queue()->selectPipeline('send_important_emails');
Flight::queue()->addJob(json_encode([ 'something' => 'that', 'ends' => 'up', 'a' => 'string' ]));

Einen Worker ausführen

Hier ist eine Beispieldatei, wie man einen Worker ausführt.

<?php

require 'vendor/autoload.php';

$Job_Queue = new n0nag0n\Job_Queue('mysql');
// PDO-Verbindung
$PDO = new PDO('mysql:dbname=testdb;host=127.0.0.1', 'user', 'pass');
$Job_Queue->addQueueConnection($PDO);

// Oder wenn Sie beanstalkd/Pheanstalk verwenden
$pheanstalk = Pheanstalk\Pheanstalk::create('127.0.0.1');
$Job_Queue->addQueueConnection($pheanstalk);

$Job_Queue->watchPipeline('send_important_emails');
while(true) {
    $job = $Job_Queue->getNextJobAndReserve();

    // Passen Sie es an, was Ihnen nachts besser schlafen lässt (nur für Datenbankwarteschlangen, beanstalkd benötigt diese if-Anweisung nicht)
    if(empty($job)) {
        usleep(500000);
        continue;
    }

    echo "Verarbeite {$job['id']}\n";
    $payload = json_decode($job['payload'], true);

    try {
        $result = doSomethingThatDoesSomething($payload);

        if($result === true) {
            $Job_Queue->deleteJob($job);
        } else {
            // Dies entfernt es aus der bereitstehenden Warteschlange und legt es in eine andere Warteschlange, die später aufgegriffen und "getreten" werden kann.
            $Job_Queue->buryJob($job);
        }
    } catch(Exception $e) {
        $Job_Queue->buryJob($job);
    }
}

Lange Prozesse mit Supervisord verwalten

Supervisord ist ein Prozesskontrollsystem, das sicherstellt, dass Ihre Worker-Prozesse kontinuierlich laufen. Hier ist eine umfassendere Anleitung, wie Sie es mit Ihrem einfachen Job-Queue-Worker einrichten:

Supervisord installieren

# Auf Ubuntu/Debian
sudo apt-get install supervisor

# Auf CentOS/RHEL
sudo yum install supervisor

# Auf macOS mit Homebrew
brew install supervisor

Erstellen eines Worker-Skripts

Zuerst speichern Sie Ihren Worker-Code in einer dedizierten PHP-Datei:

<?php

require 'vendor/autoload.php';

$Job_Queue = new n0nag0n\Job_Queue('mysql');
// PDO-Verbindung
$PDO = new PDO('mysql:dbname=your_database;host=127.0.0.1', 'username', 'password');
$Job_Queue->addQueueConnection($PDO);

// Setzen Sie die Pipeline, die überwacht werden soll
$Job_Queue->watchPipeline('send_important_emails');

// Protokolliere den Start des Workers
echo date('Y-m-d H:i:s') . " - Worker gestartet\n";

while(true) {
    $job = $Job_Queue->getNextJobAndReserve();

    if(empty($job)) {
        usleep(500000); // Schlafen für 0,5 Sekunden
        continue;
    }

    echo date('Y-m-d H:i:s') . " - Verarbeite Job {$job['id']}\n";
    $payload = json_decode($job['payload'], true);

    try {
        $result = doSomethingThatDoesSomething($payload);

        if($result === true) {
            $Job_Queue->deleteJob($job);
            echo date('Y-m-d H:i:s') . " - Job {$job['id']} erfolgreich abgeschlossen\n";
        } else {
            $Job_Queue->buryJob($job);
            echo date('Y-m-d H:i:s') . " - Job {$job['id']} fehlgeschlagen, beerdigt\n";
        }
    } catch(Exception $e) {
        $Job_Queue->buryJob($job);
        echo date('Y-m-d H:i:s') . " - Ausnahme bei der Verarbeitung des Jobs {$job['id']}: {$e->getMessage()}\n";
    }
}

Konfigurieren von Supervisord

Erstellen Sie eine Konfigurationsdatei für Ihren Worker:

[program:email_worker]
command=php /path/to/worker.php
directory=/path/to/project
autostart=true
autorestart=true
startretries=3
stderr_logfile=/var/log/simple_job_queue_err.log
stdout_logfile=/var/log/simple_job_queue.log
user=www-data
numprocs=2
process_name=%(program_name)s_%(process_num)02d

Wichtige Konfigurationsoptionen:

Worker mit Supervisorctl verwalten

Nach dem Erstellen oder Modifizieren der Konfiguration:

# Supervisor-Konfiguration neu laden
sudo supervisorctl reread
sudo supervisorctl update

# Steuerung spezifischer Worker-Prozesse
sudo supervisorctl start email_worker:*
sudo supervisorctl stop email_worker:*
sudo supervisorctl restart email_worker:*
sudo supervisorctl status email_worker:*

Mehrere Pipelines ausführen

Für mehrere Pipelines erstellen Sie separate Worker-Dateien und Konfigurationen:

[program:email_worker]
command=php /path/to/email_worker.php
# ... andere Konfigurationen ...

[program:notification_worker]
command=php /path/to/notification_worker.php
# ... andere Konfigurationen ...

Überwachen und Protokolle

Überprüfen Sie die Protokolle, um die Aktivität der Worker zu überwachen:

# Protokolle anzeigen
sudo tail -f /var/log/simple_job_queue.log

# Status überprüfen
sudo supervisorctl status

Dieses Setup sorgt dafür, dass Ihre Job-Worker auch nach Abstürzen, Serverneustarts oder anderen Problemen weiterlaufen, was Ihr Warteschlangensystem zuverlässig für Produktionsumgebungen macht.

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/ghost_session

Ghostff/Session

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

Klicken Sie hier, um den Code zu sehen.

Installation

Installieren Sie mit Composer.

composer require ghostff/session

Grundkonfiguration

Sie sind nicht verpflichtet, etwas zu übergeben, um die Standardeinstellungen mit Ihrer Sitzung zu verwenden. Sie können mehr über die Einstellungen im Github Readme lesen.


use Ghostff\Session\Session;

require 'vendor/autoload.php';

$app = Flight::app();

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

// Eine Sache, die Sie sich merken müssen, ist, dass Sie Ihre Sitzung bei jedem Seitenaufruf bestätigen müssen
// oder Sie müssen auto_commit in Ihrer Konfiguration aktivieren. 

Einfaches Beispiel

Hier ist ein einfaches Beispiel, wie Sie dies verwenden könnten.

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

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

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

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

// Diese Überprüfung könnte in der Logik der eingeschränkten Seite sein, oder mit Middleware umhüllt werden.
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 die eingeschränkte Seite durch
});

// die Middleware-Version
Flight::route('/some-restricted-page', function() {
    // reguläre Seitenlogik
})->addMiddleware(function() {
    $session = Flight::session();

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

Komplexeres Beispiel

Hier ist ein komplexeres Beispiel, wie Sie dies verwenden könnten.


use Ghostff\Session\Session;

require 'vendor/autoload.php';

$app = Flight::app();

// Legen Sie einen benutzerdefinierten Pfad zu Ihrer Sitzungskonfigurationsdatei fest und geben Sie ihr eine zufällige Zeichenfolge für die Sitzungs-ID
$app->register('session', Session::class, [ 'path/to/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 "von allen Geräten abmelden" Funktionalität möchten)
            Session::CONFIG_DRIVER        => Ghostff\Session\Drivers\MySql::class,
            Session::CONFIG_ENCRYPT_DATA  => true,
            Session::CONFIG_SALT_KEY      => hash('sha256', 'my-super-S3CR3T-salt'), // Bitte ändern Sie dies in etwas anderes
            Session::CONFIG_AUTO_COMMIT   => true, // Tun Sie dies nur, wenn es erforderlich ist und/oder es schwierig ist, Ihre Sitzung zu committen.
                                                   // Zusätzlich könnten Sie Flight::after('start', function() { Flight::session()->commit(); }); tun
            Session::CONFIG_MYSQL_DS         => [
                'driver'    => 'mysql',             # Datenbanktreiber für PDO-DNS z.B. (mysql:host=...;dbname=...)
                'host'      => '127.0.0.1',         # Datenbankhost
                'db_name'   => 'my_app_database',   # Datenbankname
                'db_table'  => 'sessions',          # Datenbanktabelle
                'db_user'   => 'root',              # Datenbankbenutzername
                'db_pass'   => '',                  # Datenbankpasswort
                'persistent_conn'=> false,          # Verhindern Sie die Überlastung durch die Herstellung 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
            ]
        ]);
    }
);

Hilfe! Meine Sitzungsdaten werden nicht gespeichert!

Setzen Sie Ihre Sitzungsdaten und sie werden nicht zwischen den Anforderungen gespeichert? Sie haben vielleicht vergessen, Ihre Sitzungsdaten zu bestätigen. Sie können dies tun, indem Sie $session->commit() aufrufen, nachdem Sie Ihre Sitzungsdaten gesetzt haben.

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

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

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

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

Eine andere Möglichkeit ist, wenn Sie Ihren Sitzungsdienst einrichten, müssen Sie auto_commit auf true in Ihrer Konfiguration setzen. Dadurch werden Ihre Sitzungsdaten automatisch nach jeder Anforderung bestätigt.


$app->register('session', Session::class, [ 'path/to/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(); }); tun, um Ihre Sitzungsdaten nach jeder Anfrage zu bestätigen.

Dokumentation

Besuchen Sie das Github Readme für die vollständige Dokumentation. Die Konfigurationsoptionen sind gut dokumentiert in der default_config.php Datei selbst. Der Code ist einfach zu verstehen, wenn Sie dieses Paket selbst durchsehen möchten.

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/migrations

Migrationen

Eine Migration für Ihr Projekt verfolgt alle Datenbankänderungen, die mit Ihrem Projekt verbunden sind. byjg/php-migration ist eine wirklich hilfreiche Kernbibliothek, um Ihnen den Einstieg zu erleichtern.

Installation

PHP-Bibliothek

Wenn Sie nur die PHP-Bibliothek in Ihrem Projekt verwenden möchten:

composer require "byjg/migration"

Befehlszeilenschnittstelle

Die Befehlszeilenschnittstelle ist eigenständig und erfordert keine Installation mit Ihrem Projekt.

Sie können global installieren und einen symbolischen Link erstellen.

composer require "byjg/migration-cli"

Bitte besuchen Sie byjg/migration-cli für weitere Informationen zur Migration CLI.

Unterstützte Datenbanken

Datenbank Treiber Verbindungszeichenfolge
Sqlite pdo_sqlite sqlite:///path/to/file
MySql/MariaDb pdo_mysql mysql://username:password@hostname:port/database
Postgres pdo_pgsql pgsql://username:password@hostname:port/database
Sql Server pdo_dblib, pdo_sysbase Linux dblib://username:password@hostname:port/database
Sql Server pdo_sqlsrv Windows sqlsrv://username:password@hostname:port/database

Wie funktioniert es?

Die Datenbankmigration verwendet reines SQL, um das Datenbankversioning zu verwalten. Um es zum Laufen zu bringen, müssen Sie:

Die SQL-Skripte

Die Skripte sind in drei Gruppen unterteilt:

Das Verzeichnis der Skripte ist :

 <root dir>
     |
     +-- base.sql
     |
     +-- /migrations
              |
              +-- /up
                   |
                   +-- 00001.sql
                   +-- 00002.sql
              +-- /down
                   |
                   +-- 00000.sql
                   +-- 00001.sql

Multi-Entwicklungsumgebung

Wenn Sie mit mehreren Entwicklern und mehreren Branches arbeiten, ist es schwierig zu bestimmen, welche Nummer die nächste ist.

In diesem Fall haben Sie das Suffix "-dev" nach der Versionsnummer.

Sehen Sie sich das Szenario an:

In beiden Fällen werden die Entwickler eine Datei mit dem Namen 43-dev.sql erstellen. Beide Entwickler werden ohne Probleme hoch und runter migrieren können, und Ihre lokale Version wird 43 sein.

Aber Entwickler 1 hat seine Änderungen zusammengeführt und eine endgültige Version 43.sql erstellt (git mv 43-dev.sql 43.sql). Wenn Entwickler 2 seinen lokalen Branch aktualisiert, hat er eine Datei 43.sql (von dev 1) und seine Datei 43-dev.sql. Wenn er versucht, hoch oder runter zu migrieren, wird das Migrationsskript abgebrochen und ihn warnen, dass es zwei Versionen 43 gibt. In diesem Fall muss Entwickler 2 seine Datei in 44-dev.sql aktualisieren und weiterarbeiten, bis er die Änderungen zusammenführt und eine endgültige Version generiert.

Verwendung der PHP-API und Integration in Ihre Projekte

Die grundlegende Verwendung ist

Sehen Sie sich ein Beispiel an:

<?php
// Erstellen Sie die Verbindungs-URI
// Weitere Informationen: https://github.com/byjg/anydataset#connection-based-on-uri
$connectionUri = new \ByJG\Util\Uri('mysql://migrateuser:migratepwd@localhost/migratedatabase');

// Registrieren Sie die Datenbank oder Datenbanken, die diese URI verarbeiten können:
\ByJG\DbMigration\Migration::registerDatabase(\ByJG\DbMigration\Database\MySqlDatabase::class);

// Erstellen Sie die Migrationsinstanz
$migration = new \ByJG\DbMigration\Migration($connectionUri, '.');

// Fügen Sie eine Callback-Fortschrittsfunktion hinzu, um Informationen von der Ausführung zu erhalten
$migration->addCallbackProgress(function ($action, $currentVersion, $fileInfo) {
    echo "$action, $currentVersion, ${fileInfo['description']}\n";
});

// Stellen Sie die Datenbank mit dem "base.sql"-Skript wieder her
// und führen Sie ALLE vorhandenen Skripte aus, um die Datenbankversion auf die neueste Version zu bringen
$migration->reset();

// Führen Sie ALLE vorhandenen Skripte für hoch oder runter die Datenbankversion aus
// von der aktuellen Version bis zur $version-Nummer;
// Wenn die Versionsnummer nicht angegeben ist, migrieren Sie bis zur letzten Datenbankversion
$migration->update($version = null);

Das Migrationsobjekt steuert die Datenbankversion.

Erstellen einer Versionskontrolle in Ihrem Projekt

<?php
// Registrieren Sie die Datenbank oder Datenbanken, die diese URI verarbeiten können:
\ByJG\DbMigration\Migration::registerDatabase(\ByJG\DbMigration\Database\MySqlDatabase::class);

// Erstellen Sie die Migrationsinstanz
$migration = new \ByJG\DbMigration\Migration($connectionUri, '.');

// Dieser Befehl erstellt die Versions-Tabelle in Ihrer Datenbank
$migration->createVersion();

Aktuelle Version abrufen

<?php
$migration->getCurrentVersion();

Callback zum Steuern des Fortschritts hinzufügen

<?php
$migration->addCallbackProgress(function ($command, $version, $fileInfo) {
    echo "Befehl ausführen: $command bei Version $version - ${fileInfo['description']}, ${fileInfo['exists']}, ${fileInfo['file']}, ${fileInfo['checksum']}\n";
});

Instanz des Db-Treibers abrufen

<?php
$migration->getDbDriver();

Um es zu verwenden, besuchen Sie bitte: https://github.com/byjg/anydataset-db

Teilweise Migration vermeiden (nicht verfügbar für MySQL)

Eine partielle Migration ist, wenn das Migrationsskript in der Mitte des Prozesses aufgrund eines Fehlers oder einer manuellen Unterbrechung unterbrochen wird.

Die Migrationstabelle hat den Status partial up oder partial down und muss manuell behoben werden, bevor sie wieder migrieren kann.

Um diese Situation zu vermeiden, können Sie angeben, dass die Migration in einem Transaktionskontext ausgeführt wird. Wenn das Migrationsskript fehlschlägt, wird die Transaktion zurückgesetzt und die Migrationstabelle wird als complete markiert und die Version wird die unmittelbar vorherige Version vor dem Skript sein, das den Fehler verursacht hat.

Um diese Funktion zu aktivieren, müssen Sie die Methode withTransactionEnabled aufrufen und true als Parameter übergeben:

<?php
$migration->withTransactionEnabled(true);

HINWEIS: Diese Funktion ist nicht für MySQL verfügbar, da es DDL-Befehle innerhalb einer Transaktion nicht unterstützt. Wenn Sie diese Methode mit MySQL verwenden, ignoriert die Migration sie stillschweigend. Weitere Informationen: https://dev.mysql.com/doc/refman/8.0/en/cannot-roll-back.html

Tipps zum Schreiben von SQL-Migrationen für Postgres

Zur Erstellung von Triggern und SQL-Funktionen

-- DO
CREATE FUNCTION emp_stamp() RETURNS trigger AS $emp_stamp$
    BEGIN
        -- Überprüfen, ob empname und salary angegeben sind
        IF NEW.empname IS NULL THEN
            RAISE EXCEPTION 'empname darf nicht null sein'; -- es ist egal, ob diese Kommentare leer sind oder nicht
        END IF; --
        IF NEW.salary IS NULL THEN
            RAISE EXCEPTION '% darf kein null Gehalt haben', NEW.empname; --
        END IF; --

        -- Wer arbeitet für uns, wenn sie dafür bezahlen müssen?
        IF NEW.salary < 0 THEN
            RAISE EXCEPTION '% darf kein negatives Gehalt haben', NEW.empname; --
        END IF; --

        -- Merken Sie, wer die Gehaltsliste wann geändert hat
        NEW.last_date := current_timestamp; --
        NEW.last_user := current_user; --
        RETURN NEW; --
    END; --
$emp_stamp$ LANGUAGE plpgsql;

-- DON'T
CREATE FUNCTION emp_stamp() RETURNS trigger AS $emp_stamp$
    BEGIN
        -- Überprüfen, ob empname und salary angegeben sind
        IF NEW.empname IS NULL THEN
            RAISE EXCEPTION 'empname darf nicht null sein';
        END IF;
        IF NEW.salary IS NULL THEN
            RAISE EXCEPTION '% darf kein null Gehalt haben', NEW.empname;
        END IF;

        -- Wer arbeitet für uns, wenn sie dafür bezahlen müssen?
        IF NEW.salary < 0 THEN
            RAISE EXCEPTION '% darf kein negatives Gehalt haben', NEW.empname;
        END IF;

        -- Merken Sie, wer die Gehaltsliste wann geändert hat
        NEW.last_date := current_timestamp;
        NEW.last_user := current_user;
        RETURN NEW;
    END;
$emp_stamp$ LANGUAGE plpgsql;

Da die PDO-Datenbank-Abstraktionsschicht keine Batchverarbeitungen von SQL-Anweisungen ausführen kann, muss byjg/migration, wenn es eine Migrationsdatei liest, den gesamten Inhalt der SQL-Datei an den Semikolons aufteilen und die Anweisungen einzeln ausführen. Es gibt jedoch eine Art von Anweisung, die mehrere Semikolons in ihrem Körper haben kann: Funktionen.

Um Funktionen korrekt parsen zu können, begann byjg/migration 2.1.0 damit, Migrationsdateien an der Semikolon + EOL-Sequenz anstelle nur am Semikolon aufzuteilen. Auf diese Weise kann byjg/migration sie parsen, wenn Sie nach jedem inneren Semikolon einer Funktionsdefinition einen leeren Kommentar anhängen.

Leider wird die Bibliothek die CREATE FUNCTION-Anweisung in mehrere Teile aufteilen und die Migration wird fehlschlagen, wenn Sie vergessen, diese Kommentare hinzuzufügen.

Vermeidung des Doppelpunktzeichens (:)

-- DO
CREATE TABLE bookings (
  booking_id UUID PRIMARY KEY,
  booked_at  TIMESTAMPTZ NOT NULL CHECK (CAST(booked_at AS DATE) <= check_in),
  check_in   DATE NOT NULL
);

-- DON'T
CREATE TABLE bookings (
  booking_id UUID PRIMARY KEY,
  booked_at  TIMESTAMPTZ NOT NULL CHECK (booked_at::DATE <= check_in),
  check_in   DATE NOT NULL
);

Da PDO das Doppelpunkt-Zeichen verwendet, um benannte Parameter in vorbereiteten Anweisungen zu kennzeichnen, führt die Verwendung zu Problemen in anderen Kontexten.

Zum Beispiel können PostgreSQL-Anweisungen :: verwenden, um Werte zwischen Typen zu casten. Auf der anderen Seite wird PDO dies als ungültigen benannten Parameter in einem ungültigen Kontext behandeln und fehlschlagen, wenn er versucht, es auszuführen.

Die einzige Möglichkeit, diese Inkonsistenz zu beheben, besteht darin, Doppelpunkte ganz zu vermeiden (in diesem Fall hat PostgreSQL auch eine alternative Syntax: CAST(value AS type)).

Verwenden Sie einen SQL-Editor

Abschließend kann das Schreiben manueller SQL-Migrationen mühsam sein, aber es ist deutlich einfacher, wenn Sie einen Editor verwenden, der die SQL-Syntax versteht, Autovervollständigung bietet, Ihr aktuelles Datenbankschema inspiziert und/oder Ihren Code automatisch formatiert.

Umgang mit unterschiedlichen Migrationen innerhalb eines Schemas

Wenn Sie unterschiedliche Migrationsskripte und Versionen innerhalb desselben Schemas erstellen müssen, ist dies möglich, aber es ist zu riskant und ich empfehle es nicht.

Um dies zu tun, müssen Sie unterschiedliche "Migrationstabellen" erstellen, indem Sie den Parameter an den Konstruktor übergeben.

<?php
$migration = new \ByJG\DbMigration\Migration("db:/uri", "/path", true, "NEUER_MIGRATIONSTABELLENNAME");

Aus Sicherheitsgründen ist diese Funktion nicht über die Befehlszeile verfügbar, aber Sie können die Umgebungsvariable MIGRATION_VERSION verwenden, um den Namen zu speichern.

Wir empfehlen dringend, diese Funktion nicht zu verwenden. Die Empfehlung ist, eine Migration für ein Schema durchzuführen.

Ausführen von Unit-Tests

Basis-Unit-Tests können ausgeführt werden mit:

vendor/bin/phpunit

Ausführen von Datenbanktests

Integrationstests erfordern, dass Sie die Datenbanken online und verfügbar haben. Wir haben ein einfaches docker-compose.yml bereitgestellt, und Sie können es verwenden, um die Datenbanken für Tests zu starten.

Ausführen der Datenbanken

docker-compose up -d postgres mysql mssql

Führen Sie die Tests aus

vendor/bin/phpunit
vendor/bin/phpunit tests/SqliteDatabase*
vendor/bin/phpunit tests/MysqlDatabase*
vendor/bin/phpunit tests/PostgresDatabase*
vendor/bin/phpunit tests/SqlServerDblibDatabase*
vendor/bin/phpunit tests/SqlServerSqlsrvDatabase*

Optional können Sie den Host und das Passwort, das von den Unit-Tests verwendet wird, festlegen.

export MYSQL_TEST_HOST=localhost     # standardmäßig localhost
export MYSQL_PASSWORD=newpassword      # verwenden Sie '.' wenn Sie ein leeres Passwort haben möchten
export PSQL_TEST_HOST=localhost        # standardmäßig localhost
export PSQL_PASSWORD=newpassword       # verwenden Sie '.' wenn Sie ein leeres Passwort haben möchten
export MSSQL_TEST_HOST=localhost       # standardmäßig localhost
export MSSQL_PASSWORD=Pa55word
export SQLITE_TEST_HOST=/tmp/test.db   # standardmäßig /tmp/test.db

Awesome-plugins/session

FlightPHP Sitzung - Leichtgewichtiger dateibasiierter Sitzungs-Handler

Dies ist ein leichtgewichtiger, dateibasierter Sitzungs-Handler-Plugin für das Flight PHP Framework. Es bietet eine einfache, aber leistungsstarke Lösung zum Verwalten von Sitzungen, mit Funktionen wie nicht-blockierenden Sitzungslesungen, optionaler Verschlüsselung, Auto-Commit-Funktion und einem Testmodus für die Entwicklung. Sitzungsdaten werden in Dateien gespeichert, was es ideal für Anwendungen macht, die keine Datenbank benötigen.

Wenn Sie eine Datenbank verwenden möchten, sehen Sie sich das ghostff/session Plugin an, das viele dieser gleichen Funktionen, aber mit einem Datenbank-Backend bietet.

Besuchen Sie das Github-Repository für den vollständigen Quellcode und Details.

Installation

Installieren Sie das Plugin über Composer:

composer require flightphp/session

Grundlegende Verwendung

Hier ist ein einfaches Beispiel, wie man das flightphp/session Plugin in Ihrer Flight-Anwendung verwendet:

require 'vendor/autoload.php';

use flight\Session;

$app = Flight::app();

// Registrieren Sie den Sitzungsdienst
$app->register('session', Session::class);

// Beispielroute mit Sitzungsverwendung
Flight::route('/login', function() {
    $session = Flight::session();
    $session->set('user_id', 123);
    $session->set('username', 'johndoe');
    $session->set('is_admin', false);

    echo $session->get('username'); // Gibt aus: johndoe
    echo $session->get('preferences', 'default_theme'); // Gibt aus: default_theme

    if ($session->get('user_id')) {
        Flight::json(['message' => 'Benutzer ist angemeldet!', 'user_id' => $session->get('user_id')]);
    }
});

Flight::route('/logout', function() {
    $session = Flight::session();
    $session->clear(); // Löscht alle Sitzungsdaten
    Flight::json(['message' => 'Erfolgreich abgemeldet']);
});

Flight::start();

Wichtige Punkte

Konfiguration

Sie können den Sitzungs-Handler anpassen, indem Sie ein Array von Optionen beim Registrieren übergeben:

$app->register('session', Session::class, [
    'save_path' => '/custom/path/to/sessions',         // Verzeichnis für Sitzungsdateien
    'encryption_key' => 'a-secure-32-byte-key-here',   // Verschlüsselung aktivieren (32 Bytes empfohlen für AES-256-CBC)
    'auto_commit' => false,                            // Auto-Commit für manuelle Kontrolle deaktivieren
    'start_session' => true,                           // Sitzung automatisch starten (Standard: true)
    'test_mode' => false                               // Testmodus für die Entwicklung aktivieren
]);

Konfigurationsoptionen

Option Beschreibung Standardwert
save_path Verzeichnis, in dem Sitzungsdateien gespeichert werden sys_get_temp_dir() . '/flight_sessions'
encryption_key Schlüssel für die AES-256-CBC-Verschlüsselung (optional) null (keine Verschlüsselung)
auto_commit Automatisches Speichern von Sitzungsdaten beim Herunterfahren true
start_session Sitzung automatisch starten true
test_mode Im Testmodus ausführen, ohne PHP-Sitzungen zu beeinflussen false
test_session_id Benutzerdefinierte Sitzungs-ID für den Testmodus (optional) Zufällig generiert, falls nicht festgelegt

Erweiterte Verwendung

Manuelles Commit

Wenn Sie Auto-Commit deaktivieren, müssen Sie die Änderungen manuell committen:

$app->register('session', Session::class, ['auto_commit' => false]);

Flight::route('/update', function() {
    $session = Flight::session();
    $session->set('key', 'value');
    $session->commit(); // Änderungen explizit speichern
});

Sitzungssicherheit mit Verschlüsselung

Aktivieren Sie die Verschlüsselung für sensible Daten:

$app->register('session', Session::class, [
    'encryption_key' => 'your-32-byte-secret-key-here'
]);

Flight::route('/secure', function() {
    $session = Flight::session();
    $session->set('credit_card', '4111-1111-1111-1111'); // Automatisch verschlüsselt
    echo $session->get('credit_card'); // Bei der Abfrage entschlüsselt
});

Sitzungsregeneration

Regenerieren Sie die Sitzungs-ID zur Sicherheit (z.B. nach dem Login):

Flight::route('/post-login', function() {
    $session = Flight::session();
    $session->regenerate(); // Neue ID, Daten behalten
    // ODER
    $session->regenerate(true); // Neue ID, alte Daten löschen
});

Middleware-Beispiel

Schützen Sie Routen mit sitzungsbasierter Authentifizierung:

Flight::route('/admin', function() {
    Flight::json(['message' => 'Willkommen im Admin-Panel']);
})->addMiddleware(function() {
    $session = Flight::session();
    if (!$session->get('is_admin')) {
        Flight::halt(403, 'Zugriff verweigert');
    }
});

Dies ist nur ein einfaches Beispiel, wie man dies in Middleware verwendet. Für ein umfassenderes Beispiel siehe die Middleware Dokumentation.

Methoden

Die Session Klasse bietet diese Methoden:

Alle Methoden außer get() und id() geben die Session-Instanz für das Chaining zurück.

Warum dieses Plugin verwenden?

Technische Details

Mitwirken

Beiträge sind willkommen! Forken Sie das Repository, nehmen Sie Ihre Änderungen vor und senden Sie eine Pull-Anfrage. Melden Sie Fehler oder schlagen Sie Funktionen über den Github-Fehlerverfolger vor.

Lizenz

Dieses Plugin ist unter der MIT-Lizenz lizenziert. Siehe das Github-Repository für Details.

Awesome-plugins/runway

Startbahn

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

Klicken Sie hier, um den Code anzusehen.

Installation

Mit Composer installieren.

composer require flightphp/startbahn

Grundkonfiguration

Das erste Mal, wenn Sie Startbahn ausführen, wird es Sie durch einen Einrichtungsprozess führen und eine .runway.json-Konfigurationsdatei im Stammverzeichnis Ihres Projekts erstellen. Diese Datei wird einige notwendige Konfigurationen enthalten, damit Startbahn ordnungsgemäß funktioniert.

Verwendung

Startbahn hat 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 startbahn [Befehl] im Stammverzeichnis Ihres Projekts ausführen.
  2. Wenn Sie Startbahn als über Composer installiertes Paket verwenden, können Sie vendor/bin/startbahn [Befehl] im Stammverzeichnis Ihres Projekts ausführen.

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

php startbahn routes --help

Hier sind ein paar Beispiele:

Einen Controller generieren

Basierend auf der Konfiguration in Ihrer .runway.json-Datei wird der Standardort einen Controller für Sie im app/controllers/ Verzeichnis generieren.

php startbahn make:controller MeinController

Einen Aktiven Datensatz-Model generieren

Basierend auf der Konfiguration in Ihrer .runway.json-Datei wird der Standardort einen Controller für Sie im app/records/ Verzeichnis generieren.

php startbahn make:record benutzer

Wenn Sie zum Beispiel die benutzer Tabelle mit dem folgenden Schema haben: id, name, email, created_at, updated_at, wird eine Datei ähnlich der folgenden in der app/records/BenutzerDatensatz.php erstellt:

<?php

declare(strict_types=1);

namespace app\records;

/**
 * ActiveRecord-Klasse für die benutzer Tabelle.
 * @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
 * // Sie können hier auch Beziehungen hinzufügen, sobald Sie sie im $relations-Array definieren
 * @property CompanyRecord $company Beispiel für eine Beziehung
 */
class BenutzerDatensatz erstreckt sich über \flight\ActiveRecord
{
    /**
     * @var array $relations Setzen Sie die Beziehungen für das Modell
     *   https://docs.flightphp.com/awesome-plugins/active-record#relationships
     */
    protected array $relations = [];

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

Alle Routen anzeigen

Dies wird alle Routen anzeigen, die derzeit bei Flight registriert sind.

php startbahn routes

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

# Nur GET-Routen anzeigen
php startbahn routes --get

# Nur POST-Routen anzeigen
php startbahn routes --post

# usw.

Anpassen von Startbahn

Wenn Sie entweder ein Paket für Flight erstellen oder Ihre eigenen benutzerdefinierten Befehle in Ihr Projekt integrieren möchten, können Sie dies tun, indem Sie ein src/befehle/, flight/befehle/, app/befehle/ oder befehle/ 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 ausführen-Methode.

<?php

declare(strict_types=1);

namespace flight\commands;

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

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

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

        // Hier etwas machen

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

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

Awesome-plugins/tracy_extensions

Tracy Flight Panel Erweiterungen

Dies ist eine Sammlung 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!

Flight-Daten Flight-Datenbank Flight-Anfrage

Klicke hier, um den Code anzusehen.

Installation

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

Konfiguration

Es gibt sehr wenig Konfiguration, die Sie benötigen, 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 die gleichen 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 erfasst es die Zeit, die Abfrage und die Parameter, wann immer Sie eine Abfrage machen

// Dies verbindet die Punkte
if(Debugger::$showBar === true) {
    // Dies muss falsch sein, oder Tracy kann tatsächlich nicht gerendert werden :(
    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 z.B. ghostff/session), können Sie beliebige Sitzungsdaten an Tracy übergeben, und es wird sie automatisch für Sie ausgeben. Übergeben Sie es mit dem session_data-Schlüssel im zweiten Parameter des Konstruktors von TracyExtensionLoader.


use Ghostff\Session\Session;

require 'vendor/autoload.php';

$app = Flight::app();

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

if(Debugger::$showBar === true) {
    // Dies muss falsch sein, oder Tracy kann tatsächlich nicht gerendert werden :(
    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 an den TracyExtensionLoader-Konstruktor mit dem latte-Schlüssel im zweiten Parameter ü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 falsch sein, oder Tracy kann tatsächlich nicht gerendert werden :(
    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 Aktive Datensätze

Ein aktiver Datensatz ist die Zuordnung einer Datenbankentität zu einem PHP-Objekt. Einfach gesagt, wenn Sie eine Tabelle für Benutzer in Ihrer Datenbank haben, können Sie eine Zeile in dieser Tabelle in eine User-Klasse und ein $user-Objekt in Ihrem Code übersetzen. Siehe ein einfaches Beispiel.

Klicken Sie hier für das Repository auf GitHub.

Einfaches Beispiel

Angenommen, Sie haben die folgende Tabelle:

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

Jetzt können Sie eine neue Klasse einrichten, um diese Tabelle darzustellen:

/**
 * Eine ActiveRecord-Klasse ist normalerweise im Singular
 * 
 * Es wird dringend empfohlen, die Eigenschaften der Tabelle hier als Kommentare hinzuzufügen
 * 
 * @property int    $id
 * @property string $name
 * @property string $password
 */ 
class User extends flight\ActiveRecord {
    public function __construct($database_connection)
    {
        // so können Sie es einrichten
        parent::__construct($database_connection, 'users');
        // oder so
        parent::__construct($database_connection, null, [ 'table' => 'users']);
    }
}

Jetzt beobachten Sie, wie die Magie geschieht!

// für sqlite
$database_connection = new PDO('sqlite:test.db'); // dies ist nur ein Beispiel, Sie würden wahrscheinlich eine echte Datenbankverbindung verwenden

// für mysql
$database_connection = new PDO('mysql:host=localhost;dbname=test_db&charset=utf8bm4', 'username', 'password');

// oder mysqli
$database_connection = new mysqli('localhost', 'username', 'password', 'test_db');
// oder mysqli mit nicht objektbasierter Erstellung
$database_connection = mysqli_connect('localhost', 'username', 'password', 'test_db');

$user = new User($database_connection);
$user->name = 'Bobby Tables';
$user->password = password_hash('ein cooles Passwort');
$user->insert();
// oder $user->save();

echo $user->id; // 1

$user->name = 'Joseph Mamma';
$user->password = password_hash('ein anderes cooles Passwort!!!');
$user->insert();
// $user->save() kann hier nicht verwendet werden, da es als Update betrachtet wird!

echo $user->id; // 2

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

$user->find(1); // finde id = 1 in der Datenbank und gebe sie zurück.
echo $user->name; // 'Bobby Tables'

Und was ist, wenn Sie alle Benutzer finden möchten?

$users = $user->findAll();

Wie wäre es mit einer bestimmten Bedingung?

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

Sehen Sie, wie viel Spaß das macht? Lassen Sie uns das 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. Vollständig Ihnen überlassen.

Eigenständig

Stellen Sie sicher, dass Sie eine PDO-Verbindung an den Konstruktor weitergeben.

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

$User = new User($pdo_connection);

Möchten Sie nicht immer Ihre Datenbankverbindung im Konstruktor einstellen? Siehe Datenbankverbindungsmanagement für weitere Ideen!

Als Methode in Flight registrieren

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

Flight::register('user', 'User', [ $pdo_connection ]);

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

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

runway Methoden

runway ist ein CLI-Tool für Flight, das einen benutzerdefinierten Befehl für diese Bibliothek hat.

# Verwendung
php runway make:record database_table_name [class_name]

# Beispiel
php runway make:record users

Dies wird eine neue Klasse im Verzeichnis app/records/ als UserRecord.php mit folgendem Inhalt erstellen:

<?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 $username
 * @property string $email
 * @property string $password_hash
 * @property string $created_dt
 */
class UserRecord extends \flight\ActiveRecord
{
    /**
     * @var array $relations Legen Sie die Beziehungen für das Modell fest
     *   https://docs.flightphp.com/awesome-plugins/active-record#relationships
     */
    protected array $relations = [
        // 'relation_name' => [ self::HAS_MANY, 'RelatedClass', 'foreign_key' ],
    ];

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

CRUD-Funktionen

find($id = null) : boolean|ActiveRecord

Findet einen Datensatz und weist ihn dem aktuellen Objekt zu. Wenn Sie eine $id irgendeiner Art übergeben, wird eine Abfrage mit 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.

// finde einen Datensatz mit vorher festgelegten Bedingungen
$user->notNull('password')->orderBy('id DESC')->find();

// finde einen Datensatz nach einer bestimmten id
$id = 123;
$user->find($id);

findAll(): array<int,ActiveRecord>

Findet alle Datensätze in der von Ihnen angegebenen Tabelle.

$user->findAll();

isHydrated(): boolean (v0.4.0)

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

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

insert(): boolean|ActiveRecord

Fügt den aktuellen Datensatz in die Datenbank ein.

$user = new User($pdo_connection);
$user->name = 'demo';
$user->password = md5('demo');
$user->insert();
Textbasierte Primärschlüssel

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

$user = new User($pdo_connection, [ 'primaryKey' => 'uuid' ]);
$user->uuid = 'some-uuid';
$user->name = 'demo';
$user->password = md5('demo');
$user->insert(); // oder $user->save();

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

class User extends flight\ActiveRecord {
    public function __construct($database_connection)
    {
        parent::__construct($database_connection, 'users', [ 'primaryKey' => 'uuid' ]);
        // Sie können auch so anstelle des obigen Arrays den Primärschlüssel festlegen.
        $this->primaryKey = 'uuid';
    }

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

Wenn Sie den Primärschlüssel vor dem Einfügen nicht festlegen, wird er auf den rowid gesetzt und die Datenbank wird ihn für Sie generieren, aber es wird nicht gespeichert, da dieses Feld möglicherweise nicht in Ihrer Tabelle vorhanden ist. Aus diesem Grund wird empfohlen, das Ereignis zu verwenden, um dies automatisch für Sie zu verwalten.

update(): boolean|ActiveRecord

Aktualisiert den aktuellen Datensatz in der Datenbank.

$user->greaterThan('id', 0)->orderBy('id desc')->find();
$user->email = 'test@example.com';
$user->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, andernfalls wird er eingefügt.

$user = new User($pdo_connection);
$user->name = 'demo';
$user->password = md5('demo');
$user->save();

Hinweis: Wenn Sie Beziehungen, die in der Klasse definiert sind, haben, werden diese ebenfalls rekursiv gespeichert, wenn sie definiert, instanziiert und überarbeitete Daten zum Aktualisieren aufweisen. (v0.4.0 und höher)

delete(): boolean

Löscht den aktuellen Datensatz aus der Datenbank.

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

Sie können auch mehrere Datensätze löschen, indem Sie zuvor eine Suche durchführen.

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

dirty(array $dirty = []): ActiveRecord

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

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

// zu diesem Zeitpunkt ist nichts "schmutzig".

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

$user->password = password_hash('newpassword'); // jetzt ist dies schmutzig
$user->dirty(); // Nichts zu übergebendes löscht alle schmutzigen Einträge.
$user->update(); // nichts wird aktualisiert, da nichts als schmutzig erfasst wurde.

$user->dirty([ 'name' => 'etwas', 'password' => password_hash('ein anderes Passwort') ]);
$user->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.

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

isDirty(): boolean (v0.4.0)

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

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

reset(bool $include_query_data = true): ActiveRecord

Setzt den aktuellen Datensatz auf seinen ursprünglichen Zustand zurück. Dies ist wirklich gut in Schleifenverhalten zu verwenden. Wenn Sie true übergeben, werden auch die Abfragedaten zurückgesetzt, die verwendet wurden, um das aktuelle Objekt zu finden (Standardverhalten).

$users = $user->greaterThan('id', 0)->orderBy('id desc')->find();
$user_company = new UserCompany($pdo_connection);

foreach($users as $user) {
    $user_company->reset(); // beginne mit einem sauberen Zustand
    $user_company->user_id = $user->id;
    $user_company->company_id = $some_company_id;
    $user_company->insert();
}

getBuiltSql(): string (v0.4.1)

Nachdem Sie eine find(), findAll(), insert(), update() oder save()-Methode ausgeführt haben, können Sie das SQL abrufen, das erstellt wurde und für Debugging-Zwecke 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)

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

from(string $table)

Technisch können Sie auch eine andere Tabelle wählen! Warum nicht?!

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

join(string $table_name, string $join_condition)

Sie können sogar eine andere Tabelle in der Datenbank verknüpfen.

$user->join('contacts', 'contacts.user_id = users.id')->find();

where(string $where_conditions)

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

$user->where('id=1 AND name="demo"')->find();

Sicherheitsnotiz - Sie könnten versucht sein, etwas wie $user->where("id = '{$id}' AND name = '{$name}'")->find(); zu tun. BITTE MACHEN SIE DAS NICHT!!! Dies ist anfällig für das, was als SQL-Injection-Angriffe bekannt ist. Es gibt viele Artikel online, bitte googeln Sie "sql injection attacks php" und Sie werden viele Artikel zu diesem Thema finden. Der richtige Weg, dies mit dieser Bibliothek zu behandeln, besteht darin, anstelle dieser where()-Methode etwas mehr wie $user->eq('id', $id)->eq('name', $name)->find(); zu tun. Wenn Sie dies absolut tun müssen, hat die PDO-Bibliothek $pdo->quote($var), um es für Sie zu escapen. Erst nachdem Sie quote() verwenden, 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.

$user->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.

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

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

Begrenzen Sie die Anzahl der zurückgegebenen Datensätze. Wenn eine zweite ganze Zahl angegeben wird, wird sie wie in SQL offset und limit.

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

WHERE-Bedingungen

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

Wo field = $value

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

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

Wo field <> $value

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

isNull(string $field)

Wo field IS NULL

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

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

Wo field IS NOT NULL

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

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

Wo field > $value

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

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

Wo field < $value

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

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

Wo field >= $value

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

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

Wo field <= $value

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

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

Wo field LIKE $value oder field NOT LIKE $value

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

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

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

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

between(string $field, array $values)

Wo field BETWEEN $value AND $value1

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

ODER-Bedingungen

Es ist möglich, Ihre Bedingungen in einer ODER-Anweisung einzuwickeln. Dies erfolgt entweder durch die Methoden startWrap() und endWrap() oder indem Sie den 3. Parameter der Bedingung nach dem Feld und dem Wert ausfüllen.

// Methode 1
$user->eq('id', 1)->startWrap()->eq('name', 'demo')->or()->eq('name', 'test')->endWrap('OR')->find();
// Dies wird ausgewertet zu `id = 1 AND (name = 'demo' OR name = 'test')`

// Methode 2
$user->eq('id', 1)->eq('name', 'demo', 'OR')->find();
// Dies wird ausgewertet zu `id = 1 OR name = 'demo'`

Beziehungen

Sie können mit dieser Bibliothek mehrere Arten von Beziehungen festlegen. Sie können Eins-zu-viele- und Eins-zu-eins-Beziehungen zwischen Tabellen festlegen. Dies erfordert eine kleine zusätzliche Einrichtung in der Klasse im Voraus.

Das Festlegen des $relations-Arrays ist nicht schwer, aber die richtige Syntax zu erraten, kann verwirrend sein.

protected array $relations = [
    // Sie können den Schlüssel benennen, wie Sie möchten. Der Name des ActiveRecord ist wahrscheinlich gut. Beispiel: user, contact, client
    'user' => [
        // 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
        // abhängig vom Beziehungstyp
        // self::HAS_ONE = der Fremdschlüssel, der auf den Join verweist
        // self::HAS_MANY = der Fremdschlüssel, der auf den Join verweist
        // self::BELONGS_TO = der lokale Schlüssel, der auf den Join verweist
        'local_or_foreign_key',
        // nur zur Info, dies verbindet sich ebenfalls 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 beim Verknüpfen der Beziehung möchten
        // $record->eq('client_id', 5)->select('COUNT(*) as count')->limit(5))

        // optional
        'back_reference_name' // dies ist, wenn Sie diese Beziehung wieder auf sich selbst zurückverweisen möchten, z. B.: $user->contact->user;
    ];
]
class User extends ActiveRecord{
    protected array $relations = [
        'contacts' => [ self::HAS_MANY, Contact::class, 'user_id' ],
        'contact' => [ self::HAS_ONE, Contact::class, 'user_id' ],
    ];

    public function __construct($database_connection)
    {
        parent::__construct($database_connection, 'users');
    }
}

class Contact extends ActiveRecord{
    protected array $relations = [
        'user' => [ self::BELONGS_TO, User::class, 'user_id' ],
        'user_with_backref' => [ self::BELONGS_TO, User::class, 'user_id', [], 'contact' ],
    ];
    public function __construct($database_connection)
    {
        parent::__construct($database_connection, 'contacts');
    }
}

Jetzt haben wir die Referenzen eingerichtet, sodass wir sie sehr einfach verwenden können!

$user = new User($pdo_connection);

// finde den aktuellsten Benutzer.
$user->notNull('id')->orderBy('id desc')->find();

// hole Kontakte mithilfe der Beziehung:
foreach($user->contacts as $contact) {
    echo $contact->id;
}

// oder wir können es andersherum machen.
$contact = new Contact();

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

// hole Benutzer mithilfe der Beziehung:
echo $contact->user->name; // dies ist der Benutzername

Ganz schön cool, oder?

Benutzerdefinierte Daten festlegen

Manchmal müssen Sie etwas Einzigartiges an Ihrem ActiveRecord anhängen, z. B. eine benutzerdefinierte Berechnung, die es einfacher machen könnte, einfach an das Objekt anzuhängen, das dann an beispielsweise eine Vorlage übergeben wird.

setCustomData(string $field, mixed $value)

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

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

Und dann können Sie einfach auf sie zugreifen wie auf eine normale Objekt-Eigenschaft.

echo $user->page_view_count;

Ereignisse

Eine weitere großartige Funktion dieser Bibliothek sind die Ereignisse. Ereignisse werden zu bestimmten Zeiten ausgelöst, basierend auf bestimmten Methoden, die Sie aufrufen. Sie sind sehr hilfreich, um automatisch Daten für Sie einzurichten.

onConstruct(ActiveRecord $ActiveRecord, array &config)

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

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

//
//
//

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

    protected function onConstruct(self $self, array &$config) { // vergessen Sie nicht, die &-Referenz
        // Sie könnten dies tun, um die Verbindung automatisch festzulegen
        $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 jede Abfrage bei Bedarf manipulieren müssen.

class User extends flight\ActiveRecord {

    public function __construct($database_connection)
    {
        parent::__construct($database_connection, 'users');
    }

    protected function beforeFind(self $self) {
        // immer id >= 0 ausführen, wenn das Ihre Vorliebe ist
        $self->gte('id', 0); 
    } 
}

afterFind(ActiveRecord $ActiveRecord)

Dies ist wahrscheinlich nützlicher, wenn Sie immer eine Logik ausführen müssen, jedes Mal, 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 soll's)?

class User extends flight\ActiveRecord {

    public function __construct($database_connection)
    {
        parent::__construct($database_connection, 'users');
    }

    protected function afterFind(self $self) {
        // etwas entschlüsseln
        $self->secret = yourDecryptFunction($self->secret, $some_key);

        // vielleicht etwas Benutzerdefiniertes speichern wie eine 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 jede Abfrage bei Bedarf manipulieren müssen.

class User extends flight\ActiveRecord {

    public function __construct($database_connection)
    {
        parent::__construct($database_connection, 'users');
    }

    protected function beforeFindAll(self $self) {
        // immer id >= 0 ausführen, wenn das Ihre Vorliebe ist
        $self->gte('id', 0); 
    } 
}

afterFindAll(array<int,ActiveRecord> $results)

Ähnlich wie afterFind(), aber Sie können es auf alle Datensätze anwenden!

class User extends flight\ActiveRecord {

    public function __construct($database_connection)
    {
        parent::__construct($database_connection, 'users');
    }

    protected function afterFindAll(array $results) {

        foreach($results as $self) {
            // etwas Cooles tun wie bei afterFind()
        }
    } 
}

beforeInsert(ActiveRecord $ActiveRecord)

Sehr hilfreich, wenn Sie jedes Mal Standardwerte festlegen müssen.

class User extends flight\ActiveRecord {

    public function __construct($database_connection)
    {
        parent::__construct($database_connection, 'users');
    }

    protected function beforeInsert(self $self) {
        // einige sinnvolle Standardwerte festlegen
        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 Benutzerfall, um Daten nach dem Einfügen zu ändern?

class User extends flight\ActiveRecord {

    public function __construct($database_connection)
    {
        parent::__construct($database_connection, 'users');
    }

    protected function afterInsert(self $self) {
        // machen Sie, was Sie möchten
        Flight::cache()->set('most_recent_insert_id', $self->id);
        // oder was auch immer....
    } 
}

beforeUpdate(ActiveRecord $ActiveRecord)

Sehr hilfreich, wenn Sie jedes Mal Standardwerte festlegen müssen, wenn eine Aktualisierung erfolgt.

class User extends flight\ActiveRecord {

    public function __construct($database_connection)
    {
        parent::__construct($database_connection, 'users');
    }

    protected function beforeInsert(self $self) {
        // einige sinnvolle Standardwerte festlegen
        if(!$self->updated_date) {
            $self->updated_date = gmdate('Y-m-d');
        }
    } 
}

afterUpdate(ActiveRecord $ActiveRecord)

Vielleicht haben Sie einen Benutzerfall, um Daten nach der Aktualisierung zu ändern?

class User extends flight\ActiveRecord {

    public function __construct($database_connection)
    {
        parent::__construct($database_connection, 'users');
    }

    protected function afterInsert(self $self) {
        // machen Sie, was Sie möchten
        Flight::cache()->set('most_recently_updated_user_id', $self->id);
        // oder was auch immer....
    } 
}

beforeSave(ActiveRecord $ActiveRecord)/afterSave(ActiveRecord $ActiveRecord)

Dies ist nützlich, wenn Sie Ereignisse auslösen möchten, sowohl wenn Einfügungen als auch Aktualisierungen erfolgen. Ich spare Ihnen die lange Erklärung, aber ich bin mir sicher, dass Sie erraten können, was es ist.

class User extends flight\ActiveRecord {

    public function __construct($database_connection)
    {
        parent::__construct($database_connection, 'users');
    }

    protected function beforeSave(self $self) {
        $self->last_updated = gmdate('Y-m-d H:i:s');
    } 
}

beforeDelete(ActiveRecord $ActiveRecord)/afterDelete(ActiveRecord $ActiveRecord)

Ich bin mir nicht sicher, was Sie hier tun möchten, aber hier wird nicht geurteilt! Legen Sie los!

class User extends flight\ActiveRecord {

    public function __construct($database_connection)
    {
        parent::__construct($database_connection, 'users');
    }

    protected function beforeDelete(self $self) {
        echo 'Er war ein tapferer Soldat... :cry-face:';
    } 
}

Verwaltung der Datenbankverbindung

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() (v0.4.1) festlegen.

$pdo_connection = new PDO('sqlite:test.db'); // zum Beispiel
$user = new User($pdo_connection);
// oder
$user = new User(null, [ 'connection' => $pdo_connection ]);
// oder
$user = new User();
$user->setDatabaseConnection($pdo_connection);

Wenn Sie vermeiden möchten, jedes Mal eine $database_connection festzulegen, wenn Sie einen aktiven Datensatz aufrufen, gibt es Möglichkeiten, dies zu umgehen!

// index.php oder bootstrap.php
// Setzen Sie dies als registrierte Klasse in Flight
Flight::register('db', 'PDO', [ 'sqlite:test.db' ]);

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

    public function __construct(array $config = [])
    {
        $database_connection = $config['connection'] ?? Flight::db();
        parent::__construct($database_connection, 'users', $config);
    }
}

// Und jetzt, keine Argumente erforderlich!
$user = new User();

Hinweis: Wenn Sie planen, Unit-Tests durchzuführen, kann es einige Herausforderungen beim Testen mit dieser Methode geben, aber insgesamt ist es nicht zu schlecht, da Sie Ihre Verbindung mit setDatabaseConnection() oder $config['connection'] injizieren können.

Wenn Sie die Datenbankverbindung aktualisieren müssen, z. B. 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_connection) erneut festlegen.

Beitragen

Bitte tun Sie das. :D

Einrichtung

Wenn Sie einen Beitrag leisten, stellen Sie sicher, dass Sie composer test-coverage ausführen, um 100 % Testabdeckung aufrechtzuerhalten (das ist keine echte Unit-Testabdeckung, mehr wie Integrationstests).

Stellen Sie auch sicher, dass Sie composer beautify und composer phpcs ausführen, um alle Linting-Fehler zu beheben.

Lizenz

MIT

Awesome-plugins/latte

Latte

Latte ist ein voll ausgestatteter Template-Engine, der 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

Installieren Sie mit Composer.

composer require latte/latte

Grundkonfiguration

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 speichert Latte Ihre Templates, um die Geschwindigkeit zu erhöhen
    // Eine interessante Sache an Latte ist, dass es automatisch Ihren Cache aktualisiert,
    // wenn Sie Änderungen an Ihren Templates vornehmen!
    $latte->setTempDirectory(__DIR__ . '/../cache/');

    // Geben Sie Latte an, wo sich das Stammverzeichnis für Ihre Ansichten befinden wird.
    // $app->get('flight.views.path') ist in der config.php-Datei festgelegt
    //   Sie könnten auch einfach etwas wie `__DIR__ . '/../views/'` tun
    $latte->setLoader(new \Latte\Loaders\FileLoader($app->get('flight.views.path')));
});

Einfaches Layoutbeispiel

Hier ist ein einfaches Beispiel für eine Layoutdatei. Diese Datei wird verwendet, um alle Ihre 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 liegt die Magie -->
            {block content}{/block}
        </div>
        <div id="footer">
            &copy; Urheberrecht
        </div>
    </body>
</html>

Und jetzt haben wir Ihre Datei, die in diesem Inhaltsblock gerendert werden soll:

<!-- app/views/home.latte -->
<!-- Dies sagt Latte, 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 bei meiner App!</p>
{/block}

Dann, wenn Sie dies in Ihrer Funktion oder Ihrem Controller rendern möchten, würden Sie etwas Ähnliches tun:

// einfache 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'
        ]);
    }
}

Schauen Sie in der Latte-Dokumentation nach weiteren Informationen darüber, wie Sie Latte optimal nutzen können!

Awesome-plugins/awesome_plugins

Tolle Plugins

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

API-Dokumentation

API-Dokumentation ist entscheidend für jede API. Sie hilft Entwicklern zu verstehen, wie sie mit Ihrer API interagieren können und was sie im Gegenzug erwarten können. Es stehen einige Tools zur Verfügung, um Ihnen zu helfen, API-Dokumentation für Ihre Flight-Projekte zu erstellen.

Authentifizierung/Autorisierung

Authentifizierung und Autorisierung sind entscheidend für jede Anwendung, die Kontrollen darüber verlangt, wer auf was zugreifen kann.

Caching

Caching ist eine großartige Möglichkeit, 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 Datenelemente auf der Client-Seite zu speichern. Sie können verwendet werden, um Benutzereinstellungen, Anwendungsoptionen 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 der meisten Anwendungen. So speichern und holen Sie Daten. Einige Datenbankbibliotheken sind einfach Wrapper, um Abfragen zu schreiben, und einige sind vollwertige ORMs.

Verschlüsselung

Verschlüsselung ist entscheidend für jede Anwendung, die sensible Daten speichert. Die Daten zu verschlüsseln und zu entschlüsseln ist nicht allzu schwer, aber das korrekte Speichern des Verschlüsselungsschlüssels kann schwierig sein. Das Wichtigste ist, Ihren Verschlüsselungsschlüssel niemals in einem öffentlichen Verzeichnis zu speichern oder ihn in Ihrem Code-Repository zu committen.

Job-Warteschlange

Job-Warteschlangen sind sehr hilfreich, um Aufgaben asynchron zu verarbeiten. Dies kann das Versenden von E-Mails, das Verarbeiten von Bildern oder alles sein, was nicht in Echtzeit erledigt werden muss.

Sitzung

Sitzungen sind für APIs nicht wirklich nützlich, aber für den Aufbau einer Webanwendung können Sitzungen entscheidend sein, um den Status und die Anmeldeinformationen aufrechtzuerhalten.

Vorlagen

Vorlagen sind der Kern jeder Webanwendung mit einer UI. Es gibt eine Reihe von Template-Engines, die mit Flight verwendet werden können.

Mitwirken

Haben Sie ein Plugin, das Sie teilen möchten? Reichen Sie eine Pull-Anfrage ein, um es zur Liste hinzuzufügen!

Media

Medien

Wir haben versucht, alles zu verfolgen, was wir an verschiedenen Arten von Medien rund um das Internet zu Flight finden konnten. Siehe unten für verschiedene Ressourcen, die Sie nutzen können, um mehr über Flight zu erfahren.

Artikel und Berichte

Videos und Tutorials

Examples

Brauchen Sie einen schnellen Start?

Sie haben zwei Optionen, um mit einem neuen Flight-Projekt zu beginnen:

Von der Community beigesteuerte Beispiele:

Brauchen Sie etwas Inspiration?

Während diese nicht offiziell vom Flight-Team gesponsert werden, könnten diese Ihnen Ideen geben, wie Sie Ihre eigenen Projekte strukturieren, 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 dieser Liste hinzuzufügen!

Install/install

Installation

Dateien herunterladen

Stellen Sie sicher, dass PHP auf Ihrem System installiert ist. Wenn nicht, klicken Sie hier, um Anweisungen zur Installation für Ihr System zu erhalten.

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

composer require flightphp/core

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

Konfigurieren Sie Ihren Webserver

Eingebauter PHP-Entwicklungsserver

Dies ist bei weitem der einfachste Weg, um loszulegen. Sie können den integrierten Server verwenden, um Ihre Anwendung auszuführen und sogar SQLite für eine Datenbank zu verwenden (solange sqlite3 auf Ihrem System installiert ist) und praktisch nichts benötigen! Führen Sie nach der Installation von PHP einfach den folgenden Befehl aus:

php -S localhost:8000

Öffnen Sie dann Ihren Browser und gehen Sie zu http://localhost:8000.

Wenn Sie das Dokumentenverzeichnis Ihres Projekts in ein anderes Verzeichnis ändern möchten (Beispiel: Ihr Projekt ist ~/myproject, aber Ihr Dokumentenstamm ist ~/myproject/public/), können Sie nach dem Wechsel in das Verzeichnis ~/myproject den folgenden Befehl ausführen:

php -S localhost:8000 -t public/

Öffnen Sie dann Ihren Browser und gehen Sie zu http://localhost:8000.

Apache

Stellen Sie sicher, dass Apache bereits auf Ihrem System installiert ist. Wenn nicht, suchen Sie bei Google nach Anweisungen zur Installation von Apache auf Ihrem System.

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 RewriteBase /subdir/ direkt nach RewriteEngine On hinzu.

Hinweis: Wenn Sie alle Serverdateien schützen möchten, z. B. eine Datenbank- oder Umgebungsdatei. Fügen Sie dies in Ihre .htaccess-Datei ein:

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

Nginx

Stellen Sie sicher, dass Nginx bereits auf Ihrem System installiert ist. Wenn nicht, suchen Sie bei Google nach Anweisungen zur Installation von Nginx auf Ihrem System.

Fügen Sie für Nginx Folgendes zur Serverdeklaration hinzu:

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

Erstellen Sie Ihre index.php-Datei

<?php

// Wenn Sie Composer verwenden, erfordern Sie den Autoloader.
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 zur Behandlung der Anfrage zu.
Flight::route('/', function () {
  echo 'Hallo Welt!';
});

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

PHP installieren

Wenn Sie bereits über php auf Ihrem System verfügen, überspringen Sie diese Anweisungen und wechseln Sie zum Download-Abschnitt

Sicher! Hier sind die Anweisungen zur Installation von PHP auf macOS, Windows 10/11, Ubuntu und Rocky Linux. Ich werde auch Details darüber enthalten, wie verschiedene Versionen von PHP installiert werden.

macOS

PHP mit Homebrew installieren

  1. Homebrew installieren (wenn nicht bereits installiert):

    • Öffnen Sie das Terminal und führen Sie aus:
      /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
  2. PHP installieren:

    • Installieren Sie die neueste Version:
      brew install php
    • Um eine bestimmte Version zu installieren, z. B. PHP 8.1:
      brew tap shivammathur/php
      brew install shivammathur/php/php@8.1
  3. Zwischen PHP-Versionen wechseln:

    • Verknüpfen Sie die aktuelle Version und verknüpfen Sie die gewünschte Version:
      brew unlink php
      brew link --overwrite --force php@8.1
    • Überprüfen Sie die installierte Version:
      php -v

Windows 10/11

PHP manuell installieren

  1. PHP herunterladen:

    • Besuchen Sie PHP für Windows und laden Sie die neueste oder eine bestimmte Version (z. B. 7.4, 8.0) als zip-Datei ohne Thread-Sicherheit herunter.
  2. PHP extrahieren:

    • Extrahieren Sie die heruntergeladene Zip-Datei nach C:\php.
  3. PHP zum System-PATH hinzufügen:

    • Gehen Sie zu Systemeigenschaften > Umgebungsvariablen.
    • Unter Systemvariablen suchen Sie Path und klicken Sie auf Bearbeiten.
    • Fügen Sie den Pfad C:\php (oder wo immer Sie PHP extrahiert haben) hinzu.
    • Klicken Sie auf OK, um alle Fenster zu schließen.
  4. PHP konfigurieren:

    • Kopieren Sie php.ini-development nach php.ini.
    • Bearbeiten Sie php.ini, um PHP nach Bedarf zu konfigurieren (z. B. extension_dir setzen, Erweiterungen aktivieren).
  5. PHP-Installation überprüfen:

    • Öffnen Sie die Eingabeaufforderung und führen Sie aus:
      php -v

Mehrere PHP-Versionen installieren

  1. Wiederholen Sie die obigen Schritte für jede Version und platzieren Sie sie jeweils in einem separaten Verzeichnis (z. B. C:\php7, C:\php8).

  2. Zwischen den Versionen wechseln, indem Sie die System-PATH-Variable anpassen, um auf das gewünschte Versionsverzeichnis zu verweisen.

Ubuntu (20.04, 22.04, usw.)

PHP mit apt installieren

  1. Paketlisten aktualisieren:

    • Öffnen Sie das Terminal und führen Sie aus:
      sudo apt update
  2. PHP installieren:

    • Installieren Sie die neueste PHP-Version:
      sudo apt install php
    • Um eine bestimmte Version zu installieren, z. B. PHP 8.1:
      sudo apt install php8.1
  3. Zusätzliche Module installieren (optional):

    • Zum Beispiel, um die MySQL-Unterstützung zu installieren:
      sudo apt install php8.1-mysql
  4. Zwischen PHP-Versionen wechseln:

    • Verwenden Sie update-alternatives:
      sudo update-alternatives --set php /usr/bin/php8.1
  5. Installierte Version überprüfen:

    • Führen Sie aus:
      php -v

Rocky Linux

PHP mit yum/dnf installieren

  1. EPEL-Repository aktivieren:

    • Öffnen Sie das Terminal und führen Sie aus:
      sudo dnf install epel-release
  2. Remi-Repository installieren:

    • Führen Sie aus:
      sudo dnf install https://rpms.remirepo.net/enterprise/remi-release-8.rpm
      sudo dnf module reset php
  3. PHP installieren:

    • Um die Standardversion zu installieren:
      sudo dnf install php
    • Um eine bestimmte Version zu installieren, z. B. PHP 7.4:
      sudo dnf module install php:remi-7.4
  4. Zwischen PHP-Versionen wechseln:

    • Verwenden Sie den Befehl dnf module:
      sudo dnf module reset php
      sudo dnf module enable php:remi-8.0
      sudo dnf install php
  5. Überprüfen Sie die installierte Version:

    • Führen Sie aus:
      php -v

Allgemeine Hinweise

Guides

Leitfäden

Flight PHP ist so konzipiert, dass es einfach und dennoch leistungsstark ist, und unsere Leitfäden helfen Ihnen, Schritt für Schritt echte Anwendungen zu erstellen. Diese praktischen Tutorials führen Sie durch vollständige Projekte, um zu demonstrieren, wie Flight effektiv eingesetzt werden kann.

Offizielle Leitfäden

Einen Blog erstellen

Erfahren Sie, wie Sie eine funktionale Bloganwendung mit Flight PHP erstellen. Dieser Leitfaden führt Sie durch:

Dieses Tutorial ist perfekt für Anfänger, die sehen möchten, wie die einzelnen Teile in einer echten Anwendung zusammenpassen.

Unoffizielle Leitfäden

Obwohl diese Leitfäden nicht offiziell vom Flight-Team verwaltet werden, sind sie wertvolle Ressourcen, die von der Community erstellt wurden. Sie decken verschiedene Themen und Anwendungsfälle ab und bieten zusätzliche Einblicke in die Verwendung von Flight PHP.

Erstellen einer RESTful API mit Flight Framework

Dieser Leitfaden führt Sie durch die Erstellung einer RESTful API mit dem Flight PHP Framework. Er behandelt die Grundlagen des Einrichtens einer API, das Definieren von Routen und das Zurückgeben von JSON-Antworten.

Einen einfachen Blog erstellen

Dieser Leitfaden führt Sie durch die Erstellung eines einfachen Blogs mit dem Flight PHP Framework. Er hat tatsächlich 2 Teile: einen, um die Grundlagen abzudecken, und den anderen, um fortgeschrittenere Themen und Verfeinerungen für einen produktionsbereiten Blog abzudecken.

Einen Pokémon API in PHP erstellen: Ein Leitfaden für Anfänger

Dieser unterhaltsame Leitfaden führt Sie durch die Erstellung einer einfachen Pokémon API mit Flight PHP. Er behandelt die Grundlagen des Einrichtens einer API, das Definieren von Routen und das Zurückgeben von JSON-Antworten.

Mitwirken

Haben Sie eine Idee für einen Leitfaden? Einen Fehler gefunden? Wir begrüßen Beiträge! Unsere Leitfäden werden im FlightPHP-Dokumentationsrepository verwaltet.

Wenn Sie etwas Interessantes mit Flight erstellt haben und es als Leitfaden teilen möchten, reichen Sie bitte einen Pull-Request ein. Ihr Wissen zu teilen hilft der Flight-Community, zu wachsen.

Suchen Sie API-Dokumentation?

Wenn Sie nach spezifischen Informationen zu den Kernfunktionen und -methoden von Flight suchen, schauen Sie im Lernbereich unserer Dokumentation vorbei.