Autor wpisu: sokzzuka, dodany: 05.02.2011 12:56, tagi: php, zend_framework
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”.