9. Podgląd zdjęcia

Galeria zdjęć musi także umożliwiać pełen podgląd zdjęcia wraz z wyświetleniem komentarzy użytkowników. Tym zajmiemy się teraz. Zaczniemy od kodu PHP (plik /actions/preview.php):

function action()
{
    // Sprawdz poprawnosc danych
    if(!isset($_GET['id']) || !ctype_digit($_GET['id']))
    {
        $view = new Opt_View('message.tpl');
        $view->title = 'Komunikat';
        $view->message = 'Nieprawidłowe parametry wywołania!';
        $view->redirect = 'index.php';
        return $view;
    }
 
    // Sprobuj wczytac zdjecie
    $photo = Doctrine::getTable('Photo')->find($_GET['id']);
    if(empty($photo))
    {
        $view = new Opt_View('message.tpl');
        $view->title = 'Komunikat';
        $view->message = 'Podane zdjęcie nie zostało znalezione.';
        $view->redirect = 'index.php';
        return $view;
    }
 
    // Przygotuj widok
    $view = new Opt_View('preview.tpl');
    $view->title = 'Podgląd zdjęcia "'.$photo->title.'"';
    $view->photo = $photo;
    $view->setFormat('photo', 'Objective');
 
    // Dodaj liste komentarzy
    $view->comments = Doctrine_Query::create()
        ->select('id, author, date, content')
        ->from('Comment')
        ->where('photo_id = ?', $_GET['id'])
        ->orderBy('id')
        ->execute(array(), Doctrine::HYDRATE_ARRAY);
 
    return $view;
} // end action();

Nasza akcja na początku sprawdza, czy w adresie URL znajduje się pole ID, następnie znaną już konstrukcją próbujemy pobrać podany wiersz. Jeśli to się nie uda, wyświetlamy błąd. Później bierzemy się za przygotowywanie widoku dla OPT. Po stronie szablonów znamy już konstrukcję $pojemnik.zmienna, którą póki co kojarzymy wyłącznie z tablicami. Tutaj jednak do zmiennej $photo przypisujemy obiekt. Mimo iż szablony pozwalają dość prosto korzystać z obiektów PHP, nie jest to najlepszy pomysł. Zastanówmy się: czy naprawdę, skoro już i tak kompilujemy szablony, musimy w nich pamiętać, czy dany pojemnik jest tablicą czy obiektem? Najczęściej będziemy chcieli z niego tylko wyciągnąć jakieś dane, zostawiając wszelkie metody w spokoju. Co więcej, jeśli po stronie skryptu stwierdzimy, że jednak musimy zmienić typ z obiektów na tablice lub na odwrót, nasze szablony z zapisami {$photo[name]} czy {$photo::name} również musiałyby zostać przepisane. Na szczęście z OPT nie trzeba się tym przejmować. Wystarczy, że w szablonie napiszemy {$photo.name}, a następnie w skrypcie metodą setFormat() zdefiniujemy format danych. Zalety:

  1. Szablony mogą powstawać bardziej niezależnie od skryptu – pisząc je, nie trzeba znać aż tylu szczegółów implementacyjnych skryptu.

  2. Jeśli w wyniku poprawiania i ulepszania kodu zdecydujemy się na zmianę typu, wystarczy, że poprawimy sam skrypt i powiadomimy o tym OPT.

  3. Formaty danych to coś więcej, niż typy danych. Możemy za ich pomocą wpływać na algorytmy, jakie realizują np. sekcje i w ten sposób przystosowywać je do pobierania danych bezpośrednio z różnych złożonych struktur. Sam OPT obsługuje domyślnie dwa formaty tablic dla sekcji, różniące się sposobem obsługi sekcji zagnieżdżonych.

  4. Bez względu na zastosowany format, kod szablonu pozostaje niezmienny.

  5. Możemy bardzo łatwo kopiować kod z jednego szablonu do drugiego (nawet między projektami). Wystarczy skonfigurować formaty w nowym miejscu i szablon zaczyna działać tam bez żadnych przeróbek.

Popatrzmy na szablon (/templates/preview.tpl):

<?xml version="1.0"?>
<opt:extend file="layout.tpl">
<opt:snippet name="content">
    <p><img parse:src="'photos/'~$photo.filename" /></p>
    <p>Dodano: {$photo.date_text}</p>
    <h3>Komentarze</h3>
    <opt:show name="comments">
        <div class="comment" opt:section="comments">
            <p class="author">Napisał {$comments.author} dnia {$comments.date_text}</p>
            <p>{$comments.content}</p>
        </div>
    <opt:showelse><p>Nie ma jeszcze żadnych komentarzy dla tego zdjęcia.</p></opt:showelse>
    </opt:show>
 
    <p><a parse:href="'index.php?action=comment&id='~$photo.id">Dodaj komentarz</a></p>
    <p><a href="'index.php">Powrót</a></p>
</opt:snippet>
</opt:extend>

Czy widać tu jakiekolwiek ślady programowania obiektowego PHP? Nie – i o to chodzi, bo nie jest to naprawdę nam do niczego potrzebne. W tym szablonie możemy również zapoznać się z kolejnym rodzajem sekcji – opt:section, w dodatku podanym jako atrybut do znacznika <div>. Jest to skrócona forma do wygodniejszego zapisu. OPT obejmuje sekcją również sam znacznik, a nie tylko jego treść. Opt:section jest najprostszą instrukcją sekcji do tworzenia zwykłych list, gdzie elementy znajdują się jeden pod drugim. Pozostałe zasady działania są identyczne, jak w opt:grid. Dane dla sekcji komentarzy pobierane są bezpośrednio z Doctrine. Jak pamiętamy, model automatycznie formatuje nam datę i możemy do niej odwołać się poprzez {$comments.date_text}.