Fájl feltöltés, megjelenítés

Dalos Donát | 2022. 11. 28. 16:51 | Olvasási idő: 3 perc

Címkék: #Adatbázis (Database) #Cloud #Controller #HTML #Ingyenes (Free) #Laravel #Laravel 9 #MySQL #Nézet (View) #PHP #Vendégblogger

Dalos Donát hallgatóm készített egy bejegyzést a Laravel-es fájlfeltöltésről, én pedig igyekeztem megtalálni a téma helyét a tudásbázisunkban. Adta magát a lehetőség, hogy építsek a leírására és kössem össze a Breeze új, profil oldal funkciójával. Ebben a bejegyzésben a profil oldalhoz fogunk készíteni egy képfeltöltő funkcionalitást. Hiszen a mai világban már lassan nem is létezik olyan weboldal, ahol ne lenne valamilyen profil- vagy borítókép megjelenítve, amiket mindenképp tárolni kell, erre nézünk most egy példát.
Fajlfeltoltes

Kell hozzá a Blade komponens témakör!

Ha létrehozunk egy Laravel projektet, akkor láthatjuk, hogy létezik egy tároló mappa (storage). A Laravel alapértelmezetten ide menti el azokat a fájlokat, amit a felhasználó feltölt majd. Amire most szükségünk lesz, illetve ahol tárolni fogjuk az a  storage / app / public /... 

Megjegyzés: a storage mappa tartalma még az alkalmazásunk naplózását végző log fájl a logs mappájában, valamint a keretrendszerhez (framework) kapcsolódó részek, mint például a nézetek (views) lefordított verziói. De ha valakit érdekel a háttér, akkor megnézheti, hogy milyen kódot generált a mi nézeteinkből a Laravel motorja: storage / framework / views mappában az egyik véletlen karaktersorozat elnevezésű php fájlban találjuk a nézeteink lefordított verzióit, ez lesz az, amit megkap majd a felhasználó böngészője.

Első lépésben nekünk most az a célunk, hogy a felhasználó által feltöltött fájlok publikusan elérhetőek legyenek majd. Ehhez arra van szükség, hogy a public (nyilvános hozzáférésű) mappánkat összekössük a storage / app / public mappával. Ezt egy link segítségével fogjuk megtenni. Így elérhető lesz a felhasználó számára a feltöltött fájl. A következő parancssal lehet megoldani a link létrehozását:

php artisan storage:link

Ha lefutott, látható, hogy a public mappában megjelent egy storage mappa link.

Mivel általában sok képet mentünk el egy alkalmazásban, ezért mindenképp célszerű adatbázisban tárolni a nevüket és a (merevlemezen eltárolt) helyüket.

Hozzunk létre egy új migrációs fájlt pictures néven (vagy esetleg használd egy már létező táblád például termékeknél, márkáknál stb.).

php artisan make:migration create_pictures_table

Három darab új oszlopot kell hozzáadni, ahogy feljebb is említettem, és ha megvan, mehet is a migrálás.

public function up()
{
  Schema::create('pictures', function (Blueprint $table) {
    $table->id();
    $table->string('name')->nullable();
    $table->string('location')->nullable();
	$table->foreignId('user_id')->constrained()->onUpdate('cascade')->onDelete('cascade');
    $table->timestamps();
  });
}

A név és a hely oszlopokról már írtam, de vegyük észre, hogy itt van egy külső kulcs is, amivel hozzákötjük a profilképet a bejelentkezett felhasználóhoz (ha pedig a felhasználó módosul vagy törlődik, akkor a profilképe is hasonlóan "cselekszik", lásd a cascade paramétereket).

Migráljuk az adatbázisunkba a táblát:

php artisan migrate

Mivel adattábláról van szó, mindenképp kelleni fog egy modell osztály is, hozzuk is létre Picture néven.

php artisan make:model Picture

Ezen belül meg hivatkozzunk arra a két mezőre, amiket a migrációs fájlban definiáltunk:

protected $fillable = [
  'name',
  'location'
];

A teszt miatt létrehoztam egy új Controller-t is (de ez nem feltétlenül lenne kötelező).

php artisan make:controller PictureUploaderController

Ha ez megvan, akkor létrehozok három új útvonalat a web.php-ban és azon belül a middleware('auth') részben (ahol a többi profile útvonal is van már - ezáltal csak bejelentkezett felhasználók tudják majd elérni ezeket az új útvonalakat): az egyik a űrlapra fog vezetni (kvázi "create" Controller metódus), míg a másik az adatok eltárolására szolgál (kvázi "store" Controller metódus), és lesz még egy, ami a képet fogja megmutatni (kvázi "show" Controller metódus).

Route::get("/profile/picture/create" , [PictureUploaderController::class, 'create'])->name('profilepic.create');
Route::post("/profile/picture" , [PictureUploaderController::class, 'store'])->name('profilepic.store');
Route::get("/profile/picture" , [PictureUploaderController::class, 'show'])->name('profilepic.show');

A web.php tetején importáljuk be a PictureUploaderController fájlt.

Majd kezdjük a "create" útvonallal és annak a Controller metódusával, ami majd egy űrlapra fog vezetni minket.

public function create()
{
  return view('profile.picture.create');
}

Írjuk meg az űrlapot, ahhoz viszont hozzuk létre a resources / views / profile / picture / create.blade.php fájlt (ehhez persze szükség van a picture új mappára is).

A form tagbe nem hiányozhat a enctype="multipart/form-data", mert adatot mozgatunk.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Profilkép feltöltése</title>
</head>
<body>
    <form action="/profile/picture" method="POST" enctype="multipart/form-data">
        @csrf
        <label for="file">Profilkép kiválasztása:</label>
        <input type="file" id="file" name="file">
    </form>
</body>
</html>

Hozzuk létre a store() metódus magját is:

$request->validate([
            'file' => 'required|mimes:jpg,png|max:2048' // jelen pillanatban csak az img és png fájlokat fogadja el
            //megtudjuk adni mekkora legyen a max fájlméret
        ]);
        $save = new Picture(); // új példány létrehozása
        if ($request->file()) {
            $renames = time() . '_' . rand() . $request->file->getClientOriginalName();
            //Mivel fájlt kezelünk célszerű átnevezni a fájlt nehogy legyen egy ugyan olyan nevű
            //én egy idő értéket és egy random számot tűzök a kép neve elé
            $picture = $request->file('file')->storeAs( 'kepfeltolt' ,$renames , 'public'); // hova kerüljön a fájl
            $save->picturename = $renames; //elmentem a nevét
            $save->filelocation = 'storage/' . $picture; //lokációját
            $save->save();
        }
        return redirect("/"); // Visszatérés a fő oldalra

Már csak egy dolgunk van hátra, a fájlok lekérése. Még a web.php-nál át lett írva a welcome nézet, hogy a controllerben le tudjunk kérni az adatokat, mindenképp useolni kell a DB-t.

public function welcome()
{
  $keplekeses = DB::table("pictures")->select("*")->get();
  return view('welcome', compact("keplekeres"));
}

Ha ez megvan akkor utolsó lépésként jelenítsük meg a feltöltött képeket:

<html lang="hu">
<head>
    <title>Fő oldal</title>
</head>
<body>
@foreach ($keplekeres as $kep)
    <img src="{{$kep->filelocation}}" alt="">
@endforeach
</body>
</html>