Blog

Fortsätter med det svåra

Som jag lovade i fredags skulle jag presentera resultatet av att kombinera flera olika formulär. Här är det visuella resultatet:

Inte vackert någonstans, och inte intuitivt att använda. Men allt sådant kommer senare. Först ska alla grundläggande funktioner finnas på plats. Det som står närmast är att fånga upp alla aktuella komponenter och göra relevanta saker med dem. Just nu har jag problem att hitta åt rätt värden i det Request-objekt som skapas. Kanske finns lösningen i att använda Form-objektet istället? Jag får återkomma.

Lycka till denna vecka alla ni måndagsälskare!


…göra det svåra

Jag har på ett ganska enkelt sätt kunna använda Symfonys console maker för att skapa CRUD-funktionalitet genom webbläsaren. Respektive entitet har getts ett eget User Interface för att kunna interagera med det. Nu kan användare genom webbläsaren se vilka entiteter som finns av en viss typ, skapa nya eller uppdatera dem. Men för tillfället finns respektive entitet på sin egen sida, alltså inte på en enda gemensam sida. Det jag vill uppnå är vad jag redan har åstadkommit i min gamla version av Bokarenan. Se bilden nedan:

Som framgår av bilden så har respektive entitet samlats under en rubrik/knapp. Det som händer när man trycker på ”Lägg till” är att applikationen kommer söka efter respektive entitet i databasen och lägga till den om den inte redan finns.

Nu ska jag däremot samla Symfony-entiteter i ett formulär. Och som jag redan har uttryckt så tycker jag att de guider som Symfony har är toppen. Självklart finns det en guide som kan hjälpa mig här: How to embed forms och How to embed a collection of forms. På måndag ser jag fram emot att kunna presentera resultatet.

Och nu blir det helg. Jag fortsätter att utforska rymden i Elite Dangerous. För närvarande kör jag många frakt-uppdrag, och förhoppningsvis kan jag snart skaffa mig ett nytt skepp som jag kan anpassa för gruvverksamhet. Jag både gillar spelet och tycker det är tråkigt. Det är toppen att spela och lyssna på en podcast.

Trevlig helg!


Gör det enkla

När jag skulle börja göra ett navigationsfält för Bokarenan med hjälp av Twig så hamnar jag lite vilse. Jag vill nämligen ha ett navigationsfält med huvudsidorna för applikationen synliga med indikation för den sida som för tillfället visas. Här har jag tänkt mig att texten kommer göras fetare och bakgrunden något mörkare. I övrigt kommer navigationsfältet vara likadant överallt på sidan. Navigationsfältet kommer därför återanvändas överallt genom att det inkluderas i huvudmallen, av vilka övriga mallar kommer bygga vidare på.

Tidigare har jag använt enkel PHP för att göra en kontroll efter vad en variabel har för värde. I navigationsfältet hade jag om-kontroller för varje sak i fältet för att kolla om variabeln överensstämde med kontroll-värdet.
<div class="<?php if ($page == "start") {echo ' active';}?>">

Det förutsätter dock att variabeln har ett värde som är unikt för varje sida, varje sida måste därmed sätta variabeln före det att koden för navigationsfältet inkluderades i filen:
$page = "start";
include($path_navbar);

Det funkar okej, men är något av spagetti för mig, eftersom jag inte skickar variabeln någonstans utan förutsätter att den inkluderade koden har rätt variabelnamn för att hitta rätt.

När jag nu använder mig av Twig-mallar för att generera min presentation av applikationen så behöver jag ändra logiken något. Jag vill ju att respektive sida ska kunna anmäla sig som den aktuella sidan och huvudmallen ska därmed reflektera detta i navigationsfältet. Jag googlade lite och blev lite skrämd av svaren. Någon styrde det genom att skicka en variabel till den aktuella sidan genom en kontroller. Om den personen hade flera olika kontroller som sedan förlängde en ursprungskontroll med den funktionen eller om samma logik fick användas om på flera olika ställen framgick inte. Visst är det ju så att kontroller är det som styr vad som presenteras när, men jag kände mig inte helt bekväm med att för tillfället använda kontroller för något som jag trodde var ganska enkelt.

Min lösning för närvarande blev istället att huvudmallen har block för respektive navigationslänk. En sida kan därmed ange vilket block i huvudmallen som ska indikeras som aktiv.
Huvudmallen:
<li class="{% block navHome %}{% endblock %}"><a href="/">Hem</a></li>

Undermallen:
{% block navHome %}active{% endblock %}

Det får jobbet gjort. Men jag är inte helt nöjd med det. Det som är bra med detta är att jag fått bort om-kontroller och att jag inte behöver oroa mig över en vilsen variabel. Det som jag inte är nöjd med är att jag kommer behöva hoppa mellan två olika mallar för att hålla koll på alla olika block.


Att logga in

Jag fortsätter följa guiden från Symfony för hur man sätter upp ett inloggningssystem. Det finns script redo att hjälpa en att komma igång. Med ett enkelt kommando: php bin/console make:auth, så genereras/uppdateras en konfigurationsfil, en kontroller, en autentiserare och HTML-fil för login-sidan. När jag kollar på HTML-filen så finns där ett inloggningsformulär med POST-metod. Detta är jag van vid. Dock så finns det inte angivet vad som ska vara mottagare för formuläret. Det brukar anges av action="". Men detta saknas i HTML-filen där det i formulärtaggen helt enkelt står: <form method="post"> . Istället läser jag: ”When you submit the form, the LoginFormAuthenticator will intercept the request”. Om jag förstår detta rätt så innebär det att formuläret inte behöver en mottagare. Istället kommer denna autentiserare ligga och lyssna efter formulärposter från login-sidan. För att få svar på detta så kan jag pröva mig fram. Jag prövar att registrera en ny användare, et voilà: det funkar*.

* Jo, det funkar som jag föreställde mig, men jag behövde göra lite justeringar då det automatisk genererade registreringsformuläret saknade ett fält för epost.

Hur justerar man då de automatiskt genererade formulären? Det går ju att göra som jag gjorde först: ändra i Twig-filen (det vill säga det som blir HTML-kod). Det var ganska enkelt att lägga till ett fält och få det presenterat för sig. Kruxet är bara det att det fältet ska snappas upp av en kontroller. Det jag behövde göra var att gå in i App\Form\RegistrationFormType och lägga till ett fält i en FormBuilder med funktionen:
->add('email', EmailType::class)
Och därmed var min lycka gjord.

När jag nu fått till inloggningsfunktionen så fortsätter jag med att lägga till entiteter med Symfonys CLI (Command Line Interface), eller vad de kallar för maker bundle. CLI:t gör det hela pinsamt enkelt att lägga till entiteter. Jag får hjälp av det att bestämma fält och typ samt relationer, och då genereras/uppdateras entitets- och förvarar-klasser med rätt information.


Dokumentation som är bra

Jag anpassar för närvarande Bokarenan till att nyttja Symfonys olika komponenter. Det är åtminstone planen men det blir mycket läsande. Jag är ute på nya marker när jag nu utforskar ett framework utan en bok som grund. Men det gör ingenting! Jag tycker dokumentationen är utmärkt. Symfony har guider för att komma igång med grunderna, för att starta med Unit-tester och för att sätta upp ett inloggningssystem. Fler finns det, men detta är så många som jag har gjort just nu. För närvarande går jag igenom Security-guiden. Eller, jag höll på med det, tills den föreslog att jag skulle gå igenom guiden för att sätta upp en inloggningssida. Det blir lite som att hoppa ned i hål efter hål, och hoppas man kommer tillbaka någon gång.

Den här veckan har det gått långsamt att programmera. Det har kanske blivit att jag funnit en timme per dag att programmera eller läsa om programmering. Anledningen: bebisarna växer och behöver mer stimulans, och jag har känt ett ökat behov av att träna mer. Det blir därför fler promenader och ett antal timmar på gymmet under veckan. Men jag känner mig nöjd med programmeringen. Jag är i huvudsak pappa, och programmering är min hobby. Så länge som jag hittar någon tid att sitta ned och programmera så är jag nöjd.

Det jag kommer göra till nästa uppdatering här på bloggen är att sätta upp en enkel front-end och lägga till entiteter och kontroller för att hantera böcker.

Sen så är det ju självklart fredag igen, och med helgen så kommer mina enkla nöjestips. Jag är rätt så bevandrad nu, i och med alla barnvagnspromenader. Och sen en månad tillbaka så ser jag fram emot mina promenader, för då kan jag lyssna på podcasts. Och en av mina favoriter just nu är Linear Digressions. De består av en duo – en webbutvecklare och en datavetare som diskuterar olika tillämpningar av machine learning. Det jag älskar med denna podd är att jag som bara känner till ämnet hyfsat ytligt kan följa med. Och det är alltid trevligt att lyssna på denna duo som har sån bra dynamik sinsemellan.

Så slår jag också ännu en gång ett slag för Elite: Dangerous. Den gångna veckan har jag somnat ett par gånger framför det när jag försökt spela när bebisar varit lugna. Spelet kanske låter något tråkigt nu, men det är mest för att jag varit något utmattad vid slutet av dagen.

Trevlig helg, allihop!


Jag testar och experimenterar

Det råkade bli testning inkluderat, som jag beskrev i mitt förra inlägg. Jag har inte mycket erfarenhet av att testa, men jag hade några enklare JUnit-tester när jag höll på med Java, och efter att ha mixtrat lite med PHPUnit så skulle jag påstå att jag uppnått samma låga kompetensnivå i det.

Såsom jag jobbar nu blir det att jag lägger till ett test och sedan den metod som testet kollar. Jag började med att testa att repository gör det den ska, men det kändes något onödigt. Anledningen: jag vill testa min kod, inte någon annans. Och med tanke på att Symfony kommer med Doctrine så fanns det egentligen inget där att testa för mig förrän jag inkluderade mina egna funktioner. Så de första stegen var att se lite som uppvärmning.

Snart så inkluderade jag ändå egna metoder, och mycket riktigt så hade jag skrivit test för dem. En sådan metod var att repository skulle söka med så kallade wildcards. Enligt testet så funkar det galant.

Testen startar jag från konsolen med utgångspunkt från mitt projekts mapp med instruktionen ./bin/phpunit, och som svar får jag OK (5 tests, 5 assertions). Som ni kan se är jag fortfarande i startgroparna, men det känns bra i magen när man ser testen köras och kan ändra ett fel till ett rätt.

Något som är helt nytt för mig är att testa att Controller presenterar korrekt sida till klienter. Symfony Docs är mig behjälplig och med instruktioner där ifrån så har jag mitt första test klart:
public function testShowHome() {        
$client = static::createClient();
    $client->request('GET', '/');
    $this->assertEquals(200, 

$client->getResponse()->getStatusCode());    
}

Testet kollar att HTTP-statuskoden är 200, vilket vill säga att korrekt sida hittats och levererats till klienten. I detta exempel så kollar testen helt enkelt om index-sidan hittas.


Att hantera innehåll

Helgen är slut och en ny vecka är påbörjad. Denna helg kom jag en bit ut i rymden i Elite: Dangerous. Det är helt fantastiskt hur omfattande det spelet är. Jag gillar att sugas in i det, men det går rätt långsamt. Jag vet inte riktigt vad jag tycker om utforskandet. Där handlar det om att först skicka ut en energipuls för att säkerställa att det finns himlakroppar i ett solsystem att upptäcka. När det är gjort så öppnar man ett fönster där man justerar ”radiofrekvensen” för att ställa in rätt kanal och därefter zooma in mot en himlakroppindikation. Det är bara att kanalen verkar glida något så man måste vara alert för att bibehålla rätt kanal. Jag får fortsätta med detta till nästa helg så kanske det hela klickar för mig.

Denna vecka fortsätter jag med Bokarenan. Innehållet till Bokarenan tänker hanteras av en databas. Databasen innehåller data om bland annat böcker, författare, användare och användares listor och recensioner.

I en tidigare iteration av Bokarenan så hanterade jag interaktioner med databasen genom SQL-instruktioner. När en användare hade skrivit en recension så sparades den till databasen med följande SQL-instruktion:
$q="INSERT INTO review (review, rate, book_id, title, reviewer)
VALUES ('$review', $rate, $book_id, '$title', $reviewer)";

Variablerna lät jag sanera innan de tilläts sättas in i SQL-strängen men det var inte vackert. Jag var inte konsekvent med var i kedjan av funktionsrop som jag lät sanera innehållet.

Datahanteringen behöver göras om från grunden. Det jag vill uppnå är överblickbar kod som är säker och flexibel. Säker är den datahantering som stänger ute användare från att injicera SQL-instruktioner. Flexibel är den kod som gör det enkelt att expandera med fler databasentiteter och justera relationer mellan dem. Eftersom jag gått mot objektorienterat denna gång så kommer jag använda en ORM (Object Relational Mapping). Det innebär att jag inte skriver egna SQL-instruktioner (och det läggs ett ytterligare lager mellan användare och deras möjlighet att injicera SQL). Det innebär också snyggare kod.

Den ORM jag använder mig av här är Doctrine. Genom annotationer kan jag instruera Doctrine hur den ska hantera innehåll i entiteter (objekt som ska sparas i databasen) och hur entiteter relaterar till varandra.

Jag försöker modelera entiteterna så gott det går mot den databas som finns sedan tidigare. En utmaning är att den nya databasen inte kommer bli identisk, men ska ändå tillåta att innehåll från tidigare version ska kunna importeras till den nya.

Nog kan det vara svårt att behärska sig från att kasta sig över än mer saker. Jag har kommit fram till att jag vill köra tester. Det innebär att jag SAMTIDIGT lär mig ORM och PHPUnit. Jag är inte bekväm med mock-objekt som testerna körs på. Alternativet skulle vara att koppla tester till databasen med transaktioner som påbörjas men sedan ”rullas tillbaka”. När det kommer till Repositories rekommenderas att testa dem mot en riktigt databaskoppling ( https://symfony.com/doc/current/testing/doctrine.html ). Jag får testa enligt denna rekommendation.

Anledningen till att jag till slut beslöt mig för att köra PHPUnit var att det är enklare att lägga till tester i ett tidigt skede än att göra dem som en efterhandskonstruktion. Det innebär också att det kommer finnas tester som säkerställer korrekt funktion när jag vill modifiera applikationen.


Fredagsmys

Detta med Vagrant. Jag blev introducerad till Vagrant i boken Learning PHP 7 (2016) av Antonio Lopez. Konceptet är väldigt lovande: Man får en virtuell låda/maskin som kommer ha samma konfigurering oavsett var den körs, så länge man utgår från samma konfigurationsfil.

”Using Vagrant is quite easy.” (Lopez 2016)
Nja, detta var inte min upplevelse riktigt. Jag hade flera tillfällen där jag snubblade. Planen var att köra laravel/homestead i Vagrant men min upplevelse att upprätta denna box var lite svårartad.

Bild

Det började med att jag försökte få Vagrant att fungera med den virtuella maskinen som Windows 10 Pro kommer med, nämligen Hyper-V. Jag startar kommandotolken och kör vagrant init och up. Då stöter jag på mitt första problem med att vagrant inte hittar någon virtuell maskin. Jag specificerar att vagrant ska använda Hyper-V och får då det klart för mig att jag måste köra med administratörrättigheter. Så jag gör det, och får då klart för mig att jag har problem att fortsätta med Hyper-V. Då beslöt jag mig för att använda Virtual Box istället. Jag avställde Hyper-V-servicen i Windows och startade om. Så jag kör Vagrant med Virtual Box istället. TRODDE JAG! Det visade sig att Hyper-V stod gömd i kulisserna och la krokben för Virtual Box när den skulle fram i rampljuset. Lite googling och en träff på Stack Overflow gav mig en lösning. Omstart igen! Nu kunde vagrant starta och jag kunde koppla upp mig mot den.

Jag får se om jag återvänder till Vagrant. På lite omvägar har jag landat på Symfony som ett framework och den kommer med en server som är lätt att köra. Finns mycket jag gillar med Symfony, och jag återkommer framöver med mina upplevelser. Kan hända att jag illustrerar den lika vackert som jag illustrerat min upplevelse av Vagrant.

Så vill jag avsluta veckan med att konstatera att det är helg även denna gång! Något som jag tycker om är att spela TV-spel. Det gör jag när tid finns över och min hjärna är för trött för programmeringen. Nu när det är helg så låter jag hjärnan vila lite, och plockar upp handkontrollen när bebisarna sover. Liksom förra veckan så tittar jag mot Elite: Dangerous. Jag är fortfarande i startgroparna. Jag håller mig fortfarande till startområdet och har inte riktigt vågat bege mig utanför den trygga bubblan. Men med ett något mer slagkraftigt skepp än Sidewinder (startskeppet) och ett antal pirater tillintetgjorda så börjar jag känna mig redo för lite utforskande.

Trevlig helg, allihop!


Omtag

När jag började implementera MVC till Bokarenan så kom jag också att använda RewriteEngine som ger instruktioner till Apache-servern hur den ska hantera adresser. Filstrukturen är en projektmapp med de två mapparna public och app. App innehåller backend-logiken och public innehåller frontend-materialet. App är oåtkomligt för användare. Strukturen innebär att adresser behöver behandlas av servern för att inte avslöja den interna strukturen. Jag vill inte att användare ska behöva ange bokarenan.se/bokarenan/public/pages/ för att komma till startsidan. bokarenan.se ska räcka.

Jag har skrivit instruktioner i .htaccess-filen och lyckas på så sätt omdirigera besökarna till rätt adress. Men ju mer jag försöker få den att presentera adresser på rätt sätt desto mer inser jag mina begränsningar. Jag är inte helt nöjd med detta sätt att hantera användarupplevelsen.

Om jag förstått saken rätt så har många MVC-frameworks sina egen router-logik implementerat i PHP. Den grunden som jag har byggt efter Traversy-kursen saknar detta. Jag ska därför se till ytterligare material för att få detta att fungera. Dock misstänker jag att jag alltid kommer behöva .htaccess (RewriteEngine) så länge som jag inte vill placera en index-fil i root-mappen som därifrån kan dirigera trafiken.

Som avslutning denna gång; min uppfattning om MVC-strukturen. Controller är spindeln i nätet som får stå för mycket av backend-logiken.

Bild


Smått och gott

Vad är unset och varför ska det vara bra? Funktionen träffade jag på för första gången när jag följde en kurs för PHP MVC. Som jag läser det så kommer unset att förstöra en variabel. I kontexten för kursen så användes en variabel för att ta ut vilken Controller som skulle användas ur en URL. När en Controller har valts så tas det aktuella elementet bort ur en array. Syftet skulle kunna vara att samma värde inte används igen, eller för att klargöra att elementet inte kommer användas igen över huvudtaget. I så fall är det mer av ett semantiskt ingrepp än en funktionell.

Detta tycker jag är magiskt:
protected $currentController = 'Pages';
$this->currentController = new $this->currentController;
Det innebär att PHP kan omtolka en sträng till en klass och det är ju sjukt användbart. Men jag är också lite rädd inför denna kraft. Det kan bli svårt att särskilja vad som är vad, tänker jag. Det är nog mina Java-demoner som gör sig påminda, där varje objekt är av specifik typ om man inte tydligt anger att det ska vara något annat.

Detta med att kod inkluderas i en fil från en annan och att man sedan förutsätter i en tredje fil att sagda fil har inkluderats är något som jag upplever som förvirrande. Det skulle bli svårt att uppdatera koden eller att använda filen i en annan kontext. Detta var något som jag använde mig mycket av i mitt första utkast till Bokarenan, och något som nu förekommit ett par gånger i Treversys kurs. Det är visserligen mycket tydligare i kursen vad som är vad. Men jag saknar att se varifrån till exempel en konstant har hämtats i från när man tittar i en fil som säger något som <?php echo APPROOT ?>. Det framkommer inte att konstanten har hämtats från en config-fil.

Det finns en hel del jag får med mig från kursen, men jag ser också behov att komplettera. Däribland gillar jag inte att ha views som php-filer. När jag kommer implementera kursens kod till Bokarenan kommer jag använda Twig. Detta har att göra med att låta views stå för presentation och ingen logik. Med PHP finns möjligheten att göra mer än att bara presentera en vy.

Jag kommer göra kursen så långt att grunden blir klar. Då kommer jag att ha byggt ett slags framework för MVC. Resten av veckan kommer jag att ta detta framework och bygga Bokarenan i. Jag får utvärdera om jag vill ta och implementera PHPUnit för att testa vad jag bygger. Saken är att jag vill bygga egna projekt så fort som möjligt som jag har lärt mig något för att på så sätt befästa kunskapen. Om jag skulle lära mig PHPUnit just nu så kan det innebära att jag får ytterligare avstånd till MVC innan jag bygger med det.

På detta sätt börjar jag alltså en ny vecka: många funderingar, mycket vilja och en stor dos experimentlusta.