Archive for the ‘php’ Category

For one of my projects based on Zend Framework I do a lot of forms creation and validation but I found out is that there is no way to perform all validation on the client side, which is a huge time-saver.

So I figured that since all form generaing code is already in place and all elements are rendered so nicely – it should be possible to generate validation code with as simple step as just adding one line of decorator. Such a decorator would have to do the following steps:

  1. For each element defined in the form
  2. get defined validators
  3. for each validator generate validation javascript code
  4. get all error messages TRANSLATED if necessarry and apply them when validating (eg. using alert window)
  5. add onsubmit handler for running validation code

One major requirement is to have ONLY standard JavaScript code NO EXTERNAL libraries. Why? Because it just makes things easier. This doesn’t mean that it’s not possible – anyone interested can just extend JsValidation class and perform his own validation.

The idea isn’t new, there already exists an approach that performs javascript validation but it lacks translated error messages. Additionally it contains very bad line:

//Replace Form decorator with our own
$form->removeDecorator('Form');
$form->addDecorator(new CU_Form_Decorator_Form());

Why is it bad, you might ask – along JS decorator one is forced to use SPECIAL form decorator.

Currently my library supports 5 9 – in my opinion* – most widely used decorators :

Updated link to docs.

There’s probably one thing that nees some more explanation – namely the strategy for keeping consistent order of running validation rules. So you do want to have check for non-empty before validating that value is float. In order to achieve it every validator is connected with corresponding STRENGTH integer value which defines the order of execution. So non-empty check is before float but less-than and greater-than might be executed in any order.

In the code it’s realized inside getValidator method whose second returned value is the execution order. Afterwards which value is used by „inner” class ElementValidators inside of its add method which uses it as an array key.

So this is it – the rest should be pretty straighforward – in case it isn’t feel free to leave some comments/questions below. One more remark – currently validation errors are displayed using alert function but yes I’m planning to display them inline the same way ZF’s validation erros are displayed. Erros are displayed the same way regular form validation happens so from user perspective there should be difference – additionally you can provide/override your own Zend.Form.ErrorReporter. Additionally validator rules are defines as functions in Zend.Validator.Rules namespace – each rules has the same name as its PHP counter-part, eg.

Zend.Form.Validator.Rules.Zend_Validate_StringLength = function(value, opts, msgs) {
}

Where:

  • value is the value to be validated
  • opts are options passed to the validator eg. minLength
  • msgs are internationalized messages displayed when validation fails

Source code available on github.

You can also checkout gists for this project

Usage:

<?php  
error_reporting(E_ALL|E_STRICT);  
set_include_path(get_include_path() . PATH_SEPARATOR .  
                 './library');  
require_once 'Zend/Loader.php';  
  
Zend_Loader::registerAutoload();  
//May need to have this set, the JavaScript file paths use baseUrl at the moment  
//Zend_Controller_Front::getInstance()->setBaseUrl('public');  
  

// display validation messages in French
$translator = new Zend_Translate(
    array(
        'adapter' => 'array',
        'content' => '/resources/languages',
        'locale'  => 'fr',
        'scan' => Zend_Translate::LOCALE_DIRECTORY
    )
);
Zend_Validate_Abstract::setDefaultTranslator($translator);

$form = new Zend_Form();  
$form->setView(new Zend_View());  
$form->addDecorator(new Zend_Form_Decorator_JsValidation());  
  
$name = $form->createElement('text', 'name', array(  
        'label' => 'Name'  
));  
  
$name->addValidator('NotEmpty')  
     ->setRequired(true);  
  
$submit = $form->createElement('submit', 'ok', array(  
        'ignore' => true,  
        'label' => 'OK'  
));  
  
$form->setElements(array(  
        $name,  
        $submit  
));  

echo $form->getView()->headScript();  
echo $form->getView()->inlineScript();  
  
echo $form->render();  
  

custom validator (php part):
custom validator (javascript part):

* After one project with ZF

Jakiś czas temu znalazłem pewne ograniczenie w bibliotece phpUnit – polegało ono na niepoprawnym rozpoznawaniu klasy testowej w przypadku gdy nie dziedziczyła bezpośrednio po klasie testCase.

Naprawiłem to u siebie, ale uznałem, że jak open-soruce to open-source i fajnie by było to zgłosić autorowi, co też zrobiłem,  i dzisiaj dostałem informacje, że została ona zatwierdzona do release’a 3.3.16.

Narazie prace nad moim rozszerzeniem stanęły w miejscu, ale poszukując informacji nt. budowy takowego znalazłem pare ciekawych artykułów i wszystkie oscylują wokół wykonywania php i przetwarzania kodu na wewnętrzną reprezentację Zend engine, czli opcode’y (nie wiem jaki jest odpowiednik po polsku), oto one.

Na początek wspominana już wcześniej przeze mnie Sarah Golemon i jej wprowadzenie do opcodeów nowy link. Później  Terry Chay (chyba, wniskuję z nazwy domeny) opisuje swoją batalię z Zend enginem. Następnie lista opcodeów lokalnie zapisana z opisem i wytłumaczeniem. I ostatni z nich, czyli jak są Zend engine przetwarza tablice.

A wszystko zaczęło sie od tego, że zacząłem sie zastanawiać jakby tu udoskonalić jakiś system szablonów np. Smarty. Pierwszy strzał padł na rozszerzenie języka, dystrybuowane jako pliki źródłowe, kompilowane dynamicznie (jako .so), ale teraz myślę, że chyba lepiej by było rozszerzyć sam Zend engine o mapowanie kodów danego języka szablonów, bezpośrednio na opcode’y, ale do tego to jeszcze długa droga.

Są jeszcze 2 rzeczy, które planuje wykorzystać jako drogowskazy. Są to gotowe rozszerzenia php, dostępne przez system instalacji PECL. Jedno z nich to opcode cache, które ma zapewniać, ponowne wykorzystywanie opcodeów, tak żeby nie była potrzebna ich kompilacja – czyli autorzy też musieli się dość mocno wgryźć w sam Zend engine i na to właśnie liczę:)

Druga to już chyba nieco prostsza sprawa: pecl_http , które ma chować cała magię związaną z wysyłaniem i odbieraniem żądania HTTP, a że przeglądałem podobne rozwiązania zarówno w Apache Httpd (ma całkiem miły framework w C do budowania rozszerzeń i filtrów), HttpServletRequest w Javie (specyfikacja Servlet 2.4), kończąc na mojej implementacji (na potrzeby Fligg’a) to doszedłem do wniosku, że pomimo różnic między wszystkimi prezentowanymi rozwiązaniami, łatwiej mi się będzie przegryzać przez rozszerzenie pecl’owe.

No nic zobaczymy jak z czasem będzie, może pecl_smarty kiedyś ujrzy światło dzienne.

Kontynuuje moje poszukiwania narzędzi i informacji nt. tworzenia rozszerzeń języka php, jednak niestety tutki na zend.com autorstwa Sary Golemon kończą się w miejscu najbardziej dla mnie interesującym czyli jak tworzyć obiekty/interfejsy/iteratory, niby jest zapowiedź kolejnej części, ale wątpię, żeby ona kiedykolkiek ukazała się w witrynie, bo Sara po pierwsze wydała książkę nt pisania rozszerzeń (niestety nie znalazłem polskiego wydania), a po drugie od tej zapowiedzi minęły już 4 lata. Nicto trzeba szukać dalej, troche guglania i znowu jakis skrawek informacji, na blogu niejakiego Ananta można tam znaleźć link do tutka Marcusa Boergera, który skupia sie na OOP właśnie, ale niestety i on jest już chyba dość przestarzały, bo nie obyło się bez problemów podczas kompilacji kodu, ale wystarczył szybki rzut oka w inne moduły i źródła zend engine, żeby odkryć rozwiązanie (open-source się sprawdza :D). Niestety pisanie modułów w ten sposób napewno nie przypomina dobrej zabawy, te wszystkie makra, długaśne nazwy funkcji, haki na wielowątkowość markami z rodziny TSRMLS_*, no np. żeby się przespacerować po tablicy trzeba użyć takiego potwora:

for(
zend_hash_internal_pointer_reset_ex( arr_hash, &pointer );
zend_hash_get_current_data_ex(arr_hash, (void**)&data, &pointer ) == SUCCESS;
zend_hash_move_forward_ex(arr_hash, &pointer )
){
// tutaj ma sie cos dziac
}

Nie, to zdecydowanie nie jest to co tygryski lubią najbardziej :/

Anant podaje link go generatora kodu rozszerzeń, dostępnego w repozytoriach pear/pecl, które się nazywa CodeGen_PECL, ale po doświadczeniach z boost::python i łyku elgancji i prostoty z jaką można tworzyć rozszerzenia zapragnąłem czegoś podobnego, już już zacząłem obmyślać koncepcje kiedy zapaliła się żarówka – może nie tylko mnie zrobiło sie niedobrze na widok tej gmatwaniny i już coś takiego napisał? Jak się zapewne domyślacie tak jest. Po wpisaniu w guglu boost php, wyskakuje strona projektu o tejże nazwie, autorstwa Morioshiego. Sama biblioteka chyba nie została nigdy zgłoszona do komitetu akceptacyjnego boost.org, a może coś przegapiłem 🙂

Skontaktowałem się z autorem w sprawie dopisania paru rzeczy i obiecał dodać mnie do projektu, no to cytując kapitana planete „Goooo Planet!”.

Otóż zacząłem stawiać pierwsze kroki do celu, który chodził mi od dawna po głowie, czyli napisani własnego modułu do języka php5. Ten wpis nie jest żadnym tutkiem, ani wprowadzeniem, po prostu chciałem zebrać moje 2 znaleziska w tej dziedzinie.

Jedno pewnie będzie oczywiste, bo ze stron zend’a (link: http://devzone.zend.com/node/view/id/1021), jednak chciałem też zwrócić uwagę na artykuł Paula Hudsona (http://www.hudzilla.org/phpbook/read.php/20_3_0), gdyż nie zwiera on tak wiele teorii, więc jeżeli ktoś, tak jak ja, chce po prostu odpalić swoje „hello world” i już to polecam. W drugim czy trzecim podrozdziale jest błąd z brakiem referencji, podczas pobierania drugiego argumentu poprzez funkcję zend_parse_parameters, ale jest poprawiony w komentarzach, więc jeżeli po odpaleniu skryptu testowego dostaniecie segfaulta, to wiadomo gdzie szukać odpowiedzi.

Moje proste rozszerzenie nawet coś wypisuje, teraz czas na boost.spirit 🙂

Korzystacie z Propela i przeszkadza Wam jego inspirowane Javą Criteria api? Otóż jest proste rozwiazanie – sfPropelFinder napisany jak nazwa wskazuje pod framework Symfony, ale można go z powodzeniem stosować bez samego frameworka! Instalacja dostępna przez PEAR’a, a sztuczki jakie można za pomoca tego plugina realizować niektórzy porównuja do tych znanych z jQuery.

Parę przykładów z Fligga:

  • pobierz listę głosów dla linku i użytkownika (link)
  • pobierz liczbę głosów na dany komentarz linka (dla danego użytkownika) (link)
  • wybierz moduł po nazwie (link)
  • zmień status grupy linków (link)

Jak coś przybędzie to napewno tutaj dopiszę.

Jednym z założeń projektu Fligg jest niezależność od konkretnego silnika bazodanowego, a narzędziem które ma to  umożliwić jest Propel – ORM php’owy (od wersji 1.3 korzystający z PDO). W dokumentacji pisza, że wystarczy sobie skonfigurować poprawnie bazę, dopisać parę linijek konfiguracji dla phinga i gotowe. Rzeczywistość przedstawia się nieco bladziej i żeby zmusić taska phingowego do wygenerowania tego co chciałem musiałem sie sporo namęczyć, no ale koniec końców, działa tak jakbym chciał – tzn. na podstawie xml’owego opisu bazy danych generuje implementację dla każdego skonfigurowanego silnika bazowanowego, a następnie podczas wykonywania dodaje odpowiednią ścieżkę do include_path (w celu include’owania klas wygenerowanych dla właściwego silnika). Skrypt bash’owy generujący implementację można sciągnąć tutaj – warto chyba w tym miejscu nadmienić, że build phing’owy obslugujący całe to ustrojstwo przychodzi  razem z Propelem i po instalacji przez PEAR’a można go znaleźć w katalogu: $PEAR_PATH/data/propel_generator/pear_build.xml lub build.xml (starsza wersja).

I tak oto dochodzimy do problemów jakie się pojawiły po odpaleniu genratora kodu dla Oracle’a.

  1. Pierwszy problem dotyczył identyfiaktorów. Niby nic wielkiego, nazwy kolumn i tabel przy wypełnianiu bazy są wprowadzane małymi literami, a podczas wykonywania kodu wszytkie stałe  (z klas *Peer) operujące na identyfikatorach wielkimi, więc żeby sobie uprościć życie dodałem strToUpper tu i tam i problem zniknął.
  2. Druga sprawa to format daty. Po instalacji 10g-xe na moim linuchu, domyślny format to DD-MON-YY, czyli jak na przenośny kod dość nieciekawie. To można oczywiście zmienić, ale żaden ze sposobów podpowiadanych przez gugla nie zadziałał, więc pozostało mi to zmienić po stronie aplikacji – tak też się stało. Zaraz po połączeniu, w przypadku wykrycia, że jesteśmy pod Oracle’m wykonywanie jest zapytanie:ALTER SESSION SET NLS_TIME_FORMATA format pochodzi z pliku konfiguracyjnego (kod dostępny tutaj).
  3. Ostatnim problemem typowo Oracle’owym, jest dodawanie aliasu w przypadku zapytania zliczającego rekordy (COUNT), otóż jest on najzupełniej  zbędny.

I tak dochodzimy do ostatniej części tego wpisu, czyli sposobu w jaki Propel żongluje kodem odpowiedzialnym za współpracę z konkretnym slinikiem bazodanowym. Domyślnie parametry połączenia są zapisywane do pliku konfiguracyjnego (propel-runtime.php), a Propel podczas inicjalizacji połączenia je sobie wczytuje, co jak się domyślacie wcale nie ułatwiło mi zadania, gdyż potrzebnowałem sposobu na wygenerowanie konfiguracji Propel’a podczas wykonywania programu i przekazania jej do niego, najlepiej w formie tablicy. Tak też zrobiłem, wymagało to drobnych zabiegów w interfejsie Propel’owym, ale działa bez pudła  (metoda initFromArray):)

Zapowiadało się łatwo, prosto i przyjemnie:

sudo pecl install PDO_OCI

PDO już jest więc powinno pójść jak z płatka, ale niestety…

marek2@marek-laptop:/tmp/pear/temp$ sudo pecl install PDO_OCI
pear/PDO_OCI requires PHP extension „pdo” (version >= 1.0)
No valid packages found
install failed

Chwila guglania i jedyna rozsądna rada to zainstalować sobie PDO_OCI samemu, bo wtedy ponoć instaluje sie bez problemów, no więc jedziemy:

sudo pecl download PDO_OCI

sudo tar xzf PDO_OCI*.tgz

cd PDO_OCI*

sudo phpize

sudo ./configure

tutaj może się pojawić krótkie zająknięcie nt. braku ORACLE_HOME pomimo tego, że jest jak byk, no ale to da sie szybko załatwić:

sudo ./configure –with-pdo-oci=$ORACLE_HOME

make

sudo cp modules/pdo_oci.so /usr/lib/php5/20060613+lfs/

marek2@marek-laptop:/tmp/pear/temp/PDO_OCI-1.0$ php -m | grep -i pdo
PDO
pdo_mysql
PDO_OCI
pdo_pgsql

I voila 🙂

Garść informacji dostępna także na blogu Diablo.