Tipy a triky Nette 2.4 - jednoduchá komponenta pro zobrazení YouTube videa

V tomhle článku si ukážeme, jak si v Nette 2.4 napsat vlastní jednoduchou komponentu pro zobrazení videa z Youtube.

Jako vstupní parametr bude mít url videa na Youtube a případné další parametry. Komponenta pak ve stránce vykreslí embedované video podle našich parametrů. Postup se dá ovšem použít pro jakoukoli komponentu.

Nejprve si trochu prozkoumáme, jak může takové url videa na Youtube vypadat. Zjistíme, že může mít řadu různých formátů, například:

https://www.youtube.com/watch?v=ilM9uM63Wdo
https://youtu.be/ilM9uM63Wdo
https://m.youtube.com/watch?app=desktop&v=ilM9uM63Wdo

Vidíme, že formáty se trochu liší, ale jedna věc zůstává - unikátní id videa (v tomto případě "ilM9uM63Wdo"). Podle dokumentace jde o 11 znaků dlouhý řetězec, který může obsahovat čísla, písmena anglické abecedy, pomlčky a podtržítka.

Naše komponenta bude tedy schopna ze zadaného url extraktovat právě tohle unikání id a pak ho použít. A navíc by jí mělo stačit i zadání jen přímo toho samotného 11 místného kódu - třeba budeme někdy chtít mít třeba v databázi jenom seznam těch id.

Vytvoříme si tedy nejdřív tenhle adresář:

/FrontModule/components/YouTubeBox

a v něm tyhle tři soubory:

youTubeBox.php
box.latte
empty.latte

Soubor youTubeBox.php bude obsahovat kód naší komponenty. Soubor box.latte bude šablona kódu, který se ve stránce objeví, pokud je vstupní url/id videa validní, šablona empty.latte se objeví, pokud url/id neodpovídá pravidlům.

Celý kód si můžete stáhnout zde.

youTubeBox.php:

<?php
namespace SkachCz\Components;

use Nette;
use Nette\Application\UI;

class YouTubeBox extends UI\Control
{
    public function render(string $url, string $title = '', int $width = 560, int $height = 315)    {
        $ytId = $this->extractYtCode($url);
        $tpl = $this->template;
        if($ytId === null) {
            $tpl->setFile(__DIR__ . "/empty.latte");
        } else {
            $tpl->setFile(__DIR__ . "/box.latte");
            $tpl->url = 'https://www.youtube.com/embed/' . $ytId;
            $tpl->title = $title;
            $tpl->width = $width;
            $tpl->height = $height;
        }
        $tpl->render();
    }

    private function extractYtCode(string $url) : ?string {
        // check if parameter is just youtube id (not url)
        if (preg_match('/^[a-zA-Z0-9_-]{11}$/', $url) > 0) {
            return $url;
        }
        preg_match("#(?<=v=)[a-zA-Z0-9-]+(?=&)|(?<=v\/)[^&\n]+(?=\?)|(?<=v=)[^&\n]+|(?<=youtu.be/)[^&\n]+#", $url, $matches);
        return isset($matches[0]) ? $matches[0] : null;
    }
}

Naše komponenta dědí z třídy Nette\UI\Control, která se stará o všechny důležité věci.

Vidíme, že jsme si vytvořili funkci extractYtCode(), která s pomocí regexpu ze zadaného url dokáže extrahovat id videa, případně pozná, že jsme kód poslali přímo.

Dále tam máme funkci render(), zde se postaráme o to, co se má ve stránce vykreslit.

Funkce render má parametry. Sem se předají ty parametry, které zadáme v šabloně při volání této komponenty.

$tpl = $this->template;
- tady si převezmeme standardní šablonu komponenty, o kterou se nám postarala třída UI\Control.

S pomocí metody ->setFile() nastavíme šabloně příslušnou latte šablonu, podle toho, zda jsme získali platné id videa, nebo ne.

Do šablony si nastavíme parametry, které jsme si sem poslali a pak jen pustíme metodu ->render(), která naplněnou šablonu vykreslí.

V "úspěšné" šabloně box.latte vykreslíme embed kód zkopírovaný z toho, který standardně generuje Youtube a jen nahradíme měnitelné parametry těmi našimi:

box.latte

<div class="yt-box">
    <iframe width="{$width}" height="{$height}" src="{$url}" title="{$title}" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</div>

V "neúspěšné" šabloně jenom napíšeme, že video nebylo nalezeno.

empty.latte

<div class="yt-box empty">
Video není dostupné
</div>

Komponentu máme hotovou, teď ji vytvoříme v presenteru, je to docela jednoduché:

class MujPresenter extends \App\FrontModule\Presenters\BasePresenter
{ ...

    public function createComponentYouTubeBox() {
        return new \SkachCz\Components\YouTubeBox();
    }

v naší latte šabloně pak komponentu zavoláme třeba takhle:


<span>video 1</span>
{control youTubeBox "https://www.youtube.com/watch?v=dQw4w9WgXcQ"}

<span>video 2</span>
{control youTubeBox "dQw4w9WgXcQ", "Písnička", 720, 350}