Címkék: #composer #Integráció (Integration) #Laravel #Laravel 9 #npm #PHP #Telepítés (Installation)
Mivel az egyéb kötelességeim miatt régebben tudtam csak bejegyzést írni, ezért kicsit elavultak már azok a projektek, amiken dolgoztam korábban. Emiatt mindenképpen érdemes felfrissíteni ezeket a Laravel projektjeinket. Mit is értek ezalatt? Azt már tudjuk, hogy a webes világban szerencsére nem kell mindig "újra és újra feltalálni a kereket", ezért dolgozhatunk úgynevezett harmadik féltől származó osztálykönyvtárakkal, csomagokkal (3rd party libraries).
Emlékeztetőül: a weben mindig (legalább) két oldallal kell foglalkoznunk: a kliens és a szerver oldali kódjainkkal. Jó ezt feleleveníteni, mert a következő blogbejegyzésem a validációról fog szólni és ott is majd (legalább) ezt a két oldalt kell ellenőrizni... na de most még maradjunk a projekt felfrissítésénél.
Szerver oldal
A szerver oldali csomagjaink a projekt gyökerének vendor mappájában vannak, ezeket ugye manuálisan jobb nem piszkálni, ezért van nekünk a composer csomagkezelőnk, amely a frissítés megkezdésekor a composer.json fájlt veszi alapul akkor, amikor futtatjuk a composer update parancsot a terminal-ban. Ez azonban még csak a kiindulási pontja a műveletnek: először megnézi, hogy milyen harmadik féltől származó csomagokat használunk, majd megpróbálja letölteni az összes olyan csomagverziót, amiből talál frissebbet (csak akkor persze, ha a verziószám előtt ott van a ^ karakter, ami azt mondja meg a composer-nek, hogy "legalább ilyen verziószámú csomagot telepíts nekem"), a letöltés (downloading) után pedig következik a csomagok tényleges felfrissítése (upgrading).
Itt van például a nesbot/carbon csomag, amely jelenleg 281 különböző nyelven támogatja a dátumok és idők kezelését, úgyhogy ezt aránylag sokszor alkalmazhatjuk a projektjeinkben (esetleg nem is tudunk róla, hogy benne van már a Laravel projektünkben): https://packagist.org/packages/nesbot/carbon
Látható, hogy a legfrissebb stabil (!) verzió az a 2.58.0-s, de emellett a hármas verzióból van már fejlesztői változat is. Az oszlopokban bal oldalon látható, hogy milyen futtatókörnyezetet (PHP verziót) és csomagokat igényel mindenképpen éles környezetben, utána lévő oszlopban pedig a fejlesztői környezetes igényelt csomagjait is láthatjuk. A jobb oldali oszlopban, ha esetleg "el kell indulnunk visszafelé" (downgrading) a csomag verziószámaiban, kattinthatunk, válthatunk és akkor szintén mutatja nekünk, hogy épp az a kiválasztott verzió milyen más dolgokat igényel. Szóval ez packagist weboldal rettentő hasznos tud lenni a munka során.
Kliens oldal
A kliens oldali párjai mindezeknek a node_modules mappában találhatók meg. Itt az npm csomagkezelő lesz a segítségünkre, aminek a kiindulási pontja a package.json fájlunk lesz. npm update utasítás kiadásával szépen felfrissülnek a kliens oldalt támogató csomagjaink... ha minden szép és jó az életben. De azért ez elég ritka, úgyhogy bőven előfordulhat, hogy belefutunk olyan verziókülönbségekből adódó problémákba, amelyek megnehezíthetik a dolgunkat. Ilyenkor a package.json fájlban kezdünk el praktikusan turkálni (egy nagyon javasolt probléma- és megoldáskeresés futtatás után), és a verziókat próbáljuk meg megfelelően beállítani azért, hogy hiba nélkül lefuthasson a csomagok frissítése. Na de milyen verziókat is állítsunk be azért, hogy menjen minden, mint a karikacsapás? Ebben nagy segítségünkre van egy weboldal, amivel könnyedén tudunk keresni csomagokra és a kiválasztás után látszódik, hogy milyen verziószámmal dolgoznak aktuálisan, emellett ő maguknak milyen egyéb függőségeik vannak... jó mélyre is áshatunk, attól függően, hogy mekkora galibába kerültünk bele, de én mindenkinek a legjobbakat kívánom és persze azt, hogy sikerüljön minden ütközést feloldani. A kliens oldali függőségek rengetegében is van egy segítő weboldalunk: https://www.npmjs.com/
Itt is, ha ki szeretnék emelni egy példát, akkor a React osztálykönyvtárra hívnám fel a figyelmet: https://www.npmjs.com/package/react Az oldal röviden bemutatja nekünk a csomagot, megmondja, hogy hol található a repo-ja, weboldala, mi a legfrissebb verziószáma és még egy alap működtetést is bemutat nekünk. Amire fel szeretném hívni a figyelmet ennek kapcsán, az a felső tab-os navigációban látható: jelenleg 1 csomagtól függ a React, ellenben tőle 88 127 egyéb másik csomag függ, amelyeket mind böngészhetünk... jó nagy szám! Általában nekem az volt mindig a benyomásom, hogy a kliens oldali függőségek sokkal mélyebbek, szerteágazóbbak, mint a szerver oldaliak, de lehet ez csak egy amolyan megérzés a részemről... ha valakinek van cáfolata, azt szívesen fogadom.
Ha pedig már mindent IS frissítettünk (webszerver, PHP, MySQL, PHPMyAdmin, Laravel, külső csomagok stb.), akkor esetleg elveszhetünk az összes korábbi, ámde majd további "újraélesztést" igénylő projektünk felfrissítésébe... ez tényleg egy függőségi pokol már.
De aki itt elveszne, azt csak biztatni tudom, hogy legalább nem kell még React Native-ot használnia (mobil alkalmazásfejlesztéshez), aminél aztán tényleg elszabadul minden, és ami egy nappal korábban még működött, az másnapra már nem biztos, hogy fog, pedig nem változtattunk a saját kódunkon semmit, csak épp a függőségek már mást és másképp igényelnek...
Friss, ropogós, valós életbeli példa - avagy hogyan érjük el és módosítsuk az adatbázist kívülről, ha csak a programkódon keresztül van hozzáférésünk...?
Egy kis "nindzsázást"
tartogattam a bejegyzés végére, ugyanis a blog oldalam új tárhelyéül
szolgáló szerveren is frissült a PHP verziószáma, aminek okán már tudtam
frissíteni a Laravel-t is a legfrissebb verzióra, ezért is kapcsolódik ez a mostani blogbejegyzéshez.
A frissítés során, természetesen akadt egy olyan probléma,
hogy sajnos az adatbáziskezelő szerver elérése kívülről még nem
biztosított, ami alapból nem is lenne probléma, viszont a sok
csomagfrissítés miatt bekerült egy olyan bővítés is a blog projektembe,
hogy egy plusz oszlopot is igényel az egyik tábla, aminek a kitöltése
kötelező, anélkül nem megy... mit lehet ilyenkor tenni, ha sehogy sem
tudjuk elérni az adatbázisunkat? Erre mutatok egy megoldási javaslatot a továbbiakban.
Nyilván a migrációs fájlok
lehetnek a segítségünkre, azonban, amikor azt mondtam, hogy sehogy sem
érjük el a távoli szerveren lévő adatbázist még, akkor azt tényleg
komolyan gondoltam (se PHPMyAdmin, se Workbench kapcsolat, se terminal-os / CLI-s elérés, semmi...). Tehát hiába hozzuk létre mi szuperül a migrációs
fájlunkat, nem fogjuk tudni futtatni a távoli szerver termináljában a php artisan migrate parancsot. Nekem egy QueryException-t dob a rendszer, mivel azt írja, hogy a driver nem található...
Ki kellett tehát találni, hogy hogyan lehet Artisan parancsot futtatni a PHP kódunkból. Erre szerencsére van megoldás, amit már használtam is korábban egy másik munkám során, amikor a beállítási paramétereket kellett frissíteni és egyben el is tárolni a cache-ben, ami így nézett ki:
use Illuminate\Support\Facades\Artisan;
...
Artisan::call('config:cache');
Egy importálás után a "php artisan" részt leszámítva kapja meg az Artisan call statikus metódusa paraméteréül a végrehajtandó utasítást. A kérdés csak az, hogy melyik fájlba is tegyük mindezt ahhoz, hogy végrehajtódjon...? Én azt javaslom, hogy az app / Providers / AppServiceProvider.php boot metódusába helyezzük el az Artisan call utasítást, mert az ott biztosan végre fog hajtódni, amikor beindítjuk az alkalmazást (de egy másik, teljesen jó módszer lehet az is, hogy a web.php-ban egy útvonalhoz rendeljük a hívást, és azzal indítjuk be az artisan parancs lefutását).
Ha a kapcsolódó migrációs fájlom a helyén van, akkor azt gondoltam, hogy már csak a fenti példa alapján végrehajtandó migrate parancsot kell "futtatnom" (például oldallekéréssel végrehajtatnom), azonban ez nem teljesen volt így... mivel ugye élesben dolgozok, tehát "production" a környezet, ezért amikor kiadnám terminal-ból ezt a php artisan migrate parancsot, akkor a rendszer visszakérdezne, hogy biztosan végre akarom-e hajtani a migrálást éles környezetben, amire válaszolhatnék igennel (yes) és nemmel (no) is. Itt viszont most nincsen esélyem ilyen "párbeszéd lefolytatására". Úgyhogy egy kicsit trükközni kell: hozzá kell adni egy --force kapcsolót, ami a visszakérdezést megelőzi és rögtön végre is hajtja a migrációt. Azonban ez még mindig nem elég, mivel két további beállítást is át kell adni az Artisan call metódushívásnak: 1. meg kell adni neki az útvonalat, hogy milyen útvonalon hajtsa végre a kód lefutását (alapból a terminálból egyértelmű lenne, azonban itt fel kell paraméterezni, hogy a database mappa migrations almappájában tegye ezt meg a --path kapcsoló segítségével), illetve 2. azt is meg kell adni neki, hogy melyik adatkapcsolatot (--database kapcsoló) használja a migráláshoz, nálam ez a "mysql" nevű kapcsolat lesz. Végül tehát így néz ki az a kód, amit az AppServiceProvider osztály boot metódusába elhelyezek:
Artisan::call('migrate', array('--force' => true ,
'--path' => 'database/migrations', '--database' => 'mysql'));
A paraméterek sorrendje nem lényeges a tömbben. További információ itt található az artisan parancsok programozott végrehajtásáról és paraméterezéséről: https://laravel.com/docs/9.x/artisan#programmatically-executing-commands
Ezután, ha egy sima oldal újratöltés nem lenne elég a migráció végrehajtásához, akkor futtassuk ezt az utasítást a terminal-ban:
composer dump-autoload
Amit azért adunk ki, mert a Composer nem fogja látni az új migrációs fájlunkat/osztályunkat automatikusan, hanem ezzel újrageneráljuk neki azt a listát, amit ő az osztályainkról számon tart és közben észreveszi, hogy "Jé, van itt valami új dolog, gyorsan fel is veszem a megfigyelési listámra!", betöltés után pedig már indítja is az általunk elhelyezett Artisan call parancshívást. Remélhetőleg ez gyorsan végrehajtódik, amit ugye most nehezen lehet ellenőrizni, de nálam lefutott egy olyan képfeltöltés, ami korábban az itt leírt problémát generálta: egy mező meglétét hiányolta egy adattáblából, és pont emiatt hoztam létre a migrációs fájlt, hogy ezt beletegyem... mivel a képfeltöltés most már hiba nélkül megtörtént, ezért arra a következtetésre jutottam, hogy a migráció sikeresen végrehajtódott. Végül, de nem utolsó sorban, ne felejtsük el kivenni az Artisan call hívást az AppServiceProvider-ből, mivel nagy valószínűséggel nem szeretnénk minden oldal betöltődéskor újrafuttatni éles környezetben a migrációt...
Saját tapasztalatok?
Szívesen fogadok saját tapasztalatokat is a "függőségi pokoljárásokról" (szigorúan a témához illeszkedően!), úgyhogy ha van valamilyen egyéni megoldásotok, amelyet egy régi projekt életre keltésekor, felfrissítésekor kellett megoldanotok, akkor jöhetnek a kommentek a kapcsolódó Facebook vagy Linkedin bejegyzésem alá.
A következő bejegyzésben már ismét tudunk a fő fejlesztési irányvonalunkra koncentrálni, hiszen egy teljesen felfrissített projekt lesz a kezeink alatt.