Función rellenar entradas

Esta función nos rellena la tabla de entradas con el número que le pasemos:

 

  public function rellenar($cantidad) {
 for ($i = 0; $i < $cantidad; $i++) {
 $this->Entrada->create();
 $this->Entrada->save(
 array(
 'titulo' => 'titulo' . $i, 
 'texto' => 'texto' . $i
 )
 );
 }
 return $this->redirect(array('action' => 'index'));
 }

Rutas personalizadas en CakePHP

Podemos reenrutar cualquier url para que nos vaya a un controlador específico. Esto nos evita tener que poner nombres específicos a los controladores, entre otras cosas.

La configuración está en  /app/config/routes.php y usa el siguiente formato:

Router::connect(
    'URL',
    array('nombreParam' => 'valorPorDefecto'),
    array('nombreParam' => 'expresionRegular')
)

Por ejemplo, si yo tengo el controlador ‘entradas’ para ver las entradas pero quiero acceder también con ‘posts’ podría hacer lo siguiente:

Router::connect(
    '/posts',
    array('controller' => 'entradas', 'action' => 'index')
);
Router::connect(
 '/:controller/:id', array('action' => 'view'), array(
 'pass' => array('id'),
 'id' => '[0-9]+'
 )
);

Otros ejemplos:

Router::connect(
 '/contacto', array('controller' => 'pages', 'action' => 'display', 'contacto')
);

Router::connect(
 '/vendedores/:action/*', array('controller' => 'proveedores')
);

Este ejemplo sencillo muestra cómo 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 cómo reconocer nombres de controladores en el URL. El elemento :id es propio, y debe ser clarificado especificando una expresión regular en el tercer parámetro de conenct(). Esto le dice a CakePHP cómo reconocer el ID en el URL en contraposición a cualquier otra cosa que esté allí, como el nombre de una acción.

En este ejemplo cambiamos la manera de pasar parámetros:

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 parámetro $articuloID de tu acción.
        'pass' => array('id', 'slug'),
        'id' => '[0-9]+'
    )
)

 

Vistas en CakePHP

Las vistas en cakePhp se guardan dentro de la carpeta /app/views/, normalmente dentro de una carpeta con el mismo nombre que el controlador. Cuando se ejecuta una acción de un controlador, si no especificamos nada, se renderiza la vista con el mismo nombre de la acción.

Por ejemplo, si tengo lo siguiente:

class RecetasController extends AppController {
function ver($id)     {
//la lógica de la acción va aqui…
}

}

Y llamo a la url:

localhost/recetas/ver

Se ejecuta la acción ver y se muestra la vista que esté situada en:

/app/views/recetas/ver.ctp

Las plantillas de las vistas tienen extensión .ctp

Podemos usar una vista diferente con el comando render:

  $this -> render(`/OtraVista/index`);

Ejemplo de parámetros nombrados

El siguiente código filtra con like si pasamos un parámetro con nombre que coincida con un elemento de la tabla:

 public function index() {
 $filtro = array();
 foreach ($this->passedArgs as $clave => $valor) {
 if (in_array($clave, array_keys($this->Autor->schema()))) {
 $filtro['Autor.' . $clave . ' like'] = '%' . $valor . '%';
 }
 }
 $this->Autor->recursive = 0;

 $this->set('autors', $this->Paginator->paginate(
 $filtro)
 );
 }

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>

 

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

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',
 ),
 ),
 );