Autor Zpráva
vddv
Profil *
Zdravím,

momentálně se snažím pořádně naučit PHP objektově, a jelikož mám nejraději učit se na něčem za chodu, snažím se napsat univerzální tvorbu formulářů, s následnou validací. Zatím mám uděláno pouze tvorbu formulářových Inputů a následné přidělené vlastních validačních pravidel.

Chtěl bych od vás proto radu, jestli na to jdu vůbec aspoň trochu dobře, abych pak nezjistil, že jsem se celou dobu učil psát OOP špatným způsobem. Proto děkuji za prolouskání mého kódu a udělení nějaký rad, zda-li je kód vůbec použitelný.

Díky.

PHP kód:
<?php

class Forms {
  
  /* 
   * Defaultni nastaveni pravidel pro vsechny formularova data 
   * Tyto data muzete pote libovolne upravovat, viz funkce teto tridy zvana 'add_rule'
   * 
   */
  public $rules = Array ( "DEFAULT" => Array ( "MAXLENGHT" => "20", 
                                               "MINLENGHT" => "10",
                                               "REQUIRED" => TRUE )
                        ); 
  /* Funkce umoznujici nastaveni pravidel pro formularova data 
   * Nastaveni se zapisuje ve tvaru:
   *  
   * AddRule ( "PRAVIDLO", "HODNOTA" ) 
   * popripade vicenasobne pridani pravidel:
   * AddRule ( "PRAVIDLO_1", "HODNOTA_1", "PRAVIDLO_2", "HODNOTA_2", atd... )
   *  
   */
  public function AddRule( $rules ) {
    $rules = func_get_args(); 
    foreach($rules as $key => $value) {
      if($key % 2 == 0) $this->rules["USER_DEFINED"][$value] = isset($rules[$key++]) ? $rules[$key++] : null; 
    }
    $this->rules[$this->id] = array_merge( $this->rules["DEFAULT"], $this->rules["USER_DEFINED"] );
    return $this;   
  }
  
  /* ADD CHILD
   * 
   * Funkce dostava vygenerovany formularovy input a formularovy label, ktery spoji a vypise na obrazovku vysledny formularovy prvek
   * 
   */
  public function AddChild( $control, $label ) {
    echo $label -> label . $control -> form;
  }
/* ADD TEXT INPUT
 * 
 * Funkce dovoluje vytvorit formularovy prvek typu - <input type="text" />
 * 
 * Pri vytvareni tridy predame pomoci parametru vsechny mozne nastaveni, ve tvaru:
 * AddTextInput ( $name, $label, $value, $cls, $id )
 * Tedy napr.:
 * AddTextInput ( "username", "Uzivatelske jmeno", "Zadejte uz. jmeno", "usernam_trida", "username_id" );
 * 
 * Tyto informace predame tride TextInput, ktera vygeneruje vysledny formularovy input
 * Dalsi doplnujici info predame tride Label, ktera nam vygeneruje vysledny LABEL ve tvaru <label for="id"> $label </label>
 * Vysledek spojime pomoci funkce AddChild a konecny formularovy prvek vypiseme
 * 
 */
  public function AddTextInput( $name = NULL, $label = NULL, $value = NULL, $cls = NULL, $id = NULL ) {
    if ( $id == "" ) { $id = $name; }
    $this -> id = $id;
    $control = new TextInput( $type = "text", $name, $value, $cls, $id );
    $label = new Label ( $label, $id );
    $this -> AddChild( $control, $label );
    return $this;
  }

/* ADD PASSWORD INPUT
 * 
 * Totozna jako funkce AddTextInput
 * 
 */
  public function AddPasswordInput( $name = NULL, $label = NULL, $value = NULL, $cls = NULL, $id = NULL ) {
    if ( $id == "" ) { $id = $name; }
    $this -> id = $id;
    $control = new TextInput( $type = "password", $name, $value, $cls, $id );
    $label = new Label ( $label, $id );
    $this -> AddChild( $control, $label );
    return $this;
  } 

/* ADD EMAIL INPUT
 * 
 * Totozna jako funkce AddTextInput
 * 
 */
  public function AddEmailInput( $name = NULL, $label = NULL, $value = NULL, $cls = NULL, $id = NULL ) {
    if ( $id == "" ) { $id = $name; }
    $this -> id = $id;
    $control = new TextInput( $type = "text", $name, $value, $cls, $id );
    $label = new Label ( $label, $id );
    $this -> AddChild( $control, $label );
    return $this;
  } 
  
 /* ADD SUBMIT INPUT
 * 
 * Totozna jako funkce AddTextInput
 * 
 */
  public function AddSubmitInput( $name = NULL, $label = NULL, $value = NULL, $cls = NULL, $id = NULL ) {
    if ( $id == "" ) { $id = $name; }
    $control = new TextInput( $type = "submit", $name, $value, $cls, $id );
    $label = new Label ( $label, $id );
    $this -> AddChild( $control, $label );
    return $this;
  } 
  
}

/* TEXT INPUT
 * 
 * Trida dostava pomoci parametru uzivatelsky definovane informace o formularovem inputu
 * A nasledne z nej sklada dany formularovy prvek a predava zpet
 * 
 */
class TextInput extends Forms {
  public function __construct( $type, $name, $value, $cls, $id ) {
    $this -> form = '<input type="'.$type.'" name="'.$name.'" value="'.$value.'" class="'.$cls.'" id="'.$id.'" onChange="validate(this)" />'."\n" . '<div class="validate_input" id="'.$id.'_validate"></div>'."\n"; 
  }
}

/* LABEL
 * 
 * Trida dostava pomoci parametru uzivatelsky definovane informace o formularovem labelu
 * A nasledne z nej sklada dany formularovy label a predava zpet
 * 
 */
class Label extends Forms {
  public function __construct( $label, $id ) {
    if ( $label != "" ) $this -> label = "\t".'<label for="'.$id.'">'.$label.'</label>';
    else $this -> label = "";
  }
}

?>


HTML Vytváření formulářů, příklad:
$forms = new Forms();
$forms -> AddTextInput("username", "Vase jmeno", "Vlozte sve jmeno", "input_cls", "input_id") -> AddRule( "MAXLENGHT","50" );
$forms -> AddPasswordInput("password", "Vase heslo", "Vlozte sve heslo", "cls", "id") -> AddRule(" MAXLENGHT","40" );
$forms -> AddEmailInput("email", "Email:", "Vlozte svuj email", "cls", "id") -> AddRule( "MAXLENGHT","40", "MINLENGHT","30" );
$forms -> AddSubmitInput("submit", "", "ODESLAT", "submit_cls", "submit_id");
Majkl578
Profil
Pokud jde kód samotný:
a) Coding standard je nejednotný, působí nepřehledně a místy zmatečně.
b) Komentáře nad metodami a třídami nejsou PHPDoc, ty začínají /**.


Pokud jde o objektový návrh, je v podstatě celý špatně. Některé klíčové věci v bodech:
a) Je zpatláno vykreslení formuláře s logikou samotnou. Chybí jakákoliv abstrakce.
b) Je přeci naprostý nesmysl, aby např. TextInput nebo Label dědily od Forms, samy formulářem nejsou. Natož stavět Label a TextInput na stejnou úroveň. Copak dává smysl, aby Label mělo validace?
c) Názvy validačních pravidel by měly být třídní konstanty.
d) Metoda AddRule se chová nečekaně a nesmyslně. Měla by přidávat přesně jedno pravidlo. Navíc má být vázaná na konkrétní control formuláře, ne na formulář samotný.
e) Vlastnost $rules má divnou, nelogickou a nepředvídatelnou strukturu. A rozhodně nemá být public.
f) Metoda AddChild by měla být private, jelikož neposkytuje API třídy. Nicméně její chování je stejně nežádoucí (viz bod a).
g) Metody Add*Input mají nelogicky strukturované argumenty. Nebo snad dává smysl, aby existovalo nějaké políčko bez názvu?
h) Třída TextInput nemá dědit od Forms. Nejen že to nedává smysl, ale dokonce to způsobuje naprostou nelogičnost jejího API (viz přidávání dalších prvků pod sebe sama). Zároveň dělá nežádoucí generování HTML kódu.
i) Třída Label trpí v podstatě stejnými neduhy jako třída TextInput.
j) Chválihodné je, že API nabízí fluent přístup (vracení $this).


Pro začátek, jak to vylepšit:
a) Upravit kód:
i.) Celý jej přepsat, restrukturovat a zanést větší a lepší míru abstrakce.
ii.) Oddělit vykreslení formuláře od jeho sestavování.
iii.) Udělat z formuláře vesměs jen kontejner svých prvků
iv.) Zamyslet se a předělat vytváření a správu políček formuláře, zároveň jim dát logické API. Rozhodně kompletně oddělit od formuláře (viz současné dědění od něj).

b) Vykašlat se na vlastní řešení a použít nějaké kvalitní, již existující, např. Nette Frameworku.
kolemjdoucí
Profil *
Majkl578:
Možná to je off topic, ale jak se pak máme (také se učím oop naučit oop když použijeme již hotové řešení?
Majkl578
Profil
kolemjdoucí:
Myslím si, že studováním kvalitního (= správně navrženého a implementovaného) již existujícího řešení získáš mnoho znalostí. A dost možná víc, než trápením se nad svým kódem, o kterém se budeš subjektivně domnívat, že je již nevylepšitelný.

Nicméně rozlišoval bych přinejmenším dva druhy znalosti OOP:
1. Teoretická a praktická znalost OOP v daném jazyce. Chápat jej a umět jej používat. K naučení se tohoto se právě skvěle hodí již existující (ale zároveň relativně jednoduché) kvalitní knihovny. Jedním z příkladů budiž dibi. Nette Framework už tak jednoduchý není, nicméně kvalitní uživatelská základna usnadňuje křivku učení a zároveň je stále jednodušší než jiné kvalitní a robustní frameworky (např. Symfony 2).
2. Schopnost navrhnout aplikaci (popř. její část) objektově tak, aby návrh jako celek dával smysl. To samozřejmě pro začátečníka v oblasti OOP není jednoduché a vyžaduje určitou míru teorie (např. základní druhy používaných návrhových vzorů, ale i určité analytické myšlení).
kolemjdoucí
Profil *
Majkl578:
Ano, s tím souhlasím, ale dost často cítím potřebu zkusit si něco vlastního (většinou již existujícího) napsat a vyzkoušet tak samotné oop bez fw. Párkrát jsem zkoušel i svůj "framework" (samozřejmě, že zůstane naspodu mého hardisku :D) a je to pokus od pokusu lepší, ale pořád nejsem se svýma návrhama spokojen a nevím, jak se posunout dál. Cizí zdrojové kódy zkoumám a procházím. Nemáš ještě nějakou radu jak se zdokonalit v objektovém návrhu?
Ugo
Profil
Já bych to neviděl tak černě jako Majkl, sem konzervativní a důležité pro mě je jen to jestli věc funguje, jeslti funguje dobře, rychle, žere málo paměti, je přehledná a jednoduchá. Za mě tedy nedává moc smysl dělit formulář na 50 druhů objektů, když pominu náročnost a více práce při používání, tak už by to chtělo i namespace nebo pořádný prefixy, jelikož takový množství tříd se bude jednou prát s uživatelovo kódem. Vzhledem k tomu, že v 99% pracuju na serverech kde je PHP 5.2, tak namespace nepřipadá v úvahu, takže zend style. Co s emi nelíbí je systém parametrů, je málo flexibilní a je jich moc, takže to je věčné nahlížení do dokumentace. Já bych to naopak více sjednotil.

K čemu se ještě přikláním je nelogicky použitá dědičnost, nemá ani logický ani funkční význam.

btw. nebylo by opravdu hezčí psát ...
$form->AddTextInput('nazev',array('id'=>'nazev','class'=>'longtext'))->label('Zadej nazev')->AddRule('Nezadali jste nazev','REQUIRED');
echo $form;
if($form->validate()) {};
... trochu jednoduchosti to chce :)

osobně se mi třeba formuláře v nette nelíbí, umí všechno, po "systematické" stránce jsou dokonalé, ale používání mě třeba nevyhovuje, je to jistě otázka zvyku, ale než napíšu v nette 1 základní formulář, tak jinde mám hotovo včetně všeho kolem.

kolemjdoucí:
proč zůstává vespod harddisku? Ne všechny FW musí být kolosy. konkrétně proč používat (oproti konkurenci velice rychlé) Nette někde kde mi můj FW usnadní práci z hodin na minuty a přitom to poběží 10x rychleji a vím co to dělá. Učit se je samozřejmě dobré, zbytečné je aby na každého programátora existoval vystavený FW totožný s těmi ostatními :)

PS. konkrétně v jádru FW mě vůbec nezajímá jak funguje, je to věc která je naprosto zbytečná, jediné co má FW dělat je zlehčovat práci a přitom neubírat možnosti - nenastavovat vlastní systém : musí to být takto, i když v PHP existuje 100 dalších možností.

Vaše odpověď

Mohlo by se hodit

Odkud se sem odkazuje


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: