29
CakePHP 2.1+ Fundamentos Daniel Glez-Peña

Cakephp 2.1 Fundamentos

Embed Size (px)

Citation preview

CakePHP 2.1+Fundamentos

Daniel Glez-Peña

Daniel Glez-Peña

● CakePHP es un framework que se basa en el patrón Modelo-Vista-Controlador para la Web, también conocido como framework basado en acciones.

● La funcionalidad de la aplicación se divide en:● Modelos. Recuperan, guardan y validan datos en la base de datos.● Controladores. Implementan la lógica de negocio.● Vistas. Generan el HTML final de respuesta.● Todos se implementan en lenguaje PHP.

● A mayores, cakePHP define:● Componentes. Implementan funcionalidad para apoyar a los controladores.● Helpers o ayudantes para las vistas.● Elementos para creación de plantillas, es decir, partes comunes a todas las

vistas (Layouts, View Blocks y Elements).

Daniel Glez-Peña

● Cómo se despacha una petición

Daniel Glez-Peña

● Un Modelo es una clase PHP.● Se encarga de recuperar y guardar datos.● Ubicados en app/Model.

● Se suele crear un modelo por cada entidad de la BD.● Los modelos de cakePHP se basan en el patrón ActiveRecord, por lo que

realizan dos misiones.– Permiten recuperar, insertar, eliminar registros.– Representan un único registro de una tabla registro activo en cada momento, con

acceso para leer/escribir la columna del objeto "activo”.

● Importante: La clase y el fichero deben nombrarse como la entidad en la BD. (Principio Convention over Configuration)

<?php//fichero app/Model/Ingredient.phpclass Ingredient extends AppModel {    public $name = 'Ingredient';}

Daniel Glez-Peña

● Algunos métodos y atributos de los Modelos.● Atributo id. Clave primaria del registro activo actual.

– Es obligatorio definir en todas las tablas un id auto incremental.– Se establece automáticamente después de crear un registro (método create).

● Métodos – find(...). Devuelve registros de la base de datos en forma de array. No

modifican el registro activo.– create(...). Crean un nuevo registro en la base de datos. El atributo id pasa a

ser el del registro creado.– read(...). Lee un registro de la base de datos que ahora será el registro activo.

– set(...). Establece un valor de un campo en el registro activo (no lo guarda en la BD), para ello se usa save(...).

– save(...). Guarda datos en un registro que pueden ser 1) pasádos como parámetros mediante array o 2) los valores presentes en el registro activo.

– updateAll(...). Establece varios valores en los registros que cumplan una condición.

Daniel Glez-Peña

● Ejemplos básicos.● Crear/Actualizar (métodos create(), save() y updateAll())

● Eliminar

// Crear (create + save): id no establecido o es null$this­>Recipe­>create();$this­>Recipe­>save(array("name"=>"spaguetti carbonara"));

// Actualizar un registro (establecer id + save)$this­>Recipe­>id = 2;$this­>Recipe­>save(array("name"=>"spaguetti carbonara"));

// Actualizar varios registros: updateAll(campos, condiciones)$this­>Recipe­>updateAll(array("approved” => true), array("name LIKE" => "%spaguetti%"));

//Eliminar un registro$this­>Recipe­>delete($id);

//Eliminar varios registros$this­>Recipe­>deleteAll(array("name" => "spaguetti carbonara"));

Daniel Glez-Peña

● Ejemplos básicos (II)● Recuperar

– El método find(modo, parametros) permite recuperar datos de la BD.

– Los modos más básicos (existen más y se pueden definir propios) son:● null. Recupera el único registro cuyo id sea el del registro activo● "all”. Recuperar todas las filas que cumplan las condiciones. Devuelve un array

asociativo, agrupando primero por número de fila, luego por tabla (a veces una consulta tiene varias tablas) y luego por campo.

● "count”. Devuelve la cuenta de filas que cumplen las condiciones.

//Select * from recipe where recipe.id = $this­>Recipe­>id$this­>Recipe­>find()

//Select * from recipe$this­>Recipe­>find('all'); 

//Select * from recipes where name LIKE "spaguetti%”$this­>Recipe­>find('all', 

array("conditions” => array("name LIKE” => "spagetti%”)) 

Daniel Glez-Peña

● Relaciones.● Las relaciones entre las entidades deben establecerse en las

clases Modelo.● En función del tipo de relación (1:1, 1:N, N:1, N:M), se debe usar

un atributo distinto.– Ese atributo es, como mínimo, el nombre del otro modelo relacionado.

Se pueden indicar varias relaciones del mismo tipo, empleando un array.● La siguiente tabla muestra qué atributo se debe usar:

Daniel Glez-Peña

● Relaciones (II).● Ejemplo

<?phpclass User extends AppModel {    public $name = 'User';    public $hasMany = 'Comment';}

//Resultado de $this­>User­>find()Array(    [User] => Array        (            [id] => 121            [name] => Gwoo the Kungwoo            [created] => 2007­05­01 10:31:01        )    [Comment] => Array        (            [0] => Array                (                    [id] => 123                    [user_id] => 121                    [title] => On Gwoo the Kungwoo                    [body] => The Kungwooness is not so Gwooish                    [created] => 2006­05­01 10:31:01                )            [1] => Array                (                    [id] => 124                    [user_id] => 121                    [title] => More on Gwoo                    [body] => But what of the ‘Nut?                    [created] => 2006­05­01 10:41:01                )        ))

Si no se define, se asume que las claves foráneas se nombran así:<tablaRelacionada>_id

Daniel Glez-Peña

● Relaciones (III).

● Al recuperar, se recuperan por defecto todos los registros relacionados.

– Para evitarlo, se debe especificar "recursive" => 0.

● Al tener un modelo relacionado con otro, desde uno se puede acceder al otro.

● El método delete(), recibe el parámetro cascade para decidir si se deben eliminar los registros relacionados.$this­>Recipe­>delete($id, true);

$this­>Recipe­>Ingredient­>find('all')$this­>Recipe­>Ingredient­>find('all')

$this­>Recipe­>find('all', array("recursive"=>0))

Daniel Glez-Peña

● Validación.● La lógica de validación de datos también se incluye en los Modelos.● CakePHP proporciona muchas reglas de validación por defecto.● Las reglas de validación se establecen en el atributo validate en el

Modelo.

● También se pueden crear reglas de validación propias que devolverán un booleano si el campo es correcto o no.

public User extends AppModel{  public $validate = array(    'login' => array(        'loginRule­1' => array(            'rule'    => 'alphaNumeric',            'message' => 'Only alphabets and numbers allowed',         ),        'loginRule­2' => array(            'rule'    => array('minLength', 8),            'message' => 'Minimum length of 8 characters'        )    )  );}

Daniel Glez-Peña

● Un Controlador es una clase PHP.● Se encarga de atender una petición y ejecutar la lógica de negocio correspondiente.● Ubicados en app/Controller.

● Se compone de un conjunto de acciones (cada acción es un método). La acción por defecto es index().

# /app/Controller/RecipesController.phpclass RecipesController extends AppController {    public function view($id) {        //action logic goes here..    }

    public function share($customerId, $recipeId) {        //action logic goes here..    }

    public function search($query) {        //action logic goes here..    }}

Daniel Glez-Peña

● Las peticiones HTTP llegan a los controladores en función de la URL.Ejemplo: la URL: http://host/products/search/pizzase convierte en la llamada:ProductsController::search("pizza")

● La petición HTTP está en el atributo $this­>request● Los datos pasados por formulario POST están en $this­>request­>data

● Los parámetros pasados por GET están en $this­>request­>query

● Otros, como la cabecera Referer, están directamente en $this­>referer()

● Ciclo de vida. Existen hooks que se pueden sobreescribir para actuar de forma genérica antes o después de cualquier acción.● beforeFilter(). Se ejecuta antes de cada acción. Buen lugar para comprobar

permisos, elementos de sesión, etc.● beforeRender(). Después de la acción y antes de pasar a renderizar la vista.● afterFilter(). Después de la acción y de que se haya renderizado la vista.

Daniel Glez-Peña

● Controladores y Modelos.● Los controladores tienen acceso a un Modelo en función de su

nombre.– Ejemplo: el controlador RecipesController, tiene acceso a Recipe, a

través de $this­>Recipe

● Controladores y Vistas.● Los controladores típicamente pasan resultados a la vista

estableciendo variables con el método set.– En la vista, existirán variables con el nombre y valor indicados

● También es habitual que un controlador quiera responder redirigiendo al cliente (HTTP 30x).– Por ejemplo, tras un POST, para implementar POST-REDIRECT-GET.

$this­>set('recipes', $this­>Recipe­>find('all'))

$this­>redirect(array('action' => 'index'));

Daniel Glez-Peña

● Existen dos controladores por defecto.● PagesController (pages).

– Controlador para contenido estático (sin apenas lógica de negocio)

– Toda petición /pages/algo, simplemente renderizará la plantilla /View/Pages/algo.php

● AppController– Clase base para los controladores. Buen lugar para

poner comportamiento genérico a todos los controladores.

Daniel Glez-Peña

● Los controladores pueden emplear componentes, que añaden funcionalidad a los controladores. ● Se definen en el atributo components mediante un array que

asocia el nombre del componente a usar y opciones particulares del mismo.

● Los componentes están disponibles en $this­>Componente

class PostsController extends AppController {    public $components = array(        'Session',        'Auth' => array(            'authorize' => array('controller'),            'loginAction' => array('controller' => 'users', 'action'                                                              => 'login')        ),        'Cookie' => array('name' => 'CookieMonster')    );

$this­>Session­>setFlash("Recipe added successfully”)

Daniel Glez-Peña

● Algunos componentes.● Sessions.

– Manejo de sesiones. Tiene métodos a mayores que el manejo propio de PHP.● Por ejemplo, setFlash(), que permite meter mensajes temporales en sesión (ej: "producto

p dado de alta correctamente”). Útil para implementar POST-REDIRECT-GET. En el POST se ejecuta setFlash, y en el GET la plantilla renderizará el mensaje flash una sóla vez, mediante el SessionHelper::flash.

● Access control lists.– Implementa el modelo ACL, es decir, permite autorizar/denegar la realización de

ciertas acciones sobre ciertos elementos a ciertos usuarios. Los permisos se pueden guardar en base de datos (DbAcl) o en ficheros INI (IniAcl).

● Authentication (Auth).● Otros: Security, Access control lists, Cookies, Emails, etc.

Daniel Glez-Peña

● Las vistas son ficheros PHP (con extensión .ctp). Típicamente HTML con PHP incrustado.

● Ubicadas en /app/View/<Controlador>/<accion.ctp>

● En la vista están definidas las variables establecidas previamente en el controlador mediante set(nombre_variable, valor).

● En la vista se pueden emplear Ayudantes o Helpers, que deben ser declarados en el controlador con el atributo helpers

● Por defecto, la vista se corresponde con la acción del controlador ejecutada. Sin embargo, el controlador puede emplear otra vista si lo desea, simplemente invocando $this­>render()

<?phpclass PostsController extends AppController {    public $helpers = array('Html', 'Form');

<?php// Render the element in /View/Elements/ajaxreturn.ctp$this­>render('/Elements/ajaxreturn');

Daniel Glez-Peña

● Ejemplo de vista<!­­ File: /app/View/Posts/index.ctp ­­><h1>Blog posts</h1><table>    <tr>        <th>Id</th>        <th>Title</th>        <th>Created</th>    </tr>

    <!­­ Recorremos $posts, que ha sido establecido mediante set en el controlador ­­>

    <?php foreach ($posts as $post): ?>    <tr>        <td><?php echo $post['Post']['id']; ?></td>        <td>            <?php echo $this­>Html­>link($post['Post']['title'],array('controller' => 'posts', 'action' => 'view', $post['Post']['id'])); ?>        </td>        <td><?php echo $post['Post']['created']; ?></td>    </tr>    <?php endforeach; ?>    <?php unset($post); ?></table>

Daniel Glez-Peña

● CakePHP define un mecanismo para organizar las partes comunes en las vistas. Se basa en View Blocks (desde cakePHP 2.1), Layouts, Views y Elements.

● View Blocks. Definen "slots" que se insertan en un sitio (generalmente el Layout), pero se rellena desde otras partes (típicamente las Views).

● El block por defecto es "content", que es donde se inserta el contenido renderizado por View que no sea de otro block.

● Otros blocks predefinidos son "meta”, "css”, "script”, que permite que las vistas definan meta-tags, hojas de estilos y scripts. Para rellenar esos bloques se puede utilizar HtmlHelper, que tiene una función para añadir contenido a cada uno.

● La plantilla por defecto está /App/View/Layouts/default.ctp

● Los view block se insertan con $this­>fetch("nombrebloque”) y su contenido se en cualquier vista, con los métodos start/append/end.

<?php// In the view: create the sidebar block.$this­>start('sidebar');echo "this is the sidebar content”;$this­>end();echo "this is for the content”;// Append into the sidebar later on.$this­>append('sidebar');echo "more content to the sidebar”;$this­>end();

<?php// in the layout<html><body><div id=”sidebar”><? echo $this­>fetch('sidebar'); ?></div><div id=”content”><? echo $this­>fetch('content'); ?></div></body>

Daniel Glez-Peña

● Views. Las que renderizan el contenido propio de la acción ejecutada. Su contenido se carga en el block "content”.

● Layout. Plantilla principal y común a las vistas. La mayoría de los view blocks son invocados en ella.

<html><head><title><?php echo $title_for_layout?></title><?phpecho $this­>fetch('meta');echo $this­>fetch('css');echo $this­>fetch('script');?></head><body>

<!­­ If you'd like some sort of menu toshow up on all of your views, include it here ­­><div id="header"> ... </div>

<!­­ Here's where I want my views to be displayed ­­><?php echo $this­>fetch('content'); ?>

<!­­ Add a footer to each displayed page ­­><div id="footer">...</div></body></html>

Lo que renderice la view concreta va aquí (slot content)

Daniel Glez-Peña

● Elements. Definen fragmentos de vista reutilizables y parametrizables, que son llamados con $this­>element desde cualquier vista o layout.● Suele ser habitual que los element requieran de lógica de negocio (ej: un element que

carga los productos más comprados y que forman parte de la plantilla global).● Para ello se recomienda invocar a una acción de un controlador (ej:

/Products/bestsellers), para respetar el MVC.● Para llamar a una acción directamente desde un element, se debe usar $this­>requestAction() en el element.

● En el Controlador se debe distinguir si la petición es nomal o viene pedida desde un requestAction, ya que en el primer caso debe usar set para enviar el resultado a la plantilla y en el segundo debe devolver el resultado como valor de retorno.

Daniel Glez-Peña

● Ejemplo de Element insertado en un Layout y que usa un Controlador.

<!­­ Element /app/View/Elements/best.ctp ­­><h2>Best sellers</h2><?php $bests = $this­>requestAction('products/best'); ?><?php foreach ($bests as $best): ?><ol>    <li><?php echo $best['Product']['name']; ?></li></ol><?php endforeach; ?>

//Controller<?phpclass ProductsController extends AppController {    // ...    public function best() {        $best = // find best products in the BD;        if ($this­>request­>is('requested')) {            return $best;        } else {            $this­>set('bests', $best);        }    }}

<!­­ In the Layout ­­>...<div id=”best”><?php echo $this­>element('best'); ?></div>...

Daniel Glez-Peña

● Consisten básicamente en clases que ayudan en tareas típicas de la vista.

● Deben ser declarados en el controlador con el atributo helpers.

● Los más habituales son Html, Form y Session.● HtmlHelper. Generar Html más fácil, como la cabecera DOCTYPE,

tablas, URLs basados en la semántica controlador+acción,etc.● FormHelper. Generación del Html de formularios, validación y rellenado

automático.● SessionHelper. Visualización de variables de sesión (previamente

establecidas con el SessionComponent).

<?phpclass BakeriesController extends AppController {    public $helpers = array('Form', 'Html', 'Session');}

Daniel Glez-Peña

● Se emplea para crear formularios desde la vista PHP.

● Llevan a cabo tareas típicas de formularios sobre entidades de una BD.– Seleccionan el componente visual más adecuado en función del tipo de dato de la base de datos.

– Ayudan en la validación básica. Muestran los errores de validación establecidos en los modelos.

– Establecen valores por defecto (útil para formularios de edición de un registro de la BD).

● Es altamente configurable, aunque si no se dan opciones, siempre hay un comportamiento por defecto.

● Los valores por defecto de los campos se pueden establecer previamente desde el controlador en $this->request->data

<?phpecho $this­>Form­>create(); //Modelo por defecto, el del controlador actual

echo $this­>Form­>input('username');   //textecho $this­>Form­>input('password');   //passwordecho $this­>Form­>input('approved');   //day, month, year, hour, minute, meridianecho $this­>Form­>input('quote');      //textarea

echo $this­>Form­>end('Add'); //incluye un botón de submit

Daniel Glez-Peña

● Se puede emplear AJAX en CakePHP del siguiente modo.

● Las acciones pasan a generar una vista JSON/XML.● Las vistas hacen peticiones AJAX desde scripts JavaScript.

– O también se puede emplear JsHelper que ayuda a generar JavaScript basado en Jquery (u otras librerías) desde PHP.

● Para habilitar JSON y que todas las peticiones terminadas en .json pasan a generar la vista en ese formato:

– Ejemplo: /recipes/index.json

– Incluir Routes::parseExtensions("json”) en routes.php

– Incluir el componente RequestHandler en el controlador

– Establecer la variable de vista _serialize a aquella/s variable/s de vista que se desean sacar en json si se solicita este formato.

Daniel Glez-Peña

● Ejemplo:class BooksController extends AppController{  public $components = array('RequestHandler');  public $helpers = array('Js', 'Html');    function index(){

$this­>set("books", array("quijote", "divina comedia"));$this­>set("_serialize", array("books"));

  } }

<?echo $this­>Html­>script('jquery'); //ATENCION DESCARGAR jquery y ponerlo en /app/webroot/js/jquery.js?><input type="button" id="boton" value="test!"></input><?$this­>Js­>get("#boton");$this­>Js­>event(    'click',    $this­>Js­>request(        array('action' => 'index', 'controller'=>'links','ext'=>'json'),        array('async' => true,'success'=>”alert(data['books')”)    ));echo $this­>Js­>writeBuffer(); // Write cached scripts?>

Router::parseExtensions("json");

/app/Config/routes.php

/app/Controller/BooksController.php

/app/View/Books/index.ctp

Daniel Glez-Peña

● Todas las URLs entrantes son dirigidas a un controlador y una acción.

● Se configura en app/Config/routes.php

● Por defecto las URLs son:

● http://host/<controlador>/<accion>/<p1>/<p2>

● Si no hay <accion>, la acción por defecto es index()

● Si no hay <controlador>, el controlador es pages y la accion es home()

● Un uso habitual de routes vale para establecer una acción por defecto como home.

CakePHP 2.1+Fundamentos

Daniel Glez-Peña