Está en la página 1de 550

Manual CakePHP

Ver. 1.3.x

Fuente:
http://book.cakephp.org
Compilador por:
Ing. Luis Diaz

Agosto de 2010

ndice de contenido
Manual CakePHP.......................................................................................................................................1
1 Comenzando con CakePHP..............................................................................................................18
1.1 Qu es CakePHP y por qu hay que utilizarlo?......................................................................18
1.2 Dnde obtener ayuda................................................................................................................19
1.3 Entendiendo Modelo-Vista-Controlador..................................................................................21
2 Principios bsicos de CakePHP........................................................................................................23
2.1 Estructura de CakePHP.............................................................................................................23
2.1.1 Extensiones de los Controladores ("Componentes")........................................................23
2.1.2 Extensiones de las Vistas..................................................................................................24
2.1.3 Extensiones de los Modelos..............................................................................................24
2.1.4 Extensiones de la Aplicacin............................................................................................25
2.2 Una peticin tpica de CakePHP...............................................................................................25
2.3 Estructura de archivos de CakePHP.........................................................................................28
2.4 Convenciones de CakePHP .....................................................................................................30
2.4.1 Convenciones de los nombres de archivos y clases..........................................................30
2.4.2 Convenciones de Modelo y de la Base de datos...............................................................30
2.4.3 Convenciones de Controladores.......................................................................................31
2.4.3.1 Consideraciones de URL para nombres de controladores.........................................32
2.4.4 Convenciones de Vistas....................................................................................................33
3 Desarrollando con CakePHP............................................................................................................34
3.1 Requerimientos.........................................................................................................................34
3.2 Preparndose para Instalar........................................................................................................34
3.2.1 Obteniendo CakePHP.......................................................................................................35
3.2.2 Permisos............................................................................................................................35
3.3 Instalacin.................................................................................................................................35
3.3.1 Desarrollo..........................................................................................................................36
3.3.2 Produccin........................................................................................................................36
3.3.3 Instalacin Avanzada.........................................................................................................37
3.3.3.1 Rutas de Clase Adicionales.......................................................................................38
3.3.4 Apache y mod_rewrite (y .htaccess).................................................................................39
3.3.5 Lighttpd y mod_magne.....................................................................................................41
3.3.6 Pretty URLs en nginx........................................................................................................42
3.3.7 URL Rewrites on IIS7 (Windows hosts)...........................................................................43
3.3.8 Encindelo.........................................................................................................................44
3.4 Configuracin...........................................................................................................................45
3.4.1 Configuracin de Base de Datos.......................................................................................45
3.4.2 Configuracin del Core.....................................................................................................46
3.4.3 La Clase de Configuracin................................................................................................46
3.4.3.1 Mtodos de la Clase Configure.................................................................................47
3.4.3.1.1 write...................................................................................................................47
3.4.3.1.2 read....................................................................................................................47
3.4.3.1.3 delete..................................................................................................................48
3.4.3.1.4 load....................................................................................................................48
3.4.3.1.5 version...............................................................................................................48
3.4.3.2 Variables de Configuracin Principales de CakePHP...............................................48
3.4.3.3 Constantes de Configuracin....................................................................................50

3.4.4 La Clase App.....................................................................................................................50


3.4.4.1 Usando App::import()...............................................................................................50
3.4.4.2 Importando libreras del Core...................................................................................50
3.4.4.3 Importando Controladores, Modelos, Ayudantes, Comportamientos y Componentes
...............................................................................................................................................51
3.4.4.3.2 Cargando Modelos [Model]...............................................................................51
3.4.4.3.3 Cargando Componentes [Components].............................................................51
3.4.4.3.4 Cargando Comportamientos [Behaviors]..........................................................51
3.4.4.3.5 Cargando Ayudantes[Helpers]...........................................................................51
3.4.4.4 Cargando desde Plugins............................................................................................51
3.4.4.5 Cargando Archivos de Terceros.................................................................................52
3.4.4.5.1 Ejemplos de archivos de terceros......................................................................52
3.4.5 Configuracin de Rutas.....................................................................................................52
Enrutamiento por Defecto.....................................................................................................52
Parmetros con Nombre.............................................................................................................53
Definir Rutas..............................................................................................................................53
Pasando parmetros a la accin.................................................................................................56
Rutas con prefijos......................................................................................................................57
3.4.5.1 Enrutamiento por defecto..........................................................................................58
3.4.5.2 Passed arguments......................................................................................................58
3.4.5.4 Defining Routes.........................................................................................................59
3.4.5.5 Pasando parmetros a las acciones............................................................................62
3.4.5.6 Prefix Routing...........................................................................................................62
3.4.5.7 Rutas y plugins..........................................................................................................63
3.4.5.8 Extensiones de archivo..............................................................................................64
3.4.5.9 Custom Route classes................................................................................................64
3.4.6 Inflexiones Propias............................................................................................................65
3.4.7 Haciendo Bootstrap de CakePHP.....................................................................................66
3.5 Controladores............................................................................................................................67
3.5.1 The App Controller...........................................................................................................68
3.5.2 The Pages Controller.........................................................................................................68
3.5.3 Atributos del Controlador.................................................................................................69
3.5.3.1 $name........................................................................................................................69
3.5.3.2 $components, $helpers y $uses.................................................................................69
3.5.3.3 Atributos Relacionados con la Pgina: "$layout" y "$pageTitle".............................70
3.5.3.4 El Atributo de Parmetros ("$params").....................................................................71
3.5.3.4.1 form...................................................................................................................71
3.5.3.4.2 admin.................................................................................................................71
3.5.3.4.4 isAjax.................................................................................................................71
3.5.3.4.5 controller............................................................................................................72
3.5.3.4.6 action.................................................................................................................72
3.5.3.4.7 pass....................................................................................................................72
3.5.3.4.8 url ......................................................................................................................72
3.5.3.4.9 data....................................................................................................................72
3.5.3.4.10 prefix................................................................................................................73
3.5.3.4.11 named...............................................................................................................73
3.5.3.5 Otros Atributos..........................................................................................................73
3.5.3.6 persistModel..............................................................................................................74
3.5.4 Mtodos del Controlador..................................................................................................75

3.5.4.1 Interactuando con Vistas...........................................................................................75


3.5.4.1.1 set.......................................................................................................................75
3.5.4.1.2 render.................................................................................................................75
3.5.4.2 Control de Flujo........................................................................................................76
3.5.4.2.1 redirect...............................................................................................................76
3.5.4.2.2 flash...................................................................................................................77
3.5.4.3 Retrollamadas ("Callbacks").....................................................................................77
3.5.4.4 Otros Mtodos tiles................................................................................................78
3.5.4.4.1 constructClasses................................................................................................78
3.5.4.4.2 referer................................................................................................................79
3.5.4.4.3 disableCache......................................................................................................79
3.5.4.4.4 postConditions...................................................................................................79
3.5.4.4.5 paginate..............................................................................................................80
3.5.4.4.6 requestAction.....................................................................................................80
3.5.4.4.7 loadModel..........................................................................................................82
3.6 Componentes............................................................................................................................83
3.6.1 Configuracin de componentes.........................................................................................83
3.6.2 Creando Componentes a medida......................................................................................84
3.6.2.1 Aadiendo Componentes a tus Controladores..........................................................84
3.6.2.2 Acceso a clases MVC dentro de componentes..........................................................85
3.6.2.3 Usando Componentes en tu Componente.................................................................86
3.7 Modelos....................................................................................................................................88
3.7.1 La Comprensin de Modelos............................................................................................88
3.7.2 Creando Tablas de Bases de Datos...................................................................................90
3.7.2.1 Asociaciones de Tipo de Dato por Base de Datos.....................................................91
3.7.2.1.1 MySQL..............................................................................................................91
3.7.2.1.2 MySQLi.............................................................................................................91
3.7.2.1.3 ADOdb...............................................................................................................92
3.7.2.1.4 DB2....................................................................................................................92
3.7.2.1.5 Firebird/Interbase..............................................................................................92
3.7.2.1.6 MS SQL.............................................................................................................93
3.7.2.1.7 Oracle................................................................................................................93
3.7.2.1.8 PostgreSQL........................................................................................................94
3.7.2.1.9 SQLite................................................................................................................94
3.7.2.1.10 Sybase..............................................................................................................94
3.7.2.2 Titulos........................................................................................................................95
3.7.2.3 Creado y modificado ("created" y "modified").........................................................95
3.7.2.4 Utilizando UUIDs como Claves Primarias...............................................................95
3.7.3 Recuperando tus Datos.....................................................................................................96
3.7.3.1 find............................................................................................................................96
3.7.3.1.1 find('first')..........................................................................................................97
3.7.3.1.2 find('count')........................................................................................................98
3.7.3.1.3 find('all').............................................................................................................98
3.7.3.1.4 find('list')............................................................................................................99
3.7.3.1.5 find('threaded').................................................................................................101
3.7.3.1.6 find('neighbors')...............................................................................................103
3.7.3.2 findAllBy.................................................................................................................104
3.7.3.3 findBy......................................................................................................................104
3.7.3.4 query........................................................................................................................105

3.7.3.5 field..........................................................................................................................106
3.7.3.6 read().......................................................................................................................106
3.7.3.7 Condiciones Complejas de Bsqueda.....................................................................107
3.7.4 Guardando Tus Datos......................................................................................................110
3.7.4.1 Guardando Datos de Modelos Relacionados (hasOne, hasMany, belongsTo)........114
3.7.4.1.1 counterCache - Cache your count().................................................................116
3.7.4.2 Guardando Datos de Modelos Relacionados (HABTM)........................................117
3.7.5 Borrando Datos...............................................................................................................118
3.7.5.1 del............................................................................................................................118
3.7.5.2 deleteAll..................................................................................................................118
3.7.6 Asociaciones: Enlazando Modelos..................................................................................118
3.7.6.1 Tipos de Relaciones.................................................................................................119
3.7.6.2 hasOne.....................................................................................................................120
3.7.6.3 belongsTo................................................................................................................122
3.7.6.4 hasMany..................................................................................................................124
3.7.6.5 hasAndBelongsToMany (HABTM)........................................................................126
3.7.6.6 Creando y Destruyendo Asociaciones al Vuelo......................................................132
3.7.6.7 Mltiples relaciones al mismo modelo....................................................................134
3.7.6.8 Joining tables...........................................................................................................135
3.7.7 Mtodos Callback...........................................................................................................137
3.7.7.1 beforeFind...............................................................................................................137
3.7.7.2 afterFind..................................................................................................................137
3.7.7.3 beforeValidate..........................................................................................................138
3.7.7.4 beforeSave...............................................................................................................139
3.7.7.5 afterSave..................................................................................................................139
3.7.7.6 beforeDelete............................................................................................................140
3.7.7.7 afterDelete...............................................................................................................140
3.7.7.8 onError....................................................................................................................140
3.7.8 Atributos del Modelo......................................................................................................140
3.7.8.1 useDbConfig............................................................................................................140
3.7.8.2 useTable...................................................................................................................141
3.7.8.3 tablePrefix...............................................................................................................141
3.7.8.4 primaryKey..............................................................................................................142
3.7.8.5 displayField.............................................................................................................142
3.7.8.6 recursive..................................................................................................................142
3.7.8.7 order........................................................................................................................143
3.7.8.8 data..........................................................................................................................143
3.7.8.9 _schema...................................................................................................................143
3.7.8.10 validate..................................................................................................................144
3.7.8.11 virtualFields...........................................................................................................144
3.7.8.12 name......................................................................................................................144
3.7.8.13 cacheQueries.........................................................................................................144
3.7.9 Mtodos Personalizados y Propiedades..........................................................................145
3.7.9.1 Using virtualFields..................................................................................................145
3.7.10 Virtual fields..................................................................................................................147
3.7.10.1 Creating virtual fields............................................................................................147
3.7.10.2 Using virtual fields................................................................................................148
3.7.10.3 Virtual fields and model aliases.............................................................................149
3.7.10.4 Limitations of virtualFields...................................................................................149

3.7.11 Transactions..................................................................................................................150
3.8 Comportamientos....................................................................................................................150
3.8.1 Utilizando Comportamientos..........................................................................................151
3.8.2 Creando Comportamientos Personalizados....................................................................153
3.8.3 Creating behavior methods.............................................................................................153
3.8.4 Behavior callbacks..........................................................................................................154
3.8.5 Creating a behavior callback...........................................................................................154
3.9 DataSources (fuentes de datos)...............................................................................................155
3.9.1 API bsica para DataSources..........................................................................................156
3.9.2 Un ejemplo......................................................................................................................157
3.10 Vistas.....................................................................................................................................160
3.10.1 Plantillas de la Vista......................................................................................................160
3.10.2 Layouts..........................................................................................................................160
3.10.3 Elementos......................................................................................................................163
3.10.3.1 Pasar Variables a un elemento...............................................................................163
3.10.3.2 Cache de Elements................................................................................................165
3.10.3.3 Utilizar Elements de un Plugin..............................................................................165
3.10.4 Mtodos de la vista.......................................................................................................165
3.10.4.1 set()........................................................................................................................166
3.10.4.2 getVar()..................................................................................................................166
3.10.4.3 getVars()................................................................................................................166
3.10.4.4 error()....................................................................................................................166
3.10.4.5 element()................................................................................................................166
3.10.4.6 uuid........................................................................................................................167
3.10.4.7 addScript().............................................................................................................167
3.10.5 Temas............................................................................................................................167
3.10.5.1 Increasing performance of plugin and theme assets..............................................168
3.10.6 Vistas de Medios...........................................................................................................169
3.11 Helpers..................................................................................................................................170
3.11.1 Usando Helpers.............................................................................................................170
3.11.2 Creando Helpers............................................................................................................170
3.11.2.1 Including other Helpers.........................................................................................171
3.11.2.2 Callback method....................................................................................................172
3.11.2.3 Usando tu Helper...................................................................................................172
3.11.3 Creando Funcionalidad para todos los Helpers.............................................................172
3.11.4 Helpers del Core............................................................................................................173
3.12 Scaffolding............................................................................................................................174
3.12.1 Creating a simple admin interface with scaffolding.....................................................175
3.12.2 Personalizando Vistas Scaffold ....................................................................................176
3.13 La consola de CakePHP........................................................................................................177
3.13.1 Creando Shells y Tasks.................................................................................................178
3.13.1.1 Creando tus Propios Shells....................................................................................178
3.13.1.2 Tasks (Tareas)........................................................................................................180
3.13.2 Running Shells as cronjobs...........................................................................................181
3.14 Plugins..................................................................................................................................182
3.14.1 Crear un Plugin.............................................................................................................183
3.14.2 Controladores del Plugin...............................................................................................183
3.14.3 Modelos del Plugin.......................................................................................................184
3.14.4 Vistas del Plugin............................................................................................................185

3.14.5 Componentes, Ayudantes y Comportamientos.............................................................185


3.14.6 CSS y Javascript en los Plugins....................................................................................186
3.14.7 Consejos para desarrollar Plugins.................................................................................186
3.15 Constantes y Funciones Globales.........................................................................................187
3.15.1 Funciones globales........................................................................................................187
3.15.1.1 __...........................................................................................................................187
3.15.1.2 a.............................................................................................................................188
3.15.1.3 aa...........................................................................................................................188
3.15.1.4 am..........................................................................................................................188
3.15.1.5 config.....................................................................................................................188
3.15.1.6 convertSlash..........................................................................................................189
3.15.1.7 debug.....................................................................................................................189
3.15.1.8 e.............................................................................................................................189
3.15.1.9 env.........................................................................................................................189
3.15.1.10 fileExistsInPath...................................................................................................189
3.15.1.11 h...........................................................................................................................190
3.15.1.12 ife.........................................................................................................................190
3.15.1.13 low.......................................................................................................................190
3.15.1.14 pr..........................................................................................................................190
3.15.1.15 r............................................................................................................................190
3.15.1.16 stripslashes_deep.................................................................................................190
3.15.1.17 up.........................................................................................................................190
3.15.1.18 uses......................................................................................................................191
3.15.2 Constantes predefinidas................................................................................................191
3.16 Paquetes de terceros (Vendor packages)...............................................................................192
3.16.1 Vendor assets.................................................................................................................192
4 Tareas comunes con CakePHP.......................................................................................................193
4.1 Validacin de Datos................................................................................................................193
4.1.1 Reglas Simples................................................................................................................195
4.1.2 Una regla por campo.......................................................................................................195
4.1.2.1 rule...........................................................................................................................196
4.1.2.2 required....................................................................................................................196
4.1.2.3 allowEmpty.............................................................................................................197
4.1.2.4 on.............................................................................................................................197
4.1.2.5 message...................................................................................................................197
4.1.3 Mltiples Reglas por Campo..........................................................................................198
4.1.4 Reglas de Validacin Incorporadas.................................................................................200
4.1.4.1 alphaNumeric..........................................................................................................200
4.1.4.2 between....................................................................................................................200
4.1.4.3 blank........................................................................................................................200
4.1.4.4 boolean....................................................................................................................201
4.1.4.5 cc.............................................................................................................................201
4.1.4.6 comparison..............................................................................................................202
4.1.4.7 date..........................................................................................................................203
4.1.4.8 decimal....................................................................................................................203
4.1.4.9 email........................................................................................................................204
4.1.4.10 equalTo..................................................................................................................204
4.1.4.11 extension................................................................................................................204
4.1.4.12 file..........................................................................................................................205

4.1.4.13 ip............................................................................................................................205
4.1.4.14 isUnique................................................................................................................205
4.1.4.15 minLength.............................................................................................................206
4.1.4.16 maxLength.............................................................................................................206
4.1.4.17 money....................................................................................................................206
4.1.4.18 multiple..................................................................................................................207
4.1.4.19 inList......................................................................................................................207
4.1.4.20 numeric..................................................................................................................207
4.1.4.21 notEmpty...............................................................................................................208
4.1.4.22 phone.....................................................................................................................208
4.1.4.23 postal.....................................................................................................................208
4.1.4.24 range......................................................................................................................209
4.1.4.25 ssn..........................................................................................................................209
4.1.4.26 url..........................................................................................................................209
4.1.5 Reglas de Validacin Personalizadas..............................................................................210
4.1.5.1 Validacin Personalizada Mediante Expresiones Relugares...................................210
4.1.5.2 Validacin Mediante Mtodos Personalizados........................................................210
4.1.6 Validando datos desde el Controlador.............................................................................211
4.2 Limpieza de Datos..................................................................................................................212
4.2.1 paranoid...........................................................................................................................212
4.2.2 html.................................................................................................................................212
4.2.3 escape..............................................................................................................................213
4.2.4 clean................................................................................................................................213
4.3 Manejo de Errores...................................................................................................................214
4.4 Depuracin..............................................................................................................................215
4.4.1 Depuracin bsica...........................................................................................................215
4.4.2 Usando la clase Debugger...............................................................................................216
4.4.3 Clase Debugger...............................................................................................................218
4.5 Caching...................................................................................................................................219
4.6 Logging...................................................................................................................................219
4.6.1 Uso de la funcin log......................................................................................................219
4.6.2 Using the default FileLog class.......................................................................................220
4.6.3 Creating and configuring log streams.............................................................................221
4.6.4 Interacting with log streams............................................................................................222
4.6.5 Error logging...................................................................................................................222
4.7 Testing.....................................................................................................................................222
4.7.1 Preparndose para el testing............................................................................................222
4.7.1.1 Installing SimpleTest...............................................................................................223
4.7.1.2 Ejecutando los test-cases incorporados...................................................................223
4.7.2 Introduccin a los test - Unit testing vs. Web testing......................................................224
4.7.3 Preparando datos de prueba............................................................................................224
4.7.3.1 Acerca de las fixtures..............................................................................................224
4.7.3.2 Creando fixtures......................................................................................................224
4.7.3.3 Importar informacin de tabla y registros...............................................................226
4.7.4 Creando los tests.............................................................................................................228
4.7.4.1 CakeTestCase Callback Methods............................................................................229
4.7.5 Testing models................................................................................................................229
4.7.5.1 Creating a test case..................................................................................................229
4.7.5.2 Creating a test method.............................................................................................231

4.7.6 Testing controllers...........................................................................................................231


4.7.6.1 Creando un test case................................................................................................231
4.7.6.2 El mtodo testAction...............................................................................................233
4.7.6.3 Pitfalls......................................................................................................................234
4.7.7 Testing Helpers...............................................................................................................234
4.7.7.1 Creating Helper test, part I......................................................................................234
4.7.8 Probando componentes...................................................................................................235
4.7.8.1 Initializing the component.......................................................................................236
4.7.8.2 Creando un mtodo de prueba.................................................................................236
4.7.9 Web testing - Testeando las vistas...................................................................................237
4.7.9.1 About CakeWebTestCase........................................................................................237
4.7.9.2 Creando un test........................................................................................................237
4.7.9.3 Walking through a page...........................................................................................238
4.7.10 Testing plugins..............................................................................................................239
4.7.11 Miscellaneous................................................................................................................240
4.7.11.1 Customizing the test reporter................................................................................240
4.7.11.2 Test Reporter methods...........................................................................................240
4.7.11.3 Grouping tests........................................................................................................241
4.7.12 Running tests in the Command Line.............................................................................242
4.7.13 Test Suite changes in 1.3...............................................................................................243
4.8 Internacionalizacin & Localizacin......................................................................................245
4.8.1 Internacionalizando su aplicacin...................................................................................245
4.8.2 Localizacin en CakePHP...............................................................................................246
4.9 Paginacin...............................................................................................................................248
4.9.1 Preparacin del controlador............................................................................................248
4.9.2 Pagination in Views........................................................................................................250
4.9.3 Paginacin AJAX............................................................................................................251
# Configuring the PaginatorHelper to use a custom helper................................................252
4.9.4 Custom Query Pagination...............................................................................................252
4.10 REST....................................................................................................................................253
4.10.1 The Simple Setup..........................................................................................................254
4.10.2 Custom REST Routing..................................................................................................256
5 Componentes del Ncleo................................................................................................................257
5.1 Listas de Control de Acceso...................................................................................................257
5.1.1 Entendiendo cmo funciona ACL...................................................................................258
5.1.2 Definiendo Permisos: ACL basado en INI......................................................................263
5.1.3 Definiendo Permisos: ACL en la base de datos..............................................................265
5.1.3.1 Comenzando............................................................................................................265
5.1.3.2 Creando Access Request Objects (AROs) y Access Control Objects (ACOs).......266
5.1.3.3 Asignando Permisos................................................................................................272
5.1.3.4 Verificando Permisos: El Componente ACL...........................................................274
5.2 Autenticacin..........................................................................................................................275
5.2.1 Configurando las variables del componente Auth..........................................................277
5.2.2 Mostrando Mensajes de Error en la Autenticacin.........................................................278
5.2.3 Problemas comunes con Auth.........................................................................................278
5.2.4 Cambiar la Funcin Hash................................................................................................279
5.2.5 Mtodos de AuthComponent..........................................................................................280
5.2.5.1 action.......................................................................................................................280
5.2.5.2 allow........................................................................................................................280

5.2.5.3 deny.........................................................................................................................281
5.2.5.4 hashPasswords.........................................................................................................281
5.2.5.5 mapActions..............................................................................................................282
5.2.5.6 login.........................................................................................................................282
5.2.5.7 logout.......................................................................................................................283
5.2.5.8 password..................................................................................................................283
5.2.5.9 user..........................................................................................................................284
5.2.6 Atributos de AuthComponent.........................................................................................285
5.2.6.1 userModel................................................................................................................285
5.2.6.2 fields........................................................................................................................285
5.2.6.3 userScope................................................................................................................285
5.2.6.4 loginAction..............................................................................................................285
5.2.6.5 loginRedirect...........................................................................................................286
5.2.6.6 logoutRedirect.........................................................................................................286
5.2.6.7 loginError................................................................................................................286
5.2.6.8 authError..................................................................................................................286
5.2.6.9 autoRedirect............................................................................................................287
5.2.6.10 authorize................................................................................................................288
5.2.6.11 sessionKey.............................................................................................................290
5.2.6.12 ajaxLogin...............................................................................................................290
5.2.6.13 authenticate............................................................................................................290
5.2.6.14 actionPath..............................................................................................................290
5.2.6.15 flashElement..........................................................................................................290
5.3 Cookies...................................................................................................................................291
5.3.1 Configuracin del Controlador.......................................................................................291
5.3.2 Utilizando el Componente..............................................................................................292
5.4 Email.......................................................................................................................................294
5.4.1 Atributos y Variables de la clase.....................................................................................294
5.4.1.1 Envo mltiple de emails en bucle..........................................................................295
5.4.1.2 Debugging Emails...................................................................................................295
5.4.2 Envo de un mensaje simple...........................................................................................295
5.4.2.1 Configurando el Layout..........................................................................................295
5.4.2.2 Configurar un elemento Email para el cuerpo del mensaje....................................296
5.4.2.3 Controlador..............................................................................................................297
5.4.2.4 Attachments.............................................................................................................298
5.4.3 Enviar un mail por SMTP...............................................................................................298
5.5 Request Handling....................................................................................................................299
5.5.1 Obtaining Request Information.......................................................................................299
5.5.2 Request Type Detection..................................................................................................301
5.5.3 Obtaining Additional Client Information........................................................................302
5.5.4 Responding To Requests.................................................................................................302
5.6 El Componente Security.........................................................................................................304
5.6.1 Configuracin.................................................................................................................304
5.6.2 Mtodos...........................................................................................................................306
5.6.2.1 requirePost()............................................................................................................306
5.6.2.2 requireSecure()........................................................................................................306
5.6.2.3 requireAuth()...........................................................................................................306
5.6.2.4 requireLogin().........................................................................................................306
5.6.2.5 loginCredentials(string $type).................................................................................306

5.6.2.6 loginRequest(array $options)..................................................................................306


5.6.2.7 parseDigestAuthData(string $digest)......................................................................307
5.6.2.8 generateDigestResponseHash(array $data).............................................................307
5.6.2.9 blackHole(object $controller, string $error)............................................................307
5.6.3 Uso..................................................................................................................................307
5.6.4 Basic HTTP Authentication............................................................................................308
5.7 Sesiones..................................................................................................................................309
5.7.1 Mtodos...........................................................................................................................310
5.7.1.1 write.........................................................................................................................310
5.7.1.2 setFlash....................................................................................................................310
5.7.1.3 read..........................................................................................................................311
5.7.1.4 check........................................................................................................................311
5.7.1.5 delete.......................................................................................................................311
5.7.1.6 destroy.....................................................................................................................312
5.7.1.7 error.........................................................................................................................312
6 Core Behaviors (Comportamientos Basicos).................................................................................313
6.1 ACL........................................................................................................................................313
6.1.1 Using the AclBehavior....................................................................................................313
6.1.2 node()..............................................................................................................................315
6.2 Containable.............................................................................................................................315
# Using Containable.................................................................................................................316
# Containing deeper associations.............................................................................................318
6.2.1 Using Containable with pagination.................................................................................320
# ContainableBehavior options................................................................................................321
6.3 Translate..................................................................................................................................322
6.3.1 Inicializando las tablas de la Base de datos i18n............................................................322
6.3.2 Adjuntando el Comportamiento de Traduccin a tus Modelos.......................................322
6.3.3 Definiendo los Campos...................................................................................................323
6.3.4 Conclusiones...................................................................................................................323
6.3.5 Obtener todos los registros de traduccin para un campo determinado.........................324
6.3.5.1 Using the bindTranslation method..........................................................................325
6.3.6 Saving in another language.............................................................................................326
6.3.7 Multiple Translation Tables............................................................................................327
6.3.7.1 Create the TranslateModel......................................................................................328
6.3.7.2 Changing the Table..................................................................................................328
6.4 Arboles (Tree).........................................................................................................................329
6.4.1 Requerimientos...............................................................................................................329
6.4.2 Uso Bsico......................................................................................................................329
6.4.2.1 Agregando datos......................................................................................................331
6.4.2.2 Modificando datos...................................................................................................332
6.4.2.3 Borrando datos........................................................................................................333
6.4.2.4 Haciendo consultas y usando tus datos...................................................................334
6.4.2.4.1 El mtodo children..........................................................................................334
6.4.2.4.2 Contando los hijos...........................................................................................335
6.4.2.4.3 generatetreelist.................................................................................................335
6.4.2.4.4 getparentnode..................................................................................................336
6.4.2.4.5 getpath.............................................................................................................336
6.4.3 Uso Avanzado.................................................................................................................337
6.4.3.1 moveDown..............................................................................................................337

6.4.3.2 moveUp...................................................................................................................338
6.4.3.3 removeFromTree.....................................................................................................339
6.4.3.4 reorder.....................................................................................................................340
6.4.4 Data Integrity..................................................................................................................340
6.4.4.1 Recover....................................................................................................................340
6.4.4.2 Reorder....................................................................................................................341
6.4.4.3 Verify.......................................................................................................................342
7 Ayudantes del Core.........................................................................................................................343
7.1 AJAX......................................................................................................................................343
7.1.1 AjaxHelper Options........................................................................................................344
7.1.1.1 General Options.......................................................................................................344
7.1.1.2 Opciones de retrollamadas (Callback Options).......................................................344
7.1.2 Mtodos...........................................................................................................................345
7.1.2.1 link...........................................................................................................................345
7.1.2.2 remoteFunction........................................................................................................347
7.1.2.3 remoteTimer............................................................................................................348
7.1.2.4 form.........................................................................................................................348
7.1.2.5 submit......................................................................................................................349
7.1.2.6 observeField............................................................................................................350
7.1.2.7 observeForm............................................................................................................350
7.1.2.8 autoComplete..........................................................................................................351
7.1.2.9 isAjax......................................................................................................................352
7.1.2.10 drag & drop...........................................................................................................352
7.1.2.11 slider......................................................................................................................353
7.1.2.12 editor......................................................................................................................354
7.1.2.13 sortable..................................................................................................................355
7.2 Cache......................................................................................................................................356
7.2.1 Generalidades en Caching...............................................................................................356
7.2.2 Motores de Cache en Cake.............................................................................................356
7.2.3 Configuracion del Cache Helper.....................................................................................357
7.2.4 Caching en los Controllers..............................................................................................357
7.2.5 Marking Non-Cached Content in Views.........................................................................358
7.2.6 Clearing the Cache..........................................................................................................359
7.3 Formularios.............................................................................................................................359
7.3.1 Creando Formularios......................................................................................................359
7.3.1.1 $options[type].......................................................................................................361
7.3.1.2 $options[action]....................................................................................................361
7.3.1.3 $options[url].........................................................................................................362
7.3.1.4 $options[default]...................................................................................................362
7.3.1.5 7.3.1.5 $options['inputDefaults'].............................................................................362
7.3.2 Closing the Form.............................................................................................................363
7.3.3 Automagic Form Elementos...........................................................................................363
7.3.3.1 Field naming convention.........................................................................................365
7.3.3.2 $options[type].......................................................................................................366
7.3.3.3 $options[before], $options[between], $options[separator] and $options[after]
.............................................................................................................................................366
7.3.3.4 $options[options]..................................................................................................367
7.3.3.5 $options[multiple]................................................................................................369
7.3.3.6 $options[maxLength]............................................................................................369

7.3.3.7 $options[div].........................................................................................................369
7.3.3.8 $options[label]......................................................................................................370
7.3.3.9 $options['legend']....................................................................................................371
7.3.3.10 $options[id].........................................................................................................371
7.3.3.11 $options['error'].....................................................................................................371
7.3.3.12 $options['default']..................................................................................................372
7.3.3.13 $options[selected]...............................................................................................372
7.3.3.14 $options[rows], $options[cols]........................................................................372
7.3.3.15 $options[empty]..................................................................................................373
7.3.3.16 $options[timeFormat].........................................................................................373
7.3.3.17 $options[dateFormat]..........................................................................................374
7.3.3.18 $options['minYear'], $options['maxYear'].............................................................374
7.3.3.19 $options['interval'].................................................................................................374
7.3.3.20 $options['class'].....................................................................................................374
7.3.4 File Fields........................................................................................................................374
7.3.4.1 Validating Uploads..................................................................................................375
7.3.5 Form Element-Specific Methods....................................................................................376
7.3.5.1 checkbox..................................................................................................................376
7.3.5.2 button.......................................................................................................................376
7.3.5.3 year..........................................................................................................................377
7.3.5.4 month.......................................................................................................................378
7.3.5.5 dateTime..................................................................................................................379
7.3.5.6 day...........................................................................................................................379
7.3.5.7 hour..........................................................................................................................380
7.3.5.8 minute......................................................................................................................380
7.3.5.9 meridian...................................................................................................................380
7.3.5.10 error.......................................................................................................................380
7.3.5.11 file..........................................................................................................................380
7.3.5.12 hidden....................................................................................................................381
7.3.5.13 isFieldError............................................................................................................381
7.3.5.14 label.......................................................................................................................381
7.3.5.15 password................................................................................................................382
7.3.5.16 radio.......................................................................................................................382
7.3.5.17 select......................................................................................................................383
7.3.5.18 submit....................................................................................................................383
7.3.5.19 text.........................................................................................................................384
7.3.5.20 textarea..................................................................................................................384
7.3.6 1.3 improvements............................................................................................................385
7.4 HTML.....................................................................................................................................387
7.4.1 Inserting Well-Formatted elements.................................................................................388
7.4.1.1 charset......................................................................................................................388
7.4.1.2 css............................................................................................................................388
7.4.1.3 meta.........................................................................................................................389
7.4.1.4 docType...................................................................................................................391
7.4.1.5 style.........................................................................................................................391
7.4.1.6 image.......................................................................................................................392
7.4.1.7 link...........................................................................................................................392
7.4.1.8 tag............................................................................................................................394
7.4.1.9 div............................................................................................................................394

7.4.1.10 para........................................................................................................................394
7.4.1.11 script......................................................................................................................395
7.4.1.12 scriptBlock............................................................................................................395
7.4.1.13 scriptStart..............................................................................................................396
7.4.1.14 scriptEnd................................................................................................................396
7.4.1.15 tableHeaders..........................................................................................................396
7.4.1.16 tableCells...............................................................................................................397
7.4.1.17 url..........................................................................................................................398
7.4.2 Changing the tags output by HtmlHelper.......................................................................399
7.5 Js.............................................................................................................................................400
7.5.1 Using a specific Javascript engine..................................................................................400
# Using jQuery with other libraries.....................................................................................401
7.5.2 Creating a Javascript Engine...........................................................................................401
7.5.3 Javascript engine usage...................................................................................................401
# Common options..............................................................................................................402
# Callback wrapping............................................................................................................402
7.5.3.1 Working with buffered scripts.................................................................................402
7.5.4 Methods...........................................................................................................................404
7.5.5 Ajax Pagination...............................................................................................................413
# Making Ajax Links...........................................................................................................413
# Adding effects and transitions..........................................................................................414
7.6 Javascript................................................................................................................................415
7.6.1 Methods...........................................................................................................................415
7.7 Number...................................................................................................................................418
7.7.1 currency...........................................................................................................................418
7.7.2 precision..........................................................................................................................419
7.7.3 toPercentage....................................................................................................................420
7.7.4 toReadableSize................................................................................................................420
7.7.5 format..............................................................................................................................420
7.8 Paginator.................................................................................................................................421
7.8.1 Mtodos...........................................................................................................................421
7.9 RSS.........................................................................................................................................423
7.9.1 Creando un RSS feed con el RssHelper..........................................................................423
7.9.1.1 Cdigo para el Controlador.....................................................................................424
7.9.1.1.1 Layout RSS......................................................................................................424
7.9.1.1.2 La vista............................................................................................................425
7.10 Sesin....................................................................................................................................427
7.10.1 Methods.........................................................................................................................428
7.10.2 flash...............................................................................................................................428
# Using Flash for Success and Failure................................................................................428
7.11 Text.......................................................................................................................................429
# autoLinkEmails.....................................................................................................................429
# autoLinkUrls.........................................................................................................................430
# autoLink................................................................................................................................430
# excerpt...................................................................................................................................430
# highlight................................................................................................................................430
# stripLinks..............................................................................................................................431
# toList.....................................................................................................................................431
# truncate..................................................................................................................................431

# trim........................................................................................................................................432
7.12 Tiempo..................................................................................................................................432
7.12.1 Formatting.....................................................................................................................432
7.12.2 Testing Time..................................................................................................................434
7.13 XML.....................................................................................................................................434
7.13.1 serialize.........................................................................................................................434
7.13.2 elem...............................................................................................................................435
7.13.3 header............................................................................................................................435
8 Librerias de utilidades del ncleo...................................................................................................436
8.1 App..........................................................................................................................................436
8.2 Inflector...................................................................................................................................436
8.2.1 Class methods.................................................................................................................436
8.3 Cadenas (String).....................................................................................................................437
8.3.1 uuid.................................................................................................................................437
8.3.2 tokenize...........................................................................................................................437
8.3.3 insert................................................................................................................................437
8.3.4 cleanInsert.......................................................................................................................438
8.4 Xml.........................................................................................................................................438
8.4.1 Anlisis Xml....................................................................................................................438
8.5 Set...........................................................................................................................................439
8.5.1 Set-compatible Path syntax.............................................................................................439
8.5.2 insert................................................................................................................................440
8.5.3 sort...................................................................................................................................442
8.5.4 reverse.............................................................................................................................444
8.5.5 combine...........................................................................................................................447
8.5.6 normalize.........................................................................................................................454
8.5.7 countDim.........................................................................................................................457
8.5.8 diff...................................................................................................................................458
8.5.9 check...............................................................................................................................460
8.5.10 remove...........................................................................................................................461
8.5.11 classicExtract................................................................................................................462
8.5.12 matches.........................................................................................................................467
8.5.13 extract............................................................................................................................468
8.5.14 format............................................................................................................................469
8.5.15 enum..............................................................................................................................471
8.5.16 numeric.........................................................................................................................471
8.5.17 map................................................................................................................................473
8.5.18 pushDiff........................................................................................................................475
8.5.19 filter...............................................................................................................................476
8.5.20 merge.............................................................................................................................476
8.5.21 contains.........................................................................................................................478
8.6 Security...................................................................................................................................478
8.7 Cache......................................................................................................................................478
8.7.1 Cache::read()...................................................................................................................478
8.7.2 Cache::write().................................................................................................................479
8.7.3 Cache::delete()................................................................................................................479
8.7.4 Cache::config()...............................................................................................................480
8.7.5 Cache::set().....................................................................................................................480
8.8 HttpSocket..............................................................................................................................481

8.8.1 get....................................................................................................................................481
8.8.2 post..................................................................................................................................481
8.8.3 request.............................................................................................................................481
9 Aplicaciones de Consola Principales..............................................................................................483
9.1 Generacin de Cdigo con Bake............................................................................................483
9.1.1 Bake improvements in 1.3..............................................................................................484
9.2 Gestin del Esquema de la BBDD y Migraciones..................................................................487
9.2.1 Generando y Usando Archivos de Esquemas.................................................................487
9.2.2 Migrations with CakePHP schema shell.........................................................................488
9.3 Modificando el HTML producido por defecto del script bake...............................................489
10 Deployment..................................................................................................................................489
11 Ejemplo de Aplicacin.................................................................................................................490
11.1 Blog.......................................................................................................................................490
11.1.1 Obteniendo Cake...........................................................................................................491
11.1.2 Creando la Base de Datos del Blog...............................................................................491
11.1.3 Configuracin de la Base de Datos en Cake.................................................................492
11.1.4 Configuracin Opcional................................................................................................493
11.1.5 Una aclaracin para mod_rewrite.................................................................................494
11.1.6 Crear un modelo Post....................................................................................................495
11.1.7 Crear un controlador para Post......................................................................................496
11.1.8 Creando las Vistas(Views) de los Post .........................................................................497
11.1.9 Agregando Posts............................................................................................................501
11.1.10 Validacin de Datos.....................................................................................................502
11.1.11 Borrando Posts............................................................................................................504
11.1.12 Editando Posts.............................................................................................................505
11.1.13 Rutas............................................................................................................................507
11.1.14 Conclusin..................................................................................................................508
11.2 Simple Acl controlled Application........................................................................................509
11.2.1 Preparando nuestra aplicacin.......................................................................................509
11.2.2 Preparndose para agregar Autentificacin (Auth).......................................................511
11.2.3 Inicializar las tablas Acl en la BD.................................................................................512
11.2.4 Act as a Requester (Solicitante)....................................................................................513
11.2.4.1 11.2.4.1 Group-only ACL......................................................................................515
11.2.5 Creando ACOs..............................................................................................................516
11.2.6 Una herramienta automtica para crear ACOs..............................................................517
11.2.7 Configurando los permisos...........................................................................................521
11.2.8 Logueo de Usuarios......................................................................................................523
11.2.9 Logout (deslogueo).......................................................................................................523
11.2.10 Todo hecho..................................................................................................................524
12 Apendices.....................................................................................................................................525
12.1 Migrando desde CakePHP 1.2 a 1.3.....................................................................................525
# Removed Constants..............................................................................................................525
# Configuration and application bootstrapping........................................................................525
# File renames and internal changes........................................................................................527
12.1.1 Controller & Components.............................................................................................528
# Library Classes......................................................................................................................529
12.1.2 Model Databases and Datasources................................................................................533
# View and Helpers..................................................................................................................535
# Console and shells.................................................................................................................538

12.1.3 Vendors, Test Suite & schema.......................................................................................539


12.2 Nuevas caractersticas en CakePHP 1.3...............................................................................540
# Componentes.........................................................................................................................540
# View & Helpers.....................................................................................................................541
12.2.1 Logging.........................................................................................................................542
# Caching.................................................................................................................................542
# Models, Behaviors and Datasource.......................................................................................543
# Console.................................................................................................................................545
# Router and Dispatcher...........................................................................................................546
# Library classes......................................................................................................................546
# Miscellaneous.......................................................................................................................548

1 Comenzando con CakePHP


Bienvenido al Cookbook, el manual para el framework CakePHP que convierte el desarrollo de
aplicaciones web en un juego de nios!
Este manual supone que posees conocimientos generales de PHP y conocimientos bsicos de
programacin orientada a objetos (POO). Las diferentes funciones del framework utilizan varias
tecnologas -por ejemplo, SQL, JavaScript o XML. El manual no pretende explicar dichas
tecnologas, sino cmo se utilizan en este contexto.

1.1 Qu es CakePHP y por qu hay que utilizarlo?

CakePHP es un marco de desarrollo [framework] rpido para PHP, libre, de cdigo abierto. Se
trata de una estructura que sirve de base a los programadores para que stos puedan crear aplicaciones
Web. Nuestro principal objetivo es que puedas trabajar de forma estructurada y rpida, sin prdida de
flexibilidad.
Con CakePHP el desarrollo web ya no es montono porque ofrecemos las herramientas para
que empieces a escribir el cdigo que realmente necesitas: la lgica especfica de tu aplicacin.
Consigue una copia de CakePHP, empieza con lo verdaderamente importante y no reinventes la rueda
cada vez que te incorpores a un nuevo proyecto.
CakePHP tiene un equipo de desarrolladores y una comunidad activos, lo que aade valor al
proyecto. Con CakePHP, adems de no tener que reinventar la rueda, el ncleo de tu aplicacin se
mejora constantemente y est bien probado.
Esta es una lista breve con las caractersticas de las que disfrutars al utilizar CakePHP:
Comunidad activa y amistosa
Licencia flexible
Compatible con PHP4 y PHP5
CRUD integrado para la interaccin con la base de datos
Soporte de aplicacin [scaffolding]
Generacin de cdigo

Arquitectura Modelo Vista Controlador (MVC)


Despachador de peticiones [dispatcher], con URLs y rutas personalizadas y limpias
Validacin integrada
Plantillas rpidas y flexibles (sintaxis de PHP, con ayudantes[helpers])
Ayudantes para AJAX, Javascript, formularios HTML y ms
Componentes de Email, Cookie, Seguridad, Sesin y Manejo de solicitudes
Listas de control de acceso flexibles
Limpieza de datos
Cach flexible
Localizacin
Funciona en cualquier subdirectorio del sitio web, con poca o ninguna configuracin de Apache

1.2 Dnde obtener ayuda


# El sitio oficial CakePHP - http://www.cakephp.org
El sitio web oficial de CakePHP es siempre un gran lugar para visitar. Cuenta con enlaces a
herramientas de desarrollo frecuentemente utilizadas, videos, oportunidades de donar, y descargas.
# El Cookbook - http://book.cakephp.org
Este manual (y la API) es probablemente el primer lugar al que tienes que dirigirte para obtener
ayuda. Como ocurre con muchos otros proyectos de cdigo abierto, tenemos gente nueva con
regularidad, por lo que, para reducir nuestra carga de trabajo, intenta primero buscar respuestas por t
mismo.
Las respuestas pueden demorarse, pero una vez obtenidas las recordars durante mucho tiempo.
Tanto el manual como la API tienen una versin en lnea.
# El Bakery - http://bakery.cakephp.org
La Panadera de CakePHP (CakePHP Bakery) es un almacn de cosas relacionadas con
CakePHP. Consltalo si ests buscando tutoriales, casos de estudio o ejemplos de cdigo. Cuando ests
familiarizado con CakePHP, accede a l y comparte tus conocimientos con la comunidad.

# El API - http://api.cakephp.org/
Directo al grano y directamente de los desarrolladores de CakePHP, la API (Interfaz de
Programacin de Aplicaciones) CakePHP es la documentacin ms completa y directa que explica los
detalles internos del funcionamiento del framework. Se trata de una gua de referencia de cdigo
concisa.
# CakeForge - http://www.cakeforge.org
CakeForge es otro recurso para desarrolladores que puedes utilizar para hospedar tus proyectos
CakePHP para compartir con los dems. Si ests buscando (o quieres compartir) un componente
interesante o un plugin recomendable, echa un vistazo a CakeForge.
# Los Casos de Prueba - http://api.cakephp.org/tests
Si crees que la informacin que proporciona la API no es suficiente, consulta el cdigo de los
casos de prueba que proporciona CakePHP 1.2. Estos te pueden servir de ejemplos prcticos para el uso
de funciones y datos miembros de una clase. Para obtener casos de prueba necesitas bajar un paquete
nightly o hacer un checkout de un branch de svn. Los casos de prueba se encuentran en:
cake/tests/cases
# El canal IRC
#cakephp -- Discusin General

#cakephp-docs -- Documentacin

#cakephp-bakery -- Bakery
Si te quedas estancado en algn punto, consltanos en el canal IRC de CakePHP. Generalmente,

algn miembro del equipo de desarrollo suele estar conectado, sobre todo durante las horas de luz solar
de Amrica del Norte y Amrica del Sur.
Nos gustara mucho saber de t: si necesitas ayuda, si deseas encontrar usuarios en tu rea o si
quieres donar tu flamante coche deportivo.
#cakephp-es -- Canal de la comunidad hispano-parlante
# El Google Group
Adems, CakePHP tiene un grupo Google muy activo; un recurso excelente en que se
encuentran respuestas archivadas, preguntas frecuentes, y donde tambin puedes obtener respuestas
inmediatas a tus problemas.

http://groups.google.com/group/cake-php/
Si ests buscando un grupo Google en espaol, suscrbete al grupo de la comunidad
hispanohablante.
http://groups.google.com/group/cakephp-esp/

1.3 Entendiendo Modelo-Vista-Controlador


Las aplicaciones CakePHP bien escritas siguen el patrn de diseo de software MVC (ModeloVista-Controlador). Programar utilizando MVC consiste en separar la aplicacin en tres partes
principales. El modelo representa los datos de la aplicacin, la vista hace una presentacin del modelo
de datos, y el controlador maneja y enruta las peticiones [requests] hechas por los usuarios.

Figura 1: Una peticin MVC bsica


La figura 1 muestra un ejemplo sencillo de una peticin [request] MVC en CakePHP. A efectos
ilustrativos, supongamos que un usuario llamado Ricardo acaba de hacer clic en el enlace "Comprar
un pastel personalizado ahora!" de la pgina de inicial de la aplicacin.
1. Ricardo hace clic en el enlace apuntando a http://www.ejemplo.com/pasteles/comprar, y su
navegador hace una peticin al servidor web.
2. El despachador comprueba la URL de la peticin (/pasteles/comprar), y le pasa la peticin al
controlador adecuado.
3. El controlador realiza lgica de aplicacin especfica. Por ejemplo, puede comprobar si Ricardo
ha iniciado sesin.

4. El controlador tambin utiliza modelos para acceder a los datos de la aplicacin. La mayora de
las veces los modelos representan tablas de una base de datos, aunque tambin pueden
representar entradas LDAP, canales RSS, o ficheros en el sistema. En este ejemplo, el
controlador utiliza un modelo para buscar la ltima compra de Ricardo en la base de datos.
5. Una vez que el controlador ha hecho su magia en los datos, se los pasa a la vista. La vista toma
los datos y los deja listos para su presentacin al usuario. La mayora de las veces las vistas en
CakePHP vienen en formato HTML, pero una vista puede ser fcilmente un PDF, un documento
XML, o un objeto JSON, dependiendo de tus necesidades.
6. Una vez que el objeto encargado de procesar vistas en CakePHP ha utilizado los datos del
controlador para construir una vista completa, el contenido se devuelve al navegador de
Ricardo.
Casi todas las peticiones a tu aplicacin seguirn este patrn bsico. Ms adelante, vamos a
completar algunos detalles especficos de Cake, as que, por favor, ten esto en cuenta a medida que
avanzamos.
# Beneficios
Por qu utilizar MVC? Porque es un patrn de diseo de software probado y se sabe que
funciona. Con MVC la aplicacin se puede desarrollar rpidamente, de forma modular y mantenible.
Separar las funciones de la aplicacin en modelos, vistas y controladores hace que la aplicacin sea
muy ligera. Estas caractersticas nuevas se aaden fcilmente y las antiguas toman automticamente
una forma nueva.
El diseo modular permite a los diseadores y a los desarrolladores trabajar conjuntamente, as
como realizar rpidamente el prototipado. Esta separacin tambin permite hacer cambios en una parte
de la aplicacin sin que las dems se vean afectadas.
Aunque lleva algn tiempo acostumbrarse a construir aplicaciones as, estamos seguros de que,
una vez construyas tu primera aplicacin con CakePHP, no querrs volver a hacerlo de otra forma.

2 Principios bsicos de CakePHP


El framework CakePHP proporciona una base robusta para tu aplicacin. Puede manejar
cualquier aspecto, desde la solicitud inicial del usuario hasta el renderizado final de la pgina web.
Adems, como el framework sigue los principios MVC, puedes fcilmente personalizar y extender
muchos aspectos de tu aplicacin.
El framework tambin proporciona una estructura de organizacin bsica, desde los nombres de
los archivos hasta los de las tablas de la base de datos, manteniendo toda tu aplicacin consistente y
lgica. Este aspecto es simple pero poderoso. Sigue las convenciones y siempre sabrs exactamente
dnde estn las cosas y cmo estn organizadas.

2.1 Estructura de CakePHP


CakePHP incluye las clases Controlador [Controller], Modelo [Model] y Vista [View], pero
tambin incluye otras clases y objetos que hacen que el desarrollo en MVC sea un poco ms rpido y
agradable. Los Componentes [Components], Comportamientos [Behaviors], y Ayudantes [Helpers] son
clases que proporcionan extensibilidad y reusabilidad; agregan rpidamente funcionalidad a las clases
base MVC de las aplicaciones. Como de momento nos vamos a mantener en este nivel de dificultad, ve
preparando los detalles acerca de cmo usar estas herramientas.
2.1.1 Extensiones de los Controladores ("Componentes")
Un componente es una clase que ayuda a la lgica de un controlador. Si tienes alguna lgica y la
quieres compartir entre varios controladores (o aplicaciones), un componente suele ser una buena
eleccin. A modo de ejemplo, la clase del ncleo EmailComponent hace que la creacin y el envo de
mensajes de correo electrnico sea tan sencillo como coser y cantar. En lugar de escribir lgica en el
mtodo de un controlador, puedes empaquetarla en un componente para poder compartirla.
Los Controladores tambin estn equipados con callbacks. Puedes utilizar estos callbacks si
necesitas insertar alguna lgica en las operaciones del ncleo de CakePHP. Los Callbacks disponibles
incluyen:
beforeFilter(), se ejecuta antes que cualquier otra accin del controlador
beforeRender(), se ejecuta despus de la lgica del controlador, pero antes de que la vista se
renderice

afterFilter(), se ejecuta despus de toda la lgica del controlador, incluido el renderizado de la


vista. Puede que no haya ninguna diferencia entre afterRender() y afterFilter(), a menos que
hayas llamado manualmente a render() en el controlador y hayas incluido alguna lgica despus
de esa llamada.
2.1.2 Extensiones de las Vistas
Un ayudante [Helper] es una clase que ayuda a la lgica de una vista. Del mismo modo que
varios controladores utilizan un componente, los ayudantes [helpers] hacen que varias vistas accedan y
compartan lgica presentacional. Con uno de los ayudantes del ncleo, el AjaxHelper, el manejo de las
peticiones Ajax en las vistas es mucho ms fcil.
La mayora de las aplicaciones repiten piezas de cdigo en sus vistas. CakePHP facilita la
reutilizacin de este cdigo con diseos [layouts] y elementos [elements]. Por defecto, toda vista
renderizada por un controlador se coloca en un diseo [layout]; los elementos entran en juego cuando
hay que reutilizar estos fragmentos pequeos de contenido.
2.1.3 Extensiones de los Modelos
Del mismo modo, los Comportamientos [Behaviors] son formas de aadir funcionalidad comn
entre los modelos. Por ejemplo, si almacena datos de los usuarios en una estructura de rbol, puede
especificar que su modelo de usuario se comporte como un rbol, y obtener libre funcionalidad para
eliminar, aadir, y mover nodos en la estructura de rbol subyacente.
Los modelos tambin cuentan con el apoyo de otra clase llamada DataSource (Origen de datos).
Los DataSources son una abstraccin que permite a los modelos manipular diferentes tipos de datos en
forma consistente. Si bien la principal fuente de datos en una aplicacin CakePHP es a menudo una
base de datos, puede escribir DataSources adicionales que le permitan a sus modelos representar
canales RSS, archivos CSV, entradas LDAP, o eventos iCal. Los DataSources le permiten asociar
registros de diferentes fuentes: en lugar de limitarse slo a uniones [joins] SQL, los DataSources le
permiten decirle a su modelo LDAP que est asociado a muchos eventos iCal.
As como los controladores, los modelos tambin incluyen callbacks:
beforeFind()
afterFind()
beforeValidate()

beforeSave()
afterSave()
beforeDelete()
afterDelete()

Los nombres de estos mtodos deben ser lo suficientemente descriptivos para que sepa lo que
hacen. Asegrese de obtener los detalles en el captulo acerca de los modelos.
2.1.4 Extensiones de la Aplicacin
Tanto los controladores como los ayudantes [helpers] y modelos tienen una clase padre que
puede usarse para definir cambios a nivel global de la aplicacin. AppController (localizado en
/app/app_controller.php), AppHelper (localizado en /app/app_helper.php) y AppModel (localizado en
/app/app_model.php) son magnficos lugares donde colocar mtodos que desee compartir entre todos
los controladores, ayudantes [helpers] o modelos.
Las rutas juegan un rol en las peticiones hechas a CakePHP. Las definiciones de rutas le dicen a
CakePHP cmo mapear URLs a acciones de controladores. El comportamiento por defecto asume que
la URL "/controller/action/var1/var2/" mapea a Controller::action($var1, $var2), pero puede usar rutas
para personalizar URLs y la forma en que stas son interpretadas por su aplicacin.
Algunas caractersticas en una aplicacin merecen ser empaquetadas como un todo. Un plugin
es un paquete de modelos, controladores y vistas que cumplen un propsito especfico que puede
abarcar mltiples aplicaciones. Un sistema de administracin de usuarios o un blog simplificado
pueden ser buenos ejemplos para plugins de CakePHP.

2.2 Una peticin tpica de CakePHP


Hemos cubierto los ingredientes bsicos de CakePHP, as que echemos un vistazo a cmo los
objetos trabajan juntos para completar una peticin bsica. Continuando con nuestro ejemplo de
peticin original, imaginemos que nuestro amigo Ricardo acaba de hacer clic en el enlace "Comprar
un pastel personalizado ahora!" en una pgina de bienvenida de una aplicacin CakePHP.

Figura 2. Peticin tpica de Cake.


Negro = elemento requerido, Gris = elemento opcional, Azul = callback

Ricardo hace clic en el enlace apuntando a http://www.ejemplo.com/tortas/comprar, y su


navegador hace una peticin a su servidor Web.

El enrutador analiza la URL para extraer los parmetros para esta peticin: el controlador, la
accin, y cualquier otro argumento(s) que pueda afectar a la lgica de negocio durante esta
peticin.
Usando las rutas, una peticin URL es mapeada a una accin de controlador (un mtodo en una
clase de controlador especfica). En este caso, es el mtodo comprar() del controlador
PastelesController. El callback beforeFilter() del controlador es llamado antes de que cualquier
accin lgica del controlador sea ejecutada.
El controlador puede usar modelos para ganar acceso a los datos de la aplicacin. En este
ejemplo, el controlador usa un modelo para obtener informacin de la base de datos de las
ltimas compras de Ricardo. Cualquier callback de modelo, comportamiento [behavior], y
orgenes de datos [DataSources] aplicables pueden activarse durante esta operacin. Mientras
que el uso del modelo no es requerido, todos los controladores de CakePHP inicialmente

requieren al menos un modelo, salvo que el desarrollador indique lo contrario.


Despus que el modelo ha obtenido toda la informacin, sta es devuelta al controlador. Pueden
activarse callbacks del modelo.
El controlador puede usar componentes para refinar aun ms los datos o realizar otras
operaciones (manipulacin de sesiones, autenticacin, o envos de email, por ejemplo).
Una vez que el controlador ha usado modelos y componentes para preparar suficientemente la
informacin, sta es entregada a la vista usando el mtodo set() del controlador. Los callbacks
de controlador pueden ser aplicados antes de que la informacin sea enviada. La lgica de vista
es ejecutada, la cual puede incluir el uso de elementos y/o ayudantes [helpers]. Por defecto, la
vista es creada dentro del diseo [layout].
Callbacks del controlador adicionales (como afterFilter) pueden ser aplicados. El cdigo
completo creado por la vista es enviado al navegador de Ricardo.

2.3 Estructura de archivos de CakePHP


Tras descargar y extraer CakePHP, estos sern los ficheros y carpetas que deberas ver:
app
cake
vendors
.htaccess
index.php
README
Observars 3 carpetas principales:
La carpeta app ser donde haremos nuestra magia: es donde se ubicarn los ficheros de tu
aplicacin.
La carpeta cake es donde nosotros hemos hecho nuestra magia. Compromtete a no modificar
los ficheros de esta carpeta. No podremos ayudarte si has modificado el ncleo.
Finalmente, la carpeta vendors es donde ubicars las libreras PHP de terceros que necesites
usar con tus aplicaciones en CakePHP.

# La Carpeta App
La carpeta app de CakePHP es donde realizars la mayor parte del desarrollo de tu aplicacin.
Vemos un poco ms de cerca las carpetas dentro de app.

Contiene los (pocos) archivos de configuracin que usa CakePHP. Detalles de


config

conexin a bases de datos, arranque (bootstrapping), archivos de configuracin


del ncleo y dems deberan ser almacenados aqu.

controllers

Contiene los controladores de tu aplicacin y sus componentes.

locale

Almacena archivos de cadenas de texto para la internacionalizacin.

models
plugins

Contiene los modelos de tu aplicacin, comportamientos (behaviors) y orgenes


de datos (datasources).
Contiene los paquetes de plugins.
Aqu es donde CakePHP almacena datos temporales. La informacin que
realmente se almacena depende de cmo hayas configurado CakePHP, pero
normalmente esta carpeta es usada para almacenar descripciones de modelos,

tmp

registros (logs) y algunas veces informacin de sesiones.


Asegrate de que esta carpeta existe y tiene permisos de escritura, ya que de lo
contrario el rendimiento de tu aplicacin se ver muy afectado. En modo debug
CakePHP te avisar si este no es el caso.
Cualesquiera clases o libreras de terceros deberan ser ubicadas aqu. Hacerlo
as hace que sea ms fcil de acceder a ellas usando la funcin
App::Import('vendor','nombre'). Los observadores meticulosos

vendors

notarn que esto parece redundante, ya que tambin existe una carpeta
vendors en el nivel superior de nuestra estructura de directorios. Veremos las
diferencias entre las dos cuando discutamos acerca de la administracin de
mltiples aplicaciones y configuraciones de sistemas ms complejos.

views

Los archivos de presentacin son ubicados aqu: elementos (elements), pginas


de error, ayudantes (helpers), layouts y archivos de vistas.
En una configuracin de produccin, esta carpeta debera servir como la raz

webroot

del sitio (document root) para tu aplicacin. Las carpetas aqu tambin sirven
como lugares de almacenamiento para hojas de estilo en cascada (CSS
stylesheets), imgenes y archivos JavaScript.

2.4 Convenciones de CakePHP


Somos grandes fanticos de convencin sobre configuracin. Aun cuando toma un poco de
tiempo aprender las convenciones de CakePHP, usted ahorrar tiempo en la marcha: siguiendo las
convenciones, usted obtiene libre funcionalidad, y tambin se libera de la pesadilla del mantenimiento
del seguimiento de los archivos de configuracin. Las convenciones tambin hacen un sistema de
desarrollo muy uniforme, permitiendo a otros desarrolladores ayudar ms fcilmente.
Las convenciones de CakePHP han sido destiladas de aos de experiencia de desarrollo web y
mejores prcticas. Mientras que le sugerimos el uso de estas convenciones durante el desarrollo con
CakePHP, deberamos mencionar que muchos de estos postulados pueden ser anulados, esto es
especialmente til cuando se trabaja con sistemas heredados.
2.4.1 Convenciones de los nombres de archivos y clases
En general, los nombres de archivo llevan el smbolo underscore "_", mientras que los nombres
de las clases usan CamelCase. La clase MyNiftyClass puede ser encontrada en el archivo
my_nifty_class.php, por ejemplo.
Sin embargo, el nombre de la clase que contiene un archivo puede no necesariamente ser
encontrada en el nombre de archivo. La clase EmailComponent es encontrada en un archivo llamado
email.php, y la clase HtmlHelper es encontrada en un archivo llamado html.php.
2.4.2 Convenciones de Modelo y de la Base de datos
Los nombres de las clases de modelos estn en singular y en formato CamelCase. Persona,
PersonaGrande, y PersonaMuyGrande son todos ejemplos de nombres de modelos
convencionales.
Los nombres de las tablas correspondientes a modelos de CakePHP estn en plural y usando
guin bajo. Las tablas subyacentes para los modelos arriba mencionados seran: personas,
personas_grandes, y personas_muy_grandes respectivamente.
Puedes utilizar la librera de utilidades "Inflector" para verificar las palabras singulares/plurales.
Consulta la documentacin de Inflector para ms informacin.
Los nombres de los campos con dos o ms palabras se definen con guiones bajos:
nombre_y_apellidos.

El nombre por defecto de las claves forneas en relaciones hasMany, belongsTo o hasOne, es el
nombre de la tabla relacionada (en singular) seguido de _id. As, si Panadero hasMany Tarta, la
tabla tartas referenciar la tabla panaderos mediante la clave fornea panadero_id. Para una
tabla compuesta por varias palabras como tipos_categorias, la clave fornea sera
tipo_categoria_id.
El nombre de las tablas de unin entre modelos, usadas en relaciones hasAndBelongToMany
(HABTM), debera estar formado por el nombre de las tablas que une puestos en orden alfabtico
(cebras_manzanas en vez de manzanas_cebras).
Todas las tablas con las que interaccionan los modelos de CakePHP (con excepcin de las de
unin de tablas) necesitan una clave primaria simple que identifique inequvocamente cada fila. Si
deseas modelar una tabla que no tiene una clave primaria de un slo campo, como por ejemplo las filas
de una tabla de unin posts_tags, la convencin de CakePHP dicta que se aada una clave primaria
de un solo campo a la tabla.
CakePHP no soporta claves primarias compuestas. Si deseas manipular directamente los datos
de tu tabla de unin, usa llamadas directas a query o aade una clave primaria para que actue como un
modelo normal. Por ejemplo:
CREATE TABLE posts_tags (

);

id INT(10) NOT NULL AUTO_INCREMENT,


post_id INT(10) NOT NULL,
tag_id INT(10) NOT NULL,
PRIMARY KEY(id)

En vez de utilizar una clave autoincremental como clave primaria, puedes utilizar char(36). De
este modo CakePHP utilizar un uuid(String::uuid) nico de 36 caracteres siempre que grabes un nuevo
registro utilizando el mtodo Model::save.
2.4.3 Convenciones de Controladores
Los nombres de las clases de los controladores son en plural, con formato CamelCased, y
Terminan en Controller. PersonasController y UltimosArticulosController son
ejemplos de nombres convencionales de controladores.
El primer mtodo que escribas para un controlador debe de ser el mtodo index(). Cuando la
peticin especifica un controlador pero no una accin, el comportamiento por defecto de CakePHP es

ejecutar

el

mtodo

index()

de

dicho

controlador.

Por

ejemplo,

una

peticin

de

http://www.example.com/apples/ se corresponde con la llama al mtodo index() del controlador


ApplesController, mientras que http://www.example.com/apples/view se corresponde con una llamada
al mtodo view() del controlador ApplesController.
Tambin puedes cambiar la visibilidad de los mtodos de los controladores en CakePHP
anteponiendo al nombre del mtodo guiones bajos. Si un mtodo de un controllador comienza por un
guin bajo, el mtodo no ser accesible diretamente desde la web, sino que estar disponible slo para
uso interno. Por ejemplo:
<?php
class NoticiasController extends AppController {
function ultimas() {
$this->_buscaNuevosArticulos();
}
function _buscaNuevosArticulos() {
//Lgica para encontrar los nuevos articulos.
}
}
?>

Mientras que la pgina http://www.example.com/noticias/ultimas/ est accesible de manera


normal,

si

alguien

intenta

acceder

la

pgina

http://www.example.com/noticias/_buscaNuevosArticulos/ obtendr un error porque el nombre del


mtodo est precedido por un guin bajo.
2.4.3.1 Consideraciones de URL para nombres de controladores

Como se puede ver, los controladores con un nombre simple (de una sola palabra) pueden ser
fcilmente mapeados a una url en minsculas. Por ejemplo, ApplesController (que se define en
el archivo 'apples_controller.php') y accedido desde http://example.com/apples.
Por otro lado mltiples combinaciones de palabras pueden ser transformadas automticamente
en un mismo nombre de controlador:

/redApples

/RedApples

/Red_apples

/red_apples

Todas resuelven la accin index de controlador RedApples. sin embargo, la convencin es que
las urls sean en minsculas y separadas con guin bajo, por lo tanto /red_apples/go_pick es la
forma correcta de acceder a la accin. RedApplesController::go_pick.
Para mas informacin sobre CakePHP URLs y sus parametros, ver Configuracin de Rutas.
2.4.4 Convenciones de Vistas
Los archivos de plantillas de Vistas (Views) deben ser nombradas despus de las funciones de
los controladores con guin bajo "_". La funcion getReady() del controlador PeopleController se
visualizara con la plantilla de vista en /app/views/people/get_ready.ctp por ejemplo.
El patrn bsico es: /app/views/controller/underscored_function_name.ctp
Al nombrar las piezas de su aplicacin utilizando las convenciones de CakePHP, usted adquiere
funcionalidad sin mucho mantenimiento de la configuracin. Aqu encontramos un ejemplo final de las
convenciones

Tabla de Base de Datos: people

Clase de Modelo: Person, encontrada en /app/models/person.php

Clase de Controlador: PeopleController, encontrada en /app/controllers/people_controller.php

Plantilla de Vista, encontrada en /app/views/people/index.ctp

Usando estas convenciones, CakePHP entiende que la peticion http://example.com/people/


apunta a la llamada de funcion index() en el controlador , PeopleController, donde el modelo Person
esta disponible automaticamente (y apunta automaticamente a la tabla people en la base de datos), y
se renderiza en el archivo. Ninguna de estas relaciones han sido configuradas por otra razon que crear
clases y archivos que usted necesita crear.
Ahora que usted ya se ha involucrado con los fundamentos de CakePHP, puede revisar el
tutorial para realizar un Blog en CakePHP, que se encuentra al final de este manual.

3 Desarrollando con CakePHP


Y ahora, a cocinar.

3.1 Requerimientos

Servidor HTTP. Por ejemplo: Apache. Preferiblemente con mod_rewrite, pero no requerido.

PHP 4.3.2 o superior. Si, CakePHP funciona genial en PHP 4 y 5.


Tcnicamente no se requiere un motor de base de datos, pero nos imaginamos que la mayora de

las aplicaciones usarn uno. CakePHP soporta una gran variedad de motores de almacenamiento:

MySQL (4 o superior)

PostgreSQL

Firebird DB2

Microsoft SQL Server

Oracle

SQLite

ODBC

ADOdb

3.2 Preparndose para Instalar


CakePHP es rpido y fcil de instalar.Los requisitos mnimos son un servidor web y una copia
de Cake, solo eso! Aunque este manual se enfoca primariamente en la configuracin sobre Apache
(por que es el usado comnmente), Tu puedes configurar Cake para correr sobre la mayora de
servidores web, tales como, LightHTTPD o bien Microsoft IIS. Preparar la instalacin consta de los
siguientes pasos:

Descargue CakePHP

Configure su servidor para manejar php si es necesario

Chequee los permisos de los archivos

3.2.1 Obteniendo CakePHP


Hay dos principales maneras de obtener una copia limpia de CakePHP. Puedes descargar una
copia comprimida (zip/tar.gz/tar.bz2) de la pgina web principal, o puedes obtener el cdigo desde el
repositorio git.
Para descargar la ltima release principal de CakePHP, dirgete a la pgina web
http://www.cakephp.org y haz clic en el enlace Download Now.
Todas las releases actuales estn alojadas en CakeForge. Este site tambin contiene enlaces a
muchos otros proyectos en CakePHP, incluyendo plugins y aplicaciones para CakePHP. Las releases de
CakePHP estsn disponibles en http://cakeforge.org/projects/cakephp.
Se crean nightly builds alternativas que incluyen parches y mejoras al minuto (bueno, al da).
Estas

pueden

ser

accedidas

desde

la

pgina

principal

de

descargas

aqu:

http://cakephp.org/downloads/index/nightly. Para actualizaciones realmente al minuto, puedes obtener


el cdigo directamente de la rama de desarrollo del repositorio git aqu: http://code.cakephp.org/source.
3.2.2 Permisos
CakePHP usa el directorio /app/tmp para diferentes operaciones, como almacenar descripciones
de los modelos, vistas en cache, informacin de sesiones, entre otros.
Por ello, asegrate que el directorio /app/tmp de tu instalacin de Cake tenga permisos de
escritura por el usuario del servidor web

3.3 Instalacin
Instalar CakePHP puede ser tan simple como colocar el directorio en el servidor, o tan complejo
y flexible como necesites. Esta seccin cubrir los tres tipos principales de instalacin para CakePHP:
desarrollo, produccin y avanzado

Desarrollo: fcil para iniciar, los URL de la aplicacin incluyen el nombre del directorio, y es
menos seguro.

Produccin: Requiere la capacidad de configurar el servidor web para definir el "document


root", muy seguro.

Avanzado: Con cierta configuracin, permite ubicar los directorios clave de CakePHP en
diferentes partes del sistema de archivos, para compartir una misma instalacin de CakePHP

para varias aplicaciones.


3.3.1 Desarrollo
Usar una instalacin de desarrollo es el mtodo ms rpido para montar Cake. Este ejemplo te
ayudar

instalar

una

aplicacin

de

CakePHP

hacerla

disponible

en

http://www.ejemplo.com/cake_1_2/. Asumimos para el fin de este ejemplo que tu raz de


documentos est establecido a /var/www/html.
Descomprime los contenidos del archivo Cake en /var/www/html. Ahora tienes una carpeta
en tu raz de documentos con un nombre dependiente de la versin que te has descargado (p.ej.
cake_1.2.0.7962). Renombra esta carpeta a cake_1_2. Tu configuracin de desarrollo ser
como la siguiente en el sistema de archivos:

/var/www/html
cake_1_2
/app
/cake
/vendors
.htaccess
/index.php
README
Si tu servidor web est configurado correctamente, deberas encontrar tu aplicacin de Cake

accesible en http://www.ejemplo.com/cake_1_2/.
3.3.2 Produccin
Una instalacin de produccin es una manera ms flexible de instalar Cake. Usar este mtodo
permite que un dominio entero se comporte como una aplicacin CakePHP nica. Este ejemplo te
ayudar a installar Cake en cualquier sitio de tu sistema de ficheros y ponerlo disponible en
http://www.ejemplo.com. Tener en cuenta que esta instalacin puede requerir los privilegios
para cambiar el DocumentRoot (raz de documentos) en servidores web Apache.
Descomprime los contenidos del archivo Cake en un directorio a tu eleccin. Por motivos de
ejemplo, asumimos que escoges instalar Cake en /cake_install. Tu configuracin de produccin
se ver de la siguiente manera en el sistema de ficheros:

/cake_install/

/app
/webroot (este directorio es el establecido con la directiva DocumentRoot)
/cake
/vendors
/.htaccess
/index.php
/README
Los desarrolladores que usan Apache debern establecer la directiva DocumentRoot para el
dominio a:
DocumentRoot /cake_install/app/webroot

Si tu servidor web est configurado correctamente, deberas encontrar tu aplicacin Cake


accesible en http://www.ejemplo.com.
3.3.3 Instalacin Avanzada
Existen situaciones en las que querrs colocar los directorios de CakePHP en lugares diferentes
del sistema de archivos. Esto puede ser debido a restricciones de un servidor compartido, o quizs
simplemente deseas que algunas de tus aplicaciones compartan las mismas libreras de Cake. Esta
seccin describe cmo esparcir los directorios de CakePHP sobre un sistema de archivos.
En primer lugar, date cuenta que existen tres partes principales de una aplicacin Cake:
1. Las libreras principales(core) de CakePHP, en /cake.
2. El cdigo de tu aplicacin, en /app.
3. El webroot de la aplicacin, normalmente en /app/webroot.
Cada uno de estos directorios puede ser ubicado en cualquier lugar de tu sistema de archivos, a
excepcin del webroot, que debe ser accesible por el servidor web. Incluso puedes mover el directorio
webroot fuera de tu carpeta app siempre que le indiques a Cake en donde lo has puesto.
Para

configurar

tu

instalacin

de

Cake,

necesitars

hacer

algunos

cambios

/app/webroot/index.php. Hay tres constantes que debers editar: ROOT, APP_DIR, y


CAKE_CORE_INCLUDE_PATH.

ROOT debe contener la ruta del directorio que contiene la carpeta app (es decir, el padre de
APP_DIR).

APP_DIR debe ser establecida con el nombre(base) de tu carpeta app.

CAKE_CORE_INCLUDE_PATH debe contener la ruta al directorio que contiene las libreras de


Cake.
Vamos a mostrar un ejemplo para ver cmo quedara una instalacin avanzada en la prctica.

Imagina que quiero configurar CakePHP para que funcione de esta manera:

Las Libreras de CakePHP sern ubicadas en /usr/lib/cake.

El webroot de mi aplicacin ser /var/www/misitio/.

El directorio app de mi aplicacin estar en /home/yo/misitio.


Dada esta configuracin, necesitar editar mi webroot/index.php (el cual terminar

ubicado en /var/www/misitio/index.php, en este ejemplo) para que sea as:


// /app/webroot/index.php (codigo parcial, sin comentarios)
if (!defined('ROOT')) {
define('ROOT', DS.'home'.DS.'yo');
}
if (!defined('APP_DIR')) {
define ('APP_DIR', 'misitio');
}
if (!defined('CAKE_CORE_INCLUDE_PATH')) {
define('CAKE_CORE_INCLUDE_PATH', DS.'usr'.DS.'lib');
}

Es recomendable utilizar la constante DS en lugar de barras inclinadas para delimitar las rutas
de los archivos. Esto evita errores por falta de archivo como resultado de usar el delimitador
equivocado, y adems hace tu cdigo ms portable.
3.3.3.1 Rutas de Clase Adicionales

Ocasionalmente es til compartir clases MVC entre aplicaciones en el mismo sistema. Si


quieres el mismo controler en dos aplicaciones, puedes usar el archivo bootstrap.php de CakePHP
para traer estas clases adicionales a la escena.
En el archivo bootstrap.php, define algunas variables especiales para que CakePHP sepa
otros lugares en donde buscar clases MVC:
$viewPaths

= array();

$controllerPaths
$modelPaths
$helperPaths
$componentPaths
$behaviorPaths
$pluginPaths
$vendorPaths
$localePaths
$shellPaths

=
=
=
=
=
=
=
=
=

array();
array();
array();
array();
array();
array();
array();
array();
array();

Cada una de estas variables especiales pude ser establecida a un array de rutas absolutas en el
sistema de archivos donde las clases adicionales pueden ser encontradas cuando se solicite. Asegrate
que cada ruta contenga una barra inclinada (o preferiblemente la constante DS) al final.
3.3.4 Apache y mod_rewrite (y .htaccess)
A pesar de que CakePHP est hecho para funcionar con mod_rewrite sin tocar nada, y
normalmente as es, hemos notado que algunos usuarios tienen dificultades para lograr que todo
funcione correctamente en sus sistemas.
Aqu hay unas cuantas cosas que puedes probar para conseguir que funcione correctamente.
Primero mira en tu httpd.conf (asegrate de estar editando el httpd.conf del sistema y que no
es httpd.conf especfico de un usuario o del site).
1. Asegrate que la reescritura .htaccess est permitida y que AllowOverride est establecido
a All para el DocumentRoot adecuado. Deberas ver algo similar a:
# Cada directorio al que tiene acceso Apache puede ser configurado en
# funcin de qu servicios y caractersticas estn permitidas y/o
# desactivadas en dicho directorio (y sus subdirectorios).
#
# Primero, configuramos "por defecto" para que sea un conjunto de
# caractersticas muy restrivo.
#
<Directory />
Options FollowSymLinks
AllowOverride All
#
Order deny,allow
#
Deny from all
</Directory>

2. Asegrate de estar cargando el mdulo mod_rewrite correctamente. Debes ver algo como:
LoadModule rewrite_module libexec/apache2/mod_rewrite.

En muchos sistemas esto estar comentado (comenzando la lnea con #) por defecto, as que
slo tendrs que quitar los smbolos # del principio.

Tras realizar los cambios reinicia Apache para estar seguro de que las opciones de configuracin
estn activas.
Asegrate de que tus ficheros .htaccess estn en los directorios correctos. Esto puede pasar
durante la copia porque algunos sistemas operativos consideran los archivos que comienzan por '.'
como ocultos y por lo tanto no los copian.
3. Asegrate de que tu copia de CakePHP es de las seccin de descargas de nuestro site o nuestro
repositorio GIT, y que ha sido desempaquetado correctamente verificando que existen los
ficheros .htaccess:

En el directorio raz de Cake (necesita ser copiado al directorio, esto redirige todo a tu aplicacin de
Cake):
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule
^$ app/webroot/
[L]
RewriteRule
(.*) app/webroot/$1 [L]
</IfModule>

En el directorio app de Cake (ser copiado por bake):


<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule
^$
webroot/
RewriteRule
(.*) webroot/$1
</IfModule>

[L]
[L]

En el directorio webroot de Cake (ser copiado a tu webroot de la aplicacin por bake):


<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]
</IfModule>

En muchos servicios de hosting (GoDaddy, 1and1), tu servidor web est realmente siendo
servido desde un directorio de usuario que ya utiliza mod_rewrite. Si ests instalando CakePHP en un
directorio de usuario (http://ejemplo.com/~nombreusuario/cakephp), o en cualquier otra estructura que
ya utilice mod_rewrite necesitars aadir sentencias RewriteBase a los archivos .htaccess que
utiliza CakePHP (/.htaccess, /app/.htaccess, /app/webroot/.htaccess)
Esto puede ser aadido a la misma seccin con la directiva RewriteEngine, as, por ejmplo,

tu archivo .htaccess en el webroot devera ser as:


<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]
</IfModule>

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]
</IfModule>
Los detalles de esos cambios dependen de tu configuracin, y pueden incluir cosas adicionales
que no estn relacionadas con Cake. Consulta la documentacin online de Apache para ms
informacin.
3.3.5 Lighttpd y mod_magne
Aunque Lighttpd cuenta con un mdulo de reescritura, no es equivalente al mod_rewrite de
Apache. Las funcinalidades completas de mod_rewrite se reparten entre el mod_rewrite de Lighttp, el
mod_magnet y el mod_proxy.
Sin embargo, CakePHP, mayoritariamente necesita mod_magnet para redirigir las solicitudes a
fin de trabajar con bastantes URLs
Para utilizar bastantes URLs con CakePHP y Lighttp, sustituye este lua script en
/etc/lighttpd/cake.
-- pequea funcion helper
function file_exists(path)
local attr = lighty.stat(path)
if (attr) then
return true
else
return false
end
end
function removePrefix(str, prefix)
return str:sub(1,#prefix+1) == prefix.."/" and str:sub(#prefix+2)
end

-- prefijo sin la barra


local prefix = ''
-- la magia ;)
if (not file_exists(lighty.env["physical.path"])) then
-- fichero an desaparecido, pasarlo al fastcgi Backend
request_uri = removePrefix(lighty.env["uri.path"], prefix)
if request_uri then
lighty.env["uri.path"]
= prefix .. "/index.php"
local uriquery = lighty.env["uri.query"] or ""
lighty.env["uri.query"] = uriquery .. (uriquery ~= "" and "&" or "") ..
"url=" .. request_uri
lighty.env["physical.rel-path"] = lighty.env["uri.path"]
lighty.env["request.orig-uri"] = lighty.env["request.uri"]
lighty.env["physical.path"]
= lighty.env["physical.doc-root"] ..
lighty.env["physical.rel-path"]
end
end
-- fallthrough pondr de nuevo la solucititud en el bucle lighty
-- eso significa que tenemos la manipulacin 304 de forma gratuita. ;)

Then tell Lighttpd about your vhost:


$HTTP["host"] =~ "example.com" {
server.error-handler-404

= "/index.php"

magnet.attract-physical-path-to = ( "/etc/lighttpd/cake.lua" )
server.document-root = "/var/www/cake-1.2/app/webroot/"
# adems piensa como coger los ficheros vim tmp fuera
url.access-deny = (
"~", ".inc", ".sh", "sql", ".sql", ".tpl.php",
".xtmpl", "Entries", "Repository", "Root",
".ctp", "empty"
)
}

3.3.6 Pretty URLs en nginx


nginx es un servidor popular que, del mismo modo que Lighttpd, consume menos recursos del
sistema. Su inconveniente es que no utiliza ficheros .htaccess como Apache y Lighttpd, por lo que es
necesario crear esas reescrituras de URLs en la configuracin de site-available. Dependiendo de tu
configuracin, necesitars modificar esto, pero como mnimo necesitars que PHP se ejecute como
instancia de FastCGI.
server {
listen
80;
server_name www.ejemplo.com;
rewrite ^(.*) http://ejemplo.com$1 permanent;

}
server {
listen
80;
server_name ejemplo.com;
access_log /var/www/ejemplo.com/log/access.log;
error_log /var/www/ejemplo.com/log/error.log;
location / {
root
/var/www/ejemplo.com/public/app/webroot/;
index index.php index.html index.htm;
if (-f $request_filename) {
break;
}
if (-d $request_filename) {
break;
}
rewrite ^(.+)$ /index.php?q=$1 last;
}
location ~ .*\.php[345]?$ {
include /etc/nginx/fcgi.conf;
fastcgi_pass
127.0.0.1:10005;
fastcgi_index
index.php;
fastcgi_param SCRIPT_FILENAME
/var/www/ejemplo.com/public/app/webroot$fastcgi_script_name;
}
}

3.3.7 URL Rewrites on IIS7 (Windows hosts)


IIS7 does not natively support .htaccess files. While there are add-ons that can add this support,
you can also import htaccess rules into IIS to use CakePHP's native rewrites. To do this, follow these
steps:
1. Use Microsoft's Web Platform Installer to install the URL Rewrite Module 2.0.
2. Create a new file in your CakePHP folder, called web.config
3. Using Notepad or another XML-safe editor, copy the following code into your new
web.config file...
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Imported Rule 1" stopProcessing="true">
<match url="^(.*)$" ignoreCase="false" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsDirectory"

negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsFile"
negate="true" />
</conditions>
<action type="Rewrite" url="index.php?url={R:1}"
appendQueryString="true" />
</rule>
<rule name="Imported Rule 2" stopProcessing="true">
<match url="^$" ignoreCase="false" />
<action type="Rewrite" url="/" />
</rule>
<rule name="Imported Rule 3" stopProcessing="true">
<match url="(.*)" ignoreCase="false" />
<action type="Rewrite" url="/{R:1}" />
</rule>
<rule name="Imported Rule 4" stopProcessing="true">
<match url="^(.*)$" ignoreCase="false" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsDirectory"
negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsFile"
negate="true" />
</conditions>
<action type="Rewrite" url="index.php?url={R:1}"
appendQueryString="true" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>

It is also possible to use the Import functionality in IIS's URL Rewrite module to import rules
directly from CakePHP's .htaccess files in root, /app/, and /app/webroot/ - although some
editing within IIS may be necessary to get these to work. When Importing the rules this way, IIS will
automatically create your web.config file for you.
Once the web.config file is created with the correct IIS-friendly rewrite rules, CakePHP's
links, css, js, and rerouting should work correctly.
3.3.8 Encindelo
Muy bien, ahora veamos a CakePHP en accin. Dependiendo de la configuracin que hayas
usado, deberas apuntar tu navegador a http://example.com/ o http://example.com/mi_aplicacion/. En
este punto, se te presentar la vista de bienvenida de CakePHP por omisin, y un mensaje que indica el
estado de conexin con la base de datos.
Felicidades! Ya ests listo para crear tu primera aplicacin CakePHP.

3.4 Configuracin
Configurar aplicaciones CakePHP es pan comido. Despues de instalar CakePHP, crear una
aplicacin web bsica solo requiere aplicar la configuracin de una base de datos. Existen, otras
configuraciones opcionales, que puedes realizar con el objetivo de aprovechar las ventajas de la
arquitectura flexible de CakePHP. Tu puedes agregar facilmente elementos al ncleo de CakePHP,
configurar URL personalizadas y definir inflexiones.
3.4.1 Configuracin de Base de Datos
CakePHP espera que los detalles de configuracin de la base de datos estn en
app/config/database.php.

Un ejemplo

de configuracin

puede encontrarse en el archivo

app/config/database.php.default. Esta configuracin debera verse como sigue:


var $default = array('driver'
'persistent'
'host'
'login'
'password'
'database'
'prefix'

=> 'mysql',
=>
=>
=>
=>
=>
=>

false,
'localhost',
'cakephpuser',
'c4k3roxx!',
'mi_proyecto',
''

);

El arreglo de configuracin $default es el utilizado a menos que se especifique algn otro en la


propiedad $usDbConfig de los modelos. Por ejemplo, si mi aplicacin tiene aplicaciones legadas
adicionales a la que se va a utilizar por defecto, podra utilizarla en mis modelos creando un nuevo
arreglo de configuracin $legada que sea similar a $default, y asignado var $useDbConfig = 'legada';
en los modelos correspondientes.
Rellena cada para clave/valor en el arreglo de configuracin, como mejor se ajuste a tus
necesidades
Clave

Valor

driver

El nombre del controlador de base de datos que se desea utilizar. Ejemplo: mysql,
postgres, sqlite, pear-nombrededriver, adodb-nombrededriver, mssql, oracle, odbc.

persistent

Si se debe usar o no una conexin persistente a la base de datos.

host

El nombre de servidor de la base de datos (o direccin IP).

login

El nombre de usuario para la cuenta.

password

La contrasea para la cuenta.

database

Nombre de la base de datos a usar para la conexin

prefix (opcional)

El texto que prefija cada nombre de tabla en la base de datos. til si se comparte la
base de datos con varias aplicaciones. Dejar vaco si no se desea ninguno.

port (opcional)

El puerto TCP o socket Unix a usarse para la conexin con el servidor de base de
datos.

encoding

Indica la codificacin de caracteres a usar para enviar las sentencias SQL al


servidor.

schema

Usado en la configuracin de PostgreSQL para especificar el esquema a utilizar.

Nota que los prefijos son para las tablas, no para los modelos. Por ejemplo, si creaste una tabla
join

para

tus

modelos

Torta

Sabor,

esta

debe

llamarse

prefijo_sabor_torta

(no

prefijo_sabor_prefijo_torta), y asignar la clave prefix con prefijo_.


A este punto, pudieras querer echar un vistazo a las Convenciones de CakePHP, enunciadas en
el apndice de este manual. Nombrar correctamente tus tablas (y algunas columnas) segn las
convenciones puede librarte de mucho trabajo de configuracin. Por ejemplo, si nombras una tabla
como tortas, el modelo Torta y el controller TortasController, todo funcionar automticamente si
necesidad de tu intervencin. Por convencin, utiliza guiones bajos, minsculas, y nombres en plural
para los nombres de tus tablas - por ejemplo: reposteros, reposterias, sabores.
3.4.2 Configuracin del Core
La configuracin de la aplicacin en CakePHP se encuentra en /app/config/core.php. Este
archivo es una coleccin de definiciones de variables Configure y definiciones de constantes que
determinan como ha de comportarse la aplicacin. Antes de sumergirse en cada una de estas directivas,
necesitars familiarizarte con Configure, la clase de registro de configuraciones de CakePHP
3.4.3 La Clase de Configuracin
A pesar de que muy pocas cosas necesitan configuracin en CakePHP, a veces es til tener tus
propias reglas de configuracin para tu aplicacin. En el pasado seguramente habras definido alguno
de estos valores creando constantes en varios archivos. Hacerlo de esa manera te obligara a incluir
estos archivos cada vez que desees utilizarlos.
La nueva clase Configure de CakePHP puede ser utilizada para guardar y recuperar valores
especficos de la aplicacin o de tiempo de ejecucin. Se cuidadoso, esta clase permite almacenar
cualquier cosa en ella, para luego usarla en cualquier lugar de tu cdigo: una tentacin segura para

romper el patrn MVC con el cual fue diseado CakePHP. El objetivo principal de la clase Configure
es mantener centralizadas las variables que pueden ser compartidas entre varios objetos. Recuerda
tratar de mantener la filosofa de "convencin sobre configuracin" y as no terminars rompiendo la
estructura MVC que se ha diseado.
Esta clase acta como un singletn, y sus mtodos pueden ser llamados desde cualquier lugar en
tu aplicacin, en un contexto esttico.
<?php Configure::read('debug'); ?>

3.4.3.1 Mtodos de la Clase Configure


3.4.3.1.1 write
write(string $clave, mixed $valor)

Utiliza write() para almacenar datos en la configuracin de la aplicacin


Configure::write('Empresa.nombre','Pizza, Inc.');
Configure::write('Empresa.lema','Pizza para tu cuerpo y alma');

Nota el uso de la notacin punto en el parmetro $clave. Puedes utilizar esta notacin para organizar
tus configuraciones dentro de grupos lgicos.
El ejemplo anterior pudo ser escrito en una sola llamada:
Configure::write(
'Empresa',array('nombre'=>'Pizza, Inc.','lema'=>'Pizza para tu cuerpo y alma')
);

Puedes utilizar Configure::write(debug, $int) para cambiar entre desarrollo y produccin


dentro de la ejecucin de tu programa. Esto es especialmente til para interacciones AMF o SOAP
donde la informacin de depuracin puede ocasionar problema de parseo.
3.4.3.1.2 read
read(string $clave = 'debug')
Se usa para leer datos de configuracin de la aplicacin. Por
defecto

devuelve

el

importante

valor

de

"debug"

(nivel

de

depuracin). Si se especifica una clave, los datos correspondientes

son

devueltos.

Usando

nuestros

anteriores

ejemplos

de

write(),

podemos leer esos datos de vuelta:


Configure::read('Empresa.nombre');

//devuelve: 'Pizza, Inc.'

Configure::read('Empresa.lema');

//devuelve: 'Pizza para tu cuerpo y alma'

Configure::read('Empresa');
//devuelve:
array('nombre' => 'Pizza, Inc.', 'lema' => 'Pizza para tu cuerpo y alma');

3.4.3.1.3 delete
delete(string $clave)
Se usa para borrar informacin de configuracin de la aplicacin.
Configure::delete('Empresa.nombre');

3.4.3.1.4 load
load(string $path)
Usa este mtodo para cargar informacin de configuracin desde una archivo especfico.
// /app/config/mensajes.php:
<?php
$config['Empresa']['nombre'] = 'Pizza, Inc.';
$config['Empresa']['lema'] = 'Pizza para tu cuerpo y alma';
$config['Empresa']['telefono'] = '555-55-55';
?>
<?php
Configure::load('mensajes');
Configure::read('Empresa.nombre');
?>

3.4.3.1.5 version
version()
Devuelve la versin de CakePHP de la aplicacin actual.
3.4.3.2 Variables de Configuracin Principales de CakePHP
La clase Configure se usa para manejar un conjunto de variables de configuracin de CakePHP.
Estas variables pueden ser encontradas en app/config/core.php. Abajo se encuentra una descripcin de

cada variable y cmo afecta tu aplicacin CakePHP.


Variable de
Configuracin

Descripcin
Cambia el nivel de depuracin de cake

debug

0 = Modo producin. No produce ninguna salida.


1 = Muestra los error y warnings.
2 = Muestra los error, warnings, y consultas SQL

App.baseUrl

Descomenta esta definicin si no deseas utilizar el mod_rewrite de Apache.


No te olvides de eliminar los archivos .htaccess tambin.

Routing.admin

Descomenta esta definicin si deseas utilizar las rutas admin de CakePHP.


Asigna la variable al nombre de la ruta que te gustara utilizar. Ms adelante
se explicar en detalle.

Cache.disable

Cuando se asigna true, el cache se deshabilita para toda la aplicacin.

Cache.check

Si se asigna true, habilita el cache de las vistas. Tambin es necesario activar


el cache en los controllers, pero esta variable habilita la deteccin de dichas
configuraciones.
Le indica a CakePHP qu mecanismo de almacenamiento de sesiones se debe
utilizar

Session.save

php = Utiliza el almacenamiento por defecto de php


cake = Guarda los datos de sesin en /app/tmp
database = Guarda los datos en una tabla de la base de datos. Asegrate de
cargar el archivo SQL ubicado en /app/config/sql/sessions.sql.

Session.table

El nombre de la tabla (sin incluir el prefijo) que guarda los datos de la sesin.

Session.database

El nombre de la base de datos que guarda los datos de sesin.

Session.cookie

El nombre del cookie utilizado para hacer seguimiento de las sesiones.

Session.timeout

El tiempo base de validez de la sesin en segundos. El valor real depende de


la variable Security.level

Session.start

Inicia automticamente la sesin cuando se asigna true.

Session.checkAgent

Cuando se asigna false, Las sesiones de CakePHP no se asegurarn de que el


"user agent" del usuario no cambie entre peticiones.
El nivel de seguridad de CakePHP. El tiempo de validez de la sesin definido
en 'Session.timeout' se multiplica de acuerdo a lo siguiente.

Security.level

Valores vlidos:
'high' = x 10
'medium' = x 100
'low' = x 300

Security.salt

Una palabra aleatoria usada en sumas de seguridad.

Acl.classname,
Acl.database

Variables usadas para las Listas de Control de Acceso de CakePHP. Lee el


captulo de listas de control de acceso para ms informacin.

Nota: La configuracin de Cache tambin puede ser encontrada en el archivo core.php Ms adelante cubriremos
este tema.

La clase Configure puede ser utilizada para leer y escribir valores durante la ejecucin del
programa. Esto puede ser especialmente til si desea deshabilitar el nivel de deburacion ("debug") para
una seccin limita de lgica en tu aplicacin.

3.4.3.3 Constantes de Configuracin


A pesar de que la mayora de las opciones de configuracin se manejan con la clase Configure,
existen unas pocas constantes que utiliza CakePHP durante su ejecucin.
Constante

Descripcin

LOG_ERROR

Constante de error. Usada para diferenciar entre registros de depuracin y


registros de error. Actualmente PHP solo soporta LOG_DEBUG.

3.4.4 La Clase App


Cargar clases adicionales se ha vuelto mucho ms sencillo con CakePHP. En versiones
anteriores existan funciones diferentes para cargar una clase dependiendo de su tipo. Estas funciones
han sido reemplazadas, ahora toda la carga de clases debera hacerse a travs de el mtodo
App::import(). ste mtodo te asegura que una clase ha sido cargada slo una vez, que las clases que
extiende se hayan cargado apropiadamente, y resuelve las rutas de ubicacin automticamente en la
gran mayora de los casos.
3.4.4.1 Usando App::import()
App::import($type, $name, $parent, $search, $file, $return);
A primera vista App::import parece complejo, sin embargo, en la mayora de los casos es
suficiente con tan slo dos parmetros.
3.4.4.2 Importando libreras del Core
Las libreras del Core, como Sanitize y Xml pueden ser cargadas mediante:
App::import('Core', 'Sanitize');
Lo anterior har que la clase Sanitize est disponible para su uso.

3.4.4.3 Importando Controladores, Modelos, Ayudantes, Comportamientos y Componentes


App::import('Controller', 'MyController');
Llamando a App::import es equivalente a require. Es importante darse cuenta que la
clase posteriormente necesita ser inicializada.
<?php
// Lo mismo que require('controllers/users_controller.php');
App::import('Controller', 'Users');
// Necesitamos cargar la clase
$Users = new UsersController;
// If we want the model associations, components, etc to be loaded
$Users->constructClasses();
?>

3.4.4.3.2 Cargando Modelos [Model]


App::import('Model', 'MyModel');
3.4.4.3.3 Cargando Componentes [Components]
App::import('Component', 'Auth');
3.4.4.3.4 Cargando Comportamientos [Behaviors]
App::import('Behavior', 'Tree');
3.4.4.3.5 Cargando Ayudantes[Helpers]
App::import('Helper', 'Html');
3.4.4.4 Cargando desde Plugins
Cargar clases en plugins funciona casi igual que cargar clases ubicadas en el Core o en la
aplicacin principal, a excepcin de que debe especificarse el nombre del plugin donde reside la clase a
cargar.
App::import('Modelo', 'NombrePlugin.Comentario');

3.4.4.5 Cargando Archivos de Terceros


La funcin vendor() ha sido reemplazada. Los archivos de terceros deben ser cargados tambin
mediante App::import(). La sintaxis y los argumentos adicionales son levemente diferentes, debido a
que los archivos de terceros y su estructura pueden variar inmensamente, y no todos los archivos de
terceros contienen clases.
Los siguientes ejemplos ilustran cmo cargar archivos de terceros en diferentes rutas y
estructuras. Los archivos de terceros deben estar ubicados en cualquiera de los directorios vendor.
3.4.4.5.1 Ejemplos de archivos de terceros
Para cargar vendors/geshi.php
App::import('Vendor', 'geshi');
Para cargar vendors/flickr/flickr.php
App::import('Vendor', 'flickr/flickr');
Para cargar vendors/cierto.nombre.php
App::import('Vendor', 'CiertoNombre', array('file' => 'cierto.nombre.php'));
Para cargar vendors/services/well.named.php
App::import('Vendor', 'WellNamed', array('file' => 'services'.DS.'well.named.php'));

3.4.5 Configuracin de Rutas


El enrutamanieto permite hacer una relacin entre URLs y acciones de los controller. Fue
aadido a CakePHP para hacer ms bonitos los URLs, ms configurables, y ms flexibles. Usar el
mod_rewrite de Apache no es un requisito para utilizar el enrutamiento, pero har lucir mucho mejor tu
barra de direcciones.
Las rutas en CakePHP 1.2 han sido mejoradas y pueden llegar a ser muy poderosas.
Enrutamiento por Defecto
Antes de que aprendas a configurar tus propias rutas, deberas saber que CakePHP viene
configurado con un conjunto de rutas por defecto. Estas rutas te llevarn bastante lejos en cualquier
aplicacin. Puedes acceder a una accin directamente desde el URL colocando su nombre en la

peticin. Tambin puedes pasar parmetros a las acciones de tus controladores usando el URL.
Patron URL de las rutas por defecto:
http://example.com/controlador/accion/param1/param2/param3

El

URL /articulos/ver

dirige

la

accinver()

action

del ArticulosController,

/productos/listaCompleta dirige a la accion to the lista_completa() de ProductosController. Si no se


especifica ninguna accin en el URL, se asume que se trata de la accin index().
La configuracin inicial de enrutamiento permite pasar parmetros a tus acciones usando el
URL. Una peticin para /articulos/ver/25 sera equivalente a llamar ver(25) en el ArticulosController,
por ejemplo.
Parmetros con Nombre
Algo novedoso en CakePHP 1.2 es la habilidad de usar parmetros con nombre (named
parameters). Puedes nombrar parmetros y enviar sus valores usando el URL. Una peticin para
/articulos/ver/titulo:primer+articulo/categoria:general resultara en una llmada a la accion view() de
ArticulosController. En dicha accin, puedes encontrar los valores del ttulo y la categora dentro de
$this->passedArgs['titulo'] and $this->passedArgs['categoria'] respectivamente.
Algunos ejemplos que resuman las rutas por defecto puede resultar til.

URL: /monos/saltar
Dirige a: MonosController->saltar();
URL: /productos
Dirige a: ProductosController->index();
URL: /tareas/ver/45
Dirige a: TareasController->ver(45);
URL: /donaciones/ver/recientes/2001
Dirige a: DonacionesController->ver('recientes', '2001');
URL: /contenidos/ver/capitulo:modelos/seccion:asociaciones
Dirige a: ContenidosController->ver();
$this->passedArgs['capitulo'] = 'modelos';
$this->passedArgs['seccion'] = 'asociaciones';

Definir Rutas
Definir tus propias rutas te permite definir cmo va a responder tu aplicacin cuando se solicite
un URL determinado. Tus rutas deben ser definidas en el archivo /app/config/routes.php usando el
mtodo Router::connect().

El mtodo connect() toma hasta tres parmetros: el patron de URL que deseas hacer coindicir,
los valores por defecto para los elementos de enrutamient propios, y expresiones regulares que ayuden
al enrutador a hacer coincidir elementos en el URL.
El formto bsico para una definicin de ruta es:
Router::connect(

'URL',
array('nombreParam' => 'valorPorDefecto'),
array('nombreParam' => 'expresionRegular')

El primer parmetro es usado para decirle al enrutador qu tipo de URL ests tratando de
controlar. El URL es una cadena de caracteres separadas por barras inclinadas (slash), pero tambin
pueden contener el un comodn comodn (*) o elementos de enrutamiento propios (Elementos de URL
prefijados con el caracter dos puntos ":"). Usar un comodn le indica al enrutador qu tipos de URL
quieres hacer coincidir, y especificar elementos de enrutamiento te permite recolectar parmetros para
las acciones de tus controladores
Una vez que hayas especificado un URL, debes utilizar los ltimos dos parmetros del mtodo
connect() para decirle a CakePHP que hacer con esa peticin una vez que ha sido seleccionada la regla
adecuada. El segundo parmetro es una arreglo asociativo. Las claves de este arreglo deben ser
nombradas como los elementos de enrutamiento en el URL, o los elementos por defecto, que son,
:controller, :action y :plugin. Los valores en este arreglo son los valores por omisin para cada una de
las claves. Veamos algunos ehjemplos bsicos antes de empezar a usar el tercer parmetro de connect()
Router::connect(
'/pages/*',
array('controller' => 'pages', 'action' => 'display')
);

Esta ruta se encuentra en el archivo routes.php distribuido con CakePHP (linea 40). Esta ruta
coincide con los URL que comienzan con /pages/ y delega a la accin display() de PagesController el
manejo de la peticin. La peticin /pages/productos puede sera dirigida a PagesController>display('productos'), por ejemplo.
Router::connect(

);

'/mujeres',
array('controller' => 'productos', 'action' => 'mostrar', 5)

Este segundo ejemplo muestra como usar el segundo parmetro de connect() para definir
parmetros por omisin. Si construiste un sitio que muestra productos para diferentes categoras de
clientes, puedes considerar el hacer una ruta. Esto te ayuda a crear el enlace /mujeres en lugar de
/productos/mostrar/5
Para tener flexibilidad adicional, puedes especificar elementos de enrutamiento propios. Hacer
esto te da el poder de definir lugares en el URL donde los parmentros para las acciones deben residir.
Cuando se hace una peticin, los valores para estos elementos propios se encuentran en $this-gt;params
del controlador. Estos son diferentres de los parametros con nombre, y esta es la diferencia: los
parmmetros con nombre (/controlador/accion/nombre:valor) se encuentran en $this->passedArgs,
mientras que los elementos propios de enrutamiento se encuentran en $this->params. Cuando defines
un elemento propio de enrutamiento, tambin necesitas especificar una expresin regular. Esto le indica
a CakePHP cmo reconocer si el URL est bien formado o no.
Router::connect(

);

'/:controller/:id',
array('action' => 'ver'),
array('id' => '[0-9]+')

Este ejemplo sencillo muestra cmo crear una manera sencilla de ver registros desde cualquier
controlador accediendo a un URL que luce como /mincontrolador/id. El URL suministrado a connect()
especifica dos elementos de enrutamiento, :controller e :id, El primer elemento es uno que viene por
defecto con CakePHP, as que el enrutador sabe cmo reconocer nombres de controladores en el URL.
El elemento :id es propio, y debe ser clarificado especificando una expresin regular en el tercer
parmetro de conenct(). Esto le dice a CakePHP cmo reconocer el ID en el URL en contraposicin a
cualquier otra cosa que est all, como el nombre de una accin.
Una vez que hayas definido esta ruta, solicitar /manzanas/5, sera lo mismo que solicitar
/manzanas/ver/5. Ambos harn una llamada al mtodo ver() de ManzanasController. Dentro del mtodo
ver(), podras acceder al id en $this->params['id'].
Un ejemplo ms y sers un profesional del enrutador.
Router::connect(
'/:controller/:year/:month/:day',
array('action' => 'listar', 'day' => null),
array(
'year' => '[12][0-9]{3}',
'month' => '(0[1-9]|1[012])',
'day' => '(0[1-9]|[12][0-9]|3[01])'

)
);

Puede parecer un poco enredado, pero muestra lo poderosas que pueden ser las rutas. El URL
suministrado tiene cuatro elemento. El primero ya debe resultarte familiar: el elemento que le dice a
CakePHP que se trata de un nombre de controlador.
A continuacin, vamos a especificar algunos valores por defecto. Sin importar el controlador,
queremos que la accin listar() sea llamada. Asignamos el parmetro day (da, que es el cuarto
elemento en el URL) a null, para marcarlo como opcional.
Finalmente especificamos algunas expresiones regulares que coindidiran con aos, meses y das
en su forma numrica.
Una vez definda, esta ruta coindcidir con /articulos/2007/02/01, /escritos/2004/11/16 y
/productos/2001/05 (recuerdas que el parametro day era opcional?), enviando la peticin a listar() de
sus respectivos controladores, con los parmetros de fecha definidos en $this->params.
Pasando parmetros a la accin
Asumiendo que tu accin fue definida como se muestra a continuacin, y que desea acceder a
los argumentos usando $articuloID en lugar de $this->params['id'], simplemente agrega
el tercer parmetro de Router::connect().
// some_controller.php
function ver($articuloID = null, $slug = null) {
// mi codigo aqui...
}
// routes.php
Router::connect(
// E.g. /blog/3-CakePHP_Rocks
'/blog/:id-:slug',
array('controller' => 'blog', 'action' => 'ver'),
array(
// el orden importa, puesto que esto enviar ":id" como el parmetro
$articuloID de tu accin.
'pass' => array('id', 'slug'),
'id' => '[0-9]+'
)
)

Y ahora, gracias a las capacidades de enrutamiento inverso, puedes usar el arreglo de url que se
muestra a continuacin y Cake sabr cmo formar el URL tal como fue definido en las rutas.
// ver.ctp

// Esto va a devolver un lik a /blog/3-CakePHP_Rocks


<?php echo $html->link('CakePHP Rocks', array(
'controller' => 'blog',
'action' => 'view',
'id' => 3,
'slug' => Inflector::slug('CakePHP Rocks')
)) ?>

Rutas con prefijos


Muchas cplicaciones requieren una zona administrativa donde los usuarios privilegiados puedan
hacer

cambios.

Estos

es

comunment

hecho

travs

de

un

URL

especial

como

/admin/usuarios/editar/5. En CakePHP, las rutas admin pueden ser habilitadas en el archivo


core.php asignando la ruta para Routing.admin.
Configure::write('Routing.admin', 'admin');

En tu controlador, cualquier accin que empiece por admin_ ser llamada. Usando nuestro
ejemplo de usuarios, el nombre de la accin de nuestro UsuariosController debe ser
admin_editar
Puedes usar el enrutador para usar prefijos propios para usos ms all de la administracin.
Router::connect('/perfiles/:controller/:action', array('prefix' => 'perfiles'));

Cualquier llamada a la seccin de perfiles buscar el prefijo perfiles_ en las llamadas a


mtodos. Nuestro ejemplo de usuarios tendra una estructura de URL que lucira como
/perfiles/usuarios/editar/5, lo cual invocara el mtodo perfiles_editar del
UsuariosController. tambin es importante reordar que usar el Ayudante HTML para construir
tus enlaces te ayudar a mantener los prefijos. Este es un ejemplo de un enlace usando el ayudante
HTML .
echo $html->link('Editar tu perfil', array('controller' => 'usuarios', 'action' =>
'perfiles_editar'));

Puedes utilizar mltiples prefijos de ruta para crar una muy flexible estructura de URL para tu
aplicacin.

3.4.5.1 Enrutamiento por defecto

Antes de que leas como configurar tus rutas, deberas saber que CakePHP incluye algunas por
defecto. El enrutamiento en CakePHP te ofrece mucho ms que cualquier otra aplicacin. Puedes
acceder directamente a cualquier accin ponindola solo en la URL. Puedes enviar tambin variables a
la accin a travs de la URL.
Patrones de enrutamiento por defecto:
http://example.com/controller/action/param1/param2/param3

La URL /posts/view enruta hacia la accion view() del controlador PostsController y


/products/viewClearance enruta hacia la accion view_clearance() del controlador ProductsController. Si
la accin no esta definida en la URL, el mtodo index() es asumido por defecto.
El enrutamiento por defecto te permite enviar parmetros a la accin a travs de la URL. Una
peticin hacia /posts/view/25 sera equivalente a llamar a la accin view(25) en el controlador
PostsController.
3.4.5.2 Passed arguments

Una nueva caracterstica en CakePHP 1.2 es la posibilidad de setear nombres de parmetros y


su valor por la URL. Una peticin a /posts/view/title:first+post/category:general resultara en una
llamada a la accin view() del controlador PostsController. En esta accin, podrs encontrar los valores
para

title

category

dentro

de

$this->passedArgs['title']

$this->passedArgs['category']

respectivamente.
Algunos ejemplos que pueden ser de utilidad.
Acceder a la accin jump() del controlador MonkeysController desde la URL:
URL: /monkeys/jump
Enrutado: MonkeysController->jump();
URL: /products
Enrutado: ProductsController->index();
URL: /tasks/view/45
Enrutado: TasksController->view(45);
URL: /donations/view/recent/2001
Enrutado: DonationsController->view('recent', '2001');
URL: /contents/view/chapter:models/section:associations
Enrutado: ContentsController->view();
$this->passedArgs['chapter'] = 'models';

$this->passedArgs['section'] = 'associations';

3.4.5.4 Defining Routes

Defining your own routes allows you to define how your application will respond to a given
URL.

Define

your

own

routes

in

the

/app/config/routes.php

file

using

the

Router::connect() method.
The connect() method takes up to three parameters: the URL you wish to match, the default
values for your route elements, and regular expression rules to help the router match elements in the
URL.
The basic format for a route definition is:
Router::connect(
'URL',
array('paramName' => 'defaultValue'),
array('paramName' => 'matchingRegex')
)

The first parameter is used to tell the router what sort of URL you're trying to control. The URL
is a normal slash delimited string, but can also contain a wildcard (*) or route elements (variable names
prefixed with a colon). Using a wildcard tells the router what sorts of URLs you want to match, and
specifying route elements allows you to gather parameters for your controller actions.
Once you've specified a URL, you use the last two parameters of connect() to tell CakePHP
what to do with a request once it has been matched. The second parameter is an associative array. The
keys of the array should be named after the route elements in the URL, or the default elements:
:controller, :action, and :plugin. The values in the array are the default values for those keys. Let's look
at some basic examples before we start using the third parameter of connect().
Router::connect(
'/pages/*',
array('controller' => 'pages', 'action' => 'display')
);

This route is found in the routes.php file distributed with CakePHP (line 40). This route matches
any URL starting with /pages/ and hands it to the display() method of the
PagesController();

The

request

/pages/products

PagesController->display('products'), for example.

would

be

mapped

to

Router::connect(
'/government',
array('controller' => 'products', 'action' => 'display', 5)
);

This second example shows how you can use the second parameter of connect() to define
default parameters. If you built a site that features products for different categories of customers, you
might consider creating a route. This allows you link to /government rather than
/products/display/5.
Another common use for the Router is to define an "alias" for a controller. Let's say that instead
of accessing our regular URL at /users/someAction/5, we'd like to be able to access it by
/cooks/someAction/5. The following route easily takes care of that:
Router::connect(
);

'/cooks/:action/*', array('controller' => 'users', 'action' => 'index')

This is telling the Router that any url beginning with /cooks/ should be sent to the users controller.
When generating urls, routes are used too. Using array('controller' => 'users',
'action' => 'someAction', 5) as a url will output /cooks/someAction/5 if the above
route is the first match found.
If you are planning to use custom named arguments with your route, you have to make the
router aware of it using the Router::connectNamed function. So if you want the above route to
match urls like /cooks/someAction/type:chef we do:
Router::connectNamed(array('type'));
Router::connect(
'/cooks/:action/*', array('controller' => 'users', 'action' => 'index')
);

Router::connectNamed(array('type'));
1. Router::connect(
2. '/cooks/:action/*', array('controller' => 'users', 'action' =>
'index')
3. );
You can specify your own route elements, doing so gives you the power to define places in the
URL where parameters for controller actions should lie. When a request is made, the values for these
route elements are found in $this->params of the controller. This is different than named parameters are
handled, so note the difference: named parameters (/controller/action/name:value) are found in $this-

>passedArgs, whereas custom route element data is found in $this->params. When you define a custom
route element, you also need to specify a regular expression - this tells CakePHP how to know if the
URL is correctly formed or not.
Router::connect(

);

'/:controller/:id',
array('action' => 'view'),
array('id' => '[0-9]+')

This simple example illustrates how to create a quick way to view models from any controller
by crafting a URL that looks like /controllername/id. The URL provided to connect() specifies two
route elements: :controller and :id. The :controller element is a CakePHP default route element, so the
router knows how to match and identify controller names in URLs. The :id element is a custom route
element, and must be further clarified by specifying a matching regular expression in the third
parameter of connect(). This tells CakePHP how to recognize the ID in the URL as opposed to
something else, such as an action name.
Once this route has been defined, requesting /apples/5 is the same as requesting /apples/view/5.
Both would call the view() method of the ApplesController. Inside the view() method, you would need
to access the passed ID at $this->params['id'].
One more example, and you'll be a routing pro.
Router::connect(
'/:controller/:year/:month/:day',
array('action' => 'index', 'day' => null),
array(
'year' => '[12][0-9]{3}',
'month' => '0[1-9]|1[012]',
'day' => '0[1-9]|[12][0-9]|3[01]'
)
);

This is rather involved, but shows how powerful routes can really become. The URL supplied
has four route elements. The first is familiar to us: it's a default route element that tells CakePHP to
expect a controller name.
Next, we specify some default values. Regardless of the controller, we want the index() action
to be called. We set the day parameter (the fourth element in the URL) to null to flag it as being
optional.
Finally, we specify some regular expressions that will match years, months and days in

numerical form. Note that parenthesis (grouping) are not supported in the regular expressions. You can
still specify alternates, as above, but not grouped with parenthesis.
Once

defined,

this

route

will

match

/articles/2007/02/01,

/posts/2004/11/16,

and

/products/2001/05 (as defined, the day parameter is optional as it has a default), handing the requests to
the index() actions of their respective controllers, with the date parameters in $this->params.
3.4.5.5 Pasando parmetros a las acciones

Asumiendo que tu action fue definida as y quieres acceder los argumentos usando
$articleID en vez de $this->params['id'], tan solo agrega un array extra en el 3er
parmetro de Router::connect().
// some_controller.php
function view($articleID = null, $slug = null) {
// some code here...
}
// routes.php
Router::connect(
// E.g. /blog/3-CakePHP_Rocks
'/blog/:id-:slug',
array('controller' => 'blog', 'action' => 'view'),
array(
// el orden es importante ya que esto va a mapear ":id" con $articleID en tu
action
'pass' => array('id', 'slug'),
'id' => '[0-9]+'
)
);

Y ahora, gracias a la capacidad de enrutamiento inverso podrs pasar la url como se muestra
abajo y Cake sabr como formar la URL como se defini en los routers.
// view.ctp
// esto devolver un link a /blog/3-CakePHP_Rocks
<?php echo $html->link('CakePHP Rocks', array(
'controller' => 'blog',
'action' => 'view',
'id' => 3,
'slug' => Inflector::slug('CakePHP Rocks')
)); ?>

3.4.5.6 Prefix Routing

Muchas aplicaciones necesitan una seccin administrativa donde los usuarios con privilegios
puedan

hacer

cambios.

Con

frecuencia,

esto

se

hace

con

una

URL especial

como

/admin/users/edit/5. En CakePHP, el admin routing puede activarse dentro del archivo de


configuracin del core ajustando la ruta de administracin para Routing.admin.
Configure::write('Routing.admin', 'admin');
En tu controlador, ser llamada cualquier accin con un prefijo admin_. Recurriendo a nuestro
ejemplo de usuarios, acceder a la URL /admin/users/edit/5 debera llamar al mtodo
admin_edit de nuestro UsersController pasando 5 como primer parmetro.
Puedes mapear la URL /admin a tu accin admin_index del pages controller usando la
ruta.
Router::connect('/admin',

array('controller'

=>

'pages',

'action'

=>

'index',

'admin' => true));

Puedes configurar el Router usado mltiples prefijos:


Router::connect('/profiles/:controller/:action/*',

array('prefix'

=>

'profiles',

'profiles' => true));

Cualquier llamada a la seccin Profiles buscara el prefijo profiles_ en las llamadas a los
mtodos. Nuestro ejemplo tendra una URL como /profiles/users/edit/5 que llamara al
mtodo profiles_edit en el UsersController. Es tambin importante recordar que usar el
HTML helper para construir tus enlaces, te ayudar a mantener las llamadas a los prefijos. He aqu
cmo construir este enlace usando el HTML helper:
echo $html->link('Edit your profile', array('profiles' => true, 'controller' =>
'users', 'action' => 'edit', 'id' => 5));

Puedes ajustar mltiples rutas con prefijos usando esta metodologa para crear una estructura de URL
flexible para tu aplicacin.

3.4.5.7 Rutas y plugins

Las rutas a Plugins utilizan la clave plugin. Puedes crear enlaces que apunten a un plugin
siempre que aadas la clave plugin al array de la url.

echo

$html->link('New

todo',

array('plugin'

=>

'todo',

'controller'

=>

'todo_items', 'action' => 'create'));

Por el contrario, si la peticin activa es un plugin y quieres crear un enlace que no tiene plugin,
puedes hacerlo como sigue.
echo

$html->link('New

todo',

array('plugin'

=>

null,

'controller'

=>

'users',

'action' => 'profile'));

Al poner plugin => null le ests diciendo al Router que quieres crear un enlace que no forma
parte de un plugin.
3.4.5.8 Extensiones de archivo

Para manejar diferentes extensiones de archivo con tus rutas, necesitas una lnea extra en el
archivo de configuracin de rutas:
Router::parseExtensions('html', 'rss');

Esto le dir al router que retire las extensiones de archivo coincidentes y que procese entonces
el resto..
Si quieres crear una url como /page/title-of-page.html podras crear tu ruta como se explica a
continuacin:
Router::connect(

);

'/page/:title',
array('controller' => 'pages', 'action' => 'view'),
array(
'pass' => array('title')
)

Para crear enlaces que se mapeen a esas rutas simplemente usamos:


$html->link('Link

title',

array('controller'

=>

'pages',

'action'

=>

'view',

'title' => Inflector::slug('text to slug', '-'), 'ext' => 'html'))

3.4.5.9 Custom Route classes

Custom route classes allow you to extend and change how individual routes parse requests and
handle reverse routing. A route class should extend CakeRoute and implement one or both of
match() and parse(). Parse is used to parse requests and match is used to handle reverse routing.

You can use a custom route class when making a route by using the routeClass option, and
loading the file containing your route before trying to use it.
Router::connect(
'/:slug',
array('controller' => 'posts', 'action' => 'view'),
array('routeClass' => 'SlugRoute')
);

This route would create an instance of SlugRoute and allow you to implement custom
parameter handling
3.4.6 Inflexiones Propias
Las convenciones de nomenclatura de CakePHP pueden ser muy buenas. Nombras la tabla de
base de datos "usuarios", tu modelo "Usuario", tu controlador "UsuariosController" y todo funcionar
automticamente. La forma en que CakePHP sabe como atar unas cosas a otras es a travs de las
inflexiones de palabras entre formas en singular y plural.
Hay ocasiones, sobre todo para usuarios de habla hispana, en que encontrars situaciones donde
el inflector de CakePHP no funcione como lo esperas. Si CakePHP no es capaz de reconocer tu Reloj o
Ciudad, editar el archivo de inflexiones propias es la manera de indicarle a CakePHP que existen otros
casos especiales. Este archivo se encuentra en /app/config/inflections.php.
En este archivo encontrars seis variables. Cada una de ellas te permite definir a un grado muy
fino el comportamiento de inflexiones de CakePHP.
Variable de
inflections.php

Descripcin

$pluralRules

Este arreglo contienen las expresiones regulares para pluralizar los casos
especiales. Las claves del arreglo son los patrones y los valores los
reemplazos.

$uninflectedPlural

Un arreglo que contiene palabras que no han de ser modificadas para


obtener su plural, como la palabra gente o dinero.

$irregularPlural

Un arreglo que contiene palabras y su respectivo plural. Las claves de este


arreglo contienen la forma singular y los valores la forma plural. Este
arreglo debe ser utilizado para colocar palabras que no sigan las reglas
definidas en $pluralRules.

$singularRules

Igual que $pluralRules, solo que contiene las reglas para singularizar
palabras.

$uninflectedSingular

Igual que $uninflectedPlural, solo que este arreglo contiene las palabras
que no tienen singular. Por defecto es igual que $uninflectedPlural.

Variable de
inflections.php

Descripcin

$irregularSingular

Igual que $irregularPlural, solo que con palabras en forma singular.

3.4.7 Haciendo Bootstrap de CakePHP


Si tienes necesidades de configuracin adicionales, usa el archivo de bootstrap de CakePHP que
se encuentra en /app/config/bootstrap.php. Este archivo es ejecutado inmediatamente despus de el
bootstrap propio de CakePHP.
Este archivo es ideal para un nmero de tareas comunes:
Definir funciones de conveniencia
Definir constantes globales
Definir rutas adicionales para modelos, controladores, vistas, plugins...
S cuidadoso de mantener el patrn de diseo MVC cuando agregues cosas al archivo
bootstrap, puede resultar tentador colocar funciones para dar formato a texto all para luego usarlas en
controladores.
Resiste la tentacin. Te lo agradecers ms adelante a ti mismo.
Podras considerar colocar cosas en la clase AppController. Esta clase en poder de todos los
controladores de la aplicacin. AppController es til para colocar funciones que se ejecutan antes o
despus de eventos definidos (callbacks), que sern usados en todos tus controladores.

3.5 Controladores
# Introduccin
Un controlador (Controller) se usa para manejar la lgica de cierta seccin de su aplicacin.
Comnmente, los controladores (Controllers) son usados para manejar la lgica de un solo modelo
(Model). Por ejemplo, si ests construyendo un sitio de una pastelera, podras tener un
RecetasController y un IngredientesController para manejar las recetas y sus ingredientes. En
CakePHP, los controladores se nombran segn el modelo que manejan, y se ponen siempre en plural.
El modelo Receta es manejado por el RecetasController, el modelo Producto es manejado por el
ProductosController, y as sucesivamente.
Los controladores de su aplicacin son sub-clases de la clase AppController de CakePHP, que a
su vez extiende la clase principal Controller. La clase AppController puede ser definida en
/app/app_controller.php y debe contener mtodos que son compartidos entre todos los controladores de
su aplicacin. AppController es una sub-clase de Controller que es una clase de la biblioteca estndar
de Cake.
Los controladores pueden tener cualquier cantidad de mtodos a los que normalmente se les
llama acciones. Las acciones son mtodos de controladores en tu aplicacin web para mostrar vistas.
Una accin es un nico mtodo de un controlador. El Dispatcher de CakePHP ejecuta acciones cuando
una solicitud entrante contiene en su URL el nombre de una accin del controlador. El controlador
estara ubicado en /app/controllers/recetas_controller.php con el siguiente contenido:
<?php
# /app/controllers/recetas_controller.php
class RecetasController extends AppController {
function ver($id)
{
//la lgica de la accin va aqui...
}
function compartir($cliente_id, $receta_id) {
//la lgica de la accin va aqui...
}
function buscar($query) {
//la lgica de la accin va aqui...
}
}
?>

Para que puedas usar un controlador de manera productiva en tu propia aplicacin, repasaremos
algunos de los atributos y mtodos provistos por los controladores de CakePHP.
3.5.1 The App Controller
Como se coment en la introduccin, la clase AppController es la clase superior a todos los
controladores de tu aplicacin. AppController extiende la clase Controller incluida en la libreria base de
CakePHP. As, AppController es definida en /app/app_controller.php como:
<?php
class AppController extends Controller {
}
?>

Las propiedades y mtodos creados en tu AppController estarn disponibles para todos los
controladores de tu aplicacin. Es el sitio ideal para poner el cdigo que ser comn a todos los
controladpres de tu aplicacin. Los Componentes (los cuales veremos despus) son lo ms utilizado
para el cdigo que se utiliza en la mayora (pero no necesariamente en todos) los controladores.
Cuando se aplica la herencia a los objetos, CakePHP tambin realiza un trabajo extra cuando
existen atributos especiales en el controlador, como una lista de componentes o ayudantes utilizados
por un controlador. En estos casos, los arrays del AppControler son combinados con los arrays de la
clase hijo.
Por favor, recuerda realizar las llamadas a los callbacks de AppController desde los
controladores de tu aplicacin para que todo funcione correctamente:
function beforeFilter(){
parent::beforeFilter();
}

3.5.2 The Pages Controller


El ncleo de CakePHP viene con un controlador por defecto llamado the Pages Controller (el
Controlador de Pginas) (cake/libs/controller/pages_controller.php). La pgina de
inicio que ves luego de la instalacin, es generada utilizando este controlador. Por ejemplo: S creas un
archivo de vista app/views/pages/about_us.ctp puedes accesarlo utilizando la url
http://example.com/pages/about_us
Cuando "cocinas" una aplicacin utilizando la consola de CakePHP el controlador de
pginas es copiado a tu carpeta app/controllers/ y puedes modificarla a tus necesidades si es

necesario. O simplemente puedes copiar el archivo page_controller.php del ncleo a tu app.


3.5.3 Atributos del Controlador
Para

ver

la

lista

completa

de atributos

visite

la API

de CakePHP en

la

seccin

http://api.cakephp.org/class/controller.
3.5.3.1 $name

Los usuarios de PHP4 deberan empezar la definicin de sus controladores con el atributo
$name. Este atributo debera ser asignado con el nombre del controlador. Usualmente este es
simplemente el plural del modelo principal al que el controlador est asociado. Esto previene algunos
problemas de distincin de maysculas que tiene PHP4 para los nombres de las clases.
<?php
#

$name Ejemplo de uso del atributo $name

class RecetasController extends AppController {


var $name = 'Recetas';
}
?>

3.5.3.2 $components, $helpers y $uses

Los siguientes atributos ms comunmente utilizados del controlador indican a CakePHP qu


ayudantes (helpers), componentes (components), y modelos (models) utilizars en conjuncin con el
controlador actual. Utilizar esos atributos hace que las clases MVC estn disponibles al controlador
como variable de clase($this->ModelName, por ejemplo).
Los controladores tienen acceso a su modelo primario disponible por defecto. Nuestro
RecipesController tendr disponible la clase modelo Recipe en $this->Recipe, y nuestro
ProductsController tambin posee el modelo Product en $this->Product.
Los ayudantes (Helpers) Html, Form, y Session estn siempre disponibles por defecto, como lo
es SessionComponent. Para aprender ms sobre estas clases, no olvides leer sus respectivas secciones
ms adelante en este manual.
Veamos cmo decirle a un controlador de CakePHP que planeas utilizar clases MVC
adicionales.

<?php
class RecipesController extends AppController {
var $name = 'Recipes';
var $uses = array('Recipe', 'User');
var $helpers = array('Ajax');
var $components = array('Email');
}
?>

Cada una de estas variables es fusionada con sus valores heredados, por lo tanto no es necesario
(por ejemplo) declarar le ayudante (helper) Form, o cualquier cosa que es declarada en tu controlador
App.
3.5.3.3 Atributos Relacionados con la Pgina: "$layout" y "$pageTitle"

Existen unos pocos atributos en los controladores de CakePHP que te dan control sobre cmo se
colocan tus vistas (views) dentro del diseo (layout).
Al atributo $layout se le puede asignar el nombre de un diseo (layout) guardado en
/app/views/layouts. Especificas un diseo al igualar $layout al nombre del archivo con el
diseo excluyendo la extensin .ctp. Si este atributo no ha sido definido, CakePHP renderiza el
diseo

por

defecto,

default.ctp.

Si

no

has

definido

un

diseo

en

/app/views/layouts/default.ctp, el diseo por defecto del ncleo de CakePHPs ser


renderizado.
<?php
//

Usando <em>$layout</em> para definir un diseo alternativo

class RecipesController extends AppController {


function quickSave() {
$this->layout = 'ajax';
}
}
?>

Tambin puedes cambiar el ttulo de la pgina (que est localizado en la barra en la parte
superior de tu navegador) utilizando $pageTitle. Para que esto funcione apropiadamente, tu diseo
(layout) necesita incluir la variable $title_for_layout como mnimo entre las etiquetas <title> y
</title> en la cabecera del documento HTML.
<?php

//

Usando <em>$pageTitle</em> para definir el ttulo de la pgina

class RecipesController extends AppController {


function quickSave() {
$this->pageTitle = 'Mi ttulo del motor de bsquedas optimizado';
}
}
?>

Tambin puedes establecer el ttulo desde la vista (view) usando $this->pageTitle (Has
de incluir la parte $this->; se recomienda, ya que separa la lgica del diseo y el contenido). Para
una pgina esttica has de usar $this->pageTitle en la vista si quieres un ttulo personalizado.
Si $this->pageTitle no est establecido, se generar automticamente un ttulo basado en
el nombre del controlador, o el nombre del fichero de la vista en el caso de una pgina esttica.
3.5.3.4 El Atributo de Parmetros ("$params")

Los parmetros del controlador estn disponibles en $this->params en tu controlador de


CakePHP. Esta variables es usada para proporcionar acceso a la informacin sobre la peticin actual. El
uso ms comn de $this->params es obtener acceso a informacin que ha sido entregada al
controlador a travs de las operaciones POST o GET.
3.5.3.4.1 form

$this->params['form']
Cualquier dato POST de cualquier formulario se almacena aqu, incluyendo informacin
tambin hallada en $_FILES.
3.5.3.4.2 admin

$this->params['admin']
Almacena un 1 si el diseo (layout) actual est vaco; 0 si no.
3.5.3.4.4 isAjax

$this->params['ajax']
Almacena un 1 si la peticin actual es una llamada ajax; 0 si no. Esta variables slo se establece
si el componente RequestHandler es usado en el controlador.

3.5.3.4.5 controller

$this->params['controller']
Almacena el nombre del controlador actual que est sirviendo la peticin. Por ejemplo, si fue
pedida la URL /posts/view/1, $this->params['controller'] ser igual a "posts".
3.5.3.4.6 action

$this->params['action']
3.5.3.4.7 pass

$this->params['pass']
Almacena la cadena de consulta GET enviada con la peticin actual. Por ejemplo, si fue pedida
la URL /posts/view/?var1=3&var2=4, entonces $this->params['pass'] ser igual a
"?var1=3&var2=4".
3.5.3.4.8 url

$this->params['url']
Almacena la URL actual pedida, junto con los pares clave-valor de variables get. Por ejemplo, si se
llam a la URL /posts/view/?var1=3&var2=4, entonces $this->params['url'] debera
contener:
[url] => Array
(
[url] => posts/view
[var1] => 3
[var2] => 4
)

3.5.3.4.9 data

$this->data
Usado para manejar datos POST enviados desde los formularios de FormHelper al
controlador.
// El helper FormHelper es usado para crear un elemento de formulario:
$form->text('User.first_name');

El cual al ser renderizado, se ve parecido a:


<input name="data[User][first_name]" value="" type="text" />

Cuando el formulario es enviado al controlador mediante POST, los datos aparecen en this->data
// El valor first_name enviado se puede encontrar aqu:
$this->data['User']['first_name'];

3.5.3.4.10 prefix

$this->params['prefix']
Establecido al prefijo de enrutado. Por ejemplo, este atributo contendra la cadena "admin"
durante una peticin a /admin/posts/someaction.
3.5.3.4.11 named

$this->params['named']
Almacena cualquier parmetro con nombre /clave:valor/ de la cadena de peticin de la
URL. Por ejemplo, si se pidi la URL /posts/view/var1:3/var2:4, entonces $this>params['named'] debera contener el array:
[named] => Array
(
[var1] => 3
[var2] => 4
)

3.5.3.5 Otros Atributos

Aunque puedes ojear todos los detalles para todos los atributos del controlador en el API, hay
otros atributos del controlador que merecen sus propias secciones en el manual.
El atributo $cacheAction ayuda en el "cacheado" (caching) de vistas (views), y el atributo
$paginate es usado para establecer las opciones por defecto de paginado para el controlador. Para
ms informacin sobre cmo utilizar esos atributos, cha un vistazo a sus respectivas secciones ms
adelante en este manual.

3.5.3.6 persistModel

Usado para crear instancias almacenadas en cach de modelos (Models) un uso de Controlador
(Controller). Cuando se coloca en verdadero (true), todos los modelos relacionados con el controlador
(Controller) se almacenan en cach. Esto puede incrementar el desempeo en muchos casos.

3.5.4 Mtodos del Controlador


Para una lista completa de los mtodos del controlador y sus descripciones visita el API de
CakePHP. Echa un vistazo a http://api.cakephp.org/1.2/class_controller.html.
3.5.4.1 Interactuando con Vistas
3.5.4.1.1 set

set(string $variable, mixed $valor)


El mtodo set() es la principal manera de enviar datos desde tu controlador a tu vista (view).
Una vez que has utilizado set(), la variable puede ser accedida en tu vista.
<?php
// Primero pasas datos desde el controlador:
$this->set('color', 'azul');
// Despue, en las vista, puedes utilizar el dato:
?>
Has seleccionado <?php echo $color; ?>ar la tarta.

El mtodo set() tambin toma una array asociativo como primer parmetro. A menudo, esto
puede ser una manera rpida de asignar un conjunto de informacin a la vista.
Las claves (keys) sern flexionadas (inflected) antes de ser asignadas a la vista
('clave_con_subrayado' se convierte en 'claveConSubrayado', etc.):
<?php
$data = array(
'color' => 'pink',
'type' => 'sugar',
'base_price' => 23.95
);
// hace que $color, $type, y $basePrice
// estn disponibles a la vista:
$this->set($data);
?>

3.5.4.1.2 render

render(string $action, string $layout, string $file)

El mtodo render() es llamado automticamente al final de cada accin de controlador


pedida. Este mtodo lleva a cabo toda la lgica de la vista (usando los datos que has proporcionado con
el mtodo set()), coloca la vista (view) dentro de su diseo (layout) y lo sirve de vuelta al usuario
final.
El fichero de vista por defecto utilizado por render es determinado por convenio. Por
ejemplo, si se pide la accin search() del controlador RecipesController, ser renderizado el
fichero de vista en /app/views/recipes/search.ctp.
class RecipesController extends AppController {
function search() {
// Render the view in /views/recipes/search.ctp
$this->render();
}
...
}

A pesar de que CakePHP lo llamar automticamente (a menos que hayas establecido $this>autoRender a falso) despus de cada lgica de las acciones, puedes utilizar render para
especificar un fichero de vista alternativo indicando un nombre de accin en el controlador usando
$action.
Si $action comienza por '/' se asume que es un fichero de vista o elemento relativo a la
carpeta /app/views. Esto permite el renderizado inmediato de elementos, algo muy til en las
llamadas ajax.
// Render the element in /views/elements/ajaxreturn.ctp
$this->render('/elements/ajaxreturn');

Tambin puedes especificar un fichero de vista alternativo usando el tercer parmetro, $file.
Cuando ests usando $file, no olvides utilizar unas pocas de las constantes globales de CakePHP
(como VIEWS).
El parmetro $layout te permite especificar el diseo en el que la vista es renderizada.
3.5.4.2 Control de Flujo
3.5.4.2.1 redirect

redirect(string $url, integer $status, boolean $exit)


El mtodo de control de flujo que ms frecuentemente utilizars es redirect(). Este mtodo

toma su primer parmetro en forma de URL relativa de CakePHP. Por ejemplo, cuando un usuario ha
hecho un pedido satisfactoriamente, probablemente desears redirigirle a una ventana de recibo.
function realizarPedidos() {
// La lgina para finalizar el pedido va aqu
if($satisfactorio) {
$this->redirect(array('controller' => 'pedidos', 'action' => 'gracias'));
} else {
$this->redirect(array('controller' => 'pedidos', 'action' =>
'confirmar'));
}
}

El segundo parmetro de redirect() te permite definir un cdigo de estado HTTP que


acompae la redireccin. Puede que desees usar 301 (movido permanentemente) o 303 (mirar otro),
dependiendo de la naturaleza de la redireccin.
El metodo ejecutar exit() tras la redireccin a menos que establezcas el tercer parmetro a
false.
3.5.4.2.2 flash

flash(string $message, string $url, integer $pause)


Igualmente, el mtodo flash() es usado para redirigir un usuario a una nueva pgina tras una
operacin. El mtodo flash() es diferente en cuanto que muestra un mensaje antes de enviar al
usuario a otra URL.
El primer parmetro debera contener el mensaje a mostrar, y el segundo parmetro es una URL
relativa a CakePHP. CakePHP mostrar el mensaje en $message durante el nmero de segundos en
$pause antes de reenviar al usuario a otra pgina.
Para mensajes flash en la pgina, cercinate de echarle un ojo al mtodo setFlash() del
componente SessionComponent.
3.5.4.3 Retrollamadas ("Callbacks")

Los controladores de CakePHP vienen con retrollamas (callbacks) empotradas que puedes usar
para insertar lgica justo antes o despus de que las acciones del controlador sean llevadas a cabo.
beforeFilter()
Esta funcin se ejecuta antes de toda accin en el controlador. Es un lugar prctico para

comprobar una sesin activa o inspeccionar los permisos del usuario.


beforeRender()
Llamada tras la lgica de accin del controlador, pero antes de que la vista es renderizada. Este
callback no es utilizado a menudo, pero puedes necesitarlo si ests llamando a render()
manualmente antes del final de una accin dada.
afterFilter()
Llamada tras toda accin del controlador.
afterRender()
Llamada tras haber sido renderizada una accin.

CakePHP tambin soporta callbacks relacionados con el scaffolding.


_beforeScaffold($metodo)
$metodo es el nombre del mtodo llamado, por ejemplo: index, edit, etc.
_afterScaffoldSave($metodo)
$metodo es el nombre del mtodo llamado tras edit o update.
_afterScaffoldSaveError($metodo)
$metodo es el nombre del mtodo llamado tras edit o update.
_scaffoldError($metodo)
$metodo es el nombre del mtodo llamado, por ejemplo: index, edit, etc.
3.5.4.4 Otros Mtodos tiles
3.5.4.4.1 constructClasses

Este mtodo carga los modelos requeridos por el controlador. El proceso de carga es realizado
por CakePHP normalmente, pero hay que tener a mano este mtodo cuando se accede a los
controladores desde una perspectiva diferente. Si necesitas CakePHP en un script de lnea de comando
o algn otro uso externo, constructClasses() ser til.

3.5.4.4.2 referer

Devuelve la URL remitente de la peticin actual. Ver referer en la wikipedia para ms


informacin.
3.5.4.4.3 disableCache

3.5.4.4.4 postConditions

postConditions(array $datos, mixed $operadores, string $bool, boolean $exclusivo)


Usa este mtodo para convertir un conjunto de datos de modelo recibidor mediante POST (de
inputs compatibles con HtmlHelper) en un conjunto de condiciones de bsqueda para un modelo.
Esta funcin ofrece un atajo rpido para la construccin de la lgica de bqueda. Por ejemplo, un
usuario administrativo puede querer buscar pedidos para saber qu elementos necesitan ser enviados.
Puedes utilizar los ayudantes FormHelper y HtmlHelper para crear un formulario rpido basado
en el modelo Pedido. Entonces, una accin de un controlador puede usar los datos recibidos desde ese
formulario para encauzar las condiciones de bsqueda:
function index() {
$o = $this->Pedidos->findAll($this->postConditions($this->data));
$this->set('pedidos', $o);
}

Si $this->data[Pedido][destino] es igual a Old Towne Bakery, postConditions convierte


esa condicin en un array compatible para ser usado en un mtodo Model->findAll(). En este
caso, array(pedido.destino => Old Towne Bakery).
Si deseas usar un operador SQL distinto entre trminos, proporcinalos usando el segundo
parmetro.
/*
contenidos de $this->data
array(
'Pedido' => array(
'num_items' => '4',
'referrer' => 'Ye Olde'
)
)
*/
//Obtengamos los pedidos que tiene como mnimo 4 elementos y contienen Ye Olde
$o = $this->Pedido->findAll($this->postConditions(
$this->data,
array('>=', 'LIKE')
));

La clave al especificar operadores es el orden de las columnas en el array $this->data.


Dado que num_items est de primero, el operador >= es el que se le aplica.
El tercer parmetro te permite decirle a CakePHP qu operador booleano SQL usar entre
condiciones de bsqueda. Una cadena de carateres como AND, OR y XOR son valores vlidos.
Finalmente, si el ltimo parmetro se establece a true, y el parmetro $operadores es un
array, los campos no incluidos en $operadores no se incluirn en las condiciones devueltas.
3.5.4.4.5 paginate

Este mtodo es usado para paginar resultados cargados por tus modelos. Puedes especificar
tamao de pginas, condiciones de bsqueda del modelo y ms. Mira la seccin paginacin para ms
detalles sobre cmo usar paginate.
3.5.4.4.6 requestAction

requestAction(string $url, array $opciones)


Esta funcin llama a una accin de un controlador de cualquier lugar y devuelve los datos de la
accin.

La

direccin

$url

pasada

es

una

URL

relativa

de

CakePHP

(/nombrecontrolador/nombreaccion/parametros). Para pasar datos extras a la accin


del controladores receptor, adelos al array $options.
Puedes usar requestAction() para obtener una vista completamente renderizada pasando
'return' en las opciones: requestAction($url, array('return'));
Si se utiliza sin cach, requestAction puede llevar a un pobre rendimiento. Es rramente
apropiado usarlo en un controlador o modelo.
Es mejor usar requestAction junto con elementos en cach, como una manera de obtener
datos para un elemento antes de renderizar. Usemos el ejemplo de poner un elemento "ltimos
comentarios" en el diseo (layout). Primero necesitamos crear una funcin en un controlador que
devolver los datos.
// controllers/comments_controller.php
class CommentsController extends AppController {
function latest() {
return $this->Comment->find('all',
array(
'order' => 'Comment.created DESC',
'limit' => 10)
);
}

Si ahora creamos un elemento simple para llamar a esa funcin:


// views/elements/latest_comments.ctp
$comments = $this->requestAction('/comments/latest');
foreach($comments as $comment) {
echo $comment['Comment']['title'];
}

Podemos colocar esos elementos en cualquier sitio para obtener la salida usando:
echo $this->element('latest_comments');

Escrito de esta manera, siempre que el elemento sea renderizado, se realizar una peticin al
controlador para obtener los datos, los datos sern procesados y devueltos. De todos modos, de acuerdo
con el aviso anterior, es mejor utilizar cach de elementos para prevenir procesamiento innecesario.
Modificando la llamada a element para que se vea as:
echo $this->element('latest_comments', array('cache'=>'+1 hour'));

La llamada a requestAction no se realizar mientras que la el archivo de la vista del


elemento en cache exista y sea vlido.
Adems, requestAction ahora toma urls con estilo cake basadas en arrays:
echo $this->requestAction(
array(
'controller' => 'articles',
'action' => 'featured'
),
array('return')
);

Esto permite a la llamada a requestAction evitar el uso de Router::url lo que puede


incrementar el rendimiento. Las urls basadas en arrays son las mismas que las que
HtmlHelper:link usa, con una diferencia. Si ests usando parmetros con nombre en tu url,
entonces el array de url debe envolver los parmetros con nombre en la clave 'named'. Esto es porque
requestAction slo combina los argumentos nombrados del array en el array de miembros de
Controller::params y no coloca los argumentos con nombre en la clave 'named'.
echo $this->requestAction('/articles/featured/limit:3');

Este, como array en requestAction debera ser:


echo $this->requestAction(
array(
'controller' => 'articles',
'action' => 'featured',
'named' => array(
'limit' => 3
)
)
);

A diferencia de otros lugares donde las urls de arrays son anlogas a urls de cadenas,
requestAction las trata de manera diferente.
Cuando utilices una url de array junto con requestAction() has de especificar todos los
parmetros que necesitars en la accin pedida. Esto incluye parmetros como $this->data y
$this->params['form']
3.5.4.4.7 loadModel

loadModel(string $modelClass, mixed $id)


La funcin loadModel es til cuando se necesita usar un modelo que no es propiamente el
modelo por defecto del controlador o uno de sus modelos asociados.
$this->loadModel('Article');
$recentArticles

$this->Article->find('all',

'Article.created DESC'));
$this->loadModel('User', 2);
$user = $this->User->read();

array('limit'

=>

5,

'order'

=>

3.6 Componentes
# Introduccin
Los componentes son paquetes de lgica que son compartidos entre los controladores. Si tiene
ganas de copiar y pegar cdigo de un controlador a otro, debera antes considerar agrupar algunas
funcionalidades en un componente.
CakePHP incluye un conjunto fantstico de componentes listos para usar para conseguir ayuda con:
Seguridad
Sesiones
Lista de control de acceso (ACL)
Emails
Cookies
Autenticacin
Manejo de pedidos (Requests)
Cada uno de estos componentes del ncleo (Core) son detallados en su propio capitulo. Por el
momento, veremos como crear sus propios componentes. Con esto ayudar a mantener el cdigo de los
controladores limpio y le ser mas sencillo reusar cdigo entre proyectos.
3.6.1 Configuracin de componentes.
Muchos de los componentes bsicos requieren ser configurados. Algunos ejemplos de
componentes que requieren ser configurados son: Auth, Cookie e Email. Toda la configuracin de estos
componentes y los componentes en general se hacen en el mtodo del controlador
beforeFilter().
function beforeFilter() {
$this->Auth->authorize = 'controller';
$this->Auth->loginAction = array('controller' => 'users', 'action' =>
'login');
}

$this->Cookie->name = 'CookieMonster';

El cdigo anterior sera un ejemplo de configuracin de las variables de componente del


controlador beforeFilter()

3.6.2 Creando Componentes a medida


Supongamos que nuestra aplicacin online necesita efectuar una compleja operacin
matemtica en muchas partes de la aplicacin. Creariamos un componente que albergara esa lgica
compartida para poder ser usada en diferentes controladores
El primer paso es crear una nueva clase y fichero de componente. Crea el fichero en
/app/controllers/components/math.php. La estructura bsica para el componente quedara as.
<?php
class MathComponent extends Object {
function doComplexOperation($amount1, $amount2) {
return $amount1 + $amount2;
}
}
?>

3.6.2.1 Aadiendo Componentes a tus Controladores

Una vez finalizado nuestro componente, podemos usarlo en los controladores de la aplicacin
aadiendo su nombre (excepto la parte "Component" al array $components del controlador.
Automticamente, el controlador recibir un nuevo atributo con un nombre a partir del nombre del
componente, a travs del cual podremos acceder a una instancia del mismo:
/* Hace el nuevo componente accesible en $this->Math,
al igual que el standard $this->Session */
var $components = array('Math', 'Session');

Los componentes declarados en AppController sern combinados con los de tus otros
controladores, as que no hay necesidad de redeclarar el mismo componente dos veces.
Cuando se incluyen Componentes a un Controlador tambien puedes declarar un conjunto de
parmetros que sern pasados al mtodo intialize() de los Componentes. Estos parmetros pueden ser
manejados por el Componente.
var $components = array(
'Math' => array(
'precision' => 2,
'randomGenerator' => 'srand'
),
'Session', 'Auth'
);

Este cdigo pasara el array conteniendo precision y randomGenerator al mtodo intialize() de

MathComponent como segundo parmetro.


Por ahora, esta sintaxis no est implementada por ninguno de los Componentes Core.
3.6.2.2 Acceso a clases MVC dentro de componentes

Para acceder a la instancia del controlador desde tu recien creado componente, necesitars
implementar el mtodo initialize() o el startup(). Estos mtodos especiales llevan una referencia al
controlador como primer parmetro y son llamados automticamente. El mtodo initialize() es llamado
antes del mtodo beforeFilter(), y el mtodo startup() despus del mtodo beforeFilter. Si por algn
motivo no deseas que el mtodo startup() sea llamado cuando el controlador est inicializando cosas,
dale el valor true a la variable $disableStartup.
Si deseas insertar algn cdigo de lgica antes de que el controlador beforeFilter() sea llamado,
necesitars usar el mtodo initialize() del componente.
<?php
class CheckComponent extends Object {
//llamado antse de Controller::beforeFilter()
function initialize(&$controller) {
// salvando la referencia al controlador para uso posterior
$this->controller =& $controller;
}
//llamado tras Controller::beforeFilter()
function startup(&$controller) {
}

}
?>

function redirectSomewhere($value) {
// ulizando un mtodo de controlador
$this->controller->redirect($value);
}

Tambin podrias querer utilizar otros componentes dentro del componente a medida. Para ello,
simplemente crea una variable de clase $components (tal como lo haras en un controlador ) como un
array que contenga los nombres de los componentes que quieres utilizar.
<?php
class MyComponent extends Object {
// Este componente usa otros componentes
var $components = array('Session', 'Math');
function doStuff() {
$result = $this->Math->doComplexOperation(1, 2);
$this->Session->write('stuff', $result);
}

}
?>

No es muy recomendable acceder o usar un modelo en un componente, pero si tras sopesar las
posibilidades eso es lo que quieres hacer, tendrs que instanciar tu clase modelo y usarla manualmente.
Aqu tienes un ejemplo:
<?php
class MathComponent extends Object {
function doComplexOperation($amount1, $amount2) {
return $amount1 + $amount2;
}
function doUberComplexOperation ($amount1, $amount2) {
$userInstance = ClassRegistry::init('User');
$totalUsers = $userInstance->find('count');
return ($amount1 + $amount2) / $totalUsers;
}
}
?>

3.6.2.3 Usando Componentes en tu Componente

A veces uno de tus componentes puede depender de otro. Si las funcionalidades que estos
componentes proveen no estn relacionados, excepto por su dependencia el uno del otro, entonces no
querrs ponerlos dentro de un solo componente.
En cambio puedes hacer que tu componente sea un "Padre" e indicarle con el array
$components la lista de sus "Hijos". Los componentes padres se cargan antes que sus componentes
hijos, y cada componente hijo tiene acceso a su padre.
Declaracin del padre:
<?php
class PadreComponent extends Object {
var $name = "Padre";
var $components = array( "Hijo" );
function initialize(&$controller) {
$this->Hijo->foo();
}
function bar() {
// ...
}
}

Declaracin del hijo:


<?php
class HijoComponent extends Object {
var $name = "Hijo";
function initialize(&$controller) {
$this->Padre->bar();
}
function foo() {
// ...
}
}

3.7 Modelos
3.7.1 La Comprensin de Modelos
Un Modelo representa tu modelo de datos y, en programacin orientada a objetos, es un objeto
que representa una "cosa", como un coche, una persona, o una casa. Un blog, por ejemplo, puede
contener varios artculos (posts) y cada artculo puede contener varios comentarios. Los objetos Blog,
Artculo (Post) y Comentario son ejemplos de modelos, cada uno asociado con el otro.
Aqu presentamos un ejemplo simple de definicin de modelo en CakePHP:
<?php
class Ingredient extends AppModel {
var $name = 'Ingredient';
}
?>

Simplemente con esta declaracin, se le otorga al modelo Ingredient toda la funcionalidad que
necesitars para crear consultas junto con guardado y borrado de datos. Estos mtodos mgicos
provienen del modelo de herencia de CakePHP. El modelo Ingredient extiende el modelo de
aplicacinm AppModel, el cual extiende la clase Model, interna de CakePHP. Es esta clase Model
interna la que otorga la funcionalidad a nuestro modelo pesonalizado, Ingredient.
La clase intermedia AppModel est vaca y reside por defecto dentro de la carpeta /cake/.
Redefinir AppModel te permitir definir funcionalidad que debera estar disponible a todos los modelos
dentro de tu aplicacin. Para hacer eso, necesitas crear tu propio fichero app_model.php que reside
en la raz de la carpeta /app/. Creando un proyecto utilizando Bake, Bake generar automticamente
este fichero por ti.
Crea tu fichero modelo en PHP en el directorio /app/models/ o en un subdirectorio de
/app/models/. CakePHP lo encontrar en cualquier lugar en el directorio. Por convencin, debera
tener el mismo nombre que la clase; para este ejemplo, ingredient.php.
CakePHP crear dinamicamente un objeto modelo por ti si no puede encontrar un archivo
correspondiente en /app/models. Esto tambin significa que si, accidentalmente, nombras tu
archivo de manera errnea (p.ej. Ingredient.php o ingredients.php) CakePHP utilizar
AppModel en lugar de tu archivo de modelo con nombre incorrecto. Si ests tratando de utilizar un
mtodo de un modelo personalizado y ests obteniendo errores SQL, normalmente es porque CakePHP

no puede encontrar tu modelo.


Ver tambin Comportamientos para ms informacin sobre cmo aplicar lgica similar para
mltiples modelos.
La propiedad $name es necesaria para PHP4 pero opcional para PHP5.
Con tu modelo definido, este puede ser accedido dentro de tu Controlador. CakePHP
automaticamente har que se pueda acceder al modelo cuando su nombre concuerde con el del
controloador. Por ejemplo, un controlador llamado IngredientsController automaticamente inicializar
el modelo Ingredient y ser accesible por el controlador mediante $this->Ingredient.
<?php
class IngredientsController extends AppController {
function index() {
//obtiene todos los ingredientes y los pasa a la vista:
$ingredients = $this->Ingredient->find('all');
$this->set('ingredients', $ingredients);
}
}
?>

Estn disponibles los modelos asociados a travs del modelo principal. En el siguiente ejemplo,
el modelo Receta (Recipe) tiene una asociacin con el modelo Ingrediente (Ingredient).
$this->Recipe->Ingredient->find('all');

Como podrs ver en Controllers, puedes atar mltiples modelos al controlador y acceder
directamente desde l. En el siguiente ejemplo, ambos modelos Recipe y User son accesibles desde el
controlador actual.
<?php
class RecipeController extends AppController {
var $uses = array('Recipe', 'User');
function index() {
$this->Recipe->find('all');
$this->User->find('all');
}
}
?>

Si no has aadido el modelo a travs de la propiedad $uses entonces necesitars importar el modelo
manualmente e instanciarlo dentro de la accin.

<?php
class RecipeController extends AppController {
var $uses = array('Recipe');
function index() {
$this->Recipe->find('all');
App::import('Model', 'User');
$user = new User();
$user->find('all');
}
?>

3.7.2 Creando Tablas de Bases de Datos


A pesar de que CakePHP puede tener orgenes de datos (datasources) que no son manejadas por
sistemas de gestin de bases de datos, la mayora de las veces lo son. CakePHP est diseado para ser
agnstico y funcionar con MySQL, MSSQL, Oracle, PostgreSQL y otros. Puedes crear tus tablas de
base de datos como lo haras normalmente. Cuando creas tus clases del Modelo, automticamente se
mapean a las tablas que has creado.
Los nombres de las tablas son, por convencin, en minsculas y en plural, con las palabras de
los nombres de tablas de varias palabras separadas por guiones de subrayado (_). Por ejemplo, un
nombre de Modelo de Ingredient espera el nombre de tabla ingredients. un nombre de Modelo de
EventRegistration debera esperar un nombre de tabla event_registrations. CakePHP inspeccionar tus
tablas para determinar el tipo de dato de cada campo y utiliza esta informacin apra automatizar varias
caractersticas como la salida de campos de formulario en la vista.
Los nombres de los campos son, por convencin, en minscula y separados por guiones de
subrayado (_).
Las asociaciones del modelo con el nombre de la tabla pueden ser anuladas con el atributo
useTable del modelo, explicado ms adelante en este captulo.
En el resto de esta seccin vers cmo CakePHP "mapea" tipos de campos de bases de datos en
tipos de datos PHP y cmo CakePHP puede automatizar tareas basandose en cmo tus campos estn
definidos.
CakePHP viene preparado para el ingls. En caso de desear flexiones para el espaol es
necesario modificar eL fichero cake/libs/inflector.php

3.7.2.1 Asociaciones de Tipo de Dato por Base de Datos

Todo RDMS define tipos de datos de manera ligeramente diferente. Dentro de la clase de origen
de datos (o "fuente de datos", datasource) para cada sistema de base de datos, CakePHP "mapea"
dichos tipos a algo que reconoce y crea una interfaz unificada sin importar en qu sistema de bases de
datos necesitas ejecutarlo.
El siguiente desglose describe cmo est "mapeado" cada uno.
3.7.2.1.1 MySQL

Tipo CakePHP
Propiedades del Campo
primary_key
NOT NULL auto_increment
string
varchar(255)
text
text
integer
int(11)
float
float
datetime
datetime
timestamp
datetime
time
time
date
date
binary
blob
boolean
tinyint(1)
Un campo de tipo tinyint(1) es considerado booleano por CakePHP.
3.7.2.1.2 MySQLi

Tipo CakePHP
primary_key
string
text
integer
float
datetime
timestamp
time
date
binary
boolean

Propiedades del Campo


DEFAULT NULL auto_increment
varchar(255)
text
int(11)
float
datetime
datetime
time
date
blob
tinyint(1)

3.7.2.1.3 ADOdb

Tipo CakePHP
primary_key
string
text
integer
float
datetime
timestamp
time
date
binary
boolean

Propiedades del Campo


R(11)
C(255)
X
I(11)
N
T (Y-m-d H:i:s)
T (Y-m-d H:i:s)
T (H:i:s)
T (Y-m-d)
B
L(1)

3.7.2.1.4 DB2

Tipo CakePHP
primary_key
string
text
integer
float
datetime
timestamp
time
date
binary
boolean

Propiedades del Campo


not null generated by default as identity (start with 1,
increment by 1)
varchar(255)
clob
integer(10)
double
timestamp (Y-m-d-H.i.s)
timestamp (Y-m-d-H.i.s)
time (H.i.s)
date (Y-m-d)
blob
smallint(1)

3.7.2.1.5 Firebird/Interbase

Tipo CakePHP
primary_key
string
text
integer
float

Propiedades del Campo


IDENTITY (1, 1) NOT NULL
varchar(255)
BLOB SUB_TYPE 1 SEGMENT SIZE 100 CHARACTER
SET NONE
integer
float

datetime
timestamp
time
date
binary
boolean

timestamp (d.m.Y H:i:s)


timestamp (d.m.Y H:i:s)
time (H:i:s)
date (d.m.Y)
blob
smallint

3.7.2.1.6 MS SQL

Tipo CakePHP
primary_key
string
text
integer
float
datetime
timestamp
time
date
binary
boolean

Propiedades del Campo


IDENTITY (1, 1) NOT NULL
varchar(255)
text
int
numeric
datetime (Y-m-d H:i:s)
timestamp (Y-m-d H:i:s)
datetime (H:i:s)
datetime (Y-m-d)
image
bit

3.7.2.1.7 Oracle

Tipo CakePHP
primary_key
string
text
integer
float
datetime
timestamp
time
date
binary
boolean
number
inet

Propiedades del Campo


number NOT NULL
varchar2(255)
varchar2
numeric
float
date (Y-m-d H:i:s)
date (Y-m-d H:i:s)
date (H:i:s)
date (Y-m-d)
bytea
boolean
numeric
inet

3.7.2.1.8 PostgreSQL

Tipo CakePHP
primary_key
string
text
integer
float
datetime
timestamp
time
date
binary
boolean
number
inet

Propiedades del Campo


serial NOT NULL
varchar(255)
text
integer
float
timestamp (Y-m-d H:i:s)
timestamp (Y-m-d H:i:s)
time (H:i:s)
date (Y-m-d)
bytea
boolean
numeric
inet

3.7.2.1.9 SQLite

Tipo CakePHP
primary_key
string
text
integer
float
datetime
timestamp
time
date
binary
boolean

Propiedades del Campo


integer primary key
varchar(255)
text
integer
float
datetime (Y-m-d H:i:s)
timestamp (Y-m-d H:i:s)
time (H:i:s)
date (Y-m-d)
blob
boolean

3.7.2.1.10 Sybase

Tipo CakePHP
primary_key
string
text
integer
float
datetime
timestamp

Propiedades del Campo


numeric(9,0) IDENTITY PRIMARY KEY
varchar(255)
text
int(11)
float
datetime (Y-m-d H:i:s)
timestamp (Y-m-d H:i:s)

time
date
binary
boolean

datetime (H:i:s)
datetime (Y-m-d)
image
bit

3.7.2.2 Titulos

Un objeto, en sentido fsico, a menudo tiene un nombre o un ttulo con el que referirse. Una
persona tiene un nombre como Juan o Ambrosio o Colega. Una entrada de un blog tiene un ttulo. Una
categora tiene un nombre.
Al especificar el campo title (ttulo) o name (nombre), CakePHP automticamente utilizar
esta etiqueta en varias circunstancias:
Scaffolding ttulos de pginas, etiquetas de fieldset
Listas - normalmente utilizado para los desplegables <select>
TreeBehavior reordenacin, vistas de rbol
Si tienes un campo title y un campo name en tu tabla, el campo title ser el utilizado.
3.7.2.3 Creado y modificado ("created" y "modified")

Al definir un campo created (creado) o modified (modificado) en tu tabla de la base de


datos como campo de tipo datetime, CakePHP reconocer esos campos y los rellenar
automaticamente cuando un registro sea creado o grabado en la base de datos.
Los campos created y modified sern establecidos a la fecha y hora actuales cuando el
registro es inicialmente aadido. El campo modified ser actualizado con la fecha y hora actuales
cuando el registro existente sea grabado.
Nota: Un campo llamado updated (actualizado) exhibir el mismo comportamiento que modified.
Estos campos necesitan ser del tipo datetime con el valor por defecto establecido a NULL para ser
reconocidos por CakePHP.
3.7.2.4 Utilizando UUIDs como Claves Primarias

Las claves primarias son normalmente definidas como campos INT. La base de datos
incrementar automticamente el campo, comenzando en 1, para cada nuevo registro que se aade.
Alternativamente, si especificas tu clave primaria como CHAR(36), CakePHP generar
automticamente UUIDs (Identificadores nicos Universales) cuando son creados nuevos registros.

Un UUID es una cadena de 32 bytes separada por guiones, con un total de 36 caracteres. Por
ejemplo:
550e8400-e29b-41d4-a716-446655440000

Los UUIDs estn diseados para ser nicos, no slo dentro de una tabla dada, sino tambin a
travs de tablas y bases de datos. Si necesitas que un campo permanezca nico a travs de sistemas, los
UUIDs son un genial enfoque.
3.7.3 Recuperando tus Datos
3.7.3.1 find

find($tipo, $parametros)
$tipo es 'all', 'first', 'count', 'neighbors', 'list' o 'threaded'. 'first' es
el tipo de bsqueda predeterminado.
$parametros es un array con cualquiera de las siguientes opciones disponibles como claves:
array(

campos

'conditions' => array('Model.field' => $thisValue), //array de condiciones


'recursive' => 1, //int
'fields' => array('Model.field1', 'Model.field2'), //array de nombres de
'order' => 'Model.created', //string o array definiendo el orden
'group' => array('Model.field'), //campos para GROUP BY
'limit' => n, //int
'page' => n //int

Si ests utilizando find('list'), la clave 'fields' en $parametros define la clave,


valor y grupo
// la lista generada ser indexada por Post.id, con valor de Post.title
$this->Post->find('list', array('fields'=>'Post.title'));
// la lista generada ser indexada por Post.slug, con valor de Post.title
$this->Post->find('list',
array(
'fields'=>array('Post.slug',
'Post.title')
)
);
// la lista generada ser agrupoada por Post.author_id, y cada grupo indexado por
Post.id, con valor de Post.title
$this->Post->find('list',
array(

);

'fields'=> array('Post.id',
'Post.title',
'Post.author_id')
)

Si ests utilizando find('neighbors'), la clave 'field' en $parametros define el


campo a analizar, y la clave 'value' en el array $parametros define el valor a mirar para
determinar el siguiente y el anterior. Notar que las claves 'field' y 'value' no son usadas para
find('all') y este es un caso especial para find('neighbors').
// asumiendo que tenermos id's de 1 a 10, veremos assuming we have id's from 110, veremos <em>prev</em> establecido a 1 y <em>next</em> establecido a 3
$this->Post->id = 2;
$one = $this->Post->find('neighbors');
// para obtener los datos vecinos utilizando un campo diferente...
$two = $this->Post->find('neighbors',
array(
'field'=> 'Post.title',
'value'=> $data['Post']['title'])
);

Para compatibilidad hacia atra, find tambin acepta la sintasix previa:


find(string $condiciones, array $campos, string $orden, int $recursivo)
3.7.3.1.1 find('first')

find('first', $params)
'first' es el tipo find por defecto, y devolver un solo resultado, deberas utilizar esto para cualquier caso
donde esperes solo un resultado. Abajo hay un par de ejemplos simples (cdigo del controlador
[controller]):
function some_function() {
...
$this->Article->order = null; // reseteando si ya ha sido inicializado
$semiRandomArticle = $this->Article->find();
$this->Article->order = 'Article.created DESC'; // simulando el modelo teniendo
un rden por defecto
$lastCreated = $this->Article->find();
$alsoLastCreated
=
$this->Article->find('first',
array('order'
=>
array('Article.created DESC')));
$specificallyThisOne = $this->Article->find('first', array('conditions' =>
array('Article.id' => 1)));
...
}

En este primer ejemplo, ningn parmetro se le ha pasado a find - por lo tanto ningn criterio de
condicin o de ordenamiento ser utilizado. El formato devuelto por la llamada a find('first')

ser de la siguiente forma:


Array
(
[ModelName] => Array
(
[id] => 83
[field1] => value1
[field2] => value2
[field3] => value3
)
[AssociatedModelName] => Array
(
[id] => 1
[field1] => value1
[field2] => value2
[field3] => value3
)
)

No hay parmetros adicionales usador por find('first').


3.7.3.1.2 find('count')

find('count', $params)
Devuelve un valor entero. Debajo hay un par de ejemplos sencillos (cdigo controlador):
function some_function() {
...
$total = $this->Article->find('count');
$pending
=
$this->Article->find('count',
array('conditions'
array('Article.status' => 'pending')));
$authors = $this->Article->User->find('count');
$publishedAuthors = $this->Article->find('count', array(
'fields' => 'DISTINCT Article.user_id',
'conditions' => array('Article.status !=' => 'pending')
));
...
}

=>

No pasar campos como arrays a find('count'). Podras necesitar campos especficos para
DISTINCT count (de lo contrario, count es siempre lo mismo - dictatado por las conditions
(condiciones)).
No hay parmetros adicionales usados con find('count').
3.7.3.1.3 find('all')

find('all', $params)

Devuelve un array de resultados(potentially multiple); es, de hecho, el mecanismo usado por


todas las variantes del mtodo find(), como por ejemplo para paginar. Debajo puedes ver un par
de (cdigo controlador) ejemplos:
function some_function() {
...
$allArticles = $this->Article->find('all');
$pending
=
$this->Article->find('all',
array('conditions'
=>
array('Article.status' => 'pending')));
$allAuthors = $this->Article->User->find('all');
$allPublishedAuthors = $this->Article->User->find('all', array('conditions' =>
array('Article.status !=' => 'pending')));
...
}

El ejemplo de abajo $allAuthors busca todos los campos de la tabla users, no se le han
aplicado condiciones a find.
Los resultados de llamar a find('all') sern de la siguiente forma:
Array
(
[0] => Array
(
[ModelName] => Array
(
[id] => 83
[field1] => value1
[field2] => value2
[field3] => value3
)
[AssociatedModelName] => Array
(
[id] => 1
[field1] => value1
[field2] => value2
[field3] => value3
)
)

Aqu no hay parmetros condicionales usados por find('all').


3.7.3.1.4 find('list')

find('list', $params)
Devuelve un array indexado, til para cualquier uso donde podras querer una lista como los
polulares campos select de los formularios. Debajo hay un par de simples ejemplos (cdigo

controlador):
function some_function() {
...
$allArticles = $this->Article->find('list');
$pending

$this->Article->find('list',

array('conditions'

=>

array('Article.status' => 'pending')));


$allAuthors = $this->Article->User->find('list');
$allPublishedAuthors = $this->Article->User->find('list', array('conditions' =>
array('Article.status !=' => 'pending')));
...
}

En el ejemplo siguiente $allAuthors va a contener todos los usuarios de la tabalo usuers, no


se le aplica ninguna condicin para filtrar la bsqueda que lleva a cabo find.
Los resultado tras llamar al mtodo find('list') tendrn el siguiente aspecto:
Array
(
//[id]
[1] =>
[2] =>
[4] =>
[5] =>
[6] =>
[3] =>
)

=> 'displayValue',
'displayValue1',
'displayValue2',
'displayValue4',
'displayValue5',
'displayValue6',
'displayValue3',

Cuando find('list') es llamado, los parmetros pasados son usados para determinar
que debera ser usado como la key del array, value y opcionalmente a que grupo pertenecen los
resultados. Por defecto la clave primaria para el modelo es usada por la key, y el valor que se muestra
es el usado por el value. Algunos ejemplos aclarar un poco ms:
function some_function() {
...
$justusernames
=
$this->Article->User->find('list',
array('User.username'));
$usernameMap
=
$this->Article->User->find('list',
array('User.username', 'User.first_name'));
$usernameGroups = $this->Article->User->find('list',
array('User.username', 'User.first_name', 'User.group'));
...
}

array('fields'

=>

array('fields'

=>

array('fields'

=>

En el anterior ejemplo, el resultado devuelto se parecera a esto:


$justusernames = Array
(
//[id] => 'username',
[213] => 'AD7six',
[25] => '_psychic_',
[1] => 'PHPNut',
[2] => 'gwoo',
[400] => 'jperras',
)
$usernameMap = Array
(
//[username] => 'firstname',
['AD7six'] => 'Andy',
['_psychic_'] => 'John',
['PHPNut'] => 'Larry',
['gwoo'] => 'Gwoo',
['jperras'] => 'Jol',
)
$usernameGroups = Array
(
['Uber'] => Array
(
['PHPNut'] => 'Larry',
['gwoo'] => 'Gwoo',
)
['Admin'] => Array
(
['_psychic_'] => 'John',
['AD7six'] => 'Andy',
['jperras'] => 'Jol',
)
)

3.7.3.1.5 find('threaded')

find('threaded', $params)
Devuelve un array anidado, y es apropiado si quieres usar el campo parent_id de tu modelo
de datos para construir resultados anidados. Abajo se muestran un par de ejemplos (cdigo
controlador):
function some_function() {
...
$allCategories = $this->Category->find('threaded');
$aCategory
=
$this->Category->find('first',
array('conditions'
array('parent_id' => 42)); // not the root
$someCategories = $this->Category->find('threaded', array(
'conditions' => array(

=>

'Article.lft >=' => $aCategory['Category']['lft'],


'Article.rght <=' => $aCategory['Category']['rght']

));
...
}

No es necesario utilizar el comportamiento en rbol para usar este mtodo, pero todos los
resultados deseados deben poderse encontrar en una sencilla consulta.
El anterior ejemplo, $allCategories contendra un array anidado representando la
estuctura entera de la categora. El segundo ejemplo hace uso de la estructura de datos Tree behavior
the return a partial, nested, result for $aCategory and everything below it. The results of a call to
find('threaded') will be of the following form:
Array
(
[0] => Array
(
[ModelName] => Array
(
[id] => 83
[parent_id] => null
[field1] => value1
[field2] => value2
[field3] => value3
)
[AssociatedModelName] => Array
(
[id] => 1
[field1] => value1
[field2] => value2
[field3] => value3
)
[children] => Array
(
[0] => Array
(
[ModelName] => Array
(
[id] => 42
[parent_id] => 83
[field1] => value1
[field2] => value2
[field3] => value3
)
[AssociatedModelName] => Array
(
[id] => 2
[field1] => value1
[field2] => value2
[field3] => value3

)
)

)
...

)
[children] => Array
(
)

El orden en el que aparecen los resultados puede ser cambiado como lo es la influencia de la
orden de procesamiento. Por ejemplo, si 'order' => 'name ASC' es pasado en los parmetros a
find('threaded'), los resultados van a aparecer en orden segn el nombre. Del mismo modo
cualquier orden puede ser usado, there is no inbuilt requirement of this method for the top result to be
returned first.
No hay parmetros adicionales usados por find('threaded').
3.7.3.1.6 find('neighbors')

find('neighbors', $params)
'neighbors' realiza una bsqueda similar a 'first', a diferencia que devuelve el registro precedente
y posterior del solicitado. A continuacin un (cdigo en controlador) ejemplo:
function some_function() {
$neighbors = $this->Article->find('neighbors', array('field' => 'id', 'value'
=> 3));
}

En este ejemplo podemos ver dos elementos esenciales del arreglo $params: 'field' y 'value'.
Adems de estos, se pueden utilizar otros elementos que se utilizan en las dems implementaciones del
mtodo find (Por ejemplo: Si tu modelo acta como contenedor, deberas de utilizar 'contain' en el
arreglo $params). El formato de salida para una llamada find('neighbors') es de la siguiente
forma:
Array
(
[prev] => Array
(
[ModelName] => Array
(
[id] => 2
[field1] => value1
[field2] => value2
...
)
[AssociatedModelName] => Array

(
[id] => 151
[field1] => value1
[field2] => value2
...

)
)
[next] => Array
(
[ModelName] => Array
(
[id] => 4
[field1] => value1
[field2] => value2
...
)
[AssociatedModelName] => Array
(
[id] => 122
[field1] => value1
[field2] => value2
...
)
)

Note que el resultado siempre tendr dos arreglos principales: prev y next.
3.7.3.2 findAllBy

findAllBy<nombreCampo>(string $valor)
Estas funciones mgias pueden ser usadas como atajos para buscar en tus tablas por cierto
campo. Simplemente aade el nombre del campo (en formato CamelCase) al final del nombre de esas
funciones (<nombreCampo>) y proporciona los criterios para ese campo como primer parmetro.
3.7.3.3 findBy

findBy<nombreCampo>(string $valor)
Estas funciones mgicas pueden ser usadas como atajo en la bsqueda en tus tablas por cierto
campo. Simplemente aade el nombre del campo (en forma CamelCase) al final de las funciones
(<nombreCampo>), y proporciona los criterios para ese campo como primer parmetro.
Ejemplo findAllBy<x> en PHP5
$this->Product->findAllByOrderStatus(3);
$this->Recipe->findAllByType(Cookie);
$this->User->findAllByLastName(Anderson);
$this->Cake->findById(7);

Fragmento SQL Correspondiente


Product.order_status = 3
Recipe.type = Cookie
User.last_name = Anderson
Cake.id = 7

$this->User->findByUserName(psychic);
User.user_name = psychic
Los usuarios de PHP4 han de utilizar esta funcin de manera un poco diferente debido a cierto caseinsensitivity en PHP4:
Ejemplo findAllBy<x> en PHP4
Fragmento SQL Correspondiente
$this->Product->findAllByOrder_status(3);
Product.order_status = 3
$this->Recipe->findAllByType(Cookie);
Recipe.type = Cookie
$this->User->findAllByLast_name(Anderson); User.last_name = Anderson
$this->Cake->findById(7);
Cake.id = 7
$this->User->findByUser_name(psychic);
User.user_name = psychic
El resultado devuelto es un array formateado tal y como sera en find() o findAll().
3.7.3.4 query

query(string $consulta)
Se pueden realizar llamadas SQL personalizadas usando el mtodo query() del modelo.
Si alguna vez usas consultas SQL personalizadas en tu aplicacin, no olvides leer la seccin
Desinfeccin de Datos (Sanitization) de CakePHP, la cual ayuda a limpiar datos de usuario de injection
y ataques de cross-site scripting.
query() utiliza el nombre de la tabla en la consulta como clave del array de datos devueltos, en vez
del nombre del modelo. Por ejemplo:
$this->Fotografia->query("SELECT * FROM fotografias LIMIT 2;");

debera devolver
Array
(
[0] => Array
(
[fotografas] => Array
(
[id] => 1304
[user_id] => 759
)
)
[1] => Array
(
[fotografas] => Array
(
[id] => 1305
[user_id] => 759
)
)

Para usar el nombre del modelo como clave del array, y obtener un resultado consistente con el
devuelto por los mtodos Find, la consulta puede ser reescrita:
$this->Fotografia->query("SELECT * FROM fotografia AS Fotografia LIMIT 2;");

la cual devuelve
Array
(
[0] => Array
(
[Fotografia] => Array
(
[id] => 1304
[user_id] => 759
)
)
[1] => Array
(
[Fotografia] => Array
(
[id] => 1305
[user_id] => 759
)
)
)

3.7.3.5 field

field(string $nombre, string $condiciones, string $orden)


Devuelve el valor de un campo singular, especificado en $name, del primer registro que cumpla
$condiciones estando ordenado por $orden.
3.7.3.6 read()

read($fields, $id)
read() es un mtodo usado para establecer los datos del modelo actual (Model::$data)-as tambin mientras se est editando--pero tambin puede ser usado en otras circunstancias para
obtener un solo registro de la base de datos.
$fields es usado para especificar un nombre de campo, como cadena, o un arreglo de
nombres de campo que sern incluidos en la consulta; si no se especifica un valor, entonces todos los
campos sern incluidos.

$id especifica el ID de registro que ser ledo. Por defecto, el registro actualmente
seleccionado, especificado por Model::$id, es usado. Si se especifica un valor diferente a $id
causar que el registro que cumpla con la condicin ser seleccionado.
function beforeDelete($cascade) {
...
$rating = $this->read('rating'); // obtiene el <em>rating</em> del registro que
ser borrado.
$name = $this->read('name', $id2); // obtiene el nombre un segundo registro.
$rating = $this->read('rating'); // obtiene el <em>rating</em> del segundo
registro
$this->id = $id3; //
$this->Article->read(); // lee un tercer registro, especificado por
<code>$id3</code>.
$record = $this->data // almacena el tercer registro en <code>$record</code>
...
}

Notar que la tercera llamada a read() obtiene el rating del mismo registro ledo anteriormente
por la llamada $this->read('name', $id2). Esto es porque read() cambia el valor en
Model::$id a cualquier valor pasado como $id. Las lineas 6-8 demuestran como read() cambia
los datos del modelo actual.
3.7.3.7 Condiciones Complejas de Bsqueda

La mayora de las llamadas de bsqueda del modelo involucran pasar conjuntos de condiciones
de una u otra manera. La aproximacin ms simple a ello es utilizar la clusula WHERE de SQL. Si ves
que necesitas ms control, puedes utilizar arrays.
Usar arrays permite una lectura ms clara y fcil, y tambin hace muy fcil la construccin de
consultas. Esta sintaxis tambin particiona los elementos de tu consulta (campos, valores, operadores,
etc.) en partes discretas y manipulables. Esto permite a CakePHP generar la consulta ms eficiente
posible, asegurar una sintaxis SQL apropiada, y formatear apropiadamente cada parte individual de la
consulta.
En su forma ms bsica, una consulta basada en array es as:
$condiciones = array("Articulo.title" => "Esto es un artculo");
// Ejemplo de uso con un modelo:
$this->Articulo->find($condiciones);

La estructura aqu es bastante autoexplicativa: buscar cualquier artculo donde el ttulo sea
igual a "Esto es un artculo". Notar que podramos haber utilizado como nombre de campo

simplemente 'title', pero cuando se construyen consultas es buena prctica especificar siempre el
nombre del modelo (en este caso, Articulo), ya que mejora la claridad del cdigo y ayuda a prevenir
colisiones en el futuro, en cuyo caso deberas modificar tu esquema de tablas.
Qu hay sobre otros tipos de condiciones? Estas son igualmente simples. Digamos que
queremos buscar todos los artculos donde el ttulo no sea 'Esto no es un artculo':
array("Articulo.title <>" => "Esto no es un artculo")

Notar el '<>' que est detrs del nombre del campo. CakePHP puede analizar sintcticamente
cualquier operador de comparacin en SQL, incluyendo las expresiones usando LIKE, BETWEEN, o
REGEX, siempre y cuando dejes un espacio entre el nombre del campo y el operador. La unica
excepcin aqu es la condicin de bsqueda del tipo IN (...). Digamos que queras buscar artculos
donde el ttulo estaba dentro de un conjunto dado de valores:
array(
"Articulo.title" => array("Primer artculo", "Segundo artculo", "Tercer
artculo")
)

Para realizar una bsqueda con condicin NOT IN(...) para encontrar artculos cuyo ttulo
no est en el conjunto de valores dado:
array(

"NOT" => array( "Articulo.title" => array("Primer artculo", "Segundo


artculo", "Tercer artculo") )
)

Aadir filtros adicionales a las condiciones es tan simple como aadir pares clave/valor adicionales al
array:
array (
"Articulo.title" => array("Primer artculo", "Segundo artculo", "Tercer
artculo"),
"Articulo.created >" => date('Y-m-d', strtotime("-2 weeks"))
)

Tambin puedes crear bsquedas que comparen dos campos en la base de datos:
array("Articulo.created = Articulo.modified")

Este ejemplo de arriba devolver artculos en los cuales la fecha de creacin es igual a la fecha
de modificacin (p.e. devolver artculos que nunca han sido modificados).

Por defecto, CakePHP junta mltiples condiciones con AND booleano; es decir, las condiciones
de ms arriba slo coincidirn con artculos que han sido creados en las ltimas dos semanas (-2
weeks), y posean un ttulo que coincida con alguno de los dados en el conjunto ("Primer artculo",...).
No obstante, podemos igualmente buscar artculos que coincidan con cualquiera de las condiciones:
array(
"or" => array (
"Articulo.title" => array("Primer artculo", "Segundo artculo", "Tercer
artculo"),
"Articulo.created >" => date('Y-m-d', strtotime("-2 weeks"))
)
)

Cake acepta todas las operaciones booleanas de SQL vlidas, incluyendo AND, OR, NOT, XOR,
etc..., y pueden estar en maysculas o minsculas, como prefieras. Estas condiciones son tambin
infinitamente anidables. Digamos que tienes una relacin belongsTo entre Articulos y Autores.
Digamos que quieres buscar todos los artculos que contienen una cierta palabra (p.e. "magico")
o que han sido creados en las ltimas dos semanas, pero quieres restringir tu bsqueda a artculos
escritos por Pedro:
array (
"Autor.name" => "Pedro",
"or" => array (
"Articulo.title LIKE" => "%magico%",
"Articulo.created >" => date('Y-m-d', strtotime("-2 weeks"))
)
)

Cake tambin puede comprobar campos nulos (null). En este ejemplo, la consulta devolver
registros en los que el ttulo del artculo no es nulo:
array (
"not" => array (
"Articulo.title" => null,
)
)

Para manejar consultas con BETWEEN, puedes usar lo siguiente:


array('Articulo.id BETWEEN ? AND ?' => array(1,10))

Nota: CakePHP entrecomillar los valores numricos dependiendo del tipo de campo definido en tu
base de datos.

Puedes crear condiciones muy complejas anidando mltiples arrays de condiciones:


array(
'OR' => array(
array('Compania.name' => 'Emporio Futuro'),
array('Compania.name' => 'Megatrabajos de Acero')
),
'AND' => array(
array(
'OR'=>array(
array('Compania.status' => 'activo'),
'NOT'=>array(
array('Compania.status'=> array('inactivo', 'suspendido'))
)
)
)
)
);

Las cuales producen el siguiente cdigo SQL:


SELECT `Compania`.`id`, `Compania`.`name`,
`Compania`.`description`, `Compania`.`location`,
`Compania`.`created`, `Compania`.`status`, `Compania`.`size`
FROM
`companias` AS `Compania`
WHERE
((`Compania`.`name` = 'Emporio Futuro')
OR
(`Compania`.`name` = 'Megatrabajos de Acero'))
AND
((`Compania`.`status` = 'activo')
OR (NOT (`Compania`.`status` IN ('inactivo', 'suspendido'))))

3.7.4 Guardando Tus Datos


CakePHP hace que el salvado de los datos del modelo sea instantneo. Los datos listos para ser
salvados debern ser pasados al mtodo save() del modelo usando el formato bsico siguiente:
Array
(
[NombreModelo] => Array
(
[nombrecampo1] => 'valor'
[nombrecampo2] => 'valor'
)
)

La mayora de las veces no necesitars preocuparte por este formato: los ayudantes de CakePHP
HtmlHelper, FormHelper, y mtodos de bsqueda empaquetan los datos en este formato. Si ests
usando alguno de los ayudantes, los datos tambin estn convenientemente disponibles en $this>data para su uso rpido.
Aqu est un ejemplo rpido de una accin de un controlador que usa un modelo de CakePHP
para salvar datos en una tabla de una base de datos:
function edit($id) {
// Ha POSTeado algn dormulario datos?
if(!empty($this->data)) {
// Si el formulario puede ser validado y salvado...
if($this->Receta->save($this->data)) {
// Establede un mensaje flash y redirige.
$this->Session->setFlash("Receta guardada!");
$this->redirect('/recetas');
}
}

// Si no hay datos de formularo, busca la receta a editar y psala a la vista


$this->set('receta', $this->Receta->findById($id));

Una nota adicional: cuando se llama a save(), los datos pasados a la funcin como primer
parmetro son validados usando el mecanismo de validacin de CakePHP (ver el captulo de validacin
de datos para ms informacin). Si por alguna razn tus datos no se graban, comprueba si alguna regla
de validacin se est incumpliendo.
Hay unos pocos mtodos relacionados con el salvado que encontrars tiles:
save(array $datos = null, boolean $validar = true, array $listaCampos = array())
Mostrado arriba, este mtodo graba datos formateados en array. El segundo parmetro
($validar) te permite eludir la validacin, y el tercero ($listaCampos) te permite proveer una
lista de campos del modelo a ser grabados. Como seguridad aadida, puedes limitar los campos
grabados a aquellos listados en $listaCampos.
Una vez que un salvado ha sido completado, el identificador ID del objeto se encuentra en el
atributo $id del objeto del modelo (algo especialmente til cuando se crean nuevos objetos).
$this->Ingrediente->save($datosNuevos);
$nuevoIngredienteId = $this->Ingrediente->id;

Cuando se llama a save() en un bucle, no olvides llamar a create().


create(array $datos = array())
Este mtodo resetea el estado del modelo para grabar nueva informacin.
Si se pasa el parmetro $datos (usando el formato de array descrito arriba), la instancia del
modelo estar lista para salvar con esos datos (accesibles en $this->data).
saveField(string $nombreCampo, string $valorCampo, $validar = false)
Usado para salvar un nico valor de un campo. Establece el ID del modelo ($this>nombreModelo->id = $id) antes de llamar a saveField(). Cuando usas este mtodo,
$nombreCampo debera contener slo el nombre del campo, no el nombre del modelo y campo.
Por ejemplo, para actualizar el ttulo de una entrada de un blog, la llamada a saveField desde un
controlador debera parecerse a esto:
$this->Entrada->saveField('titulo', 'Un Nuevo Ttulo para un Nuevo Da');

updateAll(array $campos, array $condiciones)


Actualiza varios registros en una nica llamada. Los registros a ser actualizados estn identificados por
el array $conditions, y los campos a ser actualizados, as como sus valores, estn identificados por
el array $fields.
Por ejemplo, para aprobar a todos los panaderos que han sido miembros durante ms de un ao, la
llamada de actualizacin debera ser algo como:
$este_ao = date('Y-m-d h:i:s', strtotime('-1 year'));
$this->Panadero->updateAll(
array('Panadero.approved' => true),
array('Panadero.created <=' => "$este_ao")
);

El array $campos acepta expresiones SQL. Los valores literales deberan ser entrecomillados
manualmente.
Por ejemplo, para cerrar todos los tickets que pertenecen a cierto vendedor:
$this->Ticket->updateAll(
array('Ticket.estado' => "'cerrado'"),
array('Ticket.vendedor_id' => 453)
);

saveAll(array $datos = null, array $opciones = array())


Usado para salvar (a) mltiples registros individuales para un nico modelo o (b) este registro
as como todos los registros asociados.
Para salvar mltiples registros de un nico modelo, $data necesita ser un array de registros
indexado numricamente como esto:
Array
(

[0] => Array


(
)
[1] => Array
(

[titulo] => titulo 1

[titulo] => titulo 2

Para salvar un registro junto con su registro relacionado teniendo una asociacin hasOne o
belognsTo, el array de datos debera ser como:
Array
(
[Usuario] => Array
(
[nombreusuario] => billy
)
[Perfil] => Array
(
[sexo] => Varon
[ocupacion] => Programador
)
)

Para salvar un registro junto con sus registros relacionados teniendo una asociacin hasMany, el
array de datos debera ser como:
Array
(
[Articulo] => Array
(
[titulo] => Mi primer artculo
)
[Comentario] => Array
(
[0] => Array
(
[comentario] => Comment 1
[comentario] => 1
)
[1] => Array

(
[comentario] => Comment 2
[comentario] => 2
)

3.7.4.1 Guardando Datos de Modelos Relacionados (hasOne, hasMany, belongsTo)

Cuando estamos trabajando con modelos asociados, es importante tener en cuenta que al
guardar los datos de un modelo hay que hacerlo con el correspondiente modelo de CakePHP. Si ests
guardando una nueva Entrada y sus Comentarios asociados, entonces deberas usar ambos modelos,
Entrada y Comentario, durante la operacin de guardado.
Si ninguno de los registros de los modelos asociados existe an (por ejemplo, quieres guardar
registros de un nuevo Usuario y su Perfil relacionado a la vez ), primero necesitars guardar el modelo
primario o padre.
Para tener una idea de cmo funciona esto, imaginemos que tenemos una accin en nuestro
controlador de usuarios UsersController que maneja el guardado de un nuevo usuario y su perfil
correspondiente. En la accin de ejemplo mostrada abajo se asumir que has POSTeado sufientes datos
(usando el FormHelper) para crear un solo Usuario y un solo Perfil.
<?php
function add() {
if (!empty($this->data)) {
// Podemos guardar los datos de Usuario
// deberan estar en: $this->data['Usuario']
$this->Usuario->save($this->data);
// El ID del nuevo Usuario est ahora en $this->User->id, as que lo
// aadimos a los datos a grabar y grabamos el Perfil
$this->data['Perfil']['usuario_id'] = $this->Usuario->id;
// Como nuestro "Usuario hasOne Perfil", podemos acceder
// al modelo Perfil a travs del modelo Usuario
$this->Usuario->Perfil->save($this->data);
}
?>

Como norma general, cuando trabajamos con asociaciones hasOne, hasMany y belongsTo
('tiene un', 'tiene varios', y 'pertenece a'), todo es cuestin de las claves. La idea bsica es coger la clave
de un modelo y ponerla en el campo de clave fornea en el otro. A veces esto puede implica usar el
atributo $id de la clase del modelo despus de save(), pero otras veces podra simplemente implicar
obtener el ID desde un campo oculto de un formulario POSTeado a una accin del controlador.

Para complementar el enfoque bsico usado arriba, CakePHP tambin ofrece el mtodo muy til
saveAll, el cual te permite validar y grabar mltiples modelos de golpe. Adems, saveAll provee
de soporte transaccional para asegurar la integridad de los datos en tu base de datos (p.ej. si un modelo
falla en la grabacin, los otros modelos tampoco sern grabados).
Para que las transacciones funcionen correctametne en MySQL, tus tablas han de usar el
mecanismo InnoDB. Recuerda que las tablas MyISAM no soportan transacciones.
Veamos cmo podemos usar saveAll() para grabar modelos de Compaa (utilizamos este
nombre incorrecto por motivos didcticos) y Cuenta al mismo tiempo.
Primero, necesitas construir tu formulario tanto para el modelo Compaa como el modelo
Cuenta (asumismo que Compaa hasMany Cuenta).
echo
echo
echo
echo

$form->create(Compaa, array('action'=>'add'));
$form->input('Compaa.nombre', array('label'=>'Nombre de compaa'));
$form->input('Compaa.descripcin');
$form->input('Compaa.localizacin');

echo $form->input('Cuenta.0.nombre', array('label'=>'Nombre de cuenta'));


echo $form->input('Cuenta.0.nombreusuario');
echo $form->input('Cuenta.0.email');
echo $form->end('Aadir');

Echemos un vistazo a la manera en que hemos nombrado los campos del formulario para el
modelo Cuenta. Si Compaa es nuestro modelo principal, saveAll esperar que los datos de los
modelos relacionados (en este caso, Cuenta) llegue en un formado especfico, y teniendo
Cuenta.0.nombreCampo es exactamente lo que necesitamos.
El nombrado de campos de arriba es necesario para la asociacin hasMany. Si la asociacin
entre los modelos es hasOne, necesitars usar la notacin NombreModelo.nombreCampo para el
modelo asociado.
Ahora, en nuestro compaias_controler.php podemos crear una accin add():
function add() {
if(!empty($this->data)) {
$this->Compaia->saveAll($this->data, array('validate'=>'first'));
}
}

Esto es todo para ello. Ahora nuestros modelos Compaa y Cuenta sern validados y grabados
al

mismo

tiempo.

Una

cosa

rpida

que

comentar

aqu

es

el

uso

de

array('validate'=>'first'): esa opcin asegurar que ambos modelos son validados.


3.7.4.1.1 counterCache - Cache your count()

This function helps you cache the count of related data. Instead of counting the records
manually via find('count'), the model itself tracks any addition/deleting towards the associated
$hasMany model and increases/decreases a dedicated integer field within the parent model table.
The name of the field consists of the singular model name followed by a underscore and the
word "count".
my_model_count

Let's say you have a model called ImageComment and a model called Image, you would add
a new INT-field to the image table and name it image_comment_count.
Here are some more examples:
Model
Associated Model Example
User
Image
users.image_count
Image
ImageComment
images.image_comment_count
BlogEntry BlogEntryComment blog_entries.blog_entry_comment_count
Once you have added the counter field you are good to go. Activate counter-cache in your
association by adding a counterCache key and set the value to true.
class Image extends AppModel {
var $belongsTo = array(
'ImageAlbum' => array('counterCache' => true)
);
}

From now on, every time you add or remove a Image associated to ImageAlbum, the number
within image_count is adjusted automatically.
You can also specify counterScope. It allows you to specify a simple condition which tells
the model when to update (or when not to, depending on how you look at it) the counter value.
Using our Image model example, we can specify it like so:

class Image extends AppModel {


var $belongsTo = array(
'ImageAlbum' => array(
'counterCache' => true,
'counterScope' => array('Image.active' => 1) // only count if "Image"
is active = 1
));
}

3.7.4.2 Guardando Datos de Modelos Relacionados (HABTM)

Grabar modelos que estn asociados por hasOne, belongsTo y hasMany es bastante simple:
simplemente rellenas el campo de clave fornea con el ID del modelo asociado. Una vez que est
hecho, simplemente llamas al mtodo save() del modelo y todo queda enlazado correctamente.
Con HABTM (Has And Belongs To Many), necesitas establecer el ID del modelo asociado en tu
array de datos. Construiremos un formulario que crea una nueva etiqueta y la asocia al vuelo con
alguna receta.
El formulario ms simple debera parecerse al algo como esto (asumimos que $receta_id ya
est establecido a algo):
<?php
echo $form->create('Etiqueta');
echo
$form->input('Receta.id',
$receta_id));
echo $form->input('Etiqueta.nombre');
echo $form->end('Aadir etiqueta');
?>

array('type'=>'hidden',

'value'

=>

En este ejemplo, puedes ver el campo oculto Receta.id cuyo valor se establece al ID de la
receta a la que queremos enlazar la etiqueta. La accin del controlador que se encarga de guardar este
formulario es muy simple:
function add() {
// Graba la asociacin
if ($this->Etiqueta->save($this->data)) {
// Hacer algo si todo fue bien
}
}

Y de esa manera, nuestra nueva Etiqueta es creada y asociada con Receta, cuyo ID estaba en
$this->data['Receta']['id'].

3.7.5 Borrando Datos


3.7.5.1 del

del(int $id = null, boolean $cascada = true);


Borra el registro identificado por $id. Por defecto, tambin borra los registros dependientes del
registro especificado a ser borrado.
Por ejemplo, cuando se borra un registro Usuario que est ligado a varios registros Receta:
si $cascada est establecido a true, los registros Receta relacionados tambin son
borrados si el valor de dependent (ver la seccin hasMany) en el modelo est establecida a
true.
si $cascada est establecido a false, los registros Receta permanecern despus de que el
Usuario haya sido borrado.
3.7.5.2 deleteAll

deleteAll(mixed $condiciones, $cascada = true)


De la misma manera que del() y remove(), excepto que deleteAll() borra todos los
registros que cumplen las condiciones dadas. El array $condiciones debera ser pasado como un
fragmento SQL o array.
3.7.6 Asociaciones: Enlazando Modelos
Una de las caractersticas ms potentes de CakePHP es la habilidad para enlazar el mapeado
relacional proporcionado por el modelo. En CakePHP, los enlaces entre modelos son manejados
mediante asociaciones.
Definir relaciones entre diferentes objetos en tu aplicacin debera ser un proceso natural. Por
ejemplo, en una base de datos de recetas, una receta puede tener varias revisiones, las revisiones tienen
un nico autor, y los autores pueden tener varias recetas. El definir la manera en que funcionan estas
relaciones te permite acceder a tus datos de manera intuitiva y potente.
El propsito de esta seccin es mostrarte cmo disear, definir y utilizar asociaciones entre
modelos en CakePHP.
Mientras que los datos pueden provenir de una variedad de orgenes, la form ms comn de

almacenamiento en aplicaciones web es una base de datos relacional. La mayora de cosas que cubre
esta seccin estar en ese contexto.
Para obtener informacin sobre asociaciones con modelos de Plugin, ver Plugin Models.
3.7.6.1 Tipos de Relaciones

Los cuatro tipos de relaciones en CakePHP son: hasOne, hasMany, belongsTo y


hasAndBelongsToMany (HABTM), "tiene un", "tiene muchos", "pertenece a" y "tiene y pertenece a
muchos", respectivamente.
Relacin
uno a uno

Tipo de Asociacin
hasOne ("tiene un")

uno a muchos hasMany ("tiene muchos")

Ejemplo
Un usuario tiene un perfil.
Los usuarios en un sistema pueden tener

mltiples recetas.
muchos a uno belongsTo ("pertenece a")
Una receta pertenece a un usuario.
muchos
a hasAndBelongsToMany ("tiene y pertenece Las recetas tienen, y pertenecen, a muchas
muchos

a muchos")

etiquetas.

Las asociaciones son definidas creando una variable de clase nombrada tras la asociacin que
ests definiendo. La variable de clase puede, a veces, ser tan simple como una cadena de caracteres,
pero puede ser tan completa como un array multidimensional usado para definir asociaciones concretas.
<?php
class Usuario extends AppModel {
var $name = 'Usuario';
var $hasOne = 'Pefil';
var $hasMany = array(
'Receta' => array(
'className' => 'Receta',
'conditions' => array('Receta.aprobada' => '1'),
'order'
=> 'Receta.created DESC'
)
);
}
?>

En el ejemplo de arriba, la primera instancia de la palabra 'Receta' es lo que se llama un 'Alias'.


Este es un identificador para la relacin y puede ser cualquier cosa que escojas. Normalmente,
escogers el mismo nombre que la clase que referencia. De todos modos, los alias han de ser nicos
dentro de un modelo dado y en ambas partes de una relacin belongsTo/hasMany o belongsTo/hasOne.
Escoger nombres no nicos para alias puede causar comportamiento inesperados.

3.7.6.2 hasOne

Configuremos un modelo Usuario con una relacin hasOne con un modelo Perfil.
Primero, necesitas establecer las claves de tus tablas de base de datos correctamente. Para que
funcione una relacin hasOne correctamente, una tabla ha de contener una clave fornea que apunte a
un registro en la otra. En este caso, la tabla 'perfiles' contendr un campo llamado usuario_id. El
patrn bsico es:
hasOne: el otro modelo contiene la clave fornea.
Relacin
Manzana hasOne Pltano
Usuario hasOne Perfil
Doctor hasOne Mentor

Esquema
plananos.manzana_id
perfiles.usuario_id
mentores.doctor_id

El archivo del modelo Usuario ser grabado en /app/models/usuario.php. Para definir


la asociacin 'Usuario hasOne Perfil', aade la propiedad $hasOne a la clase del modelo. Recuerda
tener un modelo Perfil en /app/models/perfil.php, o la asociacin no funcionar.
<?php
class Usuario extends AppModel {
var $name = 'Usuario';
var $hasOne = 'Perfil';
}
?>

Hay dos manera de describir esta relacin en tus archivos del modelo. La manera ms simple es
establecer el atributo $hasOne a una cadena de caracteres conteniendo el nombre de la clase del
modelo asociado, como hemos hecho arriba.
Si necesitas ms control, puedes definir tus asociaciones utilizando sintaxis de arrays. Por
ejemplo, podras desear limitar la asociacin para incluir slo ciertos registros.
<?php
class Usuario extends AppModel {
var $name = 'Usuario';
var $hasOne = array(
'Perfil' => array(
'className'
=> 'Perfil',
'conditions'
=> array('Perfil.publicado' => '1'),
'dependent'
=> true
)
);
}
?>

Las claves posibles para los arrays de asociaciones hasOne incluyen:


className: el nombre de la clase del modelo que est siendo asociado al modelo actual. si ests
definiendo una relacin 'Usuario hasOne Perfil', la clave className debera ser igual a
'Perfil'.
foreignKey: el nombre de la clave fornea que se encuentra en el otro modelo. Esto es
especialmente til si necesitas definir mltiples relaciones hasOne. El valor por defecto para
esta clave es el nombre en singular del modelo actual, seguido del sufijo '_id'. En el ejemplo de
arriba, debera ser por defecto 'usuario_id'.
conditions: Un fragmento SQL usado para filtrar registros del modelo relacionado. Es buena
prctica usar nombres de modelos en los fragmentos SQL: 'Perfil.aprobado = 1' siempre es
mejor que simplemente 'aprobado = 1'.
fields: Una lista de campos a ser devueltos cuando se traen los datos del modelo asociado. Por
defecto devuelve todos los campos.
dependent: Cuando la clave dependent se establece a true, y el mtodo delete() del
modelo es llamado con el parmetro $cascada con valor true, los registros del modelo
asociado tambin son borrados. En este caso lo ponemos a true de manera que borrando un
Usuario tambin borrar su Perfil asociado.
Una vez que esta asociacin ha sido definida, las operaciones de bsqueda en el modelo usuario traern
tambin el registro Perfil relacionado si existe:
// Resultados de ejemplo de una llamada a $this->Usuario->find()
Array
(
[Usuario] => Array
(
[id] => 121
[name] => Gwoo the Kungwoo
[created] => 2007-05-01 10:31:01
)
[Perfil] => Array
(
[id] => 12
[user_id] => 121
[habilidad] => Hornear Pasteles
[created] => 2007-05-01 10:31:01
)
)

3.7.6.3 belongsTo

Ahora que tenemos acceso a los datos de Perfil desde el modelo Usuario, definamos la
asociacin belongsTo (perteneceA) en el modelo Perfil para tener acceso a los datos de Usario
relacionados. La asociacin belongsTo es un complemento natural a las asociaciones hasOne (tieneUn)
y hasMany (tieneMuchos): nos permite ver los datos de la otra direccin.
A la hora de establecer las claves de las tablas de tu base de datos para una relacin belongsTo,
sigue estas convenciones:
belongsTo: el modelo actual contiene la clave fornea.
Relacin
Platano belongsTo Manzana
Perfil belongsTo Usuario
Mentor belongsTo Doctor

Esquema
platanos.manzana_id
perfiles.usuarios_id
mentores.doctores_id

Si un modelo (tabla) contiene una clave fornea, "perteneceA" (belongsTo) el otro modelo (tabla).
Podemos definir la asociacin belongsTo en nuestro modelo Perfil en /app/models/perfil.php
usando la sintaxis de cadena de caracteres as:
<?php
class Perfil extends AppModel {
var $name = 'Perfil';
var $belongsTo = 'Usuario';
}
?>

Tambin podemos definir una relacin ms especfica usando sintaxis de arrays:


<?php
class Perfil extends AppModel {
var $name = 'Perfil';
var $belongsTo = array(
'Usuario' => array(
'className'
=> 'Usuario',
'foreignKey'
=> 'usuario_id'
)
);
}
?>

Claves posibles para los arrays de la asociacin belongsTo son:


className: el nombre de la clase del modelo que se est asociando al modelo actual. Si ests
definiendo una relacin 'Perfil belongsTo Usuario', la clave className ha de tener el valor
'Usuario'.
foreignKey: el nombre de la clave fornea que se encuentra en el modelo actual. Esto es
especialmente til si necesitas definir mltiples relaciones belongsTo. El valor por defecto de
esta clave es el nombre en singular del otro modelo (separado por guiones de subrayado) con el
sufijo '_id'.
conditions: el fragmento SQL filtra los registros del modelo relacionado. Es buena prctica usar
el nombre de los modelos en los fragmentos SQL: 'Usuario.activo = 1' siempre es
mejor que simplemente 'activo = 1'.
fields: lista de campos a ser recuperados cuando los datos del modelo asociado se traen de la
base de datos. Por defecto devuelve todos los campos.
counterCache: (booleano) si se establece a true, el modelo asociado automticamente
incrementar o decrementar el campo '[nombre_modelo_en_singular]_count' de
la tabla fornea siempre que hagas un save() o delete() (ver counterCache). El valor en el
campo contador representa el nmero de filas relacionadas.
Una vez que esta asociacin ha sido definida, las operaciones de bsqueda en el modelo Perfil tambin
traern el registro de Usuario relacionado si existe:
// Resultados de ejemplo de la llamada a $this->Perfil->find().
Array
(
[Perfil] => Array
(
[id] => 12
[usuario_id] => 121
[habilidad] => Baking Cakes
[created] => 2007-05-01 10:31:01
)
[Usuario] => Array
(
[id] => 121
[name] => Gwoo the Kungwoo
[created] => 2007-05-01 10:31:01
)
)

3.7.6.4 hasMany

Siguiente paso: definiendo una asociacin "Usuario hasMany Comentario". Una asociacin
hasMany (tieneMuchos) nos permitir traer los comentarios del usuario cuando se trae un registro
Usuario.
A la hora de establecer las claves de las tablas de tu base de datos para una relacin hasMany, sigue
estas convenciones:
hasMany: el otro modelo contiene la clave fornea.
Relacin
Esquema
Usuario hasMany Comentario comentarios.usuario_id
Cake hasMany Virtud
virtudes.cake_id
Producto hasMany Opcion
opciones.producto_id
Podemos
definir
la
asociacin
hasMany

en

nuestro

modelo

Usuario

en

/app/models/usuario.php usando la sintaxis de cadena de caracteres as:


<?php
class Usuario extends AppModel {
var $name = 'Usuario';
var $hasMany = 'Comentario';
}
?>

Tambin podemos definir una relacin ms especfica usando sintaxis de arrays:


<?php
class Usuario extends AppModel {
var $name = 'Usuario';
var $hasMany = array(
'Comentario' => array(
'className'
=> 'Comentario',
'foreignKey'
=> 'usuario_id',
'conditions'
=> array('Comentario.estado' => '1'),
'order'
=> 'Comentario.created DESC',
'limit'
=> '5',
'dependent'=> true
)
);
}
?>

Las claves posibles para los arrays de la asociacin hasMany son:


className: el nombre de la clase del modelo que est siendo relacionado con el modelo actual.
Si ests definiendo una relacin 'Usuario hasMany Comentario', el valor de clasName ha de
ser 'Comentario'.

foreignKey: el nombre de la clave fornea en el otro modelo. Esto es especialmente til si


necesitas definir mltiples relaciones hasMany. El valor por defecto para esta clave es el
nombre en singular del otro modelo (separado por guiones de subrayado), con el sufijo '_id'.
conditions: un fragmento SQL filtra los registros del modelo relacionado. Es buena prctica
usar el nombre de los modelos en los fragmentos SQL: 'Usuario.activo = 1' siempre
es mejor que simplemente 'activo = 1'.
fields: lista de campos a ser recuperados cuando los datos del modelo asociado se traen de la
base de datos. Por defecto devuelve todos los campos.
order: un fragmento SQL que define el orden de las filas asociadas devueltas.
limit: el nmero mximo de filas asociadas que quieres que devuelva.
offset: el nmero de filas asociadas que quieres saltarte (dadas las condiciones y orden actuales)
antes de traer las filas y asociarlas.
dependent: Cuando dependent se establece a true, es posible el borrado recursivo del
modelo. En este ejemplo, los registros Comentario sern borrados cuando sus registros Usuario
asociados han sido borrados.
El segundo parmetro del mtodo Modelo->delete() ha de establecerse a true para que
ocurra un borrado recursivo.
finderQuery: Una consulta SQL completa que CakePHP puede usar para traer los registros del
modelo asociado. Esto debera ser usado en situaciones que requieren unos resultados muy
personalizados.
Una vez que esta asociacin ha sido definida, las operaciones de bsqueda en el modelo Usuario
tambin traern los registros Comentario relacionados si existen:
// Resultados de ejemplo de llamada a $this->Usuario->find().
Array
(
[Usuario] => Array
(
[id] => 121
[name] => Gwoo the Kungwoo
[created] => 2007-05-01 10:31:01
)
[Comentario] => Array
(
[0] => Array
(
[id] => 123
[usuario_id] => 121
[title] => On Gwoo the Kungwoo

[cuerpo] => The Kungwooness is not so Gwooish


[created] => 2006-05-01 10:31:01

)
[1] => Array
(
[id] => 123
[usuario_id] => 121
[title] => More on Gwoo
[cuerpo] => But what of the Nut?
[created] => 2006-05-01 10:41:01
)
)

Algo a recordar es que necesitars la asociacin complementaria 'Comentario belongsTo


Usuario' para obtener los datos en ambas direcciones. Lo que hemos esbozado en esta seccin te
permite obtener datos de Comentario desde Usuario. Aadir la asociacin 'Comentario belongsTo
Usuario' en el modelo comentario te permite obtener los datos de Usuario desde el modelo Comentario,
completando la conexin y permitiendo el flujo de la informacin desde ambas perspectivas del
modelo.
3.7.6.5 hasAndBelongsToMany (HABTM)

Perfecto. En este punto puedes llamarte "profesional de asociaciones del modelo de CakePHP".
Ya ests versado en tres de las asociaciones que tratan la mayora de las relaciones de objetos.
Tratemos el ltimo tipo de relacin: hasAndBelongsToMany (tieneYPerteneceAMuchos), o
HABTM. Esta asociacin es usada cuando tienes dos modelos que necesitas unir, repetidamente,
muchas veces, de muchas maneras distintas.
La principal diferencia entre hasMany y HABTM es que un enlace entre modelos en HABTM no
es exclusivo. Por ejemplo, vamos a unir nuestro modelo Receta con un modelo Etiqueta usando
HABTM. Atando la etiqueta 'Italiano' a la receta 'Gnocci' de mi abuela no 'acapara' la etiqueta; tambin
puedo etiquetar con 'Italiano' mis 'Espaguettis a la barbacoa con miel glaseada".
Los enlaces entre objetos asociados mediante hasMany son exclusivos. Si mi 'Usuario hasMany
Comentarios', un comentario est slo enlazado a un usuario especfico. Deja de estar disponible para
todos.
Andando. Necesitaremos establecer una tabla extra en la base de datos para manejar las
asociaciones HABTM. El nombre de esta nueva tabla de unin necesita incluir los nombres de ambos
modelos involucrados en plural, en orden alfabtico, y separados por un guin de subrayado ( _ ). El

esquema de la tabla debera contener como mnimo dos campos, cada uno clave fornea (que deberan
ser enteros) apuntando a ambas claves primarias de los modelos involucrados.
HABTM necesita una tabla de unin separada que incluya los nombres de ambos modelos.
Relacin
Esquema
Receta HABTM Etiqueta id, etiquetas_recetas.receta_id, etiquetas_recetas.etiqueta_id
Cake HABTM Fan
id, cakes_fans.cake_id, cakes_fans.fan_id
Foo HABTM Bar
id, bars_foos.foo_id, bars_foos.bar_id
Los nombres de las tablas estn, por convencin, en orden alfabtico.
Una vez que esta nueva tabla ha sido creada, podemos definir las asociaciones HABTM en los ficheros
del modelo. Vamos a saltar directamente a la sintaxis de arrays esta vez:
<?php
class Receta extends AppModel {
var $name = 'Receta';
var $hasAndBelongsToMany = array(
'Etiqueta' =>
array('className'
'joinTable'
'foreignKey'
'associationForeignKey'
'with'
'conditions'
'order'
'limit'
'unique'
'finderQuery'
'deleteQuery'
'insertQuery'
)
);
}
?>

=> 'Etiqueta',
=> 'etiquetas_recetas',
=> 'receta_id',
=> 'etiqueta_id',
=> '',
=> '',
=> '',
=> '',
=> true,
=> '',
=> '',
=> ''

Claves posibles para los arrays de asociaciones HABTM son:


className: el nombre de la clase del modelo que se est asociando al modelo actual. Si ests
definiendo una relacin 'Usuario hasAndBelongsToMany Comentarios', className debera
ser igual a 'Comentario'.
joinTable: el nombre de la tabla de unin usuada en esta asociacin (si si la tabla actual no se
adhiere a la convencin de nombrado para tablas de unin HABTM).
foreignKey: el nombre de la clave fornea que se encuentra en el modelo actual. Esto es
especialmente til si necesitas definir mltiples relaciones HABTM. El valor por defecto para
esta clave es el nombre en singular, separado por guiones de subrayado (_), del modelo actual

con el sufijo '_id'.


associationForeignKey: el nombre de la clave fornea que se encuentra en el otro modelo. Esto
es especialmente til si necesitas definir mltiples relaciones HABTM. El valor por defecto para
esta clave es el nombre en singulas, separado por guiones de subrayado (_), del modelo actual
con el sufijo '_id'.
with: define el nombre del modelo para la tabla de unin. Por defecto, CakePHP autocrear un
modelo por ti. Usando el ejemplo de arriba, se llamara EtiquetaReceta. Usando esta clave
puedes sustituir este nombre por defecto. El modelo de la tabla de unin puede ser usado como
cualquier modelo 'regular' para acceder a la tabla de unin directamente
conditions: fragmento SQL usado para filtrar registros del modelo relacionado. Es buena
prctica usar nombres de modelos en los fragmentos SQL: 'Comentario.estado = 1' siempre es
preferible a simplemente 'estado = 1'.
fields: lista de campos a ser devueltos cuando los datos del modelo asociado son trados.
Devuelve todos los campos por defecto.
order: fragmento SQL que define el orden de las filas asociadas devueltas.
limit: el nmero mximo de filas asociadas que deseas que sean devueltas.
unique: si tiene el valor true (valor por defecto) Cake borrar primero los registros de
relacin existentes en la tabla de claves forneas antes de insertar nuevas filas, cuando se
actualiza un registro. As, las asociaciones existentes debern ser pasadas de nuevo durante las
actualizaciones.
offset: el nmero de filas asociadas que omitir (dadas las condiciones actuales y orden) antes de
buscar y asociar.
finderQuery, deleteQuery, insertQuery: una consulta SQL completa que CakePHP puede usar
para buscar, borrar o crear nuevos registros del modelo asociado. Esto debera ser usado en
situaciones que requieren resultados muy personalizados.
Una vez que esta asociacin ha sido definida, las operaciones de bsqueda en el modelo Receta
tambin devolvern los registros Etiqueta relacionados si existen:
// Resultados de ejemplo de una llamada a $this->Receta->find().
Array
(
[Receta] => Array
(
[id] => 2745
[name] => Bombas de Cholocate con Azcar Glaseada

[created] => 2007-05-01 10:31:01


[usuario_id] => 2346

)
[Etiqueta] => Array
(
[0] => Array
(
[id] => 123
[name] => Desayuno
)
[1] => Array
(
[id] => 124
[name] => Postre
)
[2] => Array
(
[id] => 125
[name] => Enfermedad del Corazn
)
)
)

Recuerda definir una asociacin HABTM en el modelo Etiqueta si quieres traer datos de Receta
cuando uses el modelo Etiqueta.
Tambin es posible ejecutar consultas de bsqueda personalizadas basadas en relaciones
HABTM. Considera los ejemplos siguientes:
Asumiendo la misma estructura en el ejemplo de arriba (Receta HABTM Etiqueta), digamos que
queremos obtener todas las Recetas con la etiqueta 'Postre', una manera potencial (pero errnea) de
conseguirlo sera aplicar una condicin a la misma asociacin:
$this->Receta->bindModel(array(
'hasAndBelongsToMany' => array(
'Etiqueta' => array(
'conditions'=>array('Etiqueta.name'=>'Postr
e') )
)
)
);
$this->Receta->find('all');
// Datos devueltos
Array
(
0 => Array
{
[Receta] => Array
(
[id] => 2745
[name] => Bombas de Cholocate con Azcar Glaseada
[created] => 2007-05-01 10:31:01

[usuario_id] => 2346


)
[Etiqueta] => Array
(
[0] => Array
(
[id] => 124
[name] => Postre
)
)

)
1 => Array
{
[Receta] => Array
(
[id] => 2745
[name] => Pasteles de Cangrejo
[created] => 2008-05-01 10:31:01
[usuario_id] => 2349
)
[Etiqueta] => Array
(
}
}

Notar que este ejemplo devuelve TODAS las recetas pero slo la etiqueta 'Postre'. Para
conseguir nuestro objetivo adecuadamente, hay diversas maneras de hacerlo. Una opcin es buscar en
el modelo Etiqueta (en vez de Receta), lo que nos dar tambin todas las Recetas asociadas.
$this->Receta->Tag->find('all',
array('conditions'=>array('Etiqueta.name'=>'Postre')));

Podramos tambin usar el modelo de tabla de unin (que CakePHP nos provee), para buscar por un ID
dado.
$this->Receta->bindModel(array('hasOne' => array('EtiquetaReceta')));
$this->Receta->find('all', array(
'fields' => array('Receta.*'),
'conditions'=>array('EtiquetaReceta.etiqueta_id'=
>124) // id de Postre
));

Tambin es posible crear una asociacin extica con el propsito de crear tantas uniones como
necesarias para permitir el filtrado, por ejemplo:
$this->Receta->bindModel(
array(
'hasOne' => array(

'EtiquetaReceta',
'EtiquetaFiltro' => array(
'className' => 'Tag',
'foreignKey' => false,
'conditions' => array('EtiquetaFiltro.id =
EtiquetaReceta.id')
)

)
)

);
$this->Receta->find('all', array(
'fields' => array('Receta.*'),
'conditions'=>array('EtiquetaReceta.name'=>'Postre'
)
));

Ambos devolvern los siguientes datos:


// Datos devueltos
Array
(
0 => Array
{
[Receta] => Array
(
[id] => 2745
[name] => Bombas de Cholocate con Azcar Glaseada
[created] => 2007-05-01 10:31:01
[usuario_id] => 2346
)
[Etiqueta] => Array
(
[0] => Array
(
[id] => 123
[name] => Desayuno
)
[1] => Array
(
[id] => 124
[name] => Postre
)
[2] => Array
(
[id] => 125
[name] => Enfermedad del corazn
)
)
}

Para ms informacin sobre asociaciones de modelo ligadas al vuelo mira Creando y Destruyendo
Asociaciones al Vuelo
Mezcla y encaja tcnicas para conseguir tu objetivo especfico.

3.7.6.6 Creando y Destruyendo Asociaciones al Vuelo

Algunas veces es necesario crear y destruir asociaciones del modelo al vuelo. Esto puede ser por
varias razones:
Quieres reducir la cantidad de datos asociados buscados, pero todas tus asociaciones estn en el
primer nivel de recursin.
Deseas cambiar la manera en que la asociacin est definida para ordenar o filtar los datos
asociados.
Esta creacin y destruccin de asociaciones se realiza usando los mtodos del modelo de
CakePHP bindModel() y unbindModel(). Tambin hay un comportamiento muy til llamado
'Containable', mirar la seccin del manual sobre comportamientos empotrados para ms informacin.
Establezcamos unos pocos modelos para que podamos ver cmo funcionan bindModel() y
unbindModel(). Empezaremos con dos modelos:
<?php
class Lider extends AppModel {
var $name = 'Lider';
var $hasMany = array(
'Seguidor' => array(
'className' => 'Seguidor',
'order'
=> 'Seguidor.rango'
)
);
}
?>
<?php
class Seguidor extends AppModel {
var $name = 'Seguidor';
}
?>

Ahora, en el LideresController podemos usar el mtodo find() en el modelo Lider


para obtener un lider y sus seguidores asociados. Como puedes ver arriba, el array de asociacin en el
modelo Lider define una relacin 'Lider hasMany Seguidores'. Por motivos demostrativos, usemos
unbindModel() para eliminar esa asociacin en una accin de un controlador

function algunaAccion() {
// Esto obtiene Lideres, y sus Seguidores asociados
$this->Lider->findAll();
// Eliminemos el hasMany...
$this->Lider->unbindModel(
array('hasMany' => array('Seguidor'))
);
// Ahora usar una funcion find devolver
// Lideres, sin Seguidores
$this->Lider->findAll();
// NOTE: unbindModel slo afecta la siguiente funcin
// function. Una llamada adicional a find usar la
// informacin de la asociacin configurada.
// Hemos uado findAll() tras unbindModel(),
// as que esto obtendr Lideres con Seguidores asociados
// una vez ms...
$this->Lider->findAll();
}

Eliminar o aadir asociaciones usando bind- y unbindModel() slo funciona para la


operacin del modelo next() a menos que el segundo parmetro haya sido establecido a false. Si
el segundo parmetro ha sido establecido a false, la unin se mantiene para el resto de la peticin.
Aqu est el patrn bsico de uso para unbindModel():
$this->Modelo->unbindModel(
array('tipoAsociacion' => array('nombreDeClaseDelModeloAsociado'))
);

Ahora que hemos eliminado satisfactoriamente una asociacin al vuelo, aadamos otra. Nuestro
Lider 'sin todava' principios necesita algunos Principios asociados. El fichero del modelo para nuestro
modelo Principio est vaco, excepto por la declaracin var $name. Asociemos algunos Principios a
nuestro Lider al vuelo (pero recuerda, slo para la siguiente operacin de bsqueda). Esta funcin
aparece en LiderController:
function otraAccion() {
// No hay 'Lider hasMany Principio' en
// el fichero de modelo lider.php, asi que una bsqueda
// aqu slo obtiene Lideres.
$this->Lider->findAll();
// Usemod bindModel() para aadir una nueva asociacin
// al modelo Lider:
$this->Lider->bindModel(
array('hasMany' => array(
'Principio' => array(
'className' => 'Principio'
)

)
);

// Ahora que hemos asociado correctamente,


// podemos usar una funcin de bsqueda para obtener
// Lideres con sus principios asociados:
$this->Lider->findAll();

Ah lo tienes. El uso bsico para bindModel() es la encapsulacin de un array normal de


asociacin dentro de un array cuya clave es nombrada tras el tipo de asociacin que ests tratando de
crear:
$this->Modelo->bindModel(
array('nombreAsociacion' => array(
'nombreDeClaseDelModeloAsociado' => array(
// claves de asociacion normales van aqu...
)
)
)
);

A pesar de que el nuevo modelo unido no necesita ningn tipo de asociacin en la definicin de
su fichero de modelo, todava necesitar tener la clave correcta para que la nueva asociacin funcione
correctamente.
3.7.6.7 Mltiples relaciones al mismo modelo

Hay casos en los que un Modelo tiene ms de una relacin a otro Modelo. Por ejemplo podras
tener un Modelo Mensaje que tiene dos relaciones al Modelo Usuario. Una relacin con el usuario que
enva el mensaje y una segunda relacin con el usuario que recibe el mensaje. La tabla mensaje tendr
el campo usuario_id, pero tendr adems un campo receptor_id. Tu Modelo Mensaje lucira as::
<?php
class Mensaje extends AppModel {
var $name = 'Mensaje';
var $belongsTo = array(
'Emisor' => array(
'className' => 'Usuario',
'foreignKey' => 'usuario_id'
),
'Receptor' => array(
'className' => 'Usuario',
'foreignKey' => 'receptor_id'
)
);
}
?>

Receptor es un alias para el Modelo Usuario. Ahora veamos como se vera el Modelo Usuario.
<?php
class Usuario extends AppModel {
var $name = 'Usuario';
var $hasMany = array(
'MensajeEnviado' => array(
'className' => 'Mensaje',
'foreignKey' => 'usuario_id'
),
'MensajeRecibido' => array(
'className' => 'Mensaje',
'foreignKey' => 'receptor_id'
)
);
}
?>

3.7.6.8 Joining tables

In SQL you can combine related tables using the JOIN statement. This allows you to perform
complex searches across multiples tables (i.e: search posts given several tags).
In CakePHP some associations (belongsTo and hasOne) performs automatic joins to retrieve
data, so you can issue queries to retrieve models based on data in the related one.
But this is not the case with hasMany and hasAndBelongsToMany associations. Here is where
forcing joins comes to the rescue. You only have to define the necessary joins to combine tables and get
the desired results for your query.
To force a join between tables you need to use the "modern" syntax for Model::find(), adding a
'joins' key to the $options array. For example:
$options['joins'] = array(
array('table' => 'channels',
'alias' => 'Channel',
'type' => 'LEFT',
'conditions' => array(
'Channel.id = Item.channel_id',
)
)
);
$Item->find('all', $options);

Note that the 'join' arrays are not keyed.


In the above example, a model called Item is left joined to the channels table. You can alias the table
with the Model name, so the retrieved data complies with the CakePHP data structure.

The keys that define the join are the following:


table: The table for the join.
alias: An alias to the table. The name of the model associated with the table is the best bet.
type: The type of join: inner, left or right.
conditions: The conditions to perform the join.
With joins, you could add conditions based on Related model fields:
$options['joins'] = array(
array('table' => 'channels',
'alias' => 'Channel',
'type' => 'LEFT',
'conditions' => array(
'Channel.id = Item.channel_id',
)
)
);
$options['conditions'] = array(
'Channel.private' => 1
);
$privateItems = $Item->find('all', $options);

You could perform several joins as needed in hasBelongsToMany:


Suppose a Book hasAndBelongsToMany Tag association. This relation uses a books_tags table as join
table, so you need to join the books table to the books_tags table, and this with the tags table:
$options['joins'] = array(
array('table' => 'books_tags',
'alias' => 'BooksTag',
'type' => 'inner',
'conditions' => array(
'Books.id = BooksTag.books_id'
)
),
array('table' => 'tags',
'alias' => 'Tag',
'type' => 'inner',
'conditions' => array(
'BooksTag.tag_id = Tag.id'
)
)
);
$options['conditions'] = array(
'Tag.tag' => 'Novel'
);
$books = $Book->find('all', $options);

Using joins with Containable behavior could lead to some SQL errors (duplicate tables), so you need to
use the joins method as an alternative for Containable if your main goal is to perform searches based on
related data. Containable is best suited to restricting the amount of related data brought by a find
statement.
3.7.7 Mtodos Callback
Si necesitas colar alguna lgica justo antes o despus de una operacin de modelo de CakePHP,
utiliza los callbacks del modelo (funciones de retrollamada). Estas funciones pueden ser definidas en
clases del modelo (incluido tu AppModel). Asegrate de mirar el valor de retorno esperado para cada
una de estas funciones especiales.
3.7.7.1 beforeFind

beforeFind(mixed $datosConsulta)
Llamado antes de cualquier operacin relacionada con bsquedas. Los datos de consulta
$datosConsulta pasados a este callback contienen informacin sobre la consulta actual:
condiciones, campos, etc.
Si no deseas que la operacin de bsqueda comience (posiblemente basado en una decisin
relacionada con las opciones de $datosConsulta), devuelve false. De lo contrario, devuleve
$datosConsulta posiblemente modificado, o cualquier cosa que quieras pasar a la bsquea y sus
homlogos.
Deberas usar este callback para restringir las operaciones de bsqueda basado en el rol de un
usuario, o llevar a cabo decisiones de cacheo basadas en la carga actual.
3.7.7.2 afterFind

afterFind(array $resultados, bool $primario)


Usa este callback para modficar los resultados que han sido devueltos de una operacin de
bsqueda, o para realizar cualquier otra lgica tras la bsqueda. El parmetro $resultados pasado a
este callback contiene los resultados devueltos por la operacin de bsqueda del modelo, p.ej. algo
como:

$resultados = array(
0 => array(
'NombreModelo' => array(
'campo1' => 'valor1',
'campo2' => 'valor2',
),
),
);

Los valores devueltos por este callback deberan ser los resulados (posiblemente modificados)
de la operacin de bsqueda que dispararon este callback.
Si $primario es false, el formato de $resultados ser un poco diferente de lo que uno
debera esperar; en vez del resultado que obtendras normalmente de una operacin de bsqueda,
obtendras esto:
$resultados = array(
'campo_1' => 'valor',
'campo_2' => 'valor2'
);

El cdigo que espera que $primario sea true probablemente obtedr un error falta "Cannot
use string offset as an array" de PHP si se usa una bsqueda recursiva
Abajo se muestra un ejemplo de cmo afterFind puede ser usado para formateo de datos:
function afterFind($resultados) {
foreach ($resultados as $clave => $valor) {
if (isset($valor['Evento']['fechainicio'])) {
$resultados[$clave]['Evento']['fechainicio'] = $this>formatoFechaAfterFind($valor['Evento']['fechainicio']);
}
}
return $resultados;
}
function formatoFechatAfterFind($cadenaFecha) {
return date('d-m-Y', strtotime($cadenaFecha));
}

3.7.7.3 beforeValidate

beforeValidate()
Usa este callback para modificar datos del modelo antes de que sean validados. Tambin puede ser
usado para aadir reglas de validacin adicionales ms complejas usando Model::invalidate().
En este contexto, los datos del modelo son accesibles via $this->data. Esta funcin tambin debe
devolver true, de lo contrario la ejecucin actual de save() ser abortada.

3.7.7.4 beforeSave

beforeSave()
Sita cualquier lgica de antes de grabar en esta funcin. Esta funcin se ejecuta
inmediatamente despus de que los datos del modelo han sido satisfactoriamente validados, pero justo
antes de que los datos sean grabados. Esta funcin debera tambin devolver true si deseas que
contine la operacin de grabado.
Este callback es especialmente til para cualquier lgica de tratamiento de datos que necesita
ocurrir antes de que tus datos sean almacenados. Si tu mecanismo de almacenamiento necesita datos en
un formato especfico, accede a ellos mediante $this->data y modifcalos.
Abajo se muestra un ejemplo de cmo beforeSave puede ser usado para conversin de
fechas. El cdigo en el ejemplo es usado para una aplicacin con una fechainicio formateada
como AAAA-MM-DD en la base de datos y es mostrada como DD-MM-AAAA en la aplicacin. Por
supuesto, esto puede ser cambiado muy facilmente. Usa el cdigo siguiente en el modelo apropiado.
function beforeSave() {
if(!empty($this->data['Evento']['fechainicio']) && !empty($this>data['Evento']['fechafin'])) {
$this->data['Evento']['fechainicio'] = $this>formatoFechaBeforeSave($this->data['Evento']['fechainicio']);
$this->data['Evento']['fechafin'] = $this>formatoFechaBeforeSave($this->data['Evento']['fechafin']);
}
return true;
}
function formatoFechaBeforeSave($cadenaFecha) {
return date('Y-m-d', strtotime($cadenaFecha)); // Direction is from
}

Asegrate de que beforeSave() devuelve true, o tu grabado fallar.


3.7.7.5 afterSave

afterSave(boolean $creado)
Si tienes lgica que necesitas que sea ejecutada justo despus de cada operacin de grabacin,
colcala en este mtodo callback.
El valor de $creado ser true si fue creado un nuevo objeto (en vez de una actualizacin).

3.7.7.6 beforeDelete

beforeDelete(boolean $cascada)
Coloca en esta funcin cualquier lgica de antes de borrar. Esta funcin debera devolver true
si deseas que contine el borrado, y false si quieres que aborte.
El valor de $cascada ser true si los registros que dependen de este registro tambin sern
borrados.
3.7.7.7 afterDelete

afterDelete()
Coloca en este mtodo callback cualquier lgica que quieras que sea ejecutada despus de cada
borrado.
3.7.7.8 onError

onError()
Callback llamado si ocurre cualquier problema.
3.7.8 Atributos del Modelo
Los atributos del modelo te permiten establecer propiedades que pueden redefinir el
comportamiento por defecto del modelo.
Para una lista completa de los atributos del modelo y sus respectivas descripciones, visita la API
del CakePHP. Echa un vistazo a http://api.cakephp.org/1.2/class_model.html.
3.7.8.1 useDbConfig

La propiedad useDbConfig es un cadena de caracteres que especifica el nombre de la


conexin a la base de datos usada para enlazar tu clase modelo a la tabla de la base de datos
relacionada. Puedes estabecer el valor a cualquiera de las conexiones definidas dentro de tu fichero de
configuracin de tu base de datos. El fichero de configuracin de la base de datos se encuentra en
/app/config/database.php.
La propiedad useDbConfig tiene por defecto la conexin a la base de datos 'default' (
$useDbConfig = 'default'; )

Ejemplo de uso:
class Ejemplo extends AppModel {
var $useDbConfig = 'alternativo';
}

3.7.8.2 useTable

La propiedad $useTable especifica el nombre de la tabla de la base de datos. Por defecto, el


modelo usa la forma plural y en minsculas del nombre de la clase del modelo. Establece este atributo
al nombre de una tabla alternativa, o dale el valor false si deseas que el modelo no use una tabla de
base de datos.
Ejemplo de uso:
class Ejemplo extends AppModel {
var $useTable = false; // Este modelo no usa una tabla de base de datos
}

Alternativamente:
class Ejemplo extends AppModel {
var $useTable = 'exmp'; // Este modelo usa la tabla 'exmp' de la base de datos
}

3.7.8.3 tablePrefix

El nombre del prefijo de tabla usado para el modelo. El prefijo de tabla se establece
inicialmente en el fichero de conexin a la base de datos /app/config/database.php. Por
defecto es sin prefijo. Puedes sustituir la configuracin por defecto estableciendo el atributo
tablePrefix en el modelo.
Ejemplo de uso:
class Ejemplo extends AppModel {
var $tablePrefix = 'otros_'; // buscar la tabla 'otros_ejemplos'
}

3.7.8.4 primaryKey

Normalmente cada tabla tiene una clave primaria id. Puedes cambiar qu nombre de campo
usar el modelo como clave primaria. Esto es comn cuando se configura CakePHP para usar una tabla
de base de datos ya existente.
Ejemplo de uso:
class Ejemplo extends AppModel {
var $primaryKey = 'ejemplo_id'; // ejemplo_id es el nombre del campo en la
base de datos
}

3.7.8.5 displayField

El atributo displayField ('visualizarCampo') especifica qu campo de la base de datos debera ser


usado como etiqueta para el registro. La etiqueta se utiliza en scaffolding y en llamadas
find('lista'). El modelo usar por defecto el campo name o title.
Por ejemplo, para utilizar el campo nombre_de_usuario:
class Ejemplo extends AppModel {
var $displayField = 'nombre_de_usuario';
}

No se pueden combinar nombres de campos mltiples en un nico campo de display (de visualizacin).
Por ejemplo, no puedes especificar array('nombre',

'apellido') como campo de

visualizacin.
3.7.8.6 recursive

La propiedad $recursive define la profundidad a la que CakePHP ha de llegar para obtener


los datos de modelos asociados mediante los mtodos find() y findAll().
Imagina que tu aplicacin muestra Grupos que pertenecen a un Dominio que tiene muchos
Usuarios que, a su vez, tienen muchos Artculos. Puedes establecer $recursive con diferentes
valores basados en la cantidad de datos quieres obtener con una llamada a $this->Grupo->find():
Profundidad
-1
0
1

Descripcin
Cake obtiene slo los datos de Grupo, no realiza uniones (joins).
Cake obtiene datos de Grupo y su Dominio
Cake obtiene un Grupo, su Dominio y sus Usuarios asociados

Cake obtiene un Grupo, su Dominio, sus Usuarios asociados y los Artculos asociados a

los Usuarios
No lo establezcas a un valor mayor de lo que necesites. Hacer que CakePHP obtenga datos que

no vas a utilizar ralentiza tu aplicaci innecesariamente.


Si deseas combinar $recursive con la funcionalidad de $fields, necesitars aadir las
columnas que contienen las claves forneas necesarias al array fields manualmente. En el ejemplo
de arriba, esto podra significar aadir domain_id.
3.7.8.7 order

El criterio de ordenacin de datos por defecto para cualquier operacin de bsqueda. Algunos valores
posibles son:
$order
$order
$order
$order
$order
$order

=
=
=
=
=
=

"campo"
"Modelo.campo";
"Modelo.campo asc";
"Modelo.campo ASC";
"Modelo.campo DESC";
array("Modelo.campo" => "asc", "Modelo.campo2" => "DESC");

3.7.8.8 data

El contenedor para los datos del modelo que se han obtenido. A pesar de que los datos devueltos
por una clase del modelo normalmente se utilizan como los devueltos por una llamada a find(),
dentro de un callback del modelo necesitars acceder a la informacin almacenadana a travs de
$data.
3.7.8.9 _schema

Contiene metadatos describiendo los campos de tabla de la base de datos del modelo. Cada
campo es descrito por:
nombre
tipo (integer, string, datetime, etc.)
null
valor por defecto
longitud

3.7.8.10 validate

Este atributo contiene reglas que permiten al modelo realizar decisiones de validacin de datos
antes de grabar. Las claves nombradas tras los campos contienen expresiones regulares permitiendo al
modelo buscar correspondencias.
Para ms informacin, mira el captulo Validacin de Datos ms adelante en este manual.
3.7.8.11 virtualFields

Array of virtual fields this model has. Virtual fields are aliased SQL expressions. Fields added
to this property will be read as other fields in a model but will not be saveable.
Example usage for MySQL:
var $virtualFields = array(
'name' => "CONCAT(User.first_name, ' ', User.last_name)"
);

In subsequent find operations, your User results would contain a name key with the result of
the concatenation. It is not advisable to create virtual fields with the same names as columns on the
database, this can cause SQL errors.
For more information on the virtualFields property, its proper usage, as well as
limitations, see the section on virtual fields.
3.7.8.12 name

Como habrs visto antes en este captulo, el atributo $name es una caracterstica de
compatibilidad para los usuarios de PHP4 y se establece el valor al nombre del modelo.
Ejemplo de uso:
class Ejemplo extends AppModel {
var $name = 'Ejemplo';
}

3.7.8.13 cacheQueries

Si se establece a true, los datos obtenidos por el modelo durante una peticin son cacheados
(cached). Este cacheo es slo en memoria, y dura slo el tiempo de duracin de la peticin. Cualquier
peticin duplicada de los mismos datos es tratada por la cach.

3.7.9 Mtodos Personalizados y Propiedades


Aunque las funciones de modelo de CakePHP deberan llevarte donde necesites ir, no olvides
que las clases modelos son justamente eso: clases que te permiten escribir tus propios mtodos o definir
tus propias propiedades.
Cualquier operacin que maneja la grabacin o bsqueda de datos es mejor que est alojada en
tus clases modelo. Este concepto es a menudo referido como "fat model".
class Ejemplo extends AppModel {
function getReciente() {
$condiciones = array(
'created BETWEEN (curdate() - interval 7 day) and (curdate() - interval 0
day))'
);
return $this->find('all', compact($condiciones));
}
}

Ahora, este mtodo getReciente() puede ser usado dentro del controlador.
$reciente = $this->Ejemplo->getReciente();

3.7.9.1 Using virtualFields

Virtual fields are a new feature in the Model for CakePHP 1.3. Virtual fields allow you to create
arbitrary SQL expressions and assign them as fields in a Model. These fields cannot be saved, but will
be treated like other model fields for read operations. They will be indexed under the model's key
alongside other model fields.

How to create virtual fields


Creating virtual fields is easy. In each model you can define a $virtualFields property that
contains an array of field => expressions. An example of virtual field definitions would be:
var $virtualFields = array(
'name' => 'CONCAT(User.first_name, ' ', User.last_name)'
);

In subsequent find operations, your User results would contain a name key with the result of
the concatenation. It is not advisable to create virtual fields with the same names as columns on the

database, this can cause SQL errors.


Using virtual fields
Creating virtual fields is straightforward and easy, interacting with virtual fields can be done
through a few different methods.
Model::hasField()
Model::hasField() has been updated so that it can will return true if the model has a
virtualField with the correct name. By setting the second parameter of hasField to true,
virtualFields will also be checked when checking if a model has a field. Using the example field
above,
$this->User->hasField('name'); // Will return false, as there is no concrete field
called name
$this->User->hasField('name', true); // Will return true as there is a virtual
field called name

Model::isVirtualField()
This method can be used to check if a field/column is a virtual field or a concrete field. Will return true
if the column is virtual.
$this->User->isVirtualField('name'); //true
$this->User->isVirtualField('first_nname'); //false

Model::getVirtualField()
This method can be used to access the SQL expression that comprises a virtual field. If no argument is
supplied it will return all virtual fields in a Model.
$this->User->getVirtualField('name');

//returns

'CONCAT(User.first_name,

'

',

User.last_name)'

Model::find() and virtual fields


As stated earlier Model::find() will treat virtual fields much like any other field in a model. The
value of a virtual field will be placed under the model's key in the resultset. Unlike the behavior of
calculated fields in 1.2
$results = $this->User->find('first');
// results contains the following
array(
'User' => array(

'first_name' => 'Mark',


'last_name' => 'Story',
'name' => 'Mark Story',
//more fields.

)
);

Pagination and virtual fields


Since

virtual

fields

behave

much

like

regular

fields

when

doing

find's,

Controller::paginate() has been updated to allows sorting by virtual fields.


3.7.10 Virtual fields
Virtual fields are a new feature in the Model for CakePHP 1.3. Virtual fields allow you to create
arbitrary SQL expressions and assign them as fields in a Model. These fields cannot be saved, but will
be treated like other model fields for read operations. They will be indexed under the model's key
alongside other model fields.
3.7.10.1 Creating virtual fields

Creating virtual fields is easy. In each model you can define a $virtualFields property
that contains an array of field => expressions. An example of a virtual field definition using MySQL
would be:
var $virtualFields = array(
'full_name' => 'CONCAT(User.first_name, " ", User.last_name)'
);

1. var $virtualFields = array(


2. 'full_name' => 'CONCAT(User.first_name, " ", User.last_name)'
3. );
And with PostgreSQL: Plain Text View
var $virtualFields = array(
'name' => 'User.first_name || \' \' || User.last_name'
);

In subsequent find operations, your User results would contain a name key with the result of
the concatenation. It is not advisable to create virtual fields with the same names as columns on the
database, this can cause SQL errors.
It is not always useful to have User.first_name fully qualified. If you do not follow the
convention (i.e. you have multiple relations to other tables) this would result in an error. In this case it

may be better to just use first_name || \'\' || last_name without the Model Name.
3.7.10.2 Using virtual fields

Creating virtual fields is straightforward and easy, interacting with virtual fields can be done
through a few different methods.
Model::hasField()
Model::hasField() has been updated so that it can return true if the model has a virtualField with the
correct name. By setting the second parameter of hasField to true, virtualFields will also be checked
when checking if a model has a field. Using the example field above,
$this->User->hasField('name'); // Will return false, as there is no concrete field
called name
$this->User->hasField('name', true); // Will return true as there is a virtual
field called name

Model::isVirtualField()
This method can be used to check if a field/column is a virtual field or a concrete field. Will return true
if the column is virtual.
$this->User->isVirtualField('name'); //true
$this->User->isVirtualField('first_name'); //false

Model::getVirtualField()
This method can be used to access the SQL expression that comprises a virtual field. If no
argument is supplied it will return all virtual fields in a Model.
$this->User->getVirtualField('name'); //returns 'CONCAT(User.first_name, ' ',
User.last_name)'

Model::find() and virtual fields


As stated earlier Model::find() will treat virtual fields much like any other field in a
model. The value of a virtual field will be placed under the model's key in the resultset. Unlike the
behavior of calculated fields in 1.2
$results = $this->User->find('first');
// results contains the following
array(
'User' => array(
'first_name' => 'Mark',
'last_name' => 'Story',
'name' => 'Mark Story',
//more fields. ) );

Pagination and virtual fields


Since

virtual

fields

behave

much

like

regular

fields

when

doing

find's,

Controller::paginate() has been updated to allows sorting by virtual fields.


3.7.10.3 Virtual fields and model aliases

When you are using virtualFields and models with aliases that are not the same as their name,
you can run into problems as virtualFields do not update to reflect the bound alias. If you are using
virtualFields in models that have more than one alias it is best to define the virtualFields in your
model's constructor
function __construct($id = false, $table = null, $ds = null) {
parent::__construct($id, $table, $ds);
$this->virtualFields['name'] = sprintf('CONCAT(%s.first_name,
%s.last_name)', $this->alias, $this->alias);
}

"

",

This will allow your virtualFields to work for any alias you give a model.
3.7.10.4 Limitations of virtualFields

The implementation of virtualFields in 1.3 has a few limitations. First you cannot use
virtualFields on associated models for conditions, order, or fields arrays. Doing so will generally
result in an SQL error as the fields are not replaced by the ORM. This is because it difficult to estimate
the depth at which an associated model might be found.
A common workaround for this implementation issue is to copy virtualFields from one
model to another at runtime when you need to access them.
$this->virtualFields['full_name'] = $this->Author->virtualFields['full_name'];

Alternatively, you can define $virtualFields in your model's constructor, using $this>alias, like so:
public function __construct($id=false,$table=null,$ds=null){
parent::__construct($id,$table,$ds);
$this->virtualFields = array(
'name'=>"CONCAT(`{$this->alias}`.`first_name`,'
>alias}`.`last_name`)"
);
}

',`{$this-

3.7.11 Transactions
To perform a transaction, a model's tables must be of a type that supports transactions.
All transaction methods must be performed on a model's DataSource object. To get a model's
DataSource from within the model, use:
$dataSource = $this->getDataSource();

You can then use the data source to start, commit, or roll back transactions.
$dataSource->begin($this);
//Perform some tasks
if(/*all's well*/) {
$dataSource->commit($this);
} else {
$dataSource->rollback($this);
}

Nested transactions are currently not supported. If a nested transaction is started, a commit will
return false on the parent transaction.

3.8 Comportamientos
Los comportamientos del modelo (Model behaviors) son una manera de organizar parte de la
funcionalidad definida en los modelos de CakePHP. Nos permiten separar la lgica que puede no estar
relacionada directamente con un modelo, pero que necesita estar ah. Proveyendo una manera simple
pero potente manera de extender modelos, los comportamientos nos permiten atar funcionalidad a los
modelos definiendo una simple variable de clase. As es como los comportamientos permiten a los
modelos deshacerse de todo el peso extra que no debera ser parte de contrato de negocio que estn
modelando, o al menos es necesario en diferentes modelos y puede, entonces, ser extrapolado.
Como ejemplo, considera un modelo que nos da acceso a una tabla de una base de datos la cual
almacena informacin estructural de un rbol. Eliminando, aadiendo y migrando nodos en el rbol no
es tan simple como borrar, insertar y editar filas en una tabla. Muchos registros debern ser
actualizados segn las cosas se mueven. En vez de crear esos mtodos de manipulacin del rbol en
cada base de modelo (para todo modelo que necesita dicha funcionalidad), podramos simplemente
decirle a nuestro modelo que utilize el TreeBehavior (ArbolComportamiento), o en trminos ms
formales, decirle a nuestro modelo que se comporte como un rbol. Esto es conocido como atar un

comportamiento a un modelo. Con slo una lnea de cdigo, nuestro modelo de CakePHP toma todo un
nuevo conjunto de mtodos que le permiten interactuar con la estructura subyacente.
CakePHP ya incluye comportamientos para estructuras de rbol, contenido traducido,
interaccin con listas de control de acceso, sin comentar los comportamientos aportados por la
comunidad disponibles en CakePHP Bakery. En esta seccin cubriremos el patrn bsico de uso para
aadir comportamientos a modelos, cmo utilizar los comportamientos de CakePHP incorporados y
cmo crear uno nosotros mismos.
3.8.1 Utilizando Comportamientos
Los comportamientos son atados a modelos mediante la variable de clase del modelo $actsAs:
<?php
class Category extends AppModel {
var $name
= 'Category';
var $actsAs = array('Tree');
}
?>

Este ejemplo muestra cmo un modelo de Category puede ser manejado en una estructura de
rbol utilizando el comportamiento de rbol (TreeBehavior). Una vez que un comportamiento ha sido
especificado, utiliza los mtodos aadidos por el comportamiento como si siempre existiesen como
parte del modelo original:
// Set ID
$this->Category->id = 42;
// Utilizar un mtodo de comportamiento, children():
$kids = $this->Category->children();

Algunos comportamientos pueden requerir o permitir opciones a ser definidas cuando el


comportamiento es atado al modelo. Aqu, decimos a nuestro TreeBehavior (comportamiento de rbol)
los nombres de los campos left (izquierdo) y right (derecho) en la tabla de base de datos subyacente:
<?php
class Category extends AppModel {
var $name
= 'Category';
var $actsAs = array(
'Tree' => array(
'left' => 'left_node',
'right' => 'right_node'
)
); } ?>

Podemos tambin atar varios comportamientos a un modelo. No hay razn por la que, por
ejemplo, nuestro modelo Category deba slo comportarse como un rbol, tambin puede necesitar
soporte de internacionalizacin:
<?php
class Category extends AppModel {
var $name
= 'Category';
var $actsAs = array(
'Tree' => array(
'left' => 'left_node',
'right' => 'right_node'
),
'Translate'
);
}
?>

Hasta el momento hemos estado aadiendo comportamientos a modelos utilizando una variable
de la clase. Eso significa que nuestros comportamientos sern atados a muestros modelos durante todo
el tiempo de vida del modelo. Sin embargo, puede ser que necesitemos "desatar" comportamientos de
nuestros modelos en tiempo de ejecucin. Digamos que en nuestro modelo Category anterior, el cual
est actuando como un modelo Tree y Translate, necesitamos por alguna razn forzar a que deje de
actuar como un modelo Translate:
// Desata un comportamiento de nuestro modelo:
$this->Category->Behaviors->detach('Translate');

Eso har que nuestro modelo Category deje de comportarse como un modelo Translate desde
ese momento. Tal vez necesitemos, en cambio, simplemente desactivar el comportamiento Translate de
actuar sobre operaciones normales del modelo: nuestras bsquedas, grabados, etc. De hecho, estamos
buscando desactivar el comportamiento de actuar sobre nuestros callbacks del modelo de CakePHP. En
vez de desatar el comportamiento, le decimos a nuestro modelo que pare de informar sobre dichos
callbacks al comportamiento Translate:
// Parar de dejar al comportamiento manejar los callbacks de nuestro modelo
$this->Category->Behaviors->disable('Translate');

Tambin necesitaremos saber si nuestro comportamiento est manejando los callbacks del
modelo, y si no, restauramos su habilidad para reaccionar a ellos:
// Si nuestro comportamiento no est manejando los callbacks del modelo
if (!$this->Category->Behaviors->enabled('Translate')) {
// Decirle que comience a hacerlo
$this->Category->Behaviors->enable('Translate'); }

Tal como podemos desatar completamente un comportamiento de un modelo en tiempo de


ejecucin, tambin podemos atar nuevos comportamientos. Digamos que nuestro modelo Category
necesita empezar a comportarse como un modelo Christmas (Navidad), pero slo en el da de Navidad:
// Si hoy es 25 de diciembre
if (date('m/d') == '12/25') {
// Nuestro modelo necesita comportarse como un modelo Christmas
$this->Category->Behaviors->attach('Christmas');
}

Podemos tambin utilizar el mtodo attach() para sobreescribir las opciones de comportamiento:
// Cambiaremos una opcin de nuestro ya atado comportamiento
$this->Category->Behaviors->attach('Tree', array('left' => 'new_left_node'));

Tambin hay un mtodo para obtener la lista de comportamientos atados a un modelo:


attached(). Si pasamos el nombre de un comportamiento al mtodo, nos dir si dicho comportamiento
est atado al modelo; de cualquier otra manera nos dar una lista de los comportamientos atados.
// Si el comportamiento "Translate" no est atado al modelo
if (!$this->Category->Behaviors->attached('Translate')) {
// Obtener la lista de todos los comportamientos atados al modelo
$behaviors = $this->Category->Behaviors->attached();
}

3.8.2 Creando Comportamientos Personalizados


3.8.3 Creating behavior methods
Behavior methods are automatically available on any model acting as the behavior. For example
if you had:
class Duck extends AppModel {
var $name = 'Duck';
var $actsAs = array('Flying');
}

You would be able to call FlyingBehavior methods as if they were methods on your Duck
model. When creating behavior methods you automatically get passed a reference of the calling model
as the first parameter. All other supplied parameters are shifted one place to the right. For example
$this->Category->fly('toronto', 'montreal');

Although this method takes two parameters, the method signature should look like:

function fly(&$Model, $from, $to) {


// Do some flying.
}

Keep in mind that methods called in a $this->doIt() fashion from inside a behavior
method will not get the $model parameter automatically appended.
3.8.4 Behavior callbacks
Model Behaviors can define a number of callbacks that are triggered before/after the model
callbacks of the same name. Behavior callbacks allow your behaviors to capture events in attached
models and augment the parameters or splice in additional behavior.
The available callbacks are:
beforeValidate is fired before a model's beforeValidate
beforeFind is fired before a model's beforeFind
afterFind is fired before a model's afterFind
beforeSave is fired before a model's beforeSave
afterSave is fired before a model's afterSave
beforeDelete is fired after a model's beforeDelete
afterDelete is fired before a model's afterDelete
3.8.5 Creating a behavior callback
Model behavior callbacks are defined as simple methods in your behavior class. Much like
regular behavior methods, they receive a $Model parameter as the first argument. This parameter is
the model that the behavior method was invoked on.
function beforeFind(&$model, $query)
If a behavior's beforeFind return's false it will abort the find(). Returning an array will augment
the query parameters used for the find operation.
afterFind(&$model, $results, $primary)
You can use the afterFind to augment the results of a find. The return value will be passed on as
the results to either the next behavior in the chain or the model's afterFind.

beforeDelete(&$model, $cascade = true)


You can return false from a behavior's beforeDelete to abort the delete. Return true to allow it
continue.
afterDelete(&$model)
You can use afterDelete to perform clean up operations related to your behavior.
beforeValidate(&$model)
You can use beforeValidate to modify a model's validate array or handle any other prevalidation logic. Returning false from a beforeValidate callback will abort the validation and cause it to
fail.

3.9 DataSources (fuentes de datos)


DataSources son el enlace entre los modelos y la fuente de datos que cada modelo representa.
En muchos caos, los datos son recuperados de una base de datos relacional, como MySQL, PostgreSQL
o MSSQL. CakePHP se distribuye con varias datasources especficas para varias bases de datos
(consulta los archivos de clases dbo_* class files en cake/libs/model/datasources/dbo/),
aqu se lista un resumen de los mismos para tu comodidad:
dbo_adodb.php
dbo_db2.php
dbo_firebird.php
dbo_mssql.php
dbo_mysql.php
dbo_mysqli.php
dbo_odbc.php
dbo_oracle.php
dbo_postgres.php
dbo_sqlite.php
dbo_sybase.php
Cuando

se

especifica

una

configuracin

de

conexin

base

de

datos

en

app/config/database.php, CakePHP usa de forma transparente la datasource correspondiente

a la base de datos para todas las operaciones con modelos. Por eso, aunque creas que no sabes nada de
datasources, ya las has estado usando desde siempre.
Todas las fuentes de datos indicadas arriba derivan de una clase base DboSource la cual aade
alguna lgica comn a la mayora de bases de datos relaciones. Si decides crear una datasource
RDBMS, tu mejor apuesta es trabajar a paritr de una de ellas (por ejemeplo: dbo_mysql.php o
dbo_mssql.php) La mayor parte de la gente, sin embargo, est interesada en escribir datasources
para fuentes de datos externas, como APIs REST remotas o incluso servidores LDAP. As que eso es lo
que vamos a examinar en adelante.
3.9.1 API bsica para DataSources
Una datasource puede, y debera implementar al menos uno de los siguientes mtodos:
create, read, update y/o delete (la signatura y detalles de implementacin no son importantes
en este momento, y sern descritos ms tarde). No necesitas implementar ms mtodos de los
necesarios de los descritos arriba - si ests escribiendo una datasource de slo-lectura, no hay razn
para implementar create y update.
Mtodos que deben ser implementados
describe($model)
listSources()
Al menos uno de:
create($model, $fields = array(), $values = array())
read($model, $queryData = array())
update($model, $fields = array(), $values = array())
delete($model, $id = null)
Es posible tambin (y muchas veces bastante til) definir el atributo de clase $_schema dentro
la datasource misma, en lugar de en el modelo. Y esto es casi todo lo que hay. Emparejando una
datasource a un modelo podrs utilizar Model::find()/save/() como haras normalmentem y
los datos y/o parmetros adecuados sern usados para llamar a esos mtodos sern pasados a la propia
datasource, donde puedes decidir implementar cualquier prestacin que necesites (por ejemplo:
opciones para Model::find como procesasr 'conditions', 'limit' o incluso tus propios
parmetros a medida).

3.9.2 Un ejemplo
Lo que sigue es un ejemplo simple de como usar dataSources y HttpSocket para
implementar una fuente muy bsica de Twitter que nos permita utilizar la API de twitter y enviar
nuestras actualizaciones.
Este ejemplo slo funcionar sobre PHP 5.2 o superior, debido al uso de json_decode para
procesar los datos en formato JSON.
Tendrs

que

colocar

la

datasource

para

Twitter

en

tu

app/models/datasources/twitter_source.php:
<?php
/**
* Twitter DataSource
*
* Utilizada para leer y escribir en Twitter usando modelos.
*
* PHP Version 5.x
*
* CakePHP(tm) : Rapid Development Framework (http://www.cakephp.org)
*
Copyright
2005-2009,
Cake
Software
Foundation,
Inc.
(http://www.cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @filesource
*
@copyright
Copyright
2009,
Cake
Software
Foundation,
Inc.
(http://www.cakefoundation.org)
* @link
http://cakephp.org CakePHP(tm) Project
* @license
http://www.opensource.org/licenses/mit-license.php The MIT
License
*/
App::import('Core', 'HttpSocket');
class TwitterSource extends DataSource {
protected $_schema = array(
'tweets' => array(
'id' => array(
'type' => 'integer',
'null' => true,
'key' => 'primary',
'length' => 11,
),
'text' => array(
'type' => 'string',
'null' => true,
'key' => 'primary',
'length' => 140
),
'status' => array(
'type' => 'string',
'null' => true,

),

'key' => 'primary',


'length' => 140

);
public function __construct($config) {
$auth = "{$config['login']}:{$config['password']}";
$this->connection = new HttpSocket(
"http://{$auth}@twitter.com/"
);
parent::__construct($config);
}
public function listSources() {
return array('tweets');
}
public function read($model, $queryData = array()) {
if (!isset($queryData['conditions']['username'])) {
$queryData['conditions']['username'] = $this>config['login'];
}
$url = "/statuses/user_timeline/";
$url .= "{$queryData['conditions']['username']}.json";
$response = json_decode($this->connection->get($url), true);
$results = array();
foreach ($response as $record) {
$record = array('Tweet' => $record);
$record['User'] = $record['Tweet']['user'];
unset($record['Tweet']['user']);
$results[] = $record;
}
return $results;
}
public function create($model, $fields = array(), $values = array()) {
$data = array_combine($fields, $values);
$result = $this->connection->post('/statuses/update.json', $data);
$result = json_decode($result, true);
if (isset($result['id']) && is_numeric($result['id'])) {
$model->setInsertId($result['id']);
return true;
}
return false;
}
public function describe($model) {
return $this->_schema['tweets'];
}
}
?>

La implementacin de tu modelo puede ser tan simple como:


<?php
class Tweet extends AppModel {
public $useDbConfig = 'twitter';
}
?>

Si no hemos definido nuestro esquema en la propia datasource, nos dar un mensaje de error al
efecto aqu.
Y los ajustes de configuracin en tu app/config/database.php se parecern a estos:
<?php

var $twitter = array(


'datasource' => 'twitter',
'login' => 'username',
'password' => 'password',
);

?>

Usando los familiares mtodos de modelo desde un controlador:


<?php
// Usar el nombre de usuario definido en $twitter como se mostr arriba:
$tweets = $this->Tweet->find('all');
// Encontrar tweets de otros usuario
$conditions= array('username' => 'caketest');
$otherTweets = $this->Tweet->find('all', compact('conditions'));
?>

De forma similar, guardando una actualizacin del estatus:


<?php
$this->Tweet->save(array('status' => 'This is an update'));
?>

3.10 Vistas
3.10.1 Plantillas de la Vista
La capa vista de CakePHP es cmo hablas a tus usuarios. La mayor parte del tiempo tu vista
estar mostrando documentos (X)HTML a los navegadores, pero tal vez necesites servir datos AMF a
un objeto Flash, responder a una aplicacin remota mediante SOAP o producir un fichero CSV para un
usuario.
Los ficheros de vista de CakePHP estn escritos en PHP plano y tienen la extensin .ctp
(CakePHP Template) por defecto . Estos ficheros contienen toda la lgica de representacin necesaria
para obtener los datos recibidos del controlador en un formato que est preparado para la audiencia a la
que ests atendiendo.
Los ficheros de vista se almacenan en /app/views/, en una carpeta nombrada tras el
controlador que usa los ficheros, y nombrada tras la accin a la que corresponde. Por ejemplo, el
fichero de vista para el la accin view() del controlador Productos, normalmente, se encontrara en
/app/views/productos/view.ctp.
La capa vista en CakePHP puede estar formada por un nmero diferentes de partes. Cada parte
tiene usos diferentes, y ser tratado en este captulo:
layouts (diseos): ficheros de vista que contienen el cdigo de presentacin que se encuentra
envolviendo muchas interfaces en tu aplicacin. La mayora de vistas son 'renderizadas'
(presentadas) dentro de un layout (diseo).
elements (elementos): trozo de cdigo de vista ms pequeo y reutilizable. Los elementos
generalmente son renderizados dentro de vistas.
helpers (ayudantes): estas clases encapsulan lgica de vista que es necesaria en muchas partes
en la capa vista. Adems de otras cosas, los ayudantes en CakePHP pueden ayudarte a construir
formularios, construir funcionalidad AJAX, paginar los datos del modelo o servir feeds RSS.
3.10.2 Layouts
Un diseo contiene el cdigo de presentacin que envuelve una vista. Cualquier cosa que
quieras ver en todas tus vistas debera estar situada en un layout.
Los ficheros de diseo deberan situarse en /app/views/layouts. El diseo por defecto de

CakePHP

puede

ser

sustituido

creando

un

nuevo

diseo

por

defecto

en

/app/views/layouts/default.ctp. Una vez que ha sido creado un nuevo diseo, el cdigo


de la vista renderizado por el controlador se coloca dentro del diseo por defecto cuando la pgina es
renderizada.
Cuando creas un diseo, necesitas decirle a CakePHP dnde colocar el cdigo para tus vistas.
Para hacer eso, estate seguro que tu diseo incluye un lugar para $content_for_layout (y
opcionalmente, $title_for_layout). Aqu est un ejemplo de a lo que debera parecerse un
diseo por defecto:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title><?php echo $title_for_layout?></title>
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
<!-- Incluir ficheros y scripts externos aqu (Mirar el ayudante HTML para ms
informacin -->
<?php echo $scripts_for_layout ?>
</head>
<body>
<!-- Si quieres algn tipo de men que mostrar en todas tus vistas, incluyelo
aqu -->
<div id="cabecera">
<div id="menu">...</div>
</div>
<!-- Aqu es donde quiero que se vean mis vistas -->
<?php echo $content_for_layout ?>
<!-- Aadir un pie de pgina a cada pgina mostrada -->
<div id="pie">...</div>
</body>
</html>

$scripts_for_layout contiene cualquier fichero externo y scripts incluidos con el ayudante


HTML incrustado. Es ltil para incluir ficheros javascript y CSS de las vistas.
Cuando uses $html->css() o $javascript->link() en los ficheros de vista, especifica
false en el argumento 'in-line' para colocar el fuente html en $scripts_for_layout. (Mirar
API para ms detalles de uso).
$content_for_layout contiene la vista. Aqu es donde ser colocado el cdigo de la vista.
$title_for_layout contiene el ttulo de la pgina.

Para establecer el ttulo para el diseo, es fcil hacerlo en el controlador, estableciendo el valor de la
variable $title_for_layout.
<?php
class UsuariosController extends AppController {
function verActivos() {
$this->set('title_for_layout', 'Ver Usuarios Activos');
}
}
?>

Puedes crear tantos diseos como desees: simplemente colcalos en el directorio


app/views/layouts e intercambialos dentro de tus acciones del controlador usando la variable
$layout del cotrolador, o la funcin setLayout().
Por ejemplo, si una seccin de mi site incluye un espacio menor con banner de publicidad,
debera crear un nuevo diseo (layout) con el espacio publicitario menor, especificndolo como el
diseo para todas las acciones del controlador haciendo algo como:
var $layout = 'publicidad_pequena_pordefecto';

<?php
class UsuariosController extends AppController {
function verActivos() {
$this->set('title_for_layout', 'Ver Usuarios Activos');
$this->layout = 'publicidad_pequena_pordefecto';
}

}
?>

function verImagen() {
$this->layout = 'imagen';
//mostrar la imagen del usuario
}

CakePHP ofrece dos diseos comunes (adems del diseo por defecto de CakePHP) que puedes
usar en tus propias aplicaciones: 'ajax' y 'flash'. El diseo Ajax es til para contruir las respuestas Ajax;
es un diseo vaco (la mayora de las llamadas ajax slo requiren una pocas etiquetas como respuesta,
ms que una interfaz completa). El diseo flash es usado por mensajes mostrados por el mtodo
flash() del controlador.
Existen otros tres diseos: xml, js y rss en el ncleo como una manera rpida y fcil de servir
contenido que no sea text/html.

3.10.3 Elementos
Muchas aplicaciones tienen pequeos bloques de cdigo de presentacin que necesita ser
repetido de pgina en pgina, algunas veces en diferentes lugares del diseo. CakePHP puede ayudarte
a repetir partes de tu website que necesitan ser reutilizadas. Estar partes reutilizadas son llamadas
Elementos. Anuncios, cajas de ayuda, controles de navegacin, mens extras, formularios de login y
llamadas estn a menudo implementadas en CakePHP en forma de elementos. Un elemento es
bsicamente una minivista que puede ser incluido en otras vistas, en diseos, e incluso dentro de otros
elementos. Los elementos pueden ser usados para hacer una vista ms legible, situando el renderizado
de elementos que se repiten en sus propios ficheros. Pueden tambin ayudarte a reutilizar fragmentos
de contenido en tus aplicaciones.
Los elementos estn en la carpeta /app/views/elements/ y tienen la extensin de
archivo .ctp. Son mostrados usando el mtodo element() de la vista.
<?php echo $this->element('cajaayuda'); ?>

3.10.3.1 Pasar Variables a un elemento

Puedes pasarle datos a un elemento usando el segundo argumento de element():


<?php echo
$this->element('helpbox',
array("helptext" => "Oh, this text is very helpful."));
?>

Dentro del archivo del elemento, todas las variables pasadas estan disponibles como miembros
del array de parmetros (de la misma manera que set() en el controlador funciona con los archivos
de las vistas). En el ejemplo siguiente, el archivo /app/views/elements/helpbox.ctp puede
usar la variable $helptext.
<?php
echo $helptext; //outputs "Oh, this text is very helpful."
?>

La funcin element() combina opciones para el elemento con los datos a pasar en element.
Las dos opciones son 'cache' y 'plugin'. Un ejemplo:

<?php echo
$this->element('helpbox',
array(
"helptext" => "Esto es pasado al elemento como $helptext"
"foobar" => "Esto es pasado al elemento como $foobar"
"cache" => "+2 days" //setea el 'cacheo' a +2 das.
"plugin" => "" //para renderizar un elemento desde un plugin
)
);
?>

Para tener en cache distintas versiones del mismo elemento en una aplicacin, provee una clave
nica de cache usando el siguiente formato:
<?php
$this->element('helpbox',
array(
"cache" => array('time'=> "+7 days",'key'=>'unique value')
)
);
?>

Puedes

aprovechar

bien

los

elementos

usando

requestAction().

La

funcin

requestAction() trae las variables desde una accin de controlador y las retorna como un array.
Esto permite que tus elementos cumplan con el diseo MVC. Crea una accin de controlador que
prepare las variables de la vista para tus elementos, luego haz la llamada requestAction() dentro
del segundo parmetro de element() para proveerle al elemento las variables de vista desde tu
controlador.
Para hacer esto, en tu controlador aade algo como lo siguiente, para el ejemplo de Post.
<?php
class PostsController extends AppController {
...
function index() {
$posts = $this->paginate();
if (isset($this->params['requested'])) {
return $posts;
} else {
$this->set(compact('posts'));
}
}
}
?>

Ahora en el elemento podemos acceder el modelo de posts paginados. Para tener los ltimos
cinco posts en una lista ordenada deberamos hacer lo siguiente:

<h2>Latest Posts</h2>
<?php $posts = $this->requestAction('posts/index/sort:created/order:asc/limit:5');
?>
<?php foreach($posts as $post): ?>
<ol>
<li><?php echo $post['Post']['title']; ?></li>
</ol>
<?php endforeach; ?>

3.10.3.2 Cache de Elements

Puedes aprovechar el cache de vistas de CakePHP si aportas un parmetro 'cache'. Si lo ajustas a


true, mantendr en cache durante un da. De otro modo, puedes ajustar tiempos de caducidad
alternativos. Lee Cache para ms informacin sobre cmo fijar la caducidad.
<?php echo $this->element('helpbox', array('cache' => true)); ?>

Si dibujas el mismo elemento ms de una vez en una vista y tienes el cache activado, asegrate
de ajustar el parmetro 'key' con un nombre diferente cada vez. Esto evitar que cada sucesiva llamada
sobreescriba el resultado almacenado en cache de la anterior llamada element(). Por ejemplo:
<?php
echo $this->element('helpbox', array('cache' => array('key' => 'first_use', 'time'
=> '+1 day'), 'var' => $var));
echo $this->element('helpbox', array('cache'
'time' => '+1 day'), 'var' => $differentVar));
?>

=>

array('key'

=>

'second_use',

Lo anterior asegura que ambos elementos son almacenados en cache de forma separada.
3.10.3.3 Utilizar Elements de un Plugin

Si ests usando un plugin y deseas usar elements dentro de ese plugin, simplemente especifica
el parmetro plugin. Si la vista est siendo dibujada para un controlador/accin de un plugin, se usar el
elemento del plugin. Si el elemento no existe en el plugin, se buscar en la carpeta APP principal.
<?php echo $this->element('helpbox', array('plugin' => 'pluginname')); ?>

3.10.4 Mtodos de la vista


Los mtodos de la Vista estn disponibles para todos los archivos de vistas, elementos y
plantillas. Para llamar a cualquier mtodo de la vista utilice: $this->method()

3.10.4.1 set()

set(string $var, mixed $value)


Las Vistas tienen un metodo set() que es anlogo al set() encontrado en los objetos
Controller. Te permite agregar variables al viewVars. Usando set() desde tu archivo de vista, agregar
las variables a la capa (layout) y elementos (elements) que luego sern renderizados. Ver
Controller::set() para mas informacin en el uso de set().
En tu archivo vista puedes hacer
$this->set('activeMenuButton', 'posts');

3.10.4.2 getVar()

getVar(string $var)
Obtiene el valor de la viewVar con el nombre $var
3.10.4.3 getVars()

getVars()
Obtiene una lista con todas las variables disponibles en el mbito de la vista actual. Devuelve un
arreglo con los nombres de las variables.
3.10.4.4 error()

error(int $code, string $name, string $message)


Displays an error page to the user. Uses layouts/error.ctp to render the page.
$this->error(404, 'Not found', 'This page was not found, sorry');

This will render an error page with the title and messages specified. Its important to note that
script execution is not stopped by View::error() So you will have to stop code execution yourself
if you want to halt the script.
3.10.4.5 element()

element(string $elementPath, array $data, bool $loadHelpers)


Renders an element or view partial. See the section on View Elements for more information and

examples.
3.10.4.6 uuid

uuid(string $object, mixed $url)


Generates a unique non-random DOM ID for an object, based on the object type and url. This method
is often used by helpers that need to generate unique DOM ID's for elements such as the AjaxHelper.
$uuid = $this->uuid('form', array('controller' => 'posts', 'action' =>
'index'));
//$uuid contains 'form0425fe3bad'

3.10.4.7 addScript()

addScript(string $name, string $content)


Adds content to the internal scripts buffer. This buffer is made available in the layout as
$scripts_for_layout. This method is helpful when creating helpers that need to add javascript
or css directly to the layout. Keep in mind that scripts added from the layout, or elements in the layout
will not be added to $scripts_for_layout. This method is most often used from inside helpers,
like the Javascript and Html Helpers.
3.10.5 Temas
Puedes aprovechar los temas (themes), haciendo sencillo el cambio de la apariencia de tu pgina
de una forma rpida y fcil.
Para usar los temas, necesitas decirle a tu controlador que use la clase ThemeView en lugar de
la clase por defecto View.
class ExampleController extends AppController {
var $view = 'Theme';
}

Para declarar qu tema usar por defecto, especifica el nombre del tema en tu controlador.
class ExampleController extends AppController {
var $view = 'Theme';
var $theme = 'ejemplo';
}

Tambin puedes setear o cambiar el nombre del tema dentro de una accin o en las funciones de

callback beforeFilter() o beforeRender().


$this->theme = 'otro_ejemplo';

Los archivos de vista de los temas deben estar dentro de la carpeta /app/views/themed/ . Dentro
de la carpeta themed, crea una carpeta usando el nombre de tu tema. Despus de eso, la estructura de
carpetas dentro de /app/views/themed/example/ es exactamente igual a /app/views/.
Por ejemplo, el archivo de vista de una accin de edicin de un controlador de Posts estara
ubicado en /app/views/themed/example/posts/edit.ctp. Los archivos de Layout estaran en
/app/views/themed/example/layouts/.
Si un archivo de vista no puede ser encontrado en el tema, CakePHP tratar de localizarlo en la
carpeta /app/views/. De esta forma, puedes crear archivos de vista maestros y simplemente
sobreescribirlos segn cada caso dentro de la carpeta de tu tema.
Si tienes archivos CSS o JavaScript que son especficos para tu tema, puedes almacenarlos en
una carpeta de tema dentro de la carpetawebroot/. Por ejemplo, tus hojas de estilo seran almacenadas
en

/app/webroot/themed/example/css/

tus

archivos

JavaScript

estaran

en

/app/webroot/themed/example/js/.
Todos los helpers de CakePHP son concientes de los temas y crearn las rutas correctas
automticamente. Como con los archivos de vistas, si un archivo no est en la carpeta del tema, se
ubicar por defecto en la carpeta webroot principal.
3.10.5.1 Increasing performance of plugin and theme assets

Its a well known fact that serving assets through PHP is guaranteed to be slower than serving
those assets without invoking PHP. And while the core team has taken steps to make plugin and theme
asset serving as fast as possible, there may be situations where more performance is required. In these
situations its recommended that you either symlink or copy out plugin/theme assets to directories in
app/webroot with paths matching those used by cakephp.
app/plugins/debug_kit/webroot/js/my_file.js becomes
app/webroot/debug_kit/js/my_file.js
app/views/themed/navy/webroot/css/navy.css becomes
app/webroot/theme/navy/css/navy.css

3.10.6 Vistas de Medios


Las vistas de medios te permiten enviar archivos binarios al usuario. Por ejemplo, puedes querer
tener un directorio de archivos fuera de la carpeta /webroot para prevenir que los usuarios tengan
acceso directo a ellos. Puedes usar vistas Media para traer el archivo desde una carpeta especial dentro
de /app/, pudiendo hacer autenticacin antes de entregar el archivo al usuario.
Para usar vistas Media, necesitas decirle a tu controlador que use la clase MediaView en vez
de la clase por defecto View. Despus de esto, slo pasa los parmetros adicionales para especificar
dnde est ubicado tu archivo.
class EjemploController extends AppController {
function download () {
$this->view = 'Media';
$params = array(
'id' => 'ejemplo.zip',
'name' => 'ejemplo',
'download' => true,
'extension' => 'zip',
'path' => 'files' . DS
);
$this->set($params);
}
}

Parmetros Descripcin
id
El ID es el nombre del archivo tal como est en el servidor, incluyendo su extensin.
El nombre (name) te permite especificar un nombre de archivo alternativo para ser
name
enviado al usuario. Especifica el nombre sin la extensin del archivo.
download
Un valor booleano que indica si los encabezados deben forzar la descarga.
La extensin del archivo. Esto se compara con una lista interna de tipos MIME
extension

path
mimeType

aceptados. Si el tipo MIME especificado no est en la lista, el archivo no ser


descargado.
El nombre del archivo, incluyendo el separador del directorio final. La ruta (path es
relativa a la carpeta app/.
Un arreglo con tipos MIME adicionales que sern mezclados con la lista interna de tipos
MIME aceptados.

3.11 Helpers
Helpers son las clases simil-componentes para la capa de aplicacin de tu aplicacin. Ellos
contienen la lgica presentacional que es compartida entre vistas, elementos, o layouts. Este captulo te
mostrar cmo crear tus propios helpers, abarcando las tareas bsicas en las que los helpers del ncleo
CakePHP pueden ayudarte a lograr. Para ms informacin sobre los helpers del ncleo, dirgete a
Helpers 'de fbrica'.
3.11.1 Usando Helpers
T usas helpers en CakePHP haciendo que un controlador sepa de su existencia. Cada
controlador tiene una propiedad $helpers que lista los helpers que estarn disponibles en la vista.
Para habilitar un helper en tu vista, agrega el nombre del helper en el arreglo $helpers del
controlador.
<?php
class BakeriesController extends AppController {
var $helpers = array('Form', 'Html', 'Javascript', 'Time');
}
?>

Tambin pueden agregar helpers desde dentro de una accin, de esta forma slo estarn
disponibles para esa accin y no para las dems acciones que permanezcan a ese controlador. Esto
ahorra poder de procesamiento para las dems acciones que no usan el helper, y mantinen al
controlador mejor organizado.
<?php
class BakeriesController extends AppController {
function bake {
$this->helpers[] = 'Time';
}
function mix {
// El helper Time no es cargado aqu, no estar disponible.
}
}
?>

3.11.2 Creando Helpers


Si un helper del core (o alguno mostrado en Cakeforge o en la Bakery) no se ajusta a tus
necesidades, los helpers son fciles de crear.
Digamos que quisieramos crear un helper que pudiera ser usado para mostrar como salida un

link especficamente creado con CSS que lo necesitas en diferentes partes de tu aplicacin. Para poder
ajustar tu lgica dentro de la estructura existente de helpers de CakePHP, necesitars crear una nueva
clase en /app/views/helpers. Llamemos a nuestro helper LinkHelper. El archivo de clase se ver algo
como esto:
<?php
/* /app/views/helpers/link.php */
class LinkHelper extends AppHelper {
function makeEdit($title, $url) {
// Lgica para crear un link con un formato especfico va aqui...
}
}
?>

Existen algunos mtodos incluidos en la clase de Helper en CakePHP de la cual quisieras sacar ventaja:
output(string $string)
Usa esta funcin para enviar cualquier informacin de regreso a tu vista.
<?php
function makeEdit($title, $url) {
// Usa la funcin de salida del helper para enviar
// datos con formato de regreso a la vista:
return $this->output(
"<div class=\"editOuter\">
<a href=\"$url\" class=\"edit\">$title</a>
</div>"
);
}
?>

3.11.2.1 Including other Helpers

Es posible que necesites usar alguna funcionalidad existente en otro helper. Para hacerlo, puedes
especificar los helpers que deseas utilizar con un arreglo $helpers, con el formato que usaras en un
controlador.
<?php
/* /app/views/helpers/link.php (usando otros helpers) */
class LinkHelper extends AppHelper {
var $helpers = array('Html');
function makeEdit($title, $url) {
// Usa el helper de HTML para mostrar
// informacin con formato:
$link = $this->Html->link($title, $url, array('class' => 'edit'));

return $this->output("<div class=\"editOuter\">$link</div>");


}
?>

3.11.2.2 Callback method

Helpers feature a callback used by the parent controller class.


beforeRender()
The beforeRender method is called after the controller's beforeRender method but before the
controller's renders views and layout.
3.11.2.3 Usando tu Helper

Una vez hayas creado tu helper y de haberlo colocado dentro de /app/views/helpers/, podrs
incluirlo dentro de tus controllers usando la variable especial $helpers.
Una vez tu controller se haya dado cuenta de esta nueva clase, podrs usarla en los views
accesando mediante una variable llamada por ese helper:
<!-- crear un link usando el nuevo helper -->
<?php echo $link->makeEdit('Change this Recipe', '/recipes/edit/5') ?>

Recuerda incluir el FormHelper en el array de $helpers si es apropiado. Los ayudantes Html y


Session (si esta activa una sesin) siempre estarn disponibles.
3.11.3 Creando Funcionalidad para todos los Helpers
Todos los helpers extienden a una clase especial, AppHelper (as como los modelos extienden
AppModel y los controladores extienden AppController). Para crear funcionalidad que podra estar
disponible para todos los helpers, crea /app/app_helper.php.
<?php
class AppHelper extends Helper {
function customMethod () {
}
}
?>

3.11.4 Helpers del Core


CakePHP contiene un buen nmero de helpers que ayudan en la creacin de la vista. Ellos
asisten en crear notacin (markup) con buen formato (incluyendo formas), ayudan a dar formato a
texto, tiempo y nmeros, y tambin pueden acelerar la funcionalidad de Ajax. Aqu est un resumen de
los helpers disponibles por defecto. Para ms imformacin revisa Helpers del Core.
Helper de
CakePHP

Descripcin
Usado en conjunto con Prototype Javascript Library para crear funcionalidad en las

Ajax

vistas. Contiene mtodos rpidos para drag/drop (levantar/tirar), formularios ajax &

Cache

enlaces, observadores, y ms.


Es usado por el ncleo (core) para almacenar el contenido de las vistas en cach.
Crea formularios HTML y elementos de formulario que se poblan solas y manejan

Form
Html
Javascript
Number
Paginator
Rss
Session
Text
Time
Xml

problemas de validacin.
Mtodos convenientes para crear cdigo (markup) bien formateado. Imgenes, links,
tablas, tags de headers y ms.
Usado para 'escapar' valores para usarse en JavaScript, escribir tus propios objetos
JSON, y dar formato a bloques de cdigo.
Formato para nmeros y tipo de cambio.
Paginar y ordenar informacin de modelos.
Mtodos convenientes para regresar datos RSS feed XML.
Aceso para escribir valores de la sesin en las vistas.
Enlaces inteligentes, marcadores, truncado inteligente de palabras.
Deteccin de proximidad (es este siguiente ao?), buen formateo de cadenas de
caracteres (Hoy, 10:20 am) y conversiones de usos horarios.
Mtodos convenientes para crear elementos y headers XML.

3.12 Scaffolding
El scaffolding (creacin de plataformas temporales) en aplicaciones es una tcnica que permite
a un desarrollador definir y crear aplicaciones bsicas que pueden crear, retirar, actualizar y borrar
objetos. El scaffolding en CakePHP tambin permite a los desarrolladores definir cmo los objetos
estn relacionados unos con otros, y para crear y romper estos enlaces.
Todo lo que se necesita para crear un scaffold (plataforma temporal) es un modelo y su
controlador. Una vez que se declare la variable $scaffold en el controlador, ya estas listo y corriendo.
El scaffolding de CakePHP es bastante agradable. Te permite tener una aplicacin CRUD bsica
funcional en minutos. Es tan agradable, que querrs usarla en aplicaciones de produccin. Ahora,
nosotros pensamos que es agradable tambin, pero por favor, ese cuenta lo que el scaffoldding
(plataforma temporal) es... bueno... es solo una plataforma temporal. Su estructura flexible la deshaces
rpidamente al inicio de un proyecto para poder iniciar. No fue pensada para ser completamente
flexible, fue pensada como una manera temporal de iniciar un proyecto rpidamente. Si usted se
encuentra realmente tratando de personalizar la lgica en sus vistas, es momento de derrumbar su
scaffolding para poder escribir ms cdigo. La consola Bake de CakePHP, vista en la siguiente seccin,
es un gran segundo paso: genera todo el cdigo que producira el mismo resultado que el ms reciente
escalonado.
Scaffolding es una gran manera de iniciar las primeras partes de una aplicacin web iniciada.
Los esquemas de bases de datos tempranos son sujetos a cambios, lo cual es perfectamente normal en
una parte temprana del proceso de diseo. Esto tiene su inconveniente: un desarrollador web detesta
formas que nunca sern utilizadas. Para reducir el estrs en el desarrollador, el scaffolding ha sido
incluido en CakePHP. El scaffolding analiza sus tablas en la base de datos y crea listas estandard con
botones de agregar, borrar y editar, forms estandar para editar y vistas estandar para inspeccionar un
nico elemento en la base de datos.
Para agregar scaffolding a tu aplicacin, en el controlador, , agrega la variable $scaffold:
<?php
class CategoriesController extends AppController {
var $scaffold;
}
?>

Si has creado la clase basica del modelo Category en el archivo /app/models/category.php, ya


ests listo para comenzar!. Visita http://example.com/categories para ver tu nuevo scaffold.
El crear mtodos en controladores que se hayan sido "scaffoldeados" pueden causar resultados
no deseados. Por ejemplo, si crea un mtodo index() en un controlador "scaffoldeado", su mtodo index
ser mostrado en lugar que la funcionalidad de scaffoling.
El scaffolding es reconocido por sus asociaciones de modelos, as que si tu modelo Category
pertenece a un User ["belongsTo" User], usted ver las IDs del modelo User relacionadas en el listado
del modelo Category. Si usted quisiera ver algo aparte de un ID (como el apellido del usuario), lo
lograr activando la variable $displayField en el modelo.
Inicializaremos la variable $displayField en nuestra clase de User para que los usuarios
relacionados con categoras sern mostrados por el primer nombre en lugar de solo el ID en el
scaffolding. Esta caracterstica hace el scaffolding ms leble en muchas instancias.
<?php
class User extends AppModel {
var $name = 'User';
var $displayField = 'first_name';
}
?>

3.12.1 Creating a simple admin interface with scaffolding


If

you

have

enabled

admin

routing

Configure::write('Routing.prefixes',

in

your

app/config/core.php,

array('admin'));

you

scaffolding to generate an admin interface.


Once you have enabled admin routing assign your admin prefix to the scaffolding variable.
var $scaffold = 'admin';

You will now be able to access admin scaffolded actions: Plain Text View
http://example.com/admin/controller/index
http://example.com/admin/controller/view
http://example.com/admin/controller/edit
http://example.com/admin/controller/add
http://example.com/admin/controller/delete

can

with
use

This is an easy way to create a simple backend interface quickly. Keep in mind that you cannot
have both admin and non-admin methods scaffolded at the same time. As with normal scaffolding you
can override individual methods and replace them with your own.
function admin_view($id = null) {
//custom code here
}

Once you have replaced a scaffolded action you will need to create a view file for the action as well.
3.12.2 Personalizando Vistas Scaffold
Si ests buscando para algo un poco diferente a tus vistas scaffolded, puees crear templetes.
Nosotros an no recomendamos esta tcnica para aplicaciones de produccin, pero semejante
personalizacin puede ser muy til durante el esarrollo e prototipos.
La personalizacin se hace creando templetes de vistas:
Vistas

personalizadas

para

un

controlador

especfico

(para

este

ejemplo

PostsController) debe ser colocado como lo siguiente:


/app/views/posts/scaffold.index.ctp
/app/views/posts/scaffold.show.ctp
/app/views/posts/scaffold.edit.ctp
/app/views/posts/scaffold.new.ctp
Las vistas scaffolding personalizadas para todos los controladores deberan ser
colocadas como las siguientes:
/app/views/scaffolds/index.ctp
/app/views/scaffolds/show.ctp
/app/views/scaffolds/edit.ctp
/app/views/scaffolds/new.ctp
/app/views/scaffolds/add.ctp

3.13 La consola de CakePHP


Esta seccin provee una introduccin a CakePHP en la lnea de comandos. Si tu alguna vez has
utilizado tus clases MVC de CakePHP en un cron job o cualquier otro script de lnea de comandos, esta
seccin es para ti.
PHP provee un poderoso cliente CLI que hace que crear interfases entre tus archivos de sistema
y tus aplicaciones sea mucho ms sencillo. La Consola CakePHP provee un framework para crear
scritps de shell. La Consola usa una configuracin del tipo despachador para cargar una un shell o una
tarea, y para regresar sus parmetros.
Una versin de lnea de comandos (cli) de PHP debe de estar disponible en el sistema si planeas
usar la Consola.
Antes de que nos metamos en cosas ms especficas, hay que asegurarnos de que podemos
correr CakePHP en consola. Primero, necesitas abrir una terminal el sistema. Los ejemplos mostrados
en esta seccin sern en bash, pero la Consola e CakePHP es compatible con Windows tambin.
Ejecutemos el programa de Consola desde bash. Este ejemplo asume que el usuario ya esta logeado en
una sesin de bash y se encuentra en la raz de la instalacin de CakePHP.
Puedes tcnicamente correr la consola usando algo similar a esto:
$ cd /my/cake/app_folder
$ ../cake/console/cake

Pero el uso preferido es agregando el directorio de consola a tu ruta para que puedas usar el comando
cake en cualquier lado:
$ cake

Ejecutar la Consola sin argumentos produce el siguiente mensaje de ayuda:


Hello user,
Welcome to CakePHP v1.2 Console
--------------------------------------------------------------Current Paths:
-working: /path/to/cake/
-root: /path/to/cake/
-app: /path/to/cake/app/
-core: /path/to/cake/
Changing Paths:
your working path should be the same as your application path

to change your path use the '-app' param.


Example: -app relative/path/to/myapp or -app /absolute/path/to/myapp
Available Shells:
app/vendors/shells/:
- none
vendors/shells/:
- none
cake/console/libs/:
acl
api
bake
console
extract
To run a command, type 'cake shell_name [args]'
To get help on a specific command, type 'cake shell_name help'

La primera informacin mostrada se relaciona con las rutas. Esto es epecialmente til si estas
ejecutando la consola de diferentes partes del sistema de archivos.
Muchos usuarios agregan la Consola de CakePHP a sus rutas del sistema operativo para que pueda ser
ejecutado fcilmente. Imprimiendo las rutas del directorio de trabajo root, app, y core te permite ver
donde la Consola har los cambios. Para cambiar la carpeta de app con el que deseas trabajar, puedes
proporcionar su ruta como el primer argumento al comando cake. Este siguiente ejemplo nos muestra
como especificar un folder de app, asumiendo que ya has agregado el carpeta de la consola en tu PATH:
$ cake -app /path/to/app

La ruta provista puede ser relativa al directorio de trabajo actual o provista como una ruta absoluta.
3.13.1 Creando Shells y Tasks
3.13.1.1 Creando tus Propios Shells

Crearemos una shell para usarla en la Consola. Para este ejemplo, crearemos una report' shell
que imprima datos de un modelo. Primero, crea un report.php en /vendors/shells/.
<?php
class ReportShell extends Shell {
function main() {}
}
?>

Desde este punto, ya podemos correr el shell, pero no har mucho. Agreguemos algunos
modelos al shell para que podamos crear un reporte de algn tipo. Esto se hace de la misma forma que
en el controlador: al agregar los nombres de los modelos a la variable $uses;
<?php
class ReportShell extends Shell {
var $uses = array('Order');
function main() {
}

}
?>

Una vez que agregamos nuestro modelo al arreglo $uses, podemos usarlo en el mtodo main();
En este ejemplo, nuestro modelo Order debe de ahora ser accesible como $this->Order en el mtodo
main() de nuestro nuevo shell.
Aqu hay un ejemplo simple de la lgica que podemos usar en este shell:
class ReportShell extends Shell {
var $uses = array('Order');
function main() {
//Agrega las rdenes enviadas el mes pasado.
$month_ago = date('Y-m-d H:i:s',
strtotime('-1 month'));
$orders
=
$this->Order>find("all",array('conditions'=>"Order.shipped >= '$month_ago'"));
//Imprime la informacin de cada orden.
foreach($orders as $order) {
$this->out('Order date: ' .

. "\n");

['amount'], 2) . "\n");

$this->out('Amount: $' .

$order['Order']['created']

number_format($order['Order']

$this->out('----------------------------------------' .

"\n");

$total += $order['Order']['amount'];
}
//Imprime el total de las ordenes seleccionadas.
$this->out("Total: $" .
number_format($total, 2) . "\n");
}

Debes de ser caps de correr este reporte ejecutando este comando (si el comando cake esta en tu
PATH):
$ cake report

donde report es el nombre del archivo shell en /vendor/shells/ sin la extensin .php. Esto deber
regresar lo siguiente:

Hello user,
Welcome to

CakePHP v1.2 Console

--------------------------------------------------------------App : app
Path:

/path/to/cake/app

--------------------------------------------------------------Order date:
Amount:

2007-07-30 10:31:12
$42.78

---------------------------------------Order date:
Amount:

2007-07-30 21:16:03
$83.63

---------------------------------------Order date:
Amount:

2007-07-29 15:52:42
$423.26

---------------------------------------Order date:
Amount:

2007-07-29 01:42:22
$134.52

---------------------------------------Order date:
Amount:

2007-07-29 01:40:52
$183.56

---------------------------------------Total:

$867.75

3.13.1.2 Tasks (Tareas)

Los tasks (tareas) son pequeas extensiones para los shells. Nos permiten que haya lgica
comapartida entre shells, y son agregadas a nuestros shells usando una variable de clase especial $task.
Por ejemplo en la shell core de bake, hay un cierto nmero de tasks definidos:
<?php
class BakeShell extends Shell {
var $tasks = array('Project', 'DbConfig', 'Model', 'View', 'Controller');
}
?>

Los tasks son almacenados en /vendors/shells/tasks/ en archivos con el nombre de sus clases.
As que si quisiramos crear una nueva tarea cool , la clase CookTask (que extiende de Shell) sera
colocada en /vendors/shells/tasks/cool.php. La clase VeryCoolTask (que extiende Shell) sera colocada
en /vendors/shells/tasks/cool.php.

Cada task debe de tener por lo menos un mtodo execute() - los shells llamarn a este mtodo
para iniciar la lgica del task.
<?php
class SoundTask extends Shell {
var $uses = array('Model'); // Lo mismo que en el controlador var $uses
function execute() {}
}
?>

Puedes acceder a tasks dentro de tus clases de shell y ejecutarlas desde ah:
<?php
class SeaShell extends Shell // Se encuentra en /vendors/shells/sea.php {
var $tasks = array('Sound'); //Se encuentra en /vendors/shells/tasks/sound.php
function main() {
$this->Sound->execute();
}
}
?>

Un mtodo llamado sound en la clase SeaShell podra sustituir la habilidad de acceder a la


funcionalidad de la tarea Sound especificada en el arreglo $tasks.
Puedes tambin acceder a los tasks directamente desde la lnea de comados:
$ cake sea sound

3.13.2 Running Shells as cronjobs


A common thing to do with a shell is making it run as a cronjob to clean up the database once in
a while or send newsletters. However, when you have added the console path to the PATH variable via
~/.profile, it will be unavailable to the cronjob.
The following BASH script will call your shell and append the needed paths to $PATH. Copy
and save this to your vendors folder as 'cakeshell' and don't forget to make it executable. (chmod +x
cakeshell)
#!/bin/bash
TERM=dumb
export TERM
cmd="cake"
while [ $# -ne 0 ]; do
if [ "$1" = "-cli" ] || [ "$1" = "-console" ]; then
PATH=$PATH:$2

shift
else
cmd="${cmd} $1"
fi
shift
done
$cmd

You can call it like:


$ ./vendors/cakeshell myshell myparam -cli /usr/bin -console
/cakes/1.2.x.x/cake/console

The -cli parameter takes a path which points to the php cli executable and the -console parameter
takes a path which points to the CakePHP console.
As a cronjob this would look like:
# m h dom mon dow command
*/5 *

* /full/path/to/cakeshell myshell myparam -cli /usr/bin

-console /cakes/1.2.x.x/cake/console -app /full/path/to/app

A simple trick to debug a crontab is to set it up to dump it's output to a logfile. You can do this like:
# m h dom mon dow command
*/5 *

* /full/path/to/cakeshell myshell myparam -cli /usr/bin

-console /cakes/1.2.x.x/cake/console -app /full/path/to/app >>


/path/to/log/file.log

3.14 Plugins
CakePHP nos permite combinar una serie de controladores, modelos y vistas y publicarlos
como una aplicacin empaquetada, plugin, que otros pueden integrar en sus aplicaciones CakePHP.
Has desarrolado un mdulo de administracin de usuarios amigable, un blog sencillo o un web service
en alguna de tus aplicaciones? Empaqutalo como un plugin de CakePHP e inclyelo en otras
aplicaciones.
El principal vnculo entre un plugin y la aplicacin en la que se instala es la configuracin de la
aplicacin (conexin a la base de datos, etc.). Por lo dems, el plugin opera en su propio espacio,
comportndose como si fuese una aplicacin en s mismo.

3.14.1 Crear un Plugin


Como ejemplo, vamos a crear un nuevo plugin que encargue pizzas. Para empezar tendremos
que colocar todos los archivos de nuestro plugin en el directorio /app/plugins. El nombre del directorio
padre del plugin es importante y se referenciar muy a menudo, as que conviene escogerlo con
prudencia. Para este ejemplo utilizaremos el nombre 'pizza'. La estructura de archivos ser la siguiente:
/app
/plugins
/pizza
/controllers

<- controladores del plugin

/models

<- modelos del plugin

/views

<- vistas del plugin

/pizza_app_controller.php

<- clase AppController del plugin

/pizza_app_model.php

<- clase AppModel del plugin

Si queremos acceder a nuestro plugin a travs de una URL, es necesario definir las clases
AppController y AppModel para el mismo. Estas dos clases especiales tienen el nombre del plugin y
extienden las clases AppController y AppModel de la aplicacin principal. En nuestro ejemplo:
// /app/plugins/pizza/pizza_app_controller.php:
<?php
class PizzaAppController extends AppController {
//...
}
?>
// /app/plugins/pizza/pizza_app_model.php:
<?php
class PizzaAppModel extends AppModel {
//...
}
?>

Si olvidamos definir estas clases, CakePHP nos mostrar el error "Missing Controller".
3.14.2 Controladores del Plugin
Los controladores de nuestro plugin pizza se almacenan en /app/plugins/pizza/controllers/.
Puesto que las acciones que ms trataremos son las peticiones de pizza, necesitaremos el controlador
PeticionesController para este plugin.
Aunque no es necesario, conviene llamar los controladores de los plugin con un nombre
relativamente nico, con el fin de evitar conflictos de espacios de nombre con la aplicacin principal.

No es extrao pensar que una aplicacin podra tener controladores como UsuariosController,
PeticionesController o ProductosController: deberamos ser creativos con los nombres de los
controladores, o anteponer el nombre del plugin al nombre de la clase (PizzaPeticionesController en
nuestro ejemplo).
As, ubicamos nuestro nuevo controlador, PizzaPeticionesController, en /app/plugins/pizza/controllers,
quedando:
// /app/plugins/pizza/controllers/pizza_peticiones_controller.php
class PizzaPeticionesController extends PizzaAppController {
var $name = 'PizzaPeticiones';
var $uses = array('Pizza.PizzaPeticion');
function index() {
//...
}
}

Observa cmo este controlador extiende el controlador AppController del plugin (llamado
PizzaAppController) en lugar del controlador AppController de la aplicacin principal.
Adems, al nombre del modelo se aade como prefijo el nombre del plugin. Esta lnea de
cdigo se aade por claridad, pero no es necesaria en este caso.
Si quieres acceder a lo que hemos hecho hasta ahora, visita /pizza/pizzaPeticiones. Deberas
obtener un error Missing Model, porque no hemos definido todava el modelo PizzaPeticion.
3.14.3 Modelos del Plugin
Los modelos de un plugin son almacenados en /app/plugins/pizza/models. En el apartado
anterior, definimos el controlador PizzaPeticionesController para nuestro plugin de ejemplo. Ahora
crearemos el modelo para ese controlador, PizzaPeticion, definicin consistente con el esquema de
nombres que establecimos previamente, anteponiendo a todas las clases de nuestro plugin el nombre
del mismo, Pizza.
// /app/plugins/pizza/models/pizza_peticion.php:
class PizzaPeticion extends PizzaAppModel {
var $name = 'PizzaPeticion';
}
?>

Acceder a /pizza/pizzaPeticiones ahora (suponiendo que tenemos una tabla en nuestra base de
datos llamada pizza_peticiones) nos debera dar un error Missing View. Este ser el prximo paso.
Si necesitamos referenciar un modelo dentro de nuestro plugin, tenemos que incluir el nombre

del plugin junto con el nombre del modelo, separados por un punto.
// /app/plugins/pizza/models/pizza_peticion.php:
class ExampleModel extends PizzaAppModel {
var $name = 'ExampleModel';
var $hasMany = array('Pizza.PizzaPeticion');
}
?>

3.14.4 Vistas del Plugin


Las vistas se comportan en un plugin exactamente igual a como lo hacen en una aplicacin
normal. Basta con colocarlas en la carpeta adecuada en /app/plugins/[plugin]/views/. Para nuestro
plugin

encargado

de

pedir

pizza,

necesitaremos

una

vista

para

la

accin

PizzaPeticionesController::index():
// /app/plugins/pizza/views/pizza_peticiones/index.ctp:
<h1>Pide una Pizza</h1>
<p>Nada combina con Cake mejor que una buena pizza!</p>
<!-- Aqu debera ir un formulario para solicitar pizza...-->

3.14.5 Componentes, Ayudantes y Comportamientos


Al igual que una aplicacin tpica, un plugin puede tener Componentes (Components),
Ayudantes (Helpers) y Comportamientos (Behaviors). Incluso podemos crear plugins que incluyan
nicamente estas clases, siendo un mecanismo excelente para construir mdulos reutilizables que
pueden aadirse fcilmente en cualquier proyecto.
Los componentes se desarrollan exactamente de la misma manera a como se desarrollan en una
aplicacin normal, sin ninguna convencin de nombres especial. Hacer referencia a nuestros
componentes desde el mismo plugin no requiere ninguna notacin especial.
// Componente
class EjemploComponent extends Object {
}
// desde los controladores de nuestro plugin:
var $components = array('Ejemplo');

Para invocar el Componente desde fuera del entorno del plugin, tenemos que indicar el nombre del
mismo.
var $components = array('PluginNombre.Ejemplo');
var

$components

array('Pizza.Ejemplo');

//

referencia

al

componente

EjemploComponent en el plugin Pizza.

La misma tcnica se aplica a los Ayudantes y Comportamientos.


3.14.6 CSS y Javascript en los Plugins
Podemos incluir archivos CSS y Javascript en nuestros plugins, colocndolos, respectivamente,
en nuestro_plugin/vendors/css y nuestro_plugin/vendors/js. Pueden incluirse en
nuestras vistas usando los ayudantes nativos del framework.
<?php echo $html->css('/nuestro_plugin/css/mi_css'); ?>
<?php echo $javascript->link('/nuestro_plugin/js/mi_javascript');

Las lneas anteriores son ejemplos de como incluir archivos javascript y css en nuestro plugin.
Es importante observar como se incluye en la ruta del arhivo js o css /nuestro_plugin/. Esto
hace que la magia funcione
3.14.7 Consejos para desarrollar Plugins
Una vez que ya hemos desarrollado todo lo necesario, nuestro plugin est listo para ser
distribuido (aunque sera conveniente aadir unos cuantos extras, como un readme o un fichero SQL).
Despus de instalar el plugin en /app/plugins, podemos acceder al mismo siguiendo la URL
/nombreplugin/nombrecontrolador/accion. En nuestro plugin de ejemplo para ordenar pizza, accedemos
a PizzaPeticionesController en /pizza/pizzaPeticiones.
Algunos consejos tiles a tener en cuenta cuando trabajamos con plugins en nuestras
aplicaciones CakePHP:
Si no definimos [Plugin]AppController y [Plugin]AppModel, recibiremos errores "Missing
Controller" cuando intentemos accede a un controlador del plugin.
Podemos tener un controlador por defecto con el mismo nombre de nuestro plugin. Podemos
acceder a l via /[plugin]/accion. Por ejemplo, a un plugin llamado 'usuarios' con un controlador
UsuariosController podemos acceder en /usuarios/add si no hay ningn plugin llamado
AddController en la carpeta [plugin]/controllers.
Podemos definir el diseo de nuestros plugins en app/plugin/views/layouts. En caso contrario,
los plugins usarn, por defecto, los diseos en /app/views/layouts folder by default.

Usando $this->requestAction('/plugin/controller/accion'); en los controladores logramos


comunicar distintos plugins.
Si pretendemos usar requestAction, debemos asegurarnos de que los nombres de modelos y
controladores son tan nicos como sea posible. Si no fuera as, pueden surgir errores PHP del
tipo "clase redefinida ..."

3.15 Constantes y Funciones Globales


Aunque en la mayor parte de nuestro trabajo diario en CakePHP utilizaremos clases y mtodos
nativos, es til conocer una serie de funciones globales que ofrece CakePHP. Muchas de ellas estn
orientadas al trabajo con las clases de CakePHP (cargando las clases de modelo o componente), pero
muchas otras hacen ms sencillo trabajar con matrices o cadenas.
Tambin veremos en esta seccin algunas de las constantes disponibles en las aplicaciones
CakePHP. Usarlas ayuda a realizar actualizaciones menos complicadas, adems de ser tiles a la hora
de referenciar ciertos archivos o directorios en nuestras aplicaciones CakePHP.
3.15.1 Funciones globales
stas son las funciones globales disponibles en CakePHP. Muchas de ellas simplemente
facilitan la llamada a funciones de PHP con nombres largos, pero otras (como vendor() y uses())
se pueden usar para incluir cdigo o realizar otras funciones tiles. Lo ms probable es que si ests
buscando una funcin para realizar una tarea con mucha frecuencia, la encuentres aqu.
3.15.1.1 __

__(string $string_id, boolean $return = false)


Esta funcin gestiona la localizacin en las aplicaciones CakePHP. El parmetro $string_id
identifica la ID de una traduccin, mientras que el segundo parmetro indica si se debe mostrar
automticamente la cadena (por defecto), o devolverla para su procesamiento (pasar el valor true para
que esto suceda).
Visita la seccin Localizacin e Internacionalizacin para ms informacin.

3.15.1.2 a

a(mixed $uno, $dos, $tres...)


Devuelve un array con los parmetros pasados a la funcin.
print_r(a('foo', 'bar'));
// salida:
array(
[0] => 'foo',
[1] => 'bar'
)

3.15.1.3 aa

aa(array $uno, $dos, $tres...)


Crea arrays asociativos a partir de los parmetros enviados a la funcin.
echo aa('a','b');
// salida:
array(
'a' => 'b'
)

3.15.1.4 am

am(array $uno, $dos, $tres...)


Combina todos los arrays pasados como parmetros y devuelve el array resultante.
3.15.1.5 config

Puede ser usado para cargar archivos desde el directorio config mediante include_once. La
funcin checa si existe el archivo antes de incluir y regresa un booleano. Toma un nmero opcional de
argumento.
Ejemplo: config('some_file', 'myconfig');

3.15.1.6 convertSlash

convertSlash(string $cadena)
Sustituye las barras ("/") por subrayados ("_") y elimina el primer y el ltimo subrayados en una
cadena. Devuelve la cadena convertida.
3.15.1.7 debug

debug(mixed $var, boolean $showHtml = false)


Si el nivel de depuracin, variable de configuracin DEBUG, es distinto de cero, se muestra
$var. Si $showHTML es true, los datos se formatean para mostrarlos adecuadamente en los
navegadores web.
3.15.1.8 e

e(mixed $datos)
Simplifica la llamada a la funcin echo().
3.15.1.9 env

env(string $key)
Obtiene una variable de entorno a partir de las fuentes disponibles. Alternativa si las variables
$_SERVER o $_ENV estn deshabilitadas.
Tambin permite emular las variables PHP_SELF y DOCUMENT_ROOT en los servidores que
no permitan su uso. De hecho, es una buena prctica usar env() en lugar de $_SERVER o
getenv() (sobretodo si pensamos distribuir el cdigo), ya que ofrece la misma funcionalidad y es
totalmente compatible.
3.15.1.10 fileExistsInPath

fileExistsInPath(string $archivo)
Comprueba que el fichero $archivo est en el include_path actual de PHP. Devuelve un valor
booleano.

3.15.1.11 h

h(string $texto, string $charset)


Alias de la funcin htmlspecialchars().
3.15.1.12 ife

ife($condicion, $siNoVacia, $siVacia)


til en operaciones ternarias. Si $condicion no es vaca, devuelve $siNoVacia; si no, devuelve
$siVacia.
3.15.1.13 low

low(string $cadena)
Alias de la funcin strtolower().
3.15.1.14 pr

pr(mixed $var)
Alias de la funcin print_r(), aadiendo la etiqueta <pre> a la salida.
3.15.1.15 r

r(string $cadena_buscada, string $cadena_sustituta, string $cadena_original)


Alias de la funcin str_replace().
3.15.1.16 stripslashes_deep

stripslashes_deep(array $valor)
Elimina recursivamente las barras invertidas de $valor. Devuelve el array modificado.
3.15.1.17 up

up(string $cadena)
Alias de la funcin strtoupper().

3.15.1.18 uses

uses(string $lib1, $lib2, $lib3...)


Permite cargar las libreras nativas de CakePHP (localizadas en cake/libs/). Pasar como parmetro
el nombre de la librera sin la extensin '.php'.
3.15.2 Constantes predefinidas
constante
APP

Ruta absoluta dentro de la aplicacin al ...


directorio raz.

APP_PATH

directorio app.

CACHE

directorio de archivos de cache.

CAKE

directorio cake.

COMPONENTS

directorio components.

CONFIGS

directorio de archivos de configuracin.

CONTROLLER_TES directorio controller de los tests.


TS
CONTROLLERS

directorio controllers.

CSS

directorio de archivos CSS.

ELEMENTS

directorio elements.

HELPER_TESTS

directorio helper de los tests.

HELPERS

directorio helpers.

INFLECTIONS

directorio

inflections

(normalmente

dentro

configuracin).
JS

directorio de archivos JavaScript (en webroot).

LAYOUTS

directorio layouts.

LIB_TESTS

directorio CakePHP Library de los tests.

LIBS

directorio de libreras CakePHP.

del

directorio

de

LOGS

directorio de logs (en app).

MODEL_TESTS

directorio model de los tests.

MODELS

directorio models.

SCRIPTS

directorio de scripts de Cake.

TESTS

directorio tests (directorio padre de los directorios de test para los


modelos, controladores, etc.)

TMP

directorio tmp.

VENDORS

directorio vendors.

VIEWS

directorio views.

WWW_ROOT

ruta completa a webroot.

3.16 Paquetes de terceros (Vendor packages)


3.16.1 Vendor assets
Support for vendor assets have been removed for 1.3. It is recommended that you take any
vendor assets you have and repackage them into plugins. See Plugin assets for more information.

4 Tareas comunes con CakePHP


4.1 Validacin de Datos
La validacin de los datos es una parte importante de cualquier aplicacin, ya que asegura que
los datos en un modelo estn conformes a las reglas de negocio de la aplicacin. Por ejemplo, tu
podrias querer que los passwords tengan a lo menos un largo de ocho caracteres, o asegurar que los
username sean nicos. Definir reglas de validacin hace que el manejo de los formularios sea
muchsimo ms fcil.
Hay muchos diferentes aspectos del proceso de validacin. En esta seccin cubriremos el lado
del modelo, es decir, lo que ocurre cuando tu llamas al mtodo save() de tu modelo. Para ms
informacin acerca de cmo manejar el despliegue de errores de validacin, revisa la seccin que cubre
el FormHelper.
El primer paso en la validacin de datos es la creacin de las reglas de validacin en el Modelo.
Para hacer eso, usa el arreglo Model::validate en la definicin del Modelo, por ejemplo:
<?php
class User extends AppModel {
var $name = 'User';
var $validate = array();
}
?>

En el ejemplo de arriba, el arreglo $validate se agrega al modelo User, pero el arreglo no


contiene reglas de validacin. Asumiendo que la tabla users tiene los campos login, password, email y
born, el ejemplo de abajo muestra algunas simples reglas de validacin que se aplican a esos campos:
<?php
class User extends AppModel {
var $name = 'User';
var $validate = array(
'login' => 'alphaNumeric',
'email' => 'email',
'born' => 'date'
);
}
?>

El ejemplo muestra cmo se pueden agregar reglas de validacin a los campos de un modelo.
Para el campo login sern aceptadas slo letras y nmeros, el email debe ser vlido, y born debe ser
una fecha vlida. La definicin de reglas de validacin habilitan en CakePHP el despliegue automtico
de mensajes de error en formularos si los datos enviados no cumplen las reglas de validacin.
CakePHP incluye muchas reglas de validacin y usarlas puede ser bastante simple. Algunas de
las reglas incluidas permiten verificar el formato de los emails, URLs, y nmeros de tarjeta de crdito las cubriremos en detalle ms adelante.
Ac tenemos un ejemplo de validacin ms complejo que aprovecha algunas de las reglas incluidas:
<?php
class User extends AppModel {
var $name = 'User';
var $validate = array(
'login' => array(
'alphaNumeric' => array(
'rule' => 'alphaNumeric',
'required' => true,
'message' => 'Slo letras y nmeros'
),
'between' => array(
'rule' => array('between', 5, 15),
'message' => 'Entre 5 y 15 caracteres'
)
),
'password' => array(
'rule' => array('minLength', '8'),
'message' => 'Largo mnimo de 8 caracteres'
),
'email' => 'email',
'born' => array(
'rule' => 'date',
'message' => 'Ingrese una fecha vlida',
'allowEmpty' => true
)
);
}
?>

Dos reglas de validacin son definidas para login: debera contener slo letras y nmeros, y su
largo debe ser de 5 a 15. El campo password debe tener un largo mnimo de 8 caracteres. El email debe
contener una direccin de correo vlida, y born debe ser una fecha vlida. Adems, notar que puedes
agregar mensajes de error propios que CakePHP mostrar cuando estas reglas de validacin no se
cumplan.
Como lo muestra el ejemplo de arriba, un nico campo puede tener mltiples reglas de
validacin. Y si las reglas incluidas no coinciden con lo que necesitas, puedes agregar tus propias reglas
de validacin segn tus requerimientos.
Ahora que viste a grandes rasgos cmo funciona la validacin, veamos cmo estas reglas son
definidas en el modelo. Hay tres diferentes maneras para definir reglas de validacin: arreglos simples,
una nica regla por campo, y mltiples reglas por campo.
4.1.1 Reglas Simples
Tal como el nombre lo sugiere, esta es la manera ms simple de definir una regla de validacin.
La sintaxis para la definicin de reglas usando esta manera es:
var $validate = array('fieldName' => 'ruleName');

Donde, 'fieldName' es el nombre del campo para el cual se est definiendo una regla, y
'ruleName' es el nombre de una regla pre-definida (cubriremos esto en la siguiente seccin).
4.1.2 Una regla por campo
sta tcnica de definicin permite un mejor control del funcionamiento de las reglas de
validacin. Pero antes de su discusin, veamos el patrn de uso general para agregar una regla a un solo
campo:
var $validate = array(
'fieldName1' => array(
'rule' => 'ruleName', // : array('ruleName', 'param1', 'param2' ...)
'required' => true,
'allowEmpty' => false,
'on' => 'create', // : 'update'
'message' => 'Su mensaje de error'
)
);

El ndice 'rule' es requerido. Si slo se setea 'required' => true la validacin del formulario no
funcionar correctamente. Esto debido a que 'required' no es en realidad una regla.
Como puedes ver, cada campo (arriba se est mostrando slo un campo) es asociado con un
arreglo que contiene cinco ndice: rule, required, allowEmpty, on y message. Veamos con ms
detalle cada uno de estos ndices.
4.1.2.1 rule

El ndice rule define el mtodo de validacin y acepta un slo valor o un arreglo. El valor para
rule especificado puede ser el nombre de un mtodo en tu modelo, un mtodo de la clase core
Validation, o una expresin regular. Para un completo listado de todas las reglas incorporadas ver la
seccin llamada "Reglas de Validacin Incorporadas".
Si la regla no requiere parmetros, rule puede ser un slo valor, por ejemplo:
var $validate = array(
'login' => array(
'rule' => 'alphaNumeric'
)
);

Si la regla requiere algunos parmetros (como max, min o range), entonces rule debera ser un
arreglo:
var $validate = array(
'password' => array(
'rule' => array('minLength', 8)
)
);

Recuerda, el ndice rule es requerido para la definicin de reglas basadas en arreglos.


4.1.2.2 required

Este ndice debera tener asignado un valor booleano. Si required es true, el campo debe estar
presente en el arreglo de datos. Por ejemplo, si la regla de validacin ha sido definida de la siguiente
manera:

var $validate = array(


'login' => array(
'rule' => 'alphaNumeric',
'required' => true
)
);

Los datos enviados al mtodo save() del modelo deben contener un valor para el campo login.
Si no es as, la validacin falla (la regla no se cumple). El valor por defecto para este ndice es un false
booleano.
Si el ndice login estn presente pero no tiene un valor asignado, la validacin ser exitosa.
Setear required a true slo verifica que el ndice del campo este presente.
4.1.2.3 allowEmpty

Al ndice allowEmpty se le debera asignar un valor booleano. Si allowEmpty es false, los


datos pasados al mtodo save() del modelo deben incluir el campo a un valor no-vaco para ese
campo. Cuando se deja en true, un campo vaco pasar exitosamente la validacin de ese campo.
El valor por defecto de allowEmpty es null. Esto significa que el campo siempre procesar
las reglas de validacin incluyendo la ejecucin de funciones de validacin propias.
4.1.2.4 on

El ndice on puede ser seteado con uno de los siguientes valores: update o create. Esto
provee un mecanismo que permite que cierta regla sea aplicada ya sea durante la creacin de un nuevo
registro, o durante la actualizacin de un registro.
Si la regla fue definida como on => create, entonces la regla slo ser verificada durante la
creacin de un nuevo registro. De igual manera, si es definida como on => update, la regla slo ser
verificada durante la actualizacin de un registro.
El valor por defecto de on es null. Cuando on es null, la regla ser verificada durante la
creacin y actualizacin de un registro.
4.1.2.5 message

El ndice message permite definir un mensaje de error de validacin para la regla:

var $validate = array(


'password' => array(
'rule' => array('minLength', 8),
'message' => 'Password debe tener a lo menos 8 caracteres'
)
);

4.1.3 Mltiples Reglas por Campo


La tcnica descrita anteriormente nos entrega mayor flexibilidad que la asignacin de reglas
simples, pero hay un paso adicional que podemos tomar para lograr un control ms fino de la
validacin de datos. La siguiente tcnica que revisaremos nos permite asignar mltiples reglas de
validacin por cada campo de un modelo.
Si quieres asignar mltiples reglas de validacin a un slo campo, bsicamente as es cmo se
ver:
var $validate = array(
'nombreCampo' => array(
'nombreRegla' => array(
'rule' => 'nombreRegla',
// ac van ndices extra como on, required, etc.
),
'nombreRegla2' => array(
'rule' => 'nombreRegla2',
// ac van ndices extra como on, required, etc.
)
)
);

Como puedes ver, esto es bastante similar a lo que hicimos en la seccin previa. Anteriormente,
por cada campo tenamos un slo arreglo con parmetros de validacin. En este caso, cada
nombreCampo consiste en un arreglo de ndices de reglas. Cada nombreRegla contiene un arreglo
distinto con parmetros de validacin.
Esto se entiende mejor con un ejemplo prctico:

var $validate = array(


'login' => array(
'alphanumeric' => array(
'rule' => 'alphaNumeric',
'message' => 'Se permiten slo letras y nmeros',
'last' => true
),
'minlength' => array(
'rule' => array('minLength', '8'),
'message' => 'Largo mnimo de 8 caracteres'
),
)
);

El ejemplo de arriba define dos reglas para el campo login: alphanumeric y minLength. Como
puedes ver, cada regla se identifica con un nombre de ndice. En este caso particular, los nombres de
ndice son similares a las reglas que usan, pero el nombre de ndice puede ser cualquier nombre.
Por defecto CakePHP trata de validar un campo usando todas las reglas de validacin
declaradas para l y retorna un mensaje de error para la ltima regla no satisfecha. Pero si el ndice
last es dejado como true y la regla no es satisfecha, entonces se mostrar el mensaje de error para
esa regla y no se validar ninguna regla adicional. Asi que si prefieres mostrar un mensaje de error para
la primera regla no satisfecha entonces debes dejar 'last' => true por cada regla.
Si vas a usar mensajes de error internacionalizados podrias quierer especificar los mensajes de
error en las vistas:
echo $form->input('login', array(
'label' => __('Login', true),
'error' => array(
'alphanumeric' => __('Se permiten slo letras y nmeros', true),
'minlength' => __('Largo mnimo de 8 caracteres', true)
)
)
);

El campo ahora est totalmente internacionalizado, y puedes eliminar los mensajes del modelo.
Para ms informacin acerca de la funcin __() ver "Localization & Internationalization"

4.1.4 Reglas de Validacin Incorporadas


La clase Validation de CakePHP contiene muchas reglas de validacin incorporadas que pueden
hacer mucho ms fcil la validacin de datos. Esta clase contiene muchas tcnicas de validacin
frecuentemente usadas que no necesitars escribir por tu cuenta. Abajo encontrars una lista completa
de todas las reglas, junto ejemplos de uso.
4.1.4.1 alphaNumeric

Los datos para el campo deben contener slo letras y nmeros.


var $validate = array(
'login' => array(
'rule' => 'alphaNumeric',
'message' => 'Los nombres de usuario deben contener slo letras y
nmeros.'
)
);

4.1.4.2 between

El largo de los datos para el campo debe estar dentro de un rango numrico especfico. Se debe
indicar un valor mnimo y mximo.
var $validate = array(
'password' => array(
'rule' => array('between', 5, 15),
'message' => 'Las contraseas deben tener un largo entre 5 y 15
caracteres.'
)
);

4.1.4.3 blank

Esta regla es usada para asegurar que el campo es dejado en blanco o con slo espacios en
blanco como su valor. Los espacios en blanco incluyen los caracteres de la barra espaciadora,
tabulador, retorno de carro y nueva lnea.

var $validate = array(


'id' => array(
'rule' => 'blank',
'on' => 'create'
)
);

4.1.4.4 boolean

El campo debe contener un valor booleano. Los valores aceptados son true o false, los
enteros 0 o 1 y las cadenas "0" o "1".
var $validate = array(
'myCheckbox' => array(
'rule' => array('boolean'),
'message' => 'Valor incorrecto en myCheckbox'
)
);

4.1.4.5 cc

Esta regla es usada para verificar si los datos corresponden a un nmero de tarjeta de credito
vlido. Acepta tres parmetros: type, deep y regex.
El type puede ser fast, all o cualquiera de los siguientes:
bankcard
diners
disc
electron
enroute
jcb
maestro
mc
solo
switch
visa

voyager
Si type es dejado en fast, se validan los datos contra el formato numrico de las principales
tarjetas de crdito. Tambin se puede dejar type como un arreglo con todos los tipos de validaciones
que se quiere satisfacer.
El ndice deep debera dejarse con un valor booleano. Si es verdadero, la validacin usar el
algoritmo de Luhn para tarjetas de crdito (http://en.wikipedia.org/wiki/Luhn_algorithm). Por defecto
el valor se asume como falso.
El ndice regex permite indicar una expersin regular propia que ser usada para validar el
nmero de tarjeta de credito.
var $validate = array(
'ccnumber' => array(
'rule' => array('cc', array('visa', 'maestro'), false, null),
'message' => 'El nmero de tarjeta de crdito que ha suministrado no es
vlido.'
)
);

4.1.4.6 comparison

Esta regla es usada para comparar valores numricos. Soporta is greater, is less, greater or
equal, less or equal, is less, equal to, y not equal. A continuacin algunos ejemplos:
var $validate = array(
'age' => array(
'rule' => array('comparison', '>=', 18),
'message' => 'Debe tener al menos 18 aos para calificar.'
)
);
var $validate = array(
'age' => array(
'rule' => array('comparison', 'greater or equal', 18),
'message' => 'Debe tener al menos 18 aos para calificar.'
)
);

4.1.4.7 date

Esta regla asegura que los datos enviados esten en un formato de fecha vlido. Un nico
parmetro (que puede ser un arreglo) puede ser pasado y que ser usado para verificar el formato de la
fecha indicada. El valor del parmetro puede ser uno de los siguientes formatos:
dmy por ejemplo 27-12-2006 o 27-12-06 (los separadores pueden ser espacio, punto, guion,
slash)
mdy por ejemplo 12-27-2006 or 12-27-06 (los separadores pueden ser espacio, punto, guion,
slash)
ymd por ejemplo 2006-12-27 or 06-12-27 (los separadores pueden ser espacio, punto, guion,
slash)
dMy por ejemplo 27 December 2006 o 27 Dec 2006
Mdy por ejemplo December 27, 2006 o Dec 27, 2006 (la coma es opcional)
My por ejemplo (December 2006 o Dec 2006)
my por ejemplo 12/2006 o 12/06 (los separadores pueden ser espacio, punto, guion, slash)
Si no especifica ningn ndice, se usar el ndice por defecto ymd.
var $validate = array(
'born' => array(
'rule' => 'date',
'message' => 'Ingrese una fecha vlida usando el formato AA-MM-DD.',
'allowEmpty' => true
)
);

Mientras que muchos almacenes de datos (motores de bases de datos) requieren cierto formato
de datos, podrias considerar aceptar una amplia variedad de formatos de fechas y luego convertirlos, en
vez de forzar a los usuarios a ingresar cierto formato. Entre ms trabajo puedas hacer por tus usuarios,
mejor.
4.1.4.8 decimal

Esta regla asegura que el dato es un nmero decimal vlido. Se puede pasar un parmetro para
especificar la cantidad de dgitos requeridos despus del punto decimal. Si no se pasa ningn
parmetro, el dato ser validado como un nmero de punto flotante cientfico, que causar que la
validacin no sea satisfecha si es que no se encuentra ningn dgito despus del punto decimal.

var $validate = array(


'price' => array(
'rule' => array('decimal', 2)
)
);

4.1.4.9 email

Esta regla verifica que el dato sea una direccin de correo electrnico vlida. Al pasar un valor
booleano verdadero como segundo parmetro se tratar tambin de verificar que el host de la direccin
sea vlido.
var $validate = array('email' => array('rule' => 'email'));
var $validate = array(
'email' => array(
'rule' => array('email', true),
'message' => 'Por favor indique una direccin de correo electrnico
vlida.'
)
);

4.1.4.10 equalTo

Esta regla asegura que el valor sea equivalente a, y del mismo tipo que el valor indicado.
var $validate = array(
'food' => array(
'rule' => array('equalTo', 'cake'),
'message' => 'El valor debe ser el string cake'
)
);

4.1.4.11 extension

Esta regla verifica que la extensin de archivo sea como .jpg o .png. Para permitir mltiples
extensiones estas se deben pasar dentro de un arreglo.

var $validate = array(


'image' => array(
'rule' => array('extension', array('gif', 'jpeg', 'png', 'jpg'),
'message' => 'Por favor indique una imgen vlida.'
)
);

4.1.4.12 file

Esta seccin an tiene que ser escrita, si tienes una idea de qu poner aqui, por favor usa los
links y djanos saber tu sugerencia!
4.1.4.13 ip

Esta regla asegura que haya sido ingresada una direccin IPv4 vlida.
var $validate = array(
'clientip' => array(
'rule' => 'ip',
'message' => 'Por favor ingrese una direccin IP vlida.'
)
);

4.1.4.14 isUnique

El dato para este campo debe ser nico, no puede ser usado por ningn otro registro.
var $validate = array(
'login' => array(
'rule' => 'isUnique',
'message' => 'Este nombre de usuario ya ha sido asignado.'
)
);

4.1.4.15 minLength

Esta regla asegura que el dato cumple con un requisito de largo mnimo.
var $validate = array(
'login' => array(
'rule' => array('minLength', '8'),
'message' => 'Los nombres de usuario deben tener un largo de al menos 8
caracteres.'
)
);

4.1.4.16 maxLength

Esta regla asegura que el dato siempre est dentro del requisito de largo mximo.
var $validate = array(
'login' => array(
'rule' => array('maxLength', '15'),
'message' => 'Los nombres de usuario no pueden tener un largo mayor a 15
caracteres.'
)
);

4.1.4.17 money

Esta regla asegura que el valor sea una cantidad en formato monetario vlido.
El segundo parmetro define dnde se ubica el smbolo: left/right (izquierda/derecha).
var $validate = array(
'salary' => array(
'rule' => array('money', 'left'),
'message' => 'Por favor ingrere una cantidad monetaria vlida.'
)
);

4.1.4.18 multiple

Empleado para validar campos input select multiple. Soporta los paramentros "in", "max" y
"min".
var $validate = array(
'multiple' => array(
'rule' => array('multiple', array('in' => array('foo', 'bar'), 'min' => 1,
'max' => 3)),
'message' => 'Por favor seleccione una, dos o tres opciones'
)
);

4.1.4.19 inList

Esta regla asegura que el valor est dentro de un conjunto dado. Necesita de un arreglo de
valores. El valor es vlido si coincide con uno de los valores del arreglo indicado.
var $validate = array(
'function' => array(
'allowedChoice' => array(
'rule' => array('inList', array('Foo', 'Bar')),
'message' => 'Ingreso Foo o ingrese Bar.'
)
)
);

4.1.4.20 numeric

Verifica si el dato ingresado es un nmero vlido.


var $validate = array(
'cars' => array(
'rule' => 'numeric',
'message' => 'Por favor indique la cantidad de vehculos.'
)
);

4.1.4.21 notEmpty

Regla bsica para asegurar que un campo no este vaco.


var $validate = array(
'title' => array(
'rule' => 'notEmpty',
'message' => 'Este campo no puede quedar vaco.'
)
);

4.1.4.22 phone

Phone valida nmeros telefnicos de EE.UU. Si quieres validar nmeros telefnicos que no
sean de EE.UU. puedes proveer una expresin regular como segundo parmetro para cubrir formatos
adicionales.
var $validate = array(
'phone' => array(
'rule' => array('phone', null, 'us')
)
);

4.1.4.23 postal

Postal es usado para validar cdigos ZIP de EE.UU. (us), Canada (ca), Reino Unido (uk), Italia
(it), Alemania (de) y Blgica (be). Para otros formatos ZIP puedes proveer una expersin regular como
segundo parmetro.
var $validate = array(
'zipcode' => array(
'rule' => array('postal', null, 'us')
)
);

4.1.4.24 range

Esta regla asegura que el valor est dentro de un rango dado. Si no se indica un rango, la regla
va a verificar si el valor es un nmero finito vlido en la actual plataforma.
var $validate = array(
'number' => array(
'rule' => array('range', 0, 10),
'message' => 'Por favor ingrese un nmero entre 0 y 10'
)
);

El ejemplo de arriba aceptar cualquier valor mayor a 0 (por ejemplo 0.01) y menor a 10 (por
ejemplo 9.99).
4.1.4.25 ssn

Ssn valida los nmeros de seguridad social de EE.UU. (us), Dinamarca (dk), y los Paises Bajos (nl).
Para otros formatos de nmeros de seguridad social puedes proveer una expersin regular.
var $validate = array(
'ssn' => array(
'rule' => array('ssn', null, 'us')
)
);

4.1.4.26 url

Esta regla verifica formatos de URL vlidos. Soporta los protocolos http(s), ftp(s), file, news, y gopher.
var $validate = array(
'website' => array(
'rule' => 'url'
)
);

4.1.5 Reglas de Validacin Personalizadas


Si hasta el momento no has encontrado lo que buscabas, siempre podrs crear tus propias reglas
de validacin personalizadas. Hay dos maneras de hacer esto: definiendo expresiones regulares
personalizadas, o creando mtodos de validacin personalizados.
4.1.5.1 Validacin Personalizada Mediante Expresiones Relugares

Si la tcnica de validacin que necesitas usar puede ser completada usando expresiones
regulares, puedes definir una expresin personalizada como una regla de validacin de un campo.
var $validate = array(
'login' => array(
'rule' => array('custom', '/^[a-z0-9]{3,}$/i'),
'message' => 'Slo letras y enteros, mnimo 3 caracteres'
)
);

El ejemplo de arriba verifica si login contiene slo letras y enteros, con un largo mnimo de tres
caracteres.
4.1.5.2 Validacin Mediante Mtodos Personalizados

Algunas veces revisar los datos usando expresiones regulares no es suficiente. Por ejemplo, si
quieres asegurar que un cdigo promocional slo pueda ser usado 25 veces, necesitas agregar una
funcin de validacin personalizada, como se muestra ms abajo:
<?php
class User extends AppModel {
var $name = 'User';
var $validate = array(
'promotion_code' => array(
'rule' => array('limitDuplicates', 25),
'message' => 'Este cdigo ha sido usado demasiadas veces.'
)
);
function limitDuplicates($data, $limit){
$existing_promo_count = $this->find( 'count', array('conditions' => $data,
'recursive' => -1) );
return $existing_promo_count < $limit;
}
}
?>

Si quieres pasar parmetros a tu funcin de validacin personalizada, agrega elementos extra al


arreglo rule y trtalos como parmetros extra (despes del parmetro principal $data) en tu funcin
personalizada.
Tu funcin de validacin personalizada puede estar en el modelo (como en el ejemplo de
arriba), o en un behavior implementado por el modelo. Esto incluye los modelos mapeados.
Notar que los mtodos del model/behavior son verificados primero, antes de buscar un mtodo
en la clase Validation. Esto significa que puedes sobreescribir mtodos de validacin existentes
(como por ejemplo alphaNumeric()) en el nivel de aplicacin (agregando el mtodo a
AppModel), o en el nivel de modelo.
4.1.6 Validando datos desde el Controlador
Mientras que normalmente slo usars el mtodo save del modelo, habrn veces que te gustara
validar los datos sin guardarlos. Por ejemplo, podras querer mostrar algo de informacin adicional al
usuario antes de guardar los datos a la base de datos. Validar datos requiere de un proceso ligeramente
distinto al de slo guardar los datos.
Primero, debes setear los datos al modelo:
$this->ModelName->set( $this->data );

Luego, para verificar si los datos se validan correctamente, usa el mtodo validates del modelo,
que retornar true si es que se valida y false si es que no:
if ($this->ModelName->validates()) {
// paso la lgica de validacin
} else {
// no paso la lgica de validadicin
}

El mtodo validates invoca el mtodo invalidFields que le asignar un valor a la propiedad


validationErrors del modelo. El mtodo invalidFields tambin retorna los datos como su resultado.
$errors
=
$this->ModelName->invalidFields();
validationErrors

//

contiene

el

arrego

Es importante notar que los datos se deben primero setear al modelo antes de poder validarlos.
Esto es diferente al mtodo save que permite pasar los datos como un parmetro. Tambin, ten en
cuenta que no es necesario llamar a validates antes de llamar a save ya que save validar
automticamente los datos antes realmente de guardarlos.

4.2 Limpieza de Datos


La clase Sanitize de CakePHP puede ser usada para eliminar datos maliciosos y otra
informacin no deseada desde los datos enviados por un usuario. Sanitize es una librera del ncleo, por
lo que puede ser usada en cualquier parte de tu cdigo, pero probablemente ser mejor usada en los
controladores y modelos.
CakePHP te protege automticamente contra Inyeccin SQL si usas los mtodos ORM de
CakePHP (como find() y save()) y la notacin de arrays apropiada (ejemplo array('campo' => $valor))
en lugar de sentencias SQL incrustadas en el cdigo. Para la limpieza de datos contra XSS
generalmente es mejor guardar el HTML sin tratar en la base de datos y posteriormente limpiar los
datos en el momento de mostrarlos.
Todo lo que necesitas hacer es inclur la librera del ncleo Sanitize (p.ej. antes de la definicin
de la clase controlador):
App::import('Sanitize');
class MiController extends AppController {
...
...
}

Una vez hecho eso, puedes hacer llamadas estticas a Sanitize.


4.2.1 paranoid
paranoid(string $string, array $allowedChars);
Esta funcin elimina cualquier cosa desde $string que no sean caracteres alfanumricos. Esta
funcin no eliminar ciertos caracteres al pasarlos en el arreglo $allowedChars.
$badString = ";:<script><html><

// >@@#";

echo Sanitize::paranoid($badString);// salida: scripthtml


echo Sanitize::paranoid($badString, array(' ', '@'));// salida: scripthtml

@@

4.2.2 html
html(string $string, boolean $remove = false)
Este mtodo prepara los datos enviados por un usuario para desplegarlos dentro de HTML. Esto

es especialmente til si no quieres que los usuarios quiebren tus layouts o inserten imgenes o scripts
dentro de las pginas HTML. Si la opcin $remove se deja en true, el contenido HTML detectado es
eliminado en vez de mostrado como entidades HTML.
$badString = '<font size="99" color="#FF0000">HEY</font><script>...</script>';
echo Sanitize::html($badString);
//salida:&lt;fontsize=&quot;99&quot;color=&quot;#FF0000&quot;&gt;HEY&lt;/font&gt;&
lt;script&gt;...&lt;/script&gt;
echo Sanitize::html($badString, true);// salida: HEY...

4.2.3 escape
escape(string $string, string $connection)
Usado para escapar sentencias SQL agregndole barras invertidas, dependiendo de la configuracin de
magic_quotes_gpc del sistema. $connection es el nombre de la base de datos para la cual escapar el
string, segn el nombre definido en app/config/database.php.
4.2.4 clean
Sanitize::clean(mixed $data, mixed $options)
Esta funcin es un limpiador multi-propsito y de potencia industrial, y sirve para ser usado en
arreglos (como $this->data, por ejemplo). La funcin recibe un arreglo (o string) y retorna su versin
limpia. Las siguientes operaciones de limpieza son realizadas en cada elemento del arreglo
(recursivamente):
Los espacios raros (incluyendo 0xCA) son reemplazados con espacios regulares.
Verificacin doble de caracteres especiales y remocin de retornos de carro para una mayor
seguridad SQL.
Se agregan barras para SQL (slo llama a la funcin sql explicada anteriormente).
Se reemplazan las barras invertidas ingresadas por el usuario por barras invertidas confiables.

4.3 Manejo de Errores


En caso de un error irrecuperable en tu aplicacin, es comn detener el procesamiento y mostrar
una pgina de error al usuario. Para ahorrarte tener que codificar el manejo de esto en cada uno de tus
controladores y componentes, puedes usar el mtodo:
$this->cakeError(<string errorType>, [array parameters]);

Al llamar este mtodo se mostrar una pgina de error al usuario y se detendr cualquier tipo de
procesamiento en tu aplicacion.
CakePHP pre-define un conjunto de tipos de error, pero en estos momentos (escritura de este
manual), la mayora son realmente tiles para el mismo framework. Uno que es ms til para el
desarrollador de aplicaciones es el viejo y querido error 404. Puede ser llamado sin ningn parmetro
de la siguiente manera:
$this->cakeError('error404');

De manera alternativa, puedes hacer que la pgina reporte que el error fue en una URL
especfica pasando el parmetro url:
$this->cakeError('error404', array('url' => 'some/other.url'));

Todo esto comienza a ser mucho ms til al extender el administrador de errores para que use
tus propios tipos de error. Los administradores de error customizados son principalmente como
acciones de un controlador. Tpicamente vas a usar set() para dejar disponibles sus parmetros en la
vista y luego mostrar (render) un fichero tipo vista desde el directorio app/views/errors.
Crea un fichero app/app_error.php con la siguiente definicin.
<?php
class AppError extends ErrorHandler {
}
?>

Se pueden implementar administradores (handlers) para nuevos tipos de error agregando


mtodos a esta clase. Simplemente crea un nuevo mtodo con el nombre que quieres usar como tu tipo
de error.
Digamos que tenemos una aplicacin que escribe cierta cantidad de ficheros a disco y que es

apropiado mostrale al usuario los errores de escritura. No quieremos agregar cdigo para esto en
diferentas partes de la aplicacin, as que es un buen caso para usar un nuevo tipo de error.
Agrega un nuevo mtodo a tu clase AppError. Vamos a aceptar un parmetro llamado file
que ser la ruta al fichero cuya escritura fallo.
function cannotWriteFile($params) {
$this->controller->set('file', $params['file']);
$this->__outputMessage('cannot_write_file');
}

Crea la vista en app/views/errors/cannot_write_file.ctp


<h2>No fue posible escribir en el fichero</h2>
<p>No se pudo escribir el fichero <?php echo $file ?> en el disco.</p>

y lanza el error en tu controllador/componente


$this->cakeError('cannotWriteFile', array('file'=>'somefilename'));

La implementacin por defecto de $this->__outputMessage() slo mostrar la vista en


views/errors/.ctp.

Si

quieres

cambiar

este

comportamiento,

puedes

redefinir

__outputMessage($template) en tu clase AppError.

4.4 Depuracin
La depuracin es una parte necesaria e inevitable de cualquier ciclo de desarrollo. Mientras que
CakePHP no ofrece ninguna herramienta que se conecte directamente con ningn editor o IDE, provee
de varias herramientas para ayudar en la depuracin y exponer lo que se esta ejecutando dentro de su
aplicacin.
4.4.1 Depuracin bsica
debug($var, $showHTML = false, $showFrom = true)
La funcin debug() est disponible de forma global, esta trabaja similar a la funcin de PHP
print_r(). La funcin debug() permite mostrar el contenido de una variable en diferente nmero de
formas. Primero, si quieres que la data se muestre en formato HTML amigable, establece el segundo
parmetro a true. Por defecto la funcin muestra la lnea y el archivo donde se origina.

La salida de esta funcin solo se muestra si la variable debug del core (app/config/core.php,
lnea 43) se ha establecido a un valor mayor que 0.
4.4.2 Usando la clase Debugger
Para usar el depurador hay que primero asegurarse que Configure::read('debug') este seteado a
un valor mayor a 0.
dump($var)
Dump muestra el contenido de una variable. Desplegar todas las propiedades y mtodos (si
existen) de la variable que se indique.
$foo = array(1,2,3);
Debugger::dump($foo);
//outputs
array(
1,
2,
3
)
//objeto simple
$car = new Car();
Debugger::dump($car);
//despliegue
Car::
Car::colour = 'red'
Car::make = 'Toyota'
Car::model = 'Camry'
Car::mileage = '15000'
Car::acclerate()
Car::decelerate()
Car::stop()

log($var, $level = 7)

Crea un log detallado de la traza de ejecucin al momento de su invocacin. El mtodo log()


genera datos similares a los de Debugger::dump() pero los enva al archivo debug.log en vez del buffer
de salida. Notar que el directorio app/tmp (y su contenido) debe tener permisos de escritura para el
servidor web para que log() funcione correctamente.
trace($options)
Retorna la traza de ejecucin actual. Cada lnea de la traza incluye el mtodo que fue llamado,
incluyendo desde cul archivo y desde que lnea la llamada se origin.
//En PostsController::index()
pr( Debugger::trace() );
//despliege
PostsController::index() - APP/controllers/downloads_controller.php, line 48
Dispatcher::_invoke() - CORE/cake/dispatcher.php, line 265
Dispatcher::dispatch() - CORE/cake/dispatcher.php, line 237
[main] - APP/webroot/index.php, line 84

Arriba se muestra una traza de ejecucin generada llamando a Debugger::trace() desde una
accin de un controlador. Al leer la traza de ejecucin desde abajo hacia arriba se muestra el orden de
las funciones actualmente en ejecucin (stack frames). En el ejemplo de arriba, index.php llam a
Dispatcher::dispatch(), que a su vez llam a Dispatcher::_invoke(). Luego el mtodo _invoke() llam a
PostsController::index(). Esta informacin es til cuando se trabaja con operaciones recursivas, ya que
se identifican las funciones que estaban en ejecucin al momento de llamar a trace().
excerpt($file, $line, $context)
Toma un extracto desde un archivo en $path (que es una ruta absoluta), destaca la lnea nmero
$line con la cantidad de $context lneas a su alrededor.
pr( Debugger::excerpt(ROOT.DS.LIBS.'debugger.php', 321, 2) );
//se despliegar lo siguiente
Array
(
[0]

=>

<code><span

style="color:

#000000">

@access

public</span></code>
[1] => <code><span style="color: #000000"> */</span></code>
[2] => <code><span style="color: #000000">

function excerpt($file,

$line, $context = 2) {</span></code>


[3] => <span class="code-highlight"><code><span style="color:
#000000">

$data = $lines = array();</span></code></span>


[4] => <code><span style="color: #000000">

$data =

@explode("\n", file_get_contents($file));</span></code>
)

Aunque este mtodo es usado internamente, te puede ser prctico si estas creando tus propios
mensajes de error o entradas de log en ocasiones especiales.
exportVar($var, $recursion = 0)
Convierte una variable de cualquier tipo a un string para su uso en el despliegue del depurador.
Este mtodo tambin es usado mucho por Debugger para conversiones internas de variables, y puede
ser usado tambin en tus propios Debuggers.
invoke($debugger)
Reemplazar el Debugger de CakePHP con un nuevo Administrador de Errores.
4.4.3 Clase Debugger
La clase Debugger es nueva en CakePHP 1.2, ofrece muchas opciones para obtener informacin
de depuracin. Tiene muchos mtodos que pueden ser invocados de forma esttica, proveyendo
volcado, trazabilidad, y funciones de gestin de errores.
La clase Debugger sobreescribe el manejo de errores por defecto de PHP, reemplazndolo con
informacin de errores mucho ms til. La depuracin de errores est activa por defecto en CakePHP.
Al igual que con todas las funciones de depuracin, se debe establecer Configure::debug a un valor
mayor que 0.
Cuando ocurre un error, el depurador genera dos salidas de informacin, una a la pgina y la
otra crea una entrada en el archivo error.log. El reporte de errores generado contiene tanto la pila de
llamadas como un extracto del cdigo donde ocurri el error. Haga clic en el enlace "Error" para ver la
pila de llamadas, y el enlace "Code" para ver las lneas de cdigo causantes del error.

4.5 Caching
Almacenamiento en cach se puede hacer en diferentes niveles en una aplicacin de CakePHP.
Para obtener ms informacin, consulte cmo deshabilitar la memoria cach del navegador, pgina
completa o elemento de cach, el almacenamiento en cach de consultas o la memoria cach o tambin
la funcin - cach a cualquier cosa. Para ms informacin.

4.6 Logging
Aunque los ajustes de Configuracin de la clase desde el corazn de CakePHP realmente puede
ayudarle a ver qu pasa en el fondo, usted necesitar algn tiempo para grabar datos en el disco para
saber lo que pasa. En un mundo cada vez ms dependientes de tecnologas como SOAP y AJAX, la
depuracin puede ser difcil. .
La grabacin (registro) puede ser tambin una manera de descubrir es que ocurri en su
solicitud en cualquier momento. Qu trminos de bsqueda se utilizaron? Qu tipo de errores de mis
usuarios que han visto? Con qu frecuencia se ejecuta una consulta?
En CakePHP la grabacin (registro) es fcil - la funcin log () es un elemento de la clase Object,
que es el ancestro comn de la mayora de las clases CakePHP. Si el contexto es una clase CakePHP
(Modelo, Controlador, Componente ... lo que sea), puede guardar sus datos.
4.6.1 Uso de la funcin log
La funcin log() toma dos parmetros. El primero es el mensaje que se desea escribir en el
archivo de log. Por defecto, este mensaje de error es escrito en el log de errores ubicado en
app/tmp/logs/error.log.
//Ejecutando esto dentro de una clase CakePHP:
$this->log("Algo que no hace nada!");
//El resultado de esto se agrega a app/tmp/logs/error.log
2007-11-02 10:22:02 Error: Algo que no hace nada!

El segundo parmetro es usado para definir el tipo de log con el se quiere escribir el mensaje. Si
no se suministra, el valor por defecto es LOG_ERROR, el cual escribe en el log de errores previamente
mensionado. Como alternativa, Se puede establecer este segundo parmetro a LOG_DEBUG, para
escribir su mensaje en el log de depuracin ubicado en app/tmp/logs/debug.log:

///Ejecutando esto dentro de una clase CakePHP:


$this->log('Un mensaje de depuracin.', LOG_DEBUG);
//El resultado de esto se agrega a app/tmp/logs/debug.log (en lugar de error.log)
2007-11-02 10:22:02 Error: Un mensaje de depuracin.

El usuario del servidor web debe poder escribir en el directorio app/tmp para que el log pueda
funcionar correctamente.
4.6.2 Using the default FileLog class
While CakeLog can be configured to write to a number of user configured logging adapters, it
also comes with a default logging configuration. This configuration is identical to how CakeLog
behaved in CakePHP 1.2. The default logging configuration will be used any time there are no other
logging adapters configured. Once a logging adapter has been configured you will need to also
configure FileLog if you want file logging to continue.
As its name implies FileLog writes log messages to files. The type of log message being written
determines the name of the file the message is stored in. If a type is not supplied, LOG_ERROR is used
which writes to the error log. The default log location is app/tmp/logs/$type.log
//Executing this inside a CakePHP class:
$this->log("Something didn't work!");
//Results in this being appended to app/tmp/logs/error.log
2007-11-02 10:22:02 Error: Something didn't work!

You can specify a custom log names, using the second parameter. The default built-in FileLog
class will treat this log name as the file you wish to write logs to.
//called statically
CakeLog::write('activity', 'A special message for activity logging');
//Results

in

this

being

appended

to

app/tmp/logs/activity.log

(rather

than

error.log)
2007-11-02 10:22:02 Activity: A special message for activity logging

The configured directory must be writable by the web server user in order for logging to work
correctly.
You can configure additional/alternate FileLog locations using CakeLog::config().

FileLog accepts a path which allows for custom paths to be used.


CakeLog::config('custom_path', array(
'engine' => 'FileLog',
'path' => '/path/to/custom/place/'
));

4.6.3 Creating and configuring log streams


Log stream handlers can be part of your application, or part of plugins. If for example you had a
database logger called DataBaseLogger. As part of your application it would be placed in
app/libs/log/data_base_logger.php. As part of a plugin it would be placed in
app/plugins/my_plugin/libs/log/data_base_logger.php.

When

configured

CakeLog will attempt to load Configuring log streams is done by calling CakeLog::config().
Configuring our DataBaseLogger would look like
//for app/libs
CakeLog::config('otherFile', array(
'engine' => 'DataBaseLogger',
'model' => 'LogEntry',
...
));
//for plugin called LoggingPack
CakeLog::config('otherFile', array(
'engine' => 'LoggingPack.DataBaseLogger',
'model' => 'LogEntry',
...
));

When configuring a log stream the engine parameter is used to locate and load the log
handler. All of the other configuration properties are passed to the log stream's constructor as an array.
class DataBaseLogger {
function __construct($options = array()) {
//...
}
}

CakePHP has no requirements for Log streams other than that they must implement a write
method. This write method must take two parameters $type, $message in that order. $type is
the string type of the logged message, core values are error, warning, info and debug. In
addition you can define your own types by using them when you call CakeLog::write.
It should be noted that you will encounter errors when trying to configure application level
loggers from app/config/core.php. This is because paths are not yet bootstrapped. Configuring
of loggers should be done in app/config/bootstrap.php to ensure classes are properly loaded.
4.6.4 Interacting with log streams
You can introspect the configured streams with CakeLog::configured(). The return of
configured() is an array of all the currently configured streams. You can remove streams using
CakeLog::drop($key). Once a log stream has been dropped it will no longer receive messages.
4.6.5 Error logging
Errors

are

now

logged

when

Configure::write('debug',

0);.

You

can

use

Configure::write('log', $val), to control which errors are logged when debug is off. By
default all errors are logged.
Configure::write('log', E_WARNING);

Would log only warning and fatal errors. Setting Configure::write('log', false);
will disable error logging when debug = 0.

4.7 Testing
A partir de CakePHP 1.2 disponemos de soporte para un completo entorno de testing
incorporado en CakePHP. Este entorno es una extensin del entorno SimpleTest para PHP. En esta
seccin discutiremos cmo preparar la aplicacin para testing y cmo construir y ejecutar tus tests.
4.7.1 Preparndose para el testing
Preparado/a para empezar a hacer test? Bien! Vamos all entonces!

4.7.1.1 Installing SimpleTest

El entorno de testing provisto con CakePHP 1.2 est construido sobre el entorno de testing
SimpleTest. SimpleTest no se distribuye con la instalacin por defecto de CakePHP por lo que debemos
descargarlo primero. Lo puedes encontrar aqu: http://simpletest.sourceforge.net/
Consigue la ltima versin y descomprime el cdigo en tu carpeta cake/vendors, o en tu
app/vendors,

carpeta

segn

tus

preferencias.

Ahora

deberas

tener

un

directorio

vendors/simpletest con todos los archivos y carpetas de SimpleTest dentro. Recuerda tener el
nivel de DEBUG al menos a 1 en tu archivo app/config/core.php antes de ejecutar cualquier
test!
Si

no

tienes

una

conexin

de

base

de

datos

para

test

definida

en

app/config/database.php, las tablas de test se crearn con un prefijo test_suite_. Puedes


crear una conexin de base de adtos $test para que contenga slo las tablas de test como la que te
mostramos debajo:
var $test = array(
'driver' => 'mysql',
'persistent' => false,
'host' => 'dbhost',
'login' => 'dblogin',
'password' => 'dbpassword',
'database' => 'databaseName'
);

Si la base de datosd e test est disponible y CakePHP puede conectarse a ella, todas las tablas
sern creadas en esta base de datos.
4.7.1.2 Ejecutando los test-cases incorporados

CakePHP 1.2 se distribuye con un gran paquete de test-cases sobre la funcionalidad del ncleo
de CakePHP
Puedes acceder a estos test navegando a http://your.cake.domain/cake_folder/test.php dependiendo de como sea la disposicin especfica de tu aplicacin. Intenta ejecutar alguno de los
grupos de test del ncleo haciendo click en el enlace correspondiente. Ejecutar un test puede llevar un
rato, pero deberas ver algo parecido a "2/2 test casese complete: 49 passes, 0 fails and 0 exceptions.".
Felicidades, ya ests listo/a para empezar a escribir tests!

4.7.2 Introduccin a los test - Unit testing vs. Web testing


El entorno de test de CakePHP soporta dos tipos de testing. Uno es el Unit Testing, en el cual t
pruebas pequeas partes de tu cdigo, como pueden ser un mtodo en un componente o una accin en
un controlador. El otro tipo de testing soportado es el Web Testing, en el cual automatizas el trabajo de
evaluar tu aplicacin mediante la navegacin por las pginas, relleno de formularios, hacer clic en
enlaces y dems.
4.7.3 Preparando datos de prueba
4.7.3.1 Acerca de las fixtures

Cuando pruebes cdigo que dependa de modelos y datos, puedes usar fixtures como una forma
de generar tablas temporales de datos cargados con datos de ejemplo que pueden ser utilizados por el
test. El beneficio de usar fixtures es que tus test no pueden de ningn modo alterar los datos de la
aplicacin en marcha. Adems, as puedes empezar a probar tu cdigo antes de desarrollar contenido en
vivo para tu aplicacin.
CakePHP

intenta

utilizar

la

conexin

denominada

$test

en

tu

archivo

app/config/database.php. Si esta conexin no es utilizable, usar la configuracin de base de


datos $default y crear las tablas de test en la base de datos definida en esa configuracin. En
cualquier caso, aadir el prefijo "test_suite_" a tu propio prefijo para las tablas (si es que hay alguno)
para evitar colisiones con las tablas existentes.
CakePHP realiza los siguientes pasos durante el curso de un test case basado en fixture:
1. Crea tablas para cada una de las fixtures necesarias
2. Rellena las tablas con datos, si es que se han proporcionado stos en la fixture
3. Ejecuta los mtodos de los test
4. Vaca las tablas fixture
5. Elimina las tablas fixture de la base de datos
4.7.3.2 Creando fixtures

Cuando se crea un fixture se deben definir 2 cosas:


1) cmo se crea la tabla (que campos sern parte de la tabla)
2) cmo se guardarn los registros en la tabla de prueba. Luego podremos crear nuestro primer fixture,
que utilizaremos para testear nuestro modelo Article. Creamos un archivo llamado article_fixture.php

en la carpeta app/tests/fixtures, con el siguiente cdigo:


<?php
class ArticleFixture extends CakeTestFixture {
var $name = 'Article';
var $fields = array(
'id' => array('type' => 'integer', 'key' => 'primary'),
'title' => array('type' => 'string', 'length' => 255, 'null' => false),
'body' => 'text',
'published' => array('type' => 'integer', 'default' => '0', 'null' =>
false),
'created' => 'datetime',
'updated' => 'datetime'
);
var $records = array(
array ('id' => 1, 'title' => 'First Article', 'body' => 'First Article
Body', 'published' => '1', 'created' => '2007-03-18 10:39:23', 'updated' => '200703-18 10:41:31'),
array ('id' => 2, 'title' => 'Second Article', 'body' => 'Second Article
Body', 'published' => '1', 'created' => '2007-03-18 10:41:23', 'updated' => '200703-18 10:43:31'),
array ('id' => 3, 'title' => 'Third Article', 'body' => 'Third Article
Body', 'published' => '1', 'created' => '2007-03-18 10:43:23', 'updated' => '200703-18 10:45:31')
);
}
?>

Usamos $fields para indicar los campos que sern parte de la tabla, y cmo sern definidos. El
formato que se usa para definir los campos es el mismo que usamos en la funcion
generateColumnSchema() definida en el motor de base de datos de Cake (por ejemplo en
dbo_mysql.php.) Los atributos que un campo puede tenes son los siguientes:
type
es el tipo de dato de CakePHP. Actualmente los soportados son: string (mapea como
VARCHAR), text (mapea como TEXT), integer (mapea como INT), float (mapea como FLOAT),
datetime (mapea como DATETIME), timestamp (mapea como TIMESTAMP), time (mapea

como TIME), date (mapea como DATE), y binary (mapea como BLOB)
key
setea el campo como primary para hacerlo auto-incrementable (AUTO_INCREMENT), y clave
primaria (PRIMARY KEY) de la tabla.
length
setea el tamao del campo.
null
setea true o false. Si puede ser nulo indicamos true, si no se permiten nulos va false
default
el valor por defecto del campo.
Finalmente podemos setear un conjunto de registros que seran cargados luego de que la tabla de
testeo se crea. El formato es bastante simple, sin embargo necesita un poco ms de expilcacin. Solo
ten en cuenta que cada registro del array $records debe tener una key para cada campo del array
$fields. Si un campo para un registro en particular necesita tener el valor nulo, solo especifica el valor
de ese campo como nulo (NULL true).
4.7.3.3 Importar informacin de tabla y registros

Tu aplicacin puede tener ya modelos funcionando con datos reales asociados, y puedes decidir
probar tu modelo con esos datos. Sera entonces un esfuerzo doble tener que definir la tabla y/o los
registros en tus fixtures. Por suerte, hay una forma de hacer que la definicin de la tabla y/o los
registros para una fixture en particular vengan de un modelo o una tabla ya existentes.
Comencemos con un ejemplo. Asumiento que tienes un modelo llamado Article disponible en tu
aplicacin (que se corresponde con una tabla llamada articles), cambiamos la fixture de ejemplo que
dimos en la seccin anterior (app/tests/fixtures/article_fixture.php) a:
<?php
class ArticleFixture extends CakeTestFixture {
var $name = 'Article';
var $import = 'Article';
}
?>

Esta sentencia le dice a la test suite que importe tu definicin de tabla de la tabla asociada al
modelo llamado Article. Puedes usar cualquier modelo disponible en tu aplicacin. La expresin
anterior no importa registros, pero puedes hacerlo cambiandola para que sea:

<?php
class ArticleFixture extends CakeTestFixture {
var $name = 'Article';
var $import = array('model' => 'Article', 'records' => true);
}
?>

Si, por otro lado, tienes una tabla creada pero no un modelo disponible para ella, puedes
especificar que tu importacin consistir en leer la informacin de la tabla. Por ejemplo:
<?php
class ArticleFixture extends CakeTestFixture {
var $name = 'Article';
var $import = array('table' => 'articles');
}
?>

Esto importar la definicin de una tabla llamada 'articles' usando tu conexin de base de datos
denominada 'default'. Si quieres cambiar la conexin slo tienes que hacer:
<?php
class ArticleFixture extends CakeTestFixture {
var $name = 'Article';
var $import = array('table' => 'articles', 'connection' => 'other');
}
?>

Ya que se usa tu conexin a la base de datos, si hay algn prefijo de tabla declarado, este ser
usado automticamente al recabar la informacin de tabla. Los dos fragmentos anteriores no importan
registros de la tabla. Para forzar a la fixture a importar tambin los registros, cambialo a:
<?php
class ArticleFixture extends CakeTestFixture {
var $name = 'Article';
var $import = array('table' => 'articles', 'records' => true);
}
?>

Naturalmente puedes importar tus definiciones de tabla de un modelo o tabla existente, pero
tener tus registros definidos directamente en la fixture, como se mostraba en la seccin anterior. Por
ejemplo:

<?php
class ArticleFixture extends CakeTestFixture {
var $name = 'Article';
var $import = 'Article';
var $records = array(
array ('id' => 1, 'title' => 'First Article', 'body' => 'First
Article Body', 'published' => '1', 'created' => '2007-03-18 10:39:23', 'updated'
=> '2007-03-18 10:41:31'),
array ('id' => 2, 'title' => 'Second Article', 'body' => 'Second
Article Body', 'published' => '1', 'created' => '2007-03-18 10:41:23', 'updated'
=> '2007-03-18 10:43:31'),
array ('id' => 3, 'title' => 'Third Article', 'body' => 'Third
Article Body', 'published' => '1', 'created' => '2007-03-18 10:43:23', 'updated'
=> '2007-03-18 10:45:31')
);
}
?>

4.7.4 Creando los tests


En primer lugar, revisar una serie de normas y directrices para los tests:
1. Los archivos de PHP que contiene los tests deben estar en : app/tests/cases/[algun_ archivo].
2. Los nombres de estos archivos deben terminar con un .test.php en lugar de slo .php.
3. Las clases que contienen los tests debe extender o heredar de CakeTestCase o
CakeWebTestCase.
4. El nombre de cualquier mtodo que contenga un test (por ejemplo, que contiene una
afirmacin) debera comenzar con test, como en testPublished().
Cuando se crea un caso test, puede ejecutarce por medio del navegador en la siguiente direccin
http://tu.dominio.cake/carpeta_cake/test.php (dependiendo de cmo se ve especficamente tu
configuracin) y haciendo clic en App casos de test, y a continuacin, haga clic en el enlace a su
archivo.

4.7.4.1 CakeTestCase Callback Methods

If you want to sneak in some logic just before or after an individual CakeTestCase method,
and/or before or after your entire CakeTestCase, the following callbacks are available:
start()
First method called in a test case.
end()
Last method called in a test case.
startCase()
called before a test case is started.
endCase()
called after a test case has run.
before($method)
Announces the start of a test method.
after($method)
Announces the end of a test method.
startTest($method)
Called just before a test method is executed.
endTest($method)
Called just after a test method has completed.
4.7.5 Testing models
4.7.5.1 Creating a test case

Let's say we already have our Article model defined on app/models/article.php, which looks like
this:
<?php
class Article extends AppModel {
var $name = 'Article';
function published($fields = null) {
$params = array(
'conditions' => array(
$this->name . '.published' => 1
),

'fields' => $fields


);
}

return $this->find('all',$params);

}
?>

We now want to set up a test that will use this model definition, but through fixtures, to test
some functionality in the model. CakePHP test suite loads a very minimum set of files (to keep tests
isolated), so we have to start by loading our parent model (in this case the Article model which we
already defined), and then inform the test suite that we want to test this model by specifying which DB
configuration it should use. CakePHP test suite enables a DB configuration named test_suite that is
used for all models that rely on fixtures. Setting $useDbConfig to this configuration will let CakePHP
know that this model uses the test suite database connection.
CakePHP Models will only use the test_suite DB config if they rely on fixtures in your testcase!

Since we also want to reuse all our existing model code we will create a test model that will
extend from Article, set $useDbConfig and $name appropiately. Let's now create a file named
article.test.php in your app/tests/cases/models directory, with the following contents:
<?php
App::import('Model','Article');
class ArticleTestCase extends CakeTestCase {
var $fixtures = array( 'app.article' );
}
?>

We have created the ArticleTestCase. In variable $fixtures we define the set of fixtures that
we'll use.
If your model is associated with other models, you will need to include ALL the fixtures for
each associated model even if you don't use them. For example: A hasMany B hasMany C hasMany D.
In ATestCase you will have to include fixtures for a, b, c and d.

4.7.5.2 Creating a test method

Let's now add a method to test the function published() in the Article model. Edit the file
app/tests/cases/models/article.test.php so it now looks like this:
<?php
App::import('Model', 'Article');
class ArticleTestCase extends CakeTestCase {
var $fixtures = array( 'app.article' );
function testPublished() {
$this->Article =& ClassRegistry::init('Article');
$result = $this->Article->published(array('id', 'title'));
$expected = array(
array('Article' => array( 'id' => 1, 'title' => 'First Article'

)),

array('Article' => array( 'id' => 2, 'title' => 'Second Article'

)),
);

array('Article' => array( 'id' => 3, 'title' => 'Third Article' ))

$this->assertEqual($result, $expected);
}

?>

You can see we have added a method called testPublished(). We start by


creating an instance of our fixture based Article model, and then run our
published() method. In $expected we set what we expect should be the proper result
(that we know since we have defined which records are initally populated to the
article table.) We test that the result equals our expectation by using the
assertEqual method. See the section Creating Tests for information on how to run
the test.

4.7.6 Testing controllers


4.7.6.1 Creando un test case

Digamos que tienes un tpico controlador de artculos, con su correspondiente modelo, y que se
parece a ste:
<?php
class ArticlesController extends AppController {
var $name = 'Articles';
var $helpers = array('Ajax', 'Form', 'Html');
function index($short = null) {
if (!empty($this->data)) {
$this->Article->save($this->data);
}
if (!empty($short)) {
$result = $this->Article->findAll(null, array('id',

'title'));
} else {
$result = $this->Article->findAll();
}
if (isset($this->params['requested'])) {
return $result;
}
$this->set('title', 'Articles');
$this->set('articles', $result);
}
?>

Crea un archivo llamado articles_controller.test.php y pon lo siguiente dentro:


<?php
class ArticlesControllerTest extends CakeTestCase {
function startCase() {
echo '<h1>Comenzando Test Case</h1>';
}
function endCase() {
echo '<h1>Terminado Test Case</h1>';
}
function startTest($method) {
echo '<h3>Comenzando mtodo ' . $method . '</h3>';
}
function endTest($method) {
echo '<hr />';
}
function testIndex() {
$result = $this->testAction('/articles/index');
debug($result);
}
function testIndexShort() {
$result = $this->testAction('/articles/index/short');
debug($result);
}
function testIndexShortGetRenderedHtml() {
$result = $this->testAction('/articles/index/short',
array('return' => 'render'));
debug(htmlentities($result));
}
function testIndexShortGetViewVars() {
$result = $this->testAction('/articles/index/short',
array('return' => 'vars'));
debug($result);
}
function testIndexFixturized() {
$result = $this->testAction('/articles/index/short',
array('fixturize' => true));
debug($result);
}
function testIndexPostFixturized() {
$data = array('Article' => array('user_id' => 1, 'published'
=> 1, 'slug'=>'new-article', 'title' => 'New Article', 'body' => 'New

Body'));
$result = $this->testAction('/articles/index',
array('fixturize' => true, 'data' => $data, 'method' => 'post'));
debug($result);
}
}
?>

4.7.6.2 El mtodo testAction

La novedad aqu es el mtodo testAction. El primer argumento de este mtodo es la URL "en
formato Cake" de la accin del controlador que se quiere probar, como en '/articles/index/short'.
El segundo argumento es un array de parmetros, consistente en:
return
Indica lo que se va a devolver. Los valores vlidos son:
'vars' - Obtienes las variables de la vista disponibles tras ejecutar la accin
'view' - Obtienes la vista generada, sin layout
'contents' - Obtienes todo el html de la vista, incluyendo layout
'result' - Obtienes el valor de retorno de la accin como cuando se usa $this>params['requested'].
El valor por defecto es 'result'.
fixturize
Ponlo a true si quieres que tus modelos se "auto-simulen" (de modo que las tablas de la
aplicacin se copian, junto con los registros, para que al probar las tablas si cambias datos no
afecten a tu aplicacin real.) Si en 'fixturize' pones un array de modelos, entonces slo esos
modelos se auto-simularn mientras que los dems utilizarn las tablas reales. Si quieres usar tus
archivos de fixtures con testAction() no uses fixturize, y en su lugar usa las fixtures como haras
normalmente.
method
Ajustalo a 'post' o 'get' si quieres pasarle datos al controlador
data
Los datos que se pasarn. Ser un array asociativo consistente en pares de campo => valor.
chale un vistazo a function testIndexPostFixturized() en el case test de arriba
para ver cmo emulamos pasar datos de formulario como post para un nuevo artculo.

4.7.6.3 Pitfalls

If you use testAction to test a method in a controller that does a redirect, your test will terminate
immediately, not yielding any results.
See https://trac.cakephp.org/ticket/4154 for a possible fix.
4.7.7 Testing Helpers
Since a decent amount of logic resides in Helper classes, it's important to make sure those
classes are covered by test cases.
Helper testing is a bit similar to the same approach for Components. Suppose we have a helper called
CurrencyRendererHelper located in app/views/helpers/currency_renderer.php with its
accompanying

test

case

file

located

in

app/tests/cases/helpers/currency_renderer.test.php
4.7.7.1 Creating Helper test, part I

First of all we will define the responsibilities of our CurrencyRendererHelper. Basically, it will
have two methods just for demonstration purpose:
function usd($amount)
This function will receive the amount to render. It will take 2 decimal digits filling empty space
with zeros and prefix 'USD'.
function euro($amount)
This function will do the same as usd() but prefix the output with 'EUR'. Just to make it a bit
more complex, we will also wrap the result in span tags:
<span class="euro"></span>

Let's create the tests first:


<?php
//Import the helper to be tested.
//If the tested helper were using some other helper, like Html,
//it should be impoorted in this line, and instantialized in startTest().
App::import('Helper', 'CurrencyRenderer');
class CurrencyRendererTest extends CakeTestCase {
private $currencyRenderer = null;

//Here we instantiate our helper, and all other helpers we need.


public function startTest() {
$this->currencyRenderer = new CurrencyRendererHelper();
}
//testing usd() function.
public function testUsd() {
$this->assertEqual('USD 5.30', $this->currencyRenderer->usd(5.30));
//We should always have 2 decimal digits.
$this->assertEqual('USD 1.00', $this->currencyRenderer->usd(1));
$this->assertEqual('USD 2.05', $this->currencyRenderer->usd(2.05));
//Testing the thousands separator
$this->assertEqual('USD 12,000.70', $this->currencyRenderer>usd(12000.70));
}
}

Here, we call usd() with different parameters and tell the test suite to check if the returned
values are equal to what is expected.
Executing the test now will result in errors (because currencyRendererHelper doesn't even exist
yet) showing that we have 3 fails.
Once we know what our method should do, we can write the method itself:
<?php
class CurrencyRendererHelper extends AppHelper {
public function usd($amount) {
return 'USD ' . number_format($amount, 2, '.', ',');
}
}

Here we set the decimal places to 2, decimal separator to dot, thousands separator to comma,
and prefix the formatted number with 'USD' string.
Save this in app/views/helpers/currency_renderer.php and execute the test. You
should see a green bar and messaging indicating 4 passes.
4.7.8 Probando componentes
Supongamos que queremos hacer test a un componente llamado TransporterComponent, el cual
usa un modelo llamado Transporter para proporcionar funcionalidad a otros controladores.
Utilizaremos cuatro archivos:
Un

componente

llamado

Transporters

que

se

encuentra

en

app/controllers/components/transporter.php
Un modelo llamado Transporte que est en app/models/transporter.php
Una

fixture

llamada

TransporterTestFixture

situada

en

app/tests/fixtures/transporter_fixture.php
El cdigo para el test, en app/tests/cases/transporter.test.php
4.7.8.1 Initializing the component

Ya que CakePHP desaliante importar modelos directamente en los componentes necesitamos un


controlador para acceder a los datos en el mmodelo.
Si el mtodo startup() del componente tiene este aspecto:
public function startup(&$controller){
$this->Transporter = $controller->Transporter;
}

entonces podemos simplemente crear una clase sencilla:


class FakeTransporterController {}

y asignarle valores dentro de ella como aqu:


$this->TransporterComponentTest = new TransporterComponent();
$controller = new FakeTransporterController();
$controller->Transporter = new TransporterTest();
$this->TransporterComponentTest->startup(&$controller);

4.7.8.2 Creando un mtodo de prueba

Simplemente crea una clase que extienda CakeTestCase y comienza a escribir tests!
class TransporterTestCase extends CakeTestCase {
var $fixtures = array('transporter');
function testGetTransporter() {
$this->TransporterComponentTest = new TransporterComponent();
$controller = new FakeTransporterController();
$controller->Transporter = new TransporterTest();
$this->TransporterComponentTest->startup(&$controller);
$result = $this->TransporterComponentTest->getTransporter("12345",
"Sweden", "54321", "Sweden");
$this->assertEqual($result, 1, "SP is best for 1xxxx-5xxxx");
$result = $this->TransporterComponentTest->getTransporter("41234",

"Sweden", "44321", "Sweden");


$this->assertEqual($result, 2, "WSTS is best for 41xxx-44xxx");
$result = $this->TransporterComponentTest->getTransporter("41001",
"Sweden", "41870", "Sweden");
$this->assertEqual($result, 3, "GL is best for 410xx-419xx");
$result = $this->TransporterComponentTest->getTransporter("12345",
"Sweden", "54321", "Norway");
$this->assertEqual($result, 0, "Noone can service Norway");
}
}

4.7.9 Web testing - Testeando las vistas


La mayoria, si no es que lo son todos, los proyectos CakePHP son aplicaciones web. Aunque el
testeo unitario es una excelente manera de testear pequeas porciones de nuestro cdigo, hay ocaciones
en la que querriamos hacer un testeo a gran escala. La clase CakeWebTestCase nos brinda una muy
buena manera de hacer ste tipo de testing, desde el punto de vista del usuario.
4.7.9.1 About CakeWebTestCase

CakeWebTestCase es una extensin directa de SimpleTest WebTestCase, sin ninguna


funcionalidad extra. Toda la funcionalidad encontrada en la documentacin de SimpleTest para Testeo
Web (Web testing) tambien estn disponibles aqui. Esto quiere decir que no se pueden usar los fixtures,
y que todos los casos de testeo involucrados en un ABM (alta, baja o modificacin) a la base de
datos modificarn permanentemente los valores. Los resultados del Test son comparados
frecuentemente con los qe tiene la base de datos, por lo tanto, asegurarse que la bd tenga los valores
que se esperan, es parte del proceso de construccin del test.
4.7.9.2 Creando un test

Manteniendo las convenciones de los otros tests, los archivos de testeo de vistas se debern
crear en la carpeta tests/cases/views. Claro que se podrian guardar en otra ubicacin, pero siempre es
bueno

seguir

las

convenciones.

Entonces,

crearemos

el

archivo:

tests/cases/views/complete_web.test.php
Para escribir testeos web, debers extender la clase CakeWebTestCase y no CakeTestCase, tal
como era en los otros tests:
class CompleteWebTestCase extends CakeWebTestCase

Si necesitas hacer alguna inicializacin antes de que comience el test, crea el constructor:
function CompleteWebTestCase(){
//Do stuff here
}

Cuando escribes los test cases, lo primero que vas a necesitar hacer es capturar algun tipo de
salida o resultado donde ver y analizar. sto puede ser realizado haciendo un request get o post, usando
los mtodos get() o post() respectivamente. A ambos mtodos se le pasa como primer parmetro la url,
aunque

puede

ser

traida

dinmicamente

si

asumimos

que

script

de

testing

est

en

http://your.domain/cake/folder/webroot/test.php tipeando:
$this->baseurl = current(split("webroot", $_SERVER['PHP_SELF']));

Entonces podremos hacer gets y posts usando las urls de Cake, por ejemplo:
$this->get($this->baseurl."/products/index/");
$this->post($this->baseurl."/customers/login", $data);

El segundo parmetro del mtodo post, $data, es un array asociativo que contiene post data en
el formato de Cake:
$data = array(
"data[Customer][mail]" => "user@user.com",
"data[Customer][password]" => "userpass");

Una vez que se hizo el request a la pgina, se pueden utilizar todos los mismos asserts que veniamos
usando en SimpleTest.
4.7.9.3 Walking through a page

CakeWebTest also gives you an option to navigate through your page by clicking links or
images, filling forms and clicking buttons. Please refer to the SimpleTest documentation for more
information on that.

4.7.10 Testing plugins


Tests for plugins are created in their own directory inside the plugins folder.
/app
/plugins
/pizza
/tests
/cases
/fixtures
/groups

They work just like normal tests but you have to remember to use the naming conventions for
plugins when importing classes. This is an example of a testcase for the PizzaOrder model from the
plugins chapter of this manual. A difference from other tests is in the first line where 'Pizza.PizzaOrder'
is imported. You also need to prefix your plugin fixtures with 'plugin.plugin_name.'.
<?php
App::import('Model', 'Pizza.PizzaOrder');
class PizzaOrderCase extends CakeTestCase {
// Plugin fixtures located in /app/plugins/pizza/tests/fixtures/
var $fixtures = array('plugin.pizza.pizza_order');
var $PizzaOrderTest;
function testSomething() {
// ClassRegistry makes the model use the test database connection
$this->PizzaOrderTest =& ClassRegistry::init('PizzaOrder');

// do some useful test here


$this->assertTrue(is_object($this->PizzaOrderTest));

}
?>

If you want to use plugin fixtures in the app tests you can reference them using
'plugin.pluginName.fixtureName' syntax in the $fixtures array.
That is all there is to it.

4.7.11 Miscellaneous
4.7.11.1 Customizing the test reporter

The standard test reporter is very minimalistic. If you want more shiny output to impress
someone, fear not, it is actually very easy to extend. By creating a new reporter and making a request
with a matching output GET parameter you can get test results with a custom reporter.
Reporters generate the visible output from the test suite. There are two built in reporters: Text
and Html. By default all web requests use the Html reporter. You can create your own reporters by
creating

files

in

your

app/libs.

For

example

you

could

create

the

file

app/libs/test_suite/reporters/my_reporter.php and in it create the following:


require_once CAKE_TEST_LIB . 'reporter' . DS . 'cake_base_reporter.php';
class MyReporter extends CakeBaseReporter {
//methods go here.
}

Extending CakeBaseReporter or one of its subclasses is not required, but strongly


suggested as you may get missing errors otherwise. CakeBaseReporter encapsulates a few
common test suite features such as test case timing and code coverage report generation. You can use
your custom reporter by setting the output query string parameter to the reporter name minus
'reporter'. For the example above you would set output=my to use your custom reporter.
4.7.11.2 Test Reporter methods

Reporters have a number of methods used to generate the various parts of a Test suite response.
paintDocumentStart()
Paints the start of the response from the test suite. Used to paint things like head elements in an
html page.
paintTestMenu()
Paints a menu of available test cases.
testCaseList()
Retrieves and paints the list of tests cases.
groupCaseList()

Retrieves and paints the list of group tests.


paintHeader()
Prints before the test case/group test is started.
paintPass()
Prints everytime a test case has passed. Use $this->getTestList() to get an array of information
pertaining to the test, and $message to get the test result. Remember to call
parent::paintPass($message).
paintFail()
Prints everytime a test case has failed. Remember to call parent::paintFail($message).
paintSkip()
Prints everytime a test case has been skipped. Remember to call parent::paintSkip($message).
paintException()
Prints

everytime

there

is

an

uncaught

exception.

Remember

to

call

parent::paintException($message).
paintError()
Prints everytime an error is raised. Remember to call parent::paintError($message).
paintFooter()
Prints when the test case/group test is over, i.e. when all test cases has been executed.
paintDocumentEnd()
Paints the end of the response from the test suite. Used to paint things like footer elements in an
html page.
4.7.11.3 Grouping tests

If you want several of your test to run at the same time, you can try creating a test group. Create
a file in /app/tests/groups/ and name it something like your_test_group_name.group.php. In this
file, extend GroupTest and import test as follows:
<?php
class TryGroupTest extends TestSuite {
var $label = 'try';
function tryGroupTest() {
TestManager::addTestCasesFromDirectory($this, APP_TEST_CASES . DS . 'models');
}
}
?>

The code above will group all test cases found in the /app/tests/cases/models/ folder. To add an
individual file, use TestManager::addTestFile($this, filename).

4.7.12 Running tests in the Command Line


If you have simpletest installed you can run your tests from the command line of your
application.
from app/
cake testsuite help
Usage:
cake testsuite category test_type file
- category - "app", "core" or name of a plugin
- test_type - "case", "group" or "all"
- test_file - file name with folder prefix and without the (test|
group).php suffix
Examples:

cake testsuite app all


cake testsuite core all
cake testsuite app case behaviors/debuggable
cake testsuite app case models/my_model
cake testsuite app case controllers/my_controller
cake testsuite core case file
cake testsuite core case router
cake testsuite core case set
cake testsuite app group mygroup
cake testsuite core group acl
cake testsuite core group socket
cake
//
cake
//

testsuite bugs
for the plugin
testsuite bugs
for the plugin

case models/bug
'bugs' and its test case 'models/bug'
group bug
bugs and its test group 'bug'

Code Coverage Analysis:


Append 'cov' to any of the above in order to enable code coverage analysis

As the help menu suggests, you'll be able to run all, part, or just a single test case from your app,
plugin, or core, right from the command line.
If you have a model test of test/models/my_model.test.php you'd run just that test case by running:
cake testsuite app models/my_model

4.7.13 Test Suite changes in 1.3


The TestSuite harness for 1.3 was heavily refactored and partially rebuilt. The number of
constants and global functions have been greatly reduced. Also the number of classes used by the test
suite has been reduced and refactored. You must update app/webroot/test.php to continue
using the test suite. We hope that this will be the last time that a change is required to
app/webroot/test.php.
Removed Constants
CAKE_TEST_OUTPUT
RUN_TEST_LINK
BASE
CAKE_TEST_OUTPUT_TEXT
CAKE_TEST_OUTPUT_HTML
These constants have all been replaced with instance variables on the reporters and the ability to
switch reporters.
Removed functions
CakePHPTestHeader()
CakePHPTestSuiteHeader()
CakePHPTestSuiteFooter()
CakeTestsGetReporter()
CakePHPTestRunMore()
CakePHPTestAnalyzeCodeCoverage()
CakePHPTestGroupTestList()
CakePHPTestCaseList()
These methods and the logic they contained have been refactored/rewritten into
CakeTestSuiteDispatcher and the relevant reporter classes. This made the test suite more
modular and easier to extend.
Removed Classes
HtmlTestManager

TextTestManager
CliTestManager
These classes became obsolete as logic was consolidated into the reporter classes.
Modified methods/classes
The following methods have been changed as noted.
TestManager::getExtension() is no longer static.
TestManager::runAllTests() is no longer static.
TestManager::runGroupTest() is no longer static.
TestManager::runTestCase() is no longer static.
TestManager::getTestCaseList() is no longer static.
TestManager::getGroupTestList() is no longer static.
testsuite Console changes
The output of errors, exceptions, and failures from the testsuite console tool have been updated
to remove redundant information and increase readability of the messages. If you have other tools built
upon the testsuite console, be sure to update those tools with the new formatting.
CodeCoverageManager changes
CodeCoverageManager::start()'s

functionality

has

been

moved

CodeCoverageManager::init()
CodeCoverageManager::start() now starts coverage generation.
CodeCoverageManager::stop() pauses collection
CodeCoverageManager::clear() stops and clears collected coverage reports.

to

4.8 Internacionalizacin & Localizacin


Una de las mejores maneras para que tus aplicaciones lleguen a un pblico ms amplio es
brindarlo en varios idiomas. Esto a menudo puede resultar ser una tarea de enormes proporciones, pero
las funciones de internacionalizacin y localizacin en CakePHP lo hace mucho ms fcil.
En primer lugar, es importante comprender algunos trminos. Internacionalizacin se refiere a
la capacidad de una aplicacin para ser localiza. El trmino localizacin se refiere a la adaptacin de
una aplicacin para responder a los requerimientos de un lenguaje (o cultura) especfico (es decir, un
"lugar"). La internacionalizacin y localizacin son a menudo abreviados como i18n y l10n,
respectivamente, 18 y 10 son el nmero de caracteres entre el primero y el ltimo carcter.
4.8.1 Internacionalizando su aplicacin
Hay slo unos pocos pasos para pasar de una aplicacin de un solo idioma a una aplicacin
multi-idioma, la primera de ellas es hacer uso de la funcin __() en su cdigo. A continuacin se
muestra un ejemplo de cdigo para una aplicacin de un solo idioma:
<h2>Posts</h2>

Para internacionalizar su cdigo todo lo que necesitas hacer es envolver las cadenas de texto en
la funcin translate como se muestra a continuacin:
<h2><?php __('Posts') ?></h2>

Si no hace nada ms, estos dos ejemplos de cdigo son funcionalmente idnticos ambos
envan el mismo contenido al navegador. La funcin __() traducir la cadena de texto que se pasa si
la traduccin est disponible, si no, devolver la cadena sin modificar. Funciona de manera similar a
otras implementaciones de Gettext (igual que otras funciones de traduccin como __d(), __n() etc)
Con el cdigo listo para ser multi-idioma, el siguiente paso es crear su archivo pot, que es el
modelo para todas las cadenas de texto traducibles en su aplicacin. Para generar archivos pot(s) todo
lo que necesita es ejecutar la tarea i18n en la consola, que buscar las funciones translate utilizadas en
su cdigo y crear los archivos por usted. Usted puede y debe volver a ejecutar esta tarea cada vez que
se produzca algn cambio de las traducciones en el cdigo.
Los archivos pot(s) en si mismos no son utilizados por CakePHP, son las plantillas utilizadas
para crear o actualizar los archivos po, que contienen las traducciones. Cake buscar los archivos po en

la siguiente ubicacin:
/app/locale/<locale>/LC_MESSAGES/<domain>.po

El dominio por defecto es 'default', por lo tanto en su carpeta locale se ver algo como esto:
/app/locale/eng/LC_MESSAGES/default.po (English)
/app/locale/fre/LC_MESSAGES/default.po (French)
/app/locale/por/LC_MESSAGES/default.po (Portuguese)

Para crear o editar su archivo po no se recomienda que utilice su editor favorito. Para crear un
archivo po por primera vez es recomendable copiar el archivo pot a la ubicacin correcta y cambiar la
extensin, a menos que usted est familiarizado con su formato. Es muy fcil crear un archivo po
invlido o guardarlos con una codificacin errnea (si est editando manualmente el archivo po use
UTF-8 para evitar problemas). Existen herramientas gratuitas como PoEdit que hacen de la edicin y
actualizacin de sus archivos po una tarea fcil.
Los cdigos de localizacin correctos son los de tres caracteres conforme al estandar ISO 639-2
aunque si crea locales regionales (en_US, en_GB, etc.) Cake los utiliza si procede.
hay un lmite de 1.014 caracteres para cada valor msgstr.
Recuerde que los archivos po son tiles para mensajes cortos, si necesita traducir prrafos
largos, o incluso pginas completas, debe considerar aplicar una solucin diferente. Por ejemplo:
// App Controller Code.
function beforeFilter() {
$locale = Configure::read('Config.language');
if ($locale && file_exists(VIEWS . $locale . DS . $this->viewPath)) {
//
e.g.
use
/app/views/fre/pages/tos.ctp
instead
/app/views/pages/tos.ctp
$this->viewPath = $locale . DS . $this->viewPath;
}
}

o
// View code
echo $this->element(Configure::read('Config.language') . '/tos')

4.8.2 Localizacin en CakePHP


Para cambiar o definir el idioma para su aplicacin slo necesita hacer lo siguiente:
Configure::write('Config.language', 'fre');

of

Esto le dice a Cake qu localizacin debe usar (si usa una localizacin regional como fr_FR,
como alternativa en caso que no exista, se utilizar la localizacin de la norma ISO 639-2). Puede
cambiar el idioma en cualquier momento, por ejemplo en el bootstrap si desea definir el idioma por
defecto para su aplicacin, en el beforeFilter del controlador si el idioma es especfico para una
peticin o un usuario o en cualquier otro momento si desea mostrar un mensaje en un idioma diferente.
Es una buena idea mostrar contenido disponible en varios idiomas a partir de una URL diferente
esto hace que sea fcil para los usuarios (y los motores de bsqueda) encontrar lo que estn buscando
en el idioma esperado. Hay varias formas de hacer esto, puede ser utilizando subdominios especficos
para cada idioma, (en.example.com, fra.example.com, etc), o usando un prefijo en la URL, como se
hace en esta aplicacin. Usted tambin podra obtener la informacin del navegador del usuario, entre
otras cosas.
Como se menciona en la seccin anterior, para mostrar el contenido localizado se utiliza la
funcin __() o una de las funciones de traduccin disponibles a nivel mundial. El primer parmetro de
la funcin se utiliza como msgid definidos en los archivos .po.
Recuerde que debe usar el parmetro return de la funcin __() si no desea que se muestre la
cadena de texto directamente. Por ejemplo:
<?php
echo $form->error(
'Card.cardNumber',
__("errorCardNumber", true),
array('escape' => false)
);
?>

Si a usted le gusta tener todos los mensajes de error de validacin traducidos por defecto, una
solucin simple sera aadir el siguiente cdigo en el app_model.php:
function invalidate($field, $value = true) {
return parent::invalidate($field, __($value, true));
}

La tarea i18n de la consola no ser capaz de determinar el id del mensaje del ejemplo anterior,
lo que significa que tendr que aadir las entradas a su archivo po manualmente (o a travs de su
propio script). Para evitar la necesidad de editar los archivos default.po cada vez que ejecute la tarea
i18n de la consola, puede utilizar un dominio diferente, tal como:
function invalidate($field, $value = true) {
return parent::invalidate($field, __d('validation_errors', $value, true));
}

Hay otro aspecto de la localizacin de su aplicacin que no est cubierto por el uso de las
funciones de traduccin, estos son los formatos de fecha y moneda. No olvide que CakePHP es PHP :),
por lo tanto para establecer los formatos para este tipo de cosas deber utilizar setlocale.
Si pasa una localizacin que no existe en su computadora a setlocale, no tendr ningn
efecto. Puede encontrar la lista de localizaciones disponibles ejecutando el comando $locale -a

4.9 Paginacin
Uno de los obstculos principales al crear aplicaciones web flexibles y amigables al usuario
(user-friendly) es disear una Interfaz de Usuario intuitiva. Muchas aplicaciones tienden a crecer en
tamao y complejidad rpidamente, y tanto diseadores como programadores se encuentran conque no
pueden arreglrselas para visualizar cientos o miles de registros. Refactorizar lleva tiempo, y el
rendimiento y la satisfaccin del usuario pueden sufrir.
Visualizar un nmero razonable de registros por pgina ha sido siempre una parte crtica de toda
aplicacin y sola causar muchos dolores de cabeza a los desarrolladores. CakePHP aligera la carga del
desarrollador proveyendo una manera rpida y fcil de paginar los datos.
El ayudante PaginatorHelper ofrece una genial solucin porque es fcil de usar. Adems
de paginacin, empaqueta algunas caractersticas de ordenacin muy fciles de usar. Por ltimo, pero
no menos importante, tambin estn soportados el paginado y la ordenacin Ajax.
4.9.1 Preparacin del controlador
En el controlador comenzamos definiendo los valores de paginacin por defecto en la variable
$paginate. Es importante sealar que la clave 'order' debe estar definida en la estructura de array dada.
class RecipesController extends AppController {
var $paginate = array(
'limit' => 25,
'order' => array(
'Post.title' => 'asc'
)
);
}

Tambin puedes incluir otras opciones para find(), como fields


class RecipesController extends AppController {
var $paginate = array(

'fields' => array('Post.id', 'Post.created'),


'limit' => 25,
'order' => array(
'Post.title' => 'asc'
)
}

);

Pueden incluirse otras claves en el array $paginate similares a los parmetos del mtodo Model>find('all'), esto es: conditons, fields, order, limit, page, contain y recursive. De hecho, puedes definir
ms de un conjunto de valores de paginacin por defecto en el controllador, simplemente nombra cada
parte del array segn el modelo que desees configurar:
class RecipesController extends AppController {

var $paginate = array(


'Recipe' => array (...),
'Author' => array (...)
);

Ejemplo de sintaxis usando Containable Behavior:


class RecipesController extends AppController {

var $paginate = array(


'limit' => 25,
'contain' => array('Article')
);

Una vez que la variable $paginate ha sido definida, podemos llamar al mtodo paginate() en las
acciones del controlador. Este mtodo devuelve los resultados de find('all') del modelo (aplicndoles
los parmetros de la paginacin), y obtiene algunas estadsticas de paginacin adicionales, que son
pasadas a la Vista de forma invisible. Este mtodo tambin aade PaginatorHelper a la lista de helpers
en tu controlador, si es que no estaba ya.
function list_recipes() {
// similar to findAll(), but fetches paged results
$data = $this->paginate('Recipe');
$this->set(compact('data'));
}

Puedes filtrar los registros pasando condiciones como segundo parmetro al mtodo paginate()
$data = $this->paginate('Recipe', array('Recipe.title LIKE' => 'a%'));

O tambin puedes ajustar la clave conditions en la variable paginate.

4.9.2 Pagination in Views


Es cosa tuya decidir cmo mostrar los registros al usuario, aunque lo ms habitual es hacerlo
mediante tablas HTML. Los ejemplos que siguen asumen una disposicin tabular, pero el
PaginatorHelper, disponible en las vistas, no siempre necesita restringirse de ese modo.
Como ya se ha dicho, PaginatorHelper ofrece capacidades para ordenacin que pueden
integrarse fcilmente en las cabeceras de las columnas de tus tablas:
// app/views/recipes/list_recipes.ctp
<table>
<tr>
<th><?php echo $paginator->sort('ID', 'id'); ?></th>
<th><?php echo $paginator->sort('Title', 'title'); ?></th>
</tr>
<?php foreach($data as $recipe): ?>
<tr>
<td><?php echo $recipe['Recipe']['id']; ?> </td>
<td><?php echo $recipe['Recipe']['title']; ?> </td>
</tr>
<?php endforeach; ?>
</table>

Los enlaces generados por el mtodo sort() de PaginatorHelper permiten a los usuarios hacer
click en las cabeceras de las tablas y alternar la ordenacin de los datos por un campo dado.
Tambin es posible ordenar una columna en base a asociaciones:
<table>
<tr>
<th><?php echo $paginator->sort('Title', 'title'); ?></th>
<th><?php echo $paginator->sort('Author', 'Author.name'); ?></th>
</tr>
<?php foreach($data as $recipe): ?>
<tr>
<td><?php echo $recipe['Recipe']['title']; ?> </td>
<td><?php echo $recipe['Author']['name']; ?> </td>
</tr>
<?php endforeach; ?>
</table>

El ingrediente final de la paginacin en las vistas es aadir la navegacin de pginas, que


tambin viene proporcionada por PaginationHelper.
<!-- Muestra los nmeros de pgina -->
<?php echo $paginator->numbers(); ?>
<!-- Muestra los enlaces para Anterior y Siguiente -->
<?php
echo $paginator->prev(' Previous ', null, null, array('class' =>
'disabled'));
echo

$paginator->next('

Next

',

null,

null,

array('class'

=>

'disabled'));
?>
<!-- Muestra X de Y, donde X es la pgina actual e Y el total del pginas -->
<?php echo $paginator->counter(); ?>

El texto generado por el mtodo counter() puede personalizarse usando marcadores especiales:
<?php
echo $paginator->counter(array(
'format' => 'Page %page% of %pages%, showing %current% records out of
%count% total, starting on record %start%, ending on %end
%'
));
?>

Para pasar todos los argumentos de la URL a las funciones del paginador, aade lo siguiente a tu
vista:
$paginator->options(array('url' => $this->passedArgs));

Tambin puedes especificar qu parmetros pasar manualmente:


$paginator->options(array('url' =>

array("0", "1")));

4.9.3 Paginacin AJAX


Es muy fcil incorporar funcionalidad Ajax en la paginacin. El nico cdigo extra que
necesitas es incluir la librera JavaScript Prototype, ajustar el indicador (el icono de carga dentro la
DIV) y especificar la DIV que ser actualizada en lugar de recargar la pgina.
No olvides aadir el componente RequestHandler para poder usar llamadas Ajax en tu controlador:

var $components = array('RequestHandler');

# Configuring the PaginatorHelper to use a custom helper

By default in 1.3 the PaginatorHelper uses JsHelper to do ajax features. However, if you
don't want that and want to use the AjaxHelper or a custom helper for ajax links, you can do so by
changing the $helpers array in your controller. After running paginate() do the following.
$this->set('posts', $this->paginate());
$this->helpers['Paginator'] = array('ajax' => 'Ajax');

Will change the PaginatorHelper to use the AjaxHelper for ajax operations. You could
also set the 'ajax' key to be any helper, as long as that class implements a link() method that behaves
like HtmlHelper::link()
4.9.4 Custom Query Pagination
Fix me: Please add an example where overriding paginate is justified
A good example of when you would need this is if the underlying DB does not support the SQL
LIMIT syntax. This is true of IBM's DB2. You can still use the CakePHP pagination by adding the
custom query to the model.
Should you need to create custom queries to generate the data you want to paginate, you can
override the paginate() and paginateCount() model methods used by the pagination
controller logic.
Before continuing check you can't achieve your goal with the core model methods.
The paginate() method uses the same parameters as Model::find(). To use your own
method/logic override it in the model you wish to get the data from.
/**
* Overridden paginate method - group by
*/
function paginate($conditions, $fields,
null, $extra = array()) {
$recursive = -1;
$group = $fields = array('week',
return $this->find('all',
'limit', 'page', 'recursive', 'group'));
}

week, away_team_id and home_team_id


$order, $limit, $page = 1, $recursive =
'away_team_id', 'home_team_id');
compact('conditions', 'fields', 'order',

You also need to override the core paginateCount(), this method expects the same
arguments as Model::find('count'). The example below uses some Postgres-specifc features,
so please adjust accordingly depending on what database you are using.
/**
* Overridden paginateCount method
*/
function paginateCount($conditions = null, $recursive = 0, $extra = array()) {
$sql = "SELECT DISTINCT ON(week, home_team_id, away_team_id) week,
home_team_id, away_team_id FROM games";
$this->recursive = $recursive;
$results = $this->query($sql);
return count($results);
}

The observant reader will have noticed that the paginate method we've defined wasn't actually
necessary - All you have to do is add the keyword in controller's $paginate class variable.
/**
* Add GROUP BY clause
*/
var $paginate = array(
'MyModel' => array('limit' => 20,
'order' => array('week' => 'desc'),
'group' => array('week', 'home_team_id',
'away_team_id'))
);
/**
* Or on-the-fly from within the action
*/
function index() {
$this->paginate = array(
'MyModel' => array('limit' => 20,
'order' => array('week' => 'desc'),
'group' => array('week', 'home_team_id',
'away_team_id'))
);

However, it will still be necessary to override the paginateCount() method to get an accurate
value.

4.10 REST
Many newer application programmers are realizing the need to open their core functionality to a
greater audience. Providing easy, unfettered access to your core API can help get your platform
accepted, and allows for mashups and easy integration with other systems.
While other solutions exist, REST is a great way to provide easy access to the logic you've

created in your application. It's simple, usually XML-based (we're talking simple XML, nothing like a
SOAP envelope), and depends on HTTP headers for direction. Exposing an API via REST in CakePHP
is simple.
4.10.1 The Simple Setup
The fastest way to get up and running with REST is to add a few lines to your routes.php file,
found in app/config. The Router object features a method called mapResources(), that is used to set up
a number of default routes for REST access to your controllers. If we wanted to allow REST access to a
recipe database, we'd do something like this:
//In app/config/routes.php...
Router::mapResources('recipes');
Router::parseExtensions();

The first line sets up a number of default routes for easy REST access where method specifies
the desired result format (e.g. xml, json, rss). These routes are HTTP Request Method sensitive.
HTTP Method URL.method
Controller action invoked
GET
/recipes.method
RecipesController::index()
GET
/recipes/123.method RecipesController::view(123)
POST
/recipes.method
RecipesController::add()
PUT
/recipes/123.method RecipesController::edit(123)
DELETE
/recipes/123.method RecipesController::delete(123)
POST
/recipes/123.method RecipesController::edit(123)
CakePHP's Router class uses a number of different indicators to detect the HTTP method being
used. Here they are in order of preference:
1. The _method POST variable
2. The X_HTTP_METHOD_OVERRIDE
3. The REQUEST_METHOD header
The _method POST variable is helpful in using a browser as a REST client (or anything else
that can do POST easily). Just set the value of _method to the name of the HTTP request method you
wish to emulate.
Once the router has been set up to map REST requests to certain controller actions, we can
move on to creating the logic in our controller actions. A basic controller might look something like
this:
// controllers/recipes_controller.php

class RecipesController extends AppController {


var $components = array('RequestHandler');
function index() {
$recipes = $this->Recipe->find('all');
$this->set(compact('recipes'));
}
function view($id) {
$recipe = $this->Recipe->findById($id);
$this->set(compact('recipe'));
}
function edit($id) {
$this->Recipe->id = $id;
if ($this->Recipe->save($this->data)) {
$message = 'Saved';
} else {
$message = 'Error';
}
$this->set(compact("message"));
}
function delete($id) {
if($this->Recipe->delete($id)) {
$message = 'Deleted';
} else {
$message = 'Error';
}
$this->set(compact("message"));
}
}

Since we've added a call to Router::parseExtensions(), the CakePHP router is already primed to
serve up different views based on different kinds of requests. Since we're dealing with REST requests,
the view type is XML. We place the REST views for our RecipesController inside app/views/xml. We
can also use the XmlHelper for quick-and-easy XML output in those views. Here's what our index view
might look like:
// app/views/recipes/xml/index.ctp
<recipes>
<?php echo $xml->serialize($recipes); ?>
</recipes>

Experienced CakePHP users might notice that we haven't included the XmlHelper in our
RecipesController $helpers array. This is on purpose - when serving up a specific content type using
parseExtensions(), CakePHP automatically looks for a view helper that matches the type. Since we're
using XML as the content type, the XmlHelper is automatically loaded up for our use in those views.

The rendered XML will end up looking something like this:


<posts>
<post id="234" created="2008-06-13" modified="2008-06-14">
<author id="23423" first_name="Billy" last_name="Bob"></author>
<comment id="245" body="This is a comment for this
post."></comment>
</post>
<post id="3247" created="2008-06-15" modified="2008-06-15">
<author id="625" first_name="Nate" last_name="Johnson"></author>
<comment id="654" body="This is a comment for this
post."></comment>
</post>
</posts>

Creating the logic for the edit action is a bit trickier, but not by much. Since you're providing an
API that outputs XML, it's a natural choice to receive XML as input. Not to worry, however: the
RequestHandler and Router classes make things much easier. If a POST or PUT request has an XML
content-type, then the input is taken and passed to an instance of Cake's Xml object, which is assigned
to the $data property of the controller. Because of this feature, handling XML and POST data in
parallel is seamless: no changes are required to the controller or model code. Everything you need
should end up in $this->data.
4.10.2 Custom REST Routing
If the default routes created by mapResources() don't work for you, use the Router::connect()
method to define a custom set of REST routes. The connect() method allows you to define a number of
different options for a given URL. The first parameter is the URL itself, and the second parameter
allows you to supply those options. The third parameter allows you to specify regex patterns to help
CakePHP identify certain markers in the specified URL.
We'll provide a simple example here, and allow you to tailor this route for your other RESTful
purposes. Here's what our edit REST route would look like, without using mapResources():
Router::connect(
"/:controller/:id",
array("action" => "edit", "[method]" => "PUT"),
array("id" => "[0-9]+")
)

Advanced routing techniques are covered elsewhere, so we'll focus on the most important point
for our purposes here: the [method] key of the options array in the second parameter. Once that key has
been set, the specified route works only for that HTTP request method (which could also be GET,
DELETE, etc.)

5 Componentes del Ncleo


CakePHP posee una serie de componentes integrados. stos proveen distintas funcionalidades
para tareas realizadas comnmente.
El componente Acl provee una sencilla interfaz para listas de control de acceso

Acl

(access control list) basadas en archivos ini o base de datos.


El componente Auth provee un sistema de autenticacin fcil de utilizar usando

Auth

diferentes procesos de validacin, como ser callbacks en los controladores, Acl u

Session

callbacks en los objetos.


El componente Session provee un wrapper de almacenamiento independiente a las
sesiones de PHP.
El componente RequestHandler permite analizar las peticiones HTTP para

RequestHandler informarle a la aplicacin acerca del tipo de contenido y la informacin requerida

Security
Email
Cookie

por el usuario.
El componente Security permite aumentar la seguridad y gestionar autenticacin
HTTP.
Una interfaz que puede ser utilizada para enviar emails usando distintos MTA (mail
transfer agent) incluyendo la funcin mail() de PHP y el protocolo SMTP.
El componente Cookie se comporta en cierta forma similar al Session ya que provee

un wrapper para el soporte nativo de cookies en PHP.


Para aprender ms acerca de cada componente mira en el menu a la izquierda, o aprende acerca de
cmo crear tus propios componentes.

5.1 Listas de Control de Acceso


La funcionalidad de listas de control de acceso en CakePHP es una de las ms comentadas, en
parte porque es una de las ms solicitadas, y en parte porque puede ser algo confusa al principio. Si
ests buscando un buen lugar para comenzar a utilizar ACL en general, contina leyendo.
Debes ser valiente, incluso cuando las cosas se compliquen. Una vez que asimiles estos
conceptos, las listas de control de acceso son una herramienta extremadamente poderosa para tener a
mano al desarrollar tu aplicacin.

5.1.1 Entendiendo cmo funciona ACL

Las listas de control de acceso permiten gestionar detalladamente los permisos de una
aplicacin de forma sencilla y escalable.
Las listas de control de acceso, o ACL, manejan principalmente dos cosas: las entidades que
solicitan el control de algo y las entidades que se quiere controlar. En la jerga de ACL, las entidades
que quieren controlar algo, que la mayora de las veces son los usuarios, son los ARO (en ingls access
request objects), y las entidades del sistema que se quiere controlar, que normalmente son acciones o
datos, son los ACO (en ingls access control objects). A los ARO se les llama 'objetos' porque quien
realiza la peticin no siempre es una persona; los ACO son cualquier cosa que desees controlar: desde
la accin de un controlador o un servicio Web, hasta el diario en lnea ntimo de tu abuela.
En resumen:
ACO - Access Control Object - Objeto que se quiere controlar
ARO - Access Request Object - Objeto que solicita el control de algo
Esencialmente, las ACL se utilizan para decidir cundo un ARO puede acceder a un ACO.
Vamos a utilizar un ejemplo prctico para ver cmo encajan todas estas piezas. Imaginemos que
el grupo de aventureros de la novela de fantasa El seor de los Anillos trabaja con una aplicacin
CakePHP, y que el lder, Gandalf, se encarga de gestionar los elementos del grupo. Para garantizar la
privacidad y la seguridad de los miembros del grupo, pues, lo primero que hace Gandalf es crear la lista
de AROs involucrados:
Gandalf
Aragorn
Bilbo
Frodo
Gollum
Legolas
Gimli
Pippin
Merry

Fjate que ACL no es lo mismo que la autenticacin; ACL es lo que ocurre despus de que el
usuario se autentica. Aunque suelen utilizarse los dos a la vez, es importante ver la diferencia entre
saber quin es alguien (autenticacin) y saber qu puede hacer (ACL).
A continuacin, Gandalf tiene que crear una lista con las cosas, o ACOs, que el sistema maneja.
Esta lista puede ser como la siguiente:
Armas
El Anillo
Jamn
Diplomacia
Cerveza
Armas El Anillo Jamn Diplomacia Cerveza
Gandalf

Permitir Permitir

Permitir

Aragorn Permitir

Permitir Permitir

Permitir

Bilbo

Permitir

Frodo

Permitir

Gollum

Permitir
Permitir

Legolas

Permitir

Permitir Permitir

Gimli

Permitir

Permitir

Pippin

Permitir

Merry

Permitir
Permitir
Permitir

A simple vista, parece que este tipo de sistema funciona bastante bien. En efecto, las
asignaciones garantizan la seguridad (slo Frodo puede acceder al anillo) y previenen los accidentes
(los Hobbits se mantienen lejos del jamn y de las armas). Parece bastante detallado y fcil de leer,
verdad?
Sin embargo, una matriz como esta slo funciona en un sistema pequeo; en un sistema que
tenga previsto crecer, o que tenga muchos recursos (ACOs) y usuarios (AROs), es difcil mantenerla.
Ciertamente, te imaginas, en este ejemplo, cmo se controlara el acceso a cientos de campamentos de
guerra, gestionndolos por unidad? Otro inconveniente de las matrices es que no permiten formar
grupos lgicos de usuarios ni aplicar cambios de permiso en cascada a estos grupos. En otras palabras,
estara muy bien que, una vez terminada la batalla, los hobbits pudieran acceder a la cerveza y al

jamn; en otras palabras, otorgar individualmente permisos a hobbits es tedioso y propenso a errores,
mientras que aplicarles un cambio en cascada es mucho ms fcil.
ACL se suele implementar en una estructura de rbol, y, generalmente, existe un rbol de AROs
y un rbol de ACOs. Organizando los objetos as, los permisos se gestionan de forma granular y se
mantiene una visin general; en consecuencia, siendo el sabio lder que es, Gandalf decide utilizar ACL
en su sistema y organiza los objetos de la siguiente manera:
Comunidad del Anillo
Guerreros
Aragorn
Legolas
Gimli
Magos
Gandalf
Hobbits
Frodo
Bilbo
Merry
Pippin
Visitantes
Gollum
Utilizar una estructura de rbol en los AROs permite a Gandalf definir permisos que se aplican
a un grupo de usuarios, de una sola vez. Por lo tanto, Gandalf aade ahora estos permisos a los grupos:
Comunidad del Anillo
(Denegar: todo)
Guerreros
(Permitir: Armas, Cerveza, Raciones, Jamn)
Aragorn
Legolas
Gimli
Magos

(Permitir: Jamn, Diplomacia, Cerveza)


Gandalf
Hobbits
(Permitir: Cerveza)
Frodo
Bilbo
Merry
Pippin
Visitantes
(Permitir: Jamn)
Gollum
Para ver si Pippin tiene acceso a la cerveza, lo primero que tenemos que hacer es obtener su
camino en el rbol: Comunidad del Anillo->Hobbits->Pippin. A continuacin, hay que ver los permisos
que residen en cada uno de esos puntos, y, finalmente, se utiliza el ms especfico relacionado con
Pippin y la Cerveza.
Nodo ARO
Comunidad del Anillo
Hobbits
Pippin

Informacin de Permisos
Denegar todo
Permitir 'Cerveza'
--

Resultado
Acceso a la Cerveza denegado.
Acceso a la Cerveza permitido!
Todava se le permite la Cerveza!

Como el nodo de 'Pippin' del rbol ACL no deniega especficamente el acceso al ACO
'Cerveza', el resultado final es que se permite el acceso a ese ACO.
Adems, el rbol permite realizar ajustes ms finos para tener un control ms granular y no
pierda la capacidad de realizar cambios importantes en los grupos de AROs:
Comunidad del Anillo
(Denegar: todo)
Guerreros
(Permitir: Armas, Cerveza, Raciones, Jamn)
Aragorn
(Permitir: Diplomacia)
Legolas

Gimli
MAgos
(Permitir: Jamn, Diplomacia, Cerveza)
Gandalf
Hobbits
(Permitir: Cerveza)
Frodo
(Permitir: Anillo)
Bilbo
Merry
(Denegar: Cerveza)
Pippin
(Permitir: Diplomacia)
Visitantes
(Permitir: Jamn)
Gollum
Esta aproximacin permite realizar cambios de permisos globales y, al mismo tiempo, ajustes
granulares. Por lo tanto, podemos decir que, a excepcin de Merry, todos los hobbits tienen acceso a la
cerveza. De nuevo, para saber si Merry tiene acceso a la Cerveza, primero debemos encontrar su
camino en el rbol, Comunidad del Anillo->Hobbits->Merry, bajar, y analizar los premisos
relacionados con la Cerveza:
Nodo ARO
Comunidad del Anillo
Hobbits
Merry

Informacin de Permisos
Denegar todo
Permitir 'Cerveza'
Denegar 'Cerveza'

Resultado
Acceso a la Cerveza denegado.
Acceso a la Cerveza permitido!
Cerveza denegada.

5.1.2 Definiendo Permisos: ACL basado en INI


La primer implementacin de ACL en Cake fue basada en archivos INI almacenados en el
directorio de instalacin de Cake. Si bien es til y estable, recomendamos que utilices la solucin de
ACL apoyada en la base de datos, sobre todo por la posibilidad de crear nuevos ACOs y AROs dentro
de la aplicacin. La implementacin con archivos INI fue pensada para ser utilizada en aplicaciones
simples, especialmente en aquellas que por alguna razn podran no utilizar una base de datos.
Por defecto, CakePHP utiliza el sistema de ACL apoyado en la base de datos. Para habilitar el
uso de ACL con archivos INI, tiene que decirle a CakePHP qu sistema vas a usar editando las
siguientes lneas en app/config/core.php
//Cambiar stas lneas:
Configure::write('Acl.classname', 'DbAcl');
Configure::write('Acl.database', 'default');
//Para que se vean como stas:
Configure::write('Acl.classname', 'IniAcl');
//Configure::write('Acl.database', 'default');

Los permisos ARO/ACO son especificados en /app/config/acl.ini.php. Bsicamente los AROs


se deben especificar en la seccin del INI que tiene tres propiedades: grupos, permitir y denegar.
grupos: nombres de los grupos de AROs a los que pertenece este ARO.
permitir: nombres de los ACOs a los que tiene acceso este ARO.
denegar: nombres de los ACOs a los que este ARO no tiene acceso.

Los ACOs se definen en la seccin del INI que slo incluye las propiedades permitir y denegar.
Como ejemplo, veamos cmo se vera la estructura de AROs de la Comunidad del Anillo en la sintaxis
del INI:
;------------------------------------; AROs
;------------------------------------[aragorn]
grupos = guerreros
permitir = diplomacia
[legolas]
grupos = guerreros
[gimli]
grupos = guerreros
[gandalf]
grupos = magos
[frodo]
grupos = hobbits
permitir = ring
[bilbo]
grupos = hobbits
[merry]
grupos = hobbits
deny = cerveza
[pippin]
grupos = hobbits
[gollum]
grupos = visitantes
;------------------------------------; ARO Groups
;------------------------------------[guerreros]
permitir = armas, cerveza, jamn
[magos]
permitir = jamn, diplomacia, cerveza
[hobbits]
permitir = cerveza
[visitantes]
permitir = jamn

Ahora que ya has definido los permisos, puede saltar a la seccin de verificacin de permisos
utilizando el componente ACL.

5.1.3 Definiendo Permisos: ACL en la base de datos


Ahora que ya hemos cubierto los permisos de ACL basados en archivos INI, veamos los
permisos (ms comnmente utilizados) basados en base de datos.
5.1.3.1 Comenzando

La implementacin de ACL por defecto est basada en la base de datos. sta consiste en un
conjunto de modelos y una aplicacin de consola que viene con la instalacin de Cake. Los modelos
son usados por Cake para interactuar con la base de datos para poder almacenar y recuperar los nodos
en forma de rbol. La aplicacin de consola se utiliza para inicializar la base de datos e interacturar con
los rboles de ACOs y AROs
Para comenzar, lo primero que deber asegurarte es que /app/config/database.php
exista y est correctamente configurado. Referirse a la seccin 4.1 para ms informacin acerca de la
configuracin de la base de datos.
Una vez que hayas hecho esto, tienes que utilizar la consola de CakePHP para crear las tablas de
ACL:
$ cake schema run create DbAcl

Ejecutando este comando recrear las tablas necesarias para almacenar los rbols de ACOs y
AROs (si las tablas ya existan, este comando las elimina y las vuelve a crear). La salida de la consola
debera verse algo as:
--------------------------------------------------------------Cake Schema Shell
--------------------------------------------------------------The following tables will be dropped.
acos
aros
aros_acos
Are you sure you want to drop the tables? (y/n)
[n] > y
Dropping tables.
acos updated.
aros updated.
aros_acos updated.
The following tables will be created.
acos
aros
aros_acos

Are you sure you want to create the tables? (y/n)


[y] > y
Creating tables.
acos updated.
aros updated.
aros_acos updated.
End create.

sto reemplaza al viejo comando "initdb", el cul ya es obsoleto.


Tambin

puedes

utilizar

el

archivo

SQL

que

se

encuentra

en

app/config/sql/db_acl.sql, pero est lejos de ser tan divertido.


Cuando finalices, deberas tener tres nuevas tablas en tu sistema: acos, aros, and aros_acos (la
tabla de la relacin n a n donde se definen los permisos entre los dos rboles).
Si eres curioso en saber cmo Cake almacena la informacin de los rboles en esas tablas, debes
leer acerca del recorrido de rboles en bases de datos (en ingls modified database tree traversal). El
componente ACL utiliza el Comportamiento de rbol para gestionar la herencia dentro del rbol. Las
clases pertenecientes a los modelos de ACL estn contenidas en un nico archivo db_acl.php.
Ahora que ya hemos configurado todo, creemos algunos rboles de AROs y ACOs
5.1.3.2 Creando Access Request Objects (AROs) y Access Control Objects (ACOs)

Al crear nuevos objetos ACL (ACOs y AROs), hay dos formas de nombrar y acceder a los
nodos. El primer mtodo consiste en realizar un enlace entre el objeto ACL directamente con el registro
de la base de datos, especificando el nombre del modelo y el valor de la clave externa. El segundo
mtodo puede usarse cuando un objeto no tiene relacin con un registro en la base de datos; puedes
proveer un alias para este tipo de objetos.
En general, cuando ests creando un grupo o un nivel ms alto de objetos, deber usar un alias.
Si ests gestionando el acceso a un registro especfico de la base de datos, debes usar el mtodo de
modelo/clave externa.
Para crear nuevos objetos ACL debes utilizar los modelos de ACL provistos por CakePHP, en
los cuales existen algunos campos que necesitas conocer para almacenar la informacin: model,
foreign_key, alias, y parent_id.
Los campos model y foreign_key de un objeto ACL te permiten enlazar directamente el
objeto con el correspondiente registro de la base de datos (si existe alguno). Por ejemplo, muchos

AROs tendrn su correspondencia con registros de Usuarios en la base de datos. Estableciendo el


campo foreign_key del ARO con el ID del Usuario te permitir enlazar la informacin del ARO y
del Usuario con una simple llamada find() del modelo del Usuario si las relaciones fueron configuradas
correctamente. En cambio, si lo que quieres es gestionar las operaciones de editar en un post especfico
en un blog o un listado de recetas, podras elegir enlazar un ACO a ese registro en particular.
El campo alias de un objeto ACL es slo una etiqueta que puede ser fcilmente interpretada
por un ser humano, y se utiliza para identificar un objeto ACL que no tiene una correlacin directa con
algn registro de un modelo. Los alias son muy tiles para nombrar grupos de usuarios en colecciones
de ACOs.
El campo parent_id de un objeto ACL te permite completar la estructura del rbol. Debes
proveer el ID del nodo padre en el rbol para crear un nuevo hijo.
Antes de crear nuevos objetos ACL, necesitamos cargar las respectivas clases. La forma ms
fcil de hacer esto es incluir el componente ACL en el array $components de tu controlador:
var $components = array('Acl');

Una vez que haz hecho esto, veamos ejemplos de cmo sera la creacin de algunos objetos. El
cdigo siguiente puede ser colocado en la accin de algn controlador:
Mientras los ejemplos se enfocan en la creacin de AROs, las mismas tcnicas pueden ser
usadas para crear el rbol de ACOs.
Siguiendo con la configuracin de la Comunidad, creemos primero nuestro grupo de ACOs.
Debido a que nuestros grupos no tendrn registros especficos asociados a ellos, usaremos alias en la
creacin de los objetos ACL. Lo que estamos haciendo aqu es desde la perspectiva de la accin de un
controlador, pero puede realizarse en otro lugar. Lo que vamos a usar es una aproximacin algo
artificial, pero deberas sentirte cmodo usando estas tcnicas para crear AROs y ACOs al vuelo.
Esto no debera ser algo drsticamente nuevo, slo estamos utilizando los modelos para guardar los
datos como siempre hacemos:

function algunaAccion()
{
$aro = new Aro();
//Aqu tenemos la informacin de nuestros grupos en un array sobre el cual
iteraremos luego
$groups = array(
0 => array(
'alias' => 'guerreros'
),
1 => array(
'alias' => 'magos'
),
2 => array(
'alias' => 'hobbits'
),
3 => array(
'alias' => 'visitantes'
),
);
//Iterar para crear los ARO de los grupos
foreach($groups as $data)
{
//Recuerda llamar a create() cuando ests guardando informacin
dentro de bucles...
$aro->create();

//Guardar datos
$aro->save($data);

//Aqu va otra lgica de la accin...


}

Una vez creados, podemos utilizar la aplicacin de consola de ACL para verificar la estructura
de los rboles.
$ cake acl view aro
Aro tree:
--------------------------------------------------------------[1]guerreros
[2]magos
[3]hobbits
[4]visitantes
---------------------------------------------------------------

Supongo que no se parece mucho a un rbol en este punto, pero al menos pudimos verificar que
tenemos los cuatro nodos de primer nivel. Agreguemos algunos hijos a esos nodos agregando nuestros
AROs especficos de cada usuario dentro de esos grupos. Todo buen ciudadano de la Tierra Media tiene

una cuenta en nuestro nuevo sistema, entonces nosotros referiremos esos AROs a los registros dentro
del modelo especfico en la base de datos.
Cuando agregue hijos al rbol, asegrese de utilizar el ID del nodo ACL y no un valor de foreign_key.
function algunaAccion()
{
$aro = new Aro();
//Aqu tenemos nuestros registros de usuario, listos para ser relacionados
con nuevos registros ARO
//Estos datos pueden venir de un modelo, pero en este caso estamos usando
arrays estticos
//con propsitos de demostracin.
$users = array(
0 => array(
'alias' => 'Aragorn',
'parent_id' => 1,
'model' => 'User',
'foreign_key' => 2356,
),
1 => array(
'alias' => 'Legolas',
'parent_id' => 1,
'model' => 'User',
'foreign_key' => 6342,
),
2 => array(
'alias' => 'Gimli',
'parent_id' => 1,
'model' => 'User',
'foreign_key' => 1564,
),
3 => array(
'alias' => 'Gandalf',
'parent_id' => 2,
'model' => 'User',
'foreign_key' => 7419,

),
4 => array(
'alias' => 'Frodo',
'parent_id' => 3,
'model' => 'User',
'foreign_key' => 7451,
),
5 => array(
'alias' => 'Bilbo',
'parent_id' => 3,
'model' => 'User',
'foreign_key' => 5126,
),
6 => array(
'alias' => 'Merry',
'parent_id' => 3,
'model' => 'User',
'foreign_key' => 5144,
),
7 => array(
'alias' => 'Pippin',
'parent_id' => 3,
'model' => 'User',
'foreign_key' => 1211,
),
8 => array(
'alias' => 'Gollum',
'parent_id' => 4,
'model' => 'User',
'foreign_key' => 1337,
),
);
//Iterar y crear los AROs (como hijos)
foreach($users as $data)
{
///Recuerda llamar a create() cuando ests guardando informacin
dentro de bucles...
$aro->create();

//Guardar datos
$aro->save($data);
}
//Aqu va otra lgica de la accin...
}

Tpicamente no usars el alias y los campos model/foreing_key al mismo tiempo, pero aqu
estamos utilizando los dos para que la estructura sea ms fcil de leer y para propsitos de
demostracin.
La salida de la aplicacin de consola ahora debera ser un poco ms interesante. Veamos:
$ cake acl view aro
Aro tree:
--------------------------------------------------------------[1]guerreros
[5]Aragorn
[6]Legolas
[7]Gimli
[2]magos
[8]Gandalf
[3]hobbits
[9]Frodo
[10]Bilbo
[11]Merry
[12]Pippin
[4]visitantes
[13]Gollum
---------------------------------------------------------------

Ahora que ya tenemos nuestro rbol de AROs configurado apropiadamente, discutamos una
posible aproximacin para la estructura del rbol de ACOs. Mientras que podemos estructurar ms de
una representacin abstracta de nuestros ACOs, a menudo es ms prctico modelar un rbol de ACOs

despus de configurar los controladores y acciones. Tenemos cindo objetos principales que queremos
manejar en este escenario, y la configuracin natural para una aplicacin Cake es un grupo de modelos
y en segundo lugar, los controladores que los manipulan. Es en stos controladores donde queremos
controlar el acceso a algunas acciones especficas.
Basndonos en esa idea, vamos a crear un rbol de ACOs que imite una aplicacin Cake. Como
tenenos cinco ACOs, vamos a crear un rbol de ACOs que se ver algo as:
Armas
Anillo
Jamn
EsfuerzosDiplomticos
Cervezas
Una buena caracterstica de la implementacin de ACL en Cake, es que cada ACO
automticamente contiene cuatro propiedades relacionadas con las acciones CRUD (en ingls create,
read, update, and delete). Puedes crear nodos dentro de cada uno de esos ACOs principales, pero
usando la gestin de acciones que provee Cake abarcars las operaciones bsicas de CRUD sobre un
objeto dado. Teniendo esto en mente har que tu rbol de ACOs sea ms pequeo y fcil de mantener.
Veremos cmo usadas esas propiedades cuando hablemos acerca de cmo asignar permisos.
Como ya eres un profesional creando AROs, usa las mismas tcnicas para crear este rbol de
ACOs. Crea esos grupos de nivel superior usando el modelo bsico de Aco
5.1.3.3 Asignando Permisos

Despus de crear los ACOs y los AROs, finalmente podremos asignar los permisos entre los dos
grupos. Esto se realiza utilizando el componente ACL de Cake. Sigamos con nuestro ejemplo
En este ejemplo trabajaremos en el contexto de una accin de un controlador. Tenemos que
hacer esto debido a que los permisos son manejados por el componente ACL
class AlgunController extends AppController
{
// Podras colocar esta declaracin en AppController
// para que sea heredada por todos los controladores
var $components = array('Acl');
}

Asignemos algunos permisos bsicos utilizando el componente ACL in la accin dentro de este
controlador
function index()
{
//Permitirle a los guerreros acceso total a las armas
//Ambos ejemplos usan la sintaxis de alias vista anteriormente
$this->Acl->allow('guerreros', 'Armas');
//Aunque el Rey puede no querer que todo el mundo tenga
//acceso irrestricto
$this->Acl->deny('guerreros/Legolas', 'Armas', 'delete');
$this->Acl->deny('guerreros/Gimli',

'Armas', 'delete');

die(print_r('hecho', 1));
}

En la primer llamada que hicimos al componente ACL permitimos que cualquier usuario dentro
del grupo ARO denominado "guerreros" tenga acceso irrestricto a cualquier arma dentro del grupo
ACO denominado "Armas". Esto lo realizamos referenciando a ambos grupos por sus alias.
Has notado el uso del tercer parmetro? Ah es donde utilizamos esas acciones pre-contruidos
para todos los ACOs dentro de Cake. La opcin por defecto para ese parmetro son create, read,
update, y delete, pero puedes agregar una columna en la tabla aros_acos (comenzando con el
prefijo "_", por ejemplo _admin) y utilizarla junto con las otras acciones.
La segunda llamada es un intento de realizar una asignacin de permisos mucho ms granular.
Nosotros queremos que Aragorn tenga acceso irrestricto, pero no queremos que los otros guerreros
pertenecientes al grupo tengan la habilidad de borrar registros de Armas. En el ejemplo utilizamos la
sintaxis de alias, pero se puede usar tambin de la forma model/foreign_key. El ejemplo anterior es
equivalente a este:
// 6342 = Legolas
// 1564 = Gimli
$this->Acl->deny(array('model'

=>

'User',

'foreign_key'

=>

6342),

'Armas',

=>

'User',

'foreign_key'

=>

1564),

'Armas',

'delete');
$this->Acl->deny(array('model'
'delete');

Para acceder a un nodo utilizando la sintaxis de alias, debemos usar una cadena de caracteres
delimitada por barras ('/usuarios/empleados/desarrolladores'). Para acceder a un nodo utilizando la
sintaxis model/foreign_key debes utilizar un arreglo con dos parmetros: array('model' =>
'Usuario', 'foreign_key' => 8282).
La prxima seccin nos ayudar a validar nuestra configuracin utilizando el componente ACL
para verificar los permisos que acabamos de asignar.
5.1.3.4 Verificando Permisos: El Componente ACL

Vamos a utilizar el componente ACL para asegurarnos que ni los enanos ni los elfos pueden
quitas armas de la armera. En este punto, deberamos ser capaces de utilizar AclComponent para
verificar los permisos entre los ACOs y AROs que hemos creado. La sintaxis bsica para realizar una
verificacin de permisos es:
$this->Acl->check( $aro, $aco, $action = '*');

Vamos a intentarlo dentro de una accin en un controlador:


function index()
{
//Todos estos devuelven true
$this->Acl->check('guerreros/Aragorn',
$this->Acl->check('guerreros/Aragorn',
$this->Acl->check('guerreros/Aragorn',
$this->Acl->check('guerreros/Aragorn',
$this->Acl->check('guerreros/Aragorn',

'Armas');
'Armas', 'create');
'Armas', 'read');
'Armas', 'update');
'Armas', 'delete');

//Recuerda que tambin podemos utilizar la sintaxis model/foreign_key


//para los AROs de nuestro usuario
$this->Acl->check(array('model' => 'User', 'foreign_key' => 2356),
'Armas');
//Estos tambin deben devolver true:
$result = $this->Acl->check('guerreros/Legolas', 'Armas', 'create');
$result = $this->Acl->check('guerreros/Gimli', 'Armas', 'read');

//Pero estos devuelven false:


$result = $this->Acl->check('guerreros/Legolas', 'Armas','delete');
$result = $this->Acl->check('guerreros/Gimli', 'Armas', 'delete');

El uso que le dimos aqu es solamente con propsitos de demostracin, pero esperamos que puedas ver
cmo la verificacin de permisos de esta forma puede ser utilizada para decidir cundo permitir o no
determinada accin, mostrar un mensaje de error o redirigir al usuario a la pantalla de autenticacin.

5.2 Autenticacin
Un sistema de autenticacin de usuarios es una parte comn de muchas aplicaciones web. En
CakePHP hay muchas formas para autenticar usuarios, cada una de estas provee diferentes opciones.
La esencia de componente de autenticacin es comprobar si el usuario tiene una cuenta con el sitio. De
ser as, el componente da al usuario acceso completo a sitio.
Este componente se puede combinar con el componente ACL (access control lists) para crear
niveles ms complejos de acceso al sitio. El componente ACL, por ejemplo, podra permitir acceso a un
usuario a reas publicas del sitio, mientras que concede a otro usuario acceso a porciones
administrativas protegidas del sitio.
El AuthComponent de CakePHP se puede usar para crear un sistema fcil y rpidamente.
Veamos como construir un sistema de autenticacin simple.
Al igual que todos los componentes, se utiliza mediante la incorporacin de 'Auth' a la lista de
componentes en el controlador:
class FooController extends AppController {
var $components = array('Auth');

O aadelo al AppController si todos tus controladores lo van a usar:


class AppController extends Controller {
var $components = array('Auth');

Ahora, hay unas pocas convenciones en las que pensar cuando se usa el AuthComponent. Por
defecto, el AuthComponent espera que se tenga una tabla llamada 'users' con campos llamados
'username' y 'password'. En algunos casos, las bases de datos no permiten usar 'password' como
nombre de columna, mas tarde, veremos como cambiar el nombre por defecto de los campos para
trabajar con nuestro propio entorno.
Vamos a crear nuestra tabla 'users' usando el siguiente SQL:
CREATE TABLE users (
id integer auto_increment,
username char(50),
password char(50),
PRIMARY KEY (id)
);

Algo a tener en cuenta a la hora de crear una tabla para almacenar todos los datos de
autenticacin del usuario es que el AuthComponent espera el valor del password almacenado est
encriptado en vez de estar almacenado en texto plano. Asegrese de que el campo que utilizar para
almacenar la contrasea sea suficientemente largo para almacenar el hash (40 caracteres para SHA1,
por ejemplo).
Para la configuracin ms bsica usted solo tiene que crear dos acciones en el controlador:
class UsersController extends AppController {
var $name = 'Users';
var $components = array('Auth'); //No es necesario si se declaro en el app
controller
/**
*

El AuthComponent proporciona la funcionalidad necesaria

para el acceso (login), por lo que se puede dejar esta funcin en blanco.

*/
function login() {
}
function logout() {
$this->redirect($this->Auth->logout());
}
}

Si bien usted puede dejar la funcin login() en blanco, necesitara crear la vista para la accin
login (guardela en app/views/users/login.ctp). Esta es la nica vista del UsersController que es
necesario crear, sin embargo. El siguiente ejemplo asume que ya est familiarizado con el uso del Form
helper:
<?php
echo $session->flash('auth');
echo $form->create('User', array('action' => 'login'));
echo $form->input('username');
echo $form->input('password');
echo $form->end('Login');
?>

Esta vista crea un simple formulario de login en el cual introducir el nombre de usuario y la
clave. Una vez enviado este formulario, el AuthComponent se encargar del resto por usted. El session
flash message mostrara cualquier informacin generada por el AuthComponent.
Lo creas o no, ya est! Esta es la manera de implementar una increiblemente simple, base de
datos de autenticacin usando el componente Auth. Sin embargo, hay mucho ms que podemos hacer.
Echemos un vistazo a algunos usos ms avanzados del componente.
5.2.1 Configurando las variables del componente Auth
Para cambiar las opciones predeterminadas de AuthComponent tienes que crear el mtodo
beforeFilter() en el controlador, llamar a varios mtodos predefinidos, y configurar algunas variables
del componente.
Para cambiar el nombre del campo que se utiliza para guardar las contraseas, 'password', a
'secretword', por ejemplo, haramos lo siguiente:
class UsersController extends AppController {
var $components = array('Auth');
function beforeFilter() {
$this->Auth->fields = array(
'username' => 'username',
'password' => 'secretword'
);
}
}

En este caso, no olvidemos que tambin hay que cambiar en la vista el nombre del campo!
Las variables del componente Auth tambin se utilizan para que los usuarios que no han entrado en el
sistema puedan acceder a determinados mtodos.
Por ejemplo, si queremos que todos los usuarios puedan acceder solamente a los mtodos index y view,
hacemos lo siguiente:
function beforeFilter() {
$this->Auth->allow('index','view');
}

5.2.2 Mostrando Mensajes de Error en la Autenticacin


Con el objetivo de desplegar los mensajes de error que la autentificacin muestra, necesitas
aadir el siguiente cdigo en tu vista. En este caso, el mensaje aparecer debajo de los mensajes flash
regulares:
<?php
if ($session->check('Message.flash')) {
$session->flash();
}
if ($session->check('Message.auth')) {
$session->flash('auth');
}
?>

5.2.3 Problemas comunes con Auth


A veces puede ser difcil diagnosticar problemas cuando encuentras comportamientos
inesperados. Recordar estos puntos te puede ayudar.
Password hashing
Al enviar informacin a travs de un formulario, el componente Auth encripta automticamente el
contenido del campo contrasea, si tambin hay datos en el campo nombre de usuario. As que si ests
intentando crear algn tipo de pgina de registro de nuevo usuario, asegrate de que el usuario rellene
un campo "confirmar contrasea" que puedas comparar. Aqu va un cdigo de ejemplo:
<?php
function register() {
if ($this->data) {
if

($this->data['User']['password']

>data['User']['password_confirm'])) {
$this->User->create();
$this->User->save($this->data);
}
}
}
?>

==

$this->Auth->password($this-

5.2.4 Cambiar la Funcin Hash


AuthComponent usa la clase Security para encriptar una contrasea. La clase Security usa el
esquema SHA1 por defecto. Para cambiar a otra funcin hash usada por el componente Auth, usa el
mtodo setHash pasndole md5, sha1 o sha256 como primer y nico parmetro.
Security::setHash('md5'); // o sha1 o sha256.

La clase Security usa el valor de inicializacin (salt value, que se encuentras en


/app/config/core.php) para el hashing de la contrasea.
Si quieres usar una lgica diferente para el hashing de la contrasea ms all de md5/sha1 con
el valor salt de la aplicacion, necesitar reescribir el mecanismo estandar hashPassword - podras
necesitar hacer esto si, por ejemplo, tuvieses una base de datos existente que anteriormente usaba un
esquema de hashing sin un valor de salt. Para hacer esto, crea el metodo hashPasswords en la clase
que quieras que se haga a cargo del hashing de las contraseas (normalmente el modelo User ) y
establece el atributo authenticate de Auth al objeto contra el que se est autenticando
(normalmente es User) de este modo:
function beforeFilter() {
$this->Auth->authenticate = ClassRegistry::init('User');
...
parent::beforeFilter();
}

Con el cdigo anterior, el mtodo hashPasswords() del modelo User ser llamado cada vez
que Cake llame a AuthComponent::hashPasswords(). Aqu est un ejemplo del mtodo
hashPasswords, apropiado si ya tienes una tabla de usuarios repleta de contraseas de hash 'plain
md5':
class User extends AppModel {
function hasPasswords($data) {
if (isset($data['User']['password'])) {
$data['User']['password'] = md5($data['User']['password']);
return $data;
}
return $data;
}
}

5.2.5 Mtodos de AuthComponent


5.2.5.1 action

action (string $action = ':controller/:action')


Si estas usando ACOs como parte de tu estructura ACL, puedes obtener la ruta al nodo del ACO
que est enlazado a un par controlador/accin particular.
$acoNode = $this->Auth->action('users/delete');

Si no le pasas valores, utilizar el par controlador/accin actual (el que se est ejecutando).
5.2.5.2 allow

Si tienes acciones en tu controlador que no necesitas que se autentiquen contra ellas (como una
accin de registro de usuarios), puedes agregar mtodos que debe ignorar AuthComponent. El siguiente
ejemplo muestra como permitir una accin llamada 'register'.
function beforeFilter() {
...
$this->Auth->allow('register');
}

Si deseas permitir que mltiples acciones no usen autenticacin, las pasas como parmetros al
mtodo allow():
function beforeFilter() {
...
$this->Auth->allow('foo', 'bar', 'baz');
}

Atajo: tambin puedes permitir todas las acciones en un controlador usando '*'.
function beforeFilter() {
...
$this->Auth->allow('*');
}

Si ests usando requestAction en tu layout o en tus elementos, deberas permitir esas acciones
para poder abrir la pgina de login correctamente.
El componente auth supone que tus nombres de acciones siguen las convenciones y usan guiones bajos.

5.2.5.3 deny

Habr algunas veces que quieras eliminar acciones de la lista de acciones permitidas (aadidas
usando $this->Auth->allow()). He aqu un ejemplo:
function beforeFilter() {
$this->Auth->authorize = 'controller';
$this->Auth->allow('delete');
}
function isAuthorized() {
if ($this->Auth->user('role') != 'admin') {
$this->Auth->deny('delete');
}
...
}

5.2.5.4 hashPasswords

hashPasswords ($data)
Este mtodo verifica si $data contiene los campos nombre de usuario(username) y
contrasea(password), tal y como est especificado en la variable $fields indexados por el nombre
del modelo especificado en $userModel. Si el array $data contiene el nombre de usuario y la
contrasea, realiza el hash del campo contrasea en el array y devuelve el array $data con el mismo
formato. Esta funcin debe ser usada antes de realizar llamadas de insercin o actualizacin de los
datos del usuario cuando afecta al campo contrasea.
$data['User']['username'] = 'me@me.com';
$data['User']['password'] = 'changeme';
$hashedPasswords = $this->Auth->hashPasswords($data);
pr($hashedPasswords);
/* devuelve:
Array
(
[User] => Array
(
[username] => me@me.com
[password] => 8ed3b7e8ced419a679a7df93eff22fae
)
)
*/

En el campo $hashedPasswords['User']['password'] ahora debera ser realizado el 'hash'


usando el mtodo password del componente.
Si tu controlador usa el compoente Auth y los datos recibidos por POST contienen los campos
explicados arriba, automticamente realizar el hash al campo contrasea usando esta funcin.
5.2.5.5 mapActions

Si ests utilizando Acl en modo CRUD, tal vez desees asignar ciertas acciones no
predeterminadas a cada parte de CRUD.
$this->Auth->mapActions(
array(
'create' => array('ciertaAccion'),
'read' => array('ciertaAccion', 'ciertaAccion2'),
'update' => array('ciertaAccion'),
'delete' => array('ciertaAccion')
)
);

5.2.5.6 login

login($data = null)
Si ests haciendo algn tipo de login basada en Ajax, puedes usar este mtodo para identificar
manualmente a alguien en el sistema. Si no pasas ningn valor para $data, automticamente usar los
datos enviados mediante POST al controlador.
Por ejemplo, en una aplicacin tal vez desees asignar a un usuario una contrasea y
autoidentificarlo en el sistema tras el registro. En un ejemplo muy simplificado:
Vista:
echo $form->create('User',array('action'=>'registrar'));
echo $form->input('username');
echo $form->end('Regstrame');

Controlador:
function registrar() {
if(!empty($this->data)) {
$this->User->create();

$contrasena_asignada = "ConTr4senna";
$this->data['User']['password'] = $contrasena_asignada;
if($this->User->save($this->data)) {
// enviar el email de registro conteniendo la contrasea al nuevo usuario
$this->Auth->login($this->data);
$this->redirect("inicio");
}
}

Una cosa a remarcar es que has de redirigir manualmente al usuario tras el login ya que no se
invoca loginRedirect().
$this->Auth->login($data) devuelve 1 tras un login exitoso, 0 en caso de fallo.
5.2.5.7 logout

Provee de una manera rpida de 'deautenticar' a alguien y redirigirlo a donde necesite ir. Este
mtodo tambin es til si deseas proporcionar un enlace 'Cerrar sesin' dentro de una seccin para
usuarios registrados de tu aplicacin.
Ejemplo:
$this->redirect($this->Auth->logout());

5.2.5.8 password

password (string $password)


Psale una cadena de texto, y obtendrs la contrasea 'hasheada'. Esta es una funcionalidad
esencial si ests creando una pantala de registro de usuario donde los usuarios han de insertar sus
contraseas una segunda vez para confirmarlas.
if ($this->data['User']['password'] ==
$this->Auth->password($this->data['User']['password2'])) {
// Las contraseas concuerdan, continuar procesando
...
} else {
$this->flash('Las contraseas introducidas no concuerdan', 'users/registrar');
}

El componente Auth automticamente aplicar el hash al campo contrasea (password) si


tambin est presente el campo nombre de usuario (username) en los datos recibidos en la peticin.
Cake aade tu cadena contrasea a un valor salt y despus realiza el hash. La funcin de hash
utilizada depende de la seleccionada por la clase utilidad del ncleo Security (sha1 por defecto).
Puedes utilizar la funcin Security::setHash para cambiar el mtodo para calcular el hash. El
valor salt es el indicado en la configuracin de tu aplicacin definido en tu core.php.
5.2.5.9 user

user(string $key = null)


Este mtodo proporciona informacin sobre el usuario actualmente identificado. La informacin
es tomada de la sesin. Por ejemplo:
if ($this->Auth->user('rol') == 'admin') {
$this->flash('Tienes acceso de administrador');
}

Tambin puede ser usado para obtener todos los datos de sesin del usuario as:
$data['User'] = $this->Auth->user();

Si este mtodo devuelve null es que el usuario no se ha identificado (logged in).


En la vista puedes utilizar el helper Session para obtener la informacin del usuario actualmente
autenticado:
$session->read('Auth.User'); // devuelve el registro completo del usuario
$session->read('Auth.User.nombre') //devuelve el valor particular de un campo

La clave de la sesin puede ser diferente dependiendo de qu modelo se ha configurado para ser
utilizado por Auth. P.e., si usas el modelo Cuenta en vez de User, entonces la clave de sesin sera
Auth.Cuenta.

5.2.6 Atributos de AuthComponent


Ahora hay varias variables relacionadas con Auth que tambin puedes utilizar. Normalmente
aades esta configuracin en el mtodo beforeFilter() de tu controlador. Si
necesitas

aplicar

dicha

configuracin

todo

el

sitio,

deberas

aadirla a beforeFilter() de AppController.


5.2.6.1 userModel

No deseas utilizar un modelo User contra el que autenticar? No hay problema. Simplemente
cmbialo configurando este valor con el nombre del modelo que deseas usar.
<?php
$this->Auth->userModel = 'Miembro';
?>

5.2.6.2 fields

Sobreescribe los campos de usuario y contrasea por defecto usados para la autenticacin.
<?php
$this->Auth->fields = array('username' => 'email', 'password' => 'passwd');
?>

5.2.6.3 userScope

Utiliza esto para aadir requisitos adicionales para que la autenticacin sea exitosa.
<?php
$this->Auth->userScope = array('User.activo' => true);
?>

5.2.6.4 loginAction

Puedes cambiar el login por defecto de /users/login para que sea cualquier accin a tu eleccin.
<?php
$this->Auth->loginAction = array('admin' => false, 'controller' => 'miembros',
'action' => 'inicio_sesion');
?>

5.2.6.5 loginRedirect

El componente AuthComponent recuerda qu par controlador/accin estabas tratando de


ejecutar antes de que pedirte que te autenticaras, almacenando el valor en Session bajo la clave
Auth.redirect. Sin embargo, si este valor de la sesin no est definido (si vienes de la pgina de
login de un enlace externo, por ejemplo), entonces el usuario ser redirigido a la URL indicada en
loginRedirect.
Ejemplo:
<?php
$this->Auth->loginRedirect = array('controller' => 'miembros', 'action' =>
'inicio');
?>

5.2.6.6 logoutRedirect

You can also specify where you want the user to go after they are logged out, with the default
being the login action.
<?php
$this->Auth->logoutRedirect = array(Configure::read('Routing.admin') => false,
'controller' => 'members', 'action' => 'logout');
?>

5.2.6.7 loginError

Cambia el mensaje de error por defecto que se mostrar, cuando el login no sea exitoso.
<?php
$this->Auth->loginError = "No, you fool!

That's not the right password!";

?>

5.2.6.8 authError

Cambia el mensaje de error por defecto que ser mostrado, cuando intenten acceder a un objeto
o a una accin a la que no autorizada.
<?php
$this->Auth->authError = "Sorry, you are lacking access.";
?>

5.2.6.9 autoRedirect

Normally, the AuthComponent will automatically redirect you as soon as it authenticates.


Sometimes you want to do some more checking before you redirect users:
<?php
function beforeFilter() {
...
$this->Auth->autoRedirect = false;
}
...
function login() {
//-- code inside this function will execute only when autoRedirect was set
to false (i.e. in a beforeFilter).
if ($this->Auth->user()) {
if (!empty($this->data['User']['remember_me'])) {
$cookie = array();
$cookie['username'] = $this->data['User']
['username'];
$cookie['password'] = $this->data['User']
['password'];
$this->Cookie->write('Auth.User', $cookie, true,
'+2 weeks');
unset($this->data['User']['remember_me']);
}
$this->redirect($this->Auth->redirect());
}
if (empty($this->data)) {
$cookie = $this->Cookie->read('Auth.User');
if (!is_null($cookie)) {
if ($this->Auth->login($cookie)) {
// Clear auth message, just in case we
use it.
$this->Session->delete('Message.auth');
$this->redirect($this->Auth->redirect());
}
}
}
}
?>

The code in the login function will not execute unless you set $autoRedirect to false in a
beforeFilter. The code present in the login function will only execute after authentication was
attempted. This is the best place to determine whether or not a successful login occurred by the
AuthComponent (should you desire to log the last successful login timestamp, etc.).
With autoRedirect set to false, you can also inject additional code such as keeping track of the
last successful login timestamp

<?php
function login() {
if( !(empty($this->data)) && $this->Auth->user() ){
$this->User->id = $this->Auth->user('id');
$this->User->saveField('last_login', date('Y-m-d H:i:s')
);
$this->redirect($this->Auth->redirect());
}
}
?>

5.2.6.10 authorize

Normally, the AuthComponent will attempt to verify that the login credentials you've entered
are accurate by comparing them to what's been stored in your user model. However, there are times
where you might want to do some additional work in determining proper credentials. By setting this
variable to one of several different values, you can do different things. Here are some of the more
common ones you might want to use.
<?php
$this->Auth->authorize = 'controller';
?>

When authorize is set to 'controller', you'll need to add a method called isAuthorized() to your
controller. This method allows you to do some more authentication checks and then return either true or
false.
<?php
function isAuthorized() {
if ($this->action == 'delete') {
if ($this->Auth->user('role') == 'admin') {
return true;
} else {
return false;
}
}
return true;
}
?>

Remember that this method will be checked after you have already passed the basic
authentication check against the user model.
<?php
$this->Auth->authorize = array('model'=>'User');
?>

Don't want to add anything to your controller and might be using ACO's? You can get the
AuthComponent to call a method in your user model called isAuthorized() to do the same sort of thing:
<?php
class User extends AppModel {
...
function isAuthorized($user, $controller, $action) {

}
?>

switch ($action) {
case 'default':
return false;
break;
case 'delete':
if ($user['User']['role'] == 'admin') {
return true;
}
break;
}

Lastly, you can use authorize with actions such as below


<?php
$this->Auth->authorize = 'actions';
?>

By using actions, Auth will make use of ACL and check with AclComponent::check(). An
isAuthorized function is not needed.
<?php
$this->Auth->authorize = 'crud';
?>

By using crud, Auth will make use of ACL and check with AclComponent::check(). Actions
should be mapped to CRUD (see mapActions).

5.2.6.11 sessionKey

Name of the session array key where the record of the current authed user is stored.
Defaults to "Auth", so if unspecified, the record is stored in "Auth.{$userModel name}".
<?php
$this->Auth->sessionKey = 'Authorized';
?>

5.2.6.12 ajaxLogin

Si ests haciendo solicitudes basadas en Ajax o Javascript que requieren sesiones autenticadas,
establece en esta variable el nombre del elemento vista que deseas mostrar y retornar cuando la sesin
es invlida o ha expirado.
Como con cualquier parte de CakePHP, asegrate de revisar la clase AuthComponent para
mayores detalles.
5.2.6.13 authenticate

This variable holds a reference to the object responsible for hashing passwords if it is necessary
to change/override the default password hashing mechanism. See Changing the Encryption Type for
more info.
5.2.6.14 actionPath

If using action-based access control, this defines how the paths to action ACO nodes is
computed. If, for example, all controller nodes are nested under an ACO node named 'Controllers',
$actionPath should be set to 'Controllers/'.
5.2.6.15 flashElement

In case that you want to have another layout for your Authentication error message you can
define with the flashElement variable that another element will be used for display.
<?php
$this->Auth->flashElement
?>

= "message_error";

5.3 Cookies
El componente Cookie es una abstraccin para acceder al mtodo nativo de PHP setcookie().
Tambin incluye una serie de funcionalidades muy tiles para agilizar la escritura de cookies. Antes de
tratar de utilizar el componente Cookie, debe asegurarse que se encuentra habilitado en el arreglo
$components: si est habilitado uno de los elementos del arreglo debe ser 'Cookie'
5.3.1 Configuracin del Controlador
Hay una serie de variables que se configuran en el controlador, y te permiten modificar la forma
en que las cookies son creadas y gestionadas. Estas variables especiales generalmente se setean en el
mtodo beforeFilter() de tu controlador.
Variable
Cookie
string $name

por defecto descripcin

'CakeCookie' El nombre de la cookie.


Esta cadena es utilizada para encriptar el valor escrito en la cookie. La
string $key
null
cadena debera ser aleatoria y difcil de adivinar.
El nombre de dominio habilitado para acceder a la cookie, ej. Use
string $domain ''
'.tudominio.com' para permitir acceso desde todos los subdominios.
El tiempo en que expirar la cookie. Los enteros son interpretados
int

string

$time

como segundos, y un valor 0 es equivalente a 'cookie de sesin', es


'5 Days'

decir, la cookie expira cuando se cierra el navegador. Si el valor es una


cadena, ser interpretada con la funcin de PHP strtotime(). Puedes
configurar esto directamente dentro del mtodo de escritura write().
La ruta del servidor donde la cookie ser aplicada. Si $cookiePath est
seteada a '/foo/', la cookie estar disponible slo dentro del directorio

string $path

'/'

/foo/ y todos los subdirectorios (como por ejemplo /foo/bar/) de tu


dominio. La opcin por defecto es en todo el dominio. Puedes
configurar esto directamente dentro del mtodo de escritura write().
Indica que la cookie deber ser transmitida nicamente por una

boolean $secure false

conexin segura HTTPS. Cuando este valor sea true, la cookie ser
creada slo si existe una conexin segura. Puedes configurar esto

directamente dentro del mtodo de escritura write()


El siguiente recorte del cdigo de un controlador muestra cmo incluir el componente Cookie y
cmo configurar las variables necesarias para enviar una cookie llamada 'baker_id' para el dominio

'example.com' que a su vez necesita una conexin segura, debe estar disponible para la ruta
/bakers/preferencias/, y expira en una hora.
var $components

= array('Cookie');

function beforeFilter() {
$this->Cookie->name = 'baker_id';
$this->Cookie->time =

3600;

// o '1 hour'

$this->Cookie->path = '/bakers/preferencias/';
$this->Cookie->domain = 'example.com';
$this->Cookie->secure = true;

//enviar slo por una conexin segura HTTPS

$this->Cookie->key = 'qSI232qs*&sXOw!';
}

A continuacin, veremos cmo utilizar los diferentes mtodos del componente Cookie.
5.3.2 Utilizando el Componente
Esta seccin resume los mtodos del componente Cookie.
write(mixed $key, mixed $value, boolean $encrypt, mixed $expires)
El mtodo write() es el corazn del componente, $key es la variable que se quiere guardar en la
cookie y $value es el dato para almacenar.
$this->Cookie->write('nombre','Pepito');

Tambin puedes agrupar variables utilizando la notacin de 'punto' en el parmetro $key.


$this->Cookie->write('Usuario.nombre', 'Pepito');
$this->Cookie->write('Usuario.rol','Lider');

Si deseas escribir ms de un valor a la vez en la cookie, puedes pasar un arreglo:


$this->Cookie->write(
array('nombre'=>'Pepito','rol'=>'Lider')
);

Todos los valores de las cookis son encriptados por defecto. Si desea almacenar valores en texto
puro, cambie el tecer parmetro del mtodo write() a false.
$this->Cookie->write('nombre','Pepito',false);

El ltimo parmetro del mtodo es $expires: el nmero de segundos antes de que la cookie
expire. Por convenienia, este parmetro puede ser pasado como una cadena que entienda la funcin
strtotime() de PHP:
//Ambas cookies expiran en una hora.
$this->Cookie->write('nombre','Pepito',false, 3600);
$this->Cookie->write('Apellido','Gonzales',false, '1 hour');

read(mixed $key)
Este mtodo es utilizado para leer el valor de una variable almaenada en una cookie. La variable
a leer debe ser especificada en el parmetro $key.
//Muestra Pepito
echo $this->Cookie->read('name');
//Tambin se puede utilizar la notacin de 'punto' para leer
echo $this->Cookie->read('Usuario.nombre');
//Para obtener las variables que has agrupado utilizando
//la notacin de 'punto' como un arreglo debes usar
$this->Cookie->read('Usuario');
//esto devuelve un arreglo similar a array('nombre' => 'Pepito', 'rol'=>'Lider')

del(mixed $key)
Borra el contenido de la variable $key almacenada en una cookie. Tambin funciona con la
notacin de 'punto'.
//Borrar una variable
$this->Cookie->del('bar')
//Borrar la variable bar, pero no todas las contenidas en foo
$this->Cookie->del('foo.bar')

destroy()
Destruye la cookie actual.

5.4 Email
El componente Email es una manera simple de agregarle a tu aplicacin CakePHP la
funcionalidad de envo de mails, usando los mismos conceptos de layouts, vistas, archivos .ctp, etc,
formateados como texto, html, o ambos. Puede enviar mails por medio de las funciones propias de
PHP, va servidor SMTP o en modo DEBUG en el que escribe el mensaje en un mensaje flash de
sesin. Tambin soporta archivos adjuntados y inclusin/filtrado simple de encabezados. Hay un
montn de cosas que no hace por t, pero te pondr en movimiento.
5.4.1 Atributos y Variables de la clase
Estos

son

los

valores

que

puedes

configurar

antes

de

hacer

la

llamada

EmailComponent::send()
to
cc
bcc
replyTo
from
subject
template

direccin a la que se dirige el mensaje (string)


arreglo de direcciones a enviar copias del mensaje (CC)
arreglo de direcciones a enviar las copias ocultas del mensaje (CCO)
direccin de respuesta(string)
direccin remitente (string)
asunto del mensaje (string)
Elemento
email
a
usar
para
el
mensaje(ubicado

en

app/views/elements/email/html/

en

app/views/elements/email/text/)
Layout usado por el mail (ubicado en app/views/layouts/email/html/ y en

layout

app/views/layouts/email/text/)
lineLength Longitud (en caracteres) en la que corta las lneas largas. Por defecto es 70. (integer)
Como quieres mandar el mensaje: text(texto), html(cdigo HTML) o both(ambos).
sendAs
attachments Arreglo de archivos a enviar (rutas absolutas y relativas)
Como enviar el mensaje (mail, smtp [requerir el campo smtpOptions explicado
delivery
abajo] y debug)
Arreglo asociativo de opciones para el envo por SMTP. (port(puerto),
smtpOptions host(servidor), timeout(tiempo de espera), username(nombre de usuario),
password(contrasea))
Hay algunas opciones ms para configurar, para mayor informacin consulta la documentacin
de CakePHP.

5.4.1.1 Envo mltiple de emails en bucle

Si lo que quieres es enviar varios emails usando un bucle, debers resetear los campos de mails
usando el mtodo reset() del componente Email. Necesitars resetearlo antes de setear nuevamente
las propiedades del email.
$this->Email->reset()

5.4.1.2 Debugging Emails

If you do not want to actually send an email and instead want to test out the functionality, you
can use the following delivery option:
$this->Email->delivery = 'debug';

In order to view those debugging information you need to create an extra line in your view or
layout file (e.g. underneath your normal flash message in /layouts/default.ctp):
<?php echo $this->Session->flash(); ?>
<?php echo $this->Session->flash('email'); ?>

5.4.2 Envo de un mensaje simple


Para enviar un mensaje sin usar ningn template, slo pasa el cuerpo del mensaje como una
cadena (string) o un arreglo de lneas al mtodo send(). Por ejemplo:
$this->Email->from
= 'Alguien <alguien@ejemplo.com>';
$this->Email->to
= 'Alguien ms <alguien.mas@ejemplo.com>';
$this->Email->subject = 'Prueba';
$this->Email->send('Hola cuerpo de mensaje!!!');

5.4.2.1 Configurando el Layout

Para usar tanto texto como html en el email necesitars crear los archivos de layout para ellos.
Tal como lo hayas hecho para tu layout default para las vistas en un navegador, precisas establecer los
layouts default para tus emails. En la carpeta app/views/layouts/ precisas tener (como mnimo)
esta estructura
email/

html/
text/

default.ctp
default.ctp

Estos son los archivos que conservan los valores por defecto para los templates de layout para
tus mensajes. Un simple ejemplo de contenido:
email/text/default.ctp
<?php echo $content_for_layout; ?>

email/html/default.ctp
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<body>
<?php echo $content_for_layout; ?>
</body>
</html>

5.4.2.2 Configurar un elemento Email para el cuerpo del mensaje

En el directorio app/views/elements/email/ debes configurar carpetas para


text(mails modo texto) y html(mails modo HTML) a menos que quieras usar slo uno de ellos. En
cada una de estas carpetas debes crear templates para poder utilizar con el contenido que le enves a la
vista ya sea usando $this->set() o usando el parmetro $contents del mtodo send(). Algunos ejemplos
simples a continuacin, usando el template simple_message.ctp
text
Estimado <?php echo $User['first']. ' ' . $User['last'] ?>,
Gracias por su inters.

html
<p>Estimado <?php echo $User['first']. ' ' . $User['last'] ?>,<br />
&nbsp;&nbsp;&nbsp;Gracias por su inters.</p>

5.4.2.3 Controlador

En tu controlador necesitas agregar el componente a tu array $components o agregar un


array $components a tu controlador de la forma:
<?php
var $components = array('Email');
?>

En este ejemplo configuraremos un mtodo privado para manejar el envo de mensajes de email
a un usuario identificado por un $id. En nuestro controlador (usemos el controlador User en este
ejemplo):
<?php
function _sendNewUserMail($id) {
$User = $this->User->read(null,$id);
$this->Email->to = $User['User']['email'];
$this->Email->bcc = array('secreto@ejemplo.com');
$this->Email->subject = 'Bienvenido a nuestra cosa genial';
$this->Email->replyTo = 'support@ejemplo.com';
$this->Email->from = 'Cool Web App <app@ejemplo.com>';
$this->Email->template = 'simple_message'; // NOTAR QUE NO HAY '.ctp'
//Enviar como 'html', 'text' or 'both' (ambos) - (por defecto es 'text')
$this->Email->sendAs = 'both'; // queremos enviar un lindo email
//Variables de la vista
$this->set('User', $User);
//NO PASAMOS ARGUMENTOS A SEND()
$this->Email->send();
}
?>

Has enviado un mensaje, podras llamarlo desde otro mtodo de esta forma: Plain Text View

$this->_sendNewUserMail( $this->User->id );

5.4.2.4 Attachments

Here's how you can send file attachments along with your message. You set an array containing
the paths to the files to attach to the attachments property of the component.
$this->Email->attachments = array(
TMP . 'foo.doc',
'bar.doc' => TMP . 'some-temp-name'
);

The first file foo.doc will be attached with the same filename. For the second file we specify
an alias bar.doc will be be used for attaching instead of its actual filename some-temp-name
5.4.3 Enviar un mail por SMTP
Para enviar un mail usando servidor SMTP, los pasos a seguir son similares a los del mensaje
bsico. Configurar el mtodo de entrega (delivery) a smtp y asignar las opciones a las propiedades del
objeto de Email smtpOptions. Tambin puedes obtener los errores SMTP generados durante la
sesin leyendo la propiedad smtpError del componente.
/* Opciones SMTP*/
$this->Email->smtpOptions = array(
'port'=>'25',
'timeout'=>'30',
'host' => 'tu.servidor.smtp',
'username'=>'tu_nombre_usuario_smtp',
'password'=>'tu_contrasea_smtp');
/* Configurar mtodo de entrega */
$this->Email->delivery = 'smtp';
/* No le pases ningn argumento a send() */
$this->Email->send();
/* Chequeo de errores SMTP. */
$this->set('smtp-errors', $this->Email->smtpError);

Si tu servidor SMTP requiere autenticacin, asegrate de especificar los parmetros de nombre de


usuario y contrasea en smtpOptions como se ve en el ejemplo.

5.5 Request Handling


El componente Request Handler (manejador de la peticin) es usado en CakePHP para obtener
informacin adicional sobre las peticiones HTTP que son realizadas a tus aplicaciones. Puedes usarlo
para informar a tus controladores sobre Ajax, como tambin para obtener informacin adicional sobre
tipos de contenido que el cliente acepta y cambiar automticamente al layout apropiado cuando estn
activadas las extensiones de ficheros.
Por defecto, RequestHandler detectar automticamente las peticiones Ajax basadas en la
cabecera HTTP-X-Requested-With que utilizan muchas libreras javascript. Cuando se utiliza junto con
Router::parseExtensions(), RequestHandler cambiar automticamente los ficheros de
layout y vista a aquellos que coincidan con el tipo pedido. Adems, si existe un helper con el mismo
nombre que la extensin pedida, se aadir al array de helpers del controlador. Finalmente, si son
"POSTeados" datos XML a tus controladores, se parsearn en un objecto XML que se asigna a
Controller::data, y que puede entonces ser salvado como datos de modelo. Para poder hacer
uso de Request handler, debe ser includo en tu array $components.
<?php
class WidgetController extends AppController {
var $components = array('RequestHandler');
//resto del controlador
}
?>

5.5.1 Obtaining Request Information


Request Handler has several methods that provide information about the client and its request.
accepts ( $type = null)
$type can be a string, or an array, or null. If a string, accepts will return true if the client accepts
the content type. If an array is specified, accepts return true if any one of the content types is accepted
by the client. If null returns an array of the content-types that the client accepts. For example:
class PostsController extends AppController {
var $components = array('RequestHandler');
function beforeFilter () {
if ($this->RequestHandler->accepts('html')) {
// Execute code only if client accepts an HTML (text/html) response
} elseif ($this->RequestHandler->accepts('xml')) {
// Execute XML-only code
}
if ($this->RequestHandler->accepts(array('xml', 'rss', 'atom'))) {
// Executes if the client accepts any of the above: XML, RSS or Atom
}
}}

Other request 'type' detection methods include:


isAjax()
Returns true if the request contains the X-Requested-Header equal to XMLHttpRequest.
isSSL()
Returns true if the current request was made over an SSL connection.
isXml()
Returns true if the current request accepts XML as a response.
isRss()
Returns true if the current request accepts RSS as a response.
isAtom()
Returns true if the current call accepts an Atom response, false otherwise.
isMobile()
Returns true if user agent string matches a mobile web browser, or if the client accepts WAP
content. The supported Mobile User Agent strings are:
iPhone
MIDP
AvantGo
BlackBerry
J2ME
Opera Mini
DoCoMo
NetFront
Nokia
PalmOS
PalmSource
portalmmm
Plucker
ReqwirelessWeb

SonyEricsson
Symbian
UP.Browser
Windows CE
Xiino
isWap()
Returns true if the client accepts WAP content.
All of the above request detection methods can be used in a similar fashion to filter
functionality intended for specific content types. For example when responding to Ajax requests, you
often will want to disable browser caching, and change the debug level. However, you want to allow
caching for non-ajax requests. The following would accomplish that:
if ($this->RequestHandler->isAjax()) {
Configure::write('debug', 0);
$this->header('Pragma: no-cache');
$this->header('Cache-control: no-cache');
$this->header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
}
//Continue Controller action

You could also disable caching with the functionally analogous Controller::disableCache
if ($this->RequestHandler->isAjax()) {
$this->disableCache();
}
//Continue Controller action

5.5.2 Request Type Detection


RequestHandler also provides information about what type of HTTP request has been made and
allowing you to respond to each Request Type.
isPost()
Returns true if the request is a POST request.

isPut()
Returns true if the request is a PUT request.
isGet()
Returns true if the request is a GET request.
isDelete()
Returns true if the request is a DELETE request.
5.5.3 Obtaining Additional Client Information
getClientIP()
Get the remote client IP address
getReferer()
Returns the domain name from which the request originated
getAjaxVersion()
Gets Prototype version if call is Ajax, otherwise empty string. The Prototype library sets a
special "Prototype version" HTTP header.
5.5.4 Responding To Requests
In addition to request detection RequestHandler also provides easy access to altering the output
and content type mappings for your application.
setContent($name, $type = null)
$name string - The name or file extension of the Content-type ie. html, css, json, xml.
$type mixed - The mime-type(s) that the Content-type maps to.
setContent adds/sets the Content-types for the given name. Allows content-types to be mapped
to friendly aliases and or extensions. This allows RequestHandler to automatically respond to requests
of each type in its startup method. If you are using Router::parseExtension, you should use the file
extension as the name of the Content-type. Furthermore, these content types are used by prefers() and
accepts().
setContent is best used in the beforeFilter() of your controllers, as this will best leverage the

automagicness of content-type aliases.


The default mappings are:
javascript text/javascript
js text/javascript
json application/json
css text/css
html text/html, */*
text text/plain
txt text/plain
csv application/vnd.ms-excel, text/plain
form application/x-www-form-urlencoded
file multipart/form-data
xhtml application/xhtml+xml, application/xhtml, text/xhtml
xhtml-mobile application/vnd.wap.xhtml+xml
xml application/xml, text/xml
rss application/rss+xml
atom application/atom+xml
amf application/x-amf
wap text/vnd.wap.wml, text/vnd.wap.wmlscript, image/vnd.wap.wbmp
wml text/vnd.wap.wml
wmlscript text/vnd.wap.wmlscript
wbmp image/vnd.wap.wbmp
pdf application/pdf
zip application/x-zip
tar application/x-tar
prefers($type = null)
Determines which content-types the client prefers. If no parameter is given the most likely
content type is returned. If $type is an array the first type the client accepts will be returned. Preference
os determined primarily by the file extension parsed by Router if one has been provided. and secondly
by the list of content-types in HTTP_ACCEPT.

renderAs($controller, $type)
$controller - Controller Reference
$type - friendly content type name to render content for ex. xml, rss.
Change the render mode of a controller to the specified type. Will also append the appropriate
helper to the controller's helper array if available and not already in the array.
respondAs($type, $options)
$type - Friendly content type name ex. xml, rss or a full content type like application/xshockwave
$options - If $type is a friendly type name that has more than one content association, $index is
used to select the content type.
Sets the response header based on content-type map names. If DEBUG is greater than 1, the
header is not set.
responseType()
Returns the current response type Content-type header or null if one has yet to be set.
mapType($ctype)
Maps a content-type back to an alias

5.6 El Componente Security


El componente Security provee una forma fcil de aumentar la seguridad en tu aplicacin. Con
el componente Security se puede crear una intefaz para manejar autenticaciones HTTP. Se configura en
el mtodo beforeFilter() de tus controladores, y tiene distintos parmetros para ajustar. Todas esas
propiedades pueden configurarse directamente con los mtodos creados para tal fin, y que se llaman de
la misma manera.
5.6.1 Configuracin
$blackHoleCallback
Un callback del controlador que se encargar de manejar las peticiones que hayan sido enviadas
al "agujero negro".

$requirePost
Una lista de acciones del controlador que requieren una peticin POST para ejecutarse. Un
arreglo de acciones del controlador o '*' para forzar que todas las acciones requieran POST.
$requireSecure
Lista de acciones que requieren una conexin SSL para ejecutarse. Un arreglo de acciones del
controlador o '*' para forzar que todas las acciones requieran una conexin SSL.
$requireAuth
Una lista de acciones que requieren una clave de autenticacin vlida. Esta clave es configurada
por el componente Security.
$requireLogin
Una lista de acciones que requieren autenticacin HTTP (basic o diges). Tambin acepta '*'
indicando que todas las acciones del controlador requieren autenticacin HTTP.
$loginOptions
Opciones para la autenticacin HTTP. Permite definir que tipo de autenticacin utilizar, y los
callbacks del controlador para el proceso de autenticacin.
$loginUsers
Un arreglo asociativo de usuarios => passords que sonusados para autenticaciones HTTP. Si ests
utilizando autenticacion digest, los passwords deben ser encryptados con el algoritmo MD5.
$allowedControllers
Una lista de controladores desde los cuales la accin del controlador actual puede recibir
peticiones. Tambin puede utilizarse para peticiones entre controladores.
$allowedActions
Una lista de acciones desde las cuales las acciones del controlador actual pueden para recibir
peticiones. Tambin puede utilizarse para peticiones entre controladores.
$disabledFields
Campos del formulario que se necesitan deshabilitar para una peticin dada.

5.6.2 Mtodos
5.6.2.1 requirePost()

Define las acciones que requieren una peticin POST. Acepta cualquier nmero de argumentos.
Puede ser llamado sin argumentos para forzar a que todas las acciones requieran una peticin POST.
5.6.2.2 requireSecure()

Define las acciones que requieren una conexin SSL presente. Acepta cualquier cantidad de
argumentos. Puede ser llamado sin argumentos para forzar que todas las acciones requieran una
conexin SSL.
5.6.2.3 requireAuth()

Define las acciones que requieren un token vlido generado por el componente Security. Acepta
cualquier nmero de argumentos. Puede ser llamado sin argumentos para forzar que todas las acciones
requieran una autenticacin vlida.
5.6.2.4 requireLogin()

Define las acciones que requieren una autenticacin HTTP vlida. Acepta cualquier nmero de
argumentos. Puede ser llamada sin argumentos para forzar que todas las acciones requieran una
autenticacin HTTP vlida.
5.6.2.5 loginCredentials(string $type)

Trata de validar las credenciales para una peticin de autenticacin HTTP. $type es el tipo de
autenticacin que se desea verificar. Puede ser 'basic', o 'digest'. Si se deja como null o vaci, tratar de
verificar las dos. Devuelve un arreglo con el nombre de usuario y el password si tuvo xtito.
5.6.2.6 loginRequest(array $options)

Generates the text for an HTTP-Authenticate request header from an array of $options.
$options generally contains a 'type', 'realm' . Type indicate which HTTP-Authenticate method to
use. Realm defaults to the current HTTP server environment.

5.6.2.7 parseDigestAuthData(string $digest)

Parse an HTTP digest authentication request. Returns and array of digest data as an associative
array if succesful, and null on failure.
5.6.2.8 generateDigestResponseHash(array $data)

Creates a hash that to be compared with an HTTP digest-authenticated response. $data should
be an array created by SecurityComponent::parseDigestAuthData().
5.6.2.9 blackHole(object $controller, string $error)

Black-hole an invalid request with a 404 error or a custom callback. With no callback, the
request will be exited. If a controller callback is set to SecurityComponent::blackHoleCallback, it will
be called and passed any error information.
5.6.3 Uso
EL uso del componente security generalmente se hace en el mtodo beforeFilter() del
controlador. Usted especifica las restricciones de seguridad que desee y el componente Security las
hara cumplir en el arranque.
<?php
class WidgetController extends AppController {
var $components = array('Security');
function beforeFilter() {
$this->Security->requirePost('delete');
}
}
?>

En este ejemplo la accion delete solo puede ser lanzada satisfactoriamente si se recive una solicitud
POST.
<?php
class WidgetController extends AppController {
var $components = array('Security');

function beforeFilter() {
if(isset($this->params[Configure::read('Routing.admin')])){
$this->Security->requireSecure();
}
}
}
?>

Este ejemplo forzara todas las acciones que tengan enrrutamiento admin a requerir peticiones
seguras del SSL.
5.6.4 Basic HTTP Authentication
The SecurityComponent has some very powerful authentication features. Sometimes you may
need to protect some functionality inside your application using HTTP Basic Authentication. One
common usage for HTTP Auth is protecting a REST or SOAP API.
This type of authentication is called basic for a reason. Unless you're transferring information
over SSL, credentials will be transferred in plain text.
Using the SecurityComponent for HTTP authentication is easy. The code example below
includes the SecurityComponent and adds a few lines of code inside the controller's beforeFilter
method.
class ApiController extends AppController {
var $name = 'Api';
var $uses = array();
var $components = array('Security');
function beforeFilter() {
$this->Security->loginOptions = array(
'type'=>'basic',
'realm'=>'MyRealm'
);
$this->Security->loginUsers = array(
'john'=>'johnspassword',
'jane'=>'janespassword'
);

$this->Security->requireLogin();
}
function index() {
//protected application logic goes here...
}
}

The loginOptions property of the SecurityComponent is an associative array specifying how


logins should be handled. You only need to specify the type as basic to get going. Specify the realm if
you want display a nice message to anyone trying to login or if you have several authenticated sections
(= realms) of your application you want to keep separate.
The loginUsers property of the SecurityComponent is an associative array containing users and
passwords that should have access to this realm. The examples here use hard-coded user information,
but you'll probably want to use a model to make your authentication credentials more manageable.
Finally, requireLogin() tells SecurityComponent that this Controller requires login. As with
requirePost(), above, providing method names will protect those methods while keeping others open.

5.7 Sesiones
El componente Session de CakePHP provee una forma de persistir datos entre las peticiones de
las pginas. Acta como una abstraccin para acceder a las variables $_SESSION, y a su vez, agrega
distintos mtodos tiles relacionados con este arreglo.
Las sesiones pueden persistirse de diferentes maneras. Por defecto se utilizan los mtodos provistos por
PHP; sin embargo, existen otras opciones:
cake
Guarda los archivos de la sesin en el directorio temporal de tu aplicacin tmp/sessions.
database
Guarda la informacin dentro de la base de datos.
php
La opcin por defecto. Guarda la informacin como se indica en php.ini
Para cambiar el mtodo por defecto de gestin de sesiones, debes modificar el parmetro de
configuracin Session.save para reflejar la opcin deseada. Si eliges 'database', tambin deberas

descomentar el parmetro Session.database y ejecutar el archivo SQL perteneciente a la sesin


localizado en app/config
En views/elements la sesin puede ser accedida por medio del helper Session
5.7.1 Mtodos
El componente Session es usado para interactuar con la informacin de la sesin. Incluye
operaciones bsicas de ABM (Alta, Baja y Modificacin) como tambin opciones para comunicarse
con los usuarios.
Debe notarse que se pueden crear estructuras de arreglos en las sesiones utilizando la notacin
de 'punto'. De esta forma, Usuario.email equivaldr a:
array('Usuario' =>
array('email' => 'clarkKent@dailyplanet.com')
);

Los puntos son usados para indicar arreglos anidados.


5.7.1.1 write

write($name, $value)
Guarda en la sesin una variable llamada $name con el valor $value. $name puede utilizar la
notacin de 'punto'. Por ejemplo:
$this->Session->write('Persona.colorOjos', 'Verde');

Escribe el valor 'Verde' en la sesin, dentro de Persona => colorOjos.


5.7.1.2 setFlash

setFlash($message, $layout = 'default', $params = array(), $key = 'flash')


Se utiliza para guardar una variable de sesin que puede ser mostrada en la vista. $layout
permite controlar qu layout (ubicado en /app/views/layouts) se utilizar para mostrar el
mensaje. Si la variable $layout queda configurada con su valor por defecto, 'default', el mensaje se
mostrar como se ve a continuacin:
<div id="flashMessage" class="message"> [message] </div>

$params
permite pasar variables adicionales para mostrar en el layout. $key es utilizado para modificar
el ndice del arreglo $message en el arreglo de mensajes (por defecto es 'flash'). $message es el texto
que se quiere cargar en la sesin.
Los parmetros puede afectar el div que se muestre, por ejemplo pasando un parmetro 'class'
en el arreglo $params, se modificar el div resultante de utilizar el mtodo $session->flash()
en la vista.
setFlash('Mensaje de ejemplo', 'default', array('class' => 'clase_ejemplo'))

La salida de $session->flash() del ejemplo anterior ser:


<div id="flashMessage" class="clase_ejemplo">Mensaje de ejemplo</div>

5.7.1.3 read

read($name)
Devuelve el contenido de la variable $name dentro de la sesin. Si $name es null, se devolver todo el
contenido de la sesin. Ej.
$verde = $this->Session->read('Persona.colorOjos');

Recupera el valor 'Verde' de la sesin.


5.7.1.4 check

check($name)
Se utiliza para verificar si una variable ha sido seteada en la sesin. Devuelve true en caso afirmativo, y
false si la variable nunca fue seteada.
5.7.1.5 delete

delete($name)
Borra los datos de la variable $name dentro de la sesin. Ej.
$this->Session->delete('Persona.colorOjos');

Nuestra informacin de sesin ya no tiene el valor 'Verde', ni siquiera la clave 'colorOjos'. Sin

embardo, Persona todava existe en la sesin. Para eliminar la variable completa de la sesin se debe
usar:
$this->Session->delete('Persona');

5.7.1.6 destroy

El mtodo destroy eliminar la cookie de sesin y todos los datos almacenados en los
archivos temporales del sistema. Destruir la sesin de PHP y crear una sesin nueva.
$this->Session->destroy()

5.7.1.7 error

error()
Se utiliza para determinar el ltimo error en una sesin.

6 Core Behaviors (Comportamientos Basicos)


Los comportamientos (Behaviors) agregan funcionalidad extra a tus modelos. CakePHP viene
con un numero de comportamientos incorporados tales como el Arbol (Tree) y Contenible
(Containable).

6.1 ACL
El comportamiento Acl provee una forma de integrar un modelo con tu sistema ACL. Puede
crear tanto los AROs o los ACOs transparentemente.
Para usar el nuevo comportamiento, puedes aadirlo a la propiedad $actsAs de tu modelo.
Cuando lo agregas al arreglo $actsAs, se pueden elegir entre hacer la entrada actual como un ARO o un
ACO. El valor por defecto es para crear AROs.
class User extends AppModel {
var $actsAs = array('Acl' => array('type' => 'requester'));
}

Esto incluye el comportamiento de Acl en el modo ARO. Para que el comportamiento ACL sea
ACO, se debe usar:
class Post extends AppModel {
var $actsAs = array('Acl' => array('type' => 'controlled'));
}

Se puede agregar el comportamiento ACL al vuelo, de la siguiente forma:


$this->Post->Behaviors->attach('Acl', array('type' => 'controlled'));

6.1.1 Using the AclBehavior


Muchos de los comportamientos ACL funcionan transparentemente en el mtodo afterSave() del
Modelo. Sin embargo, usarlo requiere que tu Modelo tenga el mtodo parentNode() definido. Esto es
usado por el comportamiento ACL para determinar las relaciones padre-hijo. El mtodo parentNode()
del modelo debe retornar null, o bien, retornar una referencia al modelo padre.

function parentNode() {
return null;
}

Si se quiere setear un nodo ACO o ARO como padre del modelo, parentNode() debe retornar el
alias del nodo ACO o ARO.
function parentNode() {
return 'root_node';
}

Un ejemplo ms completo. Usando un modelo User, donde User tiene la relacin belongsTo con
el modelo Group.
function parentNode() {
if (!$this->id && empty($this->data)) {
return null;
}
$data = $this->data;
if (empty($this->data)) {
$data = $this->read();
}
if (!$data['User']['group_id']) {
return null;
} else {
$this->Group->id = $data['User']['group_id'];
$groupNode = $this->Group->node();
return array('Group' => array('id' => $groupNode[0]['Aro']
['foreign_key']));
}
}

En el ejemplo de arriba el valor de retorno es un arreglo que tiene la misma estructura que el
resultado de la operacin find() del modelo. Es importante setear el valor del id o la relacion
parentNode fallar. El comportamiento Acl usa esta data para construir la estructura del rbol.

6.1.2 node()
El comportamiento ACL tambin permite rescatar el nodo ACL asociado al registro del modelo.
Despues de setear $model->id se puede utilizar $model->node() para rescatar el nodo ACL asociado.
Tambien se puede rescatar el nodo ACL de cualquier fila, pasandolo dentro de un arreglo.
$this->User->id = 1;
$node = $this->User->node();
$user = array('User' => array(
'id' => 1
));
$node = $this->User->node($user);

Ambos retornaran la misma informacin del nodo ACL.

6.2 Containable
A new addition to the CakePHP 1.2 core is the ContainableBehavior. This model
behavior allows you to filter and limit model find operations. Using Containable will help you cut
down on needless wear and tear on your database, increasing the speed and overall performance of
your application. The class will also help you search and filter your data for your users in a clean and
consistent way.
Containable allows you to streamline and simplify operations on your model bindings. It works
by temporarily or permanently altering the associations of your models. It does this by using supplied
the containments to generate a series of bindModel and unbindModel calls.
To use the new behavior, you can add it to the $actsAs property of your model:
class Post extends AppModel {
var $actsAs = array('Containable');
}

You can also attach the behavior on the fly:


$this->Post->Behaviors->attach('Containable');

# Using Containable
To see how Containable works, let's look at a few examples. First, we'll start off with a find()
call on a model named Post. Let's say that Post hasMany Comment, and Post hasAndBelongsToMany
Tag. The amount of data fetched in a normal find() call is rather extensive:
debug($this->Post->find('all'));
[0] => Array
(

)
[1] => Array
(

[Post] => Array(


[id] => 1
[title] => First article
[content] => aaa
[created] => 2008-05-18 00:00:00
)
[Comment] => Array(
[0] => Array
(
[id] => 1
[post_id] => 1
[author] => Daniel
[email] => dan@example.com
[website] => http://example.com
[comment] => First comment
[created] => 2008-05-18 00:00:00
)
[1] => Array
(
[id] => 2
[post_id] => 1
[author] => Sam
[email] => sam@example.net
[website] => http://example.net
[comment] => Second comment
[created] => 2008-05-18 00:00:00
)
)
[Tag] => Array(
[0] => Array
(
[id] => 1
[name] => Awesome
)
[1] => Array
(
[id] => 2
[name] => Baking
)
)

[Post] => Array


(...

For some interfaces in your application, you may not need that much information from the Post
model. One thing the ContainableBehavior does is help you cut down on what find() returns.
For example, to get only the post-related information, you can do the following:
$this->Post->contain();
$this->Post->find('all');

You can also invoke Containable's magic from inside the find() call:
$this->Post->find('all', array('contain' => false));

Having done that, you end up with something a lot more concise:
[0] => Array
(

)
[1] => Array
(

[Post] => Array(


[id] => 1
[title] => First article
[content] => aaa
[created] => 2008-05-18 00:00:00
)

[Post] => Array(


[id] => 2
[title] => Second article
[content] => bbb
[created] => 2008-05-19 00:00:00
)
)

This sort of help isn't new: in fact, you can do that without the ContainableBehavior
doing something like this:
$this->Post->recursive = -1;
$this->Post->find('all');

Containable really shines when you have complex associations, and you want to pare down
things that sit at the same level. The model's $recursive property is helpful if you want to hack off
an entire level of recursion, but not when you want to pick and choose what to keep at each level. Let's
see how it works by using the contain() method.
The contain method's first argument accepts the name, or an array of names, of the models to
keep in the find operation. If we wanted to fetch all posts and their related tags (without any comment
information), we'd try something like this:

$this->Post->contain('Tag');
$this->Post->find('all');

Again, we can use the contain key inside a find() call:


$this->Post->find('all', array('contain' => 'Tag'));

Without Containable, you'd end up needing to use the unbindModel() method of the model,
multiple times if you're paring off multiple models. Containable creates a cleaner way to accomplish
this same task.
# Containing deeper associations
Containable also goes a step deeper: you can filter the data of the associated models. If you
look at the results of the original find() call, notice the author field in the Comment model. If you are
interested in the posts and the names of the comment authors and nothing else you could do
something like the following:
$this->Post->contain('Comment.author');
$this->Post->find('all');
//or..
$this->Post->find('all', array('contain' => 'Comment.author'));

Here, we've told Containable to give us our post information, and just the author field of the
associated Comment model. The output of the find call might look something like this:
[0] => Array(
[Post] => Array(
[id] => 1
[title] => First article
[content] => aaa
[created] => 2008-05-18 00:00:00
)
[Comment] => Array(
[0] => Array(
[author] => Daniel
[post_id] => 1
)
[1] => Array(
[author] => Sam
[post_id] => 1
)
)
)
[1] => Array
(...

As you can see, the Comment arrays only contain the author field (plus the post_id which is
needed by CakePHP to map the results).
You can also filter the associated Comment data by specifying a condition:
$this->Post->contain('Comment.author = "Daniel"');
$this->Post->find('all');
//or...
$this->Post->find('all', array('contain' => 'Comment.author = "Daniel"'));

This gives us a result that gives us posts with comments authored by Daniel:
[0] => Array
(
[Post] => Array
(
[id] => 1
[title] => First article
[content] => aaa
[created] => 2008-05-18 00:00:00
)
[Comment] => Array
(
[0] => Array
(
[id] => 1
[post_id] => 1
[author] => Daniel
[email] => dan@example.com
[website] => http://example.com
[comment] => First comment
[created] => 2008-05-18 00:00:00
)
)
)

Additional filtering can be performed by supplying the standard Model->find() options:


$this->Post->find('all', array('contain' => array(
'Comment' => array(
'conditions' => array('Comment.author =' => "Daniel"),
'order' => 'Comment.created DESC'
)
)));

Here's an example of using the ContainableBehavior when you've got deep and complex
model relationships.

Let's consider the following model associations:


User->Profile
User->Account->AccountSummary
User->Post->PostAttachment->PostAttachmentHistory->HistoryNotes
User->Post->Tag

This is how we retrieve the above associations with Containable:


$this->User->find('all', array(
'contain'=>array(
'Profile',
'Account' => array(
'AccountSummary'
),
'Post' => array(
'PostAttachment' => array(
'fields' => array('id', 'name'),
'PostAttachmentHistory' => array(
'HistoryNotes' => array(
'fields' => array('id', 'note')
)
)
),
'Tag' => array(
'conditions' => array('Tag.name LIKE' => '%happy
%')
)
)
)
));

Keep in mind that contain key is only used once in the main model, you don't to use 'contain'
again for related models
When using 'fields' and 'contain' options - be careful to include all foreign keys that your query
directly or indirectly requires. Please also note that because Containable must to be attached to all
models used in containment, you may consider attaching it to your AppModel.
6.2.1 Using Containable with pagination
By including the 'contain' parameter in the $paginate property it will apply to both the
find('count') and the find('all') done on the model
See the section Using Containable for further details.

Here's an example of how to contain associations when paginating.


$this->paginate['User'] = array(
'contain' => array('Profile', 'Account'),
'order' => 'User.username'
);
$users = $this->paginate('User');

# ContainableBehavior options
The ContainableBehavior has a number of options that can be set when the Behavior is
attached to a model. The settings allow you to fine tune the behavior of Containable and work with
other behaviors more easily.
recursive (boolean, optional) set to true to allow containable to automatically determine the
recursiveness level needed to fetch specified models, and set the model recursiveness to this
level. setting it to false disables this feature. The default value is true.
notices (boolean, optional) issues E_NOTICES for bindings referenced in a containable call
that are not valid. The default value is true.
autoFields: (boolean, optional) auto-add needed fields to fetch requested bindings. The default
value is true.
You can change ContainableBehavior settings at run time by reattaching the behavior as seen in
Using behaviors
ContainableBehavior can sometimes cause issues with other behaviors or queries that use
aggregate functions and/or GROUP BY statements. If you get invalid SQL errors due to mixing of
aggregate and non-aggregate fields, try disabling the autoFields setting.
$this->Post->Behaviors->attach('Containable', array('autoFields' => false));

6.3 Translate
TranslateBehavior es bastante fcil de configurar y trabaja fuera de la caja con muy poca
configuracin. En esta seccin, usted aprender cmo aadir y configurar el comportamiento
(behavior) para usarlo en cualquier modelo.
6.3.1 Inicializando las tablas de la Base de datos i18n
Puede utilizar la consola de CakePHP o puede crearlo manualmente. Se recomienda utilizar la
consola para esto, por que podran pasar que hallan cambios de diseo en las futuras versiones de
CakePHP. Si lo haces por consola, puedes estar seguro que tiene el correcto diseo.
./cake i18n

Seleccione [I] y se ejecuta el script e inicializa la Base de datos i18n. Se le preguntar si desea
eliminar cualquiera que exista y si desea crearla.Responde un S, si usted esta seguro de que no existe
una tabla i18n, y responda con S para crear la tabla de nuevo.
6.3.2 Adjuntando el Comportamiento de Traduccin a tus Modelos
Se debe incorporar al modelo haciendo uso de la propiedad $actsAs como en el siguiente
ejemplo.
<?php
class Post extends AppModel {
var $name = 'Post';
var $actsAs = array(
'Translate'
);
}
?>

Esto no har nada an, pues es necesario configurar algunas opciones antes de comenzar a funcionar.
Se deben definir qu campos de el modelo actual sern rastreados en la tabla de traducciones creada en
el paso anterior.

6.3.3 Definiendo los Campos


Se pueden establecer los campos simplemente extendiendo el valor 'Translate' con otro array, por
ejemplo:
<?php
class Post extends AppModel {
var $name = 'Post';
var $actsAs = array(
'Translate' => array(
'campoUno', 'campoDos', 'campoN'
)
);
}
?>

Luego de haber hecho esto (por ejemplo poner "nombre" como uno de los campos) ya has
terminado la configuracin bsica. Genial! De acuerdo con el ejemplo anterior, ahora el modelo debera
verse algo as:
<?php
class Post extends AppModel {
var $name = 'Post';
var $actsAs = array(
'Translate' => array(
'nombre'
)
);
}
?>

6.3.4 Conclusiones
Desde ahora en cada actualizacin/creacin de un registro har que TranslateBehavior copie el
valor "nombre" en la tabla de traducciones (por defecto: i18n) de acuerdo a la localizacin actual. Una
localizacin corresponde al identificador de una lengua
La localizacin actual es el valor actual de Configure::read('Config.language').
El valor de Config.language es establecido en la Clase L10n - a no ser que ya se haya establecido. Sin
embargo, TranlateBehavior te permite invalidar esto ltimo 'al vuelo', lo cual permite al usuario de tus
pginas crear multiples versiones sin la necesidad de que este cambie sus preferencias. Ms sobre esto
en la siguiente seccin.

6.3.5 Obtener todos los registros de traduccin para un campo determinado


Si se desea obtener todos los registros de traduccin asociados al modelo actual, simplemente se
extiende el arreglo de campos en la configuracion como se muestra abajo. El nombre se puede definir
sin restricciones
<?php
class Post extends AppModel {
var $name = 'Post';
var $actsAs = array(
'Translate' => array(
'name' => 'nameTranslation'
)
);
}
?>

Con esta configuracin el resultado de find() se ver similar a esto:


Array
(
[Post] => Array
(
[id] => 1
[name] => Beispiel Eintrag
[body] => lorem ipsum...
[locale] => de_de
)
[nameTranslation] => Array
(
[0] => Array
(
[id] => 1
[locale] => en_us
[model] => Post
[foreign_key] => 1
[field] => name
[content] => Example entry
)
[1] => Array
(
[id] => 2
[locale] => de_de
[model] => Post
[foreign_key] => 1
[field] => name
[content] => Beispiel Eintrag
)
)

Nota: El registro del modelo contiene un campo virtual llamado "locale", el cual indica que "locale" es
usado en el resultado.
6.3.5.1 Using the bindTranslation method

You can also retrieve all translations, only when you need them, using the bindTranslation
method
bindTranslation($fields, $reset)
$fields is a named-key array of field and association name, where the key is the translatable
field and the value is the fake association name.
$this->Post->bindTranslation(array ('name' => 'nameTranslation'));
$this->Post->find('all', array ('recursive'=>1)); // need at least recursive 1 for
this to work.

With this setup the result of your find() should look something like this:
Array
(
[Post] => Array
(
[id] => 1
[name] => Beispiel Eintrag
[body] => lorem ipsum...
[locale] => de_de
)
[nameTranslation] => Array
(
[0] => Array
(
[id] => 1
[locale] => en_us
[model] => Post
[foreign_key] => 1
[field] => name
[content] => Example entry
)
[1] => Array
(
[id] => 2
[locale] => de_de
[model] => Post
[foreign_key] => 1
[field] => name
[content] => Beispiel Eintrag
)
)
)

6.3.6 Saving in another language


You can force the model which is using the TranslateBehavior to save in a language other than
the on detected.
To tell a model in what language the content is going to be you simply change the value of the
$locale property on the model before you save the data to the database. You can do that either in
your controller or you can define it directly in the model.
Example A: In your controller
<?php
class PostsController extends AppController {
var $name = 'Posts';
function add() {
if ($this->data) {
$this->Post->locale = 'de_de'; // we are going to save the
german version
$this->Post->create();
if ($this->Post->save($this->data)) {
$this->redirect(array('action' => 'index'));
}
}
}
}
?>

Example B: In your model


<?php
class Post extends AppModel {
var $name = 'Post';
var $actsAs = array(
'Translate' => array(
'name'
)
);
// Option 1) just define the property directly
var $locale = 'en_us';

// Option 2) create a simple method


function setLanguage($locale) {
$this->locale = $locale;
}
}
?>

6.3.7 Multiple Translation Tables


If you expect a lot entries you probably wonder how to deal with a rapidly growing database
table. There are two properties introduced by TranslateBehavior that allow to specify which "Model" to
bind as the model containing the translations.
These are $translateModel and $translateTable.
Lets say we want to save our translations for all posts in the table "post_i18ns" instead of the
default "i18n" table. To do so you need to setup your model like this:
<?php
class Post extends AppModel {
var $name = 'Post';
var $actsAs = array(
'Translate' => array(
'name'
)
);
// Use a different model (and table)
var $translateModel = 'PostI18n';
}
?>

Important is that you have to pluralize the table. It is now a usual model and can be treated as such
and thus comes with the conventions involved. The table schema itself must be identical with the one
generated by the CakePHP console script. To make sure it fits one could just initialize a empty i18n
table using the console and rename the table afterwards.

6.3.7.1 Create the TranslateModel

For this to work you need to create the actual model file in your models folder. Reason is that
there is no property to set the displayField directly in the model using this behavior yet.
Make sure that you change the $displayField to 'field'.
<?php
class PostI18n extends AppModel {
var $displayField = 'field'; // important
}
// filename: post_i18n.php
?>

That's all it takes. You can also add all other model stuff here like $useTable. But for better
consistency we could do that in the model which actually uses this translation model. This is where the
optional $translateTable comes into play.
6.3.7.2 Changing the Table

If you want to change the name of the table you simply define $translateTable in your model,
like so:
<?php
class Post extends AppModel {
var $name = 'Post';
var $actsAs = array(
'Translate' => array(
'name'
)
);
// Use a different model
var $translateModel = 'PostI18n';
// Use a different table for translateModel
var $translateTable = 'post_translations';
}
?>

Please note that you can't use $translateTable alone. If you don't intend to use a custom
$translateModel then leave this property untouched. Reason is that it would break your setup and
show you a "Missing Table" message for the default I18n model which is created in runtime.

6.4 Arboles (Tree)


Es muy comn que se desea almacenar datos jerrquicos en una tabla de base de datos.
Ejemplos de estos datos pueden ser: categoras con subcategoras ilimitadas, los datos relativos a un
sistema de mens multinivel o una representacin literal de la jerarqua tal como se utiliza para
almacenar objetos de control de acceso con la lgica ACL.
Para pequeos rboles de datos, o cuando los datos son de slo unos pocos niveles de
profundidad es simple aadir un campo parent_id a su tabla de base de datos y utilizar este para hacer
un seguimiento de cual item es padre de quien. Sin embargo, Cake Viene equipado con este paquete,
pero con un comportamiento de gran alcance que le permite utilizar los beneficios de la lgica MPTT
sin preocuparse de cualquiera de los entresijos de la tcnica - a menos que ud lo desee ;).
6.4.1 Requerimientos
Para poder usar la funcionalidad de rbol, la tabla de la base de datos debe tener los 3 campos
listados a continuacin (enteros todos):
padre - el nombre por defecto del campo es parent_id, para almacenar el id del objeto padre
izquierda - el nombre por defecto del campo es lft, para almacenar el valor lft de la fila actual.
deracha - el nombre por defecto del campo es rght, para almacenar el valor rght de la fila
actual.
Si esta familiarizado con la lgina MPTT ud puede preguntarse por que el campos parent existe
- simplemente es ms facil de realizar ciertas tareas si existe un enlace directo al padre almacenado en
la base de datos - tales como la bsquera de los hijos directos.
6.4.2 Uso Bsico
El comportamiento de arbol tiene muchas cosas incluidas, pero empecemos con un simple
ejemplo - crearemos una pequea tabla en una base de datos y le agregaremos algunos datos:
CREATE TABLE categories (
id INTEGER(10) UNSIGNED NOT NULL AUTO_INCREMENT,
parent_id INTEGER(10) DEFAULT NULL,
lft INTEGER(10) DEFAULT NULL,
rght INTEGER(10) DEFAULT NULL,
name VARCHAR(255) DEFAULT '',
PRIMARY KEY (id)
);
INSERT INTO `categories` (`id`, `name`, `parent_id`, `lft`, `rght`) VALUES(1, 'Mis

Categorias', NULL, 1, 30);


INSERT INTO `categories` (`id`,
'Diversion', 1, 2, 15);
INSERT INTO `categories` (`id`,
'Deportes', 2, 3, 8);
INSERT INTO `categories` (`id`,
'Surfing', 3, 4, 5);
INSERT INTO `categories` (`id`,
'Alpinismo', 3, 6, 7);
INSERT INTO `categories` (`id`,
'Amigos', 2, 9, 14);
INSERT INTO `categories` (`id`,
'Gerald', 6, 10, 11);
INSERT INTO `categories` (`id`,
'Gwendolyn', 6, 12, 13);
INSERT INTO `categories` (`id`,
'Trabajo', 1, 16, 29);
INSERT INTO `categories` (`id`,
'Reportes', 9, 17, 22);
INSERT INTO `categories` (`id`,
'Anual', 10, 18, 19);
INSERT INTO `categories` (`id`,
'Status', 10, 20, 21);
INSERT INTO `categories` (`id`,
'Viajes', 9, 23, 28);
INSERT INTO `categories` (`id`,
'Nacional', 13, 24, 25);
INSERT INTO `categories` (`id`,
'Internacional', 13, 26, 27);

`name`,

`parent_id`,

`lft`,

`rght`)

VALUES(2,

`name`,

`parent_id`,

`lft`,

`rght`)

VALUES(3,

`name`,

`parent_id`,

`lft`,

`rght`)

VALUES(4,

`name`,

`parent_id`,

`lft`,

`rght`)

VALUES(5,

`name`,

`parent_id`,

`lft`,

`rght`)

VALUES(6,

`name`,

`parent_id`,

`lft`,

`rght`)

VALUES(7,

`name`,

`parent_id`,

`lft`,

`rght`)

VALUES(8,

`name`,

`parent_id`,

`lft`,

`rght`)

VALUES(9,

`name`, `parent_id`, `lft`, `rght`) VALUES(10,


`name`, `parent_id`, `lft`, `rght`) VALUES(11,
`name`, `parent_id`, `lft`, `rght`) VALUES(12,
`name`, `parent_id`, `lft`, `rght`) VALUES(13,
`name`, `parent_id`, `lft`, `rght`) VALUES(14,
`name`, `parent_id`, `lft`, `rght`) VALUES(15,

Para el propsito de verificar que todo est configurado correctamente, podemos crear un
metodo de testeo y obtener los contenidos de nuestro arbol de categorias para ver como queda. Con un
simple controlador:
<?php
class CategoriesController extends AppController {
var $name = 'Categories';
function index() {
$this->data = $this->Category->generatetreelist(null, null, null,
'&nbsp;&nbsp;&nbsp;');
debug ($this->data); die;
}
}
?>

y un metodo aun mas simple en el modelo:

<?php
// app/models/category.php
class Category extends AppModel {
var $name = 'Category';
var $actsAs = array('Tree');
}
?>

Podemos verificar como se ve que nuestro arbol de categoria visitando /categories Deberias ver
algo como:
Mis Categorias
Diversion
Deportes
Surfing
Alpinismo
Amigos
Gerald
Gwendolyn
Trabajo
Reportes
Anual
Status
Viajes
Nacional
Internacional
6.4.2.1 Agregando datos

En la seccion anterior, usamos datos pre-existentes y chequeamos que se vieran en forma


jerarquica con el mtodo generatetreelist. Sin embargo, usualmente agregaramos los datos de
la misma forma que lo hariamos con cualquier modelo. Por ejemplo:
// pseudo cdigo del controlador
$data['Category']['parent_id'] =
$data['Category']['name'] =

3;

'Skating';

$this->Category->save($data);

Cuando se usa el comportamiento de arbol no es necesario hacer nada mas que configurar el
parent_id, y el comportamiento de arbol se encargara del resto. Si no se setea el parent_id el
comportamiento de arbol lo agregara al arbol como una entrada en el nivel superior:

// pseudo codigo controlador


$data = array();
$data['Category']['name'] =

'Otra Categoria';

$this->Category->save($data);

Ejecutando estos dos trozos de cdigo alterar el rbol como sigue:


Mis Categorias
Diversion
Deportes
Surfing
Alpinismo
Skating New
Amigos
Gerald
Gwendolyn
Trabajo
Reportes
Anual
Status
Viajes
Nacional
Internacional
Otra Categoria New
6.4.2.2 Modificando datos

Modificar datos es tan transparente como agregar nuevos datos. Si modificas algo, pero no
modificas el campo parent_id - la estructura de tus datos permanecera inalterada. Por ejemplo:
// pseudo codigo

de controlador

$this->Category->id = 5; // id de Apinismo
$this->Category->save(array('name' =>'Pesca'));

El codigo anterior no modifica el parent_id - incluso si el parent_id es incluido en los datos que
son pasados al mtodo save, si el valor no ha sido cambiado, tampoco lo hace la estructura de datos.
Entonces, el arbol de datos queda:
Mis Categorias
Diversion
Deportes
Surfing
Pesca Updated
Skating

Amigos
Gerald
Gwendolyn
Trabajo
Reportes
Anual
Status
Viajes
Nacional
Internacional
Otra Categoria
Mover un dato a traves del arbol tambien es simple. Digamos que Pesca no pertenece a
Deportes, sino que deberia estar en Otra Categoria. Con el siguiente cdigo:
// pseudo codigo de controlador
$this->Category->id = 5; // id of Pesca
$newParentId = $this->Category->field('id', array('name' => 'Otra Categoria'));
$this->Category->save(array('parent_id' => $newParentId));

Como es de esperar la estructura queda modificada a:


Mis Categorias
Diversion
Deportes
Surfing
Skating
Amigos
Gerald
Gwendolyn
Trabajo
Reportes
Anual
Status
Viajes
Nacional
Internacional
Otra Categoria
Pesca Movido
6.4.2.3 Borrando datos

El comportamiento de arbol provee algunas formas para manejar la eliminacin de datos. Para
comenzar con un ejemplo simple, diremos que la categoria reportes ya no es necesaria. Para eliminarla

y cualquier hijo que ella tenga basta llamar a delete tal como lo harias en cualquier modelo. Por
ejemplo, en el siguiente cdigo:
// pseudo codigo de controlador
$this->Category->id = 10;
$this->Category->delete();

El arbol de categorias sera modificado como sigue:


Mis Categorias
Diversion
Deportes
Surfing
Skating
Amigos
Gerald
Gwendolyn
Trabajo
Viajes
Nacional
Internacional
Otras Categorias
Pesca
6.4.2.4 Haciendo consultas y usando tus datos

Usar y manipular datos jerarquicos puede ser algo complejo. Ademas de los metodos de
busqueda del nucleo como find(), con los arboles tenemos unos cuantos metodos ms para su
manipulacion.
Muchos metodos del comportamiento de arbol devuelven y se apoyan en el orden del campo
lft. Si llamas a find() y no ordenas por el campo lft, o llamas algun metodo de arboles
entregandole un tipo de ordenamiento, quizas obtengas resultados no deseados.
6.4.2.4.1 El mtodo children

El mtodo children toma la llave primaria (id) de una fila y retorna los hijos, por defecto en
el roden en que aparecen en el rbol. El segundo parmetro es opcional y define si se entregan o no
slo los hijos directos. Usando el ejemplo de la seccin anterior:
$allChildren = $this->Category->children(1); // un arreglo plano con 11 valores
// -- o bien -$this->Category->id = 1;

$allChildren = $this->Category->children(); // un arreglo plano con 11 valores


// Retornar solo los hijos directos
$directChildren = $this->Category->children(1, true); //un arreglo plano con 2
valores

Si quieres un arreglo recursivo utiliza find('threaded')


6.4.2.4.2 Contando los hijos

Tal como el mtodo children, childCount toma la llave primaria (id) y retorna cuantos
hijos tiene. El segundo parmetro es opcional y define si se contarn o no los hijos directos. Usando los
datos del ejemplo anterior:
$totalChildren = $this->Category->childCount(1); // entrega 11
// -- o bien -$this->Category->id = 1;
$directChildren = $this->Category->childCount(); // entrega 11
//Solo los hijos directos
$numChildren = $this->Category->childCount(1, true); // entrega 2

6.4.2.4.3 generatetreelist

generatetreelist

($conditions=null,

$keyPath=null,

$valuePath=null,

$spacer=

'_',

$recursive=null)
This method will return data similar to find('list'), with an indented prefix to show the
structure of your data. Below is an example of what you can expect this method to return.
$conditions - Uses the same conditional options as find().
$keyPath - Path to the field to use for the key.
$valuePath - Path to the field to use for the label.
$spacer - The string to use in front of each item to indicate depth.
$recursive - The number of levels deep to fetch associated records
All the parameters are optional, with the following defaults:
$conditions = null
$keyPath = Model's primary key

$valuePath = Model's displayField


$spacer = '_'
$recursive = Model's recursive setting
$treelist = $this->Category->generatetreelist();

Output:
array(
[1] =>
[2] =>
[3] =>
[4] =>
[16] =>
[6] =>
[7] =>
[8] =>
[9] =>
[13] =>
[14] =>
[15] =>
[17] =>
[5] =>

"My Categories",
"_Fun",
"__Sport",
"___Surfing",
"___Skating",
"__Friends",
"___Gerald",
"___Gwendolyn",
"_Work",
"__Trips",
"___National",
"___International",
"Other People's Categories",
"_Extreme fishing"

6.4.2.4.4 getparentnode

This convenience function will, as the name suggests, return the parent node for any node, or false if
the node has no parent (its the root node). For example:
$parent = $this->Category->getparentnode(2); //<- id for fun
// $parent contains All categories

6.4.2.4.5 getpath

getpath( $id = null, $fields = null, $recursive = null )


The 'path' when refering to hierachial data is how you get from where you are to the top. So for
example the path from the category "International" is:
My Categories
...
Work
Trips
...
International
Using the id of "International" getpath will return each of the parents in turn (starting from the top).

$parents = $this->Category->getpath(15);
// contents of $parents
array(
[0] =>

array('Category' => array('id' => 1, 'name' => 'My Categories',

..)),
[1] =>

array('Category' => array('id' => 9, 'name' => 'Work', ..)),

[2] =>

array('Category' => array('id' => 13, 'name' => 'Trips', ..)),

[3] =>

array('Category' => array('id' => 15, 'name' => 'International',

..)),
)

6.4.3 Uso Avanzado


Este comportamiento de modelo no slo trabaja en segundo plano, hay una gran variedad de
mtodos especficos definidos en este comportamiento para antender todas tus necesidades de datos
jerrquicos, y cualquier problema inesperado que pueda surgir en el proceso.
6.4.3.1 moveDown

Utilizado para mover un nico nodo hacia abajo del rbol. Debes indicar el ID del elemento a
mover y un nmero entero positivo de cuantas posiciones el nodo debera ser movido hacia abajo.
Todos los nodos hijos del nodo a mover tambin sern movidos
Un ejemplo de una accin de controlador (en un controlador llamado Categories) que mueve un
nodo hacia abajo del arbol:
function movedown($name = null, $delta = null) {
$cat = $this->Category->findByName($name);
if (empty($cat)) {
$this->Session->setFlash('No hay una categora de nombre ' . $name);
$this->redirect(array('action' => 'index'), null, true);
}
$this->Category->id = $cat['Category']['id'];
if ($delta > 0) {
$this->Category->moveDown($this->Category->id, abs($delta));
} else {

$this->Session->setFlash('Por favor indique el nmero de posiciones


que el nodo debe ser movido hacia abajo.');
}
$this->redirect(array('action' => 'index'), null, true);
}

Por ejemplo, si quicieras mover la categora "Sport" un nivel hacia abajo, deberas llamar a:
/categories/movedown/Sport/1.
6.4.3.2 moveUp

Used to move a single node up the tree. You need to provide the ID of the element to be moved
and a positive number of how many positions the node should be moved up. All child nodes will also
be moved.
Here's an example of a controller action (in a controller named Categories) that moves a node
up the tree:
function moveup($name = null, $delta = null){
$cat = $this->Category->findByName($name);
if (empty($cat)) {
$this->Session->setFlash('There is no category named ' . $name);
$this->redirect(array('action' => 'index'), null, true);
}
$this->Category->id = $cat['Category']['id'];
if ($delta > 0) {
$this->Category->moveup($this->Category->id, abs($delta));
} else {
$this->Session->setFlash('Please provide a number of positions the
category should be moved up.');
}
$this->redirect(array('action' => 'index'), null, true);
}

For example, if you would like to move the category "Gwendolyn" up one position you would
request /categories/moveup/Gwendolyn/1. Now the order of Friends will be Gwendolyn, Gerald.
6.4.3.3 removeFromTree

removeFromTree($id=null, $delete=false)
Using this method wil either delete or move a node but retain its sub-tree, which will be
reparented one level higher. It offers more control than delete(), which for a model using the tree
behavior will remove the specified node and all of its children.
Taking the following tree as a starting point:
My Categories
Fun
Sport
Surfing
Extreme knitting
Skating
Running the following code with the id for 'Sport'
$this->Node->removeFromTree($id);

The Sport node will be become a top level node:


My Categories
Fun
Surfing
Extreme knitting
Skating
Sport Moved
This demonstrates the default behavior of removeFromTree of moving the node to have no parent,
and re-parenting all children.
If however the following code snippet was used with the id for 'Sport'
$this->Node->removeFromTree($id,true);

The tree would become


My Categories
Fun
Surfing
Extreme knitting

Skating
This demonstrates the alternate use for removeFromTree, the children have been reparented and
'Sport' has been deleted.
6.4.3.4 reorder

reorder ( array('id' => null, 'field' => $Model->displayField, 'order' => 'ASC', 'verify'
=> true) )
Reorders the nodes (and child nodes) of the tree according to the field and direction specified in
the parameters. This method does not change the parent of any node.
$model->reorder(array(
'id' => ,

//id of record to use as top node for reordering, default:

$Model->id
'field' => , //which field to use in reordering, default: $Model->displayField
'order' => , //direction to order, default: 'ASC'
'verify' =>

//whether or not to verify the tree before reorder, default: true

));

6.4.4 Data Integrity


Debido a la naturaleza de las estructuras complejas autorreferentes como los rboles y las listas
enlazadas, ocasionalmente pueden romperse debido a una llamada poco cuidadosa. Tmalo con calma,
no todo est perdido! Tree Behavior contiene varias caractersticas que antes no estaban
documentadas, diseadas para recuperarse de tales situaciones.
6.4.4.1 Recover

recover(&$model, $mode = 'parent', $missingParentAction = null)


The mode parameter is used to specify the source of info that is valid/correct. The opposite
source of data will be populated based upon that source of info. E.g. if the MPTT fields are corrupt or
empty, with the $mode 'parent' the values of the parent_id field will be used to populate the
left and right fields. The missingParentAction parameter only applies to "parent" mode and
determines what to do if the parent field contains an id that is not present.
Available $mode options:
'parent' - use the existing parent_id's to update the lft and rght fields

'tree' - use the existing lft and rght fields to update parent_id
Available missingParentActions options when using mode='parent':
null - do nothing and carry on
'return' - do nothing and return
'delete' - delete the node
int - set the parent_id to this id
// Rebuild all the left and right fields based on the parent_id
$this->Category->recover();
// or
$this->Category->recover('parent');
// Rebuild all the parent_id's based on the lft and rght fields
$this->Category->recover('tree');

6.4.4.2 Reorder

reorder(&$model, $options = array())


Reorders the nodes (and child nodes) of the tree according to the field and direction specified in
the parameters. This method does not change the parent of any node.
Reordering affects all nodes in the tree by default, however the following options can affect the
process:
'id' - only reorder nodes below this node.
'field' - field to use for sorting, default is the displayField for the model.
'order' - 'ASC' for ascending, 'DESC' for descending sort.
'verify' - whether or not to verify the tree prior to resorting.
$options is used to pass all extra parameters, and has the following possible keys by default,
all of which are optional:
array(
'id' => null,
'field' => $model->displayField,
'order' => 'ASC',
'verify' => true

6.4.4.3 Verify

verify(&$model)
Returns true if the tree is valid otherwise an array of errors, with fields for type, incorrect
index and message.
Each record in the output array is an array of the form (type, id, message)
type is either 'index' or 'node'
'id' is the id of the erroneous node.
'message' depends on the error
$this->Categories->verify();

Example output:
Array
(
[0] => Array
(
[0] =>
[1] =>
[2] =>
)
[1] => Array
(
[0] =>
[1] =>
[2] =>
)
[10] => Array
(
[0] =>
[1] =>
[2] =>
)
[99] => Array
(
[0] =>
[1] =>
[2] =>
)
)

node
3
left and right values identical

node
2
The parent node 999 doesn't exist

index
123
missing

node
163
left greater than right

7 Ayudantes del Core


Los Ayudantes o Helpers son clases a modo de componentes para la capa de presentacin de tu
aplicacin. Contienen lgica de presentacin que puede ser compartida por muchas vistas, elementos y
layouts.
Esta seccin describe cada uno de los Helpers incluidos en CakePHP como Form, Html,
JavaScript y RSS.
Lee la seccin Helpers para aprender ms acerca de los helpers y cmo puedes crear los tuyos propios.

7.1 AJAX
El AjaxHelper utilizas las populares libreras Prototype y script.aculo.us para operaciones Ajax
y efectos en el lado del cliente. Para utilizar el AjaxHelper has de tener la versin actual de las libreras
de JavaScript de www.prototypejs.org y http://script.aculo.us situadas en /app/webroot/js.
Adems has de incluir las libreras Prototype y script.aculo.us en los layouts o vistas que requieran las
funcionalidades de AjaxHelper.
Para poder cargar las libreras Prototype y script.aculo.us necesitars incluir los helpers Ajax y
Javascript en tu controlador:
class WidgetsController extends AppController {
var $name = 'Widgets';
var $helpers = array('Html','Ajax','Javascript');
}

Una vez que hayas incluido el helper de javascript en tu controlador, puedes utilizar el mtodo
link() de $javascript para incluir las liberas Prototype y script.aculo.us en la vista:
echo $javascript->link('prototype');
echo $javascript->link('scriptaculous');

Ahora ya puedes puedes utilizar el helper Ajax en tu vista:


$ajax->loquesea();

Si se incluye el componente RequestHandler en el controlador, CakePHP automticamente


aplicar el layout Ajax cuando se realize una peticin de una accin mediante AJAX.
class WidgetsController extends AppController {

var $name = 'Widgets';


var $helpers = array('Html','Ajax','Javascript');
var $components = array( 'RequestHandler' );
}

7.1.1 AjaxHelper Options


La mayora de los mtodos del AjaxHelper permiten suministrar un arreglo de opciones ($options).
Puedes usar este arreglo para configurar el comportamiento del AjaxHelper. Antes de cubrir los
mtodos especficos del helper, veamos las diferentes opciones disponibles a travs de este arreglo.
Esta seccin ser de utilidad como referencia mientras inicias el uso de los mtodos del AjaxHelper.
7.1.1.1 General Options

$options['url']
La url del controlador/accin que se quiere llamar.
$options['update']
El id del elemento DOM a ser actualizado con el contenido que retorne.
$options['frequency']
El nmero de segundos entre intervalos de observacin.
$options['type']
Indica si la peticin se realiza de forma sncrona asncrona (por omisin).

7.1.1.2 Opciones de retrollamadas (Callback Options)

Las opciones de Callbacks te permiten llamar a las funciones de JavaScript en puntos


especficos en el proceso de solicitud (request). Si ests buscando insertar un poco de lgica antes,
despus, o durante tus operaciones de AjaxHelper, usa estas Callbacks para estableces las cosas.
$options keys Description
$options['conditi El fragmento de cdigo JavaScriptque necesita evaluar a true antes de que la solicitud
on']

se inicie.

$options['before' Se ejecuta antes de que una solicitud sea efectuada. Un uso comn de esta es permitir
]

la visibilidad de un indicador de progreso.

$options['confir Texto a mostrar en un cuadro de confirmacin de JavaScript antes de proceder.


m']
$options['loadin Cdigo de la Callback que se ejecutar mientras que los datos se recuperan desde el
g']

servidor.

$options['after'] JavaScript llamado inmediatamente despus de que se ejecuta una solicitud; se dispare
antes de que se ejecute la callback $options['loading'].
$options['loaded'Cdigo de la Callback a ser ejecutado cuando un documento remoto es recivido por el
]

cliente.

$options['interac Llamada cuando un usuario puede interactuar con el documento remoto, a pesar de
tive']

que no ha terminado de cargar.

$options['compl Callback JavaScript a ser ejecutada cuando se completa un XMLHttpRequest.


ete']

7.1.2 Mtodos
7.1.2.1 link

link(string

$title,

string

$href,

array

$options,

string

$confirm,

boolean

$escapeTitle)
Devuelve un enlace a una accin remota definida por $options['url'] o $href que se
llama en background utilizando XMLHttpRequest cuando se hace clic en el enlace. El resultado de esa
peticin puede ser insertada en un objeto DOM cuya identificacin se puede especificar con
$options['update'].
Si $options['url'] esta en blanco href es utilizado en su lugar
Ejemplo:
<div id="post">
</div>
<?php echo $ajax->link(
'View Post',
array( 'controller' => 'posts', 'action' => 'view', 1 ),
array( 'update' => 'post' )
);
?>

Por defecto, estas solicitudes son procesadas asincrnicamente mientras se utilizan diferentes
callbacks
Ejemplo:
<div id="post">
</div>
<?php echo $ajax->link(
'View Post',
array( 'controller' => 'posts', 'action' => 'post', 1 ),
array( 'update' => 'post', 'complete' => 'alert( "Hello World" )'

);
?>

Para usa procesamiento sincrnico especificar $options['type'] = 'synchronous'.


Para automatizar que el layout utilizado sea ajax incluir el componente RequestHandler en el
controlador
Por defecto el contenido del elemento es reemplazado. Para cambiar este comportamiento especificar
$options['position']
Ejemplo:
<div id="post">
</div>
<?php echo $ajax->link(
'View Post',
array( 'controller' => 'posts', 'action' => 'view', 1),
array( 'update' => 'post', 'position' => 'top' )
);
?>

$confirm puede ser usado para llamar un JavaScript confirm() message antes de que la
peticin se efecte. Permite al usuario prever la ejecucin.
Ejemplo:
<div id="post">
</div>
<?php echo $ajax->link(
'Delete Post',
array( 'controller' => 'posts', 'action' => 'delete', 1 ),
array( 'update' => 'post' ),
'Do you want to delete this post?'
);
?>

7.1.2.2 remoteFunction

remoteFunction(array $options);
Esta funcion crea el codigo JavaScript necesario para hacer una llamada remota. Es usado
principalmente como un helper(ayudante) para los enlaces(link). Esto no se utiliza muy a menudo a
menos que usted necesite generar algunos codigos personalizados.
The $options for this function are the same as for the link method
Example:
<div id="post">
</div>
<script type="text/javascript">
<?php echo $ajax->remoteFunction(
array(
'url' => array( 'controller' => 'posts', 'action' => 'view', 1 ),
'update' => 'post'
)
); ?>
</script>

It can also be assigned to HTML Event Attributes:


<?php
$remoteFunction = $ajax->remoteFunction(
array(
'url' => array( 'controller' => 'posts', 'action' => 'view', 1 ),
'update' => 'post' )
);
?>
<div id="post" onmouseover="<?php echo $remoteFunction; ?>" >
Mouse Over This
</div>

If $options['update'] is not passed, the browser will ignore the server response.

7.1.2.3 remoteTimer

remoteTimer(array $options)
Periodically calls the action at $options['url'], every $options['frequency']
seconds. Usually used to update a specific div (specified by $options['update']) with the result
of the remote call. Callbacks can be used.
remoteTimer

is

the

same

as

the

remoteFunction

except

for

the

extra

$options['frequency']
Example:
<div id="post">
</div>
<?php
echo $ajax->remoteTimer(
array(
'url' => array( 'controller' => 'posts', 'action' => 'view', 1 ),
'update' => 'post', 'complete' => 'alert( "request completed" )',
'position' => 'bottom', 'frequency' => 5
)
);
?>

The default $options['frequency'] is 10 seconds


7.1.2.4 form

form(string $action, string $type, array $options)


Returns a form tag that submits to $action using XMLHttpRequest instead of a normal HTTP
request via $type ('post' or 'get'). Otherwise, form submission will behave exactly like normal: data
submitted is available at $this->data inside your controllers. If $options['update'] is specified, it will be
updated with the resulting document. Callbacks can be used.
The options array should include the model name e.g. Plain Text View
$ajax->form('edit','post',array('model'=>'User','update'=>'UserInfoDiv'));

Alternatively, if you need to cross post to another controller from your form:
$ajax->form(array('type' => 'post',
'options' => array(
'model'=>'User',
'update'=>'UserInfoDiv',
'url' => array(
'controller' => 'comments',
'action' => 'edit'
)
)
));

You should not use the $ajax->form() and $ajax->submit() in the same form. If you
want the form validation to work properly use the $ajax->submit() method as shown below.
7.1.2.5 submit

submit(string $title, array $options)


Returns a submit button that submits the form to $options['url'] and updates the div
specified in $options['update']
<div id='testdiv'>
<?php
echo $form->create('User');
echo $form->input('email');
echo $form->input('name');
echo

$ajax->submit('Submit',

array('url'=>

array('controller'=>'users',

'action'=>'add'), 'update' => 'testdiv'));


echo $form->end();
?>
</div>

Use the $ajax->submit() method if you want form validation to work properly. i.e. You want the
messages you specify in your validation rules to show up correctly.

7.1.2.6 observeField

observeField(string $fieldId, array $options)


Observa el campo con el id DOM especificado por $field_id (cada $options['frequency'] segundos ) y
realiza un XMLHttpRequest si su contenido ha cambiado.
<?php echo $form->create( 'Post' ); ?>
<?php $titles = array( 1 => 'Tom', 2 => 'Dick', 3 => 'Harry' ); ?>
<?php echo $form->input( 'title', array( 'options' => $titles ) ) ?>
</form>
<?php
echo $ajax->observeField( 'PostTitle',
array(
'url' => array( 'action' => 'edit' ),
'frequency' => 0.2,
)
);
?>

observeField utiliza las mismas opciones que link


El campo a enviar puede ser asignado utilizando $options['with']. Por defecto este
contiene Form.Element.serialize('$fieldId'). Los datos enviados estn disponibles en
$this->data de tu controlador. Los Callbacks pueden ser utilizados con esta funcin.
Para enviar un formulario completo cuando el contenido cambie utilice $options['with']
= Form.serialize( $('Form ID') )
7.1.2.7 observeForm

observeForm(string $form_id, array $options)


Similar to observeField(), but operates on an entire form identified by the DOM id $form_id.
The supplied $options are the same as observeField(), except the default value of the $options['with']
option evaluates to the serialized (request string) value of the form.

7.1.2.8 autoComplete

autoComplete(string $fieldId, string $url, array $options)


Renders a text field with $fieldId with autocomplete. The remote action at $url should return a
suitable list of autocomplete terms. Often an unordered list is used for this. First, you need to set up a
controller action that fetches and organizes the data you'll need for your list, based on user input:
function autoComplete() {
//Partial strings will come from the autocomplete field as
//$this->data['Post']['subject']
$this->set('posts', $this->Post->find('all', array(
'conditions' => array(
'Post.subject LIKE' => $this->data['Post']
['subject'].'%'
),
'fields' => array('subject')
)));
$this->layout = 'ajax';
}

Next, create app/views/posts/auto_complete.ctp that uses that data and creates an


unordered list in (X)HTML:
<ul>
<?php foreach($posts as $post): ?>
<li><?php echo $post['Post']['subject']; ?></li>
<?php endforeach; ?>
</ul>

Finally, utilize autoComplete() in a view to create your auto-completing form field:


<?php echo $form->create('User', array('url' => '/users/index')); ?>
<?php echo $ajax->autoComplete('Post.subject', '/posts/autoComplete')?>
<?php echo $form->end('View Post')?>

Once you've got the autoComplete() call working correctly, use CSS to style the auto-complete
suggestion box. You might end up using something similar to the following:
div.auto_complete
{
position
:absolute;
width
:250px;
background-color :white;
border
:1px solid #888;
margin
:0px;
padding
:0px;
}
li.selected
{ background-color: #ffb; }

7.1.2.9 isAjax

isAjax()
Allows you to check if the current request is a Prototype Ajax request inside a view. Returns a
boolean. Can be used for presentational logic to show/hide blocks of content.
7.1.2.10 drag & drop

drag(string $id, array $options)


Makes a Draggable element out of the DOM element specified by $id. For more information on
the parameters accepted in $options see http://github.com/madrobby/scriptaculous/wikis/draggable.
Common options might include:
$options keys

Description
Sets whether the element should only be draggable by an embedded handle. The

$options['handle']

$options['revert']
$options['constraint']

value must be an element reference or element id or a string referencing a CSS


class value. The first child/grandchild/etc. element found within the element
that has this CSS class value will be used as the handle.
If set to true, the element returns to its original position when the drags ends.
Revert can also be an arbitrary function reference, called when the drag ends.
Constrains the drag to either 'horizontal' or 'vertical', leave blank for no

constraints.
drop(string $id, array $options)
Makes the DOM element specified by $id able to accept dropped elements. Additional
parameters

can

be

specified

with

$options.

For

more

information

see

http://github.com/madrobby/scriptaculous/wikis/droppables.
Common options might include:
$options keys

Description
Set to a string or javascript array of strings describing CSS classes that the

$options['accept']

droppable element will accept. The drop element will only accept elements of
the specified CSS classes.
The droppable element will only accept the dragged element if it is contained

$options['containment'] in the given elements (element ids). Can be a string or a javascript array of id
$options['overlap']

references.
If set to 'horizontal' or 'vertical', the droppable element will only react to a

draggable element if it is overlapping the droparea by more than 50% in the


given axis.
A javascript call back that is called when the dragged element is dropped on

$options['onDrop']

the droppable element.


dropRemote(string $id, array $options)
Makes a drop target that creates an XMLHttpRequest when a draggable element is dropped on
it. The $options array for this function are the same as those specified for drop() and link().
7.1.2.11 slider

slider(string $id, string $track_id, array $options)


Creates

directional

slider

control.

For

more

information

see

http://wiki.github.com/madrobby/scriptaculous/slider.
Common options might include:
$options keys
$options['axis']

Description
Sets the direction the slider will move in. 'horizontal' or 'vertical'. Defaults to
horizontal

$options['handleIma The id of the image that represents the handle. This is used to swap out the image
ge']

src with disabled image src when the slider is enabled. Used in conjunction with
handleDisabled.

$options['increment' Sets the relationship of pixels to values. Setting to 1 will make each pixel adjust
]

the slider value by one.

$options['handleDis The id of the image that represents the disabled handle. This is used to change the
abled']

image src when the slider is disabled. Used in conjunction handleImage.

$options['change'] JavaScript callback fired when the slider has finished moving, or has its value
$options['onChange' changed. The callback function receives the slider's current value as a parameter.
]
$options['slide']

JavaScript callback that is called whenever the slider is moved by dragging. It

$options['onSlide'] receives the slider's current value as a parameter.

7.1.2.12 editor

editor(string $id, string $url, array $options)


Creates an in-place editor at DOM id. The supplied $url should be an action that is
responsible

for

saving

element

data.

For

more

information

and

demos

see

http://github.com/madrobby/scriptaculous/wikis/ajax-inplaceeditor.
Common options might include:
$options keys
$options['collection']

Description
Activate the 'collection' mode of in-place editing.
$options['collection'] takes an array which is turned into
options for the select. To learn more about collection see
http://github.com/madrobby/scriptaculous/wikis/ajaxinplacecollectioneditor.

$options['callback']

A function to execute before the request is sent to the


server. This can be used to format the information sent to
the server. The signature is function(form, value)

$options['okText']

Text of the submit button in edit mode

$options['cancelText']

The text of the link that cancels editing

$options['savingText']

The text shown while the text is sent to the server

$options['formId']
$options['externalControl']
$options['rows']

The row height of the input field

$options['cols']

The number of columns the text area should span

$options['size']

Synonym for cols when using single-line

$options['highlightcolor']

The highlight color

$options['highlightendcolor'] The color which the highlight fades to


$options['savingClassName']
$options['formClassName']

$options['loadingText']
$options['loadTextURL']
Example
<div id="in_place_editor_id">Text To Edit</div>
<?php
echo $ajax->editor(
"in_place_editor_id",
array(
'controller' => 'Posts',
'action' => 'update_title',
$id
),
array()
);
?>

7.1.2.13 sortable

sortable(string $id, array $options)


Makes a list or group of floated objects contained by $id sortable. The options array supports a
number

of

parameters.

To

find

out

more

about

sortable

see

http://wiki.github.com/madrobby/scriptaculous/sortable.
Common options might include:
$options keys
$options['tag']

Description
Indicates what kind of child elements of the container will be made sortable.
Defaults to 'li'.

$options['only']

Allows for further filtering of child elements. Accepts a CSS class.

$options['overlap']

Either 'vertical' or 'horizontal'. Defaults to vertical.

$options['constraint']

Restrict the movement of the draggable elements. accepts 'horizontal' or


'vertical'. Defaults to vertical.

$options['handle']

Makes the created Draggables use handles, see the handle option on
Draggables.

$options['onUpdate']

Called when the drag ends and the Sortable's order is changed in any way.
When dragging from one Sortable to another, the callback is called once on

each Sortable.
$options['hoverclass'] Give the created droppable a hoverclass.
$options['ghosting']

If set to true, dragged elements of the sortable will be cloned and appear as a
ghost, instead of directly manipulating the original element.

7.2 Cache
El helper Cache permite almacenar temporalmente (caching) layouts y vistas completas,
ahorrando tiempo en descargar y retornar algunos datos. El caching de vistas en CakePHP almacena
temporalmente los layouts y vistas utilizando el motor de almacenamiento seleccionado. Es importante
notar que el helper de Cache opera de manera diferente a otros helpers. No tiene metodos que se
puedan llamar directamente. En vez de eso, una vista es marcada con tags, que permiten decirle cuales
bloques no deben ser cacheados.
Cuando una URL es requerida, CakePHP verifica si aquel requerimiento esta cacheado.Si lo
est, el resto del proceso es saltado. Cualquier bloque no cacheado se procesa normalmente y la vista es
entregada. Esto crea grandes ahorros en tiempos de proceso para cada requerimiento para una URL
cacheada, asi tambien menos cdigo es ejecutado. Si CakePHP no encuentra una vista cacheada, o el
cache ha expirado para la URL requerida, se contina normalmente con el requerimiento.
7.2.1 Generalidades en Caching
El caching tiene como intencin ser un medio de almacenamiento temporal que reduce la carga
del servidor. Por ejemplo podras almacenar el resultado de una consulta que requiere mucho tiempo de
modo de no realizarla nuevamente en cada actualizacin de la pgina.
El Caching no debe utilizarze nunca para almacenar datos en forma permanente. Solo debes
cachear elementos que puedan ser eventualmente regenerados si es necesario.
7.2.2 Motores de Cache en Cake
Lo nuevo en la version 1.2 de CakePHP son varios motores de cache. El helper de cache
interactua transparentemente con estos motores, permitiendo almacenar vistas en multiples formas sin
preocuparse de las caracteristicas especificas del medio de almacenamiento. La eleccin del motor de
cache es controlada a traves del archivo app/config/core.php config. Muchas opciones para cada motor

de cache son listados en el archivo de configuracion core.php, mas detalles acerca de cada motor se
puede encontrar en la seccion de Caching.
El File Engine es el motor por defecto en CakePHP. Escribe archivos planos en el sistema
File

de archivos y cuenta con numerosos parmetros, pero funciona bien con los valores por
defecto.
EL motor APC implementa el mtodo Alternative PHP Cache. Asi como XCache, este

APC
XCache

motor almacena codigo ya compilado de PHP.


El motor XCache opera en forma similar al APC, pero implementanto el mtodo XCache.
Requiere la autenticacion de usuarios para funcionar apropiadamente.
El motor Memcache funciona utilizando un servidor de almacenamiento en memoria, lo

Memcache que permite crear objetos cache en la memoria del sistema. Mas informacion acerca de
este mtodo puede ser encontrada en php.net y memcached

7.2.3 Configuracion del Cache Helper


El caching de vistas y el helper de cache tienen varioes elementos de configuracin importantes.
Estos se detallan ms abajo.
Para usar el cache helper en cualquier vista o controlador, debes primero configurar
Configure::Cache.check a true en la linea 80 de core.php. Si no se configura a true, entonces el
cache no sera verificado o creado.
7.2.4 Caching en los Controllers
Cualquier controlador que utilice la funcionalidad de caching necesita incluir el CacheHelper en
el arreglo $helpers.
var $helpers = array('Cache');

Necesitas ademas indicar cuales acciones necesitan caching, y cuanto tiempo durar cacheada
cada accin. Esto se hace a traves de la variable $cacheAction en tus controladores. $cacheAction
debera ser configurada como un arreglo el cual contiene las acciones a ser cacheadas y la duracion en
segundos que deben permanecer en tal condicion. EL tiempo puede expresarse en formato strtotime().
(ie. "1 hour", o "3 minutes").
Usando como ejemplo ArticlesController, que recibe un gran trfico que necesita cachearse.

Por ejemplo, cachear los articulos visitados frecuentemente por diversos periodos de tiempo
var $cacheAction = array(
'view/23/' => 21600,
'view/48/' => 36000,
'view/52'

=> 48000

);

Hacer caching de una accin completa en este caso un listado de articulos


var $cacheAction = array(
'archives/' => '60000'
);

Cachear todas las acciones del controlador usando un formato amigable strtotime() para indicar
el tiempo de cacheo.
var $cacheAction = "1 hour";

7.2.5 Marking Non-Cached Content in Views


There will be times when you don't want an entire view cached. For example, certain parts of
the page may look different whether a user is currently logged in or browsing your site as a guest.
To indicate blocks of content that are not to be cached, wrap them in <cake:nocache>
</cake:nocache> like so:
<cake:nocache>
<?php if ($session->check('User.name')) : ?>
Welcome, <?php echo $session->read('User.name')?>.
<?php else: ?>
<?php echo $html->link('Login', 'users/login')?>
<?php endif; ?>
</cake:nocache>

It should be noted that once an action is cached, the controller method for the action will not be
called - otherwise what would be the point of caching the page. Therefore, it is not possible to wrap
<cake:nocache> </cake:nocache> around variables which are set from the controller as they
will be null.

7.2.6 Clearing the Cache


It is important to remember that the Cake will clear a cached view if a model used in the cached
view is modified. For example, if a cached view uses data from the Post model, and there has been an
INSERT, UPDATE, or DELETE query made to a Post, the cache for that view is cleared, and new
content is generated on the next request.
If you need to manually clear the cache, you can do so by calling Cache::clear(). This will clear
all cached data, excluding cached view files. If you need to clear the cached view files, use
clearCache().

7.3 Formularios
El FormHelper es una nueva adicin a CakePHP. La mayor parte del trabajo de creacin de
formularios recae sobre el uso de esta nueva clase, en lugar de los (ahora obsoletos) mtodos del
HtmlHelper. El FormHelper se centra en la creacin de formularios rpidamente, de esta manera agiliza
la validacin, el precargado y el diseo de la interfaz. El FormHelper es bastante flexible - este har
casi todo automticamente por usted, o si lo desea puede usar mtodos especficos para hacer solo lo
que necesite.
7.3.1 Creando Formularios
El primer mtodo que necesitars para poder aprovecha el FormHelper es create(). Este
mtodo se encarga de escribir la etiqueta de apertura del formulario.
create(string $modelo = null, array $opciones = array())
Todos los parmetros son opcionales. Si create() es llamado sin parmetros, asume que
ests construyendo un formulario que ser enviado al controlador actual, ya sea va la accin add() o
edit(). El mtodo por omisin para el envo es POST. El elemento form es regresado con un ID
DOM. El ID es generado usando el nombre del modelo y el nombre de la accin del controlador en
formato CamelCased. Si fuera a llamar create() dentro de una vista de UsersController, vera algo
como lo siguiente en la vista
<form id="UserAddForm" method="post" action="/users/add">

Puedes tambin pasar false para el parmetro $modelo. Esto pondr los datos de tu
formulario en el array: $this->data (en lugar de ponerlos en en sub-array: $this-

>data['Model']). Esto puede ser muy til para formularios cortos que quiz no representen nada
en tu base de datos.
The create() method allows us to customize much more using the parameters, however.
First, you can specify a model name. By specifying a model for a form, you are creating that form's
context. All fields are assumed to belong to this model (unless otherwise specified), and all models
referenced are assumed to be associated with it. If you do not specify a model, then it assumes you are
using the default model for the current controller.
<?php echo $form->create('Recipe'); ?>
//Output:
<form id="RecipeAddForm" method="post" action="/recipes/add">

This will POST the form data to the add() action of RecipesController. However, you can also
use the same logic to create an edit form. The FormHelper uses the $this->data property to
automatically detect whether to create an add or edit form. If $this->data contains an array
element named after the form's model, and that array contains a non-empty value of the model's
primary key, then the FormHelper will create an edit form for that record. For example, if we browse to
http://site.com/recipes/edit/5, we might get the following:
// controllers/recipes_controller.php:
<?php
function edit($id = null) {
if (empty($this->data)) {
$this->data = $this->Recipe->findById($id);
} else {
// Save logic goes here
}
}
?>
// views/recipes/edit.ctp:
// Since $this->data['Recipe']['id'] = 5, we should get an edit form
<?php echo $form->create('Recipe'); ?>
//Output:
<form id="RecipeEditForm" method="post" action="/recipes/edit/5">
<input type="hidden" name="_method" value="PUT" />

Since this is an edit form, a hidden input field is generated to override the default HTTP method.
The $options array is where most of the form configuration happens. This special array can
contain a number of different key-value pairs that affect the way the form tag is generated.

7.3.1.1 $options[type]

This key is used to specify the type of form to be created. Valid values include post, get,
file, put and delete.
Supplying either post or get changes the form submission method accordingly.
<?php echo $this->Form->create('User', array('type' => 'get')); ?>
//Output:
<form id="UserAddForm" method="get" action="/users/add">

Specifying file changes the form submission method to post, and includes an enctype of
multipart/form-data on the form tag. This is to be used if there are any file elements inside the form.
The absence of the proper enctype attribute will cause the file uploads not to function.
<?php echo $this->Form->create('User', array('type' => 'file')); ?>
//Output:
<form

id="UserAddForm"

enctype="multipart/form-data"

method="post"

action="/users/add">

When using put or delete, your form will be functionally equivalent to a 'post' form, but
when submitted, the HTTP request method will be overridden with 'PUT' or 'DELETE', respectively.
This allows CakePHP to emulate proper REST support in web browsers.
7.3.1.2 $options[action]

The action key allows you to point the form to a specific action in your current controller. For example,
if youd like to point the form to the login() action of the current controller, you would supply an
$options array like the following:
<?php echo $this->Form->create('User', array('action' => 'login')); ?>
//Output:
<form id="UserLoginForm" method="post" action="/users/login">
</form>

7.3.1.3 $options[url]

If the desired form action isnt in the current controller, you can specify a URL for the form
action using the url key of the $options array. The supplied URL can be relative to your CakePHP
application, or can point to an external domain.
<?php echo $this->Form->create(null, array('url' => '/recipes/add')); ?>
// or
<?php

echo

$this->Form->create(null,

array('url'

=>

array('controller'

=>

'recipes', 'action' => 'add'))); ?>


//Output:
<form method="post" action="/recipes/add">
<?php echo $this->Form->create(null, array(
'url' => 'http://www.google.com/search',
'type' => 'get'
)); ?>
//Output:
<form method="get" action="http://www.google.com/search">

Also check HtmlHelper::url method for more examples of different types of urls.
7.3.1.4 $options[default]

If default has been set to boolean false, the forms submit action is changed so that pressing
the submit button does not submit the form. If the form is meant to be submitted via AJAX, setting
default to false suppresses the forms default behavior so you can grab the data and submit it via
AJAX instead.
7.3.1.5 7.3.1.5 $options['inputDefaults']

You can declare a set of default options for input() with the inputDefaults key to
customize your default input creation.
echo $this->Form->create('User', array(
'inputDefaults' => array(
'label' => false,
'div' => false
)
));

All inputs created from that point forward would inherit the options declared in inputDefaults.
You can override the defaultOptions by declaring the option in the input() call.
echo $this->Form->input('password'); // No div, no label
echo $this->Form->input('username', array('label' => 'Username')); // has a label
element

7.3.2 Closing the Form


El FormHelper tambien incluye un mtodo end() que completa el cdigo del formulario. A
menudo, el mtodo end() solo escribe la etiqueta de cierre del formulario, pero el usar end() tambin
hace que el FormHelper inserte los elementos hidden necesarios en el formulario para los mtodos que
dependen de este.
<?php echo $form->create(); ?>
<!-- Form elements go here -->
<?php echo $form->end(); ?>

Si una cadena es colocada como primer parmetro del end(), el FormHelper agregar un boton
submit llamado de esa manera adems de la etiqueta de cierre del formulario.
<?php echo $form->end('Finish'); ?>
Output:
<div class="submit">
<input type="submit" value="Finish" />
</div>
</form>

7.3.3 Automagic Form Elementos


Primero, demos una mirada a algunos de los mtodos de crecin ms automticos en el
FormHelper. El Mtodo principal que veremos es input(). Este mtodo automaticamente inspecciona el
modelo del campo que ha sido proporcionado a fin de crear un elemento de entrada apropiado para ese
campo.

input(string $fieldName, array $options = array())


Column Type
Resulting Form Field
string (char, varchar, etc.)
text
boolean, tinyint(1)
checkbox
text
textarea
text, with name of password, passwd, or psword password
date
day, month, and year selects
datetime, timestamp
day, month, year, hour, minute, and meridian selects
time
hour, minute, and meridian selects
For example, lets assume that my User model includes fields for a username (varchar),
password (varchar), approved (datetime) and quote (text). I can use the input() method of the
FormHelper to create appropriate inputs for all of these form fields.
<?php echo $form->create(); ?>
<?php
echo $form->input('username');

//text

echo $form->input('password');

//password

echo $form->input('approved');

//day, month, year, hour, minute, meridian

echo $form->input('quote');

//textarea

?>
<?php echo $form->end('Add'); ?>

A more extensive example showing some options for a date field:


echo $form->input('birth_dt', array( 'label' => 'Date of birth'
, 'dateFormat' => 'DMY'
, 'minYear' => date('Y') - 70
, 'maxYear' => date('Y') - 18 )
);

Besides the specific input options found below you can specify any html attribute (for instance
onfocus). For more information on $options and $htmlAttributes see HTML Helper.
And to round off, here's an example for creating a hasAndBelongsToMany select. Assume that
User hasAndBelongsToMany Group. In your controller, set a camelCase plural variable (group ->
groups in this case, or ExtraFunkyModel -> extraFunkyModels) with the select options. In the
controller action you would put the following:
$this->set('groups', $this->User->Group->find('list'));

And in the view a multiple select can be expected with this simple code:
echo $form->input('Group');

If you want to create a select field while using a belongsTo- or hasOne-Relation, you can add
the following to your Users-controller (assuming your User belongsTo Group):
$this->set('groups', $this->User->Group->find('list'));

Afterwards, add the following to your form-view:


echo $form->input('group_id');

If your model name consists of two or more words, e.g., "UserGroup", when passing the data
using set() you should name your data in a pluralised and camelCased format as follows:
$this->set('userGroups', $this->UserGroup->find('list'));
// or
$this->set('reallyInappropriateModelNames',
$this->ReallyInappropriateModelName>find('list'));

7.3.3.1 Field naming convention

The Form helper is pretty smart. Whenever you specify a field name with the form helper
methods, it'll automatically use the current model name to build an input with a format like the
following:
<input type="text" id="ModelnameFieldname" name="data[Modelname][fieldname]">

You can manually specify the model name by passing in Modelname.fieldname as the first
parameter.
echo $this->Form->input('Modelname.fieldname');

If you need to specify multiple fields using the same field name, thus creating an array that can
be saved in one shot with saveAll(), use the following convention:
<?php
echo $this->Form->input('Modelname.0.fieldname');
echo $this->Form->input('Modelname.1.fieldname');
?>
<input type="text" id="Modelname0Fieldname" name="data[Modelname][0][fieldname]">
<input type="text" id="Modelname1Fieldname" name="data[Modelname][1][fieldname]">

7.3.3.2 $options[type]

You can force the type of an input (and override model introspection) by specifying a type. In
addition to the field types found in the table above, you can also create file, and password inputs.
<?php echo $this->Form->input('field', array('type' => 'file')); ?>
Output:
<div class="input">
<label for="UserField">Field</label>
<input type="file" name="data[User][field]" value="" id="UserField" />
</div>

7.3.3.3 $options[before], $options[between], $options[separator] and $options[after]

Use these keys if you need to inject some markup inside the output of the input() method.
<?php echo $this->Form->input('field', array(
'before' => '--before--',
'after' => '--after--',
'between' => '--between---'
));?>
Output:
<div class="input">
--before-<label for="UserField">Field</label>
--between--<input name="data[User][field]" type="text" value="" id="UserField" />
--after-</div>

For radio type input the 'separator' attribute can be used to inject markup to separate each
input/label pair.
<?php echo $this->Form->input('field', array(
'before' => '--before--',
'after' => '--after--',
'between' => '--between---',

'separator' => '--separator--',


'options' => array('1', '2')
));?>
Output:
<div class="input">
--before-<input name="data[User][field]" type="radio" value="1" id="UserField1" />
<label for="UserField1">1</label>
--separator-<input name="data[User][field]" type="radio" value="2" id="UserField2" />
<label for="UserField2">2</label>
--between----after-</div>

For date and datetime type elements the 'separator' attribute can be used to change the
string between select elements. Defaults to '-'.
7.3.3.4 $options[options]

This key allows you to manually specify options for a select input, or for a radio group. Unless
the type is specified as radio, the FormHelper will assume that the target output is a select input.
<?php echo $this->Form->input('field', array('options' => array(1,2,3,4,5))); ?>

Output:
<div class="input">
<label for="UserField">Field</label>
<select name="data[User][field]" id="UserField">
<option value="0">1</option>
<option value="1">2</option>
<option value="2">3</option>
<option value="3">4</option>
<option value="4">5</option>
</select>
</div>

Options can also be supplied as key-value pairs.


<?php echo $this->Form->input('field', array('options' => array(
'Value 1'=>'Label 1',
'Value 2'=>'Label 2',
'Value 3'=>'Label 3'
))); ?>

Output:
<div class="input">
<label for="UserField">Field</label>
<select name="data[User][field]" id="UserField">
<option value="Value 1">Label 1</option>
<option value="Value 2">Label 2</option>
<option value="Value 3">Label 3</option>
</select>
</div>

If you would like to generate a select with optgroups, just pass data in hierarchical format. Works on
multiple checkboxes and radio buttons too, but instead of optgroups wraps elements in fieldsets.
<?php echo $this->Form->input('field', array('options' => array(
'Label1' => array(
'Value 1'=>'Label 1',
'Value 2'=>'Label 2'
),
'Label2' => array(
'Value 3'=>'Label 3'
)
))); ?>

Output:
<div class="input">
<label for="UserField">Field</label>
<select name="data[User][field]" id="UserField">
<optgroup label="Label1">
<option value="Value 1">Label 1</option>
<option value="Value 2">Label 2</option>
</optgroup>
<optgroup label="Label2">
<option value="Value 3">Label 3</option>
</optgroup>
</select>
</div>

7.3.3.5 $options[multiple]

Si multiple es puesto a true para una entrada de tipo select, el select admitir multiples
selecciones. Alternativamente, poniendo multiple igual a checkbox la salida ser una lista de
checkboxes relacionados.
$form->input('Modelo.campo', array( 'type' => 'select', 'multiple' => true ));
$form->input('Modelo.campo', array( 'type' => 'select', 'multiple' => 'checkbox'
));

7.3.3.6 $options[maxLength]

Defines the maximum number of characters allowed in a text input.


7.3.3.7 $options[div]

Use this option to set attributes of the input's containing div. Using a string value will set the
div's class name. An array will set the div's attributes to those specified by the array's keys/values.
Alternatively, you can set this key to false to disable the output of the div.
Setting the class name:
echo $this->Form->input('User.name', array('div' => 'class_name'));

Output:
<div class="class_name">
<label for="UserName">Name</label>
<input name="data[User][name]" type="text" value="" id="UserName" />
</div>

Setting multiple attributes:


echo

$this->Form->input('User.name',

array('div'

=>

array('id'

=>

'mainDiv',

'title' => 'Div Title', 'style' => 'display:block')));

Output:
<div class="input text" id="mainDiv" title="Div Title" style="display:block">
<label for="UserName">Name</label>
<input name="data[User][name]" type="text" value="" id="UserName" />
</div>

Disabling div output:


<?php echo $this->Form->input('User.name', array('div' => false));?>

Output:
<label for="UserName">Name</label>
<input name="data[User][name]" type="text" value="" id="UserName" />

7.3.3.8 $options[label]

Set this key to the string you would like to be displayed within the label that usually
accompanies the input.
<?php echo $this->Form->input( 'User.name', array( 'label' => 'The User Alias' )
);?>

Output:
<div class="input">
<label for="UserName">The User Alias</label>
<input name="data[User][name]" type="text" value="" id="UserName" />
</div>

Alternatively, set this key to false to disable the output of the label.
<?php echo $this->Form->input( 'User.name', array( 'label' => false ) ); ?>

Output:
<div class="input">
<input name="data[User][name]" type="text" value="" id="UserName" />
</div>

Set this to an array to provide additional options for the label element. If you do this, you can
use a text key in the array to customize the label text.
<?php echo $this->Form->input( 'User.name', array( 'label' => array('class' =>
'thingy', 'text' => 'The User Alias') ) ); ?>

Output:
<div class="input">
<label for="UserName" class="thingy">The User Alias</label>
<input name="data[User][name]" type="text" value="" id="UserName" />
</div>

7.3.3.9 $options['legend']

Some inputs like radio buttons will be automatically wrapped in a fieldset with a legend title
derived from the fields name. The title can be overridden with this option. Setting this option to false
will completely eliminate the fieldset.
7.3.3.10 $options[id]

Set this key to force the value of the DOM id for the input.
7.3.3.11 $options['error']

Using this key allows you to override the default model error messages and can be used, for
example, to set i18n messages. It has a number of suboptions which control the wrapping element,
wrapping element class name, and whether HTML in the error message will be escaped.
To disable error message output set the error key to false.
$this->Form->input('Model.field', array('error' => false));

To modify the wrapping element type and its class, use the following format:
$this->Form->input('Model.field', array('error' => array('wrap' => 'span', 'class'
=> 'bzzz')));

To prevent HTML being automatically escaped in the error message output, set the escape suboption to
false:
$this->Form->input('Model.field', array('error' => array('escape' => false)));

To override the model error messages use an associate array with the keyname of the validation rule:
$this->Form->input('Model.field', array('error' => array('tooShort' => __('This is
not long enough', true) )));

As seen above you can set the error message for each validation rule you have in your models. In
addition you can provide i18n messages for your forms.

7.3.3.12 $options['default']

Used to set a default value for the input field. The value is used if the data passed to the form
does not contain a value for the field (or if no data is passed at all).
Example usage:
<?php
echo $this->Form->input('ingredient', array('default'=>'Sugar'));
?>

Example with select field (Size "Medium" will be selected as default):


<?php
$sizes = array('s'=>'Small', 'm'=>'Medium', 'l'=>'Large');
echo $this->Form->input('size', array('options'=>$sizes, 'default'=>'m'));
?>

You cannot use default to check a checkbox - instead you might set the value in $this>data in your controller, $this->Form->data in your view, or set the input option checked to
true.
Date and datetime fields' default values can be set by using the 'selected' key.
7.3.3.13 $options[selected]

Used in combination with a select-type input (i.e. For types select, date, time, datetime). Set
selected to the value of the item you wish to be selected by default when the input is rendered.
echo

$this->Form->input('close_time',

array('type'

=>

'time',

'selected'

'13:30:00'));

The selected key for date and datetime inputs may also be a UNIX timestamp.
7.3.3.14 $options[rows], $options[cols]

These two keys specify the number of rows and columns in a textarea input.
echo $this->Form->input('textarea', array('rows' => '5', 'cols' => '5'));

Output:
<div class="input text">
<label for="FormTextarea">Textarea</label>

=>

<textarea name="data[Form][textarea]" cols="5" rows="5" id="FormTextarea" >


</textarea>
</div>

7.3.3.15 $options[empty]

If set to true, forces the input to remain empty.


When passed to a select list, this creates a blank option with an empty value in your drop down
list. If you want to have a empty value with text displayed instead of just a blank option, pass in a string
to empty.
<?php

echo

$this->Form->input('field',

array('options'

=>

array(1,2,3,4,5),

'empty' => '(choose one)')); ?>

Output:
<div class="input">
<label for="UserField">Field</label>
<select name="data[User][field]" id="UserField">
<option value="">(choose one)</option>
<option value="0">1</option>
<option value="1">2</option>
<option value="2">3</option>
<option value="3">4</option>
<option value="4">5</option>
</select>
</div>

If you need to set the default value in a password field to blank, use 'value' => '' instead.
Options can also supplied as key-value pairs.
7.3.3.16 $options[timeFormat]

Used to specify the format of the select inputs for a time-related set of inputs. Valid values
include 12, 24, and none.

7.3.3.17 $options[dateFormat]

Used to specify the format of the select inputs for a date-related set of inputs. Valid values
include DMY, MDY, YMD, and NONE.
7.3.3.18 $options['minYear'], $options['maxYear']

Used in combination with a date/datetime input. Defines the lower and/or upper end of values
shown in the years select field.
7.3.3.19 $options['interval']

This option specifies the number of minutes between each option in the minutes select box.
<?php
echo $this->Form->input('Model.time', array('type' => 'time', 'interval' => 15));
?>

Would create 4 options in the minute select. One for each 15 minutes.
7.3.3.20 $options['class']

You can set the classname for an input field using $options['class']
echo $this->Form->input('title', array('class' => 'custom-class'));

7.3.4 File Fields


To add a file upload field to a form, you must first make sure that the form enctype is set to
"multipart/form-data", so start off with a create function such as the following.
echo $this->Form->create('Document', array('enctype' => 'multipart/form-data') );
// OR
echo $this->Form->create('Document', array('type' => 'file'));

Next add either of the two lines to your form view file.
echo $this->Form->input('Document.submittedfile', array('between'=>'<br
/>','type'=>'file'));
// or
echo $this->Form->file('Document.submittedfile');

Due to the limitations of HTML itself, it is not possible to put default values into input fields of
type 'file'. Each time the form is displayed, the value inside will be empty.
Upon submission, file fields provide an expanded data array to the script receiving the form
data.
For the example above, the values in the submitted data array would be organized as follows, if
the CakePHP was installed on a Windows server. 'tmp_name' will have a different path in a Unix
environment.
$this->data['Document']['submittedfile'] = array(
'name' => conference_schedule.pdf
'type' => application/pdf
'tmp_name' => C:/WINDOWS/TEMP/php1EE.tmp
'error' => 0
'size' => 41737
);

This array is generated by PHP itself, so for more detail on the way PHP handles data passed via
file fields read the PHP manual section on file uploads.
7.3.4.1 Validating Uploads

Below is an example validation method you could define in your model to validate whether a
file has been successfully uploaded.
//

Based

on

comment

from:

http://bakery.cakephp.org/articles/view/improved-

advance-validation-with-parameters
function isUploadedFile($params){
$val = array_shift($params);
if ((isset($val['error']) && $val['error'] == 0) ||
(!empty( $val['tmp_name']) && $val['tmp_name'] != 'none')) {
return is_uploaded_file($val['tmp_name']);
}
return false;
}

7.3.5 Form Element-Specific Methods


The rest of the methods available in the FormHelper are for creating specific form elements.
Many of these methods also make use of a special $options parameter. In this case, however, $options
is used primarily to specify HTML tag attributes (such as the value or DOM id of an element in the
form).
<?php echo $this->Form->text('username', array('class' => 'users')); ?>

Will output:
<input name="data[User][username]" type="text" class="users" id="UserUsername" />

7.3.5.1 checkbox

checkbox(string $fieldName, array $options)


Creates a checkbox form element. This method also generates an associated hidden form input
to force the submission of data for the specified field.
<?php echo $this->Form->checkbox('done'); ?>

Will output:
<input type="hidden" name="data[User][done]" value="0" id="UserDone_" />
<input type="checkbox" name="data[User][done]" value="1" id="UserDone" />

7.3.5.2 button

button(string $title, array $options = array())


Creates an HTML button with the specified title and a default type of "button". Setting
$options['type'] will output one of the three possible button types:
1. submit: Same as the $this->Form->submit method - (the default).
2. reset: Creates a form reset button.
3. button: Creates a standard push button.
<?php
echo $this->Form->button('A Button');
echo $this->Form->button('Another Button', array('type'=>'button'));
echo $this->Form->button('Reset the Form', array('type'=>'reset'));
echo $this->Form->button('Submit Form', array('type'=>'submit'));
?>

Will output:
<button type="submit">A Button</button>
<button type="button">Another Button</button>
<button type="reset">Reset the Form</button>
<button type="submit">Submit Form</button>

The button input type allows for a special $option attribute called 'escape' which accepts a
bool and determines whether to HTML entity encode the $title of the button. Defaults to false.
<?php
echo $this->Form->button('Submit Form', array('type'=>'submit','escape'=>true));
?>

7.3.5.3 year

year(string $fieldName, int $minYear,

int $maxYear, mixed $selected, array

$attributes)
Creates a select element populated with the years from $minYear to $maxYear, with the
$selected year selected by default. HTML attributes may be supplied in $attributes. If
$attributes['empty'] is false, the select will not include an empty option.
<?php
echo $this->Form->year('purchased',2000,date('Y'));
?>

Will output:
<select name="data[User][purchased][year]" id="UserPurchasedYear">
<option value=""></option>
<option value="2009">2009</option>
<option value="2008">2008</option>
<option value="2007">2007</option>
<option value="2006">2006</option>
<option value="2005">2005</option>
<option value="2004">2004</option>
<option value="2003">2003</option>
<option value="2002">2002</option>
<option value="2001">2001</option>
<option value="2000">2000</option>
</select>

7.3.5.4 month

month(string $fieldName, mixed $selected, array $attributes, boolean $showEmpty)


Creates a select element populated with month names.
<?php
echo $this->Form->month('mob');
?>

Will output:
<select name="data[User][mob][month]" id="UserMobMonth">
<option value=""></option>
<option value="01">January</option>
<option value="02">February</option>
<option value="03">March</option>
<option value="04">April</option>
<option value="05">May</option>
<option value="06">June</option>
<option value="07">July</option>
<option value="08">August</option>
<option value="09">September</option>
<option value="10">October</option>
<option value="11">November</option>
<option value="12">December</option>
</select>

You can pass in your own array of months to be used by setting the 'monthNames' attribute, or
have months displayed as numbers by passing false. (Note: the default months are internationalized and
can be translated using localization.)
<?php
echo $this->Form->month('mob', null, array('monthNames' => false));
?>

7.3.5.5 dateTime

dateTime($fieldName, $dateFormat = 'DMY', $timeFormat = '12', $selected = null,


$attributes = array())
Creates a set of select inputs for date and time. Valid values for $dateformat are DMY,
MDY, YMD or NONE. Valid values for $timeFormat are 12, 24, and null.
You can specify not to display empty values by setting "array('empty' => false)" in the attributes
parameter. You also can pre-select the current datetime by setting $selected = null and $attributes =
array("empty" => false).
7.3.5.6 day

day(string $fieldName, mixed $selected, array $attributes, boolean $showEmpty)


Creates a select element populated with the (numerical) days of the month.
To create an empty option with prompt text of your choosing (e.g. the first option is 'Day'), you
can supply the text as the final parameter as follows:
<?php
echo $this->Form->day('created');
?>

Will output:
<select name="data[User][created][day]" id="UserCreatedDay">
<option value=""></option>
<option value="01">1</option>
<option value="02">2</option>
<option value="03">3</option>
...
<option value="31">31</option>
</select>

7.3.5.7 hour

hour(string

$fieldName,

boolean

$format24Hours,

mixed

$selected,

array

$attributes, boolean $showEmpty)


Creates a select element populated with the hours of the day.
7.3.5.8 minute

minute(string $fieldName, mixed $selected, array $attributes, boolean $showEmpty)


Creates a select element populated with the minutes of the hour.
7.3.5.9 meridian

meridian(string

$fieldName,

mixed

$selected,

array

$attributes,

boolean

$showEmpty)
Creates a select element populated with am and pm.
7.3.5.10 error

error(string $fieldName, mixed $text, array $options)


Shows a validation error message, specified by $text, for the given field, in the event that a
validation error has occurred.
Options:
'escape' bool Whether or not to html escape the contents of the error.
'wrap' mixed Whether or not the error message should be wrapped in a div. If a string, will be
used as the HTML tag to use.
'class' string The classname for the error message
7.3.5.11 file

file(string $fieldName, array $options)


Creates a file input.
<?php
echo $this->Form->create('User',array('type'=>'file'));
echo $this->Form->file('avatar');
?>

Will output:
<form enctype="multipart/form-data" method="post" action="/users/add">
<input name="data[User][avatar]" value="" id="UserAvatar" type="file">

When using $this->Form->file(), remember to set the form encoding-type, by setting the type
option to 'file' in $this->Form->create()
7.3.5.12 hidden

hidden(string $fieldName, array $options)


Creates a hidden form input. Example:
<?php
echo $this->Form->hidden('id');
?>

Will output:
<input name="data[User][id]" value="10" id="UserId" type="hidden">

7.3.5.13 isFieldError

isFieldError(string $fieldName)
Returns true if the supplied $fieldName has an active validation error.
<?php
if ($this->Form->isFieldError('gender')){
echo $this->Form->error('gender');
}
?>

When using $this->Form->input(), errors are rendered by default.


7.3.5.14 label

label(string $fieldName, string $text, array $attributes)


Creates a label tag, populated with $text.
<?php
echo $this->Form->label('status');
?>

Will output:
<label for="UserStatus">Status</label>

7.3.5.15 password

password(string $fieldName, array $options)


Creates a password field.
<?php
echo $this->Form->password('password');
?>

Will output:
<input name="data[User][password]" value="" id="UserPassword" type="password">

7.3.5.16 radio

radio(string $fieldName, array $options, array $attributes)


Creates a radio button input. Use $attributes['value'] to set which value should be
selected default.
Use $attributes['separator'] to specify HTML in between radio buttons (e.g. <br />).
Radio

elements

are

wrapped

with

label

and

fieldset

by

default.

Set

$attributes['legend'] to false to remove them.


<?php
$options=array('M'=>'Male','F'=>'Female');
$attributes=array('legend'=>false);
echo $this->Form->radio('gender',$options,$attributes);
?>

Will output:
<input name="data[User][gender]" id="UserGender_" value="" type="hidden">
<input name="data[User][gender]" id="UserGenderM" value="M" type="radio">
<label for="UserGenderM">Male</label>
<input name="data[User][gender]" id="UserGenderF" value="F" type="radio">
<label for="UserGenderF">Female</label>

If for some reason you don't want the hidden input, setting $attributes['value'] to a
selected value or boolean false will do just that.

7.3.5.17 select

select(string $fieldName, array $options, mixed $selected, array $attributes)


Creates a select element, populated with the items in $options, with the option specified by
$selected shown as selected by default. If you wish to display your own default option, add your
string value to the 'empty' key in the $attributes variable, or set it to false to turn off the default
empty option
<?php
$options = array('M' => 'Male', 'F' => 'Female');
echo $this->Form->select('gender', $options)
?>

Will output:
<select name="data[User][gender]" id="UserGender">
<option value=""></option>
<option value="M">Male</option>
<option value="F">Female</option>
</select>

The select input type allows for a special $option attribute called 'escape' which
accepts a bool and determines whether to HTML entity encode the contents of the select options.
Defaults to true.
<?php
$options = array('M' => 'Male', 'F' => 'Female');
echo $this->Form->select('gender', $options, null, array('escape' => false));
?>

7.3.5.18 submit

submit(string $caption, array $options)


Creates a submit button with caption $caption. If the supplied $caption is a URL to an
image (it contains a . character), the submit button will be rendered as an image.
It is enclosed between div tags by default; you can avoid this by declaring $options['div'] =
false.
<?php
echo $this->Form->submit();
?>

Will output:
<div class="submit"><input value="Submit" type="submit"></div>

You can also pass a relative or absolute url to an image for the caption parameter instead of caption
text.
<?php
echo $this->Form->submit('ok.png');
?>

Will output:
<div class="submit"><input type="image" src="/img/ok.png"></div>

7.3.5.19 text

text(string $fieldName, array $options)


Creates a text input field.
<?php
echo $this->Form->text('first_name');
?>

Will output:
<input name="data[User][first_name]" value="" id="UserFirstName" type="text">

7.3.5.20 textarea

textarea(string $fieldName, array $options)


Creates a textarea input field.
<?php
echo $this->Form->textarea('notes');
?>

Will output:
<textarea name="data[User][notes]" id="UserNotes"></textarea>

The textarea input type allows for the $options attribute of 'escape' which
determines whether or not the contents of the textarea should be escaped. Defaults to true.
<?php
echo $this->Form->textarea('notes', array('escape' => false);
// OR....
echo $this->Form->input('notes', array('type' => 'textarea', 'escape' => false);
?>

7.3.6 1.3 improvements


The FormHelper is one of the most frequently used classes in CakePHP, and has had several
improvements made to it.
Entity depth limitations
In 1.2 there was a hard limit of 5 nested keys. This posed significant limitations on form input
creation in some contexts. In 1.3 you can now create infinitely nested form element keys. Validation
errors and value reading for arbitrary depths has also been added.
Model introspection
Support for adding 'required' classes, and properties like maxlength to hasMany and other
associations has been improved. In the past only 1 model and a limited set of associations would be
introspected. In 1.3 models are introspected as needed, providing validation and additional information
such as maxlength.
Default options for input()
In the past if you needed to use 'div' => false, or 'label' => false you would
need to set those options on each and every call to input(). Instead in 1.3 you can declare a set of
default options for input() with the inputDefaults key.
echo $this->Form->create('User', array(
'inputDefaults' => array(
'label' => false,
'div' => false
)
));

All inputs created from that point forward would inherit the options declared in inputDefaults.
You can override the defaultOptions by declaring the option in the input() call.
echo $this->Form->input('password'); // No div, no label
echo $this->Form->input('username', array('label' => 'Username')); // has a label
element

Omit attributes
You can now set any attribute key to null or false in an options/attributes array to omit that
attribute from a particular html tag.

echo $this->Form->input('username', array(


'div' => array('class' => false)
)); // Omits the 'class' attribute added by default to div tag

Accept-charset
Forms now get an accept-charset set automatically, it will match the value of App.encoding,
it can be overridden or removed using the 'encoding' option when calling create().
// To remove the accept-charset attribute.
echo $this->Form->create('User', array('encoding' => null));

Removed parameters
Many methods such as select, year, month, day, hour, minute, meridian and
datetime took a $showEmpty parameter, these have all been removed and rolled into the
$attributes parameter using the 'empty' key.
Default url
The default url for forms either was add or edit depending on whether or not a primary key
was detected in the data array. In 1.3 the default url will be the current action, making the forms submit
to the action you are currently on.
Disabling hidden inputs for radio and checkbox
The automatically generated hidden inputs for radio and checkbox inputs can be disabled by
setting the 'hiddenField' option to false.
button()
button() now creates button elements, these elements by default do not have html entity
encoding enabled. You can enable html escaping using the escape option. The former features of
FormHelper::button have been moved to FormHelper::submit.
submit()
Due to changes in button(), submit() can now generate reset, and other types of input
buttons. Use the type option to change the default type of button generated. In addition to creating all
types of buttons, submit() has before and after options that behave exactly like their
counterparts in input().

$options['format']
The HTML generated by the form helper is now more flexible than ever before. The $options
parameter to Form::input() now supports an array of strings describing the template you would like said
element to follow. It's just been recently added to SCM, and has a few bugs for non PHP 5.3 users, but
should be quite useful for all. The supported array keys are array('before', 'input',
'between', 'label', 'after', 'error').

7.4 HTML
El rol del HtmlHelper de CakePHP es hacer los tags referentes a HTML y sus opciones simples,
rpidas, y ms resistentes al cambio. Usando este ayudante pondremos ms luz sobre tu aplicacin, y
ms flexibilidad en cuanto a donde se encuentre en relacin al dominio principal.
El rol del HtmlHelper ha cambiado significativamente desde CakePHP 1.1. Los metodos
relacionados a Form ya no se usan y han sido movidos al nuevo FormHelper. Si tu estas buscando
ayuda para los formularios HTML, Revisa lo nuevo de FormHelper.
Antes de dar un vistaso a los metodos de HtmlHelper, vas a necesitar conocimientos sobre
configuracin y usos en las situaciones que te puede ayudar esta clase. En primer lugar, en un esfuerzo
para aliviar a aquellos que gustan de usar las etiquetas cortas (<?= ?>) o muchas llamadas a echo() en el
codigo de sus vistas todos los metodos del HtmlHelper son pasados por el metodo output(). Si tu deseas
activar automticamente la salida para generar HTML con el ayudante simplemente implementa
output() en tu AppHelper.
function output($cadena) {
echo $cadena;
}

Haciendo esto no necesitars agregar llamadas a echo en el codigo de tus vistas.


Muchos metodos HtmlHelper incluyen parametros $htmlAttributes, esto te permite hilvanar
cualquier atributo extra en tus tags. Aqu hay algunos ejemplos de como se usan los parmetros
$htmlAttributes
Atributos Deseados: <tag class="algunaClase" />
Arreglo de Parametros: array('class'=>'algunaClase')
Atributos Deseados: <tag name="foo" value="bar" />
Arreglo de Parametros:

array('name' => 'foo', 'value' => 'bar')

El HtmlHelper est disponible en todas las vistas de forma predeterminada. Si usted est
recibiendo un error que le informa que no est ah, es por lo general debido a su nombre que esta
faltando y puede configurarlo manualmente en la variable $helpers del controlador.
7.4.1 Inserting Well-Formatted elements
The most important task the HtmlHelper accomplishes is creating well formed markup. Don't be
afraid to use it often - you can cache views in CakePHP in order to save some CPU cycles when views
are being rendered and delivered. This section will cover some of the methods of the HtmlHelper and
how to use them.
7.4.1.1 charset

charset(string $charset=null)
Usada para crear metadatos que especificarn la codificacin de los caracteres del documento.
El valor por defecto es UTF-8.
<?php echo $html->charset(); ?>

Generar como salida:


<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

O sino tambien:
<?php echo $html->charset('ISO-8859-1'); ?>

Generar como salida:


<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />

7.4.1.2 css

css(mixed $path, string $rel = null, array $htmlAttributes = array(), boolean


$inline = true)
Crea un enlace a una o ms hojas de estilos CSS. Si $inline est en false, los tags de enlace son
agregados en la variable $scripts_for_layout, la cual puedes imprimir dentro del tag head del
documento.
Este mtodo de inclusin de CSS asume que el archivo CSS especificado est en el directorio

/app/webroot/css.
<?php echo $html->css('forms'); ?>

Har la salida:
<link rel="stylesheet" type="text/css" href="/es/css/forms.css" />

El primer parmetro puede ser un arreglo para incluir varios archivos.


<?php echo $html->css(array('forms','tables','menu')); ?>

Har la salida:
<link rel="stylesheet" type="text/css" href="/es/css/forms.css" />
<link rel="stylesheet" type="text/css" href="/es/css/tables.css" />
<link rel="stylesheet" type="text/css" href="/es/css/menu.css" />

7.4.1.3 meta

meta(string $type, string $url = null, array $attributes = array(), boolean $inline
= true)
Este mtodo es til para vincular a los recursos externos como los feeds RSS / Atom y favicons.
Como CSS (), puede especificar si desea o no que esta etiqueta a aparezca en la lnea o en la etiqueta de
la cabecera con el cuarto parmetro.
Si establece el atributo "type" usando el parmetro $htmlAttributes, CakePHP contiene algunos
atajos:
type
html
rss
atom
icon

valor traducido
text/html
application/rss+xml
application/atom+xml
image/x-icon

<?php echo $html->meta(


'favicon.ico',
'/favicon.ico',
array('type' => 'icon')
);?> //Salida (saltos de linea aadidos) </p>

<link
href="http://example.com/favicon.ico"
title="favicon.ico" type="image/x-icon"
rel="alternate"
/>
<?php echo $html->meta(
'Comments',
'/comments/index.rss',
array('type' => 'rss'));
?>
//Salida (saltos de linea aadidos)
<link
href="http://example.com/comments/index.rss"
title="Comments"
type="application/rss+xml"
rel="alternate"
/>

Este mtodo tambin puede utilizarse para agregar las etiquetas "meta" para las palabras claves
y las descripciones. Ejemplo:
<?php echo $html->meta(
'keywords',
'ingrese las palabas claves aqu'
);?>
//Salida <meta name="keywords" content="ingrese las palabas claves aqu"/>
//
<?php echo $html->meta(
'description',
'ingrese alguna descripcion meta aqu'
);?>
//Salida <meta name="description" content="ingrese alguna descripcion meta aqu"/>

Si deseas aadir una etiqueta meta personalizada en el primer parmetro se debe establecer una
matriz. Para una salida de la etiqueta "robots noindex" debe utilizar el siguiente cdigo:
echo $html->meta(array('name' => 'robots', 'content' => 'noindex'));

7.4.1.4 docType

docType(string $type = 'xhtml-strict')


Returns a (X)HTML doctype tag. Supply the doctype according to the following table:
type
html
html4-strict
html4-trans
html4-frame
xhtml-strict
xhtml-trans
xhtml-frame
xhtml11

translated value
text/html
HTML4 Strict
HTML4 Transitional
HTML4 Frameset
XHTML1 Strict
XHTML1 Transitional
XHTML1 Frameset
XHTML 1.1

<?php echo $this->Html->docType(); ?>


<!DOCTYPE

html

PUBLIC

"-//W3C//DTD

XHTML

1.0

Strict//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<?php echo $this->Html->docType('html4-trans'); ?>
<!DOCTYPE

HTML

PUBLIC

"-//W3C//DTD

HTML

4.01

Transitional//EN"

"http://www.w3.org/TR/html4/loose.dtd">

7.4.1.5 style

style(array $data, boolean $oneline = true)


Construye una definicin de estilo CSS basada en las claves y valores del vector pasado al
metodo. Especialmente util si tu archivo CSS es dinamico.
<?php echo $html->style(array(
'background'

=> '#633',

'border-bottom' => '1px solid #000',


'padding' => '10px'
)); ?>

Mostrara:
background:#633; border-bottom:1px solid #000; padding:10px;

7.4.1.6 image

image(string $path, array $htmlAttributes = array())


Crea una etiqueta de imagen, la ruta especificada ser relativa a /app/webroot/img/.
<?php echo $html->image('cake_logo.png', array('alt' => 'CakePHP'))?>

Mostrar:
<img src="/img/cake_logo.png" alt="CakePHP" />

Si desea crear un link asociado a la imagen especifique el link de destino usando la opcin url
option en $htmlAttributes.
<?php echo $html->image("recipes/6.jpg", array(
"alt" => "Bizcochos",
'url' => array('controller' => 'recipes', 'action' => 'view', 6)
)); ?>

Mostrar:
<a href="/es/recipes/view/6">
<img src="/img/recipes/6.jpg" alt="Bizcochos" />
</a>

7.4.1.7 link

link(string

$title,

mixed

$url

null,

array

$options

array(),

string

$confirmMessage = false)
General purpose method for creating HTML links. Use $options to specify attributes for the
element and whether or not the $title should be escaped.
<?php echo $this->Html->link('Enter', '/pages/home',
array('class'=>'button','target'=>'_blank')); ?>

Will output:
<a href="/es/pages/home" class="button" target="_blank">Enter</a>

Specify $confirmMessage to display a javascript confirm() dialog.

<?php echo $this->Html->link(


'Delete',
array('controller'=>'recipes', 'action'=>'delete', 6),
array(),
"Are you sure you wish to delete this recipe?"
);?>

Will output:
<a href="/es/recipes/delete/6" onclick="return confirm('Are you sure you wish to
delete this recipe?');">Delete</a>

Query strings can also be created with link().


<?php echo $this->Html->link('View image', array(
'controller' => 'images',
'action' => 'view',
1,
'?' => array( 'height' => 400, 'width' => 500))
);

Will output:
<a href="/es/images/view/1?height=400&width=500">View image</a>

HTML special characters in $title will be converted to HTML entities. To disable this
conversion, set the escape option to false in the $options array.
<?php
echo $this->Html->link(
$this->Html->image("recipes/6.jpg", array("alt" => "Brownies")),
"recipes/view/6",
array('escape'=>false)
);
?>

Will output:
<a href="/es/recipes/view/6">
<img src="/img/recipes/6.jpg" alt="Brownies" />
</a>

Also check HtmlHelper::url method for more examples of different types of urls.

7.4.1.8 tag

tag(string $tag, string $text, array $htmlAttributes)


Returns text wrapped in a specified tag. If no text is specified then only the opening <tag> is returned.
<?php echo $this->Html->tag('span', 'Hello World.', array('class' => 'welcome'));?
>
//Output
<span class="welcome">Hello World</span>
//No text specified.
<?php echo $this->Html->tag('span', null, array('class' => 'welcome'));?>
//Output
<span class="welcome">

7.4.1.9 div

div(string $class, string $text, array $options)


Used for creating div-wrapped sections of markup. The first parameter specifies a CSS class,
and the second is used to supply the text to be wrapped by div tags. If the last parameter has been set to
true, $text will be printed HTML-escaped.
If no text is specified, only an opening div tag is returned.
<?php echo $this->Html->div('error', 'Please enter your credit card number.');?>
//Output
<div class="error">Please enter your credit card number.</div>

7.4.1.10 para

para(string $class, string $text, array $htmlAttributes, boolean $escape = false)


Returns a text wrapped in a CSS-classed <p> tag. If no text is supplied, only a starting <p> tag
is returned.
<?php echo $this->Html->para(null, 'Hello World.');?>
//Output
<p>Hello World.</p>

7.4.1.11 script

script(mixed $url, mixed $options)


Creates link(s) to a javascript file. If key inline is set to false in $options, the link tags are
added to the $scripts_for_layout variable which you can print inside the head tag of the document.
Include a script file into the page. $options['inline'] controls whether or not a script
should be returned inline or added to $scripts_for_layout. $options['once'] controls, whether or
not you want to include this script once per request or more than once.
You can also use $options to set additional properties to the generated script tag. If an array of
script tags is used, the attributes will be applied to all of the generated script tags.
This method of javascript file inclusion assumes that the javascript file specified resides inside
the /app/webroot/js directory.
<?php echo $this->Html->script('scripts'); ?>

Will output:
<script type="text/javascript" href="/es/js/scripts.js"></script>

You can link to files with absolute paths as well to link files that are not in app/webroot/js
<?php echo $this->Html->script('/otherdir/script_file'); ?>

The first parameter can be an array to include multiple files.


<?php echo $this->Html->script(array('jquery','wysiwyg','scripts')); ?>

Will output:
<script type="text/javascript" href="/es/js/jquery.js"></script>
<script type="text/javascript" href="/es/js/wysiwyg.js"></script>
<script type="text/javascript" href="/es/js/scripts.js"></script>

7.4.1.12 scriptBlock

scriptBlock($code, $options = array())


Generate a code block containing $code set $options['inline'] to false to have the
script block appear in $scripts_for_layout. Also new is the ability to add attributes to script

tags. $this->html->scriptBlock('stuff', array('defer' => true)); will create


a script tag with defer="defer" attribute.
7.4.1.13 scriptStart

scriptStart($options = array())
Begin a buffering code block. This code block will capture all output between
scriptStart() and scriptEnd() and create an script tag. Options are the same as
scriptBlock()
7.4.1.14 scriptEnd

scriptEnd()
End a buffering script block, returns the generated script element or null if the script block was
opened with inline = false.
An example of using scriptStart() and scriptEnd() would be:
$this->Html->scriptStart(array('inline' => false));
echo $this->Js->alert('I am in the javascript');
$this->Html->scriptEnd();

7.4.1.15 tableHeaders

tableHeaders(array $names, array $trOptions = null, array $thOptions = null)


Crea una fila de encabezados de tabla para ser usados dentro de la etiqueta <table>.
<?php echo $html->tableHeaders(array('Fecha','Nombre','Activo'));?>
//Salida
<tr>
<th>Fecha</th>
<th>Nombre</th>
<th>Activo</th>
</tr>
<?php echo $html->tableHeaders(
array('Fecha','Nombre','Activo'),
array('class' => 'estado'),
array('class' => 'tabla_productos')
);?>

//Salida
<tr class="estado">
<th class="tabla_productos">Fecha</th>
<th class="tabla_productos">Nombre</th>
<th class="tabla_productos">Activo</th>
</tr>

7.4.1.16 tableCells

tableCells(array $data, array $oddTrOptions = null, array $evenTrOptions = null,


$useCount = false, $continueOddEven = true)
Creates table cells, in rows, assigning <tr> attributes differently for odd- and even-numbered
rows. Wrap a single table cell within an array() for specific <td>-attributes.
<?php echo $this->Html->tableCells(array(
array('Jul 7th, 2007', 'Best Brownies', 'Yes'),
array('Jun 21st, 2007', 'Smart Cookies', 'Yes'),
array('Aug 1st, 2006', 'Anti-Java Cake', 'No'),
));
?>
//Output
<tr><td>Jul 7th, 2007</td><td>Best Brownies</td><td>Yes</td></tr>
<tr><td>Jun 21st, 2007</td><td>Smart Cookies</td><td>Yes</td></tr>
<tr><td>Aug 1st, 2006</td><td>Anti-Java Cake</td><td>No</td></tr>
<?php echo $this->Html->tableCells(array(
array('Jul 7th, 2007', array('Best Brownies', array('class'=>'highlight')) ,
'Yes'),
array('Jun 21st, 2007', 'Smart Cookies', 'Yes'),
array('Aug 1st, 2006', 'Anti-Java Cake', array('No', array('id'=>'special'))),
));
?>
//Output
<tr><td>Jul

7th,

2007</td><td

class="highlight">Best

Brownies</td><td>Yes</td></tr>
<tr><td>Jun 21st, 2007</td><td>Smart Cookies</td><td>Yes</td></tr>
<tr><td>Aug 1st, 2006</td><td>Anti-Java Cake</td><td id="special">No</td></tr>

<?php echo $this->Html->tableCells(


array(
array('Red', 'Apple'),
array('Orange', 'Orange'),
array('Yellow', 'Banana'),
),
array('class' => 'darker')
);
?>
//Output
<tr class="darker"><td>Red</td><td>Apple</td></tr>
<tr><td>Orange</td><td>Orange</td></tr>
<tr class="darker"><td>Yellow</td><td>Banana</td></tr>

7.4.1.17 url

url(mixed $url = NULL, boolean $full = false)


Devuelve un URL que apunta a alguna combinacin de controlador y accin. Si $url est vaco
devuelve el valor de REQUEST_URI, en caso contrario genera el URL para la combinacin de
controlador y accin. Si $full es true, se antepondr el URL base del sitio al resultado.
<?php echo $html->url(array(
"controller" => "posts",
"action" => "view",
"bar"));?>
// Salida
/posts/view/bar

Enseguida ms ejemplos de uso:


URL con parmetros nombrados (named parameters)
<?php echo $html->url(array(
"controller" => "posts",
"action" => "view",
"foo" => "bar"));
?>
// Salida
/posts/view/foo:bar

URL con extensin


<?php echo $html->url(array(
"controller" => "posts",
"action" => "list",
"ext" => "rss"));
?>
// Salida
/posts/list.rss

URL (empezando con '/') con el URL completo del sitio agregado al inicio.
<?php echo $html->url('/posts', true); ?>
//Salida
http://www.example.com/posts

URL con parmetros GET y ancla nombrada (named anchor)


<?php echo $html->url(array(
"controller" => "posts",
"action" => "buscar",
"?" => array("foo" => "bar"),
"#" => "primero"));
?>
//Salida
/posts/buscar?foo=bar#primero

Por mas info ver el Router::url en el API.


7.4.2 Changing the tags output by HtmlHelper
The built in tag sets for HtmlHelper are XHTML compliant, however if you need to generate
HTML for HTML4 you will need to create and load a new tags config file containing the tags you'd
like to use. To change the tags used create app/config/tags.php containing:
$tags = array(
'metalink' => '<link href="%s"%s >',
'input' => '<input name="%s" %s >',
//...
);

You can then load this tag set by calling $html->loadConfig('tags');

7.5 Js
Since the beginning CakePHP's support for Javascript has been with Prototype/Scriptaculous.
While we still think these are an excellent Javascript library, the community has been asking for
support for other libraries. Rather than drop Prototype in favour of another Javascript library. We
created

an

Adapter

based

helper,

and

included

of

the

most

requested

libraries.

Prototype/Scriptaculous, Mootools/Mootools-more, and jQuery/jQuery UI. And while the API is not as
expansive as the previous AjaxHelper we feel that the adapter based solution allows for a more
extensible solution giving developers the power and flexibility they need to address their specific
application needs.
Javascript Engines form the backbone of the new JsHelper. A Javascript engine translates an
abstract Javascript element into concrete Javascript code specific to the Javascript library being used. In
addition they create an extensible system for others to use.
7.5.1 Using a specific Javascript engine
First of all download your preferred javascript library and place it in app/webroot/js
Then you must include the library in your page. To include it in all pages, add this line to the
<head>

section

of

app/views/layouts/default.ctp

(copy

this

file

from

cake/libs/view/layouts/default.ctp if you have not created your own).


echo $this->Html->script('jquery'); // Include jQuery library

Replace jquery with the name of your library file (.js will be added to the name).
By default scripts are cached, and you must explicitly print out the cache. To do this at the end
of each page, include this line just before the ending </body> tag
echo $this->Js->writeBuffer(); // Write cached scripts

You must include the library in your page and print the cache for the helper to function.
Javascript engine selection is declared when you include the helper in your controller.
var $helpers = array('Js' => array('Jquery'));

The above would use the Jquery Engine in the instances of JsHelper in your views. If you do
not declare a specific engine, the jQuery engine will be used as the default. As mentioned before, there

are three engines implemented in the core, but we encourage the community to expand the library
compatibility.
# Using jQuery with other libraries

The jQuery library, and virtually all of its plugins are constrained within the jQuery namespace.
As a general rule, "global" objects are stored inside the jQuery namespace as well, so you shouldn't get
a clash between jQuery and any other library (like Prototype, MooTools, or YUI).
That said, there is one caveat: By default, jQuery uses "$" as a shortcut for "jQuery"
To override the "$" shortcut, use the jQueryObject variable.
$this->Js->JqueryEngine->jQueryObject = '$j';
print $this->Html->scriptBlock('var $j = jQuery.noConflict();',
array('inline' => false)); //Tell jQuery to go into noconflict mode

7.5.2 Creating a Javascript Engine


Javascript engine helpers follow normal helper conventions, with a few additional restrictions.
They must have the Engine suffix. DojoHelper is not good, DojoEngineHelper is correct.
Furthermore, they should extend JsBaseEngineHelper in order to leverage the most of the new
API.
7.5.3 Javascript engine usage
The JsHelper provides a few methods, and acts as a facade for the the Engine helper. You
should not directly access the Engine helper except in rare occasions. Using the facade features of the
JsHelper allows you to leverage the buffering and method chaining features built-in; (method
chaining only works in PHP5).
The JsHelper by default buffers almost all script code generated, allowing you to collect
scripts throughout the view, elements and layout, and output it in one place. Outputting buffered scripts
is done with $this->Js->writeBuffer(); this will return the buffer contents in a script tag.
You can disable buffering wholesale with the $bufferScripts property or setting buffer =>
false in methods taking $options.
Since most methods in Javascript begin with a selection of elements in the DOM, $this>Js->get() returns a $this, allowing you to chain the methods using the selection. Method chaining

allows you to write shorter, more expressive code. It should be noted that method chaining Will not
work in PHP4.
$this->Js->get('#foo')->event('click', $eventCode);

Is an example of method chaining. Method chaining is not possible in PHP4 and the above
sample would be written like:
$this->Js->get('#foo');
$this->Js->event('click', $eventCode);

# Common options

In attempts to simplify development where Js libraries can change, a common set of options is
supported by JsHelper, these common options will be mapped out to the library specific options
internally. If you are not planning on switching Javascript libraries, each library also supports all of its
native callbacks and options.
# Callback wrapping

By default all callback options are wrapped with the an anonymous function with the correct
arguments. You can disable this behavior by supplying the wrapCallbacks = false in your
options array.
7.5.3.1 Working with buffered scripts

One drawback to previous implementation of 'Ajax' type features was the scattering of script
tags throughout your document, and the inability to buffer scripts added by elements in the layout. The
new JsHelper if used correctly avoids both of those issues. It is recommended that you place $this>Js->writeBuffer() at the bottom of your layout file above the </body> tag. This will allow
all scripts generated in layout elements to be output in one place. It should be noted that buffered
scripts are handled separately from included script files.
writeBuffer($options = array())
Writes all Javascript generated so far to a code block or caches them to a file and returns a
linked script.

Options
inline - Set to true to have scripts output as a script block inline if cache is also true, a
script link tag will be generated. (default true)
cache - Set to true to have scripts cached to a file and linked in (default false)
clear - Set to false to prevent script cache from being cleared (default true)
onDomReady - wrap cached scripts in domready event (default true)
safe - if an inline block is generated should it be wrapped in <![CDATA[ ... ]]> (default true)
Creating a cache file with writeBuffer() requires that webroot/js be world writable
and allows a browser to cache generated script resources for any page.
buffer($content)
Add $content to the internal script buffer.
getBuffer($clear = true)
Get the contents of the current buffer. Pass in false to not clear the buffer at the same time.
Buffering methods that are not normally buffered
Some methods in the helpers are buffered by default. The engines buffer the following methods
by default:

event
sortable
drag
drop
slider
Additionally you can force any other method in JsHelper to use the buffering. By appending an

boolean to the end of the arguments you can force other methods to go into the buffer. For example the
each() method does not normally buffer.
$this->Js->each('alert("whoa!");', true);

The above would force the each() method to use the buffer. Conversely if you want a method
that does buffer to not buffer, you can pass a false in as the last argument.
$this->Js->event('click', 'alert("whoa!");', false);

This would force the event function which normally buffers to return its result.

7.5.4 Methods
The core Javascript Engines provide the same feature set across all libraries, there is also a
subset of common options that are translated into library specific options. This is done to provide end
developers with as unified an API as possible. The following list of methods are supported by all the
Engines included in the CakePHP core. Whenever you see separate lists for Options and Event
Options both sets of parameters are supplied in the $options array for the method.
object($data, $options = array())
Converts values into JSON. There are a few differences between this method and
JavascriptHelper::object(). Most notably there is no affordance for stringKeys or q options found in
the JavascriptHelper. Furthermore $this->Js->object(); cannot make script tags.
Options:
prefix - String prepended to the returned data.
postfix - String appended to the returned data.
Example Use:
$json = $this->Js->object($data);

sortable($options = array())
Sortable generates a javascript snippet to make a set of elements (usually a list) drag and drop
sortable.
The normalized options are:
Options
containment - Container for move action
handle - Selector to handle element. Only this element will start sort action.
revert - Whether or not to use an effect to move sortable into final position.
opacity - Opacity of the placeholder
distance - Distance a sortable must be dragged before sorting starts.
Event Options
start - Event fired when sorting starts

sort - Event fired during sorting


complete - Event fired when sorting completes.
Other options are supported by each Javascript library, and you should check the documentation
for your javascript library for more detailed information on its options and parameters.
Example use:
$this->Js->get('#my-list');
$this->Js->sortable(array(
'distance' => 5,
'containment' => 'parent',
'start' => 'onStart',
'complete' => 'onStop',
'sort' => 'onSort',
'wrapCallbacks' => false
));

Assuming you were using the jQuery engine, you would get the following code in your
generated Javascript block:
$("#myList").sortable({containment:"parent",

distance:5,

sort:onSort,

start:onStart, stop:onStop});

request($url, $options = array())


Generate a javascript snippet to create an XmlHttpRequest or 'AJAX' request.
Event Options
complete - Callback to fire on complete.
success - Callback to fire on success.
before - Callback to fire on request initialization.
error - Callback to fire on request failure.
Options
method - The method to make the request with defaults to GET in more libraries
async - Whether or not you want an asynchronous request.
data - Additional data to send.

update - Dom id to update with the content of the request.


type - Data type for response. 'json' and 'html' are supported. Default is html for most libraries.
evalScripts - Whether or not <script> tags should be eval'ed.
dataExpression - Should the data key be treated as a callback. Useful for supplying
$options['data'] as another Javascript expression.
Example use
$this->Js->event('click',
$this->Js->request(array(
'action' => 'foo', param1), array(
'async' => true,
'update' => '#element')));

get($selector)
Set the internal 'selection' to a CSS selector. The active selection is used in subsequent
operations until a new selection is made.
$this->Js->get('#element');

The JsHelper now will reference all other element based methods on the selection of
#element. To change the active selection, call get() again with a new element.
drag($options = array())
Make an element draggable.
Options
handle - selector to the handle element.
snapGrid - The pixel grid that movement snaps to, an array(x, y)
container - The element that acts as a bounding box for the draggable element.
Event Options
start - Event fired when the drag starts
drag - Event fired on every step of the drag
stop - Event fired when dragging stops (mouse release)

Example use
$this->Js->get('#element');
$this->Js->drag(array(
'container' => '#content',
'start' => 'onStart',
'drag' => 'onDrag',
'stop' => 'onStop',
'snapGrid' => array(10, 10),
'wrapCallbacks' => false
));

If you were using the jQuery engine the following code would be added to the buffer.
$("#element").draggable({containment:"#content",

drag:onDrag,

grid:[10,10],

start:onStart, stop:onStop});

drop($options = array())
Make an element accept draggable elements and act as a dropzone for dragged elements.
Options
accept - Selector for elements this droppable will accept.
hoverclass - Class to add to droppable when a draggable is over.
Event Options
drop - Event fired when an element is dropped into the drop zone.
hover - Event fired when a drag enters a drop zone.
leave - Event fired when a drag is removed from a drop zone without being dropped.
Example use
$this->Js->get('#element');
$this->Js->drop(array(
'accept' => '.items',
'hover' => 'onHover',
'leave' => 'onExit',
'drop' => 'onDrop',
'wrapCallbacks' => false
));

If you were using the jQuery engine the following code would be added to the buffer:
<code class=
"php">$("#element").droppable({accept:".items",

drop:onDrop,

out:onExit,

over:onHover});</code>

''Note'' about MootoolsEngine::drop


Droppables in Mootools function differently from other libraries. Droppables are implemented
as an extension of Drag. So in addtion to making a get() selection for the droppable element. You must
also provide a selector rule to the draggable element. Furthermore, Mootools droppables inherit all
options from Drag.
slider()
Create snippet of Javascript that converts an element into a slider ui widget. See your libraries
implementation for additional usage and features.
Options
handle - The id of the element used in sliding.
direction - The direction of the slider either 'vertical' or 'horizontal'
min - The min value for the slider.
max - The max value for the slider.
step - The number of steps or ticks the slider will have.
value - The initial offset of the slider.
Events
change - Fired when the slider's value is updated
complete - Fired when the user stops sliding the handle
Example use
$this->Js->get('#element');
$this->Js->slider(array(
'complete' => 'onComplete',
'change' => 'onChange',
'min' => 0,
'max' => 10,
'value' => 2,
'direction' => 'vertical',
'wrapCallbacks' => false
));

If you were using the jQuery engine the following code would be added to the buffer:
$("#element").slider({change:onChange,

max:10,

min:0,

orientation:"vertical",

stop:onComplete, value:2});

effect($name, $options = array())


Creates a basic effect. By default this method is not buffered and returns its result.
Supported effect names
The following effects are supported by all JsEngines
show - reveal an element.
hide - hide an element.
fadeIn - Fade in an element.
fadeOut - Fade out an element.
slideIn - Slide an element in.
slideOut - Slide an element out.
Options
speed - Speed at which the animation should occur. Accepted values are 'slow', 'fast'. Not all
effects use the speed option.
Example use
If you were using the jQuery engine.
$this->Js->get('#element');
$result = $this->Js->effect('fadeIn');
//$result contains $("#foo").fadeIn();

event($type, $content, $options = array())


Bind an event to the current selection. $type can be any of the normal DOM events or a
custom event type if your library supports them. $content should contain the function body for the
callback. Callbacks will be wrapped with function (event) { ... } unless disabled with the
$options.

Options
wrap - Whether you want the callback wrapped in an anonymous function. (defaults to true)
stop - Whether you want the event to stopped. (defaults to true)
Example use
$this->Js->get('#some-link');
$this->Js->event('click', $this->Js->alert('hey you!'));

If you were using the jQuery library you would get the following Javascript code.
$('#some-link').bind('click', function (event) {
alert('hey you!');
return false;
});

You can remove the return false; by passing setting the stop option to false.
$this->Js->get('#some-link');
$this->Js->event('click', $this->Js->alert('hey you!'), array('stop' => false));

If you were using the jQuery library you would the following Javascript code would be added to
the buffer. Note that the default browser event is not cancelled.
$('#some-link').bind('click', function (event) {
alert('hey you!');
});

domReady($callback)
Creates the special 'DOM ready' event. writeBuffer() automatically wraps the buffered
scripts in a domReady method.
each($callback)
Create a snippet that iterates over the currently selected elements, and inserts $callback.
Example
$this->Js->get('div.message');
$this->Js->each('$(this).css({color: "red"});');

Using the jQuery engine would create the following Javascript


$('div.message').each(function () { $(this).css({color: "red"});});

alert($message)
Create a javascript snippet containing an alert() snippet. By default, alert does not buffer,
and returns the script snippet.
$alert = $this->Js->alert('Hey there');

confirm($message)
Create a javascript snippet containing a confirm() snippet. By default, confirm does not
buffer, and returns the script snippet.
$alert = $this->Js->confirm('Are you sure?');

prompt($message, $default)
Create a javascript snippet containing a prompt() snippet. By default, prompt does not
buffer, and returns the script snippet.
$prompt = $this->Js->prompt('What is your favorite color?', 'blue');

submit()
Create a submit input button that enables XmlHttpRequest submitted forms. Options can
include both those for FormHelper::submit() and JsBaseEngine::request(), JsBaseEngine::event();
Forms submitting with this method, cannot send files. Files do not transfer over
XmlHttpRequest and require an iframe, or other more specialized setups that are beyond the scope
of this helper.
Options
confirm - Confirm message displayed before sending the request. Using confirm, does not
replace any before callback methods in the generated XmlHttpRequest.
buffer - Disable the buffering and return a script tag in addition to the link.
wrapCallbacks - Set to false to disable automatic callback wrapping.

Example use
echo $this->Js->submit('Save', array('update' => '#content'));

Will create a submit button with an attached onclick event. The click event will be buffered by default.
echo $this->Js->submit('Save', array('update'
'type' => 'json', 'async' => false));

=>

'#content',

'div'

=>

false,

Shows how you can combine options that both FormHelper::submit() and
Js::request() when using submit.
link($title, $url = null, $options = array())
Create an html anchor element that has a click event bound to it. Options can include both those
for HtmlHelper::link() and JsBaseEngine::request(), JsBaseEngine::event(); $htmlAttributes is
used to specify additional options that are supposed to be appended to the generated anchor element. If
an option is not part of the standard attributes or $htmlAttributes it will be passed to
request() as an option. If an id is not supplied, a randomly generated one will be created for each
link generated.
Options
confirm - Generate a confirm() dialog before sending the event.
id - use a custom id.
htmlAttributes - additional non-standard htmlAttributes. Standard attributes are class, id,
rel, title, escape, onblur and onfocus.
buffer - Disable the buffering and return a script tag in addition to the link.
Example use
echo $this->Js->link('Page 2', array('page' => 2), array('update' => '#content'));

Will create a link pointing to /page:2 and updating #content with the response.
You can use the htmlAttributes option to add in additional custom attributes.
echo $this->Js->link('Page 2', array('page' => 2), array(
'update' =&gt; '#content',
'htmlAttributes' =&gt; array('other' =&gt; 'value')
));
//Creates the following html
<a href="/es/posts/index/page:2" other="value">Page 2</a>

serializeForm($options = array())
Serialize the form attached to $selector. Pass true for $isForm if the current selection is a form
element. Converts the form or the form element attached to the current selection into a string/json
object (depending on the library implementation) for use with XHR operations.
Options
isForm - is the current selection a form, or an input? (defaults to false)
inline - is the rendered statement going to be used inside another JS statement? (defaults to
false)
Setting inline == false allows you to remove the trailing ;. This is useful when you need to
serialize a form element as part of another Javascript operation, or use the serialize method in an Object
literal.
redirect($url)
Redirect the page to $url using window.location.
value($value)
Converts a PHP-native variable of any type to a JSON-equivalent representation. Escapes any
string values into JSON compatible strings. UTF-8 characters will be escaped.
7.5.5 Ajax Pagination
Much like Ajax Pagination in 1.2, you can use the JsHelper to handle the creation of Ajax
pagination links instead of plain HTML links.
# Making Ajax Links

Before you can create ajax links you must include the Javascript library that matches the adapter
you are using with JsHelper. By default the JsHelper uses jQuery. So in your layout include
jQuery (or whichever library you are using)
echo $this->Html->script('jquery');

Similar to 1.2 you need to tell the PaginatorHelper that you want to make Javascript
enhanced links instead of plain HTML ones. To do so you use options()

$this->Paginator->options(array(
'update' => '#content',
'evalScripts' => true
));

The PaginatorHelper now knows to make javascript enhanced links, and that those links
should update the #content element. Of course this element must exist, and often times you want to
wrap $content_for_layout with a div matching the id used for the update option. You also
should set evalScripts to true if you are using the Mootools or Prototype adapters, without
evalScripts these libraries will not be able to chain requests together. The indicator option is
not supported by JsHelper and will be ignored.
You then create all the links as needed for your pagination features. Since the JsHelper
automatically buffers all generated script content to reduce the number of <script> tags in your
source code you must call write the buffer out. At the bottom of your view file. Be sure to include:
echo $this->Js->writeBuffer();

If you omit this you will not be able to chain ajax pagination links. When you write the buffer,
it is also cleared, so you don't have worry about the same Javascript being output twice.
# Adding effects and transitions

Since indicator is no longer supported, you must add any indicator effects yourself.
<html>
<head>
<?php echo $this->Html->script('jquery'); ?>
//more stuff here.
</head>
<body>
<div id="content">
<?php echo $content_for_layout; ?>
</div>
<?php
indicator')); ?>
</body>
</html>

echo

$this->Html->image('indicator.gif',

array('id'

=>

'busy-

Remember to place the indicator.gif file inside app/webroot/img folder. You may see a situation
where the indicator.gif displays immediately upon the page load. You need to put in this css #busyindicator { display:none; } in your main css file.
With the above layout, we've included an indicator image file, that will display a busy indicator
animation that we will show and hide with the JsHelper. To do that we need to update our
options() function.
$this->Paginator->options(array(
'update' => '#content',
'evalScripts' => true,
'before' => $this->Js->get('#busy-indicator')->effect('fadeIn', array('buffer'
=> false)),
'complete'

=>

$this->Js->get('#busy-indicator')->effect('fadeOut',

array('buffer' => false)),


));

This will show/hide the busy-indicator element before and after the #content div is updated.
Although indicator has been removed, the new features offered by JsHelper allow for more
control and more complex effects to be created.

7.6 Javascript
EL ayudante Javascript es usado para en la creacin de etiquetas y bloques de cdigo javascript
bien formados. Existen varios mtodos algunos de los cuales estn diseados para trabajar con el
framework Javascript Prototype.
7.6.1 Methods
codeBlock($script,

$options

array('allowCache'=>true,'safe'=>true,'inline'=>true),

$safe)
string $script - The JavaScript to be wrapped in SCRIPT tags
array $options - Set of options:
allowCache: boolean, designates whether this block is cacheable using the current cache
settings.
safe: boolean, whether this block should be wrapped in CDATA tags. Defaults to helper's

object configuration.
inline: whether the block should be printed inline, or written to cached for later output
(i.e. $scripts_for_layout).
boolean $safe - DEPRECATED. Use $options['safe'] instead
codeBlock returns a formatted script element containing $script. But can also return null if
Javascript helper is set to cache events. See JavascriptHelper::cacheEvents(). And can write in
$scripts_for_layout if you set $options['inline'] to false.
blockEnd()
Ends a block of cached Javascript. Can return either a end script tag, or empties the buffer,
adding the contents to the cachedEvents array. Its return value depends on the cache settings. See
JavascriptHelper::cacheEvents()
link($url, $inline = true)
mixed $url - String URL to JavaScript file, or an array of URLs.
boolean $inline If true, the <script> tag will be printed inline, otherwise it will be printed in
$scripts_for_layout
Creates a javascript link to a single or many javascript files. Can output inline or in
$scripts_for_layout.
If the filename is prefixed with "/", the path will be relative to the base path of your application.
Otherwise, the path will be relative to your JavaScript path, usually webroot/js.
escapeString($string)
string $script - String that needs to get escaped.
Escape a string to be JavaScript friendly. Allowing it to safely be used in javascript blocks.
The characters that are escaped are:
"\r\n" => '\n'
"\r" => '\n'
"\n" => '\n'
'"' => '\"'
"'" => "\\'"

event($object, $event, $observer, $useCapture)


string $object - DOM Object to be observed.
string $event - type of event to observe ie 'click', 'over'.
string $observer - Javascript function to call when event occurs.
array $options - Set options: useCapture, allowCache, safe
boolean $options['useCapture'] - Whether to fire the event in the capture or bubble phase
of event handling. Defaults false
boolean $options['allowCache'] - See JavascriptHelper::cacheEvents()
boolean $options['safe'] - Indicates whether <script /> blocks should be written 'safely,'
i.e. wrapped in CDATA blocks
Attach a javascript event handler specified by $event to an element DOM element specified by
$object. Object does not have to be an ID reference it can refer to any valid javascript object or CSS
selectors. If a CSS selector is used the event handler is cached and should be retrieved with
JavascriptHelper::getCache(). This method requires the Prototype library.
cacheEvents($file, $all)
boolean $file - If true, code will be written to a file
boolean $all - If true, all code written with JavascriptHelper will be sent to a file
Allows you to control how the JavaScript Helper caches event code generated by event(). If $all
is set to true, all code generated by the helper is cached and can be retrieved with getCache() or written
to file or page output with writeCache().
getCache($clear)
boolean $clear - If set to true the cached javascript is cleared. Defaults to true.
Gets (and clears) the current JavaScript event cache
writeEvents($inline)
boolean $inline - If true, returns JavaScript event code. Otherwise it is added to the output of
$scripts_for_layout in the layout.
Returns cached javascript code. If $file was set to true with cacheEvents(), code is cached to a
file and a script link to the cached events file is returned. If inline is true, the event code is returned
inline. Else it is added to the $scripts_for_layout for the page.

includeScript($script)
string $script - File name of script to include.
Includes the named $script. If $script is left blank the helper will include every script in your
app/webroot/js directory. Includes the contents of each file inline. To create a script tag with an src
attribute use link().
object($data, $options)
array $data - Data to be converted
array $options - Set of options: block, prefix, postfix, stringKeys, quoteKeys, q
boolean $options['block'] - Wraps return value in a <script /> block if true. Defaults to
false.
string $options['prefix'] - Prepends the string to the returned data.
string $options['postfix'] - Appends the string to the returned data.
array $options['stringKeys'] - A list of array keys to be treated as a string.
boolean $options['quoteKeys'] - If false, treats $stringKey as a list of keys *not* to be
quoted. Defaults to true.
string $options['q'] - The type of quote to use.
Generates a JavaScript object in JavaScript Object Notation (JSON) from $data array.

7.7 Number
The NumberHelper contains convenience methods that enable display numbers in common
formats in your views. These methods include ways to format currency, percentages, data sizes, format
numbers to specific precisions and also to give you more flexibility with formating numbers.
All of these functions return the formated number; They do not automatically echo the output
into the view.
7.7.1 currency
currency(mixed $number, string $currency= 'USD', $options = array())
This method is used to display a number in common currency formats (EUR,GBP,USD). Usage
in a view looks like:

<?php echo $this->Number->currency($number,$currency); ?>

The first parameter, $number, should be a floating point number that represents the amount of
money you are expressing. The second parameter is used to choose a predefined currency formatting
scheme:
$currency 1234.56, formatted by currency type
EUR
1.236,33
GBP
1,236.33
USD
$ 1,236.33
The third parameter is an array of options for further defining the output. The following options
are available:
Option
before
after

Description
The currency symbol to place before whole numbers ie. '$'
The currency symbol to place after decimal numbers ie. 'c'. Set to boolean false to use no

decimal symbol. eg. 0.35 => $0.35.


zero
The text to use for zero values, can be a string or a number. ie. 0, 'Free!'
places
Number of decimal places to use. ie. 2
thousands Thousands separator ie. ','
decimals Decimal separator symbol ie. '.'
negative Symbol for negative numbers. If equal to '()', the number will be wrapped with ( and )
escape
Should the output be htmlentity escaped? Defaults to true
If a non-recognized $currency value is supplied, it is prepended to a USD formatted number.
For example:
<?php echo $this->Number->currency('1234.56', 'FOO'); ?>
//Outputs:
FOO 1,234.56

7.7.2 precision
precision (mixed $number, int $precision = 3)
This method displays a number with the specified amount of precision (decimal places). It will
round in order to maintain the level of precision defined.
<?php echo $this->Number->precision(456.91873645, 2 ); ?>
//Outputs:
456.92

7.7.3 toPercentage
toPercentage(mixed $number, int $precision = 2)
Like precision(), this method formats a number according to the supplied precision (where
numbers are rounded to meet the given precision). This method also expresses the number as a
percentage and prepends the output with a percent sign.
<?php echo $this->Number->toPercentage(45.691873645); ?>
//Outputs:
45.69%

7.7.4 toReadableSize
toReadableSize(string $data_size)
This method formats data sizes in human readable forms. It provides a shortcut way to convert
bytes to KB, MB, GB, and TB. The size is displayed with a two-digit precision level, according to the
size of data supplied (i.e. higher sizes are expressed in larger terms):
echo $this->Number->toReadableSize(0);

// 0 Bytes

echo $this->Number->toReadableSize(1024); // 1 KB
echo $this->Number->toReadableSize(1321205.76); // 1.26 MB
echo $this->Number->toReadableSize(5368709120); // 5.00 GB

7.7.5 format
format (mixed $number, mixed $options=false)
This method gives you much more control over the formatting of numbers for use in your views
(and is used as the main method by most of the other NumberHelper methods). Using this method
might looks like:
$this->Number->format($number, $options);

The $number parameter is the number that you are planning on formatting for output. With no
$options supplied, the number 1236.334 would output as 1,236. Note that the default precision is zero
decimal places.
The $options parameter is where the real magic for this method resides.

If you pass an integer then this becomes the amount of precision or places for the function.
If you pass an associated array, you can use the following keys:
places (integer): the amount of desired precision
before (string): to be put before the outputted number
escape (boolean): if you want the value in before to be escaped
decimals (string): used to delimit the decimal places in a number
thousands (string): used to mark off thousand, millions, places
echo $this->Number->format('123456.7890', array(
'places' => 2,
'before' => ' ',
'escape' => false,
'decimals' => '.',
'thousands' => ','
));
// output ' 123,456.79'

7.8 Paginator
El Paginator helper, se usa para imprimir los controles de los nmeros de pgina y de los links
siguiente y previo.
Ve tambin Tareas comunes con CakePHP - Paginacion para ms informacin.
7.8.1 Mtodos
options($options = array())
options() : Opciones por defecto de la paginacin para los links. Si se suministra un string, ste
se usa como el id del elemento DOM a updatear. Vea #options para la lista de las llaves
posibles.
options() configura todas las opciones para el Paginator Helper. Las opciones soportadas son:
format
Formato del contador. Los formatos soportados son 'range' y 'pages' y custon (personalizado)
que es el por defecto. En el modo por defecto el string proporcionado es parseado y los tokens son
reemplazados por sus verdaderos valores. Los tokens disponibles son:

%page% - la pgina actual.


%pages% - nmero total de pginas.
%current% - nmero actual de registros mostrados.
%count% - nmero total de registros en el conjunto resultado.
%start% - numero del primer registro mostrado.
%end% - numero del ultimo registro mostrado.
Ahora que sabes los tokens disponibles, puedes usar el mtodo counter() para mostrar todos tipo
de informacin retornada en los resultados, por ejemplo:
echo $paginator->counter(array(
'format' => 'Pagina %page% de %pages%,
mostrando %current% registros de un total de %count%,
comenzando en el registro %start%, terminando en el %end%'
));

separator
El separador entre la pagina actual y el numero de paginas. El valor por defecto es ' of '. Esto se
usa en conjunto con formato = 'pages'
url
La url de la accion de paginacin. url tiene algunas sub opciones tambin
sort - la llave por la cual los registros estan ordenados
direction - la direccin en la cual se ordena. Valor por defecto 'ASC'
page - el nmero de pgina a mostrar
model
El nombre del modelo que esta siendo paginado.
escape
Define si el campo de ttulo de los links debera ser sin HTML. Valor por defecto true.
update
El id del elemento DOM a updatear con los resultados de una llamada AJAX.. Si no esta
especificada, se crearn links regulares.

indicator
El id del elemento DOM que ser mostrado como indicador de descarga o trabajo en curso
mientras se ejecuta la llamada AJAX.
link($title, $url = array(), $options = array())
string $title - El ttulo del link.
mixed $url Url para la accin. Ver Router::url()
array $options Opciones para el link. ver options() para la lista de llaves.
Crea un link regular o AJAX con los parametros de paginacin.
echo $paginator->link('Ordenados por ttulo en pagina 5',
array('sort' => 'title', 'page' => 5, 'direction' => 'desc'));

Si se cre en la vista en /posts/index Debera crear un link apuntando a


'/posts/index/page:5/sort:title/direction:desc'

7.9 RSS
El helper RSS hace que generar XML para un RSS feed sea muy fcil.
7.9.1 Creando un RSS feed con el RssHelper
Este ejemplo asume que tu tienes creados un controlador de Posts y un modelo de Post y que
quieres hacer una vista alternativa para RSS.
Crear una version xml/rss de posts/index es algo muy fcil con CakePHP 1.2. Despues de unos
simples pasos puedes aadir la extension .rss a post/index haciendo tu URL posts/index.rss. Antes de
adelantarnos tratando de conseguir que nuestro servicio web quede listo, debemos hacer algunas
pequeas cosas. Primero debemos activar parseExtensions, esto se hace en app/config/routes.php
Router::parseExtensions('rss');

En segundo lugar una buena idea es agregar RequestHandler al arreglo de componentes


$components de PostsController. Esto permitir que ocurra mucha automagia. En la llamanda anterior
hemos activado la extension .rss. Cuando usamos Router::parseExtensions() podemos pasar tantos
argumentos o extensiones como queramos. Esto activar cada 'extension/content-type' para el uso de
nuestra aplicacin. Ahora, cuando la direccin posts/index.rss sea requerida obtendrs una versin xml

de posts/index. Sin embargo, lo primero que necesitamos es hacer que los archivos de vista que crearn
nuestro rss/xml feed.
7.9.1.1 Cdigo para el Controlador

Antes de crear nuestra version RSS de posts/index necesitamos poner algunas cosas en orden.
Es tentador poner el canal de metadatos en la accion del controlador y pasarlo a nuestas vistas usando
la funcin Controller::set() pero es es inapropiado. Esta informacin tambin ir a la vista. Pero eso
vendr despus, por ahora si tienes alguna lgica diferente para los datos usados en el RSS feed y los
datos que se usan en la vista html puedes usar el mtodo RequestHandler::isRss(), de otra forma tu
controlador puede quedar igual.
// Modificar la accion del controlador de Posts que corresponde
// a la cual entrega el rss feed, que en nuestro caso
// es la accion index
public function index(){
if( $this->RequestHandler->isRss() ){
$posts = $this->Post->find('all', array('limit' => 20, 'order' =>
'Post.created DESC'));
$this->set(compact('posts'));
} else {
// esta no es una llamada Rss, entonces entregamos
// usamos los datos para la salida html
$this->paginate['Post'] = array('order' = 'Post.created DESC', 'limit' =>
10);
$posts = $this->paginate();
$this->set(compact('posts'));
}
}

Con todas las variables de vista configuradas necesitamos crear un layout rss.
7.9.1.1.1 Layout RSS

Un

layout

RSS

es

muy

app/view/layouts/rss/default.ctp:

simple,

escribe

lo

siguiente

en

echo $rss->header();
if (!isset($documentData)) {
$documentData = array();
}
if (!isset($channelData)) {
$channelData = array();
}
if (!isset($channelData['title'])) {
$channelData['title'] = $title_for_layout;
}
$channel = $rss->channel(array(), $channelData, $content_for_layout);
echo $rss->document($documentData,$channel);

No parece ser la gran cosa, sin embargo gracias al poder del RssHelper hara un monton de cosas
por nosotros. No hemos configrado $documentData o $channelData en nuestro controlador, sin
embargo, en CakePHP 1.2 tus vistas pueden pasar variables de vuelta al layout. En este momento
nuestro arreglo $channelData entrar en accin para configurar todos los metadatos para nuestro feed.
Lo siguiente es el archivo de vista de posts/index. As como necesitamos un layout, necesitamos
crear el directorio views/posts/rss/ y crear un nuevo index.ctp dentro. El contenido de ese archivo est
mas abajo.
7.9.1.1.2 La vista

Nuestra vista comienza por configurar las variables $documentData y $channelData para el
layout, estos contienen todos los metadatos para nuestro RSS feed. Esto se hace utilizando el mtodo
View::set() el cual es anlogo al mtodo Controller::set(). Ac estamos pasando los metadatos del canal
de vuelta al layout.
$this->set('documentData', array(
'xmlns:dc' => 'http://purl.org/dc/elements/1.1/'));
$this->set('channelData', array(
'title' => __("Artculos ms ledos", true),
'link' => $html->url('/', true),
'description' => __("Artculos ms recientes.", true),
'language' => 'en-us'));

La segunda parte de la vista genera los elementos para los registros del feed. Esto se consigue
haciendo un ciclo a los datos entregados a la vista ($items) y usando el mtodo RssHelper::item(). El
otro mtodo que puedes usar es, RssHelper::items() el cual toma una llamada y un arreglo de items para
el feed. (El metodo usado para las llamadas siempre a se ha llamado transformRss()). Hay un punto
dbil en este mtodo, que es que no puedes usar ningn mtodo de otro helper para preparar los datos
dentro del metodo de la llamada, porque el mbito dentro de la llamada no incluye nada que no se haya
entregado desde afuera, lo que no da acceso al TimeHelper o cualquier otro que necesitemos. El
metodo RssHelper::item() transforma el arreglo asociativo en un elemento para cada par llave-valor.
foreach ($entries as $entry) {
$postTime = strtotime($entry['Entry']['created']);
$entryLink = array(
'controller' => 'entries',
'action' => 'view',
'year' => date('Y', $postTime),
'month' => date('m', $postTime),
'day' => date('d', $postTime),
$entry['Entry']['slug']);
// deberas importar Sanitize
App::import('Sanitize');
// Ac es donde se limpia el cuerpo del texto para la salida como la
descripcin
// de los items rss, esto necesita tener solo texto para asegurarnos de
que valide el feed
$bodyText = preg_replace('=\(.*?)\=is', '', $entry['Entry']['body']);
$bodyText = $text->stripLinks($bodyText);
$bodyText = Sanitize::stripAll($bodyText);
$bodyText = $text->truncate($bodyText, 400, '...', true, true);
echo

$rss->item(array(), array(

'title' => $entry['Entry']['title'],


'link' => $entryLink,
'guid' => array('url' => $entryLink, 'isPermaLink' => 'true'),
'description' =>

$bodyText,

'dc:creator' => $entry['Entry']['author'],


'pubDate' => $entry['Entry']['created']));
}

Puedes ver que podemos usar el loop para preparar los datos para ser transformados en
elementos XML. Es importante filtrar cuaquier caracter que no sea de texto plano, especialmente si
estas usando un editor de html para el cuerpo de tu blog. En el codigo anterior usamos el mtodo
TextHelper::stripLinks() y algunos pocos mtodos de la clase Sanitize, pero recomendamos escribir un
helper especializado para dejar el texto realmente limpio. Una vez que hemos configurado los datos
para el feed, podemos usar el mtodo RssHelper::item() para crear el XML del formato RSS. Una vez
que hayas hecho todo esto, puedes probar tu RSS dirigindote a la direccion /entries/index.rss y vers
tu nuevo feed. Siempre es importante que valides tu RSS feed antes de ponerlo en produccion. Esto se
puede

hacer

visitando

algunos

sitios

como

FeedValidator

el

sitio

de

w3c

en

http://validator.w3.org/feed/.

7.10 Sesin
Como contraparte natural al Componente Session, el Helper Session refleja la mayora de las
funcionalidades de los componentes y las hace disponible a las vistas. El Helper de Sesin se agrega
automticamente a tu vista, no es necesario agregarlo en el arreglo $helpers en el controlador.
La mayor diferencia entre el Helper y el Componente de Sesin es que el Helper no puede
escribir en la sesin.
Al igual que en el Componente de Sesin, los datos son escritos y ledos usando estructuras de
arreglos separadas por puntos.
array('User' =>
array('username' => 'super@ejemplo.com')
);

Dada la estructura de arreglo previa, el nodo sera accesado por User.username, con el
punto indicando el arreglo enlazado. Esta notacin es usada por todos los mtodos del Helper de Sesin
siempre que se utilice $key.

7.10.1 Methods
read($key

Read from the Session. Returns a string or array depending on the contents of the session.
)
id()
Returns the current session ID.
check($ke
Check to see if a key is in the Session. Returns a boolean on the key's existence.
y)
flash($key This will return the contents of the $_SESSION.Message. It is used in conjunction with the
)
error()

Session Component's setFlash() method.


Returns the last error in the session if one exists.

7.10.2 flash
The flash method uses the default key set by setFlash(). You can also retrieve specific keys
in the session. For example, the Auth component sets all of its Session messages under the 'auth' key
// Controller code
$this->Session->setFlash('My Message');
// In view
echo $this->Session->flash();
// outputs "<div id='flashMessage' class='message'>My Message</div>"
// output the AuthComponent Session message, if set.
echo $this->Session->flash('auth');

# Using Flash for Success and Failure

In some web sites, particularly administration backoffice web applications it is often expected
that the result of an operation requested by the user has associated feedback as to whether the operation
succeeded or not. This is a classic usage for the flash mechanism since we only want to show the user
the result once and not keep the message.
One way to achieve this is to use Session->flash() with the layout parameter. With the layout
parameter we can be in control of the resultant html for the message.
In the controller you might typically have code:

if ($user_was_deleted) {
$this->Session->setFlash('The

user

was

deleted

successfully.',

'flash_success');
} else {
$this->Session->setFlash('The user could not be deleted.', 'flash_failure');
}

The flash_success and flash_failure parameter represents an element file to place in the root
app/views/elements

folder,

e.g.

app/views/elements/flash_success.ctp,

app/views/elements/flash_failure.ctp
Inside the flash_success element file would be something like this:
<div class="flash flash_success">
<?php echo $message ?>
</div>

The final step is in your main view file where the result is to be displayed to add simply
<?php echo $this->Session->flash(); ?>

And of course you can then add to your CSS a selector for div.flash, div.flash_success and
div.flash_failure

7.11 Text
The TextHelper contains methods to make text more usable and friendly in your views. It aids in
enabling links, formatting urls, creating excerpts of text around chosen words or phrases, highlighting
key words in blocks of text, and to gracefully truncating long stretches of text.
# autoLinkEmails
autoLinkEmails(string $text, array $htmlOptions=array())
Adds links to the well-formed email addresses in $text, according to any options defined in
$htmlOptions (see HtmlHelper::link()).
$my_text = 'For more information regarding our world-famous pastries and desserts,
contact info@example.com';
$linked_text = $this->Text->autoLinkEmails($my_text);

Output:
For more information regarding our world-famous pastries and desserts,
contact <a href="mailto:info@example.com">info@example.com</a>

# autoLinkUrls
autoLinkUrls(string $text, array $htmlOptions=array())
Same as in autoLinkEmails(), only this method searches for strings that start with https,
http, ftp, or nntp and links them appropriately.
# autoLink
autoLink(string $text, array $htmlOptions=array())
Performs the functionality in both autoLinkUrls() and autoLinkEmails() on the
supplied $text. All URLs and emails are linked appropriately given the supplied $htmlOptions.
# excerpt
excerpt(string $haystack, string $needle, int $radius=100, string $ending="...")
Extracts an excerpt from $haystack surrounding the $needle with a number of characters
on each side determined by $radius, and suffixed with $ending. This method is especially handy
for search results. The query string or keywords can be shown within the resulting document.
echo $this->Text->excerpt($last_paragraph, 'method', 50);

Output:
mined by $radius, and suffixed with $ending. This method is especially handy for
search results. The query...

# highlight
highlight(string

$haystack,

string

$needle,

$highlighter='<span

class="highlight">\1</span>')
Highlights $needle in $haystack using the $highlighter string specified.
echo $this->Text->highlight($last_sentence, 'using');

Output:
Highlights $needle in $haystack <span class="highlight">using</span>
the $highlighter string specified.

# stripLinks
stripLinks($text)
Strips the supplied $text of any HTML links.
# toList
toList(array $list, $and='and')
Creates a comma-separated list where the last two items are joined with and.
echo $this->Text->toList($colors);

Output:
red, orange, yellow, green, blue, indigo and violet

# truncate
truncate(string $text, int $length=100, array $options)
Cuts a string to the $length and adds a suffix with 'ending' if the text is longer than
$length. If 'exact' is passed as false, the truncation will occur after the next word ending. If
'html' is passed as true, html tags will be respected and will not be cut off.
$options is used to pass all extra parameters, and has the following possible keys by default,
all of which are optional:
array(

'ending' => '...',


'exact' => true,
'html' => false

)
echo $this->Text->truncate(
'The killer crept forward and tripped on the rug.',
22,
array(
'ending' => '...',
'exact' => false
) ); //The killer crept...

# trim
trim()
An alias for truncate.

7.12 Tiempo
El ayudante de tiempo (Time Helper), como su nombre lo indica, te ayuda a ahorrar tiempo.
Permite que se haga un procesamiento rpido de la informacin relacionada con el tiempo. Este
ayudante tiene dos tareas principales que puede realizar
1. Puede dar formato a textos de tiempo
2. Puede probar el tiempo (pero no pude doblarlo, lo sentimos).
7.12.1 Formatting
fromString( $date_string )
fromString toma una cadena de texto y la convierte en un objeto de tiempo. Si la cadena
suministrada es un nmero, la convertir a un entero, siendo este el nmero de segundos que han
transcurrido desde el Epoch de Unix (1 de Enero 1970 00:00:00 GMT). Pasarle un texto "20081231"
crear un resultado indeseado ya que tratar de convertirlo a segundos, lo que resultar en este caso
"Vier, Ago 21 1970, 06:07"
toQuarter( $date_string, $range = false )
toQuarter devolver 1, 2, 3 o 4 dependiendo de en qu trimestre del ao la fecha se encuantra.
Si el $range es true, devolver un arreglo con dos elementos con las fechas de inicio y fin en el formato
"2008-03-31"
toUnix( $date_string )
toUnix es un sinnimo para fromString.
toAtom( $date_string )
toAtom devuelve una texto de tiempo en el formato Atom "2008-01-12T00:00:00Z"
toRSS( $date_string )
toRSS devuelve un texto de tiempo en el formato RSS "Sat, 12 Jan 2008 00:00:00 -0500"

nice( $date_string = null )


nice toma una texto de tiempo y lo devuelve en el formato "Tue, Jan 1st 2008, 19:25".
niceShort( $date_string = null )
niceShort toma un texto de tiempo y lo devuelve en el formato "Jan 1st 2008, 19:25". Si la
fecha es el da actual el formato ser "Hoy, 19:25". Si la fecha ayer, devolver en el formato "Ayer,
19:25".
daysAsSql( $begin, $end, $field_name )
daysAsSql devuelve una cadena de texto en el formato "($campo >= '2008-01-21 00:00:00')
AND ($campo <= '2008-01-25 23:59:59')".
dayAsSql( $date_string, $field_name )
dayAsSql crea una cadena de texto en el mismo formato que daysAsSql, pero solo necesita un
nico objeto de tiempo
timeAgoInWords( $date_string, $options = array(), $backwards = null )
timeAgoInWords toma una cadena de texto que representa una fecha y lo convierte a un
formato amigable como "Hace 3 semanas, 3 das". Pasarle true en $backwards har que se declare el
tiempo en el futuro, lo que devolver el formato "el 31/12/08".
Opcin Descripcin
format un formato de fechas; por defecto "on 31/12/08"
determina el el punto de corte en el que no uar ms palabras y usar el formato de fechas en
end
su lugar, por defecto "+1 month"
relativeTime( $date_string, $format = 'j/n/y' )
relativeTime es un bsicamente un sinnimo para timeAgoInWords.
gmt( $date_string = null )
gmt devolver la fecha como un entero fijado al tiempo medio de Greenwich (GMT).
format( $format = 'd-m-Y', $date_string)
format es un sinnimo para la funcin date de php.

Funcin
nice

Formato
Mar, Enero 1 2008, 19:25
Enero
1

2008,

19:25

niceShort

Hoy,

19:25

daysAsSql
dayAsSql

Ayer, 19:25
($campo >= '2008-01-21 00:00:00') AND ($campo <= '2008-01-25 23:59:59')
($campo >= '2008-01-21 00:00:00') AND ($campo <= '2008-01-21 23:59:59')
el 21/01/08

timeAgoInWords Hace 3 mese, 3 semanas, 2 das


relativeTime

Hace 7 minutos

gmt

Hace 2 segundos
1200787200

7.12.2 Testing Time

isToday (es Hoy)


isThisWeek (es esta Semana)
isThisMonth (es este MEs)
isThisYear (es este Ao)
wasYesterday (fue Ayer)
isTomorrow (es Maana)
wasWithinLast (sucedi dentro del rango de tiempo)
Todas las funciones anteriores devuelve true o false al pasarle una cadena de texto que

represente una fecha. wasWithinLast toma el parmetro adicional $time_interval (intervalo


de tiempo):
$time->wasWithinLast( $time_interval, $date_string )
wasWithinLast toma un intervalo de tiempo que es un texto en el formato "3 months" y
acepta un intervalo de tiempo en segundos, minutos, horas, das, semanas, meses, aos. Si un intervalo
de tiempo no es reconocido (por ejemplo se tipe errneamente), se usar por defecto das

7.13 XML
El helper XML simplifica la salida de documentos XML.
7.13.1 serialize
El mtodo serialize toma un arreglo y crea una cadena XML de los datos. Esto es usado

comnmente para serializar datos de modelos.


<?php
echo $xml->serialize($data);
// El formato ser similar a:
// <model_name id="1" field_name="content" />
?>

El mtodo serialize actua como un atajo para instanciar la clase XML incorporada en CakePHP,
y usar el mtodo toString de la misma. Si necesitas ms control sobre la serializacin, quizs quieras
invocar la clase XML directamente.
7.13.2 elem
El mtodo elem permite construir una cadena-nodo XML con atributos y tambin contenido
interno.
string elem (string $name, $attrib = array(), mixed $content = null, $endTag = true)
echo $xml->elem('count', array('namespace' => 'myNameSpace'), 'contenido');
// genera: <myNameSpace:count>contenido</count>

Si quieres empaquetar tu nodo de texto con CDATA, el tercer argumento debera ser un arreglo
con dos llaves: 'cdata' y 'value'
echo $xml->elem('count', null, array('cdata'=>true,'value'=>'contenido');
// genera: <count><![CDATA[contenido]]></count>

7.13.3 header
El mtodo header() se usa para escribir la declaracin de XML.
<?php
echo $xml->header();
// genera: <?xml version="1.0" encoding="UTF-8" ?>
?>

Puedes entregar el nmero de la versin y tipo de codificacin como parmetros del metodo header.
<?php
echo $xml->header(array('version'=>'1.1'));
// genera: <?xml version="1.1" encoding="UTF-8" ?>
?>

8 Librerias de utilidades del ncleo


CakePHP incluye libreras de utilidades de propsito general que se pueden invocar desde
cualquier lugar de la aplicacin. Por ejemplo, Set y HttpSocket.

8.1 App
App is a very small utility library. It only contains the import method. But, with the import method,
you can accomplish a lot.
// examples
App::Import('Core','File');
App::Import('Model','Post');
App::import('Vendor', 'geshi');
App::import('Vendor', 'flickr/flickr');
App::import('Vendor', 'SomeName', array('file' => 'some.name.php'));
App::import('Vendor',

'WellNamed',

array('file'

=>

'services'.DS.'well.named.php'));

You can read more about it in the book or the API documentation

8.2 Inflector
La clase Inflector toma una cadena y puede manipularla produciendo variaciones en las palabras
tales como pluralizacion y notacion de CaMeLlo, siendo accedida normalmente de forma esttica.
Ejemplo: Inflector::pluralize('ejemplo') retorna "ejemplos".
8.2.1 Class methods
Input
Output
pluralize Apple, Orange, Person, Man
Apples, Oranges, People, Men
singularize Apples, Oranges, People, Men
Apple, Orange, Person, Man
camelize
Apple_pie, some_thing, people_person
ApplePie, SomeThing, PeoplePerson
It should be noted that underscore will only convert camelCase formatted words. Words
underscore that contains spaces will be lower-cased, but will not contain an underscore.
applePie, someThing
apple_pie, some_thing
humanize apple_pie, some_thing, people_person
Apple Pie, Some Thing, People Person
tableize
Apple, UserProfileSetting, Person
apples, user_profile_settings, people

classify
variable

apples, user_profile_settings, people


Apple, UserProfileSetting, Person
apples, user_result, people_people
apples, userResult, peoplePeople
Slug converts special characters into latin versions and converting unmatched characters

slug

and spaces to underscores. The slug method expects UTF-8 encoding.


apple pure
apple_puree

8.3 Cadenas (String)


La clase String incluye mtodos para crear y manipular cadenas cmodamente. Estos mtodos
se acceden normalmente de forma esttica; por ejemplo: String::uuid().
8.3.1 uuid
El mtodo uuid se utiliza para generar identificadores nicos de acuerdo a la especificacin
RFC 4122. El uuid es una cadena de 128 bits con el formato 485fc381-e790-47a3-9794-1337c0a8fe68.
String::uuid(); // 485fc381-e790-47a3-9794-1337c0a8fe68

8.3.2 tokenize
string tokenize ($data, $separator = ',', $leftBound = '(', $rightBound = ')')
Divide una cadena en subcadenas (tokens), ignorando cualquier instancia de $separator que
aparece entre $leftBound y $rightBound.
8.3.3 insert
string insert ($string, $data, $options = array())
El mtodo insert se utiliza para sustituir las claves de una plantilla (basada en una cadena de
caracteres) por los valores de una matriz asociativa.
String::insert('Mi nombre es :nombre y tengo :edad aos de edad.', array('nombre'
=> 'Bob', 'edad' => '65'));
// genera: "Mi nombre es Bob y tengo 65 aos de edad."

8.3.4 cleanInsert
string cleanInsert ($string, $options = array())
Limpia la cadena String::insert de acuerdo a las opciones de la matriz $options, en funcin de la
clave 'clean' de $options. El mtodo que se utiliza por defecto es texto, pero tambin est disponible
html. El objetivo de esta funcin es sustituir, alrededor de los marcadores, los espacios en blanco y las
marcas innecesarias que no sustituye Set::insert.

8.4 Xml
Con la clase Xml podemos generar y analizar cmodamente fragmentos y documentos XML.
Esta solucin, ntegra en PHP, slo necesita que la extensin Xml/Expat est instalada.
8.4.1 Anlisis Xml
Para analizar un documento con la clase Xml, necesitamos una cadena con el Xml que
queremos analizar.
$input = '<' . '?xml version="1.0" encoding="UTF-8" ?' . '>
<container>
<element id="first-el">
<name>My element</name>
<size>20</size>
</element>
<element>
<name>Your element</name>
<size>30</size>
</element>
</container>';
$xml = new Xml($input);

Esto crea un objeto de tipo documento Xml. A partir de este momento, el objeto se puede leer,
manipular, y convertir en una cadena de caracteres. .
Con el ejemplo anterior podemos hacer lo siguiente:
echo $xml->children[0]->children[0]->name;
// outputs 'element'

echo $xml->children[0]->children[0]->children[0]->children[0]->value;
// outputs 'My Element'
echo $xml->children[0]->child('element')->attributes['id'];
//outputs 'first-el'

8.5 Set
Gestionar correctamente las matrices puede ser una herramienta muy til, poderosa y puede
ayudar a construir un cdigo ms optimizado y elegante. Para esto, CakePHP ofrece un conjunto muy
til de utilidades estticas en la clase Set.
Se puede llamar a la clase Set de CakePHP desde cualquier modelo o controlador, del mismo
modo que se llama a Inflector. Por ejemplo, Set::combine().
8.5.1 Set-compatible Path syntax
The Path syntax is used by (for example) sort, and is used to define a path.
Usage example (using Set::sort()):
$a = array(
0 => array('Person' => array('name' => 'Jeff')),
1 => array('Shirt' => array('color' => 'black'))
);
$result = Set::sort($a, '{n}.Person.name', 'asc');
/* $result now looks like:
Array
(
[0] => Array
(
[Shirt] => Array
(
[color] => black
)
)
[1] => Array
(
[Person] => Array
(
[name] => Jeff
)
)
)
*/

As you can see in the example above, some things are wrapped in {}'s, others not. In the table
below, you can see which options are available.
Expression
{n}
{s}
Foo
{[a-z]+}

Definition
Represents a numeric key
Represents a string
Any string (without enclosing brackets) is treated like a string literal.
Any string enclosed in brackets (besides {n} and {s}) is interpreted as a regular

expression.
This section needs to be expanded.
8.5.2 insert
array Set::insert ($list, $path, $data = null)
Inserta $data en un arreglo segun es definido en $path.
$a = array(
'pages' => array('name' => 'page')
);
$result = Set::insert($a, 'files', array('name' => 'files'));
/* $result ahora queda como:
Array
(
[pages] => Array
(
[name] => page
)
[files] => Array
(
[name] => files
)
)
*/
$a = array(
'pages' => array('name' => 'page')
);
$result = Set::insert($a, 'pages.name', array());
/* $result ahora queda:
Array

(
[pages] => Array
(
[name] => Array
(
)
)
)
*/
$a = array(
'pages' => array(
0 => array('name' => 'main'),
1 => array('name' => 'about')
)
);
$result = Set::insert($a, 'pages.1.vars', array('title' => 'page title'));
/* $result ahora queda como:
Array
(
[pages] => Array
(
[0] => Array
(
[name] => main
)
[1] => Array
(
[name] => about
[vars] => Array
(
[title] => page title
)
)
)
)
*/

8.5.3 sort
array Set::sort ($data, $path, $dir)
Ordena un arreglo segn cualquier valor, determinado por una ruta compatible con Set.
$a = array(
0 => array('Person' => array('name' => 'Jeff')),
1 => array('Shirt' => array('color' => 'black'))
);
$result = Set::sort($a, '{n}.Person.name', 'asc');
/* $result ahora queda:
Array
(
[0] => Array
(
[Shirt] => Array
(
[color] => black
)
)
[1] => Array
(
[Person] => Array
(
[name] => Jeff
)
)
)
*/
$result = Set::sort($a, '{n}.Shirt', 'asc');
/* $result ahora queda:
Array
(
[0] => Array
(
[Person] => Array
(
[name] => Jeff

)
)
[1] => Array
(
[Shirt] => Array
(
[color] => black
)
)
)
*/
$result = Set::sort($a, '{n}', 'desc');
/* $result ahora queda:
Array
(
[0] => Array
(
[Shirt] => Array
(
[color] => black
)
)
[1] => Array
(
[Person] => Array
(
[name] => Jeff
)
)
)
*/
$a = array(
array(7,6,4),
array(3,4,5),
array(3,2,1),
);

$result = Set::sort($a, '{n}.{n}', 'asc');


/* $result ahora queda:
Array
(
[0] => Array
(
[0] => 3
[1] => 2
[2] => 1
)
[1] => Array
(
[0] => 3
[1] => 4
[2] => 5
)
[2] => Array
(
[0] => 7
[1] => 6
[2] => 4
)
)
*/

8.5.4 reverse
array Set::reverse ($object)
Set::reverse es bsicamente el opuesto de Set::map. Convierte un objeto en un arreglo. Si
$object no es un objeto, reverse simplemente retornar $object.
$result = Set::reverse(null);
// Null
$result = Set::reverse(false);
// false
$a = array(
'Post' => array('id'=> 1, 'title' => 'First Post'),
'Comment' => array(

array('id'=> 1, 'title' => 'First Comment'),


array('id'=> 2, 'title' => 'Second Comment')
),
'Tag' => array(
array('id'=> 1, 'title' => 'First Tag'),
array('id'=> 2, 'title' => 'Second Tag')
),
);
$map = Set::map($a); // Convierte $a en un objeto de clase
/* $map ahora queda como:
stdClass Object
(
[_name_] => Post
[id] => 1
[title] => First Post
[Comment] => Array
(
[0] => stdClass Object
(
[id] => 1
[title] => First Comment
)
[1] => stdClass Object
(
[id] => 2
[title] => Second Comment
)
)
[Tag] => Array
(
[0] => stdClass Object
(
[id] => 1
[title] => First Tag
)
[1] => stdClass Object
(
[id] => 2
[title] => Second Tag

)
)
)
*/
$result = Set::reverse($map);
/* $result ahora queda como:
Array
(
[Post] => Array
(
[id] => 1
[title] => First Post
[Comment] => Array
(
[0] => Array
(
[id] => 1
[title] => First Comment
)
[1] => Array
(
[id] => 2
[title] => Second Comment
)
)
[Tag] => Array
(
[0] => Array
(
[id] => 1
[title] => First Tag
)
[1] => Array
(
[id] => 2
[title] => Second Tag
)
)

)
)
*/
$result = Set::reverse($a['Post']); // Slo retorna un arreglo
/* $result ahora queda como:
Array
(
[id] => 1
[title] => First Post
)
*/

8.5.5 combine
array Set::combine ($data, $path1 = null, $path2 = null, $groupPath = null)
Crea un arreglo asociativo usando un $path1 como la ruta para construir las llaves, y
opcionalmente $path2 como la ruta para obtener los valores. Si $path2 no es especificado, todos los
valores sern inicializados como null (lo cual es til para Set::merge). Opcionalmente se pueden
agrupar los valores obtenidos segn la ruta especificada en $groupPath.
$result = Set::combine(array(), '{n}.User.id', '{n}.User.Data');
// $result == array();
$result = Set::combine('', '{n}.User.id', '{n}.User.Data');
// $result == array();
$a = array(
array('User' => array('id' => 2, 'group_id' => 1,
'Data' => array('user' => 'mariano.iglesias','name' => 'Mariano
Iglesias'))),
array('User' => array('id' => 14, 'group_id' => 2,
'Data' => array('user' => 'phpnut', 'name' => 'Larry E.
Masters'))),
array('User' => array('id' => 25, 'group_id' => 1,
'Data' => array('user' => 'gwoo','name' => 'The Gwoo'))));
$result = Set::combine($a, '{n}.User.id');
/* $result ahora queda como:

Array
(
[2] =>
[14] =>
[25] =>
)
*/
$result = Set::combine($a, '{n}.User.id', '{n}.User.non-existant');
/* $result ahora queda como:
Array
(
[2] =>
[14] =>
[25] =>
)
*/
$result = Set::combine($a, '{n}.User.id', '{n}.User.Data');
/* $result ahora queda como:
Array
(
[2] => Array
(
[user] => mariano.iglesias
[name] => Mariano Iglesias
)
[14] => Array
(
[user] => phpnut
[name] => Larry E. Masters
)
[25] => Array
(
[user] => gwoo
[name] => The Gwoo
)
)
*/

$result = Set::combine($a, '{n}.User.id', '{n}.User.Data.name');


/* $result ahora queda como:
Array
(
[2] => Mariano Iglesias
[14] => Larry E. Masters
[25] => The Gwoo
)
*/
$result = Set::combine($a, '{n}.User.id', '{n}.User.Data', '{n}.User.group_id');
/* $result ahora queda como:
Array
(
[1] => Array
(
[2] => Array
(
[user] => mariano.iglesias
[name] => Mariano Iglesias
)
[25] => Array
(
[user] => gwoo
[name] => The Gwoo
)
)
[2] => Array
(
[14] => Array
(
[user] => phpnut
[name] => Larry E. Masters
)
)
)
*/

$result

Set::combine($a,

'{n}.User.id',

'{n}.User.group_id');
/* $result ahora queda como:
Array
(
[1] => Array
(
[2] => Mariano Iglesias
[25] => The Gwoo
)
[2] => Array
(
[14] => Larry E. Masters
)
)
*/
$result = Set::combine($a, '{n}.User.id');
/* $result ahora queda como:
Array
(
[2] =>
[14] =>
[25] =>
)
*/
$result = Set::combine($a, '{n}.User.id', '{n}.User.Data');
/* $result ahora queda como:
Array
(
[2] => Array
(
[user] => mariano.iglesias
[name] => Mariano Iglesias
)
[14] => Array
(
[user] => phpnut

'{n}.User.Data.name',

[name] => Larry E. Masters


)
[25] => Array
(
[user] => gwoo
[name] => The Gwoo
)
)
*/
$result = Set::combine($a, '{n}.User.id', '{n}.User.Data.name');
/* $result ahora queda como:
Array
(
[2] => Mariano Iglesias
[14] => Larry E. Masters
[25] => The Gwoo
)
*/
$result = Set::combine($a, '{n}.User.id', '{n}.User.Data', '{n}.User.group_id');
/* $result ahora queda como:
Array
(
[1] => Array
(
[2] => Array
(
[user] => mariano.iglesias
[name] => Mariano Iglesias
)
[25] => Array
(
[user] => gwoo
[name] => The Gwoo
)
)
[2] => Array
(

[14] => Array


(
[user] => phpnut
[name] => Larry E. Masters
)
)
)
*/
$result

Set::combine($a,

'{n}.User.id',

'{n}.User.Data.name',

'{n}.User.group_id');
/* $result ahora queda como:
Array
(
[1] => Array
(
[2] => Mariano Iglesias
[25] => The Gwoo
)
[2] => Array
(
[14] => Larry E. Masters
)
)
*/
$result = Set::combine($a, '{n}.User.id', array('{0}: {1}', '{n}.User.Data.user',
'{n}.User.Data.name'), '{n}.User.group_id');
/* $result ahora queda como:
Array
(
[1] => Array
(
[2] => mariano.iglesias: Mariano Iglesias
[25] => gwoo: The Gwoo
)
[2] => Array
(
[14] => phpnut: Larry E. Masters

)
)
*/
$result

Set::combine($a,

array('{0}:

{1}',

'{n}.User.Data.user',

'{n}.User.Data.name'), '{n}.User.id');
/* $result ahora queda como:
Array
(
[mariano.iglesias: Mariano Iglesias] => 2
[phpnut: Larry E. Masters] => 14
[gwoo: The Gwoo] => 25
)
*/
$result

Set::combine($a,

array('{1}:

{0}',

'{n}.User.Data.user',

'{n}.User.Data.name'), '{n}.User.id');
/* $result ahora queda como:
Array
(
[Mariano Iglesias: mariano.iglesias] => 2
[Larry E. Masters: phpnut] => 14
[The Gwoo: gwoo] => 25
)
*/
$result

Set::combine($a,

array('%1$s:

%2$d',

'{n}.User.Data.user',

'{n}.User.id'), '{n}.User.Data.name');
/* $result ahora queda como:
Array
(
[mariano.iglesias: 2] => Mariano Iglesias
[phpnut: 14] => Larry E. Masters
[gwoo: 25] => The Gwoo
)
*/
$result

Set::combine($a,

array('%2$d:

%1$s',

'{n}.User.Data.user',

'{n}.User.id'), '{n}.User.Data.name');
/* $result ahora queda como:
Array
(
[2: mariano.iglesias] => Mariano Iglesias
[14: phpnut] => Larry E. Masters
[25: gwoo] => The Gwoo
)
*/

8.5.6 normalize
array Set::normalize ($list, $assoc = true, $sep = ',', $trim = true)
Normaliza un string o arreglo lista.
$a = array('Tree', 'CounterCache',
'Upload' => array(
'folder' => 'products',
'fields' => array('image_1_id', 'image_2_id',
'image_3_id', 'image_4_id', 'image_5_id')));
$b =

array('Cacheable' => array('enabled' => false),


'Limit',
'Bindable',
'Validator',
'Transactional');

$result = Set::normalize($a);
/* $result ahora queda como:
Array
(
[Tree] =>
[CounterCache] =>
[Upload] => Array
(
[folder] => products
[fields] => Array
(
[0] => image_1_id
[1] => image_2_id
[2] => image_3_id

[3] => image_4_id


[4] => image_5_id
)
)
)
*/
$result = Set::normalize($b);
/* $result ahora queda como:
Array
(
[Cacheable] => Array
(
[enabled] =>
)
[Limit] =>
[Bindable] =>
[Validator] =>
[Transactional] =>
)
*/
$result = Set::merge($a, $b); // Ahora mezclamos ambos y luego normalizamos
/* $result ahora queda como:
Array
(
[0] => Tree
[1] => CounterCache
[Upload] => Array
(
[folder] => products
[fields] => Array
(
[0] => image_1_id
[1] => image_2_id
[2] => image_3_id
[3] => image_4_id
[4] => image_5_id
)

)
[Cacheable] => Array
(
[enabled] =>
)
[2] => Limit
[3] => Bindable
[4] => Validator
[5] => Transactional
)
*/
$result = Set::normalize(Set::merge($a, $b));
/* $result ahora queda:
Array
(
[Tree] =>
[CounterCache] =>
[Upload] => Array
(
[folder] => products
[fields] => Array
(
[0] => image_1_id
[1] => image_2_id
[2] => image_3_id
[3] => image_4_id
[4] => image_5_id
)
)
[Cacheable] => Array(
[enabled] =>
)
[Limit] =>
[Bindable] =>
[Validator] =>
[Transactional] =>
)
*/

8.5.7 countDim
integer Set::countDim ($array = null, $all = false, $count = 0)
Cuenta las dimensiones de un arreglo. Si $all est seteado como falso (su valor por defecto) slo
se considerarn las dimensiones del primer elemento en el arreglo.
$data = array('one', '2', 'three');
$result = Set::countDim($data);
// $result == 1
$data = array('1' => '1.1', '2', '3');
$result = Set::countDim($data);
// $result == 1
$data

array('1'

=>

array('1.1'

=>

'1.1.1'),

'2',

'3'

=>

array('3.1'

=>

'3.1.1'));
$result = Set::countDim($data);
// $result == 2
$data = array('1' => '1.1', '2', '3' => array('3.1' => '3.1.1'));
$result = Set::countDim($data);
// $result == 1
$data = array('1' => '1.1', '2', '3' => array('3.1' => '3.1.1'));
$result = Set::countDim($data, true);
// $result == 2
$data

array('1'

=>

array('1.1'

=>

'1.1.1'),

'2',

'3'

=>

array('3.1'

=>

=>

'1.1.1'),

'2',

'3'

=>

array('3.1'

=>

=>

'1.1.1'),

array('2'

=>

array('2.1'

=>

array('3.1.1' => '3.1.1.1')));


$result = Set::countDim($data);
// $result == 2
$data

array('1'

=>

array('1.1'

array('3.1.1' => '3.1.1.1')));


$result = Set::countDim($data, true);
// $result == 3
$data

array('1'

array('2.1.1'

=>

=>

array('1.1'

'2.1.1.1'))),

'3'

=>

array('3.1'

=>

array('3.1.1'

=>

'3.1.1.1')));
$result = Set::countDim($data, true);
// $result == 4
$data

array('1'

array('2.1.1'

=>

=>

array('1.1'

=>

array('2.1.1.1')))),

'1.1.1'),
'3'

=>

array('2'

array('2.1'

=>

array('3.1.1'

=>

=>

array('2.1'

=>

'3'

=>

array('3.1'

=>

array('2'

=>

array('2.1'

=>

=>

array('3.1'

=>

array('3.1'

=>
=>

'3.1.1.1')));
$result = Set::countDim($data, true);
// $result == 5
$data

array('1'

array('2.1.1'

=>

=>

array('1.1'

array('2.1.1.1'

=>
=>

'1.1.1'),

array('2'

'2.1.1.1.1')))),

array('3.1.1' => '3.1.1.1')));


$result = Set::countDim($data, true);
// $result == 5
$set

array('1'

array('2.1.1'

=>

=>

array('1.1'

array('2.1.1.1'

=>
=>

'1.1.1'),

'2.1.1.1.1')))),

'3'

array('3.1.1' => '3.1.1.1')));


$result = Set::countDim($set, false, 0);
// $result == 2
$result = Set::countDim($set, true);
// $result == 5

8.5.8 diff
array Set::diff ($val1, $val2 = null)
Calcula la diferencia entre un Set y un arreglo, dos Sets, o dos arreglos
$a = array(
0 => array('name' => 'main'),
1 => array('name' => 'about')
);
$b = array(
0 => array('name' => 'main'),
1 => array('name' => 'about'),
2 => array('name' => 'contact')
);

$result = Set::diff($a, $b);


/* $result ahora queda:
Array
(
[2] => Array
(
[name] => contact
)
)
*/
$result = Set::diff($a, array());
/* $result ahora queda:
Array
(
[0] => Array
(
[name] => main
)
[1] => Array
(
[name] => about
)
)
*/
$result = Set::diff(array(), $b);
/* $result ahora queda:
Array
(
[0] => Array
(
[name] => main
)
[1] => Array
(
[name] => about
)
[2] => Array
(

[name] => contact


)
)
*/
$b = array(
0 => array('name' => 'me'),
1 => array('name' => 'about')
);
$result = Set::diff($a, $b);
/* $result ahora queda:
Array
(
[0] => Array
(
[name] => main
)
)
*/

8.5.9 check
boolean Set::check ($data, $path = null)
Verifica si una ruta particular est seteada en un arreglo
$set = array(
'My Index 1' => array('First' => 'The first item')
);
$result = Set::check($set, 'My Index 1.First');
// $result == True
$result = Set::check($set, 'My Index 1');
// $result == True
$result = Set::check($set, array());
// $result == array('My Index 1' => array('First' => 'The first item'))
$set = array(
'My Index 1' => array('First' =>
array('Second' =>
array('Third' =>

array('Fourth' => 'Heavy. Nesting.'))))


);
$result = Set::check($set, 'My Index 1.First.Second');
// $result == True
$result = Set::check($set, 'My Index 1.First.Second.Third');
// $result == True
$result = Set::check($set, 'My Index 1.First.Second.Third.Fourth');
// $result == True
$result = Set::check($set, 'My Index 1.First.Seconds.Third.Fourth');
// $result == False

8.5.10 remove
boolean Set::remove ($list, $path = null)
Elimina un elemento de un Set o arreglo segn sea definido en una ruta en la variable $path.
$a = array(
'pages'

=> array('name' => 'page'),

'files'

=> array('name' => 'files')

);
$result = Set::remove($a, 'files', array('name' => 'files'));
/* $result ahora queda como:
Array
(
[pages] => Array
(
[name] => page
)
)
*/

8.5.11 classicExtract
array Set::classicExtract ($data, $path = null)
Obtiene un valor desde un arreglo u objeto que est contenido en una ruta entregada usando una
sintxis de ruta de arreglo, es decir:
"{n}.Person.{[a-z]+}" - Donde "{n}" representa una llave numrica, "Person" representa una
cadena literal
"{[a-z]+}" (es decir, cualquier string literal encerrado en llaves junto a {n} y {s}) es
interpretado como una expresin regular.
Ejemplo 1
$a = array(
array('Article' => array('id' => 1, 'title' => 'Article 1')),
array('Article' => array('id' => 2, 'title' => 'Article 2')),
array('Article' => array('id' => 3, 'title' => 'Article 3')));
$result = Set::extract($a, '{n}.Article.id');
/* $result ahora queda:
Array
(
[0] => 1
[1] => 2
[2] => 3
)
*/
$result = Set::extract($a, '{n}.Article.title');
/* $result ahora queda:
Array
(
[0] => Article 1
[1] => Article 2
[2] => Article 3
)
*/
$result = Set::extract($a, '1.Article.title');
// $result == "Article 2"
$result = Set::extract($a, '3.Article.title');// $result == null

Ejemplo 2 Plain Text View


$a = array(
0 => array('pages' => array('name' => 'page')),
1 => array('fruites'=> array('name' => 'fruit')),
'test' => array(array('name' => 'jippi')),
'dot.test' => array(array('name' => 'jippi'))
);
$result = Set::extract($a, '{n}.{s}.name');
/* $result ahora queda como:
Array
(
[0] => Array
(
[0] => page
)
[1] => Array
(
[0] => fruit
)
)
*/
$result = Set::extract($a, '{s}.{n}.name');
/* $result ahora queda como:
Array
(
[0] => Array
(
[0] => jippi
)
[1] => Array
(
[0] => jippi
)
)
*/
$result = Set::extract($a,'{\w+}.{\w+}.name');
/* $result ahora queda como:

Array
(
[0] => Array
(
[pages] => page
)
[1] => Array
(
[fruites] => fruit
)
[test] => Array
(
[0] => jippi
)
[dot.test] => Array
(
[0] => jippi
)
)
*/
$result = Set::extract($a,'{\d+}.{\w+}.name');
/* $result ahora queda como:
Array
(
[0] => Array
(
[pages] => page
)
[1] => Array
(
[fruites] => fruit
)
)
*/
$result = Set::extract($a,'{n}.{\w+}.name');
/* $result Ahora queda como:
Array
(
[0] => Array

(
[pages] => page
)
[1] => Array
(
[fruites] => fruit
)
)
*/
$result = Set::extract($a,'{s}.{\d+}.name');
/* $result ahora queda como:
Array
(
[0] => Array
(
[0] => jippi
)
[1] => Array
(
[0] => jippi
)
)
*/
$result = Set::extract($a,'{s}');
/* $result ahora queda como:
Array
(
[0] => Array
(
[0] => Array
(
[name] => jippi
)
)
[1] => Array
(
[0] => Array
(

[name] => jippi


)
)
)
*/
$result = Set::extract($a,'{[a-z]}');
/* $result ahora queda como:
Array
(
[test] => Array
(
[0] => Array
(
[name] => jippi
)
)
[dot.test] => Array
(
[0] => Array
(
[name] => jippi
)
)
)
*/
$result = Set::extract($a, '{dot\.test}.{n}');
/* $result ahora queda como:
Array
(
[dot.test] => Array
(
[0] => Array
(
[name] => jippi
)
)
)
*/

8.5.12 matches
boolean Set::matches ($conditions, $data=array(), $i = null, $length=null)
Set::matches puede ser usado para ver su un item o una ruta calza con ciertas condiciones.
$a = array(
array('Article' => array('id' => 1, 'title' => 'Article 1')),
array('Article' => array('id' => 2, 'title' => 'Article 2')),
array('Article' => array('id' => 3, 'title' => 'Article 3')));
$res=Set::matches(array('id>2'), $a[1]['Article']);
// returns false
$res=Set::matches(array('id>=2'), $a[1]['Article']);
// returns true
$res=Set::matches(array('id>=3'), $a[1]['Article']);
// returns false
$res=Set::matches(array('id<=2'), $a[1]['Article']);
// returns true
$res=Set::matches(array('id<2'), $a[1]['Article']);
// returns false
$res=Set::matches(array('id>1'), $a[1]['Article']);
// returns true
$res=Set::matches(array('id>1', 'id<3', 'id!=0'), $a[1]['Article']);
// returns true
$res=Set::matches(array('3'), null, 3);
// returns true
$res=Set::matches(array('5'), null, 5);
// returns true
$res=Set::matches(array('id'), $a[1]['Article']);
// returns true
$res=Set::matches(array('id', 'title'), $a[1]['Article']);
// returns true
$res=Set::matches(array('non-existant'), $a[1]['Article']);
// returns false
$res=Set::matches('/Article[id=2]', $a);
// returns true
$res=Set::matches('/Article[id=4]', $a);
// returns false
$res=Set::matches(array(), $a);
// returns true

8.5.13 extract
array Set::extract ($path, $data=null, $options=array())
Set::extract utiliza la sintxis bsica XPath 2.0 para retornar subconjuntos de la data resultante
de un find(). Esta funcin permite extraer datos rpidamente sin tener que hacer un ciclo a travs de un
arreglos multidimensionales o de estructuras de rbol.
Si $path es un arreglo o $data es vaco la llamada se redirigir a la funcin Set::classicExtract.
// Uso comn:
$users = $this->User->find("all");
$results = Set::extract('/User/id', $users);
// results retorna:
// array(1,2,3,4,5,...);

Los seleccionadores implementados actualmente son:


Seleccionador
/User/id
/User[2]/name
/User[id<2]
/User[id>2][<5]
/
Post/Comment[author_name=jo
hn]/../name
/Posts[title]
/Comment/.[1]
/Comment/.[:last]
/Comment/.[:first]
/Comment[text=/cakephp/i]

Descripcin
Similar al clsico {n}.User.id
Selecciona el nombre del segundo User
Selecciona todos los Users con un id < 2
Selecciona todos los Users con un id > 2 pero < 5
Selecciona los nombres de todos los Posts que tienen al menos un
comentario escrito por john
Selecciona todos los Post que tienen la llave 'title'
Selecciona el contenido del primer comentario
Selecciona el ltimo comentario
Selecciona el primer comentario
Selecciona todos los comentarios que tienen un texto que calce con la

expresin regular (regex) /cakephp/i


/Comment/@*
Selecciona todos los nombres clave de todos los comentarios
Actualmente, solo las rutas absolutas con un solo '/' estn soportadas. Por favor reporte
cualquier bug que encuentre en ellas, y tambin las sugerencias para futuras funcionalidades son bien
recibidas.
Para aprender ms acerca de Set::extract refirase a la funcin testExtract() en
/cake/tests/cases/libs/set.test.php.

8.5.14 format
array Set::format ($data, $format, $keys)
Returns a series of values extracted from an array, formatted in a format string.
$data = array(
array('Person' => array('first_name' => 'Nate', 'last_name' => 'Abele',
'city' => 'Boston', 'state' => 'MA', 'something' => '42')),
array('Person' => array('first_name' => 'Larry', 'last_name' => 'Masters',
'city' => 'Boondock', 'state' => 'TN', 'something' => '{0}')),
array('Person'

=>

array('first_name'

=>

'Garrett',

'last_name'

=>

'Woodworth', 'city' => 'Venice Beach', 'state' => 'CA', 'something' => '{1}')));
$res

Set::format($data,

'{1},

{0}',

array('{n}.Person.first_name',

'{n}.Person.last_name'));
/*
Array
(
[0] => Abele, Nate
[1] => Masters, Larry
[2] => Woodworth, Garrett
)
*/
$res

Set::format($data,

'{0},

{1}',

array('{n}.Person.city',

'{{0},

{1}}',

array('{n}.Person.city',

'{n}.Person.state'));
/*
Array
(
[0] => Boston, MA
[1] => Boondock, TN
[2] => Venice Beach, CA
)
*/
$res

Set::format($data,

'{n}.Person.state'));
/*
Array
(

[0] => {Boston, MA}


[1] => {Boondock, TN}
[2] => {Venice Beach, CA}
)
*/
$res

Set::format($data,

'{%2$d,

%1$s}',

array('{n}.Person.something',

'{n}.Person.something'));
/*
Array
(
[0] => {42, 42}
[1] => {0, {0}}
[2] => {0, {1}}
)
*/
$res

Set::format($data,

'%2$d,

%1$s',

array('{n}.Person.first_name',

'%1$s,

%2$d',

array('{n}.Person.first_name',

'{n}.Person.something'));
/*
Array
(
[0] => 42, Nate
[1] => 0, Larry
[2] => 0, Garrett
)
*/
$res

Set::format($data,

'{n}.Person.something'));
/*
Array
(
[0] => Nate, 42
[1] => Larry, 0
[2] => Garrett, 0
)
*/

8.5.15 enum
string Set::enum ($select, $list=null)
The enum method works well when using html select elements. It returns a value from an array
list if the key exists.
If a comma separated $list is passed arrays are numeric with the key of the first being 0 $list =
'no, yes' would translate to $list = array(0 => 'no', 1 => 'yes');
If an array is used, keys can be strings example: array('no' => 0, 'yes' => 1);
$list defaults to 0 = no 1 = yes if param is not passed
$res = Set::enum(1, 'one, two');
// $res is 'two'
$res = Set::enum('no', array('no' => 0, 'yes' => 1));
// $res is 0
$res = Set::enum('first', array('first' => 'one', 'second' => 'two'));
// $res is 'one'

8.5.16 numeric
boolean Set::numeric ($array=null)
Checks to see if all the values in the array are numeric
$data = array('one');
$res = Set::numeric(array_keys($data));
// $res is true
$data = array(1 => 'one');
$res = Set::numeric($data);
// $res is false
$data = array('one');
$res = Set::numeric($data);

// $res is false
$data = array('one' => 'two');
$res = Set::numeric($data);
// $res is false
$data = array('one' => 1);
$res = Set::numeric($data);
// $res is true
$data = array(0);
$res = Set::numeric($data);
// $res is true
$data = array('one', 'two', 'three', 'four', 'five');
$res = Set::numeric(array_keys($data));
// $res is true
$data = array(1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four', 5 =>
'five');
$res = Set::numeric(array_keys($data));
// $res is true
$data = array('1' => 'one', 2 => 'two', 3 => 'three', 4 => 'four', 5 =>
'five');
$res = Set::numeric(array_keys($data));
// $res is true
$data = array('one', 2 => 'two', 3 => 'three', 4 => 'four', 'a' =>
'five');
$res = Set::numeric(array_keys($data));
// $res is false

8.5.17 map
object Set::map ($class = 'stdClass', $tmp = 'stdClass')
This method Maps the contents of the Set object to an object hierarchy while maintaining
numeric keys as arrays of objects.
Basically, the map function turns array items into initialized class objects. By default it turns an
array into a stdClass Object, however you can map values into any type of class. Example:
Set::map($array_of_values, 'nameOfYourClass');
$data = array(
array(
"IndexedPage" => array(
"id" => 1,
"url" => 'http://blah.com/',
'hash' => '68a9f053b19526d08e36c6a9ad150737933816a5',
'get_vars' => '',
'redirect' => '',
'created' => "1195055503",
'updated' => "1195055503",
)
),
array(
"IndexedPage" => array(
"id" => 2,
"url" => 'http://blah.com/',
'hash' => '68a9f053b19526d08e36c6a9ad150737933816a5',
'get_vars' => '',
'redirect' => '',
'created' => "1195055503",
'updated' => "1195055503",
),
)
);
$mapped = Set::map($data);
/* $mapped now looks like:
Array

(
[0] => stdClass Object
(
[_name_] => IndexedPage
[id] => 1
[url] => http://blah.com/
[hash] => 68a9f053b19526d08e36c6a9ad150737933816a5
[get_vars] =>
[redirect] =>
[created] => 1195055503
[updated] => 1195055503
)
[1] => stdClass Object
(
[_name_] => IndexedPage
[id] => 2
[url] => http://blah.com/
[hash] => 68a9f053b19526d08e36c6a9ad150737933816a5
[get_vars] =>
[redirect] =>
[created] => 1195055503
[updated] => 1195055503
)
)
*/

Using Set::map() with a custom class for second parameter:


class MyClass {
function sayHi() {
echo 'Hi!';
}
}
$mapped = Set::map($data, 'MyClass');
//Now you can access all the properties as in the example above,
//but also you can call MyClass's methods
$mapped->[0]->sayHi();

8.5.18 pushDiff
array Set::pushDiff ($array1, $array2)
This function merges two arrays and pushes the differences in array2 to the bottom of the
resultant array.
Example 1
$array1

array('ModelOne'

=>

array('id'=>1001,

'field_one'=>'a1.m1.f1',

=>

array('id'=>1003,

'field_one'=>'a3.m1.f1',

'field_two'=>'a1.m1.f2'));
$array2

array('ModelOne'

'field_two'=>'a3.m1.f2', 'field_three'=>'a3.m1.f3'));
$res = Set::pushDiff($array1, $array2);
/* $res now looks like:
Array
(
[ModelOne] => Array
(
[id] => 1001
[field_one] => a1.m1.f1
[field_two] => a1.m1.f2
[field_three] => a3.m1.f3
)
)
*/

Example 2
$array1 = array("a"=>"b", 1 => 20938, "c"=>"string");
$array2 = array("b"=>"b", 3 => 238, "c"=>"string", array("extra_field"));
$res = Set::pushDiff($array1, $array2);
/* $res now looks like:
Array
(
[a] => b
[1] => 20938
[c] => string
[b] => b
[3] => 238
[4] => Array
(
[0] => extra_field
)
)
*/

8.5.19 filter
array Set::filter ($var, $isArray=null)
Filtra los elementos vacos de una ruta de arreglo, excluyendo el cero '0'.
$res = Set::filter(array('0', false, true, 0, array('una cosa', 'Te digo', 'es
asi', false)));
/* $res now looks like:
Array (
[0] => 0
[2] => 1
[3] => 0
[4] => Array
(
[0] => una cosa
[1] => Te digo
[2] => es asi
[3] =>
)
)
*/

8.5.20 merge
array Set::merge ($arr1, $arr2=null)
Esta funcin se puede considerar como un hbrido entre las funciones array_merge y
arraymerge_recursive, ambas de PHP. La diferencia esta en que si un arreglo de llaves contiene otro
arreglo entonces la funcin se comporta recursivamente, a diferencia de array_merge, pero no lo hace si
las llaves que contienen strings, a diferencia de array_merge_recursive. Verifica el test de unidad para
mas informacin.
Esta funcin trabaja sobre un numero ilimitado de argumentos y hace un casting como arreglos
a los argumentos que no lo sean.
$arry1 = array(
array(
'id' => '48c2570e-dfa8-4c32-a35e-0d71cbdd56cb',
'name' => 'mysql raleigh-workshop-08 < 2008-09-05.sql ',

'description' => 'Importing an sql dump'


),
array(
'id' => '48c257a8-cf7c-4af2-ac2f-114ecbdd56cb',
'name' => 'pbpaste | grep -i Impago | pbcopy',
'description' => 'Eliminar las lineas que dicen "Impago".',
)
);
$arry2 = 4;
$arry3 = array(0=>"Arreglo de prueba", "gatos"=>"perros");
$res = Set::merge($arry1, $arry2, $arry3);
/* $res ahora queda como:
Array
(
[0] => Array
(
[id] => 48c2570e-dfa8-4c32-a35e-0d71cbdd56cb
[name] => mysql raleigh-workshop-08 < 2008-09-05.sql
[description] => Importing an sql dump
)
[1] => Array
(
[id] => 48c257a8-cf7c-4af2-ac2f-114ecbdd56cb
[name] => pbpaste | grep -i Impago | pbcopy
[description] => Eliminar las lineas que dicen "Impago".
)
[2] => 4
[3] => Arreglo de prueba
[gatos] => perros
)
*/

8.5.21 contains
boolean Set::contains ($val1, $val2 = null)
Determines if one Set or array contains the exact keys and values of another.
$a = array(
0 => array('name' => 'main'),
1 => array('name' => 'about')
);
$b = array(
0 => array('name' => 'main'),
1 => array('name' => 'about'),
2 => array('name' => 'contact'),
'a' => 'b'
);
$result = Set::contains($a, $a);
// True
$result = Set::contains($a, $b);
// False
$result = Set::contains($b, $a);
// True

8.6 Security
The security library handles basic security measures such as providing methods for hashing and
encrypting data.

8.7 Cache
La clase Cache en CakePHP provee una interfaz generica con varios metodos de cache. Es
posible tener varias configuraciones y motores en el archivo app/config/core.php
8.7.1 Cache::read()
Cache::read($key, $config = null)
El mtodo Cache::read() se utiliza para leer el valor guardado en el cache con el nombre $key
de la configuracin $config. Si $config es null se utiliza el configuracin por defecto.

Cache::read() retornar el valor almacenado si es un cache valido o false si el cache expir o


no existe. Los contenidos del cache podran evaluarse como false, as que asegrate de usar el operador
de comparacin estricta === o !==.
Por ejemplo:
$cloud = Cache::read('cloud');
if ($cloud !== false) {
return $cloud;
}
// generate cloud data
// ...
// store data in cache
Cache::write('cloud', $cloud);
return $cloud;

8.7.2 Cache::write()
Cache::write($key, $value, $config = null);
Cache::write() escribir un valor $value en el Cache. Puedes leer o borrar ese valor ms
adelante refirindote a l por $key. Puedes especificar opcionalmente una configuracin para guardar
el cache. Si no se especifica $config se usar la configuracin por defecto. Cache::write() puede
almacenar cualquier tipo de objeto y es ideal para guardar resultados de bsquedas de modelos.
if (($posts = Cache::read('posts')) === false) {
$posts = $this->Post->find('all');
Cache::write('posts', $posts);
}

Usa Cache::write() y Cache::read() para reducir con facilidad la cantidad de viajes a la base de
datos para recuperar registros.
8.7.3 Cache::delete()
Cache::delete($key, $config = null)
Cache::delete() te permitir eliminar completamente cualquier objeto que tengas
guardado en el Cache.

8.7.4 Cache::config()
Cache::config() se usa para crear configuraciones de Cache adicionales. Estas
configuraciones a mayores pueden tener diferente duracin, motores, rutas, o prefijos de los que tiene
tu configuracin por defecto. Usar configuraciones mltiples te puede ayudar a reducir la cantidad de
veces que necesitas usar Cache::set() as como centralizar todos tus ajustes de Cache.
Debes especificar qu motor usar. No se pone por defecto a File.
Cache::config('short', array(
'engine' => 'File',
'duration'=> '+1 hours',
'path' => CACHE,
'prefix' => 'cake_short_'
));
// long
Cache::config('long', array(
'engine' => 'File',
'duration'=> '+1 week',
'probability'=> 100,
'path' => CACHE . 'long' . DS,
));

Aadiendo el cdigo anterior en tu app/config/core.php tendrs dos configuraciones de


Cache adicionales. El nombre de estas configuraciones 'short' o 'long' se usa como parmetro
$config para Cache::write() y Cache::read().
8.7.5 Cache::set()
Cache::set() te permite puentear temporalmente los ajustes de configuracin de Cache
para una operacin (normalmente read o write). Si usas Cache::set() para cambiar los ajustes para
una escritura, deberas usar Cache::set() antes de leer los datos ms tarde. Si no haces eso, se
usar la configuracin por defecto cuando se lea la clave de la cache.
Cache::set(array('duration' => '+30 days'));
Cache::write('results', $data);
// Later on
Cache::set(array('duration' => '+30 days'));
$results = Cache::read('results');

Si usar repetidamente Cache::set() quizs deberas crear una nueva configuracin de Cache. Esto
eliminar la necesidad de llamar a Cache::set().

8.8 HttpSocket
CakePHP includes an HttpSocket class which can be used easily for making requests, such as
those to web services.
8.8.1 get
The get method makes a simple HTTP GET request returning the results.
string get($uri, $query, $request)
$uri is the web address where the request is being made; $query is any query string
parameters, either in string form: "param1=foo&param2=bar" or as a keyed array: array('param1' =>
'foo', 'param2' => 'bar').
App::import('Core', 'HttpSocket');
$HttpSocket = new HttpSocket();
$results = $HttpSocket->get('http://www.google.com/search', 'q=cakephp');
//returns html for Google's search results for the query "cakephp"

8.8.2 post
The post method makes a simple HTTP POST request returning the results.
string function post ($uri, $data, $request)
The parameters for the post method are almost the same as the get method, $uri is the web
address where the request is being made; $query is the data to be posted, either in string form:
"param1=foo&param2=bar" or as a keyed array: array('param1' => 'foo', 'param2' => 'bar').
App::import('Core', 'HttpSocket');
$HttpSocket = new HttpSocket();
$results

$HttpSocket->post('www.somesite.com/add',

array('name'

=>

'test',

'type' => 'user'));


//$results contains what is returned from the post.

8.8.3 request
The base request method, which is called from all the wrappers (get, post, put, delete). Returns
the results of the request.

string function request($request)


$request is a keyed array of various options. Here is the format and default settings:
var $request = array(
'method' => 'GET',
'uri' => array(
'scheme' => 'http',
'host' => null,
'port' => 80,
'user' => null,
'pass' => null,
'path' => null,
'query' => null,
'fragment' => null
),
'auth' => array(
'method' => 'Basic',
'user' => null,
'pass' => null
),
'version' => '1.1',
'body' => '',
'line' => null,
'header' => array(
'Connection' => 'close',
'User-Agent' => 'CakePHP'
),
'raw' => null,
'cookies' => array()
);

9 Aplicaciones de Consola Principales


CakePHP viene con muchas aplicaciones de consola por defecto. Algunas de ellas se utilizan en
combinacion con algunas de las funcionalidades de Cake, (ejemplo ACL o i18n), y otras son de uso
general para ayudarte a producir ms rpido
Esta seccin explica cmo usar las aplicaciones de consola que vienen empaquetadas con
CakePHP
Antes de que sigas con esta seccin, tal vez quisieras ver La consola de CakePHP. La
configuracin de la consola no est cubierta por este captulo, as que si nunca la has usado
anteriormente, echale un vistazo.

9.1 Generacin de Cdigo con Bake


Ya has aprendido sobre scaffolding en CakePHP: una forma simple de armar una aplicacin con
slo una base de datos y algunas clases bsicas. La consola Bake es otro esfuerzo para tener CakePHP
corriendo rpido. La consola Bake puede crear cualquiera de los ingredientes bsicos de CakePHP:
modelos, vistas y controladores. Y no estamos hablando slo de clases estructurales: Bake puede crear
una aplicacin completamente funcional en slo unos minutos. De hecho, Bake es el paso natural que
toman las aplicaciones una vez que han pasado por la etapa de scaffolding
Para utilizar Bake necesitar ejecutar el script localizado en el directorio /cake/console/

$ cd ./cake/console/
$ cake bake

Dependiendo de tu configuracin, podras necesitar darle permisos de ejecucin al script bash o


llamarlo usando./cake bake. La consola de Cake corre usando PHP CLI (command line interface).
Si tienes algn problema con el script, asegrate de que tienes PHP CLI instalado y que adems tienes
los mdulos necesarios habilitados(Ej: MySQL).
Cuando utilices Bake por primera vez, te pedir que crees un archivo de configuracin para la
base de datos, si todava no creaste uno.

Una vez que hayas configurado la base de datos, cuando ejecutes Bake te presentar estas opciones:
--------------------------------------------------------------App : app
Path: /ruta/al/proyecto
--------------------------------------------------------------Interactive Bake Shell
--------------------------------------------------------------[D]atabase Configuration
[M]odel
[V]iew
[C]ontroller
[P]roject
[Q]uit
What would you like to Bake? (D/M/V/C/P/Q)
>

Alternativamente, puedes ejecutar cualquiera de estos comandos directamente de la lnea de comandos:


$ cake bake db_config
$ cake bake model
$ cake bake view
$ cake bake controller
$ cake bake project

9.1.1 Bake improvements in 1.3


For 1.3 bake has had a significant overhaul, and a number of features and enhancements have
been built in.
Two new tasks (FixtureTask and TestTask) are accessible from the main bake menu
A third task (TemplateTask) has been added for use in your shells.
All the different bake tasks now allow you to use connections other than default for baking.
Using the -connection parameter.
Plugin support has been greatly improved. You can use either -plugin PluginName or
Plugin.class.
Questions have been clarified, and made easier to understand.

Multiple validations on models has been added.


Self Associated models using parent_id are now detected. For example if your model is
named Thread, a ParentThread and ChildThread association will be created.
Fixtures and Tests can be baked separately.
Baked Tests include as many fixtures as they know about, including plugin detection (plugin
detection does not work on PHP4).
So with the laundry list of features, we'll take some time to look at some of the new commands,
new parameters and updated features.
New FixtureTask, TestTask and TemplateTask.
Fixture and test baking were a bit of a pain in the past. You could only generate tests when
baking the classes, and fixtures could only be generated when baking models. This made adding tests to
your applications later or even regenerating fixtures with new schemas a bit painful. For 1.3 we've
separated out Fixture and Test making them separate tasks. This allows you to re-run them and
regenerate tests and fixtures at any point in your development process.
In addition to being rebuildable at any time, baked tests are now attempt to find as many
fixtures as possible. In the past getting into testing often involved fighting through numerous 'Missing
Table' errors. With more advanced fixture detection we hope to make testing easier and more
accessible.
Test cases also generate skeleton test methods for every non-inherited public method in your
classes. Saving you one extra step.
TemplateTask is a behind the scenes task, and it handles file generation from templates. In
previous versions of CakePHP baked views were template based, but all other code was not. With 1.3
almost all the content in the files generated by bake are controlled by templates and the
TemplateTask.
The FixtureTask not only generates fixtures with dummy data, but using the interactive
options or the -records option you can enable fixture generation using live data.
New bake command
New commands have been added to make baking easier and faster. Controller, Model, View
baking all feature an all subcommand, that builds everything at once and makes speedy rebuilds easy.

cake bake model all

Would bake all the models for an application in one shot. Similarly cake

bake

controller all would bake all controllers and cake bake view all would generate all
view files. Parameters on the ControllerTask have changed as well. cake

bake

controller scaffold is now cake bake controller public. ViewTask has had an
-admin flag added, using -admin will allow you to bake views for actions that begin with
Routing.admin
As mentioned before cake bake fixture and cake bake test are new, and have
several subcommands each. cake bake fixture all will regenerate all the basic fixtures for
your application. The -count parameter allows you to set the number of fake records that are created.
By running fixture task interactively you can generate fixtures using the data in your live tables. You
can use cake bake test <type> <class> to create test cases for already created objects in
your app. Type should be one of the standard CakePHP types ('component', 'controller', 'model',
'helper', 'behavior') but doesn't have to be. Class should be an existing object of the chosen type.
Templates Galore
New in bake for 1.3 is the addition of more templates. In 1.2 baked views used templates that
could be changed to modify the view files bake generated. In 1.3 templates are used to generate all
output from bake. There are separate templates for controllers, controller action sets, fixtures, models,
test cases, and the view files from 1.2. As well as more templates, you can also have multiple template
sets or, bake themes. Bake themes can be provided in your app, or as part of plugins. An example
plugin

path

for

bake

theme

would

be

app/plugins/bake_theme/vendors/shells/templates/dark_red/. An app bake


theme

called

blue_bunny

would

app/vendors/shells/templates/blue_bunny.

be
You

placed
can

look

in
at

cake/console/templates/default/ to see what directories and files are required of a bake


theme. However, like view files, if your bake theme doesn't implement a template, other installed
themes will be checked until the correct template is found.

Additional plugin support.


New in 1.3 are additional ways to specify plugin names when using bake. In addition to cake
bake

plugin

Todo

controller

Posts, there are two new forms. cake

bake

controller Todo.Posts and cake bake controller Posts -plugin Todo. The
plugin parameter can be while using interactive bake as well. cake bake controller -plugin
Todo, for example will allow you to use interactive bake to add controllers to your Todo plugin.
Additional / multiple plugin paths are supported as well. In the past bake required your plugin to be in
app/plugins. In 1.3 bake will find which of the pluginPaths the named plugin is located on, and add the
files there.

9.2 Gestin del Esquema de la BBDD y Migraciones


El SchemaShell proporciona la funcionalidad para crear un esquema de objetos, volcados del
esquema sql, as como crear y restaurar instantneas de base de datos.
9.2.1 Generando y Usando Archivos de Esquemas
Un archivo de esquema permite transportar fcilmente el esquema de la base de datos, sin
importar en qu motor se vaya a implementar. Puedes generar un archivo de esquema de la base de
datos usando:

$ cake schema generate

Esto generar un archivo llamado schema.php en tu directorio app/config/sql.


La aplicacin SchemaShell procesar slo las tablas para las cuales existe un modelo definido.
Para forzar a que cree un esquema de todas las tablas, debes aadir la opcin -f en la lnea de
comandos.
Para reconstruir el esquema de la base de datos a partir de un archivo schema.php generado
anteriormente, debes ejecutar:
$ cake schema run create

Esto borrar y volver a crear todas las tablas basndose en el contenido del archivo
schema.php.
Los archivos de esquema pueden ser usado para genera volcados de SQL. Para generar un
archivo SQL que contenga las sencencias CREATE TABLE ejecuta:

$ cake schema dump volcado.sql

Donde volcado.sql es el nombre que deseas ponerle al volcado. Si omites este nombre, el
volcado ser mostrado por pantalla sin ser escrito en ningn archivo.
9.2.2 Migrations with CakePHP schema shell
Migrations allow for versioning of your database schema, so that as you develop features you
have an easy and database agnostic way to distribute database changes. Migrations are achieved
through either SCM controlled schema files or schema snapshots. Versioning a schema file with the
schema shell is quite easy. If you already have a schema file created running

$ cake schema generate

Will bring up the following choices:


Generating Schema...
Schema file exists.
[O]verwrite
[S]napshot
[Q]uit
Would you like to do? (o/s/q)

Choosing [s] (snapshot) will create an incremented schema.php. So if you have schema.php, it
will create schema_2.php and so on. You can then restore to any of these schema files at any time by
running:

$ cake schema update -s 2

Where 2 is the snapshot number you wish to run. The schema shell will prompt you to confirm
you wish to perform the ALTER statements that represent the difference between the existing database
the currently executing schema file.
You can perform a dry run by adding a -dry to your command.

9.3 Modificando el HTML producido por defecto del script bake


Si deseas modificar el HTML producido por el comando "bake", sigue los siguientes pasos:
1. Dirgete a: cake/console/libs/templates/views
2. Existen cuatro archivos ah
3. Cpialos en: app/vendors/shells/templates/views
4. Haz los cambios a la salida HTML para controlar la forma en que "bake" construye las vistas.

10 Deployment
Steps to deploy on a Hosting Server.

11 Ejemplo de Aplicacin
En esta seccin podrs ver cmo se unen todas las piezas en una aplicacin de CakePHP tpica.
Alternativamente, puedes visitar CakeForge y The Bakery para encontrar aplicaciones
existentes y otros componentes.

11.1 Blog
Bienvenidos a CakePHP! Probablemente ests viendo este tutorial porque deseas aprender ms
acerca de cmo funciona Cake. Es nuestro deseo incrementar la productividad y hacer la programacin
ms agradable: esperamos que notes esto a medida que vayas avanzando con el tutorial.
Este tutorial te guiar para que puedas crear un blog simple. Obtendremos e instalaremos Cake,
creando la base de datos y configurndola, y creando luego la lgica necesaria para mostrar, aadir,
editar y borrar posts del blog.
Esto es lo que necesitas:
1. Un servidor web. Aqu asumiremos que ests usando Apache, aunque las instrucciones para
utilizar otros servidores deberan ser similares. Tal vez necesitemos jugar un poco con la
configuracin del servidor, pero la mayora de pueden obtener y poner en marcha Cake sin
modificar la configuracin para nada.
2. Un servidor de base de datos. Nosotros utilizaremos MySQL es este tutorial. Debers saber lo
suficiente de SQL como para crear una base de datos: Cake se encarga del resto a partir de ah.
3. Conocimiento bsico de PHP. Cuanto ms programacin orientada a objetos hayas hecho,
mejor, pero no tengas miedo si eres un fan de la programacin procedural.
4. Finalmente, necesitars un conocimiento bsico del patrn MVC. Puedes darle un vistazo al
captulo "Comenzando con CakePHP", en la seccin: Entendiendo Modelo-Vista-Controlador.
No te preocupes, es menos de una pgina.
Comencemos!

11.1.1 Obteniendo Cake


Primero debemos conseguir una copia reciente de CakePHP.
Para

esto

debes

visitar

la

seccin

del

proyecto

CakePHP

en

Cakeforge

http://cakeforge.org/projects/cakephp/ y descargar la versin estable. Para este tutorial vamos a usar la


1.2.x.x
Tambin

puedes

obtener

una

copia

mediante

svn

en

https://svn.cakephp.org/repo/trunk/cake/1.2.x.x/
Sin importar cmo hayas conseguido Cake, deber colocar los archivos en el directorio raz del
servidor (DocumentRoot). Una vez terminado, los directorios deberan lucir algo as:
/ruta_al_directorio_raiz
/app
/cake
/docs
/vendors
.htaccess
index.php

Este es un buen momento para aprender un poco ms acerca de cmo Cake utiliza la estructura
de directorios: puedes verlo en el captulo "Principios bsicos de CakePHP", seccin : Estructura de
archivos de CakePHP.
11.1.2 Creando la Base de Datos del Blog
A continuacin debemos crear la base de datos en la que se basar nuestro blog. Lo primero que
haremos ser crear una tabla para almacenar nuestros posts. Tambin insertaremos algunos posts para
poder utilizarlos de testeo. Ejecuta el siguiente cdigo SQL en tu base de datos:
/* Primero, crear la tabla para los posts: */
CREATE TABLE posts (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(50),
body TEXT,
created DATETIME DEFAULT NULL,
modified DATETIME DEFAULT NULL
);

/* Luego insertar algunos posts de ejemplo: */


INSERT INTO posts (title,body,created)
VALUES ('El ttulo', 'Este es el cuerpo del post.', NOW());
INSERT INTO posts (title,body,created)
VALUES ('Un ttulo otra vez', 'Y el cuerpo del post a continuacin.', NOW());
INSERT INTO posts (title,body,created)
VALUES ('Ttulo ataca de nuevo', 'Esto es realmente exitante! No.', NOW());

La eleccin de los nombres de la tabla y las columnas no es arbitrario. Si sigues las


convenciones de Cake relacionadas a la base de datos, y las convenciones relacionadas a los nombres
de las clases (puedes consultar ambas en "Convenciones de CakePHP"), tendrs la posibilidad de
aprovechar muchas ventajas y evitar la configuracin. Cake es lo suficientemente flexible como para
acomodarse inclusive al peor esquema de base de datos de aplicaciones antiguas, sin embargo, si
utilizas las convenciones ahorrars mucho tiempo de desarrollo.
Puedes ver las "Convenciones de CakePHP" para ms informacin, pero es suficiente con decir
que al llamar a la tabla 'posts' automticamente estar asociada con el modelo Post, y al tener los
campos 'modified' y 'created', stos sern manejados automticamente por Cake.
11.1.3 Configuracin de la Base de Datos en Cake
Vamos a decirle a Cake dnde est nuestra base de datos y cmo conectarse a ella. Para muchos,
esta ser la primera y ltima vez que configuren algo.
Una copia del archivo de configuracin de la base de datos se encuentra en
/app/config/database.php.default. Haz una copia en el mismo directorio, pero
nombrndola database.php.
El archivo de configuracin debera ser fcil de seguir: slo debes reemplazar los valores en el
arreglo $default con la informacin que se corresponda a tu configuracin. Un ejemplo completo
debere verse como el siguiente:
var $default = array(
'driver' => 'mysql',
'persistent' => 'false',
'host' => 'localhost',

'port' => '',


'login' => 'usuario_de_la_BD',
'password' => 'c4k3-rUl3Z',
'database' => 'tutorial_blog',
'schema' => '',
'prefix' => '',
'encoding' => ''
);

Una vez que hayas guardado el nuevo database.php, deberas poder abrir el navegador en
la pgina de inicio de Cake y ver que puede conectarse a la base de datos sin problemas.
11.1.4 Configuracin Opcional
Hay dos tems ms que pueden ser configurados. La mayora de los desarrolladores realiza estos
pasos, pero para este tutorial no son necesarios. El primero es definir una cadena (o "salt") para darle
ms seguridad a los hash. El segundo tem es darle acceso de escritura a Cake, a su directorio tmp.
La cadena de seguridad (o "salt") es usada para generar hashes. Puedes cambiarla editando el
archivo /app/config/core.php. No importan tanto cul es el nuevo valor del salt, siempre y
cuando no sea fcil de adivinar.
<?php
/**
* Una cadena aleatoria usada en los mtodos de hashing de seguridad.
*/
Configure::write('Security.salt', 'pl345e-P45s_7h3*S@l7!');
?>

La segunda tarea es darle al servidor web permisos de escritura sobre el directorio app/tmp.
La mejor forma de hacer esto es encontrar con qu nombre de usuario est corriendo el servidor (<?
php echo `whoami`; ?>) y cambiar el propietario de app/tmp a ese usuario. El comando a
ejecutar (en sistemas *nix) puede lucir similar a esto:

$ chown -R www-data app/tmp

Si por alguna razn CakePHP no puede escribir en ese directorio, podrs ver un aviso cuando te
encuentres navegando la aplicacin en modo debug.
11.1.5 Una aclaracin para mod_rewrite
Es muy probable que los usuarios novatos tengan problemas con mod_rewrite, as que haremos
una mencin aqu. Si la pgina de bienvenida de CakePHP se ve un poco rara (sin imgenes o estilos
CSS), probablemente no tengas funcionando el mdulo mod_rewrite en tu sistema. Algunos consejos
para que hacerlo funcionar:
1. Asegrate que la sobreescritura (override) est permitida (allowed): en tu httpd.conf,
deberas tener una seccin en la que se definen los permisos sobre cada Directorio en tu
servidor. Asegrate que AllowOverride est puesto en All para el Directorio correcto. Por
razones de seguridad y de performance, no setees AllowOverride en All dentro de
<Directory />. A su vez, busca el bloque <Directory> que haga referencia al directorio
de tu sitio web..
2. Asegrate que ests editando el httpd.conf correcto en vez de un httpd.conf especfico
de usuario o sitio web.
3. Por una u otra razn, puedes haber conseguido una copia de CakePHP sin los archivos
.htaccess necesarios. Esto a veces sucede porque algunos sistemas operativos tratan a los
archivos cuyo nombre comienza con '.' como ocultos, y no los copia. Asegrate que tu copia de
CakePHP proviene de la seccin de descargas del sitio o desde nuestro repositorio SVN.
4. Asegrate que Apache est cargando mod_rewrite correctamente! Deberas ver algo como
LoadModule rewrite_module libexec/httpd/mod_rewrite.so o (en Apache
1.3) AddModule mod_rewrite.c en tu httpd.conf.
Si no quieres o no puedes hacer funcionar mod_rewrite (o algn otro mdulo compatible),
necesitars usar las 'pretty' URLs proporcionadas por CakePHP. En /app/config/core.php,
descomenta la lnea que diga algo como:
Configure::write('App.baseUrl', env('SCRIPT_NAME'));

Also remove these .htaccess files:


/.htaccess
/app/.htaccess
/app/webroot/.htaccess

Esto

har

que

tus

URLs

se

vean

de

www.example.com/index.php/controllername/actionname/param

la
en

forma
vez

de

www.example.com/controllername/actionname/param.
11.1.6 Crear un modelo Post
La clase Model es el pan y manteca de las aplicaciones CakePHP. Creando un modelo CakePHP
que interacte con nuestra base de datos, tendremos la base para poder hacer luego nuestras acciones de
vista, agregar, editar, y eliminar.
Los archivos de clases de modelo de CakePHP van en la carpeta /app/models, y el archivo
que crearemos lo grabaremos en /app/models/post.php. El archivo completo debera verse as:
<?php
class Post extends AppModel {
var $name = 'Post';
}
?>

La convencin en la nomenclatura es muy importante en CakePHP. Nombrando nuestro modelo


como Post, CakePHP puede automticamente inferir que este modelo ser usado en el controlador
PostsController, y ser atado a la tabla de la base de datos llamada posts.
CakePHP dinmicamente crear un objeto de modelo por ti, si no puede encontrar el archivo
correspondiente en /app/models. Esto tambin dice que si nombras incorrectamente tu archivo (i.e.
Post.php or posts.php) CakePHP no reconocer ninguna de tus configuraciones y usar las
opciones por defecto.
Siempre es una buena idea agregar la variable $name, y suele ahorrarnos problemas con los
nombres de las clases en PHP4.
Para ms informacin sobre modelos, como prefijos de tabla, callbacks, y validacin, revisar el
captulo Models del Manual.

11.1.7 Crear un controlador para Post


A continuacin, crearemos un controlador para nuestros posts. El controlador es donde existe
toda la lgica del negocio para la interaccin con los posts. En pocas palabras, es el lugar en el que
juegas con los modelos y realizas el trabajo con los posts. Ubicaremos este nuevo controlador en un
archivo llamado posts_controller.php dentro del directorio /app/controllers. As es
como debe verse un controlador bsico:
<?php
class PostsController extends AppController {
var $name = 'Posts';
}
?>

Ahora, agreguemos una accin a nuestro controlador. Las acciones a menudo representan una
funcin o una interfase en una aplicacin. Por ejemplo, cuando los usuarios ingresan
www.example.com/posts/index (que es lo mismo que www.example.com/posts/),
esperan ver un listado de posts. El cdigo para esa accin se vera como esto:
<?php
class PostsController extends AppController {
var $name = 'Posts';
function index() {
$this->set('posts', $this->Post->find('all'));
}
}
?>

Djenme explicar un poquito la accin. Definiendo la funcin index() en nuestro


PostsController,

los

usuarios

pueden

ahora

acceder

la

lgica

ubicada

en

www.example.com/posts/index. De forma similar, si definimos una funcin llamada


foobar(), los usuarios podran acceder a ella en www.example.com/posts/foobar.
Puede tentarte querer nombrar a tus controladores y acciones de cierta forma para obtener cierto
URL. Resiste la tentacin. Sigue las convenciones de CakePHP (nombres en plural para los
controladores, etc.) y crea nombres legibles y entendibles para las acciones. Puedes mapear luego

URLs a tu cdigo usando "routes".


La nica instruccin en la accin usa set() para pasar datos desde el controlador a la vista
(que crearemos a continuacin). La lnea iguala la variable de vista llamada 'posts' al valor retornado
por el mtodo del modelo Post find('all'). Nuestro modelo Post est disponible automticamente
en $this->Post porque hemos seguido la convencin de nombres de Cake.
Para aprender ms sobre los controladores de Cake, chequea el captulo "Desarrollando con
CakePHP": "Controllers".
11.1.8 Creando las Vistas(Views) de los Post
Ahora que tenemos los datos que fluyen a nuestro modelo y la lgica de nuestra aplicacin y el
flujo definido por nuestro controlador, vamos a crear una vista (view) para la accin index que hemos
creado anteriormente.
Cake view(vistas) son solo fragmentos de presentaciones-sabrosas que se adaptan dentro de las
aplicaciones diseadas. Para la mayora de las aplicaciones estaremos mezclando HTML con PHP, pero
puede terminar usando XML, CSV, o incluso de datos binarios.
Los Diseos (Layouts) de presentacin son el cdigo que se envuelve alrededor de las vista
(views), y pueden ser definidas y modificadas, pero por ahora, vamos a usar el valor por defecto.
Recuerda que en la ltima seccin la forma en que asigno la variable "posts" a de la vista fue
usando mtodo set()? La forma que transmite datos a la vista sera algo como esto:
// print_r($posts) output:
Array
(
[0] => Array
(
[Post] => Array
(
[id] => 1
[title] => The title
[body] => This is the post body.
[created] => 2008-02-13 18:34:55
[modified] =>
)

)
[1] => Array
(
[Post] => Array
(
[id] => 2
[title] => A title once again
[body] => And the post body follows.
[created] => 2008-02-13 18:34:56
[modified] =>
)
)
[2] => Array
(
[Post] => Array
(
[id] => 3
[title] => Title strikes back
[body] => This is really exciting! Not.
[created] => 2008-02-13 18:34:57
[modified] =>
)
)
)

Los archivos de las Cakes views (vistas de cake) se almacenan en /app/views dentro de una
carpeta con el nombre del controlador que corresponden (tendremos que crear una carpeta llamada
"posts" en este caso). Para dar formato a los datos de los posts en un cuadro lindo, el cdigo de nuestra
vista podra ser algo como esto:
<!-- Archivo: /app/views/posts/index.ctp -->
<h1>Blog posts</h1>
<table>
<tr>
<th>Id</th>
<th>Title</th>
<th>Created</th>
</tr>

<!-- Aqui se hace el ciclo que recorre nuestros arreglo $posts ,


imprimiendo la informacin de cada post-->
<?php foreach ($posts as $post): ?>
<tr>
<td><?php echo $post['Post']['id']; ?></td>
<td>
<?php echo $html->link($post['Post']['title'],
"/posts/view/".$post['Post']['id']); ?>
</td>
<td><?php echo $post['Post']['created']; ?></td>
</tr>
<?php endforeach; ?>
</table>

Creemos que esto debera ser algo sencillo.


Usted puede haber notado el uso de un objeto llamado $html. Esta es una instancia de la clase
CakePHP HtmlHelper. CakePHP viene con un conjunto de "view helpers" (vistas de ayuda) que
hacen cosas como la vinculacin, la forma de salida, manejo JavaScript y Ajax. Puede obtener ms
informacin sobre cmo utilizarlas en el captulo "Built-in Helpers", pero lo que es importante sealar
aqu es que el mtodo link() generar un vnculo HTML con un ttulo determinado (el primer
parmetro) y la URL (la segunda parmetro).
Al especificar las URL en Cake, slo tiene que dar una ruta relativa de la base de la aplicacin,
y cake llena en el resto. Es as, que las URL se suelen quedar de la forma de
/controlador/accin/parametro1/parametro2 (/controller/action/param1/param2).
En

este

punto,

usted

debera

ser

capaz

de

escribir

en

el

navegador

http://www.example.com/posts/index. Usted debe observar en la vista, el formato


correcto con el ttulo y la lista de los posts.
Si le sucedi que hizo click en uno de los enlaces que hemos creado en esta vista (que vinculan
el ttulo de un post a una URL /posts/view/some_id), probablemente ha sido informado por
CakePHP que la accin an no ha sido definida. Si no recibi el informe, es que algo ha ido mal, o que
realmente ya la a definido, en cuyo caso es muy astuto. De lo contrario, la vamos a crear ahora en el

PostsController:
<?php
class PostsController extends AppController {
var $name = 'Posts';
function index() {
$this->set('posts', $this->Post->find('all'));
}
function view($id = null) {
$this->Post->id = $id;
$this->set('post', $this->Post->read());
}
}
?>

La llamada set() les debe lucir familiar. Informamos de que estamos usando read() en
lugar de find('all') porque realmente solo queremos la informacin de un nico post.
Tenga en cuenta que la accin de nuestra vista toma un parmetro: la ID del post que nos
gustara ver. Este parmetro se entrega a la accin a travs de la URL solicitada. Si un usuario solicita
/posts/view/3, entonces el valor '3' es pasado como $id.
Ahora vamos a crear la vista para las view de nuestra nueva accin y lo colocaremos en
/app/views/posts/view.ctp.
<!-- archivo: /app/views/posts/view.ctp -->
<h1><?php echo $post['Post']['title']?></h1>
<p><small>Created: <?php echo $post['Post']['created']?></small></p>
<p><?php echo $post['Post']['body']?></p>

Verifique que esto esta funcionando en los vnculos de /posts/index o manualmente


solicitando un post accediendo a /posts/view/1.

11.1.9 Agregando Posts


Leer y mostrar de la base de datos nuestros posts es un gran comienzo, pero debe habilitarse
para agregar nuevos posts.
En primer lugar, empezar por crear la accin add() controlador PostsController:
<?php
class PostsController extends AppController {
var $name = 'Posts';
function index() {
$this->set('posts', $this->Post->find('all'));
}
function view($id) {
$this->Post->id = $id;
$this->set('post', $this->Post->read());
}
function add() {
if (!empty($this->data)) {
if ($this->Post->save($this->data)) {
$this->Session->setFlash('Your post has been
saved.');
$this->redirect(array('action' => 'index'));
}
}
}
}
?>

Lo que esta accin add() hace es lo siguiente: si los datos del formulario presentado no estn
vacos, trate de guardar los datos utilizando el modelo Post. Si por alguna razn, no guarda,
simplemente hacer que se quede en la vista. Esto nos da la oportunidad de mostrar los errores de
validacin de usuario u otras advertencias.
Cuando un usuario utiliza un formulario de datos POST en su aplicacin, esta informacin est
disponible en $this->data. Usted puede usar las funciones pr() o debug para imprimir, si

quieres ver como luce esto.


Usamos la funcin del componente Session setFlash() para adjuntar un mensaje a una
variable de sesin que se mostrar en la pgina despus de la redireccin. En el diseo tenemos
$session->flash() , que muestra el mensaje y borra la variable de sesin correspondiente. La
funcin

redirect

del

controlador

redirige

otra

direccin

URL.

El

parmetro

array('action'=>'index) se traduce en la URL /posts es decir, la accin index del


controlador posts. Puede referirse a Router::url en funcin de la API para ver los formatos en los que se
puede especificar una direccin URL para diversas funciones de cake.
Llamando al mtodo save() haremos comprobacin de errores de validacin y abortar el
guardado si algo ocurre. Hablaremos de cmo se manejan los errores en las siguientes secciones.
11.1.10 Validacin de Datos
Cake lleva un largo camino recogiendo la monotona de la validacin de formularios de entrada.
Todo el mundo odia a la codificacin de sus infinitos formularios y rutinas de validacin. CakePHP
hace que sea ms fcil y ms rpido.
Para aprovechar las caractersticas de la validacin, tendrs que utilizar FormHelper de Cake en
tus vistas. El FormHelper est disponible por defecto en todas las vista en $form.
Esta es nuestra Vista Agregar(add view):
<!-- File: /app/views/posts/add.ctp -->
<h1>Add Post</h1>
<?php
echo $form->create('Post');
echo $form->input('title');
echo $form->input('body', array('rows' => '3'));
echo $form->end('Save Post');
?>

Aqu, nosotros usamos el FormHelper para generar la etiqueta de apertura de un formulario


HTML. Aqu est el cdigo HTML que genera $form->create() :
<form id="PostAddForm" method="post" action="/posts/add">

Si create() es llamado sin suministrarle parmetros, este supone que est construyendo un
formulario que suministra datos a la accin add() (o a la accin edit() cuando el parmetro id
esta includo en los datos del formulario ($form->data)), a travs del metodo POST.
El mtodo $form->input() es utilizado para crear elementos de formulario del mismo
nombre. El primer parmetro le dice a CakePHP a que campo corresponden, y el segundo parmetro le
permite especificar una amplia gama de opciones - en este caso, el nmero de filas para el textarea. Hay
un poco de introspeccin y automtizacion aqu: input() es la salida de diferentes elementos
basados en el modelo del campo especificado.
El $form->end() genera una llamada al botn de enviar y termina el formulario. Si una
cadena se suministra como el primer parmetro a end(), FormHelper producir un botn de enviar
con ese nombre seguido del cierre de la etiqueta. Una vez ms, consulte el Chapter "Built-in Helpers"
para conocer ms acerca de los helpers.
Ahora vamos a volver y actualizar nuestro /app/views/posts/index.ctp para incluir
un nuevo enlace "Aadir entrada". Antes de el <table>, aada la siguiente lnea:
<?php

echo

$html->link('Add

Post',array('controller'

=>

'posts',

'action'

=>

'add'))?>

Puede estar preguntarse: cmo le digo a mi CakePHP sobre los requisitos de validacin?
Reglas de validacin se definen en el modelo. Vamos a mirar hacia atrs en nuestro modelo y despus
haremos algunos ajustes:
<?php
class Post extends AppModel
{
var $name = 'Post';
var $validate = array(
'title' => array(
'rule' => 'notEmpty'
),
'body' => array(
'rule' => 'notEmpty'
)
);
}
?>

El arreglo $validate le dice a CakePHP cmo validar sus datos cuando se llama el mtodo
save() . Aqu, he especificado que tanto el campos cuerpo y el ttulo no deben estar vaca. El motor
de validacin de CakePHP es fuerte, con una serie de normas pre-construidas (nmeros de tarjetas de
crdito, direcciones de correo electrnico, etc) y la flexibilidad para aadir sus propias reglas de
validacin. Para obtener ms informacin sobre esta configuracin, consulte el Captulo Validacin de
Datos.
Ahora que tiene las reglas de validacin en su lugar, utilice la aplicacin para tratar de aadir un
post con un ttulo o el cuerpo vaco para ver cmo funciona. Como hemos utilizado el mtodo
input() del componente FormHelper para crear elementos de nuestro formulario, nuestros mensajes
de error de validacin se mostrar automticamente.
11.1.11 Borrando Posts
A continuacin, vamos a crear un medio para que los usuarios eliminen posts. Comenzaremos
con la accin delete() en el PostsController:
function delete($id) {
$this->Post->delete($id);
$this->Session->setFlash('The post with id: '.$id.' has been deleted.');
$this->redirect(array('action'=>'index'));
}

Esta lgica es eliminar el post por $ id, y utiliza $this->Session->setFlash() para


mostrar al usuario un mensaje de confirmacin despus de la reorientacin a /posts.
Porque estamos slo ejecutando una lgica y redireccionando, esta accin no tiene ninguna
vista. Es posible que desee actualizar su vista de ndice (index) con vnculos que permitan a los
usuarios eliminar posts, entonces:
/app/views/posts/index.ctp
<h1>Blog posts</h1>
<p><?php echo $html->link('Add Post', array('action' => 'add')); ?></p>
<table>
<tr>
<th>Id</th>
<th>Title</th>
<th>Actions</th>
<th>Created</th>

</tr>
<!--

Aqu

esta

el

ciclo

que

muestra

$posts

travs

de

nuestro

arreglo,

imprimiendo la informacin de los posts -->


<?php foreach ($posts as $post): ?>
<tr>
<td><?php echo $post['Post']['id']; ?></td>
<td>
<?php echo $html->link($post['Post']['title'], array('action' =>
'view', 'id' => $post['Post']['id']));?>
</td>
<td>
<?php echo $html->link('Delete', array('action' => 'delete',
$post['Post']['id']), null, 'Are you sure?' )?>
</td>
<td><?php echo $post['Post']['created']; ?></td>
</tr>
<?php endforeach; ?>
</table>

El cdigo de esta vista tambin utiliza HtmlHelper para que pregunte al usuario con un dilogo
de confirmacin JavaScript de antes de intentar borrar un post.
11.1.12 Editando Posts
Editando Post: aqu vamos! Eres un CakePHP pro por ahora, por lo que deberas haber
adoptado un patrn. Hacer la accin, luego la vista. Aqu esta la accin edit() del PostsController
que se vera como:
function edit($id) {
$this->Post->id = $id;
if (empty($this->data)) {
$this->data = $this->Post->read();
} else {
if ($this->Post->save($this->data)) {
$this->Session->setFlash('Your post has been updated.');
$this->redirect(array('action' => 'index'));

}
}
}

Esta accin primero chequea los datos del formulario para enviarlos. Si no fue enviado, este
busca el post y se lo pasa a la vista. Si algunos datos se han enviado, intenta guardar los datos
utilizando el modelo Post (o los rechazar y mostrara al usuario los errores de validacin).
La vista de edicin puede tener un aspecto parecido a este:
/app/views/posts/edit.ctp
<h1>Edit Post</h1>
<?php
echo $form->create('Post', array('action' => 'edit'));
echo $form->input('title');
echo $form->input('body', array('rows' => '3'));
echo $form->input('id', array('type'=>'hidden'));
echo $form->end('Save Post');
?>

Esta vista muestra el formulario de edicin (con los valores de publicados), junto con los
mensajes de errores de validacin necesarios.
Cabe destacar aqu: que CakePHP asumir que usted est editando un registro si el campo 'id'
est presente en el arreglo de datos. Si 'id' no est presente (mirar hacia atrs en nuestra opinin de
aadir), Cake asumir que usted est aadiendo un nuevo registro para llamar a save()
Ahora puede actualizar su vista de indice, con enlaces para ir a editar posts especficos:
/app/views/posts/index.ctp (edit links added)
<h1>Blog posts</h1>
<p><?php echo $html->link("Add Post", array('action'=>'add')); ?>
<table>
<tr>
<th>Id</th>
<th>Title</th>
<th>Action</th>
<th>Created</th>

</tr>
<!-- Aqui se hace el ciclo que recorre nuestros arreglo $posts , imprimiendo la
informacin de cada post -->
<?php foreach ($posts as $post): ?>
<tr>
<td><?php echo $post['Post']['id']; ?></td>
<td>
<?php

echo

$html->link($post['Post']

['title'],array('action'=>'view', 'id'=>$post['Post']['id']));?>
</td>
<td>
<?php echo $html->link(
'Delete',
array('action'=>'delete', 'id'=>$post['Post']
['id']),
null,
'Are you sure?'
)?>
<?php echo $html->link('Edit', array('action'=>'edit',
'id'=>$post['Post']['id']));?>
</td>
<td><?php echo $post['Post']['created']; ?></td>
</tr>
<?php endforeach; ?>
</table>

11.1.13 Rutas
Para algunos, el enrutamiento por defecto de CakePHP funciona lo suficientemente bien. Los
desarrolladores que son sensibles a la facilidad de uso y compatibilidad del motor de bsqueda general
aprecian la forma en que CakePHP URL mapea acciones especficas. As que vamos a hacer un cambio
rpido a las rutas en este tutorial.
Para obtener ms informacin sobre las tcnicas avanzadas de enrutamiento, consulte "Configuracin
de Rutas".

Por defecto, CakePHP responde a una peticin de la raz de su sitio (es decir,
http://www.example.com) con su PagesController, haciendo una vista llamada "home". En lugar de
ello, vamos a sustituir esto con nuestros PostsController mediante la creacin de una regla de
enrutamiento.
El enrutamiento de Cake se encuentra en /app/config/routes.php. Usted querr
comentar o eliminar la lnea que define la ruta raz predeterminada. El aspecto que presenta es:
Router::connect ('/', array('controller'=>'pages', 'action'=>'display', 'home'));

Esta lnea conecta a la URL "/" con la pgina de inicio por defecto de CakePHP. Queremos que
esto se conecte con nuestro propio controlador, por lo que aadiremos una lnea que tiene que ver asi:
Router::connect ('/', array('controller'=>'posts', 'action'=>'index'));

Esto debe conectar a los usuarios que solicitan '/' a la accin ndex() de nuestra pronto-a-sercreado PostsController.
CakePHP tambin hace uso de "enrutamiento inverso" - si con la citada ruta que defini
array('controller'=>'posts', 'action'=>'index') pasa a una funcin que espera
un arreglo, la url resultante utilizada es '/'. Es, por tanto, una buena idea utilizar siempre los arreglos
(arrays) de urls como rutas, esto significa definir a dnde va una url, y tambin se asegura de que los
enlaces llevan al mismo sitio.
11.1.14 Conclusin
Creado aplicaciones de esta manera ganar paz, honor, amor, y dinero, incluso ms all de sus
fantasas ms salvajes. Simple, no? Tenga en cuenta que este tutorial es muy bsico. CakePHP tiene
muchas ms caractersticas que ofrecer, y es flexible en formas que no se quiso cubrir aqu para
simplificar. Utilice el resto de este manual como una gua para la construccin de aplicaciones con ms
ricas-caractersticas.
Ahora que ha creado la base de una aplicacin Cake est listo para algo real. Comience su
propio proyecto, lea el resto del Manual y API.
Si necesita ayuda, vengan a vernos en el #cakephp. Bienvenido a CakePHP!

11.2 Simple Acl controlled Application


Bienvenido a CakePHP, si eres nuevo con CakePHP revisa primero el tutorial del Blog. Si ya lo
has visto, y ya leiste acerca del uso de bake, y ests necesitando configurar un sistema Auth y Acl para
el ingreso y autenticacin de tus usuarios, entonces este es el tutorial para ti.
Como ya mencionamos anteriormente este tutorial asume que ya tienes experiencia con
CakePHP, y que ests familiarizado con todos los conceptos del MVC que constituyen el ncleo.
Tambin te sientes cmodo con el uso de la consola y el script bake. Si no conoces lo anterior, primero
aprende todas estos elementos y luego vuelve. Este tutorial ser mucho ms facil de seguir y tendra ms
sentido para ti. En este tutorial usaremos AuthComponent y AclComponent. Si no sabes lo que
son, revisa sus pginas en el manual antes de proceder.
Que necesitas?
1. Un servidor web. Asumiremos que usas Apache, pero las instrucciones son similares en caso de
otro servidor. Quizas debamos jugar un poco con la configuracin del servidor, pero muchos
consiguen utilizar CakePHP sin tener que configurar nada.
2. Un servidor de bases de datos. Usaremos mySQL en este tutorial. Necesitars conocer suficiente
SQL para crear la base de datos: CakePHP tomar las riendas de aqu en adelante.
3. Conocimiento PHP bsico. Mientras mas programacin orientada a objeto que hayas hecho
mejor: pero si eres fantico de la programacin procedural no tienes nada que temer.
11.2.1 Preparando nuestra aplicacin
Primero, consigamos una copia fresca de CakePHP.
Para

descargarla,

visita

la

pgina

de

CakePHP

en

Cakeforge:

http://cakeforge.org/projects/cakephp/ y descarga la ltima versin estable. Para este tutorial necesitaras


la version 1.2.x.x
Tambin

puedes

hacer

checkout/export

desde

el

trunk

en:

https://svn.cakephp.org/repo/trunk/cake/1.2.x.x/
Una vez que tengas la copia de Cake, configuraremos el archivo database.php, y cambiemos
ademas el valor de Security.salt en el archivo app/config/core.php. Desde ac construiremos un
esquema de base de datos simple para nuestra aplicacin. Ejecuta el siguiente cdigo SQL en tu base de
datos.

CREATE TABLE users (


id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(255) NOT NULL UNIQUE,
password CHAR(40) NOT NULL,
group_id INT(11) NOT NULL,
created DATETIME,
modified DATETIME
);
CREATE TABLE groups (
id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
created DATETIME,
modified DATETIME
);
CREATE TABLE posts (
id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
user_id INT(11) NOT NULL,
title VARCHAR(255) NOT NULL,
body TEXT,
created DATETIME,
modified DATETIME
);
CREATE TABLE widgets (
id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
part_no VARCHAR(12),
quantity INT(11)
);

Estas sern las tablas que usaremos para construir el resto de la aplicacin. Una vez que
tengamos la estructura en la base de datos ya podemos comenzar a hornear. Usa cake bake para crear
rapidamente tus modelos, controladores y vistas.
Evite el uso de Scaffold(andamios) aqu. La generacin de la ACOS se vern seriamente
afectados si hornear los controladores con la funcin de Scaffold.
Mientras hornees tus modelos Cake automagicamente detectara las asociaciones entre tus
modelos (o relaciones entre las tablas). Dejemos que Cake entregue las asociaciones hasMany y
belongsTo apropiadas. Si te pregunta por elegir hasOne o hasMany, en general necesitars una relacin

hasMany (solo) para este tutorial.


Dejaremos admin routing fuera por ahora, este tema ya es bastante complejo sin ellos.
Asegurate adems de NO agregar ninguno de los dos componentes a ningn controlador mientras estes
hornendolo. Haremos eso tan pronto podamos. Ahora debieras tener modelos, controladores y vistas
para tus tablas users (usuarios), groups (grupos), posts (artculos) y widgets.
En modo actions (acciones), esto autenticar nuestros ARO que son los groups y users, con
los objetos ACO - controladores & acciones.
11.2.2 Preparndose para agregar Autentificacin (Auth)
Ahora tenemos un funcionamiento de aplicacin CRUD. Bake debe tener todas las
configuraciones de las relaciones que necesitamos, si no es as debemos aadirlas ahora. Hay algunas
otras piezas que aadiremos antes de que podamos agregar los componentes de autenticacin y acl. En
primer lugar aadir las acciones login(inicio sesin) y logout(salir sesin) en el controlador
UsersController.
function login() {
//Autentificacin Magica
}
function logout() {
//limpio por ahora.
}

No es necesario preocuparse por agregar cualquier hash de contraseas, debido a que


AuthComponent lo har por nosotros automticamente al crear/editar los usuarios, y cuando se inicia
sesin, una vez configurado correctamente. Adems, si usted agrega un hash de las contraseas
manualmente AuthComponent no podr iniciar sesin en absoluto. Pues los hash no coincidiran.
A continuacin tenemos que hacer algunas modificaciones a AppController. Si usted no
tiene el controlador /app/app_controller.php, crelo. Tenga en cuenta que esto va en /app/
y no /app/controllers/. Dado que queremos que todo el sitio este con el control de
autentificacin y ACL, vamos a ponerlos en AppController.

class AppController extends Controller {


var $components = array('Acl', 'Auth');
function beforeFilter() {
//Configure AuthComponent
$this->Auth->authorize = 'actions';
$this->Auth->loginAction = array('controller' => 'users', 'action' =>
'login');
$this->Auth->logoutRedirect = array('controller' => 'users', 'action' =>
'login');
$this->Auth->loginRedirect = array('controller' => 'posts', 'action' =>
'add');
}
}

Antes de configurar la ACL en todo tendr que aadir algunos usuarios y grupos. Con
AuthComponent en uso no podremos acceder a ninguna de nuestras acciones, ya que no se ha
iniciado sesin. Ahora vamos a aadir algunas excepciones de manera que AuthComponent nos
permitir crear algunos grupos y usuarios. Por lo tanto en GroupsController y
UsersController aadiremos lo siguiente.
function beforeFilter() {
parent::beforeFilter();
$this->Auth->allowedActions = array('*');
}

Estas declaraciones son para decirle a AuthComponent que permita el acceso del pblico a todas
las acciones. Esto es slo temporal y se eliminar una vez que tengamos unos usuarios y grupos en
nuestra base de datos. No agregue los usuarios o grupos, no todava.
11.2.3 Inicializar las tablas Acl en la BD
Antes de que creemos nuestros users o groups querremos conectarlos con el Acl. Sin embargo,
en este punto aun no tenemos ninguna tabla Acl y si tratamos de ver cualquier pgina en este momento,
obtendremos un error de tabla no encontrada. Para eliminar estos errores necesitamos ejecutar un
archivo de esquema. En una consola ejecuta el siguiente codigo: cake schema run create
DbAcl. Este esquema te preguntara acerca de eliminar y crear estas tablas. Acepta la eliminacin y
creacin de stas tablas.

Recuerda especificar la ruta de tu directorio app si ests fuera de ella.


1. En tu directorio de aplicacin app:
$ /path/to/cake/console/cake schema run create DbAcl
2. Fuera de tu directorio de aplicacin app:
$ /path/to/cake/console/cake -app /path/to/app/dir schema run
create DbAcl
Con los controladores listos para la entrada de datos y con las tablas Acl inicializadas estamos
listos para empezar cierto?... no del todo, an necesitamos un poco de trabajo en los modelos de users y
groups. Llammoslo, hacerlos automgicamente ligados a Acl.
11.2.4 Act as a Requester (Solicitante)
Para que Auth y Acl funcionen apropiadamente necesitamos asociar a nuestros modelos users y
groups con registros en las tablas Acl. Para hacer esto usaremos el AclBehavior. El
AclBehavior permite la conexin automgica entre los modelos y las tablas Acl. Su uso requiere la
implementacin de parentNode() en tu modelo. En nuestro modelo User agregaremos lo
siguiente:
var $name = 'User';
var $belongsTo = array('Group');
var $actsAs = array('Acl' => array('requester'));
function parentNode() {
if (!$this->id && empty($this->data)) {
return null;
}
$data = $this->data;
if (empty($this->data)) {
$data = $this->read();
}
if (!$data['User']['group_id']) {
return null;
} else {
return array('Group' => array('id' => $data['User']['group_id']));
}
}

Entonces en nuestro modelo Group agrega lo siguiente:


var $actsAs = array('Acl' => array('requester'));
function parentNode() {
return null;
}

Lo que hace esto es unir los modelos Group y User al Acl, y decirle a CakePHP que cada vez
que crees un User o Group agregues una entrada en la tabla aros. Esto hace la administracin de Acl
muy fcil ya que tus AROs se ligan transparentemente a tus tablas de users y groups. De esta
forma, cada vez que se crea o elimina un usuario la tabla de Aro se actualiza.
Nuestros controladores y modelos ahora estn preparados para agregar algunos datos iniciales, y
nuestros modelos Group y User estan unidos a la tabla Acl. Ahora agregaremos unos groups y users
usando los formularios que creamos con bake. Yo cre en este caso los siguientes grupos:
administrators
managers
users
Tambien cre un user en cada group de tal forma de tener un user por cada grupo de acceso
diferente para probarlos luego. Escribe todo facil de recordar, sobre todos los passwords. Si haces un
SELECT * FROM aros; desde la consola de mysql obtendrs algo como:
+----+-----------+-------+-------------+-------+------+------+
| id | parent_id | model | foreign_key | alias | lft

| rght |

+----+-----------+-------+-------------+-------+------+------+
|

1 |

NULL | Group |

1 | NULL

1 |

4 |

2 |

NULL | Group |

2 | NULL

5 |

8 |

3 |

NULL | Group |

3 | NULL

9 |

12 |

4 |

1 | User

1 | NULL

2 |

3 |

5 |

2 | User

2 | NULL

6 |

7 |

6 |

3 | User

3 | NULL

10 |

11 |

+----+-----------+-------+-------------+-------+------+------+
6 rows in set (0.00 sec)

Esto nos muestra que tenemos tres groups y 3 users. Los users estan anidados dentro de los
grupos., lo que significa que podemos fijar permisos mediante grupos o por usuarios.

Cuando modificamos un user, debes actualizar manualmente los ARo. Este codigo debera ser
ejecutado cada vez que actualices la informacin del usuario:
// Verificar si sus permisos de grupo han cambiado
$oldgroupid = $this->User->field('group_id');
if ($oldgroupid !== $this->data['User']['group_id']) {
$aro =& $this->Acl->Aro;
$user = $aro->findByForeignKeyAndModel($this->data['User']['id'], 'User');
$group

$aro->findByForeignKeyAndModel($this->data['User']['group_id'],

'Group');
// Guardar en la tabla ARO
$aro->id = $user['Aro']['id'];
$aro->save(array('parent_id' => $group['Aro']['id']));
}

11.2.4.1 11.2.4.1 Group-only ACL

In case we want simplified per-group only permissions, we need to implement bindNode()


in User model.
function bindNode($user) {
return array('Group' => array('id' => $user['User']['group_id']));
}

This method will tell ACL to skip checking User Aro's and to check only Group Aro's.
Every user has to have assigned group_id for this to work.
In this case our aros table will look like this:
+----+-----------+-------+-------------+-------+------+------+
| id | parent_id | model | foreign_key | alias | lft

| rght |

+----+-----------+-------+-------------+-------+------+------+
|

1 |

NULL | Group |

1 | NULL

1 |

2 |

2 |

NULL | Group |

2 | NULL

3 |

4 |

3 |

NULL | Group |

3 | NULL

5 |

6 |

+----+-----------+-------+-------------+-------+------+------+
3 rows in set (0.00 sec)

11.2.5 Creando ACOs


Ahora que ya tenemos nuestros users y groups (aros), podemos empezar a ingresar nuestros
controladores en el Acl y fijar los permisos para cada grupo de usuarios, adems, habilitar el login y
logout.
Nuestros AROs son automaticamente creados cuando nuevos usuarios y grupos son creados.
Que hay de autogenerar los ACOs desde nuestros controladores y sus acciones?. Desafortunadamente
no hay una manera mgica de hacer esto. Las clases del ncleo ofrecen unas pocas formas de crear
ACOs manualmente. Se pueden crear ACOs a travs de la consola o usando el AclComponent.
Desde la consola esto se ve as:

cake acl create aco root controllers

Mientras que desde el AclComponent se ve asi:


$this->Acl->Aco->create(array('parent_id' => null, 'alias' => 'controllers'));
$this->Acl->Aco->save();

Ambos ejemplos crear nuestra 'raiz' (root) o ACO de nivel superior, el cual se llama 'controllers'.
El propsito de este nodo raiz es hacer fcil permitir/denegar (allow/deny) acceso en el mbito global
de la aplicacin y permitir el uso del Acl para propsitos no relacionados con los
controladores/acciones tales como verificar permisos de registro del modelo. As como usaremos una
raz global para los ACO necesitaremos hacer una pequea modificacin a la configuracin de nuestro
AuthComponent. AuthComponent necesita saber de la existencia de este nodo raz, de tal forma
que cuando hacemos que ACL lo verifique, pueda usar la ruta correcta al nodo cuando busque un(a)
controlador/accion. En AppController agrega el siguiente cdigo a beforeFilter:
$this->Auth->actionPath = 'controllers/';

11.2.6 Una herramienta automtica para crear ACOs


Tal como se mencion anteriormente, no hay una forma pre-construida para insertar y conectar
nuestros controladores y sus funciones dentro del Acl. Sin embargo, todos odiamos hacer tareas
repetitivas como tipear lo que tal vez sean cientos de acciones en una aplicacin grande. He escrito una
funcin automtica para construir mi tabla de Aco's. Esta funcin mirar en cada controlador de la
aplicacin. Aadir cualquier metodo no privativo, ni propio del Controller. Puedes agregar y
ejecutar esto en tu AppController o cualquier otro controlador con ese propsito, solo asegurate de
eliminarlo antes de poner la aplicacin en produccin.
/**
* Reconstruye el Acl basado en los controladores actuales de la aplicacin.
*
* @return void
*/
function buildAcl() {
$log = array();
$aco =& $this->Acl->Aco;
$root = $aco->node('controllers');
if (!$root) {
$aco->create(array('parent_id' => null, 'model' => null, 'alias' =>
'controllers'));
$root = $aco->save();
$root['Aco']['id'] = $aco->id;
$log[] = 'Creado el nodo Aco para los controladores';
} else {
$root = $root[0];
}
App::import('Core', 'File');
$Controllers = Configure::listObjects('controller');
$appIndex = array_search('App', $Controllers);
if ($appIndex !== false ) {
unset($Controllers[$appIndex]);
}
$baseMethods = get_class_methods('Controller');
$baseMethods[] = 'buildAcl';
// miramos en cada controlador en app/controllers

foreach ($Controllers as $ctrlName) {


App::import('Controller', $ctrlName);
$ctrlclass = $ctrlName . 'Controller';
$methods = get_class_methods($ctrlclass);
//buscar / crear nodo de controlador
$controllerNode = $aco->node('controllers/'.$ctrlName);
if (!$controllerNode) {
$aco->create(array('parent_id' => $root['Aco']['id'], 'model' =>
null, 'alias' => $ctrlName));
$controllerNode = $aco->save();
$controllerNode['Aco']['id'] = $aco->id;
$log[] = 'Creado el nodo Aco del controlador '.$ctrlName;
} else {
$controllerNode = $controllerNode[0];
}
//Limpieza de los metodos, para eliminar aquellos en el controlador
//y en las acciones privadas
foreach ($methods as $k => $method) {
if (strpos($method, '_', 0) === 0) {
unset($methods[$k]);
continue;
}
if (in_array($method, $baseMethods)) {
unset($methods[$k]);
continue;
}
$methodNode = $aco->node('controllers/'.$ctrlName.'/'.$method);
if (!$methodNode) {
$aco->create(array('parent_id' => $controllerNode['Aco']
['id'], 'model' => null, 'alias' => $method));
$methodNode = $aco->save();
$log[] = 'Creado el nodo Aco para '. $method;
}
}
}
debug($log);
}

Quizs quieras mantener esta funcin cerca cuando aadas nuevos ACO's para todos los
controladores & acciones que tiene tu aplicacin cada vez que la ejecutes. Sin embargo, no remueve los
nodos de las acciones que ya no existen, esto implica tener que limpiar a mano la tabla ACO. Ahora
que todo lo ms complejo est hecho, necesitamos ahora configurar los permisos, y eliminar el cdigo
que deshabilit el AuthComponent anteriormente.
Ahora, que ya est funcionando, quizs notes que tienes problemas accesando cualquier plugin
que quizs estabas ocupando. El truco para automatizar el controlador de ACO's para los plugins, es
que necesita un App::import que siga la convencion de nombre de plugins, que es
PluginNombre.PluginControllerNombre.
Entonces lo que necesitamos es una funcin que nos entregar una lista de los nombres de los
controladores de los plugins, y que los importe en la misma forma que lo hicimos arriba para los
controladores normales. La funcin de abajo har exactamente eso:
/**
* Obtener los nombres de los controladores de plugins
*
* Esta funcion entrega un arreglo con los nombres de los controladores
* de los plugins y adems se asegura que los controladores estn disponibles
* para nosotros, de modo de obtener los nombres de los metodos al hacer un
* App:import para cada uno de los plugins.
*
* @return arreglo con los nombres de los plugins.
*
*/
function _get_plugin_controller_names(){
App::import('Core', 'File', 'Folder');
$paths = Configure::getInstance();
$folder =& new Folder();
// Cambiamos al directorio de plugins
$folder->cd(APP.'plugins');
// Obtener la lista de los archivos que terminan con
// controller.php
$files = $folder->findRecursive('.*_controller\.php');
// Obtener la lista de plugins
$Plugins = Configure::listObjects('plugin');

// Ciclo a travs de los controladores que encontramos en el


// directorio de plugins
foreach($files as $f => $fileName)
{
// Obtener el nombre de archivo base
$file = basename($fileName);
// Obtener el nombre del controlador
$file

Inflector::camelize(substr($file,

0,

strlen($file)-

strlen('_controller.php')));
// Ciclo a travs de los plugins
foreach($Plugins as $pluginName){
if (preg_match('/^'.$pluginName.'/', $file)){
// Primero nos deshacemos del AppController del plugin
// Hacemos esto porque nunca lo llamamos directamente
if (preg_match('/^'.$pluginName.'App/', $file)){
unset($files[$f]);
} else {
if (!App::import('Controller',
$pluginName.'.'.$file))
{
debug('Error importando el archivo '.
$file.' para el plugin '.$pluginName);
}
// Ahora le agregamos el nombre del plugin al inicio
// Esto lo necesitamos para poder obtener los nombres
// de los mtodos
$files[$f] = $file;
}
break;
}
}
}
return $files;
}

Tu puedes modificar el cdigo original para incluir los controladores de plugins al mezclarlos con la
lista que obtuviste (ubicarlo antes del ciclo foreach):
$Plugins = $this->_get_plugin_controller_names();
$Controllers = array_merge($Controllers, $Plugins);

11.2.7 Configurando los permisos


Crear los permisos al igual que crear los ACO's no tiene una solucion mgica, en este caso no
proveeremos una forma automtica. Para permitir a los ARO's acceder a los ACO's desde la consola,
usamos:

cake acl grant $aroAlias $acoAlias [create|read|update|delete|'*']}

* Necesita estar entre comillas simples ('*')


Para permitir acceso a travs del AclComponent haz lo siguiente:
$this->Acl->allow($aroAlias, $acoAlias);

Ahora aadiremos algunas sentencias para permitir y denegar el acceso. Agrega lo siguiente a tu
funcin temporal en tu UsersController e ingresa a la direccin adecuada en tu navegador para
ejecutarla. Si haces un SELECT * FROM aros_acos deberas ver toda un montn de unos y ceros.
Una vez que hayas confirmado los permisos, elimina la funcin.
function initDB() {
$group =& $this->User->Group;
//Permite a los administradores hacer todo
$group->id = 1;
$this->Acl->allow($group, 'controllers');
//permite a los editores postear y accesar los widgets
$group->id = 2;
$this->Acl->deny($group, 'controllers');
$this->Acl->allow($group, 'controllers/Posts');
$this->Acl->allow($group, 'controllers/Widgets');
//permite a los usuarios aadir y editar posts y widgets

$group->id = 3;
$this->Acl->deny($group, 'controllers');
$this->Acl->allow($group, 'controllers/Posts/add');
$this->Acl->allow($group, 'controllers/Posts/edit');
$this->Acl->allow($group, 'controllers/Widgets/add');
$this->Acl->allow($group, 'controllers/Widgets/edit');
}

Ahora hemos seteado algunas reglas bsicas de acceso. Hemos permitido a los administradores
accesar a todas las funciones. Los editores pueden accesar a todas las funcionalidades de los posts y los
widgets. En cambio los usuarios solo pueden accesar aquellas funciones que permiten agregar y editar
posts y widgets.
Debemos obtener una referencia del modelo Group y modificar su id para poder especificar el
ARO que queremos, esto es debido a la forma en que trabaja el AclBehavior. El AclBehavior
no configura el campo alias en la tabla aros, por lo que debemos usar una referencia a un objeto ARO
que necesitemos.
Quizs hayas notado que deliberadamente deje fuera index y view fuera de mis permisos ACL.
Haremos que los metodos index y view sean de acceso pblico en el controlador PostsController
y en el WidgetsController. Esto permite a los usuarios no autorizados para ver estas paginas,
haciendolas pblicas. Sin embargo, en cualquier momento puedes eliminar estas acciones desde
AuthComponent::allowedActions y los permisos de estas dos funciones volvern a su
configuracin original del Acl.
Ahora queremos eliminar las referencias al Auth->allowedActions en los controladores
de users y groups. Entonces agregamos el siguiente cdigo en los controladores de posts y widgets:
function beforeFilter() {
parent::beforeFilter();
$this->Auth->allowedActions = array('index', 'view');
}

Esto elimina el "interruptor de apagado" que colocamos anteriormente el los controladores de


groups y users, y otorga acceso pblico a las acciones index y view en aquellos controladores. En
AppController::beforeFilter() agrega lo siguiente:
$this->Auth->allowedActions = array('display');

Esto hace que la accin 'display' sea pblica. Esto mantendr publica nuestra accin
PagesController::display(). Esto es importante pues a menudo sta es la accion accesada por defecto del
routing de la aplicacin.
11.2.8 Logueo de Usuarios
Nuestra aplicacin ya esta bajo control de acceso, y cualquier intento de ver alguna pgina sin
acceso pblico ser redirigida a la pgina de login. Sin embargo, necesitamos crear una vista de login
antes

de

que

alguien

pueda

loguerase.

Agrega

el

siguiente

cdigo

app/views/users/login.ctp si es que an no lo has hecho.


<h2>Login</h2>
<?php
echo $form->create('User', array('url' => array('controller' => 'users', 'action'
=>'login')));
echo $form->input('User.username');
echo $form->input('User.password');
echo $form->end('Login');
?>

Tal vez quieras agregar un flash() para los mensajes del componente Auth en tu layout. Copia el
layout por defecto que se encuentra en cake/libs/views/layouts/default.ctp - a la
carpeta

de

layouts

de

tu

aplicacin

si

es

que

an

no

lo

has

hecho.

En

app/views/layouts/default.ctp agrega:
$session->flash('auth');

Ahora deberias poder loguerte y todo deber funcionar automgicamente. Cuando el acceso sea
denegado el mensaje apropiado del Auth ser desplegado si es que has agragado $session>flash('auth')
11.2.9 Logout (deslogueo)
Ahora al logout. Hace un momento dejamos esta funcin en blanco, ahora es el momento de
llenarla. En UsersController::logout() aade lo siguiente:
$this->Session->setFlash('Adios y nos vemos.');
$this->redirect($this->Auth->logout());

Esto establece el mensaje flash y saca al usuario de la aplicacin usando el mtodo logout del
componente Auth. Este mtodo bsicamente elimina la llave de la sesin del usuario y devuelve la url
que puede ser usada en el redireccionamiento. Si es que hay otros datos en la sesin que necesiten ser
eliminados se debe agregar ese cdigo ac.
11.2.10 Todo hecho
En este momento ya deberas tener una aplicacin controlada por los componentes Auth y Acl.
Los permisos de usuarios se hicieron al nivel de grupo, pero pueden ser configurados a nivel de
usuarios en cualquier momento. Tambin puedes configurar los permisos a nivel global y tambin por
controladores y acciones. Adems, tienes a tu disposicin un cdigo reusable para facilmente expandir
tu tabla de ACO a medida que tu aplicacin crece.

12 Apendices
Notas adicionales sobre el desarrollo con CakePHP

12.1 Migrando desde CakePHP 1.2 a 1.3


Esta gua resume muchos de los cambios necesarios al migrar desde CakePHP 1.2 al 1.3. Cada
seccin contiene informacin relevante acerca de las modificaciones hechas a los mtodos existentes
as como los mtodos que han sido eliminados/renombrados.
Reemplazos de archivos de aplicacin (importante)
webroot/index.php: Debe ser reemplazado debido a cambios en el proceso de bootstrapping.
config/core.php: Han sido aadidas configuraciones adicionales requeridas por PHP 5.3.
webroot/test.php: Reemplace este archivo si desea correr pruebas unitarias (unit tests).
# Removed Constants
Las siguientes constantes han sido eliminadas de CakePHP. Si su aplicacin depende de una de
ellas, debe definirla previamente en app/config/bootstrap.php
CIPHER_SEED

Reemplazada

por

la

variable

de

la

clase

Configure

Security.cipherSeed que debe ser cambiada en app/config/core.php


PEAR
INFLECTIONS
VALID_NOT_EMPTY
VALID_EMAIL
VALID_NUMBER
VALID_YEAR
# Configuration and application bootstrapping
Bootstrapping Additional Paths.
In your app/config/bootstrap.php you may have variables like $pluginPaths or
$controllerPaths.

There is a new way to add those paths. As of 1.3 RC1 the $pluginPaths variables will no
longer

work.

You

must

use

App::build() to modify paths.


App::build(array(
'plugins' => array('/full/path/to/plugins/', '/next/full/path/to/plugins/'),
'models' =>

array('/full/path/to/models/', '/next/full/path/to/models/'),

'views' => array('/full/path/to/views/', '/next/full/path/to/views/'),


'controllers'

=>

array('/full/path/to/controllers/',

=>

array('/full/path/to/datasources/',

'/next/full/path/to/controllers/'),
'datasources'
'/next/full/path/to/datasources/'),
'behaviors'

=>

array('/full/path/to/behaviors/',

'/next/full/path/to/behaviors/'),
'components'

=>

array('/full/path/to/components/',

'/next/full/path/to/components/'),
'helpers' => array('/full/path/to/helpers/', '/next/full/path/to/helpers/'),
'vendors' => array('/full/path/to/vendors/', '/next/full/path/to/vendors/'),
'shells' => array('/full/path/to/shells/', '/next/full/path/to/shells/'),
'locales' => array('/full/path/to/locale/', '/next/full/path/to/locale/')
));

Also

changed

is

the

order

in

which

bootstrapping

occurs.

In

the

past

app/config/core.php was loaded after app/config/bootstrap.php. This caused any


App::import() in an application bootstrap to be un-cached and considerably slower than a cached
include. In 1.3 core.php is loaded and the core cache configs are created before bootstrap.php is loaded.
Loading custom inflections
inflections.php ha sido removido, se trataba de un archivo innecesario, y las
caractersticas relacionadas fueron reprogramadas en un mtodo para incrementar su flexibilidad.
Ahora utilice Inflector::rules() para cargar las inflexiones personalizadas.
Inflector::rules('singular', array(
'rules'

=>

array('/^(bil)er$/i'

=>

'\1',

'\1ta'),
'uninflected' => array('singulars'),
'irregular' => array('spins' => 'spinor')
));

'/^(inflec|contribu)tors$/i'

=>

Will merge the supplied rules into the infection sets, with the added rules taking precedence
over the core rules.
# File renames and internal changes
Library Renames
Core

libraries

of

libs/session.php,

libs/socket.php,

libs/model/schema.php

and

libs/model/behavior.php have been renamed so that there is a better mapping between filenames and
main classes contained within (as well as dealing with some name-spacing issues):
session.php cake_session.php
App::import('Core', 'Session') App::import('Core', 'CakeSession')
socket.php cake_socket.php
App::import('Core', 'Socket') App::import('Core', 'CakeSocket')
schema.php cake_schema.php
App::import('Model', 'Schema') App::import('Model', 'CakeSchema')
behavior.php model_behavior.php
App::import('Core', 'Behavior') App::import('Core', 'ModelBehavior')
In most cases, the above renaming will not affect userland code.
Inheritance from Object
The following classes no longer extend Object:
Router
Set
Inflector
Cache
CacheEngine
If you were using Object methods from these classes, you will need to not use those methods.

12.1.1 Controller & Components


Controller
Controller::set() no longer changes variables from $var_name to $varName.
Variables always appear in the view exactly as you set them.
Controller::set('title', $var) no longer sets $title_for_layout when
rendering the layout. $title_for_layout is still populated by default. But if you want to
customize it, use $this->set('title_for_layout', $var).
Controller::$pageTitle

has

been

removed.

Use

$this-

>set('title_for_layout', $var); instead.


Controller has two new methods startupProcess and shutdownProcess. These
methods are responsible for handling the controller startup and shutdown processes.
Component
Component::triggerCallback has been added. It is a generic hook into the component
callback process. It supplants Component::startup(), Component::shutdown()
and Component::beforeRender() as the preferred way to trigger callbacks.
CookieComponent
del is deprecated use delete
AclComponent + DbAcl
Node reference checks done with paths are now less greedy and will no longer consume intermediary
nodes when doing searches. In the past given the structure:
ROOT/
Users/
Users/
edit

The path ROOT/Users would match the last Users node instead of the first. In 1.3, if you were
expecting to get the last node you would need to use the path ROOT/Users/Users

RequestHandlerComponent
getReferrer is deprecated use getReferer
SessionComponent & SessionHelper
del is deprecated use delete
SessionComponent::setFlash() second param used to be used for setting the layout
and accordingly rendered a layout file. This has been modifed to use an element. If you specified
custom session flash layouts in your applications you will need to make the following changes.
1. Move the required layout files into app/views/elements
2. Rename the $content_for_layout variable to $message
3. Make sure you have echo $session->flash(); in your layout
SessionComponent and SessionHelper are not automatically loaded.
Both SessionComponent and SessionHelper are no longer automatically included
without you asking for them. SessionHelper and SessionComponent now act like every other
component and must be declared like any other helper/component. You should update
AppController::$components and AppController::$helpers to include these classes
to retain existing behavior.
var $components = array('Session', 'Auth', ...);
var $helpers = array('Session', 'Html', 'Form' ...);

These change were done to make CakePHP more explicit and declarative in what classes you
the application developer want to use. In the past there was no way to avoid loading the Session classes
without modifying core files. Which is something we want you to be able to avoid. In addition Session
classes were the only magical component and helper. This change helps unify and normalize behavior
amongst all classes.
# Library Classes
CakeSession
del is deprecated use delete

SessionComponent
SessionComponent::setFlash() now uses an element instead of a layout as its second
parameter. Be sure to move any flash layouts from app/views/layouts to app/views/elements and
change instances of $content_for_layout to $message.
Folder
mkdir is deprecated use create
mv is deprecated use move
ls is deprecated use read
cp is deprecated use copy
rm is deprecated use delete
Set
isEqual is deprecated. Use == or ===.
String
getInstance is deprecated, call String methods statically.
Router
Routing.admin is deprecated. It provided an inconsistent behavior with other prefix style
routes in that it was treated differently. Instead you should use Routing.prefixes. Prefix routes in
1.3 do not require additional routes to be declared manually. All prefix routes will be generated
automatically. To update simply change your core.php.
//from:
Configure::write('Routing.admin', 'admin');
//to:
Configure::write('Routing.prefixes', array('admin'));

See the New features guide for more information on using prefix routes. A small change has
also been done to routing params. Routed params should now only consist of alphanumeric chars, - and
_ or /[A-Z0-9-_+]+/.
Router::connect('/:$%@#param/:action/*', array(...)); // BAD
Router::connect('/:can/:anybody/:see/:m-3/*', array(...)); //Acceptable

For 1.3 the internals of the Router were heavily refactored to increase performance and reduce
code clutter. The side effect of this is two seldom used features were removed, as they were
problematic and buggy even with the existing code base. First path segments using full regular
expressions was removed. You can no longer create routes like
Router::connect('/([0-9]+)-p-(.*)/', array('controller' => 'products', 'action' =>
'show'));

These routes complicated route compilation and impossible to reverse route. If you need routes
like this, it is recommended that you use route parameters with capture patterns. Next mid-route greedy
star support has been removed. It was previously possible to use a greedy star in the middle of a route.
Router::connect(
'/pages/*/:event',
array('controller' => 'pages', 'action' => 'display'),
array('event' => '[a-z0-9_-]+')
);

This is no longer supported as mid-route greedy stars behaved erratically, and complicated route
compiling. Outside of these two edge-case features and the above changes the router behaves exactly as
it did in 1.2
Also, people using the 'id' key in array-form URLs will notice that Router::url() now treats this
as a named parameter. If you previously used this approach for passing the ID parameter to actions, you
will need to rewrite all your $html->link() and $this->redirect() calls to reflect this change.
// old format:
$url = array('controller' => 'posts', 'action' => 'view', 'id' => $id);
// use cases:
Router::url($url);
$html->link($url);
$this->redirect($url);
// 1.2 result:
/posts/view/123
// 1.3 result:
/posts/view/id:123
// correct format:
$url = array('controller' => 'posts', 'action' => 'view', $id);

Dispatcher
Dispatcher is no longer capable of setting a controller's layout/viewPath with request
parameters. Control of these properties should be handled by the Controller, not the Dispatcher. This
feature was also undocumented, and untested.
Debugger
Debugger::checkSessionKey()

has

been

renamed

to

works.

Use

Debugger::checkSecurityKeys()
Calling

Debugger::output("text")

no

longer

Debugger::output("txt").
Object
Object::$_log has been removed. CakeLog::write is now called statically. See New
Logging features for more information on changes made to logging.
Sanitize
Sanitize::html() now actually always returns escaped strings. In the past using the
$remove parameter would skip entity encoding, returning possibly dangerous content.
Sanitize::clean() now has a remove_html option. This will trigger the
strip_tags feature of Sanitize::html(), and must be used in conjunction with the
encode parameter.
Configure and App
Configure::listObjects() replaced by App::objects()
Configure::corePaths() replaced by App::core()
Configure::buildPaths() replaced by App::build()
Configure no longer manages paths.
Configure::write('modelPaths', array...) replaced by App::build(array('models' => array...))
Configure::read('modelPaths') replaced by App::path('models')
There is no longer a debug = 3. The controller dumps generated by this setting often caused
memory consumption issues making it an impractical and unusable setting. The $cakeDebug
variable has also been removed from View::renderLayout You should remove this
variable reference to avoid errors.

Configure::load()

can

now

load

configuration

files

from

plugins.

Use

Configure::load('plugin.file'); to load configuration files from plugins. Any


configuration files in your application that use . in the name should be updated to use _
Cache
In addition to being able to load CacheEngines from app/libs or plugins, Cache underwent some
refactoring for CakePHP1.3. These refactorings focused around reducing the number and frequency of
method calls. The end result was a significant performance improvement with only a few minor API
changes which are detailed below.
The changes in Cache removed the singletons used for each Engine type, and instead an engine
instance is made for each unique key created with Cache::config(). Since engines are not
singletons anymore, Cache::engine() was not needed and was removed. In addition
Cache::isInitialized() now checks cache configuration names, not cache engine names. You
can still use Cache::set() or Cache::engine() to modify cache configurations. Also checkout
the New features guide for more information on the additional methods added to Cache.
It should be noted that using an app/libs or plugin cache engine for the default cache config can
cause performance issues as the import that loads these classes will always be uncached. It is
recommended that you either use one of the core cache engines for your default configuration, or
manually include the cache engine class before configuring it. Furthermore any non-core cache engine
configurations should be done in app/config/bootstrap.php for the same reasons detailed
above.
12.1.2 Model Databases and Datasources
Model
Model::del()

and

Model::remove()

have

been

removed

in

favor

of

Model::delete(), which is now the canonical delete method.


Model::findAll, findCount, findNeighbours, removed.
Dynamic calling of setTablePrefix() has been removed. tableprefix should be with the
$tablePrefix property, and any other custom construction behavior should be done in an
overridden Model::__construct().
DboSource::query() now throws warnings for un-handled model methods, instead of

trying to run them as queries. This means, people starting transactions improperly via the
$this->Model->begin() syntax will need to update their code so that it accesses the
model's DataSource object directly.
Missing validation methods will now trigger errors in development mode.
Missing behaviors will now trigger a cakeError.
Model::find(first) will no longer use the id property for default conditions if no
conditions are supplied and id is not empty. Instead no conditions will be used
For Model::saveAll() the default value for option 'validate' is now 'first' instead of true
Datasources
DataSource::exists() has been refactored to be more consistent with non-database backed
datasources. Previously, if you set var $useTable = false; var $useDbConfig =
'custom';, it was impossible for Model::exists() to return anything but false. This
prevented custom datasources from using create() or update() correctly without some
ugly hacks. If you have custom datasources that implement create(), update(), and
read() (since Model::exists() will make a call to Model::find('count'), which
is passed to DataSource::read()), make sure to re-run your unit tests on 1.3.
Databases
Most database configurations no longer support the 'connect' key (which has been deprecated
since pre-1.2). Instead, set 'persistent' => true or false to determine whether or not a
persistent database connection should be used
SQL log dumping
A commonly asked question is how can one disable or remove the SQL log dump at the bottom
of the page?. In previous versions the HTML SQL log generation was buried inside DboSource. For 1.3
there is a new core element called sql_dump. DboSource no longer automatically outputs SQL
logs. If you want to output SQL logs in 1.3, do the following:
<?php echo $this->element('sql_dump'); ?>

You can place this element anywhere in your layout or view. The sql_dump element will only
generate output when Configure::read('debug') is equal to 2. You can of course customize or
override this element in your app by creating app/views/elements/sql_dump.ctp.

# View and Helpers


View
View::renderElement removed. Use View::element() instead.
Automagic support for .thtml view file extension has been removed either declare $this>ext = 'thtml'; in your controllers, or rename your views to use .ctp
View::set('title', $var) no longer sets $title_for_layout when rendering
the layout. $title_for_layout is still populated by default. But if you want to customize
it, use $this->set('title_for_layout', $var).
View::$pageTitle has been removed. Use $this->set('title_for_layout',
$var); instead.
The $cakeDebug layout variable associated with debug = 3 has been removed. Remove it
from your layouts as it will cause errors. Also see the notes related to SQL log dumping and
Configure for more information.
All core helpers no longer use Helper::output(). The method was inconsistently used and
caused output issues with many of FormHelper's methods. If you previously overrode
AppHelper::output() to force helpers to auto-echo you will need to update your view files to
manually echo helper output.
TextHelper
TextHelper::trim() is deprecated, used truncate() instead.
TextHelper::highlight() no longer has:
an $highlighter parameter. Use $options['format'] instead.
an $considerHtmlparameter. Use $options['html'] instead.
TextHelper::truncate() no longer has:
an $ending parameter. Use $options['ending'] instead.
an $exact parameter. Use $options['exact'] instead.
an $considerHtmlparameter. Use $options['html'] instead.
PaginatorHelper
PaginatorHelper has had a number of enhancements applied to make styling easier.
prev(), next(), first() and last()

The disabled state of these methods now defaults to <span> tags instead of <div> tags.
passedArgs are now auto merged with url options in paginator.
sort(), prev(), next() now add additional class names to the generated html. prev()
adds a class of prev. next() adds a class of next. sort() will add the direction currently being
sorted, either asc or desc.
FormHelper
FormHelper::dateTime()

no

longer

has

$showEmpty

parameter.

Use

$attributes['empty'] instead.
FormHelper::year()

no

longer

has

$showEmpty

parameter.

Use

$showEmpty

parameter.

Use

parameter.

Use

parameter.

Use

parameter.

Use

parameter.

Use

$attributes['empty'] instead.
FormHelper::month()

no

longer

has

$attributes['empty'] instead.
FormHelper::day()

no

longer

has

$showEmpty

$attributes['empty'] instead.
FormHelper::minute()

no

longer

has

$showEmpty

$attributes['empty'] instead.
FormHelper::meridian()

no

longer

has

$showEmpty

$attributes['empty'] instead.
FormHelper::select()

no

longer

has

$showEmpty

$attributes['empty'] instead.
Default urls generated by form helper no longer contain 'id' parameter. This makes default urls
more consistent with documented userland routes. Also enables reverse routing to work in a
more intuitive fashion with default FormHelper urls.
FormHelper::submit() Can now create other types of inputs other than type=submit. Use
the type option to control the type of input generated.
FormHelper::button() Now creates <button> elements instead of reset or clear
inputs. If you want to generate those types of inputs use FormHelper::submit() with a
'type' => 'reset' option for example.
FormHelper::secure() and FormHelper::create() no longer create hidden
fieldset elements. Instead they create hidden div elements. This improves validation with

HTML4.
Also be sure to check the Form helper improvements for additional changes and new features in
the FormHelper.
HtmlHelper
HtmlHelper::meta() no longer has an $inline parameter. It has been merged with the
$options array.
HtmlHelper::link()

no

longer

has

an

$escapeTitle

parameter.

Use

$options['escape'] instead.
HtmlHelper::para()

no

longer

has

an

$escape

parameter.

Use

$options['escape'] instead.
HtmlHelper::div()

no

longer

has

an

$escape

parameter.

Use

longer

has

an

$escape

parameter.

Use

longer

has

an

$inline

parameter.

Use

$options['escape'] instead.
HtmlHelper::tag()

no

$options['escape'] instead.
HtmlHelper::css()

no

$options['inline'] instead.
SessionHelper
flash() no longer auto echos. You must add an echo $session->flash(); to your
session->flash() calls. flash() was the only helper method that auto outputted, and was changed
to create consistency in helper methods.
CacheHelper
CacheHelper's interactions with Controller::$cacheAction has changed slightly. In the
past if you used an array for $cacheAction you were required to use the routed url as the keys, this
caused caching to break whenever routes were changed. You also could set different cache durations for
different passed argument values, but not different named parameters or query string parameters. Both
of these limitations/inconsistencies have been removed. You now use the controller's action names as
the keys for $cacheAction. This makes configuring $cacheAction easier as its no longer
coupled to the routing, and allows cacheAction to work with all custom routing. If you need to have
custom cache durations for specific argument sets you will need to detect and update cacheAction in
your controller.

TimeHelper
TimeHelper has been refactored to make it more i18n friendly. Internally almost all calls to
date() have been replaced by strftime(). The new method TimeHelper::i18nFormat() has been added
and will take localization data from a LC_TIME locale definition file in app/locale following the
POSIX standard. These are the changes made in the TimeHelper API:
TimeHelper::format() can now take a time string as first parameter and a format string as the
second one, the format must be using the strftime() style. When called with this parameter order
it will try to automatically convert the date format into the preferred one for the current locale. It
will also take parameters as in 1.2.x version to be backwards compatible, but in this case format
string must be compatible with date().
TimeHelper::i18nFormat() has been added
Deprecated Helpers
Both the JavascriptHelper and the AjaxHelper are deprecated, and the JsHelper + HtmlHelper
should be used in their place.
You should replace
$javascript->link() with $html->script()
$javascript->codeBlock()

with

$html->scriptBlock()

or

$html-

>scriptStart() and $html->scriptEnd() depending on your usage.


# Console and shells
Shell
Shell::getAdmin() has been moved up to ProjectTask::getAdmin()
Schema shell
cake schema run create has been renamed to cake schema create
cake schema run update has been renamed to cake schema update
Console Error Handling
The shell dispatcher has been modified to exit with a 1 status code if the method called on the
shell explicitly returns false. Returning anything else results in a 0 status code. Before the value
returned from the method was used directly as the status code for exiting the shell.

Shell methods which are returning 1 to indicate an error should be updated to return false
instead.
Shell::error() has been modified to exit with status code 1 after printing the error
message which now uses a slightly different formatting.
$this->error('Invalid Foo', 'Please provide bar.');
// outputs:
Error: Invalid Foo
Please provide bar.
// exits with status code 1

ShellDispatcher::stderr() has been modified to not prepend Error: to the message


anymore. It's signature is now similar to Shell::stdout().
ShellDispatcher::shiftArgs()
The method has been modified to return the shifted argument. Before if no arguments were
available the method was returning false, it now returns null. Before if arguments were available the
method was returning true, it now returns the shifted argument instead.
12.1.3 Vendors, Test Suite & schema
vendors/css, vendors/js, and vendors/img
Support for these three directories, both in app/vendors as well as plugin/vendors has
been removed. They have been replaced with plugin and theme webroot directories.
Test Suite and Unit Tests
Group tests should now extend TestSuite instead of the deprecated GroupTest class. If your
Group tests do not run, you will need to update the base class.
Vendor, plugin and theme assets
Vendor asset serving has been removed in 1.3 in favour of plugin and theme webroot
directories.
Schema files used with the SchemaShell have been moved to app/config/schema instead
of app/config/sql Although config/sql will continue to work in 1.3, it will not in future
versions, it is recommend that the new path is used.

12.2 Nuevas caractersticas en CakePHP 1.3


CakePHP 1.3 introdujo varias caractersticas nuevas. Esta gua intenta resumir los cambios y
vincular a la documentacin expandida donde sea necesario.
# Componentes
SecurityComponent
Los mtodos requireXX como requireGet y requirePost ahora aceptan un nico array
como argumento adems de una coleccin de cadenas de texto.
$this->Security->requirePost(array('edit', 'update'));

Configuracin de componentes
La configuracin para todos los componentes del ncleo puede ser definida desde el array
$components. De la misma forma que los comportamientos, se pueden declarar parametros de
configuracin cuando se declara el componente.
var $components = array(
'Cookie' => array(
'name' => 'MyCookie'
),
'Auth' => array(
'userModel' => 'MyUser',
'loginAction' => array('controller' => 'users', 'action' => 'login')
)
);

Esto debera reducir la cantidad de cdigo en los mtodos beforeFilter().


EmailComponent
Ahora se puede obtener el contenido del correo electrnico creado, leyendo $this->Email>htmlMessage y $this->Email->textMessage. Estas propiedades almacenan el
contenido en html y en texto plano respectivamente.
Muchos de los mtodos privados (private) del EmailComponent's ahora son protegidos
(protected) para facilitar la extensin de los mismos.
EmailComponent::$to ahora tambin puede ser un array, facilitando la configuracin de

mltiples destinatarios, y mejorando la consistencia con otras propiedades.


EmailComponent::$messageId ha sido aadida, y permite controlar el encabezado
Message-ID del correo electrnico.
# View & Helpers
Helpers can now be addressed at $this->Helper->func() in addition to $helper>func(). This allows view variables and helpers to share names and not create collisions.
New JsHelper and new features in HtmlHelper
See JsHelper documentation for more information
Pagination Helper
Pagination helper provides additional css classes for styling and you can set the default sort()
direction. PaginatorHelper::next() and PaginatorHelper::prev() now generate span
tags by default, instead of divs.
Helper
Helper::assetTimestamp() has been added. It will add timestamps to any asset under
WWW_ROOT. It works with Configure::read('Asset.timestamp'); just as before, but
the functionality used in Html and Javascript helpers has been made available to all helpers. Assuming
Asset.timestamp == force
$path = 'css/cake.generic.css'
$stamped = $this->Html->assetTimestamp($path);
//$stamped contains 'css/cake.generic.css?5632934892'

The appended timestamp contains the last modification time of the file. Since this method is
defined in Helper it is available to all subclasses.
TextHelper
highlight() now accepts an array of words to highlight.
NumberHelper
A new method addFormat() has been added. This method allows you to set currency
parameter sets, so you don't have to retype them.

$this->Number->addFormat('NOK', array('before' => 'Kr. '));


$formatted = $this->Number->currency(1000, 'NOK');

FormHelper
The form helper has had a number of improvements and API modifications, see Form Helper
improvements for more information.
12.2.1 Logging
Logging and CakeLog have been enhanced considerably, both in features and flexibility. See
New Logging features for more information.
# Caching
Cache engines have been made more flexible in 1.3. You can now provide custom Cache
adapters in app/libs as well as in plugins using $plugin/libs. App/plugin cache engines can
also override the core engines. Cache adapters must be in a cache directory. If you had a cache engine
MyCustomCacheEngine

named

it

app/libs/cache/my_custom_cache.php

would
as

be
an

placed
app/libs.

in

either
Or

in

$plugin/libs/cache/my_custom_cache.php as part of a plugin. Cache configs from


plugins need to use the plugin dot syntax.
Cache::config('custom', array(
'engine' => 'CachePack.MyCustomCacheEngine',
...
));

New Cache methods


Cache has a few new methods for 1.3 which make introspection and testing teardown easier.
Cache::configured() returns an array of configured Cache engine keys.
Cache::drop($config) drops a configured Cache engine. Once dropped cache engines
are no longer readable or writeable.
Cache::increment() Perform an atomic increment on a numeric value. This is not
implemented in FileEngine.
Cache::decrement() Perform an atomic decrement on a numeric value. This is not

implemented in FileEngine.
# Models, Behaviors and Datasource
App::import(), datasources & datasources from plugins
Datasources can now be included loaded with App::import() and be included in plugins!
To

include

datasource

in

your

plugin

you

put

it

in

my_plugin/models/datasources/your_datasource.php. To import a Datasource from


a plugin use App::import('Datasource', 'MyPlugin.YourDatasource');
Using plugin datasources in your database.php
You can use plugin datasources by setting the datasource key with the plugin name. For
example

if

you

had

WebservicePack

plugin

with

LastFm

datasource

(plugin/webservice_pack/models/datasources/last_fm.php), you could do:


var $lastFm = array(
'datasource' => 'WebservicePack.LastFm'
...

Model
Missing Validation methods now trigger errors, making debugging why validation isn't working
easier.
Models now support virtual fields
Behaviors
Using behaviors that do not exist, now triggers a cakeError making missing behaviors easier
to find and fix.
CakeSchema
CakeSchema can now locate, read and write schema files to plugins. The SchemaShell also
exposes this functionality, see below for changes to SchemaShell. CakeSchema also supports
tableParameters. Table Parameters are non column specific table information such as collation,
charset, comments, and table engine type. Each Dbo implements the tableParameters they support.

tableParameters in MySQL
MySQL supports the greatest number of tableParameters; You can use tableParameters to set a
variety of MySQL specific settings.
engine Control the storage engine used for your tables.
charset Control the character set used for tables.
encoding Control the encoding used for tables.
In addition to tableParameters MySQL dbo's implement fieldParameters. fieldParameters
allow you to control MySQL specific settings per column.
charset Set the character set used for a column
encoding Set the encoding used for a column
See below for examples on how to use table and field parameters in your schema files.
tableParameters in Postgres
....
tableParameters in SQLite
....
Using tableParameters in schema files
You use tableParameters just as you would any other key in a schema file. Much like
indexes:
var $comments => array(
'id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'key' =>
'primary'),
'post_id' => array('type' => 'integer', 'null' => false, 'default' => 0),
'comment' => array('type' => 'text'),
'indexes' => array(
'PRIMARY' => array('column' => 'id', 'unique' => true),
'post_id' => array('column' => 'post_id'),),
'tableParameters' => array(
'engine' => 'InnoDB',
'charset' => 'latin1',
'collate' => 'latin1_general_ci')
);

is an example of a table using tableParameters to set some database specific settings. If


you use a schema file that contains options and features your database does not implement, those
options will be ignored. For example if you imported the above schema to a PostgreSQL server, all of
the tableParameters would be ignore as PostgreSQL does not support any of the included options.
# Console
Bake
Bake has had a number of significant changes made to it. Those changes are detailed in the bake
updates section
Subclassing
The ShellDispatcher has been modified to not require shells and tasks to have Shell as their
immediate parent anymore.
Output
Shell::nl() has been added. It returns a single or multiple linefeed sequences.
Shell::out(), err() and hr() now accept a $newlines parameter which is passed to nl()
and allows for controlling how newlines are appended to the output.
Shell::out() and Shell::err() have been modified, allowing a parameterless usage.
This is especially useful if you're often using $this->out('') for outputting just a single newline.
Acl Shell
All AclShell commands now take node parameters. node parameters can be either an alias
path like controllers/Posts/view or Model.foreign_key ie. User.1. You no longer need to
know or use the aco/aro id for commands.
The Acl shell dataSource switch has been removed. Use the Configure settings instead.
SchemaShell
The Schema shell can now read and write Schema files and SQL dumps to plugins. It expects
and will create schema files in $plugin/config/schema
....

# Router and Dispatcher


Router
Generating urls with new style prefixes works exactly the same as admin routing did in 1.2.
They use the same syntax and persist/behave in the same way. Assuming you have
Configure::write('Routing.prefixes', array('admin', 'member')); in your
core.php you will be able to do the following from a non-prefixed url:
$this->Html->link('Go',

array('controller'

=>

'posts',

'action'

=>

'index',

array('controller'

=>

'posts',

'action'

=>

'index',

'member' => true));


$this->Html->link('Go',
'admin' => true));

Likewise, if you are in a prefixed url and want to go to a non-prefixed url, do the following:
$this->Html->link('Go',

array('controller'

=>

'posts',

'action'

=>

'index',

array('controller'

=>

'posts',

'action'

=>

'index',

'member' => false));


$this->Html->link('Go',
'admin' => false));

Route classes
For 1.3 the router has been internally rebuilt, and a new class CakeRoute has been created.
This class handles the parsing and reverse matching of an individual connected route. Also new in 1.3
is the ability to create and use your own Route classes. You can implement any special routing features
that may be needed in application routing classes. Developer route classes must extend CakeRoute, if
they do not an error will be triggered. Commonly a custom route class will override the parse()
and/or match() methods found in CakeRoute to provide custom handling.
Dispatcher
Accessing filtered asset paths, while having no defined asset filter will create 404 status code
responses.
# Library classes
Inflector
You can now globally customize the default transliteration map used in Inflector::slug using
Inflector::rules.

eg.

Inflector::rules('transliteration',

array('//'

=>

'aa', '//' => 'oe'))


The Inflector now also internally caches all data passed to it for inflection (except slug method).
Set
Set has a new method Set::apply(), which allows you to apply callbacks to the results of
Set::extract and do so in either a map or reduce fashion.
Set::apply('/Movie/rating', $data, 'array_sum');

Would return the sum of all Movie ratings in $data.


L10N
All languages in the catalog now have a direction key. This can be used to determine/define the
text direction of the locale being used.
File
File now has a copy() method. It copies the file represented by the file instance, to a new
location.
Configure
Configure::load()

can

now

load

configuration

files

from

plugins.

Use

Configure::load('plugin.file'); to load configuration files from plugins. Any


configuration files in your application that use . in the name should be updated to used _
App/libs
In addition to app/vendors a new app/libs directory has been added. This directory can
also be part of plugins, located at $plugin/libs. Libs directories are intended to contain 1st party
libraries that do not come from 3rd parties or external vendors. This allows you to separate your
organization's internal libraries from vendor libraries. App::import() has also been updated to
import from libs directories.
App::import('Lib', 'ImageManipulation'); //imports app/libs/image_manipulation.php

You can also import libs files from plugins


App::import('Lib',

'Geocoding.Geocode');

app/plugins/geocoding/libs/geocode.php

//imports

The remainder of lib importing syntax is identical to vendor files. So if you know how to import
vendor files with unique names, you know how to import libs files with unique names.
Configuration
The default Security.level in 1.3 is medium instead of high
There is a new configuration value Security.cipherSeed this value should be
customized to ensure more secure encrypted cookies, and a warning will be generated in
development mode when the value matches its default value.
i18n
Now you can use locale definition files for the LC_TIME category to retrieve date and time
preferences for a specific language. Just use any POSIX compliant locale definition file and store it at
app/locale/language/ (do not create a folder for the category LC_TIME, just put the file in there).
For example, if you have access to a machine running debian or ubuntu you can find a french
locale file at: /usr/share/i18n/locales/fr_FR. Copy the part corresponding to LC_TIME into
app/locale/fr_fr/LC_TIME file. You can then access the time preferences for French language this way:
Configure::write('Config.language','fr-fr'); // set the current language
$monthNames = __c('mon',LC_TIME,true); // returns an array with the month names in
French
$dateFormat = __c('d_fmt',LC_TIME,true); // return the preferred dates format for
France

You can read a complete guide of possible values in LC_TIME definition file in this page
# Miscellaneous
Error Handling
Subclasses of ErrorHandler can more easily implement additional error methods. In the past you
would need to override __construct() and work around ErrorHandler's desire to convert all error
methods into error404 when debug = 0. In 1.3, error methods that are declared in subclasses are not
converted to error404. If you want your error methods converted into error404, then you will need
to do it manually.
Scaffolding
With the addition of Routing.prefixes scaffolding has been updated to allow the

scaffolding of any one prefix.


Configure::write('Routing.prefixes', array('admin', 'member'));
class PostsController extends AppController {
var $scaffold = 'member';
}

Would use scaffolding for member prefixed urls.


Validation
After 1.2 was released, there were numerous requests to add additional localizations to the
phone() and postal() methods. Instead of trying to add every locale to Validation itself, which
would result in large bloated ugly methods, and still not afford the flexibility needed for all cases, an
alternate path was taken. In 1.3, phone() and postal() will pass off any country prefix it does not
know how to handle to another class with the appropriate name. For example if you lived in the
Netherlands you would create a class like
class NlValidation {
function phone($check) {
...
}
function postal($check) {
...
}
}

This file could be placed anywhere in your application, but must be imported before attempting
to use it. In your model validation you could use your NlValidation class by doing the following.
var $validate = array(
'phone_no' => array('rule' => array('phone', null, 'nl')),
'postal_code' => array('rule' => array('postal', null, 'nl'))
);

When your model data is validated, Validation will see that it cannot handle the 'nl' locale and
will attempt to delegate out to NlValidation::postal() and the return of that method will be
used as the pass/fail for the validation. This approach allows you to create classes that handle a subset
or group of locales, something that a large switch would not have. The usage of the individual

validation methods has not changed, the ability to pass off to another validator has been added.
IP Address Validation
Validation of IP Addresses has been extended to allow strict validation of a specific IP Version.
It will also make use of PHP native validation mechanisms if available.
Validation::ip($someAddress);

// Validates both IPv4 and IPv6

Validation::ip($someAddress, 'IPv4'); // Validates IPv4 Addresses only


Validation::ip($someAddress, 'IPv6'); // Validates IPv6 Addresses only

Validation::uuid()
A uuid() pattern validation has been added to the Validation class. It will check that a given
string matches a uuid by pattern only. It does not ensure uniqueness of the given uuid.

También podría gustarte