Symfony 6 + wyświetlanie zawartości tablic w widoku

W Symfony 6 tworzenie tablic i wyświetlanie ich w widoku jest stosunkowo proste i intuicyjne. Najczęściej tworzymy tablice w kontrolerze, gdzie mogą zawierać różne rodzaje danych, na przykład rekordy z bazy danych lub formularze. Po stworzeniu tablicy przekazujemy ją do widoku, który zajmuje się jej wyświetleniem.

W widoku możemy wykorzystać różne mechanizmy do wyświetlania tablic, np. pętlę for lub foreach, która pozwala na iterację po elementach tablicy i wyświetlanie ich w sposób dynamiczny. Dodatkowo możemy wykorzystać mechanizmy sortowania, filtrowania i paginacji, które pozwolą na bardziej zaawansowane operacje na danych.

Widoki w Symfony 6 korzystają z szablonów Twig, który pozwala na łatwe generowanie HTML i wykorzystanie różnych funkcji pomocniczych, np. do formatowania tekstu czy tworzenia linków. W ten sposób możemy w łatwy sposób wyświetlać dane w formie tabel, list czy nawet formularzy.

Stwórzmy kontroler ArrayController:

php bin/console make:controller Array

Następnie w pliku kontrolera dodajmy następujący kod:

<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class ArrayController extends AbstractController
{
    #[Route('/array', name: 'app_array')]
    public function array(): Response
    {
        $data = array(
            array('name' => 'Adam', 'surname' => 'Smith', 'age' => 35, 'email' => 'adam.smith@example.com'),
            array('name' => 'Emily', 'surname' => 'Jones', 'age' => 27, 'email' => 'emily.jones@example.com'),
            array('name' => 'Michael', 'surname' => 'Brown', 'age' => 42, 'email' => 'michael.brown@example.com'),
            array('name' => 'Samantha', 'surname' => 'Lee', 'age' => 23, 'email' => 'samantha.lee@example.com'),
            array('name' => 'William', 'surname' => 'Davis', 'age' => 31, 'email' => 'william.davis@example.com'),
            array('name' => 'Olivia', 'surname' => 'Miller', 'age' => 29, 'email' => 'olivia.miller@example.com'),
            array('name' => 'Benjamin', 'surname' => 'Wilson', 'age' => 38, 'email' => 'benjamin.wilson@example.com'),
            array('name' => 'Isabella', 'surname' => 'Taylor', 'age' => 26, 'email' => 'isabella.taylor@example.com'),
        );

        return $this->render('array/index.html.twig', [
            'data' => $data,
        ]);
    }
}

Jak widać stworzona została tablica dwuwymiarowa, gdzie każdy rekord podstawowej tablicy jest kolejną tablicą asocjacyjną z kluczami i przyporządkowanymi do nich wartościami. Po stworzeniu tablicy przekazywana ona jest do widoku.

W widoku stwórzmy następujący kod:

{% extends 'base.html.twig' %}

{% block title %}ArrayView{% endblock %}

{% block body %}
    <table>
        <thead>
        <tr>
            <th>Name
            <th>Surname
            <th>Age
            <th>Email
        </thead>
        <tbody>
        {% for record in data %}
            <tr>
                <td>{{ record.name }}
                <td>{{ record.surname }}
                <td>{{ record.age }}
                <td>{{ record.email }}
        {% endfor %}
        </tbody>
    </table>
{% endblock %}

W widoku jak widać można wyświetlić dane z tablicy przekazanej z kontrolera w tabeli HTML za pomocą pętli „for” lub „foreach”.

Dodajmy sortowanie tabeli po danych kolumnach. Wykonamy to za pomocą przekazania w URL odpowiednich parametrów.

Najpierw dodajmy w widoku linki służące do sortowania tabeli:

{% extends 'base.html.twig' %}

{% block title %}ArrayView{% endblock %}

{% block body %}
    <table>
        <thead>
        <tr>
            <th><a href="{{ path('app_array', {'sortBy': 'name'}) }}">Name</a>
            <th><a href="{{ path('app_array', {'sortBy': 'surname'}) }}">Surname</a>
            <th><a href="{{ path('app_array', {'sortBy': 'age'}) }}">Age</a>
            <th><a href="{{ path('app_array', {'sortBy': 'email'}) }}">Email</a>
        </thead>
        <tbody>
        {% for record in data %}
            <tr>
                <td>{{ record.name }}
                <td>{{ record.surname }}
                <td>{{ record.age }}
                <td>{{ record.email }}
        {% endfor %}
        </tbody>
    </table>
{% endblock %}

Następnie w kontrolerze dodajemy kod odpowiedzialny za sortowanie:

<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class ArrayController extends AbstractController
{
    #[Route('/array', name: 'app_array')]
    public function array(Request $request): Response
    {
        $data = array(
            array('name' => 'Adam', 'surname' => 'Smith', 'age' => 35, 'email' => 'adam.smith@example.com'),
            array('name' => 'Emily', 'surname' => 'Jones', 'age' => 27, 'email' => 'emily.jones@example.com'),
            array('name' => 'Michael', 'surname' => 'Brown', 'age' => 42, 'email' => 'michael.brown@example.com'),
            array('name' => 'Samantha', 'surname' => 'Lee', 'age' => 23, 'email' => 'samantha.lee@example.com'),
            array('name' => 'William', 'surname' => 'Davis', 'age' => 31, 'email' => 'william.davis@example.com'),
            array('name' => 'Olivia', 'surname' => 'Miller', 'age' => 29, 'email' => 'olivia.miller@example.com'),
            array('name' => 'Benjamin', 'surname' => 'Wilson', 'age' => 38, 'email' => 'benjamin.wilson@example.com'),
            array('name' => 'Isabella', 'surname' => 'Taylor', 'age' => 26, 'email' => 'isabella.taylor@example.com'),
        );

        $sortBy = $request->query->get('sortBy', 'default');
        if ($sortBy == 'name') {
            usort($data, function($a, $b) {
                return strcmp($a['name'], $b['name']);
            });
        } elseif ($sortBy == 'surname') {
            usort($data, function($a, $b) {
                return strcmp($a['surname'], $b['surname']);
            });
        } elseif ($sortBy == 'age') {
            usort($data, function($a, $b) {
                return $a['age'] - $b['age'];
            });
        } elseif ($sortBy == 'email') {
            usort($data, function($a, $b) {
                return strcmp($a['email'], $b['email']);
            });
        }


        return $this->render('array/index.html.twig', [
            'data' => $data,
        ]);
    }
}

Jak widać możemy sortować daną kolumnę, jednak tylko w jedną stronę. Dodajmy możliwość sortowania w górę i w dół danej kolumny – po drugim kliknięciu w link kolumna posortuje się odwrotnie. Aby to wykonać musimy przekazać w URL kolejny parametr określający kierunek sortowania, tworzymy odpowiednie linki w widoku:

{% extends 'base.html.twig' %}

{% block title %}ArrayView{% endblock %}

{% block body %}
    <table>
        <thead>
        <tr>
            <th><a href="{{ path('app_array', {'sortBy': 'name', 'sortOrder': (sortBy == 'name' and sortOrder == 'asc') ? 'desc' : 'asc'}) }}">Name</a>
            <th><a href="{{ path('app_array', {'sortBy': 'surname', 'sortOrder': (sortBy == 'surname' and sortOrder == 'asc') ? 'desc' : 'asc'}) }}">Surname</a>
            <th><a href="{{ path('app_array', {'sortBy': 'age', 'sortOrder': (sortBy == 'age' and sortOrder == 'asc') ? 'desc' : 'asc'}) }}">Age</a>
            <th><a href="{{ path('app_array', {'sortBy': 'email', 'sortOrder': (sortBy == 'email' and sortOrder == 'asc') ? 'desc' : 'asc'}) }}">Email</a>
        </thead>
        <tbody>
        {% for record in data %}
            <tr>
                <td>{{ record.name }}
                <td>{{ record.surname }}
                <td>{{ record.age }}
                <td>{{ record.email }}
        {% endfor %}
        </tbody>
    </table>
{% endblock %}

Zwróć uwagę, że w tagu a href używany jest helper path, który generuje URL na podstawie nazwy routingu oraz przekazanych parametrów. W tym przypadku, generowany jest URL dla nazwy routingu „app_array”, czyli dla metody array w kontrolerze ArrayController. Następnie, w przekazanych parametrach podajemy sortBy z wartością np. „name”, co oznacza, że chcemy posortować po kolumnie „name”. Dodatkowo, używany jest parametr sortOrder, który odpowiada za kierunek sortowania – „asc” (rosnąco) lub „desc” (malejąco). Ten parametr jest obliczany w locie w oparciu o aktualny stan sortowania. Jeśli sortBy jest równy „name” i sortOrder jest równy „asc”, to ustawiamy sortOrder na „desc”, aby umożliwić sortowanie malejąco po kolumnie „name”. W przeciwnym razie, ustawiamy sortOrder na „asc”, aby umożliwić sortowanie rosnąco po kolumnie „name”.

W kontrolerze dodajemy obsługę sortowania w górę i w dół:

<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class ArrayController extends AbstractController
{
    #[Route('/array', name: 'app_array')]
    public function array(Request $request): Response
    {
        $data = array(
            array('name' => 'Adam', 'surname' => 'Smith', 'age' => 35, 'email' => 'adam.smith@example.com'),
            array('name' => 'Emily', 'surname' => 'Jones', 'age' => 27, 'email' => 'emily.jones@example.com'),
            array('name' => 'Michael', 'surname' => 'Brown', 'age' => 42, 'email' => 'michael.brown@example.com'),
            array('name' => 'Samantha', 'surname' => 'Lee', 'age' => 23, 'email' => 'samantha.lee@example.com'),
            array('name' => 'William', 'surname' => 'Davis', 'age' => 31, 'email' => 'william.davis@example.com'),
            array('name' => 'Olivia', 'surname' => 'Miller', 'age' => 29, 'email' => 'olivia.miller@example.com'),
            array('name' => 'Benjamin', 'surname' => 'Wilson', 'age' => 38, 'email' => 'benjamin.wilson@example.com'),
            array('name' => 'Isabella', 'surname' => 'Taylor', 'age' => 26, 'email' => 'isabella.taylor@example.com'),
        );

        $sortBy = $request->query->get('sortBy', 'default');
        $sortOrder = $request->query->get('sortOrder', 'asc');

        if ($sortBy == 'name') {
            usort($data, function($a, $b) use ($sortOrder) {
                $result = strcmp($a['name'], $b['name']);
                return $sortOrder === 'asc' ? $result : -$result;
            });
        } elseif ($sortBy == 'surname') {
            usort($data, function($a, $b) use ($sortOrder) {
                $result = strcmp($a['surname'], $b['surname']);
                return $sortOrder === 'asc' ? $result : -$result;
            });
        } elseif ($sortBy == 'age') {
            usort($data, function($a, $b) use ($sortOrder) {
                $result = $a['age'] - $b['age'];
                return $sortOrder === 'asc' ? $result : -$result;
            });
        } elseif ($sortBy == 'email') {
            usort($data, function($a, $b) use ($sortOrder) {
                $result = strcmp($a['email'], $b['email']);
                return $sortOrder === 'asc' ? $result : -$result;
            });
        }

        return $this->render('array/index.html.twig', [
            'data' => $data,
            'sortOrder' => $sortOrder,
            'sortBy' => $sortBy
        ]);
    }
}

Na sam koniec dodajmy jeszcze znacznik sortowania, tak aby po kliknięciu w dany link było wiadomo, względem której kolumny mamy posortowaną tabelę. Dodajemy warunki do widoku:

{% extends 'base.html.twig' %}

{% block title %}ArrayView{% endblock %}

{% block body %}
    <table>
        <thead>
        <tr>
            <th><a href="{{ path('app_array', {'sortBy': 'name', 'sortOrder': (sortBy == 'name' and sortOrder == 'asc') ? 'desc' : 'asc'}) }}">Name</a>
                {% if sortBy == 'name' %}
                    {% if sortOrder == 'asc' %}
                        <span>↑</span>
                    {% else %}
                        <span>↓</span>
                    {% endif %}
                {% endif %}
            <th><a href="{{ path('app_array', {'sortBy': 'surname', 'sortOrder': (sortBy == 'surname' and sortOrder == 'asc') ? 'desc' : 'asc'}) }}">Surname</a>
                {% if sortBy == 'surname' %}
                    {% if sortOrder == 'asc' %}
                        <span>↑</span>
                    {% else %}
                        <span>↓</span>
                    {% endif %}
                {% endif %}
            <th><a href="{{ path('app_array', {'sortBy': 'age', 'sortOrder': (sortBy == 'age' and sortOrder == 'asc') ? 'desc' : 'asc'}) }}">Age</a>
                {% if sortBy == 'age' %}
                    {% if sortOrder == 'asc' %}
                        <span>↑</span>
                    {% else %}
                        <span>↓</span>
                    {% endif %}
                {% endif %}
            <th><a href="{{ path('app_array', {'sortBy': 'email', 'sortOrder': (sortBy == 'email' and sortOrder == 'asc') ? 'desc' : 'asc'}) }}">Email</a>
                {% if sortBy == 'email' %}
                    {% if sortOrder == 'asc' %}
                        <span>↑</span>
                    {% else %}
                        <span>↓</span>
                    {% endif %}
                {% endif %}
        </thead>
        <tbody>
        {% for record in data %}
            <tr>
                <td>{{ record.name }}
                <td>{{ record.surname }}
                <td>{{ record.age }}
                <td>{{ record.email }}
        {% endfor %}
        </tbody>
    </table>
{% endblock %}

W kodzie powyżej zostały dodane kolejne bloki warunkowe, które sprawdzają, czy dana kolumna jest aktualnie sortowana, i w zależności od tego, czy sortowanie jest w kolejności rosnącej czy malejącej, wyświetlają odpowiedni znak sortowania (↑ dla rosnącej, ↓ dla malejącej).

Udało Ci się stworzyć prosty kontroler oraz widok, w którym mogliśmy wyświetlać przykładowe dane w tabeli. Następnie zaktualizowaliśmy kontroler i widok, tak aby umożliwić sortowanie w górę i w dół po kliknięciu na nagłówki tabeli. Teraz użytkownicy Twojej aplikacji będą mieli większą kontrolę nad sposobem sortowania danych, co z pewnością poprawi ich wrażenia z korzystania z Twojej aplikacji. Pamiętaj, że w trakcie pisania kodu ważne jest dbanie o czystość i czytelność kodu, dzięki czemu będzie on łatwiejszy do zrozumienia i utrzymania w przyszłości.

Leave a Comment

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

Scroll to Top