AJAJ Autocompleter
In incercarile de a reduce cat de mult posibil cantitatea de date transportata intre server si client in mod asincron, am renuntat la a mai folosi XML ca standard, facand trecerea catre JSON (puteti incepe de aici). Majoritatea solutiilor au devenit astfel “AJAJ based”.
Cu siguranta fiecare dintre voi a folosit sau cel putin testat la un moment dat Autocompleter-ul Script.aculo.us. Ei bine, aceasta modalitate de autocomplete este buna, mai putin faptul ca trebuie generat server-side intreg UL-ul corespunzator rezultatelor. Aceasta metoda are doua dezavantaje:
- Cantitatea mai mare de date. Fac o mica paranteza aici. Sunt perfect constient de faptul ca exemplul autocompleter-ului nu este tocmai relevant din acest punct de vedere. Orice solutie de autocomplete va trebui oricum sa intoarca un numar relativ mic de rezultate, altfel avantajul utilizatorului devine nul, el trebuind sa scaneze atent sugestiile ce ar trebui sa ii scurteze munca. Ma folosesc totusi de acest exemplu pentru ca vreau sa pregatesc terenul pentru un articol viitor care va ilustra perfect avantajul unei solutii mai “light”.
- Amestecul markup-ului pe partea server. Si aici simt nevoia de justificari suplimentare. Atunci cand e vorba de o singura persoana implicata intr-un proiect / parte a unui proiect, legatura intre back-end si front-end este mult mai stransa. Dar, cand este vorba de echipe in cadrul carora fiecare persoana este responsabila doar de una din aceste parti, atunci separarea cat mai clara intre acesta este indicata.
Revenind la exemplul Autocompleter-ului Script.aculo.us, acesta poate fi rapid ajustat pentru lucrul cu date in format JSON, prin simpla “suprascriere” a functiei ce se ocupa de inserarea in pagina a rezultatelor transferului in felul urmator:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | Ajax.Autocompleter.prototype.updateChoices = function (choices) { if (!this.changed && this.hasFocus) { this.update.update('<ul></ul>'); response = choices.evalJSON(); if (response) { response.each((function (suggestion) { this.update.down('ul').insert((new Template("<li>#{text}</li>")).evaluate({text: suggestion})); }).bind(this)); } Element.cleanWhitespace(this.update); Element.cleanWhitespace(this.update.down()); if (this.update.firstChild && this.update.down().childNodes) { this.entryCount = this.update.down().childNodes.length; for (var i = 0; i < this.entryCount; i++) { var entry = this.getEntry(i); entry.autocompleteIndex = i; this.addObservers(entry); } } else { this.entryCount = 0; } this.stopIndicator(); this.index = 0; if (this.entryCount == 1 && this.options.autoSelect) { this.selectEntry(); this.hide(); } else { this.render(); } } } |
Doar liniile 4-11 sunt cele modificate, restul reprezinta functia initiala. Sfatul meu este sa nu editati direct libraria controls.js din Script.aculo.us, pentru ca orice modificare direct pe fisierele librariei va duce la ingreunarea unui viitor update, trebuind operate de fiecare data schimbarile pe noua versiune. Mult mai simplu este sa includeti pur si simplu codul de mai sus intr-un fisier ce va fi incarcat dupa Script.aculo.us.
PHP Class: AutoLoader
Oricine a adoptat metodologia OOP in lucrul cu PHP cu siguranta s-a bucurat la implementarea functiei __autoload in PHP 5, ce permite incarcarea automata a fisierului corespunzator unei clase la momentul invocarii acesteia.
Probleme
In ciuda potentialului imens adus de aceasta functionalitate, majoritatea cartilor de specialitate prezinta doar cel mai elementar exemplu pentru exploatarea acestei functii, si anume simpla incarcare a fisierului cu numele identic sau asemanator cu cel al clasei necesare:
1 2 3 | function __autoload($class_name) { require_once $class_name . '.php'; } |
Imediat dupa trecerea entuziasmului, incepem sa observam minusurile acestei abordari:
- Necesitatea ca fisierele si clasele corespunzatoare sa fie denumite la fel.
- Toate fisierele vor trebui sa fie situate in acelasi director, pentru a putea fi incluse.
- Fiecare fisier va putea contine o singura clasa. (Cu toate ca si eu consider “best-practice” pastrarea cate unui singur fisier per clasa, prefer sa stiu ca nu sunt constrans in aceasta directie).
Cerinte
Una din marile frumuseti ale programarii este ca permite transpunerea logicii gandirii umane intr-un limbaj “inteles” de catre tehnologiile disponibile. La fel este si cazul procesului decizional ce urmeaza:
- Avem nevoie de un sistem de localizare si incarcare a claselor care sa fie independent de structura directoarelor aplicatiei, si care sa rezolve punctele enumerate mai sus.
- Va trebui ca solutia adoptata sa poata depista clasele in anumite directoare alese, in acest fel asigurandu-se incarcarea unui fisier necesar, din locatia deja cunoscuta a acestuia.
- Pentru a evita solicitarea excesiva a serverului, este necesar ca sistemul sa permita o memorare (cache) a locatiei fiecarei clase, asa incat parcurgerea directoarelor sa se faca o singura data.
Solutie
Dupa ce a trecut prin mai multe iteratii si versiuni (si probabil va mai trece), va invit sa descarcati si folositi versiunea actuala a clasei AutoLoader. Modul de utilizare este simplu, doar incarcati fisierul in care se afla aceasta, si folositi urmatoarea varianta a functiei __autoload:
1 2 3 4 5 6 7 8 9 | function __autoload($class) { $class_dirs = array("./"); // array ce va contine directoarele in care vom cauta (inclusiv subdirectoarele acestora, recursiv) $autoloader = new AutoLoader($class_dirs, 'autoloader-cache.php'); try { $autoloader->loadClass($class); } catch (Exception $e) { exit($e->getMessage()); } } |
Puteti vedea output-ul unui scurt exemplu aici, ce contine urmatorul cod PHP:
1 2 3 | include("AutoLoader.class.php"); include("autoload.func.php"); new Test; |
Avantaje
- Incarcarea explicita a unei singure clase, cea de autoload.
- Parcurgerea recursiva a directoarelor indicate si pastrarea locatiei fiecarei clase intr-un fisier de cache, pentru acces rapid.
- Regenerarea automata a acestui fisier pe parcursul dezvoltarii. In momentul adaugarii / modificartii unei clase, locatia acesteia negasindu-se in fisierul existent, acesta este recreat.
- Inexistenta restrictiei privitoare la legatura intre numele unei clase si denumirea fisierului in care aceasta se afla.
Dezavantaje
Unul din dezavantajele minore ale acestui sistem este imposibilitatea existentei a doua clase cu acelasi nume. In cazul in care numele a doua clase coincid, locatia primei intalnite la scanarea fisierelor va fi suprascrisa in fisierul de cache de catre cea de-a doua.
Cu toate ca in mod normal nu ar trebui sa existe doua clase denumite la fel, se impune in acest fel o atentie sporita in momentul utilizarilor de clase / plugin-uri “3rd party”, deoarece numele uneia din acestea poate coincide cu cel al unei clase deja existente.
Download
Puteti downloada atat clasa AutoLoader, cat si toate fisierele corespunzatoare exemplului anterior:
Download AutoLoader.class.php
Download exemplu
Ca de obicei, sunt foarte interesat de eventualele imbunatatiri / modificari pe care le-ati propune. De asemenea, daca depistati bug-uri, as fi recunoscator daca mi le-ati indica.
Sunt Victor Stanciu, web developer, si scriu despre dezvoltare, standarde, tehnici si tehnologii. (