Maršrutēšana

Piezīme: Vai vēlaties uzzināt vairāk par maršrutēšanu? Apskatiet "why a framework?" lapu, lai iegūtu padziļinātu skaidrojumu.

Pamata maršrutēšana Flight tiek veikta, saskaņojot URL paraugu ar atsaukuma funkciju vai klases un metodes masīvu.

Flight::route('/', function(){
    echo 'hello world!';
});

Maršruti tiek saskaņoti secībā, kādā tie ir definēti. Pirmais maršruts, kas saskaņojas ar pieprasījumu, tiks izsaukts.

Atsaukumi/Funkcijas

Atsaukums var būt jebkurš aicināms objekts. Tātad jūs varat izmantot regulāru funkciju:

function hello() {
    echo 'hello world!';
}

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

Klases

Jūs varat izmantot arī klases statisko metodi:

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

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

Vai izveidojot objektu vispirms un pēc tam izsaucot metodi:

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

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

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

Flight::route('/', [ $greeting, 'hello' ]);
// Jūs varat izdarīt to arī bez objekta izveidošanas vispirms
// Piezīme: Argumenti netiks ievadīti konstruktorā
Flight::route('/', [ 'Greeting', 'hello' ]);
// Turklāt jūs varat izmantot šo īsāko sintaksi
Flight::route('/', 'Greeting->hello');
// vai
Flight::route('/', Greeting::class.'->hello');

Atkarību ievadīšana caur DIC (Atkarību ievades konteineru)

Ja vēlaties izmantot atkarību ievadi caur konteineru (PSR-11, PHP-DI, Dice utt.), vienīgais maršrutu veids, kur tas ir pieejams, ir vai nu tieši izveidojot objektu pats un izmantojot konteineru, lai izveidotu savu objektu, vai arī izmantojot virknes, lai definētu klasi un metodi, ko izsaukt. Jūs varat doties uz Dependency Injection lapu, lai iegūtu vairāk informācijas.

Lūk, ātrs piemērs:

use flight\database\PdoWrapper;

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

    public function hello(int $id) {
        // izdariet kaut ko ar $this->pdoWrapper
        $name = $this->pdoWrapper->fetchField("SELECT name FROM users WHERE id = ?", [ $id ]);
        echo "Hello, world! My name is {$name}!";
    }
}

// index.php

// Izveidojiet konteineru ar nepieciešamajiem parametriem
// Skatiet Atkarību ievades lapu, lai iegūtu vairāk informācijas par PSR-11
$dice = new \Dice\Dice();

// Neaizmirstiet pārrakstīt mainīgo ar '$dice = '!!!!!
$dice = $dice->addRule('flight\database\PdoWrapper', [
    'shared' => true,
    'constructParams' => [ 
        'mysql:host=localhost;dbname=test', 
        'root',
        'password'
    ]
]);

// Reģistrējiet konteinera apstrādātāju
Flight::registerContainerHandler(function($class, $params) use ($dice) {
    return $dice->create($class, $params);
});

// Maršruti kā parasti
Flight::route('/hello/@id', [ 'Greeting', 'hello' ]);
// vai
Flight::route('/hello/@id', 'Greeting->hello');
// vai
Flight::route('/hello/@id', 'Greeting::hello');

Flight::start();

Metodes Maršrutēšana

Pēc noklusējuma maršrutu paraugi tiek saskaņoti ar visām pieprasījuma metodēm. Jūs varat reaģēt uz konkrētām metodēm, izvietojot identifikatoru pirms URL.

Flight::route('GET /', function () {
  echo 'I received a GET request.';
});

Flight::route('POST /', function () {
  echo 'I received a POST request.';
});

// Jūs nevarat izmantot Flight::get() maršrutiem, jo tas ir metode 
//    lai iegūtu mainīgos, nevis izveidotu maršrutu.
// Flight::post('/', function() { /* code */ });
// Flight::patch('/', function() { /* code */ });
// Flight::put('/', function() { /* code */ });
// Flight::delete('/', function() { /* code */ });

Jūs varat arī kartēt vairākas metodes uz vienu atsaukumu, izmantojot | atdalītāju:

Flight::route('GET|POST /', function () {
  echo 'I received either a GET or a POST request.';
});

Turklāt jūs varat iegūt Router objektu, kuram ir daži palīgmetodes, ko izmantot:

$router = Flight::router();

// kartē visas metodes
$router->map('/', function() {
    echo 'hello world!';
});

// GET pieprasījums
$router->get('/users', function() {
    echo 'users';
});
// $router->post();
// $router->put();
// $router->delete();
// $router->patch();

Regulārās izteiksmes

Jūs varat izmantot regulārās izteiksmes savos maršrutos:

Flight::route('/user/[0-9]+', function () {
  // Šis saskaņosies ar /user/1234
});

Lai gan šī metode ir pieejama, ieteicams izmantot nosauktos parametrus vai nosauktos parametrus ar regulārām izteiksmēm, jo tie ir lasāmāki un vieglāk uzturami.

Nosauktie parametri

Jūs varat norādīt nosauktos parametrus savos maršrutos, kas tiks nodoti jūsu atsaukuma funkcijai. Tas vairāk ir maršruta lasāmības dēļ nekā kaut kas cits. Lūdzu, skatiet sadaļu zemāk par svarīgu brīdinājumu.

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

Jūs varat arī iekļaut regulārās izteiksmes ar jūsu nosauktajiem parametriem, izmantojot : atdalītāju:

Flight::route('/@name/@id:[0-9]{3}', function (string $name, string $id) {
  // Šis saskaņosies ar /bob/123
  // Bet nesaskaņosies ar /bob/12345
});

Piezīme: Saskaņošana ar regex grupām () pozicionāliem parametriem netiek atbalstīta. :'(

Svarīgs brīdinājums

Kaut arī piemērā augstāk šķiet, ka @name ir tieši saistīts ar mainīgo $name, tas nav. Parametru secība atsaukuma funkcijā nosaka, kas tiek nodots tai. Tātad, ja jūs mainītu parametru secību atsaukuma funkcijā, mainīgie tiktu mainīti arī. Lūk, piemērs:

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

Un ja jūs dotos uz šādu URL: /bob/123, izvade būtu hello, 123 (bob)!. Lūdzu, esiet uzmanīgi, kad iestatāt savus maršrutus un atsaukuma funkcijas.

Izvēles parametri

Jūs varat norādīt nosauktos parametrus, kas ir izvēles saskaņošanai, ietinot segmentus iekavās.

Flight::route(
  '/blog(/@year(/@month(/@day)))',
  function(?string $year, ?string $month, ?string $day) {
    // Šis saskaņosies ar šādiem URL:
    // /blog/2012/12/10
    // /blog/2012/12
    // /blog/2012
    // /blog
  }
);

Jei izvēles parametri, kas nav saskaņoti, tiks nodoti kā NULL.

Visi elementi

Saskaņošana tiek veikta tikai uz atsevišķiem URL segmentiem. Ja vēlaties saskaņot vairākus segmentus, jūs varat izmantot * vispārīgo simbolu.

Flight::route('/blog/*', function () {
  // Šis saskaņosies ar /blog/2000/02/01
});

Lai maršrutētu visus pieprasījumus uz vienu atsaukumu, jūs varat izdarīt:

Flight::route('*', function () {
  // Izdariet kaut ko
});

Pārnešana

Jūs varat nodot izpildi uz nākamo saskaņojošo maršrutu, atgriežot true no jūsu atsaukuma funkcijas.

Flight::route('/user/@name', function (string $name) {
  // Pārbaudiet kādu nosacījumu
  if ($name !== "Bob") {
    // Turpiniet uz nākamo maršrutu
    return true;
  }
});

Flight::route('/user/*', function () {
  // Šis tiks izsaukts
});

Maršrutu aliasi

Jūs varat piešķirt aliasu maršrutam, lai URL varētu dinamiski tikt ģenerēts vēlāk jūsu kodā (piemēram, šablonā).

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

// vēlāk kodā kaut kur
Flight::getUrl('user_view', [ 'id' => 5 ]); // atgriezīs '/users/5'

Tas ir īpaši noderīgi, ja jūsu URL gadās mainīties. Piemērā augstāk, pieņemsim, ka lietotāji tika pārvietoti uz /admin/users/@id vietā. Ar aliasiem vietā, jums nav jāmaina nekur, kur jūs atsaucaties uz aliasu, jo alias tagad atgriezīs /admin/users/5 kā piemērā.

Maršrutu aliasi joprojām darbojas grupās:

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

// vēlāk kodā kaut kur
Flight::getUrl('user_view', [ 'id' => 5 ]); // atgriezīs '/users/5'

Maršrutu informācija

Ja vēlaties pārbaudīt saskaņoto maršrutu informāciju, ir 2 veidi, kā to izdarīt. Jūs varat izmantot executedRoute īpašumu vai pieprasīt, lai maršruta objekts tiktu nodots jūsu atsaukumam, pievienojot true kā trešo parametru maršruta metodē. Maršruta objekts vienmēr būs pēdējais parametrs, kas nodots jūsu atsaukuma funkcijai.

Flight::route('/', function(\flight\net\Route $route) {
  // Masīvs ar HTTP metodēm, kas saskaņotas
  $route->methods;

  // Masīvs ar nosauktajiem parametriem
  $route->params;

  // Saskaņotā regulārā izteiksme
  $route->regex;

  // Satur jebkādu '*' saturu, kas izmantots URL paraugā
  $route->splat;

  // Rāda URL ceļu....ja jums tas tiešām vajadzīgs
  $route->pattern;

  // Rāda, kāds starplikums ir piešķirts šim
  $route->middleware;

  // Rāda aliasu, kas piešķirts šim maršrutam
  $route->alias;
}, true);

Vai, ja vēlaties pārbaudīt pēdējo izpildīto maršrutu, jūs varat izdarīt:

Flight::route('/', function() {
  $route = Flight::router()->executedRoute;
  // Izdariet kaut ko ar $route
  // Masīvs ar HTTP metodēm, kas saskaņotas
  $route->methods;

  // Masīvs ar nosauktajiem parametriem
  $route->params;

  // Saskaņotā regulārā izteiksme
  $route->regex;

  // Satur jebkādu '*' saturu, kas izmantots URL paraugā
  $route->splat;

  // Rāda URL ceļu....ja jums tas tiešām vajadzīgs
  $route->pattern;

  // Rāda, kāds starplikums ir piešķirts šim
  $route->middleware;

  // Rāda aliasu, kas piešķirts šim maršrutam
  $route->alias;
});

Piezīme: executedRoute īpašums tiks iestatīts tikai pēc maršruta izpildes. Ja mēģināt piekļūt tam pirms maršruta izpildes, tas būs NULL. Jūs varat izmantot executedRoute arī starplikumos!

Maršrutu grupēšana

Var būt reizes, kad vēlaties grupēt saistītos maršrutus kopā (piemēram, /api/v1). Jūs varat izdarīt to, izmantojot group metodi:

Flight::group('/api/v1', function () {
  Flight::route('/users', function () {
    // Saskaņojas ar /api/v1/users
  });

  Flight::route('/posts', function () {
    // Saskaņojas ar /api/v1/posts
  });
});

Jūs pat varat ligzdot grupas:

Flight::group('/api', function () {
  Flight::group('/v1', function () {
    // Flight::get() iegūst mainīgos, tas nekādē maršrutu! Skatiet objekta kontekstu zemāk
    Flight::route('GET /users', function () {
      // Saskaņojas ar GET /api/v1/users
    });

    Flight::post('/posts', function () {
      // Saskaņojas ar POST /api/v1/posts
    });

    Flight::put('/posts/1', function () {
      // Saskaņojas ar PUT /api/v1/posts
    });
  });
  Flight::group('/v2', function () {

    // Flight::get() iegūst mainīgos, tas nekādē maršrutu! Skatiet objekta kontekstu zemāk
    Flight::route('GET /users', function () {
      // Saskaņojas ar GET /api/v2/users
    });
  });
});

Grupēšana ar Objekta kontekstu

Jūs joprojām varat izmantot maršrutu grupēšanu ar Engine objektu šādā veidā:

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

  // izmantot $router mainīgo
  $router->get('/users', function () {
    // Saskaņojas ar GET /api/v1/users
  });

  $router->post('/posts', function () {
    // Saskaņojas ar POST /api/v1/posts
  });
});

Grupēšana ar Starplikumu

Jūs varat arī piešķirt starplikumu grupai maršrutu:

Flight::group('/api/v1', function () {
  Flight::route('/users', function () {
    // Saskaņojas ar /api/v1/users
  });
}, [ MyAuthMiddleware::class ]); // vai [ new MyAuthMiddleware() ], ja vēlaties izmantot instanci

Skatiet vairāk detaļu group middleware lapā.

Resursu maršrutēšana

Jūs varat izveidot maršrutu kopu resursam, izmantojot resource metodi. Tas izveidos maršrutu kopu resursam, kas atbilst RESTful konvencijām.

Lai izveidotu resursu, izdariet sekojošo:

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

Un kas notiks fonā, tas izveidos sekojošos maršrutus:

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

Un jūsu kontrolieris izskatīsies šādi:

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
    {
    }
}

Piezīme: Jūs varat skatīt nesen pievienotos maršrutus ar runway, izpildot php runway routes.

Pielāgošana Resursu maršrutiem

Ir daži varianti, lai konfigurētu resursu maršrutus.

Alias Bāze

Jūs varat konfigurēt aliasBase. Pēc noklusējuma alias ir pēdējā URL daļa, kas norādīta. Piemēram, /users/ rezultētos ar aliasBaseusers. Kad šie maršruti tiek izveidoti, alias ir users.index, users.create utt. Ja vēlaties mainīt alias, iestatiet aliasBase uz vērtību, ko vēlaties.

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

Tikai un Izņemot

Jūs varat arī norādīt, kurus maršrutus vēlaties izveidot, izmantojot only un except opcijas.

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

Tie ir balto un melno sarakstu opcijas, lai norādītu, kurus maršrutus vēlaties izveidot.

Starplikums

Jūs varat arī norādīt starplikumu, kas jāizpilda katrā no maršrutiem, ko izveido resource metode.

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

Straumēšana

Jūs tagad varat straumēt atbildes klientam, izmantojot streamWithHeaders() metodi. Tas ir noderīgi, lai sūtītu lielas failus, ilgstošus procesus vai ģenerētu lielas atbildes. Straumēšana maršrutā tiek apstrādāta nedaudz savādāk nekā parastais maršruts.

Piezīme: Straumētas atbildes ir pieejamas tikai, ja jums ir flight.v2.output_buffering iestatīts uz false.

Straumēšana ar Manuāliem Headeriem

Jūs varat straumēt atbildi klientam, izmantojot stream() metodi maršrutā. Ja jūs to darāt, jums jāiestata visas metodes ar roku pirms kaut ko izvadat klientam. Tas tiek darīts ar header() php funkciju vai Flight::response()->setRealHeader() metodi.

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

    // acīmredzami jūs sanitizētu ceļu un tā tālāk.
    $fileNameSafe = basename($filename);

    // Ja jums ir papildu headeri, ko iestatīt šeit pēc maršruta izpildes
    // jums tie jādefinē pirms kaut kas tiek izvadīts.
    // Tie visi jābūt raw izsaukumam uz header() funkciju vai 
    // izsaukumam uz Flight::response()->setRealHeader()
    header('Content-Disposition: attachment; filename="'.$fileNameSafe.'"');
    // vai
    Flight::response()->setRealHeader('Content-Disposition', 'attachment; filename="'.$fileNameSafe.'"');

    $filePath = '/some/path/to/files/'.$fileNameSafe;

    if (!is_readable($filePath)) {
        Flight::halt(404, 'File not found');
    }

    // manuāli iestatiet satura garumu, ja vēlaties
    header('Content-Length: '.filesize($filePath));

    // Straumējiet failu klientam, kamēr tas tiek lasīts
    readfile($filePath);

// Šī ir maģiskā rinda šeit
})->stream();

Straumēšana ar Headeriem

Jūs varat arī izmantot streamWithHeaders() metodi, lai iestatītu headerus pirms sākat straumēt.

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

    // jūs varat pievienot jebkādus papildu headerus, ko vēlaties šeit
    // jūs vienkārši jāizmanto header() vai Flight::response()->setRealHeader()

    // tomēr, kā jūs velkat datus, tikai kā piemērs...
    $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 ',';
        }

        // Tas ir nepieciešams, lai nosūtītu datus klientam
        ob_flush();
    }
    echo '}';

// Šis ir veids, kā jūs iestatīsit headerus pirms sākat straumēt.
})->streamWithHeaders([
    'Content-Type' => 'application/json',
    'Content-Disposition' => 'attachment; filename="users.json"',
    // izvēles statusa kods, pēc noklusējuma 200
    'status' => 200
]);