Etikett Twig

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!


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.


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!