Arkiv oktober 2019

Nu drar det igång med statistik

Tidigare inlägg har varnat om det och nu är det dags; här är mitt första inlägg om statistik. Så jag påbörjar en grundläggande kurs i statistik denna vecka. Jag går den med syfte att uppdatera mig om metodiken för att kunna tillämpa det inom mina intresseområden. Jag har gått tidigare kurs i ”kvantitativa metoder”, men det var 2010. Mycket av den kunskapen finns kvar någonstans och jag behöver hjälp att ta fram det. Jag hoppas trots det att jag lär mig lite nytt. Jag hoppas kunna göra regressionsanalyser och presentera resultat på ett spårbart och enkelt sätt. Kanske finns det möjligheter att göra kopplingar till Bokarenan i framtagning av exempelvis läsrekommendationer. Svårigheten att göra det på Bokarenan kan ju ses i det dataunderlag som finns. För närvarande har applikationen endast EN användare.

Denna veckan kommer jag läsa igenom lite grundläggande begrepp inom statistik. Det handlar om medelvärde, median, standardavvikelse, kvartiler, med mera.

Image of a dice.

Vad är sannolikheten att jag ska få en femma när jag kastar en tärning? Svaret har att göra med sannolikhet. Sannolikheten för att få ett värde av sex möjliga är alltså: 1/6.

Vad är sannolikheten att jag ska få en femma om båda gångerna om jag kastar en tärning två gånger? Jo, det är:

Alltså är sannolikheten för två femmor på raden lika med 1/36, vilket är knappt 3%.

För att beräkna sannolikheten för på varandra oberoende händelser så kan man använda det som kallas sannolikhetslärans multiplikationssats. Det var detta som jag precis gjorde.

Till nästa gång kommer jag att ha börjat tugga på Practice of statistics for business and economics av Alwan Layth. Det är en nästan 1000 sidor tjock bok och utgör kursens enda litteratur. Det ser jag fram emot. Den har många bilder!


Sökfunktion och DQL

Denna veckan blir antagligen den sista på ett tag med uppdateringar om Bokarenan och programmering. Jag påbörjar en kurs om statistik och kommer använda Femte Arenan för att beskriva de lärdomar jag drar av det. Så jag passar på att beskriva det senaste jag gjort i programmeringsväg över helgen.

Jag lämnade förra veckan med en fundering på om jag skulle hinna få på plats en sökfunktion. När jag gjorde en sökfunktion till den nuvarande Bokarenan så svalde jag efter för mycket. Jag gjorde så att användaren kunde söka efter varje detalj i varje liten entitet. Det gjorde sökfunktionen lite svår att använda. Istället har jag gjort sökfunktionen till ett textfält som alltid finns tillhands i navigationsfältet och det man söker efter är BÖCKER. Jag har för närvarande gjort så att man kan söka efter författare eller boktitel, men sökresultatet är alltid BÖCKER. Inte författare eller något annat. Jag är rätt nöjd med resultatet. Det var också rätt så enkelt att implementera med hjälp av Doctrine och dess queryBuilder.

Så efter att ha fått på plats sökfunktionen så kände jag att jag var på rull. Därnäst så implementerade jag ett navigationsträd för böcker. I navigationsfältet har användaren en länk som heter Böcker. Klickar man på den så kommer man till sida för att välja böcker enligt genrer. Genrer är uppbyggda hierarkiskt, så att till exempel thriller är en underkategori till skönlitteratur. Klickar man på Skönlitteratur så får man upp en ny lista på genrer inom skönlitteratur samt de populäraste böckerna associerade med genren skönlitteratur.

Implementeringen av genrer i kombination med lista på populära böcker innebar att jag hade att hantera tre olika entiteter: Book, BookAnalysis och Genre. Tidigare har jag helt enkelt använt den repository som var lämplig. Jag försökte mig på att använda repository för BookAnalysis med förhoppning att kunna använda den Book-referens som den entiteten har. Book har i sin tur referens till Genre-entitet. Jag vred och vände men fick inte till det. Jag hade några alternativ kvar, som tur var. Nuvarande Bokarena använder sig av SQL-kod som jag skrivit. Nackdelen med att använda det är att jag inte får tillbaka entitets-objekt, utan det är något som jag fått initialisera ”manuellt”. Men jag behöver inte göra på samma sätt här. Jag kan använda DQL (Doctrine Query Language) istället. Det innebär att jag blir lika flexibel som om jag skrev SQL men jag får fördelen med att få tillbaka de rätta entiteterna. Med följande sats så blev det inte så komplicerat trots allt:
"SELECT a FROM App\Entity\BookAnalysis a JOIN a.book b WHERE b.genre = $id ORDER BY a.numReviews DESC, a.avgRate DESC"

Ha en sån trevlig vecka. Nästa gång skriver jag om data i stora mängder.


Favoriter på framsidan

Så till slut kan jag säga att jag har uppnått veckans mål; att få fram en lista med rekommenderade recensioner och en lista på de böcker som fått bäst betyg. Resan hit tog en liten omväg. Hur lång? – Inte särskilt lång!

Respektive bok har inte ett betyg, men däremot har de recensioner som boken är associerad med ett betyg. För att kunna ta fram exempelvis de fem bästa böckerna behöver jag hämta alla böckers respektive recensioner, sedan ordna böckerna i fallande ordning utefter de genomsnittliga betygen. Därefter skulle jag kunna presentera resultatet för användarna. Detta tyckte jag verkade som ganska mycket jobb att göra varje gång någon laddar framsidan. Den lösning som jag tagit fram är istället att ordna en ny entitet: BookAnalysis. Denna entitet innehåller såväl genomsnittliga betyg för respektive bok som antal användare som har boken som ”att läsa”. Denna entitet kan innehålla fler fält, men vi börjar med detta. Idén är att bara administratörer kan komma åt kontrollen för BookAnalysis och därigenom aktivera en analys av databasens recensioner och böcker. På framsidan kan jag därför presentera de 5 bästa böckerna genom att hämta toppresultatet från BookAnalysis. Nackdelen är att användarna inte får det absolut senaste resultatet, men fördelen är att servern inte behöver genomföra beräkningar som bara kommer växa och bli större och tynga ner processorerna. Kanske är det så att beräkningarna inte skulle bli så tunga, men eftersom jag har en loop inom en loop så vill jag undvika risken.

Nu har jag fått ganska mycket på plats, men jag saknar någon sök-funktion. Detta skulle jag vilja få plats härnäst. Men! Frågan är om jag kommer ha någon tid över till det den närmaste tiden. Nästa vecka börjar jag en kurs om statistik och det kommer också synas på denna sidan. Och innan vi lämnar denna vecka så vill jag gå in på lite nöje!

Jag har under veckan haft nöjet att pröva ett spel som min sambo valt ut till mig: Shadow of the Tomb Raider. Spelet påminner mig i delar om Indiana Jones-filmerna och Rovdjuret. Man spelar som Lara Croft, en forskare/äventyrare, som är på jakt för att hämnas sin far. Men jakten uppdagar förebud om världens undergång. Och detta är något som Lara känner stor skuld till eftersom det mycket väl kan ha varit hennes hätska agerande som orsakat det. Så lika mycket som det handlar om hämnd handlar spelet om att försöka med alla medel att stoppa undergången. Jag har haft så himla kul och varit så imponerad av ett spel på länge. Det hänför mig med fantastiska miljöer och påhittiga banor. Jag sitter på spänn när jag hoppar mot en klippkant för att försöka klättra högre. Jag känner mig så grym när jag gömmer mig indränkt i lera mot en klippvägg och inväntar Laras fiender. På resans gång har Lara gått från att vara ett bytesdjur till att bli djungelns jaguar. Det spel jag kommer bita i härnäst är Hellblade: Senua’s Sacrifice. Jag har hört lite grann om spelet och jag är rädd för att det inte kommer ge mig samma tillfredsställelse som Tomb Raider men däremot en resa som kommer vara med mig länge. Vi får se.

Trevlig helg, allihopa!


Lista av recensioner och lista av böcker

Nu har jag i applikationen (Bokarenan) fått till såväl en lista av rekommenderade recensioner såväl som ett urval av de senaste recenserade böckerna. Jag påstod i föregående inlägg att jag denna vecka skulle få till en lista med de böcker med bäst betyg. Det kan fortfarande bli så men jag fokuserade istället på att få till de senaste recenserade böckerna.

För att få till urvalet av de senaste recenserade böckerna så har jag fått gå till Repository-klassen för Review. Där har jag lagt till funktionen findByLatest(int $limit). Genom den funktionen så hämtar jag de senaste x-antal recensionerna. Utifrån den samlingen av recensioner så hämtar jag referenserna till de böcker som de refererar. Eftersom en bok kan recenseras flera gånger så använder jag mig av php-funktionen array_unique(). Därmed så tar jag bort överflödiga referenser och kan presentera en bok inte fler än en gång på framsidan.

Det jag vill göra härnäst är att skapa en personlig lista av böcker att läsa. Och från den listan kan man sedan välja att recensera den bok man vill.


review.review.review

Det som är veckans uppgift är att få till en presentation på välkomstsidan som innehåller två delar. Första delen är en lista av recensioner som har valts av administratörer som lämpliga. Andra delen är en lista av böcker med bäst betyg.

Jag har kommit en bit på vägen med en lista av rekommenderade recensioner. Det har inneburit att jag skapat en ny entitet (RecommendedReview), och gjort det möjligt för de med administratörsrättigheter att lägga till recensioner till listan. Jag har också gjort det möjligt att visa alla de recensioner som finns i rekommendationslistan. Nu återstår att få denna listan till framsidan. Men i utvecklingen av presentationen av listan så har jag råkat göra något hemskt! Genom en template engine (Twig) så låter jag loopa igenom en array och presentera innehållet i en tabell:

{% for review in reviews %}            
<tr>
<td>{{ review.review.id }}</td>
<td>{{ review.review.name }}</td>
<td>{{ review.review.review }}</td>
</tr>
{% endfor %}

Som ni kan se så har jag alltså följande sats: review.review.review. Det är inte hållbart! Det första review står för RecommendedReview och innebär att den relaterar ett recensionsobjekt till det datum när den lades till i listan för rekommenderade recensioner. Det andra review står för ett recensionsobjekt. Det tredje review är ett fält i recensionsobjektet som står för recensionstexten. Det är inte så snyggt eller pedagogiskt att låta en sak betyda tre olika saker. Lämpligen borde jag refaktorera det hela så att jag istället har: recommendedReview.review.text. Det bästa hade varit att göra det rätt från början. Det näst bästa är att göra det rätt nu.

Först går jag till controllern och ändrar variabelnamnet för arrayen med RecommendedReview-objekt från reviews till recommendedReviews. Sedan ändrar jag variabelnamnet för det aktuella RecommededReview-objektet i for-loopen från review till recommendedReview.

Sedan återstår att ändra fältnamnet i Review-entiteten från review till text. Jag gör det, och passar också på att ändra getter– och setter-metoderna i entiteten. Nu har jag gjort ett antal ändringar som kommer bryta vissa referenser i ett antal templates och, framförallt, hur databasen är uppbyggd. Jag kör därför Doctrine:s konsolverktyg för att analysera och åtgärda differensen mellan databasen och entiteterna. Och mycket riktigt så snappar Doctrine upp att jag ändrat namnet på fältet review till text.


Aktiveringsfredag

Denna vecka har jag alltså fortsatt med auktoriseringssystem för applikationen (Bokarenan). Framförallt har det handlat om att få till en aktiveringsfunktion, så att man inte kan registrera sig med någon annans epost. Kolla bara alla mina git-meddelanden:

Eftersom aktiveringsfunktionen inte är något som kommer som standard i Symfony så är det något som jag fått lägga till. Första steget var att justera användarentiteten (User) med två nya fält: aktiv, och en aktiveringssträng. Enligt standard så kommer en ny användare att registreras som icke-aktiv. I det andra steget så kontrolleras att den användare som försöker logga in är aktiverad. Om användaren inte är aktiv så kan den inte logga in. För att ändra detta så kommer det tredje steget: applikationen har postat en aktiveringslänk till användarens epost. När användaren klickar på den så skickas två parametrar till applikationen, nämligen användarens epost och aktiveringssträngen. Dessa parametrar jämförs med data från applikationens databas. Om de överensstämmer så aktiveras användaren och denne kan därmed logga in.

Så här långt har det gått helt okej. Nästa uppgift blir att presentera recensioner på ett bra sätt. Jag tänker mig att förstasidan ska innehålla en utvald recension. Ytterligare ska finnas en sida där man kan se olika böcker, samt hur många recensioner de har. Klickar man på boken så kommer recensionerna upp. Detta blir nästa veckas uppgift.

Eftersom det nu är fredag så skulle jag vilja göra en nöjesrekommendation, och detta i form av Playstation 4-spelet Horizon: Zero Dawn. Spelet bjuder på en värld där människor lever som nomader och jagar robot-dinosaurier. Det är fantastiskt vackert och mycket underhållande. Man får vara kreativ i hur man tar ned robotarna. Större bestar kräver att man sätter upp fällor eller skjuter av deras kanoner så att man själv kan använda dem. Mindre bestar kan det räcka med att man smyger sig inpå dem och överfaller (eller omprogrammerar). Liksom det spel jag körde igenom förra veckan så finns en hel uppsjö av bakgrundsstory att hitta. Varför finns alla dessa robotar? Varför lever folk som nomader? Jag har haft väldigt roligt med spelet och ser verkligen fram emot en fortsättning.

En Watcher från Horizon: Zero Dawn

Trevlig helg, allihopa!


Kommer i form

Sagan fortsätter. Senast hade jag problem med att uppdatera användares roller. Rollerna avgör vad användare kan göra på hemsidan. I huvudsak gäller det om en användare ska vara administratör eller inte. När jag skrev senaste inlägget så lyckades jag inte med att uppdatera användares roller och någonstans låg problemet i administratörskontrollen (controller) eller i formuläret. Jag visste inte exakt var problemet låg, men det gör jag nu: det var i båda!

Så jag är lite av en härmapa när jag håller på att lära mig nya saker, och när det kom till användare så härmade jag hur upplägget såg ut för att uppdatera till exempel författare. Och här är kruxet: upplägget för författare och användare är olika. För författare så färdiggenereras en formulärklass som man kan skicka till Twig, vilket är en så kallad template engine. Det innebär att utifrån givna parametrar så genererar Twig den html-kod som behövs för att visa givet innehåll. Och jag byggde upp en formulärklass för användare också, men använde inte Twig till att generera den. Istället så skräddarsydde jag html-koden för att motsvara exakt vad som behövs för att uppdatera användare med rätt roller. I ett parallellt spår med detta så byggde jag controller enligt samma sätt som controller för författare. Det innebar att controllern kontrollerade om det färdiggenererade formuläret innehöll någon ny data. Och eftersom jag inte använde mig av det färdiggenererade formuläret så innebar det att controllern inte fick någon uppdaterad data. Lösningen blev därför att uppdatera controllern med att kolla i svarsobjektet istället för i formulärobjektet. Och därmed hade jag på 5 minuter löst ett problem som hållit mig fast i ett par timmer.

Ytterligare utveckling denna veckan har varit att lägga till en aktiveringsprocess när man registrerar sig som ny användare. Det innebär att applikationen kommer kontrollera att den som registrerat sig också är användare av den epost som har angetts. På den fronten har det gått snabbt, men det beror också på att jag kunnat sitta i åtminstone 20 minuter åt gången för att programmera.

På återseende på fredag!


Snubblarmåndag

Så kör vi igång med en ny vecka. Målet för förra veckan var att få igång ett auktoriseringssystem, och till viss del har jag fått igång det. Målet denna vecka är att få klart det.

Varför blev det inte klart förra veckan? Jo, för att jag vet inte vilket problem jag har. Mer exakt vet jag inte varför min kontroll och formulär inte lyckas med att spara när jag ändrar typ av roll som en användare ska ha. Jag kommer återkomma i veckan med var problemet ligger någonstans och hur jag väljer att hantera det. Om jag inte lyckas med detta så återstår att jobba direkt mot databasen.

En annan anledning till att jag inte blivit klar är att jag för närvarande oftast får 10 minuter åt gången när jag kan sätta mig ned och programmera. Det är alldeles för korta stunder för att hinna sätta in mig i vad jag försöker göra. Vad jag istället hinner med är att teckna lite:

”Skakar hand.”

Alltså, det där är vad min hjärna kan göra när den har 10 minuter åt gången.

Nu hoppas jag att jag kan få mer gjort denna vecka, men det beror på sömn och bebisar. Annars blir det fler teckningar.


Administratörsrättigheter

Den här veckan har varit full av diskussioner om rättigheter. Jag har upprättat ett auktoriseringssystem som kan särskilja användare utifrån vilka rättigheter de har. En vanlig användare ska inte kunna komma åt administratörsverktyg. En administratör ska inte kunna bevilja administratörsrättigheter. En super-administratör kan allt – nästan. Super-administratörens viktigaste uppgift är att bevilja eller ta bort administratörsrättigheter. De är i en hierarkisk ordning, vilket innebär att det inte finns något behov för en användare att ha flera olika rättigheter; det är en rättighet åt gången som gäller.

Något som blivit en utmaning för mig denna vecka är hur jag ska tillsätta rättigheter. Jag hade problem om jag direkt i databasen försökte tillsätta rättigheter, så jag försöker via applikationen istället. Men då behöver jag få till en sökfunktion för att ta fram rätt användare, och sedan en sida för att visa användaren och där i ändra rättigheter.

Jag har fått till sökfunktion och sidan för att visa användaren. Men jag har ännu inte fått till funktionen för att tillsätta rättigheter. Snart har jag fått min Sorteringshatt.

Så är det ju fredag igen! Jag tar på mig glittriga strumpor och sjunger Rebecka Blacks ”Friday”. Jag har spelat ut spelet Control, och jag gillade det! Jag gillade det jättemycket. Det hade en unik atmosfär och världsuppbyggnad. Jag läste varje papper som jag hittade i spelvärlden och för varje papper så blev jag mer trollbunden. Nu får vi se vad det blir härnäst. Jag lämnar tillbaka spelet på biblioteket och får se vad de har inne denna gång.


Auktorisering aktiverad

Så har det visat sig igen att det goda folket bakom Symfony kan göra bra guider. Jag har nu implementerat funktion för att avgränsa ytor av applikation till relevanta roller: så som att man måste vara inloggad som användare för att kunna göra inlägg, och som administratör så finns lite fler verktyg för att hantera entiteter. Det som återstår att göra är att skapa en super-administratör som kan lägga till roller för olika användare.

När jag är klar med super-administratören så finns det lite finlir jag behöver ta hand om. Till exempel behöver jag anpassa kontrollerna för entiteter så att de motsvarar hur jag vill använda dem. I och med dessa anpassningar behöver jag också justera form-klasser och presentationen av formulären.

Jag får se därefter hur mycket tid till övers jag kommer ha framöver. Snart kommer jag att börja en deltids kurs för dataanalys på grundläggande nivå. Det innebär att mina framtida uppdateringar från och med november kommer prata om statistik och att jag redan är inkörd på sömnbrist i och med bebisar.