Å skyve Laravel videre - beste tips og god praksis for Laravel 5.7

Dette innlegget har en lydversjon takket være Miguel Piedrafitas Blogcast-app.

Laravel er allerede kjent av mange PHP-utviklere for å skrive ren, fungerende og debuggerbar kode. Den har også støtte for mange mange funksjoner, som noen ganger ikke er oppført i dokumentene, eller de var, men de ble fjernet av forskjellige grunner.

Jeg har jobbet med Laravel i produksjonsbruk i 2 år og har lært fra å skrive dårlig kode til bedre kode, og jeg har benyttet meg av Laravel siden første gang jeg begynte å skrive kode med den. Jeg skal vise deg de mystiske triksene som kan hjelpe deg når du skriver kode med Laravel.

Bruk lokale omfang når du trenger spørsmål

Laravel har en fin måte å skrive spørsmål til databasedriveren din ved å bruke Query Builder. Noe sånt som dette:

$ orders = Bestill :: hvor ('status', 'levert') -> hvor ('betalt', sant) -> få ();

Dette er ganske fint. Dette fikk meg til å gi opp SQL og fokusere på koding som er mer tilgjengelig for meg. Men denne koden kan skrives bedre hvis vi bruker lokale omfang.

Lokale omfang lar oss lage våre egne Query Builder-metoder vi kan lenke når vi prøver å hente data. I stedet for -> hvor () uttalelser, kan vi for eksempel bruke -> levert () og -> betalt () på en renere måte.

For det første, i vår ordremodell, bør vi legge til noen metoder:

klasse Order utvider Model
{
   ...
   public function scopeDelivered ($ query) {
      returner $ spørring-> hvor ('status', 'levert');
   }
   public function scopePaid ($ spørring) {
      returner $ spørring-> hvor ('betalt', sant);
   }
}

Når du erklærer lokale omfang, bør du bruke omfanget [Noe] nøyaktig navngivning. På denne måten vil Laravel vite at dette er et omfang og vil benytte seg av det i Query Builder. Forsikre deg om at du inkluderer det første argumentet som blir automatisk injisert av Laravel, og er forekomsten av spørringsbyggeren.

$ ordrer = Ordre :: levert () -> betalt () -> få ();

For mer dynamisk henting, kan du bruke dynamiske lokale omfang. Hvert omfang lar deg gi parametere.

klasse Order utvider Model
{
   ...
   public function scopeStatus ($ spørring, streng $ status) {
      returner $ spørring-> hvor ('status', $ status);
   }
}
$ ordrer = Ordre :: status ('levert') -> betalt () -> få ();

Senere i denne artikkelen lærer du hvorfor du bør bruke snake_case for databasefelt, men her er den første grunnen: Laravel bruker som standard der [Noe] for å erstatte det tidligere omfanget. Så i stedet for den tidligere, kan du gjøre:

Bestill :: whereStatus ( 'levert') -> betalt () -> get ();

Laravel vil søke etter snake_case-versjonen av Noe derfra [Noe]. Hvis du har status i DB-en, bruker du forrige eksempel. Hvis du har shipping_status, kan du bruke:

Bestill :: whereShippingStatus ( 'levert') -> betalt () -> get ();

Det er ditt valg!

Bruk Forespørsler filer når det er nødvendig

Laravel gir deg en veltalende måte å validere skjemaene dine. Enten er det en POST-forespørsel eller en GET-forespørsel, den vil ikke unnlate å validere den hvis du trenger den.

Du kan validere på denne måten i kontrolleren:

offentlig funksjonsbutikk (Be om $ forespørsel)
{
    $ validatedData = $ request-> validate ([
        'title' => 'påkrevd | unikt: innlegg | maks: 255',
        'body' => 'påkrevd',
    ]);

    // Blogginnlegget er gyldig ...
}

Men når du har for mye kode i kontrollmetodene dine, kan det være ganske stygt. Du vil redusere så mye kode som mulig i kontrolleren. I det minste er det dette som er det første jeg tenker hvis jeg må skrive virkelig mye logikk.

Laravel gir deg en * søt * måte å validere forespørsler ved å opprette forespørselsklasser og bruke dem i stedet for den gammeldagse forespørselsklassen. Du må bare opprette forespørselen:

php artisan make: be StoreBlogPost

Inne i appen / Http / Forespørsler / mappen finner du forespørselsfilen din:

class StoreBlogPostRequest utvider FormRequest
{
   autorisere offentlig funksjon ()
   {
      returner $ this-> bruker () -> kan ('create.posts');
   }
   regler for offentlig funksjon ()
   {
       komme tilbake [
         'title' => 'påkrevd | unikt: innlegg | maks: 255',
         'body' => 'påkrevd',
       ];
   }
}

Nå, i stedet for Illuminate \ Http \ Request i metoden din, bør du erstatte med den nyopprettede klassen:

bruk App \ Http \ Requests \ StoreBlogPostRequest;
offentlig funksjonsbutikk (StoreBlogPostRequest $ forespørsel)
{
    // Blogginnlegget er gyldig ...
}

Autorisasjonsmetoden () bør være en boolsk. Hvis den er usann, kaster den en 403, så pass på at du fanger den i appen / Exceptions / Handler.php 's render () -metode:

gjengivelse av offentlig funksjon ($ forespørsel, unntak $ unntak)
{
   if ($ unntakstilfelle av \ Illuminate \ Auth \ Access \ AuthorizationException) {
      //
   }
   retur foreldre :: render ($ forespørsel, $ unntak);
}

Den manglende metoden her, i forespørselsklassen, er meldinger () -funksjonen, det vil si en matrise som inneholder meldingene som vil bli returnert i tilfelle valideringen mislykkes:

class StoreBlogPostRequest utvider FormRequest
{
   autorisere offentlig funksjon ()
   {
      returner $ this-> bruker () -> kan ('create.posts');
   }
   regler for offentlig funksjon ()
   {
       komme tilbake [
         'title' => 'påkrevd | unikt: innlegg | maks: 255',
         'body' => 'påkrevd',
       ];
   }
   offentlige funksjonsmeldinger ()
   {
      komme tilbake [
        'title.required' => 'Tittelen kreves.',
        'title.unique' => 'Innleggstittelen eksisterer allerede.',
        ...
      ];
   }
}

For å fange dem i kontrolleren din, kan du bruke feilvariabelen inne i bladfilene:

@if ($ error-> any ())
   @foreach ($ feil-> alle () som $ feil)
      {{$ error}}
   @endforeach
@slutt om

I tilfelle du ønsker å få valideringsmeldingen til et bestemt felt, kan du gjøre det slik (det vil returnere en falsk-boolsk enhet hvis valideringen er passert for det feltet):


@if ($ error-> har ('tittel'))
   
@slutt om

Magiske omfang

Når du bygger ting, kan du bruke de magiske omfangene som allerede er innebygd

  • Hent resultatene ved opprettet_at, synkende:
Bruker :: siste () -> get ();
  • Hent resultatene etter hvilket som helst felt, synkende:
Bruker :: nyeste ( 'last_login_at') -> får ();
  • Hent resultater i tilfeldig rekkefølge:
Bruker :: inRandomOrder () -> får ();
  • Kjør en spørsmålsmetode bare hvis noe er sant:
// La oss anta at brukeren er på nyhetssiden, og vil sortere den etter den nyeste først
// mydomain.com/news?sort=new
Bruker :: når ($ forespørsel-> spørring ('sort'), funksjon ($ spørring, $ sortering) {
   if ($ sort == 'nytt') {
      returner $ spørring-> siste ();
   }
   
   returner $ spørring;
}) -> får ();

I stedet for når () du kan bruke med mindre, er det motsatt av når ().

Bruk forhold til å unngå store spørsmål (eller dårlig skrevet)

Har du noen gang brukt massevis av sammenføyninger i et spørsmål bare for å få mer informasjon? Det er ganske vanskelig å skrive disse SQL-kommandoene, selv med Query Builder, men modeller gjør det allerede med Relationships. Kanskje du ikke vil bli kjent med først, på grunn av mye informasjon som dokumentasjonen gir, men dette vil hjelpe deg å forstå bedre hvordan tingene fungerer og hvordan du får applikasjonen din smidigere.

Sjekk forhold til dokumentasjonen her.

Bruk jobber til tidkrevende oppgaver

Laravel Jobs er et kraftig må-til-verktøy for å kjøre oppgaver i bakgrunnen.

  • Vil du sende en e-post? Arbeidsplasser.
  • Vil du sende en melding? Arbeidsplasser.
  • Vil du behandle bilder? Arbeidsplasser.

Jobber hjelper deg med å gi opp ladetiden for brukerne dine på tidkrevende oppgaver som disse. De kan settes i navngitte køer, de kan prioriteres, og gjett hva - Laravel implementerte køer nesten overalt der det var mulig: enten å behandle noen PHP i bakgrunnen eller sende varsler eller kringkaste hendelser, køer er der!

Du kan sjekke køenes dokumentasjon her.

Jeg elsker å bruke Laravel Horizon til køer siden det er enkelt å sette opp, det kan dememoniseres ved hjelp av Supervisor og gjennom konfigurasjonsfilen, kan jeg fortelle Horizon hvor mange prosesser jeg vil ha for hver kø.

Hold deg til databasestandarder og tilbehør

Laravel lærer deg helt fra starten at variablene og metodene dine skal være $ camelCase camelCase () mens databasefeltene dine skal være snake_case. Hvorfor? Fordi dette hjelper oss å bygge bedre aksessorer.

Tilbehør er tilpassede felt vi kan bygge rett fra vår modell. Hvis databasen vår inneholder fornavn, etternavn og alder, kan vi legge til et egendefinert felt med navn som sammenligner fornavn og etternavn. Ikke bekymre deg, dette blir ikke skrevet i DB på noen måte. Det er bare et tilpasset attributt denne spesifikke modellen har. Alle tilbehør, som scopes, har en tilpasset navnesyntaks: getSomethingAttribute:

klasse Bruker utvider Model
{
   ...
   offentlig funksjon getNameAttribute (): streng
   {
       returner $ dette-> fornavn. ' ' $ Dette-> last_name.;
   }
}

Når du bruker $ bruker-> navn, returnerer det sammenkjøringen.

Som standard vises ikke attributtet hvis vi dd ($ bruker), men vi kan gjøre dette generelt tilgjengelig ved å bruke variablen $ appends:

klasse Bruker utvider Model
{
   beskyttede $ appends = [
      'Navn',
   ];
   ...
   offentlig funksjon getNameAttribute (): streng
   {
       returner $ dette-> fornavn. ' ' $ Dette-> last_name.;
   }
}

Hver gang vi dd ($ bruker), vil vi se at variabelen er der (men fortsatt, dette er ikke til stede i databasen)

Vær imidlertid forsiktig: hvis du allerede har et navnefelt, er tingene litt forskjellige: navnet på $ appends er ikke lenger nødvendig, og attributtfunksjonen venter på en parameter, som er den allerede lagrede variabelen (vi vil ikke lenger bruk $ dette).

For det samme eksemplet, kan det hende vi ønsker å bekrefte () navnene:

klasse Bruker utvider Model
{
   beskyttede $ appends = [
      //
   ];
   ...
   offentlig funksjon getFirstNameAttribute ($ firstName): string
   {
       return ucfirst ($ firstName);
   }
   offentlig funksjon getLastNameAttribute ($ lastName): streng
   {
      return ucfirst ($ lastName);
   }
}

Når vi bruker $ user-> first_name, vil det returnere en versjon med store bokstaver.

På grunn av denne funksjonen er det bra å bruke snake_case til databasefeltene.

Ikke lagre modellrelaterte statiske data i konfigurasjoner

Det jeg elsker å gjøre er å lagre modellrelaterte statiske data inne i modellen. La meg vise deg.

Istedenfor dette:

BettingOdds.php

klasse BettingOdds utvider Model
{
   ...
}

config / bettingOdds.php

komme tilbake [
   'sports' => [
      'fotball' => 'sport: 1',
      'tennis' => 'sport: 2',
      'basketball' => 'sport: 3',
      ...
   ]
];

Og få tilgang til dem ved å bruke:

konfig (’bettingOdds.sports.soccer’);

Jeg foretrekker å gjøre dette:

BettingOdds.php

klasse BettingOdds utvider Model
{
   beskyttet statisk $ sports = [
      'fotball' => 'sport: 1',
      'tennis' => 'sport: 2',
      'basketball' => 'sport: 3',
      ...
   ];
}

Og få tilgang til dem ved å bruke:

BettingOdds :: $ sport [ 'fotball'];

Hvorfor? Fordi det er lettere å bli brukt i videre operasjoner:

klasse BettingOdds utvider Model
{
   beskyttet statisk $ sports = [
      'fotball' => 'sport: 1',
      'tennis' => 'sport: 2',
      'basketball' => 'sport: 3',
      ...
   ];
   public function scopeSport ($ spørring, streng $ sport)
   {
      if (! isset (self :: $ sports [$ sport])) {
         returner $ spørring;
      }
      
      returner $ spørring-> hvor ('sport_id', self :: $ sports [$ sport]);
   }
}

Nå kan vi glede oss over omfang:

BettingOdds :: sport ( 'fotball') -> får ();

Bruk samlinger i stedet for raw-array-behandling

Tilbake i dagene var vi vant til å jobbe med matriser på en rå måte:

$ frukt = ['eple', 'pære', 'banan', 'jordbær'];
foreach ($ frukt som $ frukt) {
   ekko 'jeg har'. $ Frukt;
}

Nå kan vi bruke avanserte metoder som hjelper oss med å behandle dataene innenfor matriser. Vi kan filtrere, transformere, iterere og endre data i en matrise:

$ frukt = samle ($ frukt);
$ frukt = $ frukt-> avvis (funksjon ($ frukt) {
   returner $ frukt === 'eple';
}) -> toArray ();
['pære', 'banan', 'jordbær']

For mer informasjon, sjekk den omfattende dokumentasjonen om samlinger.

Når du jobber med Query Builders, returnerer metoden -> get () en samling-forekomst. Men vær forsiktig så du ikke forveksler Collection med en spørringsbygger:

  • Sett inn Query Builder, vi hentet ingen data. Vi har mange spørringsrelaterte metoder: orderBy (), hvor (), etc.
  • Etter at vi traff -> få (), blir dataene hentet, minnet har blitt brukt, det returnerer en samling-forekomst. Noen Query Builder-metoder er ikke tilgjengelige, eller de er, men de heter forskjellige. Sjekk tilgjengelige metoder for mer.

Hvis du kan filtrere data på Query Builder-nivå, gjør det! Ikke stol på å filtrere når det gjelder samling-forekomsten - du vil bruke for mye minne noen steder, og det vil du ikke. Begrens resultatene og bruk indekser på DB-nivå.

Bruk pakker og ikke finn opp hjulet på nytt

Her er noen pakker jeg bruker:

  • Laravel Bladdirektiv
  • Laravel CORS (beskytt rutene dine mot andre opphav)
  • Laravel Tag Helper (bedre bruk av HTML-koder i Blade)
  • Laravel Sggggable (nyttig når det gjelder å generere snegler)
  • Laravel Responder (bygg enklere JSON API)
  • Bildeintervensjon (håndter bilder med stil)
  • Horisont (veiledningskøer med minimal konfigurasjon)
  • Socialite (minimal konfigurasjon for innlogging med sosiale medier)
  • Pass (OAuth-implementering for ruter)
  • Spatie's ActivityLog (sporaktivitet for modeller)
  • Spatie's Backup (sikkerhetskopifiler og databaser)
  • Spatie's Blade-X (definer dine egne HTML-koder; fungerer bra med Laravel Tag Helper)
  • Spatias mediebibliotek (enkel måte å knytte filer til modeller)
  • Spatie's Response Cache (svar fra cache controller)
  • Spatie's Collection Makroer (flere makroer på samlinger)

Her er noen pakker jeg har skrevet:

  • Vennlig (som, følg og blokker som i sosiale medier)
  • Planlegg (lag rutetider og sjekk mot timer og dager)
  • Rangering (takstmodeller)
  • Guardian (tillatelsessystem, den enkle måten)

For vanskelig å forstå? Nå meg!

Hvis du har flere spørsmål om Laravel, hvis du trenger hjelp med informasjon relatert til DevOps eller bare vil si takk !, kan du finne meg på Twitter @rennokki!