Tartalomjegyzék

< Laravel

Laravel jegyzet

A jegyzet Laravel 8 verzióhoz készült

Projekt készítése

A projektek készítéséhez és működéséhez szükséges, hogy telepítve legyen a php és a composer programok, a projekteket parancssorban tudjuk létrehozni. Készítsünk egy új projektet:

composer create-project laravel/laravel jegyzetProject

Útvonalak

Az útvonalak biztosítják a végpontok és a végrehajtó osztályok, illetve a nézetek között a kapcsolatot. A végpontokat, útvonalakat két helyen tudjuk felvenni, komplex alkalmazás esetén a routes/web.php állományban, REST API esetében a routes/api.php fájlban.

Szintaktika

Nézet alapú útvonal:

Route::view( "<végpont>", "<nézet fájl>" );

Függvény alapú útvonal:

Route::<method>( "<végpont>", function( [paraméterek] ) {
    return view( "<nézet fájl>" );
});

Osztály alapú útvonal:

Route::<method>( "<végpont>", [ <osztály név>::class, "metódus név" ]);

Használat

Hozzunk létre egy nézet fájlt a resources/views könyvtárban jegyzet.blade.php néven (nézetekről bővebben a nézetek szekcióban), a tartalma:

<h1>Jegyzet nézet</h1>

készítsük el a nézet alapú útvonalat a megjelenítéshez.

Route::view( "/jegyzet", "jegyzet" );

Nézzük meg böngészőben. Készítsünk függvény alapú útvonalat ugyanehhez a nézethez.

Route::get( "/jegyzet", function() {
    return view( "jegyzet" );
});

Nézzük meg böngészőben, a tartalom nem változhat. Készítsünk osztály alapú útvonalat a jegyzet nézethez. Ehhez először készítsünk egy vezérlőt parancssorban.

php artisan make:controller NoteController

Készítsünk egy index metódust amely visszaadja a nézetünket.

<?php
 
namespace App\Http\Controllers;
 
use Illuminate\Http\Request;
 
class NoteController extends Controller {
 
    public function index() {
        return view( "jegyzet" );
    }
}

Hozzuk létre az útvonalat amely a vezérlőn keresztül jeleníti meg a nézetet.

Route::get( "/jegyzet", [ NoteController::class, "index" ]);

Az útvonal megadásánál get metódust használunk, első paraméter a végpont, második paraméter egy tömb, melynek első eleme a vezérlő osztály, másokik eleme a hivott metódus. Ahhoz, hogy az útvonal és a vezélő között kapcsolat legyen be kell emelnünk a vezérlő osztályt a web.php fájlba.

use App\Http\Controllers\NoteController;

Próbáljuk ki böngészőben.


Paraméterek átadása

A kérések felől érkező paraméterek fogadásához alakítsuk át az index metódust a vezérlőben. Küldjünk egy id paramétert.

public function index( $noteId ) {
        echo "<h3>Id: </h3>" . $noteId;
 
        return view( "jegyzet" );
    }

Az id paraméter az útvonalon érkezik, tehát ott kell átvennünk először. Írjuk át az útvonalat, hogy várjon egy paramétert. Laravel szintaxis szerint a paraméterek kapcsos zárójelek között érkeznek és automatikusan kerülnek a hívott metódusba.

Route::get( "/jegyzet/{id}", [ NoteController::class, "index" ]);

Ha paraméter opcionális akkor egy kérdőjellel jelőljük meg a beérkező paramétert, az útvonal így néz ki:

Route::get( "/jegyzet/{id?}", [ NoteController::class, "index" ]);

Ebben az esetben a vezélőben a fogadott paramétert kötelező ellátni alapértelmezett értékkel.

public function index( $noteId = null ) {
        echo "<h3>Id: </h3>" . $noteId;
 
        return view( "jegyzet" );
    }

Fogadhatunk több paramétert is.

Route::get( "/jegyzet/{id}/{name}", [ NoteController::class, "index" ]);
public function index( $noteId, $name ) {
        echo "<h3>Id: </h3>" . $noteId . ", " . $name;
 
        return view( "jegyzet" );
    }

Ha az egyik paraméter opcionális:

Route::get( "/jegyzet/{id}/{name?}", [ NoteController::class, "index" ]);
public function index( $noteId, $name = "" ) {
        echo "<h3>Id: </h3>" . $noteId . ", " . $name;
 
        return view( "jegyzet" );
    }

Beérkező paraméterek ellenőrzése reguláris kifejezéssel:

Route::get( "jegyzet/{id}/{name}", function( $id, $name ) {
 
    echo "<h1>Id: ".$id."</h1>";
    echo "<h1>Név: ".$name."</h1>";
 
})->where([ "id" => "[0-9]+", "name" => "[a-zA-z]+" ]);

Nézetek

A nézetek html állományok melyek a resources/views könyvtárban helyezkednek el néhány kivételtől eltekintve (pl. komponensek). Ezeknek a fájloknak kötelezően <nézetnév>.blade.php kiterjesztése kell, hogy legyen mivel a vezérlők és az útvonalon létrehozott függvények alapértelmezetten ebben a könyvtárban és ezzel a kiterjesztéssel keresik a nézet állományokat.

Szintaxis a nézetekben

Kommentek

<!-- HTML komment -->
// egysoros php komment
/*
Több
soros php
komment
*/
{{-- Laravel komment --}}

Kifejezések kiértékelése

<?php
echo 1 + 1;
?>
 
{{ 1 + 1 }}

Php nyelven függvényeket használunk Laravelben direktívákat melyeket @ karakterrel vezetünk be és a megnyitott direktívákat le kell zárni.

<?php
   if( isset( $name )) {
       echo $name;
   }
?>
 
@isset( $name )
    $name
@endisset
 
<?php
if( empty( $name )) {
       echo "Üres";
   }
?>
 
@empty( $name )
   Ez Üres
@endempty
 
<?php
if( count( $names ) > 0 ) {
       echo "Nem üres";
   }
?>
 
@if( count( $names) > 0 )
   Ez nem üres
@endif
 
<?php
   $i = 0;
   if( $i == 0 ) {
       echo "nulla";
   }elseif( $i == 1 ) {
       echo "egy";
   }else {
       echo "más";
   }
?>
 
@if ( $i == 0 )
   Nulla
@elseif ( $i == 1 )
   Egy
@else
   Más
@endif
 
<?php
for( $i = 0; $i < 5; $i++ ) {
   echo $i;
}
?>
 
@for( $i = 0; $i < 5; $i++ )
   {{$i}}
@endfor

Nézetek használata

Hozzunk létre egy about.blade.php nézetet amelyben helyezzünk el egyszerű tartalmat és készítsünk függvény alapú útvonalat amelyben fogadjunk egy név paramétert és egy asszociatív tömbben adjuk át a nézetnek.

<h1>Rólunk oldal</h1>
Route::get( "/rolunk/{name}", function( $name ) {
    return view( "about", [ "name" => $name ] );
});

A nézetben dupla kapcsos zárójelek között vegyük át a paramétert, ez automatikusan kerül át.

<h1>Rólunk oldal</h1>
{{ $name }}

Több érték esetén vegyük fel egy tömbben a paramétereket.

Route::get( "/rolunk", function() {
    $data = [
        "name" => "János",
        "email" => "jani@gmail.com"
    ];
    return view( "about", [ "data" => $data ]);
});

Átadhatunk több értéket a compact függvényen keresztül is.

Route::get( "/about", function() {
    $name = "János";
    $email = "jani@gmail.com";
    return view( "about", compact( "name", "email" ));
});
<h1>Rólunk oldal</h1>
{{ $name }}
{{ $email }}

Adatok átadása a nézetnek vezélőn keresztül. Készítsünk egy kontrollert és helyezzünk el benne egy index metódust.

php artisan make:controller ServiceController
public function index() {
 
        $name = "Béla";
        $email = "bela@gmail.com";
 
        return view( "service", compact( "name", "email" ));
    }

Emeljük be a web.php fájlban az osztályt és írjuk meg az útvonalat

Route::get( "/szolgaltatas", [ ServiceController::class, "index" ]);

Készítsünk nézetet service.blade.php néven.

<h1>Szolgáltatások oldal</h1>
{{ $name }}
{{ $email }}

Nézetek beemelése másik nézetbe

Hozzunk létre egy templates könyvtárat a resources/views könytárban, abban egy header.blade.php állományt egyszerű tartalommal.

<h1>Header tartalom</h1>

Legyen egy útvonalunk amely a rólunk oldalt adja vissza.

Route::get( "/rolunk", function() {
    return view( "about" );
});

Az about.blade.php állományban emeljük be a header.blade.php tartalmát az @include direktívával.

@include( "templates.header" )
 
<h1>Rólunk oldal</h1>

Tegyük fel, hogy külön vannak admin és normál fájljaink. Kszítsünk egy admin könyvtárat és hozzunk létre benne egy about_admin.blade.php állományt egyszerű tartalommal, ide is emeljük be a headert és fogadjunk néhány paramétert.

@include( "templates.header" )
 
<h1>Admin rólunk oldal</h1>
 
{{ print_r( $names ) }}

Látható, hogy a header tartalom dinamikusan kerül be minden nézetbe ahol meghívjuk. Vegyük fel az útvonalat a nézethez és adjuk át az adatokat.

Route::get( "/rolunk-admin", function() {
    return view( "admin.about_admin", [ "names"
        => [ "Béla", "Géza", "Péter", "Kata" ]]);
});

Nézzük meg böngészőben, most egy array-t kapunk vissza az adatokkal. A szebb megjelenés érdekében használjuk a @foreach direktívát.

<h1>Admin rólunk oldal</h1>
 
{{ print_r( $names ) }}
 
@foreach( $names as $name )
    <h3>{{ $name }}</h3>
@endforeach

Elrendezések

Hozzunk létre egy új könyvtárat a views könyvtárban layouts néven. Ebben készítsünk egy állományt master.blade.php néven.

<html>
    <head>
        <title>Üdvözlet - főoldal</title>
    </head>
    <body>
        <h1>Master tartalom</h1>
    </body>
</html>

Legyen egy útvonalunk ami az about nézetet adja vissza.

Route::get( "/rolunk", function() {
    return view( "about" );
});

Az extends direktívával emeljük be a nézetbe a master.blade.php tartalmát.

@extends( "layouts.master" )
 
<h1>Rólunk oldal</h1>

Ha van még egy állományunk, be tudjuk emelni a master tartalmát dinamikusan oda is. Hozzunk létre egy új állományt products.blade.php néven a resources/views könyvtárban és oda is emeljük be a master.blade.php tartalmát.

@extends( "layouts.master" )
 
<h1>Termékek oldal</h1>

Készítsünk útvonalat a nézethez.

Route::get( "termekek", function() {
    return view( "products" );
});

Alakítsuk át a master.blade.php állományt, hogy dinamikusan tudjon tartalmat fogadni a @yield direktívával. Dinamikusan kerül beemelésre a cím és a body tartalma más nézetekből.

<html>
    <head>
        <title>Üdvözlet - @yield( "title" )</title>
    </head>
    <body>
        <h1>Master tartalom</h1>
        @yield( "content" )
    </body>
</html>

Hozzuk létre az about.blade.php állományban a dinamikusan beemelni kívánt tartalmat.

@extends( "layouts.master" )
 
@section( "title", "Rólunk" )
 
@section( "content" )
    <h1>Rólunk oldal</h1>
@endsection

A beemelt tartalom nevének egyeznie kell a nézetben létrehozott szekcio nevével.


Komponensek

A komponensek hasonlóan a layoutokhoz többszőr felhasználható elemek melyeket be tudunk emelni a nézeteinkbe. A komponens létrehozásakor két könyvtár jön létre, az egyik az app a másik a resources könyvtárban. Hozzuk létre a komponenst

php artisan make:component Message

Nézzük meg a könyvtárszerkezetet, létrejött az app könyvtárban egy View/Components, abban egy Message.php állomány. A resources könyvtárban szintén egy components könyvtár, abban egy message.blade.php állomány. Nézzünk bele az app/View/Components/Message.php állományba. Az osztály a Component osztályból öröklődik, és van egy konstruktora illetve egy render metódusa ami a components.message nézetet hívja. Alakítsuk át az about.blade.php állományt a komponens fogadására, majd tegyük meg a products.blade.php állományban is.

@extends( "layouts.master" )
 
@section( "title", "Rólunk" )
 
@section( "content" )
    <h1>Rólunk oldal</h1>
@endsection
 
<x-message/>
@extends( "layouts.master" )
 
@section( "title", "Termékek" )
 
@section( "content" )
    <h1>Termékek oldal</h1>
@endsection
 
<x-message/>

Készítsük el az üzenetet a message.blade.php állományban.

<div>
    <h3>Szöveg a komponensből</h3>
</div>

A komponenseknek adhatunk át paramétereket is. Alakítsuk át az about.blade.php állományt, hogy hibaüzenetet tudjunk átadni.

@extends( "layouts.master" )
 
@section( "title", "Rólunk" )
 
@section( "content" )
    <h1>Rólunk oldal</h1>
@endsection
 
<x-message type="error" message="Hiba üzenet"/>

A komponens osztályban (app/view/Message.php) át kell venni a két paramétert mint osztályváltozó.

public $type;
public $message;
 
    public function __construct( $type, $message ) {
 
        $this->type = $type;
        $this->message = $message;
    }

Alakítsuk át a message.blade.php állományt, hogy fogadni tudja a komponens paramétereit.

<div>
    <h3>Szöveg a komponensből</h3>
    {{ $type }} és {{ $message }}
</div>

Alakítsuk át a products.blade.php állományt más paraméterek fogadására.

@extends( "layouts.master" )
 
@section( "title", "Termékek" )
 
@section( "content" )
    <h1>Termékek oldal</h1>
    <x-message type="success" message="Siker üzenet"/>
@endsection

A statikus paraméterek helyett átadhatunk dinamikusan is paramétereket. Vegyük fel az útvonalaknál az új hivatkozásokat.

Route::get( "/rolunk", function() {
    return view( "about", [ "page" => "Rólunk" ] );
});
Route::get( "/termekek", function() {
    return view( "products", [ "page" => "Termékek" ]  );
});

A komponens beillesztésekor vegyük át a paramétert az útvonalról az about.blade.php állományban.

@extends( "layouts.master" )
 
@section( "title", "Rólunk" )
 
@section( "content" )
    <h1>Rólunk oldal</h1>
    <x-message type="error"
               message="Hiba üzenet"
               :page="$page"/>
@endsection

Ugyanezt tegyük meg a products.blade.php állományban is.

@extends( "layouts.master" )
 
@section( "title", "Termékek" )
 
@section( "content" )
    <h1>Termékek oldal</h1>
    <x-message type="error"
               message="Hiba üzenet"
               :page="$page"/>
@endsection

A dinamikusan átvett paramétereket kettősponttal kell bevezetni és nincs szükség a kapcsos záró jelekre. A komponens osztályban is vegyük fel az új paramétert.

public $type;
public $message;
public $page;
 
public function __construct( $type, $message, $page ) {
 
    $this->type = $type;
    $this->message = $message;
    $this->page = $page;
}

A message nézetben egészítsük ki a kiírást az új paraméterrel.

<div>
    <h3>Szöveg a komponensből</h3>
    {{ $type }} és {{ $message }} és {{ $page }}
</div>

A tartalom az útvonalról dinamikusan kerül a komponens osztályba, onnan a komponens nézetbe ami be van emelve a normál nézetbe.


Slotok

A slotok extra tartalmak átadására szolgálnak. Hozzunk létre egy Allert komponenst.

php artisan make:component Alert

Az app/Components és a views/components könyvtárakban létrejött a szokások két állomány, az osztály és a nézet. Alakítsuk át a products.blade.php nézetünket.

@extends( "layouts.master" )
 
@section( "title", "Termékek" )
 
@section( "content" )
    <h1>Termékek oldal</h1>
    <x-alert>Plussz tartalom a termékek oldalról</x-alert>
@endsection

Készítsük fel az alert.blade.php állományunkat a dinamikus tartalom fogadására. A slot változónak a segítségével kapja meg az értéket a nézet ami a products nézetből érkezik.

<div>
    {{ $slot }}
</div>

Alakítsuk át az about.blade.php állományt is, hogy lássuk tényleg dinamikusan érkeznek az adatok.

@extends( "layouts.master" )
 
@section( "title", "Rólunk" )
 
@section( "content" )
    <h1>Rólunk oldal</h1>
    <x-alert>Plussz adat a rólunk oldalról</x-alert>
@endsection

Bővítsük a slot szekciót további adatokkal mindkét állományban.

@extends( "layouts.master" )
 
@section( "title", "Rólunk" )
 
@section( "content" )
    <h1>Rólunk oldal</h1>
    <x-alert>
        Plussz adat a rólunk oldalról
        <x-slot name="title">
            További plussz a rólunk oldalról
        </x-slot>
    </x-alert>
@endsection
@extends( "layouts.master" )
 
@section( "title", "Termékek" )
 
@section( "content" )
    <h1>Termékek oldal</h1>
    <x-alert>
        Plussz adat a termékek oldalról
        <x-slot name="title">
            További plussz a termékek oldalról
        </x-slot>
    </x-alert>
@endsection

Vegyük fel a komponens nézetben (resources/components/alert.blade.php) az új paramétert

<div>
    {{ $slot }}
    <h3>Oldal típus: {{ $title }}</h3>
</div>

Saját hibaoldalak létrehozása

Ha nem létezik az oldal amit meg szeretnénk jeleníteni, akkor 404 -es hibát kapunk. A Laravelben létezik egy alapértelmezett oldal ami megjelenik ebben az esetben. Útvonala:

vendor\laravel\framework\src\illuminate\Foundation\Exceptions\views\

Próbáljuk ki írjuk át a tartalmát. Természetesen a vendor könyvtárt a composer hozza létre így amit itt módosítunk egy esetleges áttelepítésnél el fog veszni. Ha saját hibaüzenet szeretnénk akkor ki kell vinni a vendor könyvtáron kívülre. Hozzuk létre a saját hibakönyvtárunkat.

php artisan vendor:publish --tag=laravel-errors

Ezt az üzenetet kell látnunk.

Copied Directory [/vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/views] To [/resources/views/errors]
Publishing complete.

A resources\views\errors könyvtárban létrejöttek a hibaüzeneteknek a nézet fájljai. Itt találunk egy minimal.blade.php állományt ami leírja a hibaoldalakat, az egyes oldalakon pedig örököljük ezeket a beállításokat és elkészíthetjük a saját üzenetünket.


Formok

Hozzunk létre egy vezérlőt StudentController néven.

php artisan make:controller StudentController

Hozzunk létre benne egy metódust ami egy nézetet fog visszaadni.

class StudentController extends Controller {
 
    public function newStudent() {
 
        return view( "new_student");
    }
}

Hozzuk létre a nézet fájlt my-student.blade.php néven, állítsunk be útvonalat osztály alapon a nézet elérésére, emeljük be a web.php állományba a StudentControllert.

Route::get( "/uj-tanulo", [ StudentController::class, "newStudent" ]);

A nézet fájl tartalma

<h1>Tölts ki a mezőket</h1>
<form action="submit-student method="post">
    <p>
        <label for=""> Név: </label>
        <input type="text" name="name" placeholder="Név">
    </p>
    <p>
        <label for=""> Email: </label>
        <input type="text" name="email" placeholder="Email">
    </p>
    <p>
        <label for=""> Telefon: </label>
        <input type="text" name="phone" placeholder="Telefon">
    </p>
    <p>
        <button type="submit">Küldés</button>
    </p>
</form>

Hozzuk létre az adatok küldéséhez szükséges útvonalat.

Route::post( "/submit-student", [ StudentController::class, "submitStudent" ]);

A vezérlőben hozzuk létre a submitStudent metódust.

public function submitStudent( Request $request ) {
 
    print_r( $request->all() );
}

Próbáljuk ki a böngészőben, 419 page expired hibát fogunk kapni. El kell helyezni egy csrf direktívát a formon belül, ez generál egy tokent ami azonosítja az ürlapunkat.

<form action="submit-student">
    {{ csrf_field() }}
    <p>
        <label for=""> Név: </label>
        <input type="text" name="name" placeholder="Név">
    </p>

Az all metódus minden adatot kiolvas a requestből. ha csak a névre van szükségünk akkor használhatjuk az input metódust is.

public function submitStudent( Request $request ) {
 
    print_r( $request->input( "name" ) );
}

Ha egy útvonalon szeretnénk beállítani a get és a post metódusokat akkor a match metódust kell használni. Alakítsuk át az útvonalat.

Route::match( [ "get", "post" ], "uj-tanulo", [ StudentController::class, "newStudent" ]);

Alakítsuk át a vezérlő osztályt

public function newStudent() {
 
    if( $request->isMethod( "post" )) {
 
        print_r( $request->input( "name" ));
    }
    return view( "new_student");
}

A formon ne felejtsük el átírni az action értékét uj-tanulora. Nézzük meg a böngészőben.


Validálás

Három féle validálási módszer létezik. validate() metódus, Request:Validation osztály és a manuális validáció. Ha üresen küldjük el az űrlapot, az elmegy de nem lesz adat. Létre kell hozni a szerver oldali érvényesítést ami megköveteli az űrlap elemek kitöltését. A Request osztály alapértelmezetten szolgáltatja a validate() metódust. Alakítsuk át a StudentControllert, hogy alkalmas legyen a validálásra.


validate metódus

public function newStudent( Request $request ) {
 
    if( $request->isMethod( "post" )) {
 
        $request->validate([
            "name" => "required",
            "email" => "required",
            "phone" => "required"
        ]);
    }
    return( view( "new_student" ) );
}

Ha a böngészőben üresen hagyunk mezőket, nem kapunk hibát de automatikusan átirányít vissza a beviteli oldalra. Ha a hibát is látni szeretnénk alakítsuk át a form nézetet a hibaüzenet fogadásához.

<h1>Tölts ki a mezőket</h1>
 
@if( $errors->any() )
    <ul>
        @foreach( $errors->all() as $error )
            <li>
                {{ $error }}
            </li>
        @endforeach
    </ul>
@endif
 
<form action="uj-tanulo" method="post">
    {{ csrf_field() }}
    <p>
        <label for=""> Név: </label>
        <input type="text" name="name" placeholder="Név">
    </p>
    <p>
        <label for=""> Email: </label>
        <input type="text" name="email" placeholder="Email">
    </p>
    <p>
        <label for=""> Telefon: </label>
        <input type="text" name="phone" placeholder="Telefon">
    </p>
    <p>
        <button type="submit">Küldés</button>
    </p>
</form>

További feltételeket szabhatunk a validátornak.

public function newStudent( Request $request ) {
 
    if( $request->isMethod( "post" )) {
 
        $request->validate([
            "name" => "required|min:4|max:20",
            "email" => "required|unique:students,email",
            "phone" => "required|digits_between:9,11"
        ]);
    }
    return( view( "new_student" ) );
    }

A név minimum 4 de maximum 20 karakter lehet, az email cím egyedinek kell, hogy legyen a students tábla email mezőjében, a telefonszám karaktereinek a száma 9 és 11 között kell, hogy legyen. Írassuk ki a bevitt értékeket, ha hiba nélkül el tudjuk küldeni a formot, majd irányítsuk át a felhasználót a beviteli oldalra.

public function newStudent( Request $request ) {
 
    if( $request->isMethod( "post" )) {
 
        $request->validate([
            "name" => "required|min:4|max:20",
            "email" => "required",
            "phone" => "required|digits_between:9,11"
        ]);
    }
    print_r( $request->all() );
    return view( "new_student" ) ;
}

Most a hibaüzeneteket egyben kapjuk, ha szeretnénk, hogy a mezőknél jelenjenek meg alakítsuk át a form nézetet.

<h1>Tölts ki a mezőket</h1>
 
<form action="uj-tanulo" method="post">
    {{ csrf_field() }}
    <p>
        <label for=""> Név: </label>
        <input type="text" name="name" placeholder="Név">
        <br>
        @error( "name" )
            <span>{{ $message }}</span>
        @enderror
    </p>
    <p>
        <label for=""> Email: </label>
        <input type="text" name="email" placeholder="Email">
        <br>
        @error( "email" )
            <span>{{ $message }}</span>
        @enderror
    </p>
    <p>
        <label for=""> Telefon: </label>
        <input type="text" name="phone" placeholder="Telefon">
        <br>
        @error( "phone" )
            <span>{{ $message }}</span>
        @enderror
    </p>
    <p>
        <button type="submit">Küldés</button>
    </p>
</form>

Ha egyéni hibaüzenetet szeretnénk adni, egészítsük ki a StudentController osztályt. Egy újabb tömbben felvehetjük a saját üzeneteinket.

public function newStudent( Request $request ) {
 
    if( $request->isMethod( "post" )) {
 
        $request->validate([
            "name" => "required|min:4|max:20",
            "email" => "required",
            "phone" => "required|digits_between:9,11"
        ], [
            "name.required" => "Név mező kötelező",
            "email.required" => "Email mező kötelező",
            "phone.required" => "Telefon mező kötelező"
        ]);
    }
    print_r( $request->all() );
    return view( "new_student" );
}

Request validation

Alakítsuk át a StudentController osztályt, hozzunk létre egy új metódust ami szintén a new-student nézetet adja vissza.

public function addStudent() {
 
    return view( "new-student" );
}

Hozzunk létre egy új útvonalakat a web.php állományban.

Route::get( "/add-student", [ StudentController::class, "addStudent" ]);
Route::post( "/submit-student", [ StudentController::class, "submitStudent" ]);

A form nézetben cseréljük ki az action értékét

<form action="submit-student" method="post">

Hozzuk létre a StudentControllerben a submitData metódust és ellenőrizzük, hogy valóban ebbe a metódusba jutunk.

public function submitStudent( Request $request ) {
 
    print_r( $request->all() );
}

Hozzunk létre egy request osztályt.

php artisan make:request StoreStudentData

Az app\Http\Requests könyvtárban létrejött a StoreStudentData osztály. A StudentControllerben emeljük be az új Request osztályt.

use App\Http\Requests\StoreStudentData;

Alakítsuk át a request paraméter típusát StoreStudentData -ra.

public function submitStudent( StoreStudentData $request ) {
 
    print_r( $request->all() );
}

A SubmitStudentData osztály rules metódusában tudjuk felvenni a validálási szabályainkat.

public function rules() {
 
    return [
        "name" => "required|min:6",
        "email" => "required",
        "phone" => "required"
    ];
}

Mivel csak az űrlap érvényesítésére használuk az osztályt és nem akarunk bejelentkezési adatokat validálni az authorize metódusban csak átálítjuk a false értéket true -ra.

public function authorize() {
 
    return true;
}

Az osztály használatához alakítsuk át a StudentController submitData metódusát.

public function submitStudent( StoreStudentData $request ) {
 
    $request->validated();
    print_r( $request->all() )
}

A request -ben érkező adataink automatikusan a validáló osztály rules metódusába kerülnek és megtörténik az ellenőrzés. A hibaüzeneteket ugyanúgy a nézet fájlnak küldi. Ha rendben lefut a validáció vissza kell kapnunk az összes adatot. Ha a laravel eredeti hiba üzeneteit szeretnénk felülírni a saját üzeneteinkkel, hozzunk létre a StoreStudentData osztályban egy új metódust és ott adjuk át a szükséges szövegeket.

public function messages() {
 
    return [
        "name.required" => "A név mező kitöltése kötelező!",
        "email.required" => "Az email mező kitöltése kötelező!",
        "phone.required" => "A telefon mező kitöltése kötelező!",
        "name.min" => "A név minimum 6 karakter!"
    ];
}

Manuális validálás

Emeljük be a Validátor osztályt és alakítsuk át a submitData metódust a StudentController osztályban.

use Illuminate\Support\Facades\Validator;
public function submitStudent( Request $request ) {
 
    $validate = Validator::make( $request->all(), [
        "name" => "required",
        "email" => "required",
        "phone" => "required"
    ], [
        "name.required" => "A név mező kötelező!"
    ]);
 
    if( $validate->fails() ) {
 
        return redirect( "uj-tanulo" )->withErrors( $validate )->withInput();
    }
    print_r( $request->all() );
}

A validátornak át kell adni először az adatokat, majd a szabályokat végül az üzeneteket. Ha a validáció sikeresen végbemegy akkor kiírjuk az összes adatot a formból, ha hibás adatok érkeznek akkor az if feltétel fog lefutni, átirányít vissza a beviteli oldalra és kiírja a hibákat. Ha egyéni üzeneteket szeretnénk ugyanúgy egy második tömbben tudjuk átadni. Ha üres mezőt kapunk a már kitöltöttet szeretnénk megtartani. Bővítsük ki a form nézetünket a values értékkel. Vegyük fel dupla kapcsos zárójelek között a megtartani kívánt értéket.

<h1>Tölts ki a mezőket</h1>
 
<form action="submit-student" method="post">
    {{ csrf_field() }}
    <p>
        <label for=""> Név: </label>
        <input type="text" name="name" value="{{ old('name') }}" placeholder="Név">
        <br>
        @error( "name" )
            <span>{{ $message }}</span>
        @enderror
    </p>
    <p>
        <label for=""> Email: </label>
        <input type="text" name="email" value="{{ old('email') }}" placeholder="Email">
        <br>
        @error( "email" )
            <span>{{ $message }}</span>
        @enderror
    </p>
    <p>
        <label for=""> Telefon: </label>
        <input type="text" name="phone" value="{{ old('phone') }}" placeholder="Telefon">
        <br>
        @error( "phone" )
            <span>{{ $message }}</span>
        @enderror
    </p>
    <p>
        <button type="submit">Küldés</button>
    </p>
</form>

Adatbázis

Kapcsolódás

Két lehetőség van a kapcsolat kialakítására, a .env állomány, ott találhatóak a környezeti változók melyek az adatbázis kapcsolathoz használhatóak. A másik a config könyvtárban a database.php állomány. Valójában az utóbbi a .env állományból olvassa ki az adatokat. A kapcsolódáshoz létre kell hozni egy adatbázist, annak léteznie kell. Állítsuk be a .env állományban az eléréshez szükséges paramétereket. Mysql és XAMPP esetén

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=adatbázisnév
DB_USERNAME=root
DB_PASSWORD=

Nyissuk meg a config / database.php fájlt ott az alapértelmezett konfig fájl a .env. Abból olvassa ki a szükséges paramétereket.

'default' => env('DB_CONNECTION', 'mysql'),

Lejjebb találhatóak a kapcsolati adatok. Ha .env állományból ki tudja olvasni a kulcsot akkor azt használja egyébként az alapértelmezett érték kerül felhasználásra.

'mysql' => [
    'driver' => 'mysql',
    'url' => env('DATABASE_URL'),
    'host' => env('DB_HOST', '127.0.0.1'),
    'port' => env('DB_PORT', '3306'),
    'database' => env('DB_DATABASE', 'forge'),
    'username' => env('DB_USERNAME', 'forge'),
    'password' => env('DB_PASSWORD', ''),
    'unix_socket' => env('DB_SOCKET', ''),
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    'prefix' => '',
    'prefix_indexes' => true,
    'strict' => true,
    'engine' => null,
    'options' => extension_loaded('pdo_mysql') ? array_filter([
        PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
    ]) : [],
],

DB osztály

Hozzunk létre egy adatbázist amelyben CRUD műveleteket tudunk készíteni. Készítsünk egy StudentController vezérlőt és emeljük be a DB osztályt.

use \Illuminate\Support\Facades\DB;

Készítsünk egy getUsers metódust amivel le tudjuk kérdezni az adatbázisból az adatokat, használjuk a DB osztály select metódusát és állítsunk be osztály alapú útvonalat a metódushoz. A web.php állományban emeljük be a StudentController osztályt.

public function getStudents() {
 
    echo "<pre>";
    $students = DB::select( "SELECT * FROM students" );
    print_r( $students );
}
Route::get( "/tanulok", [ StudentController::class, "getStudents" ]);

Ha például csak a neveket szeretnénk látni, a lekérdezés maradhat, csak az adatok kiolvasását tegyük ciklusba és csak a neveket jelenítsük meg.

public function getStudents() {
 
    $students = DB::select( "SELECT * FROM students" );
 
    foreach( $students as $student ) {
 
        print_r( $student->name . "<br>" );
    }
}

Ha feltételt szeretnénk szabni a lekérdezéshez tovább kell folytatni az sql utasítást. A where záradéknak három féle képpen lehet átadni a feltételt, itt láthatjuk mind a hármat.

public function getStudents() {
 
    $students = DB::select( "SELECT * FROM students WHERE id = 2" );
                                                        //"id = ?", [ 2 ]
    echo "<pre>";                                       //"id = :id", [ "id" => 2 ]
    print_r( $students );
}

Adat beszúráshoz szintén a DB osztályt használhatjuk. Hozzunk létre egy insertUser metódust, ahol meghívjuk az insert metódust melynek első paramétere az sql utasítás, a második egy tömb ami az adatot tartalmazza. Készítsük el ehhez a metódushoz is az útvonalat.

Route::get( "/uj-tanulo", [ StudentController::class, "insertStudent" ]);
public function insertStudent() {
 
DB::insert( "INSERT INTO students( name, email, phone ) VALUES (?,?,?)", [
 
            "Pólika Pál",
            "pali@teszt.hu",
            "789312654"
        ]);
}

Próbáljuk ki böngészőben,ha üres oldalt kapunk akkor sikeresen végbe ment az írási folyamat, ellenkező esetben hibát kapnánk. Ellenőrizzük az adatbázisban. Adatbázis tábla adatok frissítéséhez hozzunk létre egy új metódust a StudentController osztályban és állítsuk is be az útvonalat.

public function updateStudent() {
 
    $student = DB::update( "UPDATE students SET email = ? WHERE id = ?",
                           [ "palika@teszt.hu", 5 ]);
 
    print_r( $student );
}
Route::get( "/frissit-tanulo", [ StudentController::class, "updateStudent" ]);

Próbáljuk ki böngészőben, ha az eredmény 1 akkor az update sikeresen lefutott. Adat törléséhez hozzuk létre a törlést végző metódust és az útvonalat.

Route::get( "/torol-tanulo", [ StudentController::class, "deleteStudent" ]);
public function deleteStudent() {
 
    $student = DB::delete( "DELETE FROM students WHERE id = :id", [ "id" => 5 ]);
 
    print_r( $student );
}

Ha az eredmény 1 akkor a törlés sikeresen végbement.


Migráció

Hozzunk létre egy migrációs fájlt amely egy students táblát fog létrehozni.

php artisan make:migration create_students_table

Létrejön a migrációs fájl amelyben 2 metódus található. Az up és a down. Ezek automatikusan hívódnak a migráció megfelelő műveletével. Futtassuk le a migrációs fájlt.

php artisan migrate

Létrejöttek az adatbázis táblák és mezők. A students tábla mellett még létrejöttek a failed_jobs, migrations, password_resets, personal_access_tokens és a users táblák. A mirgáció visszavonható a rollback utasítással. Adjuk ki.

php artisan migrate:rollback

Csak egy tábla maradt a migrations ami az előző migrációkat tárolja. Egészítsük ki a migrációs fájlt a szükséges adatokkal és futtasuk le.

public function up() {
 
    Schema::create('students', function (Blueprint $table) {
        $table->id();
        $table->string( "name", 50 );
        $table->string( "email", 50 );
        $table->string( "phone", 20 );
        $table->integer( "age" );
        $table->enum( "gender", [ "férfi", "nő", "egyéb" ]);
        $table->text( "address" );
        $table->timestamps();
    });
}

Ellenőrizzük az adatbázisban, a táblák létrejöttét. A mezők módosításához használhatunk kiegészítő metódusokat. nullable megengedi, hogy a rekordnak bizonyos mezői null értéket tároljanak. default null esetén beállít egy alapértelmezett értéket. comment megjegyzést lehet fűzni a mezőhöz. Végezzük el ezeket a módosításokat.

public function up() {
 
    Schema::create('students', function (Blueprint $table) {
 
        $table->id();
        $table->string( "name", 50 );
        $table->string( "email", 50 )->nullable();
        $table->string( "phone", 20 )->nullable();
        $table->integer( "age" )->default( 1 );
        $table->enum( "gender", [ "férfi", "nő", "egyéb" ]);
        $table->text( "address" )->comment( "Pontos cím" );
        $table->timestamps();
    });
}

Most újra kellene futtatni a rollback és a migrate parancsokat, erre van egy összevont módszer amely mindkettőt megcsinálja.

php artisan migrate:refresh

Ha nem szeretnénk, hogy a táblánkban null értékkel jöjjön létre a created_at és az updated_at mező, egészítsük ki a migrációs fájlt és futtassuk újra refresh utasítást.

public function up() {
 
    Schema::create('students', function (Blueprint $table) {
        $table->id();
        $table->string( "name", 50 );
        $table->string( "email", 50 )->nullable();
        $table->string( "phone", 20 )->nullable();
        $table->integer( "age" )->default( 1 );
        $table->enum( "gender", [ "férfi", "nő", "egyéb" ]);
        $table->text( "address" )->comment( "Pontos cím" );
        $table->timestamp( "created_at" )->userCurrent();
        $table->timestamp( "updated_at" )->userCurrent();
    });
}

Seederek

Seederekkel lehet feltölteni az adatbázis táblákat adatokkal, akár teszt adatokkal is. Futtassuk le az adatbázist ürítő migrate utasítást és hozzunk létre egy seedert StudentSeeder néven.

php artisan make:seeder StudentSeeder

Az app/database/seeders könyvtárban létrejön az állomány, emeljük be a DB osztályt.

use \Illuminate\Support\Facades\DB;

Töltsük fel a run metódust adatokkal amiket az adatbázis táblába szeretnénk írni.

public function run() {
 
    DB::table( "students")->insert([
        "name" => "Wincs Eszter",
        "email" => "eszti@teszt.lan",
        "phone" => "123456789",
        "age" => 35,
        "gender" => "nő",
        "address" => "Vác Kő u. 23"
    ]);
}

Két lehetőség van a futtatásra, vagy futtatjuk közvetlenül az osztály fájlt vagy a DatabaseSeeder osztályt használjuk. Először az osztály fájlt fogjuk megnézni. Futtasuk majd ellenőrizzük az adatbázisban.

php artisan db:seed --class=StudentSeeder

A másik lehetőségnél a DatabaseSeeder osztályba importáljuk a saját seederünket.

use Database\Seeders\StudentSeeder;

A run metódusban adjuk meg a futtatni kívánt seedereket (most csak egy van).

public function run() {
 
    // \App\Models\User::factory(10)->create();
 
    $this->call([
        StudentSeeder::class
    ]);
}

Írjuk át az adatokat a seederben.

public function run() {
 
    DB::table( "students")->insert([
        "name" => "Ceruza Elemér",
        "email" => "elemer@teszt.lan",
        "phone" => "987654321",
        "age" => 41,
        "gender" => "férfi",
        "address" => "Kosd Fő u. 45"
    ]);
}

Futtassuk a seedet a DatabaseSeeder osztályon keresztül.

php artisan db:seed

Nézzük meg az eredményt az adatbázisban.


Fake könyvtár

Teszt adatok generálására szolgál amivel fel tudunk tölteni adatbázis táblákat. A teljes dokumentáció megtekintehető: github.com/fzaninotto/Faker címen. Régebben a composerrel kellett telepíteni de a laravel 8-ban integrálva van a faker. Hozzuk létre egy példányát a StudentSeeder osztály run metódusában és írjuk át az adatokat.

public function run() {
 
    $faker = \Faker\Factory::create();
 
    DB::table( "students")->insert([
        "name" => $faker->name,
        "email" => $faker->safeEmail,
        "phone" => $faker->phoneNumber,
        "age" => $faker->numberBetween( 25, 45 ),
        "gender" => $faker->randomelement([
            "férfi",
            "nő",
            "egyéb"
        ]),
        "address" => $faker->address
    ]);
}

Futtassuk újra a seedert

php artisan db:seed

Nézzük meg az adatbázisban az eredményt. Most csak egy új rekord került bele a táblába. Ha több adatra van szükség akkor két lehetőségünk van. Vagy for ciklust használunk a futtatásnál vagy létrehozunk egy Factory osztályt amely többször lefuttatja a seedert. Hozzunk létre egy Student modelt.

php artisan make:model Student

Hozzuk létre hozzá a Factory osztályt is, paraméterként adjuk át neki a modelt.

php artisan make:factory StudentFactory --model=Student

A factory osztályban nem kell létrehozni a fakert, itt alapértelmezetten lehet használni. Töltsük fel a StudentFactory definition metódusát.

public function definition() {
 
    return [
        "name" => $this->faker->name,
        "email" => $this->faker->safeEmail,
        "phone" => $this->faker->phoneNumber,
        "age" => $this->faker->numberBetween( 25, 45 ),
        "gender" => $this->faker->randomElement( array(
                "férfi",
                "nő",
                "egyéb"
            )),
        "address" => $this->faker->address
    ];
}

A futtatáshoz alakítsuk át a DatabaseSeeder osztályt, importáljuk be a Student modelt vegyük ki a kommentet a factory futtatása elől és cseréljük le a model nevét.

use Illuminate\Database\Seeder;
use Database\Seeders\StudentSeeder;
use App\Models\Student;
 
class DatabaseSeeder extends Seeder {
 
    public function run() {
 
        \App\Models\Student::factory(10)->create();
 
        // $this->call([
        //     StudentSeeder::class
        // ]);
    }
}

Ürítsük ki az adatbázis táblánkat és futtassuk a seedert újra

php artisan migrate:refresh
php artisan db:seed

Nem szükséges megadni a seedert, ez meg fogja találni az összes olyan seedert amit futtatni kell. Nézzük meg az eredményt az adatbázisban.


Query builder

A DB osztály használatának van egy egyszerűbb módja is. Használhtajuk az osztály által biztosított query buildereket. Ezeknek a segítségével könnyen tudunk lekérdezéseket írni. Hozzunk létre egy metódust a StudentControllerben listStudent néven, emeljük be a DB osztályt.

public function listStudent() {
 
    $students = DB::table( "students" )->get();
 
    echo "<pre>";
    print_r( $students );
}

Készítsük el az útvonalat a metódushoz

Route::get( "/lista-tanulo", [ StudentController::class, "listStudent" ]);

Ez a lekérdezés minden adatot visszaad az adatbázis táblából. Ha csak a név és az email cím szükséges, és például aliast szeretnénk a mezőnek beállítani akkor egészítsük ki a lekérdezést.

public function listStudent() {
 
    $students = DB::table( "students" )->select( "name", "name", "email as levél" )->get();
 
    echo "<pre>";
    print_r( $students );
}

Tudunk felvenni szűrési feltételt is, ebben az esetben a get metódus helyett használjuk a first metódust.

public function listStudent() {
 
    $students = DB::table( "students" )->where( "id", 2 )->select( "name", "email as levél" )->first();
 
    echo "<pre>";
    print_r( $students );
}

Tudjuk egyszerűsíteni a lekérdezést, a where feltétel és a first metódus kiváltható, egyesíthető a find metódussal.

public function listStudent() {
 
    $students = DB::table( "students" )->select( "name", "email as levél" )->find( 2 );
 
    echo "<pre>";
    print_r( $students );
}

Rá tudunk szűrni például az email címek kiterjesztésére is. Például keressük meg a tesz.lan kiterjesztésű email címeket és olvassuk ki a rekordok adatait.

public function listStudent() {
 
    $students = DB::table( "students" )->where( "email", "like", "%teszt.lan" )->get();
 
    echo "<pre>";
    print_r( $students );
}

Rá tudunk szűrni olyan rekordokra is amelyeknek az id -ja például nagyobb mint 50.

public function listStudent() {
 
    $students = DB::table( "students" )->where( "id", ">=", 50 )->get();
 
    echo "<pre>";
    print_r( $students );
}

Két értékre történő szűrés esetén

SELECT * FROM students WHERE id = 3 AND name = "Kata"
public function listStudent() {
 
    $students = DB::table( "students" )->where( "id", 3 )->where( "name", "Kata" )->get();
 
    echo "<pre>";
    print_r( $students );
}

Másik lehetőség

public function listStudent() {
 
    $students = DB::table( "students" )->where([
        "id" => 3,
        "name" => "Kata"
    ])->get();
 
    echo "<pre>";
    print_r( $students );
}

Ha három értékre kell szűrni

SELECT * FROM students WHERE id = 3 AND name = "Kata" OR email = "kata@teszt.lan"
public function listStudent() {
 
    $students = DB::table( "students" )->where( "id", 3 )->where( function( $query ) {
        $query->where( "name", "Kata" )->orWhere( "email", "kata@teszt.hu" );
    })->get();
 
    echo "<pre>";
    print_r( $students );
}

Ha tartományt szeretnénk szűrni

SELECT * FROM students WHERE id = BETWEEN 2 AND 10
public function listStudent() {
 
    $students = DB::table( "students" )->whereBetween( "id", [ 2, 10 ])->get();
 
    echo "<pre>";
    print_r( $students );
}

Ha több érték közül bármelyik egyezik

SELECT * FROM students WHERE id IN ( 1, 33, 41 )
public function listStudent() {
 
    $students = DB::table( "students" )->whereIn( "id", [ 2, 10 ])->get();
 
    echo "<pre>";
    print_r( $students );
}

Kapcsolatok táblák között

Táblák közötti kapcsolat háromféle képpen jöhet létre. inner join, left join, és right join utasításokkal. A kipróbálásukhoz hozzunk létre egy új táblát melyben a tanulók kurzusait tartjuk nyilván. Készítsük el a migrációs fájlt.

php artisan make:migration create_courses_table
public function up() {
 
    Schema::create('courses', function (Blueprint $table) {
        $table->id();
        $table->string( "course" );
        $table->integer( "price" );
        $table->foreignId( "student_id" );
        $table->timestamps();
    });
}

Töröljük az adatbázis tartalmat, futtassuk újra a migrációs fájlokat és a StudentSeedert.

php artisan migrate:refresh
php artisan db:seed

Készítsünk egy CourseSeedert és írjuk meg a tartalmát.

php artisan make:seeder CourseSeeder
public function run() {
 
    DB::table( "courses")->insert([
        "course" => "SQL",
        "price" => 150,
        "student_id" => 8,
    ]);
}

Töltsük fel a táblát legalább három rekorddal, cseréljük az adatokat és futtassuk a seedert. Legalább egy rekord legyen a táblában aminek a külső kulcsos hivatkozásához a students táblában nincs megfelelő id.

php artisan db:seed --class=CourseSeeder

Inner join

Ha mindkét táblában igaz mindkét feltétel akkor visszaadja a közös értékeket. A StudentControllerben írjuk meg a lekérdezést a query builder segítségével.

public function listStudent() {
 
    $students = DB::table( "students" )
    ->join( "courses", "students.id", "=", "courses.student_id")->get();
 
    echo "<pre>";
    print_r( $students );
}

Ha szűrési feltételeket szeretnénk hozzáadni például az id mezőket nem szeretnénk látni és aliasokkal szeretnénk ellátni a visszakapott eredményt, bővítsük a lekérdezést.

public function listStudent() {
 
    $students = DB::table( "students" )
                ->select( "students.name as Név",
                          "students.email as Email",
                          "courses.course as Kurzus",
                          "courses.price as Ár" )
                ->join( "courses", "students.id", "=", "courses.student_id")->get();
 
    echo "<pre>";
    print_r( $students );
}

Látható, hogy a nem létező id nem került visszaadásra, csak azokat a rekordokat kaptuk meg amelyeket mindkét táblában azonosítani lehetett.

Left join

A lekérdezésben felvett táblák esetében a students a jobb, a courses a bal tábla. A left join esetén a bal táblának minden rekordját megkapjuk, ha a másik táblában nincs egyező rekord akkor a lekérdezés null értékkel tér vissza az adott rekordon. Egészítsük ki a lekérdezést.

public function listStudent() {
 
    $students = DB::table( "students" )
                ->select( "students.name as Név",
                          "students.email as Email",
                          "courses.course as Kurzus",
                          "courses.price as Ár" )
                ->leftjoin( "courses", "students.id", "=", "courses.student_id")->get();
 
    echo "<pre>";
    print_r( $students );
}

Látható, hogy a students tábla minden rekordját visszakaptuk de a courses táblában, ha nincs felvéve diák azonosító külső kulcs akkor az onnan érkező adatok null értéket kapnak.

Rigth join

Right join esetén a jobb tábla minden rekordját megkapjuk viszont, ha a bal táblában nincs megfelelő egyezés, azok az adatok null értékkel térnek vissza. Íruk át a metódust.

public function listStudent() {
 
    $students = DB::table( "students" )
                ->select( "students.name as Név",
                          "students.email as Email",
                          "courses.course as Kurzus",
                          "courses.price as Ár" )
                ->rightjoin( "courses", "students.id", "=", "courses.student_id")->get();
 
    echo "<pre>";
    print_r( $students );
}

Látható, hogy a visszakapott adathalmazban a courses táblában lévő olyan azonosító ami a students táblában nem létezik null értékek vannak a diák adatok helyén.

Adatok írása, frissítése, törlése query builder használatával

Készítsünk egy insertStudent metódust a StudentControllerben. A DB osztály legyen beemelve.

public function insertStudent() {
 
    DB::table( "students" )->insert([
        "name" => "Wincs Eszter",
        "email" => "eszter@teszt.hu",
        "phone" => "123456789"
    ]);
 
    echo "Adatok elmentve.";
}

Egy asszociatív tömbben tudjuk átadni a kiírásra szánt adatainkat. Hozzunk létre egy útvonalat a metódushoz.

Route::get( "/uj-tanulo", [ StudentController::class, "insertStudent" ]);

Ha esetleg szükségünk van az utolsó beszúrt rekord id értékére, egészítsük ki a lekérdezést.

public function insertStudent() {
 
    $last_id = DB::table( "students" )->insertGetId([
        "name" => "Negye Dóra",
        "email" => "dora@valami.hu",
        "phone" => "987654321"
    ]);
 
    echo "Adatok elmentve. Id = " . $last_id;
}

Van lehetőség több sor beszúrására is egy utasítással. Ilyenkor minden rekord adatot külön tömbben kell felvenni. Ilyenkor egy szülő tömbbe kell belehelyezni a rekordokat tartalmazó tömböket.

public function insertStudent() {
 
    $last_id = DB::table( "students" )->insert(
        [
            [ "name" => "Har Mónika", "email" => "moni@valami.hu", "phone" => "987654321" ],
            [ "name" => "Ceruza Elemér", "email" => "eli@valami.hu", "phone" => "123456789" ],
            [ "name" => "Pólika Pál", "email" => "pal@valami.hu", "phone" => "546123789" ]
        ]
    );
 
    echo "Adatok elmentve.";
}

Hozzunk létre egy updateStudent metódust és készítsük el hozzá az útvonalat.

public function updateStudent() {
 
    DB::table( "students" )->where( "id", 12 )->update([
        "name" => "Cserélt név",
        "email" => "cserelt@teszt.hu"
    ]);
 
    echo "Adatok frissítve";
}
Route::get( "/frissit-tanulo", [ StudentController::class, "updateStudent" ]);

A query builder lehetőséget ad arra is, hogy felvegyünk egy rekordot és ha létezik az adat akkor frissíti, ha nem létezik akkor beszúrja. Ennek a metódusnak két tömböt kell átadni, az elsőben a feltétel van, a másodikban az adatok. Ha nem létezik a rekord akkor összevonja a két tömböt és beszúrja mint új rekord.

public function updateStudent() {
 
    DB::table( "students" )->updateOrInsert(
 
        [ "email" => "bela@bela.hu" ],
        [ "name" => "Béla", "phone" => "22222222" ]
    );
 
    echo "Adatok frissítve";
}

Adatrekord törléséhez használjuk a delete metódust.

public function updateStudent() {
 
    DB::table( "students" )->where( "id", 19 )->delete();
}

Ha nem adunk meg feltételt akkor a tábla minden adata törölve lesz és ha új rekordot szúrunk be az id az utolsó törölt rekord id -jától folytatódik. Ha ismét 1 -től szeretnénk az id -t használni akkor ne a törlést, hanem a csonkolás metódust használjuk.

public function updateStudent() {
 
    DB::table( "students" )->truncate();
}

Eloquent ORM

Az eloquent model kapcsolatokat épít adatbázis táblák között külső kulcsok segítségével. Három féle kapcsolatot kezel, az egy - egy, az egy - több és a több -több kapcsolatot, illetve ezeknek az inverzeit. Az egy - egy kapcsolat felépítéséhez hozzunk létre egy adatbázist és migrációs állományok segítségével hozzunk létre egy students és egy courses táblát. A students tábla mezői legyenek név, email, telefon. A courses táblában név, ár és student id mező legyen. Töltsük fel tesztadatokkal, legalább 5 rekordot helyezzünk el a táblákban. Hozzunk létre egy kontrollert, illetve egy modellt a students és a courses táblához.

php artisan make:controller StudentController
php artisan make:controller CourseController
php artisan make:model Student
php artisan make:model Course

Egy-egy kapcsolat

A Student modellben hozzunk létre metódust amely a course modellre hivatkozik.

class Student extends Model
{
    use HasFactory;
 
    public function course() {
 
        return $this->hasOne( Course::class );
    }
}

A StudentControllerben készítsünk egy metódust az adatok lekérdezéséhez és emeljük be a modellt.

class StudentController extends Controller
{
    public function listUser() {
 
        return Student::find(1)->course;
    }
}

Készítsük el az útvonalat

Route::get( "/diaklista", [ StudentController::class, "listUser" ]);

Nézzük meg böngészőben, a megadott ID értékhez tartozó adatrekordot kapjuk vissza a courses táblából. Mivel egy-egy kapcsolatot építettünk, így csak egy rekordot kapunk, ami a megadott tanulóhoz kapcsolódó kurzust tartalmazza. A kapcsolat inverzéhez hozzuk létre a Course.php modellben a student metósust.

public function student() {
 
    return $this->belongsTo( Student::class );
}

Ebben az esetben a megadott kurzus id -hoz tartozó diákot fogunk kapni, de most is csak egy rekordot.


Egy-több kapcsolat

Hozzunk létre egy adat táblát students néven, név, email, telefon és kurzus id mezőkkel. Készítsük el a courses táblát course és price mezőkkel. Alakítsuk át a student modellünk course metódusát, hogy egy-több kapcsolat kezelésére legyen alkalmas.

public function course() {
 
    return $this->belongsTo( Course::class );
}

Íruk át a course modellben is a student metódust.

public function student() {
 
    return $this->hasMany( Student::class );
}

A főtábla modelljében a belongsTo a kapcsolt tábla modelljében haszáljuk a hasMany metódusokat aminek át kell adni paraméterként a másik modell osztályt. A StudentControllerben készítsünk metódust az adatok megjelenítéséhez és állítsuk be az útvonalat is.

Route::get( "/diaklista", [ StudentController::class, "listUser" ]);
public function listUser() {
 
 
    $students = Student::with( "course" )->get();
 
    foreach( $students as $student ) {
 
        echo "<pre>";
        print_r( $student->name . " ");
        print_r( $student->course->course );
    }
}

Készítsünk hozzá egy egyszerű nézetet.

<table class="table">
    <thead>
      <tr>
        <th>Id</th>
        <th>Név</th>
        <th>Email</th>
        <th>Telefon</th>
        <th>Kurzus</th>
        <th>Ár</th>
      </tr>
    </thead>
    <tbody>
      @foreach( $students as $student )
         <tr>
           <td>{{ $student->id }}</td>
           <td>{{ $student->name }}</td>
           <td>{{ $student->email }}</td>
           <td>{{ $student->phone }}</td>
           <td>{{ $student->course->course }}</td>
           <td>{{ $student->course->price }}</td>
         </tr>
      @endforeach
    </tbody>
  </table>

A kontrollerben adjuk át az adatokat a nézetnek.

public function listUser() {
 
    $students = Student::with( "course" )->get();
 
    return view( "/list_student", [
        "students" => $students
    ]);
}

Így visszaadja nekünk az összes tanulót a kurzussal együtt amire beiratkozott.Ha azt szeretnénk látni, hogy adott kurzus id melyik tanulóhoz tartozik, alakítsuk át a kontroller metódusát, hogy a kapcsolat inverzét adja vissza.

public function listUser() {
 
 
    $students = Course::find( 2 )->student;
 
    return view( "/list_student", [
        "students" => $students
    ]);
}

Több táblás kapcsolat

Ha több táblánk van és a főtáblából szeretnénk elérni egy másik táblát a köztes táblán keresztül akkor az elérni kívánt utolsó tábla modelljét kapcsoljuk a lekérdezési folyamathoz. Legyen egy adatbázisunk ahol készítsünk egy Schools táblát school, course_id mezővel, egy courses táblát course és student_id mezővel és egy students táblát name, email mezővel. A School modellben hozzuk létre a kapcsoló metódust.

public function student() {
 
    return $this->hasManyThrough( Student::class, Course::class );
}

A kontrollerben kérdezzük le az adatokat, például a tanulók nevét.

public function listUser() {
 
 
    $schools = School::with( "student" )->get();
 
    foreach( $schools as $school ) {
 
        foreach( $school->student as $stu ) {
 
           echo "<pre>";
           print_r( $stu->name );
        }
   }
}

Hozzunk létre egy útvonalat.

Route::get( "/diaklista", [ StudentController::class, "listUser" ]);

több-több kapcsolat

Ha több a többhöz viszonyuló adataink vannak például egy blog oldalon a felhasználóknak lehet több szerepe és egy szerephez tartozhat több felhasználó, akkor kapcsolótáblát kell létrehozni. A kapcsolótábla elnevezésénél figyeljünk a sorrendre a kapcsolat iránya szerint, a Laravel meghatározott névvel keresi a táblákat. Hozzunk létre adatbázist blogger névvel. Készítsünk táblákat, bloggers → név, email, roles → role és blogger_role → blogger_id, role_id mezőkkel. Hozzuk létre a modelleket és a migrációs fájlokat. Készítsünk egy BloggerController vezérlőt. A Blogger modellben készítsünk metódust ami összekapcsolja a táblákat.

public function roles() {
 
    return $this->belongsToMany( Role::class );
}

A kontrollerben kérdezzük le az adatokat, például a 3-as id blogger szerepeit.

public function listBloggers() {
 
    return Blogger::find( 3 )->roles;
}

Hozzuk létre az útvonalat.

Route::get( "/bloggers", [ BloggerController::class, "listBloggers" ]);

A kapcsolat inverze amikor az adott szerephez tartozó felhasználókat keressük. Ehhez írjunk metódust a Role modellben.

public function bloggers() {
 
    return $this->belongsToMany( Blogger::class );
}

A kontrollerben vegyük fel a Role modellt és írjuk át a lekérdező metódust.

public function listBloggers() {
 
    return Role::find( 3 )->bloggers;
}

Más név az idegen kulcsnak

A laravel alapértelmezetten az idegen kulcsokat táblanév_id konvencióval keresi. Ha nekünk más néven van felvéve az adat táblában a kapcsolat nem jön létre. Ilyenkor második paraméterként meg kell adni, az idegen kulcs nevét a modell kapcsoló metódusában. Például egy-több kapsolat esetén.

public function course() {
 
    return $this->belongsTo( Course::class, "studentId" );
}

Tinker

A tinker egy beépített parancssoros adatbázis interfész az adat táblák kezeléséhez. A project létrehozásakor alapértelmezetten települ. Ezt a composer.json állományban tudjuk ellenőrizni.

{
    "name": "laravel/laravel",
    "type": "project",
    "description": "The Laravel Framework.",
    "keywords": ["framework", "laravel"],
    "license": "MIT",
    "require": {
        "php": "^7.3|^8.0",
        "fruitcake/laravel-cors": "^2.0",
        "guzzlehttp/guzzle": "^7.0.1",
        "laravel/framework": "^8.75",
        "laravel/sanctum": "^2.11",
        "laravel/tinker": "^2.5"
    },

Ha mégsem lenne jelen ez a csomag a composerrel tudjuk telepíteni.

composer require laravel/tinker

A tinkert parancssorból tudjuk indítani.

php artisan tinker

Ezt a promptot kell látnunk. A tinker kapcsolatba lép az alkalmazásunkkal és tudunk php utasításokat kiadni.

Psy Shell v0.11.2 (PHP 7.4.28 — cli) by Justin Hileman
>>> 

Tinker modell használatával

Hozzunk létre egy adatbázist, egy students táblát id, name, email, phone, created_at és updated_at mezőkkel. Készítsük el a modellt.

php artisan make:model Student -m

Ez létre hozza a migrációs fájlt is, vegyük fel a mezőket, migráljunk és töltsük fel a táblát néhány adattal. Használjuk a tinkert. Mivel az adatbázis táblánknak van kapcsolata a Student modellel használhatjuk azt.

>>> Student::insert([ "name" => "Csaba", "email" => "csaba@csaba.hu", "phone" => "12344556", "created_at" => new DateTime(), "updated_at" => new DateTime() ])

Insert helyett használhatjuk a create metódust is, ebben az esetben a modellben fel kell venni a kitölthető mezőket.

class Student extends Model {
 
    use HasFactory;
 
    protected $fillable = [
 
        "name",
        "email",
        "phone"
    ];
}
>>> Student::create([ "name" => "Jani", "email" => "jani@jani.hu", "phone" => "12344556", "created_at" => new DateTime(), "updated_at" => new DateTime() ])

Ehhez hasonló kimenetet kell látnunk.

=> App\Models\Student {#3566
     name: "Jani",
     email: "jani@jani.hu",
     phone: "12344556",
     updated_at: "2022-04-11 17:14:05",
     created_at: "2022-04-11 17:14:05",
     id: 2,
   }

Ha le akarjuk kérdezni az adatainkat, itt is használhatjuk a modell metódusait.

Student::all()
Student::find( 2 )
Student::where( "name", "Csaba" )->get()

A where esetében egy collectiont kapunk, igazából csak egy objektumra van szükség, így használjuk a first metódust. Ilyenkor csak az objektumot kapjuk vissza.

Student::where( "name", "Csaba" )->first()

Adatok módosításához használjuk az update metódust.

Student::where( "id", 1 )->update([ "name" => "Csabika" ])

Ha a válasz 1 akkor sikeresen végbement a tranzakció. Rekord törlése a delete metódussal történik.

Student::where( "id", 2 )->delete()

A válasz most is 1.


Tinker a DB osztály használatával

Most is ugyanazokat a műveleteket fogjuk végrehajtani csak a DB osztályt fogjuk használni. Adat beszúrása.

DB::table( "students" )->insert([ "name" => "Pali", "email" => "pali@pali.hu", "phone" => "2345643", "created_at" => new DateTime(), "updated_at" => new DateTime() ])

Adatok lekérdezése.

DB::table( "students" )->get()

Adatok keresése.

DB::table( "students" )where( "id", 2 )->get()

Itt is egy collectiont kapunk, az objektum eléréséhez használjuk a first metódust.

DB::table( "students" )where( "id", 2 )->first()

adatok frissítése.

DB::table( "students" )->where( "id", 2 )->update([ "name" => "Palika" ])

Rekord törlése

DB::table( "students" )->where( "id", 2 )->delete()

Kapcsolódás több adatbázishoz

Ha arra lenne szükségünk, hogy több adatbázishoz kapcsolódjunk szerkesztenünk kell a .env állományt. Hozzunk létre két adatbázist, az egyik student, egy táblával, name, email mezőkkel. A másik teacher, egy táblával name és subject mezőkkel.

Modellek

A modellek vannak kapcsolatban az adatbázis táblákkal, a vezérlők ezeken keresztül tudják lekérdezni illetve írni a táblák rekordjait. Minden adatbázis táblához tartozik egy modell. A modell nevének az adatbázis tábla nevét kell kapnia de egyesszámban. Ha nem így van a kapcsolat nem fog működni. Hozzunk létre egy Employee modellt amihez gyártsuk le az összes szükséges osztályt is.

php artisan make:model Employee --all

Létrejön a modell, egy factory osztály, egy migrációs állomány, egy seeder és egy controller. A modellben megadhatunk több változtatást az eredeti migrációs fájlhoz képest. Az alapértelmezett paramétereket át tudjuk állítani. Ha más nevet szeretnénk adni az adatbázis táblának, más nevet szeretnénk az alapértelmezett id mezőnek, más típust szeretnénk az alapértelmezett integer helyett az egyedi azonosítónak, nem szeretnénk ha az id automatikusan növekedne, más nevet szeretnénk a timestamp mezőknek mint az alapértelmezett vagy, ha nem is szeretnénk, ha lenne timestamp mező.

class Employee extends Model {
 
    use HasFactory;
 
    protected $table = "más_táblanév";
    protected $primaryKey = "más_id";
    protected $keyType = "string";
    public $incrementing = false;
    const CREATED_AT = "más_név_a_lértrehozásnak";
    const UPDATED_AT = "más_név_a_módosításnak";
    public $timestamps = false;
}

Készítsünk egy adatbázist és hozzuk létre a migrációs fájlt majd indítsuk el.

php artisan make:migration create_students_table
public function up() {
 
    Schema::create('students', function (Blueprint $table) {
        $table->id();
        $table->string( "name", 120 );
        $table->string( "email", 50 )->nullable();
        $table->string( "phone", 20 )->nullable();
        $table->timestamps();
    });
}

Adatok írása

Hozzuk létre a StudentController osztályt, abban két metódust és a hozzájuk tartozó útvonalakat.

php artisan make:controller StudentController
class StudentController extends Controller {
 
    public function addStudent() {
 
        return view( "add_student" );
    }
 
    public function storeStudent( Request $request ) {
 
 
    }
}
Route::get( "/uj-tanulo", [ StudentController::class, "addStudent" ]);
Route::post( "/tarol-tanulo", [ StudentController::class, "storeStudent" ]);

Hozzuk létre az add-student nézetet, ezen belül egy formot az adatok felvételére.

<h1>Tölts ki a mezőket</h1>
 
<form action="tarol-tanulo" method="post">
    @csfr
    <p>
        <label for=""> Név: </label>
        <input type="text" name="name">
        <br>
    </p>
    <p>
        <label for=""> Email: </label>
        <input type="text" name="email">
        <br>
    </p>
    <p>
        <label for=""> Telefon: </label>
        <input type="text" name="phone">
    </p>
    <p>
        <button type="submit">Küldés</button>
    </p>
</form>

A StudentControllerben fogadjuk az adatokat, ellenőrizzük böngészőben.

public function storeStudent( Request $request ) {
 
    print_r( $request->all() );
}

A StudentControllerben importáljuk be a Student modelt. Alakítsuk át a storeStudent metódust, hogy a modellt használja az adatok adatbázisba írásához.

use App\Models\Student;
public function storeStudent( Request $request ) {
 
    $student = new Student;
 
    $student->name = $request->name;
    $student->email = $request->email;
    $student->phone = $request->phone;
 
    $student->save();
}

Próbáljuk ki böngészőben, ha üres oldalt kapunk, hiba nélkül lefutott a kiírás, ellenőrizzük az adatbázisban. Ha nem szeretnénk üres oldalt visszaadni be kell állítani egy üzenetet és átirányítást a beviteli oldalra.

public function storeStudent( Request $request ) {
 
    $student = new Student;
 
    $student->name = $request->name;
    $student->email = $request->email;
    $student->phone = $request->phone;
 
    $student->save();
 
    $request->session()->flash( "success", "Kiírás sikeres" );
    return redirect( "/uj-tanulo" );
}

A nézetben át kell vennünk az üzenetet.

<h1>Tölts ki a mezőket</h1>
 
@if( session()->has( "success "))
    <h3>{{ session( "success" ) }}</h3>
@endif
 
<form action="tarol-tanulo" method="post">
    @csrf
    <p>
        <label for=""> Név: </label>
        <input type="text" name="name">
        <br>
    </p>
    <p>
        <label for=""> Email: </label>
        <input type="text" name="email">
        <br>
    </p>
    <p>
        <label for=""> Telefon: </label>
        <input type="text" name="phone">
    </p>
    <p>
        <button type="submit">Küldés</button>
    </p>
</form>

Adatok lekérdezése

Készítsük el a StudentControllerben a szükséges metódust, és hozzuk létre az útvonalat.

public function selectStudent() {
 
    $students = Student::all();
 
    echo "<pre>";
    print_r( $students );
}
Route::post( "/kiir-tanulo", [ StudentController::class, "selectStudent" ]);

Próbáljuk ki böngészőben, látható, hogy a metódus visszaadja a collection objektumot és ez tartalmazza a modellt. Szűrjünk rá például a 4 id-ra a lekérdezésnél.

public function selectStudent() {
 
    $students = Student::where( "id", 4 )->get();
 
    echo "<pre>";
    print_r( $students );
}

Próbáljuk ki böngészőben. Ha nem szeretnénk, hogy a collection objektumot is megkapjuk, csak a modellt szeretnénk visszakapni, használjuk a first metódust.

public function selectStudent() {
 
    $students = Student::where( "id", 4 )->first();
 
    echo "<pre>";
    print_r( $students );
}

Láthatjuk, hogy most csak a modell objektumot kapjuk vissza. Másik szűrési lehetőség a where helyett a find. Ennek közvetlenül adjuk át a keresett id -t.

public function selectStudent() {
 
    $students = Student::find( 4 );
 
    echo "<pre>";
    print_r( $students );
}

Próbáljuk ki böngészőben. Ha több id-t szeretnénk lekérdezni helyezzük el a felsorolást egy tömbben.

public function selectStudent() {
 
    $students = Student::find([ 1, 3, 4 ]);
 
    echo "<pre>";
    print_r( $students );
}

Ilyenkor ismét egy collection objektumot kapunk vissza. Ha nem elsődleges kulcsra szűrünk akkor meg kell adni a mező nevét és a rekord értékét is. Ilyenkor újra egy modellt kapunk vissza.

public function selectStudent() {
 
    $students = Student::where( "email", "bela@bela.hu" )->first();
 
    echo "<pre>";
    print_r( $students );
}

Ezt a két opciót össze is vonhatjuk

public function selectStudent() {
 
    $students = Student::firstwhere( "email", "bela@bela.hu" );
 
    echo "<pre>";
    print_r( $students );
}

Ha csak az email címeket szeretném megjeleníteni egy ciklussal menjünk végig a lekérdezés eredményén.

public function selectStudent() {
 
    $students = Student::all();
 
    echo "<pre>";
    foreach( $students as $student ) {
 
        echo $student->email . "<br>";
    }
 
}

Nézzük meg böngészőben. Ehhez további adatokat is fűzhetünk.

public function selectStudent() {
 
    $students = Student::all();
 
    echo "<pre>";
    foreach( $students as $student ) {
 
        echo $student->email . ", " . $student->name . "<br>";
    }
 
}

Egyszerűbb lehetőség például a név kiolvasására

public function selectStudent() {
 
    $students = Student::where( "email", "bela@bela.hu" )->first();
 
    echo "<pre>";
    print_r( $students->name );
 
}

Az adatok nézetbe küldéséhez alakítsuk át a selectStudent metódust.

public function selectStudent() {
 
    $students = Student::all();
 
    return view( "kiir-tanulo" );
}

Hozzuk létre a list-student.blade.php nézetet, másoljuk be a tartalmat a következő linkről https://www.w3schools.com/bootstrap/bootstrap_tables.asp Alakítsuk át a head szekciót.

<!DOCTYPE html>
<html lang="hu">
 
<head>
  <title>Tanulo lista</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>

Majd a táblázatot is.

<!DOCTYPE html>
<html lang="hu">
 
<head>
  <title>Tanulo lista</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
 
<body>
<div class="container">
  <h2>Tanuló lista</h2>
 
  <table class="table">
    <thead>
      <tr>
        <th>Id</th>
        <th>Név</th>
        <th>Email</th>
        <th>Telefon</th>
      </tr>
    </thead>
    <tbody>
      @foreach( $students as $student )
            <tr>
                <td>{{ $student->id }}</td>
                <td>{{ $student->name }}</td>
                <td>{{ $student->email }}</td>
                <td>{{ $student->phone }}</td>
            </tr>
      @endforeach
    </tbody>
  </table>
</div>
 
</body>
</html>

A StudentControllerben adjuk hozzá a nézet hívásához az adatokat.

public function selectStudent() {
 
    $students = Student::all();
 
    return view( "list_student", [
        "students" => $students
    ] );
}

Nézzük meg böngészőben. Adat törléséhez egészítsük ki a táblázatot egy törlés gombbal, használjunk bootstrap osztályokat.

<!DOCTYPE html>
<html lang="hu">
 
<head>
  <title>Tanulo lista</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
 
<body>
<div class="container">
  <h2>Tanuló lista</h2>
 
  <table class="table">
    <thead>
      <tr>
        <th>Id</th>
        <th>Név</th>
        <th>Email</th>
        <th>Telefon</th>
      </tr>
    </thead>
    <tbody>
      @foreach( $students as $student )
            <tr>
                <td>{{ $student->id }}</td>
                <td>{{ $student->name }}</td>
                <td>{{ $student->email }}</td>
                <td>{{ $student->phone }}</td>
                <td>
                    <a class="btn btn-primary" href="/delete/{{ $student->id }}">Törlés</a>
                </td>
            </tr>
      @endforeach
    </tbody>
  </table>
</div>
 
</body>
</html>

Nézzük meg a böngészőben, a gombra kattintáskor a címsorban egy delete útvonal hívása történik és hozzákapcsolódik az adott rekord id-ja is. Készítsük el az útvonalat a törléshez.

Route::get( "/delete/{id}", [ StudentController::class, "deleteStudent" ]);

Hozzuk létre a StudentControllerben a törlő metódust

public function deleteStudent( $id ) {
 
    $student = Student::find( $id );
    $student->delete();
 
    session()->flash( "success", "Tanuló törölve" );
    return redirect( "/kiir-tanulo" );
}

Fogadjuk a nézetben a visszaküldött siker üzenetet.

<!DOCTYPE html>
<html lang="hu">
 
<head>
  <title>Tanulo lista</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
 
<body>
<div class="container">
  <h2>Tanuló lista</h2>
 
  @if( session()->has( "success" ))
        <div class="alert alert-success">
            {{ session( "success") }}
        </div>
  @endif
 
  <table class="table">
    <thead>
      <tr>
        <th>Id</th>
        <th>Név</th>
        <th>Email</th>
        <th>Telefon</th>
      </tr>
    </thead>
    <tbody>
      @foreach( $students as $student )
            <tr>
                <td>{{ $student->id }}</td>
                <td>{{ $student->name }}</td>
                <td>{{ $student->email }}</td>
                <td>{{ $student->phone }}</td>
                <td>
                    <a class="btn btn-primary" href="/delete/{{ $student->id }}">Törlés</a>
                </td>
            </tr>
      @endforeach
    </tbody>
  </table>
</div>
 
</body>
</html>

Adatok frissítése

Az adatok szerkesztéséhez alakítsuk át a táblázatunkat, helyezzünk fel egy szerkesztés gombot.

<!DOCTYPE html>
<html lang="hu">
 
<head>
  <title>Tanulo lista</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
 
<body>
<div class="container">
  <h2>Tanuló lista</h2>
 
  @if( session()->has( "success" ))
        <div class="alert alert-success">
            {{ session( "success") }}
        </div>
  @endif
 
  <table class="table">
    <thead>
      <tr>
        <th>Id</th>
        <th>Név</th>
        <th>Email</th>
        <th>Telefon</th>
      </tr>
    </thead>
    <tbody>
      @foreach( $students as $student )
            <tr>
                <td>{{ $student->id }}</td>
                <td>{{ $student->name }}</td>
                <td>{{ $student->email }}</td>
                <td>{{ $student->phone }}</td>
                <td>
                    <a class="btn btn-info" href="/update/{{ $student->id }}">Szerkesztés</a>
                    <a class="btn btn-danger" href="/delete/{{ $student->id }}">Törlés</a>
                </td>
            </tr>
      @endforeach
    </tbody>
  </table>
</div>
</body>
</html>

Állítsunk be útvonalat a szerkesztést lehetővé tevő form elérésére.

Route::get( "/update/{id}", [ StudentController::class, "showUpdateStudent" ]);

A StudentControllerben hozzuk létre a metódust

public function showUpdateStudent( $id ) {
 
    $student = Student::find( $id );
 
    return view( "show_student", [
        "student" => $student
    ]);
}

Készítsük el a nézetet is. Szükségünk lesz egy rejtett mezőre amiben az id -t tudjuk átküldeni,amivel az adatbázis táblában azonosítható a rekord.

<form action="szerkeszt-tanulo" method="post">
    @csrf
    <input type="hidden" value="{{ $student->id }}" name="student_id">
    <p>
        <label for=""> Név: </label>
        <input type="text" name="name" value="{{ $student->name }}">
        <br>
    </p>
    <p>
        <label for=""> Email: </label>
        <input type="text" name="email" value="{{ $student->email }}">
        <br>
    </p>
    <p>
        <label for=""> Telefon: </label>
        <input type="text" name="phone" value="{{ $student->phone }}">
    </p>
    <p>
        <button type="submit">Frissítés</button>
    </p>
</form>

Vegyük fel az útvonalat az adatok kiírását végző metódushoz

Route::post( "/update-student", [ StudentController::class, "submitUpdateStudent" ]);

Készítsük el a StudentControllerben ezt a metódust és ellenőrizzük, hogy megérkeznek -e az adatok.

public function submitUpdateStudent( Request $request ) {
 
    print_r( $request->all() );
}

Ha minden rendben van, írjuk meg az adat frissítést

public function submitUpdateStudent( Request $request ) {
 
    $student = Student::find( $request[ "student_id" ]);
 
    $student->name = $request[ "name" ];
    $student->email = $request[ "email" ];
    $student->phone = $request[ "phone" ];
 
    $student->save();
 
    session()->flash( "success", "Sikeres frissítés" );
 
    return redirect( "/kiir-tanulo" );
}

Accessorok

Az accessorok model szinten adnak lehetőséget az adatok átalakítására mielőtt a nézetbe kerülnének. Hozzunk létre egy adatbázist, ennek legyen egy students táblája, név, email, telefon mezőkkel. Fentebb a migráció, seederek és a fake könyvtár segítségével töltsük fel 50 rekorddal a táblát. Hozzunk létre egy StudentController vezérlőt és egy Student modellt.

php artisan make:controller StudentController --model=Student

A vezérlőben készítsünk egy students metódust és kérdezzük le a students tábla adatait. Emeljük be a Student modellt majd hozzuk létre az útvonalat a metódushoz.

public function students() {
 
        return Student::all();
    }
Route::get( "/tanulok", [ StudentController::class, "students" ]);

Ha csak 10 rekordot szeretnénk visszakapni módosítsuk a students metódust.

public function students() {
 
    return Student::limit(10)->get();
}

Például a neveket csupa nagybetűvel szeretnénk látni annékül, hogy az adatbázisban változtatásokat kelljen végrehajtani, bővítsük a Student modellt. Kérjük le az érintett mező attribútumait és állítsuk be az általunk kívánt értékre. Az attrubútumok lekérésének a szintaktikája:

get<ColumnName>Attribute( $value )
class Student extends Model {
 
    use HasFactory;
 
    public function getNameAttribute( $value ) {
 
        return strtoupper( $value );
    }
}

Ha az időbélyegző mező visszaadott értékét szeretnénk formázni használjuk a következő módszert.

public function getCreatedAtAttribute( $value ) {
 
    return date( "Y-m-d h:i:s", strtotime( $value ));
}

Mutatorok

A mutatorok ellentétben az accessorokkal nem a nézetbe irányuló adat módosítására valók, hanem ellenkezőleg, azokat az adatokat tudjuk manipulálni amiket az adatbázisba írunk. Készítsünk egy metódust a StudentControllerben ami elvégzi a beszúrást, töltsük fel statikus adatokkal és írjuk meg az útvonalat hozzá.

public function addStudent() {
 
    $student = new Student;
 
    $student->name = "Kukor Ica";
    $student->email = "ica@teszt.hu";
    $student->phone = "123456789";
 
    if( $student->save() ) {
 
        echo "<h1>Kiírás sikeres</h1>";
    }
}
Route::get( "/uj-tanulo", [ StudentController::class, "addStudent" ]);

Ellenőrizzük az adatbázist, az adatok kiírásra kerültek. Ha például a telefonszám elé szeretnénk odaírni az ország kódot, a Student modellben hozzunk létre egy mutatort. A mutatorok szintaktikája:

set<CulomnName>Attribute( $value )
public function setPhoneAttribute( $value ) {
 
    $this->attributes[ "phone" ] = "+36" . $value;
}

Modell események

Egyszerű eseménykezelés

Minden adatbázis műveletnél a modell generál egy eseményt. A három adat módosító művelethez egyenként két eseményt generál. Creating, created, updating, updated, saving, saved és deleting deleted. Ezeket tudjuk naplózni és szükség esetén visszakeresni. Legyen egy adatbázisunk student néven, egy táblával students néven, name, email, phone mezőkkel. Készítsük el a Student modellt és vegyük fel benne a szükséges metósusokat. Készítsünk egy boot nevű metódust amelynek kötelezően ez a neve és hívjuk meg benne a szülő osztály konstruktorát. Ennek a metódusnak kötelezően statikusnak kell lennie. Emeljük be a Log osztályt.

use Illuminate\Support\Facades\Log;
public static function boot() {
 
    parent::boot();
}

Majd vegyük fel az eventek rögzítéséhez szükséges további paramétereket.

public static function boot() {
 
    parent::boot();
 
    static::creating( function( $item ) {
 
        Log::info( "Creating event folyamatban ". $item );
    });
 
    static::created( function( $item ) {
 
        Log::info( "Created event befejeződött ". $item );
    });
 
    static::updating( function( $item ) {
 
        Log::info( "Updating event folyamatban ". $item );
    });
 
    static::updated( function( $item ) {
 
        Log::info( "Updating event befejeződött ". $item );
    });
 
    static::deleting( function( $item ) {
 
        Log::info( "Deleting event folyamatban ". $item );
    });
 
    static::deleting( function( $item ) {
 
        Log::info( "Deleting event folyamatban ". $item );
    });
}

Hozzunk létre egy új diákot az adatbázisban a kontroller segítségével. A log fájlt a storage/logs könyvtárban találjuk, nézzük meg a laravel.log állományt, ebben találjuk a múveletünknek a naplózását.

[2022-04-12 17:13:59] local.INFO: Creating event folyamatban
{"name":"Bekő Tóni","email":"toni@teszt.hu","phone":"123456789"}  
[2022-04-12 17:13:59] local.INFO: Created event befejeződött
{"name":"Bekő Tóni","email":"toni@teszt.hu","phone":"123456789",
"updated_at":"2022-04-12T17:13:59.000000Z","created_at":"2022-04-12T17:13:59.000000Z","id":4}

Ezek a modell eventek természetesen a többi művelettel is működnek.


Eseménykezelés dispatchesEvents használatával

A másik módja az adatbázis műveletek rögzítésének a dispatchesEvents változó. A modellben hozzuk létre.

protected $dispatchesEvents = [
    "creating",
    "created"
];

Hozzunk létre két új event osztályt.

php artisan make:event StudentCreatedEvent
php artisan make:event StudentCreatedEvent

A két osztályban írjuk meg a konstruktorokban, hogy mi történjen. Először StudentCreatingEvent osztályban.

public function __construct() {
 
    Log::info( "Creating event folyamatban" );
}

Majd a StudentCreatedEvent osztályban is.

public function __construct() {
 
    Log::info( "Created event befejeződött" );
}

A modellben adjuk át az eseményt ezeknek az osztályoknak.

protected $dispatchesEvents = [
    "creating" => \App\Events\StudentCreatingEvent::class,
    "created" => \App\Events\StudentCreatedEvent::class
];

Az esemény osztályokban importáljuk a Log osztályt.

use Illuminate\Support\Facades\Log;

Ha most elindítjuk a kiírást a log fájlban megjelenik az esemény naplózása.

[2022-04-12 19:42:35] local.INFO: Creating event folyamatban  
[2022-04-12 19:42:35] local.INFO: Created event befejeződött  

Eseménykezelés listener használatával

Természetesen nem szeretnénk a konstruktorban megadni az eseménykezelést, így hozzunk létre listener osztályokat és adjuk át neki paraméterként az eseménykezelőket.

php artisan make:listener StudentCreatingListener --event=StudentCreatingEvent
php artisan make:listener StudentCreatedListener --event=StudentCreatedEvent

Az app\Listeners könyvtárban létrejön a két osztály. Ezeket az app\Providers\EventServideProvider.php állományban regisztrálni kell.

protected $listen = [
    Registered::class => [
        SendEmailVerificationNotification::class,
    ],
    \App\Events\StudentCreatingEvent::class => [
        \App\Listeners\StudentCreatingListener::class
    ],
    \App\Events\StudentCreatedEvent::class => [
        \App\Listeners\StudentCreatedListener::class
    ]
];

Alakítsuk át a StudentCreatingEvent osztályt és vegyük ki a konstruktorból az eseménykezelést, helyette adjuk át a modellt mint paraméter és importáljuk a Student modellt.

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

Most a Student modellben létrehozott esemény automatikusan meghívja a listener osztályt. A StudentCreatingListener osztályban importálni kell a Log osztályt.

use Illuminate\Support\Facades\Log;

A handle metódusban kezeljük az eseményt. Logoljuk az adatbázis eseményt és fűzzük hozzá az érkező eseményben lévő modellt.

public function handle( StudentCreatingEvent $event ) {
 
    Log::info( "Hívás a StudentCreatingListener osztályból" . $event->student );
}

Ugyanezeket a lépéseket ismételjük meg a StudentCreatedEvent és a StudentCreatedListener osztályokban is. Indítsuk el az adatfelvételt és nézzük meg az eredményt a storate\logs\laravel.log állományban.

[2022-04-23 08:50:53] local.INFO: Hívás a StudentCreatingListener osztályból
{"name":"Teszt Elek","email":"elekecske@teszt.hu","phone":"123456789"}  
[2022-04-23 08:50:53] local.INFO: Hívás a StudentCreatedListener osztályból
{"name":"Teszt Elek","email":"elekecske@teszt.hu","phone":"123456789","updated_at":"2022-04-23T08:50:53.000000Z","created_at":"2022-04-23T08:50:53.000000Z","id":8}  

Eseménykezelés observer használatával

Hozzunk létre egy observer osztályt és adjuk át neki a modellt mint paraméter.

php artisan make:observer StudentObserver --model=Student

Az app\Observers könyvtárban létrejött az osztályunk. Egészítsük ki a saját metódusunkkal ami a létrehozást fogja majd figyelni.

public function creating(Student $student) {
    //
}
 
public function created(Student $student) {
    //
}

Az eseményfigyelőt regisztrálni kell az AppServiceProvider osztályban, importálni kell a két saját osztályunkat.

use App\Models\Student;
use App\Observers\StudentObserver;

Vegyük fel az observert a boot metódusban.

public function boot() {
 
    Student::observe( StudentObserver::class );
}

A StudentObserver osztályban emeljük be a Log osztályt.

use Illuminate\Support\Facades\Log;

Töltsük fel a creating és a created metódusokat.

public function creating(Student $student) {
 
    Log::info( "Hívás a StudentObserver creating metódusból" . $student );
}
 
public function created(Student $student) {
 
    Log::info( "Hívás a StudentObserver created metódusból" . $student );
}

Természetesen az itt található metódusok ( update, delete stb. ) is automatikusan működnek. Indítsuk el az adatbázisba írást, nézzük meg a log fájlt.

[2022-04-23 09:40:13] local.INFO: Hívás a StudentObserver creating metódusból
{"name":"Kiss P\u00e1l","email":"palika@teszt.hu","phone":"123456789"}  
[2022-04-23 09:40:13] local.INFO: Hívás a StudentObserver created metódusból
{"name":"Kiss P\u00e1l","email":"palika@teszt.hu","phone":"123456789",
"updated_at":"2022-04-23T09:40:13.000000Z","created_at":"2022-04-23T09:40:13.000000Z","id":9}  

Modellek hatóköre

Hozzunk létre egy projectet student néven, legyen egy adatbázisunk szintén student néven, name, email, phone, active mezőkkel. Töltsük fel legalább 5 rekorddal, az active mezőben 0 vagy 1 legyen. Készítsünk egy StudentController vezérlőt. Ha az adatbázisból szeretnénk kiolvasni azokat a rekordokat amelyekben az active mezőben 1 van, akkor a kontrollerben a következőképpen tudjuk lekérdezni.

public function listStudent() {
 
 
    $students = Student::where( "active", 1 )->get();
 
    echo "<pre>";
    print_r( $students );
}

Ha további feltételeink is vannak akkor halmozhatjuk a where záradékokat.

public function listStudent() {
 
 
    $students = Student::where( "active", 1 )->where()->where()->get();
 
    echo "<pre>";
    print_r( $students );
}

Local scope

Ezt elkerülve létrehozhatunk a modellben egy hatókört ( scope ).

public function scopeWhereActive( $query ) {
 
    return $query->where( "active", "1" );
}

A kontrollerben egyszerűen meghivatkozzuk a keresett mezőt.

public function listStudent() {
 
 
    $students = Student::whereactive()->get();
 
    echo "<pre>";
    print_r( $students );
}

Hogy dinamikusan tudjunk keresni az aktív és inaktív diákok között, egészítsük ki a kontrollert egy újabb metódussal és adjuk át paraméterként a szűrési feltételt.

public function listActiveStudent() {
 
    $students = Student::whereactive( "1" )->get();
 
    echo "<pre>";
    print_r( $students );
}
 
public function listInActiveStudent() {
 
    $students = Student::whereactive( "0" )->get();
 
    echo "<pre>";
    print_r( $students );
}

A modellben vegyük fel az érkező változót, ez dinamikusan be fog helyettesítődni a megfelelő helyre.

public function scopeWhereActive( $query, $arg ) {
 
    return $query->where( "active", $arg );
}

Írjuk át az útvonalakat, vegyük fel az új hivatkozást.

Route::get( "/aktiv-diaklista", [ StudentController::class, "listActiveStudent" ]);
Route::get( "/inaktiv-diaklista", [ StudentController::class, "listInActiveStudent" ]);

Global scope

Az általunk létrehozott scope-oknak nincs meghatározott helye, így az app könyvtárban hozzunk létre egy scopes könyvtárat, abban egy ActiveScope.php állományt. A scope-k használatához implementálnunk kell a Scope interfészt. Végezzük el az importálásokat.

namespace App\Scopes;
 
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;

Majd készítsük el az osztályt abban egy apply metódust a kötelező paramétereivel.

class ActiveScope implements Scope {
 
    public function apply( Builder $builder, Model $model ) {
 
        $builder->where( "active", "1" );
    }
}

A modellben készítsünk egy booted nevű metódust és hivatkozzuk meg a scope osztályunkat.

protected static function booted() {
 
    static::addGlobalScope( new ActiveScope );
}

Módosítsuk a kontrollert, kommenteljük a listInActiveStudent és írjuk át a listActiveStudent metódust.

public function listActiveStudent() {
 
 
    $students = Student::all();
 
    echo "<pre>";
    print_r( $students );
}

Most elegendő minden adatot lekérni, szűrés nélkül, mivel a scope-ban van meghatározva a szűrés feltétele. Ha nincs szükségünk a globális scope használatára tudunk úgy is lekérdezni, hogy a feltétel ne érvényesüljön.

public function listActiveStudent() {
 
    $students = Student::withoutGlobalScope( ActiveScope::class )->get();
 
    echo "<pre>";
    print_r( $students );
}

Anonymous global scope

Névtelen globális scope létrehozásához a Student modellben emeljük be a Builder osztályt.

use Illuminate\Database\Eloquent\Builder;

Majd alakítsuk át a booted metódust.

protected static function booted() {
 
    static::addGlobalScope( "active", function( Builder $builder ) {
 
         $builder->where( "active", "1" );
    });
}

A globalscope első paramétere a scope neve, második paraméter egy névtelen függvény ahol egy query buildert építünk az adat lekérdezéséhez. A kontrollerben egy egyszerű lekérdezést hozzunk létre.

public function listActiveStudent() {
 
    $students = Student::all();
 
    echo "<pre>";
    print_r( $students );
}

Ha nincs szükségünk a hatókör használatára akkor lekérdezhetjük az adatokat hatókör nélkül is. Ilyenkor nem érvényesül a szűrő.

public function listActiveStudent() {
 
    $students = Student::withoutGlobalScope( "acive" )->get();
 
    echo "<pre>";
    print_r( $students );
}

A különbség a globális scope és az anonim globalis scope között, hogy a globás scope használatához létre hoztunk egy külön osztályt, az anonim globális scope esetében pedig közvetlenül a modellben definiáltuk a szűrési feltételt.


Middleware

A middlewarek egy automatikus mechanizmust biztosítanak az alkalmazásba érkező http kérések ellenőrzésére. Minden kérésnek át kell mennie egy közbülső alkalmazáson mielőtt belépne a fő alkalmazásba. Ez a middleware vagy köztes szoftver. A middlewareknek több funkciója is van például a CORS middleware amely egy fejlécet ad minden válaszhoz. Hatókör szempontjából három féle middleware létezik, a globális, a csoportos és az irányított middleware. A globális az egész alkalmazásban általánosan érvényes, a csoportos egy megadott útvonalcsoportra, míg az irányított egy adott útvonalra érvényes. Az alkalmazott middlewarek a Http/Middleware könyvtárban vannak, ha létrehozunk egy sajátot az is ide kerül. A middlewarek felhasználását, hogy például globális a Kernel.php állomány tartalmazza csoportosítva. Vegyük példának, ha néhány országból nem akarunk beengedni kéréseket a szerverünkre akkor azt például globális middlewarrel tudjuk szűrni.

Globális middleware

Ha például az url így érkezik

url/?country=hu

Ezt engedjük be, ha mondjuk Németországból vagy Angliából érkezik akkor tiltsuk ki, illetve az ausztriai kéréseket is engedjük be. Hozzuk létre a middlewareünket

php artisan make:middleware CountryAllowed

A Http/Middleware könyvtárban létrejött a fájl, globális middleware szabályként fogjuk alkalmazni. Vegyük fel a globális middlewarek listájába a Saját osztályunkat.

protected $middleware = [
    // \App\Http\Middleware\TrustHosts::class,
    \App\Http\Middleware\TrustProxies::class,
    \App\Http\Middleware\CountryAllowed::class,
    \Fruitcake\Cors\HandleCors::class,
    \App\Http\Middleware\PreventRequestsDuringMaintenance::class,
    \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
    \App\Http\Middleware\TrimStrings::class,
    \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
];

Töltsük fel az osztályunkban a handle metódust a szabállyal.

public function handle(Request $request, Closure $next) {
 
    if( $request->country && !in_array( $request->country, array( "hu", "at" ))) {
 
        return redirect( "no-allowed" );
    }
    return $next( $request );
}

Hozzuk létre a nézetet no_allowed és az útvonalat.

<h1>Tiltott hozzáférés</h1>
Route::view( "/no-allowed", "no_allowed" );

Csoportos middleware

Ha sok útvonalunk van és szeretnénk szabályokat létrehozni de csak néhány útvonalhoz akkor nem a globális szabályokat kell alkalmazni, hanem létrehozunk egy csoportot és ott állítjuk be a szükséges szabályokat. Például, ha van négy útvonalunk de csak kettőn szeretnénk engedélyezni a tartalmat akkor ezekre az útvonalakra hozunk létre szabályokat. Maradjunk az eredeti helyzetnél, csak a magyarországi és az ausztriai kéréseket engedélyezzük. Vegyük fel az osztályunkat a middlewareGroups szekcióban, a globális szekcióból vegyük ki a szabályt.

protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            // \Illuminate\Session\Middleware\AuthenticateSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
 
        'api' => [
            // \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
            'throttle:api',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
        "apprestrict" => [
            \App\Http\Middleware\CountryAllowed::class,
        ]
    ];

Hozzuk létre az útvonalcsoportot és benne az útvonalakat.

Route::group([ "middleware" => [ "apprestrict"]], function() {
 
    Route::get( "/orszag1", function() {
        echo "<h2>Ország 1 oldala</h2>";
    });
    Route::get( "/orszag2", function() {
        echo "<h2>Ország 2 oldala</h2>";
    });
});
Route::get( "/orszag3", function() {
    echo "<h2>Ország 3 oldala</h2>";
});
Route::get( "/orszag4", function() {
    echo "<h2>Ország 4 oldala</h2>";
});

Nézzük meg böngészőben, mivel az 1 és a 2 ország tartalom védett csak az engedélyezett országkóddal lehet megnézni. Hívjuk végig az oldalakat, most minden ország oldal megjelenik.

localhost:8000/orszag1
localhost:8000/orszag2
localhost:8000/orszag3
localhost:8000/orszag4

Ha hozzácsatolunk országkódot akkor láthatjuk, hogy a szabályaink működnek.

localhost:8000/orszag1?country=hu
localhost:8000/orszag1?country=ru
localhost:8000/orszag2?country=hu
localhost:8000/orszag2?country=ru
localhost:8000/orszag3?country=hu
localhost:8000/orszag3?country=ru
localhost:8000/orszag4?country=hu
localhost:8000/orszag4?country=ru

Egyedi middleware

Vegyük fel az osztályunkat a routeMiddleware szekcióban, vegyük ki a csoportos szabályok közül és alakítsuk át az útvonalat.

protected $routeMiddleware = [
        'auth' => \App\Http\Middleware\Authenticate::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
        'can' => \Illuminate\Auth\Middleware\Authorize::class,
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
        'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
        'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
        'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
        'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
        "apprestrict" => \App\Http\Middleware\CountryAllowed::class,
    ];

Például, ha csak a negyedik útvonalat akarjuk védeni akkor ehhez az útvonalhoz csatoljuk hozzá a szabályunkat és adjuk át neki a szabály nevét.

Route::get( "/orszag1", function() {
    echo "<h2>Ország 1 oldala</h2>";
});
Route::get( "/orszag2", function() {
    echo "<h2>Ország 2 oldala</h2>";
});
Route::get( "/orszag3", function() {
    echo "<h2>Ország 3 oldala</h2>";
});
Route::get( "/orszag4", function() {
    echo "<h2>Ország 4 oldala</h2>";
})->middleware( "apprestrict" );

Próbáljuk ki böngészőben, hogyan működik a szabály.

localhost:8000/orszag1?country=ru
localhost:8000/orszag2?country=ru
localhost:8000/orszag3?country=ru
localhost:8000/orszag4?country=ru

HTTP kérés

Az interneten található harmadik féltől származó szabadon használható REST API kiszolgálók közül a teszteléshez használjuk a következőt:

https://jsonplaceholder.typicode.com

Készítsünk egy vezérlőt és egy metódust amely lekérdezi a kiszolgáló adatait. A json állomány olvasható megjelenítéséhez használjuk a json_decode() függvényt.

php artisan make:controller PostController

Emeljük be a Http osztályt.

namespace App\Http\Controllers;
 
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
 
class PostController extends Controller
{
    public function index() {
 
        $posts = Http::get("https://jsonplaceholder.typicode.com/posts");
 
        return json_decode( $posts );
    }
}

Készítsük el az útvonalat.

Route::get( "/posts", [ PostController::class, "index" ]);

Nézzük meg a böngészőben a kapott eredményt. Most jelenítsük meg nézetben a kapott adatokat. Alakítsuk át az index metódusunkat.

public function index() {
 
    $posts = Http::get("https://jsonplaceholder.typicode.com/posts");
 
    return view( "posts", [
 
       "posts" => json_decode( $posts )
    ]);
}

Hozzuk létre a nézetet.

<table>
    <thead>
        <th>Id</th>
        <th>UserId</th>
        <th>Title</th>
    </thead>
    <tbody>
        @foreach( $posts as $post )
            <tr>
                <td>{{ $post->id }}</td>
                <td>{{ $post->userId }}</td>
                <td>{{ $post->title }}</td>
            </tr>
        @endforeach
    </tbody>
</table>

URL helper

Laravelben tudunk url-t generálni egy meglévő útvonalunkból. Hozzuk létre az alábbi útvonalat.

Route::get( "/call/{id}", function( $id ) {
    echo "Ez a hívási útvonal " . $id;
});

Nézzük meg a böngészőben az eredményt, majd készítsünk egy másik útvonalat ami generál egy url-t az előző útvonalból.

Route::get( "/test", function() {
    echo url( "call/5" );
});

Nézzük meg a generált url-t. Ha az actuális url-t szeretnénk visszaadni akkor használjuk a current függvényt.

Route::get( "/test", function() {
    echo url()->current();
});

A teljes url-t a full függvénnyel tudjuk visszaadni.

Route::get( "/test", function() {
    echo url()->full();
});

Ezeket a helpereket használhatjuk az URL osztályon keresztül is. Ehhez emeljük be az URL osztályt.

use Illuminate\Support\Facades\URL;

Készítsük el az útvonalat.

Route::get( "/test", function() {
    echo URL::current();
});

Route helper

A route helper segítségével vissza tudunk adni egy másik útvonalat. Írjuk át a test útvonalunkat, hogy visszadja call útvonalat és egy tömbben adjuk át a paramétert.

Route::get( "/test", function() {
    echo route( "call", [ "id" => 3 ]);
});

Ahhoz, hogy a call útvonalat hívhassuk, el kell nevezni.

Route::get( "/call/{id}", function( $id ) {
    echo "Ez a hívási útvonal " . $id;
})->name( "call" );

Ezek a helperek működnek vezérlő metódusokra is. Hozzunk létre egy új útvonalat ami egy metódusra hivatkozik a StudentControllerben.

Route::get( "/test", function() {
    echo route( "example" );
});
Route::get( "/minta", [ StudentController::class, "example" ])->name( "example" );

Így megkapjuk az example metódus url-jét.


Action helper

Az action helper is egy url-t fog visszaadni, írjuk át a test útvonalat.

Route::get( "/test", function() {
    echo action([ StudentController::class, "example" ]);
});

Az action helperek csak osztályokkal működnek, ha egy normál útvonal url-jét próbáljuk visszaadni, hibát fogunk kapni. Ha paramétert is szeretnénk átadni, egészítsük ki egy tömbbel a helpert.

Route::get( "/test", function() {
    echo action([ StudentController::class, "example" ], [ "id" => 3 ]);
});

Természetesen ilyenkor a másik útvonalon is kell fogadnunk a paramétert.

Route::get( "/minta{id}", [ StudentController::class, "example" ])->name( "example" );

Honosítás

Ha több nyelvű oldalt szeretnénk, alapértelmezetten nem jön létre lang könyvtár, ezt nekünk kell létrehoznunk.

php artisan lang:publish

Ilyenkor létrejön a projekt alap könyvtárában egy lang könyvtár melyben alapértelmezetten egy en könyvtár található. Hozzunk létre mellé egy hu könyvtárat, ebbe kerülnek majd a magyar nyelvű tartalmak. Hozzunk létre egy ServiceController vezérlőt és abban egy service metódust, ami csak egy nézetet ad vissza.

php artisan make:controller ServiceController
class ServiceController extends Controller {
 
    public function service() {
 
        return view( "service" );
    }
}

Készítsük el a nézetet, egyszerű tartalmat helyezzünk el benne. Vegyük fel az útvonalat is.

<h1>Welcome to service page</h1>
Route::get( "/service", [ ServiceController::class, "service" ]);

Nézzük meg a böngészőben. Most a beállított tartalom jelenik meg. Nyissuk meg az app/config/config.php állományt és kerssük meg a locale változó beállítását. Állítsuk át az en értéket hu -ra. Hozzunk létre a lang/hu könyvtárban egy messages.php fájlt.

<?php
 
return [
    "page_message" => "Üdvözlet a kiszolgáló oldalán"
];

Cseréljük a tartalmat a nézetben.

<h1>{{ __( "messages.page_message" ) }}</h1>

Nézzük meg a böngészőben, most magyarul kell megjelennie az üzenetnek. Ha dinamikusan szeretnénk nyelvet választani írjuk át az útvonalat.

Route::get( "{locale}/service", [ ServiceController::class, "service" ]);

A ServiceControllerben emeljük be az App osztályt, vegyük át az útvonalról érkező változót és állítsuk be a nyelvi kódolást.

use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
 
class ServiceController extends Controller {
 
    public function service( $locale ) {
 
        App::setLocale( $locale );
 
        return view( "service" );
    }
}

A resources/lang/en könyvtárban is hozzuk létre a messages.php állományt és helyezzük el benne a szükséges szöveget.

<?php
 
return [
    "page_message" => "Welcome to service page"
];

A nézetben van több lehetőségünk megadni, hogy melyik nyelvi fájlt szeretnénk használni.

<h1>{{ __( "message.page_message" ) }}</h1>
 
<h1>{{ trans( "message.page_message" ) }}</h1>
 
<h1>{{ @lang( "message.page_message" ) }}</h1>

Azonosítás

Breeze

Laravelben rendelkezésre állnak azonosítást egyszerűsítő előre elkészített csomagok. A breeze telepítéséhez futtassuk a composer megfelelő parancsát.

composer require laravel/breeze

Ez letölti a szükséges csomagot de a projektünkben még nem tudjuk használni. Ehhez az artisan csomagkezelővel installálni kell a projektben is.

php artisan breeze:install

Értesítést kapunk, hogy telepítsük a szükséges nodejs függőségeket futtassuk a megfelelő parancsot.

npm install && npm run dev

Most már használható breeze csomag, ha megnézzük a Laravel üdvözlő oldalát megjelent jobb felső sarokban két link a regisztráláshoz és a bejelentkezéshez. Érdemes a projekt készítésének az elején telepíteni a breeze -t mert az elkészített útvonalainkat törölni fogja. Készítsünk projetet authenticating néven, telepítsük a breeze csomagot. Nézzük meg a routes/web.php állományt. Két útvonalat találunk benne amit a breeze hozott létre.

Route::get('/dashboard', function () {
    return view('dashboard');
})->middleware(['auth'])->name('dashboard');
 
require __DIR__.'/auth.php';

Az első a dashboard nézetre mutat amit csak regisztráció és bejelentkezés után érünk el. Ezt a nézetet is a breeze generálta. A második egy hivatkozás az auth.php állományra ide emeli be az ott található útvonalakat.

use App\Http\Controllers\Auth\AuthenticatedSessionController;
use App\Http\Controllers\Auth\ConfirmablePasswordController;
use App\Http\Controllers\Auth\EmailVerificationNotificationController;
use App\Http\Controllers\Auth\EmailVerificationPromptController;
use App\Http\Controllers\Auth\NewPasswordController;
use App\Http\Controllers\Auth\PasswordResetLinkController;
use App\Http\Controllers\Auth\RegisteredUserController;
use App\Http\Controllers\Auth\VerifyEmailController;
use Illuminate\Support\Facades\Route;
 
Route::middleware('guest')->group(function () {
    Route::get('register', [RegisteredUserController::class, 'create'])
                ->name('register');
 
    Route::post('register', [RegisteredUserController::class, 'store']);
 
    Route::get('login', [AuthenticatedSessionController::class, 'create'])
                ->name('login');
 
    Route::post('login', [AuthenticatedSessionController::class, 'store']);
 
    Route::get('forgot-password', [PasswordResetLinkController::class, 'create'])
                ->name('password.request');
 
    Route::post('forgot-password', [PasswordResetLinkController::class, 'store'])
                ->name('password.email');
 
    Route::get('reset-password/{token}', [NewPasswordController::class, 'create'])
                ->name('password.reset');
 
    Route::post('reset-password', [NewPasswordController::class, 'store'])
                ->name('password.update');
});
 
Route::middleware('auth')->group(function () {
    Route::get('verify-email', [EmailVerificationPromptController::class, '__invoke'])
                ->name('verification.notice');
 
    Route::get('verify-email/{id}/{hash}', [VerifyEmailController::class, '__invoke'])
                ->middleware(['signed', 'throttle:6,1'])
                ->name('verification.verify');
 
    Route::post('email/verification-notification', [EmailVerificationNotificationController::class, 'store'])
                ->middleware('throttle:6,1')
                ->name('verification.send');
 
    Route::get('confirm-password', [ConfirmablePasswordController::class, 'show'])
                ->name('password.confirm');
 
    Route::post('confirm-password', [ConfirmablePasswordController::class, 'store']);
 
    Route::post('logout', [AuthenticatedSessionController::class, 'destroy'])
                ->name('logout');
});

Látható, hogy az összes útvonal itt van felvéve ami az azonosítással kapcsolatos. A regisztráció útvonala a RegisteredUserController -re mutat, nyissuk meg. A create metódus csak egy nézetet ad vissza ahol regisztrációs form található, a store metódusban vannak leírva a regisztráció feltételei.

public function store(Request $request) {
 
    $request->validate([
        'name' => ['required', 'string', 'max:255'],
        'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
        'password' => ['required', 'confirmed', Rules\Password::defaults()],
    ]);
 
    $user = User::create([
        'name' => $request->name,
        'email' => $request->email,
        'password' => Hash::make($request->password),
    ]);
 
    event(new Registered($user));
 
    Auth::login($user);
 
    return redirect(RouteServiceProvider::HOME);
}

Validálási előírások:

name -> elvárt, szöveg, maximum 255 karakter
email -> elvárt, szöveg, email formátumú, maximum 255 karakter, a users táblában egyedi
password -> elvárt, meg kell ismételni, a Password osztály defaults() metódusa szerint legalább 8 karakter

A felhasználó adatbázisba rögzítésekor a jelszó kódolva kerül a users táblába. A végén a return egy átirányítás ami a Providers/RouteServiceProvider osztály HOME állandójára mutat. Nézzük meg.

public const HOME = '/dashboard';

Ez az állandó tárolja, hogy regiszráció után melyik nézet jelenjen meg. Most a dashboard nézetre mutat, ha szeretnénk, hogy a saját nézetünkre mutasson írjuk át a tartalmát.

public const HOME = '/sajat_nezet';

A regisztrációs nézetet a wiews/auth/register.blade.php tárolja, ha változtatni szeretnénk, itt kell módosítani. Ide komponensek vannak beemelve például az input mezők, ha szeretnénk kicserélhetjük a saját mezőinkre.


Jetstream

Két lehetőség van a használatára, a Livewire + blade és a weboldal készítéséhez az Inertia + vue. A Jetstream alkalmas a regisztráció, bejelentkezés, a két tényezős hitelesítés, session kezelés és az API támogatására a Laravel Sanctum csomagon keresztül. Készítsünk egy új projektet és telepítsük a Jetstreamet.

composer require laravel/jetstream
php artisan jetstream:install livewire

Futtasuk le a nodjs függőségeket telepítő parancsokat.

npm install && npm run dev

Livewire

Indítsuk el az alkalmazásunkat, regisztráljunk és a sikeres regisztráció után a dashboard felületen a kijelentkezés lehetőségen kívűl még kapunk egy profile opciót is. A profile lehetőségei:

Felhasználónév és email cím módosítása
Új jelszó megadása
Két tényezős autentikáció bekapcsolása
Más böngészőkben és eszközökön indított sessionokból kijelentkezés
Account törlése.

Hasonlóan mint a breeze a resources/views/auth könyvtárban találjuk a nézeteket amelyek a regisztrációs és bejelentkező felületeket biztosítják. A config/fortify.php állomány tartalmazza a profil oldalon megjelenő opcióknak a vezérlését. Ezek a metódusok az Actions/Fortify könyvtár állományaira mutatnak.

    'features' => [
        Features::registration(),
        Features::resetPasswords(),
        // Features::emailVerification(),
        Features::updateProfileInformation(),
        Features::updatePasswords(),
        Features::twoFactorAuthentication([
            'confirm' => true,
            'confirmPassword' => true,
        ]),
    ],
 
];

Itt található a HOME állandó is amelyet, ha módosítunk a saját oldalunkat jeleníthetjük meg regisztráció illetve bejelentkezés után. A config/jetstream állományban találjuk például a profil oldalon a profilkép megjelenítésének a lehetőségét. Ez alpértelmezetten ki van kommentelve.

'features' => [
        // Features::termsAndPrivacyPolicy(),
        // Features::profilePhotos(),
        // Features::api(),
        // Features::teams(['invitations' => true]),
        Features::accountDeletion(),
    ],

Inertia Js

Telepítsük a jetstreamet a szokásos módon.

composer require laravel/jetstream

Installáljuk az inertia csomagot a projectben.

php artisan jetstream:install inertia

A fájlrendszer felépítése a vezérlés részen szinte ugyanaz, a különbség a nézet fájlokban van. Létrejött a resources könytárban egy js könyvtár, ebben találjuk a nézetek komponenseit .vue kiterjesztéssel. Az autentikációs nézeteinket a resources/js/Pages/Auth könyvtárban találjuk. Ha ezekben az állományokban változtatunk valamit abban az esetben újra kell futtatni az npm run dev utasítást.


Stub

A Laravel az artisan parancsok segítségével hozza létre a különböző osztályainkat. Ezeket egy úgynevezett stub készletből generálja. Ha szeretnénk megnézni ezeket a vázakat illetve saját templétet hoznánk létre, vegyük fel a projektünkbe ezeket a vázakat.

php artisan stub:publish

Ennek a parancsnak a hatására létrejön egy stubs könyvtár, ebben találhatóak a generálható osztályok leírásai.


Saját artisan parancsok

Ha kiadjuk a php artisan parancsot listát kapunk a kiadható parancsokról. Ha létrehozunk saját parancsot akkor létrejön egy fájl ami az app/Console/Commands könyvtárban található.

php artisan make:command StudentInfo

A létrejött StudentInfo fájl tartalma:

<?php
 
namespace App\Console\Commands;
 
use Illuminate\Console\Command;
 
class StudentInfo extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'command:name';
 
    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Command description';
 
    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }
 
    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        return 0;
    }
}

Ez egy program váz ami a stub könyvtárból származik, a létrehozott parancs futtatásakor a handle metódus fog lefutni. Alakítsuk át az osztályt a saját parancsunkhoz.

protected $signature = 'student:info';
 
 /**
 * The console command description.
 *
 * @var string
 */
protected $description = 'Show student info';

Ha futtatjuk a php artisan parancsot a listában megtalálhatjuk a saját parancsunkat. A használatához írjuk át a handle metódust.

public function handle() {
 
    $firstname = $this->ask( "What is Student firstname?" );
    $lastname = $this->ask( "What is Student lastname?" );
 
    $this->info( "Student info: Firstname: " . $firstname . " Lastname: " . $lastname );
}

Most egy kérdést hoztunk létre de még további lehetőségek is vannak. Készíthetünk line, info, comment, question és error opciókat is. Ha a saját parancson keresztül szeretnénk kapcsolatba kerülni a modellel és a bevitt adatokat kiírni az adatbázisba, erre is van lehetőség. írjuk át a handle metódust. Emeljük be a User modellt és a jelszó titkosításához szükséges Hash osztályt.

use Illuminate\Support\Facades\Hash;
use App\Models\User;
public function handle() {
 
    $input[ "name" ] = $this->ask( "User name?" );
    $input[ "email" ] = $this->ask( "Email?" );
    $input[ "password" ] = $this->ask( "Password?");
    $input[ "password" ] = Hash::make( $input[ "password" ]);
 
    $this->info( "name: " . $input[ "name" ] . " email: " . $input[ "email"] . "password: " . $input[ "password" ] );
}

Most még a metódus kiírja az adatokat a konzolra, az adatbázisba íráshoz cseréljük ki a műveletet.

public function handle() {
 
    $input[ "name" ] = $this->ask( "User name?" );
    $input[ "email" ] = $this->ask( "Email?" );
    $input[ "password" ] = $this->ask( "Password?");
    $input[ "password" ] = Hash::make( $input[ "password" ]);
 
    User::create( $input );
}

Hozzunk létre egy parancsot amely kilistázza a felhaszálókat.

php artisan make:command UsersList

Emeljük be a létrejött UsersList osztályban a User modellt és alakítsuk át az osztályt a saját parancsunkhoz.

<?php
 
namespace App\Console\Commands;
 
use Illuminate\Console\Command;
use App\Models\User;
 
class UsersList extends Command {
 
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'users:list';
 
    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'List users';
 
    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }
 
    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        $this->table(
            [ "Id", "Name", "Email"],
            User::all([ "id", "name", "email" ])->toArray()
        );
    }
}

Email küldése

Küldés gmail smtp szerverrel

A hitelesítés beállításához a .env állományban vegyük fel a megfelelő adatokat.

MAIL_MAILER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USERNAME=teszt@gmail.com
MAIL_PASSWORD=titkosjelszó
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=teszt@gmail.com
MAIL_FROM_NAME="Laravel teszt"

Hozzunk létre egy vezérlőt és egy mail osztályt.

php artisan make:controller EmailController
php artisan make:mail TestMail

A TestMail osztályt a létrejött Mail könyvtárban találjuk. A kontrollerben emeljük be a saját mail osztályunkat és a Laravel saját mail osztályát.

use App\Mail\TestMail;
use Illuminate\Support\Facades\Mail;

Készítsünk egy metódust ami elkészíti a levelünket.

public function sendMail() {
 
    $details = [
        "title" => "Példa email",
        "body" => "Példa body"
    ];
 
    Mail::to( "teszt@gmail.com" )->send( new TestMail( $details ));
 
    echo "<h3>Sikeres küldés</h3>";
}

a Laravel TestMail modelljében fogadjuk a létrehozott változót.

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

A levél küldésekor az itt található build metódus hívása automatikusan megtörténik, alakítsuk át.

public function build() {
 
    return $this->subject( "Teszt levél Laravelből" )->view( "emails.test-mail" );
}

Hozzuk létre a emails/test-mail nézetet.

<h3>{{ $details["title"] }}</h3>
<p>{{ $details[ "body" ]}}</p>

Készítsük el az útvonalat, emeljük be a kontrollert.

use App\Http\Controllers\EmailController;
 
Route::get( "/send-mail", [ EmailController::class, "sendMail" ]);

Küldés markdown sablon használatával

Töröljük az előbb létrehozott Mails és a nézetben a mails könyvtárakat. Hozzuk létre újra de most a markdown segítségével.

php artisan make:mail TestMail --markdown=mails.testMail

A Mail/TestMail állományban most a build metódusban a markdown hívja meg a resources/views/testMail nézetet.

public function build() {
 
    return $this->markdown('mails.testMail');
}

Helyezzük vissza a TestMail osztályba az email részleteit tartalmazó változót.

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

Alakítsuk át a nézetet.

@component('mail::message')
    # Introduction

    The body of your message.
    <h2>{{ $details[ "title" ]}}</h2>
    <h2>{{ $details[ "body" ]}}</h2>
 
    @component('mail::button', ['url' => ''])
        Button Text
    @endcomponent
 
    Thanks,<br>
    {{ config('app.name') }}
@endcomponent

Markdown sablon testreszabása

Ha a sablonhoz szeretnénk hozzáadni panelt, bővítsük a kódot.

@component('mail::message')
# Introduction

Ez az üzenet törzse.
<h2>{{ $details[ "title" ]}}</h2>
<h2>{{ $details[ "body" ]}}</h2>
 
@component('mail::button', ['url' => ''])
Gomb felirat
@endcomponent
 
@component( "mail::panel" )
Ez egy panel komponens
@endcomponent
 
Thanks,<br>
{{ config('app.name') }}
@endcomponent

Egészítsük ki egy táblázat komponenssel.

@component( "mail::table" )
| Laravel | Táblázat  | Példa  |
| ------- |:---------:| ------:|
| sor 1   | középre   | sor 1  |
| sor 2   | jobbra    | sor 2  |
@endcomponent

Látható, hogy a logo és a html kód testreszabásához nincs lehetőség ebben a fájlban. Ha erre lenne szükség akkor közzé kell tenni az ezeket tartalmazó állományokat.

php artisan vendor:publish --tag=laravel-mail

Kapunk egy vendor/mail könyvtárat a resources/views könyvtárban. Ez tartalmazza a html kódokat az egyes komponensekhez.


Linkek

https://laravel.com/docs/8.x 86