Niezalogowany [ logowanie ]
Subskrybuj kanał ATOM Kanał ATOM

Autor wpisu: batman, dodany: 09.02.2011 08:00, tagi: php

Przez ostatnie trzy części “PHP w chmurze” poznawaliśmy Azure Storage, czy mechanizmy przechowywania danych w Windows Azure. Dla przypomnienia – były to bloby, kolejki oraz tabele. Ponieważ we wspomnianych wpisach skupiłem się na wyjaśnieniu jak one działają, a nie na ich praktycznych zastosowaniach, mechanizmy te mogły wydawać się nieco oderwane od rzeczywistości. Dzisiaj, zainspirowany jednym z tutoriali z serwisu Windows Azure for PHP, postanowiłem napisać jego nieco ulepszoną wersję.

Budowa aplikacji

Aplikacja nad którą będziemy pracować, nie będzie wiele robiła. Jej jedynym zadaniem będzie wysyłanie maili. W prawdziwym życiu, aplikacja taka stanowiłaby część większej całości. Aby nie zaciemniać obrazu, zastosowałem kilka skrótów, które w produkcyjnych aplikacjach nie powinny mieć miejsca.

Aplikacja będzie podzielona na dwie części – web role oraz worker role. Gwoli przypomnienia wyjaśnię, że rola typu web jest typową aplikacją internetową, jaką wszyscy znamy i lubimy – posiada graficzny interfejs użytkownika, można się do niej dostać z dowolnego miejsca Internetu, a odebrane dane zapisuje w celu dalszej ich obróbki. Z kolei rola typu worker, to tania siła robocza, która zajmuje się przetwarzaniem danych. Idealnie nadaje się do wykonywania zadań, mogących spowodować spadek wydajności roli web. W pewnym sensie workera można przyrównać do usługi, która działa w tle zawsze gotowa do pracy.

W naszej aplikacji rola web będzie formularzem odbierającym dane od użytkownika i zapisującym je w Azure Storage, a worker na ich podstawie będzie wysyłał emaile. Dlaczego wysyłką maili ma się zajmować worker, a nie web? Z bardzo prostego powodu. Jeśli serwer pocztowy nie będzie dostępny, wówczas rola web (widoczna dla użytkownika) przestanie działać lub w najlepszym wypadku będzie zgłaszała błąd w po wysłaniu formularza. Worker z kolei, mimo iż napotka ten sam problem, zgłosi go po cichu (z dala od wścibskich oczu). W ten sposób użytkownik cieszy cię, że strona działa szybko, dane nie są tracone, a my wysyłamy armię wyszkolonych małp do naprawienia problemu.

Do komunikacji między rolami, wykorzystane zostaną kolejki, załączniki będą przechowywane jako bloby, a tabele posłużą nam jako pojemnik na informacje wysłane przez użytkownika.

Na koniec warto wspomnieć, iż formularz, walidację danych oraz wysyłkę maili zleciłem Zend Frameworkowi. Szybko, elegancko, bez marnowania czasu.

Tworzenie projektu

Wiemy już jakie role będą nam potrzebne (jedna web i jedna worker) oraz z jakich mechanizmów przechowywania danych będziemy korzystać, czas rozpocząć prace nad aplikacją. Zaczniemy od utworzenia nowego projektu w Eclipse (instalację środowiska znajdziecie w pierwszym wpisie serii).

Z menu File wybieramy opcję New –> Project, a następnie Windows Azure PHP Project.

azure1

Jako nazwę projektu wpisujemy azuremail i klikamy przycisk Next. W kolejnym oknie w polu Role name wpisujemy web1, zaznaczamy checkbox Windows Azure Data Storage oraz ponownie klikamy przycisk Next

Czytaj dalej tutaj (rozwija treść wpisu)
Czytaj dalej na blogu autora...

Autor wpisu: matipl, dodany: 08.02.2011 09:01, tagi: php

Zend Framework Wstępnie chciałem napisać o lokalizacji, aby zaprezentować Wam jak można wykorzystać application.ini zamiast tworzyć własne zasoby (resource). Ale z drugiej strony może nie każdy wie jakie to proste w dzisiejszych czasach zrobić serwis wielojęzyczny z tłumaczeniem nie tylko statycznych napisów, ale również nawigacji czy lokalizacją kwot.

Do tłumaczeń korzystam z gettext (pliki .mo i .po). Moje pliki językowe znajdują się w project/languages i wygląda to tak:

matipl@host:~/project/languages$ ls
en_GB.mo  en_GB.po  pl_PL.mo  pl_PL.po

Gdy mamy stworzone własne tłumaczenia pora na skonfigurowanie zasobu translate w application.ini:

resources.translate.registry_key   = "Zend_Translate"
resources.translate.adapter        = "gettext"
resources.translate.content        = APPLICATION_PATH "/../languages/"
resources.translate.options.scan    = "filename"
resources.translate.disableNotices = false
resources.translate.options.logUntranslated = false
resources.translate.locale        = "pl_PL"

W ten oto sposób możemy już korzystać z plików lokalizacyjnych opartych o Zend_Translate (skonfigurowany zasób znajduje się w Zend_Registry::get(‘Zend_Translate’)). Niestety nie wie on z jakiej wersji językowej (pl czy en) chcemy skorzystać.

W tym celu stworzyłem plugin Zextend_Controller_Plugin_Locale, który pobiera wybrany (lub domyślny) język użytkownika i konfiguruje Zend_Translate. Dodatkowo mówimy widokowi i nawigacji, że ma się wspierać przez Zend_Translate z tym konkretnym językiem, który skonfigurowaliśmy.

class Zextend_Controller_Plugin_Locale extends Zend_Controller_Plugin_Abstract
{

    public function routeShutdown(Zend_Controller_Request_Abstract $request)
    {
        $view = Zend_Controller_Front::getInstance()->getParam('bootstrap')->getResource('view');
        $locale = new Zend_Locale(Zextend_Lang::getActiveLang());
        Zend_Registry::set('Zend_Locale', $locale);

        $translate = Zend_Registry::get('Zend_Translate');
        $translate->setLocale($locale);

        $view->getHelper('translate')->setTranslator($translate);
        $view->navigation()->setTranslator($translate);

        Zend_Form::setDefaultTranslator($translate);

        Zend_Registry::set('Zend_Translate', $translate);

    }

}

Na koniec wystarczy włączyć nasz plugin w application.ini:

resources.frontController.plugins.locale = "Zextend_Controller_Plugin_Locale"

Teraz możemy już swobodnie korzystać z tłumaczeń na naszej stronie, np. w widoku wywołując:

<h2><?php echo $this->translate('Contact') ?></h2>

Dla słowa „Contact” musimy mieć oczywiście odpowiedni wpis w plikach *.po. Dla wersji PL:

msgid "Contact"
msgstr "Kontakt"

Po stworzeniu tłumaczenia pamiętajmy o wygenerowaniu pliku .mo komendą: msgfmt -o pl_PL.mo pl_PL.po.

Na koniec dodam, że w danych czasach sporo rzeczy robiłem poza application.ini. Chociażby przeciążałem zasób Db, aby wprowadzić SET NAMES UTF8, czy też w index.php wpisywało się dyrektywy PHP. A obecnie?

Czytaj dalej tutaj (rozwija treść wpisu)
Czytaj dalej na blogu autora...

Autor wpisu: Śpiechu, dodany: 07.02.2011 21:41, tagi: mysql, php, zend_framework

Kontynuujemy temat zapytań z poprzedniej części. Punktem wyjścia będzie dla nas tablica wyników zapytania dorzuconego przeze mnie LEFT JOINA (w ramach aktualizacji wpisu na samym dole poprzedniej części). Aby nieco utrudnić dorzuciłem kolejnych dwóch powszechnie znanych idoli młodzieży: Antoniego Macierewicza i Stefana Niesiołowskiego, którzy dla odmiany nie będą mieli swoich ksywek. Ponadto dodałem drugą ksywkę towarzyszowi Tuskowi znanemu często na forach Onetu jako Rudy Oszust.

Reasumując: mamy polityka z dwoma ksywkami, jednego z jedną i dwóch bez ksywek. Dążymy do tego aby wyświetlić na liście rozwijanej formularza ich wszystkich. Zarówno oryginalne imię i nazwisko jak i ksywkę. Co jednak zrobić, skoro ksywka i oryginalne imię i nazwisko posiadają to samo id w bazie? Zamienimy je na unikatowe poprzez dodanie jakiegoś dodatku po oryginalnym id, np. 5–1, 5–2 itd.

Najpierw jednak stworzymy super prosty formularz zawierający pole wyboru typu select i przycisk zatwierdzający zmiany. Potrzebujemy klasy dziedziczącej po Zend_Form. Ja pracując w Zendzie zazwyczaj formularze wrzucam do katalogu forms równoległego do controllers, models itd.

class PolitycyForm extends Zend_Form {
 
   public function init() {
      $this->setMethod('post');
      // gdzie ma zostac wyslany formularz
      $this->setAction('/index/index');
 
      // tutaj wstawić zapytanie
      // z aktualizacji wpisu poprzedniej czesci
 
      $stmt = $select1->query();
      $rowset = $stmt->fetchAll();
 
      $wyniki = array();
      $counter = 1;
 
      foreach ($rowset as $row) {
         // tymczasowo kluczami staja sie wyniki zapytania,
         // a wartosciami id i kolejny numer
         $wyniki[$row['imie_nazwisko']] = $row['id'] . '-' . $counter++;
         // sprawdzamy czy ten ktos ma ksywke,
         // jezeli tak to dorzucamy do wynikow
         if ($row['ksywka'] != null) {
            $wyniki[$row['ksywka'] . ' (' . $row['imie_nazwisko'] . ')'] = $row['id']. '-' . $counter++;
         }
      }
      // nastepnie wszystko to sortujemy po kluczach
      // do poprawnego posortowania polskich znakow
      // uzywamy funkcji setlocale
      setlocale(LC_COLLATE, 'pl_PL.utf8');
      ksort($wyniki, SORT_LOCALE_STRING);
      // i zamieniamy miejscami klucze z wartosciami
      $wyniki = array_flip($wyniki);
 
      $formElement = new Zend_Form_Element_Select('politycy');
      $formElement->setRequired(true)
         // blokujemy tworzenie domyslnego walidatora
         // sprawdzajacego czy wynik jest w formie tablicy
         ->setRegisterInArrayValidator(false)
         ->setLabel('Wybierz swojego ulubionego polityka')
         ->setMultiOptions($wyniki)
         // sprawdzamy czy ktos nie robi psikusa
         ->addValidator(new Zend_Validate_Regex('/^[0-9]+\-[0-9]+$/'));   
      $this->addElement($formElement);
      // dodajemy pole typu submit
      $this->addElement('submit','wybierz');
   }   
}

Po wszystkich zabiegach tablica $wyniki przekazywana do obiektu Zend_Form_Element_Select posiada następującą strukturę:

array(7) {
  ["3-7"] => string(18) "Antoni Macierewicz"
  ["1-3"] => string(11) "Donald Tusk"
  ["2-6"] => string(31) "Jareczek (Jarosław Kaczyński)"
  ["2-5"] => string(20) "Jarosław Kaczyński"
  ["1-4"] => string(25) "Rudy Oszust (Donald Tusk)"
  ["1-2"] => string(27) "Słońce Peru (Donald Tusk)"
  ["4-8"] => string(20) "Stefan Niesiołowski"
}

Teraz pozostaje nam odebrać formularz. Żeby zbytnio nie komplikować dane odbierzemy w kontrolerze IndexController w akcji indexAction(). Na przykład tak:

$politycyForm = new PolitycyForm();
if ($this->_request->isPost()) {
   $dane = $this->getRequest()->getPost();
   if ($politycyForm->isValid($dane)) {
      // wyrzucamy szmelc po wlasciwym identyfikatorze
      $filtr = new Zend_Filter_PregReplace(
         array('match' => '/\-[0-9]+/',
               'replace' => ''));
      $przefiltrowane = $filtr->filter($dane['politycy']);
 
      // wykonujemy dzialania na bazie danych
      // co wykracza poza ramy tego wpisu
 
      // zakladamy, ze istenieje akcja panel-uzytkownika
      return $this->_redirect('/index/panel-uzytkownika');
   }
   else {
      // jezeli formularz nie przechodzi walidacji
      // to zostaje uzupelniony o wprowadzone poprzednio dane
      $politycyForm->populate($dane);
   }
}
// wyswietlamy formularz
$this->view->politycy = $politycyForm;

Możecie zapytać po co nam ten _redirect. Otóż zabezpiecza nas przed ponownym wyświetleniem użytkownikowi formularza i przed ewentualnym ponownym wysłaniem danych.

Jeżeli za szybko z czymś pojechałem, składać zażalenia w komentarzach :-)

Autor wpisu: batman, dodany: 07.02.2011 08:00, tagi: javascript

Podczas tworzenia niewielkich formularzy logowania, bardzo często można natknąć się na projekt graficzny zakładający domyślne wartości w polach login oraz hasło (zamiast etykiet obok pól) informujące użytkownika o rodzaju danych jakie ma wprowadzić. O ile login nie stanowi żadnego problemu, tak w przypadku hasła jest to nie lada wyzwanie.

Jednym z możliwych rozwiązań jest zastosowanie ukrytych pól tekstowych. Technika ta polega na wstawieniu bezpośrednio po polu typu password, pola tekstowego zawierającego domyślny tekst. Następnie przy pomocy JavaScript sterujemy widocznością hasła oraz maski.

<form id="formularz" method="post" action="">
	<div>
		<input type="text" name="login" id="login" value="Wpisz login" />
	</div>
	<div>
		<input type="password" name="password" id="password" style="display: none;" />
		<input type="text" name="password_mask" id="password_mask" value="Wpisz hasło" />
	</div>
	<div>
		<input type="submit" name="btn_signin" id="btn_signin" value="Zaloguj" />
	</div>
</form>

Dzięki jQuery całą podmianę można zmieścić zaledwie w kilku wierszach. Nic nie stoi na przeszkodzie, aby skorzystać z dowolnej biblioteki JavaScript lub nawet z “czystego” języka. Kod odpowiedzialny za ukrywanie/pokazywanie zaślepki wygląda następująco (w przykładzie pominąłem login).

$(document).ready(function() {
	$("#password_mask").focus(function() {
		$(this).hide();
		$("#password").show().focus();
	});

	$("#password").blur(function() {
		if($(this).val().length == 0) {
			$(this).hide();
			$("#password_mask").show();
		}
	});
});

Najpoważniejszą wadą zaprezentowanego rozwiązania jest jego podatność na błędy JavaScript. Dowolny błąd na stronie, np. związany ze statystykami lub innym zewnętrznym skryptem, spowoduje, że tak przygotowany formularz logowania niestety nie zadziała. Najlepszym zabezpieczeniem przed taką sytuacją jest wstrzyknięcie maskującego pola tekstowego oraz ukrycie pola typu password przez JavaScript. W ten sposób nawet w przypadku problemów z JavaScriptem, formularz logowania pozostanie sprawny. Ostatecznie cały kod będzie wyglądał przybierze następującą postać.

<form id="formularz" method="post" action="">
	<div>
		<input type="text" name="login" id="login" value="Wpisz login" />
	</div>
	<div>
		<input type="password" name="password" id="password" />
	</div>
	<div>
		<input type="submit" name="btn_signin" id="btn_signin" value="Zaloguj" />
	</div>
</form>
<script type="text/javascript">
$(document).ready(function() {
	$("<input type=\"text\" />")
		.attr("name", "password_mask")
		.attr("id", "password_mask")
		.val("Wpisz hasło")
		.insertAfter("#password");

	$("#password_mask").focus(function() {
		$(this).hide();
		$("#password").show().focus();
	});

	$("#password").hide().blur(function() {
		if($(this).val().length == 0) {
			$(this).hide();
			$("#password_mask").show();
		}
	});
});
</script>

Autor wpisu: Kamil, dodany: 06.02.2011 15:06, tagi: css

Ostatnio natknąłem się na bardzo fajną rzecz – możliwość wysyłania pliku CSS w nagłówku HTTP. Daje to bardzo łatwą możliwość ukrycia swoich stylów CSS przed niedoświadczonymi developerami, niepożądanymi i wścibskimi oczami. Oczywiście tak przesłane style CSS do strony nie stanowią większego problemu do obejścia dla doświadczonego developera (Firebug), niemniej nie każdemu będzie chciało się analizować [...]

Autor wpisu: matipl, dodany: 06.02.2011 13:26, tagi: php

Zend FrameworkW październiku 2010 roku wspominałem Wam, że wraz z pojawieniem się Zend Frameworka w wersji 1.11.0 ułatwiono nam dostosowanie aplikacji opartej o ZF dla moblinych przeglądarek.

Dzięki pomocy Raphaela w frameworku pojawiły się m.in. Zend_Http_UserAgent oraz Zend_View_Helper_UserAgent. Dzisiaj chciałbym szybko Wam pokazać jak w łatwy sposób wykryć czy mamy doczynienia z mobilną przeglądarką (zbliża się wersja bilancio dla mobilnych).

WURFL, czyli powtarzamy kroki z manuala

Zasób UserAgent korzysta z zewn. biblioteki – WURFL (Wireless Universal Resource File). Ściągamy wersję 1.1 i rozpakowujemy w dowolnym miejscu. W naszej aplikacji tworzymy /library/wurfl-php-1.1 i kopiujemy tam katalog WURFL (reszty ze ściągniętej paczki tutaj nie potrzebujemy).

Aby zakończyć ten krok musimy jeszcze skopiować plik z informacjami o urządzeniach mobilnych. Plik wurfl-latest.zip znajduje się w paczce, w ścieżce tests/resources/. Tworzymy katalog w naszej aplikacji /data/wurfl oraz /data/wurfl/cache (w tym miejscu będzie przechowywał zawartość pliku zip). Do /data/wurfl kopiujemy plik wurfl-latest.zip (kopiujemy również web_browsers_patch.xml). W skrócie (project to nazwa naszego projektu ZF):


wget "http://downloads.sourceforge.net/project/wurfl/WURFL%20PHP/1.1/wurfl-php-1.1.tar.gz?r=&amp;ts=1296984042&amp;use_mirror=sunet" -O wurfl-php-1.1.tar.gz

tar -xvf wurfl-php-1.1.tar.gz

mkdir project/library/wurfl-php-1.1

mkdir project/data

mkdir project/data/wurfl

mkdir project/data/wurfl/cache

chmod a+w project/data/wurfl

cp -R wurfl-php-1.1/WURFL project/library/wurfl-php-1.1/

cp wurfl-php-1.1/tests/resources/wurfl-latest.zip project/data/wurfl

cp wurfl-php-1.1/tests/resources/web_browsers_patch.xml project/data/wurfl

Konfiguracja WURFL

Pliki mamy skopiowane, skonfigurujmy teraz samego WURFL. Zróbmy to wg tutorialu:

<?php
$resourcesDir            = dirname(__FILE__) . '/../../data/wurfl/';

$wurfl['main-file']      = $resourcesDir  . 'wurfl-latest.zip';
$wurfl['patches']        = array($resourcesDir . 'web_browsers_patch.xml');

$persistence['provider'] = 'file';
$persistence['dir']      = $resourcesDir . '/cache/';

$cache['provider']       = null;

$configuration['wurfl']       = $wurfl;
$configuration['persistence'] = $persistence;
$configuration['cache']       = $cache;

Konfiguracja chyba jest jasna? Wskazujemy głównie miejsca plików, które wcześniej kopiowaliśmy.

Na koniec konfiguracja projektu Zend Framework. Jak ostatnio wspominałem we wpisie Zend Framework i Symfony – subiektywnie, obecnie jesteśmy w stanie zrobić większość w application.ini. W takim razie dodajmy do niego informację, że chcemy skorzystać z UserAgent i powiedzmy, gdzie umieściliśmy WURFL, który jest odpowiedzialny za „rozszyfrowanie” danych o urządzeniu mobilnym:

resources.useragent.wurflapi.wurfl_api_version = "1.1"
resources.useragent.wurflapi.wurfl_lib_dir = APPLICATION_PATH "/../library/wurfl-php-1.1/WURFL/"
resources.useragent.wurflapi.wurfl_config_file = APPLICATION_PATH "/configs/wurfl-config.php"

W tym momencie zasób UserAgent już działa i możemy z niego korzystać.

Plugin

Nasza cała aplikacja ma uwzględniać urządzenia mobilne dlatego stworzymy plugin, który w przypadku wersji mobilnej zmieni nam layout na mobilny:

class Zextend_Controller_Plugin_Mobile extends Zend_Controller_Plugin_Abstract
{

    public function routeShutdown(Zend_Controller_Request_Abstract $request)
    {
        $bootstrap = Zend_Controller_Front::getInstance()->getParam('bootstrap');
        $userAgent = $bootstrap->getResource('useragent');
        $device = $userAgent->getDevice();
        if($device->getType() == 'mobile') {
            Zend_Layout::getMvcInstance()->setLayout('mobile');
        }
    }
}

$device udostępnia nam nie tylko typ urządzenia (getType()), ale również jego szerokość ekranu (getPhysicalScreenWidth()); W bilancio będzie to po prostu przekierowanie na osobą domenę (pobierana z application.ini z app.mobileUrl), ponieważ udostępniona funkcjonalność będzie różnić się od standardowej wersji:

Czytaj dalej tutaj (rozwija treść wpisu)
Czytaj dalej na blogu autora...

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”.

Czytaj dalej tutaj (rozwija treść wpisu)
Czytaj dalej na blogu autora...

Wszystkie wpisy należą do ich twórców. PHP.pl nie ponosi odpowiedzialności za treść wpisów.