Nowa wersja developerska będzie niekompatybilna z poprzednimi pod kątem interfejsu programistycznego. Aby zaimplementować cache tak, jak chciałem, musiałem przebudować niemal całą obsługę systemu wyjścia. W serii 1.x.x pojęcie systemu wyjścia w zasadzie nie istniało. To, czy wynik działania szablonu trafi na ekran, czy do zmiennej, zależało od wyboru odpowiedniej metody. Jakieś skomplikowane przełączenia i sztuczki kierowały wszystko do miejsca docelowego, aczkolwiek nie było w tym konsekwencji i strategia działania była średnio dopracowana. Cóż, tak wychodzi, jak się zaczyna od zachowywania podobieństw do Smarty'ego, a trzeba przypomnieć, że w początkowych, pionierskich czasach, było to jednym z założeń projektu. W OPTv2 istnieje jawnie zdefiniowany interfejs ioptOutput pozwalający samodzielnie zaprogramować, co trzeba zrobić z wynikiem działania. Właśnie za jego pomocą realizowany będzie system cache, a jak - już tłumaczę.
Dotąd w kodzie były dwa systemy wyjścia: optNetOutput wysyłające wszystko na ekran i pilnujące przed dwukrotnym wysłaniem szablonu w trybie XML, oraz optReturnOutput zwracające przechwycony rezultat. Dodałem do obu możliwość dekorowania ich czym innym i utworzyłem optCachedOutput koncentrujące się w całości na obsłudze cache. Możliwości pozostaną po staremu, natomiast zmieni się sposób wywoływania i niestety trochę się rozbuduje inicjacja:
$cache = new optCachedOutput('./cache/'); // to jest cache, tu go konfigurujemy.
$tpl -> register(OPT_OUTPUT, 'my_cache', $cache);
$tpl -> decorate(OPT_OUT_SCREEN, 'my_cache');
$tpl -> decorate(OPT_OUT_RETURN, 'my_cache');
if(!$cache -> isCached('szablon.tpl', 'jakis_id'))
{
// generuj dane
}
$cache -> setCache(5, 'jakis_id'); // włącz cache na 5 sekund
$tpl -> parse('szablon.tpl', 'my_cache');
Spróbuję jakoś skrócić i uprościć to, co widać na początku, zwłaszcza że mi też się to specjalnie nie podoba. Ponadto muszę sprawdzić, czy dekoracji przypadkiem w niewłaściwą stronę (niezgodnie z logiką i intuicją) pod względem nazewnictwa nie zrobiłem :).
Obsługa wtyczek nie jest jeszcze w pełni gotowa - ukończyłem jedynie część znajdującą się w opt.class.php, jako że reszta może spokojnie być z pożytkiem dla wydajności wyekspediowana gdzie indziej. Podobnie, jak w OPT 1.1.3, będzie możliwość ustawienia kilku katalogów z pluginami, lecz parser nie będzie już żądać w nich praw do zapisu. Wrzucane tam były dodatkowe pliki opisujące zawartość katalogu i pozwalające załączyć jego zawartość bez konieczności jego skanowania. Jednak wiadomo, że im więcej include'ów, tym wolniej wszystko działa, a niektórzy potrafią tych wtyczek naprodukować tyle, że mają tam więcej plików, niż liczy sobie cały mój framework :D. Dlatego teraz OPT będzie ze wszystkich pluginów składać jeden mega-plik zawierający wszystko, czego potrzeba nam do szczęścia. Przy okazji będę mieć również nowy algorytm do następcy OPT Toolsetu, który teraz będzie obsługiwać już wszystkie biblioteki Open Power.
Ostatnia sprawa dotyczy zestawu funkcji dostępnych w szablonach. Stormfly niedawno pisał na swoim blogu, że w OPT 1.1.x był on bezsensownie dobrany i w sumie miał rację. Popatrzyłem, co tam programiście daje Smarty i okazało się, że ma tam on w zanadrzu kilka ciekawych funkcji, które mogą być naprawdę przydatne. Wstępna lista zawiera zatem:
- spacify - pomiędzy każde dwa sąsiednie znaki podanego ciągu wstawiany jest inny ciąg.
- indent - robi wcięcia w tekście.
- truncate - obcina tekst do maksymalnie podanej długości (można dodać nierozcinanie słów na pół)
- strip - redukuje wszystkie grupy białych znaków do pojedynczego znaku.
- capitalize - odpowiednik ucfirst()
- upper - odpowiednik strtoupper()
- lower - odpowiednik strtolower()
- countWords - odpowiednik str_word_count()
- countChars - odpowiednik strlen()
- money - odpowiednik money_format(), lecz ustawienia można zapisać w konfiguracji OPT.
- number - odpowiednik number_format(), lecz ustawienia można zapisać w konfiguracji OPT.
- wordWrap - odpowiednik word_wrap()
- replace - odpowiednik str_replace()
- regexReplace - odpowiednik preg_replace(), lecz z ostatnim argumentem wysuniętym na początek, aby nie było niekonsekwencji.
- date - odpowiednik date() :)
- firstof - zwraca pierwszy niepusty element z podanych.
- nl2br - odpowiednik nl2br() :)
- array - tworzenie tablic po stronie szablonów.
- build - to, co w poprzednim OPT się nazywało apply(), ale jeszcze nie wiem, czy ostatecznie zostanie właśnie taka nazwa.
W zestawie tym nie ma żadnych funkcji do escape'owania, ponieważ kompilator w wielu miejscach sam o to dba, a jeśli nie, będzie możliwość ręcznego zaznaczenia tego, aczkolwiek nie poprzez funkcję. W każdym razie chodzi o to, by kompilator wiedział, że coś jest escape'owane i z rozpędu sam czegoś od siebie nie dołożył, gdyż to równałoby się kaszanie na ekranie.
Naprodukowałem całkiem sporo funkcjonalności, lecz koniec końców nie zdążyłem wszystkiego przetestować, tak więc nie mam pewności, czy cały ten kod w ogóle działa, jak należy, aczkolwiek jakichś specjalnych rewelacji się nie spodziewam. W końcu np. algorytmy cache'ujące zasadą działania nie różnią się specjalnie od tego, co było w poprzednich wersjach. Kolejny dev ukaże się już za parę dni.
Na koniec mała statystyka:
- opt.class.php - 24 KB i więcej już nie urośnie. W poprzedniej wersji plik ten był o całe 8 KB cięższy, a w sumie oferował mniej.
- opt.compiler.php - 65 KB i wciąż rośnie.
- opt.instructions.php - 25 KB i wciąż rośnie.