Ejercicio buscar por edad

Controlador:

 public function edad($inicio = 0, $fin = 30) {
 
 if (!empty($this->request->query['inicio'])) {
 $inicio = $this->request->query['inicio'];
 }
 if (!empty($this->request->query['fin'])) {
 $fin = $this->request->query['fin'];
 }

 $params = array(
 'conditions' => array('Autor.edad BETWEEN ? AND ? ' => array($inicio, $fin)),
 'recursive' => -1,
 'order' => 'Autor.edad',
 );
 $autores = $this->Autor->find('all', $params);

 $this->set(compact('autores', 'inicio', 'fin'));
 }

La vista:

<div class="autors view">
 <h2><?php echo __('Autores entre ' . $inicio . " y " . $fin); ?></h2>
 <?php
 echo $this->Form->create('Edad', array('type' => 'get',
 'url' => array('controller' => 'Autors', 'action' => 'edad')));
 echo $this->Form->input('inicio', array(
 'label' => 'Introduzca la edad de inicio',
 'default'=>$inicio,
 ));
 echo $this->Form->input('fin', array(
 'label' => 'Introduzca la edad final',
 'default'=>$fin,
 ));
 echo $this->Form->end('Buscar');
 ?>
 <?php
 foreach ($autores as $autor):
 ?>
 <dl>
 <dt><?php echo __('Id'); ?></dt>
 <dd>
 <?php echo h($autor['Autor']['id']) . " " . h($autor['Autor']['name']); ?>
 &nbsp;
 </dd>
 <dt><?php echo __('Edad'); ?></dt>
 <dd>
 <?php echo h($autor['Autor']['edad']); ?>
 &nbsp;
 </dd>
 </dl>
 <?php
 endforeach;
 ?>
</div>

Opción upload para autores

//En index.ctp:

 <?php echo $this->Html->link(__('Upload'), array('action' => 'upload', $autor['Autor']['id'])); ?>

//En el controlador

 public function upload($id = null) {
 if (!$this->Autor->exists($id)) {
 throw new NotFoundException(__('Invalid autor'));
 }
 if ($this->request->is(array('post', 'put'))) {
 

 $archivo = $this->request->data['Autor']['archivo'];
 move_uploaded_file($archivo['tmp_name'], WWW_ROOT . 'autores/' . $id . "/" . $archivo['name']);


 $this->Flash->success(__('Archivo subido.'));
 return $this->redirect(array('action' => 'index'));
 
 } else {
 $options = array('conditions' => array('Autor.' . $this->Autor->primaryKey => $id));
 $this->set('autor', $this->Autor->find('first', $options));
 }
 }

//La vista (entera)

<h2>Subiendo archivos para el autor <?=h($autor['Autor']['name'])?></h2>
<div class="autors form">
 
 <?php echo $this->Form->create('Autor', array('type' => 'file')); ?>
 <fieldset>
 <legend><?php echo __('Escoja el archivo a subir'); ?></legend>
 <?php
 
 echo $this->Form->file('archivo');
 ?>
 </fieldset>
 <?php echo $this->Form->end(__('Submit')); ?>
</div>
<div class="actions">
 <h3><?php echo __('Actions'); ?></h3>
 <ul>

 <li><?php echo $this->Form->postLink(__('Delete'), array('action' => 'delete', $this->Form->value('Autor.id')), array('confirm' => __('Are you sure you want to delete # %s?', $this->Form->value('Autor.id')))); ?></li>
 <li><?php echo $this->Html->link(__('List Autors'), array('action' => 'index')); ?></li>
 </ul>
</div>

Subir archivos en cakePHP

Para subir archivos en cakePHP debemos modificar la vista para que el formulario esté preparado para subir archivos:

<?php echo $this->Form->create('Country', array('type' => 'file')); ?>
 <fieldset>
 <legend><?php echo __('Add Country'); ?></legend>
 <?php
 echo $this->Form->input('country');
 echo $this->Form->file('archivo');
 echo $this->Form->input('last_update');
 ?>
 </fieldset>
<?php echo $this->Form->end(__('Submit')); ?>

Después en el controlador tenemos el archivo dentro de request->data, lo movemos igual que lo haríamos en php:

 public function add() {
 if ($this->request->is('post')) {
 $this->Country->create();
 if ($this->Country->save($this->request->data)) {
 $archivo = $this->request->data['Country']['archivo'];
 move_uploaded_file($archivo['tmp_name'], WWW_ROOT . 'files' . DS . $archivo['name']);
 $this->Flash->success(__('The country has been saved.'));
 return $this->redirect(array('action' => 'index'));
 } else {
 $this->Flash->error(__('The country could not be saved. Please, try again.'));
 }
 }
 }

Ejemplo ver archivos de carpeta del autor

En el controlador:

App::uses('Folder', 'Utility');
....
 public function view($id = null) {
 if (!$this->Autor->exists($id)) {
 throw new NotFoundException(__('Invalid autor'));
 }
 $options = array('conditions' => array('Autor.' . $this->Autor->primaryKey => $id));
 $this->set('autor', $this->Autor->find('first', $options));
 $dir = new Folder(WWW_ROOT . "autores/" . $id);
 $this->set('files', $dir->find(".*"));
 }

En la vista:

<h1>Archivos</h1>
 <ul>
 <?php
 foreach ($files as $file):
 ?>
 <li><?= $this->Html->link($file,"/autores/".$autor['Autor']['id']."/".$file) ?></li>
 <?php
 endforeach;
 ?>
 </ul>

 

Ejemplos callback

//Antes de guardar en la base de datos convierte la fecha de formato y al mail añade 'mailto:'
 public function beforeSave($options = array()) {
 if (isset($this->data['Autor']['fecha'])) {
 $this->data['Autor']['fecha'] = date("Y-m-d", strtotime($this->data['Autor']['fecha']));
 }
 if (isset($this->data['Autor']['mail'])) {
 $this->data['Autor']['mail'] = 'mailto:' . $this->data['Autor']['mail'];
 }
 }

//Después de recuperar los datos de la base de datos convierte la fecha de mysql a d/m/y y quita el 'mailto:' de los mails
 public function afterFind($results, $primary = false) {

 foreach ($results as $key => $val) {
 if (isset($results[$key]['Autor']['fecha'])) {
 $results[$key]['Autor']['fecha'] = date("d-m-Y", strtotime($results[$key]['Autor']['fecha']));
 }
 if (isset($results[$key]['Autor']['mail'])) {
 $results[$key]['Autor']['mail'] = str_replace('mailto:', '', $results[$key]['Autor']['mail']);
 }
 }
 return $results;
 }

//Filtra todos los resultados que no tengan el mail 'aaa.com'
 public function beforeFind($query) {
 $query['conditions']['Autor.mail LIKE'] = "%@aaa.com%";

 return $query;
 }

//Cuando añadimos un autor nuevo crea una carpeta con su id
 public function afterSave($created, $options = array()) {

 if ($created) {
 $dir = new Folder(WWW_ROOT . 'autores/' . $this->data['Autor']['id'], true);
 }
 }

//Impedimos que se borre el autor con id 3
 public function beforeDelete($cascade = true) {
 
 if ($this->id == 3) {
 return false;
 } else {
 return true;
 }
 }

//Cuando borramos un autor eliminamos su carpeta
 public function afterDelete(){
 $folder = new Folder();
 $folder->delete(WWW_ROOT . 'autores/' . $this->id);
 }

 

Funciones de callback del modelo en cakephp

En cakephp disponemos de los siguientes callbacks predefinidos:

beforeFind(array $query)

afterFind(array $results, boolean $primary = false)

beforeValidate(array $options = array())

afterValidate()

beforeSave(array $options = array())

afterSave(boolean $created, array $options = array())

beforeDelete(boolean $cascade = true)

afterDelete()

En algunos disponemos de los datos en

$this->data o $this->id

Poner un calendar para la fecha

Para poner un calendar en una fecha tenemos varias opciones. Quizá la más sencilla sea incluir jquery y jquery ui. Para hacer esto debemos añadir las siguientes líneas en default.ctp:

 echo $this->Html->script("https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js");
 echo $this->Html->css('https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css');
 echo $this->Html->script("https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js");

Una vez hecho, sólo tenemos que cambiar la vista donde esté nuestra fecha, haciéndola de tipo texto y añadiendo el datepicker:

<script>
$(function() {
 $("#calendario").datepicker({
 dateFormat: "dd-mm-yy",
 });
});
</script>
......
 echo $this->Form->input('fecha', array(
 'id' => 'calendario',
 'type' => 'text'
 ));

Para que nos convierta la fecha al formato de mysql tenemos que ponerlo en el beforesave del modelo:

  public function beforeSave($options = array()) {
 if (isset($this->data['Autor']['fecha'])) {
 $this->data['Autor']['fecha'] = date("Y-m-d", strtotime($this->data['Autor']['fecha']));
 }
 
 }

 public function afterFind($results, $primary = false) {

 foreach ($results as $key => $val) {
 if (isset($results[$key]['Autor']['fecha'])) {
 $results[$key]['Autor']['fecha'] = date("d-m-Y", strtotime($results[$key]['Autor']['fecha']));
 }
 }
 return $results;
 }

Ejercicio validaciones

Creemos esta tabla en nuestra base de datos:

CREATE TABLE `autors` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `name` varchar(45) NOT NULL,
 `mail` varchar(200) NOT NULL,
 `edad` int(11) DEFAULT NULL,
 `password` varchar(20) DEFAULT NULL,
 `fecha` date DEFAULT NULL,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

En nuestro modelo de datos tendremos que poner las siguientes validaciones:

Nombre y mail no pueden estar en blanco

mail tiene que ser un mail válido

La edad tiene que ser un número natural entre 18 y 120

La contraseña debe ser alfanumérica y entre 6 y 20 caracteres de longitud

La fecha una fecha en formato d-m-y

Solución:

 public $validate = array(
 'name' => array(
 'notBlank' => array(
 'rule' => array('notBlank'),
 'message' => 'El nombre no puede estar en blanco',
 ),
 ),
 'mail' => array(
 'notBlank' => array(
 'rule' => array('notBlank'),
 'message' => 'El mail no puede estar en blanco',
 ),
 'mail' => array(
 'rule' => array('email'),
 'message' => 'Debe ser un email válido',
 ),
 ),
 'edad' => array(
 'natural' => array(
 'rule' => array('naturalNumber'),
 'message' => 'Números positivos y enteros',
 ),
 'rango' => array(
 'rule' => array('range',17.9,120.1),
 'message' => 'La edad debe estar entre 18 y 120',
 ),
 ),
 'password' => array(
 'alfanumerica' => array(
 'rule' => array('alphaNumeric'),
 'message' => 'La contraseña debe ser alfanumérica',
 ),
 'rango' => array(
 'rule' => array('lengthBetween',6,20),
 'message' => 'La contraseña debe tener entre 6 y 20 caracteres de longitud',
 ),
 ),
 'fecha' => array(
 'fecha' => array(
 'rule' => array('date', 'dmy'),
 'message' => 'Debe ser una fecha',
 ),
 ),
 );

Paginación en cakePHP: Paginator (helper en vistas)

Los datos recuperados por Paginator se muestran en las vistas de igual manera que los recuperados por otras funciones (como el find). Pero tenemos un helper que nos permite dibujar elementos de paginación de una manera sencilla.

Por ejemplo, para mostrar cabeceras que se puedan ordenar, podemos usar ‘sort:

echo $this->Paginator->sort('post_id');

Podemos ponerle un título alternativo:

echo $this->Paginator->sort('post_id', 'Código');

Para mostrar los números de página tenemos la función ‘numbers’:

echo $this->Paginator->numbers();

Tenemos muchas opciones:

  • before Insertar contenido antes de los números.

  • after Insertar contenido después de los números.

  • modulus Cuantos números de página, por defecto 8

  • separator Separador, por  defecto ` |`

  • tag El tag html que rodea los números, por defecto <span>.

  • first Si lo ponemos tendremos un enlace a la página inicial. Podemos poner el texto o el número de páginas a mostrar. El primero muestra un enlace con texto y el segundo las dos primeras páginas:

    echo $this->Paginator->numbers(array('first' => 'First page'));
    
    echo $this->Paginator->numbers(array('first' => 2, 'last' => 2));
  • last Igual que el anterior para las últimas.

  • ellipsis texto para la elipsis, por defecto ‘…’

  • class Si queremos una clase especial para los números.

  • currentClass La clase para la página actual. Por defecto es current.

    Para poner enlaces directos tenemos varias funciones: next, first… veamos como usarlas:

prev($title = ‘<< Previous’, $options = array(), $disabledTitle = null, $disabledOptions = array())

next($title = ‘Next >>’, $options = array(), $disabledTitle = null, $disabledOptions = array())

Añaden un enlace a la página siguiente o a la anterior. El primer parámetro es el título. Los siguientes son:

  • $options (mixed) Las opciones del elemento (class, tag…)
  • $disabledTitle (string) – El título cuando el enlace está deshabilitado (por estar en la primera página, caso del prev, por estar en la última, caso del next).
  • $disabledOptions (mixed) – Las opciones del elemento (class, tag…) cuando está deshabilitado.

Ejemplos:

echo $this->Paginator->prev(
  ' << ' . __('Anterior'),
  array(),
  null,
  array('class' => 'prev disabled')
);

echo $this->Paginator->prev(__('Anterior'), array('tag' => 'li'));

Para poner enlaces a la primera y última página, además de las opciones de numbers, tenemos las siguientes funciones:

first($first = ‘<< first’, $options = array())

last($last = ‘last >>’, $options = array())

Con las siguientes opciones:

  • tag Tag que rodea al elemento
  • after Contenido después del enlace
  • separator Separador entre enlaces
  • ellipsis Texto para la elipse

Para poder ver un contador tenemos:

counter($options = array())

Con las siguientes opciones en el texto:

  • {:page} – Página actual.
  • {:pages} – Total de páginas.
  • {:current} – Registro actual.
  • {:count} – Total de registros.
  • {:start} – Primer registro que se muestra.
  • {:end} – Último registro que se muestra.

Ejemplo:

echo $this->Paginator->counter(
    'Página {:page} de {:pages}, mostrando {:current} registros de un total de {:count} , empezando en {:start}, acabando en {:end}'
);