Tag Archives: zend framework

webmastering

Własny walidator w Zend Framework

Dzisiaj będzie coś dla wiel­bi­cieli Zend Frame­worka. A dokład­niej coś, z czym mamy do czynie­nia prze­twa­rza­jąc jaki­kol­wiek formu­larz, czyli wali­da­tory. Wali­da­cja, a więc spraw­dza­nie czy wpro­wa­dzone przez użyt­kow­nika dane odpo­wia­dają pewnemu sche­ma­towi jest obok filtra­cji, czyli wyrzu­ca­niu zbędnych/niebezpiecznych rzeczy z danych chyba najważ­niej­szą sprawą przy tworze­niu witryn WWW.

Zend Frame­work dyspo­nuje zesta­wem kilku­dzie­się­ciu wali­da­to­rów, które można łączyć w łańcu­chy przy wali­do­wa­niu poszcze­gól­nych pól formu­la­rza, np. pyta­jąc o wiek użyt­kow­nika pole musi zawie­rać wyłącz­nie liczby, czyli aż prosi się o Zend_Validate_Digits, a następ­nie należy spraw­dzić czy podana liczba znaj­duje się w jakimś ludz­kim prze­dziale, tzn. powiedzmy pomię­dzy 1 a 100, co zała­twi za nas Zend_Validate_Between.

Co w przy­padku jeżeli musimy dopa­so­wy­wać coś, czego nie prze­wi­dzieli twórcy ZF? Możemy napi­sać własny walidator.

Każdy wali­da­tor musi imple­men­to­wać inter­fejs Zend_Validate_Interface, czyli dwie publiczne metody:

  • isValid($value) — zwra­ca­jąca buliona prawda/fałsz
  • getMessages() — zwra­ca­jąca tablicę komu­ni­ka­tów co jest nie tak z warto­ścią testo­waną w isVa­lid(). Komu­ni­katy zwra­cane są w postaci kod_błędu => komunikat_w_ludzkiej_formie

W celu unik­nię­cia babra­nia się obsługą błędów i komu­ni­ka­tów twórcy ZF stwo­rzyli abstrak­cyjną klasę Zend_Validate_Abstract, która zrobi za nas więk­szość brud­nej roboty. Pozo­sta­nie nam tylko napi­sa­nie właści­wej logiki co ma być spraw­dzane i ewen­tu­al­nie jaki błąd zgłaszany.

Na potrzeby swojej apli­ka­cji napi­sa­łem własny w miarę uniwer­salny wali­da­tor, który spraw­dzi czy klucz podsta­wowy danej tablicy istnieje. Może mieć zasto­so­wa­nie jeżeli ktoś spraw­dza czy np. iden­ty­fi­ka­tor wybra­nej przez użyt­kow­nika kate­go­rii istnieje w bazie.

Poni­żej przed­sta­wiem kod z obja­śnie­niami po co coś jest. Po prze­czy­ta­niu stwier­dzi­cie, że pisa­nie wali­da­to­rów to fajna zabawa :-)

<?php
// rozszerzamy klasę abstrakcyjną dla walidatorów
class Spiechu_Validators_IsIdExists extends Zend_Validate_Abstract {     
 
  // definiujemy kody błędów i jakieś wartości dla nich
  const IDNOTEXISTS = 'idnotexists';
  const EMPTYSTRING = 'emptystring';
  const NULLVALUE = 'nullvalue';
 
  // definiujemy tablicę komunikatów błędów dla poszczególnych kodów
  // zwracam uwagę na '%value', które może być w locie zamienione na sprawdzaną wartość
  protected $_messageTemplates = array(
    self::IDNOTEXISTS   => "id '%value%' not exists",
    self::EMPTYSTRING  => 'given value is empty',
    self::NULLVALUE     => 'given value is null'
  );
 
  // zmienna typu Zend_Db_Table_Abstract, której klucz będziemy testować
  protected $_table;
 
  public function __construct(Zend_Db_Table_Abstract $table) {
    $this->_table = $table;
  }
 
  public function isValid($value) {
 
    // sprawdzamy czy zmienna nie jest nulem, a jeżeli tak to ustawiamy błąd
    if ($value === null) {
      $this->_error(self::NULLVALUE);
      return false;
    }
 
    // to samo dla pustego stringa
    if ($value === '') {
      $this->_error(self::EMPTYSTRING);
      return false;
    }
 
    $value = (int) $value;
 
    // ustawiamy wartość dla ewentualnego komunikatu %value%
    $this->_setValue($value);
 
    // metoda find szuka po kluczu podstawowym i zwraca rowset wyników
    $foundRows = $this->_table->find($value);
 
    // jeżeli nic nie znaleziono tzn. że sprawdzany klucz nie istenieje w tabeli bazy
    if (count($foundRows) == 0) {
      $this->_error(self::IDNOTEXISTS);
      return false;
    }
    else {
      return true;
    }
  }
}

Wszystko działa na tyle auto­ma­gicz­nie, że tworząc jakiś element formu­la­rza wystar­czy dodać stwo­rzony wali­da­tor np. tak:

$formElement = new Zend_Form_Element_Select('pole_formularza');
$formElement->setRequired(true)
  ->setLabel('Jakaś etykieta')
  ->setMultiOptions($dane_do_wyboru)
  ->addValidator(new Spiechu_Validators_IsIdExists(new Sprawdzana_Tabela()));
webmastering

Standardy kodowania zgodne z Zend, cz. 3/3

Dzisiaj ostatni wpis doty­czący progra­mo­wa­nia zgod­nego z Zend. Będzie mowa o doku­men­ta­cji. Sporo infor­ma­cji będzie pocho­dziło z Czystego Kodu [dalej CK].

Przede wszyst­kim bloki doku­men­ta­cji muszą być zgodne z forma­tem phpDo­cu­men­tor, czyli
/**
* Coś tam dokumentuję...
*/

Współ­cze­sne IDE nie mają problemu z pilno­wa­niem zgod­no­ści z tym forma­tem. Wpisu­jesz /** naci­skasz Enter i masz ładny blok doku­men­ta­cji. Drugi sposób to wszyst­kim znane komen­ta­rze inline tworzone poprzez // przed treścią komentarza.

Zend Frame­work wymaga od nas umiesz­cze­nia doku­men­ta­cji w trzech miej­scach: na początku pliku, przed każdą klasą i przed każdą metodą. W doku­men­ta­cji ZF podano elementy, które powinny wcho­dzić w skład bloków. Nie będę tego powta­rzał. Zwrócę uwagę tylko na to, że typy para­me­trów i warto­ści zwra­cane przez funk­cje są również obligatoryjne.

Więk­szość komen­ta­rzy jest zła. Im szyb­ciej to przy­zna­cie tym lepiej. :-) Zgod­nie z CK komen­ta­rze w więk­szo­ści służą nam do wytłu­ma­cze­nia się z błędów/niedoskonałości naszego kodu. Kod powi­nien być na tyle przej­rzy­sty, żeby komenty nie były wcale potrzebne. Czas poświę­cany na pisa­nie doku­men­ta­cji lepiej prze­zna­czyć na poprawki kodu. Łatwo rzucać slogany, trud­niej zrobić. Na pozio­mie jednej klasy często dobry efekt udaje się uzyskać poprzez rozpar­ce­lo­wa­nie długiej funk­cji na kilka mniej­szych i użycie bardziej opiso­wych nazw.

Wielce niewska­zana jest redun­dan­cja, czyli nadmia­ro­wość infor­ma­cji. Jeżeli nazwa funk­cji jest wystar­cza­jąco znacząca to rzeczy­wi­ście nie ma sensu powta­rzać tego samego. Raz, że uczy nas podświa­do­mego pomi­ja­nia doku­men­ta­cji (no bo po co coś czytać skoro jest oczy­wi­ste?), a dwa, że komen­ta­rze często nie nadą­żają za zmia­nami w kodzie. Stary koment smro­dzi bardziej niż jego brak :-) O ile CK doty­czy Javy, a więc silnie typo­wa­nego języka (zawsze wiemy jakiego typu jest zmienna czy para­metr i co zwraca metoda), o tyle w PHP musimy używać doku­men­ta­cji do tego celu. Autor CK często daje znać, że jeżeli kod jest jasny to po co go komentować?

Sporo rzeczy robi za nas system kontroli wersji. Unikamy brzyd­kiego komen­to­wa­nia już niepo­trzeb­nego kodu oraz nie kusi nas wpro­wa­dza­nie dzien­nika zmian do komen­ta­rzy. W razie potrzeb oglą­damy sobie starą wersję pliku lub czytamy tekst z commitu. Osobi­ście używam Baza­ara do swoich projek­tów (mini­mum usta­wia­nia, dostępny pod Windows i Linux).

Dobry komen­tarz to np. wyróż­nie­nie rzeczy pozor­nie nieistot­nej, infor­ma­cja co jest jesz­cze do zrobie­nia (tzw. TODO) lub też przy­kład dopa­so­wa­nia wyra­że­nia regu­lar­nego. Przy­datne jest również stwo­rze­nie porząd­nego API publicz­nego (wyobra­ża­cie sobie napi­sać cokol­wiek w Javie bez API?)

webmastering

Standardy kodowania zgodne z Zend, cz. 2/3

W drugiej części napi­szę co nieco na temat nazew­nic­twa klas i metod. Jak nazy­wać i czego unikać. Do tego na koniec dodam kilka zale­ceń Roberta C. Martina z Czystego Kodu.1

Klasy

Skład­ni­kiem nazwy klasy nie powi­nien być żaden czasow­nik. Mało tego, nie powi­nien to być również frag­ment nazwy imple­men­to­wa­nego inter­fejsu lub klasy nadrzęd­nej. Stosu­jemy Camel­Case począw­szy od dużej litery. Zgod­nie z Czystym Kodem lepsza jest dłuż­sza nazwa klasy/metody niż krót­sza plus komen­tarz wyjaśniający.

W przy­padku progra­mo­wa­nia zgod­nego z Zend nale­ża­łoby nazwę poroz­dzie­lać podkreśl­ni­kami prowa­dzą­cymi przez struk­turę kata­lo­gów do pliku zawie­ra­ją­cego kod klasy, np. Zend_File_Transfer_Adapter_Http

Pola klas

Krót­kie nazwy zmien­nych typu $i, $j dopusz­czalne są tylko w pętlach lub zmien­nych lokal­nych. Pola klasy również nazy­wamy zgod­nie z Camel­Case z tym, że rozpo­czy­namy od małej litery. Warte zwró­ce­nia uwagi jest to, że pola i metody prywatne w klasie rozpo­czy­nają się od znaku podkre­śle­nia, dzięki czemu od razu widać czy odwo­łu­jemy się do metody publicz­nej czy prywatnej.

Nazwę stałych tworzymy wyłącz­nie za pomocą dużych liter i podkreśl­ni­ków. Poni­żej przy­kład wzięty z Zend_Filter
const CHAIN_APPEND  = 'append';
const CHAIN_PREPEND = 'prepend';

Metody

Przy­jęło się kilka konwen­cji jeżeli chodzi o nazew­nic­two metod. Metody muta­to­rów (tzw. settery) i akce­so­rów (tzw. gettery), czyli usta­wia­jące i pobie­ra­jące zmienne obiektu tworzymy poprzez setNazwa($nazwa)getNazwa().

Innymi powszech­nie znanymi meto­dami są isNazwa()hasNazwa(). Czyli czy obiekt jest czymś lub czy obiekt ma jakąś własność. Muszą one zwra­cać wartość typu boolean.

Pamię­tamy o tym, że PHP oferuje ogra­ni­czone typo­wa­nie para­me­trów. A w tym zakre­sie, jakie oferuje należy je stoso­wać, czyli możemy wymu­sić, że przyj­miemy tylko obiekt okre­ślo­nego typu lub imple­men­tu­jący okre­ślony inter­fejs, czyli np. metoda(Trąbka $trąbka) wymusi nam, że obiekt musi być typu Trąbka. Niestety typów prostych typu int czy bool nie możemy wymu­sić. Zamiast tego pamię­tamy zazna­czyć typ w dokumentacji.

W Zend powszech­nie stoso­wany jest rozdział tworze­nia obiektu od jego inicja­li­za­cji za pomocą metody init(). Jeżeli na etapie tworze­nia obiektu coś się wysy­pie i konstruk­tor wyrzuci wyją­tek, obiekt nie zosta­nie utworzony.

Poni­żej kilka zale­ceń z Czystego Kodu doty­czące metod:

  • metoda powinna zajmo­wać do ok. 20 linii kodu,
  • powinna wyko­ny­wać jedną operację,
  • metoda bez para­me­trów jest zawsze lepsza niż z jednym,
  • dopusz­czalne jest do 3 para­me­trów w meto­dzie; jeżeli jest więcej tzn. że gdzieś popeł­ni­li­śmy błąd,
  • para­metr true/false najczę­ściej ozna­cza, że metoda robi dwie różne rzeczy i najle­piej rozdzie­lić ją na dwie osobne,
  • doda­wa­nie „na pałę” do każdego pola prywat­nego settera i gettera mija się z celem (po co było usta­wiać zmienną na private skoro i tak można robić z nią co się chce poprzez settery/gettery),
  • bloków try/catch nie należy mieszać z normal­nym prze­twa­rza­niem, należy je wydzie­lić do osob­nych funk­cji jako mają­cych za zada­nie obsługę błędów
  1. R. C. Martin : Czysty Kod. Gliwice : Helion, 2010