scieee AI-readable full text Open interactive document viewer

Implementació de Framework PHP per desenvolupar aplicacions web ràpidament

Martínez Soto, Andrés Ignacio

Full text

Escola T` ecnica Superior d’Enginyeria Inform` atica Universitat Polit` ecnica de Val` encia Enginyeria T` ecnica en Inform` atica de Gesti´ o Mem` oria Projecte Final de Carrera Implementaci´ o de Framework PHP per desenvolupar aplicacions web r` apidament Autor: Andr´ es Ignacio Mart´ ınez Soto Director: Pedro J. Valderas Aranda. Val` encia, juliol de 2011 2 ´ Index I Introducci´ o 13 1 Introducci´ o 15 1.1 Introducci´ o ............................... 15 1.2 Descripci´ odelprojecte ......................... 15 1.3 Motivaci´ o................................ 16 1.4 Objectius ................................ 16 1.5 Principis utilitzats en aquest desenvolupament . . . . . . . . . . . . . 17 1.6 Principals components i sistemes del framework . . . . . . . . . . . . 17 1.7 Hist` oria i versions d’aquest projecte . . . . . . . . . . . . . . . . . . 18 1.7.1 Cronologia de versions . . . . . . . . . . . . . . . . . . . . . 18 2 Antecedents 21 2.1 Introducci´ o ............................... 21 2.2 Estat de l’art: evoluci´ o ......................... 21 2.2.1 CGI Common Gateway Interface ............... 21 2.2.2 Llenguatges din` amics...................... 21 2.2.3 AJAXilaWeb2.0 ....................... 22 3 Tecnologies 23 3.1 Introducci´ o ............................... 23 3.2 Tecnologies de costat del servidor . . . . . . . . . . . . . . . . . . . 23 3.2.1 PHP: PHP HyperText Processor . . . . . . . . . . . . . . . . 23 L’Entorn de producci´ o/execuci´ odePHP............ 23 Errors comuns, fallades de seguretat . . . . . . . . . . . . . . 24 3.2.2 SOAP: Simple Object Access Protocol . . . . . . . . . . . . 24 WSDL: Web Services Description Language . . . . . . . . . 25 3.2.3 REST.............................. 25 3.3 Tecnologies de costat del client . . . . . . . . . . . . . . . . . . . . . 26 3.3.1 JavaScript............................ 26 3.3.2 CSS............................... 26 3.3.3 HTMLiXHTML........................ 27 II Arquitectura 29 4 Arquitectura i funcionament del projecte 31 4.1 Introducci´ o ............................... 31 4.1.1 Capa de persit` encia....................... 31 3 4´ INDEX 4.1.2 Capa de l` ogicadenegoci.................... 31 4.1.3 Capa de presentaci´ o ...................... 32 5 Components del marc de treball 35 5.1 Introducci´ o ............................... 35 5.2 ActiveRecord.............................. 35 5.2.1 Components d’Active Record . . . . . . . . . . . . . . . . . 36 Components generals . . . . . . . . . . . . . . . . . . . . . . 36 Esquemes............................ 37 Generaci´ odeconsultes..................... 37 Validaci´ odemodels ...................... 37 5.3 Authentication.............................. 39 5.4 Browser................................. 40 5.5 Cache .................................. 40 5.6 Config.................................. 42 5.7 Context ................................. 42 5.8 Database................................. 43 5.9 Environment............................... 44 5.10ErrorHandler.............................. 45 5.11Filter................................... 45 5.12Flash................................... 45 5.13FrontController............................. 46 5.14Helpers ................................. 47 5.15HttpResponse.............................. 48 5.16 Locale - I18N (internacionalitzaci´ o) .................. 48 5.17Log ................................... 49 5.18Mailer.................................. 49 5.19MVC .................................. 50 5.20Plugins ................................. 51 5.21Registry................................. 51 5.22Request ................................. 52 5.23REST .................................. 52 5.23.1 Partdelclient.......................... 53 5.23.2 Part del servidor . . . . . . . . . . . . . . . . . . . . . . . . 53 5.24Router.................................. 54 5.25Session ................................. 55 5.26SOAP .................................. 56 5.26.1 Partdelclient.......................... 56 5.26.2 Part del servidor . . . . . . . . . . . . . . . . . . . . . . . . 56 5.27Style................................... 56 5.28Widgets ................................. 57 6 Patrons de disseny aplicats al projecte 59 6.1 Introducci´ o ............................... 59 6.2 Singleton ................................ 59 6.3 FrontController............................. 59 6.4 Strategy................................. 60 6.5 Adapter/Wrapper ............................ 60 6.6 MVC: Model View Controller . . . . . . . . . . . . . . . . . . . . . 60 6.6.1 Flux de funcionament del sistema MVC . . . . . . . . . . . . 61 ´ INDEX 5 6.7 HMVC: Hierarchical Model View Controller . . . . . . . . . . . . . 62 6.7.1 Avantatges de l’utilitzament del patr´ o de disseny HMVC . . . 62 6.8 ActiveRecord.............................. 63 6.9 Registry................................. 63 6.10 Lazy Loading o c` arrega diferida.................. 64 6.11InterceptingFilter............................ 64 7 Funcionament del sistema 67 7.1 Modes de funcionament . . . . . . . . . . . . . . . . . . . . . . . . . 67 7.1.1 Aplicaci´ oweb ......................... 67 Introducci´ o........................... 67 Aplicaci´ oweb ......................... 67 AJAX.............................. 67 JSON.............................. 67 MIME.............................. 68 Plugins ............................. 68 7.1.2 ServeisWEB.......................... 68 Introducci´ o........................... 68 SOAP.............................. 68 REST.............................. 69 7.1.3 Tasques programades/sistema operatiu . . . . . . . . . . . . . 69 Introducci´ o........................... 69 CRON.............................. 69 III El model de dades 71 8 Introducci´ o 73 8.1 Introducci´ o ............................... 73 9 La base de dades 75 9.1 Introducci´ o ............................... 75 9.2 Configuraci´ o de la base de dades . . . . . . . . . . . . . . . . . . . . 76 9.3 API del component Database ..................... 78 9.3.1 Introducci´ o........................... 78 9.3.2 Operacions sobre connexions . . . . . . . . . . . . . . . . . 78 9.3.3 Operacions de consulta . . . . . . . . . . . . . . . . . . . . . 78 9.3.4 Altres operacions . . . . . . . . . . . . . . . . . . . . . . . . 79 9.4 Exemplecomplet ............................ 80 10 Active Record 81 10.1 Introducci´ o ............................... 81 10.2Elmodel................................. 82 10.2.1 Introducci´ o........................... 82 10.2.2 De base de dades relacional a model Active Record . . . . . . 82 10.2.3 Relacions............................ 84 Relaci´ ohas one(1:1).................... 84 Relaci´ obelongs to(1:1) .................. 86 Relaci´ ohas many(1:N)................... 87 Relaci´ ohas and belongs to many(N:M) . . . . . . . . . 88 6´ INDEX Relaci´ ohas one through(1:1) ............... 90 Relaci´ ohas many through(1:N).............. 92 Relaci´ ohas many by sql(1:N) .............. 94 relacions reflexives (1:N) . . . . . . . . . . . . . . . . . . . . 96 10.2.4 Validacions........................... 97 10.2.5 Callbacks............................ 99 10.2.6 Funcionalitat d’usuari . . . . . . . . . . . . . . . . . . . . . 100 10.2.7 Esquemes............................ 100 10.3 API d’Active Record . . . . . . . . . . . . . . . . . . . . . . . . . . 100 10.3.1 Tipus de dades de l’API . . . . . . . . . . . . . . . . . . . . 100 ModeliTree .......................... 100 Resultats (FW ActiveRecord Result).............. 102 Relacions (FW ActiveRecord Relation) ............ 103 Condicions per fer una cerca . . . . . . . . . . . . . . . . . . 104 Condicions per fer ordenaci´ o de dades . . . . . . . . . . . . . 105 10.3.2 Operacions de cerca de dades (find) . . . . . . . . . . . . . . 106 10.3.3 Operacions amb funcions de columna . . . . . . . . . . . . . 106 10.3.4 Desat, actualitzaci´ o i inserci´ o, esborrament i exist` encia de dades 107 10.3.5 Exemples............................ 107 IV Desenvolupament d’aplicacions web 111 11 Estructura de les aplicacions web 113 11.1 Introducci´ o ............................... 113 11.2Directoris ................................ 113 11.3 Estructura d’un m` odul ......................... 115 11.4EstructuraMVC............................. 116 11.4.1 Introducci´ o........................... 116 11.4.2 Elcontrolador.......................... 116 El controlador (classe FW mvc BaseController)........ 116 APIdelcontrolador....................... 117 11.4.3 Elmodel ............................ 118 El model (classe FW mvc BaseModel) ............ 118 APIdelmodel ......................... 119 11.4.4 Lavista............................. 119 Vistes i Vistes parcials . . . . . . . . . . . . . . . . . . . . . 119 Estructura d’una vista en PHP . . . . . . . . . . . . . . . . . 120 11.4.5 Layoutsweb .......................... 120 Creaci´ odeLayouts....................... 121 11.4.6 Creaci´ odeLayouts....................... 121 12 El sistema d’enrutat 125 12.1 Introducci´ o ............................... 125 12.2 Estructura d’una ruta . . . . . . . . . . . . . . . . . . . . . . . . . . 125 12.3Tipusded’accions ........................... 126 12.3.1 Accions d’aplicaci´ o....................... 126 12.3.2 Serveisweb........................... 127 12.3.3 Plugins ............................. 128 12.3.4 Altres tipus d’accions . . . . . . . . . . . . . . . . . . . . . . 128 ´ INDEX 7 12.4 Par` ametres................................ 128 12.5 Autenticaci´ o............................... 130 12.6 Cach´ e .................................. 130 12.7 Cach´ ederutes.............................. 131 13 Autenticaci´ o 133 13.1 Introducci´ o ............................... 133 13.2 Configuraci´ o de l’autenticaci´ o ..................... 133 13.3 Creaci´ o de la taula d’usuaris . . . . . . . . . . . . . . . . . . . . . . 136 13.4 Autenticar un usuari . . . . . . . . . . . . . . . . . . . . . . . . . . . 136 14 Els entorns 139 14.1 Introducci´ o ............................... 139 14.2Tipusd’entorns ............................. 139 14.3 Configuraci´ odelsentorns........................ 139 15 Programaci´ o d’accions 141 15.1 Introducci´ o ............................... 141 15.2 Estructura de la demostraci´ o ...................... 141 15.3 Definici´ odellayout........................... 146 15.4 Programaci´ o de les accions veure ´ ultims 5 entradesiveure entrada147 15.4.1 Acci´ oveure ´ ultims 5 entrades............... 147 15.4.2 Acci´ oveure entrada..................... 148 15.4.3 Vistes.............................. 149 15.4.4 Captures de pantalla . . . . . . . . . . . . . . . . . . . . . . 153 15.4.5 Rutes .............................. 154 15.5 Programaci´ o de les accions iniciar sessi´ oitancar sessi´ o. . . . 155 15.5.1 Acci´ o iniciar sessi´ o(login)................... 155 15.5.2 Tancar sessi´ o(logout) ..................... 157 15.5.3 Rutes .............................. 157 15.5.4 Vistes per aquestes accions . . . . . . . . . . . . . . . . . . . 158 15.5.5 Captures de pantalla . . . . . . . . . . . . . . . . . . . . . . 160 V Desenvolupament de plugins i helpers 163 16 Introducci´ o 165 16.1 Introducci´ o ............................... 165 16.2 Creaci´ o del m` odul a utilitzar en les desmostracions . . . . . . . . . . 165 16.2.1 Creaci´ o del layoutper a les demostracions . . . . . . . . . 165 16.2.2 Creaci´ o dels estils CSS per a les demostracions . . . . . . . . 167 17 Plugins 169 17.1 Introducci´ o ............................... 169 17.2APIdePlugins ............................. 170 17.2.1 API de Plugin Registry .................... 170 17.2.2 API del Plugin base ...................... 172 Opcions/configuraci´ o utilitzant base de dades . . . . . . . . . 172 Opcions utilitzant fitxer d’opcions options.php . . . . . . . . 173 Instal.lar/desinstal.lar un plugin . . . . . . . . . . . . . . . . 174 8´ INDEX Renderitzarvistes........................ 174 17.3 Plugin b` asic............................... 175 17.4 Creaci´ o d’un plugin d’exemple: Generador de Google Maps . . . . . 176 17.4.1 Programaci´ odelPlugin..................... 176 17.4.2 Programaci´ o del Geocoder ................... 178 17.4.3 Programaci´ o de la classe LatLng ................ 184 17.4.4 Programaci´ o de la classe Marker ................ 185 17.4.5 Programaci´ o de la classe Map ................. 188 17.4.6 Codideproves ......................... 192 Creaci´ odelavistamap..................... 194 Creaci´ odelesrutes....................... 194 18 Helpers 195 18.1 Introducci´ o ............................... 195 18.2 Creaci´ odehelpers............................ 195 VI Desenvolupament de serveis web 199 19 Introducci´ o 201 19.1 Introducci´ o ............................... 201 19.2 Creaci´ o del m` odul a utilitzar en les desmostracions . . . . . . . . . . 201 19.2.1 Creaci´ o del layoutper a les demostracions . . . . . . . . . 202 19.2.2 Creaci´ o dels estils CSS per a les demostracions . . . . . . . . 203 20 REST 207 20.1 Introducci´ o ............................... 207 20.2 Consumir serveis web REST . . . . . . . . . . . . . . . . . . . . . . 208 20.2.1 Introducci´ o........................... 208 20.2.2 API del client REST . . . . . . . . . . . . . . . . . . . . . . 208 Construcci´ o (constructor) del client de REST . . . . . . . . . 208 Cridar al servei web . . . . . . . . . . . . . . . . . . . . . . 209 20.2.3 Consumir serveis web REST en diversos formats . . . . . . . 210 20.2.4 Consumir servei web REST en format XML: Un mini-agregador defeedsRSS .......................... 211 Introducci´ o........................... 211 Connexi´ o i desc` arrega d’un feed RSS . . . . . . . . . . . . . 212 Processament dels feeds RSS . . . . . . . . . . . . . . . . . . 212 Juntanttotelcodi........................ 213 Rutes .............................. 215 Creaci´ o de les vistes i finalitzaci´ o del mini-agregador de feeds RSS ......................... 216 20.3 Creaci´ o de serveis web REST . . . . . . . . . . . . . . . . . . . . . . 218 20.3.1 Introducci´ o........................... 218 20.3.2 Autenticaci´ o .......................... 218 20.3.3 Creaci´ o d’un servei web REST senzill . . . . . . . . . . . . . 219 Operaci´ ogetTime...................... 219 Operaci´ ogreet....................... 219 Operaci´ oechoBack..................... 219 Rutes per aquesta demostraci´ o................. 220 ´ INDEX 9 20.3.4 Creaci´ o d’un servei web REST complet . . . . . . . . . . . . 221 Creaci´ o de la base de dades i del model . . . . . . . . . . . . 221 Obtindre tots els llibres getBooks ............... 222 Obtindre un llibre getBook ................... 223 Esborrar un llibre de la col.lecci´ odeleteBook ......... 224 Crear un llibre en la col.lecci´ ocreateBook ........... 224 Reemplac¸ar la col.lecci´ o de llibres sencera createBooks . . . . 226 Rutes .............................. 228 21 SOAP 231 21.1 Introducci´ o ............................... 231 21.1.1 Elscomponents......................... 231 21.1.2 WSDL: Web Services Description Language ......... 232 21.2 Consumir serveis web SOAP . . . . . . . . . . . . . . . . . . . . . . 233 21.2.1 Introducci´ o........................... 233 21.2.2 API del client SOAP . . . . . . . . . . . . . . . . . . . . . . 233 Construcci´ o (constructor) del client de SOAP . . . . . . . . . 233 Obtindre les operacions disponibles en el servei web . . . . . 234 Obtindre els tipus de dades complexos disponibles en el servei web ......................... 235 Cridar a operacions del servei web . . . . . . . . . . . . . . . 235 Altres cridades d’utilitat . . . . . . . . . . . . . . . . . . . . 236 21.2.3 Exemple: Consumir un servei web d’informaci´ o meteorol` ogica 236 Consumici´ odelserveiweb................... 237 displayCitiesByCountry . . . . . . . . . . . . . . . . 237 displayCityWeather . . . . . . . . . . . . . . . . . . . 238 Creaci´ odelesvistes ...................... 239 cities .......................... 239 noCities......................... 239 weather......................... 239 weather......................... 240 noWeather ....................... 241 Rutes .............................. 241 Captures de pantalla . . . . . . . . . . . . . . . . . . . . . . 242 21.3 Generaci´ o de serveis web SOAP . . . . . . . . . . . . . . . . . . . . 243 21.3.1 Introducci´ o........................... 243 21.3.2 Funcionament.......................... 244 21.3.3 Descripci´ odeserveisweb ................... 245 Par` ametres ........................... 245 Tipus de dades complexos . . . . . . . . . . . . . . . . . . . 246 21.3.4 Configuraci´ o del servei web . . . . . . . . . . . . . . . . . . 246 Descripci´ odelserveiweb ................... 247 Autenticaci´ o .......................... 247 21.3.5 Generaci´ o d’un servei web . . . . . . . . . . . . . . . . . . . 248 Configuraci´ o i rutes del servei web . . . . . . . . . . . . . . . 248 Creaci´ o de la base de dades i del model . . . . . . . . . . . . 251 Obtindre tots els llibres getBooks ............... 252 Obtindre un llibre getBook ................... 253 Esborrar un llibre de la col.lecci´ odeleteBook ......... 254 Crear un llibre en la col.lecci´ ocreateBook ........... 255 16 CAP´ ITOL 1. INTRODUCCI ´ O Per terminar, es poden implementar tasques autom` atiques que realitzen operacions ´ utils per al negoci de l’aplicaci´ o web. Aquestes tasques autom` atiques han de ser cridades per el programador del sistema (o execuci´ o de tasques del nostre hosting web) per a poder ser executades. Una tasca autom` atica pot ser, el generar informes diaris, setmanals i mensuals de qualsevol dada d’inter` es, generar estad´ ıstiques, enviar i rebre missatges, enviar newsletters a tots els subscriptors, fer c` opies de seguretat, ... Totes aquestes coses - i m´ es - es poden implementar amb aquest projecte, que pret´ en ser un marc de treball escrit en PHP i amb unes m´ ınimes depend` encies externes; per possibilitat el desenvolupament i educar en el desenvolupament d’aplicacions web 2.0 d’una manera senzilla, r` apida i amena. 1.3 Motivaci´ o La principal motivaci´ o que ha dut a aquest projecte ´ es el adquirir experi` encia i compet` encies en el terreny del desenvolupament de programari, ´ es a dir, millorar el nivell de programaci´ o existent i aplicar els principis d’enginyeria del programari explicats al llarg de tota la carrera. Tamb´ e el adquirir coneixements sobre desenvolupament i disseny web, encaminats cap al que - avui en dia - ´ es un dels sectors m´ es importants de la inform` atica; la web. Segonament, els marcs de treball o framework comercials existents, s´ on complicats d’aprendre, amb instal·lacions costoses, i resultats desesperants per el que comenc¸a a introduir-se en aquest m´ on, d’aix` o el desenvolupament d’aquest marc de treball en el que ´ es senzill i r` apid desenvolupar una aplicaci´ o web. Finalment, la darrera motivaci´ o, ´ es el crear un marc de treball senzill d’aprendre per a poder ser apr´ es i utilitzat per tot tipus de programadors - estudiants d’inform` atica especialment - i constituir una base sobre la que aprendre aquest apassionant mon que ´ es l’enginyeria web. 1.4 Objectius Aquest projecte t´ e de principal objectiu la construcci´ o d’un marc de treball complet per a desenvolupament d’aplicacions web d’una manera r` apida i senzilla, ´ es a dir, de facilitat la construcci´ o d’aplicacions web empresarials grans i escalables. S’esmenten a continuaci´ o els objectius d’aquest projecte: •Desenvolupament d’un marc de treball complet. •Disseny de components eficients. •Desenvolupament d’aplicacions Web 2.0. •Proporcionar serveis web per els est` andards SOAP i REST. •Proporcionar una manera senzilla d’estendre el marc de treball. •Servir de marc de treball per a principiants i estudiants, ´ es a dir, en educaci´ o. 1.5. PRINCIPIS UTILITZATS EN AQUEST DESENVOLUPAMENT 17 El haver escrit aquest marc de treball des de zero - basant-se en projectes similars - ha donat una visi´ o completa del panorama actual en el desenvolupament de programari, complementant les nocions ja vistes en les assignatures espec´ ıfiques d’intensificaci´ o d’Enginyeria del Programari, Desenvolupament de Programari per Components, Desenvolupament Avanc¸at de Programari i en la resta d’assignatures de la carrera com Enginyeria del Programari, Disseny de Bases de Dades, Bases de Dades i per descomptat Programaci´ o. Aquesta experi` encia ha aportat - sense dubte - una espurna per a l’alliberaci´ o d’aquest Projecte Final de Carrera com a projecte de programari lliure, a la creaci´ o d’una comunitat al voltant d’aquest projecte i a la programaci´ o d’aplicacions web amb aquest projecte; sempre amb l’objectiu de millorar el projecte i innovar en el camp de la web i serveis web, segons vagen apareixent noves tecnologies i formes m´ es eficients i r` apides de programar aplicacions web. 1.5 Principis utilitzats en aquest desenvolupament El desenvolupament d’aquest marc de treball inclou els seg¨ uents principis b` asics: •Codi font obert - open source. •Codi simple, principi KISS 1. •Disseny multicapa en 3 capes i v` aries subcapes. •Disseny orientat a objectes i fortament estructurat en components. •Aplicaci´ o de patrons de disseny en la construcci´ o de components. •Separaci´ o de l` ogica de negoci, fonts de dades i vistes. •Extensibilitat (a trav´ es de plugins) i reutilitzaci´ o de codi. •Facilitat de programaci´ o i corba d’aprenentatge redu¨ ıda. •Interoperatibilitat amb serveis web. •Us d’est` andars en el camp de la web (PHP, XML, JSON, AJAX). •Algorismes senzills, r` apids i eficients. •Us de metodologies ` agils i est` andars de codificaci´ o. •Servidors de codi o de control de versions per a treballs en grup. 1.6 Principals components i sistemes del framework Aquest projecte inclou els seg¨ uents components principals: •Router o enrutador de peticions, facilita la creaci´ o d’URLs personalitzades i amigables als cercadors. •Sistema MVC per desenvolupament dels diferents m` oduls d’una aplicaci´ o web. 1Keep It Simple Stupid! 18 CAP´ ITOL 1. INTRODUCCI ´ O •Sistema Active Record per a obtenci´ o i gesti´ o de dades en bases de dades. •Sistema de plugins, extensibilitat del marc de treball. •Sistema de Cach´ e que permet un major rendiment en llocs web de molt de tr` ansit. •Sistema d’AJAX amb XML i JSON. •Servidor de serveis web SOAP. •Servidor de serveis web REST. •Internacionalitzaci´ o i18n. •Sistemes de plugins i widgets per a una major reutilitzaci´ o de codi. •Validaci´ o de dades personalitzada. 1.7 Hist` oria i versions d’aquest projecte Aquest projecte va comenc¸ar despr´ es d’haver-se programat una aplicaci´ o web titulada Gesti´ o d’Activitats per a la Setmana de Benvinguda, una petita aplicaci´ o web que va gestionar el apuntats a les activitats de la mencionada setmana de benvinguda de la Universitat Jaume I de Castell´ o de la Plana des de 2006 a 2009. Mentre presentava el projecte web a les pr` actiques de l’assignatura APW Desenvolupament d’Aplicacions en Entorns Web, el professor de pr` actiques em va suggerir si podria fer-lo m´ es gen` eric i em va donar la clau per alguns components b` asics i consells per dissenyar la versi´ o de l’aplicaci´ o web presentada al 2009. Les pr` actiques d’aquesta assignatura van obrir-me la ment al m´ on del desenvolupament de programari per components i van donar or´ ıgen a la primera versi´ o d’aquest projecte. Des de llavors, les versions han estat succeint-se poc a poc, amb la remodelaci´ o de components, reescriptures, refactoritzacions de components i nous components per resoldre problemes b` asics. Aquest projecte ha estat utilitzat en un parell d’ocasions per muntar aplicacions web, una d’elles munt` a una aplicaci´ o web per enviament i gesti´ o de missatges SMS per part d’una empresa, una aplicaci´ o web multiusuari que permet enviar missatges curts a tel` efons m` obils amb agenda i gesti´ o i classificaci´ o d’aquestos missatges; va ser programada en una est` ancia en pr` actiques en l’empresa Open Xarxes Coop.V des de setembre a desembre de l’any 2010. 1.7.1 Cronologia de versions V 0.01 : Novembre de 2009, primeres proves del marc de treball. V 0.05 : Gener de 2010, reescriptura total del projecte. V 0.10 : Marc¸ de 2010, implementaci´ o del sistema d’enrutat, configuraci´ o i despatxament de peticions web. V 0.11 : Juny de 2010, implementaci´ o d’Active Record. V 0.5 : Setembre de 2010, refactorizaci´ o del sistema d’enrutat i diferents components. V 0.7 : Octubre de 2010, clients de REST i sistema de plugins. 1.7. HIST ` ORIA I VERSIONS D’AQUEST PROJECTE 19 V 0.8 : Desembre de 2010, refactoritzaci´ o del sistema de configuraci´ o i d’Active Record. V 0.9 : Desembre de 2010, llanc¸ament d’aplicaci´ o per enviament d’SMS. V 1.0 : Febrer de 2011, reescriptura total de v` aries parts del projecte. V 1.3 : Marc¸ de 2011, reescriptura d’Active Record, Front Controller i base de dades. V 1.45 : Abril de 2011, reescriptura de l’API de plugins i configuraci´ o. V 1.49 : Maig de 2011, implementaci´ o del sistema de layouts, reescriptura de sistemes de SOAP i REST, refactoritzaci´ o de Front Controller, implementaci´ o de sistema Filter, implementaci´ o de validacions. V 1.50 : Juny de 2011, reescriptura del component de logging, autenticaci´ o, connexi´ o amb bases de dades. Descripci´ o i documentaci´ o de tot el projecte. 20 CAP´ ITOL 1. INTRODUCCI ´ O Cap´ ıtol 2 Antecedents 2.1 Introducci´ o En aquesta secci´ o es presenten una breu hist` oria i evoluci´ o del desenvolupament web al llarg del darrers anys. 2.2 Estat de l’art: evoluci´ o 2.2.1 CGI Common Gateway Interface El Common Gateway Interface sigles de CGI ´ es un est` andard (veure RFC 3875) que defineix com el servidor web pot delegar la generaci´ o de p` agines a un programa o fitxer executable. Aquestos programes coneguts com scripts CGI poden ser escrits en qualsevol llenguatge de programaci´ o. Hi va haver una ` epoca en que a trav´ es del CGI era la ´ unica manera d’executar contingut din` amic. S’utilitzava molt per arreplegar valors en funcionaris de contacte. El llenguatge de programaci´ oPerl estava de moda i era el que va comenc¸ar a fer la revoluci´ o dels llenguatges din` amics, malgrat aix` o, les grans empreses o prove¨ ıdors generaven els seus CGI en llenguatges tant poc din` amics i flexibles com C o C++. Actualment totes les limitacions de CGI han estat superades i la majoria de plataformes funcionen de la mateixa manera que ho feia en l’` epoca CGI: delegant l’execuci´ o en programes externs. 2.2.2 Llenguatges din` amics Despr´ es del boom de l’` epoca del CGI, les grans companyies de programari comenc¸aren a desenvolupar els seus llenguatges de programaci´ o per programar CGIs. Apareixen les primeres versions de Microsoft ASP que permet fer aplicacions web amb l’ajuda de Visual Studio. M´ es tard apareixen de la ma de Sun Microsystems les primeres versions de Java per a la web (Java Server Pages) i J2EE . . . Per part del programari lliure, el llenguatge de programaci´ o preferit per programar webs ´ es Perl que poc a poc va deixant pas a un derivat seu que avui es coneix com a PHP. Tamb´ e sorgeixen alternatives com Python o la m´ es moderna, Ruby on Rails. 21 22 CAP´ ITOL 2. ANTECEDENTS Avui en dia el mercat est` a repartit entre Ruby on Rails, Microsoft ASP.NET, PHP i totes les implementacions corporatives de Java per a aplicacions web. 2.2.3 AJAX i la Web 2.0 AJAX s´ on les sigles de Asynchronous Javascript And Xml, (JavaScript as´ ıncron i XML), un conjunt de tecnologies que permeten actualitzar continguts web sense haver de tornar a carregar la p` agina, obrint la port a aplicacions web interactives. Ajax ´ es as´ ıncron en tant que les dades addicionals s´ on demanades i carregades en un segon pla, sense interferir en la presentaci´ o i el comportament de la p` agina. Habitualment les funcions d’Ajax es criden des del llenguatge JavaScript. S’encarega d’enviar una petici´ o HTTP al servidor i espera una resposta, que processar` a i actualitzar` a dades en la p` agina. Ajax ´ es multiplataforma i es pot usar en diversos sistemes operatius, arquitectures de computador i navegadors web ja que es basa en est` andards oberts com JavaScript i DOM. Hi ha implementacions open source de frameworks i llibreries, en especial els frameworks m´ es utilitzats: (jQuery,ExtJS,Yahoo User Interface,Mootools iGoogle Web Toolkit). Un framework de Java Script ajuda molt a desenvolupar una p` agina din` amica i interactiva, ja que permet fer m´ es f` acil la programaci´ o de les peticions AJAX, d’animacions sobre elements i de navegaci´ o i transformaci´ o sobre els nodes DOM de la p` agina. Des del moment que va eixir la possibilitat d’utilitzar AJAX i aquest es va popularitzat, no han deixat d’apar` eixer noves i curioses formes de programar la web i de fer que cada vegada s’assemble m´ es a una aplicaci´ o d’escriptori que no pas a un formulari HTML amb programaci´ o din` amica per darrere. L’evoluci´ o d’AJAX natural ´ es cap a la utilitzaci´ o de formats d’intercanvi de dades m´ es lleugers que XML (donat el temps de processament que tarda aquest format tant en el servidor com en el client) cap al format JSON (Java Script Object Notation) que al ser natiu de Java Script redueix els temps de manipulaci´ o i processament de la resposta en el propi navegador. Cap´ ıtol 3 Tecnologies 3.1 Introducci´ o Aquest projecte intenta emprar les darreres tecnologies i est` andars apareguts en el m´ on del programari orientat a objectes, l’enginyeria web, les arquitectures orientades a serveis i els darrers avanc¸os en web per a dispositius m` obils. El marc de treball prove¨ ıx una gran compatibilitat amb totes les plataformes en les que es pot fer servir, proporcionant una implementaci´ o allunyada de les caracter´ ıstiques dels sistemes operatius sobre els quals funciona, i els servidors web en els quals pot funcionar donant servei. Aix´ ı mateixa, al estar adaptat als est` andars de nova generaci´ o - per exemple l’XHTML 1.1 o l’HTML 5, SOAP, JSON . . . - , i que s´ on de molta difusi´ o; es garantitza una interoperabilitat entre plataformes. 3.2 Tecnologies de costat del servidor 3.2.1 PHP: PHP HyperText Processor PHP ´ es un llenguatge de programaci´ o interpretat i orientat a objectes que s’utilitza per a generar p` aginas web din` amiques. S’executa en el servidor mitjanc¸ant un int` erpret (o m` aquina virtual) que s’encarrera de compilar en temps d’execuci´ o el codi font en un llenguatge intermig de la m` aquina virtual, i despr´ es en codi m` aquina del sistema operatiu i m` aquina sobre el que s’executa. PHP es distribueix sota la llic` encia PHP, que la Free Software Foundation qualifica com a programari lliure. El llenguatge de programaci´ o PHP Com s’ha mencionat abans, PHP ´ es un llenguatge de programaci´ o orientat a objectes i d` ebilment tipat amb una sintaxi mescla entre C++,Perl i Java; dels quals agafa la majoria de conceptes. PHP permet - des de la versi´ on 4.0 - declarar classes, objectes i interf´ ıcies, el qual el fa molt flexible, ad´ es, la facilitat amb la que es poden gestionar els arrays o vectors; la senzillessa de connexi´ o a bases de dades i l’abs` encia de punters fa que PHP siga un llenguatge de programaci´ o molt emprat i senzill d’apendre, productiu a la vegada i f` acil de depurar. L’Entorn de producci´ o/execuci´ o de PHP L’entorn de producci´ o de PHP consisteix generalment en un int` erpret que junt a unes quantes biblioteques i extensions proporciona una API per a execuci´ o de guions d’or23 24 CAP´ ITOL 3. TECNOLOGIES dres en mode CGI. Aquesta API de CGI ´ es l’encarregada de comunicar-se amb el servidor web tant d’entrada com d’eixida de dades. Aix´ ı doncs, el servidor web s’encarrega de cridar a PHP amb certes dades d’entrada, PHP produeix unes dades d’eixida en resposta a les entrades, i les torna al servidor, que a la seva vegada les tornar` a al client que va demanar-les. Aquest entorn de producci´ o´ es fortament depenent del sistema operatiu sobre el que s’execute tot, malgrat que PHP ´ es multiplataforma - ´ es a dir, funciona i s’executa sobre diversos sistemes operatius i arquitectures de computadors - i hi ha un gran nombre de servidors web sobre els quals funciona PHP que s´ on tamb´ e multiplataforma. PHP, per tal d’abstraure tota la implementaci´ o per als diferents sistemes operatius, encapsula sota el mateix nom m` etodes i funcions que tornen els mateixos valors per` o implementats de diferent forma en cada plataforma. Per a comenc¸ar a produir p` agines PHP nom´ es es necessita un entorn m´ ınim que ´ es un int` erpret de PHP (o distribuci´ o), un servidor web - Apache2 ´ es el recomanat i m´ es emprat per la seva difusi´ o - i una base de dades - MySQL ´ es la m´ es est` andar i multiplataforma - . Amb tot aix` o i junt amb un editor de text o un entorn de programaci´ o integrat 1 es poden generar aplicacions web d’una manera r` apida i senzilla, sense disposar d’una gran i complexa instal·laci´ o que sobrecarregue la m` aquina servidora. Una manera r` apida de comenc¸ar amb PHP ´ es descarregar-se el paquet XAMPP des de l’adrecc¸a http://www.apachefriends.org/en/xampp.html que cont´ e tots els elements necessaris per a muntar un servidor web de p` agines din` amiques en pocs minuts i sota qualsevol sistema operatiu. Errors comuns, fallades de seguretat Malgrat tot aix` o, ´ es com´ u que en PHP el desenvolupador novell - tal vegada per falta de pr` actica - s’oblide de la seguretat que ´ es un dels temes pendents en totes les plataformes de programaci´ o d’aplicacions web, i que degut a la globalitzaci´ o d’internet, i a la facilitat d’explotar aplicacions web de tot tipus a dist` ancia i d’amagat; i per aix` o hi haja moltes ”fallades”a causa del que s’anomena security flaws o injeccions de codi PHP, HTML, SQL o JavaScript. La seguretat en tota aplicaci´ o´ es un tema molt important, per aix` o el marc de treball descrit en aquest projecte fa ` emfasi en aquestes q¨ uestions, forc¸ant i ajudant al desenvolupador a que evite els errors de seguretat, i que l’aplicaci´ o web que amb aquest marc de treball programe siga fiable i segura en un alt percentatge. Tamb´ e´ es responsabilitat del programador el comprovar els tipus de les variable i objectes de PHP, ja que al ser un llenguatge d` ebilment tipat, les variables i el seu tipus s’assignen en temps d’execuci´ o i sense comprovaci´ o del tipus; podent provocar errors inesperats. 3.2.2 SOAP: Simple Object Access Protocol SOAP (Simple Object Access Protocol o Protocol Simple d’Acc´ es a Objectes) ´ es un protocol de comunicaci´ o dissenyat per intercanviar missatges en format XML entre aplicacions connectats mitjanc¸ant una xarxa, i sobre el protocol HTTP. Est` a pensat per facilitar la comunicaci´ o entre aplicacions, independentment de la plataforma on s’executen i del llenguatge de programaci´ o en qu` e estiguen implementades. ´ Es senzill i f` acilment extensible. El protocol SOAP es basa en RPC Remote procedure Callque ´ es una tecnologia que permet a un programa fer que una subrutina o procediment s’execute en un altre espai d’adreces (habitualment en un altra m` aquina en una xarxa compartida) sense que 3.2. TECNOLOGIES DE COSTAT DEL SERVIDOR 25 el programador haja de programar expl´ ıcitament els detalls d’aquesta interacci´ o remota. ´ Es a dir, el programador escriuria una cridada a un procediment que est` a en altra m` aquina sense haver de preocupar-se per els detalls de la invocaci´ o ni el transport de les dades des de i fins a la m` aquina on s’ofereix el procediment o subrutina a executar. A m´ es a m´ es, SOAP tamb´ e cont´ e: •Informaci´ o adicional inclosa en el document XML que descriu el contingut, i les operacions que es poden executar i que ofereix el servidor remotament. •Definici´ o dels par` ametres d’entrada i eixida de cada operaci´ o que s’ofereix remotament. •Definici´ o de tipus de dades complexos i/o estructurats que permeten enviar i rebre dades complexes/objectes entre client i servidor. WSDL: Web Services Description Language WSDL s´ on les inicials de Web Services Description Language, un format XML que s’utilitza per descriure Serveis web. WSDL descriu la interf´ ıcie p´ ublica dels serveis web. Est` a basat en XML i descriu la forma de comunicaci´ o, ´ es a dir, els requeriments del protocol i els formats dels missatges necessaris per interactuar amb els serveis que es troben en la llista del seu cat` aleg. Les operacions i missatges que admet es descriuen de forma abstracta i s’enllacen despr´ es al protocol concret de xarxa i al format del missatge. Un programa client que es connecta a un servei web pot llegir la descripci´ o WSDL per determinar quines funcions es troben disponibles al servidor, quins s´ on els seus par` ametres d’entrada i els d’eixida. A banda, WSDL tamb´ e permet especificar tipus de dades complexos que poden emprar-se en les funcions del servidor o en les peticions del client. Actualment WSDL ´ es la forma m´ es utilitzada d’especificaci´ o de serveis web ja que amb la informaci´ o que cont´ e un sol document WSDL el client ´ es capac¸ de generar un pont d’acc´ es a una operaci´ o remota amb tots els par` ametres necessaris per a que el programador puga utilitzar aquest pont com si estigu´ es cridant a operacions dins del propi sistema malgrat que SOAP s’encarrega de processar la petici´ o, encaminar-la al servidor remot, esperar l’execuci´ o de l’operaci´ o, retornar un resultat (o error) i per ´ ultim tornar-li les dades demanades al programa client que va invocar la operaci´ o. Tot aix` o es fa de forma transparent al programador que s’abstrau dels detalls de com es transporten les dades del client al servidor remot i nom´ es ha de saber qu` e par` ametres s´ on d’entrada i quins d’eixida. 3.2.3 REST REST, acr` onim de Representational State Transfer ´ es una arquitectura de programari per a continguts hiperm` edia distribu¨ ıts sobre Internet, seguint la filosofia de la WWW. El terme es va originar l’any 2000, apareixent per primera vegada a una tesi doctoral sobre la web escrita per Roy Fielding, un dels principals autors de l’especificaci´ o de l’HTTP. El terme REST es refereix originalment a un conjunt de principis per al disseny d’arquitectures en xarxa. Aquests principis resumeixen com els recursos s´ on definits. El terme freq¨ uentment ´ es emprat en el sentit de descriure qualsevol interf´ ıcie que transmet dades espec´ ıfiques d’un domini sobre HTTP sense una capa addicional, com fa SOAP. Aquests dos significats poden xocar i fins i tot solapar-se. ´ Es possible 32 CAP´ ITOL 4. ARQUITECTURA I FUNCIONAMENT DEL PROJECTE Request : Objecte que encapsula tots els par` ametres de la petici´ o HTTP, i els fa disponibles a tota l’aplicaci´ o web. Router : Pec¸a clau que s’encarrega de processar tots els fitxers de connexions inclosos en el sistema i que defineixen les accions,qu` e m` etodes s’han de cridar per dur a terme l’acci´ o (executar-la), i quins par` ametres necessita aqueixa acci´ o per a que siga efectiva l’execuci´ o. Una vegada ha processat totes les connexions (o les ha carregades d’un fitxer serialitzades) i les t´ e carregades en mem` oria passa a atendre la petici´ o HTTP actual, cercant d’entre totes les connexions carregades quina ´ es la que ha d’executar (la que la URL correspon a la URL especificada en la connexi´ o). Aquest element proporciona una gran flexibilitat al sistema per a poder fixar adreces arbitr` aries i SEO-friendly 1important per al posicionament de p` agines web en els principals cercadors. Una vegada s’han obtingut tots els par` ametres que descriuen l’acci´ o a executar, es passa al seg¨ uent element Front Controller. El Front Controller o despatxador de peticions ´ es la pec¸a del sistema que s’encarrega de que - a partir dels par` ametres obtinguts per el Router - trobar l’acci´ o a executar, i executar-la. Per tal de fer flexible i ampli el marc de treball, el Front Controller divideix segons el tipus de petici´ o el processament, cerca d’acci´ o, i execuci´ o en diverses classes relacionades amb aquest component que s’encarreguen d’obtindre resultats per a cada tipus de petici´ o ja siga del tipus que siga. El controlador ´ es un conjunt de classes (una o v` aries per m` odul de l’aplicaci´ o web), que estan destinades a mantindre les accions que poden ser executades en el sistema. Cada controlador proveeix d’acc´ es directe al corresponent model que ´ es a trav´ es de qui obt´ e les dades a processar per la l` ogica de negoci de la base de dades o de serveis web. Ad´ es, tamb´ e proveeix de m` etodes que permeten renderitzar vistes de la capa superior; la de presentaci´ o . Per tant, aquesta capa ´ es la m´ es important de tot el sistema, i ´ es pec¸a central del patr´ o MVC, Model-View-Controller (Model-Vista-Controlador), que permet desacoblar la l` ogica de negoci de la persist` encia i la presentaci´ o. Aquest projecte utilitza aquest patr´ o de disseny junt al patr´ o anomenat Front Controller per a proveir d’un potent sistema modularitzat i amb baix acoblament. 4.1.3 Capa de presentaci´ o La capa de presentaci´ o´ es la que s’encarrega de mostrar al usuari el resultat de l’excuci´ o de les accions d’una manera visual, o de rebre el resultat d’una acci´ o demanada mitjanc¸ant un servei web. En el cas que la presentaci´ o siga mitjanc¸ant un client web, s’empren diferents petites porcions de codi anomenades viewso vistes que contenen codi xhtml, JavaScript,CSS i/o PHP. Ad´ es, per a fer una separaci´ o de codi m´ es efectiva, tamb´ e es poden desacoblar de la vista els codis de JavaScript o de CSS ficantlos en fitxers a banda, i que s´ on carregats a demanda en cada petici´ o HTTP evitant que tota l’aplicaci´ o web tinga carregat estils CSS o pedac¸os de JavaScript no necessaris per la vista que actualment s’est` a mostrant, alleugerant aix´ ı en la mida possible el pes i 1SEO: sigles de “Search Engine Optimization“ - Optimitzaci´ o per a motors de recerca - 4.1. INTRODUCCI ´ O33 temps de c` arrega d’una aplicaci´ o web. Per tal de produir vistes din` amiques, es poden emprar diferents tipus de funcions ajudants helpers que poden ajudar a fer tasques repetitives (exemple: inserir un enllac¸, inserir taules. Tamb´ e es poden construir widgets (un conjunt de codis xhtml, JavaScript i CSS que representen una petita funcionalitat dins una web), ad´ es; tamb´ e es poden instanciar plugins que mostren qualsevol resultat d’alg´ un processament, que envien correus electr` onics, sms, o que inserisquen un mapa dins una vista - sempre fent-ho amb el menor nombre de l´ ınies possibles i la major claredat - . Per a terminar, tamb´ e´ es possible que vistes renderitzen altres vistes,o que criden a altres accions del controlador podent construir una vista complexa amb moltes vistes simples. 34 CAP´ ITOL 4. ARQUITECTURA I FUNCIONAMENT DEL PROJECTE Cap´ ıtol 5 Components del marc de treball 5.1 Introducci´ o En aquest cap´ ıtol es fa una presentaci´ o de tots els components importants per el funcionament del marc de treball. Per a cada component, es descriu breument, es mostra la seva utilitat i un diagrama UML mostrant per a cada cas el component i els seus subcomponents - en cas de que els haguera - . Es presenta tamb´ e una breu refer` encia al patr´ o de disseny emprat per implementar cada component (si escau). Tots els components ac´ ı presentats estan programats dins el directori /framework/lib amb la corresponent documentaci´ o (en idioma angl` es), aquesta documentaci´ o es troba b´ e en el cap´ ıtol corresponent del component dins d’aquesta mem` oria (en cas de components molt prioritaris) o dins la documentaci´ o que acompanya a aquesta mem` oria i que est` a generada autom` aticament per el programa PHPDoc. Totes les classes, per necessitats del sistema afegeixen al nom del component el prefix FW que indica al sistema que ´ es una classe del marc de treball i li facilita la tasca al sistema de Bootstrap o c` arrega de dades, donada aquesta difer` encia amb la resta de classes i el nom de cada classe (separades les paraules amb guions baixos  ), el sistema de Bootstrap sap que ha de trencar el nom per els guions baixos, substituir-los per el car` acter separador de directoris (car` acter /) i afegir-li el sufix .class.php . Per tant, per trobar un fitxer d’un component, s’ha de fer el mateix que fa Bootstrap a partir del directori /framework/lib. 5.2 Active Record Active Record engloba un conjunt de classes que serveixen per fer un mapeig de dades Objecte-Relacional,´ es a dir, que s’encarreguen de generar objectes a partir d’informaci´ o desada en una base de dades relacional. Per fer el proc´ es de mapeig es necessita con` eixer dades de l’objecte a representar i la seva correspond` encia en una taula d’una base de dades relacional. Aquest proc´ es es fa autom` aticament mitjanc¸ant les API de reflexi´ o d’objectes en PHP - que s´ on capaces de fer instrospecci´ o en un objecte i 35 36 CAP´ ITOL 5. COMPONENTS DEL MARC DE TREBALL obtindre les seves propietats - i obtenint informaci´ o d’una taula de la base de dades. 1 Active Record proporciona una manera neta, r` apida i senzilla d’obtindre les dades d’una base de dades en forma d’objectes mitjanc¸ant la implementaci´ o d’una versi´ o del patr´ o de disseny ActiveRecord original de Ruby On Rails - utilitzat amb molt d’` exit en Ruby On Rails - i descrit per Martin Fowler en Patterns of Enterprise Application Architecture. Abstrau al desenvolupador de gestionar directament SQL i redueix les possibilitats d’un atac mitjanc¸ant SQL-Injection. A m´ es a m´ es, al transformar les dades de la base de dades relacionals en objectes, el desenvolupador es beneficia de tot un m´ on d’avantatges que permet el disseny de sistemes orientat a objectes ja que cada objecte pot encapsular l` ogica i regles de negoci segons les necessitats del client i a la vegada tindre una forma senzilla i elegant de poder guardar eixos canvis en l’objecte i els objectes relacionats en una base de dades relacional sense gaires esforc¸os per al desenvolupador. Es pot dir, que ActiveRecord ´ es el component m´ es important i gran del marc de treball i dota a aquest de facilitat per construir aplicacions web o serveis web. En conclusi´ o, un disseny m´ es senzill, un desenvolupament m´ es r` apid. 5.2.1 Components d’Active Record Components generals Active Record t´ e els seg¨ uents components principals: Model : Proporciona les funcionalitats b` asiques per a implementar un objecte i que es puga fer servir amb ActiveRecord. Totes les classes del model de dades han d’estendre de la classe Model per a aix´ ı poder utilitzar tots els avantatges que Active Record proporciona. Tamb´ e proporciona funcionalitats avanc¸ades per convertir dades a formats CSV, XML, JSON o importar-ne dades des d’aquestos formats. Tree : Extensi´ o de Active Record Model que proporciona una manera de gestionar les col·leccions de dades jer` arquiques com s´ on els arbres de dades. Active Record : Proporciona les funcionalitats comunes en una base de dades per al mapeig objecte-relacional, es suporta en ActiveRecord Metadata Manager i ActiveRecord Metadata Schema per obtindre informaci´ o sobre un objecte del model de domini i en ActiveRecord Query Builder per generar les consultes necess` aries per obtindre les dades de la base de dades i generar aix´ ı un objecte i totes les seves relacions. Utilitza el component Database per transferir-li les consultes SQL (sempre en est` andar SQL92/99) a la base de dades utilitzada per a cada cas. Result : Proporciona una col·lecci´ o d’objectes d’Active Record (resultats d’una consulta) i els m` etodes per rec´ orrer-la. Tamb´ e proporciona funcionalitats avanc¸ades per convertir dades a formats CSV, XML, JSON o importar-ne dades des d’aquestos formats. Relation : Proporciona una estructura de dades en les que emmagatzemar les relacions amb altres objectes d’una propietat d’un model d’Active Record. En aquestes re1El proc´ es est` a descrit amb m´ es detall en el cap´ ıtol corresponent al model de dades, en la part de desenvolupament 5.2. ACTIVE RECORD 37 lacions es poden obtindre, filtrar i cercar les dades gr` acies a que hereten m` etodes de Result i d’Active Record. Pagination : Proporciona funcionalitats de paginaci´ o de resultats i ajudants per mostrar en les vistes el n´ umero de p` agines, les p` agines i n´ umero de resultats disponibles. Exception : Proporciona excepcions que llanc¸a el sistema Active Record. Esquemes El component Active Record ha de saber per a cada model amb el que tracta quines columnes t´ e i quins tipus de dades tenen eixes columnes aix´ ı com les relacions entre models. Manager : Classe que funciona com a dip` osit general de tots els esquemes d’Active Record. Schema : Classe que analitza els models i proporciona informacions sobre les seves columnes, tipus de dades i relacions amb altres models. Generaci´ o de consultes El component Active Record delega en v` aries classes l’escriptura de consultes SQL o No-SQL de forma que aquestes siguen capac¸os d’escriure les consultes corresponents segons convinga i segons els models sobre els que s’utilitza. Aquesta part est` a implementada utilitzant el patr´ o de disseny Strategy de forma que es puga desacoblar la generaci´ o de consultes segons el tipus de base de dades utilitzat, ja siga SQL o NoSQL. En concret per aquestes darreres bases de dades (les No-SQL) el sistema encara no funciona, per` o ja est` a preparat per emprar un generador espec´ ıfic per cada tipus de base de dades No-SQL majorit` aria existent (CouchDB,Cassandra, . . . ) donat que es considera que seran en breu una forma d’emmagatzemar dades. L’eixida d’aquestes consultes s’envia directament al component Database que les executa contra la base de dades utilitzada a cada moment i segons convinga. QueryBuilder : Proporciona una classe base sobre la que fer les cridades a generaci´ o de consultes per executar-les en la base de dades. Gestiona els generadors de consultes (actualment nom´ es per a SQL 99 est` andard) i delega en ells la responsabilitat de generar la consulta corresponent. QueryBuilder Base : Classe b` asica i abstracta per implementar generadors de consultes. QueryBuilder SQL : Genera les consultes SQL necess` aries per consultar a la base de dades. Validaci´ o de models El component Active Record tamb´ e proporciona validacions de dades en totes les columnes d’un objecte de domini per evitar que s’inserix-ca informaci´ o incorrecta en la base de dades. Les validacions poden ser de cinc tipus: 38 CAP´ ITOL 5. COMPONENTS DEL MARC DE TREBALL •De tipus de dades en cada columna: Cada columna t´ e un tipus de dades b` asic que ha de ser respectat. •De llarg` aria del contingut de cada columna: Per a cada columna es defineix a banda d’un tipus de dades una llarg` aria m` axima i m´ ınima. •De valors nuls: Una columna que no accepte valors nuls no podr` a contindre mai un valor nul donat que provocaria un error en la base de dades. •De clau prim` aria: Assegurar-se de no repetir valors i no inserir valors nuls en aquestes columnes. •De unicitat: Assegurar-se que el valor de la columna ´ es ´ unic i est` a inserit ja en la base de dades. •Personalitzats: Es poden fer validacions personalitzades sobre qualsevol de les columnes del model. Validator : Aquest objecte analitza el esquema del model i valida pas per pas cadascun dels valors de les propietats de l’objecte. En quant a patrons de disseny Active Record implementa els seg¨ uents patrons de disseny: •Singleton a ActiveRecord Medatada Manager •Active Record a Model,Tree iActiveRecord •Iterator a ActiveRecord Result •Registry a ActiveRecord Medatada Manager 5.3. AUTHENTICATION 39 Figura 5.1: Diagrama UML del sistema ActiveRecord 5.3 Authentication El component Authentication proveu de serveis d’autenticaci´ o d’usuaris al marc de treball. Authentication utilitza una s` erie de regles per determinar la forma d’autenticar usuaris. Proveu autenticaci´ o via tres handlers (mecanismes): database : Autenticaci´ o mitjanc¸ant la base de dades. imap : Autenticaci´ o mitjanc¸ant servidors IMAP htpasswd : Autenticaci´ o mitjanc¸ant fitxers httpasswd generats per el servidor web Apache. Aquestos mecanismes poden ser configurats en forma de regles en el fitxer de configuraci´ oauthentication.php situat en el directori de configuraci´ o. Es preveu poder donar suport a autenticaci´ o via protocol OAuth en un futur. OAuth permetr` a una millor autenticaci´ o i integraci´ o amb les aplicacions web 2.0 que utilitzen aquest protocol per identificar els usuaris i intercanviar-ne dades. 40 CAP´ ITOL 5. COMPONENTS DEL MARC DE TREBALL Figura 5.2: Diagrama UML del component Authentication 5.4 Browser El component Browser s’encarrega de la detecci´ o de les caracter´ ıstiques de l’agent d’usuari (navegador) a trav´ es del qual es fa una petici´ o http al marc de treball. Browser pot identificar - llegint la capc¸alera HTTP USER AGENT que envia el client en una petici´ oHTTP - el tipus de navegador emprat per a la petici´ o, la seva versi´ o, i el sistema operatiu sobre el que funciona el navegador. Browser tamb´ e implementa el patr´ o de disseny Singleton. Figura 5.3: Diagrama UML del component Browser 5.5 Cache El component Cache ´ es un component essencial en tota aplicaci´ o web que vaja a suportar una c` arrega de tr` afic molt gran. Cache implementa un sistema de caching de dades que permet desar dades en el disc dur o en la base de dades (segons el driver de cach´ e escollit) durant un temps definit i recuperar eixa informaci´ o per a posterior usos. Aix` o evita que cada petici´ o es processe una gran quantitat d’informaci´ o que pot durar prou temps fent que el sistema tinga una pobre resposta. Es poden cachear els seg¨ uents tipus de dades: 5.5. CACHE 41 •Eixida d’una acci´ o. Es desen en la cach´ eles dades produ¨ ıdes com a eixida de l’execuci´ o d’una acci´ o. •Plantilles XHTML. Es poden desar plantilles ja composades i amb les dades necess` aries. •Dades de l’usuari, dades interm` edies que es gastaran m´ es tard , qualsevol informaci´ o que siga necess` aria i comporte un gran consum de processament de dades. El component Cache t´ e quatre formes de guardar les dades: •En fitxers en el disc dur: Desa les dades en fitxers en el disc dur. •En bases de dades: Desa les dades en una taula especialment dissenyada en la base de dades que utilitza el sistema. •En base de dades SQLite3 en mem` oria: Desa les dades en una base de dades en mem` oria en el gestor de bases de dades SQLite3, que escrit en C i molt optimitzada ´ es una de les bases de dades m´ es r` apides existents avui en dia. •En Memcache: Utilitza una extensi´ o de PHP per el sistema Memcached, que empra com a sistema d’emmagatzematge la mem` oria RAM, redu¨ ınt aix´ ı la necessitat d’accessos a disc dur o a bases de dades. El sistema de cach´ e desa dades identificades per id (habitualment es fa un md5 de la cadena ’Module—Controller—Action—Internal’ amb les dades corresponents a cada acci´ o, de forma que l’identificador ´ es ´ unic i f` acil de generar, tamb´ e s’identifiquen per una clau anomenada namespace o espai de noms i el ttl o temps de vida de les dades. Aix´ ı doncs, unes dades tenen un identificador en un espai de noms i un temps de vida. Passat aquest temps de vida (si la data de les dades convertida a segons des de l’inici de l’` epoca UNIX sumada al temps de vida ´ es major o igual que la data i hora del sistema en el moment que es gener` a la petici´ o) el sistema donar` a per expirades les dades. Figura 5.4: Diagrama UML del component Cache Aquest component implementa els patrons de disseny Singleton iStrategy 48 CAP´ ITOL 5. COMPONENTS DEL MARC DE TREBALL 5.15 HttpResponse Aquest component implementa una forma unificada i centralitzada de generar les capc¸aleres HTTP en resposta a cada petici´ o HTTP. Permet enviar capc¸aleres de cach´ e, de tipus de contingut, d’autenticaci´ o o personalitzades. Implementa el patr´ o de disseny Singleton de manera que nom´ es existeix una inst` ancia en tot el sistema d’aquest component que envia les capc¸aleres HTTP de resposta. Figura 5.13: Diagrama UML del component HttpResponse 5.16 Locale - I18N (internacionalitzaci´ o) El component Locale permet fer aplicacions multiling¨ ues amb el marc de treball. Proporciona serveis per a traduir-ne cadenes o textos i per a seleccionar el fitxer d’idioma - o locale - corresponent per a cada usuari traduint autom` aticament la web de forma totalment transparent a l’usuari. 5.17. LOG 49 Figura 5.14: Diagrama UML del component Locale 5.17 Log El component Log proveu d’un mecanisme de logging d’errors al marc de treball. Logger pot desar els missatges dels log de les seg¨ uents formes: •Text pla/fitxer .log : Desa els missatges de log dins un fitxer de text pla. •Base de dades: Desa els missatges de log dins una taula en una base de dades. •Correu electr` onic: Envia cada log per correu electr` onic. Figura 5.15: Diagrama UML del component Log Log implementa els patrons de disseny Singleton iStrategy, de manera que amb el primer es fa accessible des de qualsevol punt del marc de treball i amb el segon desacobla la l` ogica i algorismes de desat dels logs per a cada tipus. 5.18 Mailer Mailer ´ es un component encarregat de l’enviament de correus electr` onics. Fa us de la biblioteca externa PHP Mailer que proveu al marc de treball de capacitat per enviar tot tipus de correu electr` onics, incloent-hi aquells en format html o amb fitxers adjunts. Mailer implementa el patr´ o de disseny Wrapper oAdapter, ja que ´ es un embolcall de l’API de la biblioteca externa PHP Mailer 50 CAP´ ITOL 5. COMPONENTS DEL MARC DE TREBALL Figura 5.16: Diagrama UML del component Mailer 5.19 MVC El sistema MVC ´ es un component que permet al desenvolupador desenvolupar les funcionalitats de la seva aplicaci´ o web. Consisteix en un sistema composat per: BaseController : Classe base que representa la funcionalitat b` asica a utilitzar en la part del controlador del sistema MVC. BaseModel : Classe que representa la funcionalitat b` asica a utilitzar en la part del model d’una aplicaci´ o escrita amb sistema MVC. A m´ es a m´ es, proveeix un acc´ es a la base de dades. Views : Fitxers que implementen vistes,´ es a dir codi XHTML mesclat amb un m´ ınim de codi PHP. Un m` odul del sistema MVC es composa com a m´ ınim d’una classe controlador - que ha d’estendre de BaseController - , i una classe model - que ha d’estendre de la classe BaseModel -2. Les aplicacions web que poden ser desenvolupades amb aquest marc de treball es basen en el sistema MVC, amb tal de desacoblar la l` ogica de negoci (Controller), de la presentaci´ o (View) i l’obtenci´ o de dades (Model). Aquest component implementa els patrons de disseny Model View Controller i el patr´ o HMVC o Hierarchical Model View Controller. Figura 5.17: Diagrama UML del sistema MVC 2Es detalla amb m´ es precisi´ o el proc´ es en el cap´ ıtol corresponent en la part de desenvolupament 5.20. PLUGINS 51 5.20 Plugins El sistema de Plugins permet al desenvolupador estendre les funcionalitat d’aquest mitjanc¸ant llibreries externes, codis de tercers, o funcionalitats pr` opies. Aquestes noves funcionalitats es poden agrupar en forma d’afegit o Plugin, de forma que siguen accessibles des de qualsevol acci´ o del sistema MVC. El sistema de plugins del marc de treball es composa d’una classe anomenada Plugin Registry, que carrega, gestiona i proporciona les funcionalitats necess` aries per obtindre el Plugin que es necessite a cada moment. Plugin Registry cont´ e un registre (implementat mitjanc¸ant el patr´ o de disseny Registry) de Plugins disponibles en el sistema i que poden utilitzar-se per realitzar qualsevol acci´ o i obtindre un resultat a l’acci´ o executada. Cada Plugin escrit per aquest marc de treball ha d’estendre de la clase Plugin Base, que proporciona funcionalitats de c` arrega de fitxers o biblioteques, de c` arrega din` amica de models de dades (els plugins tamb´ e poden utilitzar el sistema ActiveRecord), de gesti´ o de propietats/opcions de cada plugin dins la base de dades i de c` arrega i processament d’informaci´ o del fitxer de descripci´ o de cada plugin options.php iplugin.php A m´ es a m´ es, proporciona m` etodes que inicialitzen i configuren el plugin segons les opcions a utilitzar. 3 Els plugins permeten encapsular funcionalitats externes al marc de treball - fent us dels patrons de disseny Adapter oProxy - i accedir-ne a la funcionalitat externa a trav´ es de la interf´ ıcie del plugin. D’aquesta forma, es poden incorporar funcionalitats, existents en altres biblioteques al marc de treball permetent reutilitzaci´ o de codi font i ampliaci´ o de funcionalitats m´ es enll` a de la pr` opia aplicaci´ o web a desenvolupar amb el marc de treball. Est` a especialment recomanat per a utilitzaci´ o d’APIs web externes de manera que es cree un objecte que permeta fer-ne us d’aquestes d’una manera senzilla. Aquest sistema de Plugins implementa els patrons de disseny Registry iSingleton en Plugin Registry, i Adapter en Plugin Base. Figura 5.18: Diagrama UML del sistema de Plugins 5.21 Registry El component Registry ´ es una implementaci´ o del patr´ o de disseny Registry que permet al desenvolupador desar dades en un magatzem de dades en el sistema i accedir-ne a ell en qualsevol moment del cicle de l’aplicaci´ o. 3Per m´ es informaci´ o dels plugins, veure cap´ ıtol dedicat al tema en la part de desenvolupament 52 CAP´ ITOL 5. COMPONENTS DEL MARC DE TREBALL Amb Registry es proporciona una manera senzilla i endrec¸ada d’emmagatzemar i accedir-ne a aquestes dades. El component Registry est` a implementat com una classe abstracta, per tant, per fer us d’ella s’ha de crear una classe derivada amb les funcionalitats pr` opies del tipus de registre que es necessite. Figura 5.19: Diagrama UML del component Registry 5.22 Request Request ´ es un dels principals components del marc de treball. Request emmagatzema tots els par` ametres d’una petici´ o web, tals com els par` ametres passats via els m` etodes GET i POST, la URL de la petici´ o, i els fitxers enviats mitjanc¸ant formulari. Tamb´ e serveix per obtindre dades de la petici´ o HTTP (http referrer o des d’on v´ e la petici´ o HTTP), saber si s’est` a produint la petici´ o http des d’un entorn segur (HTTPS), si aquesta ve produ¨ ıda per una petici´ o http ajax o incl` os per obtindre certes informacions de les capc¸aleres de la petici´ o http. Aquest component ´ es accessible des de qualsevol punt del marc de treball degut a que est` a implementat seguint el patr´ o de disseny Singleton. Figura 5.20: Diagrama UML del component Request 5.23 REST Aquest projecte disposa d’una implementaci´ o completa per a proporcionar serveis web implementats mitjanc¸ant l’arquitectura REST (Representational State Transfer). Per una banda disposa del component Rest Server que proporciona les funcionalitats de servidor de serveis web REST mentre que per l’altra, la part del client la proporcionen els components Rest Client iRest Response amb els seus tipus de resposta Rest Response JSON iRest Response XML. 5.23. REST 53 5.23.1 Part del client El client de serveis web basats en l’arquitectura REST ´ es capac¸ de connectar-se a un servei web i obtindre dades mitjanc¸ant peticions HTTP amb els verbs que defineix l’arquitectura REST (GET,POST,PUT i DELETE). El client de REST est` a preparat per a consumir els dos formats m´ es habituals de dades per a aquestos serveis web, XML i JSON. Aix´ ı doncs, el client pot connectarse i obtindre informaci´ o en algun d’eixos formats que despr´ es ser` a transformada dins el marc de treball a elements utilitzables senzillament com s´ on els arrays en el cas de JSON i objectes de tipus SimpleXMLElement en el cas de XML. Tamb´ e´ es capac¸ d’interpretar les capc¸aleres de resposta HTTP i els errors que aquestes poden contindre. Aquest component empra la biblioteca CURL de PHP per a poder fer connexions HTTP, aix´ ı que ´ es indispensable que la instal·laci´ o de PHP compte amb aquesta biblioteca. 5.23.2 Part del servidor El servidor REST est` a implementat com una extensi´ o del sistema d’enrutament i Front Controller en l’especialitzaci´ o d’aquest ´ ultim anomenada FrontController Rest. S’encarrega de comprovar els tipus de par` ametres, el servei sol·licitat i el m` etode HTTP de la petici´ o per a despatxar-la, obtindre el resultat i enviar-lo de tornada al client. El servidor de rest suporta els formarts XML,JSON o qualsevol tipus de dades MIME per a respostes i peticions HTTP. Els serveis web desenvolupats per a REST han de retornar un array de dades que despr´ es ser` a convertit a XML,JSON o altres formats segons convinga. Figura 5.21: Diagrama UML del sistema de serveis web REST 54 CAP´ ITOL 5. COMPONENTS DEL MARC DE TREBALL 5.24 Router Router ´ es el component del sistema que s’encarrega de processar la petici´ o web (la url i par` ametres d’aquesta, en concret) i obtindre un resultat que indique la localitzaci´ o del codi - dins el sistema MVC - , que s’ha d’executar per satisfer la petici´ o web. Router basa el seu funcionament en l’exist` encia de diferents tipus de rutes - una ruta es una s` erie de dades (url, dades del sistema MVC, par` ametres necessaris per execuci´ o de l’acci´ o corresponent, dades d’autenticaci´ o, dades de cach´ e, . . . ) organitzades en forma d’arrays - . Cada ruta pot ser d’un dels seg¨ uents tipus: application, ajax ,json ,mime ,plugin, cron, redirect, rest, static i soap . Aquestes rutes resideixen en una estructura de dades que es carrega o genera en temps d’execuci´ o i per a cada execuci´ o del marc de treball. Per accelerar el processament d’aquestes rutes i guanyar temps i mem` oria, i evitar el processament de molts fitxers, primer es carreguen les rutes en mem` oria (processant tots els fitxers PHP que calguen) i quan l’estructura de dades necess` aria est` a formada i ordenada, es desa (serialitzada) en un fitxer binari que cont´ e les dades necess` aries per a que despr´ es el marc de treball siga capac¸ d’obtindre la mateixa informaci´ o per` o sense hacer de processar fitxers de rutes, la qual cosa fa un estalvi important de temps. Si aquest fitxer amb les dades serialitzades no existeix, es genera; per altra banda, si aquest fitxer existeix, nom´ es s’ha de carregar, tenint ja totes les dades en mem` oria, el component Router ja pot processar i enrutar la URL corresponent a la petici´ o web que ha entrat al sistema. Router ´ es el component m´ es cr´ ıtic de tot el marc de treball, ja que ´ es el motor que analitza cada petici´ o web i que obt´ e la informaci´ o de l’acci´ o que ha d’executar en cada moment el marc de treball. El component Router implementa el patr´ o de disseny Singleton. 5.25. SESSION 55 Figura 5.22: Diagrama UML del sistema Router 5.25 Session El component Session s’encarrega de gestionar i mantindre la informaci´ o relativa a la sessi´ o de PHP, que emmagatzema un conjunt de dades en mem` oria del servidor amb un identificador ´ unic per a cada usuari. Session permet mantindre informaci´ o necess` aria que s’ha de tindre en mem` oria entre peticions HTTP degut a que el protocol HTTP ´ es un protocol sense estat i no pot recordar-se de dades que havia de mantindre per a futures peticions. A banda, Session tamb´ e pot emmagatzemar informaci´ o que necessite l’usuari i informaci´ o de components interns del marc de treball. Session t´ e un seguit de m` etodes que ajuden a crear i destruir la sessi´ o, a comprovar si hi ha emmagatzemada una dada en la sessi´ o, a obtindre eixa informaci´ o i a substituir o desar eixa dada en la sessi´ o. Per finalitzar, Session implementa el patr´ o de disseny Singleton, per la qual cosa, nom´ es hi ha una ´ unica inst` ancia de Session en tot el sistema a la que es pot accedir-ne globalment. Figura 5.23: Diagrama UML del component Session 56 CAP´ ITOL 5. COMPONENTS DEL MARC DE TREBALL 5.26 SOAP Aquest projecte disposa d’una implementaci´ o completa per a proporcionar serveis web implementats mitjanc¸ant l’est` andard SOAP (Simple Object Access Protocol). Per una banda disposa dels components Soap Adapter iSoap Server que proporcionen les funcionalitats de servidor de serveis web SOAP mentre que per l’altra, la part del client la proporciona el component Soap Client. 5.26.1 Part del client El component que implementa part del client de SOAP, anomenat Soap Client ´ es un adaptador que utilitza la biblioteca de client SOAP nativa de PHP. Aquest component ´ es capac¸ de connectar-se a un servei web SOAP, obtindre una descripci´ o d’ell - a trav´ es del corresponent document WSDL - , crear un proxy per a utilitzar el servei i exposar-lo a la API del marc de treball. 5.26.2 Part del servidor La part del servidor de SOAP est` a implementada sobre la biblioteca Pear::SOAP degut als problemes que presenta l’API est` andard de SOAP de PHP i donat les facilitats que aquesta biblioteca proporciona per a generar el document WSDL autom` aticament a trav´ es de les classes exposades a SOAP. El component Soap Server adapta el servidor de SOAP de la citada biblioteca al marc de treball. Per fer que es comunique amb les funcionalitats del marc de treball desenvolupades en el sistema MVC i poder exposar els m` etodes d’aquestes a serveis web SOAP, existeix el component Soap Adapter, que s’encarrega d’analitzar cada m` etode que es vol adaptar i proporcionar un representant - o proxy - per a que el servidor de SOAP es dirigeix-ca al m` etode exposat a trav´ es de l’adaptador i aix´ ı es puguen exposar a SOAP funcionalitats del marc de treball. Figura 5.24: Diagrama UML del serveis web SOAP 5.27 Style El component Style s’encarrega de gestionar els temes o estils CSS, carregar-los a petici´ o de l’usuari o autom` aticament (incorporant les capc¸aleres a la vista corresponent) i proporcionar a l’usuari un llistat de temes per a que puga escollir el tema de la web 5.28. WIDGETS 57 que m´ es li convinga. Cada tema es defineix en un fitxer de configuraci´ o que indica per a cada m` odul i cada controlador de l’aplicaci´ o quins fitxers d’estils han de carregar-se. Aquesta c` arrega ´ es gestionada mitjanc¸ant la classe Theme que representa un tema - o agrupaci´ o d’estils - que cont´ e tota la informaci´ o sobre un tema a m´ es a m´ es d’informaci´ o sobre els fitxers CSS corresponents al tema. Style tamb´ e implementa el patr´ o de disseny Singleton fent-ho accessible des de qualsevol punt del marc de treball i el patr´ o de disseny Registry amb el qual emmagatzema informaci´ o del temes d’una manera ´ unica i ben gestionada. Figura 5.25: Diagrama UML del component Style 5.28 Widgets El sistema de Widgets d’aquest projecte, permet utilitzar pedac¸os de codi escrits en llenguatge xhtml, javascript i css en les vistes corresponents a accions del sistema MVC. ´ Es molt ´ util per a webs que es basen en una aparenc¸a mestra i que necessiten components que es repeteixen una i una altra vegada en les diferents vistes. Exemples d’aplicaci´ o s´ on els breadcrumbso barra que indica al navegant en quin lloc es troba, els calendaris interactius de les barres de men´ u o qualsevol cosa que necessite ser inclosa en totes les p` agines web generades amb el marc de treball. 64 CAP´ ITOL 6. PATRONS DE DISSENY APLICATS AL PROJECTE essent la clau la identificaci´ o de cada objecte. Un registre t´ e m` etodes per emmagatzemar informaci´ o, consultar si est` a emmagatzemada una informaci´ o, obtindre informaci´ o emmagatzemada i netejar l’informaci´ o emmagatzemada. En aquest projecte s’ha emprat el patr´ oRegistry en forma d’una classe abstracta amb una col·lecci´ o d’objectes. De forma que la classe client per a cada registre ha d’heretar de Registry i per her` encia podr` a emprar aquest patr´ o de disseny. Aquest patr´ o de disseny s’ha emprat en molts components com el registre de plugins el qual mant´ e en mem` oria informaci´ o dels plugins disponibles en el marc de treball i sap obtindre informaci´ o de com instanciar-lo a l’hora d’utilitzar-lo o el contenidor de par` ametres FW Container Parameter. Aquest patr´ o de disseny facilita el treball de guardar col·leccions de dades sense haver-se de preocupar de la forma en la que s’emmagatzemen. 6.10 Lazy Loading o c` arrega diferida Aquest patr´ o dona soluci´ o al problema de la c` arrega de biblioteques i components en mem` oria amb la c` arrega diferida d’aquestos fins que no s’instancien o s’utilitzen. Aix` o fa que els components no estiguen sempre carregats en mem` oria, que aquestos no es tinguen que carregar i inicialitzar-se sempre a cada petici´ o i s’estalvia mem` oria i temps. En aquest projecte hi ha certs components que s´ on principals, estructurals i s’han de carregar a cada petici´ o, la resta dels components o biblioteques es carreguen a demanda quan s’instancien. S’ha emprat l’ajuda de la biblioteca de PHP SPL (Standard PHP Library) amb els m` etodes coneguts com autoload que s´ on cridats per PHP al haver de carregar un component o biblioteca necessari per l’execuci´ o i a demanda. Hi ha diferents m` etodes que s’encarreguen de carregar biblioteques i components del marc de treball, controladors del sistema MVC, models de l’usuari, ajudants (helpers) de vistes i classes d’usuari. Aquestos m` etodes s’executen un darrere de l’altre fins que es troba el fitxer amb el codi font a carregar o es torna un error de fitxer no trobat. A m´ es a m´ es, tots els components estan dissenyats de manera que no carreguen depend` encies o altres components fins que no es vagen a utilitzar expressament aquestos components. Gr` acies a la implementaci´ o d’aquest patr´ o de disseny el marc de treball pot respondre r` apidament a peticions en temps de l’ordre dels 50-100 ms, ser eficient i estalviar mem` oria RAM. 6.11 Intercepting Filter La majoria de les aplicacions tenen alguns requisits, com ara la seguretat i generaci´ o de missatges de depuraci´ o, que son per a totes les peticions HTTP que rep l’aplicaci´ o web. Per afegir aquesta funcionalitat per separat per a cada servei d’aplicaci´ o seria molt de temps, propens a errors i dif´ ıcil de mantenir. El patr´ oIntercepting Filter dota a l’aplicaci´ o web dels recursos existents amb un filtre que intercepta cada petici´ o HTTP i la va transformant fins formar una resposta. Un filtre pot processar, comprovar o redirigir les peticions d’aplicaci´ o. Tamb´ e pot postprocessar o reemplac¸ar el contingut de les respostes. Els filtres es poden apilar un sobre l’altre per formar una cadena de filtres de tal manera que un filtre s’execute darrere d’un altre, fins que falle un d’aquestos filtres o es complete el proc´ es amb ` exit. 6.11. INTERCEPTING FILTER 65 En aquest projecte s’empra aquest patr´ o de disseny de forma conjunta amb el Front Controller, despr´ es que s’hagen obtingut dades correctes per part del Router. Es fa passar tota la petici´ o HTTP per un seguit de filtres que comproven diferents coses i arriben a fallar o a generar un resultat. Resultat que si ´ es satisfactori continuar` a amb l’execuci´ o de l’acci´ o en cadascuna de les especialitzacions del Front Crontroller. Figura 6.3: Patr´ o de disseny Intercepting Filter 66 CAP´ ITOL 6. PATRONS DE DISSENY APLICATS AL PROJECTE Cap´ ıtol 7 Funcionament del sistema 7.1 Modes de funcionament Aquest projecte t´ e tres modes de funcionament principals 7.1.1 Aplicaci´ o web Introducci´ o A continuaci´ o es detallaran tots els modes de funcionament per aplicacions web que disposa el marc de treball. Aplicaci´ o web Com a aplicaci´ o web, el marc de treball processa una petici´ o que li demana que execute una acci´ o que produeix codi html,javascript i css. AJAX En aquest m` etode de funcionament, s’especifica al sistema que ha de tornar un document XML resultat de realitzar certa acci´ o en el sistema. ´ Es ´ util per a aplicacions web 2.0 en les que es fa una petici´ o AJAX XML al marc de treball i aquest ha de respondre en XML que ser` a processat en el client per actualitzar o generar algun component o el contingut d’una p` agina sense haver de recarregar aquesta p` agina. Aquest mode de funcionament envia obligat` oriament capc¸aleres http que indiquen que el contingut ´ es un document XML. Per tant, si l’acci´ o a executar no produeix un document XML, el navegador podria tindre problemes per a processar la resposta i no funcionaria correctament l’aplicaci´ o web. JSON En aquest m` etode de funcionament, s’especifica al sistema que ha de tornar un document en format JSON resultat de realitzar certa acci´ o en el sistema. Com amb el m` etode de funcionament AJAX, aquest m` etode tamb´ e´ es ´ util per a actualitzar components d’una p` agina web i ´ es un dels dos que m´ es s’utilitza a nivell d’aplicacions web donada la facilitat de processament de JSON per part d’un navegador web donat que 67 68 CAP´ ITOL 7. FUNCIONAMENT DEL SISTEMA JSON ´ es part de JavaScript i tots els navegadors moderns saben interpretar-ho de manera ´ unica. Per tant ´ es un bon format per obtindre dades en resposta a una petici´ o al marc de treball; tenint com a principal avantatge el processament senzill i sense transformacions dins el navegador (XML necessita unes petites transformacions per poder obtindre el resultat). Aquest mode de funcionament tamb´ e envia capc¸aleres que http que indiquen que el contingut ´ es un document JSON. Per tant, si l’acci´ o no produeix un document JSON, el navegador podria tindre problemes per processar la resposta. MIME Amb aquest mode de funcionament es poden produir tot tipus de continguts - des de text pla a un document pdf passant per imatges o fitxers binaris - , cal especificar el tipus mime del contingut correctament i que l’acci´ o a executar produeixca contingut d’eixe tipus mime. Utilitzant aquest mode de funcionament es pot fer que una petici´ o AJAX (generada per una p` agina web en un navegador) torne text pla mitjanc¸ant el tipus mime text/plain podent tornar text pla sense estructurar al navegador (cosa que es desaconsella a menys que siga per un us molt senzill donat que no hi hauria estructura de dades que continga la informaci´ o i per tant podria ser m´ es complicat de processar). Tamb´ e es poden generar imatges (utilitzant la llibreria GD de PHP o similars) ´ util per generar captchas o gr` afics estad´ ıstics o qualsevol imatge generada al vol en el marc de treball. En tot cas, s’ha d’especificar el tipus mime exacte de la imatge generada (image/png,image/jpeg, . . . ). Emprant biblioteques externes en forma de plugins o biblioteques es podrien tamb´ e generar documents PDF, en format OpenOffice.org, o formats de Microsoft Office e incl` os generar fitxers binaris/programes al vol (opci´ o forc¸a complicada). Plugins Aquest darrer mode de funcionament dels d’aplicacions web permet que s’execute una funcionalitat situada dins un plugin i que retorne resultats al navegador. 7.1.2 Serveis WEB Introducci´ o A continuaci´ o es detallaran tots els modes de funcionament que el marc de treball t´ e per a serveis web. SOAP Aquest mode de funcionament permet que el marc de treball actue com a servidor de serveis web mitjanc¸ant el protocol SOAP i a trav´ es del transport HTTP. Amb el servidor SOAP es poden atendre peticions a serveis web implementats dins els marc de treball i proporcionar d’aquesta manera serveis web i interoperabilitat entre aplicacions, que escrites en qualsevol llenguatge de programaci´ o podrien obtindre i enviar dades des de/al marc de treball. 7.1. MODES DE FUNCIONAMENT 69 REST Aquest mode de funcionament permet al marc de treball implementar serveis web amb arquitectura REST admetent peticions HTTP amb algun dels m` etodes que especifica l’arquitectura REST (GET,POST,PUT,DELETE). Per a serveis web REST es poden implementar funcionalitats dins el marc de treball que obligat` oriament han de tornar dades en forma d’array per a despr´ es transformar-les a formats JSON o XML. Amb un servei web REST es poden implementar projectes amb intercanvi d’informaci´ o entre aplicacions - especialment aplicacions en entorns m` obils - . 7.1.3 Tasques programades/sistema operatiu Introducci´ o A continuaci´ o es detallaran els m` etodes de funcionament aprofitables per a facilitar la programaci´ o de tasques en un sistema operatiu (generalment GNU-Linux/Unix). CRON Es poden programar tasques peri` odiques per a executar-les amb el programador del sistema operatiu que executen accions dins el marc de treball (exemples: enviar newsletter autom` aticament, rebre missatges, generar inventaris/factures, . . . ). Per aix` o, el marc de treball disposa d’accions de tipus CRON i dues maneres d’accedir a elles: •L´ ınia d’ordres: Es poden executar accions CRON mitjanc¸ant el punt d’entrada cron.php i arguments de la l´ ınia d’ordres que serveixen per indicar el nom de l’acci´ o (´ unic per a tot el sistema) i els par` ametres que aquesta necessite per funcionar. Aquesta ´ es indicada si es t´ e acc´ es al planificador de tasques del sistema operatiu en el que est` a el servidor. •Petici´ o HTTP: Es pot dirigir una petici´ o HTTP al punt d’entrada cron.php i pasarli la URL amb els par` ametres necessaris. Aix` o´ es ´ util si no es t´ e acc´ es directe al planificador de tasques del sistema operatiu del servidor, per` o l’allotjament web/hosting s´ ı que permet planificar tasques a trav´ es de peticions web a scripts, o incl` os si volem fer una petici´ o remota des d’un sistema remot. M´ es informaci´ o de tasques programades en el cap´ ıtol corresponent a tasques programades en la part de desenvolupament avanc¸at. 70 CAP´ ITOL 7. FUNCIONAMENT DEL SISTEMA Part III El model de dades 71 Cap´ ıtol 8 Introducci´ o 8.1 Introducci´ o En aquesta part aprendrem una de les parts m´ es importants de tota aplicaci´ o web: el model de dades. Aprendrem a emprar el patr´ o de dades Active Record per fer m´ es senzill, eficient i llegible el nostre model de dades i es mostrar` a l’API de la base de dades utilitzada per accedir alternativament a la base de dades o per recuperar dades de consultes complicades. 73 80 CAP´ ITOL 9. LA BASE DE DADES 6array getTableFields($tableName); 7?> 9.4 Exemple complet En aquest exemple ens connectarem a la base de dades, farem una operaci´ o de consulta (SELECT) i obtindrem un resultat el qual mostrarem: Listing 9.6: Exemple de funcionament del component Database 1<?php 2 3// obtindre la instancia de la base de dades 4$database = FW_Database::getInstance(); 5 6// executar una consulta contra la base de dades 7$database->query("SELECT isbn,titol FROM proves_llibres WHERE autor LIKE ’A%’"); 8 9// si el resultat del query anterior te files ... 10 if ($database->numRows()) { 11 // mentre hi hagen files en el resultat ... 12 while ($result = $database->fetchAssoc()) { 13 print "ISBN={$result["isbn"]} / Titol={$result["titol"]} "; 14 print "<br/>"; 15 } 16 } 17 18 ?> Cap´ ıtol 10 Active Record 10.1 Introducci´ o Active Record proporciona una manera neta, r` apida i senzilla d’obtindre les dades d’una base de dades en forma d’objectes mitjanc¸ant la implementaci´ o d’una versi´ o del patr´ o de disseny ActiveRecord original de Ruby On Rails - utilitzat amb molt d’` exit en Ruby On Rails - i descrit per Martin Fowler en Patterns of Enterprise Application Architecture. Abstrau al desenvolupador de gestionar directament SQL i redueix les possibilitats d’un atac mitjanc¸ant SQL-Injection. A m´ es a m´ es, al transformar les dades de la base de dades relacionals en objectes, el desenvolupador es beneficia de tot un m´ on d’avantatges que permet el disseny de sistemes orientat a objectes ja que cada objecte pot encapsular l` ogica i regles de negoci segons les necessitats del client i a la vegada tindre una forma senzilla i elegant de poder guardar eixos canvis en l’objecte i els objectes relacionats en una base de dades relacional sense molts esforc¸os per al desenvolupador. 81 82 CAP´ ITOL 10. ACTIVE RECORD Figura 10.1: Diagrama UML del sistema ActiveRecord 10.2 El model 10.2.1 Introducci´ o Active Record basa el seu funcionament en objectes de tipus Model que representen una fila d’una taula de la base de dades relacional amb totes les seves columnes (propietats en el model) i claus alienes (relacions en el model). Aquestos objectes s´ on classes de PHP derivades de la classe FW ActiveRecord Model que proporciona tota la funcionalitat d’Active Record deixant-la llesta per operar amb nom´ es heretar la funcionalitat de la mencionada classe. 10.2.2 De base de dades relacional a model Active Record Generar models d’Active Record ´ es un proc´ es realment senzill basat en una s` erie de convencions i sense haver-se de configurar. Les convencions a seguir s´ on les seg¨ uents: •Nom de la taula en min´ uscules, separant paraules amb guions baixos   i sense cap espai. S’ha de fer aix´ ı per maximitzar la compatibilitat amb tots els motors de bases de dades i tots els sistemes operatius. Exemples v` alids: user has role ,book storage , . . . •Nom del model (classe) id` entic al nom de la taula, el nom del fitxer ha de ser el nom de la taula per` o afegint-li .class.php i ha d’estar en el directori 10.2. EL MODEL 83 /app/lib/models . Exemples v` alids: book storage →book storage.class.php  usuari →usuari.php  •Totes les propietats (columnes en la taula del model relacional) del model seguiran les mateixes convencions que per els noms de les taules (mateixos motius) i tindran el modificador d’acc´ es protected per a que Active Record, Model i altres classes puguen fer-ne us d’aquestes propietats. •Si s’utilitza un prefix per a les taules de la base de dades, aquest prefix haur` a d’estar incl` os en el nom de les taules, per` o no en el nom dels models. Active Record afegir` a el prefix autom` aticament a les consultes SQL que genere per el model. Aquest prefix s’ha de configurar en la configuraci´ o de la base de dades corresponent (consulteu la secci´ o del model de dades, component Database, configuraci´ o de la base de dades). Una vegada presentades les convencions utilitzades ja podem construir models per utilitzar amb Active Record. Presentem a continuaci´ o un exemple de com de f` acil ´ es transformar una taula de la base de dades a un model d’Active Record: La taula de la base de dades: Listing 10.1: Exemple de taula de base de dades a modelar amb Active Record 1CREATE TABLE post ( 2id INTEGER PRIMARY KEY NOT NULL AUTO_INCREMENT, 3title VARCHAR(512) NOT NULL, 4content TEXT NOT NULL, 5created_at DATETIME NOT NULL, 6author VARCHAR(255) NOT NULL, 7permalink VARCHAR(255) NOT NULL UNIQUE, 8status INTEGER(1) NOT NULL DEFAULT 0 9); Es convertiria en: Listing 10.2: Model d’Active Record 1<?php 2class post extends FW_ActiveRecord_Model { 3 4protected $id; 5protected $title; 6protected $content; 7protected $created_at; 8protected $author; 9protected $permalink; 10 protected $status; 11 12 }; 13 ?> 84 CAP´ ITOL 10. ACTIVE RECORD Aquestos models han d’estar obligat` oriament en els seg¨ uents directoris: Models generals per a l’aplicaci´ o web : Directori /app/lib/models . Models generals per a aplicacions web internes del sistema : Directori /framework/app/models . Models a utilitzar amb un plugin : Directori /app/lib/plugins/NOM DEL PLUGIN/models . En les seg¨ uents seccions es s’explicar` a com fer relacions, definir restriccions, validacions, callbacks i funcionalitat d’usuari en els models creats amb Active Record. 10.2.3 Relacions Una relaci´ o entre Models d’Active Record permet que dos models estiguen relacionatspermetent emular el sistema de claus alienes del model relacional. Aix´ ı es dota al sistema Active Record de capacitat per a mantindre relacionats dos models que compartisquen dades o siguen composici´ o d’altre model m´ es gran. Malgrat el sentit unidireccional de molts tipus de relacions entre taules del model relacional de bases de dades, Active Record proporciona un sentit bidireccional. ´ Es a dir, que des d’un model es pot navegar cap a les classes relacionades i que des de les classes relacionades es pot tornar cap al model amb qui es relaciona. Existeixen set tipus de relacions entre models que es detallaran a continuaci´ o, explicant-ne l’equival` encia amb el model relacional i com definir-les en els nostres models. Totes les relacions cal que estiguen definides en cada model. Per aix` o s’utilitzen arrays amb el modificador static (per a no interferir en les propietats de cada model) i dins d’aquestos arrays es pot definir 1 ´ o moltes relacions, segons convinga. Relaci´ ohas one(1:1) Aquesta relaci´ o permet lligar un model a altre amb els mateixos valors d’una clau aliena que els relaciona. En aquest cas, cada inst` ancia del model Anom´ es podr` a relacionar-se com a m` axim amb una inst` ancia del model B. Aquestes relacions 1:1 no s´ on gaire freq¨ uents, donat que la majoria de models solen relacionar-se amb molts models. ´ Es m´ es freq¨ uent la relaci´ o 1:1 del tipus belongs to. Figura 10.2: Active Record,Relaci´ ohas one Listing 10.3: Active Record, Relacions: SQL has one 10.2. EL MODEL 85 1-- taula user 2CREATE TABLE user ( 3id INTEGER PRIMARY KEY NOT NULL AUTO_INCREMENT, 4name VARCHAR(128) NOT NULL, 5email VARCHAR(128) NOT NULL, 6account INTEGER(5) NOT NULL, 7FOREIGN KEY(account) REFERENCES account(id) ON DELETE CASCADE ON UPDATE CASCADE 8); 9 10 -- taula account 11 CREATE TABLE account ( 12 id INTEGER PRIMARY KEY NOT NULL AUTO_INCREMENT, 13 created_at DATATIME, 14 balance DOUBLE 15 ); Listing 10.4: Active Record, Relacions: Model que implementa relaci´ ohas one 1<?php 2 3// user.class.php 4class user extends FW_ActiveRecord_Model { 5protected $id; 6protected $name; 7protected $email; 8protected $account; 9 10 public static $has_one = array ( 11 array( 12 "property" => "account", 13 "table" => "account", 14 "srcColumn"=> "account", 15 "dstColumn"=> "id", 16 "update" => "cascade", 17 "delete" => "cascade" 18 ) 19 ); 20 21 }; 22 23 24 // account.class.php 25 class account extends FW_ActiveRecord_Model { 26 protected $id; 27 protected $created_at; 28 protected $balance; 29 }; 30 31 ?> 86 CAP´ ITOL 10. ACTIVE RECORD Relaci´ obelongs to(1:1) Aquest tipus de relaci´ o´ es id` entic a l’anterior per` o amb la difer` encia que el model posse¨ ıdor de la clau aliena ´ es el model Bque es relaciona amb un model A. Aquest tipus de relacions es pot emprar per indicar relacions de propietat (objecte pertany a objecte), exemples: •Un post pertany a un autor com a m` axim. •Una factura ´ es d’un prove¨ ıdor com a m` axim. •Una comanda pertany a un client com a m` axim. Figura 10.3: Active Record,Relaci´ obelongs to Listing 10.5: Active Record, Relacions: SQL belongs to 1-- taula post 2CREATE TABLE post ( 3id INTEGER PRIMARY KEY NOT NULL AUTO_INCREMENT, 4title VARCHAR(255), 5content TEXT, 6author VARCHAR(100) NOT NULL, 7FOREIGN KEY(author) REFERENCES author(name) ON UPDATE CASCADE ON DELETE CASCADE 8); 9 10 11 -- taula author 12 CREATE TABLE author ( 13 name VARCHAR(100) PRIMARY KEY NOT NULL, 14 email VARCHAR(128) NOT NULL, 15 location VARCHAR(255) NOT NULL 16 ); Listing 10.6: Active Record, Relacions: Model que implementa relaci´ obelongs to 1<?php 2 3// post.class.php 4class post extends FW_ActiveRecord_Model { 5protected $id; 6protected $title; 7protected $content; 10.2. EL MODEL 87 8protected $author; 9 10 public static $belongs_to = array ( 11 array( 12 "property" => "author", 13 "table" => "author", 14 "srcColumn"=> "author", 15 "dstColumn"=> "name", 16 "update" => "cascade", 17 "delete" => "cascade" 18 ) 19 ); 20 21 }; 22 23 24 // author.class.php 25 class author extends FW_ActiveRecord_Model { 26 protected $name; 27 protected $email; 28 protected $location; 29 }; 30 31 ?> Relaci´ ohas many(1:N) Aquest tipus de relaci´ o permet a una inst` ancia del model Arelacionar-se amb moltes inst` ancies del model B. ´ Es un dels tipus de relacions m´ es utilitzades donada la seva facilitat per a modelar-les. •Un client t´ emoltes comandes. •Un post t´ emolts comentaris. •En un poble viuen (t´ e) molts habitants. Figura 10.4: Active Record,Relaci´ ohas many Listing 10.7: Active Record, Relacions: SQL has many 1-- taula provincia 2CREATE TABLE provincia ( 3id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, 4nom VARCHAR(50) NOT NULL UNIQUE 5); 88 CAP´ ITOL 10. ACTIVE RECORD 6 7-- taula municipi 8CREATE TABLE municipi ( 9id INTEGER PRIMARY KEY NOT NULL AUTO_INCREMENT, 10 nom VARCHAR(80) NOT NULL, 11 id_provincia INTEGER NOT NULL, 12 FOREIGN KEY(id_provincia) REFERENCES provincia(id) ON UPDATE CASCADE ON DELETE CASCADE 13 ); 14 15 ?> Listing 10.8: Active Record, Relacions: Model que implementa relaci´ ohas many 1<?php 2 3// provincia.class.php 4class provincia extends FW_ActiveRecord_Model { 5protected $id; 6protected $nom; 7 8public static $has_many = array ( 9array( 10 "property" => "municipis", 11 "table" => "municipi", 12 "srcColumn"=> "id", 13 "dstColumn"=> "id_provincia", 14 "update" => "cascade", 15 "delete" => "cascade" 16 ) 17 ); 18 19 }; 20 21 22 // municipi.class.php 23 class municipi extends FW_ActiveRecord_Model { 24 protected $id; 25 protected $nom; 26 protected $id_provincia; 27 }; 28 29 ?> Relaci´ ohas and belongs to many(N:M) Aquest tipus de relaci´ o permet que una inst` ancia del model Aestiga relacionada amb moltes inst` ancies del model Bi que a la vegada, cada inst` ancia del model Bestiga relacionada amb moltes inst` ancies del model A. Aquest tipus de relaci´ o necessita d’una taula interm` edia que relacione inst` ancies d’ambd´ os models i que nom´ es cont´ e informaci´ o relativa a la clau aliena del model Ai la clau aliena del model B. 10.2. EL MODEL 89 Exemples d’aquest tipus de relaci´ o serien: •Una persona col·labora en molts grups de treball i cada grup de treball t´ e molts col·laboradors. •Un metge visita molts pacients i cada pacient ´ es visitat per molts metges. Figura 10.5: Active Record,Relaci´ ohas and belongs to many Listing 10.9: Active Record, Relacions: SQL has and belongs to many 1-- taula grup 2CREATE TABLE grup ( 3id INTEGER PRIMARY KEY NOT NULL AUTO_INCREMENT, 4nom VARCHAR(255) NOT NULL 5); 6 7-- taula grup_has_personas 8CREATE TABLE grup_has_personas ( 9id_grup INTEGER NOT NULL, 10 login_persona VARCHAR(50) NOT NULL, 11 PRIMARY KEY(id_grup,login_persona), 12 FOREIGN KEY(id_grup) REFERENCES grup(id) ON UPDATE RESTRICT ON DELETE RESTRICT, 13 FOREIGN KEY(login_persona) REFERENCES persona(login) ON UPDATE RESTRICT ON DELETE RESTRICT 14 ); 15 16 -- taula persona 17 CREATE TABLE pesona ( 18 login VARCHAR(50) NOT NULL PRIMARY KEY, 19 nom VARCHAR(100) NOT NULL, 20 email VARCHAR(100) NOT NULL 21 ); Listing 10.10: Active Record, Relacions: Model que implementa relaci´ o has and belongs to many 1<?php 2 3// grup.class.php 4class grup extends FW_ActiveRecord_Model { 5protected $id; 6protected $nom; 7 8public static $has_and_belongs_to_many = array ( 9array( 96 CAP´ ITOL 10. ACTIVE RECORD relacions reflexives (1:N) Les relacions reflexives (1:N) s´ on molt ´ utils per representar jerarquies de dades. Exemples: •Jerarquia de categories. •Jerarquia de cap-treballadors. •Jerarquia de p` agines (p` agines relacionades). •.... Active Record proveu al desenvolupador d’una funcionalitat per representar aquestos tipus de relacions (nom´ es les 1:N) d’una forma molt senzilla amb nom´ es configurar un array. Proveu els m` etodes ´ utils i necessaris per obtindre el pare de l’objecte actual, obtindre els objectes fills o obtindre els objectes germans. Active Record aprofita la forma d’aquestes de relacions que generen arbres N-aris en els que el node arrel (en aquest cas una inst` ancia d’un model) i els nodes fills (tamb´ e inst` ancies de models). D’aquesta forma es pot navegar per aquestos arbres de dades i utilitzar les dades com un arbre N-ari. Listing 10.16: Active Record, Relacions: Relacions reflexives mitjanc¸ant acts as tree 1<?php 2class category extends FW_ActiveRecord_Tree { 3 4public $id; 5public $id_parent; 6public $title; 7public $description; 8public $author; 9public $image; 10 public $created_at; 11 public $password; 12 public $posts; 13 14 15 /** 16 *fer que el model actue com un arbre 17 *utilitzant relacions 1:n reflexives 18 */ 19 20 public static $acts_as_tree = array ( 21 // columna que actua d’identificador del node 22 "idColumn" => "id", 23 // columna que actua de id del node pare (clau aliena) 24 "parentColumn" => "id_parent", 25 // ordre dels nodes germans 26 "siblingOrder" => array ( 27 array ( 28 "column" => "title", 29 "type" => "ASC" 10.2. EL MODEL 97 30 ) 31 ) 32 ); 33 34 // altres relacions ... 35 public static $has_and_belongs_to_many = array ( 36 array( 37 "property" => "posts", 38 "srcTable" => "category", 39 "srcColumn" => "id", 40 "dstTable" => "post", 41 "dstColumn" => "id", 42 "throughTable" => "post_has_category", 43 "throughTableSrcColumn" => "id_category", 44 "throughTableDstColumn" => "id_post", 45 "update" => "restrict", 46 "delete" => "restrict" 47 ) 48 ); 49 50 public static $belongs_to = array ( 51 array( 52 "property" => "author", 53 "table" => "user", 54 "srcColumn"=> "author", 55 "dstColumn"=> "username", 56 "update" => "restrict", 57 "delete" => "restrict" 58 ) 59 ); 60 61 }; 62 ?> En l’exemple es pot veure una classe del model de dades (heretant de la classe FW ActiveRecord Tree que representa una categoria (relaci´ o reflexiva categoria → categoria(pare)1:N) configurant-la en el array acts as tree, amb aquesta definici´ o s’aconsegueix que el model actue com un arbre definint sobre ell la relaci´ oid parent(enelfill)→ id(enelpare). En l’API d’Active Record Tree detallada m´ es endavant es mostra com utilitzar els m` etodes que proporciona per navegar a trav´ es de l’arbre de nodes (de tipus categoria en aquest exemple). 10.2.4 Validacions La validaci´ o de dades ´ es un proc´ es per el qual el sistema Active Record comprova cada propietat del model abans de cada operaci´ o d’actualitzaci´ o o inserci´ o, fent que nom´ es s’inserisquen dades correctes i que respecten els tipus de dades i llarg` aries de les columnes de les taules de la base de dades, aix´ ı com la integritat de les dades . Les comprovacions realitzades per defecte inclouen els seg¨ uents tipus de comprovacions: •Comprovacions de tipus de dades. 98 CAP´ ITOL 10. ACTIVE RECORD •Comprovacions de llarg` aria de les dades. •Comprovacions de valors nuls. •Comprovacions de clau prim` aria. •Comprovacions de clau alienes. Generalment les validacions per defecte s´ on suficients per a evitar introduir dades incorrectes en la base de dades, malgrat tot aix` o, existeix un altre tipus de validaci´ o en el que segons les regles de negoci del propi usuari es poden fer validacions de les propietats. Aquestes validacions personalitzades, s’han d’implementar en forma de m` etodes amb el modificador d’acc´ es protected i que tinguen un nom que comence per validate . Aquestos m` etodes seran executats en primer lloc abans de comenc¸ar amb la validaci´ o de propietats per defecte. Han de retornar els valors true (si ´ es correcta la validaci´ o) o false (si la validaci´ o´ es incorrecta). Una vegada un m` etode o una validaci´ o d’una propietat retorne el valor false, es detindr` a el proc´ es de validaci´ o i es cancel·lar` a qualsevol operaci´ o d’inserci´ o o d’actualitzaci´ o en marxa. En el seg¨ uent exemple es pot observar un exemple de validaci´ o personalitzada que comprova la restricci´ o d’unicitat per a la propietat permalink: Listing 10.17: Active Record: Validaci´ o personalitzada 1<?php 2class post extends FW_ActiveRecord_Model { 3protected $id; 4protected $title; 5protected $content; 6protected $created_at; 7protected $author; 8protected $permalink; 9protected $status; 10 11 // validacio personalitzada per una restricccio d’unicitat 12 protected function validatePermalink() { 13 $conditions = array ( 14 array ( 15 "name" => "permalink", 16 "operator" => "=", 17 "value" => $this->_permalink 18 ) 19 ); 20 $select = post::find($conditions); 21 return (!$select->hasResult()); 22 } 23 24 }; 25 ?> 10.2. EL MODEL 99 10.2.5 Callbacks Un callback ´ es una funci´ oom` etode que s’executa just abans, despr´ es o en meitat d’una operaci´ o. Per ajudar a millorar la integritat relacional de les dades contingudes en els models d’Active Record, el programador t´ e al seu abast un gran nombre d’aquestos callbacks que pot implementar en el seu model. La funci´ o que t´ e cada callback est` a explicada en el seg¨ uent codi. Tots els callbacks han d’implementar-se amb el modificador d’acc´ es protected de forma que FW ActiveRecord puga executar-los quan siga convenient. Hauran, tamb´ e de tornar un valor boole` atrue ofalse segons la l` ogica de negoci que implementen. Un valor de false de retorn d’un callback signfica - al igual que en el cas de la validaci´ o - la interrupci´ o de l’acci´ o en curs. Listing 10.18: Active Record: Callbacks 1<?php 2// despres de fer l’operacio find i construir el model 3bool afterFind(void); 4 5// abans de fer una consulta d’existencia de dades 6bool beforeExists(void); 7 8// despres de fer una consulta d’existencia de dades 9bool afterExists(void); 10 11 // abans d’esborrar les dades d’un model 12 bool beforeDelete(void); 13 14 // despres d’esborrar les dades d’un model 15 bool afterDelete(void); 16 17 // abans d’actualitzar les dades d’un model 18 bool beforeUpdate(void); 19 20 // despres d’actualitzar les dades d’un model 21 bool afterUpdate(void); 22 23 // abans d’inserir les dades d’un model 24 bool beforeInsert(void); 25 26 // despres d’inserir les dades d’un model 27 bool afterInsert(void); 28 29 // abans d’executar l’operacio save 30 bool beforeSave(void); 31 32 // despres d’executar l’operacio save 33 bool afterSave(void); 34 ?> Aquestos callbacks serveixen per fer moltes funcions, en concret: •Codificaci´ o/descodificaci´ o de dades (utf8 a iso-8859-1). 100 CAP´ ITOL 10. ACTIVE RECORD •Conversi´ o d’unitats. •Cridar a altres m` etodes del model que facen tasques de manteniment .. . 10.2.6 Funcionalitat d’usuari Dins el model ´ es possible generar funcionalitat d’usuari que el propi model de dades requereix-ca. Es poden crear qualsevol tipus de m` etodes on s’implemente la l` ogica de negoci necess` aria per a cada model. 10.2.7 Esquemes Part del funcionament del component Active Record es bassa en con` eixer de quines propietats est` a compost cada model, de quines propietats formen part de la clau prim` aria, quins tipus de dades t´ e cada propietat, . . . . Aquest coneixement es genera interrogant al motor de base de dades sobre una fila d’una taula concreta, fent introspecci´ o en el model de dades i veient quines propietats i relacions t´ e. Tota aquesta informaci´ o sobre un model ´ es desada en forma d’esquema utilitzant un component dins d’Active Record anomenat ActiveRecord Metadata Schema . Degut al gran nombre d’esquemes (1 per cada model existent en el sistema), existeix un component encarregat de coordinar la seva generaci´ o i obtindre aquell esquema necessari a cada moment. Aquest component s’anomena ActiveRecord Metadata Manager. S’encarrega de generar tots els esquemes i desar-los en un fitxer anomenat serialized activerecord manager.ser situat dins el directori /framework/cache/framework/schemas . Si es genera un nou model, ´ es necessari esborrar aquest fitxer i deixar que el sistema el genere de nou (generar` a el fitxer d’esquemes amb els nous models trobats). Aquest fitxer ´ es necessari donat que no es pot estar constantment demanant informaci´ o a la base de dades, per q¨ uestions d’efici` encia i de temps. 10.3 API d’Active Record En aquesta secci´ o es presenta l’API del component d’Active Record. Primerament veurem els tipus de dades resultats de moltes operacions, despr´ es les operacions de cerca, operacions amb funcions de columna (count,avg,sum,min,max) i operacions de desat de dades i altres operacions importants en el cicle de vida del model de dades d’una aplicaci´ o web. 10.3.1 Tipus de dades de l’API Model i Tree Els objectes FW ActiveRecord Model iFW ActiveRecord Tree (objectes base d’Active Record que representen les dades) s´ on els objectes dels que ha de derivar tot model d’Active Record. 10.3. API D’ACTIVE RECORD 101 Proporcionen una serie de funcionalitats interessants per convertir les dades contingudes en un model en formats est` andards o generar un model a partir de les dades en aquestos formats. Listing 10.19: API de FW ActiveRecord Model 1<?php 2/*operacions de transformacio entre formats estandards de les dades */ 3 4// obte un array amb totes les dades del resultat 5array toArray(array $properties=array(),array $transformations=array()); 6 7// obte un document XML amb totes les dades del resultat 8string toXML($root="",array $properties=array(),array $transformations=array(),array $cdatas=array()); 9 10 // obte un document JSON amb totes les dades del resultat 11 string toJSON(array $properties=array(),array $transformations=array(),$headers=true,$jsonFlags=null); 12 13 // obte un document CSV amb totes les dades del resultat 14 string toCSV (array $properties=array(),array $transformations=array(),$headers=true,$delimiter=","); 15 16 // genera les dades d’un model a partir de dades en format JSON 17 FW_ActiveRecord_Model static fromJSON($json="",$relations= false); 18 19 // genera les dades d’un model a partir de dades en format XML 20 FW_ActiveRecord_Model static fromXML($xml="",$relations=true ); 21 22 23 // genera les dades d’un model a partir de dades en forma d’ array 24 FW_ActiveRecord_Model static fromArray(array $data, $relations=false); 25 26 27 /*altres operacions importants */ 28 29 // obtindre les propietats que te el model 30 array getModelProperties(void); 31 32 // obte una representacio serialitzada del model i les seves dades 33 string serialize(void); 34 ?> Listing 10.20: API de FW ActiveRecord Tree 102 CAP´ ITOL 10. ACTIVE RECORD 1<?php 2// obte si aquest node es o no l’arrel de l’arbre 3bool isRoot(void); 4 5// obte si aquest node te un node pare o per el contrari es un node pare 6bool hasParent(void); 7 8// obte si aquest node te nodes germans (altres fills del seu node pare) 9bool hasSiblings(void); 10 11 // obte si aquest node te nodes fills 12 bool hasChildren(void); 13 14 // obte el node pare 15 FW_ActiveRecord_Tree getParent(void); 16 17 // obte els nodes fills d’aquest node 18 FW_ActiveRecord_Result getChildren(void); 19 20 // obte els nodes germans d’aquest node 21 FW_ActiveRecord_Result getSibling(void); 22 23 // obte l’arrel de l’arbre que forma part aquest node 24 FW_ActiveRecord_Tree root(void); 25 ?> Resultats (FW ActiveRecord Result) El tipus de dades per expressar un resultat en les operacions de cerca s’anomena FW ActiveRecord Result. Cont´ e un array de dades que es pot rec´ orrer amb bucles for,foreach i d’altres gr` acies a que implementa v` aries interf´ ıcies d’iteradors. En el seg¨ uent codi es mostren les operacions m´ es importants sobre aquest tipus de dades: Listing 10.21: API de FW ActiveRecord Result 1<?php 2/*operacions sobre el resultat */ 3 4// obte si hi ha o no elements en el resultat 5bool hasResult(void); 6 7// obte el nombre d’elements del resultat 8int count(void); 9int numResults(void); 10 11 // obte el tipus de resultat (nom del model) que emmagatzema aquest resultat 12 string getResultType(void); 13 14 15 /*operacions d’obtencio d’elements */ 10.3. API D’ACTIVE RECORD 103 16 17 // obte el primer element del resultat 18 FW_ActiveRecord_Model first(void); 19 20 // obte el darrer element del resultat 21 FW_ActiveRecord_Model last(void); 22 23 // esborra tots els elements del resultat 24 void clear(void); 25 26 // obte tots els elements del resultat 27 array getObjects(void); 28 29 30 /*operacions de transformacio en formats estandards de les dades del resultat */ 31 32 // obte un array amb totes les dades del resultat 33 array toArray(array $properties=array(),array $transformations=array()); 34 35 // obte un document XML amb totes les dades del resultat 36 string toXML($root,$elementRoot="",array $properties=array() ,array $transformations=array(),array $cdatas=array()); 37 38 // obte un document JSON amb totes les dades del resultat 39 string toJSON(array $properties=array(),array $transformations=array(),$headers=true,$jsonFlags=null); 40 41 // obte un document CSV amb totes les dades del resultat 42 string toCSV (array $properties=array(),array $transformations=array(),$delimiter=","); 43 44 ?> Relacions (FW ActiveRecord Relation) Dins d’una inst` ancia d’un model ens podem trobar amb propietats que es refereixen a objectes relacionats amb l’objecte que estem tractant. Aquestes propietats tindran un valor que ser` a de tipus FW ActiveRecord Relation, que representa una relaci´ o amb tots els objectes relacionats i proporciona certes operacions ´ utils per mantindre la integritat de les dades. Donat que aquest tipus de dades est` a definit com her` encia del tipus de dades FW ActiveRecord Result , tamb´ e t´ e acc´ es a totes les funcionalitats que t´ e aquest tipus de dades i que ajuden a rec´ orrer la col·lecci´ o de dades relacionada. FW ActiveRecord Relation t´ e una operaci´ o molt ´ util anomenada find que permet fer cerques dins els objectes relacionats. En el seg¨ uent codi es mostren les operacions m´ es importants sobre aquest tipus de dades: Listing 10.22: API de FW ActiveRecord Relation 1<?php 104 CAP´ ITOL 10. ACTIVE RECORD 2// cerca dins el resultat dels models relacionats 3FW_ActiveRecord_Result find(array $conditions=array(), array $orders=array(),$limit=0,$offset=0); 4 5// afegeix un objecte de tipus model a la relacio 6void add(FW_ActiveRecord_Model $object); 7 8// actualitza totes les dades relaciones amb la relacio 9mixed update(void); 10 11 // esborra totes les dades relaciones amb la relacio 12 mixed delete(void); 13 14 // obte el valor de la propietat que representa el valor de la clau aliena sobre la que esta la relacio 15 mixed getOldValue(void); 16 ?> Condicions per fer una cerca Per indicar-li a moltes de les operacions les condicions amb les que volem cercar les dades, definirem un array semblant al seg¨ uent codi: Listing 10.23: Definir condicions per cercar dades amb Active Record 1<?php 2$conditions = array ( 3// aci aniran les condicions de cerca 4); 5// condicio simple 6array ( 7"name" => "nom_de_la_propietat", 8"operator" => "operador", 9"value" => "valor_per_fer_la_cerca" 10 ), 11 // condicions complexes 12 array ( 13 "name" => "nom_de_la_propietat", 14 "operator" => "IN", 15 "value" => " ’valor1’,’valor2’,’valor3’ " 16 ), 17 // condicions amb funcions de dates 18 array ( 19 "name" => "YEAR(data)", 20 "operator" => ">", 21 "value" => "1999" 22 ), 23 // condicions amb cerca de text 24 array ( 25 "name" => "UPPER(columna)", 26 "operator" => "LIKE", 27 "value" => "A%B%C" 28 ), 29 10.3. API D’ACTIVE RECORD 105 30 31 // operador simple (AND,OR, ...) 32 array ("condition" => "AND" ), 33 34 35 // combinacions d’ambdos 36 37 /** 38 *Posts que son del any 2010 39 *i tenen el titol LIKE ’A%’ 40 *i foren escrits per el usuari 41 *’andreums’ 42 */ 43 $conditions = array ( 44 array ( 45 "name" => "YEAR(created_at)", 46 "operator" => "=", 47 "value" => "2010" 48 ), 49 array ("condition" => "AND"), 50 array ( 51 "name" => "title", 52 "operator" => "LIKE", 53 "value" => "A%" 54 ), 55 array ("condition" => "AND"), 56 array ( 57 "name" => "author", 58 "operator" => "=", 59 "value" => "andreums" 60 ) 61 ); 62 63 ?> Com es veu en el codi anterior, ´ es senzill definir unes condicions per cercar dades. Aquestes condicions es traduiran despr´ es a SQL i junt a l’ajuda que proporciona Active Record, s’obtindr` a el query SQL que ser` a passat al component Database per a la seva execuci´ o i retornar` a un resultat que Active Record analitzar` a. Condicions per fer ordenaci´ o de dades Per indicar-li a moltes de les operacions la nostra prefer` encia a l’hora d’ordenar les dades, definirem un array semblant al seg¨ uent codi: Listing 10.24: Definir condicions per l’ordenaci´ o de dades d’Active Record 1<?php 2$order = array ( 3array ( 4"column" => "created_at", 5"type" => "ASC" 6), 7array ( Cap´ ıtol 11 Estructura de les aplicacions web 11.1 Introducci´ o En aquest cap´ ıtol presentarem l’estructura de l’aplicaci´ o web que anem a desenvolupar. En primer lloc cal dir que l’aplicaci´ o´ es totalment modular i que aprofitant el patr´ o de disseny (HMVC Hierarchical-Model-View-Controller) que promou la modularitzaci´ o d’una aplicaci´ o estructurada mitjanc¸ant el patr´ o de disseny MVC (Model View Controller) en m´ ultiples m` oduls MVC a¨ ıllant aix´ ı el codi en funcionalitats comunes i evitant (amb la comunicaci´ o entre m` oduls) la repetici´ o de codi font. 11.2 Directoris En les imatges seg¨ uents s’aprecien els directoris que cont´ e una aplicaci´ o web 113 114 CAP´ ITOL 11. ESTRUCTURA DE LES APLICACIONS WEB Figura 11.1: Directoris d’una aplicaci´ o web (dins el directori /app) 11.3. ESTRUCTURA D’UN M ` ODUL 115 Figura 11.2: Directoris d’un m` odul (dins el directori /app/modules) 11.3 Estructura d’un m` odul Cada m` odul del desenvolupament es crear` a dins un directori en el directori /app/modules del marc de treball i amb la seg¨ uent estructura: /app/modules : Directori pare on resideixen tots els m` oduls de la nostra aplicaci´ o web. /app/modules/m` odul : Directori que contindr` a el nostre m` odul. /app/modules/m` odul/config : Directori que contindr` a la configuraci´ o del nostre m` odul. /app/modules/m` odul/config/routes.php : Fitxer que contindr` a informaci´ o d’enrutament del nostre m` odul. /app/modules/m` odul/controller : Directori que contindr` a els controladors del nostre m` odul. /app/modules/m` odul/model : Directori que contindr` a els models del nostre m` odul. /app/modules/m` odul/view : Directori que contindr` a les diferents vistes del nostre m` odul. /app/modules/m` odul/view/error : Directori que contindr` a les diferents vistes d’errors del nostre m` odul. 116 CAP´ ITOL 11. ESTRUCTURA DE LES APLICACIONS WEB /app/modules/m` odul/layout : Directori que contindr` a els diferents layouts del nostre m` odul. 11.4 Estructura MVC 11.4.1 Introducci´ o En aquesta secci´ o s’introduir` a la terminologia b` asica del patr´ o de disseny MVC aix´ ı com es presentar` a el codi necessari per a crear un m` odul d’una aplicaci´ o web amb el marc de treball del projecte. 11.4.2 El controlador Un controlador ´ es una classe cont´ e la part de l` ogica de negoci d’una aplicaci´ o mantenintla separada de l’obtenci´ o de dades i de la interf´ ıcie d’usuari. Aquesta classe s’encarrega de gestionar l’execuci´ o d’una determinada acci´ o (m` etode d’un controlador), demanant dades al model, processant-los despr´ es i finalment mostrant a l’usuari el resultat de l’acci´ o en una vista (interf´ ıcie gr` afica). Donat el principi de separaci´ o de capes que introdueix el patr´ o de disseny MVC, el controlador ha de limitar-se a treballar amb la l` ogica de negoci. ´ Es a dir, amb dades que provenen d’una petici´ o (que ´ es qui activa l’execuci´ o d’una acci´ o d’un controlador) o del model (base de dades/fonts de dades). El controlador (classe FW mvc BaseController) Cada controlador de cada m` odul d’una aplicaci´ o ha de residir en el directori controller dins cada m` odul i ha de tindre la seg¨ uent estructura de codi PHP: Listing 11.1: Controlador b` asic 1<?php 2class elMeuControladorController extends FW_mvc_BaseController { 3 4public function action1($param1,$param2) { 5... 6} 7 8public function actionN($param1,$param2,$param3) { 9... 10 } 11 }; 12 ?> El nom de la classe ha de ser exactament de l’esquema {nomDelControlador}Controller i heretar de la classe abstracta i b` asica FW mvc BaseController que ´ es qui proporciona la funcionalitat b` asica d’un controlador ha d’estar en un fitxer anomenat nomDelControladorController.class.php en el directori controller del m` odul. Un m` odul pot tindre un o m´ es controladors que obligat` oriament han d’estar relacionats amb un model situat en el directori model de cada m` odul. Cada controlador pot tindre una o m´ es accions que seran m` etodes de la classe del controlador sense par` ametres Les accions d’un controlador tenen el seg¨ uent aspecte: 11.4. ESTRUCTURA MVC 117 Listing 11.2: Acci´ o d’un controlador 1<?php 2// accions que mostren pagines 3public function mostrarFormulariContacte() { 4$this->renderView("formularis".DS."contacte"); 5return; 6} 7// accions amb parametres 8public function mostrarPagina() { 9$id = $this->escape($this->_request->getParameter(" id")); 10 if ($this->filter->isNumeric($id)) { 11 $pagina = $this->_model->getPaginaById($id); 12 if ($pagina!==null) { 13 $this->set("pagina",$pagina); 14 $this->renderView("pagines".DS." pagina"); 15 return; 16 } 17 else { 18 $this->renderErrorPage("pagines".DS. "paginaNoTrobada"); 19 return; 20 } 21 } 22 else { 23 $this->renderErrorPage("pagines".DS." paginaNoTrobada"); 24 return; 25 } 26 } 27 ?> API del controlador L’API del controlador proveu al desenvolupador de les seg¨ uents operacions: Listing 11.3: API del component FW mvc BaseController 1<?php 2// obte l’objecte FW_Request 3FW_Request request(void); 4 5// obte el usuari loggejat en el sistema 6FW_Authentication_User user(void); 7 8// obte l’objecte FW_Session 9FW_Session session(void); 10 11 // obte el model 12 FW_mvc_BaseModel model(void); 13 14 // obte l’objecte FW_Context 118 CAP´ ITOL 11. ESTRUCTURA DE LES APLICACIONS WEB 15 FW_Context context(void); 16 17 18 // redirecciona a una pagina d’error 403 19 void forbidden(void); 20 21 // redirecciona a una pagina d’error 404 22 void notFound(void); 23 24 // parseja i escapa una variable de text 25 string sanitize($variable); 26 string escape($data,$stripTags); 27 28 // convert una variable de text per mostrar-la per pantalla 29 string display($data); 30 31 // renderitza un layout 32 void renderLayout($layout); 33 34 // configura un slot del layout 35 void setSlot($name,$view,array $variables=array()); 36 37 // obte un slot del layout 38 string getSlot($name); 39 40 // obte si esta disponible un slot (si te contingut) 41 bool hasSlot($name); 42 43 ?> 11.4.3 El model Un model ´ es una classe que cont´ e l’acc´ es a dades ja siguen d’una base de dades, d’un fitxer o d’un servei web. Els m` etodes del model seran invocats per el controlador amb la finalitat d’obtindre dades o de desar dades en una font de dades. El model ha de limitar-se a l’acc´ es a les fonts de dades, mentre que tot el treball de processament de dades s’ha de fer en el controlador. El model (classe FW mvc BaseModel) Un model s’ha de correspondre necess` ariament amb un controlador del mateix nom, per tant, cada classe de model s’ha d’anomenar de la manera {nomDelControlador}Model i heretar de la classe abstracta i b` asica FW mvc BaseModel que ´ es qui proporciona la funcionalitat b` asica d’un model ha d’estar en un fitxer anomenat nomDelControladorModel.class.php en el directori model del m` odul. Per tant, cada controlador d’un m` odul t´ e associat un ´ unic model del que obtindre dades. Un model t´ e el seg¨ uent aspecte: Listing 11.4: Model b` asic 1<?php 2class elMeuControladorModel extends FW_mvc_BaseModel { 3 11.4. ESTRUCTURA MVC 119 4public function getAllPages() { 5$pages = page::find(); 6if ($pages->hasResult()) { 7return $pages; 8} 9} 10 11 public function getPageById($id) { 12 $page = page::findById($id); 13 if ($page->hasResult()) { 14 return $page->first(); 15 } 16 } 17 18 }; 19 ?> En un model pot haver-ne cero o m´ es m` etodes que poden - o no - tindre par` ametres; segons convinga per a cada situaci´ o. Generalment un model obtindr` a dades de la base de dades (directament o a trav´ es d’Active Record), d’un fitxer XML o d’un servei web. API del model El model t´ e una API senzilla en la que la ´ unica funcionalitat ´ es obtindre acc´ es a la base de dades. Listing 11.5: API del component FW mvc BaseModel 1<?php 2// obtindre la instancia de la base de dades 3FW_Database database(void); 4?> 11.4.4 La vista Una vista ´ es un fragment de codi HTML amb una l` ogica de control m´ ınima de PHP que mostra resultats de les accions realitzades en una acci´ o del controlador. Donat que les dades ja han estat processades en el controlador, la vista s’encarregar` a´ unicament de mostrar eixes dades. Utilitzant per aquesta tasca ´ unicament les estructures if, elsif, else i els bucles for, foreach, do...while i while amb la ´ unica finalitat de rec` orrer les col·leccions de dades estructurades i poder accedir a les seves propietats amb tal de mostrar-les. La vista ´ es una esp` ecie de plantilla de codi HTML re-utilitzable on es mostra un resultat d’una acci´ o que pot tindre dades diferent per a cada usuari. Vistes i Vistes parcials Una vista pot incloure una vista que mostre un codi d’un disseny d’una taula HTML per mostrar una col·lecci´ o de dades, per` o per modularitat, si volem mantindre controlat el codi on es mostra cada fila de la tabla; podem mantindre aquest a¨ ıllat en una altra vista i incloure’l quan convinga. Aquesta vista ’especial’ s’anomena vista parcial essent una ajuda per a la re-utilitzaci´ o de codi i el manteniment d’eixe codi. Malgrat tot, una vista 120 CAP´ ITOL 11. ESTRUCTURA DE LES APLICACIONS WEB Estructura d’una vista en PHP Listing 11.6: Vista simple 1<h3>Benvingut!</h3> 2<p>Estimat <?php print $user->getDisplayName(); ?> sigues benvingut a casa</p> Listing 11.7: Vista 1<h4>Llistat de pagines</h4> 2 3<table> 4<thead> 5<tr> 6<th>ID</th> 7<th>Titol</th> 8<th>Autor</th> 9<th>Data</th> 10 </tr> 11 </thead> 12 <tbody> 13 <?php 14 // si hi ha pagines 15 if (count($pagines)>0) { 16 foreach ($pagines as $pagina) { 17 $this->renderPartialView("pagines/taula/fila",array(" pagina"=>$pagina)); 18 } 19 } 20 ?> 21 </tbody> 22 </table> Listing 11.8: Vista parcial 1<tr> 2<td> <?php print $pagina->id; ?> </td> 3<td> <?php print $this->display($pagina->getTitle()); ?> </ td> 4<td> <?php print $pagina->author->getFullName(); ?> </td> 5<td> <?php print timeHelper::displayFullData($pagina-> getDate()); ?> </td> 6</tr> 11.4.5 Layouts web Un Layout ´ es una vista que conforma l’estructura d’una p` agina web que generalment ´ es est` atica i en la que nom´ es canvia una part del disseny a cada petici´ o que fa l’usuari. Utilitzarem el framework de CSS Blueprint - que es pot obtindre des del lloc web http://www.blueprintcss.org/ - ja que facilita molt la creaci´ o de Layouts web amb CSS i XHTML. 11.4. ESTRUCTURA MVC 121 Creaci´ o de Layouts Un Layout d’una aplicaci´ o web ´ es un fitxer de codi en PHP que cont´ e l’esquelet d’una p` agina web (de les seccions que no varien) junt a codi per recuperar i definir les seccions que varien. Aquestes seccions s´ on els anomenats Slots. Un slot defineix una secci´ o o zona en la que hi anir` a contingut variable (eixides de vistes d’accions). El que fan les accions del controlador ´ es definir qu` e va en cada slot (vista i variables) i retornar l’ordre de renderitzar un layout concret. Despr´ es el component Layout s’encarrega de fer la resta, ´ es a dir, d’aconseguir les dades que van en el slot i de col·locar-les en el seu indret corresponent. 11.4.6 Creaci´ o de Layouts Figura 11.3: Layout b` asic Generarem aquest layout amb el seg¨ uent codi font: Listing 11.9: Layout b` asic 1<!DOCTYPE html> 2<html> 3<head> 4<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 5<title>Demo de layout</title> 6<?php 7// mostrar els estils CSS per aquest modul 8print FW_Style_Manager::getInstance()->displayStyle( FW_Context::getInstance()->router->route); 9 10 // mostrar els estils CSS per aquesta accio 11 $styles = FW_Context::getInstance()->router->styles; 12 if (count($styles)>0) { 128 CAP´ ITOL 12. EL SISTEMA D’ENRUTAT method : M` etode HTTP utilitzat per accedir-ne a aquesta operaci´ o del servei web. mime : Tipus de dades mime (si no retornara dades en formats JSON oXML. 12.3.3 Plugins Els plugins tamb´ e poden implementar funcionalitats accessibles des d’una URL (ex: p` agina de configuraci´ o del plugin, estad´ ıstiques, . . . ). Necessita els seg¨ uents par` ametres: plugin : El plugin a executar. action : L’acci´ o del plugin a executar. mime : El tipus de dades mime que retorna aquesta acci´ o. 12.3.4 Altres tipus d’accions cron : Implementa una operaci´ o preparada per a ser executada per el planificador de tasques del sistema operatiu. Necessita els seg¨ uents par` ametres: module : El m` odul on resideix la funcionalitat a executar. controller : El controlador on resideix la funcionalitat a executar. action : L’acci´ o a executar. internal : Si est` a ofert per el framework valor a true, en cas contrari valor a false. static : Aquesta acci´ o s’encarrega de mostrar p` agines web html est` atiques. ´ Es ´ util per a utilitzar p` agines ’antigues’ est` atiques html mentre es fa una migraci´ o a una aplicaci´ o web. Necessita el seg¨ uent par` ametre: file : Fitxer a mostrar. redirect : Aquesta acci´ o nom´ es fa una re-direcci´ o a la URL especificada en el par` ametre. ´ Es ´ util per a fer migracions o proporcionar URLs SEO. Necessita el seg¨ uent par` ametre: redirect : URL a la que ser` a redirigit l’usuari. 12.4 Par` ametres Les rutes dels tipus application,ajax,json,mime,rest,soap,cron i plugin suporten par` ametres per mitj` a de la URL. Un par` ametre per la URL ´ es afegir-li un fragment de text a la URL que determine el valor del par` ametre. Aquestos par` ametres poden anar en qualsevol punt de la URL, encara que generalment es recomana que vagen al final de tota la URL, ja que poden provocar col·lisions amb altres URLs d’altres accions i fer que no s’execute l’acci´ o correcta. Aquestos par` ametres es traslladen (una vegada feta la comprovaci´ o en el component Router) a l’acci´ o per a que siga executada amb els par` ametres corresponents. Els par` ametres poden ser de qualsevol dels tipus b` asics (string, integer, float, double) 12.4. PAR ` AMETRES 129 o ser de qualsevol tipus amb un format especial especificat mitjanc¸ant expressions regulars, que en aquest cas correspon al desenvolupador crear i comprovar que funciona en tots els valors possibles del par` ametre. La descripci´ o dels par` ametres en una ruta es fa mitjanc¸ant dos arrays (parameters i parameterOrder). El primer array cont´ e estructures de dades (arrays) que defineixen a cada par` ametre: Listing 12.3: Definici´ o de par` ametres en una ruta 1<?php 2/** 3*En la definicio d’una ruta 4*/ 5"parameters" => array ( 6"nom_del_parameter" => array ( 7"name" => "nom_del_parameter", 8"type" => "tipus_del_parameter", 9"format" => "format_del_parameter" 10 ) 11 ) 12 ... 13 14 /** 15 *Exemple: 16 */ 17 "parameters" => array ( 18 "categoria" => array ( 19 "name" => "categoria", 20 "type" => "string", 21 "format" => false // no necesita cap format especial 22 ) 23 "subcategoria" => array ( 24 "name" => "subcategoria", 25 "type" => "string", 26 "format" => false // no necesita cap format especial 27 ), 28 "id" => array ( 29 "name" => "id", 30 "type" => "string", 31 "format" => "[\d+]{1,2}" 32 ) 33 ) 34 35 ?> El segon array ´ es necessari, ja que el component Router ha de saber en quin ordre estan descrits els par` ametres, per aix` o definim els segon array com segueix: Listing 12.4: Ordre de par` ametres en definici´ o d’una ruta 1<?php 2/** 130 CAP´ ITOL 12. EL SISTEMA D’ENRUTAT 3*En la definicio d’una ruta 4*/ 5"parameterOrder" => array ( 60=>"categoria", 71=>"subcategoria", 82=>"id" 9) 10 ?> 12.5 Autenticaci´ o Una ruta pot necessitar autenticaci´ o d’usuari per accedir a una zona privada. Per indicar-li a una ruta que necessita autenticaci´ o podem programar-lo com en el seg¨ uent codi font: Listing 12.5: Definici´ o d’autenticaci´ o en una ruta 1<?php 2/** 3*En la definicio d’una ruta 4*/ 5 6// autenticacio desactivada 7"authentication" => false, 8 9// autenticacio amb qualsevol rol 10 "authentication" => array(), 11 12 // autenticacio d’usuaris amb rol... 13 "authentication" => array( 14 "roles" => "rol1","rol2","rol3" 15 ), 16 ?> 12.6 Cach´ e Si volem que el resultat d’una de les nostres p` agines servides per el framework puga ser desada en la cach´ e del client durant un termini de temps per evitar que es sobrecarregue el sistema i es facen peticions de m´ es a recursos que no canvien, hem d’enviar-li al navegador les capc¸aleres necess` aries i especificades en l’est` andard HTTP que indiquen al client que eixa resposta ´ es cacheable. Es poden cachear tots els tipus d’accions a excepci´ o de les de tipus cron i redirect. Fer les accions cacheables ´ es molt senzill i requereix nom´ es d’un par` ametre: Listing 12.6: Definici´ o d’una ruta com a cacheable 1<?php 2/** 3*En la definicio d’una ruta 4*/ 5 12.7. CACH ´ E DE RUTES 131 6// cache desactivada 7"cache" => false 8 9// cachear, validessa 60 segons 10 "cache" => 60 11 ?> 12.7 Cach´ e de rutes Amb la finalitat d’accelerar el proc´ es d’enrutament, el marc de treball disposa d’una cach´ e de rutes que s´ on una s` erie de fitxers on es desa la informaci´ o de totes les rutes d’un mateix tipus. Aquestos fitxers estan situats en el directori /framework/cache/framework/router i tenen extensi´ o.ser . Si es desenvolupa una acci´ o nova i es ’connecta’ mitjanc¸ant algun fitxer de rutes, s’- haur` a de regenerar aquesta cach´ e de rutes. Per fer-ho, nom´ es cal que s’esborren tots el fitxers d’eixe directori i es fac¸a una petici´ o a qualsevol URL de la nostra aplicaci´ o web, aix´ ı es regenerar` a aquesta cach´ e. 132 CAP´ ITOL 12. EL SISTEMA D’ENRUTAT Cap´ ıtol 13 Autenticaci´ o 13.1 Introducci´ o El component Authentication serveix per proveir al marc de treball de serveis d’autenticaci´ o d’usuaris. Els usuaris poden ser autenticats per tres m` etodes: •Base de dades. •Fitxers .htaccess . •Servidor corporatiu IMAP. 13.2 Configuraci´ o de l’autenticaci´ o L’autenticaci´ o ha de configurar-se en el fitxer de configuraci´ oauthentication.xml situat en el directori /framework/config i amb un contigut semblant al seg¨ uent codi font: Listing 13.1: Configuraci´ o del component Authentication 1<?php 2$config = array( 3"sections" => array ( 4"database" => array ( 5// largaries min i max per usuari i contrasenya 6"lengths" => array ( 7"min" => 6, 8"max" => 50 9), 10 // font de dades 11 "datasource" => array ( 12 "type" => "database", 13 "table" => "user", 14 "username" => "username", 15 "password" => "password", 16 "status" => "status", 133 134 CAP´ ITOL 13. AUTENTICACI ´ O 17 "role" => "role", 18 "crypt" => "sha1" 19 ), 20 // definicio de rols 21 "roles" => array ( 22 "multiple" => true, 23 "table" => "role", 24 "join" => "user_has_roles", 25 "user" => "username", 26 "role" => "role" 27 ), 28 // codis d’error 29 "codes" => array ( 30 "success" => 200, 31 "forbidden" => 403, 32 "blocked" => 402, 33 "error" => 500 34 ), 35 // definicio de les dades d’usuari 36 "usersource" => array ( 37 "table" => "user", 38 "username" => "username", 39 "columns" => array ( 40 "username", 41 "email", 42 "name", 43 "language", 44 "theme", 45 "display_name", 46 "status" 47 ) 48 ) 49 ), 50 "file" => array ( 51 "lengths" => array ( 52 "min" => 6, 53 "max" => 50 54 ), 55 "datasource" => array ( 56 "type" => "htpasswd", 57 "filename" => "framework/.htpasswd", 58 "crypt" => "sha" 59 ), 60 "roles" => array ( 61 "multiple" => true, 62 "table" => "role", 63 "join" => "user_has_roles", 64 "user" => "username", 65 "role" => "role" 66 ), 67 "codes" => array ( 68 "success" => 200, 69 "forbidden" => 403, 70 "blocked" => 402, 13.2. CONFIGURACI ´ O DE L’AUTENTICACI ´ O135 71 "error" => 500 72 ), 73 "usersource" => array ( 74 "table" => "user", 75 "username" => "username", 76 "columns" => array ( 77 "username", 78 "email", 79 "name", 80 "language", 81 "theme", 82 "display_name", 83 "status" 84 ) 85 ) 86 ), 87 "imap" => array ( 88 "lengths" => array ( 89 "min" => 6, 90 "max" => 50 91 ), 92 "datasource" => array ( 93 "type" => "imap", 94 "host" => "imap.gmail.com", 95 "port" => "993" 96 ), 97 "roles" => array ( 98 "multiple" => true, 99 "table" => "role", 100 "join" => "user_has_roles", 101 "user" => "username", 102 "role" => "role" 103 ), 104 "codes" => array ( 105 "success" => 200, 106 "forbidden" => 403, 107 "blocked" => 402, 108 "error" => 500 109 ), 110 "usersource" => array ( 111 "table" => "user", 112 "username" => "username", 113 "columns" => array ( 114 "username", 115 "email", 116 "name", 117 "language", 118 "theme", 119 "display_name", 120 "status" 121 ) 122 ) 123 ) 124 ), 136 CAP´ ITOL 13. AUTENTICACI ´ O 125 "global" => array ( 126 "default" => "database" 127 ) 128 ); 129 130 FW_Config::createConfig("authentication"); 131 FW_Config::setConfig("authentication",$config); 132 ?> En aquest codi font es poden distingir tres seccions que corresponen amb els tres m` etodes d’autenticaci´ o descrits abans. Generalment utilitzarem nom´ es autenticaci´ o via bases de dades (a menys que hi haja algun sistema d’autenticaci´ o antic o corporatiu). 13.3 Creaci´ o de la taula d’usuaris Amb el seg¨ uent codi SQL podrem crear la taula d’usuaris en la nostra base de dades. Listing 13.2: Ordres SQL per crear les taules de dades on es desar` a la informaci´ o de l’usuari 1CREATE TABLE user ( 2username VARCHAR(50) NOT NULL PRIMARY KEY, 3password VARCHAR(50) NOT NULL, 4email VARCHAR(50) NOT NULL, 5name VARCHAR(50) NOT NULL, 6activation_key VARCHAR(50) NOT NULL, 7date_register DATETIME, 8language VARCHAR(10) NOT NULL, 9theme VARCHAR(50) NOT NULL DEFAULT ’default’, 10 display_name VARCHAR(128) NOT NULL, 11 status INTEGER(1) NOT NULL DEFAULT 0 12 ); 13 14 CREATE TABLE user_has_roles ( 15 username VARCHAR(50) NOT NULL, 16 role VARCHAR(20) NOT NULL, 17 PRIMARY KEY(username,role) 18 ); 19 20 CREATE TABLE role ( 21 role VARCHAR(20) NOT NULL PRIMARY KEY, 22 enabled INTEGER(1) NOT NULL DEFAULT 1, 23 description TEXT 24 ); Nota: Les contrasenyes s´ on encriptades mitjanc¸ant els algorismes SHA1 oMD5, consulteu el fitxer de configuraci´ o del component Authentication per saber quin algorisme emprar al desar la contrasenya. 13.4 Autenticar un usuari Per autenticar un usuari utilitzarem el seg¨ uent snippet de codi: 13.4. AUTENTICAR UN USUARI 137 Listing 13.3: Component Authentication: Snippet per autenticar usuaris 1<?php 2/*en un metode d’un controlador */ 3 4// creem unes noves credencials 5$credentials = new FW_Authentication_Credentials("usuari", "contrasenya"); 6 7// creem un contenedor de parametres i li assignem valors 8$parameters = new FW_Container_Parameter(); 9$parameters->credentials = $credentials; 10 $parameters->type = "database"; 11 $parameters->rules = "database"; 12 13 // creem la instancia del component FW_Authentication configurant-la amb les dades del contenedor de parametres 14 $auth = new FW_Authentication($parameters); 15 16 // cridem a la operacio login (200 es el codi d’error per indicar que el proces va terminar satisfactoriament) 17 if ($auth->login()===200) { 18 // autenticat correctament 19 20 // obtenim el usuari loggejat en el sistema 21 $user = $auth->getUser(); 22 } 23 else { 24 // error en usuari o contrasenya o ambdos 25 } 26 ?> 144 CAP´ ITOL 15. PROGRAMACI ´ O D’ACCIONS 109 protected $role; 110 protected $enabled; 111 }; 112 113 // /app/lib/models/user.class.php 114 class user extends FW_ActiveRecord_Model { 115 116 117 protected $username; 118 protected $password; 119 protected $email; 120 protected $role; 121 protected $name; 122 protected $activation_key; 123 protected $date_register; 124 protected $language; 125 protected $theme; 126 protected $display_name; 127 protected $status; 128 protected $url; 129 protected $bio; 130 protected $image; 131 protected $notifications; 132 133 public static $has_and_belongs_to_many = array ( 134 array( 135 "property" => "role", 136 "srcTable" => "user", 137 "srcColumn" => "username", 138 "dstTable" => "role", 139 "dstColumn" => "role", 140 "throughTable" => "user_has_roles", 141 "throughTableSrcColumn" => "username", 142 "throughTableDstColumn" => "role", 143 "update" => "restrict", 144 "delete" => "restrict" 145 ) 146 ); 147 148 public function getDisplayName() { 149 return $this->display_name; 150 } 151 152 public function setPreferences($preferences) { 153 154 if (isset($preferences["name"]) && strlen( $preferences["name"])>0) { 155 $this->name = $this->_filter->sanitizeString( $preferences["name"],true); 156 } 157 158 if (isset($preferences["email"]) && strlen( $preferences["email"])>0) { 159 $this->email = $this->_filter->sanitizeString( 15.2. ESTRUCTURA DE LA DEMOSTRACI ´ O145 $preferences["email"]); 160 } 161 162 if (isset($preferences["language"]) && strlen( $preferences["language"])>0) { 163 $this->preferredLanguage = $this->_filter-> sanitizeString($preferences["language"]); 164 } 165 166 if (isset($preferences["notifications"]) && strlen( $preferences["notifications"])>0) { 167 if ( ($preferences["notifications"]=="on") || ( $preferences["notifications"]=="off")){ 168 $this->notifications = $preferences[" notifications"]; 169 } 170 } 171 172 if ($this->validateData()) { 173 $this->save(); 174 return true; 175 } 176 else { 177 return false; 178 } 179 } 180 181 public function getName() { 182 return utf8_decode($this->name); 183 } 184 185 186 public function getRole() { 187 188 $roles = array(); 189 if ($this->role instanceof FW_ActiveRecord_Relation) { 190 foreach ($this->role as $role) { 191 $roles []= $role->role; 192 } 193 return implode(’ ’,$roles); 194 } 195 196 return $this->role; 197 } 198 199 }; 200 201 202 203 ?> 146 CAP´ ITOL 15. PROGRAMACI ´ O D’ACCIONS 15.3 Definici´ o del layout Definirem el layout est` andard per a les demostracions com a un layout que cont´ e dos columnes (men´ u a l’esquerra, contingut a la dreta), capc¸alera i peu de p` agina. Aquest layout t´ e el seg¨ uent aspecte: Listing 15.2: Layout per a les demostracions 1<!DOCTYPE html> 2<html> 3<head> 4<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 5<title>Blog</title> 6<?php 7// mostrar els estils CSS per aquest modul 8print FW_Style_Manager::getInstance()->displayStyle( FW_Context::getInstance()->router->route); 9 10 // mostrar els estils CSS per aquesta accio 11 $styles = FW_Context::getInstance()->router->styles; 12 if (count($styles)>0) { 13 foreach ($styles as $style) { 14 $file = $style["file"]; 15 $media = $style["media"]; 16 print style_tag($file,$media).’\n’; 17 } 18 } 19 ?> 20 </head> 21 22 <body> 23 <div id="wrapper"> 24 25 <div id="container" class="container"> 26 27 <!-- Capsalera --> 28 <div id="header" class="container"> 29 <h1>Blog</h1> 30 </div> 31 32 <!-- Menu lateral --> 33 <div id="sidebar" class="container span-5 column"> 34 <?php 35 if ($this->hasSlot("sidebar")) { 36 print $this->getSlot("sidebar"); 37 } 38 else { 39 $this->renderView("sidebar/default"); 40 } 41 ?> 42 </div> 43 44 <!-- Zona de contingut --> 15.4. PROGRAMACI ´ O DE LES ACCIONS VEURE ´ ULTIMS 5 ENTRADESIVEURE ENTRADA147 45 <div id="content" class="container span-16 column last"> 46 <?php 47 // si existeix el slot a mostrar ... 48 if ($this->hasSlot("content")) { 49 // imprimir els seus contingut 50 print $this->getSlot("content"); 51 } 52 ?> 53 </div> 54 55 <hr class="space" /> 56 </div> 57 </div> 58 59 <!-- Peu de pagina --> 60 <div id="footer" class="container"> 61 <p>Blog</p> 62 </div> 63 64 65 <?php 66 // mostrar els scripts per aquesta accio 67 $scripts = FW_Context::getInstance()->router->scripts; 68 if (count($scripts)>0) { 69 foreach ($scripts as $script) { 70 print html::script_tag($script); 71 } 72 } 73 ?> 74 </body> 75 </html> Aquest layout el desarem en el directori layout de cada m` odul. 15.4 Programaci´ o de les accions veure ´ ultims 5 entradesiveure entrada Aquestes dos accions s’encarreguen de mostrar entrades. 15.4.1 Acci´ oveure ´ ultims 5 entrades Aquesta acci´ o mostrar` a els darrers 5 entrades inserits en el sistema: Listing 15.3: Codi font per a l’acci´ o index (veure ´ ultimes 5 entrades) 1<?php 2// accio index (indexContorller.class.php) 3 4public function index() { 5// obtindre els 5 posts mes recents 6$posts = $this->model()->getLatestsPosts(); 7// si hi ha posts recents 148 CAP´ ITOL 15. PROGRAMACI ´ O D’ACCIONS 8if ($posts->hasResult()) { 9$this->setSlot("content","posts/posts",array("posts" =>$posts)); 10 } 11 else { 12 $this->setSlot("content","posts/noPosts"); 13 } 14 // renderitzar el layout per defecte 15 $this->renderLayout("default"); 16 } 17 18 19 // indexModel.class.php 20 public function getLatestsPosts() { 21 // condicions: el post estiga publicat 22 $conditions = array ( 23 array ( 24 "name" => "status", 25 "operator" => "=", 26 "value" => "1" 27 ) 28 ); 29 // ordre de creacio per data descendent 30 $orders = array ( 31 array ( 32 "column" => "created_at", 33 "type" => "DESC" 34 ) 35 ); 36 37 // cercar les entrades 38 $posts = post::find($conditions,$orders,array(),array(),5) ; 39 return $posts; 40 } 41 ?> 15.4.2 Acci´ oveure entrada Aquesta acci´ o mostrar` a una entrada basant-se en el seu atribut permalink que ´ es ´ unic: Listing 15.4: Codi font per a l’acci´ o viewPost (veure entrada) 1<?php 2 3// accio viewPost (indexController.class.php) 4public function viewPost($permalink) { 5// decodificar la url del permalink 6$permalink = urldecode($permalink); 7 8// cercar l’entrada amb el permalink 9$post = $this->model()->getPostByPermalink( $permalink); 10 15.4. PROGRAMACI ´ O DE LES ACCIONS VEURE ´ ULTIMS 5 ENTRADESIVEURE ENTRADA149 11 // si existeix eixa entrada, mostrar-la 12 if ($post!==null) { 13 $this->setSlot("content","posts/post",array("post"=> $post)); 14 } 15 else { 16 $this->setSlot("content","posts/notFound"); 17 } 18 // renderitzar el layout per defecte 19 $this->renderLayout("default"); 20 } 21 22 // indexModel.class.php 23 public function getPostByPermalink($permalink) { 24 // condicions de cerca (permalink i estat->publicat) 25 $conditions = array ( 26 array ( 27 "name" => "permalink", 28 "operator" => "=", 29 "value" => $permalink 30 ), 31 array ( 32 "condition" => "AND" 33 ), 34 array ( 35 "name" => "status", 36 "operator" => "=", 37 "value" => "1" 38 ) 39 ); 40 41 // cercar l’entrada 42 $post = post::find($conditions); 43 // si hi ha resultats ... 44 if ($post->hasResult()) { 45 // retornar el primer resultat 46 return $post->first(); 47 } 48 } 49 50 ?> 15.4.3 Vistes A continuaci´ o es detallen les vistes per l’acci´ o index: Listing 15.5: Vistes per l’acci´ o index 1<?php 2 3// vista posts/posts.php 4<div class="span-16 last"> 5<h2>Benvingut al blog</h2> 6<hr /> 150 CAP´ ITOL 15. PROGRAMACI ´ O D’ACCIONS 7<p>Lorem ipsum dolor sit amet...</p> 8</div> 9 10 <div class="span-16 last"> 11 <h3>Entrades</h3> 12 <hr /> 13 </div> 14 15 <?php 16 // mostrar per a cada entrada un breu contingut 17 foreach ($posts as $post) { 18 $this->renderView("posts/excerpt",array("post"=>$post) ); 19 } 20 ?> 21 22 23 24 // vista posts/excerpt.php 25 <div class="span-16 container last"> 26 <div class="span-2 column"> 27 <img src="<?php print $post->getImage(); ?>" alt=" <?php print $this->display($post->title); ?>" width="75" /> 28 </div> 29 <div class="span-14 column last"> 30 <h4><?php print html::link_to_internal("index"," index","viewPost",$this->display($post->title), array("permalink"=>$post->permalink));?></h4> 31 <p class="alt"><?php print _("Per ").html:: link_to_internal("user","user"," displayUserProfile",$this->display($post-> author->first()->display_name),array("username" =>$post->author->first()->username))._(" el "). $post->getDate(); ?></p> 32 </div> 33 34 <div class="span-16 container last"> 35 <?php print $this->display($post->excerpt); ?> 36 </div> 37 38 <div class="span-12 column"> </div> 39 <div class="span-4 last"> 40 <p>(<?php print count($post->comments); ?>) comentaris | <?php print html::link_to_internal ("index","index","viewPost","Llegir mes",array( "permalink"=>$post->permalink));?></p> 41 42 </div> 43 </div> 44 45 46 // vista noPosts.php 47 <div class="span-16 last"> 15.4. PROGRAMACI ´ O DE LES ACCIONS VEURE ´ ULTIMS 5 ENTRADESIVEURE ENTRADA151 48 <h3>Error</h3> 49 <hr /> 50 <p>Malauradament no disposem d’entrades per mostrar. Torne en uns dies a visitar-nos!</p> 51 </div> 52 53 ?> I tamb´ e les de l’acci´ o viewPost: Listing 15.6: Vistes per l’acci´ o viewPost 1<?php 2// vista posts/post.php 3<div class="span-16 container last"> 4<div class="span-2 column"> 5<img src="<?php print $post->getImage(); ?>" alt=" <?php print $this->display($post->title); ?>" width="75" /> 6</div> 7<div class="span-14 column last"> 8<h2><?php print html::link_to_internal("index"," index","viewPost",$this->display($post->title), array("permalink"=>$post->permalink));?></h2> 9<p class="alt"><?php print _("Per ").html:: link_to_internal("user","user"," displayUserProfile",$this->display($post-> author->first()->display_name),array("username" =>$post->author->first()->username)._(" el "). $post->getDate(); ?></p> 10 </div> 11 12 <div class="span-16 container last"> 13 <?php print $this->display($post->content); ?> 14 </div> 15 </div> 16 17 18 <?php 19 // si es commentable ... 20 if ($post->is_commentable || count($post->comments)>0) { 21 $this->renderView("posts/comments/comments",array(" comments"=>$post->comments)); 22 } 23 if ($post->is_commentable) { 24 if ($this->user()!==false) { 25 $this->renderView("posts/comments/commentForm", array("id_post"=>$post->id)); 26 } 27 } 28 ?> 29 30 31 32 152 CAP´ ITOL 15. PROGRAMACI ´ O D’ACCIONS 33 // vista posts/notFound.php 34 <div class="span-16 last"> 35 <h3>Error</h3> 36 <hr /> 37 <p>Lentrada que ha sol.licitat no existeix o no esta disponible</p> 38 </div> 39 40 41 42 // vista posts/comments/comments.php 43 <hr /> 44 <hr class="space" /> 45 <div class="span-16 container last"> 46 <h2>Comentaris</h2> 47 <hr /> 48 <?php 49 if (count($comments)===0) { ?> 50 <div class="span-16 last"> 51 <p>Aquesta entrada no te comentaris</p> 52 </div> 53 <?php 54 } 55 else { 56 foreach ($comments as $comment) { 57 $this->renderView("posts/comments/comment",array(" comment"=>$comment)); 58 ?> 59 <hr class="space" /> 60 <?php 61 } 62 } 63 ?> 64 <hr class="space" /> 65 </div> 66 67 68 // vista posts/comments/comment.php 69 <div class="span-12 prepend-2 last"> 70 <p class="alt"><?php print _("Per ").html:: link_to_internal("user","user","displayUserProfile", $this->display($comment->author->first()->display_name) ,array("username"=>$post->author->first()->username))._ (" el ").$comment->getDate(); ?></p> 71 <br/> 72 <?php print $this->display($comment->content); ?> 73 </div> 74 75 ?> 15.4. PROGRAMACI ´ O DE LES ACCIONS VEURE ´ ULTIMS 5 ENTRADESIVEURE ENTRADA153 15.4.4 Captures de pantalla Figura 15.1: Acci´ o index Figura 15.2: Acci´ o viewPost 256 CAP´ ITOL 21. SOAP Listing 21.26: Client de SOAP per a provar el servei web de demostraci´ o 1<?php 2// forcem al client de soap a no cachear el WSDL 3ini_set("soap.wsdl_cache_enabled","0"); 4 5class Book { 6public $isbn; 7public $title; 8public $author; 9}; 10 11 // adreca del fitxer wsdl 12 $wsdl = "http://localhost/blog/soap/webservices/soap/ provide/demo?wsdl"; 13 // creem un client web 14 $client = new SoapClient($wsdl); 15 16 // provem accio getBooks 17 $books = $client->getBooks(); 18 foreach ($books->item as $book) { 19 print "{$book->title} ISBN: {$book->isbn}, per {$book-> author} \n\n"; 20 } 21 22 // obtenim el llibre amb el ISBN ... 23 $book = $client->getBook("978-84-415-2514-6"); 24 if ($book!==null) { 25 print "Dades del llibre amb ISBN 978-84-415-2514-6: "; 26 print "{$book->title} ISBN: {$book->isbn}, per {$book-> author} \n\n"; 27 } 28 29 // creem un nou llibre 30 $b = new Book(); 31 $b->isbn = "1"; 32 $b->title = "Proves"; 33 $b->author = "Author1"; 34 35 // creem el libre 36 $result = (bool) $client->createBook($b); 37 if ($result===true) { 38 print "Llibre creat\n\n"; 39 } 40 41 // esborrem el llibre creat 42 $result = (bool) $client->deleteBook("1"); 43 if ($result===true) { 44 print "Llibre esborrat\n\n"; 45 } 46 47 ?> Listing 21.27: Possible eixida al executar el client 21.3. GENERACI ´ O DE SERVEIS WEB SOAP 257 1usuari@maquina:/var/www/framework$ php books.php 2Ajax, JavaScript y PHP ISBN: 978-84-415-2514-6, per Ballard, Phil | Moncur, Michael | Gomez del Castillo, Rosario 3 4Mi libro ISBN: 15, per blahblah 5 6Dades del llibre amb ISBN 978-84-415-2514-6: Ajax, JavaScript y PHP ISBN: 978-84-415-2514-6, per Ballard, Phil | Moncur, Michael | Gomez del Castillo, Rosario 7 8Llibre creat 9 10 Llibre esborrat 258 CAP´ ITOL 21. SOAP Part VII Temes avanc¸ats de desenvolupament 259 Cap´ ıtol 22 Introducci´ o 22.1 Introducci´ o En aquest cap´ ıtol es presenten temes avanc¸ats de desenvolupament. 261 262 CAP´ ITOL 22. INTRODUCCI ´ O Cap´ ıtol 23 Internacionalitzaci´ o 23.1 Introducci´ o La internacionalitzaci´ o (i18n) d’una aplicaci´ o web ´ es una forma d’adaptar l’interf´ ıcie de la mateixa a la llengua i costum de l’usuari, ´ es a dir, fer que una aplicaci´ o estiga disponible en molts idiomes arribant aix´ ı a molts usuaris. Per a l’internacionalitzaci´ o es fa servir la biblioteca GNU Gettext a trav´ es de la versi´ o de PHP i un programa que genera fitxers PO on s’indiquen quines cadenes s´ on tradu¨ ıbles i la seva traducci´ o. 23.2 Marcatge de cadenes com a tradu¨ ıbles Per a poder traduir una cadena de text, aquesta ha d’estar marcada amb els car` acters (”...”); o mitjanc¸ant una cridada a la funci´ o$string =gettext($cadena); cal notar que   ´ es un ` alies de la funci´ o gettext per tant, es recomana cridar a la funci´ o en comptes de gettext ja que ´ es m´ es senzill d’escriure. En el seg¨ uent fragment de codi es resumeixen les posibilitats de marcatge de cadenes com a tradu¨ ıbles. Listing 23.1: Marcatge de cadenes com a tradu¨ ıbles 1<?php 2 3$cadena = _("Cadena internacionalitzable"); 4$cadena = gettext("Cadena internacionalitzable"); 5 6print _("Aixo es una cadena traduible"); 7print gettext("Aixo es una cadena traduible"); 8 9?> M´ es documentaci´ o sobre Gettext per a PHP en l’adrec¸a http://php.net/ manual/en/function.gettext.php 263 264 CAP´ ITOL 23. INTERNACIONALITZACI ´ O 23.3 Generaci´ o dels fitxers PO de traducci´ o Per tal de que l’aplicaci´ o funcione de manera internacionalitzable s’han d’arreplegar totes les cadenes marcades com a tradu¨ ıbles en tota l’aplicaci´ o web i generar amb elles un fitxer PO per a cada idioma dels que es pensa traduir. Per fer aquest pas ens ajudarem amb el programa PoEditdescarregable des de http://www.poedit. net/ o instal·lable amb l’ordre Listing 23.2: Aspecte d’un fitxer PO 1msgid "" 2msgstr "" 3"Project-Id-Version: Poedit 1.5\n" 4"Report-Msgid-Bugs-To: [email protected]\n" 5"POT-Creation-Date: 2010-05-07 08:40+0200\n" 6"PO-Revision-Date: 2009-02-06 13:44+0100\n" 7"Last-Translator: Fulanito de tal <[email protected]>\n" 8"Language-Team: Fulanito de tal <[email protected]>\n" 9"MIME-Version: 1.0\n" 10 "Content-Type: text/plain; charset=UTF-8\n" 11 "Content-Transfer-Encoding: 8bit\n" 12 "X-Poedit-Language: Catalan\n" 13 14 #: ../src/edframe.cpp:1999 15 msgid " (modified)" 16 msgstr " (modificat)" 17 18 #. TRANSLATORS: This is version information in about dialog, it is followed 19 #. by version number when used 20 #: ../src/edframe.cpp:2351 21 #, fuzzy 22 msgid " Version " 23 msgstr "versio" 24 25 #: ../src/edframe.cpp:1964 26 #, fuzzy, c-format 27 msgid "%i %% translated, %i strings" 28 msgstr "S’han traduit %u cadenes automaticament" 23.3. GENERACI ´ O DELS FITXERS PO DE TRADUCCI ´ O265 Figura 23.1: Aspecte de Poedit Una vegada instal·lat el programa Poedit, crearem un projecte nou amb el nom blogal que li afegirem el directori /var/www/blog o el directori en el que hagem instal·lat el marc de treball i l’aplicaci´ o de demostraci´ o. Crearem un els seg¨ uents directoris dins del directori app/resources/locales marc de treball ca ES/LC MESSAGES (per a l’idioma catal` a) i es ES/LC MESSAGES per a l’idioma castell` a i altres directoris per altres idiomes que vullguem traduir l’aplicaci´ o web. Despr´ es crearem un fitxer messages.po(que contindr` a les cadenes marcades com a tradu¨ ıbles) en cadascun dels directoris creats anteriorment amb ajuda de les seg¨ uents l´ ınies d’ordres. Listing 23.3: Ordres per generar els fitxers .po 1find . -type f -iname ’*.php’ | xargs xgettext -n *.php -- from-code utf-8 -o app/resources/locales/ca_ES/ LC_MESSAGES/messages.po 2find . -type f -iname ’*.php’ | xargs xgettext -n *.php -- from-code utf-8 -o app/resources/locales/es_ES/ LC_MESSAGES/messages.po Una vegada estiguen generats tants fitxers com siguen necessaris (un fitxer per idioma), s’obriran amb el programa Poedit i s’escomenc¸aran a editar i traduir segons convinga. Cada vegada que es genere una nova cadena tradu¨ ıble o a cada vista que es complete, ´ es necessari actualitzar els fitxers .po per a que aquestos incloguen les noves cadenes que es volen traduir. 272 CAP´ ITOL 24. CACHE 7if ($obj!==null) { 8$dades = $obj->getContents(); 9} 10 ?> Verificar si ha expirat el contingut d’un cache object El m` etode hasExpired() d’un cache object proporciona informaci´ o sobre si ha expirat o no la informaci´ o desada en eixe objecte segons el par` ametre lifetime (temps de vida) amb el que es va crear. Listing 24.9: Verificar si ha expirat el contingut d’un cache object 1<?php 2// Verificar si les dades emmagatzemades en un cache_object han expirat 3bool hasExpired () 4 5$dades = null; 6$obj = $cache->get("id","les_meves_dades"); 7if ($obj!==null) { 8if (!$obj->hasExpired()) { 9$dades = $obj->getContents(); 10 } 11 else { 12 // regenerar les dades 13 } 14 } 15 ?> 24.4.3 Un exemple complet En aquest exemple obtindrem el feed RSS de l’ETSINF i el desarem el cach´ e per 600 segons (10 minuts): Listing 24.10: Exemple complet 1<?php 2$dades = null; 3 4// url del feed RSS de la UPV 5$feed = "http://tv.inf.upv.es/?feed=rss2" 6 7// component cache 8$cache = FW_Cache::getInstance(); 9$obj = $cache->get(md5($feed),"rss"); 10 11 if ($obj!==null) { 12 // tenim les dades 13 if (!$obj->hasExpired()) { 14 // no han expirat les dades 15 $dades = $obj->getContents(); 16 } 24.4. IDENTIFICACI ´ O DE DADES EN CACHE 273 17 else { 18 // regenerem les dades, ja que han expirat 19 $dades = file_get_contents($feed); 20 if (strlen($dades)>0) { 21 $cache->remove(md5($feed),"rss"); 22 $cache->set(md5($feed),"rss",serialize($dades),600); 23 } 24 } 25 } 26 else { 27 // no tenim les dades, toca obtindre-les 28 $dades = file_get_contents($feed); 29 if (strlen($dades)>0) { 30 $cache->set(md5($feed),"rss",serialize($dades),600); 31 } 32 } 33 ?> 274 CAP´ ITOL 24. CACHE Cap´ ıtol 25 Configuracions d’aplicaci´ o personalitzades 25.1 Introducci´ o A vegades ´ es necessari que les aplicacions web tinguen una s` erie de valors relacionats amb la l` ogica de negoci de la pr` opia aplicaci´ o. Aquestos valors poden ser constants, restriccions, valors computats anteriorment, regles de negoci, . . . Amb la finalitat de no emprar constants per representar aquestos valors en la nostra aplicaci´ o web i tamb´ e amb una finalitat d’estar tots aquestos valors organitzats i accessibles a trav´ es d’una interf´ ıcie comuna a les aplicacions d’usuari se’ls permet crear els seus fitxers de configuraci´ o i accedir-ne a aquestos amb una simple cadena de text de l’estil negoci.sections.produccio.preu o a trav´ es d’una classe derivada de FW Config Handler (classe ajudant que permet fer operacions sobre configuracions). 25.2 Creaci´ o de configuracions personalitzades Per crear una configuraci´ o personalitzada s’ha de crear un fitxer (que la continga) en el directori /app/config (exemple /app/config/proves.php). Sempre ´ es recomanable que el fitxer - i per tant el nom de la configuraci´ o - estiga format d’una paraula i sense accents,espais o punts que causen problemes; per tant, un nom no v` alid seria proves.de.configuraci´ oola meua configuraci´ o. 25.2.1 Esquelet d’un fitxer de configuraci´ o Un cop creat el fitxer de configuraci´ o passarem a crear en ell l’esquelet d’una configuraci´ o, que ha d’estar composta com a m´ ınim per un array amb dos claus sections i global . L’esquelet d’un fitxer de configuraci´ o seria el seg¨ uent: Listing 25.1: Esquelet d’un fitxer de configuraci´ o 1<?php 2$config = array( 3"sections" => array ( 4// aci anira la configuracio detallada 275 276 CAP´ ITOL 25. CONFIGURACIONS D’APLICACI ´ O PERSONALITZADES 5), 6"global" => array ( 7// aci anira la configuracio global 8) 9); 10 11 FW_Config::createConfig("proves"); 12 FW_Config::setConfig("proves",$config); 13 ?> 25.2.2 Creaci´ o de valors dins la configuraci´ o Despr´ es d’haver creat l’esquelet del fitxer de configuraci´ o ja podrem crear valors dins ell. En l’esquelet haviem distingit dues seccions (global isections). En la secci´ o global ´ es on crearem els nostres valors que siguen molt comuns a tota la nostra aplicaci´ o web(exemple: permetre desar el log d’operacions, engegar o apagar un component,. . . ), per altra banda, en la secci´ osections crearem valors concrets per a cada ` area que ens interesse (exemple: usuari i contrasenya del terminal de punt de venda virtual (TPVV) ). En tot cas, els valors que podem donar-lis seran de la forma (clau-valor, clau-array o combinacions d’ambdues formes) d’altra manera no funcionar` a. Listing 25.2: Exemple de fitxer de configuraci´ o 1<?php 2$config = array( 3"sections" => array ( 4"banc_del_parc" => array ( 5"username" => "bpark102030", 6"password" => "bpk10224521" 7), 8"banc_a_rrota" => array ( 9"username" => "bkrt9035", 10 "key" => "adsfasfadsjkfp1i1" 11 ) 12 ), 13 "global" => array ( 14 "permetreTPVV" => true, 15 "defaultTPVV" => "banc_del_parc" 16 ) 17 ); 18 19 FW_Config::createConfig("proves"); 20 FW_Config::setConfig("proves",$config); 21 ?> 25.2.3 Acc´ es a valors de la configuraci´ o Accedir a valors de la configuraci´ o´ es molt senzill. La forma d’accedir-ne a un valor de la configuraci´ o´ es mitjanc¸ant una clau (cadena de car` acters) de l’estil proves.sections.banc del parc.username. Tota configuraci´ o t´ e sempre dos seccions (sections oglobal), aix´ ı totes les claus comencen per proves.sections.oproves.global.i despr´ es del ´ ultim punt el nom de la clau 25.2. CREACI ´ O DE CONFIGURACIONS PERSONALITZADES 277 a recuperar. Si el valor de la clau de la configuraci´ o´ es un array poden presentar-se dos situacions: 1. Es vol obtindre l’array complet: Posarem en la clau el nom de l’array: Exemple, volem recuperar la configuraci´ o de banc del parc , llavors la clau seria proves.sections.banc del parc. 2. Es vol obtindre un valor concret de l’array d’una configuraci´ o: Posarem la clau amb el nom de l’array i li afegirem un punt .i el nom de la clau de l’array que volem recuperar: Exemple, volem recuperar el nom d’usuari de banc del parc , llavors la clau seria proves.sections.banc del parc.username. Aix´ ı, la configuraci´ o´ es totalment flexible (utilitzant arrays clau-valor), la informaci´ o es pot emmagatzemar d’eixes dues formes o de forma mixta (arrays amb valors que s´ on arrays anidats o valors que s´ on escalars). Per tant, ´ es igual de senzill obtindre una informaci´ o que estiga dins de 5 arrays anidats que una informaci´ o que siga una entrada en la secci´ o global, tot dep` en del contingut de la clau i aquesta identificar` a un´ ıvocament el valor al que es vol accedir. A continuaci´ o es pot veure un exemple de com accedir a una configuraci´ o personalitzada: Listing 25.3: Acc´ es a una configuraci´ o personalitzada 1<?php 2// metode get del component Config 3mixed get($key) 4 5// en un accio d’un controlador o en un metode d’un model ... 6/** 7Suposem que tenim una variable anomenat tipus (de pagament) 8que vindria determinada per certes condicions .. 9**/ 10 11 // obtenim la instancia del component Config 12 $config = FW_Config::getInstance(); 13 $clau = "pagaments.sections.{$tipus}"; 14 15 // obtenim el valor que hi ha desat en eixa clau 16 $configuracio = $config->get($clau); 17 if ($configuracio!==null) { 18 $tpvv = tpvv::factory($tipus,$configuracio); 19 ... 20 } 21 else { 22 throw new FW_User_Exception("No s’ha pogut trobar la forma de pagament {$tipus}"); 23 } 24 ?> Per veure m´ es m` etodes d’acc´ es a una configuraci´ o personalitzada sense emprarne una classe ajudant, llegiu la documentaci´ o corresponent la classe FW Config.´ Es 278 CAP´ ITOL 25. CONFIGURACIONS D’APLICACI ´ O PERSONALITZADES recomanable - sempre que es puga - utilitzar una classe ajudant per a gestionar configuracions. 25.3 Creaci´ o d’ajudants per a configuracions personalitzades Un ajudant o helper per una configuraci´ o personalitzada ´ es una classe que permet gestionar un fitxer de configuraci´ o personalitzat amagant la l` ogica necess` aria per accedir o generar configuracions i proporcionant una interf´ ıcie senzilla per accedir-ne a aquesta. Aix` o facilita una separaci´ o completa entre l’aplicaci´ o web i la configuraci´ o personalitzada, de manera que l’acc´ es o modificaci´ o d’aquesta no es fa directament des d’una acci´ o d’un controlador sin´ o que la classe ajudant pot tindre una l` ogica que determinant algunes condicions d’acc´ es o donades unes condicions hor` aries puga escollir una clau o altra de la configuraci´ o, . . . Per a tots aquestos problemes, podem crear una classe ajudant que far` a el treball per nosaltres. Una classe ajudant ´ es una classe de PHP derivada de la classe FW Config Handler (gestionador de configuraci´ o i que cont´ e els m` etodes necessaris per accedir, modificar-ne i afegir valors de/a la configuraci´ o) que s’ha de crear en el directori /app/config/Handler i que ha de tindre de nom en maj´ uscules el nom de la configuraci´ o a la que ajuda. Exemple: •configuraci´ o: pagaments , nom de la classe: FW Config Handler Pagaments, nom del fitxer: /app/config/Handler/Pagaments.class.php •configuraci´ o: serveis SMS , nom de la classe: FW Config Handler Serveis SMS, nom del fitxer: /app/config/Handler/Serveis SMS.class.php 25.3.1 Creaci´ o de la classe ajudant A continuaci´ o es mostra el codi font m´ ınim d’una classe ajudant per poder gestionar la configuraci´ opagaments: Listing 25.4: Codi font m´ ınim per a crear una classe ajudant de configuraci´ o 1<?php 2class FW_Config_Handler_Pagaments extends FW_Config_Handler { 3 4// Aci aniran les propietats 5 6// Aci aniran les operacions 7}; 8?> Com es pot veure, aquesta classe deriva de la classe FW Config Handler que cont´ e totes les operacions i propietats per actuar directament sobre un fitxer de configuraci´ o determinat. Com s’ha comentat abans, cada classe ajudant rep el nom del fitxer de configuraci´ o i de la configuraci´ o (tot en min´ uscules) sobre la que actua. 25.3. CREACI ´ O D’AJUDANTS PER A CONFIGURACIONS PERSONALITZADES279 25.3.2 API de l’ajudant de configuraci´ o Obtenci´ o de valors Per obtindre valors de la configuraci´ o a trav´ es d’un ajudant de configuraci´ o tenim el m` etode getParameter que amb la clau corresponent s’encarrega d’obtindre dins la configuraci´ o. Aquest m` etode pot tornar un valor escalar o array (si es troba la configuraci´ o amb la clau) o null si no troba la configuraci´ o amb la clau. Listing 25.5: Obtenci´ o de dades de la configuraci´ o dins una classe ajudant de configuraci´ o 1<?php 2// obtindre un valor de la configuracio 3mixed getParameter(string $key); 4 5// exemples 6$valor = $this->getParameter("sections.{$tipus}.usuari"); 7$valor = $this->getParameter("global.status"); 8?> Modificaci´ o de valors Per modificar-ne un valor existent a trav´ es d’un ajudant de configuraci´ o s’ha d’emprar el m` etode setParameter que amb la clau del valor que es vol modificar i el valor a modificar canviar` a el valor al que apunta eixa clau en la configuraci´ o. Listing 25.6: Modificaci´ o de dades d’una configuraci´ o dins una classe ajudant de configuraci´ o 1<?php 2// modificar un valor existent de la configuracio 3void setParameter(string $parameter,mixed $value); 4 5// exemples 6$this->setParameter("global.status","enabled"); 7$this->setParameter("sections.{$tipus}.usuari",’’); 8?> Creaci´ o de valors Per afegir-ne o crear-ne un valor a trav´ es d’un ajudant de configuraci´ o s’ha d’emprar el m` etode addParameter que amb la clau del valor que es vol crear i el valor a modificar crear` a el valor al que apunta eixa clau en la configuraci´ o. Nota, cal esmentar que aquest m` etode nom´ es funcionar` a si el valor previ (el pare del valor que anem a crear) existeix i aquest ´ es un valor de tipus array, sino estariem intentant crear una clau en un element que no ´ es de tipus array i per tant no ´ es possible crear elements dins d’un valor escalar. Listing 25.7: Creaci´ o de dades d’una configuraci´ o dins una classe ajudant de configuraci´ o 1<?php 2// afegir un valor a una configuracio 280 CAP´ ITOL 25. CONFIGURACIONS D’APLICACI ´ O PERSONALITZADES 3void addParameter(string $parameter,mixed $value); 4 5// exemples 6$this->addParameter("global.mailbox","enabled"); 7$this->setParameter("sections.mailbox.username","anmarso4" ); 8?> Rec` arrega del fitxer de configuraci´ o Es pot recarregar el contingut del fitxer de configuraci´ o (exemple: hem fet canvis que no s´ on correctes, volem refrescar el contingut de la configuraci´ o, . . . ). Aquesta operaci´ o es fa a trav´ es del m` etode reload de l’ajudant, esborra les dades de la configuraci´ o i de la cach´ e de configuraci´ o, per tant, qualsevol dada no desada en el fitxer desapareixer` a. Listing 25.8: Rec` arrega d’un fitxer de configuraci´ o dins una classe ajudant de configuraci´ o 1<?php 2// recarregar un fitxer de configuracio 3void reload(void); 4 5// exemples 6$this->addParameter("global.mailbox","enabled"); 7print $this->getParameter("global.mailbox"); // -> enabled 8 9$this->reload(); 10 print $this->getParameter("global.mailbox"); // -> null 11 ?> Desament de valors Per desar el valor actual d’una configuraci´ o (si l’hem canviat), es pot fer servir el m` etode save, que desar` a totes les dades de la nostra configuraci´ o al fitxer de configuraci´ o sobre el que estem treballant. Listing 25.9: Desament de les dades d’una configuraci´ o dins d’un ajudat de configuraci´ o 1<?php 2// desar les dades en un fitxer de configuracio 3void save(void); 4 5// exemples 6 7// al principi no tenim valor 8print $this->getParameter("global.mailbox"); // -> null 9 10 // afegim el parametre i li donem valor 11 $this->addParameter("global.mailbox","enabled"); 12 print $this->getParameter("global.mailbox"); // -> enabled 13 25.3. CREACI ´ O D’AJUDANTS PER A CONFIGURACIONS PERSONALITZADES281 14 // desem el fitxer de configuracio 15 $this->save(); 16 17 // recarreguem el fitxer de configuracio 18 $this->reload(); 19 20 // el valor existeix 21 print $this->getParameter("global.mailbox"); // -> enabled 22 ?> 25.3.3 Exemple complet Listing 25.10: Exemple complet 1<?php 2class FW_Config_Handler_Pagaments extends FW_Config_Handler { 3 4public function calcularPagament($valor,$tipus) { 5if ($tipus==="llibre") { 6$taxa = $this->getParameter("sections.taxes.llibres" ); 7} 8if ($tipus==="menjar") { 9$taxa = $this->getParameter("sections.taxes.menjar") ; 10 } 11 // calcul per a la taxa+valor ... 12 } 13 14 public function adjustarTaxa($tipus,$valor) { 15 $taxa = $this->getParameter("sections.taxes.{$tipus}") ; 16 if ($taxa!==null) { 17 $this->setParameter("sections.taxes.{$tipus}",$valor ); 18 $this->save(); 19 $this->reload(); 20 } 21 } 22 23 }; 24 ?> 288CAP´ ITOL 26. CREACI ´ O I CONFIGURACI ´ O DELS ESTILS CSS D’UNA APLICACI ´ O WEB Cap´ ıtol 27 Tasques programades: CRON 27.1 Introducci´ o A vegades ´ es necessari que determinades tasques en una aplicaci´ o web siguen realitzades autom` aticament i d’una manera regular cada determinats minuts/hores. Per a poder fer funcionar aquestes tasques, aquest projecte incorpora un m` etode de funcionament anomenat CRON que permet exposar una determinada funcionalitat a la interf´ ıcie del programador de tasques dels sistemes operatius Unix, GNU-Linux o Windows. El programador de tasques CRON dels sistemes operatius tipus UNIX o el programador de tasques de Windows permeten la programaci´ o de tasques a executar a intervals de temps; aquestos programadors permeten tant executar un script o programa per l´ ınia d’ordres, com fer una petici´ o a una determinada p` agina web. Exemples de tasques programades CRON s´ on: •Fer c` opia de seguretat de la base de dades di` ariament. •Generar informes de vendes autom` aticament cada 5h. •Enviar newsletterscada primer dia de mes. 27.2 Preparaci´ o d’ordres cron Per generar una funcionalitat i exposar-la a la interf´ ıcie CRON nom´ es cal escriure el codi de la funcionalitat i especificar en la seva definici´ o de ruta que aquesta funcionalitat ´ es de tipus cron. Listing 27.1: Exemple d’acci´ o de tipus CRON 1<?php 2public function writeLog() { 3$time = (string) date("d/m/Y H:i:s"); 4$fp = fopen("/tmp/log","a+"); 5if ($fp) { 6fwrite($fp,"{$time}\n"); 7fclose($fp); 8return 0; 9} 289 290 CAP´ ITOL 27. TASQUES PROGRAMADES: CRON 10 return -1; 11 } 12 ?> Per ´ ultim, la ruta necess` aria per utilitzar aquesta funcionalitat CRON. Listing 27.2: Ruta necess` aria per accedir a la funcionalitat CRON 1<?php 2FW_Router::Connect( 3array ( 4’url’ => ’/cron/demo’, 5’type’ => ’cron’, 6’cache’ => false, 7’authentication’ => true, 8’module’ => ’cron’, 9’controller’ => ’cron’, 10 ’action’ => ’writeLog’, 11 ’internal’ => false, 12 ’parameters’ => array (), 13 ’pattern’ => ’#ˆ/cron/demo[/]*$#’, 14 ’parameterOrder’ => array() 15 ) 16 ); 17 ?> 27.3 Autenticaci´ o en tasques CRON L’autenticaci´ o per a tasques CRON est` a implementada com a autenticaci´ o est` andard mitjanc¸ant el protocol HTTP, per tant, si volem que siga necess` aria autenticaci´ o per executar una tasca CRON haurem de configurar-ho en la seva definici´ o de ruta amb els valors corresponents ( true si volem autenticar amb qualsevol usuari del sistema o un array amb els rols que hauran de tindre els usuaris). 27.4 Execuci´ o de tasques CRON Per executar tasques CRON tenim dos opcions, les quals utilitzarem segons convinga o tinguem limitat el servidor: 27.4.1 Execuci´ o de tasques CRON des de l´ ınia d’ordres Aquesta ´ es l’opci´ o cl` assica i que podriem emprar amb el programador de tasques del sistema operatiu. Mitjanc¸ant aquesta opci´ o executem l’script cron.php al que li passarem com a par` ametre la URL de la tasca CRON i l’usuari i contrasenya - si escau - . La tasca CRON en cas que incloga par` ametres els posarem en la URL i li passarem a la tasca CRON la URL amb els par` ametres. Listing 27.3: Execuci´ o de tasques CRON des de l´ ınia d’ordres 1usuari@maquina:/var/www/framework$ php cron.php /cron/demo 2 3usuari@maquina:/var/www/framework$ php cron.php /cron/demo/param1/param2 usuari contrasenya 27.4. EXECUCI ´ O DE TASQUES CRON 291 27.4.2 Execuci´ o de tasques CRON des del navegador Si el sistema o el nostre hosting no ens permet executar tasques cron des de consola o programar directament el programador de tasques per` o s´ ı ens permet programar tasques a trav´ es d’una interf´ ıcie web simple que permet fer una petici´ o a una URL cada determinat temps, utilitzarem aquesta opci´ o. Aquesta opci´ o consisteix en fer una petici´ o a la URL de la tasca CRON amb els par` ametres inclosos. Si la tasca necessita autenticaci´ o, aquesta es demanar` a a trav´ es del navegador o es permetr` a inserir en la configuraci´ o del programador de tasques del nostre hosting. 292 CAP´ ITOL 27. TASQUES PROGRAMADES: CRON Part VIII Ap` endixos: Instal·laci´ o, configuraci´ o 293 Cap´ ıtol 28 Instal·laci´ o 28.1 Instal·laci´ o La instal·laci´ o d’aquest marc de treball ´ es molt senzilla i similar per a tots els sistemes operatius. Nom´ es s’han de complir el seg¨ uents requeriments: •Servidor web amb suport per a PHP (recomanat Apache). •PHP versi´ o 5.3 o superior. •Base de dades relacional (MySQL recomanada) Una vegada cerciorats que tenim els requeriments, instal·larem les depend` encies (servidor web, php i base de dades) per a fer funcionar el marc de treball. Aquesta instal·laci´ o es far` a mitjanc¸ant l’inserci´ o de les seg¨ uents ordres en la l´ ınia d’ordres: Listing 28.1: Instal.laci´ o de PHP en GNU-Linux 1usuari@maquina:$ sudo aptitude install apache2 2usuari@maquina:$ sudo aptitude install php5 3usuari@maquina:$ sudo aptitude install mysql-server 4usuari@maquina:$ sudo aptitude install libapache2-mod-auth-mysql 5usuari@maquina:$ sudo aptitude install php5-mysql 6usuari@maquina:$ sudo aptitude install php5-cli 7usuari@maquina:$ sudo aptitude install php5-curl 8usuari@maquina:$ sudo aptitude install libapache2-mod-php5 9usuari@maquina:$ sudo aptitude install php5-pear 10 usuari@maquina:$ sudo pear install soap Es recorda que ha de ser root o tindre permisos de sudo per a poder instal·lar programari en GNU-Linux. 28.1.1 Comprovaci´ o de que PHP funciona Per comprovar que PHP funciona correctament crearem un fitxer anomenat prova.php en el directori /var/www amb el seg¨ uent contingut: Listing 28.2: Fitxer per verificar que PHP funciona 1<?php 2print phpinfo(); 3?> 295 296 CAP´ ITOL 28. INSTAL·LACI ´ O Si tot ha estat correctament instal·lat, despr´ es d’accedir-ne amb el navegador a l’adrec¸a http://localhost/prova.php hauria d’eixir-nos una informaci´ o similar a la seg¨ uent: Figura 28.1: Prova de que tot ha estat correctament instal.lat 28.2 Instal·laci´ o del marc de treball Per instal·lar el marc de treball seguirem els seg¨ uents passos: 1. Descomprimir el marc de treball en un directori. 2. Copiar el directori descomprimit al directori /var/www 3. Accedir a trav´ es de la l´ ınia d’ordres a eixe directori i donar-li permisos d’escriptura a l’usuari www-data en el directori /framework/cache 28.3 Reescriptura de URLs utilitzant Apache mod rewrite Mod Rewrite ´ es un m` odul del servidor web Apache que permet fer reescriptures de les URLs de les peticions web al vol. Es basa en l’exist` encia d’un fitxer (anomenat .htaccess) que descriu una s` erie de regles basades en expressions regulars. Per activar aquest m` odul cal amb introduir en la l´ ınia d’ordres la seg¨ uent ordre: sudo a2enmod rewrite , el sistema ens demanar` a la contrasenya i ens activar` a aquest m` odul. 28.3. REESCRIPTURA DE URLS UTILITZANT APACHE MOD REWRITE 297 Listing 28.3: Regles d’Apache mod rewrite 1<IfModule mod_rewrite.c> 2RewriteEngine On RewriteBase / 3RewriteCond %{REQUEST_FILENAME} !-f 4RewriteCond %{REQUEST_FILENAME} !-d 5RewriteRule ˆ(.*)$ index.php/$1 [L,QSA] 6RewriteRule ˆapp/(.*)$ index.php [L] 7RewriteRule ˆframework/(.*)$ index.php [L] 8RewriteRule ˆrest/(.*)$ rest.php/$1 [L,QSA] 9RewriteRule ˆsoap/(.*)$ soap.php/$1 [L,QSA] 10 RewriteRule ˆcron/(.*)$ cron.php/$1 [L,QSA] 11 </IfModule> 12 13 # RewriteCond %{REQUEST_FILENAME} !-f 14 # RewriteCond %{REQUEST_FILENAME} !-d 15 # RewriteRule ˆ(.+)$ /index.php/$1 [L,QSA] 304 CAP´ ITOL 30. BASE DE DADES DEL PROJECTE 140 -- 141 142 CREATE TABLE ‘blog_user_has_roles‘ ( 143 ‘username‘ varchar(50) NOT NULL, 144 ‘role‘varchar(20) NOT NULL, 145 PRIMARY KEY (‘username‘,‘role‘) 146 ); Cap´ ıtol 31 Taules de figures i llistat de codi font 305 306 CAP´ ITOL 31. TAULES DE FIGURES I LLISTAT DE CODI FONT ´ Index de figures 5.1 Diagrama UML del sistema ActiveRecord . . . . . . . . . . . . . . . 39 5.2 Diagrama UML del component Authentication . . . . . . . . . . . . 40 5.3 Diagrama UML del component Browser ................ 40 5.4 Diagrama UML del component Cache ................. 41 5.5 Diagrama UML del component Config ................ 42 5.6 Diagrama UML del component Context ................ 43 5.7 Diagrama UML del component Database . . . . . . . . . . . . . . . 44 5.8 Diagrama UML del component Environment . . . . . . . . . . . . . 44 5.9 Diagrama UML del component Error Handler ............ 45 5.10 Diagrama UML del component Filter . . . . . . . . . . . . . . . . . 45 5.11 Diagrama UML del component Flash . . . . . . . . . . . . . . . . . 46 5.12 Diagrama UML del sistema Front Controller . . . . . . . . . . . . . . 47 5.13 Diagrama UML del component HttpResponse . . . . . . . . . . . . . 48 5.14 Diagrama UML del component Locale . . . . . . . . . . . . . . . . . 49 5.15 Diagrama UML del component Log . . . . . . . . . . . . . . . . . . 49 5.16 Diagrama UML del component Mailer . . . . . . . . . . . . . . . . . 50 5.17 Diagrama UML del sistema MVC . . . . . . . . . . . . . . . . . . . 50 5.18 Diagrama UML del sistema de Plugins . . . . . . . . . . . . . . . . . 51 5.19 Diagrama UML del component Registry ................ 52 5.20 Diagrama UML del component Request ................ 52 5.21 Diagrama UML del sistema de serveis web REST . . . . . . . . . . . 53 5.22 Diagrama UML del sistema Router . . . . . . . . . . . . . . . . . . . 55 5.23 Diagrama UML del component Session . . . . . . . . . . . . . . . . 55 5.24 Diagrama UML del serveis web SOAP . . . . . . . . . . . . . . . . . 56 5.25 Diagrama UML del component Style .................. 57 5.26 Diagrama UML del sistema de Widgets . . . . . . . . . . . . . . . . 58 6.1 Patr´ odedissenyMVC ......................... 61 6.2 Patr´ odedissenyHMVC ........................ 62 6.3 Patr´ o de disseny Intercepting Filter ................... 65 9.1 Diagrama UML del component Database . . . . . . . . . . . . . . . 75 9.2 Bases de dades suportades per el marc de treball . . . . . . . . . . . . 76 9.3 Par` ametres de la configuraci´ o de connexions a bases de dades . . . . . 77 10.1 Diagrama UML del sistema ActiveRecord . . . . . . . . . . . . . . . 82 10.2 Active Record,Relaci´ ohas one ..................... 84 10.3 Active Record,Relaci´ obelongs to ................... 86 307 308 ´ INDEX DE FIGURES 10.4 Active Record,Relaci´ ohas many .................... 87 10.5 Active Record,Relaci´ ohas and belongs to many ........... 89 10.6 Active Record,Relaci´ ohas one through ................ 91 10.7 Active Record,Relaci´ ohas many through ............... 93 11.1 Directoris d’una aplicaci´ o web (dins el directori /app) ........ 114 11.2 Directoris d’un m` odul (dins el directori /app/modules) ........ 115 11.3 Layout b` asic............................... 121 11.4Layoutcomplex............................. 123 15.1 Acci´ oindex............................... 153 15.2 Acci´ oviewPost ............................. 153 15.3 Acci´ o viewPost (zona comentaris) . . . . . . . . . . . . . . . . . . . 154 15.4 Acci´ ologin ............................... 160 15.5 Acci´ ologout............................... 161 17.1 Components del sistema de Plugins . . . . . . . . . . . . . . . . . . 170 17.2 Captura de pantalla de demostraci´ o del plugin map .......... 193 20.1 UML del sistema REST . . . . . . . . . . . . . . . . . . . . . . . . . 208 20.2 Diagrama de classes del client de REST . . . . . . . . . . . . . . . . 208 20.3 Resultat d’executar el codi anterior . . . . . . . . . . . . . . . . . . . 211 20.4 Demostraci´ o de serveis web REST XML ’NewsPortal’ . . . . . . . . 218 21.1 Diagrama de classes del component Soap ............... 232 21.2 Captura de pantalla corresponent al resultat de l’acci´ odisplayCitiesByCountry amb el pa´ ısEspanya...................... 243 21.3 Captura de pantalla corresponent al resultat de l’acci´ odisplayCityWeather amb la ciutat de Val` encia i el pa´ ıs Espanya . . . . . . . . . . . . 243 21.4 Diagrama UML de seq¨ u` encia que ilustra el funcionament del servidor deSOAP(Part1/2) ........................... 244 21.5 Diagrama UML de seq¨ u` encia que ilustra el funcionament del servidor deSOAP(Part2/2) ........................... 245 21.6 Autenticaci´ o HTTP b` asica per a serveis web SOAP . . . . . . . . . . 248 21.7 Diagrama UML de les classes implicades en la demostraci´ o . . . . . . 248 23.1AspectedePoedit............................ 265 28.1 Prova de que tot ha estat correctament instal.lat . . . . . . . . . . . . 296 Listings 9.1 Configuraci´ o de les connexions de la base de dades en database.php . 76 9.2 Configuraci´ o de les connexions de la base de dades en cada entorn en el fitxer environment.php ........................ 77 9.3 API de Database: Operacions sobre connexions . . . . . . . . . . . . 78 9.4 API de Database: Operacions de consulta . . . . . . . . . . . . . . . 78 9.5 API de Database: Altres operacions . . . . . . . . . . . . . . . . . . 79 9.6 Exemple de funcionament del component Database .......... 80 10.1 Exemple de taula de base de dades a modelar amb Active Record . . . 83 10.2 Model d’Active Record . . . . . . . . . . . . . . . . . . . . . . . . . 83 10.3 Active Record, Relacions: SQL has one.............. 84 10.4 Active Record, Relacions: Model que implementa relaci´ ohas one85 10.5 Active Record, Relacions: SQL belongs to............. 86 10.6 Active Record, Relacions: Model que implementa relaci´ obelongs to86 10.7 Active Record, Relacions: SQL has many............. 87 10.8 Active Record, Relacions: Model que implementa relaci´ ohas many88 10.9 Active Record, Relacions: SQL has and belongs to many..... 89 10.10Active Record, Relacions: Model que implementa relaci´ ohas and belongs to many89 10.11Active Record, Relacions: SQL has one through.......... 91 10.12Active Record, Relacions: Model que implementa relaci´ ohas one through91 10.13Active Record, Relacions: SQL has many through......... 93 10.14Active Record, Relacions: Model que implementa relaci´ ohas many through93 10.15Active Record, Relacions: Model que implementa relaci´ ohas many by sql95 10.16Active Record, Relacions: Relacions reflexives mitjanc¸ant acts as tree96 10.17Active Record: Validaci´ o personalitzada . . . . . . . . . . . . . . . . 98 10.18Active Record: Callbacks . . . . . . . . . . . . . . . . . . . . . . . . 99 10.19API de FW ActiveRecord Model .................... 101 10.20API de FW ActiveRecord Tree ..................... 101 10.21API de FW ActiveRecord Result .................... 102 10.22API de FW ActiveRecord Relation .................. 103 10.23Definir condicions per cercar dades amb Active Record . . . . . . . . 104 10.24Definir condicions per l’ordenaci´ o de dades d’Active Record . . . . . 105 10.25API Active Record: Operacions de cerca . . . . . . . . . . . . . . . . 106 10.26API Active Record: Operacions amb funcions de columna . . . . . . 106 10.27API Active Record: Operacions de desat, actualitzaci´ o i inserci´ o, esborrament i exist` enciadedades..................... 107 10.28Exemples d’us de l’API de FW ActiveRecord Result ......... 107 11.1 Controlador b` asic............................ 116 11.2 Acci´ od’uncontrolador......................... 117 11.3 API del component FW mvc BaseController .............. 117 309 310 LISTINGS 11.4 Model b` asic............................... 118 11.5 API del component FW mvc BaseModel ................ 119 11.6Vistasimple............................... 120 11.7Vista................................... 120 11.8Vistaparcial............................... 120 11.9 Layout b` asic............................... 121 11.10Layoutcomplex............................. 123 12.1 Ruta b` asica ............................... 125 12.2 C` arrega d’scripts i estils a demanda . . . . . . . . . . . . . . . . . . . 127 12.3 Definici´ o de par` ametres en una ruta . . . . . . . . . . . . . . . . . . 129 12.4 Ordre de par` ametres en definici´ o d’una ruta . . . . . . . . . . . . . . 129 12.5 Definici´ o d’autenticaci´ oenunaruta .................. 130 12.6 Definici´ o d’una ruta com a cacheable . . . . . . . . . . . . . . . . . . 130 13.1 Configuraci´ o del component Authentication .............. 133 13.2 Ordres SQL per crear les taules de dades on es desar` a la informaci´ o de l’usuari ................................. 136 13.3 Component Authentication: Snippet per autenticar usuaris . . . . . . 137 14.1 Configuraci´ o del component FW Environment ............ 140 15.1 Model de dades per a la demostraci´ o.................. 141 15.2 Layout per a les demostracions . . . . . . . . . . . . . . . . . . . . . 146 15.3 Codi font per a l’acci´ o index (veure ´ ultimes 5 entrades) . . . . . . . . 147 15.4 Codi font per a l’acci´ o viewPost (veure entrada) . . . . . . . . . . . . 148 15.5 Vistes per l’acci´ oindex......................... 149 15.6 Vistes per l’acci´ oviewPost....................... 151 15.7 Rutes per a les accions index i viesPost . . . . . . . . . . . . . . . . . 154 15.8 Codi font per a l’acci´ o login (iniciar sessi´ o) .............. 156 15.9 Codi font per a l’acci´ o logout (tancar sessi´ o).............. 157 15.10Rutes per a les accions login (iniciar sessi´ o) i logout (tancar sessi´ o) . . 157 15.11Vista per l’acci´ o login (iniciar sessi´ o) ................. 158 15.12Vista per l’acci´ o logout (tancar sessi´ o)................. 159 16.1 Codi font per crear els controladors i models per a les demostracions . 165 16.2 Layout utilitzat per a les demostracions . . . . . . . . . . . . . . . . 166 16.3 CSS per a les demostracions . . . . . . . . . . . . . . . . . . . . . . 167 16.4 Definicions d’estils per el m` odulplugin ................ 168 17.1 API de Plugin Registry: Obtindre un plugin . . . . . . . . . . . . . . 170 17.2 API de Plugin Registry: Instal·lar un plugin . . . . . . . . . . . . . . 171 17.3 API de Plugin Registry: Desinstal·lar un plugin . . . . . . . . . . . . 171 17.4 API de Plugin Registry: Comprovar si existeix (i est` a carregat) un plugin171 17.5 API de Plugin Registry: Obtindre tots els plugins carregats en el sistema 172 17.6 API de Plugin: Opcions/configuraci´ o utilitzant la base de dades . . . . 172 17.7 API de Plugin: Creaci´ o de la taula blog options en la base de dades . 173 17.8 API de Plugin: Exemple de fitxer options.php ............. 173 17.9 API de Plugin: API per utilitzar el fitxer options.php ......... 173 17.10API de Plugin: Instal·laci´ o/desinstal·laci´ o d’un plugin . . . . . . . . . 174 17.11API de Plugin: Renderitzar vistes en un plugin . . . . . . . . . . . . . 174 17.12Esquelet d’un plugin . . . . . . . . . . . . . . . . . . . . . . . . . . 175 17.13Ruta b` asica per accedir una funcionalitat d’un plugin . . . . . . . . . 175 17.14Codi font del plugin per generar mapes de Google Maps . . . . . . . 176 17.15Codi font per utilitzar el servei web de geolocalitzaci´ ode Google Maps 178 17.16Codi de la classe latLng . . . . . . . . . . . . . . . . . . . . . . . . . 184 LISTINGS 311 17.17Codi de la classe marker . . . . . . . . . . . . . . . . . . . . . . . . 186 17.18Codi de la classe map . . . . . . . . . . . . . . . . . . . . . . . . . . 188 17.19Codi font de l’acci´ odemoMaps ..................... 193 17.20Codi font de la vista map ........................ 194 17.21Rutes per a la demostraci´ o ....................... 194 18.1 Helper de demostraci´ o que ajuda a crear formularis html . . . . . . . 195 19.1 Codi font per crear els controladors i models per a les demostracions . 201 19.2 Layout utilitzat per a les demostracions . . . . . . . . . . . . . . . . 202 19.3 CSS per a les demostracions . . . . . . . . . . . . . . . . . . . . . . 203 19.4 Definicions d’estils per el m` odul webservices . . . . . . . . . . . . . 205 20.1 Constructor del client de REST . . . . . . . . . . . . . . . . . . . . . 208 20.2 Consumir un servei web enviant dades amb POST . . . . . . . . . . . 209 20.3 Consumir un servei web que genera imatges . . . . . . . . . . . . . . 210 20.4 Creacio i inicializacio d’un client de serveis web REST . . . . . . . . 212 20.5 Obtindre les dades del canal RSS . . . . . . . . . . . . . . . . . . . . 212 20.6 Obtindre les entrades del canal RSS . . . . . . . . . . . . . . . . . . 213 20.7 Codi font per consumir un feed rss . . . . . . . . . . . . . . . . . . . 214 20.8 Rutes per accedir al servei web . . . . . . . . . . . . . . . . . . . . . 215 20.9VistanewsPortal ............................ 216 20.10Vistachannels.............................. 216 20.11Vistachannels.............................. 217 20.12Vistaitem................................ 217 20.13Operaci´ ogetTime.......................... 219 20.14Operaci´ ogreet............................ 219 20.15Operaci´ oechoBack......................... 219 20.16Rutes necess` aries per aquest servei web . . . . . . . . . . . . . . . . 220 20.17Codi font per crear la taula blog book ................. 221 20.18Codi font per crear el model book ................... 222 20.19Codi font per implementar l’acci´ ogetBooks al controlador i model . . 222 20.20Codi font per implementar l’acci´ ogetBook al controlador i model . . 223 20.21Codi font per implementar l’acci´ odeleteBook al controlador i model . 224 20.22Codi font per implementar l’acci´ ocreateBook al controlador i model . 224 20.23Codi font per implementar l’acci´ ocreateBooks al controlador i model 226 20.24Rutes per accedir al servei web . . . . . . . . . . . . . . . . . . . . . 228 21.1 Constructor del client de SOAP . . . . . . . . . . . . . . . . . . . . . 233 21.2 Constructor del client de SOAP sense cach´ e de documents WSDL . . 234 21.3 Obtindre les operacions disponibles en el servei web . . . . . . . . . 234 21.4 Obtindre els tipus de dades complexos disponibles en el servei web . . 235 21.5 Cridar a operacions del servei web . . . . . . . . . . . . . . . . . . . 236 21.6 Altres cridades d’utilitat en un client de SOAP . . . . . . . . . . . . . 236 21.7 Codi font de l’acci´ odisplayCitiesByCountry .............. 237 21.8 Codi font de l’acci´ odisplayCityWeather ................ 238 21.9 Codi font de la vista cities ....................... 239 21.10Codi font de la vista noCities ...................... 239 21.11Codi font de la vista weather ...................... 239 21.12Codi font de la vista weather ...................... 240 21.13Codi font de la vista noWeather ..................... 241 21.14Rutes per accedir a les accions de l’exemple . . . . . . . . . . . . . . 241 21.15Configuraci´ o de par` ametres en rutes . . . . . . . . . . . . . . . . . . 245 21.16Configuraci´ o de tipus de dades complexos en rutes . . . . . . . . . . 246 312 LISTINGS 21.17Configuraci´ od’unserveiweb...................... 246 21.18Rutes del servei web de demostraci´ o.................. 249 21.19Configuraci´ o servei web de demostraci´ o................ 251 21.20Codi font per crear la taula blog book ................. 251 21.21Codi font per crear el model book ................... 252 21.22Codi font per implementar l’acci´ ogetBooks al controlador i model . . 252 21.23Codi font per implementar l’acci´ ogetBook al controlador i model . . 253 21.24Codi font per implementar l’acci´ odeletBook al controlador i model . 254 21.25Codi font per implementar l’acci´ ocreateBook al controlador i model . 255 21.26Client de SOAP per a provar el servei web de demostraci´ o . . . . . . 256 21.27Possible eixida al executar el client . . . . . . . . . . . . . . . . . . . 256 23.1 Marcatge de cadenes com a tradu¨ ıbles ................. 263 23.2 Aspecte d’un fitxer PO . . . . . . . . . . . . . . . . . . . . . . . . . 264 23.3 Ordres per generar els fitxers .po . . . . . . . . . . . . . . . . . . . . 265 24.1 Configuraci´ o del component Cache ................... 269 24.2 Configuraci´ o d’una ruta com a cacheable . . . . . . . . . . . . . . . . 269 24.3 Obtenci´ o de l’inst` ancia del component Cache ............. 270 24.4 Obtenci´ o de de dades de Cache ..................... 270 24.5 Desament de dades en la Cach´ e..................... 270 24.6 Esborrament de dades en la Cach´ e ................... 271 24.7 Esborrament de dades d’un espai de noms en la Cach´ e ........ 271 24.8 Obtindre les dades d’un cache object .................. 271 24.9 Verificar si ha expirat el contingut d’un cache object ......... 272 24.10Exemplecomplet ............................ 272 25.1 Esquelet d’un fitxer de configuraci´ o .................. 275 25.2 Exemple de fitxer de configuraci´ o ................... 276 25.3 Acc´ es a una configuraci´ o personalitzada . . . . . . . . . . . . . . . . 277 25.4 Codi font m´ ınim per a crear una classe ajudant de configuraci´ o . . . . 278 25.5 Obtenci´ o de dades de la configuraci´ o dins una classe ajudant de configuraci´ o ................................. 279 25.6 Modificaci´ o de dades d’una configuraci´ o dins una classe ajudant de configuraci´ o............................... 279 25.7 Creaci´ o de dades d’una configuraci´ o dins una classe ajudant de configuraci´ o ................................. 279 25.8 Rec` arrega d’un fitxer de configuraci´ o dins una classe ajudant de configuraci´ o ................................. 280 25.9 Desament de les dades d’una configuraci´ o dins d’un ajudat de configuraci´ o................................... 280 25.10Exemplecomplet ............................ 281 26.1 Descripci´ o dels estils d’un m` odul.................... 284 26.2 Descripci´ od’untema.......................... 284 26.3 Configuraci´ o del component Style ................... 286 27.1 Exemple d’acci´ o de tipus CRON .................... 289 27.2 Ruta necess` aria per accedir a la funcionalitat CRON .......... 290 27.3 Execuci´ o de tasques CRON des de l´ ınia d’ordres . . . . . . . . . . . . 290 28.1 Instal.laci´ o de PHP en GNU-Linux . . . . . . . . . . . . . . . . . . . 295 28.2 Fitxer per verificar que PHP funciona . . . . . . . . . . . . . . . . . 295 28.3 Regles d’Apache mod rewrite . . . . . . . . . . . . . . . . . . . . . 297 29.1 Configuraci´ o b` asica del projecte . . . . . . . . . . . . . . . . . . . . 299 30.1 Taules de la base de dades utilitzada en aquest projecte . . . . . . . . 301