11

Rozdział 11 z 21

Wideo i audio

Opublikowany

Rozszerzamy media o wideo i audio. Encja BlogMedia obsługuje typy video/audio, renderujemy natywne <video>/<audio controls> z fallbackiem onerror i sortowaniem po polu position.

Czego się nauczysz

  • Typy mediów w BlogMedia (video, audio)
  • Osadzanie <video> i <audio controls>
  • Fallback (onerror) i komunikaty zastępcze
  • Kolejność mediów (position) i filtrowanie po typie

Rozdział 11: Wideo i audio

Rozszerzamy media o wideo i audio. Nie potrzebujemy nowej encji — BlogMedia z Rozdziału 10 obsługuje już trzy typy (image, video, audio). Dokładamy tylko render przez natywne znaczniki <video> i <audio>, z fallbackiem i zachowaną kolejnością.

Stan wejściowy: encja BlogMedia i galeria obrazków (Rozdz. 10). Tu tylko rozszerzamy szablon strony artykułu — bez zmian w PHP.


Te same media, inne typy

W Rozdziale 10 encja BlogMedia dostała stałe na wszystkie typy:

public const TYPE_IMAGE = 'image';
public const TYPE_VIDEO = 'video';
public const TYPE_AUDIO = 'audio';

Kolekcja article.media zawiera więc wszystkie media artykułu razem, posortowane po position. Na stronie renderujemy każdy typ osobno, filtrując po type — dokładnie jak obrazki, tylko z innym znacznikiem HTML.


Osadzanie wideo

Wideo osadzamy natywnym <video controls> ze źródłem z path. Gdy plik się nie wczyta, onerror podmienia zawartość na czytelną informację (zamiast pustego odtwarzacza):

{# templates/blog/show.html.twig — sekcja wideo #}
{% set videos = article.media|filter(m => m.type == 'video') %}
{% if videos|length > 0 %}
    <div class="mb-4">
        {% for video in videos %}
            <div class="card border-0 shadow-sm mb-3">
                <div class="card-body p-3">
                    <video controls class="w-100 rounded"
                           onerror="this.parentElement.innerHTML='<p class=\'text-muted small p-2\'>{{ video.originalName }}</p>'">
                        <source src="/{{ video.path }}">
                    </video>
                    {% if video.altText %}
                        <p class="text-muted small mt-2 mb-0">{{ video.altText }}</p>
                    {% endif %}
                </div>
            </div>
        {% endfor %}
    </div>
{% endif %}
  • controls — natywne przyciski przeglądarki (play/pauza/głośność/pełny ekran). Zero własnego JS.
  • <source src="/{{ video.path }}"> — ścieżka względem public/, z wiodącym /.
  • altText służy tu jako opis/podpis pod materiałem (dla obrazków był to alt).

Osadzanie audio

Audio działa analogicznie — natywny <audio controls>, dla czytelności z ikoną obok:

{% set audios = article.media|filter(m => m.type == 'audio') %}
{% if audios|length > 0 %}
    <div class="mb-4">
        {% for audio in audios %}
            <div class="card border-0 shadow-sm mb-3">
                <div class="card-body p-3">
                    <div class="d-flex align-items-center gap-3">
                        <i class="fa-solid fa-headphones fa-2x text-primary"></i>
                        <audio controls class="flex-grow-1">
                            <source src="/{{ audio.path }}">
                        </audio>
                    </div>
                    {% if audio.altText %}
                        <p class="text-muted small mt-2 mb-0">{{ audio.altText }}</p>
                    {% endif %}
                </div>
            </div>
        {% endfor %}
    </div>
{% endif %}

Ikona (fa-headphones) to tylko element wizualny — sam odtwarzacz to natywny <audio controls>, więc działa wszędzie bez dodatkowych bibliotek.


Fallback i kolejność

Dwie rzeczy wspólne dla obrazków, wideo i audio:

  • Kolejność — wszystkie media biorą się z jednej kolekcji article.media z #[ORM\OrderBy(['position' => 'ASC'])] (Rozdział 10). Ustawiając position, sterujesz kolejnością niezależnie od typu.
  • Fallback — dla wideo onerror chowa/zamienia zepsuty odtwarzacz. Dla audio wystarcza natywny komunikat przeglądarki, gdy formatu nie da się odtworzyć.

Formaty: przeglądarki grają najlepiej mp4 (wideo) i mp3 (audio) — do bloga to bezpieczny domyślny wybór. Możesz podać wiele <source> z różnymi formatami, jeśli potrzebujesz szerszej zgodności.


Podsumowanie

Artykuł obsługuje pełen zestaw mediów:

  • ✅ te same BlogMedia (typy video/audio z Rozdziału 10) — bez nowej encji i migracji,
  • ✅ wideo przez natywny <video controls> + <source>, z fallbackiem onerror,
  • ✅ audio przez natywny <audio controls> (z ikoną),
  • ✅ kolejność wspólna dla wszystkich mediów (position), filtrowanie po type w szablonie,
  • ✅ działający stan: artykuł wyświetla obrazki, wideo i audio (media z fixtures — upload w Rozdziale 12).

W Rozdziale 12 dobudujemy upload mediów w panelu admina — bezpieczne przesyłanie plików (UploadedFile, walidacja, unikalna nazwa) i powiązanie z artykułem.

Narzędzia / paczki

BlogMedia HTML5 media Twig

Spis treści