Dodawanie kodu HTML między elementami Zend_Form

Jednym z najczęstszych problemów związanych z Zend_Form jest brak możliwości dodawania kodu HTML między elementami formularza. Na szczęście Zend_Form jest na tyle rozbudowany, iż przy odrobinie pomysłowości wspomniany problem można dosyć łatwo obejść. Rozwiązań jest co najmniej kilka. Dzisiaj przedstawię dwa najprostsze.

Pierwszym rozwiązaniem jest zastosowanie opisu (description) w elemencie, po którym chcemy dodać kod HTML.

class Application_Form_Example1 extends Zend_Form
{
    public function init()
    {
        $this->setName('form-example1');

        $name = new Zend_Form_Element_Text('name');
        $name->setLabel('Nazwa');

        $email = new Zend_Form_Element_Text('email');
        $email->setLabel('E-mail')
              ->setDescription('<div id="some-id">lorem ippsum</div>');

        $phone = new Zend_Form_Element_Text('phone');
        $phone->setLabel('Telefon');

        $submit = new Zend_Form_Element_Submit('btn_save');
        $submit->setLabel('Zapisz');

        $this->addElement($name);
        $this->addElement($email);
        $this->addElement($phone);
        $this->addElement($submit);
    }
}

Kluczowym elementem powyższego kodu jest metoda setDescription, wywołana na obiekcie $email. Dzięki niej, do kodu formularza zostanie dodany kod HTML. Niestety kod zostanie wyświetlony w takiej formie, w jakiej został dodany – na stronie wyświetli się tekst

<div id="some-id">lorem ippsum</div>

Dzieje się tak dlatego, ponieważ kod HTML jest zamieniany na encje. Rozwiązaniem tego problemu jest ustawienie opcji escape dekoratora Description na false.

$email->addDecorator('Description', array('escape' => false));

Drugi sposób polega na zastosowaniu ukrytego elementu, w którym kod HTML wyświetlany jest w etykiecie.

class Application_Form_Example2 extends Zend_Form
{
    public function init()
    {
        $this->setName('form-example2');

        $name = new Zend_Form_Element_Text('name');
        $name->setLabel('Nazwa');

        $email = new Zend_Form_Element_Text('email');
        $email->setLabel('E-mail');

        $html = new Zend_Form_Element_Hidden('html');
        $html->setLabel('<div id="some-id">lorem ippsum</div>')
             ->setIgnore(true)
             ->addDecorator('Label', array('escape' => false));

        $phone = new Zend_Form_Element_Text('phone');
        $phone->setLabel('Telefon');

        $submit = new Zend_Form_Element_Submit('btn_save');
        $submit->setLabel('Zapisz');

        $this->addElement($name);
        $this->addElement($email);
        $this->addElement($html);
        $this->addElement($phone);
        $this->addElement($submit);
    }
}

Podobnie jak w przypadku opisu, etykieta również wymaga ustawienia opcji escape na false. Oczywistym jest, że podczas wysyłania formularza dodatkowe pole jest zbędne. Dzięki użyciu metody setIgnore, nadmiarowy element nie będzie występował w tablicy wartości przesłanych przez formularz.

Leave a comment ?

14 Comments.

  1. Wydaje mi się, że podane przez Ciebie rozwiązania są przydatne, kiedy chce się wstawić wspomniany HTML raz albo dwa razy. Nie podoba mi się w nich jednak to, że kod HTML ląduje w klasie formularza. Ale jak mówiłem, jak wykorzystuje się to raz czy dwa to żadna tragedia.

    Natomiast, kiedy ten HTML ma być powtarzany często to do głowy przychodzą mi jeszcze dwa rozwiązania:

    1. viewScript jako dekorator, gdzie dajesz swój kod HTML, a potem w nim wywołujesz helper elementu na którym Ci zależy. Za to gdzieś czytałem, że dekoratory jako viewScript są mało wydajne – nie przeprowadzałem testów samemu, tak więc na razie odnoszę się do tego z dystansem.

    2. Własna klasa elementu formularza + setIgnore od razu w konstruktorze (nie pamiętam, czy elementy formularza mają metodę init()) + helper do niego.

    W obu przypadkach kod HTML ląduje poza kodem formularza, co uważam za plus, mimo że podane przeze mnie rozwiązania wymagają troszkę więcej pracy.

    Miałem kiedyś sytuację, że front-endowiec poszalał z kodem formularza (zaawansowane "divits") i wtedy zrobiłem to przez viewScript – a żałuję, że wtedy nie znałem jeszcze drugiej wspomnianej przeze mnie metody – byłoby zdecydowanie prościej i przejrzyściej.

  2. Najsensowniej byłoby napisać własny element formularza. Można również pokusić się o napisanie własnego dekoratora (zamiast viewScript), który wyświetlałby bardziej zaawansowany kod niż opis.
    Jednak w przypadku prostych treści HTML, które mają być jedynie niewielkim uzupełnieniem formularza, lepiej użyć opisu, ewentualnie etykiety.
    W sumie Zend_Form nie jest taki zły jak go malują. Przy odrobinie cierpliwości można z niego bardzo dużo wycisnąć.

  3. O, o napisaniu własnego dekoratora nie pomyślalem – następna koncepcja, thx.

    A co do Zend_Form – zgadzam się – na początku przeraża, ale w miarę korzystania i poznawania możliwości staje się naprawdę wygodnym narzędziem.

  4. Wystarczy zrobić sobie klasę Zend_Form_Element_Note o treści:

    tekst podajemy jako setValue() i wszystko śmiga.
    Zaczerpnięte z http://framework.zend.com/wiki/display/ZFPROP/Zend_Form_Element_Note+-+Jan+Pieper (komentarze)

  5. eee wcieło kod…

    class Zend_Form_Element_Note extends Zend_Form_Element_Xhtml
    {
    public $helper = 'formNote';

    public function isValid($data, $context = null) {
    return true;
    }
    }

  6. Ja od kilku lat z powodzeniem używam własnego elementu Zend_Form: http://pastebin.com/Pc2RhKbs

    Co prawda patrząc na niego teraz widzę pewne możliwe poprawki (np. możliwość wyboru czy treść ma być opakowana w div czy inny tag) ale to pozostawiam chętnym :)

  7. Nie wiem na ile to ładne rozwiązanie, ale jeżeli potrzebuje jakiś html w formularzu, który nie musi być związany z konkretnym elementem to robię sobie tak, że tworzę element 'hidden', korzystam ze wszelkich dobrodziejst Description, Label, HtmlTag i te pe, co tylko dusza zabraknie, ale z samych dekoratorów wywalam ViewHelpera. Dzięki temu renderuje mi się całe potrzebne "opakowanie", bez zbędnego w tym wypadku <input type='hidden' />

  8. Witaj,
    od niedawna bawie się zendem i idzie mi coraz lepiej. Dużo problemów natrafiam podczas dekorowania elementow formularzy i twój blog w większości przypadków mi pomaga. Nie mniej jednak trafilem na powazniejszy problem (tak mi się wydaje). Chcę za pomocą dekoratorow ułożyć ładnie checkboxy. Co to znaczy? Otóż np. z bazy pobieram 20 wpisów które mają być checkboxami ale nie chcę by były jeden pod drugim bo robi się duża lista. Moje pytanie brzmi jak zrobić by w formularzu checkboxy układały się w 3. kolumnach po równą ilość wierszy (jeśli jest liczba nierówna to w ostatniej kolumnie chciałbym by było mniej checkboxów o daną ilosć) ?

  9. Hej MitS!

    Miałem ostatnio identyczny problem. Rozwiązałem go w taki sposób, że napisałem sobie dekarator.

    Sam dekorator elementy (checkboxy) posiadał w tablicy. Dalej robi się wesoło :) Tablicę tę wstawiłem sobie do Zend_Paginatora, dzięki czemu w bardzo prosty sposób zapewniłem sobie renderowanie określonej liczby elementów w określonej ilości kolumn. Następnie każdą "stronę" z Paginatora wyrzuciłem jako elementy listy nieuporządkowanej. Tym sposobem dostałem pięknie wygenerowany kodzik. Kod dekoratora wklejam dla Ciebie tu: http://ideone.com/cnSur

    Nie jest jakoś mega elegancko i dla mnie służyło do zamiany multiselecta na checkboxy, ale mysle, ze sprawdzi się rowniez dla Ciebie przy minimalnym nakladzie pracy :)

  10. cześć dzięki za odpowiedź, kodzik całkiem miły ale mam jedno podstawowe pytanie. Jak poprawnie wywołać ten dekorator ? Bo już trochę kombinuje a dostaje cały czas błąd: Fatal error: Call to a member function getMultiOptions() on a non-object.

    Będę wdzieczny za odpowiedź :)
    Jeszcze raz dzięki.

  11. MitS: dodaję dekoratory w metodzie formularza addElement, w opcjach elementu. tzn, przykładowo:

    $this->addElement(typ, nazwa, array(
    "decorators" => array(
    'ViewHelper',
    'MojDekorator'
    ),
    ));

    coś w tym stylu :)

  12. aa.. no i oczywiście prefixy musisz dodać dla elementu lub formularza

  13. super działa :)
    Pozdrawiam

  14. Wybaczcie za opóźnienie, zatrzymało mnie coś pilnego.

    ~Uirapuru
    Dzięki za rozwiązanie problemu ~MitS'a

Leave a Comment


NOTE - You can use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Subscribe without commenting