Learn/flight_vs_laravel

Flight pret Laravel

Kas ir Laravel?

Laravel ir pilnvērtīga ietvara sistēma ar visiem zvaniņiem un svilpēm un pārsteidzošu izstrādātājiem veltītu ekosistēmu, bet ar izmaksām veiktspējā un sarežģītībā. Laravel mērķis ir nodrošināt izstrādātājam augstāko produktivitātes līmeni un padarīt izplatītās uzdevumus vieglus. Laravel ir lieliska izvēle izstrādātājiem, kuri vēlas izveidot pilnvērtīgu, uzņēmējdarbības līmeņa tīmekļa lietojumprogrammu. Tas nāk ar dažām kompromisiem, īpaši veiktspējas un sarežģītības ziņā. Laravel pamatu apguve var būt viegla, bet prasmju iegūšana ietvarā var prasīt zināmu laiku.

Ir arī tik daudz Laravel moduļu, ka izstrādātāji bieži jūtas, ka vienīgais veids, kā atrisināt problēmas, ir caur šiem moduļiem, kad patiesībā varētu izmantot citu bibliotēku vai uzrakstīt savu kodu.

Priekšrocības salīdzinājumā ar Flight

Trūkumi salīdzinājumā ar Flight

Learn/migrating_to_v3

Migrēšana uz v3

Atpakaļsaderība lielākoties ir saglabāta, bet ir daži izmaiņas, par kurām jums jāzina, migrējot no v2 uz v3. Ir daži izmaiņas, kas pārāk daudz nonāca pretrunā ar dizaina modeļiem, tāpēc bija jāveic dažas korekcijas.

Izvades buferizācijas uzvedība

v3.5.0

Izvades buferizācija ir process, kurā PHP skripta ģenerētais izvade tiek saglabāts buferī (iekšēji PHP), pirms tas tiek nosūtīts klientam. Tas ļauj modificēt izvadi pirms tās nosūtīšanas klientam.

MVC lietojumprogrammā Kontrolētājs ir "vadītājs" un tas pārvalda, ko dara skats. Ja izvade tiek ģenerēta ārpus kontrolētāja (vai Flight gadījumā dažreiz anonīma funkcija), tas pārkāpj MVC modeli. Šī izmaiņa ir lai būtu vairāk saskaņota ar MVC modeli un lai padarītu ietvaru paredzamāku un vieglāk lietojamu.

v2 versijā izvades buferizācija tika apstrādāta tā, ka tā konsekventi neaizvēra savu izvades buferi, kas apgrūtināja vienības testēšanu un straumēšanu. Lielākajai daļai lietotāju šī izmaiņa var pat nebūt ietekme uz jums. Tomēr, ja jūs izvadat saturu ārpus izsaucamajām funkcijām un kontrolētājiem (piemēram, āķī), visticamāk, saskarsieties ar problēmām. Izvades satura āķos un pirms ietvara faktiskās izpildes varēja darboties iepriekš, bet tas nedarbosies turpmāk.

Kur var rasties problēmas

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

// tikai piemērs
define('START_TIME', microtime(true));

function hello() {
    echo 'Hello World';
}

Flight::map('hello', 'hello');
Flight::after('hello', function(){
    // tas faktiski būs kārtībā
    echo '<p>This Hello World phrase was brought to you by the letter "H"</p>';
});

Flight::before('start', function(){
    // tādas lietas izraisīs kļūdu
    echo '<html><head><title>My Page</title></head><body>';
});

Flight::route('/', function(){
    // tas faktiski ir kārtībā
    echo 'Hello World';

    // Arī šis vajadzētu būt kārtībā
    Flight::hello();
});

Flight::after('start', function(){
    // tas izraisīs kļūdu
    echo '<div>Your page loaded in '.(microtime(true) - START_TIME).' seconds</div></body></html>';
});

Ieslēgšana v2 renderēšanas uzvedībai

Vai jūs joprojām varat saglabāt savu veco kodu tāpat, kā tas ir, bez pārstrādes, lai tas darbotos ar v3? Jā, varat! Jūs varat ieslēgt v2 renderēšanas uzvedību, iestatot konfigurācijas opciju flight.v2.output_buffering uz true. Tas ļaus jums turpināt izmantot veco renderēšanas uzvedību, bet ieteicams to labot turpmāk. v4 versijā ietvarā tas tiks noņemts.

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

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

Flight::before('start', function(){
    // Tagad tas būs kārtībā
    echo '<html><head><title>My Page</title></head><body>';
});

// vairāk koda 

Dispatcher izmaiņas

v3.7.0

Ja jūs tieši esat izsaukuši statiskas metodes Dispatcher klasei, piemēram, Dispatcher::invokeMethod(), Dispatcher::execute() utt., jums būs jāatjaunina jūsu kods, lai tieši neizsauktu šīs metodes. Dispatcher ir pārveidots, lai būtu vairāk objektorientēts, tāpēc atkarību injekcijas konteineri var tikt izmantoti vieglāk. Ja jums jāizsauc metode līdzīgi kā to darīja Dispatcher, jūs varat manuāli izmantot kaut ko līdzīgu $result = $class->$method(...$params); vai call_user_func_array().

halt() stop() redirect() un error() izmaiņas

v3.10.0

Noklusētā uzvedība pirms 3.10.0 bija notīrīt gan galvenes, gan atbildes ķermeni. Tas tika mainīts, lai notīrītu tikai atbildes ķermeni. Ja jums jānotīra arī galvenes, jūs varat izmantot Flight::response()->clear().

Learn/configuration

Konfigurācija

Pārskats

Flight nodrošina vienkāršu veidu, kā konfigurēt dažādus framework aspektus, lai tie atbilstu jūsu lietojumprogrammas vajadzībām. Daži ir iestatīti pēc noklusējuma, bet jūs varat tos pārrakstīt pēc vajadzības. Jūs varat arī iestatīt savas mainīgās vērtības, lai tās izmantotu visā jūsu lietojumprogrammā.

Saprašana

Jūs varat pielāgot noteiktus Flight uzvedības aspektus, iestatot konfigurācijas vērtības izmantojot set metodi.

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

app/config/config.php failā jūs varat redzēt visas noklusējuma konfigurācijas mainīgās vērtības, kas ir pieejamas jums.

Pamata izmantošana

Flight konfigurācijas opcijas

Turpmāk ir visu pieejamo konfigurācijas iestatījumu saraksts:

Loader konfigurācija

Ir papildu konfigurācijas iestatījums loader. Tas ļaus jums automatiski ielādēt klases ar _ klases nosaukumā.

// Iespējot klases ielādi ar apakšsvītrām
// Noklusējums ir true
Loader::$v2ClassLoading = false;

Mainīgās vērtības

Flight ļauj jums saglabāt mainīgās vērtības, lai tās varētu izmantot jebkur jūsu lietojumprogrammā.

// Saglabāt jūsu mainīgo
Flight::set('id', 123);

// Citur jūsu lietojumprogrammā
$id = Flight::get('id');

Lai pārbaudītu, vai mainīgais ir iestatīts, jūs varat izdarīt:

if (Flight::has('id')) {
  // Izpildīt kaut ko
}

Jūs varat notīrīt mainīgo šādi:

// Notīra id mainīgo
Flight::clear('id');

// Notīra visas mainīgās vērtības
Flight::clear();

Piezīme: Tas, ka jūs varat iestatīt mainīgo, nenozīmē, ka jums tas jādarītu. Izmantojiet šo funkciju saudzīgi. Iemesls ir tas, ka jebkas, kas uzglabāts šeit, kļūst par globālu mainīgo. Globālās mainīgās vērtības ir sliktas, jo tās var mainīt no jebkuras vietas jūsu lietojumprogrammā, padarot grūti izsekot kļūdas. Turklāt tas var sarežģīt lietas, piemēram, vienības testēšanu.

Kļūdas un izņēmumi

Visas kļūdas un izņēmumi tiek uztverti Flight un nodoti error metodei. ja flight.handle_errors ir iestatīts uz true.

Noklusējuma uzvedība ir nosūtīt vispārīgu HTTP 500 Internal Server Error atbildi ar dažām kļūdas informācijām.

Jūs varat pārrakstīt šo uzvedību savām vajadzībām:

Flight::map('error', function (Throwable $error) {
  // Apstrādāt kļūdu
  echo $error->getTraceAsString();
});

Pēc noklusējuma kļūdas netiek reģistrētas tīmekļa serverī. Jūs varat to iespējot, mainot konfigurāciju:

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

404 Nav atrasts

Kad URL nevar atrast, Flight izsauc notFound metodi. Noklusējuma uzvedība ir nosūtīt HTTP 404 Not Found atbildi ar vienkāršu ziņojumu.

Jūs varat pārrakstīt šo uzvedību savām vajadzībām:

Flight::map('notFound', function () {
  // Apstrādāt nav atrasts
});

Skatīt arī

Traucējummeklēšana

Izmaiņu žurnāls

Learn/ai

AI un izstrādātāju pieredze ar Flight

Pārskats

Flight padara viegli uzlabot jūsu PHP projektus ar AI vadītiem rīkiem un mūsdienīgiem izstrādātāju darba plūsmu. Ar iebūvētiem komandām savienojumiem ar LLM (Large Language Model) sniedzējiem un ģenerēšanu projektu specifiskām AI kodēšanas instrukcijām, Flight palīdz jums un jūsu komandai iegūt maksimālo labumu no AI asistentiem, piemēram, GitHub Copilot, Cursor un Windsurf.

Izpratne

AI kodēšanas asistenti ir visnoderīgākie, kad viņi saprot jūsu projekta kontekstu, konvencijas un mērķus. Flight AI palīgi ļauj jums:

Šīs funkcijas ir iebūvētas Flight kodolā CLI un oficiālajā flightphp/skeleton starter projektā.

Pamata lietošana

LLM akreditīvu iestatīšana

ai:init komanda ved jūs cauri jūsu projekta savienojumam ar LLM sniedzēju.

php runway ai:init

Jums tiks uzdots:

Tas izveido .runway-creds.json failu jūsu projekta saknē (un nodrošina, ka tas ir jūsu .gitignore).

Piemērs:

Welcome to AI Init!
Which LLM API do you want to use? [1] openai, [2] grok, [3] claude: 1
Enter the base URL for the LLM API [https://api.openai.com]:
Enter your API key for openai: sk-...
Enter the model name you want to use (e.g. gpt-4, claude-3-opus, etc) [gpt-4o]:
Credentials saved to .runway-creds.json

Ģenerēšana projektu specifiskām AI instrukcijām

ai:generate-instructions komanda palīdz jums izveidot vai atjaunināt instrukcijas AI kodēšanas asistentiem, pielāgotas jūsu projektam.

php runway ai:generate-instructions

Jūs atbildēsiet uz dažiem jautājumiem par jūsu projektu (apraksts, datubāze, veidnes, drošība, komandas lielums utt.). Flight izmanto jūsu LLM sniedzēju, lai ģenerētu instrukcijas, tad ieraksta tās:

Piemērs:

Please describe what your project is for? My awesome API
What database are you planning on using? MySQL
What HTML templating engine will you plan on using (if any)? latte
Is security an important element of this project? (y/n) y
...
AI instructions updated successfully.

Tagad jūsu AI rīki sniegs gudrākus, atbilstošākus ieteikumus, balstītus uz jūsu projekta reālajām vajadzībām.

Padziļinātā lietošana

Skatīt arī

Traucējummeklēšana

Izmaiņu žurnāls

Learn/unit_testing_and_solid_principles

Šis raksts sākotnēji tika publicēts vietnē Airpair 2015. gadā. Visi nopelni tiek doti Airpair un Brianam Fentonam, kurš sākotnēji uzrakstīja šo rakstu, lai gan vietne vairs nav pieejama, un raksts pastāv tikai Wayback Machine. Šis raksts ir pievienots vietnei mācību un izglītības mērķiem PHP kopienai kopumā.

1 Iestatīšana un konfigurācija

1.1 Turiet to aktuālu

Sāksim ar to – pārsteidzoši maz PHP instalāciju praksē ir aktuālas vai tiek uzturētas aktuālas. Vai tas ir dēļ koplietotas hostinga ierobežojumiem, noklusējumiem, kurus neviens nemaina, vai laika/budžeta trūkuma atjaunināšanas testēšanai, PHP binārās faili mēdz tikt atstāti novārtā. Tāpēc viena skaidra labākā prakse, kurai vajadzētu pievērst vairāk uzmanības, ir vienmēr izmantot aktuālu PHP versiju (5.6.x šajā rakstā). Turklāt ir svarīgi plānot regulāras atjaunināšanas gan pašam PHP, gan jebkādiem paplašinājumiem vai piegādātāju bibliotēkām, kuras jūs izmantojat. Atjaunināšanas sniedz jaunas valodas funkcijas, uzlabotu ātrumu, mazāku atmiņas lietojumu un drošības atjauninājumus. Jo biežāk jūs atjauninat, jo mazāk sāpīgs process kļūst.

1.2 Iestatiet saprātīgus noklusējumus

PHP veic pienācīgu darbu, iestatot labus noklusējumus ar saviem php.ini.development un php.ini.production failiem, bet mēs varam darīt labāk. Piemēram, tie mums nekur nenorāda datumu/laiku joslu. Tas ir saprātīgi no izplatīšanas viedokļa, bet bez tās PHP izmetīs E_WARNING kļūdu katru reizi, kad izsaucam datuma/laika saistītu funkciju. Lūk, daži ieteikti iestatījumi:

1.3 Paplašinājumi

Tas arī ir laba ideja deaktivizēt (vai vismaz neaktivizēt) paplašinājumus, kurus jūs neizmantosiet, piemēram, datu bāzes draiverus. Lai redzētu, kas ir aktivizēts, izpildiet phpinfo() komandu vai dodieties uz komandrindu un izpildiet šo.

$ php -i

Informācija ir tā pati, bet phpinfo() pievieno HTML formatējumu. CLI versija ir vieglāk caurvadāma uz grep, lai atrastu specifisku informāciju. Piem.

$ php -i | grep error_log

Viens ierobežojums šai metodei: iespējams, ka dažādas PHP iestatījumi attiecas uz tīmekļa versiju un CLI versiju.

2 Izmantojiet Composer

Tas varētu būt pārsteigums, bet viena no labākajām praksēm mūsdienu PHP rakstīšanai ir rakstīt mazāk no tā. Lai gan ir taisnība, ka viens no labākajiem veidiem, kā kļūt labākam programmēšanā, ir darīt to, ir daudz problēmu, kas jau ir atrisinātas PHP telpā, piemēram, maršrutēšana, pamata ievades validācijas bibliotēkas, vienību konvertēšana, datu bāzes abstrakcijas slāņi utt... Vienkārši apmeklējiet Packagist un izpētiet. Jūs, visticamāk, atradīsiet, ka ievērojamas daļas no problēmas, kuru mēģināt atrisināt, jau ir uzrakstītas un testētas.

Kaut arī vilinoši ir rakstīt visu kodu pašam (un ar to nav nekā slikta – rakstīt savu ietvaru vai bibliotēku kā mācību pieredzi), jums vajadzētu cīnīties pret šīm "Neizgudrots Šeit" izjūtām un ietaupīt sev daudz laika un galvassāpju. Sekojiet PIE doktrīnai – Lepni Izgudrots Citur. Arī, ja jūs izvēlaties rakstīt savu kaut ko, neatklaidiet to, ja tas nedara kaut ko ievērojami atšķirīgu vai labāku nekā esošie piedāvājumi.

Composer ir pakotņu pārvaldnieks PHP, līdzīgs pip Python, gem Ruby un npm Node. Tas ļauj definēt JSON failu, kas uzskaita jūsu koda atkarības, un tas mēģinās atrisināt šīs prasības, lejupielādējot un instalējot nepieciešamo kodu saišķus.

2.1 Composer instalēšana

Mēs pieņemam, ka tas ir lokāls projekts, tāpēc instalēsim Composer instanci tikai šim projektam. Dodieties uz savu projektu direktoriju un izpildiet šo:

$ curl -sS https://getcomposer.org/installer | php

Atcerieties, ka caurvadīt jebkuru lejupielādi tieši uz skripta interpreters (sh, ruby, php utt...) ir drošības risks, tāpēc izlasiet instalēšanas kodu un pārliecinieties, ka esat ar to mierā, pirms izpildāt jebkuru šādu komandu.

Ērtības dēļ (ja jūs dodat priekšroku rakstīt composer install nevis php composer.phar install), jūs varat izmantot šo komandu, lai instalētu vienu Composer kopiju globāli:

$ mv composer.phar /usr/local/bin/composer
$ chmod +x composer

Jums var būt nepieciešams izpildīt šos ar sudo, atkarībā no jūsu failu atļaujām.

2.2 Composer izmantošana

Composer ir divas galvenās atkarību kategorijas, kuras tas var pārvaldīt: "require" un "require-dev". Atkarības, kas uzskaitītas kā "require", tiek instalētas visur, bet "require-dev" atkarības tiek instalētas tikai tad, kad tās tiek īpaši pieprasītas. Parasti tās ir rīki, kad kods ir aktīvā attīstībā, piemēram, PHP_CodeSniffer. Zemāk redzams piemērs, kā instalēt Guzzle, populāru HTTP bibliotēku.

$ php composer.phar require guzzle/guzzle

Lai instalētu rīku tikai attīstības mērķiem, pievienojiet karogu --dev:

$ php composer.phar require --dev 'sebastian/phpcpd'

Tas instalē PHP Copy-Paste Detector, citu koda kvalitātes rīku kā attīstības atkarību.

2.3 Install vs update

Kad mēs pirmo reizi izpildām composer install, tas instalēs jebkuras bibliotēkas un to atkarības, balstoties uz composer.json failu. Kad tas ir paveikts, composer izveido bloķēšanas failu, paredzami sauktu composer.lock. Šis fails satur sarakstu ar atkarībām, kuras composer atrada mums, un to precīzajām versijām ar hashiem. Tad jebkuru nākamo reizi, kad izpildām composer install, tas paskatīsies bloķēšanas failā un instalēs tās precīzās versijas.

composer update ir mazliet atšķirīga būtne. Tas ignorēs composer.lock failu (ja tāds ir) un mēģinās atrast visjaunākās katras atkarības versijas, kas joprojām apmierina ierobežojumus composer.json. Tad tas rakstīs jaunu composer.lock failu, kad tas ir pabeigts.

2.4 Autoloadēšana

Gan composer install, gan composer update ģenerēs autoloader mums, kas stāsta PHP, kur atrast visas nepieciešamās failus, lai izmantotu bibliotēkas, kuras mēs tikko instalējām. Lai to izmantotu, vienkārši pievienojiet šo rindiņu (parasti uz bootstrap failu, kas tiek izpildīts katru pieprasījumu):

require 'vendor/autoload.php';

3 Sekojiet labiem dizaina principiem

3.1 SOLID

SOLID ir mnemonika, lai atgādinātu mums par piecām galvenajām principiem labā objekt-orientētā programmatūras dizainā.

3.1.1 S - Single Responsibility Principle

Tas norāda, ka klasēm vajadzētu būt tikai vienai atbildībai, vai, citādi sakot, tām vajadzētu būt tikai viens iemesls izmaiņām. Tas labi iekļaujas Unix filozofijā ar daudzām mazām rīkām, kas dara vienu lietu labi. Klases, kas dara tikai vienu lietu, ir daudz vieglāk testēt un atkļūdot, un tās mazāk jūs pārsteigs. Jūs nevēlaties, lai metodes izsaukums uz Validator klasi atjaunina db ierakstus. Lūk, piemērs ar SRP pārkāpumu, kādu jūs bieži redzētu aplikācijā, kas balstīta uz ActiveRecord pattern.

class Person extends Model
{
    public $name;
    public $birthDate;
    protected $preferences;
    public function getPreferences() {}
    public function save() {}
}

Tā ir diezgan pamata entity modelis. Bet viena no šīm lietām šeit nepieder. Entitātes modelim vajadzētu būt tikai uzvedībai, kas saistīta ar entītāti, ko tā pārstāv, tam nevajadzētu būt atbildīgam par pašas saglabāšanu.

class Person extends Model
{
    public $name;
    public $birthDate;
    protected $preferences;
    public function getPreferences() {}
}
class DataStore
{
    public function save(Model $model) {}
}

Tas ir labāk. Person modelis atgriežas pie tā, ka dara tikai vienu lietu, un saglabāšanas uzvedība ir pārvietota uz noturības objektu. Ņemiet vērā, ka es tikai type hinted uz Model, ne Person. Mēs atgriezīsimies pie tā, kad nonāksim pie L un D SOLID daļām.

3.1.2 O - Open Closed Principle

Ir lielisks tests šim, kas diezgan labi apkopo, par ko šis princips ir: padomājiet par funkciju, ko ieviest, iespējams, pēdējo, pie kuras strādājāt vai strādājat. Vai jūs varat ieviest šo funkciju esošajā kodsbazē TIKAI pievienojot jaunas klases un nemainot nevienu esošu klasi sistēmā? Jūsu konfigurācija un vadošais kods saņem mazliet atlaides, bet lielākajā daļā sistēmu tas ir pārsteidzoši grūti. Jums ir jāpaļaujas daudz uz polimorfisku nosūtīšanu, un lielākā daļā kodsbazju tas vienkārši nav iestatīts. Ja jūs interesējaties par to, ir labs Google runas video YouTube par polimorfismu un kodu rakstīšanu bez If, kas izpēta to tālāk. Kā bonuss, runu vada Miško Hevery, kuru daudzi var zināt kā AngularJs izveidotāju.

3.1.3 L - Liskov Substitution Principle

Šis princips ir nosaukts Barbara Liskov vārdā, un tas ir izdrukāts zemāk:

"Objekti programmā vajadzētu būt aizvietojami ar viņu apakštipu instancēm, nekaitējot programmas pareizībai."

Tas viss izklausās labi, bet tas ir skaidrāk ilustrēts ar piemēru.

abstract class Shape
{
    public function getHeight();
    public function setHeight($height);
    public function getLength();
    public function setLength($length);
}

Šis pārstāvēs mūsu pamata četrām pusēm formu. Nekas izsmalcināts šeit.

class Square extends Shape
{
    protected $size;
    public function getHeight() {
        return $this->size;
    }
    public function setHeight($height) {
        $this->size = $height;
    }
    public function getLength() {
        return $this->size;
    }
    public function setLength($length) {
        $this->size = $length;
    }
}

Šī ir mūsu pirmā forma, Kvadrāts. Diezgan taisni uz priekšu forma, vai ne? Jūs varat pieņemt, ka ir konstruktors, kur mēs iestatām izmērus, bet no šīs realizācijas jūs redzat, ka garums un augstums vienmēr būs vienādi. Kvadrāti vienkārši ir tādi.

class Rectangle extends Shape
{
    protected $height;
    protected $length;
    public function getHeight() {
        return $this->height;
    }
    public function setHeight($height) {
        $this->height = $height;
    }
    public function getLength() {
        return $this->length;
    }
    public function setLength($length) {
        $this->length = $length;
    }
}

Tā ir cita forma. Joprojām ir tās pašas metodes paraksti, tā joprojām ir četrām pusēm forma, bet ko, ja mēs sākam mēģināt izmantot tās citu vietā? Tagad pēkšņi, ja mēs mainām formas augstumu, mēs vairs nevaram pieņemt, ka formas garums sakritīs. Mēs esam pārkāpuši līgumu, ko bijām noslēguši ar lietotāju, kad devām viņam mūsu Kvadrāta formu.

Tas ir tipisks LSP pārkāpuma piemērs, un mums ir vajadzīgs šāds princips, lai vislabāk izmantotu tipa sistēmu. Pat duck typing nepateiks mums, ja pamata uzvedība ir atšķirīga, un, tā kā mēs to nevaram zināt bez tam lūstot, ir labāk pārliecināties, ka tā nav atšķirīga.

3.1.3 I - Interface Segregation Principle

Šis princips prasa priekšroku daudzām mazām, smalkām saskarnēm pret vienu lielu. Saskarnes vajadzētu balstīties uz uzvedību, nevis "tas ir viena no šīm klasēm". Padomājiet par saskarnēm, kas nāk ar PHP. Traversable, Countable, Serializable, tādas lietas. Tās reklamē spējas, ko objekts piemīt, nevis ko tas manto. Tāpēc turiet savas saskarnes mazas. Jūs nevēlaties, lai saskarnei būtu 30 metodes, 3 ir daudz labāks mērķis.

3.1.4 D - Dependency Inversion Principle

Jūs, iespējams, esat dzirdējuši par to citās vietās, kur runāja par Dependency Injection, bet Dependency Inversion un Dependency Injection nav gluži viena un tā pati lieta. Dependency inversion patiesībā ir veids, kā teikt, ka jums vajadzētu paļauties uz abstrakcijām savā sistēmā, nevis uz tās detaļām. Ko tas nozīmē jums ikdienā?

Neizmantojiet mysqli_query() tieši visā savā kodā, izmantojiet kaut ko kā DataStore->query() tā vietā.

Šī principa kodols ir par abstrakcijām. Tas vairāk ir par teikumu "izmantojiet datu bāzes adapteri" nevis paļaujoties uz tiešiem izsaukumiem uz lietām kā mysqli_query. Ja jūs tieši izmantojat mysqli_query pusē no savām klasēm, tad jūs visu saistāt tieši ar savu datu bāzi. Nekas pret MySQL šeit, bet, ja jūs izmantojat mysqli_query, šāda veida zemlaukuma detaļas vajadzētu būt paslēptas tikai vienā vietā, un tad šī funkcionalitāte vajadzētu būt pieejama caur ģenerisku aploksni.

Tagad es zinu, ka tas ir mazliet izmantots piemērs, ja jūs par to domājat, jo reizes, kad jūs pilnībā mainīsiet savu datu bāzes dzinēju pēc produkta ieviešanas, ir ļoti, ļoti zemas. Es to izvēlējos, jo domāju, ka cilvēki būs pazīstami ar ideju no sava koda. Arī, pat ja jums ir datu bāze, ar kuru jūs zināt, ka paliksiet, šī abstraktā aploksnes objekts ļauj jums labot kļūdas, mainīt uzvedību vai ieviest funkcijas, kuras jūs vēlaties, lai jūsu izvēlētajai datu bāzei būtu. Tas arī padara unit testēšanu iespējamo, kur zemlaukuma izsaukumi to nedarītu.

4 Objektu vingrinājumi

Šis nav pilns izpēte šiem principiem, bet pirmie divi ir viegli atcerēties, sniedz labu vērtību un var tikt nekavējoties piemēroti gandrīz jebkurai kodsbazei.

4.1 Ne vairāk kā viens indentācijas līmenis uz metodi

Tas ir noderīgs veids, kā domāt par metožu sadalīšanu mazākos gabalos, atstājot kodu, kas ir skaidrāks un vairāk pašdokumentējošs. Jo vairāk indentācijas līmeņu jums ir, jo vairāk metode dara un jo vairāk stāvokļa jums jāseko prātā, kamēr jūs ar to strādājat.

Tūlīt es zinu, ka cilvēki iebildīs pret to, bet tas ir tikai vadlīnija/heiistika, ne cieta un ātra likums. Es negaidu, ka kāds izpildīs PHP_CodeSniffer noteikumus tam (lai gan cilvēki ir).

Apskatīsim ātru paraugu, kā tas varētu izskatīties:

public function transformToCsv($data)
{
    $csvLines = array();
    $csvLines[] = implode(',', array_keys($data[0]));
    foreach ($data as $row) {
        if (!$row) {
            continue;
        }
        $csvLines[] = implode(',', $row);
    }
    return $csvLines;
}

Kamēr šis nav briesmīgs kods (tas tehniski ir pareizs, testējams utt...), mēs varam darīt daudz vairāk, lai to padarītu skaidru. Kā mēs samazinātu ligzdas līmeņus šeit?

Mēs zinām, ka mums ir jāvienkāršo foreach cikla saturs (vai to noņemt pilnībā), tāpēc sāksim tur.

if (!$row) {
    continue;
}

Šī pirmā daļa ir viegla. Tas tikai ignorē tukšas rindas. Mēs varam saīsināt šo procesu, izmantojot iebūtu PHP funkciju pirms pat nokļūšanas ciklā.

$data = array_filter($data);
foreach ($data as $row) {
    $csvLines[] = implode(',', $row);
}

Tagad mums ir mūsu viens ligzdas līmenis. Bet, skatoties uz to, viss, ko mēs darām, ir funkcijas piemērošana katram vienumam masīvā. Mums pat nav vajadzīgs foreach cikls, lai to darītu.

$data = array_filter($data);
$csvLines = array_map(function($row) {
    return implode(',', $row);
}, $data);

Tagad mums vispār nav ligzdas, un kods, visticamāk, būs ātrāks, jo mēs darām visu ciklu ar iebūtiem C funkcijām nevis PHP. Mums ir jāiesaistās mazliet viltībā, lai nodotu komatu uz implode, tāpēc jūs varētu argumentēt, ka apstāšanās pie iepriekšējā soļa ir daudz saprotamāka.

4.2 Mēģiniet neizmantot else

Tas tiešām attiecas uz divām galvenajām idejām. Pirmā ir vairākas return paziņojumi no metodes. Ja jums ir pietiekami daudz informācijas, lai pieņemtu lēmumu par metodes rezultātu, ejiet uz priekšu un pieņemiet to un return. Otrā ir ideja, kas pazīstama kā Guard Clauses. Tās ir pamata validācijas pārbaudes, kas kombinētas ar agrīniem return, parasti metodes augšdaļā. Ļaujiet man parādīt, ko es domāju.

public function addThreeInts($first, $second, $third) {
    if (is_int($first)) {
        if (is_int($second)) {
            if (is_int($third)) {
                $sum = $first + $second + $third;
            } else {
                return null;
            }
        } else {
            return null;
        }
    } else {
        return null;
    }
    return $sum;
}

Tā ir diezgan taisna uz priekšu atkal, tā pievieno 3 intus kopā un atgriež rezultātu, vai null, ja kāds no parametriem nav integers. Ignorējot to, ka mēs varētu apvienot visas šīs pārbaudes vienā rindā ar AND operatoriem, es domāju, ka jūs redzat, cik ligzotais if/else struktūra padara kodu grūtāk sekot. Tagad paskatieties uz šo piemēru.

public function addThreeInts($first, $second, $third) {
    if (!is_int($first)) {
        return null;
    }
    if (!is_int($second)) {
        return null;
    }
    if (!is_int($third)) {
        return null;
    }
    return $first + $second + $third;
}

Man šis piemērs ir daudz vieglāk sekot. Šeit mēs izmantojam guard clauses, lai verificētu mūsu sākotnējos pieņēmumus par parametriem, ko mēs pārejam, un nekavējoties izkāpjam no metodes, ja tās neizdodas. Mēs arī vairs neesam ar starpposma mainīgo, lai izsekotu summu caur visu metodi. Šajā gadījumā mēs esam verificējuši, ka mēs jau esam uz laimīgā ceļa, un varam vienkārši darīt to, ko mēs atnācām darīt. Atkal mēs varētu vienkārši darīt visas šīs pārbaudes vienā if, bet princips vajadzētu būt skaidrs.

5 Unit testēšana

Unit testēšana ir prakse rakstīt mazus testus, kas verificē uzvedību jūsu kodā. Tie gandrīz vienmēr tiek rakstīti tajā pašā valodā kā kods (šajā gadījumā PHP) un ir paredzēti, lai būtu pietiekami ātri, lai tos izpildītu jebkurā laikā. Tie ir ārkārtīgi vērtīgi kā rīks, lai uzlabotu jūsu kodu. Papildus acīmredzamajām priekšrocībām, nodrošinot, ka jūsu kods dara to, ko jūs domājat, unit testēšana var sniegt ļoti noderīgu dizaina atsauksmi. Ja koda gabals ir grūti testējams, tas bieži parāda dizaina problēmas. Tie arī dod jums drošības tīklu pret regresijām, un tas ļauj jums refactorēt daudz biežāk un attīstīt savu kodu tīrākam dizainam.

5.1 Rīki

Ir vairāki unit testēšanas rīki PHP, bet tālu un prom visizplatītākais ir PHPUnit. Jūs varat instalēt to, lejupielādējot PHAR failu tieši, vai instalēt to ar composer. Tā kā mēs izmantojam composer visam pārējam, mēs parādīsim šo metodi. Arī, tā kā PHPUnit, visticamāk, netiks izvietots ražošanā, mēs varam instalēt to kā dev atkarību ar šo komandu:

composer require --dev phpunit/phpunit

5.2 Testi ir specifikācija

Vissvarīgākā unit testu loma jūsu kodā ir nodrošināt izpildāmu specifikāciju tam, ko kods ir paredzēts darīt. Pat ja testa kods ir nepareizs vai kodā ir kļūdas, zināšanas par to, ko sistēma ir paredzēts darīt, ir nenovērtējama.

5.3 Rakstiet savus testus vispirms

Ja jums ir bijusi iespēja redzēt testu kopu, kas rakstīta pirms koda, un vienu, kas rakstīta pēc koda pabeigšanas, tās ir satriecoši atšķirīgas. "Pēc" testi ir daudz vairāk uztraukti par klases īstenošanas detaļām un labas līnijas seguma nodrošināšanu, savukārt "pirms" testi vairāk ir par vēlamās ārējās uzvedības verificēšanu. Tas tiešām ir tas, par ko mums rūp ar unit testiem, ir pārliecināties, ka klase izrāda pareizo uzvedību. Uz īstenošanu fokusēti testi faktiski padara refactorēšanu grūtāku, jo tie lūzt, ja klases iekšējās daļas mainās, un jūs tikko esat pazaudējis OOP informācijas slēptuves priekšrocības.

5.4 Kas padara labu unit testu

Labiem unit testiem ir daudz no šīm īpašībām:

Ir iemesli iet pret dažiem no šiem, bet kā vispārēji vadlīnijas tās jums kalpos labi.

5.5 Kad testēšana ir sāpīga

Unit testēšana liek jums izjust sliktā dizaina sāpes uz priekšu – Michael Feathers

Kad jūs rakstāt unit testus, jūs piespiežat sevi faktiski izmantot klasi, lai paveiktu lietas. Ja jūs rakstāt testus beigās, vai vēl sliktāk, vienkārši metat kodu pāri sienai QA vai kam, lai rakstītu testus, jūs nesaņemat atsauksmi par to, kā klase faktiski uzvedas. Ja mēs rakstām testus un klase ir reāla sāpe izmantot, mēs to uzzināsim, kamēr mēs to rakstām, kas ir gandrīz lētākais laiks to labot.

Ja klase ir grūti testējama, tas ir dizaina trūkums. Dažādi trūkumi parādās dažādos veidos, kaut gan. Ja jums ir jādara daudz mocking, jūsu klasei, iespējams, ir pārāk daudz atkarību vai jūsu metodes dara pārāk daudz. Jo vairāk iestatīšanas jums ir jāveic katram testam, jo vairāk iespējams, ka jūsu metodes dara pārāk daudz. Ja jums ir jāraksta patiešām sarežģīti testa scenāriji, lai izmantotu uzvedību, klases metodes, iespējams, dara pārāk daudz. Ja jums ir jāizrok iekšā daudz privātu metožu un stāvokļa, lai testētu lietas, varbūt tur ir cita klase, kas mēģina izkļūt. Unit testēšana ir ļoti laba, lai atklātu "aisberga klases", kur 80% no tā, ko klase dara, ir paslēpts aiz protected vai private koda. Es kādreiz biju liels fans padarīt cik iespējams daudz protected, bet tagad es sapratu, ka es tikai liku savām individuālajām klasēm atbildēt par pārāk daudz, un īstā risinājums bija sadalīt klasi mazākos gabalos.

Rakstījis Brian Fenton - Brian Fenton ir bijis PHP izstrādātājs 8 gadus Vidējos Rietumos un Bay Area, šobrīd Thismoment. Viņš fokusējas uz kodu amatniecību un dizaina principiem. Blogs www.brianfenton.us, Twitter @brianfenton. Kad viņš nav aizņemts būdams tēvs, viņam patīk ēdiens, alus, spēles un mācīšanās.

Learn/security

Drošība

Pārskats

Drošība ir svarīga lieta, kad runa ir par tīmekļa lietojumprogrammām. Jūs vēlaties pārliecināties, ka jūsu lietojumprogramma ir droša un ka jūsu lietotāju dati ir drošībā. Flight nodrošina vairākas funkcijas, lai palīdzētu jums nodrošināt jūsu tīmekļa lietojumprogrammu drošību.

Izpratne

Ir vairākas izplatītas drošības draudi, par kuriem jums jāzina, būvējot tīmekļa lietojumprogrammas. Daži no visizplatītākajiem draudiem ietver:

Templates palīdz ar XSS, automātiski aizbēgot izvadi pēc noklusējuma, tāpēc jums nav jāatceras to darīt. Sessions var palīdzēt ar CSRF, uzglabājot CSRF žetonu lietotāja sesijā, kā aprakstīts zemāk. Izmantojot sagatavotus paziņojumus ar PDO, var palīdzēt novērst SQL injekcijas uzbrukumus (vai izmantojot ērtas metodes PdoWrapper klasē). CORS var apstrādāt ar vienkāršu āķi pirms Flight::start() tiek izsaukts.

Visas šīs metodes darbojas kopā, lai palīdzētu saglabāt jūsu tīmekļa lietojumprogrammu drošību. Jums vienmēr jādomā par labākajām drošības praksēm, lai mācītos un saprastu tās.

Pamata Izmantošana

Virsraksti

HTTP virsraksti ir viens no vieglākajiem veidiem, kā nodrošināt jūsu tīmekļa lietojumprogrammu drošību. Jūs varat izmantot virsrakstus, lai novērstu clickjacking, XSS un citus uzbrukumus. Ir vairākas veidi, kā jūs varat pievienot šos virsrakstus savai lietojumprogrammai.

Divas lieliskas vietnes, kur pārbaudīt jūsu virsrakstu drošību, ir securityheaders.com un observatory.mozilla.org. Pēc tam, kad iestatīsiet zemāk esošo kodu, jūs viegli varēsiet pārbaudīt, vai jūsu virsraksti darbojas, izmantojot šīs divas vietnes.

Pievienot Manuāli

Jūs varat manuāli pievienot šos virsrakstus, izmantojot header metodi uz Flight\Response objekta.

// Iestatīt X-Frame-Options virsrakstu, lai novērstu clickjacking
Flight::response()->header('X-Frame-Options', 'SAMEORIGIN');

// Iestatīt Content-Security-Policy virsrakstu, lai novērstu XSS
// Piezīme: šis virsraksts var kļūt ļoti sarežģīts, tāpēc jums būs jāmeklē
//  piemēri internetā savai lietojumprogrammai
Flight::response()->header("Content-Security-Policy", "default-src 'self'");

// Iestatīt X-XSS-Protection virsrakstu, lai novērstu XSS
Flight::response()->header('X-XSS-Protection', '1; mode=block');

// Iestatīt X-Content-Type-Options virsrakstu, lai novērstu MIME sniffing
Flight::response()->header('X-Content-Type-Options', 'nosniff');

// Iestatīt Referrer-Policy virsrakstu, lai kontrolētu, cik daudz referrer informācijas tiek nosūtīta
Flight::response()->header('Referrer-Policy', 'no-referrer-when-downgrade');

// Iestatīt Strict-Transport-Security virsrakstu, lai piespiestu HTTPS
Flight::response()->header('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');

// Iestatīt Permissions-Policy virsrakstu, lai kontrolētu, kuras funkcijas un API var izmantot
Flight::response()->header('Permissions-Policy', 'geolocation=()');

Šos var pievienot jūsu routes.php vai index.php failu augšdaļā.

Pievienot kā Filtru

Jūs varat tos arī pievienot filtrā/āķī, kā sekojošā:

// Pievienot virsrakstus filtrā
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=()');
});

Pievienot kā Vidutāju

Jūs varat tos arī pievienot kā vidutāja klasi, kas nodrošina lielāko elastību, kurām maršrutiem to piemērot. Vispārīgi, šie virsraksti jāpiemēro visām HTML un API atbildēm.

// app/middlewares/SecurityHeadersMiddleware.php

namespace app\middlewares;

use flight\Engine;

class SecurityHeadersMiddleware
{
    protected Engine $app;

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

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

// index.php vai kur jums ir jūsu maršruti
// FYI, šī tukšā virkne darbojas kā globāls vidutājs visiem
// maršrutiem. Protams, jūs varētu izdarīt to pašu un pievienot
// to tikai specifiskiem maršrutiem.
Flight::group('', function(Router $router) {
    $router->get('/users', [ 'UserController', 'getUsers' ]);
    // vairāk maršrutu
}, [ SecurityHeadersMiddleware::class ]);

Cross Site Request Forgery (CSRF)

Cross Site Request Forgery (CSRF) ir uzbrukuma veids, kur ļaunprātīga vietne var likt lietotāja pārlūkprogrammai nosūtīt pieprasījumu uz jūsu vietni. To var izmantot, lai veiktu darbības jūsu vietnē bez lietotāja zināšanām. Flight nenodrošina iebūvētu CSRF aizsardzības mehānismu, bet jūs varat viegli ieviest savu, izmantojot vidutāju.

Iestatīšana

Vispirms jums jāģenerē CSRF žetons un jāglabā tas lietotāja sesijā. Tad jūs varat izmantot šo žetonu savās formās un pārbaudīt to, kad forma tiek iesniegta. Mēs izmantosim flightphp/session spraudni, lai pārvaldītu sesijas.

// Ģenerēt CSRF žetonu un glabāt to lietotāja sesijā
// (pieņemot, ka jūs esat izveidojis sesijas objektu un pievienojis to Flight)
// skatiet sesijas dokumentāciju vairāk informācijai
Flight::register('session', flight\Session::class);

// Jums jāģenerē tikai viens žetons uz sesiju (tā tas darbojas 
// visās vairākās cilnēs un pieprasījumos tam pašam lietotājam)
if(Flight::session()->get('csrf_token') === null) {
    Flight::session()->set('csrf_token', bin2hex(random_bytes(32)) );
}
Izmantojot noklusējuma PHP Flight Veidni
<!-- Izmantot CSRF žetonu savā formā -->
<form method="post">
    <input type="hidden" name="csrf_token" value="<?= Flight::session()->get('csrf_token') ?>">
    <!-- citas formas lauki -->
</form>
Izmantojot Latte

Jūs varat arī iestatīt pielāgotu funkciju, lai izvadītu CSRF žetonu savos Latte veidņos.


Flight::map('render', function(string $template, array $data, ?string $block): void {
    $latte = new Latte\Engine;

    // citas konfigurācijas...

    // Iestatīt pielāgotu funkciju, lai izvadītu CSRF žetonu
    $latte->addFunction('csrf', function() {
        $csrfToken = Flight::session()->get('csrf_token');
        return new \Latte\Runtime\Html('<input type="hidden" name="csrf_token" value="' . $csrfToken . '">');
    });

    $latte->render($finalPath, $data, $block);
});

Un tagad savos Latte veidņos jūs varat izmantot csrf() funkciju, lai izvadītu CSRF žetonu.

<form method="post">
    {csrf()}
    <!-- citas formas lauki -->
</form>

Pārbaudīt CSRF Žetonu

Jūs varat pārbaudīt CSRF žetonu, izmantojot vairākas metodes.

Vidutājs
// app/middlewares/CsrfMiddleware.php

namespace app\middleware;

use flight\Engine;

class CsrfMiddleware
{
    protected Engine $app;

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

    public function before(array $params): void
    {
        if($this->app->request()->method == 'POST') {
            $token = $this->app->request()->data->csrf_token;
            if($token !== $this->app->session()->get('csrf_token')) {
                $this->app->halt(403, 'Invalid CSRF token');
            }
        }
    }
}

// index.php vai kur jums ir jūsu maršruti
use app\middlewares\CsrfMiddleware;

Flight::group('', function(Router $router) {
    $router->get('/users', [ 'UserController', 'getUsers' ]);
    // vairāk maršrutu
}, [ CsrfMiddleware::class ]);
Notikuma Filtri
// Šis vidutājs pārbauda, vai pieprasījums ir POST pieprasījums un, ja ir, tas pārbauda, vai CSRF žetons ir derīgs
Flight::before('start', function() {
    if(Flight::request()->method == 'POST') {

        // uztvert csrf žetonu no formas vērtībām
        $token = Flight::request()->data->csrf_token;
        if($token !== Flight::session()->get('csrf_token')) {
            Flight::halt(403, 'Invalid CSRF token');
            // vai JSON atbildei
            Flight::jsonHalt(['error' => 'Invalid CSRF token'], 403);
        }
    }
});

Cross Site Scripting (XSS)

Cross Site Scripting (XSS) ir uzbrukuma veids, kur ļaunprātīga formas ievade var injicēt kodu jūsu vietnē. Lielākā daļa no šīm iespējām nāk no formas vērtībām, kuras jūsu gala lietotāji aizpildīs. Jums nekad nevajadzētu uzticēties izvadai no jūsu lietotājiem! Vienmēr pieņemiet, ka visi no viņiem ir labākie hakeri pasaulē. Viņi var injicēt ļaunprātīgu JavaScript vai HTML jūsu lapā. Šo kodu var izmantot, lai nozagt informāciju no jūsu lietotājiem vai veiktu darbības jūsu vietnē. Izmantojot Flight skata klasi vai citu veidņu dzinēju, piemēram, Latte, jūs varat viegli aizbēgt izvadi, lai novērstu XSS uzbrukumus.

// Pieņemsim, ka lietotājs ir gudrs un mēģina izmantot šo kā savu vārdu
$name = '<script>alert("XSS")</script>';

// Tas aizbēgs izvadi
Flight::view()->set('name', $name);
// Tas izvadīs: &lt;script&gt;alert(&quot;XSS&quot;)&lt;/script&gt;

// Ja jūs izmantojat kaut ko tādu kā Latte, kas reģistrēts kā jūsu skata klase, tas arī automātiski aizbēgs šo.
Flight::view()->render('template', ['name' => $name]);

SQL Injection

SQL Injection ir uzbrukuma veids, kur ļaunprātīgs lietotājs var injicēt SQL kodu jūsu datubāzē. To var izmantot, lai nozagt informāciju no jūsu datubāzes vai veiktu darbības jūsu datubāzē. Atkal jums nekad nevajadzētu uzticēties ievadei no jūsu lietotājiem! Vienmēr pieņemiet, ka viņi ir izslāpuši pēc asinīm. Jūs varat izmantot sagatavotus paziņojumus jūsu PDO objektos, kas novērsīs SQL injekciju.

// Pieņemot, ka jums ir Flight::db() reģistrēts kā jūsu PDO objekts
$statement = Flight::db()->prepare('SELECT * FROM users WHERE username = :username');
$statement->execute([':username' => $username]);
$users = $statement->fetchAll();

// Ja jūs izmantojat PdoWrapper klasi, to var viegli izdarīt vienā rindā
$users = Flight::db()->fetchAll('SELECT * FROM users WHERE username = :username', [ 'username' => $username ]);

// Jūs varat izdarīt to pašu ar PDO objektu ar ? aizstājējiem
$statement = Flight::db()->fetchAll('SELECT * FROM users WHERE username = ?', [ $username ]);

Nedroša Piemēra

Zemāk ir iemesls, kāpēc mēs izmantojam SQL sagatavotus paziņojumus, lai aizsargātu no nevainīgiem piemēriem, piemēram, zemāk:

// gala lietotājs aizpilda tīmekļa formu.
// formas vērtībai hakeris ievada kaut ko šādu:
$username = "' OR 1=1; -- ";

$sql = "SELECT * FROM users WHERE username = '$username' LIMIT 5";
$users = Flight::db()->fetchAll($sql);
// Pēc vaicājuma būvēšanas tas izskatās šādi
// SELECT * FROM users WHERE username = '' OR 1=1; -- LIMIT 5

// Tas izskatās dīvaini, bet tas ir derīgs vaicājums, kas darbosies. Patiesībā,
// tas ir ļoti izplatīts SQL injekcijas uzbrukums, kas atgriezīs visus lietotājus.

var_dump($users); // tas izdrukās visus lietotājus datubāzē, nevis tikai to vienu lietotājvārdu

CORS

Cross-Origin Resource Sharing (CORS) ir mehānisms, kas ļauj daudziem resursiem (piem., fonti, JavaScript utt.) tīmekļa lapā tikt pieprasītiem no cita domēna ārpus domēna, no kura resurss radies. Flight nav iebūvētas funkcionalitātes, bet to var viegli apstrādāt ar āķi, kas darbojas pirms Flight::start() metodes izsaukšanas.

// 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
    {
        // pielāgojiet jūsu atļautās saimnieces šeit.
        $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 vai kur jums ir jūsu maršruti
$CorsUtil = new CorsUtil();

// Tam jādarbojas pirms start darbojas.
Flight::before('start', [ $CorsUtil, 'setupCors' ]);

Kļūdu Apstrāde

Slēpjiet sensitīvas kļūdu detaļas produkcijā, lai izvairītos no informācijas noplūdes uzbrucējiem. Produkcijā reģistrējiet kļūdas, nevis rādiet tās ar display_errors iestatītu uz 0.

// Jūsu bootstrap.php vai index.php

// pievienojiet šo jūsu app/config/config.php
$environment = ENVIRONMENT;
if ($environment === 'production') {
    ini_set('display_errors', 0); // Izslēgt kļūdu rādīšanu
    ini_set('log_errors', 1);     // Reģistrēt kļūdas
    ini_set('error_log', '/path/to/error.log');
}

// Jūsu maršrutos vai kontroļeros
// Izmantojiet Flight::halt() kontrolētai kļūdu atbildēm
Flight::halt(403, 'Access denied');

Ievades Sanitizācija

Nekad neuzticieties lietotāja ievadei. Sanitizējiet to, izmantojot filter_var, pirms apstrādes, lai novērstu ļaunprātīgu datu iekļūšanu.


// Pieņemsim POST pieprasījumu ar $_POST['input'] un $_POST['email']

// Sanitizēt virkni ievadi
$clean_input = filter_var(Flight::request()->data->input, FILTER_SANITIZE_STRING);
// Sanitizēt e-pastu
$clean_email = filter_var(Flight::request()->data->email, FILTER_SANITIZE_EMAIL);

Paroles Hāšošana

Glabājiet paroles droši un pārbaudiet tās droši, izmantojot PHP iebūvētās funkcijas, piemēram, password_hash un password_verify. Paroles nekad nevajadzētu glabāt vienkāršā tekstā, nedrīkst tās šifrēt ar atgriezeniskām metodēm. Hāšošana nodrošina, ka pat ja jūsu datubāze ir kompromitēta, faktiskās paroles paliek aizsargātas.

$password = Flight::request()->data->password;
// Hāšot paroli, kad glabājat (piem., reģistrācijas laikā)
$hashed_password = password_hash($password, PASSWORD_DEFAULT);

// Pārbaudīt paroli (piem., pieteikšanās laikā)
if (password_verify($password, $stored_hash)) {
    // Parole sakrīt
}

Ātruma Ierobežošana

Aizsargājiet pret brute force uzbrukumiem vai servisa atteikuma uzbrukumiem, ierobežojot pieprasījumu ātrumu ar kešu.

// Pieņemot, ka jums ir uzstādīts un reģistrēts flightphp/cache
// Izmantojot flightphp/cache filtrā
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, 'Too many requests');
    }

    $cache->set($key, $attempts + 1, 60); // Atjaunot pēc 60 sekundēm
});

Skatīt Arī

Traucējummeklēšana

Izmaiņu Žurnāls

Learn/routing

Maršrutizācija

Pārskats

Maršrutizācija Flight PHP kartē URL raksturlietas ar atgriezeniskajām funkcijām vai klases metodēm, ļaujot ātri un vienkārši apstrādāt pieprasījumus. Tā ir paredzēta minimālam overhead, iesācējam draudzīgai lietošanai un paplašināmībai bez ārējām atkarībām.

Saprašana

Maršrutizācija ir kodola mehānisms, kas savieno HTTP pieprasījumus ar jūsu lietojumprogrammas loģiku Flight. Definējot maršrutus, jūs norādāt, kā dažādas URL izraisa specifisku kodu, vai nu caur funkcijām, klases metodēm vai kontroliera darbībām. Flight maršrutizācijas sistēma ir elastīga, atbalsta pamatraksturlietas, nosauktos parametrus, regulārās izteiksmes un papildu funkcijas, piemēram, atkarību injekciju un resursu maršrutizāciju. Šī pieeja uztur jūsu kodu organizētu un viegli uzturamu, vienlaikus paliekot ātra un vienkārša iesācējiem un paplašināma pieredzējušiem lietotājiem.

Piezīme: Vēlaties saprast vairāk par maršrutizāciju? Apskatiet "kāpēc ietvars?" lapu plašākam skaidrojumam.

Pamata Lietošana

Vienkārša Maršruta Definēšana

Pamata maršrutizācija Flight tiek veikta, saskaņojot URL raksturlietu ar atgriezenisko funkciju vai klases un metodes masīvu.

Flight::route('/', function(){
    echo 'sveiks pasaule!';
});

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

Funkciju Lietošana kā Atgriezeniskajām Funkcijām

Atgriezeniskā funkcija var būt jebkurš callable objekts. Tātad jūs varat izmantot parasto funkciju:

function hello() {
    echo 'sveiks pasaule!';
}

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

Klases un Metodes Lietošana kā Kontrolieris

Jūs varat izmantot klases metodi (statisku vai nē) kā:

class GreetingController {
    public function hello() {
        echo 'sveiks pasaule!';
    }
}

Flight::route('/', [ 'GreetingController','hello' ]);
// or
Flight::route('/', [ GreetingController::class, 'hello' ]); // preferred method
// or
Flight::route('/', [ 'GreetingController::hello' ]);
// or 
Flight::route('/', [ 'GreetingController->hello' ]);

Vai arī izveidojot objektu pirms tam un pēc tam izsaucot metodi:

use flight\Engine;

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

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

// index.php
$app = Flight::app();
$greeting = new GreetingController($app);

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

Piezīme: Pēc noklusējuma, kad kontrolieris tiek izsaukts ietvarā, flight\Engine klase vienmēr tiek injicēta, ja vien jūs neprecizējat caur atkarību injekcijas konteineru

Metodes Specifiska Maršrutizācija

Pēc noklusējuma maršruta raksturlietas tiek saskaņotas pret visām pieprasījuma metodēm. Jūs varat atbildēt uz specifiskām metodēm, novietojot identifikatoru pirms URL.

Flight::route('GET /', function () {
  echo 'Es saņēmu GET pieprasījumu.';
});

Flight::route('POST /', function () {
  echo 'Es saņēmu POST pieprasījumu.';
});

// You cannot use Flight::get() for routes as that is a method 
//    to get variables, not create a route.
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 atgriezenisko funkciju, izmantojot | atdalītāju:

Flight::route('GET|POST /', function () {
  echo 'Es saņēmu vai nu GET, vai POST pieprasījumu.';
});

Īpaša Apstrāde HEAD un OPTIONS Pieprasījumiem

Flight nodrošina iebūvētu apstrādi HEAD un OPTIONS HTTP pieprasījumiem:

HEAD Pieprasījumi

Flight::route('GET /info', function() {
    echo 'Šī ir kāda informācija!';
});
// A HEAD request to /info will return the same headers, but no body.

OPTIONS Pieprasījumi

OPTIONS pieprasījumi tiek automātiski apstrādāti Flight jebkuram definētam maršrutam.

// For a route defined as:
Flight::route('GET|POST /users', function() { /* ... */ });

// An OPTIONS request to /users will respond with:
//
// Status: 204 No Content
// Allow: GET, POST, HEAD, OPTIONS

Maršrutētāja Objekta Lietošana

Papildus jūs varat iegūt Maršrutētāja objektu, kuram ir daži palīgapstrādes metodes jūsu lietošanai:


$router = Flight::router();

// maps all methods just like Flight::route()
$router->map('/', function() {
    echo 'sveiks pasaule!';
});

// GET request
$router->get('/users', function() {
    echo 'lietotāji';
});
$router->post('/users',             function() { /* code */});
$router->put('/users/update/@id',   function() { /* code */});
$router->delete('/users/@id',       function() { /* code */});
$router->patch('/users/@id',        function() { /* code */});

Regulārās Izteiksmes (Regex)

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

Flight::route('/user/[0-9]+', function () {
  // This will match /user/1234
});

Lai gan šī metode ir pieejama, ieteicams izmantot nosauktos parametrus vai nosauktos parametrus ar regulārajā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 atgriezeniskajai funkcijai. Tas ir vairāk maršruta lasāmībai nekā jebkas cits. Lūdzu, skatiet sadaļu zemāk par svarīgu brīdinājumu.

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

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

Flight::route('/@name/@id:[0-9]{3}', function (string $name, string $id) {
  // This will match /bob/123
  // But will not match /bob/12345
});

Piezīme: Saskaņošanas regex grupas () ar pozicionālajiem parametriem nav atbalstītas. Piem: :'\(

Svarīgs Brīdinājums

Lai gan iepriekšējā piemērā šķiet, ka @name ir tieši saistīts ar mainīgo $name, tas nav. Parametru secība atgriezeniskajā funkcijā nosaka, kas tam tiek nodots. Ja jūs mainītu parametru secību atgriezeniskajā funkcijā, mainīgie tiktu mainīti arī. Šeit ir piemērs:

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

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

Neobligātie Parametri

Jūs varat norādīt nosauktos parametrus, kas ir neobligāti saskaņošanai, ietverot segmentus iekavās.

Flight::route(
  '/blog(/@year(/@month(/@day)))',
  function(?string $year, ?string $month, ?string $day) {
    // This will match the following URLS:
    // /blog/2012/12/10
    // /blog/2012/12
    // /blog/2012
    // /blog
  }
);

Jei kuri neobligātie parametri netiek saskaņoti, tie tiks nodoti kā NULL.

Wildcard Maršrutizācija

Saskaņošana tiek veikta tikai uz atsevišķiem URL segmentiem. Ja vēlaties saskaņot vairākus segmentus, varat izmantot * wildcard.

Flight::route('/blog/*', function () {
  // This will match /blog/2000/02/01
});

Lai maršrutētu visus pieprasījumus uz vienu atgriezenisko funkciju, varat darīt:

Flight::route('*', function () {
  // Do something
});

404 Nav Atrasts Apstrādātājs

Pēc noklusējuma, ja URL nevar atrast, Flight nosūtīs HTTP 404 Not Found atbildi, kas ir ļoti vienkārša un vienkārša. Ja vēlaties pielāgotu 404 atbildi, varat kartēt savu notFound metodi:

Flight::map('notFound', function() {
    $url = Flight::request()->url;

    // You could also use Flight::render() with a custom template.
    $output = <<<HTML
        <h1>Mans Pielāgots 404 Nav Atrasts</h1>
        <h3>Lapa, kuru jūs pieprasījāt {$url}, netika atrasta.</h3>
        HTML;

    $this->response()
        ->clearBody()
        ->status(404)
        ->write($output)
        ->send();
});

Metodes Nav Atrasts Apstrādātājs

Pēc noklusējuma, ja URL ir atrasts, bet metode nav atļauta, Flight nosūtīs HTTP 405 Method Not Allowed atbildi, kas ir ļoti vienkārša un vienkārša (Piem: Method Not Allowed. Allowed Methods are: GET, POST). Tā arī iekļaus Allow galveni ar atļautajām metodēm tam URL.

Ja vēlaties pielāgotu 405 atbildi, varat kartēt savu methodNotFound metodi:

use flight\net\Route;

Flight::map('methodNotFound', function(Route $route) {
    $url = Flight::request()->url;
    $methods = implode(', ', $route->methods);

    // You could also use Flight::render() with a custom template.
    $output = <<<HTML
        <h1>Mans Pielāgots 405 Metode Nav Atļauta</h1>
        <h3>Metode, kuru jūs pieprasījāt {$url}, nav atļauta.</h3>
        <p>Atļautās Metodes ir: {$methods}</p>
        HTML;

    $this->response()
        ->clearBody()
        ->status(405)
        ->setHeader('Allow', $methods)
        ->write($output)
        ->send();
});

Papildu Lietošana

Atkarību Injekcija Maršrutos

Ja vēlaties izmantot atkarību injekciju 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 jūsu objektu, vai arī varat izmantot virknes, lai definētu klasi un metodi, ko izsaukt. Jūs varat apmeklēt Atkarību Injekcijas lapu vairāk informācijas.

Šeit ir ātrs piemērs:


use flight\database\PdoWrapper;

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

    public function hello(int $id) {
        // do something with $this->pdoWrapper
        $name = $this->pdoWrapper->fetchField("SELECT name FROM users WHERE id = ?", [ $id ]);
        echo "Sveiks, pasaule! Mans vārds ir {$name}!";
    }
}

// index.php

// Setup the container with whatever params you need
// See the Dependency Injection page for more information on PSR-11
$dice = new \Dice\Dice();

// Don't forget to reassign the variable with '$dice = '!!!!!
$dice = $dice->addRule('flight\database\PdoWrapper', [
    'shared' => true,
    'constructParams' => [ 
        'mysql:host=localhost;dbname=test', 
        'root',
        'password'
    ]
]);

// Register the container handler
Flight::registerContainerHandler(function($class, $params) use ($dice) {
    return $dice->create($class, $params);
});

// Routes like normal
Flight::route('/hello/@id', [ 'Greeting', 'hello' ]);
// or
Flight::route('/hello/@id', 'Greeting->hello');
// or
Flight::route('/hello/@id', 'Greeting::hello');

Flight::start();

Izpildes Nodošana Nākamajam Maršrutam

Deprecated Jūs varat nodot izpildi nākamajam saskanīgajam maršrutam, atgriežot true no jūsu atgriezeniskās funkcijas.

Flight::route('/user/@name', function (string $name) {
  // Check some condition
  if ($name !== "Bob") {
    // Continue to next route
    return true;
  }
});

Flight::route('/user/*', function () {
  // This will get called
});

Tagad ieteicams izmantot middleware, lai apstrādātu sarežģītus gadījumus kā šis.

Maršruta Aliasēšana

Piešķirot aliasu maršrutam, jūs varat vēlāk dinamiski izsaukt šo aliasu savā lietojumprogrammā, lai tas tiktu ģenerēts vēlāk jūsu kodā (piem: saite HTML veidnē vai ģenerējot pāradresācijas URL).

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

// later in code somewhere
class UserController {
    public function update() {

        // code to save user...
        $id = $user['id']; // 5 for example

        $redirectUrl = Flight::getUrl('user_view', [ 'id' => $id ]); // will return '/users/5'
        Flight::redirect($redirectUrl);
    }
}

Tas ir īpaši noderīgi, ja jūsu URL mainās. Iepriekšējā piemērā, pieņemsim, ka lietotāji tika pārvietoti uz /admin/users/@id vietā. Ar aliasēšanu vietā maršrutam, jums vairs nav jāmeklē visi vecie URL jūsu kodā un jāmaina tie, jo alias tagad atgriezīs /admin/users/5, kā piemērā iepriekš.

Maršruta aliasēšana joprojām darbojas grupās:

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

Maršruta Informācijas Pārbaude

Ja vēlaties pārbaudīt saskanīgo maršruta informāciju, ir 2 veidi, kā to izdarīt:

  1. Jūs varat izmantot executedRoute īpašību uz Flight::router() objekta.
  2. Jūs varat pieprasīt, lai maršruta objekts tiktu nodots jūsu atgriezeniskajai funkcijai, nododot true kā trešo parametru maršruta metodē. Maršruta objekts vienmēr būs pēdējais parametrs, kas nodots jūsu atgriezeniskajai funkcijai.

executedRoute

Flight::route('/', function() {
  $route = Flight::router()->executedRoute;
  // Do something with $route
  // Array of HTTP methods matched against
  $route->methods;

  // Array of named parameters
  $route->params;

  // Matching regular expression
  $route->regex;

  // Contains the contents of any '*' used in the URL pattern
  $route->splat;

  // Shows the url path....if you really need it
  $route->pattern;

  // Shows what middleware is assigned to this
  $route->middleware;

  // Shows the alias assigned to this route
  $route->alias;
});

Piezīme: executedRoute īpašība tiks iestatīta tikai pēc tam, kad maršruts ir izpildīts. Ja mēģināsiet piekļūt tai pirms maršruta izpildes, tā būs NULL. Jūs varat izmantot executedRoute arī middleware!

Nodošana true maršruta definīcijā

Flight::route('/', function(\flight\net\Route $route) {
  // Array of HTTP methods matched against
  $route->methods;

  // Array of named parameters
  $route->params;

  // Matching regular expression
  $route->regex;

  // Contains the contents of any '*' used in the URL pattern
  $route->splat;

  // Shows the url path....if you really need it
  $route->pattern;

  // Shows what middleware is assigned to this
  $route->middleware;

  // Shows the alias assigned to this route
  $route->alias;
}, true);// <-- This true parameter is what makes that happen

Maršruta Grupēšana un Middleware

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

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

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

Jūs pat varat ligzdot grupu grupas:

Flight::group('/api', function () {
  Flight::group('/v1', function () {
    // Flight::get() gets variables, it doesn't set a route! See object context below
    Flight::route('GET /users', function () {
      // Matches GET /api/v1/users
    });

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

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

    // Flight::get() gets variables, it doesn't set a route! See object context below
    Flight::route('GET /users', function () {
      // Matches GET /api/v2/users
    });
  });
});

Grupēšana ar Objekta Kontekstu

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

$app = Flight::app();

$app->group('/api/v1', function (Router $router) {

  // user the $router variable
  $router->get('/users', function () {
    // Matches GET /api/v1/users
  });

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

Piezīme: Šī ir ieteiktā metode maršrutu un grupu definēšanai ar $router objektu.

Grupēšana ar Middleware

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

Flight::group('/api/v1', function () {
  Flight::route('/users', function () {
    // Matches /api/v1/users
  });
}, [ MyAuthMiddleware::class ]); // or [ new MyAuthMiddleware() ] if you want to use an instance

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

Resursu Maršrutizācija

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

Lai izveidotu resursu, dariet šādu:

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

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

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

Un jūsu kontrolieris izmantos šādas metodes:

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 jaunos pievienotos maršrutus ar runway, palaižot php runway routes.

Pielāgošana Resursu Maršrutiem

Ir dažas opcijas resursu maršrutu konfigurēšanai.

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ēs aliasBaseusers. Kad šie maršruti ir izveidoti, alias ir users.index, users.create utt. Ja vēlaties mainīt alias, iestatiet aliasBase uz vēlamo vērtību.

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.

// Whitelist only these methods and blacklist the rest
Flight::resource('/users', UsersController::class, [ 'only' => [ 'index', 'show' ] ]);
// Blacklist only these methods and whitelist the rest
Flight::resource('/users', UsersController::class, [ 'except' => [ 'create', 'store', 'edit', 'update', 'destroy' ] ]);

Šie ir pamatā balstīti uz balto sarakstu un melno sarakstu opcijām, lai jūs varētu norādīt, kurus maršrutus vēlaties izveidot.

Middleware

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

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

Plūsmas Atbildes

Jūs tagad varat plūst atbildes klientam, izmantojot stream() vai streamWithHeaders(). Tas ir noderīgi lielu failu nosūtīšanai, garām procesiem vai lielu atbilžu ģenerēšanai. Maršruta plūsmošana tiek apstrādāta nedaudz savādāk nekā parasts maršruts.

Piezīme: Plūsmas atbildes ir pieejamas tikai tad, ja jums ir iestatīts flight.v2.output_bufferingfalse.

Plūsma ar Manuālām Galvenēm

Jūs varat plūst atbildi klientam, izmantojot stream() metodi uz maršruta. Ja dariet to, jums jāiestata visas galvenes manuāli pirms izvades kaut ko klientam. Tas tiek darīts ar header() php funkciju vai Flight::response()->setRealHeader() metodi.

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

    $response = Flight::response();

    // obviously you would sanitize the path and whatnot.
    $fileNameSafe = basename($filename);

    // If you have additional headers to set here after the route has executed
    // you must define them before anything is echoed out.
    // They must all be a raw call to the header() function or 
    // a call to Flight::response()->setRealHeader()
    header('Content-Disposition: attachment; filename="'.$fileNameSafe.'"');
    // or
    $response->setRealHeader('Content-Disposition: attachment; filename="'.$fileNameSafe.'"');

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

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

    // manually set the content length if you'd like
    header('Content-Length: '.filesize($filePath));
    // or
    $response->setRealHeader('Content-Length: '.filesize($filePath));

    // Stream the file to the client as it's read
    readfile($filePath);

// This is the magic line here
})->stream();

Plūsma ar Galvenēm

Jūs varat izmantot streamWithHeaders() metodi, lai iestatītu galvenes pirms plūsmošanas sākšanas.

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

    // you can add any additional headers you want here
    // you just must use header() or Flight::response()->setRealHeader()

    // however you pull your data, just as an example...
    $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 ',';
        }

        // This is required to send the data to the client
        ob_flush();
    }
    echo '}';

// This is how you'll set the headers before you start streaming.
})->streamWithHeaders([
    'Content-Type' => 'application/json',
    'Content-Disposition' => 'attachment; filename="users.json"',
    // optional status code, defaults to 200
    'status' => 200
]);

Skatīt Arī

Traucējummeklēšana

404 Nav Atrasts vai Negaidīta Maršruta Uzvedība

Ja redzat 404 Nav Atrasts kļūdu (bet jūs zvērāt uz savu dzīvi, ka tas tiešām ir tur un tas nav drukas kļūda), tas patiesībā varētu būt problēma ar vērtības atgriešanu jūsu maršruta galapunktā, nevis tikai to izsaukšanu. Iemesls tam ir tīms, bet var uzmest dažus izstrādātājus.

Flight::route('/hello', function(){
    // This might cause a 404 Not Found error
    return 'Sveiks Pasaule';
});

// What you probably want
Flight::route('/hello', function(){
    echo 'Sveiks Pasaule';
});

Iemesls tam ir īpašs mehānisms, kas iebūvēts maršrutētājā, kas apstrādā atgriezenisko izvadi kā signālu "iet uz nākamo maršrutu". Jūs varat redzēt uzvedību, kas dokumentēta Maršrutizācijas sadaļā.

Izmaiņu Žurnāls

Learn/learn

Uzzināt Par Flight

Flight ir ātrs, vienkāršs, paplašināms ietvars PHP. Tas ir diezgan daudzpusīgs un to var izmantot jebkura veida tīmekļa lietojumprogrammas izveidei. Tas ir izveidots ar vienkāršību prātā un ir uzrakstīts tā, lai būtu viegli saprast un izmantot.

Piezīme: Jūs redzēsiet piemērus, kas izmanto Flight:: kā statisku mainīgo un dažus, kas izmanto $app-> Engine objektu. Abi darbojas savstarpēji aizstājami. $app un $this->app kontrolierī/vidējā ir ieteicamais pieeja no Flight komandas.

Kodola Komponenti

Maršrutēšana

Uzziniet, kā pārvaldīt maršrutus savai tīmekļa lietojumprogrammai. Tas ietver arī maršrutu grupēšanu, maršruta parametrus un vidējo.

Vidējais

Uzziniet, kā izmantot vidējo, lai filtrētu pieprasījumus un atbildes savā lietojumprogrammā.

Autoloadēšana

Uzziniet, kā automātiski ielādēt savas klases savā lietojumprogrammā.

Pieprasījumi

Uzziniet, kā apstrādāt pieprasījumus un atbildes savā lietojumprogrammā.

Atbildes

Uzziniet, kā nosūtīt atbildes saviem lietotājiem.

HTML Veidnes

Uzziniet, kā izmantot iebūvēto skata dzinēju, lai renderētu savas HTML veidnes.

Drošība

Uzziniet, kā nodrošināt savu lietojumprogrammu pret izplatītiem drošības draudiem.

Konfigurācija

Uzziniet, kā konfigurēt ietvaru savai lietojumprogrammai.

Notikumu Pārvaldnieks

Uzziniet, kā izmantot notikumu sistēmu, lai pievienotu pielāgotus notikumus savai lietojumprogrammai.

Paplašināšana Flight

Uzziniet, kā paplašināt ietvaru, pievienojot savas metodes un klases.

Metodes Āķi un Filtrēšana

Uzziniet, kā pievienot notikumu āķus savām metodēm un iekšējām ietvara metodēm.

Atkarību Injekcijas Konteiners (DIC)

Uzziniet, kā izmantot atkarību injekcijas konteinerus (DIC), lai pārvaldītu savas lietojumprogrammas atkarības.

Palīglasu Klases

Kolekcijas

Kolekcijas tiek izmantotas, lai turētu datus un būtu pieejamas kā masīvs vai kā objekts vieglākai izmantošanai.

JSON Apvalks

Tam ir dažas vienkāršas funkcijas, lai kodēšana un dekodēšana jūsu JSON būtu konsekventa.

PDO Apvalks

PDO dažreiz var radīt vairāk galvassāpju nekā nepieciešams. Šī vienkāršā apvalka klase var ievērojami atvieglot mijiedarbību ar jūsu datubāzi.

Augšupielādētā Faila Apstrādātājs

Vienkārša klase, lai palīdzētu pārvaldīt augšupielādētos failus un pārvietot tos uz pastāvīgu atrašanās vietu.

Svarīgi Koncepti

Kāpēc Ietvars?

Šeit ir īss raksts par to, kāpēc jums vajadzētu izmantot ietvaru. Ir laba ideja saprast ietvara izmantošanas priekšrocības, pirms jūs sākat to izmantot.

Turklāt ir izveidots lielisks mācību ceļvedis no @lubiana. Lai gan tas neiet dziļi detaļās par Flight specifiski, šis ceļvedis palīdzēs jums saprast dažus no galvenajiem konceptiem, kas saistīti ar ietvaru, un kāpēc tie ir izdevīgi izmantot. Jūs varat atrast mācību ceļvedi šeit.

Flight Salīdzinājumā Ar Citiem Ietvariem

Ja jūs migrējat no cita ietvara, piemēram, Laravel, Slim, Fat-Free vai Symfony uz Flight, šī lapa palīdzēs jums saprast atšķirības starp tiem.

Citi Temati

Vienības Testēšana

Sekojiet šim ceļvedim, lai uzzinātu, kā veikt vienības testēšanu jūsu Flight kodam, lai tas būtu stingrs kā klints.

AI & Izstrādātāja Pieredze

Uzziniet, kā Flight darbojas ar AI rīkiem un modernām izstrādātāja darba plūsmēm, lai palīdzētu jums kodēt ātrāk un gudrāk.

Migrēšana v2 -> v3

Atpakaļsaderība lielākoties ir saglabāta, bet ir dažas izmaiņas, par kurām jums vajadzētu zināt, migrējot no v2 uz v3.

Learn/unit_testing

Vienības testēšana

Pārskats

Vienības testēšana Flight palīdz nodrošināt, ka jūsu lietojumprogramma darbojas kā paredzēts, agrīnā stadijā uztver kļūdas un padara jūsu koda bāzi vieglāk uzturamu. Flight ir izstrādāts, lai gludi darbotos ar PHPUnit, populārāko PHP testēšanas ietvaru.

Saprašana

Vienības testi pārbauda jūsu lietojumprogrammas mazo daļu uzvedību (piemēram, kontrolierus vai servisus) izolēti. Flight tas nozīmē testēšanu, kā jūsu maršruti, kontrolieri un loģika reaģē uz dažādām ievadēm — bez paļaušanās uz globālo stāvokli vai reāliem ārējiem servisiem.

Galvenie principi:

Pamata izmantošana

PHPUnit iestatīšana

  1. Instalējiet PHPUnit ar Composer:
    composer require --dev phpunit/phpunit
  2. Izveidojiet tests direktoriju jūsu projekta saknes mapē.
  3. Pievienojiet testa skriptu jūsu composer.json:
    "scripts": {
       "test": "phpunit --configuration phpunit.xml"
    }
  4. Izveidojiet phpunit.xml failu:
    <?xml version="1.0" encoding="UTF-8"?>
    <phpunit bootstrap="vendor/autoload.php">
       <testsuites>
           <testsuite name="Flight Tests">
               <directory>tests</directory>
           </testsuite>
       </testsuites>
    </phpunit>

Tagad jūs varat palaist savus testus ar composer test.

Vienkārša maršruta apstrādātāja testēšana

Pieņemsim, ka jums ir maršruts, kas validē e-pastu:

// index.php
$app->route('POST /register', [ UserController::class, 'register' ]);

// UserController.php
class UserController {
    protected $app;
    public function __construct(flight\Engine $app) {
        $this->app = $app;
    }
    public function register() {
        $email = $this->app->request()->data->email;
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            return $this->app->json(['status' => 'error', 'message' => 'Invalid email']);
        }
        return $this->app->json(['status' => 'success', 'message' => 'Valid email']);
    }
}

Vienkāršs tests šim kontrolierim:

use PHPUnit\Framework\TestCase;
use flight\Engine;

class UserControllerTest extends TestCase {
    public function testValidEmailReturnsSuccess() {
        $app = new Engine();
        $app->request()->data->email = 'test@example.com';
        $controller = new UserController($app);
        $controller->register();
        $response = $app->response()->getBody();
        $output = json_decode($response, true);
        $this->assertEquals('success', $output['status']);
        $this->assertEquals('Valid email', $output['message']);
    }

    public function testInvalidEmailReturnsError() {
        $app = new Engine();
        $app->request()->data->email = 'invalid-email';
        $controller = new UserController($app);
        $controller->register();
        $response = $app->response()->getBody();
        $output = json_decode($response, true);
        $this->assertEquals('error', $output['status']);
        $this->assertEquals('Invalid email', $output['message']);
    }
}

Padomi:

Atkarību injekcijas izmantošana testējamu kontrolieru gadījumā

Injicējiet atkarības (piemēram, datubāzi vai pasta sūtītāju) savos kontrolieros, lai tos būtu viegli mock testos:

use flight\database\PdoWrapper;

class UserController {
    protected $app;
    protected $db;
    protected $mailer;
    public function __construct($app, $db, $mailer) {
        $this->app = $app;
        $this->db = $db;
        $this->mailer = $mailer;
    }
    public function register() {
        $email = $this->app->request()->data->email;
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            return $this->app->json(['status' => 'error', 'message' => 'Invalid email']);
        }
        $this->db->runQuery('INSERT INTO users (email) VALUES (?)', [$email]);
        $this->mailer->sendWelcome($email);
        return $this->app->json(['status' => 'success', 'message' => 'User registered']);
    }
}

Un tests ar mock:

use PHPUnit\Framework\TestCase;

class UserControllerDICTest extends TestCase {
    public function testValidEmailSavesAndSendsEmail() {
        $mockDb = $this->createMock(flight\database\PdoWrapper::class);
        $mockDb->method('runQuery')->willReturn(true);
        $mockMailer = new class {
            public $sentEmail = null;
            public function sendWelcome($email) { $this->sentEmail = $email; return true; }
        };
        $app = new flight\Engine();
        $app->request()->data->email = 'test@example.com';
        $controller = new UserController($app, $mockDb, $mockMailer);
        $controller->register();
        $response = $app->response()->getBody();
        $result = json_decode($response, true);
        $this->assertEquals('success', $result['status']);
        $this->assertEquals('User registered', $result['message']);
        $this->assertEquals('test@example.com', $mockMailer->sentEmail);
    }
}

Uzlabota izmantošana

Skatīt arī

Traucējumu novēršana

Izmaiņu žurnāls

Learn/flight_vs_symfony

Flight pret Symfoniju

Kas ir Symfony?

Symfony ir kopums ar pārlietojamiem PHP komponentiem un PHP ietvars tīmekļa projektiem.

Standarta pamatne, uz kuras tiek izveidotas labākās PHP lietojumprogrammas. Izvēlieties jebkuru no 50 pieejamajiem neatkarīgajiem komponentiem savām lietojumprogrammām.

Paātriniet jūsu PHP tīmekļa lietojumprogrammu izveidi un uzturēšanu. Beidziet atkārtojošos koda rakstīšanas uzdevumus un baudiet kontroles pār savu kodu priekšrocības.

Plusi salīdzinājumā ar Flight

Mīnusi salīdzinājumā ar Flight

Learn/flight_vs_another_framework

Salīdzinot Flight ar citu ietvaru

Ja jūs pārietat no cita ietvara, piemēram, Laravel, Slim, Fat-Free vai Symfony uz Flight, šī lapa palīdzēs jums saprast atšķirības starp abiem.

Laravel

Laravel ir pilnīgi iezīmēts ietvars, kuram ir visas papardes un brīnumaini izstrādātāja vērsti ekosistēma, bet par cenu veiktspējai un sarežģītībai.

Skatiet salīdzinājumu starp Laravel un Flight.

Slim

Slim ir mikro ietvars, kas ir līdzīgs Flight. Tas ir izstrādāts, lai būtu viegls un viegli lietojams, bet var būt nedaudz sarežģītāks nekā Flight.

Skatiet salīdzinājumu starp Slim un Flight.

Fat-Free

Fat-Free ir pilnas kaudzes ietvars daudz mazākā iepakojumā. Lai arī tam ir visas rīces rīku kastē, tas var padarīt dažus projektus sarežģītākus nekā tie vajadzīgi būtu.

Skatiet salīdzinājumu starp Fat-Free un Flight.

Symfony

Symfony ir modulārs uzņēmumu līmeņa ietvars, kas ir izstrādāts, lai būtu elastīgs un skalējams. Mazākiem projektiem vai jaunajiem izstrādātājiem Symfony var būt nedaudz apburošs.

Skatiet salīdzinājumu starp Symfony un Flight.

Learn/pdo_wrapper

PdoWrapper PDO Palīgdarbības klase

Pārskats

PdoWrapper klase Flight ir draudzīgs palīgs darbam ar datubāzēm, izmantojot PDO. Tā vienkāršo izplatītās datubāzes uzdevumus, pievieno dažas ērtas metodes rezultātu iegūšanai un atgriež rezultātus kā Collections vieglai piekļuvei. Tā arī atbalsta vaicājumu reģistrēšanu un lietotnes veiktspējas uzraudzību (APM) sarežģītām lietošanas situācijām.

Saprašana

Darbs ar datubāzēm PHP var būt nedaudz verbāls, īpaši, izmantojot PDO tieši. PdoWrapper paplašina PDO un pievieno metodes, kas padara vaicājumu veikšanu, rezultātu iegūšanu un apstrādi daudz vieglāku. Tā vietā, lai žonglētu ar sagatavotiem paziņojumiem un iegūšanas režīmiem, jūs iegūstat vienkāršas metodes izplatītiem uzdevumiem, un katra rindiņa tiek atgriezta kā Collection, tāpēc jūs varat izmantot masīva vai objekta notāciju.

Jūs varat reģistrēt PdoWrapper kā koplietojamu servisu Flight un pēc tam izmantot to jebkur savā lietotnē caur Flight::db().

Pamatlietošana

PDO palīgdarbības reģistrēšana

Vispirms reģistrējiet PdoWrapper klasi ar Flight:

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

Tagad jūs varat izmantot Flight::db() jebkur, lai iegūtu savienojumu ar datubāzi.

Vaicājumu izpildīšana

runQuery()

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

Izmantojiet to INSERT, UPDATE vai kad vēlaties manuāli iegūt rezultātus:

$db = Flight::db();
$statement = $db->runQuery("SELECT * FROM users WHERE status = ?", ['active']);
while ($row = $statement->fetch()) {
    // $row ir masīvs
}

Jūs varat izmantot to arī rakstīšanai:

$db->runQuery("INSERT INTO users (name) VALUES (?)", ['Alice']);
$db->runQuery("UPDATE users SET name = ? WHERE id = ?", ['Bob', 1]);

fetchField()

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

Iegūstiet vienu vērtību no datubāzes:

$count = Flight::db()->fetchField("SELECT COUNT(*) FROM users WHERE status = ?", ['active']);

fetchRow()

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

Iegūstiet vienu rindiņu kā Collection (masīva/objekta piekļuve):

$user = Flight::db()->fetchRow("SELECT * FROM users WHERE id = ?", [123]);
echo $user['name'];
// vai
echo $user->name;

fetchAll()

function fetchAll(string $sql, array $params = []): array<Collection>

Iegūstiet visas rindiņas kā Collection masīvu:

$users = Flight::db()->fetchAll("SELECT * FROM users WHERE status = ?", ['active']);
foreach ($users as $user) {
    echo $user['name'];
    // vai
    echo $user->name;
}

Izmantojot IN() aizstājējus

Jūs varat izmantot vienu ? IN() klauzulā un nodot masīvu vai komatiem atdalītu virkni:

$ids = [1, 2, 3];
$users = Flight::db()->fetchAll("SELECT * FROM users WHERE id IN (?)", [$ids]);
// vai
$users = Flight::db()->fetchAll("SELECT * FROM users WHERE id IN (?)", ['1,2,3']);

Uzlabota lietošana

Vaicājumu reģistrēšana & APM

Ja vēlaties izsekot vaicājumu veiktspēju, iespējiet APM izsekošanu reģistrēšanas laikā:

Flight::register('db', \flight\database\PdoWrapper::class, [
    'mysql:host=localhost;dbname=cool_db_name', 'user', 'pass', [/* options */], true // pēdējais parametrs iespējina APM
]);

Pēc vaicājumu izpildes jūs varat manuāli reģistrēt tos, bet APM tos reģistrēs automātiski, ja iespējots:

Flight::db()->logQueries();

Tas izraisīs notikumu (flight.db.queries) ar savienojuma un vaicājumu metrikiem, ko jūs varat klausīties, izmantojot Flight notikumu sistēmu.

Pilns piemērs

Flight::route('/users', function () {
    // Iegūstiet visus lietotājus
    $users = Flight::db()->fetchAll('SELECT * FROM users');

    // Plūsma visiem lietotājiem
    $statement = Flight::db()->runQuery('SELECT * FROM users');
    while ($user = $statement->fetch()) {
        echo $user['name'];
    }

    // Iegūstiet vienu lietotāju
    $user = Flight::db()->fetchRow('SELECT * FROM users WHERE id = ?', [123]);

    // Iegūstiet vienu vērtību
    $count = Flight::db()->fetchField('SELECT COUNT(*) FROM users');

    // Īpašā IN() sintakse
    $users = Flight::db()->fetchAll('SELECT * FROM users WHERE id IN (?)', [[1,2,3,4,5]]);
    $users = Flight::db()->fetchAll('SELECT * FROM users WHERE id IN (?)', ['1,2,3,4,5']);

    // Ievietojiet jaunu lietotāju
    Flight::db()->runQuery("INSERT INTO users (name, email) VALUES (?, ?)", ['Bob', 'bob@example.com']);
    $insert_id = Flight::db()->lastInsertId();

    // Atjauniniet lietotāju
    Flight::db()->runQuery("UPDATE users SET name = ? WHERE id = ?", ['Bob', 123]);

    // Dzēsiet lietotāju
    Flight::db()->runQuery("DELETE FROM users WHERE id = ?", [123]);

    // Iegūstiet skarto rindiņu skaitu
    $statement = Flight::db()->runQuery("UPDATE users SET name = ? WHERE name = ?", ['Bob', 'Sally']);
    $affected_rows = $statement->rowCount();
});

Skatīt arī

Traucējummeklēšana

Izmaiņu žurnāls

Learn/dependency_injection_container

Atkarību Injekcijas Konteiners

Pārskats

Atkarību Injekcijas Konteiners (DIC) ir spēcīgs uzlabojums, kas ļauj jums pārvaldīt jūsu lietojumprogrammas atkarības.

Saprašana

Atkarību Injekcija (DI) ir galvenā koncepcija mūsdienu PHP ietvaros un tiek izmantota, lai pārvaldītu objektu instantiāciju un konfigurāciju. Daži DIC bibliotēku piemēri ir: flightphp/container, Dice, Pimple, PHP-DI, un league/container.

DIC ir izsmalcināts veids, kā ļaut jums izveidot un pārvaldīt savas klases centralizētā vietā. Tas ir noderīgi, kad jums jānodod tas pats objekts uz vairākām klasēm (piemēram, jūsu kontrolieriem vai starpprogrammatūras programmatūrai).

Pamata Izmantošana

Vecais veids, kā darīt lietas, var izskatīties šādi:


require 'vendor/autoload.php';

// klase, lai pārvaldītu lietotājus no datubāzes
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());
    }
}

// jūsu routes.php failā

$db = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');

$UserController = new UserController($db);
Flight::route('/user/@id', [ $UserController, 'view' ]);
// citi UserController maršruti...

Flight::start();

No iepriekšējā koda var redzēt, ka mēs izveidojam jaunu PDO objektu un nododam to mūsu UserController klasei. Tas ir labi mazai lietojumprogrammai, bet kad jūsu lietojumprogramma aug, jūs atklāsiet, ka izveidojat vai nododat to pašu PDO objektu vairākās vietās. Tieši šeit DIC nāk palīgā.

Šeit ir tas pats piemērs, izmantojot DIC (izmantojot Dice):


require 'vendor/autoload.php';

// tā pati klase kā iepriekš. Nekas nav mainījies
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());
    }
}

// izveidojiet jaunu konteineru
$container = new \Dice\Dice;

// pievienojiet noteikumu, lai pastāstītu konteineram, kā izveidot PDO objektu
// neaizmirstiet to piešķirt atpakaļ sev, kā zemāk!
$container = $container->addRule('PDO', [
    // shared nozīmē, ka tas pats objekts tiks atgriezts katru reizi
    'shared' => true,
    'constructParams' => ['mysql:host=localhost;dbname=test', 'user', 'pass' ]
]);

// Tas reģistrē konteinera apstrādātāju, lai Flight zinātu to izmantot.
Flight::registerContainerHandler(function($class, $params) use ($container) {
    return $container->create($class, $params);
});

// tagad mēs varam izmantot konteineru, lai izveidotu mūsu UserController
Flight::route('/user/@id', [ UserController::class, 'view' ]);

Flight::start();

Es deru, ka jūs varētu domāt, ka piemēram ir pievienots daudz papildu koda. Burvība nāk tad, kad jums ir cits kontrolieris, kam nepieciešams PDO objekts.


// Ja visiem jūsu kontrolieriem ir konstruktors, kam nepieciešams PDO objekts
// katrs no maršrutiem zemāk automātiski to saņems injicēts!!!
Flight::route('/company/@id', [ CompanyController::class, 'view' ]);
Flight::route('/organization/@id', [ OrganizationController::class, 'view' ]);
Flight::route('/category/@id', [ CategoryController::class, 'view' ]);
Flight::route('/settings', [ SettingsController::class, 'view' ]);

Papildu bonuss, izmantojot DIC, ir tas, ka vienības testēšana kļūst daudz vieglāka. Jūs varat izveidot viltotu objektu un nodot to jūsu klasei. Tas ir liels ieguvums, kad jūs rakstāt testus savai lietojumprogrammai!

Centralizēta DIC apstrādātāja izveide

Jūs varat izveidot centralizētu DIC apstrādātāju savā servisu failā, paplašinot [/learn/extending] jūsu lietojumprogrammu. Šeit ir piemērs:

// services.php

// izveidojiet jaunu konteineru
$container = new \Dice\Dice;
// neaizmirstiet to piešķirt atpakaļ sev, kā zemāk!
$container = $container->addRule('PDO', [
    // shared nozīmē, ka tas pats objekts tiks atgriezts katru reizi
    'shared' => true,
    'constructParams' => ['mysql:host=localhost;dbname=test', 'user', 'pass' ]
]);

// tagad mēs varam izveidot kartējamu metodi, lai izveidotu jebkuru objektu. 
Flight::map('make', function($class, $params = []) use ($container) {
    return $container->create($class, $params);
});

// Tas reģistrē konteinera apstrādātāju, lai Flight zinātu to izmantot kontrolieriem/starpprogrammatūrai
Flight::registerContainerHandler(function($class, $params) {
    Flight::make($class, $params);
});

// pieņemsim, ka mums ir šāda parauga klase, kas prasa PDO objektu konstruktorā
class EmailCron {
    protected PDO $pdo;

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

    public function send() {
        // kods, kas nosūta e-pastu
    }
}

// Un beidzot jūs varat izveidot objektus, izmantojot atkarību injekciju
$emailCron = Flight::make(EmailCron::class);
$emailCron->send();

flightphp/container

Flight ir spraudnis, kas nodrošina vienkāršu PSR-11 atbilstošu konteineru, ko jūs varat izmantot, lai apstrādātu jūsu atkarību injekciju. Šeit ir ātrs piemērs, kā to izmantot:


// index.php piemēram
require 'vendor/autoload.php';

use flight\Container;

$container = new Container;

$container->set(PDO::class, fn(): PDO => new PDO('sqlite::memory:'));

Flight::registerContainerHandler([$container, 'get']);

class TestController {
  private PDO $pdo;

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

  function index() {
    var_dump($this->pdo);
    // pareizi izvadīs šo!
  }
}

Flight::route('GET /', [TestController::class, 'index']);

Flight::start();

Uzlabota flightphp/container Izmantošana

Jūs varat arī rekursīvi atrisināt atkarības. Šeit ir piemērs:

<?php

require 'vendor/autoload.php';

use flight\Container;

class User {}

interface UserRepository {
  function find(int $id): ?User;
}

class PdoUserRepository implements UserRepository {
  private PDO $pdo;

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

  function find(int $id): ?User {
    // Implementācija ...
    return null;
  }
}

$container = new Container;

$container->set(PDO::class, static fn(): PDO => new PDO('sqlite::memory:'));
$container->set(UserRepository::class, PdoUserRepository::class);

$userRepository = $container->get(UserRepository::class);
var_dump($userRepository);

/*
object(PdoUserRepository)#4 (1) {
  ["pdo":"PdoUserRepository":private]=>
  object(PDO)#3 (0) {
  }
}
 */

DICE

Jūs varat arī izveidot savu DIC apstrādātāju. Tas ir noderīgi, ja jums ir pielāgots konteiners, ko vēlaties izmantot, kas nav PSR-11 (Dice). Skatiet pamata izmantošanu sadaļu, kā to izdarīt.

Turklāt ir daži noderīgi noklusējumi, kas padarīs jūsu dzīvi vieglāku, izmantojot Flight.

Engine Instances

Ja jūs izmantojat Engine instanci savos kontrolieros/starpprogrammatūrā, šeit ir kā jūs to konfigurētu:


// Kur kur jūsu bootstrap failā
$engine = Flight::app();

$container = new \Dice\Dice;
$container = $container->addRule('*', [
    'substitutions' => [
        // Šeit jūs nododāt instanci
        Engine::class => $engine
    ]
]);

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

// Tagad jūs varat izmantot Engine instanci savos kontrolieros/starpprogrammatūrā

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

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

Citu Klases Pievienošana

Ja jums ir citas klases, ko vēlaties pievienot konteineram, ar Dice tas ir viegli, jo tās automātiski atrisināsies ar konteineru. Šeit ir piemērs:


$container = new \Dice\Dice;
// Ja jums nav jāinjekē atkarības savās klasēs
// jums nav jādefinē nekas!
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');

PSR-11

Flight var izmantot jebkuru PSR-11 atbilstošu konteineru. Tas nozīmē, ka jūs varat izmantot jebkuru konteineru, kas implementē PSR-11 interfeisu. Šeit ir piemērs, izmantojot League PSR-11 konteineru:


require 'vendor/autoload.php';

// tā pati UserController klase kā iepriekš

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

Tas var būt nedaudz verboseāks nekā iepriekšējais Dice piemērs, tas joprojām izpilda darbu ar tiem pašiem ieguvumiem!

Skatīt Arī

Traucējummeklēšana

Izmaiņu Žurnāls

Learn/middleware

Starpamats

Pārskats

Flight atbalsta maršruta un grupas maršruta vidusprogrammatūru. Vidusprogrammatūra ir jūsu lietojumprogrammas daļa, kur kods tiek izpildīts pirms ( vai pēc) maršruta atsauksmes. Tas ir lielisks veids, kā pievienot API autentifikācijas pārbaudes jūsu kodā vai lai pārbaudītu, vai lietotājam ir atļauja piekļūt maršrutam.

Saprašana

Vidusprogrammatūra var ievērojami vienkāršot jūsu lietojumprogrammu. Tā vietā, lai izmantotu sarežģītu abstraktas klases mantojumu vai metožu pārrakstīšanu, vidusprogrammatūra ļauj jums kontrolēt savus maršrutus, pievienojot tiem savu pielāgotu lietojumprogrammas loģiku. Jūs varat domāt par vidusprogrammatūru gandrīz kā par sendviču. Jums ir maize no ārpuses, un tad slāņi ar sastāvdaļām, piemēram, salātiem, tomātiem, gaļām un sieru. Tad iedomājieties, ka katrs pieprasījums ir kā iekost sendvičā, kur jūs ēdat ārējos slāņus vispirms un pakāpeniski nokļūstat līdz kodolam.

Šeit ir vizuāls attēlojums, kā darbojas vidusprogrammatūra. Tad mēs parādīsim jums praktisku piemēru, kā tas darbojas.

Lietotāja pieprasījums URL /api ----> 
    Vidusprogrammatūra->before() izpildīta ----->
        Atsaucamā funkcija/metode, kas pievienota /api, izpildīta un atbilde ģenerēta ------>
    Vidusprogrammatūra->after() izpildīta ----->
Lietotājs saņem atbildi no servera

Un šeit ir praktisks piemērs:

Lietotājs pāriet uz URL /dashboard
    LoggedInMiddleware->before() izpildīta
        before() pārbauda derīgu pieteikšanās sesiju
            ja jā, nedarīt neko un turpināt izpildi
            ja nē, novirzīt lietotāju uz /login
                Atsaucamā funkcija/metode, kas pievienota /api, izpildīta un atbilde ģenerēta
    LoggedInMiddleware->after() neko nav definēts, tāpēc ļauj izpildei turpināties
Lietotājs saņem dashboard HTML no servera

Izpildes secība

Vidusprogrammatūras funkcijas tiek izpildītas tajā secībā, kā tās tiek pievienotas maršrutam. Izpilde ir līdzīga tam, kā Slim Framework apstrādā šo.

before() metodes tiek izpildītas pievienotās secībā, un after() metodes tiek izpildītas pretējā secībā.

Piem.: Middleware1->before(), Middleware2->before(), Middleware2->after(), Middleware1->after().

Pamata izmantošana

Jūs varat izmantot vidusprogrammatūru kā jebkuru atsaucamu metodi, tostarp anonīmu funkciju vai klasi (ieteicams)

Anonīma funkcija

Šeit ir vienkāršs piemērs:

Flight::route('/path', function() { echo ' Here I am!'; })->addMiddleware(function() {
    echo 'Middleware first!';
});

Flight::start();

// This will output "Middleware first! Here I am!"

Piezīme: Izmantojot anonīmu funkciju, vienīgā interpretētā metode ir before() metode. Jūs nevarat definēt after() uzvedību ar anonīmu klasi.

Izmantojot klases

Vidusprogrammatūru var (un vajadzētu) reģistrēt kā klasi. Ja jums vajadzīga "after" funkcionalitāte, jūs jāizmanto klase.

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

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

$MyMiddleware = new MyMiddleware();
Flight::route('/path', function() { echo ' Here I am! '; })->addMiddleware($MyMiddleware); 
// also ->addMiddleware([ $MyMiddleware, $MyMiddleware2 ]);

Flight::start();

// This will display "Middleware first! Here I am! Middleware last!"

Jūs varat definēt tikai vidusprogrammatūras klases nosaukumu, un tā uzreiz radīs klases экземпlāru.

Flight::route('/path', function() { echo ' Here I am! '; })->addMiddleware(MyMiddleware::class); 

Piezīme: Ja jūs nodod tikai vidusprogrammatūras nosaukumu, tā automātiski tiks izpildīta, izmantojot atkarību injekcijas konteineru, un vidusprogrammatūra tiks izpildīta ar parametriem, kas tai nepieciešami. Ja jums nav reģistrēts atkarību injekcijas konteiners, tas pēc noklusējuma nodos flight\Engine экземпlāru __construct(Engine $app) metodē.

Izmantojot maršrutus ar parametriem

Ja jums vajadzīgi parametri no jūsu maršruta, tie tiks nodoti kā viens masīvs jūsu vidusprogrammatūras funkcijā. (function($params) { ... } vai public function before($params) { ... }). Iemesls tam ir tas, ka jūs varat strukturēt savus parametrus grupās, un dažās no tām jūsu parametri var parādīties citā secībā, kas salauztu vidusprogrammatūras funkciju, atsaucoties uz nepareizo parametru. Šādā veidā jūs varat piekļūt tiem pēc nosaukuma, nevis pozīcijas.

use flight\Engine;

class RouteSecurityMiddleware {

    protected Engine $app;

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

    public function before(array $params) {
        $clientId = $params['clientId'];

        // jobId may or may not be passed in
        $jobId = $params['jobId'] ?? 0;

        // maybe if there's no job ID, you don't need to lookup anything.
        if($jobId === 0) {
            return;
        }

        // perform a lookup of some kind in your database
        $isValid = !!$this->app->db()->fetchField("SELECT 1 FROM client_jobs WHERE client_id = ? AND job_id = ?", [ $clientId, $jobId ]);

        if($isValid !== true) {
            $this->app->halt(400, 'You are blocked, muahahaha!');
        }
    }
}

// routes.php
$router->group('/client/@clientId/job/@jobId', function(Router $router) {

    // This group below still gets the parent middleware
    // But the parameters are passed in one single array 
    // in the middleware.
    $router->group('/job/@jobId', function(Router $router) {
        $router->get('', [ JobController::class, 'view' ]);
        $router->put('', [ JobController::class, 'update' ]);
        $router->delete('', [ JobController::class, 'delete' ]);
        // more routes...
    });
}, [ RouteSecurityMiddleware::class ]);

Grupēšana maršrutus ar vidusprogrammatūru

Jūs varat pievienot maršruta grupu, un tad katrs maršruts šajā grupā būs ar to pašu vidusprogrammatūru. Tas ir noderīgi, ja jums vajag grupēt vairākus maršrutus, piemēram, ar Auth vidusprogrammatūru, lai pārbaudītu API atslēgu galvenē.


// added at the end of the group method
Flight::group('/api', function() {

    // This "empty" looking route will actually match /api
    Flight::route('', function() { echo 'api'; }, false, 'api');
    // This will match /api/users
    Flight::route('/users', function() { echo 'users'; }, false, 'users');
    // This will match /api/users/1234
    Flight::route('/users/@id', function($id) { echo 'user:'.$id; }, false, 'user_view');
}, [ new ApiAuthMiddleware() ]);

Ja jūs vēlaties piemērot globālu vidusprogrammatūru visiem jūsu maršrutiem, jūs varat pievienot "tukšu" grupu:


// added at the end of the group method
Flight::group('', function() {

    // This is still /users
    Flight::route('/users', function() { echo 'users'; }, false, 'users');
    // And this is still /users/1234
    Flight::route('/users/@id', function($id) { echo 'user:'.$id; }, false, 'user_view');
}, [ ApiAuthMiddleware::class ]); // or [ new ApiAuthMiddleware() ], same thing

Izplatīti izmantošanas gadījumi

API atslēgas validācija

Ja jūs vēlaties aizsargāt savus /api maršrutus, pārbaudot, vai API atslēga ir pareiza, jūs varat viegli to apstrādāt ar vidusprogrammatūru.

use flight\Engine;

class ApiMiddleware {

    protected Engine $app;

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

    public function before(array $params) {
        $authorizationHeader = $this->app->request()->getHeader('Authorization');
        $apiKey = str_replace('Bearer ', '', $authorizationHeader);

        // do a lookup in your database for the api key
        $apiKeyHash = hash('sha256', $apiKey);
        $hasValidApiKey = !!$this->db()->fetchField("SELECT 1 FROM api_keys WHERE hash = ? AND valid_date >= NOW()", [ $apiKeyHash ]);

        if($hasValidApiKey !== true) {
            $this->app->jsonHalt(['error' => 'Invalid API Key']);
        }
    }
}

// routes.php
$router->group('/api', function(Router $router) {
    $router->get('/users', [ ApiController::class, 'getUsers' ]);
    $router->get('/companies', [ ApiController::class, 'getCompanies' ]);
    // more routes...
}, [ ApiMiddleware::class ]);

Tagad visi jūsu API maršruti ir aizsargāti ar šo API atslēgas validācijas vidusprogrammatūru, ko jūs esat iestatījis! Ja jūs pievienosiet vairāk maršrutus maršrutētāja grupai, tiem uzreiz būs tā pati aizsardzība!

Pieteikšanās validācija

Vai jūs vēlaties aizsargāt dažus maršrutus, lai tie būtu pieejami tikai pieteikušies lietotājiem? To var viegli sasniegt ar vidusprogrammatūru!

use flight\Engine;

class LoggedInMiddleware {

    protected Engine $app;

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

    public function before(array $params) {
        $session = $this->app->session();
        if($session->get('logged_in') !== true) {
            $this->app->redirect('/login');
            exit;
        }
    }
}

// routes.php
$router->group('/admin', function(Router $router) {
    $router->get('/dashboard', [ DashboardController::class, 'index' ]);
    $router->get('/clients', [ ClientController::class, 'index' ]);
    // more routes...
}, [ LoggedInMiddleware::class ]);

Maršruta parametra validācija

Vai jūs vēlaties aizsargāt savus lietotājus no vērtību maiņas URL, lai piekļūtu datiem, kas tiem nepieder? To var atrisināt ar vidusprogrammatūru!

use flight\Engine;

class RouteSecurityMiddleware {

    protected Engine $app;

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

    public function before(array $params) {
        $clientId = $params['clientId'];
        $jobId = $params['jobId'];

        // perform a lookup of some kind in your database
        $isValid = !!$this->app->db()->fetchField("SELECT 1 FROM client_jobs WHERE client_id = ? AND job_id = ?", [ $clientId, $jobId ]);

        if($isValid !== true) {
            $this->app->halt(400, 'You are blocked, muahahaha!');
        }
    }
}

// routes.php
$router->group('/client/@clientId/job/@jobId', function(Router $router) {
    $router->get('', [ JobController::class, 'view' ]);
    $router->put('', [ JobController::class, 'update' ]);
    $router->delete('', [ JobController::class, 'delete' ]);
    // more routes...
}, [ RouteSecurityMiddleware::class ]);

Apstrāde vidusprogrammatūras izpildes

Pieņemsim, jums ir autentifikācijas vidusprogrammatūra, un jūs vēlaties novirzīt lietotāju uz pieteikšanās lapu, ja viņš nav autentificēts. Jums ir vairākas opcijas rīcībā:

  1. Jūs varat atgriezt false no vidusprogrammatūras funkcijas, un Flight automātiski atgriezīs 403 Forbidden kļūdu, bet bez pielāgošanas.
  2. Jūs varat novirzīt lietotāju uz pieteikšanās lapu, izmantojot Flight::redirect().
  3. Jūs varat izveidot pielāgotu kļūdu vidusprogrammatūrā un apturēt maršruta izpildi.

Vienkāršs un tiešs

Šeit ir vienkāršs return false; piemērs:

class MyMiddleware {
    public function before($params) {
        $hasUserKey = Flight::session()->exists('user');
        if ($hasUserKey === false) {
            return false;
        }

        // since it's true, everything just keeps on going
    }
}

Novirzīšanas piemērs

Šeit ir piemērs, kā novirzīt lietotāju uz pieteikšanās lapu:

class MyMiddleware {
    public function before($params) {
        $hasUserKey = Flight::session()->exists('user');
        if ($hasUserKey === false) {
            Flight::redirect('/login');
            exit;
        }
    }
}

Pielāgota kļūdas piemērs

Pieņemsim, jums vajag mest JSON kļūdu, jo jūs veidojat API. Jūs varat to izdarīt šādi:

class MyMiddleware {
    public function before($params) {
        $authorization = Flight::request()->getHeader('Authorization');
        if(empty($authorization)) {
            Flight::jsonHalt(['error' => 'You must be logged in to access this page.'], 403);
            // or
            Flight::json(['error' => 'You must be logged in to access this page.'], 403);
            exit;
            // or
            Flight::halt(403, json_encode(['error' => 'You must be logged in to access this page.']);
        }
    }
}

Skatīt arī

Traucējummeklēšana

Izmaiņu žurnāls

Learn/filtering

Filtrēšana

Pārskats

Flight ļauj jums filtrēt kartētos metodes pirms un pēc to izsaukšanas.

Saprašana

Nav iepriekš definētu āķu, kurus jums vajadzētu iegaumēt. Jūs varat filtrēt jebkuru no noklusējuma ietvara metodēm, kā arī jebkuru pielāgotu metožu, kuras esat kartējuši.

Filtra funkcija izskatās šādi:

/**
 * @param array $params Metodei, kas tiek filtrēta, nodotie parametri.
 * @param string $output (tikai v2 izvades buferizēšana) Metodes, kas tiek filtrēta, izvade.
 * @return bool Atgrieziet true/void vai neatgrieziet, lai turpinātu ķēdi, false, lai pārtrauktu ķēdi.
 */
function (array &$params, string &$output): bool {
  // Filtra kods
}

Izmantojot nodotās mainīgās, jūs varat manipulēt ar ievades parametriem un/vai izvadi.

Jūs varat likt filtram darboties pirms metodes, izdarot:

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

Jūs varat likt filtram darboties pēc metodes, izdarot:

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

Jūs varat pievienot tik daudz filtru, cik vēlaties, jebkurai metodei. Tie tiks izsaukti secībā, kādā tie ir deklarēti.

Šeit ir filtrēšanas procesa piemērs:

// Kartējiet pielāgotu metodi
Flight::map('hello', function (string $name) {
  return "Hello, $name!";
});

// Pievienojiet pirms filtra
Flight::before('hello', function (array &$params, string &$output): bool {
  // Manipulējiet parametru
  $params[0] = 'Fred';
  return true;
});

// Pievienojiet pēc filtra
Flight::after('hello', function (array &$params, string &$output): bool {
  // Manipulējiet izvadi
  $output .= " Have a nice day!";
  return true;
});

// Izsauciet pielāgoto metodi
echo Flight::hello('Bob');

Šim vajadzētu parādīt:

Hello Fred! Have a nice day!

Ja esat definējuši vairākus filtrus, jūs varat pārtraukt ķēdi, atgriežot false jebkurā no jūsu filtra funkcijām:

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

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

  // Tas beigs ķēdi
  return false;
});

// Tas netiks izsaukts
Flight::before('start', function (array &$params, string &$output): bool {
  echo 'three';
  return true;
});

Piezīme: Kodola metodes, piemēram, map un register, nevar tikt filtrētas, jo tās tiek izsauktas tieši un ne dinamiski. Skatiet Extending Flight, lai iegūtu vairāk informācijas.

Skatīt arī

Traucējummeklēšana

Izmaiņu žurnāls

Learn/requests

Pieprasījumi

Pārskats

Flight ieslēdz HTTP pieprasījumu vienā objektā, ko var piekļūt, veicot:

$request = Flight::request();

Saprašana

HTTP pieprasījumi ir viens no galvenajiem HTTP dzīves cikla aspektiem, ko jāizprot. Lietotājs veic darbību tīmekļa pārlūkprogrammā vai HTTP klientā, un tie nosūta virkni galvenes, ķermeņa, URL utt. uz jūsu projektu. Jūs varat uztvert šīs galvenes (pārlūkprogrammas valoda, kādu kompresijas veidu tās var apstrādāt, lietotāja aģents utt.) un uztvert ķermeni un URL, kas nosūtīts uz jūsu Flight lietojumprogrammu. Šie pieprasījumi ir būtiski, lai jūsu lietojumprogramma saprastu, ko darīt tālāk.

Pamata Izmantošana

PHP ir vairākas superglobālās mainīgās, tostarp $_GET, $_POST, $_REQUEST, $_SERVER, $_FILES un $_COOKIE. Flight abstraktē šīs prom praktiskajās Kolekcijās. Jūs varat piekļūt query, data, cookies un files īpašībām kā masīviem vai objektiem.

Piezīme: Ir ĻOTI atgrūstami izmantot šīs superglobālās mainīgās savā projektā, un tām jāatsaucas caur request() objektu.

Piezīme: Nav pieejama abstrakcija $_ENV.

$_GET

Jūs varat piekļūt $_GET masīvam caur query īpašību:

// GET /search?keyword=something
Flight::route('/search', function(){
    $keyword = Flight::request()->query['keyword'];
    // or
    $keyword = Flight::request()->query->keyword;
    echo "You are searching for: $keyword";
    // query a database or something else with the $keyword
});

$_POST

Jūs varat piekļūt $_POST masīvam caur data īpašību:

Flight::route('POST /submit', function(){
    $name = Flight::request()->data['name'];
    $email = Flight::request()->data['email'];
    // or
    $name = Flight::request()->data->name;
    $email = Flight::request()->data->email;
    echo "You submitted: $name, $email";
    // save to a database or something else with the $name and $email
});

$_COOKIE

Jūs varat piekļūt $_COOKIE masīvam caur cookies īpašību:

Flight::route('GET /login', function(){
    $savedLogin = Flight::request()->cookies['myLoginCookie'];
    // or
    $savedLogin = Flight::request()->cookies->myLoginCookie;
    // check if it's really saved or not and if it is auto log them in
    if($savedLogin) {
        Flight::redirect('/dashboard');
        return;
    }
});

Lai iegūtu palīdzību par jaunu sīkfailu vērtību iestatīšanu, skatiet overclokk/cookie

$_SERVER

Ir pieejams saīsinājums, lai piekļūtu $_SERVER masīvam caur getVar() metodi:


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

$_FILES

Jūs varat piekļūt augšupielādētajām failiem caur files īpašību:

// raw access to $_FILES property. See below for recommended approach
$uploadedFile = Flight::request()->files['myFile']; 
// or
$uploadedFile = Flight::request()->files->myFile;

Skatiet Uploaded File Handler vairāk informācijas.

Failu Augšupielādes Apstrāde

v3.12.0

Jūs varat apstrādāt failu augšupielādi, izmantojot ietvaru ar dažām palīgapstrādes metodēm. Tas būtībā samazinās līdz faila datu iegūšanai no pieprasījuma un to pārvietošanai uz jaunu atrašanās vietu.

Flight::route('POST /upload', function(){
    // If you had an input field like <input type="file" name="myFile">
    $uploadedFileData = Flight::request()->getUploadedFiles();
    $uploadedFile = $uploadedFileData['myFile'];
    $uploadedFile->moveTo('/path/to/uploads/' . $uploadedFile->getClientFilename());
});

Ja jums ir vairāki augšupielādēti faili, jūs varat tos iziet cauri cilpai:

Flight::route('POST /upload', function(){
    // If you had an input field like <input type="file" name="myFiles[]">
    $uploadedFiles = Flight::request()->getUploadedFiles()['myFiles'];
    foreach ($uploadedFiles as $uploadedFile) {
        $uploadedFile->moveTo('/path/to/uploads/' . $uploadedFile->getClientFilename());
    }
});

Drošības Piezīme: Vienmēr validējiet un sanitizējiet lietotāja ievadi, īpaši, kad strādājat ar failu augšupielādi. Vienmēr validējiet paplašinājumu veidus, kurus atļausiet augšupielādēt, bet jums arī vajadzētu validēt faila "magic bytes", lai nodrošinātu, ka tas patiešām ir tāds faila veids, kādu lietotājs apgalvo. Ir pieejami raksti un bibliotēkas, lai palīdzētu ar to.

Pieprasījuma Ķermenis

Lai iegūtu neapstrādātu HTTP pieprasījuma ķermeni, piemēram, strādājot ar POST/PUT pieprasījumiem, jūs varat veikt:

Flight::route('POST /users/xml', function(){
    $xmlBody = Flight::request()->getBody();
    // do something with the XML that was sent.
});

JSON Ķermenis

Ja jūs saņemat pieprasījumu ar satura veidu application/json un piemēra datiem {"id": 123} tas būs pieejams no data īpašības:

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

Pieprasījuma Galvenes

Jūs varat piekļūt pieprasījuma galvenēm, izmantojot getHeader() vai getHeaders() metodi:


// Maybe you need Authorization header
$host = Flight::request()->getHeader('Authorization');
// or
$host = Flight::request()->header('Authorization');

// If you need to grab all headers
$headers = Flight::request()->getHeaders();
// or
$headers = Flight::request()->headers();

Pieprasījuma Metode

Jūs varat piekļūt pieprasījuma metodei, izmantojot method īpašību vai getMethod() metodi:

$method = Flight::request()->method; // actually populated by getMethod()
$method = Flight::request()->getMethod();

Piezīme: getMethod() metode vispirms iegūst metodi no $_SERVER['REQUEST_METHOD'], tad to var pārspēt $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'], ja tā pastāv, vai $_REQUEST['_method'], ja tā pastāv.

Pieprasījuma Objekta Īpašības

Pieprasījuma objekts nodrošina šādas īpašības:

Palīgapstrādes Metodes

Ir dažas palīgapstrādes metodes, lai saliktu URL daļas vai strādātu ar noteiktām galvenēm.

Pilns URL

Jūs varat piekļūt pilnam pieprasījuma URL, izmantojot getFullUrl() metodi:

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

Bāzes URL

Jūs varat piekļūt bāzes URL, izmantojot getBaseUrl() metodi:

// http://example.com/path/to/something/cool?query=yes+thanks
$url = Flight::request()->getBaseUrl();
// https://example.com
// Notice, no trailing slash.

Vaicājuma Parsēšana

Jūs varat nodot URL uz parseQuery() metodi, lai parsētu vaicājuma virkni asociatīvā masīvā:

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

Saturu Pieņemšanas Veidu Sarunas

v3.17.2

Jūs varat izmantot negotiateContentType() metodi, lai noteiktu labāko satura veidu, ar kuru atbildēt, balstoties uz Accept galveni, ko nosūtījis klients.


// Example Accept header: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
// The below defines what you support.
$availableTypes = ['application/json', 'application/xml'];
$typeToServe = Flight::request()->negotiateContentType($availableTypes);
if ($typeToServe === 'application/json') {
    // Serve JSON response
} elseif ($typeToServe === 'application/xml') {
    // Serve XML response
} else {
    // Default to something else or throw an error
}

Piezīme: Ja neviena no pieejamajām veidiem nav atrasta Accept galvenē, metode atgriezīs null. Ja nav definēta Accept galvene, metode atgriezīs pirmo veidu $availableTypes masīvā.

Skatīt Arī

Traucējummeklēšana

Izmaiņu Žurnāls

Learn/why_frameworks

Kāpēc ietvaru?

Daudzi programmētāji stingri iebilst pret ietvaru izmantošanu. Viņi argumentē, ka ietvari ir pārpildīti, lēni un grūti apgūstami. Viņi saka, ka ietvari nav nepieciešami un ka jūs varat rakstīt labāku kodu bez tiem. Noteikti var izteikt dažus pamatoti iebildumus pret ietvaru izmantošanu. Tomēr ir arī daudz priekšrocību, izmantojot ietvarus.

Iemesli izmantot ietvaru

Šeit ir daži iemesli, kāpēc jums varētu būt jāapsver ietvara izmantošana:

Flight ir mikroietvars. Tas nozīmē, ka tas ir neliels un viegls. Tas nepiedāvā tik daudz funkcionalitātes kā lielāki ietvari, piemēram, Laravel vai Symfony. Tomēr tas nodrošina lielu daļu funkcionalitātes, kas jums nepieciešama, lai veidotu tīmekļa lietojumprogrammas. Tas arī ir viegli apgūstams un lietojams. Tas padara to par labu izvēli, lai ātri un viegli veidotu tīmekļa lietojumprogrammas. Ja esat jauns ietvaru jomā, Flight ir lielisks iesācēju ietvars, ar kuru sākt. Tas palīdzēs jums iemācīties par ietvaru izmantošanas priekšrocībām, neplūstot jums ar pārāk daudz sarežģītības. Kad esat ieguvis kādu pieredzi ar Flight, būs vieglāk pāriet uz sarežģītākiem ietvariem, piemēram, Laravel vai Symfony, taču Flight joprojām var veiksmīgi veidot izturīgu lietojumprogrammu.

Kas ir Maršrutēšana?

Maršrutēšana ir Flight ietvara pamatā, bet kas tas īsti ir? Maršrutēšana ir process, kurā tiek ņemts URL un tiek saskaņots ar konkrētu funkciju jūsu kodā. Tā ir veids, kā padarīt jūsu tīmekļa vietni dažāda satura, balstoties uz pieprasīto URL. Piemēram, jūs varētu vēlēties parādīt lietotāja profilu, kad viņi apmeklē /lietotājs/1234, bet parādīt visu lietotāju sarakstu, kad viņi apmeklē /lietotāji. Tas ir visu izdarīts caur maršrutēšanu.

Tas varētu darboties šādi:

Un kāpēc ir svarīgi?

Pareiza centralizēta maršrutētāja sistēma faktiski var padarīt jūsu dzīvi dramatiski vieglāku! Tas var būt grūti pamanāms sākumā. Šeit ir daži iemesli, kāpēc:

Es esmu drošs, ka esat iepazinies ar skriptu pa skriptam veidu, kā radīt tīmekļa vietni. Jums var būt fails, ko sauc index.php, kurā ir daudz if paziņojumu, lai pārbaudītu URL un tad izpildītu konkrētu funkciju, pamatojoties uz URL. Tas ir veids, kā maršrutēšana, bet tas nav ļoti organizēts un tas var ātri izvērsties. Flight maršrutēšanas sistēma ir daudz organizētāka un spēcīgāka veidā, kā apstrādāt maršrutēšanu.

Tas?

// /lietotajs/skatit_profila.php?id=1234
if ($_GET['id']) {
    $id = $_GET['id'];
    skatitLietotajaProfilu($id);
}

// /lietotajs/rediget_profila.php?id=1234
if ($_GET['id']) {
    $id = $_GET['id'];
    reditLietotajaProfilu($id);
}

// u.c...

Vai tas?

// index.php
Flight::route('/lietotajs/@id', ['LietotajaKontrolieris', 'skatitLietotajaProfilu']);
Flight::route('/lietotajs/@id/edit', ['LietotajaKontrolieris', 'reditLietotajaProfilu']);

// Varbūt jūsu app/controllers/LietotajaKontrolieris.php
class LietotajaKontrolieris {
    public function skatitLietotajaProfilu($id) {
        // darīt kaut ko
    }

    public function reditLietotajaProfilu($id) {
        // darīt kaut ko
    }
}

Cerams, jūs sākat ieraudzīt ieguvumus no centralizētas maršrutēšanas sistēmas izmantošanas. Ilgtermiņā to ir daudz vieglāk pārvaldīt un saprast!

Pieprasījumi un Atbildes

Flight nodrošina vienkāršu un vieglu veidu, kā apstrādāt pieprasījumus un atbildes. Tas ir tīmekļa ietvaru būtība. Tas pieņem pieprasījumu no lietotāja pārlūka, apstrādā to, un pēc tam nosūta atbildi. Tā ir veids, kā jūs varat veidot tīmekļa lietojumprogrammas, kas darbojas, piemēram, rāda lietotāja profilu, ļauj lietotājam pierakstīties vai ļauj lietotājam publicēt jaunu bloga ierakstu.

Pieprasījumi

Pieprasījums ir tas, ko lietotāja pārlūks sūta uz jūsu serveri, kad viņi apmeklē jūsu tīmekļa vietni. Šis pieprasījums satur informāciju par to, ko lietotājs vēlas darīt. Piemēram, tas var saturēt informāciju par to, kādu URL lietotājs vēlas apmeklēt, kādu datu lietotājs vēlas nosūtīt uz jūsu serveri vai kādu veidu dati lietotājs vēlas saņemt no jūsu servera. Svarīgi ir zināt, ka pieprasījums ir tikai lasīšanas režīmā. Jūs nevarat mainīt pieprasījumu, bet jūs to varat lasīt.

Flight nodrošina vienkāršu veidu, kā piekļūt informācijai par pieprasījumu. Jūs varat piekļūt informācijai par pieprasījumu, izmantojot Flight::request() metodi. Šī metode atgriež Pieprasījums objektu, kas satur informāciju par pieprasījumu. Jūs varat izmantot šo objektu, lai piekļūtu informācijai par pieprasījumu, piemēram, URL, metodi vai datiem, ko lietotājs nosūtījis uz jūsu serveri.

Atbildes

Atbilde ir tas, ko jūsu serveris nosūta atpakaļ uz lietotāja pārlūku, kad viņi apmeklē jūsu tīmekļa vietni. Šī atbilde satur informāciju par to, ko jūsu serveris vēlas darīt. Piemēram, tas var saturēt informāciju par to, kāda veida datus jūsu serveris vēlas nosūtīt lietotājam, kāda veida datus jūsu serveris vēlas saņemt no lietotāja vai kāda veida datus jūsu serveris vēlas saglabāt lietotāja datorā.

Flight nodrošina vienkāršu veidu, kā nosūtīt atbildi uz lietotāja pārlūku. Jūs varat nosūtīt atbildi, izmantojot Flight::response() metodi. Šī metode nospiež Atbilde objektu kā argumentu un nosūta atbildi uz lietotāja pārlūku. Jūs varat izmantot šo objektu, lai nosūtītu atbildi uz lietotāja pārlūku, piemēram, HTML, JSON vai failu. Flight palīdz jums automātiski ģenerēt dažas atbildes daļas, lai padarītu lietas vieglas,# Kāpēc ietvaru?

Daudzi programmētāji stingri iebilst pret ietvaru izmantošanu. Viņi argumentē, ka ietvari ir pārpildīti, lēni un grūti apgūstami. Viņi saka, ka ietvari nav nepieciešami un ka jūs varat rakstīt labāku kodu bez tiem. Noteikti var izteikt dažus pamatoti iebildumus pret ietvaru izmantošanu. Tomēr ir arī daudz priekšrocību, izmantojot ietvarus.

Iemesli izmantot ietvaru

Šeit ir daži iemesli, kāpēc jums varētu būt jāapsver ietvara izmantošana:

Flight ir mikroietvars. Tas nozīmē, ka tas ir neliels un viegls. Tas nepiedāvā tik daudz funkcionalitātes kā lielāki ietvari, piemēram, Laravel vai Symfony. Tomēr tas nodrošina lielu daļu funkcionalitātes, kas jums nepieciešama, lai veidotu tīmekļa lietojumprogrammas. Tas arī ir viegli apgūstams un lietojams. Tas padara to par labu izvēli, lai ātri un viegli veidotu tīmekļa lietojumprogrammas. Ja esat jauns ietvaru jomā, Flight ir lielisks iesācēju ietvars, ar kuru sākt. Tas palīdzēs jums iemācīties par ietvaru izmantošanas priekšrocībām, neplūstot jums ar pārāk daudz sarežģītības. Kad esat ieguvis kādu pieredzi...

Learn/responses

Atbildes

Pārskats

Flight palīdz ģenerēt daļu no atbildes galvenes jums, bet jūs kontrolējat lielāko daļu no tā, ko nosūtāt atpakaļ lietotājam. Lielāko daļu laika jūs tieši piekļūsiet response() objektam, bet Flight piedāvā dažas palīgmēģinājumu metodes, lai iestatītu dažas atbildes galvenes jums.

Izpratne

Pēc tam, kad lietotājs nosūta savu pieprasījumu uz jūsu lietojumprogrammu, jums jāģenerē pareiza atbilde viņiem. Viņi ir nosūtījuši jums informāciju, piemēram, valodu, kuru viņi dod priekšroku, vai viņi var apstrādāt noteiktus kompresijas veidus, viņu lietotāja aģentu utt., un pēc visu apstrādes ir pienācis laiks nosūtīt viņiem atpakaļ pareizu atbildi. Tas var būt galvenes iestatīšana, HTML vai JSON ķermeņa izvade viņiem vai novirzīšana uz lapu.

Pamata lietošana

Atbildes ķermeņa nosūtīšana

Flight izmanto ob_start(), lai buferētu izvadi. Tas nozīmē, ka jūs varat izmantot echo vai print, lai nosūtītu atbildi lietotājam, un Flight to uztvers un nosūtīs atpakaļ lietotājam ar atbilstošajām galvenēm.

// Tas nosūtīs "Hello, World!" uz lietotāja pārlūkprogrammu
Flight::route('/', function() {
    echo "Hello, World!";
});

// HTTP/1.1 200 OK
// Content-Type: text/html
//
// Hello, World!

Kā alternatīvu, jūs varat izsaukt write() metodi, lai pievienotu ķermenim.

// Tas nosūtīs "Hello, World!" uz lietotāja pārlūkprogrammu
Flight::route('/', function() {
    // verbose, bet dažreiz tas ir nepieciešams
    Flight::response()->write("Hello, World!");

    // ja vēlaties iegūt ķermeni, kuru esat iestatījis šajā brīdī
    // jūs varat to izdarīt šādi
    $body = Flight::response()->getBody();
});

JSON

Flight nodrošina atbalstu JSON un JSONP atbilžu nosūtīšanai. Lai nosūtītu JSON atbildi, jūs nododiet datus, kas jākodē JSON:

Flight::route('/@companyId/users', function(int $companyId) {
    // kaut kā izvilkt savus lietotājus no datubāzes, piemēram
    $users = Flight::db()->fetchAll("SELECT id, first_name, last_name FROM users WHERE company_id = ?", [ $companyId ]);

    Flight::json($users);
});
// [{"id":1,"first_name":"Bob","last_name":"Jones"}, /* more users */ ]

Piezīme: Pēc noklusējuma Flight nosūtīs Content-Type: application/json galveni ar atbildi. Tas arī izmantos karodziņus JSON_THROW_ON_ERROR un JSON_UNESCAPED_SLASHES, kodējot JSON.

JSON ar statusa kodu

Jūs varat arī nodot statusa kodu kā otro argumentu:

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

JSON ar skaistu izdruku

Jūs varat arī nodot argumentu pēdējā pozīcijā, lai iespējotu skaistu drukāšanu:

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

JSON argumentu secības maiņa

Flight::json() ir ļoti vecs metode, bet Flight mērķis ir saglabāt atpakaļsaderību projektiem. Tas ir ļoti vienkārši, ja vēlaties pārkārtot argumentu secību, lai izmantotu vienkāršāku sintaksi, jūs varat tikai pārkartēt JSON metodi kā jebkuru citu Flight metodi:

Flight::map('json', function($data, $code = 200, $options = 0) {

    // tagad jums nav jāizmanto `true, 'utf-8'`, kad izmantojat json() metodi!
    Flight::_json($data, $code, true, 'utf-8', $options);
}

// Un tagad to var izmantot šādi
Flight::json(['id' => 123], 200, JSON_PRETTY_PRINT);

JSON un izpildes apturēšana

v3.10.0

Ja vēlaties nosūtīt JSON atbildi un apturēt izpildi, jūs varat izmantot jsonHalt() metodi. Tas ir noderīgi gadījumos, kad jūs pārbaudāt, iespējams, kādu autorizācijas veidu, un ja lietotājs nav autorizēts, jūs varat nekavējoties nosūtīt JSON atbildi, notīrīt esošo ķermeņa saturu un apturēt izpildi.

Flight::route('/users', function() {
    $authorized = someAuthorizationCheck();
    // Pārbaudiet, vai lietotājs ir autorizēts
    if($authorized === false) {
        Flight::jsonHalt(['error' => 'Unauthorized'], 401);
        // nav izvades; nepieciešams šeit.
    }

    // Turpiniet ar pārējo maršrutu
});

Pirms v3.10.0, jums būtu jādara kaut kas šāds:

Flight::route('/users', function() {
    $authorized = someAuthorizationCheck();
    // Pārbaudiet, vai lietotājs ir autorizēts
    if($authorized === false) {
        Flight::halt(401, json_encode(['error' => 'Unauthorized']));
    }

    // Turpiniet ar pārējo maršrutu
});

Atbildes ķermeņa notīrīšana

Ja vēlaties notīrīt atbildes ķermeni, jūs varat izmantot clearBody metodi:

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

Iepriekš minētais lietošanas gadījums, iespējams, nav izplatīts, tomēr tas varētu būt izplatītāks, ja tas tiktu izmantots starpprogrammatūrā.

Izpildes palaišana uz atbildes ķermeņa

Jūs varat palaist izpildes funkciju uz atbildes ķermeņa, izmantojot addResponseBodyCallback metodi:

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

// Tas sasniegs visas atbildes visiem maršrutiem
Flight::response()->addResponseBodyCallback(function($body) {
    return gzencode($body, 9);
});

Jūs varat pievienot vairākas izpildes funkcijas, un tās tiks palaistas secībā, kādā tās tika pievienotas. Tā kā tas var pieņemt jebkuru izsaucamu, tas var pieņemt klases masīvu [ $class, 'method' ], aizvēršanu $strReplace = function($body) { str_replace('hi', 'there', $body); };, vai funkcijas nosaukumu 'minify', ja jums ir funkcija, lai samazinātu jūsu html kodu, piemēram.

Piezīme: Maršruta izpildes funkcijas nedarbosies, ja izmantojat flight.v2.output_buffering konfigurācijas opciju.

Īpašs maršruta izpildes funkcija

Ja vēlaties, lai tas attiektos tikai uz specifisku maršrutu, jūs varat pievienot izpildes funkciju pašā maršrutā:

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

    // Tas sasniegs tikai šo maršrutu atbildi
    Flight::response()->addResponseBodyCallback(function($body) {
        return gzencode($body, 9);
    });
});

Starpprogrammatūras opcija

Jūs varat arī izmantot starpprogrammatūru, lai piemērotu izpildes funkciju visiem maršrutiem caur starpprogrammatūru:

// MinifyMiddleware.php
class MinifyMiddleware {
    public function before() {
        // Šeit piemērojiet izpildes funkciju uz response() objektu.
        Flight::response()->addResponseBodyCallback(function($body) {
            return $this->minify($body);
        });
    }

    protected function minify(string $body): string {
        // kaut kā samaziniet ķermeni
        return $body;
    }
}

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

Statusa kodi

Jūs varat iestatīt atbildes statusa kodu, izmantojot status metodi:

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

Ja vēlaties iegūt pašreizējo statusa kodu, jūs varat izmantot status metodi bez jebkādiem argumentiem:

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

Atbildes galvenes iestatīšana

Jūs varat iestatīt galveni, piemēram, atbildes satura veidu, izmantojot header metodi:

// Tas nosūtīs "Hello, World!" uz lietotāja pārlūkprogrammu kā vienkāršu tekstu
Flight::route('/', function() {
    Flight::response()->header('Content-Type', 'text/plain');
    // vai
    Flight::response()->setHeader('Content-Type', 'text/plain');
    echo "Hello, World!";
});

Novirzīšana

Jūs varat novirzīt pašreizējo pieprasījumu, izmantojot redirect() metodi un nododot jaunu URL:

Flight::route('/login', function() {
    $username = Flight::request()->data->username;
    $password = Flight::request()->data->password;
    $passwordConfirm = Flight::request()->data->password_confirm;

    if($password !== $passwordConfirm) {
        Flight::redirect('/new/location');
        return; // tas ir nepieciešams, lai zemāk esošā funkcionalitāte neizpildītos
    }

    // pievienojiet jauno lietotāju...
    Flight::db()->runQuery("INSERT INTO users ....");
    Flight::redirect('/admin/dashboard');
});

Piezīme: Pēc noklusējuma Flight nosūta HTTP 303 ("See Other") statusa kodu. Jūs varat izvēles kārtā iestatīt pielāgotu kodu:

Flight::redirect('/new/location', 301); // pastāvīgs

Maršruta izpildes apturēšana

Jūs varat apturēt ietvaru un nekavējoties iziet jebkurā punktā, izsaucot halt metodi:

Flight::halt();

Jūs varat arī norādīt izvēles HTTP statusa kodu un ziņojumu:

Flight::halt(200, 'Be right back...');

Izsaucot halt, tas atmestīs jebkuru atbildes saturu līdz tam punktam un apturēs visu izpildi. Ja vēlaties apturēt ietvaru un izvadīt pašreizējo atbildi, izmantojiet stop metodi:

Flight::stop($httpStatusCode = null);

Piezīme: Flight::stop() ir dažas dīvainas uzvedības, piemēram, tas izvadīs atbildi, bet turpinās izpildīt jūsu skriptu, kas var nebūt tas, ko vēlaties. Jūs varat izmantot exit vai return pēc Flight::stop() izsaukšanas, lai novērstu turpmāku izpildi, bet parasti iesaka izmantot Flight::halt().

Tas saglabās galvenes atslēgu un vērtību atbildes objektā. Pieprasījuma dzīves cikla beigās tas izveidos galvenes un nosūtīs atbildi.

Uzlabota lietošana

Galvenes nosūtīšana nekavējoties

Var būt gadījumi, kad jums jāizdara kaut kas pielāgots ar galveni, un jums jānosūta galvene tajā pašā koda rindā, ar kuru strādājat. Ja jūs iestatāt straumētu maršrutu, tas ir tas, kas jums būtu nepieciešams. To var sasniegt caur response()->setRealHeader().

Flight::route('/', function() {
    Flight::response()->setRealHeader('Content-Type: text/plain');
    echo 'Streaming response...';
    sleep(5);
    echo 'Done!';
})->stream();

JSONP

JSONP pieprasījumiem jūs varat izvēles kārtā nodot vaicājuma parametra nosaukumu, ko izmantojat, lai definētu savu atgriezeniskās saites funkciju:

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

Tātad, veicot GET pieprasījumu, izmantojot ?q=my_func, jums vajadzētu saņemt izvadi:

my_func({"id":123});

Ja nenododat vaicājuma parametra nosaukumu, tas pēc noklusējuma būs jsonp.

Piezīme: Ja joprojām izmantojat JSONP pieprasījumus 2025. gadā un vēlāk, ielēkiet čatā un pastāstiet mums, kāpēc! Mēs mīlam dzirdēt dažus labus kaujas/briesmu stāstus!

Atbildes datu notīrīšana

Jūs varat notīrīt atbildes ķermeni un galvenes, izmantojot clear() metodi. Tas notīrīs jebkuras galvenes, kas piešķirtas atbildei, notīrīs atbildes ķermeni un iestatīs statusa kodu uz 200.

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

Tikai atbildes ķermeņa notīrīšana

Ja vēlaties notīrīt tikai atbildes ķermeni, jūs varat izmantot clearBody() metodi:

// Tas joprojām saglabās jebkuras galvenes, kas iestatītas uz response() objektu.
Flight::response()->clearBody();

HTTP kešošana

Flight nodrošina iebūvētu atbalstu HTTP līmeņa kešošanai. Ja kešošanas nosacījums ir izpildīts, Flight atgriezīs HTTP 304 Not Modified atbildi. Nākamreiz, kad klients pieprasa to pašu resursu, viņi tiks aicināti izmantot savu lokāli kešoto versiju.

Maršruta līmeņa kešošana

Ja vēlaties kešot visu savu atbildi, jūs varat izmantot cache() metodi un nodot kešošanas laiku.


// Tas kešos atbildi uz 5 minūtēm
Flight::route('/news', function () {
  Flight::response()->cache(time() + 300);
  echo 'This content will be cached.';
});

// Alternatīvi, jūs varat izmantot virkni, ko nodotu
// strtotime() metodei
Flight::route('/news', function () {
  Flight::response()->cache('+5 minutes');
  echo 'This content will be cached.';
});

Pēdējā modificēšana

Jūs varat izmantot lastModified metodi un nodot UNIX laika zīmogu, lai iestatītu datumu un laiku, kad lapa tika pēdējo reizi modificēta. Klients turpinās izmantot savu kešu, līdz pēdējās modificēšanas vērtība tiek mainīta.

Flight::route('/news', function () {
  Flight::lastModified(1234567890);
  echo 'This content will be cached.';
});

ETag

ETag kešošana ir līdzīga Last-Modified, izņemot to, ka jūs varat norādīt jebkuru ID, ko vēlaties resursam:

Flight::route('/news', function () {
  Flight::etag('my-unique-id');
  echo 'This content will be cached.';
});

Ņemiet vērā, ka izsaucot vai nu lastModified, vai etag, tas abus iestatīs un pārbaudīs keša vērtību. Ja keša vērtība ir tāda pati starp pieprasījumiem, Flight nekavējoties nosūtīs HTTP 304 atbildi un apturēs apstrādi.

Faila lejupielāde

v3.12.0

Ir palīgmēģinājuma metode, lai straumētu failu galapunktam. Jūs varat izmantot download metodi un nodot ceļu.

Flight::route('/download', function () {
  Flight::download('/path/to/file.txt');
  // No v3.17.1 jūs varat norādīt pielāgotu faila nosaukumu lejupielādei
  Flight::download('/path/to/file.txt', 'custom_name.txt');
});

Skatīt arī

Traucējummeklēšana

Izmaiņu žurnāls

Learn/events

Notikumu pārvaldnieks

no v3.15.0

Pārskats

Notikumi ļauj reģistrēt un izraisīt pielāgotu uzvedību jūsu lietojumprogrammā. Ar Flight::onEvent() un Flight::triggerEvent() pievienošanu jūs tagad varat savienoties ar galvenajiem jūsu lietojumprogrammas dzīves cikla brīžiem vai definēt savus notikumus (piemēram, paziņojumus un e-pastus), lai padarītu jūsu kodu modulārāku un paplašināmu. Šīs metodes ir daļa no Flight mappable methods, kas nozīmē, ka jūs varat pārdefinēt to uzvedību atbilstoši savām vajadzībām.

Saprašana

Notikumi ļauj atdalīt dažādas jūsu lietojumprogrammas daļas, lai tās pārāk stipri nepaļautos viena uz otru. Šī atdalīšana — bieži saukta par decoupling — padara jūsu kodu vieglāku atjaunināt, paplašināt vai atkļūdot. Tā vietā, lai rakstītu visu vienā lielā gabalā, jūs varat sadalīt savu loģiku mazākos, neatkarīgos gabalos, kas reaģē uz specifiskām darbībām (notikumiem).

Iedomājieties, ka jūs veidojat emuāru lietojumprogrammu:

Bez notikumiem jūs visu sapotu vienā funkcijā. Ar notikumiem jūs varat to sadalīt: viena daļa saglabā komentāru, cita izraisa notikumu, piemēram, 'comment.posted', un atsevišķi klausītāji apstrādā e-pastu un reģistrēšanu. Tas uztur jūsu kodu tīrāku un ļauj pievienot vai noņemt funkcijas (piemēram, paziņojumus) bez pieskāriena kodola loģikai.

Izplatīti izmantošanas gadījumi

Lielākoties notikumi ir piemēroti lietām, kas ir izvēles, bet ne absolūti kodola daļa jūsu sistēmā. Piemēram, sekojošie ir labi, bet ja tie kaut kāda iemesla dēļ neizdodas, jūsu lietojumprogramma joprojām darbojas:

Tomēr pieņemsim, ka jums ir aizmirsta parole funkcija. Tā jābūt jūsu kodola funkcionalitātes daļai un nevis notikumam, jo ja tas e-pasts netiek nosūtīts, jūsu lietotājs nevar atiestatīt paroli un izmantot jūsu lietojumprogrammu.

Pamata izmantošana

Flight notikumu sistēma ir balstīta uz divām galvenajām metodēm: Flight::onEvent() notikumu klausītāju reģistrēšanai un Flight::triggerEvent() notikumu izraisīšanai. Lūk, kā jūs varat tās izmantot:

Notikumu klausītāju reģistrēšana

Lai klausītos notikumu, izmantojiet Flight::onEvent(). Šī metode ļauj definēt, kas jānotiek, kad notikums notiek.

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

Jūs "abonējat" notikumu, sakot Flight, ko darīt, kad tas notiek. Atsaukums var pieņemt argumentus, kas nodoti no notikuma izraisītāja.

Flight notikumu sistēma ir sinhrona, kas nozīmē, ka katrs notikuma klausītājs tiek izpildīts secīgi, viens pēc otra. Kad jūs izraisa notikumu, visi reģistrētie klausītāji tam notikumam tiks izpildīti līdz galam, pirms jūsu kods turpinās. Tas ir svarīgi saprast, jo tas atšķiras no asinhronām notikumu sistēmām, kur klausītāji var darboties paralēli vai vēlākā laikā.

Vienkāršs piemērs

Flight::onEvent('user.login', function ($username) {
    echo "Welcome back, $username!";

    // you can send an email if the login is from a new location
});

Šeit, kad 'user.login' notikums tiek izraisīts, tas sveiks lietotāju vārdā un varētu ietvert loģiku e-pasta nosūtīšanai, ja nepieciešams.

Piezīme: Atsaukums var būt funkcija, anonīma funkcija vai klases metode.

Notikumu izraisīšana

Lai notikums notiktu, izmantojiet Flight::triggerEvent(). Tas saka Flight izpildīt visus klausītājus, kas reģistrēti tam notikumam, nododot līdzi jebkādu datu, ko jūs nododiet.

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

Vienkāršs piemērs

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

Tas izraisa 'user.login' notikumu un nosūta 'alice' klausītājam, ko mēs definējām iepriekš, kas izvadīs: Welcome back, alice!.

Notikumu apturēšana

Ja klausītājs atgriež false, papildu klausītāji tam notikumam netiks izpildīti. Tas ļauj apturēt notikumu ķēdi, balstoties uz specifiskiem nosacījumiem. Atcerieties, ka klausītāju secība ir svarīga, jo pirmais, kas atgriež false, apturēs pārējos.

Piemērs:

Flight::onEvent('user.login', function ($username) {
    if (isBanned($username)) {
        logoutUser($username);
        return false; // Stops subsequent listeners
    }
});
Flight::onEvent('user.login', function ($username) {
    sendWelcomeEmail($username); // this is never sent
});

Notikumu metožu pārdefinēšana

Flight::onEvent() un Flight::triggerEvent() ir pieejamas paplašināšanai, kas nozīmē, ka jūs varat pārdefinēt, kā tās darbojas. Tas ir lieliski attīstītiem lietotājiem, kas vēlas pielāgot notikumu sistēmu, piemēram, pievienojot reģistrēšanu vai mainot, kā notikumi tiek izplatīti.

Piemērs: onEvent pielāgošana

Flight::map('onEvent', function (string $event, callable $callback) {
    // Log every event registration
    error_log("New event listener added for: $event");
    // Call the default behavior (assuming an internal event system)
    Flight::_onEvent($event, $callback);
});

Tagad katru reizi, kad jūs reģistrējat notikumu, tas to reģistrē pirms turpināšanas.

Kāpēc pārdefinēt?

Kur novietot savus notikumus

Ja jūs esat jauns notikumu konceptos savā projektā, jūs varētu brīnīties: kur es reģistrēju visus šos notikumus savā lietojumprogrammā? Flight vienkāršība nozīmē, ka nav stingra noteikuma — jūs varat tos novietot kur vien tas ir loģiski jūsu projektam. Tomēr to organizēšana palīdz uzturēt jūsu kodu, kad jūsu lietojumprogramma aug. Lūk, daži praktiski varianti un labākās prakses, pielāgotas Flight vieglajai dabai:

Opcija 1: Jūsu galvenajā index.php

Mazām lietojumprogrammām vai ātriem prototipiem jūs varat reģistrēt notikumus tieši jūsu index.php failā blakus jūsu maršrutiem. Tas uztur visu vienā vietā, kas ir labi, kad vienkāršība ir jūsu prioritāte.

require 'vendor/autoload.php';

// Register events
Flight::onEvent('user.login', function ($username) {
    error_log("$username logged in at " . date('Y-m-d H:i:s'));
});

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

Flight::start();

Opcija 2: Atsevišķs events.php fails

Nedaudz lielākai lietojumprogrammai apsveriet notikumu reģistrāciju pārvietošanu uz veltītu failu, piemēram, app/config/events.php. Iekļaujiet šo failu jūsu index.php pirms jūsu maršrutiem. Tas imitē, kā maršruti bieži ir organizēti app/config/routes.php Flight projektos.

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

Flight::onEvent('user.registered', function ($email, $name) {
    echo "Email sent to $email: Welcome, $name!";
});
// index.php
require 'vendor/autoload.php';
require 'app/config/events.php';

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

Flight::start();

Opcija 3: Tuvu tam, kur tie tiek izraisīti

Vēl viena pieeja ir reģistrēt notikumus tuvu vietai, kur tie tiek izraisīti, piemēram, iekšā kontrolierī vai maršruta definīcijā. Tas labi darbojas, ja notikums ir specifisks vienai jūsu lietojumprogrammas daļai.

Flight::route('/signup', function () {
    // Register event here
    Flight::onEvent('user.registered', function ($email) {
        echo "Welcome email sent to $email!";
    });

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

Labākā prakse Flight

Padoms: Grupēt pēc mērķa

events.php failā grupējiet saistītus notikumus (piemēram, visus lietotāju saistītos notikumus kopā) ar komentāriem skaidrībai:

// app/config/events.php
// User Events
Flight::onEvent('user.login', function ($username) {
    error_log("$username logged in");
});
Flight::onEvent('user.registered', function ($email) {
    echo "Welcome to $email!";
});

// Page Events
Flight::onEvent('page.updated', function ($pageId) {
    Flight::cache()->delete("page_$pageId");
});

Šī struktūra labi paplašinās un paliek iesācējam draudzīga.

Reālas pasaules piemēri

Apskatīsim dažus reālas pasaules scenārijus, lai parādītu, kā notikumi darbojas un kāpēc tie ir noderīgi.

Piemērs 1: Lietotāja pieteikšanās reģistrēšana

// Step 1: Register a listener
Flight::onEvent('user.login', function ($username) {
    $time = date('Y-m-d H:i:s');
    error_log("$username logged in at $time");
});

// Step 2: Trigger it in your app
Flight::route('/login', function () {
    $username = 'bob'; // Pretend this comes from a form
    Flight::triggerEvent('user.login', $username);
    echo "Hi, $username!";
});

Kāpēc tas ir noderīgs: Pieteikšanās kods nav jāzina par reģistrēšanu — tas tikai izraisa notikumu. Vēlāk jūs varat pievienot vairāk klausītāju (piemēram, nosūtīt sveiciena e-pastu) bez maršruta maiņas.

Piemērs 2: Paziņošana par jauniem lietotājiem

// Listener for new registrations
Flight::onEvent('user.registered', function ($email, $name) {
    // Simulate sending an email
    echo "Email sent to $email: Welcome, $name!";
});

// Trigger it when someone signs up
Flight::route('/signup', function () {
    $email = 'jane@example.com';
    $name = 'Jane';
    Flight::triggerEvent('user.registered', $email, $name);
    echo "Thanks for signing up!";
});

Kāpēc tas ir noderīgs: Reģistrācijas loģika fokusējas uz lietotāja izveidošanu, kamēr notikums apstrādā paziņojumus. Jūs varētu vēlāk pievienot vairāk klausītāju (piemēram, reģistrēt reģistrāciju).

Piemērs 3: Keša dzēšana

// Listener to clear a cache
Flight::onEvent('page.updated', function ($pageId) {
    // if using the flightphp/cache plugin
    Flight::cache()->delete("page_$pageId");
    echo "Cache cleared for page $pageId.";
});

// Trigger when a page is edited
Flight::route('/edit-page/(@id)', function ($pageId) {
    // Pretend we updated the page
    Flight::triggerEvent('page.updated', $pageId);
    echo "Page $pageId updated.";
});

Kāpēc tas ir noderīgs: Rediģēšanas kods neuztraucas par kešošanu — tas tikai signalizē atjauninājumu. Citas lietojumprogrammas daļas var reaģēt pēc vajadzības.

Labākās prakses

Flight PHP notikumu sistēma ar Flight::onEvent() un Flight::triggerEvent() sniedz jums vienkāršu, bet spēcīgu veidu, kā būvēt elastīgas lietojumprogrammas. Ļaujot dažādām jūsu lietojumprogrammas daļām sazināties caur notikumiem, jūs varat uzturēt savu kodu organizētu, atkārtoti izmantojamu un viegli paplašināmu. Vai nu jūs reģistrējat darbības, sūtat paziņojumus vai pārvaldāt atjauninājumus, notikumi palīdz to darīt bez jūsu loģikas savijuma. Turklāt, ar iespēju pārdefinēt šīs metodes, jums ir brīvība pielāgot sistēmu savām vajadzībām. Sāciet mazu ar vienu notikumu un skatieties, kā tas pārveido jūsu lietojumprogrammas struktūru!

Iebūvētie notikumi

Flight PHP nāk ar dažiem iebūvētiem notikumiem, ko jūs varat izmantot, lai savienotos ar ietvara dzīves ciklu. Šie notikumi tiek izraisīti specifiskos pieprasījuma/atbildes cikla punktos, ļaujot jums izpildīt pielāgotu loģiku, kad notiek noteiktas darbības.

Iebūvēto notikumu saraksts

Skatīt arī

Problēmu risināšana

Izmaiņu žurnāls

Learn/templates

HTML Skati un Veidnes

Pārskats

Flight nodrošina dažas pamata HTML veidņu funkcionalitātes pēc noklusējuma. Veidņošana ir ļoti efektīvs veids, kā atdalīt jūsu lietojumprogrammas loģiku no jūsu prezentācijas slāņa.

Saprašana

Kad jūs būvējat lietojumprogrammu, jums, visticamāk, būs HTML, ko vēlaties nodot atpakaļ gala lietotājam. PHP pats par sevi ir veidņu valoda, bet ir ļoti viegli iekļaut biznesa loģiku, piemēram, datubāzes izsaukumus, API izsaukumus utt., jūsu HTML failā un padarīt testēšanu un atdalīšanu par ļoti sarežģītu procesu. Ievadot datus veidnē un ļaujot veidnei renderēt sevi, kļūst daudz vieglāk atdalīt un veikt vienības testus jūsu kodam. Jūs mums pateiksieties, ja izmantosiet veidnes!

Pamata Izmantošana

Flight ļauj nomainīt noklusējuma skata dzinēju, vienkārši reģistrējot savu paša skata klasi. Ritiniet uz leju, lai redzētu piemērus, kā izmantot Smarty, Latte, Blade un vairāk!

Latte

ieteicams

Šeit ir aprakstīts, kā izmantot Latte veidņu dzinēju jūsu skatiem.

Instalācija

composer require latte/latte

Pamata Konfigurācija

Galvenā ideja ir tā, ka jūs pārrakstāt render metodi, lai izmantotu Latte nevis noklusējuma PHP renderētāju.

// overwrite the render method to use latte instead of the default PHP renderer
Flight::map('render', function(string $template, array $data, ?string $block): void {
    $latte = new Latte\Engine;

    // Where latte specifically stores its cache
    $latte->setTempDirectory(__DIR__ . '/../cache/');

    $finalPath = Flight::get('flight.views.path') . $template;

    $latte->render($finalPath, $data, $block);
});

Latte Izmantošana Flight

Tagad, kad jūs varat renderēt ar Latte, jūs varat darīt kaut ko šāda:

<!-- app/views/home.latte -->
<html>
  <head>
    <title>{$title ? $title . ' - '}My App</title>
    <link rel="stylesheet" href="style.css">
  </head>
  <body>
    <h1>Hello, {$name}!</h1>
  </body>
</html>
// routes.php
Flight::route('/@name', function ($name) {
    Flight::render('home.latte', [
        'title' => 'Home Page',
        'name' => $name
    ]);
});

Kad jūs apmeklējat /Bob savā pārlūkā, izvade būtu:

<html>
  <head>
    <title>Home Page - My App</title>
    <link rel="stylesheet" href="style.css">
  </head>
  <body>
    <h1>Hello, Bob!</h1>
  </body>
</html>

Tālāka Lasīšana

Sarežģītāks Latte izmantošanas piemērs ar izkārtojumiem ir parādīts šīs dokumentācijas awesome plugins sadaļā.

Jūs varat uzzināt vairāk par Latte pilnām iespējām, tostarp tulkošanu un valodas iespējām, lasot oficiālo dokumentāciju.

Iebūvētais Skata Dzinējs

novecojis

Piezīme: Lai gan tas joprojām ir noklusējuma funkcionalitāte un tehniski joprojām darbojas.

Lai parādītu skata veidni, izsauciet render metodi ar veidnes faila nosaukumu un opcionāliem veidnes datiem:

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

Veidnes dati, ko jūs ievadāt, automātiski tiek ievadīti veidnē un var tikt atsauce kā lokāla mainīgā. Veidnes faili ir vienkārši PHP faili. Ja satura hello.php veidnes faila ir:

Hello, <?= $name ?>!

Izvade būtu:

Hello, Bob!

Jūs varat arī manuāli iestatīt skata mainīgos, izmantojot set metodi:

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

Mainīgais name tagad ir pieejams visos jūsu skatos. Tātad jūs varat vienkārši darīt:

Flight::render('hello');

Ņemiet vērā, ka norādot veidnes nosaukumu render metodē, jūs varat izlaist .php paplašinājumu.

Pēc noklusējuma Flight meklēs views direktoriju veidnes failiem. Jūs varat iestatīt alternatīvu ceļu jūsu veidnēm, iestatot šādu konfigurāciju:

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

Izkārtojumi

Ir izplatīti, ka tīmekļa vietnēm ir viens izkārtojuma veidnes fails ar mainīgu saturu. Lai renderētu saturu, ko izmantot izkārtojumā, jūs varat ievadīt opcionālu parametru render metodē.

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

Jūsu skats tad būs saglabājis mainīgos, ko sauc par headerContent un bodyContent. Jūs tad varat renderēt savu izkārtojumu darot:

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

Ja veidnes faili izskatās šādi:

header.php:

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

body.php:

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

layout.php:

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

Izvade būtu:

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

Smarty

Šeit ir aprakstīts, kā izmantot Smarty veidņu dzinēju jūsu skatiem:

// Load Smarty library
require './Smarty/libs/Smarty.class.php';

// Register Smarty as the view class
// Also pass a callback function to configure Smarty on load
Flight::register('view', Smarty::class, [], function (Smarty $smarty) {
  $smarty->setTemplateDir('./templates/');
  $smarty->setCompileDir('./templates_c/');
  $smarty->setConfigDir('./config/');
  $smarty->setCacheDir('./cache/');
});

// Assign template data
Flight::view()->assign('name', 'Bob');

// Display the template
Flight::view()->display('hello.tpl');

Pilnīgumam, jums vajadzētu arī pārrakstīt Flight noklusējuma render metodi:

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

Blade

Šeit ir aprakstīts, kā izmantot Blade veidņu dzinēju jūsu skatiem:

Vispirms jums jāinstalē BladeOne bibliotēka caur Composer:

composer require eftec/bladeone

Tad jūs varat konfigurēt BladeOne kā skata klasi Flight:

<?php
// Load BladeOne library
use eftec\bladeone\BladeOne;

// Register BladeOne as the view class
// Also pass a callback function to configure BladeOne on load
Flight::register('view', BladeOne::class, [], function (BladeOne $blade) {
  $views = __DIR__ . '/../views';
  $cache = __DIR__ . '/../cache';

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

// Assign template data
Flight::view()->share('name', 'Bob');

// Display the template
echo Flight::view()->run('hello', []);

Pilnīgumam, jums vajadzētu arī pārrakstīt Flight noklusējuma render metodi:

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

Šajā piemērā hello.blade.php veidnes fails var izskatīties šādi:

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

Izvade būtu:

Hello, Bob!

Skatīt Arī

Traucējummeklēšana

Izmaiņu Žurnāls

Learn/collections

Kolekcijas

Pārskats

Collection klase Flight ir ērts rīks datu kopu pārvaldībai. Tā ļauj piekļūt un manipulēt datus, izmantojot gan masīva, gan objekta notāciju, padarot jūsu kodu tīrāku un elastīgāku.

Saprašana

Collection būtībā ir apvalks ap masīvu, bet ar dažām papildu spējām. Jūs varat izmantot to kā masīvu, iterēt pār to, skaitīt tā vienumus un pat piekļūt vienumiem tā, it kā tie būtu objekta īpašības. Tas ir īpaši noderīgi, kad vēlaties nodot strukturētus datus savā lietojumprogrammā vai kad vēlaties padarīt savu kodu nedaudz lasāmāku.

Kolekcijas īsteno vairākas PHP saskarnes:

Pamata Izmantošana

Kolekcijas Izveidošana

Jūs varat izveidot kolekciju, vienkārši nododot masīvu tās konstruktoram:

use flight\util\Collection;

$data = [
  'name' => 'Flight',
  'version' => 3,
  'features' => ['routing', 'views', 'extending']
];

$collection = new Collection($data);

Vienumu Piekļūšana

Jūs varat piekļūt vienumiem, izmantojot gan masīva, gan objekta notāciju:

// Masīva notācija
echo $collection['name']; // Izvade: Flight

// Objekta notācija
echo $collection->version; // Izvade: 3

Ja mēģināsiet piekļūt atslēgai, kas nepastāv, saņemsiet null nevis kļūdu.

Vienumu Iestatīšana

Jūs varat iestatīt vienumus, izmantojot gan notāciju:

// Masīva notācija
$collection['author'] = 'Mike Cao';

// Objekta notācija
$collection->license = 'MIT';

Vienumu Pārbaude un Noņemšana

Pārbaudiet, vai vienums pastāv:

if (isset($collection['name'])) {
  // Dariet kaut ko
}

if (isset($collection->version)) {
  // Dariet kaut ko
}

Noņemiet vienumu:

unset($collection['author']);
unset($collection->license);

Iterēšana Pār Kolekciju

Kolekcijas ir iterējamas, tāpēc jūs varat izmantot tās foreach cilpā:

foreach ($collection as $key => $value) {
  echo "$key: $value\n";
}

Vienumu Skaitīšana

Jūs varat skaitīt vienumu skaitu kolekcijā:

echo count($collection); // Izvade: 4

Visu Atslēgu vai Datu Iegūšana

Iegūstiet visas atslēgas:

$keys = $collection->keys(); // ['name', 'version', 'features', 'license']

Iegūstiet visus datus kā masīvu:

$data = $collection->getData();

Kolekcijas Notīrīšana

Noņemiet visus vienumus:

$collection->clear();

JSON Serializācija

Kolekcijas var viegli konvertēt uz JSON:

echo json_encode($collection);
// Izvade: {"name":"Flight","version":3,"features":["routing","views","extending"],"license":"MIT"}

Uzlabota Izmantošana

Jūs varat pilnībā aizstāt iekšējo datu masīvu, ja nepieciešams:

$collection->setData(['foo' => 'bar']);

Kolekcijas ir īpaši noderīgas, kad vēlaties nodot strukturētus datus starp komponentiem vai kad vēlaties nodrošināt vairāk objektorientētu saskarni masīva datiem.

Skatīt Arī

Traucējumu Novēršana

Izmaiņu Žurnāls

Learn/flight_vs_fat_free

Flight salīdzinājumā ar Fat-Free

Kas ir Fat-Free?

Fat-Free (mīļi saukts par F3) ir jaudīgs, bet viegli lietojams PHP mikroietvars, kas paredzēts, lai palīdzētu jums ātri izveidot dinamiskas un robustas tīmekļa lietojumprogrammas!

Flight salīdzinājumā ar Fat-Free ir daudz kopīga un, iespējams, ir tuvākais radniecīgais ziņā par funkcijām un vienkāršību. Fat-Free ir daudzas funkcijas, kuras Flight nepiedāvā, bet tam ir arī daudz funkciju, kuras Flight piedāvā. Fat-Free sāk parādīt savu vecumu un nav tik populārs, kā tas reiz bija.

Atjauninājumi kļūst retāki, un kopiena nav tik aktīva, kā tas reiz bija. Kods ir pietiekami vienkāršs, bet dažreiz sintakses disciplīnas trūkums var padarīt to grūti lasāmu un saprotamu. Tas darbojas ar PHP 8.3, bet pats kods joprojām izskatās tā, it kā dzīvotu PHP 5.3.

Priekšrocības salīdzinājumā ar Flight

Trūkumi salīdzinājumā ar Flight

Learn/extending

Paplašināšana

Pārskats

Flight ir izstrādāts kā paplašināms ietvars. Ietvars nāk ar kopu noklusējuma metožu un komponentu, bet tas ļauj jums kartēt savas metodes, reģistrēt savas klases vai pat pārrakstīt esošās klases un metodes.

Saprašana

Ir 2 veidi, kā jūs varat paplašināt Flight funkcionalitāti:

  1. Metožu kartēšana - Tas tiek izmantots, lai izveidotu vienkāršas pielāgotas metodes, kuras jūs varat izsaukt no jebkuras vietas savā lietojumprogrammā. Šīs parasti tiek izmantotas utilītas funkcijām, kuras jūs vēlaties varēt izsaukt no jebkuras vietas savā kodā.
  2. Klases reģistrēšana - Tas tiek izmantots, lai reģistrētu savas klases ar Flight. Šis parasti tiek izmantots klasēm, kurām ir atkarības vai nepieciešama konfigurācija.

Jūs varat arī pārrakstīt esošās ietvara metodes, lai mainītu to noklusējuma uzvedību, lai labāk atbilstu jūsu projekta vajadzībām.

Ja jūs meklējat DIC (Atkarību injekcijas konteineru), pārejiet uz Dependency Injection Container lapu.

Pamata lietošana

Ietvara metožu pārrakstīšana

Flight ļauj jums pārrakstīt tā noklusējuma funkcionalitāti, lai tā atbilstu jūsu vajadzībām, bez nepieciešamības modificēt jebkuru kodu. Jūs varat apskatīt visas metodes, kuras varat pārrakstīt zemāk.

Piemēram, kad Flight nevar saskaņot URL ar maršrutu, tas izsauc notFound metodi, kas nosūta vispārīgu HTTP 404 atbildi. Jūs varat pārrakstīt šo uzvedību, izmantojot map metodi:

Flight::map('notFound', function() {
  // Rādīt pielāgotu 404 lapu
  include 'errors/404.html';
});

Flight arī ļauj jums aizstāt ietvara kodola komponentus. Piemēram, jūs varat aizstāt noklusējuma Router klasi ar savu pielāgotu klasi:

// izveidot savu pielāgoto Router klasi
class MyRouter extends \flight\net\Router {
    // pārrakstīt metodes šeit
    // piemēram, saīsinājums GET pieprasījumiem, lai noņemtu
    // pass route funkciju
    public function get($pattern, $callback, $alias = '') {
        return parent::get($pattern, $callback, false, $alias);
    }
}

// Reģistrēt savu pielāgoto klasi
Flight::register('router', MyRouter::class);

// Kad Flight ielādē Router экземпlāru, tas ielādēs jūsu klasi
$myRouter = Flight::router();
$myRouter->get('/hello', function() {
  echo "Hello World!";
}, 'hello_alias');

Tomēr ietvara metodes, piemēram map un register, nevar tikt pārrakstītas. Jūs saņemsiet kļūdu, ja mēģināsiet to izdarīt (atkal skatiet zemāk metožu sarakstam).

Kartējamās ietvara metodes

Turpmāk ir pilnīga metožu kopa ietvaram. Tā sastāv no kodola metodēm, kuras ir regulāras statiskas metodes, un paplašināmām metodēm, kuras ir kartētas metodes, kuras var filtrēt vai pārrakstīt.

Kodola metodes

Šīs metodes ir kodola ietvaram un nevar tikt pārrakstītas.

Flight::map(string $name, callable $callback, bool $pass_route = false) // Izveido pielāgotu ietvara metodi.
Flight::register(string $name, string $class, array $params = [], ?callable $callback = null) // Reģistrē klasi ietvara metodē.
Flight::unregister(string $name) // Izslēdz klasi no ietvara metodes.
Flight::before(string $name, callable $callback) // Pievieno filtru pirms ietvara metodes.
Flight::after(string $name, callable $callback) // Pievieno filtru pēc ietvara metodes.
Flight::path(string $path) // Pievieno ceļu automātiskai klases ielādei.
Flight::get(string $key) // Iegūst mainīgo, ko iestatījis Flight::set().
Flight::set(string $key, mixed $value) // Iestata mainīgo Flight dzinējā.
Flight::has(string $key) // Pārbauda, vai mainīgais ir iestatīts.
Flight::clear(array|string $key = []) // Notīra mainīgo.
Flight::init() // Inicializē ietvaru ar tā noklusējuma iestatījumiem.
Flight::app() // Iegūst lietojumprogrammas objekta экземпlāru
Flight::request() // Iegūst pieprasījuma objekta экземпlāru
Flight::response() // Iegūst atbildes objekta экземпlāru
Flight::router() // Iegūst maršrutētāja objekta экземпlāru
Flight::view() // Iegūst skata objekta экземпlāru

Paplašināmas metodes

Flight::start() // Sāk ietvaru.
Flight::stop() // Aptur ietvaru un nosūta atbildi.
Flight::halt(int $code = 200, string $message = '') // Aptur ietvaru ar opcionālu statusa kodu un ziņu.
Flight::route(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') // Kartē URL paraugu ar atsaukumu.
Flight::post(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') // Kartē POST pieprasījuma URL paraugu ar atsaukumu.
Flight::put(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') // Kartē PUT pieprasījuma URL paraugu ar atsaukumu.
Flight::patch(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') // Kartē PATCH pieprasījuma URL paraugu ar atsaukumu.
Flight::delete(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') // Kartē DELETE pieprasījuma URL paraugu ar atsaukumu.
Flight::group(string $pattern, callable $callback) // Izveido grupēšanu URL, paraugam jābūt virknei.
Flight::getUrl(string $name, array $params = []) // Ģenerē URL, balstoties uz maršruta aliasu.
Flight::redirect(string $url, int $code) // Pāradresē uz citu URL.
Flight::download(string $filePath) // Lejupielādē failu.
Flight::render(string $file, array $data, ?string $key = null) // Renderē veidnes failu.
Flight::error(Throwable $error) // Nosūta HTTP 500 atbildi.
Flight::notFound() // Nosūta HTTP 404 atbildi.
Flight::etag(string $id, string $type = 'string') // Veic ETag HTTP kešošanu.
Flight::lastModified(int $time) // Veic pēdējās modificēšanas HTTP kešošanu.
Flight::json(mixed $data, int $code = 200, bool $encode = true, string $charset = 'utf8', int $option) // Nosūta JSON atbildi.
Flight::jsonp(mixed $data, string $param = 'jsonp', int $code = 200, bool $encode = true, string $charset = 'utf8', int $option) // Nosūta JSONP atbildi.
Flight::jsonHalt(mixed $data, int $code = 200, bool $encode = true, string $charset = 'utf8', int $option) // Nosūta JSON atbildi un aptur ietvaru.
Flight::onEvent(string $event, callable $callback) // Reģistrē notikuma klausītāju.
Flight::triggerEvent(string $event, ...$args) // Izsauc notikumu.

Jebkuras pielāgotas metodes, kas pievienotas ar map un register, var arī tikt filtrētas. Piemēriem, kā filtrēt šīs metodes, skatiet Filtering Methods rokasgrāmatu.

Paplašināmas ietvara klases

Ir vairākas klases, kurām jūs varat pārrakstīt funkcionalitāti, paplašinot tās un reģistrējot savu klasi. Šīs klases ir:

Flight::app() // Lietojumprogrammas klase - paplašiniet flight\Engine klasi
Flight::request() // Pieprasījuma klase - paplašiniet flight\net\Request klasi
Flight::response() // Atbildes klase - paplašiniet flight\net\Response klasi
Flight::router() // Maršrutētāja klase - paplašiniet flight\net\Router klasi
Flight::view() // Skata klase - paplašiniet flight\template\View klasi
Flight::eventDispatcher() // Notikuma dispečera klase - paplašiniet flight\core\Dispatcher klasi

Pielāgoto metožu kartēšana

Lai kartētu savu vienkāršo pielāgoto metodi, jūs izmantojat map funkciju:

// Kartēt savu metodi
Flight::map('hello', function (string $name) {
  echo "hello $name!";
});

// Izsaukt savu pielāgoto metodi
Flight::hello('Bob');

Lai gan ir iespējams izveidot vienkāršas pielāgotas metodes, ieteicams tikai izveidot standarta funkcijas PHP. Tam ir autocomplēte IDE un tas ir vieglāk lasāms. Iepriekš minētā koda ekvivalents būtu:

function hello(string $name) {
  echo "hello $name!";
}

hello('Bob');

Tas tiek izmantots vairāk, kad jums jānodod mainīgie jūsu metodē, lai iegūtu gaidīto vērtību. Izmantojot register() metodi kā zemāk, tas ir vairāk par konfigurācijas nodošanu un tad izsaukt savu iepriekš konfigurēto klasi.

Pielāto klases reģistrēšana

Lai reģistrētu savu klasi un konfigurētu to, jūs izmantojat register funkciju. Iepriekšējs ieguvums, ko tas sniedz pār map(), ir tas, ka jūs varat atkārtoti izmantot to pašu klasi, kad izsaucat šo funkciju (tas būtu noderīgi ar Flight::db(), lai dalītos tajā pašā экземпlārā).

// Reģistrēt savu klasi
Flight::register('user', User::class);

// Iegūt klases экземпlāru
$user = Flight::user();

Reģistrēšanas metode arī ļauj jums nodot parametrus jūsu klases konstruktoram. Tātad, kad jūs ielādējat savu pielāgoto klasi, tā nāks jau inicializēta. Jūs varat definēt konstruktora parametrus, nododot papildu masīvu. Šeit ir piemērs datubāzes savienojuma ielādei:

// Reģistrēt klasi ar konstruktora parametriem
Flight::register('db', PDO::class, ['mysql:host=localhost;dbname=test', 'user', 'pass']);

// Iegūt klases экземпlāru
// Tas izveidos objektu ar definētajiem parametriem
//
// new PDO('mysql:host=localhost;dbname=test','user','pass');
//
$db = Flight::db();

// un ja jums tas būtu vajadzīgs vēlāk savā kodā, jūs tikai izsaucat to pašu metodi vēlreiz
class SomeController {
  public function __construct() {
    $this->db = Flight::db();
  }
}

Ja jūs nododit papildu atsauces parametru, tas tiks izpildīts uzreiz pēc klases konstrukcijas. Tas ļauj jums veikt jebkuru iestatīšanas procedūru jūsu jaunajam objektam. Atsauces funkcija ņem vienu parametru, jauna objekta экземпlāru.

// Atsauce tiks nodota konstrukcijas objekts
Flight::register(
  'db',
  PDO::class,
  ['mysql:host=localhost;dbname=test', 'user', 'pass'],
  function (PDO $db) {
    $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  }
);

Pēc noklusējuma katru reizi, kad jūs ielādējat savu klasi, jūs iegūsit kopīgu экземпlāru. Lai iegūtu jaunu klases экземпlāru, vienkārši nododit false kā parametru:

// Kopīgs klases экземпlārs
$shared = Flight::db();

// Jauns klases экземпlārs
$new = Flight::db(false);

Piezīme: Ņemiet vērā, ka kartētās metodes ir priekšroka pār reģistrētajām klasēm. Ja jūs deklarējat abas, izmantojot to pašu nosaukumu, tikai kartētā metode tiks izsaukta.

Piemēri

Šeit ir daži piemēri, kā jūs varat paplašināt Flight ar funkcionalitāti, kas nav iebūvēta kodolā.

Žurnālveide

Flight nav iebūvēta žurnālveides sistēma, tomēr ir patiešām viegli izmantot žurnālveides bibliotēku ar Flight. Šeit ir piemērs, izmantojot Monolog bibliotēku:

// services.php

// Reģistrēt žurnālu ar Flight
Flight::register('log', Monolog\Logger::class, [ 'name' ], function(Monolog\Logger $log) {
    $log->pushHandler(new Monolog\Handler\StreamHandler('path/to/your.log', Monolog\Logger::WARNING));
});

Tagad, kad tas ir reģistrēts, jūs varat to izmantot savā lietojumprogrammā:

// Jūsu kontrolierī vai maršrutā
Flight::log()->warning('This is a warning message');

Tas ierakstīs ziņu norādītajā žurnāla failā. Ko tad, ja jūs vēlaties ierakstīt kaut ko, kad rodas kļūda? Jūs varat izmantot error metodi:

// Jūsu kontrolierī vai maršrutā
Flight::map('error', function(Throwable $ex) {
    Flight::log()->error($ex->getMessage());
    // Rādīt savu pielāgoto kļūdas lapu
    include 'errors/500.html';
});

Jūs arī varētu izveidot pamata APM (Lietojumprogrammas veiktspējas uzraudzību) sistēmu, izmantojot before un after metodes:

// Jūsu services.php failā

Flight::before('start', function() {
    Flight::set('start_time', microtime(true));
});

Flight::after('start', function() {
    $end = microtime(true);
    $start = Flight::get('start_time');
    Flight::log()->info('Request '.Flight::request()->url.' took ' . round($end - $start, 4) . ' seconds');

    // Jūs varētu arī pievienot savu pieprasījumu vai atbildes galvenes
    // lai ierakstītu tās (esiet uzmanīgs, jo tas būtu daudz datu, ja jums ir daudz pieprasījumu)
    Flight::log()->info('Request Headers: ' . json_encode(Flight::request()->headers));
    Flight::log()->info('Response Headers: ' . json_encode(Flight::response()->headers));
});

Kešošana

Flight nav iebūvēta kešošanas sistēma, tomēr ir patiešām viegli izmantot kešošanas bibliotēku ar Flight. Šeit ir piemērs, izmantojot PHP File Cache bibliotēku:

// services.php

// Reģistrēt kešu ar Flight
Flight::register('cache', \flight\Cache::class, [ __DIR__ . '/../cache/' ], function(\flight\Cache $cache) {
    $cache->setDevMode(ENVIRONMENT === 'development');
});

Tagad, kad tas ir reģistrēts, jūs varat to izmantot savā lietojumprogrammā:

// Jūsu kontrolierī vai maršrutā
$data = Flight::cache()->get('my_cache_key');
if (empty($data)) {
    // Veikt kādu apstrādi, lai iegūtu datus
    $data = [ 'some' => 'data' ];
    Flight::cache()->set('my_cache_key', $data, 3600); // kešot uz 1 stundu
}

Viegla DIC objekta instantiācija

Ja jūs izmantojat DIC (Atkarību injekcijas konteineru) savā lietojumprogrammā, jūs varat izmantot Flight, lai palīdzētu jums instantiēt savus objektus. Šeit ir piemērs, izmantojot Dice bibliotēku:

// services.php

// izveidot jaunu konteineru
$container = new \Dice\Dice;
// neaizmirstiet to atkārtoti piešķirt sev pašam kā zemāk!
$container = $container->addRule('PDO', [
    // shared nozīmē, ka tas pats objekts tiks atgriezts katru reizi
    'shared' => true,
    'constructParams' => ['mysql:host=localhost;dbname=test', 'user', 'pass' ]
]);

// tagad mēs varam izveidot kartējamu metodi, lai izveidotu jebkuru objektu. 
Flight::map('make', function($class, $params = []) use ($container) {
    return $container->create($class, $params);
});

// Tas reģistrē konteinera apstrādātāju, lai Flight zinātu to izmantot kontrolieriem/vidējai slānim
Flight::registerContainerHandler(function($class, $params) {
    Flight::make($class, $params);
});

// pieņemsim, ka mums ir šāda parauga klase, kas ņem PDO objektu konstruktorā
class EmailCron {
    protected PDO $pdo;

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

    public function send() {
        // kods, kas nosūta e-pastu
    }
}

// Un beidzot jūs varat izveidot objektus, izmantojot atkarību injekciju
$emailCron = Flight::make(EmailCron::class);
$emailCron->send();

Eleganti, vai ne?

Skatīt arī

Traucējummeklēšana

Izmaiņu žurnāls

Learn/json

JSON Apvalks

Pārskats

Json klase Flight nodrošina vienkāršu, konsekventu veidu, kā kodēt un dekodēt JSON datus jūsu lietojumprogrammā. Tā apvalko PHP iebūvēto JSON funkciju ar labāku kļūdu apstrādi un dažām noderīgām noklusējuma vērtībām, padarot to vieglāku un drošāku strādāt ar JSON.

Saprašana

Darbs ar JSON ir ārkārtīgi izplatīts mūsdienu PHP lietojumprogrammās, īpaši, kad veidojat API vai apstrādājat AJAX pieprasījumus. Json klase centralizē visu jūsu JSON kodēšanu un dekodēšanu, tāpēc jums nav jāuztraucas par dīvainiem malu gadījumiem vai nesaprotamām kļūdām no PHP iebūvētajām funkcijām.

Galvenās funkcijas:

Pamata Izmantošana

Datu Kodēšana uz JSON

Lai pārveidotu PHP datus uz JSON virkni, izmantojiet Json::encode():

use flight\util\Json;

$data = [
  'framework' => 'Flight',
  'version' => 3,
  'features' => ['routing', 'views', 'extending']
];

$json = Json::encode($data);
echo $json;
// Output: {"framework":"Flight","version":3,"features":["routing","views","extending"]}

Ja kodēšana neizdodas, jūs saņemsiet izņēmumu ar noderīgu kļūdas ziņu.

Skaista Izdruka

Vai vēlaties, lai jūsu JSON būtu lasāms cilvēkiem? Izmantojiet prettyPrint():

echo Json::prettyPrint($data);
/*
{
  "framework": "Flight",
  "version": 3,
  "features": [
    "routing",
    "views",
    "extending"
  ]
}
*/

JSON Virkņu Dekodēšana

Lai pārveidotu JSON virkni atpakaļ uz PHP datiem, izmantojiet Json::decode():

$json = '{"framework":"Flight","version":3}';
$data = Json::decode($json);
echo $data->framework; // Output: Flight

Ja vēlaties asociatīvu masīvu nevis objektu, nododiet true kā otro argumentu:

$data = Json::decode($json, true);
echo $data['framework']; // Output: Flight

Ja dekodēšana neizdodas, jūs saņemsiet izņēmumu ar skaidru kļūdas ziņu.

JSON Validācija

Pārbaudiet, vai virkne ir derīgs JSON:

if (Json::isValid($json)) {
  // Tas ir derīgs!
} else {
  // Nav derīgs JSON
}

Pēdējās Kļūdas Iegūšana

Ja vēlaties pārbaudīt pēdējo JSON kļūdas ziņu (no iebūvētām PHP funkcijām):

$error = Json::getLastError();
if ($error !== '') {
  echo "Last JSON error: $error";
}

Uzlabota Izmantošana

Jūs varat pielāgot kodēšanas un dekodēšanas opcijas, ja vajag vairāk kontroles (skatiet PHP json_encode opcijas):

// Kodēšana ar HEX_TAG opciju
$json = Json::encode($data, JSON_HEX_TAG);

// Dekodēšana ar pielāgotu dziļumu
$data = Json::decode($json, false, 1024);

Skatīt Arī

Traucējummeklēšana

Izmaiņu Žurnāls

Learn/flight_vs_slim

Flight pret Slim

Kas ir Slim?

Slim ir PHP mikro ietvars, kas palīdz jums ātri rakstīt vienkāršas, bet spēcīgas tīmekļa lietojumprogrammas un API.

Liela daļa iedvesmas dažām no Flight 3. versijas funkcijām faktiski nāca no Slim. Maršrutu grupēšana un starpprogrammatūras izpilde noteiktā secībā ir divas funkcijas, kas tika iedvesmotas no Slim. Slim 3. versija iznāca ar mērķi uz vienkāršību, bet attiecībā uz 4. versiju ir bijušas pretrunīgas atsauksmes.

Priekšrocības salīdzinājumā ar Flight

Trūkumi salīdzinājumā ar Flight

Learn/autoloading

Autoloading

Pārskats

Autoloading ir PHP koncepts, kurā jūs norādāt direktoriju vai direktorijus, no kuriem ielādēt klases. Tas ir daudz izdevīgāk nekā izmantot require vai include klašu ielādei. Tas ir arī prasība Composer pakotņu izmantošanai.

Saprašana

Pēc noklusējuma jebkura Flight klase tiek automātiski autoloadēta jums, pateicoties composer. Tomēr, ja vēlaties autoloadēt savas klases, jūs varat izmantot Flight::path() metodi, lai norādītu direktoriju, no kura ielādēt klases.

Autoloadera izmantošana var palīdzēt ievērojami vienkāršot jūsu kodu. Tā vietā, lai faili sāktos ar daudziem include vai require paziņojumiem augšpusē, lai uztvertu visas tajā failā izmantotās klases, jūs varat dinamiski izsaukt savas klases, un tās tiks iekļautas automātiski.

Pamatlietojums

Pieņemsim, ka mums ir direktoriju koks šāds:

# Piemēra ceļš
/home/user/project/my-flight-project/
├── app
│   ├── cache
│   ├── config
│   ├── controllers - satur šī projekta kontrolierus
│   ├── translations
│   ├── UTILS - satur klases tikai šai lietojumprogrammai (tas ir visi lielie burti mērķtiecīgi piemēram vēlāk)
│   └── views
└── public
    └── css
    └── js
    └── index.php

Jūs varbūt pamanījāt, ka tas ir tāds pats failu struktūra kā šī dokumentācijas vietnei.

Jūs varat norādīt katru direktoriju, no kura ielādēt, šādi:


/**
 * public/index.php
 */

// Pievienojiet ceļu autoloaderim
Flight::path(__DIR__.'/../app/controllers/');
Flight::path(__DIR__.'/../app/utils/');

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

// nav nepieciešama vārdu telpa

// Visām autoloadētajām klasēm ieteicams būt Pascal Case (katrs vārds ar lielu burtu, bez atstarpēm)
class MyController {

    public function index() {
        // dariet kaut ko
    }
}

Vārdu telpas

Ja jums ir vārdu telpas, tas faktiski kļūst ļoti viegli ieviest. Jums vajadzētu izmantot Flight::path() metodi, lai norādītu jūsu lietojumprogrammas saknes direktoriju (nevis dokumenta sakni vai public/ mapi).


/**
 * public/index.php
 */

// Pievienojiet ceļu autoloaderim
Flight::path(__DIR__.'/../');

Tagad tas ir jūsu kontrolieris izskatītos. Skatiet piemēru zemāk, bet pievērsiet uzmanību komentāriem svarīgai informācijai.

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

// vārdu telpas ir nepieciešamas
// vārdu telpas ir tādas pašas kā direktoriju struktūra
// vārdu telpām jāatbilst tāpat kā direktoriju struktūrai
// vārdu telpām un direktorijiem nevar būt apakšsvītras (ja vien nav iestatīts Loader::setV2ClassLoading(false))
namespace app\controllers;

// Visām autoloadētajām klasēm ieteicams būt Pascal Case (katrs vārds ar lielu burtu, bez atstarpēm)
// No 3.7.2 versijas, jūs varat izmantot Pascal_Snake_Case savām klases nosaukumiem, palaižot Loader::setV2ClassLoading(false);
class MyController {

    public function index() {
        // dariet kaut ko
    }
}

Un ja jūs vēlaties autoloadēt klasi jūsu utils direktorijā, jūs darītu gandrīz to pašu:


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

// vārdu telpai jāatbilst direktoriju struktūrai un reģistram (pamaniet, ka UTILS direktorija ir visi lielie burti
//     kā failu kokā augstāk)
namespace app\UTILS;

class ArrayHelperUtil {

    public function changeArrayCase(array $array) {
        // dariet kaut ko
    }
}

Apakšsvītras klases nosaukumos

No 3.7.2 versijas, jūs varat izmantot Pascal_Snake_Case savām klases nosaukumiem, palaižot Loader::setV2ClassLoading(false);. Tas ļaus izmantot apakšsvītras jūsu klases nosaukumos. Tas nav ieteicams, bet tas ir pieejams tiem, kam tas ir nepieciešams.

use flight\core\Loader;

/**
 * public/index.php
 */

// Pievienojiet ceļu autoloaderim
Flight::path(__DIR__.'/../app/controllers/');
Flight::path(__DIR__.'/../app/utils/');
Loader::setV2ClassLoading(false);

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

// nav nepieciešama vārdu telpa

class My_Controller {

    public function index() {
        // dariet kaut ko
    }
}

Skatīt arī

Traucējummeklēšana

Klase netika atrasta (autoloading nedarbojas)

Šim var būt pāris iemesli. Zemāk ir daži piemēri, bet pārliecinieties, ka jūs arī apskatāt autoloading sadaļu.

Nepareizs faila nosaukums

Visbiežākais ir tas, ka klases nosaukums neatbilst faila nosaukumam.

Ja jums ir klase ar nosaukumu MyClass, tad failam jābūt nosauktam MyClass.php. Ja jums ir klase ar nosaukumu MyClass un fails ir nosaukts myclass.php tad autoloader nevarēs to atrast.

Nepareiza vārdu telpa

Ja jūs izmantojat vārdu telpas, tad vārdu telpai jāatbilst direktoriju struktūrai.

// ...kods...

// ja jūsu MyController ir app/controllers direktorijā un tas ir ar vārdu telpu
// tas nedarbosies.
Flight::route('/hello', 'MyController->hello');

// jums jāizvēlas viena no šīm opcijām
Flight::route('/hello', 'app\controllers\MyController->hello');
// vai ja jums ir use paziņojums augšpusē

use app\controllers\MyController;

Flight::route('/hello', [ MyController::class, 'hello' ]);
// var arī rakstīt
Flight::route('/hello', MyController::class.'->hello');
// arī...
Flight::route('/hello', [ 'app\controllers\MyController', 'hello' ]);

path() nav definēts

Skeletā lietojumprogrammā tas ir definēts config.php failā, bet lai jūsu klases tiktu atrastas, jums jāpārliecinās, ka path() metode ir definēta (droši vien uz jūsu direktorijas sakni) pirms mēģināt to izmantot.

// Pievienojiet ceļu autoloaderim
Flight::path(__DIR__.'/../');

Izmaiņu žurnāls

Learn/uploaded_file

Augšupielādētā faila apstrādātājs

Pārskats

UploadedFile klase Flight padara vieglu un drošu failu augšupielādes apstrādi jūsu lietojumprogrammā. Tā aptver PHP failu augšupielādes procesa detaļas, piedāvājot vienkāršu, objektorientētu veidu, kā piekļūt faila informācijai un pārvietot augšupielādētos failus.

Saprašana

Kad lietotājs augšupielādē failu caur formu, PHP saglabā informāciju par failu $_FILES superglobālajā mainīgajā. Flight vidē jūs reti mijiedarbojaties ar $_FILES tieši. Tā vietā Flight Request objekts (pieejams caur Flight::request()) nodrošina getUploadedFiles() metodi, kas atgriež UploadedFile objektu masīvu, padarot failu apstrādi daudz ērtāku un izturīgāku.

UploadedFile klase nodrošina metodes, lai:

Šī klase palīdz izvairīties no izplatītām kļūdām ar failu augšupielādi, piemēram, kļūdu apstrādes vai drošas failu pārvietošanas.

Pamata izmantošana

Piekļuve augšupielādētajiem failiem no pieprasījuma

Ieteicamais veids, kā piekļūt augšupielādētajiem failiem, ir caur pieprasījuma objektu:

Flight::route('POST /upload', function() {
    // Par formu lauku ar nosaukumu <input type="file" name="myFile">
    $uploadedFiles = Flight::request()->getUploadedFiles();
    $file = $uploadedFiles['myFile'];

    // Tagad jūs varat izmantot UploadedFile metodes
    if ($file->getError() === UPLOAD_ERR_OK) {
        $file->moveTo('/path/to/uploads/' . $file->getClientFilename());
        echo "Fails augšupielādēts veiksmīgi!";
    } else {
        echo "Augšupielāde neizdevās: " . $file->getError();
    }
});

Daudzu failu augšupielādes apstrāde

Ja jūsu forma izmanto name="myFiles[]" vairāku augšupielāžu gadījumā, jūs saņemsiet UploadedFile objektu masīvu:

Flight::route('POST /upload', function() {
    // Par formu lauku ar nosaukumu <input type="file" name="myFiles[]">
    $uploadedFiles = Flight::request()->getUploadedFiles();
    foreach ($uploadedFiles['myFiles'] as $file) {
        if ($file->getError() === UPLOAD_ERR_OK) {
            $file->moveTo('/path/to/uploads/' . $file->getClientFilename());
            echo "Augšupielādēts: " . $file->getClientFilename() . "<br>";
        } else {
            echo "Neizdevās augšupielādēt: " . $file->getClientFilename() . "<br>";
        }
    }
});

UploadedFile instances manuāla izveide

Parasti jūs neizveidosiet UploadedFile manuāli, bet to var izdarīt, ja nepieciešams:

use flight\net\UploadedFile;

$file = new UploadedFile(
  $_FILES['myfile']['name'],
  $_FILES['myfile']['type'],
  $_FILES['myfile']['size'],
  $_FILES['myfile']['tmp_name'],
  $_FILES['myfile']['error']
);

Piekļuve faila informācijai

Jūs viegli varat iegūt detaļas par augšupielādēto failu:

echo $file->getClientFilename();   // Oriģinālais faila nosaukums no lietotāja datora
echo $file->getClientMediaType();  // MIME tips (piem., image/png)
echo $file->getSize();             // Faila izmērs baitos
echo $file->getTempName();         // Pagaidu faila ceļš uz servera
echo $file->getError();            // Augšupielādes kļūdas kods (0 nozīmē bez kļūdas)

Augšupielādētā faila pārvietošana

Pēc faila validēšanas pārvietojiet to uz pastāvīgu atrašanās vietu:

try {
  $file->moveTo('/path/to/uploads/' . $file->getClientFilename());
  echo "Fails augšupielādēts veiksmīgi!";
} catch (Exception $e) {
  echo "Augšupielāde neizdevās: " . $e->getMessage();
}

moveTo() metode izmet izņēmumu, ja kaut kas noiet greizi (piemēram, augšupielādes kļūda vai atļauju problēma).

Augšupielādes kļūdu apstrāde

Ja augšupielādes laikā radās problēma, jūs varat iegūt lasāmu kļūdas ziņojumu cilvēkam:

if ($file->getError() !== UPLOAD_ERR_OK) {
  // Jūs varat izmantot kļūdas kodu vai noķert izņēmumu no moveTo()
  echo "Radās kļūda, augšupielādējot failu.";
}

Skatīt arī

Traucējummeklēšana

Izmaiņu žurnāls

Guides/unit_testing

Vienības testēšana Flight PHP ar PHPUnit

Šis ceļvedis iepazīstina ar vienības testēšanu Flight PHP, izmantojot PHPUnit, kas paredzēts iesācējiem, kuri vēlas saprast, kāpēc vienības testēšana ir svarīga un kā to praktiski pielietot. Mēs koncentrēsimies uz testēšanu uzvedības — nodrošinot, ka jūsu lietojumprogramma darbojas tā, kā jūs sagaidāt, piemēram, nosūtot e-pastu vai saglabājot ierakstu — nevis uz sīkumainiem aprēķiniem. Mēs sāksim ar vienkāršu maršruta apstrādātāju un pakāpeniski pāriesim pie sarežģītāka kontrolera, iekļaujot atkarību injekciju (DI) un trešo pušu servisu mockēšanu.

Kāpēc veikt vienības testus?

Vienības testēšana nodrošina, ka jūsu kods uzvedas kā paredzēts, uztverot kļūdas, pirms tās nonāk ražošanā. Tas ir īpaši vērtīgi Flight, kur vieglā maršrutēšana un elastība var radīt sarežģītas mijiedarbības. Vienības testi darbojas kā drošības tīkls solo izstrādātājiem vai komandām, dokumentējot paredzēto uzvedību un novēršot regresijas, kad jūs vēlāk atgriežaties pie koda. Tie arī uzlabo dizainu: kodu, kas ir grūti testēt, bieži norāda uz pārmērīgi sarežģītām vai cieši saistītām klasēm.

Atšķirībā no vienkāršiem piemēriem (piemēram, testēšana x * y = z), mēs koncentrēsimies uz reālās pasaules uzvedībām, piemēram, ievades validēšanu, datu saglabāšanu vai darbību izraisīšanu, piemēram, e-pastus. Mūsu mērķis ir padarīt testēšanu pieejamu un jēgpilnu.

Vispārīgi vadības principi

  1. Testējiet uzvedību, nevis realizāciju: Koncentrējieties uz rezultātiem (piemēram, "e-pasts nosūtīts" vai "ieraksts saglabāts"), nevis uz iekšējām detaļām. Tas padara testus izturīgus pret refaktoringu.
  2. Pārtrauciet izmantot Flight::: Flight statiskās metodes ir ārkārtīgi ērtas, bet apgrūtina testēšanu. Jums vajadzētu pierast izmantot $app mainīgo no $app = Flight::app();. $app satur visas tās pašas metodes, kas Flight::. Jūs joprojām varēsiet izmantot $app->route() vai $this->app->json() savā kontrolerī utt. Jums arī vajadzētu izmantot īsto Flight maršrutētāju ar $router = $app->router() un tad varēsiet izmantot $router->get(), $router->post(), $router->group() utt. Skatiet Routing.
  3. Uzturiet testus ātrus: Ātri testi veicina biežu izpildi. Izvairieties no lēnām operācijām, piemēram, datubāzes izsaukumiem vienības testos. Ja jums ir lēns tests, tas ir zīme, ka jūs rakstāt integrācijas testu, nevis vienības testu. Integrācijas testi ir tad, kad jūs patiešām iesaistāt reālas datubāzes, reālus HTTP izsaukumus, reālu e-pasta sūtīšanu utt. Tiem ir sava vieta, bet tie ir lēni un var būt nestabili, kas nozīmē, ka tie dažreiz neizdodas nezināma iemesla dēļ.
  4. Izmantojiet aprakstošus nosaukumus: Testu nosaukumiem jāapraksta skaidri testētā uzvedība. Tas uzlabo lasāmību un uzturējamību.
  5. Izvairieties no globāliem mainīgajiem kā no mēra: Minimāli izmantojiet $app->set() un $app->get(), jo tie darbojas kā globālais stāvoklis, prasot mockus katrā testā. Dodiet priekšroku DI vai DI konteineram (skatiet Dependency Injection Container). Pat izmantojot $app->map() metodi, tehniski ir "globāls" un jāizvairās no tā par labu DI. Izmantojiet sesijas bibliotēku, piemēram, flightphp/session, lai varētu mockēt sesijas objektu savos testos. Neizsauciet $_SESSION tieši savā kodā, jo tas ievada globālo mainīgo jūsu kodā, apgrūtinot testēšanu.
  6. Izmantojiet atkarību injekciju: Injektējiet atkarības (piemēram, PDO, pasta sūtītājus) kontroleros, lai izolētu loģiku un atvieglotu mockēšanu. Ja jums ir klase ar pārāk daudzām atkarībām, apsvēriet tās refaktoringu mazākās klasēs, kurām katrai ir viena atbildība, ievērojot SOLID principus.
  7. Mockējiet trešo pušu servisus: Mockējiet datubāzes, HTTP klientus (cURL) vai e-pasta servisus, lai izvairītos no ārējiem izsaukumiem. Testējiet vienu vai divus slāņus dziļi, bet ļaujiet jūsu kodola loģikai darboties. Piemēram, ja jūsu lietojumprogramma nosūta īsziņu, jūs NEGRIBAT patiešām sūtīt īsziņu katru reizi, kad palaižat testus, jo šie maksājumi sakopsies (un tas būs lēnāks). Tā vietā mockējiet īsziņas servisu un tikai pārbaudiet, ka jūsu kods izsauca īsziņas servisu ar pareizajiem parametriem.
  8. Mērķis uz augstu pārklājumu, nevis pilnību: 100% rindu pārklājums ir labs, bet tas nenozīmē, ka viss jūsu kodā ir testēts tā, kā vajadzētu (droši vien pētiet zaru/ceļa pārklājumu PHPUnit). Prioritizējiet kritiskās uzvedības (piemēram, lietotāja reģistrāciju, API atbildes un neizdevušos atbilžu uztveršanu).
  9. Izmantojiet kontrolerus maršrutiem: Savos maršruta definīcijās izmantojiet kontrolerus, nevis aizvēršanas. flight\Engine $app pēc noklusējuma tiek injicēts katrā kontrolerā caur konstruktoru. Testos izmantojiet $app = new Flight\Engine(), lai inicializētu Flight testā, injicējiet to kontrolerī un izsauciet metodes tieši (piemēram, $controller->register()). Skatiet Extending Flight un Routing.
  10. Izvēlieties mockēšanas stilu un turieties pie tā: PHPUnit atbalsta vairākus mockēšanas stilus (piemēram, prophecy, iebūvēti mocki), vai varat izmantot anonīmas klases, kurām ir savas priekšrocības, piemēram, koda pabeigšana, salūšana, ja maināt metodes definīciju utt. Tikai esiet konsekventi visos savos testos. Skatiet PHPUnit Mock Objects.
  11. Izmantojiet protected redzamību metodēm/īpašībām, kuras vēlaties testēt apakšklasēs: Tas ļauj jums tās pārrakstīt testu apakšklasēs, nepadarot tās publiskām, tas ir īpaši noderīgi anonīmu klašu mockiem.

PHPUnit iestatīšana

Vispirms iestatiet PHPUnit savā Flight PHP projektā, izmantojot Composer vieglai testēšanai. Skatiet PHPUnit Sākuma ceļvedi sīkākiem detalizācijām.

  1. Savā projektu direktorijā palaidiet:

    composer require --dev phpunit/phpunit

    Tas instalē jaunāko PHPUnit kā izstrādes atkarību.

  2. Izveidojiet tests direktoriju jūsu projekta saknē testu failiem.

  3. Pievienojiet testa skriptu composer.json ērtībai:

    // cits composer.json saturs
    "scripts": {
       "test": "phpunit --configuration phpunit.xml"
    }
  4. Izveidojiet phpunit.xml failu saknē:

    <?xml version="1.0" encoding="UTF-8"?>
    <phpunit bootstrap="vendor/autoload.php">
       <testsuites>
           <testsuite name="Flight Tests">
               <directory>tests</directory>
           </testsuite>
       </testsuites>
    </phpunit>

Tagad, kad jūsu testi ir izveidoti, varat palaidiet composer test, lai izpildītu testus.

Vienkārša maršruta apstrādātāja testēšana

Sāksim ar pamata maršrutu, kas validē lietotāja e-pasta ievadi. Mēs testēsim tā uzvedību: atgriežot veiksmīgu ziņu derīgiem e-pastiem un kļūdu nederīgiem. E-pasta validēšanai mēs izmantojam filter_var.

// index.php
$app->route('POST /register', [ UserController::class, 'register' ]);

// UserController.php
class UserController {
    protected $app;

    public function __construct(flight\Engine $app) {
        $this->app = $app;
    }

    public function register() {
        $email = $this->app->request()->data->email;
        $responseArray = [];
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            $responseArray = ['status' => 'error', 'message' => 'Invalid email'];
        } else {
            $responseArray = ['status' => 'success', 'message' => 'Valid email'];
        }

        $this->app->json($responseArray);
    }
}

Lai to testētu, izveidojiet testa failu. Skatiet Unit Testing and SOLID Principles par vairāk informācijas par testu struktūru:

// tests/UserControllerTest.php
use PHPUnit\Framework\TestCase;
use Flight;
use flight\Engine;

class UserControllerTest extends TestCase {

    public function testValidEmailReturnsSuccess() {
        $app = new Engine();
        $request = $app->request();
        $request->data->email = 'test@example.com'; // Simulate POST data
        $UserController = new UserController($app);
        $UserController->register($request->data->email);
        $response = $app->response()->getBody();
        $output = json_decode($response, true);
        $this->assertEquals('success', $output['status']);
        $this->assertEquals('Valid email', $output['message']);
    }

    public function testInvalidEmailReturnsError() {
        $app = new Engine();
        $request = $app->request();
        $request->data->email = 'invalid-email'; // Simulate POST data
        $UserController = new UserController($app);
        $UserController->register($request->data->email);
        $response = $app->response()->getBody();
        $output = json_decode($response, true);
        $this->assertEquals('error', $output['status']);
        $this->assertEquals('Invalid email', $output['message']);
    }
}

Galvenie punkti:

Palaidiet composer test, lai pārbaudītu, vai maršruts uzvedas kā paredzēts. Par vairāk informācijas par pieprasījumiem un atbildēm Flight, skatiet attiecīgos dokumentus.

Atkarību injekcijas izmantošana testējamu kontroleru izveidošanai

Sarežģītākiem scenārijiem izmantojiet atkarību injekciju (DI), lai padarītu kontrolerus testējamus. Izvairieties no Flight globāliem (piemēram, Flight::set(), Flight::map(), Flight::register()), jo tie darbojas kā globālais stāvoklis, prasot mockus katram testam. Tā vietā izmantojiet Flight DI konteineru, DICE, PHP-DI vai manuālu DI.

Izmantojiet flight\database\PdoWrapper nevis neapstrādātu PDO. Šis apvalks ir daudz vieglāk mockēt un veikt vienības testus!

Šeit ir kontroleris, kas saglabā lietotāju datubāzē un nosūta laipnu e-pastu:

use flight\database\PdoWrapper;

class UserController {
    protected $app;
    protected $db;
    protected $mailer;

    public function __construct(Engine $app, PdoWrapper $db, MailerInterface $mailer) {
        $this->app = $app;
        $this->db = $db;
        $this->mailer = $mailer;
    }

    public function register() {
        $email = $this->app->request()->data->email;
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            // adding the return here helps unit testing to stop execution
            return $this->app->jsonHalt(['status' => 'error', 'message' => 'Invalid email']);
        }

        $this->db->runQuery('INSERT INTO users (email) VALUES (?)', [$email]);
        $this->mailer->sendWelcome($email);

        return $this->app->json(['status' => 'success', 'message' => 'User registered']);
    }
}

Galvenie punkti:

Kontrolera testēšana ar mockiem

Tagad testēsim UserController uzvedību: e-pasta validēšanu, saglabāšanu datubāzē un e-pasta sūtīšanu. Mēs mockēsim datubāzi un pasta sūtītāju, lai izolētu kontroleri.

// tests/UserControllerDICTest.php
use PHPUnit\Framework\TestCase;

class UserControllerDICTest extends TestCase {
    public function testValidEmailSavesAndSendsEmail() {

        // Sometimes mixing mocking styles is necessary
        // Here we use PHPUnit's built-in mock for PDOStatement
        $statementMock = $this->createMock(PDOStatement::class);
        $statementMock->method('execute')->willReturn(true);
        // Using an anonymous class to mock PdoWrapper
        $mockDb = new class($statementMock) extends PdoWrapper {
            protected $statementMock;
            public function __construct($statementMock) {
                $this->statementMock = $statementMock;
            }

            // When we mock it this way, we are not really making a database call.
            // We can further setup this to alter the PDOStatement mock to simulate failures, etc.
            public function runQuery(string $sql, array $params = []): PDOStatement {
                return $this->statementMock;
            }
        };
        $mockMailer = new class implements MailerInterface {
            public $sentEmail = null;
            public function sendWelcome($email): bool {
                $this->sentEmail = $email;
                return true;    
            }
        };
        $app = new Engine();
        $app->request()->data->email = 'test@example.com';
        $controller = new UserControllerDIC($app, $mockDb, $mockMailer);
        $controller->register();
        $response = $app->response()->getBody();
        $result = json_decode($response, true);
        $this->assertEquals('success', $result['status']);
        $this->assertEquals('User registered', $result['message']);
        $this->assertEquals('test@example.com', $mockMailer->sentEmail);
    }

    public function testInvalidEmailSkipsSaveAndEmail() {
         $mockDb = new class() extends PdoWrapper {
            // An empty constructor bypasses the parent constructor
            public function __construct() {}
            public function runQuery(string $sql, array $params = []): PDOStatement {
                throw new Exception('Should not be called');
            }
        };
        $mockMailer = new class implements MailerInterface {
            public $sentEmail = null;
            public function sendWelcome($email): bool {
                throw new Exception('Should not be called');
            }
        };
        $app = new Engine();
        $app->request()->data->email = 'invalid-email';

        // Need to map jsonHalt to avoid exiting
        $app->map('jsonHalt', function($data) use ($app) {
            $app->json($data, 400);
        });
        $controller = new UserControllerDIC($app, $mockDb, $mockMailer);
        $controller->register();
        $response = $app->response()->getBody();
        $result = json_decode($response, true);
        $this->assertEquals('error', $result['status']);
        $this->assertEquals('Invalid email', $result['message']);
    }
}

Galvenie punkti:

Pārāk daudz mockēšana

Esiet uzmanīgi, lai nemockētu pārāk daudz sava koda. Ļaujiet man dot piemēru zemāk par to, kāpēc tas var būt sliktas lietas, izmantojot mūsu UserController. Mēs mainīsim šo pārbaudi uz metodi, ko sauc isEmailValid (izmantojot filter_var) un citas jaunas pievienojumus uz atsevišķu metodi, ko sauc registerUser.

use flight\database\PdoWrapper;
use flight\Engine;

// UserControllerDICV2.php
class UserControllerDICV2 {
    protected $app;
    protected $db;
    protected $mailer;

    public function __construct(Engine $app, PdoWrapper $db, MailerInterface $mailer) {
        $this->app = $app;
        $this->db = $db;
        $this->mailer = $mailer;
    }

    public function register() {
        $email = $this->app->request()->data->email;
        if (!$this->isEmailValid($email)) {
            // adding the return here helps unit testing to stop execution
            return $this->app->jsonHalt(['status' => 'error', 'message' => 'Invalid email']);
        }

        $this->registerUser($email);

        $this->app->json(['status' => 'success', 'message' => 'User registered']);
    }

    protected function isEmailValid($email) {
        return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
    }

    protected function registerUser($email) {
        $this->db->runQuery('INSERT INTO users (email) VALUES (?)', [$email]);
        $this->mailer->sendWelcome($email);
    }
}

Un tagad pārāk mockētais vienības tests, kas patiesībā neko netestē:

use PHPUnit\Framework\TestCase;

class UserControllerTest extends TestCase {
    public function testValidEmailSavesAndSendsEmail() {
        $app = new Engine();
        $app->request()->data->email = 'test@example.com';
        // we are skipping the extra dependency injection here cause it's "easy"
        $controller = new class($app) extends UserControllerDICV2 {
            protected $app;
            // Bypass the deps in the construct
            public function __construct($app) {
                $this->app = $app;
            }

            // We'll just force this to be valid.
            protected function isEmailValid($email) {
                return true; // Always return true, bypassing real validation
            }

            // Bypass the actual DB and mailer calls
            protected function registerUser($email) {
                return false;
            }
        };
        $controller->register();
        $response = $app->response()->getBody();
        $result = json_decode($response, true);
        $this->assertEquals('success', $result['status']);
        $this->assertEquals('User registered', $result['message']);
    }
}

Hurā, mums ir vienības testi un tie iziet! Bet pagaidi, ko tad, ja es patiesībā mainu isEmailValid vai registerUser iekšējo darbību? Mani testi joprojām izies, jo esmu mockējis visu funkcionalitāti. Ļaujiet man parādīt, ko es domāju.

// UserControllerDICV2.php
class UserControllerDICV2 {

    // ... other methods ...

    protected function isEmailValid($email) {
        // Changed logic
        $validEmail = filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
        // Now it should only have a specific domain
        $validDomain = strpos($email, '@example.com') !== false; 
        return $validEmail && $validDomain;
    }
}

Ja es palaižu savus iepriekšējos vienības testus, tie joprojām iziet! Bet tāpēc, ka es netestēju uzvedību (patiesībā neļāvu daļai koda darboties), esmu potenciāli ieprogrammējis kļūdu, kas gaida ražošanā. Tests vajadzētu modificēt, lai ņemtu vērā jauno uzvedību, un arī pretējo, kad uzvedība nav tā, ko mēs sagaidām.

Pilns piemērs

Varat atrast pilnu Flight PHP projektu piemēru ar vienības testiem GitHub: n0nag0n/flight-unit-tests-guide. Lai iegūtu dziļāku izpratni, skatiet Unit Testing and SOLID Principles.

Biežas kļūdas

Mērogošana ar vienības testiem

Vienības testi spīd lielākos projektos vai kad atgriežaties pie koda pēc mēnešiem. Tie dokumentē uzvedību un uztver regresijas, ietaupot laiku no atkārtotas mācīšanās jūsu lietojumprogrammai. Solo izstrādātājiem testējiet kritiskos ceļus (piemēram, lietotāja reģistrāciju, maksājumu apstrādi). Komandām testi nodrošina konsekventu uzvedību visās ieguldījumos. Skatiet Why Frameworks? par vairāk priekšrocībām, izmantojot ietvarus un testus.

Iesaistiet savus testēšanas padomus Flight PHP dokumentācijas repozitorijā!

Rakstījis n0nag0n 2025

Guides/blog

Vienkārša emuāra izveide ar Flight PHP

Šis ceļvedis nodrošina soļus, kā izveidot pamata emuāru, izmantojot Flight PHP ietvaru. Jūs izveidosiet projektu, definēsiet maršrutus, pārvaldīsiet ierakstus, izmantojot JSON, un attēlosiet tos ar Latte veidņu dzinēju, tādējādi demonstrējot Flight vienkāršību un elastību. Ceļojuma beigās jums būs funkcionāls emuārs ar sākumlapu, individuālām ierakstu lapām un izveides formu.

Prasības

1. solis: Iestatiet savu projektu

Sāciet, izveidojot jaunu projekta direktoriju un instalējot Flight, izmantojot Composer.

  1. Izveidojiet direktoriju:

    mkdir flight-blog
    cd flight-blog
  2. Instalējiet Flight:

    composer require flightphp/core
  3. Izveidojiet publisko direktoriju: Flight izmanto vienu ieejas punktu (index.php). Izveidojiet public/ mapi tam:

    mkdir public
  4. Pamata index.php: Izveidojiet public/index.php ar vienkāršu “hello world” maršrutu:

    <?php
    require '../vendor/autoload.php';
    
    Flight::route('/', function () {
       echo 'Sveiki, Flight!';
    });
    
    Flight::start();
  5. Palaidiet iebūvēto serveri: Pārbaudiet savu iestatījumu, izmantojot PHP izstrādes serveri:

    php -S localhost:8000 -t public/

    Apmeklējiet http://localhost:8000, lai redzētu “Sveiki, Flight!”.

2. solis: Organizējiet sava projekta struktūru

Lai nodrošinātu tīru iestatījumu, strukturējiet savu projektu šādi:

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

3. solis: Instalējiet un konfigurējiet Latte

Latte ir viegla veidņu dzinēja, kas labi integrējas ar Flight.

  1. Instalējiet Latte:

    composer require latte/latte
  2. Konfigurējiet Latte Flight: Atjauniniet public/index.php, lai reģistrētu Latte kā skata dzinēju:

    <?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' => 'Mans emuārs']);
    });
    
    Flight::start();
  3. Izveidojiet izkārtojuma veidni: app/views/layout.latte:

    <!DOCTYPE html>
    <html>
    <head>
    <title>{$title}</title>
    </head>
    <body>
    <header>
        <h1>Mans emuārs</h1>
        <nav>
            <a href="/">Sākums</a> | 
            <a href="/create">Izveidot ierakstu</a>
        </nav>
    </header>
    <main>
        {block content}{/block}
    </main>
    <footer>
        <p>&copy; {date('Y')} Flight emuārs</p>
    </footer>
    </body>
    </html>
  4. Izveidojiet sākumlapa veidni: 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}

    Restartējiet serveri, ja esat to izslēguši, un apmeklējiet http://localhost:8000, lai redzētu attēloto lapu.

  5. Izveidojiet datu failu:

    Izmantojiet JSON failu, lai simulētu datu bāzi vienkāršības labad.

    data/posts.json:

    [
       {
           "slug": "pirmais-ieraksts",
           "title": "Mans pirmais ieraksts",
           "content": "Šis ir mans pirmais emuāra ieraksts ar Flight PHP!"
       }
    ]

4. solis: Definējiet maršrutus

Atsevišķiet savus maršrutus konfigurācijas failā labākai organizācijai.

  1. Izveidojiet routes.php: app/config/routes.php:

    <?php
    Flight::route('/', function () {
       Flight::view()->render('home.latte', ['title' => 'Mans emuārs']);
    });
    
    Flight::route('/post/@slug', function ($slug) {
       Flight::view()->render('post.latte', ['title' => 'Ieraksts: ' . $slug, 'slug' => $slug]);
    });
    
    Flight::route('GET /create', function () {
       Flight::view()->render('create.latte', ['title' => 'Izveidot ierakstu']);
    });
  2. Atjauniniet index.php: Iekļaujiet maršrutu failu:

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

5. solis: Glabājiet un iegūstiet emuāru ierakstus

Pievienojiet metodes, lai ielādētu un saglabātu ierakstus.

  1. Pievienojiet ierakstu metodi: index.php pievienojiet metodi ierakstu ielādei:

    Flight::map('posts', function () {
       $file = __DIR__ . '/../data/posts.json';
       return json_decode(file_get_contents($file), true);
    });
  2. Atjauniniet maršrutus: Izmainiet app/config/routes.php, lai izmantotu ierakstus:

    <?php
    Flight::route('/', function () {
       $posts = Flight::posts();
       Flight::view()->render('home.latte', [
           'title' => 'Mans emuārs',
           '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' => 'Izveidot ierakstu']);
    });

6. solis: Izveidojiet veidnes

Atjauniniet savas veidnes, lai attēlotu ierakstus.

  1. Ieraksta lapa (app/views/post.latte):

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

7. solis: Pievienojiet ierakstu izveidi

Rīkojieties ar formas iesniegšanu, lai pievienotu jaunus ierakstus.

  1. Izveidojiet formu (app/views/create.latte):

    {extends 'layout.latte'}
    
    {block content}
        <h2>{$title}</h2>
        <form method="POST" action="/create">
            <div class="form-group">
                <label for="title">Nosaukums:</label>
                <input type="text" name="title" id="title" required>
            </div>
            <div class="form-group">
                <label for="content">Saturs:</label>
                <textarea name="content" id="content" required></textarea>
            </div>
            <button type="submit">Saglabāt ierakstu</button>
        </form>
    {/block}
  2. Pievienojiet POST maršrutu: 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. Pārbaudiet to:

    • Apmeklējiet http://localhost:8000/create.
    • Iesniedziet jaunu ierakstu (piemēram, “Otrais ieraksts” ar kādu saturu).
    • Pārbaudiet sākumlapu, lai redzētu to sarakstā.

8. solis: Uzlabojiet ar kļūdu apstrādi

Pārdefinējiet notFound metodi, lai uzlabotu 404 pieredzi.

index.php:

Flight::map('notFound', function () {
    Flight::view()->render('404.latte', ['title' => 'Lapa nav atrasta']);
});

Izveidojiet app/views/404.latte:

{extends 'layout.latte'}

{block content}
    <h2>404 - {$title}</h2>
    <p>Atvainojiet, šī lapa neeksistē!</p>
{/block}

Nākamie soļi

Secinājums

Jūs esat izveidojis vienkāršu emuāru ar Flight PHP! Šis ceļvedis demonstrē pamatfunkcijas, piemēram, maršrutēšanu, veidņu veidošanu ar Latte un formu iesniegšanu, vienlaikus saglabājot lietas vieglas. Izpētiet Flight dokumentāciju, lai uzzinātu vairāk par uzlabotām funkcijām, kas palīdzēs attīstīt jūsu emuāru tālāk!

License

MIT licences (MIT)

=====================

Autortiesības © 2024 @mikecao, @n0nag0n

Atļauja tiek piešķirta bez maksas jebkuram personai, kas iegūst šīs programmatūras kopiju un saistītos dokumentus (turpmāk - "Programmatūra"), izmantot Programmatūru jebkurā veidā bez ierobežojumiem, ieskaitot tiesības izmantot, kopēt, modificēt, apvienot, publicēt, izplatīt, licencēt un/vai pārdot Programmatūras kopijas, un atļaut personas, kam Programmatūra tiek nodrošināta to darīt, pakļautas zemāk minētajām nosacījumiem:

Minētās autortiesību paziņojums un šī atļaujas paziņojums ir jāiekļauj visās kopijās vai būtiskajos Programmatūras daļās.

PROGRAMMATŪRA TIEK NODROŠINĀTA "KĀ TĀDA", BEZ JEBKĀDAS GARANTIJAS IZTEIKTAS VAI IMPLICITAS, IETVEROT, BET NEIEROBEŽOTI, MERCHANTĀLĀS KVALITĀTES UN PIEMĒROTĪBAS KONKRĒTIEM MĒRĶIEM UN NEPĀRKĀPJUMS. NEVIENĀ GADĪJUMĀ AUTORI VAI AUTORTIESĪBU IEDZĪVOTĀJI NAV ATBILDĪGI PAR JEBKURU PRASĪBU, KAITĒJUMU VAI CITĀM SAISTĪBĀM, NEATKARĪGI NO TĀ, VAI TĀS IERAKSTS, IAUCIENS VAI CITĀDI RADIES SAISTĪBĀ AR PROGRAMMATŪRU VAI LIETOŠANU VAI CITĀDĀM DARĪBĀM AR PROGRAMMATŪRU.

About

Flight PHP Framework

Flight ir ātrs, vienkāršs, paplašināms ietvars PHP—izveidots izstrādātājiem, kuri vēlas ātri paveikt darbus, bez liekām raizēm. Vai jūs veidojat klasisku tīmekļa lietotni, ātru API vai eksperimentējat ar jaunākajām AI balstītajām rīkiem, Flight zems nospiedums un vienkāršais dizains padara to par ideālu izvēli. Flight ir domāts, lai būtu viegls, bet tas var arī tikt galā ar uzņēmuma arhitektūras prasībām.

Kāpēc izvēlēties Flight?

Video Overview

Vai tas nav pietiekami vienkārši?
Uzziniet vairāk par Flight dokumentācijā!

Quick Start

Lai veiktu ātru, pamata instalāciju, instalējiet to ar Composer:

composer require flightphp/core

Vai jūs varat lejupielādēt zip failu no repozitorijas šeit. Tad jums būs pamata index.php fails, piemēram, šāds:

<?php

// ja instalēts ar composer
require 'vendor/autoload.php';
// vai ja instalēts manuāli ar zip failu
// require 'flight/Flight.php';

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

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

Flight::start();

Tas ir viss! Jums ir pamata Flight lietotne. Tagad jūs varat palaist šo failu ar php -S localhost:8000 un apmeklēt http://localhost:8000 savā pārlūkā, lai redzētu izvadi.

Skeleton/Boilerplate App

Ir piemērs app, lai palīdzētu jums sākt projektu ar Flight. Tajā ir strukturēta izkārtojums, pamata konfigurācijas un saderība ar composer skriptiem jau no sākuma! Apskatiet flightphp/skeleton gatavam projektam vai apmeklējiet piemērus lapu iedvesmai. Vēlaties redzēt, kā AI iederas? Izpētiet AI balstītus piemērus.

Installing the Skeleton App

Tas ir pietiekami vienkārši!

# Izveidojiet jauno projektu
composer create-project flightphp/skeleton my-project/
# Ieejiet jaunajā projektu direktorijā
cd my-project/
# Palaidiet lokālo attīstības serveri, lai sāktu nekavējoties!
composer start

Tas izveidos projektu struktūru, iestatīs vajadzīgos failus, un jūs esat gatavs!

High Performance

Flight ir viens no ātrākajiem PHP ietvariem. Tā vieglais kodols nozīmē mazāku slogu un vairāk ātrumu—ideāli piemērots gan tradicionālām lietotnēm, gan mūsdienu AI balstītiem projektiem. Jūs varat redzēt visus benchmarkus TechEmpower

Skatiet benchmarku zemāk ar dažiem citiem populāriem PHP ietvariem.

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

Flight and AI

Vai jūs interesē, kā tas darbojas ar AI? Atklājiet, kā Flight atvieglo darbu ar jūsu mīļākajiem kodēšanas LLM!

Community

Mēs esam Matrix Chat

Matrix

Un Discord

Contributing

Ir divi veidi, kā jūs varat piedalīties Flight:

  1. Piedalieties kodola ietvara izstrādē, apmeklējot core repozitoriju.
  2. Palīdziet uzlabot dokumentāciju! Šī dokumentācijas vietne ir mitināta Github. Ja jūs pamanāt kļūdu vai vēlaties kaut ko uzlabot, iesniedziet pull request. Mēs mīlam atjauninājumus un jaunas idejas—īpaši ap AI un jaunām tehnoloģijām!

Requirements

Flight prasa PHP 7.4 vai jaunāku.

Piezīme: PHP 7.4 tiek atbalstīts, jo šobrīd (2024. gadā) PHP 7.4 ir noklusētā versija dažām LTS Linux izdalēm. Spiešana uz pāreju uz PHP >8 izraisītu daudz neērtību lietotājiem. Ietvars arī atbalsta PHP >8.

License

Flight ir izlaists zem MIT licences.

Awesome-plugins/php_cookie

Sīkfaili

overclokk/cookie ir vienkārša bibliotēka sīkfailu pārvaldībai jūsu lietotnē.

Instalēšana

Instalēšana ir vienkārša ar komponistu.

composer require overclokk/cookie

Izmantos̄ana

Lietošana ir tik vienkārša kā jaunas metodes reģistrēšana Flight klases.


use Overclokk\Cookie\Cookie;

/*
 * Iestatiet savā palaišanas vai public/index.php failā
 */

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

/**
 * ExampleController.php
 */

class ExampleController {
    public function login() {
        // Iestatiet sīkfailu

        // jums vajadzētu, lai tas būtu false, tādēļ, lai jūs saņemtu jaunu instanci
        // izmantojiet zemāk esošo komentāru, ja vēlaties autovērstjanu
        /** @var \Overclokk\Cookie\Cookie $cookie */
        $cookie = Flight::cookie(false);
        $cookie->set(
            'stay_logged_in', // sīkfaila nosaukums
            '1', // vērtība, kuru vēlaties iestatīt
            86400, // cik sekundes sīkfailam būtu jāpastāv
            '/', // ceļš, kurā būs pieejams sīkfails
            'example.com', // domēns, kurā būs pieejams sīkfails
            true, // sīkfails tiks pārraidīts tikai pār šifrētu HTTPS savienojumu
            true // sīkfails būs pieejams tikai caur HTTP protokolu
        );

        // pēc izvēles, ja vēlaties saglabāt noklusējuma vērtības
        // un ātri iestatīt sīkfailu ilgu laiku
        $cookie->forever('stay_logged_in', '1');
    }

    public function home() {
        // Pārbaudiet, vai jums ir sīkfails
        if (Flight::cookie()->has('stay_logged_in')) {
            // ielieciet tos piemēram, informācijas panelī.
            Flight::redirect('/dashboard');
        }
    }
}

Awesome-plugins/php_encryption

PHP Šifrēšana

defuse/php-encryption ir bibliotēka, kas var tikt izmantota datu šifrēšanai un atšifrēšanai. Uzsākšana ir diezgan vienkārša, lai sāktu šifrēt un atšifrēt datus. Viņiem ir lielisks rokasgrāmata, kas palīdz izskaidrot pamatus par to, kā izmantot bibliotēku, kā arī svarīgu drošības aspektu, kas saistīti ar šifrēšanu.

Instalēšana

Instalēšana ir vienkārša ar komponistu.

composer require defuse/php-encryption

Iestatījumi

Pēc tam jums būs jāģenerē šifrēšanas atslēga.

vendor/bin/generate-defuse-key

Tas izvadīs atslēgu, ko būsiet jāsargā. Jūs varētu saglabāt atslēgu savā app/config/config.php failā masīvā faila apakšdaļā. Lai gan tas nav ideāla vieta, tas vismaz ir kaut kas.

Lietošana

Tagad, kad jums ir bibliotēka un šifrēšanas atslēga, varat sākt šifrēt un atšifrēt datus.


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

/*
 * Uzstādiet savā bootstrap vai public/index.php failā
 */

// Šifrēšanas metode
Flight::map('encrypt', function($sastāvs_dati) {
    $šifrēšanas_atslēga = /* $config['encryption_key'] vai file_get_contents no vietas, kur likāt atslēgu */;
    return Crypto::encrypt($sastāvs_dati, Key::loadFromAsciiSafeString($šifrēšanas_atslēga));
});

// Atšifrēšanas metode
Flight::map('decrypt', function($šifrētie_dati) {
    $šifrēšanas_atslēga = /* $config['encryption_key'] vai file_get_contents no vietas, kur likāt atslēgu */;
    try {
        $sastāvs_dati = Crypto::decrypt($šifrētie_dati, Key::loadFromAsciiSafeString($šifrēšanas_atslēga));
    } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
        // Uzbrukums! Vai nu tika ielādēta nepareizā atslēga, vai arī šifrētais teksts ir mainījies, kopš tas tika izveidots - vai nu sabojājies datu bāzē vai nodomāti modificējis Eva, mēģinot veikt uzbrukumu.

        // ... apstrādājiet šo gadījumu tādā veidā, kas ir piemērots jūsu lietojumprogrammai ...
    }
    return $sastāvs_dati;
});

Flight::route('/encrypt', function() {
    $šifrētie_dati = Flight::encrypt('Šis ir noslēpums');
    echo $šifrētie_dati;
});

Flight::route('/decrypt', function() {
    $šifrētie_dati = '...'; // Iegūstiet šifrētos datus no kaut kurienes
    $atšifrētie_dati = Flight::decrypt($šifrētie_dati);
    echo $atšifrētie_dati;
});

Awesome-plugins/php_file_cache

flightphp/cache

Gaismas, vienkārša un neatkarīga PHP failā kešošanas klase, kas izveidota no Wruczek/PHP-File-Cache forka

Priekšrocības

Šī dokumentācijas vietne izmanto šo bibliotēku, lai kešotu katru no lapām!

Noklikšķiniet šeit, lai skatītu kodu.

Instalācija

Instalējiet, izmantojot composer:

composer require flightphp/cache

Lietošana

Lietošana ir diezgan vienkārša. Tas saglabā kešošanas failu kešošanas direktorijā.

use flight\Cache;

$app = Flight::app();

// Jūs nododiet direktoriju, kurā kešs tiks saglabāts, konstruktorā
$app->register('cache', Cache::class, [ __DIR__ . '/../cache/' ], function(Cache $cache) {

    // Tas nodrošina, ka kešs tiek izmantots tikai ražošanas režīmā
    // ENVIRONMENT ir konstante, kas ir iestatīta jūsu bootstrap failā vai citur jūsu lietotnē
    $cache->setDevMode(ENVIRONMENT === 'development');
});

Iegūt kešošanas vērtību

Jūs izmantojat get() metodi, lai iegūtu kešotu vērtību. Ja vēlaties ērtu metodi, kas atsvaidzinās kešu, ja tas ir beidzies, varat izmantot refreshIfExpired().


// Iegūt kešošanas instanci
$cache = Flight::cache();
$data = $cache->refreshIfExpired('simple-cache-test', function () {
    return date("H:i:s"); // return data to be cached
}, 10); // 10 sekundes

// or
$data = $cache->get('simple-cache-test');
if(empty($data)) {
    $data = date("H:i:s");
    $cache->set('simple-cache-test', $data, 10); // 10 sekundes
}

Saglabāt kešošanas vērtību

Jūs izmantojat set() metodi, lai saglabātu vērtību kešā.

Flight::cache()->set('simple-cache-test', 'my cached data', 10); // 10 sekundes

Dzēst kešošanas vērtību

Jūs izmantojat delete() metodi, lai dzēstu vērtību kešā.

Flight::cache()->delete('simple-cache-test');

Pārbaudīt, vai kešošanas vērtība pastāv

Jūs izmantojat exists() metodi, lai pārbaudītu, vai vērtība pastāv kešā.

if(Flight::cache()->exists('simple-cache-test')) {
    // do something
}

Notīrīt kešu

Jūs izmantojat flush() metodi, lai notīrītu visu kešu.

Flight::cache()->flush();

Izvilkt meta datus ar kešu

Ja vēlaties izvilkt laika zīmes un citus meta datus par kešošanas ierakstu, pārliecinieties, ka nododiet true kā pareizo parametru.

$data = $cache->refreshIfExpired("simple-cache-meta-test", function () {
    echo "Refreshing data!" . PHP_EOL;
    return date("H:i:s"); // return data to be cached
}, 10, true); // true = return with metadata
// or
$data = $cache->get("simple-cache-meta-test", true); // true = return with metadata

/*
Example cached item retrieved with metadata:
{
    "time":1511667506, <-- save unix timestamp
    "expire":10,       <-- expire time in seconds
    "data":"04:38:26", <-- unserialized data
    "permanent":false
}

Using metadata, we can, for example, calculate when item was saved or when it expires
We can also access the data itself with the "data" key
*/

$expiresin = ($data["time"] + $data["expire"]) - time(); // get unix timestamp when data expires and subtract current timestamp from it
$cacheddate = $data["data"]; // we access the data itself with the "data" key

echo "Latest cache save: $cacheddate, expires in $expiresin seconds";

Dokumentācija

Apmeklējiet https://github.com/flightphp/cache, lai skatītu kodu. Pārliecinieties, ka skatāt examples mapi papildu veidiem, kā izmantot kešu.

Awesome-plugins/permissions

FlightPHP/Atļaujas

Tas ir atļauju modulis, ko var izmantot jūsu projektos, ja jums ir vairākas lomas jūsu lietotnē, un katram no tiem ir nedaudz atšķirīga funkcionalitāte. Šis modulis ļauj definēt atļaujas katrai rolei un pēc tam pārbaudīt, vai pašreizējam lietotājam ir atļauja piekļūt konkrētai lapai vai veikt konkrētu darbību.

Noklikšķiniet šeit GitHub repozitorijai.

Uzstādīšana

Izpildiet composer require flightphp/permissions, un esat gatavs darbam!

Lietošana

Vispirms jums ir jāiestata savas atļaujas, tad jums jāpasaka savai lietotnei, ko šīs atļaujas nozīmē. Galu galā jūs pārbaudīsiet savas atļaujas ar $Permissions->has(), ->can() vai is(). has() un can() ir vienādas funkcijas, bet sauktas atšķirīgi, lai jūsu kods būtu lasāmāks.

Pamata piemērs

Iedomāsimies, ka jums ir funkcija jūsu lietotnē, kas pārbauda, vai lietotājs ir pierakstījies. Jūs varat izveidot atļauju objektu šādi:

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

// kods

// pēc tam, iespējams, jums ir kaut kas, kas jums paziņo, kāda ir pašreizējā lietotāja loma
// visticamāk, jums ir kaut kas, kas nosaka pašreizējo lomu
// no sesijas mainīgā, kas to definē
// pēc reģistrēšanās, pretējā gadījumā viņiem būs "viesis" vai "publiska" loma.
$current_role = 'admins';

// iestatīt atļaujas
$permission = new \flight\Permissions($current_role);
$permission->defineRule('pieslēdzies', function($current_role) {
    return $current_role !== 'viesis';
});

// Iespējams, ka vēlēsieties šo objektu noturētiegavēkur visur
Flight::set('permission', $permission);

Tad kādā kontrolierī varētu būt kaut kas tāds.

<?php

// dažs kontrolieris
class DaļasKontrolieris {
    public function daļasDarbība() {
        $atļauja = Flight::get('permission');
        if ($atļauja->has('pieslēdzies')) {
            // dari kaut ko
        } else {
            // dari ko citu
        }
    }
}

Jūs varat izmantot arī to, lai sekotu, vai tiem ir atļauja kaut ko darīt jūsu lietotnē. Piemēram, ja jums ir veids, kā lietotāji var mijiedarboties ar saviem ierakstiem jūsu programmā, jūs varat pārbaudiet, vai viņiem ir atļauja veikt konkrētas darbības.

$current_role = 'admins';

// iestatīt atļaujas
$permission = new \flight\Permission($current_role);
$permission->defineRule('ieraksts', function($current_role) {
    if($current_role === 'admins') {
        $atļaujas = ['izveidot', 'lasīt', 'labot', 'dzēst'];
    } else if($current_role === 'redaktors') {
        $atļaujas = ['izveidot', 'lasīt', 'labot'];
    } else if($current_role === 'autors') {
        $atļaujas = ['izveidot', 'lasīt'];
    } else if($current_role === 'līdzstrādnieks') {
        $atļaujas = ['izveidot'];
    } else {
        $atļaujas = [];
    }
    return $atļaujas;
});
Flight::set('permission', $permission);

Tad kaut kur kontrolierī...

class IerakstaKontrolieris {
    public function izveidot() {
        $atļauja = Flight::get('permission');
        if ($atļauja->can('ieraksts.izveidot')) {
            // dari kaut ko
        } else {
            // dari ko citu
        }
    }
}

Injicēt atkarības

Jūs varat injicēt atkarības closure, kas definē atļaujas. Tas ir noderīgi, ja jums ir kāda veida pārslēgšana, ID vai jebkura cita dati, pret kuriem vēlaties pārbaudīt. Tas pats attiecas uz Klases->Metodes zvana veidiem, izņemot to, ka argumentus definējat metodē.

Closure

$Permission->defineRule('pasūtījums', function(string $current_role, MyDependency $MyDependency = null) {
    // ... kods
});

// jūsu kontroliera failā
public function izveidotPasūtījumu() {
    $MyDependency = Flight::myDependency();
    $atļauja = Flight::get('permission');
    if ($atļauja->can('pasūtījums.izveidot', $MyDependency)) {
        // dari kaut ko
    } else {
        // dari ko citu
    }
}

Klases

namespace ManLietotne;

class Atļaujas {

    public function pasūtījums(string $current_role, MyDependency $MyDependency = null) {
        // ... kods
    }
}

Saīsinājums, lai iestatītu atļaujas ar klasēm

Jūs varat izmantot arī klases, lai definētu savas atļaujas. Tas ir noderīgi, ja jums ir daudz atļauju, un vēlaties uzturēt savu kodu tīru. Jūs varat darīt kaut ko tādu kā šis:

<?php

// palaistāmais kods
$Permissions = new \flight\Permission($current_role);
$Permissions->defineRule('pasūtījums', 'ManLietotne\Atļaujas->pasūtījums');

// myapp/Permissions.php
namespace ManLietotne;

class Atļaujas {

    public function pasūtījums(string $current_role, int $lietotāja_id) {
        // Asumējot, ka šis ir iestatīts iepriekš
        /** @var \flight\database\PdoWrapper $db */
        $db = Flight::db();
        $atļautās_atļaujas = [ 'lasīt' ]; // ikviens var skatīties pasūtījumu
        if($current_role === 'menedžeris') {
            $atļautās_atļaujas[] = 'izveidot'; // vadītāji var izveidot pasūtījumus
        }
        $dažs īpašs_tētis_no_db = $db->fetchField('SELECT dažs_īpašs_tētis FROM iestatījumi WHERE id = ?', [ $lietotāja_id ]);
        if($dažs_īpašs_tētis_no_db) {
            $atļautās_atļaujas[] = 'labot'; // Ja lietotājam ir īpaša tētis, viņi var atjaunināt pasūtījumus
        }
        if($current_role === 'admins') {
            $atļautās_atļaujas[] = 'dzēst'; // administratori var dzēst pasūtījumus
        }
        return $atļautās_atļaujas;
    }
}

Cool daļa ir tāda, ka ir arī saīsinājums, ko varat izmantot (kas var būt arī kešēta!!!), kur vienkārši pateiksit atļauju klasei atkartot visus metodus klasē. Tāpēc, ja ir metode ar nosaukumu pasūtījums() un metode ar nosaukumu uzņēmums(), šīs automātiski tiks atkartotas, lai jūs varētu vienkārši izpildīt $Permissions->has('pasūtījums.lasīt') vai $Permissions->has('uzņēmums.lasīt') un tas strādās. To definēt ir ārkārtīgi grūti, tāpēc palieciet šeit kopā ar mani. Jums vienkārši jāizdara šādi:

Izveidojiet atļauju klases grupēšanai.

class ManasAtļaujas {
    public function pasūtījums(string $current_role, int $pasūtījuma_id = 0): array {
        // kods, lai noteiktu atļaujas
        return $atļaujas_masīvs;
    }

    public function uzņēmums(string $current_role, int $uzņēmuma_id): array {
        // kods, lai noteiktu atļaujas
        return $atļaujas_masīvs;
    }
}

Tad padarīt atļaujas atrodamas, izmantojot šo bibliotēku.

$Atļaujas = new \flight\Permission($current_role);
$Atļaujas->defineRulesFromClassMethods(ManasAtļaujas::class);
Flight::set('permissions', $Atļaujas);

Visbeidzot, zvaniet atļaujai savā kodā, lai pārbaudītu, vai lietotājam ir atļauts veikt noteiktu atļauju.

class DažsKontrolieris {
    public function izveidotPasūtījumu() {
        if(Flight::get('permissions')->can('pasūtījums.izveidot') === false) {
            die('Jums nav atļauts izveidot pasūtījumu. Atvainojiet!');
        }
    }
}

Kešošana

Lai iespējotu kešošanu, skatiet vienkāršo wruczak/phpfilecache bibliotēku. Zemāk ir piemērs, kā iespējot to.


// šis $app var būt daļa no jūsu koda vai
// varat vienkārši padot null, un tas tiks iegūts
// no Flight::app() konstruktorā
$app = Flight::app();

// Pašlaik tas pieņem šo vienumu kā failu kešu. Citus var viegli
// pievienot nākotnē. 
$Kešatmiņa = new Wruczek\PhpFailaKešatmiņa\PhpFailaKešatmiņa;

$Atļaujas = new \flight\Permission($current_role, $app, $Kešatmiņa);
$Atļaujas->defineRulesFromClassMethods(ManasAtļaujas::class, 3600); // 3600 ir cik daudz sekundes to kešot. Atstājiet to uz neatcelšanu

Un dodieties!

Awesome-plugins/simple_job_queue

Vienkārša Darba Rinda

Vienkārša Darba Rinda ir bibliotēka, ko var izmantot, lai apstrādātu darbus asinkroni. To var izmantot ar beanstalkd, MySQL/MariaDB, SQLite un PostgreSQL.

Instalēt

composer require n0nag0n/simple-job-queue

Izmantošana

Lai tas darbotos, jums nepieciešams veids, kā pievienot darbus rindai un veids, kā apstrādāt darbus (darbinieks). Tālāk ir sniegti piemēri, kā pievienot darbu rindai un kā apstrādāt darbu.

Pievienošana Flight

Šīs pievienošana Flight ir vienkārša un tiek veikta, izmantojot metodi register(). Tālāk ir piemērs, kā to pievienot Flight.

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

// Mainiet ['mysql'] uz ['beanstalkd'], ja vēlaties izmantot beanstalkd
Flight::register('queue', n0nag0n\Job_Queue::class, ['mysql'], function($Job_Queue) {
    // ja jums jau ir PDO savienojums ar Flight::db();
    $Job_Queue->addQueueConnection(Flight::db());

    // vai, ja izmantojat beanstalkd/Pheanstalk
    $pheanstalk = Pheanstalk\Pheanstalk::create('127.0.0.1');
    $Job_Queue->addQueueConnection($pheanstalk);
});

Jauna darba pievienošana

Kad pievienojat darbu, jums jānorāda caurule (rinda). Tas ir salīdzināms ar kanālu RabbitMQ vai cauruli beanstalkd.

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

Darbinieka palaišana

Šeit ir piemēra fails, kā palaist darbinieku.

<?php

require 'vendor/autoload.php';

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

// vai, ja izmantojat beanstalkd/Pheanstalk
$pheanstalk = Pheanstalk\Pheanstalk::create('127.0.0.1');
$Job_Queue->addQueueConnection($pheanstalk);

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

    // pielāgojiet, kā jums labāk guļ naktī (tikai datu bāzu rindām, beanstalkd šī instrukcija nav nepieciešama)
    if(empty($job)) {
        usleep(500000);
        continue;
    }

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

    try {
        $result = doSomethingThatDoesSomething($payload);

        if($result === true) {
            $Job_Queue->deleteJob($job);
        } else {
            // tas izņem to no gatavo rindu un ievieto citā rindā, kuru var paņemt un "izsist" vēlāk.
            $Job_Queue->buryJob($job);
        }
    } catch(Exception $e) {
        $Job_Queue->buryJob($job);
    }
}

Ilgu Procesu Apstrāde ar Supervisord

Supervisord ir procesu kontroles sistēma, kas nodrošina, ka jūsu darbinieku procesi paliek aktīvi nepārtraukti. Šeit ir detalizētāks ceļvedis, kā to iestatīt ar savu Vienkāršo Darba Rindu darbinieku:

Supervisord instalēšana

# Uz Ubuntu/Debian
sudo apt-get install supervisor

# Uz CentOS/RHEL
sudo yum install supervisor

# Uz macOS ar Homebrew
brew install supervisor

Darbinieka skripta izveide

Vispirms saglabājiet savu darbinieka kodu veltītā PHP failā:

<?php

require 'vendor/autoload.php';

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

// Iestatiet cauruli, kuru vēlaties uzraudzīt
$Job_Queue->watchPipeline('send_important_emails');

// Ierakstiet darbinieka sākumu
echo date('Y-m-d H:i:s') . " - Darbinieks uzsākts\n";

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

    if(empty($job)) {
        usleep(500000); // Miega 0.5 sekundes
        continue;
    }

    echo date('Y-m-d H:i:s') . " - Apstrādā darba {$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') . " - Darbs {$job['id']} veiksmīgi pabeigts\n";
        } else {
            $Job_Queue->buryJob($job);
            echo date('Y-m-d H:i:s') . " - Darbs {$job['id']} neizdevās, aprakts\n";
        }
    } catch(Exception $e) {
        $Job_Queue->buryJob($job);
        echo date('Y-m-d H:i:s') . " - Izņēmums apstrādājot darbu {$job['id']}: {$e->getMessage()}\n";
    }
}

Supervisord konfigurēšana

Izveidojiet konfigurācijas failu savam darbiniekam:

[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

Galvenās konfigurācijas opcijas:

Darbinieku pārvaldība ar Supervisorctl

Pēc konfigurācijas izveides vai modificēšanas:

# Pārlādēt supervisor konfigurāciju
sudo supervisorctl reread
sudo supervisorctl update

# Kontrolēt konkrētus darbinieku procesus
sudo supervisorctl start email_worker:*
sudo supervisorctl stop email_worker:*
sudo supervisorctl restart email_worker:*
sudo supervisorctl status email_worker:*

Vairāku Cauruļu Palaišana

Vairāku cauruļu gadījumā izveidojiet atsevišķus darbinieku failus un konfigurācijas:

[program:email_worker]
command=php /path/to/email_worker.php
# ... citas konfigurācijas ...

[program:notification_worker]
command=php /path/to/notification_worker.php
# ... citas konfigurācijas ...

Uzraudzība un Ieraksti

Pārbaudiet ierakstus, lai uzraudzītu darbinieku aktivitāti:

# Apskatīt ierakstus
sudo tail -f /var/log/simple_job_queue.log

# Pārbaudīt statusu
sudo supervisorctl status

Šis iestatījums nodrošina, ka jūsu darba darbinieki turpina darboties, pat pēc avārijām, servera restartēšanas vai citiem jautājumiem, padarot jūsu rindu sistēmu uzticamu ražošanas vidēm.

Awesome-plugins/n0nag0n_wordpress

WordPress Integrācija: n0nag0n/wordpress-integration-for-flight-framework

Vai vēlaties izmantot Flight PHP savā WordPress vietnē? Šis spraudnis to padara vienkāršu! Ar n0nag0n/wordpress-integration-for-flight-framework, jūs varat palaist pilnu Flight lietotni tieši blakus jūsu WordPress instalācijai—ideāli piemērots pielāgotu API, mikropakalpojumu vai pat pilnvērtīgu lietotņu izveidošanai, neizejot no WordPress komforta.


Ko tas dara?

Instalācija

  1. Augšupielādējiet flight-integration mapi uz jūsu /wp-content/plugins/ direktoriju.
  2. Aktivizējiet spraudni WordPress administrācijā (Plugins izvēlnē).
  3. Dodieties uz Settings > Flight Framework, lai konfigurētu spraudni.
  4. Iestatiet piegādātāja ceļu uz savu Flight instalāciju (vai izmantojiet Composer, lai instalētu Flight).
  5. Konfigurējiet savu lietotnes mapes ceļu un izveidojiet mapju struktūru (spraudnis var palīdzēt ar to!).
  6. Sāciet veidot savu Flight lietotni!

Izmantošanas piemēri

Pamata maršrutēšanas piemērs

Jūsu app/config/routes.php failā:

Flight::route('GET /api/hello', function() {
    Flight::json(['message' => 'Hello World!']);
});

Kontroliera piemērs

Izveidojiet kontrolieri app/controllers/ApiController.php:

namespace app\controllers;

use Flight;

class ApiController {
    public function getUsers() {
        // Jūs varat izmantot WordPress funkcijas iekš Flight!
        $users = get_users();
        $result = [];
        foreach($users as $user) {
            $result[] = [
                'id' => $user->ID,
                'name' => $user->display_name,
                'email' => $user->user_email
            ];
        }
        Flight::json($result);
    }
}

Pēc tam jūsu routes.php:

Flight::route('GET /api/users', [app\controllers\ApiController::class, 'getUsers']);

BUJ

J: Vai man jāzina Flight, lai izmantotu šo spraudni?
A: Jā, tas ir domāts izstrādātājiem, kuri vēlas izmantot Flight iekš WordPress. Ieteicams pamata zināšanas par Flight maršrutēšanu un pieprasījumu apstrādi.

J: Vai tas palēninās manu WordPress vietni?
A: Nē! Spraudnis apstrādā tikai pieprasījumus, kas atbilst jūsu Flight maršrutiem. Visi citi pieprasījumi tiek novirzīti uz WordPress kā parasti.

J: Vai es varu izmantot WordPress funkcijas savā Flight lietotnē?
A: Protams! Jums ir pilna piekļuve visām WordPress funkcijām, āķiem un globālajiem mainīgajiem no Flight maršrutiem un kontrolieriem.

J: Kā es varu izveidot pielāgotus maršrutus?
A: Definējiet savus maršrutus config/routes.php failā savā lietotnes mapē. Skatiet parauga failu, ko izveido mapju struktūras ģenerators, piemēriem.

Izmaiņu žurnāls

1.0.0
Sākotnējais izlaidums.


Papildus informācijai skatiet GitHub repo.

Awesome-plugins/ghost_session

Ghostff/Session

PHP Sesijas pārvaldnieks (nebloķējošs, zibspuldze, segments, sesijas šifrēšana). Izmanto PHP open_ssl, lai pēc izvēles šifrētu/dešifrētu sesijas datus. Atbalsta File, MySQL, Redis un Memcached.

Noklikšķiniet here, lai apskatītu kodu.

Instalācija

Instalējiet ar composer.

composer require ghostff/session

Pamata konfigurācija

Jums nav nepieciešams neko nodot, lai izmantotu noklusējuma iestatījumus ar savu sesiju. Vairāk par iestatījumiem varat lasīt Github Readme.

use Ghostff\Session\Session;

require 'vendor/autoload.php';

$app = Flight::app();

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

// viena lieta, ko atcerēties, ir tā, ka jums ir jāapstiprina sava sesija katrā lapas ielādē
// vai jums būs nepieciešams izpildīt auto_commit savā konfigurācijā. 

Vienkāršs piemērs

Šeit ir vienkāršs piemērs, kā jūs varētu to izmantot.

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

    // veiciet savu pieteikšanās loģiku šeit
    // validējiet paroli utt.

    // ja pieteikšanās ir veiksmīga
    $session->set('is_logged_in', true);
    $session->set('user', $user);

    // jebkurā laikā, kad jūs rakstāt uz sesiju, jums tas jāapstiprina apzināti.
    $session->commit();
});

// Šo pārbaudi varētu veikt ierobežotās lapas loģikā vai ietīt ar vidējo programmu.
Flight::route('/some-restricted-page', function() {
    $session = Flight::session();

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

    // veiciet savu ierobežotās lapas loģiku šeit
});

// vidējās programmas versija
Flight::route('/some-restricted-page', function() {
    // regulāra lapas loģika
})->addMiddleware(function() {
    $session = Flight::session();

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

Sarežģītāks piemērs

Šeit ir sarežģītāks piemērs, kā jūs varētu to izmantot.

use Ghostff\Session\Session;

require 'vendor/autoload.php';

$app = Flight::app();

// iestatiet pielāgotu ceļu uz savu sesijas konfigurācijas failu kā pirmo argumentu
// vai dodiet tam pielāgotu masīvu
$app->register('session', Session::class, [ 
    [
        // ja vēlaties glabāt savu sesijas datus datu bāzē (labi, ja vēlaties kaut ko tādu kā "izrakstīties no visām ierīcēm" funkcionalitāti)
        Session::CONFIG_DRIVER        => Ghostff\Session\Drivers\MySql::class,
        Session::CONFIG_ENCRYPT_DATA  => true,
        Session::CONFIG_SALT_KEY      => hash('sha256', 'my-super-S3CR3T-salt'), // lūdzu, mainiet to uz kaut ko citu
        Session::CONFIG_AUTO_COMMIT   => true, // dariet to tikai tad, ja tas ir nepieciešams un/vai grūti izpildīt commit() savu sesiju.
                                                // turklāt jūs varētu izdarīt Flight::after('start', function() { Flight::session()->commit(); });
        Session::CONFIG_MYSQL_DS         => [
            'driver'    => 'mysql',             # Datu bāzes draiveris PDO dns, piem. (mysql:host=...;dbname=...)
            'host'      => '127.0.0.1',         # Datu bāzes hosts
            'db_name'   => 'my_app_database',   # Datu bāzes nosaukums
            'db_table'  => 'sessions',          # Datu bāzes tabula
            'db_user'   => 'root',              # Datu bāzes lietotājvārds
            'db_pass'   => '',                  # Datu bāzes parole
            'persistent_conn'=> false,          # Izvairieties no jaunas savienojuma izveidošanas katru reizi, kad skriptam jārunā ar datu bāzi, kas padara tīmekļa lietojumprogrammu ātrāku. ATRASTIET SEVI PAŠI
        ]
    ] 
]);

Palīdzība! Mana sesijas dati netiek saglabāti!

Vai jūs iestatāt savus sesijas datus un tie netiek saglabāti starp pieprasījumiem? Jūs, iespējams, esat aizmirsis apstiprināt savus sesijas datus. Jūs varat to izdarīt, izsaucot $session->commit() pēc tam, kad esat iestatījis savus sesijas datus.

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

    // veiciet savu pieteikšanās loģiku šeit
    // validējiet paroli utt.

    // ja pieteikšanās ir veiksmīga
    $session->set('is_logged_in', true);
    $session->set('user', $user);

    // jebkurā laikā, kad jūs rakstāt uz sesiju, jums tas jāapstiprina apzināti.
    $session->commit();
});

Cits veids, kā to apiet, ir tad, kad jūs iestatāt savu sesijas servisu, jums ir jāiestata auto_commit uz true savā konfigurācijā. Tas automātiski apstiprinās jūsu sesijas datus pēc katra pieprasījuma.

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

Turklāt jūs varētu izdarīt Flight::after('start', function() { Flight::session()->commit(); });, lai apstiprinātu savus sesijas datus pēc katra pieprasījuma.

Dokumentācija

Apmeklējiet Github Readme pilnai dokumentācijai. Konfigurācijas opcijas ir labi dokumentētas noklusējuma_config.php failā pašā. Kods ir vienkārši saprotams, ja jūs gribētu to izpētīt pats.

Awesome-plugins/async

Async

Async ir mazs pakotnes Flight ietvaram, kas ļauj palaist jūsu Flight lietotnes asinhronos serveros un vidēs, piemēram, Swoole, AdapterMan, ReactPHP, Amp, RoadRunner, Workerman utt. No kastes tas ietver adapterus Swoole un AdapterMan.

Mērķis: izstrādāt un atkļūdot ar PHP-FPM (vai iebūvēto serveri) un pārslēgties uz Swoole (vai citu asinhrono draiveri) ražošanā ar minimālām izmaiņām.

Prasības

Instalēšana

Instalējiet caur composer:

composer require flightphp/async

Ja plānojat palaist ar Swoole, instalējiet paplašinājumu:

# izmantojot pecl
pecl install swoole
# vai openswoole
pecl install openswoole

# vai ar pakotņu pārvaldnieku (Debian/Ubuntu piemērs)
sudo apt-get install php-swoole

Ātrs Swoole piemērs

Zemāk ir minimāla iestatīšana, kas parāda, kā atbalstīt gan PHP-FPM (vai iebūvēto serveri), gan Swoole, izmantojot to pašu koda bāzi.

Faili, kas būs nepieciešami jūsu projektā:

index.php

Šis fails ir vienkāršs slēdzis, kas piespiež lietotni palaist PHP režīmā izstrādei.

// index.php
<?php

define('NOT_SWOOLE', true);

include 'swoole_server.php';

swoole_server.php

Šis fails inicializē jūsu Flight lietotni un sāks Swoole draiveri, kad NOT_SWOOLE nav definēts.

// swoole_server.php
<?php

require_once __DIR__ . '/vendor/autoload.php';

$app = Flight::app();

$app->route('/', function() use ($app) {
    $app->json(['hello' => 'world']);
});

if (!defined('NOT_SWOOLE')) {
    // Nepieciešams SwooleServerDriver klase, kad darbojas Swoole režīmā.
    require_once __DIR__ . '/SwooleServerDriver.php';

    Swoole\Runtime::enableCoroutine();
    $Swoole_Server = new SwooleServerDriver('127.0.0.1', 9501, $app);
    $Swoole_Server->start();
} else {
    $app->start();
}

SwooleServerDriver.php

Īss draiveris, kas parāda, kā savienot Swoole pieprasījumus ar Flight, izmantojot AsyncBridge un Swoole adapterus.

// SwooleServerDriver.php
<?php

use flight\adapter\SwooleAsyncRequest;
use flight\adapter\SwooleAsyncResponse;
use flight\AsyncBridge;
use flight\Engine;
use Swoole\HTTP\Server as SwooleServer;
use Swoole\HTTP\Request as SwooleRequest;
use Swoole\HTTP\Response as SwooleResponse;

class SwooleServerDriver {
    protected $Swoole;
    protected $app;

    public function __construct(string $host, int $port, Engine $app) {
        $this->Swoole = new SwooleServer($host, $port);
        $this->app = $app;

        $this->setDefault();
        $this->bindWorkerEvents();
        $this->bindHttpEvent();
    }

    protected function setDefault() {
        $this->Swoole->set([
            'daemonize'             => false,
            'dispatch_mode'         => 1,
            'max_request'           => 8000,
            'open_tcp_nodelay'      => true,
            'reload_async'          => true,
            'max_wait_time'         => 60,
            'enable_reuse_port'     => true,
            'enable_coroutine'      => true,
            'http_compression'      => false,
            'enable_static_handler' => true,
            'document_root'         => __DIR__,
            'static_handler_locations' => ['/css', '/js', '/images', '/.well-known'],
            'buffer_output_size'    => 4 * 1024 * 1024,
            'worker_num'            => 4,
        ]);

        $app = $this->app;
        $app->map('stop', function (?int $code = null) use ($app) {
            if ($code !== null) {
                $app->response()->status($code);
            }
        });
    }

    protected function bindHttpEvent() {
        $app = $this->app;
        $AsyncBridge = new AsyncBridge($app);

        $this->Swoole->on('Start', function(SwooleServer $server) {
            echo "Swoole http server is started at http://127.0.0.1:9501\n";
        });

        $this->Swoole->on('Request', function (SwooleRequest $request, SwooleResponse $response) use ($AsyncBridge) {
            $SwooleAsyncRequest = new SwooleAsyncRequest($request);
            $SwooleAsyncResponse = new SwooleAsyncResponse($response);

            $AsyncBridge->processRequest($SwooleAsyncRequest, $SwooleAsyncResponse);

            $response->end();
            gc_collect_cycles();
        });
    }

    protected function bindWorkerEvents() {
        $createPools = function() {
            // izveidojiet darbinieka specifiskas savienojumu kopas šeit
        };
        $closePools = function() {
            // aizveriet kopas / tīriet šeit
        };
        $this->Swoole->on('WorkerStart', $createPools);
        $this->Swoole->on('WorkerStop', $closePools);
        $this->Swoole->on('WorkerError', $closePools);
    }

    public function start() {
        $this->Swoole->start();
    }
}

Servera palaišana

Padoms: Ražošanā izmantojiet reverso proxy (Nginx) Swoole priekšā, lai apstrādātu TLS, statiskos failus un slodzes līdzsvarošanu.

Konfigurācijas piezīmes

Swoole draiveris piedāvā vairākas konfigurācijas opcijas:

Pielāgojiet šos, lai atbilstu jūsu resursiem un trafika modeļiem.

Kļūdu apstrāde

AsyncBridge pārvērš Flight kļūdas pareizās HTTP atbildēs. Jūs varat arī pievienot maršruta līmeņa kļūdu apstrādi:

$app->route('/*', function() use ($app) {
    try {
        // maršruta loģika
    } catch (Exception $e) {
        $app->response()->status(500);
        $app->json(['error' => $e->getMessage()]);
    }
});

AdapterMan un citas vidēs

AdapterMan tiek atbalstīts kā alternatīvs vidēs adapteris. Pakotne ir paredzēta pielāgošanai — pievienošana vai izmantošana citu adapteru parasti seko tam pašam modelim: pārveido servera pieprasījumu/atbildi par Flight pieprasījumu/atbildi caur AsyncBridge un vidēs specifiskajiem adapteriem.

Awesome-plugins/migrations

Migrācijas

Migrācija jūsu projektam uzrauga visus datu bāzes izmaiņas, kas saistītas ar jūsu projektu.
byjg/php-migration ir ļoti noderīga kodola bibliotēka, lai jūs varētu sākt.

Instalēšana

PHP bibliotēka

Ja vēlaties izmantot tikai PHP bibliotēku savā projektā:

composer require "byjg/migration"

Komandrindas interfeiss

Komandrindas interfeiss ir patstāvīgs un neprasa to instalēt kopā ar jūsu projektu.

Jūs varat instalēt globāli un izveidot simbolisko saiti.

composer require "byjg/migration-cli"

Lūdzu, apmeklējiet byjg/migration-cli, lai iegūtu vairāk informācijas par Migrācijas CLI.

Atbalstītās datu bāzes

Datu bāze Dzinējs Savienojuma virkne
Sqlite pdo_sqlite sqlite:///path/to/file
MySql/MariaDb pdo_mysql mysql://lietotāja_vārds:parole@hostname:ports/datu_bāze
Postgres pdo_pgsql pgsql://lietotāja_vārds:parole@hostname:ports/datu_bāze
Sql Server pdo_dblib, pdo_sysbase Linux dblib://lietotāja_vārds:parole@hostname:ports/datu_bāze
Sql Server pdo_sqlsrv Windows sqlsrv://lietotāja_vārds:parole@hostname:ports/datu_bāze

Kā tas darbojas?

Datu bāzes migrācija izmanto TĪRU SQL, lai pārvaldītu datu bāzes versijas.
Lai tas darbotos, jums nepieciešams:

SQL skripti

Skripti ir sadalīti trīs skriptu grupās:

Skriptu direktorija ir:

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

Multi izstrādes vide

Ja strādājat ar vairākiem izstrādātājiem un vairākiem zara, ir grūti noteikt nākamo numuru.

Šajā gadījumā jums ir papildinājums "-dev" pēc versijas numura.

Skatiet scenāriju:

Abos gadījumos izstrādātāji izveidos failu ar nosaukumu 43-dev.sql. Abi izstrādātāji pārskatīs UP un DOWN bez problēmām, un jūsu lokālā versija būs 43.

Bet izstrādātājs 1 apvieno jūsu izmaiņas un izveido gala versiju 43.sql (git mv 43-dev.sql 43.sql). Ja izstrādātājs 2 atjauninās jūsu vietējo zaru, viņam būs fails 43.sql (no izstrādātāja 1) un jūsu fails 43-dev.sql.
Ja viņš mēģina migrēt UP vai DOWN, migrācijas skripts uzrakstīs un brīdinās viņu, ka ir DIVAS versijas 43. Šajā gadījumā izstrādātājam 2 būs jāatjaunina jūsu fails uz 44-dev.sql un jāturpina strādāt līdz apvienojat jūsu izmaiņas un ģenerējat gala versiju.

PHP API izmantošana un integrēšana savos projektos

Pamatlietošana ir

Skatiet piemēru:

<?php
// Izveidojiet savienojuma URI
// Skatiet vairāk: https://github.com/byjg/anydataset#connection-based-on-uri
$connectionUri = new \ByJG\Util\Uri('mysql://migrateuser:migratepwd@localhost/migratedatabase');

// Reģistrējiet datu bāzi vai datu bāzes, kas var apstrādāt šo URI:
\ByJG\DbMigration\Migration::registerDatabase(\ByJG\DbMigration\Database\MySqlDatabase::class);

// Izveidojiet migrācijas instance
$migration = new \ByJG\DbMigration\Migration($connectionUri, '.');

// Pievienojiet atgriezenisko saiti progresam, lai saņemtu informāciju par izpildi
$migration->addCallbackProgress(function ($action, $currentVersion, $fileInfo) {
    echo "$action, $currentVersion, ${fileInfo['description']}\n";
});

// Atjaunojiet datu bāzi, izmantojot "base.sql" skriptu
// un palaidiet VISUS esošos skriptus, lai paaugstinātu datu bāzes versiju līdz jaunākajai versijai
$migration->reset();

// Palaidiet VISUS esošos skriptus, lai paaugstinātu vai samazinātu datu bāzes versiju
// no pašreizējās versijas līdz $version numuram;
// Ja versijas numurs nav noteikts, migrējiet līdz pēdējai datu bāzes versijai
$migration->update($version = null);

Migrācijas objekts kontrolē datu bāzes versiju.

Izstrādājot versiju kontroli savā projektā

<?php
// Reģistrējiet datu bāzi vai datu bāzes, kas var apstrādāt šo URI:
\ByJG\DbMigration\Migration::registerDatabase(\ByJG\DbMigration\Database\MySqlDatabase::class);

// Izveidojiet migrācijas instance
$migration = new \ByJG\DbMigration\Migration($connectionUri, '.');

// Šī komanda izveidos versijas tabulu jūsu datu bāzē
$migration->createVersion();

Iegūstot pašreizējo versiju

<?php
$migration->getCurrentVersion();

Pievienojiet atgriezenisko saiti, lai kontrolētu progresu

<?php
$migration->addCallbackProgress(function ($command, $version, $fileInfo) {
    echo "Veicot komandu: $command pie versijas $version - ${fileInfo['description']}, ${fileInfo['exists']}, ${fileInfo['file']}, ${fileInfo['checksum']}\n";
});

Iegūstot Db Dzinēja instanci

<?php
$migration->getDbDriver();

Lai to izmantotu, lūdzu, apmeklējiet: https://github.com/byjg/anydataset-db

Daļēju migrāciju novēršana (nav pieejama MySQL)

Daļēja migrācija ir tad, ja migrācijas skripts tiek pārtraukts procesa vidū kļūdas vai manuālas pārtraukšanas dēļ.

Migrācijas tabula būs ar statusu daļējs uz augšu vai daļējs uz leju, un to nepieciešams labot manuāli, pirms var atkārtoti migrēt.

Lai izvairītos no šīs situācijas, jūs varat norādīt, ka migrācija tiks izpildīta transakcijas kontekstā.
Ja migrācijas skripts neizdodas, transakcija tiks atcelta, un migrācijas tabula tiks iezīmēta kā pabeigta, un versija būs tūlītēji iepriekšējā versija pirms skripta, kas izraisīja kļūdu.

Lai šo funkciju aktivizētu, jums jāizsauc metode withTransactionEnabled, nododot true kā parametru:

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

PIEZĪME: Šī funkcija nav pieejama MySQL, jo tas neatbalsta DDL komandas transakcijas ietvaros.
Ja jūs izmantosiet šo metodi ar MySQL, migrācija to klusi ignorēs.
Vairāk informācijas: https://dev.mysql.com/doc/refman/8.0/en/cannot-roll-back.html

Ieteikumi SQL migrāciju rakstīšanai Postgres

Par trigeru un SQL funkciju izveidi

-- DARI
CREATE FUNCTION emp_stamp() RETURNS trigger AS $emp_stamp$
    BEGIN
        -- Pārbaudiet, vai ir norādīts empname un alga
        IF NEW.empname IS NULL THEN
            RAISE EXCEPTION 'empname nedrīkst būt null'; -- nav svarīgi, vai šie komentāri ir tukši vai nē
        END IF; --

        IF NEW.salary IS NULL THEN
            RAISE EXCEPTION '% nedrīkst būt null alga', NEW.empname; --
        END IF; --

        -- Kas strādā pie mums, kad viņiem par to jāmaksā?
        IF NEW.salary < 0 THEN
            RAISE EXCEPTION '% nedrīkst būt negatīva alga', NEW.empname; --
        END IF; --

        -- Atcerieties, kurš izmainīja algu, kad
        NEW.last_date := current_timestamp; --
        NEW.last_user := current_user; --
        RETURN NEW; --
    END; --
$emp_stamp$ LANGUAGE plpgsql;

-- NEDARI
CREATE FUNCTION emp_stamp() RETURNS trigger AS $emp_stamp$
    BEGIN
        -- Pārbaudiet, vai ir norādīts empname un alga
        IF NEW.empname IS NULL THEN
            RAISE EXCEPTION 'empname nedrīkst būt null';
        END IF;
        IF NEW.salary IS NULL THEN
            RAISE EXCEPTION '% nedrīkst būt null alga', NEW.empname;
        END IF;

        -- Kas strādā pie mums, kad viņiem par to jāmaksā?
        IF NEW.salary < 0 THEN
            RAISE EXCEPTION '% nedrīkst būt negatīva alga', NEW.empname;
        END IF;

        -- Atcerieties, kurš izmainīja algu, kad
        NEW.last_date := current_timestamp;
        NEW.last_user := current_user;
        RETURN NEW;
    END;
$emp_stamp$ LANGUAGE plpgsql;

Tā kā PDO datu bāzes abstrakcijas slānis nevar izpildīt SQL komandu partijas, kad byjg/migration lasa migrācijas failu, tas ir jāizdala visus SQL faila saturus pie semikolu un jāizpilda komandas viena pa viena.
Tomēr ir viens veids, kā komanda var saturēt vairākas semikolas tās ķermenī: funkcijas.

Lai pareizi analizētu funkcijas, byjg/migration 2.1.0 sāka sadalīt migrācijas failus pēc semikola + EOL secības, nevis tikai pēc semikolas.
Šādā veidā, ja jūs pievienojat tukšu komentāru pēc katra iekšējā semikola funkcijas definīcijā, byjg/migration to varēs pareizi analizēt.

Diemžēl, ja jūs aizmirsīsiet pievienot kādu no šiem komentāriem, bibliotēka sadalīs CREATE FUNCTION paziņojumu multiple parts, un migrācija neizdosies.

Izvairieties no kolonnas rakstzīmes (:)

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

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

Tā kā PDO izmanto kolonnas rakstzīmi, lai prefixētu nosauktos parametrus sagatavotās komandas, tās izmantošana izraisa to, ka tas aptrūkst citos kontekstos.

Piemēram, PostgreSQL komandas var izmantot ::, lai konvertētu vērtības starp tipiem.
No otras puses, PDO to uztvers kā nederīgu nosauktu parametru nederīgā kontekstā un neizdosies, kad tas mēģinās to izpildīt.

Vienīgā veida, kā izlabot šo neatbilstību, ir pilnībā izvairīties no kolonnām (šajā gadījumā PostgreSQL ir alternatīva sintakse: CAST(value AS type)).

Izmantojiet SQL redaktoru

Visbeidzot, manuālas SQL migrāciju rakstīšana var būt nogurdinoša, taču to ir ievērojami vieglāk izdarīt, ja izmantojat redaktoru, kas spēj saprast SQL sintaksi, piedāvā pabeigšanu, introspektē jūsu pašreizējo datu bāzes shēmu un / vai automātiski formatē jūsu kodu.

Dažādu migrāciju apstrāde vienā shēmā

Ja jums ir jāizveido dažādi migrācijas skripti un versijas vienā shēmā, tas ir iespējams, bet tas ir ļoti riskanti un es neieteiktu to darīt.

Lai to izdarītu, jums jāizveido dažādas "migrācijas tabulas", nododot parametru konstruktora parametrā.

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

Drošības apsvērumu dēļ šī funkcija nav pieejama komandrindā, bet jūs varat izmantot vides mainīgo MIGRATION_VERSION, lai glabātu nosaukumu.

Mēs patiešām iesakām neizmantot šo funkciju. Ieteikums ir viena migrācija vienai shēmā.

Vienības testu izpilde

Pamatvienības testus var izpildīt ar:

vendor/bin/phpunit

Datu bāzu testu izpilde

Lai veiktu integrācijas testus, jums jābūt datu bāzēm, kas darbojas. Mēs esam nodrošinājuši pamata docker-compose.yml, un jūs varat to izmantot, lai uzsāktu datu bāzes testēšanai.

Datu bāzu palaidīšana

docker-compose up -d postgres mysql mssql

Testu izpilde

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*

Pēc izvēles jūs varat iestatīt resursdatora un paroles iestatījumus, ko izmanto vienības testos.

export MYSQL_TEST_HOST=localhost     # noklusējums uz localhost
export MYSQL_PASSWORD=newpassword    # izmantojiet '.', ja vēlaties nulles paroli
export PSQL_TEST_HOST=localhost      # noklusējums uz localhost
export PSQL_PASSWORD=newpassword     # izmantojiet '.', ja vēlaties nulles paroli
export MSSQL_TEST_HOST=localhost     # noklusējums uz localhost
export MSSQL_PASSWORD=Pa55word
export SQLITE_TEST_HOST=/tmp/test.db      # noklusējums uz /tmp/test.db

Awesome-plugins/session

FlightPHP Sesija - Viegls failu balstīts sesijas pārvaldnieks

Tas ir viegls, failu balstīts sesijas pārvaldnieka spraudnis Flight PHP Framework. Tas nodrošina vienkāršu, bet spēcīgu risinājumu sesiju pārvaldībai, ar iespējām kā nesekojošas sesijas lasīšanas, izvēles šifrēšanu, automātisku apstiprināšanu un testēšanas režīmu attīstībai. Sesijas dati tiek glabāti failos, padarot to ideālu lietojumprogrammām, kurām nav nepieciešama datubāze.

Ja vēlaties izmantot datubāzi, pārbaudiet ghostff/session spraudni, kas satur daudzas no šīm pašām iespējām, bet ar datubāzes aizmuguri.

Apmeklējiet Github repozitoriju pilnam avota kodam un detaļām.

Instalēšana

Instalējiet spraudni caur Composer:

composer require flightphp/session

Pamata lietošana

Lūk, vienkāršs piemērs, kā izmantot flightphp/session spraudni jūsu Flight lietojumprogrammā:

require 'vendor/autoload.php';

use flight\Session;

$app = Flight::app();

// Reģistrē sesijas servisu
$app->register('session', Session::class);

// Piemērs maršrutam ar sesijas lietošanu
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'); // Izvada: johndoe
    echo $session->get('preferences', 'default_theme'); // Izvada: default_theme

    if ($session->get('user_id')) {
        Flight::json(['message' => 'Lietotājs ir pieteicies!', 'user_id' => $session->get('user_id')]);
    }
});

Flight::route('/logout', function() {
    $session = Flight::session();
    $session->clear(); // Notīra visas sesijas datus
    Flight::json(['message' => 'Izlogojies veiksmīgi']);
});

Flight::start();

Galvenie punkti

Konfigurācija

Jūs varat pielāgot sesijas pārvaldnieku, nododot masīvu ar opcijām reģistrējot:

// Jā, tas ir dubults masīvs :)
$app->register('session', Session::class, [ [
    'save_path' => '/custom/path/to/sessions',         // Direktorija sesijas failiem
    'prefix' => 'myapp_',                              // Priekša sesijas failiem
    'encryption_key' => 'a-secure-32-byte-key-here',   // Ieslēgt šifrēšanu (32 baiti ieteikti AES-256-CBC)
    'auto_commit' => false,                            // Atslēgt automātisko apstiprināšanu manuālai kontrolei
    'start_session' => true,                           // Sākt sesiju automātiski (pēc noklusējuma: true)
    'test_mode' => false,                              // Ieslēgt testēšanas režīmu attīstībai
    'serialization' => 'json',                         // Serializācijas metode: 'json' (pēc noklusējuma) vai 'php' (legacy)
] ]);

Konfigurācijas opcijas

Opcija Apraksts Noklusētā vērtība
save_path Direktorija, kur glabājas sesijas faili sys_get_temp_dir() . '/flight_sessions'
prefix Priekša saglabātajam sesijas failam sess_
encryption_key Atslēga AES-256-CBC šifrēšanai (izvēles) null (bez šifrēšanas)
auto_commit Automātiski saglabāt sesijas datus izslēgšanās brīdī true
start_session Sākt sesiju automātiski true
test_mode Darboties testēšanas režīmā bez ietekmēšanas uz PHP sesijām false
test_session_id Pielāgota sesijas ID testēšanas režīmam (izvēles) Nejauši ģenerēta, ja nav iestatīta
serialization Serializācijas metode: 'json' (pēc noklusējuma, droša) vai 'php' (legacy, atļauj objektus) 'json'

Serializācijas režīmi

Pēc noklusējuma šī bibliotēka izmanto JSON serializāciju sesijas datiem, kas ir droša un novērš PHP objektu iesūkšanās ievainojamības. Ja jums ir nepieciešams glabāt PHP objektus sesijā (nav ieteicams lielākumam app), jūs varat izvēlēties legacy PHP serializāciju:

Piezīme: Ja izmantojat JSON serializāciju, mēģinot glabāt objektu, tiks izraisīta izņēmuma kļūda.

Paplašināta lietošana

Manuāla apstiprināšana

Ja atslēdzat automātisko apstiprināšanu, jums ir manuāli jāapstiprina izmaiņas:

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

Flight::route('/update', function() {
    $session = Flight::session();
    $session->set('key', 'value');
    $session->commit(); // Skaidri saglabā izmaiņas
});

Sesijas drošība ar šifrēšanu

Ieslēdziet šifrēšanu sensitīviem datiem:

$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'); // Šifrēts automātiski
    echo $session->get('credit_card'); // Dekodēts pie saņemšanas
});

Sesijas atjaunošana

Atjaunojiet sesijas ID drošībai (piemēram, pēc pieteikšanās):

Flight::route('/post-login', function() {
    $session = Flight::session();
    $session->regenerate(); // Jauns ID, saglabā datus
    // VAI
    $session->regenerate(true); // Jauns ID, dzēš vecos datus
});

Middleware piemērs

Aizsargājiet maršrutus ar sesijas balstītu autentifikāciju:

Flight::route('/admin', function() {
    Flight::json(['message' => 'Laipni lūgts admin panelī']);
})->addMiddleware(function() {
    $session = Flight::session();
    if (!$session->get('is_admin')) {
        Flight::halt(403, 'Piekļuve liegta');
    }
});

Tas ir tikai vienkāršs piemērs, kā to izmantot middleware. Vairāk detalizētam piemēram, skatiet middleware dokumentāciju.

Metodes

Session klase nodrošina šādas metodes:

Visas metodes izņemot get() un id() atgriež Session instanci ķēdes izveidošanai.

Kāpēc izmantot šo spraudni?

Tehniskās detaļas

Dalība

Ieteikumi ir laipni gaidīti! Forkojiet repozitoriju, veiciet izmaiņas un iesniedziet pull request. Ziņojiet par kļūdām vai ieteikumiām caur Github issue tracker.

Licence

Šis spraudnis ir licencēts zem MIT Licence. Skatiet Github repozitoriju detaļām.

Awesome-plugins/runway

Lidmašīnas

Lidmašīnas ir CLI lietotne, kas palīdz pārvaldīt jūsu Flight lietojumprogrammas. Tā var ģenerēt kontrolierus, parādīt visus maršrutus un vairāk. Tā balstīta uz lielisko adhocore/php-cli bibliotēku.

Uzklikšķiniet šeit, lai skatītu kodu.

Instalēšana

Instalējiet to ar komponistu.

composer require flightphp/runway

Pamata konfigurācija

Pirmo reizi palaižot Lidmašīnas, tā vadīs jūs caur iestatīšanas procesu un izveidos .runway.json konfigurācijas failu jūsu projekta saknē. Šajā failā būs dažas nepieciešamās konfigurācijas, lai Lidmašīnas pareizi darbotos.

Lietojums

Lidmašīnā ir vairākas komandas, ar kurām varat pārvaldīt savu Flight lietojumprogrammu. Ir divi viegli veidi, kā izmantot Lidmašīnas.

  1. Ja izmantojat ietvaru projektu, varat izpildīt php runway [komanda] no savu projekta saknes.
  2. Ja izmantojat Lidmašīnas kā paketi, kas instalēts ar komponistu, varat izpildīt vendor/bin/runway [komanda] no savu projekta saknes.

Lai iegūtu papildinformāciju par jebkuru komandu, jūs varat padot --help karodziņa.

php runway routes --help

Šeit ir daži piemēri:

Ģenerēt kontrolieri

Balstoties uz konfigurāciju jūsu .runway.json failā, noklusējuma atrašanās vieta jums ģenerēs kontrolieri app/controllers/ direktorijā.

php runway make:controller MyController

Ģenerēt aktīvās ierakstu modeles

Balstoties uz konfigurāciju jūsu .runway.json failā, noklusējuma atrašanās vieta jums ģenerēs kontrolieri app/records/ direktorijā.

php runway make:record users

Ja, piemēram, ir users tabula ar sekojošu shēmu: id, name, email, created_at, updated_at, fails līdzīgs sekojošajam tiks izveidots app/records/UserRecord.php failā:

<?php

declare(strict_types=1);

namespace app\records;

/**
 * ActiveRecord klase lietotāju tabulai.
 * @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
 * // šeit jūs varat pievienot attiecības, kad tās definētas $relations masīvā
 * @property CompanyRecord $company Attēlots attiecību piemērs
 */
class UserRecord extends \flight\ActiveRecord
{
    /**
     * @var array $relations Uzstādiet attiecības modeļim
     *   https://docs.flightphp.com/awesome-plugins/active-record#relationships
     */
    protected array $relations = [];

    /**
     * Konstruktors
     * @param mixed $databaseConnection Datu bāzes savienojums
     */
    public function __construct($databaseConnection)
    {
        parent::__construct($databaseConnection, 'users');
    }
}

Parādīt visus maršrutus

Tas parādīs visus maršrutus, kas pašlaik ir reģistrēti ar Flight.

php runway routes

Ja vēlaties skatīt tikai konkrētus maršrutus, jūs varat padot karodziņu, lai filtrētu maršrutus.

# Parādīt tikai GET maršrutus
php runway routes --get

# Parādīt tikai POST maršrutus
php runway routes --post

# u.c.

Lidmašīnas pielāgošana

Ja jūs izveidojat paketi Flight, vai vēlaties pievienot savas pielāgotas komandas savā projektā, to varat izdarīt, izveidojot src/commands/, flight/commands/, app/commands/ vai commands/ direktoriju savam projektam/paketei.

Lai izveidotu komandu, jums vienkārši jāpaplašina AbstractBaseCommand klase un jāimplementē vismaz __construct metode un execute metode.

<?php

declare(strict_types=1);

namespace flight\commands;

class ExampleCommand extends AbstractBaseCommand
{
    /**
     * Konstruktors
     *
     * @param array<string,mixed> $config JSON konfigurācija no .runway-config.json
     */
    public function __construct(array $config)
    {
        parent::__construct('make:example', 'Izveidot piemēru dokumentācijai', $config);
        $this->argument('<funny-gif>', 'Smaida GIF nosaukums');
    }

    /**
     * Izpilda funkciju
     *
     * @return void
     */
    public function execute(string $controller)
    {
        $io = $this->app()->io();

        $io->info('Izveido piemēru...');

        // Kaut ko dariet šeit

        $io->ok('Piemērs izveidots!');
    }
}

Skatiet adhocore/php-cli Dokumentāciju, lai iegūtu vairāk informācijas par to, kā izveidot savas pielāgotas komandas savā Flight lietojumprogrammā!

Awesome-plugins/tracy_extensions

Tracy Flight Panel Extensions

Šis ir paplašinājumu kopums, lai darbs ar Flight būtu nedaudz bagātāks.

Šis ir Panelis

Flight Bar

Un katrs panelis parāda ļoti noderīgu informāciju par jūsu lietojumprogrammu!

Flight Data Flight Database Flight Request

Noklikšķiniet šeit, lai skatītu kodu.

Installation

Izpildiet composer require flightphp/tracy-extensions --dev, un jūs esat ceļā!

Configuration

Ir ļoti maz konfigurācijas, kas jums jāveic, lai to sāktu. Jums būs jāinicializē Tracy atkļūdotājs pirms šī izmantošanas https://tracy.nette.org/en/guide:

<?php

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

// bootstrap code
require __DIR__ . '/vendor/autoload.php';

Debugger::enable();
// Jums var būt jānorāda jūsu vide ar Debugger::enable(Debugger::DEVELOPMENT)

// ja jūs izmantojat datubāzes savienojumus savā lietojumprogrammā, ir nepieciešams PDO apvalks, ko izmantot TIKAI ATTĪSTĪBAS VIDĒ (nevis ražošanā, lūdzu!)
// Tam ir tie paši parametri kā regulāram PDO savienojumam
$pdo = new PdoQueryCapture('sqlite:test.db', 'user', 'pass');
// vai arī, ja jūs pievienojat to Flight framework
Flight::register('db', PdoQueryCapture::class, ['sqlite:test.db', 'user', 'pass']);
// tagad, kad vienreiz izpildīsiet vaicājumu, tas uztvers laiku, vaicājumu un parametrus

// Šis savieno punktus
if(Debugger::$showBar === true) {
    // Šim jābūt false, vai Tracy nevarēs faktiski renderēt :(
    Flight::set('flight.content_length', false);
    new TracyExtensionLoader(Flight::app());
}

// vairāk koda

Flight::start();

Additional Configuration

Session Data

Ja jums ir pielāgots sesijas apstrādātājs (piemēram, ghostff/session), jūs varat nodot jebkuru sesijas datu masīvu Tracy, un tas automātiski izvadīs to jums. Jūs to nododiet ar session_data atslēgu otrajā parametru no TracyExtensionLoader konstruktora.


use Ghostff\Session\Session;
// vai izmantojiet flight\Session;

require 'vendor/autoload.php';

$app = Flight::app();

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

if(Debugger::$showBar === true) {
    // Šim jābūt false, vai Tracy nevarēs faktiski renderēt :(
    Flight::set('flight.content_length', false);
    new TracyExtensionLoader(Flight::app(), [ 'session_data' => Flight::session()->getAll() ]);
}

// maršruti un citas lietas...

Flight::start();

Latte

PHP 8.1+ ir nepieciešams šai sadaļai.

Ja jums ir Latte instalēts jūsu projektā, Tracy ir iebūvēta integrācija ar Latte, lai analizētu jūsu veidnes. Jūs vienkārši reģistrējat paplašinājumu ar jūsu Latte instanci.


require 'vendor/autoload.php';

$app = Flight::app();

$app->map('render', function($template, $data, $block = null) {
    $latte = new Latte\Engine;

    // citas konfigurācijas...

    // pievienojiet paplašinājumu tikai tad, ja Tracy Debug Bar ir iespējots
    if(Debugger::$showBar === true) {
        // šeit jūs pievienojat Latte Paneli Tracy
        $latte->addExtension(new Latte\Bridges\Tracy\TracyExtension);
    }

    $latte->render($template, $data, $block);
});

Awesome-plugins/apm

FlightPHP APM Dokumentācija

Laipni lūdzam FlightPHP APM — jūsu lietojumprogrammas personīgais veiktspējas treneris! Šis ceļvedis ir jūsu ceļakarte, lai iestatītu, izmantotu un apgūtu Lietojumprogrammas veiktspējas uzraudzību (APM) ar FlightPHP. Vai nu jūs meklējat lēnus pieprasījumus, vai vienkārši vēlaties iedziļināties latentuma diagrammās, mēs jums palīdzēsim. Padarīsim jūsu lietojumprogrammu ātrāku, jūsu lietotājus laimīgākus un jūsu atkļūdošanas sesijas vieglas!

Apskatiet demo Flight Docs vietnes panelim.

FlightPHP APM

Kāpēc APM ir svarīga

Iedomājieties: jūsu lietojumprogramma ir aizņemta restorāns. Bez veida, kā izsekot, cik ilgi aizņem pasūtījumi vai kur virtuvē rodas aizkavēšanās, jūs minaties, kāpēc klienti aiziet neapmierināti. APM ir jūsu pavāra palīgs — tas uzrauga katru soli, no ienākošajiem pieprasījumiem līdz datubāzes vaicājumiem, un atzīmē visu, kas jūs palēnina. Lēnas lapas zaudē lietotājus (pētījumi saka, ka 53% aiziet, ja vietne ielādējas vairāk nekā 3 sekundes!), un APM palīdz jums noķert šīs problēmas pirms tās sadod. Tas ir proaktīvs mierinājums — mazāk “kāpēc tas ir salūzis?” brīžu, vairāk “paskatieties, cik gludi tas darbojas!” uzvaru.

Instalācija

Sāciet ar Composer:

composer require flightphp/apm

Jums būs nepieciešams:

Atbalstītās datubāzes

FlightPHP APM pašlaik atbalsta šādas datubāzes metriku uzglabāšanai:

Jūs varat izvēlēties datubāzes tipu konfigurācijas solī (skatiet zemāk). Pārliecinieties, ka jūsu PHP videi ir instalētas nepieciešamās paplašinājumi (piem., pdo_sqlite vai pdo_mysql).

Sākšana

Šeit ir jūsu soli pa solim ceļš uz APM lieliskumu:

1. Reģistrējiet APM

Ievietojiet to savā index.php vai services.php failā, lai sāktu izsekošanu:

use flight\apm\logger\LoggerFactory;
use flight\Apm;

$ApmLogger = LoggerFactory::create(__DIR__ . '/../../.runway-config.json');
$Apm = new Apm($ApmLogger);
$Apm->bindEventsToFlightInstance($app);

// Ja pievienojat datubāzes savienojumu
// Jābūt PdoWrapper vai PdoQueryCapture no Tracy Extensions
$pdo = new PdoWrapper('mysql:host=localhost;dbname=example', 'user', 'pass', null, true); // <-- True nepieciešams, lai iespējotu izsekošanu APM.
$Apm->addPdoConnection($pdo);

Kas šeit notiek?

Pro Padoms: Paraugšana Ja jūsu lietojumprogramma ir aizņemta, žurnālošana katra pieprasījuma var pārslodzes. Izmantojiet paraugu (0.0 līdz 1.0):

$Apm = new Apm($ApmLogger, 0.1); // Žurnālo 10% pieprasījumu

Tas saglabā veiktspēju ātru, vienlaikus dodot jums stingrus datus.

2. Konfigurējiet to

Palaidiet šo, lai izveidotu jūsu .runway-config.json:

php vendor/bin/runway apm:init

Ko tas dara?

Šis process arī jautās, vai vēlaties palaist migrācijas šim iestatījumam. Ja iestatāt to pirmo reizi, atbilde ir jā.

Kāpēc divas vietas? Neapstrādātās metrikas uzkrājas ātri (domājiet nefiltrētus žurnālus). Darbinieks tās apstrādā strukturētā mērķī panelim. Saglabā visu kārtīgu!

3. Apstrādājiet metrikas ar darbinieku

Darbinieks pārvērš neapstrādātās metrikas datus, kas gatavi panelim. Palaidiet to vienreiz:

php vendor/bin/runway apm:worker

Ko tas dara?

Uzturiet to darbojošos Dzīvām lietojumprogrammām vēlaties nepārtrauktu apstrādi. Šeit ir jūsu opcijas:

Kāpēc censties? Bez darbinieka jūsu panelis ir tukšs. Tas ir tilts starp neapstrādātiem žurnāliem un izmantojamiem ieskatiem.

4. Palaidiet paneli

Redziet jūsu lietojumprogrammas vitālos rādītājus:

php vendor/bin/runway apm:dashboard

Kas tas ir?

Pielāgojiet to:

php vendor/bin/runway apm:dashboard --host 0.0.0.0 --port 8080 --php-path=/usr/local/bin/php

Atveriet URL savā pārlūkprogrammā un izpētiet!

Produkcijas režīms

Produkcijā jums var nākties izmēģināt dažas tehnikas, lai panelis darbotos, jo droši vien ir ugunsmūri un citas drošības pasākumi. Šeit ir dažas opcijas:

Vai vēlaties citu paneli?

Jūs varat izveidot savu paneli, ja vēlaties! Apskatiet vendor/flightphp/apm/src/apm/presenter direktoriju idejām, kā prezentēt datus savam panelim!

Panaļa funkcijas

Panels ir jūsu APM galvenā mītne — šeit ir, ko redzēsiet:

Ekstras:

Piemērs: Pieprasījums uz /users var rādīt:

Pievienošana pielāgotu notikumu

Izsekot jebko — piemēram, API zvanu vai maksājumu procesu:

use flight\apm\CustomEvent;

$app->eventDispatcher()->trigger('apm.custom', new CustomEvent('api_call', [
    'endpoint' => 'https://api.example.com/users',
    'response_time' => 0.25,
    'status' => 200
]));

Kur tas parādās? Panelī pieprasījuma detaļās zem “Pielāgoti notikumi” — paplašināms ar skaistu JSON formatējumu.

Lietošanas gadījums:

$start = microtime(true);
$apiResponse = file_get_contents('https://api.example.com/data');
$app->eventDispatcher()->trigger('apm.custom', new CustomEvent('external_api', [
    'url' => 'https://api.example.com/data',
    'time' => microtime(true) - $start,
    'success' => $apiResponse !== false
]));

Tagad redzēsiet, vai tas API velk jūsu lietojumprogrammu lejup!

Datubāzes uzraudzība

Izsekot PDO vaicājumus šādi:

use flight\database\PdoWrapper;

$pdo = new PdoWrapper('sqlite:/path/to/db.sqlite', null, null, null, true); // <-- True nepieciešams, lai iespējotu izsekošanu APM.
$Apm->addPdoConnection($pdo);

Ko jūs iegūstat:

Brīdinājums:

Piemēra izvade:

Darbinieka opcijas

Pielāgojiet darbinieku savai gaumei:

Piemērs:

php vendor/bin/runway apm:worker --daemon --batch_size 100 --timeout 3600

Darbojas stundu, apstrādājot 100 metrikas uzreiz.

Pieprasījuma ID lietojumprogrammā

Katram pieprasījumam ir unikāls pieprasījuma ID izsekošanai. Jūs varat izmantot šo ID savā lietojumprogrammā, lai korelētu žurnālus un metrikas. Piemēram, jūs varat pievienot pieprasījuma ID kļūdu lapai:

Flight::map('error', function($message) {
    // Iegūt pieprasījuma ID no atbildes galvenes X-Flight-Request-Id
    $requestId = Flight::response()->getHeader('X-Flight-Request-Id');

    // Papildus jūs varētu to iegūt no Flight mainīgā
    // Šī metode labi nedarbosies swoole vai citās async platformās.
    // $requestId = Flight::get('apm.request_id');

    echo "Kļūda: $message (Pieprasījuma ID: $requestId)";
});

Atjaunināšana

Ja atjaunināt uz jaunāku APM versiju, ir iespēja, ka ir datubāzes migrācijas, kas jāpalaid. Jūs varat to izdarīt, palaižot šādu komandu:

php vendor/bin/runway apm:migrate

Tas palaidīs visas nepieciešamās migrācijas, lai atjauninātu datubāzes shēmu uz jaunāko versiju.

Piezīme: Ja jūsu APM datubāze ir liela izmērā, šīs migrācijas var prasīt laiku. Jūs varat vēlēties palaidīt šo komandu ārpus maksimālās slodzes stundām.

Veco datu dzēšana

Lai saglabātu jūsu datubāzi kārtīgu, jūs varat dzēst vecus datus. Tas ir īpaši noderīgi, ja darbojaties aizņemtu lietojumprogrammu un vēlaties uzturēt datubāzes izmēru vadāmu. Jūs varat to izdarīt, palaižot šādu komandu:

php vendor/bin/runway apm:purge

Tas noņems visus datus vecākus par 30 dienām no datubāzes. Jūs varat pielāgot dienu skaitu, nododot citu vērtību --days opcijai:

php vendor/bin/runway apm:purge --days 7

Tas noņems visus datus vecākus par 7 dienām no datubāzes.

Problēmu risināšana

Iestrēdzis? Mēģiniet šos:

Awesome-plugins/tracy

Tracy

Tracy ir fantastisks kļūdu apstrādātājs, ko var izmantot ar Flight. Tam ir vairākas panelis, kas var palīdzēt jums atkļūdot jūsu lietojumprogrammu. Ir ļoti viegli paplašināt un pievienot savus paneļus. Flight komanda ir izveidojusi dažus paneļus speciāli Flight projektam, izmantojot flightphp/tracy-extensions spraudni.

Instalācija

Instalējiet ar komponistu. Un jums faktiski vajadzēs instalēt to bez izstrādes versijas, jo Tracy tiek piegādāts ar ražošanas kļūdu apstrādes komponentu.

composer require tracy/tracy

Pamata konfigurācija

Ir dažas pamata konfigurācijas opcijas, lai sāktu. Par tām varat lasīt vairāk Tracy dokumentācijā.


require 'vendor/autoload.php';

use Tracy\Debugger;

// Iespējot Tracy
Debugger::enable();
// Debugger::enable(Debugger::DEVELOPMENT) // dažreiz ir jābūt skaidrai (arī Debugger::PRODUCTION)
// Debugger::enable('23.75.345.200'); // varat norādīt arī IP adreses masīvu

// Šeit tiks reģistrēti kļūdas un izņēmumi. Pārliecinieties, ka šis katalogs pastāv un ir rakstāms.
Debugger::$logDirectory = __DIR__ . '/../log/';
Debugger::$strictMode = true; // rādīt visas kļūdas
// Debugger::$strictMode = E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED; // visas kļūdas, izņemot novecojušus paziņojumus
if (Debugger::$showBar) {
    $app->set('flight.content_length', false); // ja Tracy josla ir redzama, tad Flight nevar iestatīt satura garumu

    // Tas ir specifisks Tracy paplašinājumam Flight, ja jūs to esat iekļāvuši
    // pretējā gadījumā komentējiet to.
    new TracyExtensionLoader($app);
}

Noderīgi padomi

Kad jūs atkļūvojat savu kodu, ir dažas ļoti noderīgas funkcijas, lai izvadītu datus jums.

Awesome-plugins/active_record

Flight Aktīvais Ieraksts

Aktīvais ieraksts ir datubāzes entitātes kartēšana uz PHP objektu. Sakot vienkārši, ja jums ir lietotāju tabula jūsu datubāzē, jūs varat "tulkot" rindu šajā tabulā uz User klasi un $user objektu jūsu kodā. Skatiet pamatu piemēru.

Noklikšķiniet šeit uz noliktavas GitHub.

Pamatu Piemērs

Pieņemam, ka jums ir šāda tabula:

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

Tagad jūs varat izveidot jaunu klasi, lai attēlotu šo tabulu:

/**
 * Aktīvā ieraksta klase parasti ir vienskaitļa formā
 * 
 * Ieteicams pievienot tabulas īpašības kā komentārus šeit
 * 
 * @property int    $id
 * @property string $name
 * @property string $password
 */ 
class User extends flight\ActiveRecord {
    public function __construct($database_connection)
    {
        // jūs to varat iestatīt šādā veidā
        parent::__construct($database_connection, 'users');
        // vai šādā veidā
        parent::__construct($database_connection, null, [ 'table' => 'users']);
    }
}

Tagad skatiet, kā notiek burvība!

// sqlite gadījumā
$database_connection = new PDO('sqlite:test.db'); // tas ir tikai piemēram, jūs, iespējams, izmantotu reālu datubāzes savienojumu

// mysql gadījumā
$database_connection = new PDO('mysql:host=localhost;dbname=test_db&charset=utf8bm4', 'username', 'password');

// vai mysqli
$database_connection = new mysqli('localhost', 'username', 'password', 'test_db');
// vai mysqli bez objektu balstīta izveidošana
$database_connection = mysqli_connect('localhost', 'username', 'password', 'test_db');

$user = new User($database_connection);
$user->name = 'Bobby Tables';
$user->password = password_hash('kāds foršs parole');
$user->insert();
// vai $user->save();

echo $user->id; // 1

$user->name = 'Joseph Mamma';
$user->password = password_hash('kāds foršs parole atkal!!!');
$user->insert();
// šeit nevar izmantot $user->save(), jo tas domās, ka tas ir atjauninājums!

echo $user->id; // 2

Un bija tik viegli pievienot jaunu lietotāju! Tagad, kad datubāzē ir lietotāja rinda, kā to izvilkt?

$user->find(1); // atrast id = 1 datubāzē un atgriezt to.
echo $user->name; // 'Bobby Tables'

Un kas notiks, ja vēlaties atrast visus lietotājus?

$users = $user->findAll();

Ko teikt par noteiktu nosacījumu?

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

Redzat, cik tas ir aizraujoši? Instalēsim to un sāksim!

Instalācija

Vienkārši instalējiet ar Composer

composer require flightphp/active-record 

Izmantošana

To var izmantot kā patstāvīgu bibliotēku vai kopā ar Flight PHP rāmci. Pilnīgi atkarīgs no jums.

Patstāvīgi

Vienkārši pārliecinieties, ka nododat PDO savienojumu konstruktoram.

$pdo_connection = new PDO('sqlite:test.db'); // tas ir tikai piemēram, jūs, iespējams, izmantotu reālu datubāzes savienojumu

$User = new User($pdo_connection);

Negribiet katru reizi iestatīt savu datubāzes savienojumu konstruktorā? Skatiet Datubāzes Savienojuma Pārvaldība citām idejām!

Reģistrēt kā metodi Flight

Ja jūs izmantojat Flight PHP rāmi, varat reģistrēt aktīvā ieraksta klasi kā pakalpojumu, bet jums to patiesībā nav jāizdara.

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

// tad jūs varat to izmantot šādi kontrolierī, funkcijā utt.

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

runway Metodes

runway ir CLI rīks Flight, kas ir izstrādāts ar īpašu komandu šai bibliotēkai.

# Izmantošana
php runway make:record database_table_name [class_name]

# Piemērs
php runway make:record users

Tas izveidos jaunu klasi mapē app/records/UserRecord.php ar sekojošo saturu:

<?php

declare(strict_types=1);

namespace app\records;

/**
 * Aktīvā ieraksta klase lietotāju tabulai.
 * @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 Iestatīt attiecības modelim
     *   https://docs.flightphp.com/awesome-plugins/active-record#relationships
     */
    protected array $relations = [
        // 'relation_name' => [ self::HAS_MANY, 'RelatedClass', 'foreign_key' ],
    ];

    /**
     * Konstruktor
     * @param mixed $databaseConnection Savienojums ar datubāzi
     */
    public function __construct($databaseConnection)
    {
        parent::__construct($databaseConnection, 'users');
    }
}

CRUD funkcijas

find($id = null) : boolean|ActiveRecord

Atrast vienu ierakstu un piešķirt to pašreizējam objektam. Ja jūs nododat $id kādu vērtību, tas veiks meklēšanu pēc primārā atslēga ar šo vērtību. Ja nekas netiek nodots, tas vienkārši atradīs pirmo ierakstu tabulā.

Turklāt jūs varat nodot tam citas palīgmetodes, lai vaicātu jūsu tabulu.

// atrast ierakstu ar dažiem nosacījumiem iepriekš
$user->notNull('password')->orderBy('id DESC')->find();

// atrast ierakstu pēc noteikta id
$id = 123;
$user->find($id);

findAll(): array<int,ActiveRecord>

Atrast visus ierakstus tabulā, kuru jūs norādāt.

$user->findAll();

isHydrated(): boolean (v0.4.0)

Atgriež true, ja pašreizējais ieraksts ir bijis hidrogenizēts (iegūts no datubāzes).

$user->find(1);
// ja ir atrasts ieraksts ar datiem...
$user->isHydrated(); // true

insert(): boolean|ActiveRecord

Ievieto pašreizējo ierakstu datubāzē.

$user = new User($pdo_connection);
$user->name = 'demo';
$user->password = md5('demo');
$user->insert();
Teksta balstītas primārās atslēgas

Ja jums ir teksta balstīta primārā atslēga (piemēram, UUID), jūs varat iestatīt primārās atslēgas vērtību pirms ievietošanas vienā no diviem veidiem.

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

vai jūs varat ļaut primārajai atslēgai automātiski tikt ģenerētai jūsu vietā.

class User extends flight\ActiveRecord {
    public function __construct($database_connection)
    {
        parent::__construct($database_connection, 'users', [ 'primaryKey' => 'uuid' ]);
        // jūs varat arī iestatīt primāro atslēgu šādā veidā, nevis augstāk norādītajā masīvā.
        $this->primaryKey = 'uuid';
    }

    protected function beforeInsert(self $self) {
        $self->uuid = uniqid(); // vai kā citādi nepieciešams ģenerēt jūsu unikālos id
    }
}

Ja jūs neiestatāt primāro atslēgu pirms ievietošanas, tā tiks iestatīta uz rowid un datubāze to ģenerēs jums, taču tā neuzturēsies, jo šis lauks var nepastāvēt jūsu tabulā. Tāpēc ieteicams izmantot notikumu, lai automātiski to apstrādātu.

update(): boolean|ActiveRecord

Atjaunina pašreizējo ierakstu datubāzē.

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

save(): boolean|ActiveRecord

Ievieto vai atjaunina pašreizējo ierakstu datubāzē. Ja ierakstam ir id, tas atjauninās, citādi tas ievietos.

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

Piezīme: Ja jums ir attiecības, kas definētas klasē, tās tiek rekurzīvi saglabātas, ja tās ir bijušas definētas, instancētas un ir netīri dati, ko atjaunināt. (v0.4.0 un augstāks)

delete(): boolean

Dzēš pašreizējo ierakstu no datubāzes.

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

Jūs arī varat dzēst vairākus ierakstus, veicot meklēšanu iepriekš.

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

dirty(array $dirty = []): ActiveRecord

Netīri dati attiecas uz datiem, kas ir mainīti ierakstā.

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

// šajā brīdī nav "netīru" datu.

$user->email = 'test@example.com'; // tagad e-pasts tiek uzskatīts par "netīru", jo tas ir mainījies.
$user->update();
// tagad nav nevienu datu, kas ir netīri, jo tie ir atjaunināti un uzglabāti datubāzē

$user->password = password_hash('jaunā parole'); // tagad šis ir netīrs
$user->dirty(); // neko nenododot, tiks notīrīti visi netīrie ieraksti.
$user->update(); // nekas netiks atjaunināts, jo nekas netika sagūstīts kā netīrs.

$user->dirty([ 'name' => 'kaut kas', 'password' => password_hash('cita parole') ]);
$user->update(); // gan vārds, gan parole tiek atjaunināti.

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

Tas ir alias dirty() metodei. Tas ir nedaudz vairāk skaidrāks par to, ko jūs darāt.

$user->copyFrom([ 'name' => 'kaut kas', 'password' => password_hash('cita parole') ]);
$user->update(); // abi vārds un parole tiek atjaunināti.

isDirty(): boolean (v0.4.0)

Atgriež true, ja pašreizējais ieraksts ir mainīts.

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

reset(bool $include_query_data = true): ActiveRecord

Atjauno pašreizējo ierakstu tā sākotnējā stāvoklī. Tas ir ļoti labi izmantot ciklu tipa uzvedībā. Ja nododat true, tas arī atiestatīs vaicājuma datus, kas tika izmantoti, lai atrastu pašreizējo objektu (pamatuzvedība).

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

foreach($users as $user) {
    $user_company->reset(); // sāk ar tīru lapu
    $user_company->user_id = $user->id;
    $user_company->company_id = $some_company_id;
    $user_company->insert();
}

getBuiltSql(): string (v0.4.1)

Pēc tam, kad esat izpildījis find(), findAll(), insert(), update(), vai save() metodi, jūs varat iegūt SQL, kas tika izveidots un izmantot to problēmu risināšanai.

SQL Vaicājumu Metodes

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

Jūs varat atlasīt tikai dažus no kolonnām tabulā, ja vēlaties (tas ir efektīvāk tiešām plašām tabulām ar daudzām kolonnām)

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

from(string $table)

Tehniski jūs varat izvēlēties arī citu tabulu! Kāpēc gan ne?!

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

join(string $table_name, string $join_condition)

Jūs pat varat pievienot citu tabulu datubāzē.

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

where(string $where_conditions)

Jūs varat iestatīt dažus pielāgotus where argumentus (jūs nevarat iestatīt parametrus šajā where paziņojumā)

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

Drošības Piezīme - Iespējams, ka jūs sadarbojas ar kaut ko līdzīgu $user->where("id = '{$id}' AND name = '{$name}'")->find();. Lūdzu, NEDARĪT TO!!! Tas var būt pakļauts tam, ko sauc par SQL injekcijas uzbrukumiem. Ir daudz rakstu tiešsaistē, lūdzu, Google "sql injekcijas uzbrukumi php" un jūs atradīsiet daudz rakstu par šo tēmu. Pareizā metode, kā to apstrādāt ar šo bibliotēku, ir tā, ka, nevis šo where() metodi, jūs to darītu vairāk līdzīgi $user->eq('id', $id)->eq('name', $name)->find();. Ja jums ir absolūti jādara tā, PDO bibliotēkai ir $pdo->quote($var), lai to izdzēstu priekš jums. Tikai pēc tam, kad esat izmantojuši quote(), varat to izmantot where() paziņojumā.

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

Grupējiet savus rezultātus pēc noteikta nosacījuma.

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

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

Kārtot atgriezto vaicājumu noteiktā veidā.

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

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

Ierobežojiet atgriezto ierakstu skaitu. Ja tiek norādīta otrā int, tā būs offset, limits tieši tāpat kā SQL.

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

WHERE nosacījumi

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

Kur field = $value

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

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

Kur field <> $value

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

isNull(string $field)

Kur field IS NULL

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

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

Kur field IS NOT NULL

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

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

Kur field > $value

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

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

Kur field < $value

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

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

Kur field >= $value

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

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

Kur field <= $value

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

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

Kur field LIKE $value vai field NOT LIKE $value

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

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

Kur field IN($value) vai field NOT IN($value)

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

between(string $field, array $values)

Kur field BETWEEN $value AND $value1

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

OR Nosacījumi

Ir iespējams savus nosacījumus ietīt OR paziņojumā. To var izdarīt, izmantojot startWrap() un endWrap() metodi vai norādīt 3. parametru nosacījumam pēc lauka un vērtības.

// Metode 1
$user->eq('id', 1)->startWrap()->eq('name', 'demo')->or()->eq('name', 'test')->endWrap('OR')->find();
// Tas novērtēs `id = 1 AND (name = 'demo' OR name = 'test')`

// Metode 2
$user->eq('id', 1)->eq('name', 'demo', 'OR')->find();
// Tas novērtēs `id = 1 OR name = 'demo'`

Attiecības

Jūs varat iestatīt vairākus veidus attiecības, izmantojot šo bibliotēku. Jūs varat iestatīt vienu->daudz un vienu->vienu attiecības starp tabulām. Tas prasa mazliet papildus sagatavošanu klasē iepriekš.

Iestatīt $relations masīvu nav grūti, bet pareizā sintakse var būt mulsinoša.

protected array $relations = [
    // jūs varat nosaukt atslēgu kā vēlaties. Aktīvā ieraksta nosaukums, iespējams, ir labs. Piemērs: lietotājs, kontakts, klients
    'user' => [
        // obligāti
        // self::HAS_MANY, self::HAS_ONE, self::BELONGS_TO
        self::HAS_ONE, // šis ir attiecību veids

        // obligāti
        'Some_Class', // šī ir 'otra' Aktīvā ieraksta klase, uz kuru atsaucas

        // obligāti
        // atkarībā no attiecību veida
        // self::HAS_ONE = ārējā atslēga, kas atsaucas uz pievienošanu
        // self::HAS_MANY = ārējā atslēga, kas atsaucas uz pievienošanu
        // self::BELONGS_TO = lokālā atslēga, kas atsaucas uz pievienošanu
        'local_or_foreign_key',
        // tikai FYI, tas arī pievienojas tikai uz "otras" modeļa primāro atslēgu

        // izvēles
        [ 'eq' => [ 'client_id', 5 ], 'select' => 'COUNT(*) as count', 'limit' 5 ], // papildu nosacījumi, kurus vēlaties, pievienojot attiecību
        // $record->eq('client_id', 5)->select('COUNT(*) as count')->limit(5))

        // izvēles
        'back_reference_name' // ja vēlaties atsaukt šo attiecību atpakaļ uz sevi, piemēram, `$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');
    }
}

Tagad mums ir atsauces iestatītas, lai mēs varētu tās izmantot ļoti viegli!

$user = new User($pdo_connection);

// atrast jaunāko lietotāju.
$user->notNull('id')->orderBy('id desc')->find();

// iegūt kontaktus, izmantojot attiecību:
foreach($user->contacts as $contact) {
    echo $contact->id;
}

// vai mēs varam doties otrā virzienā.
$contact = new Contact();

// atrast vienu kontaktu
$contact->find();

// iegūt lietotāju, izmantojot attiecību:
echo $contact->user->name; // tas ir lietotāja vārds

Ļoti jauki, vai ne?

Iestatīt Pielāgotus Datus

Reizēm jums var būt nepieciešams pievienot kaut ko unikālu savam Aktīvam Ierakstam, piemēram, pielāgotu aprēķinu, kas varētu būt vieglāk pievienot objektam, kas pēc tam būtu nodots, piemēram, šablonam.

setCustomData(string $field, mixed $value)

Jūs pievienojat pielāgoto datu ar setCustomData() metodi.

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

Un tad jūs vienkārši atsaucaties uz to kā uz normālu objekta īpašību.

echo $user->page_view_count;

Notikumi

Vēl viena super jauka funkcija šajā bibliotēkā ir notikumi. Notikumi tiek aktivizēti noteiktos brīžos, pamatojoties uz noteiktām metodēm, ko jūs izsaucat. Tie ir ļoti noderīgi, lai automātiski izveidotu datus jums.

onConstruct(ActiveRecord $ActiveRecord, array &config)

Tas ir ļoti noderīgi, ja nepieciešams iestatīt noklusējuma savienojumu vai kaut ko tamlīdzīgu.

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

//
//
//

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

    protected function onConstruct(self $self, array &$config) { // neaizmirstiet par & atsauci
        // jūs varētu to izdarīt, lai automātiski iestatītu savienojumu
        $config['connection'] = Flight::db();
        // vai arī šo
        $self->transformAndPersistConnection(Flight::db());

        // jūs varat arī šādi iestatīt tabulas nosaukumu.
        $config['table'] = 'users';
    } 
}

beforeFind(ActiveRecord $ActiveRecord)

Šis visticamāk ir noderīgs, ja jums nepieciešams vaicājuma manipulācija katru reizi.

class User extends flight\ActiveRecord {

    public function __construct($database_connection)
    {
        parent::__construct($database_connection, 'users');
    }

    protected function beforeFind(self $self) {
        // vienmēr palaist id >= 0, ja tā jums patīk
        $self->gte('id', 0); 
    } 
}

afterFind(ActiveRecord $ActiveRecord)

Šis visticamāk ir noderīgāks, ja jums katru reizi ir jāpalaista kāda loģika, kad šis ieraksts tiek iegūts. Vai jums jādešifrē kaut kas? Vai jums katru reizi jāveic pielāgots skaitīšanas vaicājums (neefektīvs, bet, nu...).

class User extends flight\ActiveRecord {

    public function __construct($database_connection)
    {
        parent::__construct($database_connection, 'users');
    }

    protected function afterFind(self $self) {
        // kaut ko dešifrējot
        $self->secret = yourDecryptFunction($self->secret, $some_key);

        // varbūt glabājot kaut ko pielāgotu, piemēram, vaicājumu???
        $self->setCustomData('view_count', $self->select('COUNT(*) count')->from('user_views')->eq('user_id', $self->id)['count']; 
    } 
}

beforeFindAll(ActiveRecord $ActiveRecord)

Šis varētu būt tikai noderīgs, ja jums nepieciešama vaicājuma manipulācija katru reizi.

class User extends flight\ActiveRecord {

    public function __construct($database_connection)
    {
        parent::__construct($database_connection, 'users');
    }

    protected function beforeFindAll(self $self) {
        // vienmēr palaist id >= 0, ja tā jums patīk
        $self->gte('id', 0); 
    } 
}

afterFindAll(array<int,ActiveRecord> $results)

Līdzīgi afterFind(), bet jūs varat to izdarīt visiem ierakstiem!

class User extends flight\ActiveRecord {

    public function __construct($database_connection)
    {
        parent::__construct($database_connection, 'users');
    }

    protected function afterFindAll(array $results) {

        foreach($results as $self) {
            // darīt kaut ko foršu līdzīgi kā afterFind()
        }
    } 
}

beforeInsert(ActiveRecord $ActiveRecord)

Ļoti noderīgi, ja nepieciešams iestatīt noklusējuma vērtības katru reizi.

class User extends flight\ActiveRecord {

    public function __construct($database_connection)
    {
        parent::__construct($database_connection, 'users');
    }

    protected function beforeInsert(self $self) {
        // iestatīt dažus labus noklusējumus
        if(!$self->created_date) {
            $self->created_date = gmdate('Y-m-d');
        }

        if(!$self->password) {
            $self->password = password_hash((string) microtime(true));
        }
    } 
}

afterInsert(ActiveRecord $ActiveRecord)

Varbūt jums ir lietotāja scenārijs, lai mainītu datus pēc ievietošanas?

class User extends flight\ActiveRecord {

    public function __construct($database_connection)
    {
        parent::__construct($database_connection, 'users');
    }

    protected function afterInsert(self $self) {
        // jūs darāt sevi
        Flight::cache()->set('most_recent_insert_id', $self->id);
        // vai jebkas cits...
    } 
}

beforeUpdate(ActiveRecord $ActiveRecord)

Ļoti noderīgi, ja jums vajag dažas noklusējuma vērtības katru reizi atjaunināšanai.

class User extends flight\ActiveRecord {

    public function __construct($database_connection)
    {
        parent::__construct($database_connection, 'users');
    }

    protected function beforeInsert(self $self) {
        // iestatīt dažus labus noklusējumus
        if(!$self->updated_date) {
            $self->updated_date = gmdate('Y-m-d');
        }
    } 
}

afterUpdate(ActiveRecord $ActiveRecord)

Varbūt jums ir lietotāja gadījums, lai mainītu datus pēc atjaunināšanas?

class User extends flight\ActiveRecord {

    public function __construct($database_connection)
    {
        parent::__construct($database_connection, 'users');
    }

    protected function afterInsert(self $self) {
        // jūs darāt sevi
        Flight::cache()->set('most_recently_updated_user_id', $self->id);
        // vai jebkas cits....
    } 
}

beforeSave(ActiveRecord $ActiveRecord)/afterSave(ActiveRecord $ActiveRecord)

Tas ir noderīgi, ja vēlaties, lai notikumi notiktu gan ievietošanas, gan atjaunināšanas laikā. Es ietaupīšu jums garu skaidrojumu, bet, esmu pārliecināts, ka jūs varat uzminēt, kas tas ir.

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)

Nezinu, ko jūs šeit vēlētos darīt, bet šeit nav spriedumu! Iet uz priekšu!

class User extends flight\ActiveRecord {

    public function __construct($database_connection)
    {
        parent::__construct($database_connection, 'users');
    }

    protected function beforeDelete(self $self) {
        echo 'Viņš bija drosmīgs karavīrs... :cry-face:';
    } 
}

Datubāzes Savienojuma Pārvaldība

Kad jūs izmantojat šo bibliotēku, jūs varat iestatīt datubāzes savienojumu dažādos veidos. Jūs varat iestatīt savienojumu konstruktorā, jūs varat iestatīt to caur konfigurācijas mainīgo $config['connection'] vai jūs varat iestatīt to caur setDatabaseConnection() (v0.4.1).

$pdo_connection = new PDO('sqlite:test.db'); // piemēram
$user = new User($pdo_connection);
// vai
$user = new User(null, [ 'connection' => $pdo_connection ]);
// vai
$user = new User();
$user->setDatabaseConnection($pdo_connection);

Ja vēlaties izvairīties no katra reizes $database_connection iestatīšanas, ir veidi, kā to izdarīt!

// index.php vai bootstrap.php
// Iestatiet šo kā reģistrētu klasi 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);
    }
}

// Un tagad, nav nepieciešami argumenti!
$user = new User();

Piezīme: Ja plānojat veikt vienību testēšanu, to izdarot, var rasties grūtības, bet kopumā, jo jūs varat injicēt savu savienojumu ar setDatabaseConnection() vai $config['connection'], tas nav pārāk slikti.

Ja jums nepieciešams atsvaidzināt datubāzes savienojumu, piemēram, ja jūs veicat garu CLI skriptu un periodiski nepieciešams atsvaidzināt savienojumu, jūs varat atkārtoti iestatīt savienojumu ar $your_record->setDatabaseConnection($pdo_connection).

Ieteikums

Lūdzu, dariet to. :D

Iestatīšana

Kad jūs piedalāties, pārliecinieties, ka izpildāt composer test-coverage, lai uzturētu 100% testēšanas pārklājumu (šis nav patiesais vienību testēšanas pārklājums, drīzāk integrācijas testēšana).

Tāpat pārliecinieties, ka izpildāt composer beautify un composer phpcs, lai novērstu jebkādas linting kļūdas.

Licence

MIT

Awesome-plugins/latte

Latte

Latte ir pilnvērtīgs veidņu dz motor, kas ir ļoti viegli lietojams un jūtas tuvāk PHP sintaksei nekā Twig vai Smarty. To ir arī ļoti viegli paplašināt un pievienot savus filtrus un funkcijas.

Instalācija

Instalējiet ar composer.

composer require latte/latte

Pamata konfigurācija

Ir dažas pamata konfigurācijas opcijas, lai sāktu. Jūs varat lasīt vairāk par tām Latte dokumentācijā.


require 'vendor/autoload.php';

$app = Flight::app();

$app->map('render', function(string $template, array $data, ?string $block): void {
    $latte = new Latte\Engine;

    // Kur latte specifiski glabā savu kešu
    $latte->setTempDirectory(__DIR__ . '/../cache/');

    $finalPath = Flight::get('flight.views.path') . $template;

    $latte->render($finalPath, $data, $block);
});

Vienkāršs izkārtojuma piemērs

Šeit ir vienkāršs izkārtojuma faila piemērs. Šis ir fails, kas tiks izmantots, lai aptvertu visas jūsu citas skatus.

<!-- app/views/layout.latte -->
<!doctype html>
<html lang="en">
    <head>
        <title>{$title ? $title . ' - '}My App</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <header>
            <nav>
                <!-- jūsu navigācijas elementi šeit -->
            </nav>
        </header>
        <div id="content">
            <!-- Šī ir maģija šeit -->
            {block content}{/block}
        </div>
        <div id="footer">
            &copy; Copyright
        </div>
    </body>
</html>

Un tagad mums ir jūsu fails, kas tiks renderēts tajā satura blokā:

<!-- app/views/home.latte -->
<!-- Tas pasaka Latte, ka šis fails ir "iekšā" layout.latte failā -->
{extends layout.latte}

<!-- Šis ir saturs, kas tiks renderēts izkārtojumā satura blokā -->
{block content}
    <h1>Sākumlapa</h1>
    <p>Sveiki manā lietotnē!</p>
{/block}

Pēc tam, kad jūs dodaties renderēt to savā funkcijā vai kontrolierī, jūs darītu kaut ko šādu:

// vienkāršs maršruts
Flight::route('/', function () {
    Flight::render('home.latte', [
        'title' => 'Sākumlapa'
    ]);
});

// vai ja jūs izmantojat kontrollieri
Flight::route('/', [HomeController::class, 'index']);

// HomeController.php
class HomeController
{
    public function index()
    {
        Flight::render('home.latte', [
            'title' => 'Sākumlapa'
        ]);
    }
}

Skatiet Latte dokumentāciju, lai iegūtu vairāk informācijas par to, kā izmantot Latte pilnā potenciālā!

Kļūdu labošana ar Tracy

PHP 8.1+ ir nepieciešams šai sadaļai.

Jūs varat izmantot arī Tracy, lai palīdzētu ar jūsu Latte veidņu failu kļūdu labošanu tieši no kastes! Ja jums jau ir instalēts Tracy, jums jāpievieno Latte paplašinājums Tracy.

// services.php
use Tracy\Debugger;

$app->map('render', function(string $template, array $data, ?string $block): void {
    $latte = new Latte\Engine;

    // Kur latte specifiski glabā savu kešu
    $latte->setTempDirectory(__DIR__ . '/../cache/');

    $finalPath = Flight::get('flight.views.path') . $template;

    // Tas pievienos paplašinājumu tikai tad, ja ir iespējota Tracy atkļūdošanas josla
    if (Debugger::$showBar === true) {
        // šeit jūs pievienojat Latte paneli Tracy
        $latte->addExtension(new Latte\Bridges\Tracy\TracyExtension);
    }
    $latte->render($finalPath, $data, $block);
});

Awesome-plugins/awesome_plugins

Lieliski spraudņi

Flight ir neticami paplašināms. Ir vairāki spraudņi, ko var izmantot, lai pievienotu funkcionalitāti jūsu Flight aplikācijai. Daži no tiem oficiāli atbalsta Flight komanda, bet citi ir mikro/lite bibliotēkas, lai palīdzētu jums sākt.

API dokumentācija

API dokumentācija ir izšķiroša jebkurai API. Tā palīdz izstrādātājiem saprast, kā mijiedarboties ar jūsu API un ko sagaidīt pretī. Ir pieejami vairāki rīki, lai palīdzētu ģenerēt API dokumentāciju jūsu Flight projektiem.

Aplikācijas veiktspējas uzraudzība (APM)

Aplikācijas veiktspējas uzraudzība (APM) ir izšķiroša jebkurai aplikācijai. Tā palīdz saprast, kā jūsu aplikācija darbojas un kur ir pudeles kakli. Ir vairāki APM rīki, ko var izmantot ar Flight.

Async

Flight jau ir ātrs ietvars, bet pievienojot tam turbo dzinēju, viss kļūst jautrāks (un izaicinošāks)!

Autorizācija/Atļaujas

Autorizācija un atļaujas ir izšķirošas jebkurai aplikācijai, kas prasa kontroli par to, kam ir piekļuve kam.

Kešošana

Kešošana ir lielisks veids, kā paātrināt jūsu aplikāciju. Ir vairāki kešošanas bibliotēkas, ko var izmantot ar Flight.

CLI

CLI aplikācijas ir lielisks veids, kā mijiedarboties ar jūsu aplikāciju. Jūs varat izmantot tās, lai ģenerētu kontrolierus, parādītu visas maršrutus un vairāk.

Sīkfaili

Sīkfaili ir lielisks veids, kā uzglabāt mazus datu gabalus klientu pusē. Tos var izmantot, lai uzglabātu lietotāja preferences, aplikācijas iestatījumus un vairāk.

Kļūdu labošana

Kļūdu labošana ir izšķiroša, kad jūs attīstāt savā lokālajā vidē. Ir daži spraudņi, kas var uzlabot jūsu kļūdu labošanas pieredzi.

Datubāzes

Datubāzes ir kodols lielākajai daļai aplikāciju. Tā ir veids, kā uzglabāt un izgūt datus. Dažas datubāzu bibliotēkas ir vienkārši apvalki vaicājumu rakstīšanai, bet dažas ir pilnvērtīgas ORM.

Šifrēšana

Šifrēšana ir izšķiroša jebkurai aplikācijai, kas uzglabā sensitīvus datus. Datu šifrēšana un dešifrēšana nav pārāk grūti, bet pareiza šifrēšanas atslēgas uzglabāšana var būt grūti. Visnozīmīgākais ir nekad neuzglabāt jūsu šifrēšanas atslēgu publiskā direktorijā vai neiekļaut to jūsu koda repozitorijā.

Darbu rinda

Darbu rindas ir patiešām noderīgas, lai asinhroni apstrādātu uzdevumus. Tas var būt e-pastu sūtīšana, attēlu apstrāde vai jebkas, kam nav jābūt reāllaika.

Sesijas

Sesijas nav īsti noderīgas API, bet veidojot tīmekļa aplikāciju, sesijas var būt izšķirošas, lai uzturētu stāvokli un pieteikšanās informāciju.

Veidnes

Veidnes ir kodols jebkurai tīmekļa aplikācijai ar UI. Ir vairāki veidņu dzinēji, ko var izmantot ar Flight.

WordPress integrācija

Vai vēlaties izmantot Flight jūsu WordPress projektā? Ir ērts spraudnis tam!

Iesaiste

Vai jums ir spraudnis, ko vēlaties dalīties? Iesniedziet pull request, lai pievienotu to sarakstam!

Media

Media

Mēs esam mēģinājuši izsekot dažādu veidu medijiem internetā par Flight. Skatiet zemāk dažādus resursus, kurus varat izmantot, lai uzzinātu vairāk par Flight.

Raksti un apraksti

Video un pamācības

Trūkst kaut kas?

Vai mums trūkst kaut kas, ko jūs esat uzrakstījis vai ierakstījis? Informējiet mūs ar problēmas ziņojumu vai pull request!

Examples

Vai ātri sākt?

Jums ir divas opcijas, lai sāktu jaunu Flight projektu:

Kopienas sniegti piemēri:

Vai vajag iedvesmu?

Lai gan šie nav oficiāli atbalstīti no Flight komandas puses, tie var sniegt idejas, kā strukturēt savus paša projektus, kas izveidoti ar Flight!

Vai vēlaties dalīties ar savu paša piemēru?

Ja jums ir projekts, kuru vēlaties dalīt, lūdzu, iesniedziet pull request, lai to pievienotu šim sarakstam!

Install/install

Instalēšanas instrukcijas

Ir daži pamatpriekšnoteikumi, pirms varat instalēt Flight. Galvenokārt jums būs jā:

  1. Instalē PHP sistēmā
  2. Instalē Composer labākai izstrādātāju pieredzei.

Pamatinstalēšana

Ja izmantojat Composer, varat izpildīt šādu komandu:

composer require flightphp/core

Tas tikai ievietos Flight kodola failus jūsu sistēmā. Jums būs jādefinē projekta struktūra, izkārtojums, atkarības, konfigurācijas, automātiskā ielāde utt. Šī metode nodrošina, ka nav instalētas citas atkarības, izņemot Flight.

Varat arī lejupielādēt failus tieši un izvilkt tos savā tīmekļa direktorijā.

Ieteicamā instalēšana

Ir augsti ieteicams sākt ar flightphp/skeleton lietotni jebkuram jaunam projektam. Instalēšana ir viegla.

composer create-project flightphp/skeleton my-project/

Tas iestatīs jūsu projekta struktūru, konfigurēs automātisko ielādi ar vārdtelpām, iestatīs konfigurāciju un nodrošinās citas rīkus, piemēram, Tracy, Tracy Extensions un Runway.

Konfigurējiet savu tīmekļa serveri

Iebūvētais PHP izstrādes serveris

Šī ir vienkāršākā metode, lai sāktu darbu. Varat izmantot iebūvēto serveri, lai palaistu savu lietotni un pat izmantot SQLite datubāzei (tik ilgi, kamēr sqlite3 ir instalēts jūsu sistēmā), un neprasīt gandrīz neko! Vienreiz instalējot PHP, vienkārši izpildiet šādu komandu:

php -S localhost:8000
# vai ar skeleton lietotni
composer start

Pēc tam atveriet pārlūku un dodieties uz http://localhost:8000.

Ja vēlaties padarīt sava projekta dokumenta saknes direktoriju citu direktoriju (Piem.: jūsu projekts ir ~/myproject, bet jūsu dokumenta sakne ir ~/myproject/public/), varat izpildīt šādu komandu, atrodoties ~/myproject direktorijā:

php -S localhost:8000 -t public/
# ar skeleton lietotni tas jau ir konfigurēts
composer start

Pēc tam atveriet pārlūku un dodieties uz http://localhost:8000.

Apache

Pārliecinieties, ka Apache jau ir instalēts jūsu sistēmā. Ja nē, meklējiet Google, kā instalēt Apache jūsu sistēmā.

Apache gadījumā rediģējiet savu .htaccess failu ar šādu:

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

Piezīme: Ja nepieciešams izmantot flight apakšdirektorijā, pievienojiet rindu RewriteBase /subdir/ tieši pēc RewriteEngine On.

Piezīme: Ja vēlaties aizsargāt visus servera failus, piemēram, db vai env failu. Ievietojiet to savā .htaccess failā:

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

Nginx

Pārliecinieties, ka Nginx jau ir instalēts jūsu sistēmā. Ja nē, meklējiet Google, kā instalēt Nginx jūsu sistēmā.

Nginx gadījumā pievienojiet šādu savai servera deklarācijai:

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

Izveidojiet savu index.php failu

Ja veicat pamatinstalēšanu, jums būs nepieciešams kāds kods, lai sāktu.

<?php

// Ja izmantojat Composer, iekļaujiet autoloader.
require 'vendor/autoload.php';
// ja neizmantojat Composer, ielādējiet framework tieši
// require 'flight/Flight.php';

// Tad definējiet maršrutu un piešķiriet funkciju, lai apstrādātu pieprasījumu.
Flight::route('/', function () {
  echo 'hello world!';
});

// Visbeidzot, palaidiet framework.
Flight::start();

Ar skeleton lietotni tas jau ir konfigurēts un apstrādāts jūsu app/config/routes.php failā. Pakalpojumi ir konfigurēti app/config/services.php.

PHP instalēšana

Ja jums jau ir instalēts php jūsu sistēmā, izlaidiet šīs instrukcijas un pārejiet uz lejupielādes sadaļu.

macOS

PHP instalēšana, izmantojot Homebrew

  1. Instalējiet Homebrew (ja vēl nav instalēts):

    • Atveriet Termināli un izpildiet:
      /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
  2. Instalējiet PHP:

    • Instalējiet jaunāko versiju:
      brew install php
    • Lai instalētu specifisku versiju, piemēram, PHP 8.1:
      brew tap shivammathur/php
      brew install shivammathur/php/php@8.1
  3. Pārslēdzieties starp PHP versijām:

    • Atvienojiet pašreizējo versiju un saistiet vēlamo versiju:
      brew unlink php
      brew link --overwrite --force php@8.1
    • Pārbaudiet instalēto versiju:
      php -v

Windows 10/11

PHP instalēšana manuāli

  1. Lejupielādējiet PHP:

    • Apmeklējiet PHP for Windows un lejupielādējiet jaunāko vai specifisku versiju (piem., 7.4, 8.0) kā ne-vītu drošu zip failu.
  2. Izvelciet PHP:

    • Izvelciet lejupielādēto zip failu uz C:\php.
  3. Pievienojiet PHP sistēmas PATH:

    • Dodieties uz Sistēmas īpašībām > Vides mainīgajiem.
    • Sadaļā Sistēmas mainīgie, atrast Path un noklikšķiniet Rediģēt.
    • Pievienojiet ceļu C:\php (vai kur izvelcāt PHP).
    • Noklikšķiniet Labi, lai aizvērtu visus logus.
  4. Konfigurējiet PHP:

    • Kopējiet php.ini-development uz php.ini.
    • Rediģējiet php.ini, lai konfigurētu PHP pēc vajadzības (piem., iestatiet extension_dir, iespējiet paplašinājumus).
  5. Pārbaudiet PHP instalēšanu:

    • Atveriet Komandu uzvedni un izpildiet:
      php -v

Vairāku PHP versiju instalēšana

  1. Atkārtojiet iepriekšējos soļus katrai versijai, izvietojot katru atsevišķā direktorijā (piem., C:\php7, C:\php8).

  2. Pārslēdzieties starp versijām, pielāgojot sistēmas PATH mainīgo, lai norādītu uz vēlamo versijas direktoriju.

Ubuntu (20.04, 22.04 utt.)

PHP instalēšana, izmantojot apt

  1. Atjauniniet paketes sarakstus:

    • Atveriet Termināli un izpildiet:
      sudo apt update
  2. Instalējiet PHP:

    • Instalējiet jaunāko PHP versiju:
      sudo apt install php
    • Lai instalētu specifisku versiju, piemēram, PHP 8.1:
      sudo apt install php8.1
  3. Instalējiet papildu moduļus (pēc izvēles):

    • Piemēram, lai instalētu MySQL atbalstu:
      sudo apt install php8.1-mysql
  4. Pārslēdzieties starp PHP versijām:

    • Izmantojiet update-alternatives:
      sudo update-alternatives --set php /usr/bin/php8.1
  5. Pārbaudiet instalēto versiju:

    • Izpildiet:
      php -v

Rocky Linux

PHP instalēšana, izmantojot yum/dnf

  1. Iespējojiet EPEL repozitoriju:

    • Atveriet Termināli un izpildiet:
      sudo dnf install epel-release
  2. Instalējiet Remi's repozitoriju:

    • Izpildiet:
      sudo dnf install https://rpms.remirepo.net/enterprise/remi-release-8.rpm
      sudo dnf module reset php
  3. Instalējiet PHP:

    • Lai instalētu noklusēto versiju:
      sudo dnf install php
    • Lai instalētu specifisku versiju, piemēram, PHP 7.4:
      sudo dnf module install php:remi-7.4
  4. Pārslēdzieties starp PHP versijām:

    • Izmantojiet dnf moduļa komandu:
      sudo dnf module reset php
      sudo dnf module enable php:remi-8.0
      sudo dnf install php
  5. Pārbaudiet instalēto versiju:

    • Izpildiet:
      php -v

Vispārīgas piezīmes

Guides

Ceļveži

Flight PHP ir izstrādāts, lai būtu vienkāršs, bet spēcīgs, un mūsu ceļveži palīdzēs jums izveidot reālas pasaules aplikācijas solis pa solim. Šie praktiskie pamācību materiāli vada jūs cauri pilnīgiem projektiem, lai demonstrētu, kā Flight var tikt izmantots efektīvi.

Oficiālie ceļveži

Būvējot emu blogu

Uzziniet, kā izveidot funkcionējošu bloga aplikāciju ar Flight PHP. Šis ceļvedis vada jūs cauri:

Šī pamācība ir ideāla iesācējiem, kuri vēlas redzēt, kā visi elementi sader kopā reālā aplikācijā.

Vienības testēšana un SOLID principi

Šis ceļvedis aptver vienības testēšanas pamatus Flight PHP aplikācijās. Tajā ietilpst:

Neoficiālie ceļveži

Kaut arī šie ceļveži netiek oficiāli uzturēti Flight komandas, tie ir vērtīgi resursi, kurus izveidojusi kopiena. Tie aptver dažādas tēmas un lietošanas gadījumus, sniedzot papildu ieskatus Flight PHP izmantošanā.

Creating a RESTful API with Flight Framework

Šis ceļvedis vada jūs cauri RESTful API izveidošanai, izmantojot Flight PHP framework. Tajā tiek apskatīti API iestatīšanas pamati, maršrutu definēšana un JSON atbilžu atgriešana.

Building a Simple Blog

Šis ceļvedis vada jūs cauri vienkārša bloga izveidošanai, izmantojot Flight PHP framework. Tajā faktiski ir 2 daļas: viena, lai aptvertu pamatus, un otra, lai apskatītu vairāk uzlabotus tēmus un uzlabojumus ražošanas gatavam blogam.

Building a Pokémon API in PHP: A Beginner's Guide

Šis aizraujošais ceļvedis vada jūs cauri vienkārša Pokémon API izveidošanai, izmantojot Flight PHP. Tajā tiek apskatīti API iestatīšanas pamati, maršrutu definēšana un JSON atbilžu atgriešana.

Iesaistīšanās

Vai jums ir ideja par ceļvedi? Atrasts kļūda? Mēs priecājamies par ieguldījumiem! Mūsu ceļveži tiek uzturēti FlightPHP dokumentācijas repozitorijā.

Ja jūs esat izveidojis kaut ko interesantu ar Flight un vēlaties to dalīties kā ceļvedi, lūdzu, iesniedziet pull request. Daloties ar savām zināšanām, jūs palīdzat Flight kopienai augt.

Meklējat API dokumentāciju?

Ja jūs meklējat specifisku informāciju par Flight galvenajām funkcijām un metodēm, apskatiet Learn sadaļu mūsu dokumentācijā.