Arkiv januari 2020

Uppdaterade nyheter

Hej kära vänner och läsare! Det är fredag och helg. Många av oss sätter oss i soffan ikväll med chips och tittar på något underhållande. De senaste veckorna har jag och min sambo kunnat njuta av den dumma (men roliga!) tv-serien Medical Police på Netflix. Tyvärr var det bara 10 avsnitt så nu får vi ägna oss åt något annat. Men eftersom det är fredag så skriver jag veckans sista inlägg så här på eftermiddagen. Den här veckan har fokus varit på programmering och att lägga till en blogg-funktion till Bokarenan. I onsdags skrev jag om hur Symfony och Doctrine har underlättat skapandet av en ny entitet (BlogPost) och uppdateringen av databasen. Denna gång ska jag skriva om den avslutande delen: hur allt ska kunna presenteras till användaren.

Det finns två komponenter att beakta när det kommer till hur nyheterna presenteras till användarna: template och Controller. Jag tänkte börja med Controller.

Min tanke är att den som är administratör ska kunna skriva ett blogginlägg (nyhet). Jag löste detta genom att använda AdminController och lägga till två funktioner till denna Controller som jag alltså har haft sedan tidigare. Den första funktionen innebär att administratören kan lägga till ett nytt inlägg. Något som jag vill lyfta fram som några detaljer är att administratören kan välja publiceringsdatum. Det innebär att inläggen inte dyker upp under Nyheter om inte publiceringsdatumet har nåtts. Den andra detaljen jag vill lyfta fram är ”slugs”. Det innebär att varje inlägg har en unik länk i stil med 2020-01-31-Det_här_är_en_nyhet. Detta kommer till användning när man vill titta på endast en nyhet, eller för sökmotorers möjligheter att länka direkt till ett inlägg.

Den andra Controllern som behövde uppdateras var NewsController. Denna kontroller har tilluppgift att presentera nyheter till användare. I kontrollern så skapade jag en ny funktion som hämtar de senaste inläggen och skickar dem till template-engine. Det tillkommer lite fler detaljer som innebär att jag kan paginera allt ihop och bara hämta de inlägg som ska vara på den aktuella sidan som användaren är på. Oftast är detta första sidan, men länkar till övriga sidor dyker upp längst ned.

Vad är då template-engine? Det är i princip en funktion som renderar html (eller php-filer med html-element) med dynamiskt innehåll. Som template-engine använder jag Twig. Från NewsController skickar jag de aktuella inläggen till Twig som löser det hela med att placera innehåll på rätt ställen och presenterar det med html-element och innehåll till användaren.

I NewsController så kan det se ut så här:

    /**
     * @Route("/{page}", name="nyheter_index", methods={"GET"})
     */
    public function index(BlogPostRepository $blogRepository, $page=1): Response
    {
        if (!\is_numeric($page)) {
            $page=1;
        }

        
        $count = $blogRepository->getCount();
        $limit = 1;
        $pages = $count/$limit;
        $pages = \ceil($pages);
        if ($page > $pages) {
            $page = $pages;
        }
        $posts = $blogRepository->getLatest($page, $limit);
        return $this->render("nyheter/index.html.twig", [
            "count" => $count,
            "page" => $page,
            "pages" => $pages,
            "posts" => $posts
        ]);
    }

Man kan se att det finns en template fil under filmappen nyheter som heter index.html.twig. Den filen ser ut så här:

{% extends "content.html.twig" %}
{% block navNyheter %}active{% endblock %}
{% block content %}
    {% for post in posts %}
        <article>
            <div class="article-header">
                <h1><a href="{{ path("nyheter_view", {'slug': post.slug}) }}">{{ post.title }}</a></h1>
            </div>
            <div class="article-content">
                <p class="time">{{ post.publish|date("d/m/Y") }} av {{ post.user }}</p>
                <p>{{ post.text|striptags('<em><strong><i><mark><cite><dfn>')|raw|nl2br }}</p>
                {% if app.user == post.user %}
                    <p><a href=""></a></p>
                {% endif %}
                
            </div>
        </article>
    {% endfor %}
    <div class="flex-center">
        {% for i in 1.. pages %}
            {% if i == page %}
                <a class="page-number active" href="/nyheter/{{i}}">{{ i }}</a>
            {% else %}
                <a class="page-number" href="/nyheter/{{i}}">{{ i }}</a>
            {% endif %}
        {% endfor %}
    </div>
{% endblock %}

Som man kan se i ovanstående kod så kan jag komma åt variabeln $posts genom instruktionen {{ post }}. Och när jag använder det på rätt sätt så kan jag få ett resultat som liknar det nedan.

Så det var allt för denna gången. Jag har skrivit ett blogginlägg om att göra en bloggfunktion för att göra blogginlägg. Blogg. Nu har jag skrivit det så mycket att jag börjar läsa det hela som grogg. Och apropå det: spel! Jag har visserligen en viss varm känsla för Secret of Monkey Island, men något som jag ser fram emot nu är att börja spela Skyrim igen. Senast jag gjorde det var 2013. Nu har jag den uppdaterade versionen på PS4. Jag får se om det fortfarande kan hålla mig underhållen. Men det är lugnt. Jag har några partyspel som nog funkar gott ändå!

Trevlig helg, allihopa!


Att göra en nyhetsblogg

Denna onsdag skriver jag om Bokarenan och möjligheten att bygga på den med fler funktioner. Det som står på dagordningen denna gång är en nyhetsblogg. För att få till detta så är det tre saker som ska komma på plats:

  • Ny entitet
  • Uppdaterad databas
  • Uppdaterad presentation/view

Det enklaste är att skapa en ny entitet med hjälp av MakerBundle i Symfony. Det innebär att jag via ett CLI (kommandotolken) kan instruera Symfony att göra den nya entiteten åt mig. På vägen får jag hjälp av Symfony för vad jag ska göra härnäst. För att starta det hela så utgår jag från projektets root-mapp och kör följande kommando:
php .\bin\console make:entity

Detta ger följande interaktion:

Jag döper min nya entitet till BlogPost, och ger den följande fält:
– title [string]
– text [text]
– entered [datetime]
– modified [datetime]
– publish [datetime]
– user [ManyToOne]

Exempel på hur fältet user i BlogPost relaterar till en annan entitet. User är det objekt som alltså refereras av BlogPost. ManyToOne innebär att respektive BlogPost bara kan referera till en användare, men en användare kan skapa flera BlogPost.

Genom hela denna process så har Symfony skapat och uppdaterat klassen BlogPost. Om vi tar en översikt över kursen så har den följande metoder och fält:

Då var steg ett avklarat. Nästa steg är att uppdatera databasen. Återigen är Symfony behjälplig… eller rättare sagt så är det faktiskt Doctrine. I CLI:t så kör jag följande kommandon:
php .\bin\console make:migration
Detta är en instruktion från Symfony till Doctrine hur databasen ska uppdateras efter att en till entitet har lagts till. Då återstår att låta Doctrine uppdatera databasen:
php .\bin\console doctrine:migrations:migrate
Databasen är nu uppdaterad och har rätta relationerna mellan BloggPost-tabellen och User-tabellen.

Då var två av tre steg avklarade. Det som återstår nu är att uppdatera presentationen för denna nya entitet. Detta steg består faktiskt av flera detaljer. Det innebär att en kontroller (eller två) ska uppdateras, en template för att skapa bloggposter ska skapas, en template för att presentera bloggposter ska uppdateras. Detta steg återkommer jag till på fredag. Vi ses då!


Statistik ”avklarad” och frågan om Oauth2

Det var onsdag den 30 oktober 2019 när jag började skriva något om statistik på den här bloggen. Det har blivit 20 inlägg i den kategorin och nu är jag klar med den kurs jag gått under senhösten/vintern. Jag har behandlat ämnen så som sannolikhet, standardavvikelser, standardiserade värden, normalfördelning, hypoteser, centrala gränsvärdessatsen, konfidensintervall, proportioner, chi2 och linjär regression. Jag har gått från deskriptiv statistik till prediktiv analys med en förklaringsvariabel. Emellanåt har det varit utmanande att finna tid till att skriva om statistiken och plugga, samtidigt som jag tagit hand om bebisar, tränat och programmerat. Men jag tycker att jag lärt mig mycket om statistik och jag har nu några idéer om hur jag skulle kunna tillämpa några av de kunskaper jag fått. Så här är några idéer:

  • Undersök korrelation mellan löptid och förlorad vätska. Min hypotes är att det finns ett positivt förhållande mellan hur länge jag springer och hur mycket vätska jag blir av med.
  • Undersök om jag har preferens för en särskild kategori böcker jämfört med andra. Jag behöver dock ett större läsunderlag klart innan jag kan påbörja detta. Jag tror att chi2-analys kan vara på sin plats då.
  • Sammanställ en beskrivning hur länge det tar att lägga upp en ny recension på Bokarenan innan en användare lägger upp en ny. Hur ser sambandet mellan detta och längden på den bok som recenseras.

Så även om jag är klar med statistikkursen så är jag inte klar med statistiken. Vi får se var det smyger sig in framöver. Men nu kommer jag flytta fokus tillbaka till programmering ett tag.

Förra måndagen skrev jag att jag skulle kolla på möjligheten att logga in med oauth (eller rättare sagt oauth2) till Bokarenan. Då skrev jag att jag eventuellt skulle titta på inloggning med Google-konto. Nu har jag kollat möjligheter och provat implementeringar och kan rapportera tillbaka.

Jag kom att prova med Facebook istället för Google och provade följande behjälpliga paket: knpuniversity/oauth2-client-bundle tillsammans med league/oauth2-facebook. Det jag fick göra var att skapa en controller för Facebook-inloggning och registrering samt en autentiserare för det också. Jag upplevde instruktionerna från knpuniversity/oauth2-client-bundle var enkla att följa och redigera för egna behov. Det krävdes att jag fick lägga till ytterligare autentiserare i min konfigurering (security.yaml) och att jag skrev vilken av dem som i första hand skulle användas:

        guard:
            authenticators:
                - App\Security\FacebookAuthenticator
                - App\Security\LoginFormAuthenticator
            entry_point: App\Security\LoginFormAuthenticator

Jag fick en till konfigureringsfil (knpu_oauth2_client.yaml) med instruktioner för autentisering:

knpu_oauth2_client:
    clients:
       
        facebook_main:

            type: facebook
            client_id: '%env(OAUTH_FACEBOOK_ID)%'
            client_secret: '%env(OAUTH_FACEBOOK_SECRET)%'

            redirect_route: connect_facebook_check
            redirect_params: {}
            graph_api_version: v2.12

Det denna konfigureringsfil innehåller är alltså vilken ”användare” och vilket ”lösenord” som ska användas gentemot Facebook för att få en ingång till oauth2 (så användare kan logga in med sina Facebook-användare). Informationen för det sparas i .env-filen. Sedan finns information om vilken funktion i controllern som kommer fånga upp inloggningen.

Det som jag tyckte var det svåraste var om en Facebook-användare behövde registreras som ny användare. Det jag gjorde då var att logga in användaren och sedan dirigera denna till avregistrering om denne inte vill gå med på användarvillkoren. Jag fick ta och registrera i sessionen (via autentiseraren) att användaren var ny och sedan kontrollera detta:

if ($this->session->get('fb-new')) {
    $targetUrl = $this->router->generate('connect_facebook_register');
    return new RedirectResponse($targetUrl);
}

Jag gillade slutresultatet. Det var jätteenkelt att logga in! Men jag har beslutat att för närvarande inte inkludera funktionen i produktion. Anledningen: jag är inte ett företag. Med det vill jag säga att det finns juridiska åtaganden att ta hänsyn till när det kommer till oauth2 och jag vill inte ta ansvar för Facebooks data om användare på min hobby-sida. Det kan vara så att jag överreagerar vad gäller detta och om så vore fallet så återinför jag funktionen.

Det som jag ska göra härnäst på Bokarenan är att införa en nyhetsblogg. Vi får se hur det går. Vi ses på onsdag!


Samband mellan slajm och maskrosor

Så är det äntligen fredag igen. Och som vi har längtat till att få läsa lite om linjär regression. Just det, det är statistik igen (som utlovat)! Denna gång kommer vi återvända till farmaren Frans och hans slajmfarm. Han vill veta om det finns något samband mellan maskrosor och hur mycket slajm som slajmklumparna producerar.

Frans ringer sifferkunniga Samantha igen. Nu börjar det bli ganska många gånger som han har ringt så Sam börjar fundera på att ta ut en avgift. Men hon kommer inte långt i dem tankarna. När hon föra höra regression komma på tal släpper hon allt. Pannkakor kan hon göra sen!

De ägnar nu en dag åt att noggrant mäta den mängd maskrosor som respektive slajmklump äter under dagen, samt väga den slajm de producerar. Det är ganska mycket jobb men de väljer slumpvis 50 slajmklumpar från populationen som ska få delta i denna studie. Allt skrivs ned i ett protokoll.

Efter en lång dag på ranchen tillsammans med Frans så kan Sam äntligen pusta ut. Vid Frans köksbord tar Sam fram sin dator och startar sitt statistikprogram. Hon matar in alla siffror från protokollet i två kolumner; en för mängden maskrosor och en för mängden slajm.

Med alla siffrorna på plats tar hon och ritar upp dem på en graf. I x-led har hon mängden maskrosor och i y-led har hon mängden slajm. Då får hon en graf som ser ut så här:

Det verkar finnas ett förhållande som innebär att ju mer maskrosor som slajmklumparna konsumerat desto mer slajm har de producerat. Hur bra funkar maskrosätande som förklaringsfaktor?

Till sin hjälp har Sam något som kallas korrelationskoefficienten (r). Den visar om det finns något linjärt samband mellan två variabler och riktningen på sambandet. Den kan anta ett värde mellan -1 och 1. Om r är 0 så finns inget linjärt samband, men desto närmare 1 desto bättre stigande linjärt samband. Vice versa för -1 men då fallande samband. Om r hade varit -1 i grafen ovan så hade alla prickarna placerat sig på en linje som lutade nedåt. Genom lite läckra beräkningar där hon i princip summerar faktorer av standardiserade skillnader för varje punkt från respektive medelvärden och dividerar med antalet punkter (minus ett)… det där lät mer komplicerat än att visa formeln:

Det är lite jobbigt att göra beräkningen för hand. Sam skulle behöva beräkna produkten för varje punkt i grafen och det är 50 stycken. Hon tar hjälp av sin dator istället och får fram att korrelationskoefficienten är 0,93. Det verkar finnas ett positivt samband mellan maskrosätande och slajm producerat och det har en ganska stark koppling. Men Sam är inte riktigt klar än. Hon vill veta hur mycket slajm man kan förvänta sig om en slajmklump äter 100g maskrosor. Så hon fortsätter med regressionsanalysen.

Sam vill få fram en modell som kan beskriva hur förhållandet egentligen ser ut. Det Sam tänker sig är att ta fram en funktion som beskriver en linje som passerar genom punkterna. Ungefär så här ska funktionen se ut: y(x)=m+kx. Och den linje som Sam ska ta fram ska ha lika stor mängd som är ovanför som under linjen. Det vill säga att avstånden från linjen för alla punkter ovanför ska vara lika stor som för de punkter som är under. Åter till Sams dator, där får hon fram följande linje:

Linjen kan beskrivas med formeln: y(x)=25,8 + 1,05x +/- 0,13. Om en slajmklump äter 100 g maskrosor kan Frans förvänta sig få ungefär 131 ml slajm från den. Finns det då några andra faktorer som påverkar? Ja, det är möjligt, men maskrosätande har en förklaringsfaktor på 86%. Det är JÄTTEMYCKET.


Maskrosätande

Idag är det onsdag, och som utlovat ska vi idag utreda om gröna slajmar har ett annat förhållande till maskrosor än röda slajmar. Det stämmer, idag är det statistik på agendan!

Vi har tidigare i bloggen kollat på hur stor andel av farmaren Frans kunder som är nöjda med den slajm som han levererar (84% av alla kunder är nöjda med Slajm). Men denna gång vill vi kolla på andelar på ett annat sätt. Farmaren Frans har upptäckt några av hans slajmklumpar inte verkar tycka om de maskrosor som serveras. Han misstänker att de röda slajmarna inte har tillnärmelsevis lika stor aptit för de frekventa blommorna som de gröna slajmarna.

Frans har gott minne över hur den sifferkunnige Samantha hjälpte honom tidigare (Ska jag bry mig om 1 ml hit eller dit?). Sam kunde såklart hjälpa honom även denna gång, så tillsammans utformade de ett enkelt protokoll och iakttog de slajmklumpar som idag fanns i maskroshagen. Protokollet blev en enkel tabell som såg ut så här:

Slajmklumpar som tog för sig av blommorna räknades till de som ”gärna” äter maskrosor. De slajmklumpar som kom fram och sniffade på blommorna utan att äta räknades till de som ”kanske” äter maskrosor. De slajmklumpar som inte åt, och inte sniffade blommorna räknades till de som ”inte alls” äter maskrosor. Som tur gick det ganska enkelt att räkna och hålla reda på alla slajmar eftersom Frans känner sina slajmklumpar så bra. Så efter en dag i maskroshagen hade Frans och Sam fått fram följande resultat:

”Varför har du skrivit dit en massa extra siffror?” frågade Frans.
”Jo du ser att gröna slajmar är 36 stycken, och det finns 24 röda. Det är det som jag skrivit upp till höger”, svarade Sam.
”Okej, men varför har du skrivit summor för varje kolumn? Vad ska det vara bra för?”
”Åh, jag är inte helt klar. Vänta!”

Sam började frenetiskt skriva upp siffror. Först skrev hon 60 i mörkblått i nedre högra hörnet av tabellen.
”Det är summan av alla slajmklumpar som varit i hagen idag.”
Därefter började hon räkna på vad hon kallade var ”de förväntade antalet slajmklumpar för varje cell”. Det hon menade var att man kan förvänta sig att visst många slajmklumpar kommer fördela sig i kategorierna ”gärna”, ”kanske” och ”inte alls” på ett visst sätt om det inte finns någon skillnad mellan röda och gröna slajmare. Det hon vill undersöka är om det stämmer det som Frans påstår: att det finns en skillnad.

Efter att ha räknat ett tag har Sam skrivit upp hur många slajmklumpar det kommer finnas i varje cell om det inte är någon skillnad mellan röda och gröna slajmklumpar. Enligt hennes beräkning kan man förvänta sig att 17 gröna slajmklumpar ”gärna” äter maskrosor. Men resultatet de fick var att 18 stycken gröna slajmare gärna äter blommorna. Har Sam fått ett signifikant resultat? Det verkar som att övriga förväntade resultat ligger nära det uppmäta resultatet! Sam får fortsätta räkna.

Hon börjar med att beräkna hur stor den genomsnittliga avvikelsen är och hur långt det ifrån det förväntade värdet de uppmätta värdena är. Hon använder sig av chi2:

Detta innebär att för varje cell så gör hon en beräkning enligt ovanstående formel och summerar dem.

Sam hade nu fått fram chi2 = 0,66. Med hjälp av en chi2-fördelningskurva så hade nu Sam ett mått på hur stor sannolikheten är att de skillnader mot förväntade antal skulle uppstå av slumpen. Om hon har liten sannolikhet så kan hon utesluta att det inte skulle finnas någon skillnad mellan röda och gröna slajmar. Vad är då sannolikheten?

Till sin hjälp har Sam chi2-fördelningskurva och uträkning av grader av frihet. Grader av frihet räknar hon fram genom att ta antalet rader minus ett gånger antalet kolumner minus ett: (3-1)(2-1)=2. Hon får fram följande graf där det färgade området är sannolikheten att få så stor avvikelse eller större av slumpen. Svaret? 72%!

Sam kunde inte ge stöd åt Frans hypotes. Det verkar som att det för närvarande inte är någon skillnad om röda eller gröna slajmar kommer äta maskrosor. Med Sams hjälp har Frans nu kommit fram till att alla slajmklumpar gott kan få fortsätta dela på maskroshagen.


Uppehåll över, nytt år är igång

Det har nu gått en hel månad sedan jag senast skrev ett inlägg. Då var datumet 20:e december 2019. Det är nu den 20:e januari 2020. I stort sett har jag under hösten skrivit tre inlägg i veckan och jag planerar att fortsätta så den närmaste tiden. Det uppehåll som jag hade var välbehövt. När det kommer till familj så är det något som kommer först. Över nyår och de första veckorna därefter så ägnade jag mycket tid till att hälsa på familj och släkt tillsammans med bebisar som fortsätter att utveckla sig. Till detta har kommit att slutföra den kurs jag har ägnat övrig tid åt: grundläggande statistik. Men ni läsare som har följt mina inlägg ett tag nu vet att jag antagligen lyckats hitta tid över till programmering trots allt detta. Ni har rätt!

Den gångna månaden har jag ägnat strötiden åt att göra en lättare data scaper. Den har till uppdrag att hitta bokinformation så att användare inte ska behöva fylla i femtioelva fält på egen hand. Istället ska användare kunna ägna sig åt att skriva om sin senaste läsning. Jag laddade upp denna funktion vid lunch idag. Så om du vill se om det funkar så kan du bli medlem idag på bokarenan.se/registrera.

Nästa steg i Bokarenan är några mindre justeringar i layouten och jag ska kolla på möjligheten att införa OAuth; eller möjligheten att logga in med ditt Google-konto. Uppdateringar om det kommer längre fram.

Denna vecka på Femte Arenan så kommer jag fortsätta i statistikens tecken. På onsdag kommer jag beskriva hur man kan analysera om det finns statistiskt signifikanta skillnader mellan röda slajmar och gröna slajmar vad avser deras preferens för att äta maskrosor. På fredag kommer jag försöka förutse hur mycket slajm en slajmklump kan producera baserat på hur mycket maskrosor den har ätit under dagen. Vi kommer alltså beröra chi2-analys och linjär regressionsanalys denna vecka. Det är ju toppen, och superintressant för en slajmproducent! Vi ses på onsdag!