Herramientas de usuario

Herramientas del sitio


fw:others:cake

CakePHP

Instalación

  • Al descomprimir te toparás con 3 carpetas. En la carpeta app será donde la aplicación sea desarrollada, en cake donde está el código de CakePHP y en vendors donde podemos colocar otras librerías.
  • Se basa en el patrón MVC (Modelo Vista Controlador) y por ello existen clases Modelo, clases Vista y clases Controlador que se guardan en los directorios /app/models, /app/view y /app/controllers respectivamente.
  • Necesitarás configurar el mod_rewrite de Apache para que CakePHP funcione, aquí tienes unos posibles pasos:
    1. Si la dirección con la que accedes al index.php es: http://127.0.0.1/pruebas/cake/app/webroot/index.php y eso sigue sin funcionar, tendrás que editar los .htaccess de (siendo “tu_ruta” donde está el directorio raíz de cake): tu_ruta/.htaccess, tu_ruta/app/.htaccess y tu_ruta/app/webroot/.htaccess. Añadiendo: RewriteBase /pruebas/cake
    2. Si la ventana de bienvenida aparece sin estilos ni imágenes es porque el mod_rewrite puede no estar funcionando correctamente. Habrá que configurarlo.
    3. Instalalo en Apache y asegurate que está cargado mediante una llamada phpinfo();.
    4. Si está cargado y sigue sin ir, asegurate que los AllowOverride del fichero de configuración de Apache estén a All y no a None.
  • Aún así puedes prescindir de el mod_rewrite (algo no recomendable) si en el fichero de configuración global (/app/config/core.php) descomentas la línea: define ('BASE_URL', env('SCRIPT_NAME'));

Configuración

  • Necesitarás configurar la base de datos la primera vez que inicies una aplicación de CakePHP; para una configuración estándard renombra /app/config/database.php.default a /app/config/database.php.
  • Para separar cakephp en distintos directorios tendrás que editar el fichero app/webroot/index.php y cambiar:
    • ROOT: la carpeta dónde se encuentra la carpeta app.
    • APP_DIR: la ruta de la carpeta app.
    • CAKE_CORE_INCLUDE_PATH: la carpeta donde se encuentra la carpeta cake (el framework en sí). Por ejemplo si la ruta completa de cake es: /home/alfred/Projects/PruebasWeb/cake, haremos: define('CAKE_CORE_INCLUDE_PATH', '/home/alfred/Projects/PruebasWeb');
  • Para que los errores lanzados por CakePHP no sean descriptivos debes cambiar el valor en core.php de debug a uno más alto de 0. Esto hará también que los mensajes flash activen la redirección automática.
  • Para configurar la ruta de los ficheros que se van a cargar lo haremos en routes.php. Este archivo nos permite indicar cual será el archivo a cargar, por ejemplo, como portada. La línea que indica la ruta por defecto es:
$Route->connect('/', array('controller' => 'users', 'action' => 'display', 'home'));

El primer parámetro es el directorio en cuestión que estamos tratando (/) controller y action las páginas controlador con su respectiva acción. A partir de ahí serán los parámetros a la acción. En este caso 'home' es el primero.

Modelos, Vistas y Controladores

Nombres de clase y de archivos

Ejemplo para el elemento Post que tiene en la base de datos una tabla correspondiente llamada posts:

  • Para los modelos el nombre de la clase es el nombre de la tabla a la que están enlazados en singular (Post), el del archivo es este mismo nombre pero en minusculas (post.php). Este archivo ha de colocarse en /app/models/.
  • Para los controladores el nombre de la clase es el modelo al que pertenecen pero en plural y seguido de Controller (PostController), el nombre del archivo es en minusculas y con una raya baja entre el elemento y el controller (posts_controller.php). Este archivo ha de colocarse en /app/controllers/.
  • Las vistas se encuentran en /app/views/<controlador>/<acción> y son archivos .thtml. Por ejemplo, la view para PostController::add() estará en /app/views/posts/add.thtml.

Controladores

  • Son los que manejan la lógica de la aplicación.
  • Se puede crear el controlador de clase (AppController) de forma opcional (ha de heredar de Controller) en /app/app_controller.php, contendrá métodos que pueden ser accedidos por varios controladores de la aplicación.
  • Cada función es una de las características de la página para el elemento que “controla”.


Por ejemplo: /app/controllers/videos_controller.php

class VideosController extends AppController
{
    function view($id)
    {}
    function rent($customer_id, $video_id)
    {}
    function search($query)
    {}
}

Será accedido como:

  • http://www.example.com/videos/view/253
  • http://www.example.com/videos/rent/5124/0-235253
  • http://www.example.com/videos/search/hudsucker+proxy

Métodos

  • set (var, valor) Permite comunicar el controlador con la vista asignando variables.
  • validate () Valida el formulario
  • render (accion, layout, file) Se llama automáticamente, pero puede que la necesites.
  • redirect(url) Redirige al usuario
  • flash (msg, url, pause) Muestra un msg por pause segundos en la capa de flash (app/views/layouts/flash.html) y luego redirige al usuario a la url.
  • beforeFilter () Llamado antes de cada acción, para chequear sesiones y roles.
  • afterFilter () Llamado después de cada acción.
  • beforeRender () Llamaado justo antes de que la vista se muestre.
  • requesAction (url, extra) Para llamar a una acción del controlador (con el estilo: /controllername/actionname/params). Puedes coger datos o una vista ya renderizada de un controlador. (También es útil en casos que uses AJAX).
  • postConditions (data) Devuelve un array formateado de los data para ser pasado a otros métodos como findAll.
  • log (msg, tipo) Guardará un mensaje en /tmp, el tipo puede ser LOG_ERROR o LOG_DEBUG o ninguno (que sería un LOG_ERROR).

Variables

  • $name Útil si usas php4, para asignar el nombre de la clase.
  • $uses Por si usas más de un modelo en un controlador (un controlador carga automáticamente su modelo). var $uses = array('su_modelo', 'modelo_xtra1', 'modelo_xtra2');
  • $helpers para cargar más helpers en la vista, automáticamente se carga el html, pero si agregas otros también deberás agregarlo: var $helpers = array('Html','Ajax','Javascript');
  • $components para cargar componentes.
  • $layout Indica el nombre del layout para el controlador.
  • $autoRender Si se pone a false se dejará automáticamente de llamar a las acciones de rendering.
  • $beforeFilter puedes definir acciones que se llamarán métodos de cada acción. Por ejemplo para validar un usuario.
class ProductsController extends AppController
{
    var $beforeFilter = array('checkAccess');
    function checkAccess() {}
    function index() {}
}

Aquí se llamaría antes a checkAccess que a index

Parámetros

  • $this→data Para recoger los datos enviados por POST

Los siguientes serían la xxx de $this→params['xxx']:

  • form Recoge más datos del form
  • bare 1 si el layaut actual es vacío
  • ajax 1 si el layaut actual es ajax
  • controller nombre del controlador
  • action almacena la acción del controlador
  • pass coge el string que se le ha pasado
  • url recoge la url con la que se ha llamado

Modelos

Un modelo es un acceso a una base de datos (más concretamente a una tabla), su nombre es el de la tabla en singular (por ejemplo la tabla users tendrá el modelo user). También contendrá datos de validación y métodos específicos para esa tabla.
Los modelos se guardan en /app/models y han de heredar de la clase AppModel. Para acceder a ellos, en el controlador correspondiente, tendrás un objeto a dicho modelo. Un ejemplo de modelo sería el siguiente:

<?php
class User extends AppModel {
    var $name = 'User';
    var $validate = array();
    var $hasMany = array('Image' => array('className' => 'Image'));
 
    function makeInactive($uid) {...}
}
?>

Si existen métodos que se comparten entre dos o más modelos puedes crear tu propio modelo por defecto en app/app_model.php.

Definir funciones propias

Por ejemplo métodos para esconder u ocultar los post de un blog:

<?php
class Post extends AppModel {
   var $name = 'Post';
   function hide ($id=null) {
      if ($id) {
          $this->id = $id;
          $this->saveField('hidden', '1');
      }
   }
   function unhide ($id=null) {
      if ($id) {
          $this->id = $id;
          $this->saveField('hidden', '0');
      }
   }
}
?>

Funciones para recoger datos

  • findAll (condiciones, campos, orden, límite, pagina recursivo), retorna un número (límite) de registros con los campos específicos (fields) empezando por la página indicada (página) y con unas condiciones (por ejemplo: $conditions = “race = 'wookie' AND thermal_detonators > 3”). Puedes enlazar datos de otros modelos asociados asignando un valor mayor que 1 al parámetro recursivo.
  • find(condiciones, campos, orden, recursivo), retorna los campos (si campos tiene valor, si no los retornará todos) del primer registro que coincida con las condiciones.
  • findBy<nombreDeCampo> (valor) y findAllBy<nombreDeCampo> (valor) son funciones que se personalizan por cada modelo, sirven para encontrar valores por un campo concreto:
$this->Post->findByTitle('My First Blog Post');
$this->Author->findByLastName('Rogers');
$this->Specimen->findAllByKingdom('Animalia');
  • findNeighbours (condiciones, campo, valor) retorna los registros vecinos (anterior y posterior (por lo tanto muy útil para la funcionalidad anterior\siguiente)) de un registro concreto especificado por campo-valor. El valor sólo puede ser una fecha o un número. Por ejemplo, el siguiente código nos asinará la variable $neighbours['prev']['Image']['id'] y $neighbours['next']['Image']['id'].
function view($id) {
        $this->set('image', $this->Image->find("id = $id")); // Imágen mostrada
        $this->set('neighbours', $this->Image->findNeighbours(null, 'id', $id));
}
  • field (nombre, condiciones, orden) retorna el valor del campo del primer registro indicado.
  • findCount(condiciones) retorna el número de campos que coinciden con las condiciones.
  • generateList (condiciones, orden, limite, keyPath, valuePath), una función para crear una lista de pares de clave\valor (un atajo para los tag select de html). Por ejemplo , para recoger una lista de roles:
$this->set('Roles', $this->Role->generateList(null, 'role_name ASC', null, '{n}.Role.id', '{n}.Role.role_name'));
/*
Devolvería:
array(
    '1' => 'Account Manager',
    '2' => 'Account Viewer',
    '3' => 'System Manager',
    '4' => 'Site Visitor'
);
*/
  • read (campos, id), lee campos del registro actual cargado o del indicado por el id.
  • query(query) y execute (query) son llamadas a base de datos, la diferencia entre ellas es que query execute no hace un retorno de valores.
function posterFirstName() {
  $ret = $this->query("SELECT first_name FROM posters_table WHERE poster_id = 1");
  $firstName = $ret[0]['first_name'];
  return $firstName;
}

Indicando condiciones

Podemos especificar las condiciones mediante un array que luego pasaríamos a un método find como $this→Post→find($conditions);, ejemplos:

$conditions = array("Post.title" => "This is a post");
              array("Post.title" => "<> This is a post");
              array("Post.title" => array("First post", "Second post", "Third post")); 
                                    array ("or" => array ("Post.title" => array("First post", "Second post", "Third post"), "Post.created" => "> " . date('Y-m-d', strtotime("-2 weeks"))));
              array("Author.name" => "Bob", "or" => array ("Post.title" => "LIKE %magic%", "Post.created" => "> " . date('Y-m-d', strtotime("-2 weeks")));

Guardando datos

Para guardar datos sólo has de pasar al método save del modelo un array del estilo:

Array (
    [ModelName] => Array (
            [fieldname1] => 'value'
            [fieldname2] => 'value'
    )
)

Es muy sencillo utilizar el helper HTML ya que los datos los trae formateados para ser leidos por CakePHP ya que sólo has de añadir algo así: $html→input('Model/fieldname');.
Los datos enviados desde un form se guardan automáticamente en el array $this→data del controlador.
Un ejemplo de una función de editar:

function edit($id) {
   if (empty($this->data)) {
        $this->Property->id = $id;  // El modelo se carga automáticamente en $this->Property
        $this->data = $this->Property->read();
   } else {
      if ($this->Property->save($this->data['Property'])) 
         $this->flash('Your information has been saved.', '/properties/view/'.$this->data['Property']['id'], 2);
      // Si algunos campos no son válidos o el guardado fallase, el formulario se volvería a mostrar
   }
}

La validación se hace de forma automática, pero si no quisieses que al guardar se validase tendrás que hacer la llamada así: save($data, false).
Otras funciones muy útiles:

  • del (id, enCascada), elimina del modelo el id específico.
  • saveField (nombre, valor), para guardar un simple valor en un campo.
  • getLastInsertId (), Devuelve el último ID creado.

Llamadas internas del modelo

Existen funciones que pueden ser sobreescritas y serán llamadas en el momento indicado, según la acción a la que correspondan:

  • beforeFind
  • afterFind
  • beforeValidate
  • beforeSave
  • afterSave
  • beforeDelete
  • afterDelete

Variables del modelo

  • $primaryKey, si la primary key del modelo no fuese el campo id asigna esta variable al nombre del campo.
  • $recursive asigna el número de niveles en el que Cake enlaza el modelo de datos en una llamada a find o findAll. En un ejemplo en el que existen grupos con usuarios y cada uno con artículos los valores posibles serían:
    • -1 no asocia data.
    • 0 Cake enlaza los grupos.
    • 1 Cake enlaza los grupos con los usuarios.
    • 2 Cake enlaza los grupos con los usuarios y los usuarios con sus artículos.
  • $transactional, para activar\desactivar las transacciones (begin, commit, rollback).
  • $useTable, para asingar el nombre de la tabla para el modelo si esta no tiene el nombre que cogería por defecto.
  • $validate, donde se asigna los datos de validación
  • $useDbConfig, por defecto utiliza la configuraciónd default de la base de datos en app/config/database.php, pero puedes utilizar otra indicando en esta variable su nombre.

Asociaciones

Vistas

Las vistas son la parte de una página correspondiente a una acción de un controlador.

  • Una vista puede contener código php, xml, una imágen…
  • A la view se le pasan los datos en un array llamado $data. Puedes pasarle datos desde la función set() desde el controlador.
  • El helper HTML es añadido por defecto.

Los layouts

  • Contienen todo el código que rodea una vista.
  • Se localizan en /app/views/layouts.
  • Creando un /app/views/layouts/default.thtml se sobreescribirá el layout por defecto de CakePHP.


Al crear un layout has de indicar donde se colocará el código del controlador, para ello has de mostrar la variable $content_for_layout (también existe $title_for_layout).

<!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">
</head>
<body>
 
<div id="header">
    <div id="menu">...</div>
</div>
 
<?php echo $content_for_layout ?>
 
<div id="footer">...</div>
 
</body>
</html>

Para indicar qué título se ha de mostrar en $title_for_layout sólo has de asignar un valor a la variable $pageTitle:

class UsersController extends AppController
{
    function viewActive()
    {
        $this->pageTitle = 'View Active Users';
    }
}

Puedes definir un layout para un controlador cambiando su variable $layout, si quieres que una acción tenga un layout distinto tendrás que asignarlo dentro del método de la clase.

class CoverController extends AppController {
	var $layout = "cover";
	function index () {
		$this->layout = "default";
	}
...

Elements

Los elementos son esas pequeñas porciones de código que se muestran repetidas veces en todo el site (banners, menús extra, controles de navegación…). Básicamente son pequeñas vistas que pueden ser incluidas en otras vistas.
Han de ser ubicados en /app/views/elements como ficheros .thtml. y tienen acceso a los datos declarados para ser usados en la vista.
Para mostrar un elemento, en la vista:

<?php echo $this->renderElement('helpbox');?>

Puedes pasar un array de datos como segundo parámetro a este método.

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

Vistas de error

Puedes personalizar los mensajes de error creando los ficheros correspondientes a las vistas que CakePHP tiene definidas para los casos en los que un error aparece, están en /app/views/error estas son:

  • error404.thtml
  • missing_action.thtml
  • missing_component_class.thtml
  • missing_component_file.thtml
  • missing_connection.thtml
  • missing_controller.thtml
  • missing_helper_class.thtml
  • missing_helper_file.thtml
  • missing_layout.thtml
  • missing_model.thtml
  • missing_scaffolddb.thtml
  • missing_table.thtml
  • missing_view.thtml
  • private_action.thtml
  • scaffold_error.thtml

Las plantillas por defecto están en cake/libs/view/template/errors y puedes copiarlas al directorio de tu aplicación y luego editarlas.
Por defecto muchas de las vistas no serán mostradas cuando el DEBUG sea más grande que 0.

Otros elementos

Helpers

Son funciones que se necesitan a menudo en las vistas.

HTML

Las funciones de este helper se utilizan para generar tags html, y es accesible utilizando $html. Además, si AUTO_OUTPUT (variable asignada en /app/config/core.php) está a true el helper automáticamente mostrará la tag sin tener que poner código php con echos. Aunque puedes cambiar esto específicamente para una función dándole el valor deseado en el parámetro $return.
Las funciones que usa este helper están definidas en tags.ini.php, si quieres editarlas sólo tendrás que copiar /cake/config/tags.ini.php en /app/config/.

Funciones (muy explícitas por sí solas como para ponerme yo a explicarlas) para crear tags:

  • charset (charset, return), para crear la meta-tag de charset, si no le pasa nada por parámetro creará una tag de utf-8.
  • css (path, rel, atributos, return)
  • image(path, atributos, return)
  • link (title, url, atributos, msgConfirmación, escapeTitulo, return), el msgConfirmación se usa para indicar si saldrá algún mensaje pidiendo la confirmación del usuario (por ejemplo al borrar un elemento de algúns sitio).
  • tableHeaders (nombres, opciones, opciones)
  • tacleCells (data, opcionesImpares, opcionesPares)
  • guiListTree (data, atributos, bodyKey, childrenKey, return)

Más funciones HTML, pero estas para crear formularios:

  • submit (caption, atributos, return)
  • password (fieldName, atributos, return)
  • textarea (fieldName, atributos, return)
  • checkbox (fieldName, titulo, atributos, return)
  • file (fieldName, atributos, return)
  • hidden(fieldName, atributos, return)
  • input(fieldName, atributos, return)
  • radio (fieldName, options, inbetween, atributos, return), crea un grupo de radiobuttons, los parámetros indican: fieldName el nombre en la DB al que corresponden, options los valores con sus respectivos textos, inbetween el string entre radiobutton y radiobutton, atributos sería el correspondiente a los atributos de los tags.
  • tagErrorMsg(fieldName, msg)
$html->radio('Note/status', array('1' => 'Complete', '2' => 'In Progress'), null, array('value' => '1'));

Cómo utilizar los helpers?

Los helpers generan automáticamente los tags, se rellenan si ocurre un error y muestran los menajes de error. Imaginemos que estamos montando una aplicación para tomar notas, en el NotesController tendremos una acción de edición:

   function edit($id)
   {
      //Lo primero es mirar si los datos se han enviado correctamente
      if (!empty($this->data['Note'])) {
         // Aquí intentaríamos validar el formulario
         if ($this->Note->save($this->data['Note'])) {
            // Si se ha guardado correctamente llevaríamos al usuario a un lugar concreto
            $this->flash('Your information has been saved.', '/notes/edit/' . $id);
            exit();
         } else {
            // Si no generaríamos un error
            // llamaríamos a $this->Note->validates($this->data['Note']); si no estamos guardando
            // mostraríamos los errores
            $this->validateErrors($this->Note);
            // Y llamaríamos ya al método para mostrar la página
            $this->render();
         }
      }
      // Si no hemos recibido datos es que los queremos editar, por lo tanto mostrar la info
      $this->set('note', $this->Note->find("id = $id"));
      $this->render();
   }

En el modelo Note tendríamos un id de nota, un id del editor y el cuerpo de la nota. La vista mostraría los datos de la nota y permitiría al usuario introducir nuevos y estaría en app/views/notes/edit.thtml:

<?php echo $html->formTag('/notes/edit/' . $html->tagValue('Note/id')) ?>
 
<table cellpadding="10" cellspacing="0">
<tr>
   <td align="right">Body: </td>
   <td>
      <!-- Mostramos la nota y los errores encontrados  -->
      <?php echo $html->textarea('Note/body', array('cols'=>'60', 'rows'=>'10')); ?>
      <?php echo $html->tagErrorMsg('Note/body', 'Please enter in a body for this note.') ?>
   </td>
</tr>
<tr>
   <td></td>
   <td>
      <!-- Datos ocultos en el form  -->
      <?php echo $html->hidden('Note/id')?>
      <?php echo $html->hidden('note/submitter_id', $this->controller->Session->read('User.id'))?>
   </td>
</tr>
</table>
<?php echo $html->submit()?>
</form>

Algunas funciones necesitan que se les indique un $fieldName (por ejemplo tagErrorMsg), esto permite a CakePHP saber qué data le estás pasando y validarla correctamente, para ello se pasa en un string con valor “nombreModelo/nombreCampo”, por ejemplo, para añadir un título a la nota:

<?php echo $html->input('Note/title') ?>
<?php echo $html->tagErrorMsg('Note/title', 'Please supply a title for this note.')?>

Los mensajes de error se muestran en una div del estilo: <div class=“error_message”></div>

Ajax

El helper de Ajax de CakePHP utiliza los scripts de script.aculo.us, por lo que para poder utilizarlos deberías tener las librerías en /app/webroot/js e incluirlas en la vista. También hay que tener en cuenta que la mayoría de estas funciones reciben un parámetro de opciones, este es un array de claves (url, update, confirm…) con valores, de esta forma se le asignan las propiedades.

  • link(title, href, options, confirm, escapeTitle)
  • remoteFunction(opcions),
  • remoteTimer(options), periodicamente hace una llamada a url, cada frecuencia (segundos).
  • form(action, type, options) retorna un tag del form a la action.
  • observeField(field_id, options), cada frequency hace una llamada a url.
  • observeForm(form_id, options)
  • autoComplete(field, url, options)
  • drag(id, options)
  • drop(id, options)
  • dropRemote(id, options, ajaxOptions)
  • sortable(id, options)
  • editor(id, url, options)

JavaScript

  • codeBlock (string), retorna un script del string pasado.
  • link(url), retorna una tag url que apunta a la url pasada.
  • linkOut(url), como link pero para un dominio distinto.
  • event(object, event, observer, useCapture), enlaza un evento a un elemento (usando la librería Prototype).
  • cacheEvents()
  • writeEvents
  • includeScript

Numeros

  • precision (numero, precision), número formateado a un nivel de precisión.
  • toReadableSize(bytes), se le pasa un número de bytes y los devuelve en kb, mb, gb, o tb.
  • toPercentage(numero, precision), retorna un número formateado como porcentage.

Texto

  • highlight(texto, highlighter)
  • stripLinks(texto), de un link te retorna el texto interno.

Fecha hora

  • fromString(dateString)
  • nice(dateString, return), retorna la fecha formateada larga.
  • niceShort(dateString, return), formate al fecha en formato corto.
  • isToday(date), retorna true si la fecha indicada corresponde a la de hoy.
  • daysAsSql(begin, end, fieldName, return), retorna un sql string a buscar entre dos fechas.
  • dayAsSql(date, field, return), retorna un sql string para buscar los registros de una misma fecha.
  • isThisYear
  • wasYesterday
  • isTomorrow
  • toUnix
  • toAtom
  • toRSS
  • timeAgoInWords(date, return), retorna cuanto tiempo ha pasado.
  • relativeTime (string, return), como timeAgoInWords pero para presente, pasado y futuro.
  • wasWithinLast(intervalo, date, return) retorna true si el datetime especifico está en el intervalo (2 days, 6 hours…).

Scaffolding

El Scaffolding es la capacidad que tiene CakePHP de agilizar el pantallas de inserción, consulta y adición a la base de datos generando el código.
Se analiza la base de datos y se auto-genera el código.
Sólo has de añadir $scaffold; la variable al controlador:

<?php
class CategoriesController extends AppController
{
    var $scaffold;
}
?>

Validación

  • En la clase modelo añadiremos un array llamado $validate que controlará que los campos de entrada tengan un formato correcto.
  • Para ello puedes utilizar expresiones regulares o constantes (VALID_NOT_EMPTY, VALID_NUMBER, VALID_EMAIL, VALID_YEAR).
  • Sólo has de crear un array llamado validate en el modelo deseado con cada campo que quieres validar y su formato:
   var $validate = array(
      'login' => '/[a-z0-9\_\-]{3,}$/i',
      'password' => VALID_NOT_EMPTY,
      'email' => VALID_EMAIL,
      'born' => VALID_NUMBER
   );
  • La validación se hace en el método: Model::save()
  • Para validar los datos directamente utiliza: Model::validates() e Model::invalidFields() que devuelve un array de campos inválidos.

Sanitization

Sanitize es la clase dentro de cake que te permite filtrar las entradas a la base de datos, impidiendo que se lancen algunos carácteres que no quieres.

uses('sanitize');
$mrClean = new Sanitize();

Métodos según lo que se quiera 'limpiar':

  • paranoid
  • html
  • sql
  • cleanArray

Sesiones

CakePHP puede salvar las sesiones de tres formas distintas, para indicar cual es la deseada hay que editar /app/config/core.php y cambiar el valor de CAKE_SESSION_SAVE por 'php' (que las maneja php), 'database' (las maneja la base de datos) o 'cake' (las maneja el mismo CakePHP).
Para utilizarlas puede hacer uso de las siguientes funciones:

  • check (nombre), comprueba si el nombre ha sido asignado como variable durante la sesión.
  • del (nombre), elimina la variable de sesión.
  • read(nombre), devuelve el valor de la variable indicada.
  • renew (), renueva la sesión asignándole un nuevo id de sesión.
  • valid(), devuelve si la sesión es valida o no. Útil antes de leer una variable.
  • write (nombre, valor) asigna un valor a una variable.

Cuando accedes a la session desde la view necesitarás usar el helper de Sesiones:

<p>Nombre: <?php $session->read('user.username'); ?> </p>

Cuando accedes a la sesión desde un controlador tienes el objeto Session dentro de este:

if (!$this->Session->check('user')) {
	$this->redirect('/cover/index');
        exit();
}

Cuando almacenas un array de claves valor, tendrás que acceder a los datos mediante un string:

$theUser = $this->User->findByUsername ($this->data['User']['username']);
$this->Session->write('user', $theUser['User']);
$this->set('name', $this->Session->read ('user.username'));

Components

Un componente se crea en el directorio app/controllers/components/

class FooComponent extends Object
{
    var $someVar = null;
    var $controller = true;
    function startup(&$controller)
    {}
    function doFoo()
    {
        $this->someVar = 'foo';
    }
}

La función startup se llama al iniciar, si no quieres que sea usada o llamada pon la variable de clase $disableStartup a true.
En el controlador se agregará el componente:

var $components = array('Foo');

Y lo usuará:

$this->Foo->doFoo();

Componente Request Handler

Este componente viene con CakePHP y controla las peticiones AJAX, para usuarlo ha de ser declarado como un valor dentro de la variable del controlador $components, una vez esté declarado puede ser accedido mediante la variable RequestHandler:

class PostsController extends AppController {
    var $components = array('RequestHandler');
    function beforeFilter () {
        if ($this->RequestHandler->accepts('html'))
        ....

Sus funciones son:

  • accepts(tipo), se le pasa un string que indica un tipo da datos, si el cliente lo acepta esta función retornará true.
  • getAjaxVersion()
  • getClientIP ()
  • getReferrer(), retorna el nombre del servidor desde donde se ha hecho la petición.
  • isAjax (), retorna true si la petición actual es una XMLHttpRequest.
  • isAtom (), true si el cliente acepta contenido de feeds Atom.
  • isDelete(), isGet(), isPost() o isPut(), retornan true si la petición se hico via DELETE, GET, POST o PUT.
  • isMobile (), retorna true si el cliente es un navegador de movil.
  • isXml(), retorna true si el cliente acepta contenido XML.
  • setContent(nombre, tipo), indica un tipo de contenido.

Puede que alguna vez queramos eliminar datos de la salida, para ello tenemos las siguientes funciones que eliminan tags:

  • striptImages(str)
  • stripScripts (str)
  • stripWhiteSpace (str)
  • stripAll (str)
  • stripTags (str, tag1, tag2…), elimina los tags indicados.

setAjax es otra función muy util porque se usa para detectar automáticamente peticiones de ajax y asignar el layout del controlador como una vista AJAX:
El fichero list.thtml:

<ul>
<? foreach ($things as $thing):?>
<li><?php echo $thing;?></li>
<?endforeach;?>
</ul>

En el controlador:

function list() {
    $this->RequestHandler->setAjax($this);
    $this->set('things', $this->Thing->findAll());
}

Plugins

  • Combinación de modelos, vistas y controladores utilizados para simplificar tareas posteriores.
  • Si no se enlazan con la aplicación actuarán independientemente.
  • Se añaden a app/plugins en una carpeta, el nombre de esa carpeta será el nombre del plugin.
  • Es obligatorio definir un controlador y un modelo para el plugin, estos estarán en el mismo directorio:

Estructura:

/app
    /plugins
        /pizza
            /controllers
            /models
            /views
            /pizza_app_controller.php  
            /pizza_app_model.php       

En /app/plugins/pizza/pizza_app_controller.php:

<?php
class PizzaAppController extends AppController
{}
?>

Y en /app/plugins/pizza/pizza_app_model.php

<?php
class PizzaAppModel extends AppModel
{}
?>
  • Los nombres dados a los controladores del plugin deberían de ser únicos en la aplicación (hemos de preveer que la aplicación tendrá un UsersController).
  • Los controladores heredan del controlador del plugin no directamente del AppController. Lo mismo pasa con los modelos.
class PizzaOrdersController extends PizzaAppController
{
    var $name = 'PizzaOrders';
    function index()  {}
    function placeOrder()  {}
}
  • Los controladores utilizan los layouts por defecto de la aplicación.
  • Puedes hacer llamadas internas en el plugin haciendo algo parecido a: $this→requestAction('/plugin/controller/action');
  • Puedes acceder al plugin mediante: /pluginname/controllername/action

Montar una página

Portada

Podemos crear la portada a nuestro site creando el archivo /app/views/pages/home.thtml ya que es tal como está configurado por defecto en el routes.php. Pero también podemos crear la nuestra propia creando por ejemplo un /app/views/pages/cover.thtml y cambiando la configuración de la ruta en routes.php por $Route→connect ('/', array('controller'⇒'pages', 'action'⇒'display', 'cover'));.

Apariencia por defecto

Por defecto, toda página que crees aparecerá dentro de una página en la que se lee “CakePHP Rapid Development”, ese es el layout por defecto que está en cake/libs/view/templates/layouts/default.thtml, no es necesario que lo borres, simplemente con que crees el app/views/layouts/default.thtml ya lo tendrás.

Añadir CSS

Los archivos de estilo .css que quieras añadir a tu aplicación deberás hacerlo en la carpeta app/webroot/css, luego, para añadirlos a tu layout, en el head, haz (si por ejemplo se llama generic.css el archivo de estilos):

<?php echo $html->css('generic'); ?>

Añadir contenido

Para añadir contenido a un layout tienes varias variables en el helper de html que te serán de ayuda:

  • $content_for_layout, si haces un echo de esta variable te escribirá la view del controlador actual.
  • $title_for_layout), lo mismo pero para el title.

Para añadir links o direciones dentro del site utiliza $html→url para que te construya el path:

<form action="<?php echo $html->url('/users/login'); ?>" method="post">

Un vistazo al acceso a DB

Lectura

Imaginemos que tienes una DB de usuarios, cada uno con un perfil, es decir, dos tablas users y profiles en la que profiles se enlaza a users mediante un campo users_id dentro de esta. Cuando quieres mostrar un perfil para un usuario concreto, en el controlador puedes hacer un método del estilo:

function showprofile ($id) {
	$this->set('profile', $this->Profile->findByUsers_id($id));
}

Este busca en los perfiles por el campo users_id y lo asigna para la vista en una variable llamada profile, ahora para acceder a ella desde la vista:

<td>Nombre:</td> <td><?php echo $profile['Profile']['realname']; ?></td>

Campos de la DB en el formulario

Cuando vayas a editar algún perfil probablemente prefieras mostrar un formulario con los campos actuales ya colocados en los cuadros de texto y preparados para ser editados, para que CakePHP lo haga automáticamente deberás asignar a la variable del controlador $data el perfil:

$this->data = $this->Profile->findByUsers_id($this->Session->read('user.id'));

Luego podrás acceder a esta mediante el helper de html:

<tr>
  <td id="fieldname">Nombre Real:</td>
  <td><?php echo $html->input('Profile/realname', array('size' => 20)); ?></td>
</tr>

Esto nos sirve básicamente para indicar que un campo del formulario corresponde a un campo de la base de datos.
También puedes asignar estos campos manualmente en el controlador si editas la variable $data antes de llamar a la vista.

$this->data = $this->Profile->findByUsers_id($this->Session->read('user.id'));
$this->data['Profile']['users_id'] = $this->Session->read('user.id');

Guardar y editar

Tanto para guardar como para editar existe la función save, a esta le pasas los datos del modelo que, si el controlador ha sido llamado desde un formulario, los datos estarán en la variable $data.
La única diferencia a la hora de guardar y actualizar es que para actualizar es obligatorio indicar el id (que el modelo ha de tener).

$this->Profile->id = $this->data['Profile']['id'];
$this->Profile->save($this->data['Profile']);

Puedes guardar y editar los registros manualmente:

$actualizar = array();
$actualizar['User'] = array();
$actualizar['User']['login'] = 'danguer1';
$actualizar['User']['password'] = 'hola';
$this->id = $id_guardado;
$this->save($actualizar);

Acciones sobre la BD

Contar registros

Por ejemplo desde el controlador:

if ($this->Profile->findCount ("users_id = $id") == 0) // Perfil no definido
{ ... }

O desde el modelo con una función que después podrá ser llamada desde el controlador como: $this→User→existsUsername('juan24');:

   function existsUsername ($username) {
   	return ($this->findCount ("User.username = '$username'") > 0);
   }

Otros ejemplos:

$this->findCount("User.login='danguer' AND Article.title LIKE '%php%'");
Otras consultas
function hasProfile ($id) {
   $ret = $this->query("select COUNT(id) as count from profiles where users_id = " . $id);
   $num = $ret[0][0]['count'];
   return ($num > 0);
}

Otras cosillas a tener en cuenta

  • Recuerda como añadir de forma sencilla la tag de utf-8: $html→charset();.
  • Puedes hacer una llamada a una página interna haciendo controlador/accion/parametro1/parametro2. Si la accion de ese controlador tiene sus parámetros definidos del estilo function accion ($parametro1=false, $parametro2=false) {, se podrá llamar a esa funcion sin pasarle parametros y por defecto estos serán false los dos.

Ejemplos

Creación de validación de usuario (login)

  1. Crear la tabla users, esta tendrá campos como username, password
  2. Crear el modelo User.
  3. Crear la view app/views/users/login.thtml, a esta se le añadirán los cuadros de texto para la introducción de nombre y password.
  4. Crear el controlador de usuarios /app/controllers/users_controller.php.
    1. Añadir al controlador de usuarios un método login, ver más abajo. En este se recoge al usuario y si el login es correcto se escriben sus datos en la sesión.
    2. Añadir al controlador de usuarios un método de logout, ver más abajo. En este únicamente se elimina al usuario de la sesión.
  5. Crear un /app/app_controller.php, el controlador general de la aplicación donde añadiremos la función que chequeará si el usuario está logueado (checkSession). Para ello mira en la sesión y si no existe llama a exit(), nota que es una llamada a exit, lo que cancela cualquier ejecución y redirige al usuario al home del site.
  6. Ahora puedes añadir a cualquier otro controlador (de mensajes, de posts…) un método llamado beforeFilter, este se llamará automáticamente antes de cada llamada a cualquier método del controlador, si añades ahí una llamada al checkSession será obligatorio hacer un login para editar los posts, mensajes… O puedes únicamente colocar el checkSession al inicio de los métodos que desees.

Método login del controlador de usuarios:

function login() {
	if (!empty($this->data)) {
		$theUser = $this->User->findByUsername ($this->data['User']['username']);
		$bEmptyPassword = empty($this->data['User']['password']);
		$bSamePassword = ($theUser['User']['password'] == $this->data['User']['password']);
		if ((!$bEmptyPassword) && ($bSamePassword)) {
			$this->Session->write('user', $theUser['User']);
			$this->redirect("/users/mainpage");
			return;
		}
	}
	$this->set("error", true);
	$this->redirect ("/cover/index/1");
}

Método de logout del usuario:

function logout () {
	$this->Session->del('user');
	$this->redirect("/cover/index");
}

Controlador general de la aplicación:

class AppController extends Controller {
    function checkSession() {
        if (!$this->Session->check('user')) {
            $this->redirect('/');
            exit();
        }
    }
}

Método beforeFilter:

function beforeFilter() {
    $this->checkSession();
}

Tips & Tricks

Páginas estáticas

Para crear páginas estáticas has de crearlas en /app/views/pages como archivo .thtml. Para acceder a ellas sería: <ruta>/pages/<nombre>, por ejemplo si se crea una página llamada /views/pages/about.thtml será accesible mediante http://www.example.com/pages/about.

Variables globales

Podemos usar un objeto Configure para guardar lo que queramos y será accesible desde cualquier lugar de CakePHP.

$config =& Configure::getInstance();
$config->myVar = 'test';

Controlador sin modelo

Puedes crear un controlador sin modelo de base de datos asignando un array vacío a la variable $uses:

  <?php
    class HellosController extends AppController {
        var $name = 'Hellos';
        var $uses = array();
 
        function index() {
        }
    }    
  ?>

Notas

Convenciones de la Base de Datos

  • Nombres de tablas en inglés y en plural.
  • Las tablas deben tener una clave primaria llamada id.
  • Para crear claves foráneas utiliza nombres del estilo nombretabla_id.
  • Campos como created o modified del tipo datetime se rellenarán automáticamente.

Ficheros

fw/others/cake.txt · Última modificación: 2020/05/09 09:25 (editor externo)