O walidacji słów kilka

W dyskusji pod wpisem na blogu Matiego poruszyłem temat „walidatorów” w kontekście komponentu Zend Form w Zend Frameworku i tego, że mam zastrzeżenia co do ich koncepcji. Żeby być precyzyjnym nt. przedmiotu o którym będę się rozwodził pozwolę sobie po pierwsze odpowiedzieć na pytanie – czym jest walidacja ?

Otóż słowo walidacja, jest spolszczeniem angielskiego czasownika „to validate”, który pochodzi od rzeczownika „valid”. „Valid” oznacza po prostu „poprawny”, a więc intuicyjnie „walidacja” to sprawdzanie poprawności. W przypadku oprogramowania walidacja, oznacza sprawdzenie poprawności danych w kontekście aplikacji, w której są one wykorzystane.

Najpowszechniejsze zastosowanie walidacji w aplikacjach opartych na ZF ma miejsce przy wszelkiego rodzaju formularzach. Zwykle w akcji kontrolera tworzony jest obiekt formularza potrzebnej klasy, w którym do kolejnych jego elementów „przypięte” są walidatory. Gdy wystąpi interesujące nas zdarzenie, zwykle jest nim wysłanie formularza metodą „POST”, następuje przekazanie danych do formularza, który sprawdza ich poprawność. Następnie dane są z niego wyciągane i przekazywane do jakiegoś modelu, który już zajmuje się nimi dalej.

Taki typowy flow prezentuje poniższy kod:

class Article_Form extends Zend_Form {

	public function init(){

		$oTitle = new Zend_Form_Element_Text('title');
		$oTitle->addValidator(new Zend_Validator_NotEmpty);

		$this->addElement($oTitle);
//...inne elementy
	}

}

class ArticleController extends Zend_Controller_Action {

	public function createAction(){

		$oForm = new Article_Form();
		if($this->_request->isPost()){
				$aPost = $this->_request->getPost();
				if($oForm->isValid($aPost)){
					$oArticleTable = new Article_Table;
					$oArticleTable->insert($oForm->getValues());

					$this->_redirect('/somepage');
				}

		}
		$this->view->form = $oForm;
	}

//... inne metody

}

Rozwiązanie to świetnie się sprawdza, gdy całe działanie naszej strony sprowadza się do operacji typu CRUD (Create Retrieve Update Delete). Typowym przykładem takiej aplikacji jest dowolny blog, czy prosty firmowy CMS.

Problem z tego typu walidacją pojawia się wtedy, kiedy nasza aplikacja zaczyna robić się skomplikowana. Klient potrzebuje zaimplementować złożona logikę biznesową i działanie naszego softu nie sprowadza się już do przeprowadzania podstawowych operacji na bazie danych. Zadania jakie są przed nim postawione wymagają dogłębnej znajomości procesów biznesowych klienta.

Uczestniczyłem w takim projekcie (ecommerce) dla dużego hurtowego dostawcy artykułów papierniczych. Możecie mi wierzyć albo i nie, ale zamówienie długopisu albo żółtych samoprzylepnych karteczek może być bardzo skomplikowanym procesem, w którym zaangażowane jest kilka osób/użytkowników systemu.

Wróćmy jednak do meritum, czyli naszych walidatorów. Co jest nie tak z kodem, który został zaprezentowany wcześniej ? Otóż wraz ze wzrostem złożoności warunków, które spełniać ma flow naszego kodu, rośnie jego zależność od kontekstu w jakim zostaje wykonywany. Niestety okazuje się, że walidatory, którymi możemy sprawdzać poprawność pojedynczego pola przestają wystarczyć. Oczywiście można napisać taki walidator, który sprawdza poprawność pola w kontekście innych pól naszego formularza. Można też napisać walidator, który sięgnie do bazy danych by sprawdzić jakieś dodatkowe informacje. Zawsze jednak koniec końców, kończymy z wielką zagmatwaną siecią if-ów.

Stosując taką strategię walidacji dorobimy się całego wianuszka walidatorów albo też alternatywnie zaczniemy przenosić część walidacji do akcji kontrolera. Jeżeli jeszcze dodatkowo chcemy wykorzystać dany formularz w innym miejscu systemu, gdzie wygląd formularza jest taki sam, natomiast kontekst jest trochę inny, dołożymy kolejne „ify” i skończymy z nieczytelnym i nierozwiązywalnym węzłem gordyjskim.

Raz już spotkałem się z taką sytuacją i jako, że pośrednio sam się do niej przyczyniłem, postanowiłem poszukać jakiegoś rozwiązania, które pozwoli mi uniknąć takiej sytuacji w przyszłości. Po wielu poszukiwaniach w internecie trafiłem na metodykę DDD (Domain Driven Design). DDD proponuje rozwiązanie opcji walidacji w bardzo elegancki sposób.

Całą idee przestawię prosto na przykładzie aplikacji do rejestrowania pacjentów w placówkach polskiej tzw. „służby zdrowia”.

Encją jak wiemy z moich poprzednich wpisów jest taka klasa obiektów, które mają własną tożsamość. Pacjent bez dwóch zdań tożsamość ma a więc będzie się do nich zaliczał. Value object w naszym przykładzie, będzie to numer PESEL, który unikanie identyfikuje nam pacjentów. Natomiast usługą będzie klasa „RejestrPacjentów”, która jak nazwa mówi, będzie służyła nam do rejestracji pacjentów na wizyty czy też zabiegi. Spójrzmy na kod:

Klasa Pacjent (encja):


class Pacjent {

    private $_pesel;
    private $_firstName;
    private $_lastName;
    private $_birthDate;

    public function __construct(Pesel $pesel, $firstName, $lastName, DateTime $birthDate){
        $this->_pesel = $pesel;
        $this->_setName($firstName, $lastName);
        $this->_birthDate = $birthDate;
    }

    private function _setName($firstName, $lastName){
        //walidacja
    }

    public function pesel(){
        return $this->_pesel;
    }

    public function firstName(){
        return $this->_firstName;
    }

    public function lastName(){
        return $this->_lastName;
    }

    public function lastVisit(){
        //kod
    }
}

Klasa Pesel (Value Object):


final class Pesel {

    private $_pesel;

    public function __construct($pesel){
        //walidacja
        $this->_pesel = $pesel;
    }

    public function  __toString() {
        return $this->_pesel;
    }
}

Klasa RejestratorPacjentow (Usługa):


class RejestratorPacjentow {

    public function zarejestrujWizyte(Pacjent $pacjent, Lekarz $lekarz, DateTime $data){
        //walidacja
    }

    public function zarejestrujZabieg(Pacjent $pacjent, Zabieg $zabieg){
        //walidacja
    }

    public function sprawdzTerminy(DateTime $data){

    }
}

Mamy już cały zarys kodu. Po pobieżnej analizie, pierwsze co rzuca się w oczy to wszechobecne typowanie argumentów funkcji. Dlaczego taki zabieg został zastosowany ? Metodyka DDD mówi, że obiekty występujące w domenie, zawsze powinny mieć poprawny swój wewnętrzny stan, co oznacza, że nie będą akceptować żadnych danych, które nie są poprawne w ich kontekście. Dzięki temu mamy gwarancję, że jeżeli utworzymy nowy obiekt klasy „Pacjent” to będzie on zawsze „valid”.

Przyjrzyjmy się klasie „Pesel”. W konstruktorze zaznaczyłem, że przed ustawieniem swojej wartości następuje walidacja, czy string który jest podany jako argument jest poprawnym numerem PESEL. Jeżeli nie to powinien wyrzucony być wyjątek.

Walidacja występuje również w metodach klasy RejestratorPacjentow, która jak to w przypadku usług bywa nie posiada żadnego wewnętrznego stanu, dlaczego tak jest ? Otóż możliwe jest, że oprócz tego, że obiekty przekazane do metody są wewnętrznie poprawne, to występuje jakiś dodatkowy kontekst operacji, który ma zostać sprawdzony. Natomiast w tych metodach w przeciwieństwie do walidacji w encjach i vo nie zostanie wyrzucony wyjątek, lecz metoda zwróci błąd w postaci czy to tekstowej czy jakiejś tablicy/obiektu z jego szczegółami.

Jak z powyższych „klocków” złożyć działająca aplikację ? Jak mają się one do formularzy oraz informowania użytkowników o błędach? Zilustruje to poniższy kod:

Kontroler:


class RejestratorController extends Zend_Controller_Action {

    public function nowyPacjentAction() {
        $oForm = new Pacjent_Form;

        if($this->_request->isPost()) {
            $aPost = $this->_request->getPost();

            $oFacade = new PrzychodniaFacade;
            $aErrors = $oFacade->nowyPacjent($aPost);

            $oForm->setErrors($aErrors);
        }

        $this->view->form = $oForm;
    }

    public function zarejestrujWizyteAction() {
        $oFacade = new PrzychodniaFacade;
        $oForm = new ZarejestrujWizyte_Form;

        $aData = array(
                'pacjenci' => $oFacade->listaPacjentow(),
                'lekarze' => $oFacade->listaLekarzy()
        );

        $oForm->populate($aData);
        if($this->_request->isPost()) {
            $aPost = $this->_request->getPost();
            $aErrors = $oFacade->zarejestrujWizyte($aPost);
            $oForm->setErrors($aErrors);
        }

        $this->view->form = $oForm;
    }
    //inne metody
}

Fasada:


class PrzychodniaFacade {

    //inny kod

    public function listaPacjentow(){
        return $this->pacjenci->findAll()->toDictionary();
    }

    public function listaLekarzy(){
        return $this->lekarze->findAll()->toDictionary();
    }

    public function zarejestrujWizyte(array $data){
        $oPacjent = $this->pacjenci->find($data['pacjent_id']);
        $oLekarz = $this->lekarze->find($data['lekarz_id']);
        $oDate = new DateTime($data['data']);

        $mResult = $this->rejestrPacjentow->zarejestrujWizyte($oPacjent, $oLekarz, $oDate);
        if(is_array($mResult)){
            return $mResult;
        }
        return array();
    }

    public function nowyPacjent($data){
        try {
            $oPesel = new Pesele($data['pesel']);
            $oBirthDate = new DateTime($data['time']);
            $oPacjent = new Pacjent($oPesel, $data['firstName'], $data['lastName'], $oBirthDate);

            $this->pacjenci->persist($oPacjent);
        } catch(ValidationException $e){
            return $e->toArray();
        }
        //kod
    }
}

Jak widzimy w powyższym przykładzie, Zend_Form również znalazł swoje zastosowanie. Stał się zwykłym komponentem wizualnym, do którego przekazywane są dane w celu prezentacji. Dzięki temu, może być on również wykorzystywany w innych miejscach systemu, ponieważ nie zależy od niego żadna logika aplikacji.

Walidacja następuje natomiast tam, gdzie jest jej miejsce – w modelu, jest ona w końcu częścią logiki aplikacji.

By dopełnić obraz całości – kilka słów o tym, czym i po co jest fasada. Klasa fasady, jest klasą, która rozdziela warstwę kontrolera od warstwy naszej domeny. Jest to swego rodzaju API, by warstwa kontrolera nie musiała być zależna od wielu klas, które występują w naszej domenie, a tylko od jednej, która zajmuje się „tłumaczeniem” z „domenowego” na „kontrolerowy”. Stosowanie fasady ma jeszcze tą zaletę, że dzięki temu, że jej metody przyjmują tylko dane w postaci prostej (tablice i wartości skalarne) nadaje się doskonale by wystawić ją jako web service, zamiast stosowania w kontrolerze.

Podsumowując ten przepastny wpis – zawsze należy dobrać odpowiednie narzędzia do problemu. Klasyczna walidacja przy pomocy Zend_Form sprawdza się gdy mamy do czynienia z prostymi przypadkami. Natomiast, gdy sytuacja robi się złożona, dobrze jest zdecydować się na podejście w stylu DDD, ponieważ jest dużo bardziej czytelniejsze i lepiej odpowiada skali skomplikowanych i dużych aplikacji.

Linki:

  1. singles pisze:

    Widzę, że poruszyłeś tutaj bardzo szeroki temat, pt. „gdzie powinna być przeprowadzana walidacja”. W modelu? W formularzu? W kontrolerze? Czy tak jak w pokazanych przez Ciebie przypadkach w Service bądź ValueObject?
    To wszystko zależy od wybranego podejścia i architektury systemu.

    Natomiast jeśli jednak decyduje się na walidację danych w formularzu (abstrahując już od tego, czy słusznie czy nie), to uważam koncepcja walidacji stosowana w przypadku Zend_Form spełnia swoje zadanie bardzo dobrze.
    Od Ciebie zależy, co chcesz z tymi danymi dalej zrobić.
    Lecz nie zmienia to faktu, że tandem Zend_Form + Zend_Validate wykonał swoje zadanie – dokonał sprawdzenia poprawności danych wg zdefiniowanych reguł.

  2. Zgadzam się z artykułem, ale ja podszedłbym do tematu walidacji w jeszcze inny sposób. Na potrzeby własnych rozwiązań utworzyłem klasę Form, która w podstawowej wersji zapewnia automatyczną walidację formularzy dla operacji CRUD – to można zautomatyzować. Założyłem jednak, że ogólnie formularz jest i powinien być pojmowany jako zbiór pól, które coś znaczą w kontekście danego formularza, dlatego dla każdego z nich mogę rozszerzyć klasę Form i nadpisać metodę validate(), dzięki czemu mogę zarówno wykonać parent::validate() dla sprawdzenia ogólnego (nip, regon, kod pocztowy) jak i dopisać własne reguły „domenowe” dla podanych danych. Formularz, podobnie jak widok, przed wykonaniem walidacji otrzymuje zestaw modeli i danych potrzebnych mu do poprawnego sprawdzenia.

  3. batman pisze:

    Walidacja danych w ZF dobrze spełnia swoje zadanie. Niestety jeśli dane nie pochodzą z formularza, dzieje się to o czym napisałeś, czyli toniemy w bagnie if-ów. Rozwiązałem to w nieco inny sposób, niż przez Ciebie opisany. Stworzyłem coś, co można określić walidacją po stronie modelu, przy czym tak na prawdę dane walidowane są tuż przed zapisaniem ich do bazy. Na szczęście ZF dostarcza gotowe mechanizmy, które to umożliwiają, więc nie było z tym dużo roboty. Za jakiś czas dokładniej opiszę na blogu ten sposób walidacji danych w ZF.

  4. singles pisze:

    Przy zapisywaniu danych do modelu, jeśli chcemy uniknąć walidacji po jego [modelu] stronie, to jedyne rozwiązanie jakie przychodzi mi na myśl, to wymaganie konkretnych obiektów – tak jak to opisane tutaj w przypadku DDD, a nie np. array’a z danymi. Bo nic nie powstrzyma nowego programisty w projekcie przed wstawieniem tam danych niezwalidowanych napisanych z ręki, bądź pobranych z $_POSTa bezpośrednio.

    @batman – odnośnie gotowych mechanizmów – Zend_Filter_Input? :>

  5. @tomasz kowalczyk: też stosowałem to podejście i niestety w przypadku tamtego skomplikowanego systemu nie zdało egzaminu, chociaż nie wykluczam, że w innych przypadkach by działało

    @batman, spotkałem się też z twoim rozwiązaniem i sam je stosowałem robiąc hooka na preSave w Doctrine 1, jednakże zauważ, że nie każda operacja kończy się zapisem do bazy, niektóre kończą się np. komunikacją z web service lub wygenerowaniem pdf-a albo jeszcze w jakiś inny sposób

  6. Tak btw. zastosowanie DDD tutaj ma jeszcze jedną niewątpliwą zaletę – system staje się bardziej spójny wewnętrznie. Łatwiej się jest też połapać w kodzie ponieważ operacje jakie są wykonywane, mają „ludzkie” nazwy.

  7. batman pisze:

    @Wojciech Soczyński
    Dlatego nie nazywam tego „prawdziwą walidacją modelu” 😉

    Niestety PHP nie oferuje obecnie żadnego sensownego sposobu walidowania modelu. Teoretycznie można skorzystać z PHPDoc + refleksja. W praktyce jest to rzeźbienie w wiadomo czym. Musimy poczekać na adnotacje.

  8. Ja bym nie rozróżniał tego na prawdziwą i nieprawdziwą walidację modelu. Oczywiście można zrobić to w sposób niejawny i automatyczny przy pomocy adnotacji. Jednak sposób jawny też ma wiele zalet i nie można powiedzieć wcale, że jest zły. Poza tym nie postrzegał bym walidacji w oderwaniu od innej „logiki biznesowej” bo wg. mnie walidacja jest jej nierozerwalną częścią.

  9. @Wojciech: To podejście zawsze „da radę” – kwestia tego, że projektując już samą warstwę formularzy trzeba wszystko poukładać w systemie tak, żeby pasowało do niej. Dlatego ciężko będzie dostosować inną strukturę do tego sposobu myślenia. Swoją drogą – mógłbyś dać przykład, kiedy własna funkcja walidująca ma problem z sprawdzeniem danych?

  10. @tomasz: to nie jest kwestia tego, że nie da rady. Problem pojawia się np. w momencie, gdy jeden formularz występuje w dwóch kontekstach. Tj. układ formularza jest mniej więcej ten sam, tylko, że w reguły walidacji w kontekście 1 są inne niż w kontekście 2-gim. Prosty przypadek – kiedy użytkownik edytuje swoje dane osobiście, nie może zostawić żadnego pola pustego. Natomiast jeżeli robi to administrator, to ma taką możliwość. Oczywiście ten przypadek jest trywialny do rozwiązania, ale można sobie wyobrazić inne, które nie są i powodują problemy.

  11. Zyx pisze:

    Sprawdzanie poprawności danych to jak najbardziej odpowiedzialność modelu. Model operuje na danych, model powinien zatem wiedzieć, czym są „poprawne dane”.

    Natomiast należy się zastanowić, dlaczego rzeczy takie, jak Zend_Validator w ogóle istnieją. Jak najbardziej zgadzam się, że podejście zaprezentowane we wpisie daje dużą spójność i czytelny kod, ale ma jedną epicką wręcz wadę: beznadziejnie się na jej podstawie buduje interfejs użytkownika. Gdy rzucamy wyjątek, przerywamy normalny bieg programu. Jeśli gdzieś dalej są jakieś błędy, nie zostaną one w ogóle wykryte. Mamy informację tylko o jednym błędzie nawet, jeśli ich jest ze 30. Tymczasem projektując formularze chcielibyśmy, aby w przypadku problemów wymienić wszystkie, i w dodatku najlepiej by podać, jakich pól dotyczą. Niestety w świecie idealnym te dwie rzeczy są nie do pogodzenia. Albo mamy prosty i czytelny kod, albo wypisujemy wszystkie błędy, np. poprzez kompozycję sprawdzarek. W zaprezentowanym rozwiązaniu można próbować przy napotkaniu pierwszego błędu przełączać model w „tryb awaryjny”, w którym mimo wszystko staramy się dalej próbować budowanie kompletnego obiektu tylko po to, by wychwycić jak najwięcej błędów. Niestety, to też zrodzi nam bardzo dużo ifów.

  12. @zyx: pokazany kod to tylko pewien prototyp – koncepcja. Jestem przekonany, że mimo użycia wyjątków, dało by się to jakoś pogodzić z raportowaniem błędów. Można np stworzyć metodę „tryCreate”, która przechwyci wyjątki.

    function tryCreate($className, $arguments, $errors = array()){
        $oReflector = new ReflectionClass($className);
        try {
            $oInstance = $oReflector->newInstanceArgs($arguments);
            return array($oInstance, $errors);
        } catch (ValidationException $e){
            return array(null, array_merge($errors, $e->getErrors()));
        }
    }
    

    Wystarczy przy każdej próbie stworzenia jakiegoś obiektu zastosować tą metodę i mamy ładną zbieraczkę błędów…

  13. @Wojciech: Teraz rozumiem, co masz na myśli – dla mnie jednak, jeśli formularz występuje w różnych kontekstach, to są dwa różne formularze. ;] Rozwiązaniem może być konfigurowalna funkcja walidująca – „kontekst”, który ustawialibyśmy np. w kontrolerze. Wiem, że przy takim podejściu mamy o wiele więcej pracy, ale skoro różne miejsca wykorzystania wymagają różnych sposobów walidacji, to niestety gdzieś trzeba obie te metody zaimplementować.

  14. @Tomasz: fakt, trzeba wybrać miejsce implementacji. Jak dla mnie takim miejscem nie będzie formularz, ale właśnie np. metoda jakiejś usługi. Dzięki temu, uwolnimy nasz formularz i będzie mógł być wykorzystywany w różnych miejscach jako komponent czysto wizualny. Natomiast metody usługi już będą odpowiedzialne za walidację w odpowiednim kontekście.

  15. Zyx pisze:

    Wojciech Soczyński – tu nie chodzi o przechwytywanie wyjątków, tylko o to, że rzucając wyjątek przerywasz dalsze wykonanie, zatem nie wykryjesz błędów, które mogłyby wystąpić później. Zaproponowany kod nic tu nie pomoże, bo co mi z tego, że może pomieścić dowolną liczbę błędów, kiedy poleci już w drugiej linijce przetwarzania i do linijek 10, 30, 100, gdzie np. także są błędy, w ogóle nie dotrze?

  16. @zyx: dlaczego uważasz, że w ogóle nie dotrze ? Popatrz na metodę nowyPacjent z fasady zrefaktorowaną przy pomocy tryCreate:

    public function nowyPacjent($data) {
            $aErrors = array();
            
            list($oPesel, $aErrors) = tryCreate('Pesel',array($data['pesel']), $aErrors);
            list($oBirthDate, $aErrors) = tryCreate('DateTime', array($data['time']), $aErrors);
            
            list($oPacjent, $aErrors) = tryCreate('Pacjent', array($oPesel, $data['firstName'], $data['lastName'], $oBirthDate), $aErrors);
            
            if(!empty($aErrors)) {
                return $aErrors;
            }
            $this->pacjenci->persist($oPacjent);
        }
    

    Jak widzisz, wszystkie błędy są agregowane do tablicy „$aError” i jeżeli nie jest pusta to finalizacja metody w fasadzie nie dochodzi do skutku…

  17. @zyx: poza tym, dla potrzeb wyświetlania błędów w formularzu można jeszcze każdemu obiektowi domenowemu dopisać statyczną metodę „isDataValid”, która będzie miała taką samą sygnaturę jak konstruktor i nie będzie rzucać wyjątków tylko zwracać arraya z błędami… Możliwości jest multum.

  18. Rodzyn pisze:

    Myślę, że zyxowi (zarówno jak i mi) chodzi o to, że nawet w tryCreate przy pierwszym rzuceniu ValidationException następuje zwrócenie de facto pierwszego napotkanego błędu.
    A tak wracając do tematu narzekania na Zend_Form… to uważam, że jego validatory są odpowiedzialne za validację danych wejściowych i wiadomo, że do logiki biznesowej, średnio się nadają. Natomiast, jeżeli chodzi o validację taką podstawową są bardzo dobre. Najlepszym imho rozwiązaniem jest polaczenie Zend_Formowych validatorów oraz tych specjalnych dla modeli.

  19. Tak jak mówiłem, walidacja na formularzu jest ok, ale dla prostych przypadków i przy założeniu, że nasza site kończy się w widoku jako html. Natomiast jak robimy już powiedzmy webservice to przecież nie użyjemy formularza ;P ?

  20. singles pisze:

    @Wojtek – nie, ale możemy użyć Zend_Filter_Input 😉

  21. singles pisze:

    @Wojtek Formularza nie, ale Zend_Filter_Input jak najbardziej 😉

  22. @singles: masz w zupełności rację. Dlatego uważam, że co do miejsca walidacji:
    Niezbędne dla poprawności encji dane powinny być walidowane przez nią samą. Pozostałe powinny być walidowane w metodzie Usługi lub Fasady i wtedy jest to robione w odpowiednim kontekście. Jako środek do osiągnięcia celu można użyć zarówno walidatorów z rodziny Zend_Validate jak i Zend_Filter_Input.

  23. Zyx pisze:

    Wiem, że możliwości jest multum, ale jeśli chcemy mieć sensowny interfejs użytkownika, to musimy się jednak natrudzić dużo bardziej, niż sugeruje to treść wpisu :). Rodzyn słusznie zauważył – albo mamy eleganckie wyjątki, albo dużo pracy, z której Zend_Validate mimo wszystko nas zwalnia, by mieć eleganckie powiadomienia o błędach.

    I ja bym tutaj generalnie całkowicie olał wyjątki, zamiast obudowywać to jakimiś „tryCreate()”. Skoro nie chcemy przerywać biegu programu mimo napotkania błędów, to możemy po prostu budować sobie ich listę bezpośrednio, bez zbędnego kombinowania :).

    Gdzieś czytałem, że w typowej aplikacji procedury obsługi błędów zajmują jakiś kosmicznie duży procent objętości całego kodu i coś w tym jest.

  24. Jednym z rozwiązań, które jest kompromisem pomiędzy wyjątkami a raportowaniem błędów będzie metoda fabryczna. Dokona ona walidacji i jeżeli jest wszystko ok to utworzy obiekt, a jeżeli nie to zwróci array z listą błędów, to rozwiązanie chyba najmniej kombinatorskie :)

  25. ehhhe pisze:

    Przeczytanie tego wpisu oraz komentarzy utwierdzilo mnie w przekonaniu zeby trzymac sie z daleka od ZF. Wyglada na to ze ten framework generuje wiecej problemow niz ich rozwiazuje.

  26. No nie jest taki zły ten ZF. Jest pewnym standardem wśród przynajmniej polskich firm. Nie jest doskonały, jednak dzięki temu, że nie jest to monolityczny twór to można korzystać tylko z tych jego funkcjonalności, które spełniają nasze oczekiwania.

  27. matipl pisze:

    Nie wiem jaki jest wniosek?

    Na początku zjechałeś formularze, ale nie wiem czemu?
    Przecież walidatory w ZF są osobnym bytem i możesz je użyć w DOWOLNYM MIEJSCU. chociażby tworząc osobną walidację modeli.

    Poza tym formularzy frameworka (ZF czy to Symfony) trudno użyć do bardziej skomplikowanych rzeczy, dlatego spokojnie można z klocków frameworka stworzyć inne cuda.

  28. Nie zjechałem w żadnym miejscu formularzy. Stwierdziłem tylko, że połączenie Zend_Form z walidatorami sprawdza się tylko w najprostszych przypadkach, oraz to, że niektórzy myślą, że to jedyna właściwa droga bo tak jest w tutorialach dotyczących ZF.

    Wskazałem też możliwe inne rozwiązania kwestii walidacji danych.

    Wniosek jest więc taki jak w podsumowaniu wpisu:
    walidacja na formularzach to nie jedyne rozwiązanie. Są inne, które przedstawiłem ja, oraz ludzie w komentarzach i trzeba zawsze rozważyć różne warianty w zależności od sytuacji.

  29. matipl pisze:

    :) Trzeba pamiętać, że wszelkie biblioteki tylko umożliwiają daną funkcję.
    Przy bardziej skomplikowanych rzeczach potrzebny jest programista, bo żaden automat nie będzie wiedział co i jak…

    Mi po prostu wstęp trochę nie przypadł do gustu 😉

  30. No ja nie widzę nic takiego kontrowersyjnego we wstępie. Dla mnie jest dość wyważony :>

  1. […] serwisu Follow us on Twitter 81 śledzących RSS Feed  /  Mail 367 czytelników O walidacji słów kilka 1 głosuj! W dyskusji pod wpisem na blogu Matiego poruszyłem temat „walidatorów” w […]

  2. […] Na koniec polecam także inny ciekawy artykuł kończący się słowami: … gdy sytuacja robi się złożona, dobrze jest zdecydować się na podejście w stylu DDD, ponieważ jest dużo bardziej czytelniejsze i lepiej odpowiada skali skomplikowanych i dużych aplikacji. (źr. La Galère / Propaganda Kapitana Pazura » Blog Archive » O walidacji słów kilka). […]

Leave a Reply

Informuj mnie o odpowiedziach poprzez e-mail. Możesz również subskrybować wpis bez zostawiania komentarza.