15. Zend Framework Form Decorator használata

Default book

Az űrlapok használata során beleütköztem abba a problémába, hogyan lehet tetszőleges HTML tartalmat vagy szöveget kiíratni az űrlapba egy űrlapelemhez kapcsolódóan.

Sok olvasás után arra jöttem rá, hogy Decorator lesz a kulcsszó!

Mik is a Decoratorok?

Olyan osztályok, amelyek felelősek a tartalom kiíratásért.

Minden űrlapelemhez tartozik több dekorátor is és ezek a dekorátorok egymás után futnak le és beburkolják az eredeti mezei űrlapelemet különféle keretekkel. Mindez akkor fut le, amikor például egy controller fájlban meghívjuk a

$this->render("view") 

függvényt, ahol a view egy view.phtml script a megfelelő helyen elhelyezve ( mondjuk az APPLICATION_PATH/views/scripts/view.phtml helyen)

Vannak alapértelmezett dekorátorok a Zend Frameworkben. Egy űrlapelem alapértelmezett decorator-ai:

  • ViewHelper - Ez jeleníti meg magát az űrlapelemet (INPUT, TextArea, stb...)
  • Errors - Ez a helper a validáció során esetlegesen felmerülő hibákat írja ki az űrlapelemhez közel.
  • HtmlTag - Ez egy dd tag-et tesz az űrlapelem köré
  • Label - Egy címkét írhatsz az űrlapelem elé

Minden decoratornak van render metodusa, ami a render metódus meghívásakor az űrlapelemre az alábbi módon fut le:

$label->render($htmlTag->render($errors->render($viewHelper->render('Űrlap elem tartalma'))))

Az alábbi példát a fentiek így hozzák létre:

ViewHelper eredménye:

        <input name="foo" id="foo" type="text" value="" />

     Errors decorator eredménye:

   <input name="foo" id="foo" type="text" value="" />
        <div class="error"><ul>
            <li>...</li>
        </ul></div>

A HtmlTag decorator eredménye:

<dd>
  <input name="foo" id="foo" type="text" value="" />
  <div class="error">
    <ul>
      <li>...</li>
    </ul>
  </div>
</dd>

A Label utáni eredmény és egyúttal végeredmény:

<dt><label for="foo" class="optional">Foo</label><dt>
<dd>
  <input name="foo" id="foo" type="text" value="" />
  <div class="error">
    <ul>
      <li>...</li>
    </ul>
  </div>
</dd>

Amikor egy űrlapot állítok össze, akkor a kiíratáskor meghívódnak az űrlap dekorátorai is, alapértelmezetten: 

  • Formelements - Végigmegy az űrlap elemein és kiírja az űrlapelem dekorátorai segítségével a megfelelő tartalmat

  • HtmlTag - (<dl> taget tesz )

  • Form - Magát a Form fejlécét és láblécét teszi ki.

Hogyan lehet módosítani programból az űrlap vagy egy űrlapelem dekorátorait, azaz az űrlap vagy az űrlapelemek kinézetét?

Az alábbi példán egy decorátor eredményét (label) nem az űrlapelem elé, hanem mögé tesszük a html kódban. A placement paraméter prepend és append lehet.

$label = $element->getDecorator('label');    //elkérjük az űrlapelem decorátorának hivatkozását
$label->setOption('placement', 'append');    // Módosítjuk a megfelelő paraméterét

Bármelyik ?rlapelem decorátorát kitörölhetjük a listából, ha nem kell:

$element->removeDecorator('label');

Sajnos a decorator-ok sorába nem tudunk beszúrni, ezért csak törölni lehet az összes decorator-t, majd újból hozzáadni a megfelelő sorrendbe a decorator-okat.

Az alábbi példában decorator-okat egy utasítással adjuk hozzá az elemhez. Ilyenkor egy tömböt kell használnunk.a definíció során. Ha HtmlTag decorátort akarunk hasznáni, akkor meg lehet adni azt is, hogy mi legyen a HtmlTag burkoló. Például lehet egy tömböt is a form elemei köré tenni vagy div-ekből felépíteni a burkoló elemeket.

$element->setDescription($desc);
$element->setDecorators(array(
    'ViewHelper',
    'Description',
    'Errors',
    array('HtmlTag', array('tag' => 'dd')),
    array('Label', array('tag' => 'dt')),
));

Használhatjuk a setDecorator() metódust is, ekkor csak egy decoratort adunk az elemhez és az esetleges korábbi decorator-okat töröljük.

Az addDecorator() egy decorátort ad hozzá az addDecorators() több decoratort ad hozzá a decoratorok sorához.

Ha például több HtmlTag decoratort adunk hozzá a decorátorok sorához, akkor aliast kell használnunk, például az alábbi példában az egyik HtmlTag egy div, a másik egy td-t tesz az elem köré. Az elementDiv és a td aliasokat használjuk.

$element->setDecorators(array(
    'ViewHelper',
    'Description',
    'Errors',
    array(array('elementDiv' => 'HtmlTag'), array('tag' => 'div')),
    array(array('td' => 'HtmlTag'), array('tag' => 'td')),
    array('Label', array('tag' => 'td')),
));

A szabványos decorator-ok listája az alábbi:

  • Callback:  PHP callback függvény adja vissza a taretalmat
  • Description: Description tulajdonságot ad hozzá az elemhez
  • DtDdWrapper:  <dd> és <dt> elemek közé zárja a tartalmat
  • Errors: Hibakódokat ír ki, ha kell
  • Fieldset: Fieldset-et tud kiíratni
  • Formelements: Végigmegy egy Form elemein, a subformokon kiiratási csoportokon, stb...
  • Form: Form tagba zárja az űrlapelemeket
  • HtmlTag: Html tag-et ír az űrlapelemek elé és mögé. Ha a prepend vagy az append paramétert használjuk, akkor az elem elé vagy mögé teszi a tartalmat. Ha openOnly=true vagy closeOnly=true paramétert használunk, akkor a tag-nek csak a nyitó vagy zárótagját teszi ki.
  • Image: render a form image based on the current element
  • Label: Egy elem címkéjét jeleníti meg (előre alapértelmezetten)
  • ViewHelper: Ha van, akkor az elemhez tartozó helpert hívja meg. (azt, amit az elem helper tulajdonságába írtunk).
  • ViewScript: Magát az elemet jeleníti meg. 

Hogyan írhatunk saját decorator osztályt?

Minden decoratornak az alábbi metódusokkal kell rendelkeznie, vagyis ez az interface kell.

interface Zend_Form_Decorator_Interface
{
    public function __construct($options = null);
    public function setelement($element);
    public function getelement();
    public function setOptions(array $options);
    public function setConfig(Zend_Config $config);
    public function setOption($key, $value);
    public function getOption($key);
    public function getOptions();
    public function removeOption($key);
    public function clearOptions();
    public function render($content);
}

A Zend_Form_Decorator_Abstract minden decoratorok ősatyja, a render() kivételével az összes metódust szállítja nekünk, tehát a mi osztályunk csak terjessze ki az abstract metódust és készítsünk hozzá rendert!

class My_Form_Decorator_Foo extends Zend_Form_Decorator_Abstract
{
    public function render($content)
    {
        // ...
        return $content
    }
}

Ha egy olyan decoratort szeretnénk írni, amely tetszőleges tartalmat tesz ki, akkor az alábbi kódom alapján ezt meg lehet írni:

require_once ('Zend/Form/Decorator/HtmlTag.php');
class Fz_Form_Decorator_Html extends Zend_Form_Decorator_Abstract
{ 
    /**
     * Saját Render függvény tetszőleges tartalom kiiratására egy ?rlapelem elé vagy mögé
     * @see Zend_Form_Decorator_HtmlTag::render()
     */
    public function render($content)   
    {
     $separator = $this->getSeparator();
     $this->setOption('tag','');
     $s = $this->getOption('html');
     $this->removeOption('html');
    
      $placement  = $this->getPlacement();
     
     if($placement == self::PREPEND){
      $content = $s . $separator . $content;     
     }else{    
      $content .= $separator. $s ;
     }
     return $content;
    }
}

Ezzel a decoratorral a placement paramétert meghívva prepend tartalommal => az űrlapelem elé tudunk tetszőleges tartalmat tenni, alapesetben az űrlapelem mögé lehet tetszőleges tartalmat tenni.

Használata például:

$element->addDecorator(array("aliasnev" =>'Html'),
   array(    
      'placement' =>Zend_Form_Decorator_Abstract::APPEND,    
      'html' => "Valami html tartalom"
  ));:

Sajnos a HtmlTag decorator erre azért nem jó, mert a tag paraméterbe beírt adatokat "tisztítja", azaz kivesz minden nem alfanumerikus karaktert és csupa kisbetűvé alakítja.

Arra felhívom a figyelmet, hogy a rosszul megírt APPEND és PREPEND decoratorok könnyen galibát okozhatnak a böngésző megjelenítésében.

Ha HtmlTag decoratort használunk, akkor tartózkodjunk a megjelenítés formai részének bekódolásától, inkább csak div-eket és egyéb kontent jelleg? tartalmat írassunk ki esetleg is és esetleg class attribútummal, és a formázást css-ből intézzük el.

Az eredeti cikket itt találtam: http://devzone.zend.com/article/3450. Ennek alapján értettem meg a decorator-ok működését.