Ejercicio repaso

Creamos la base de datos 'empresa' con las siguientes tablas:

CREATE TABLE `empresa`.`proveedores` (
 `id` INT NOT NULL AUTO_INCREMENT,
 `razon` VARCHAR(45) NULL,
 `nif` VARCHAR(15) NULL,
 `fecha_alta` DATE NULL,
 `credito` DECIMAL(6,2) NULL,
 PRIMARY KEY (`id`));

CREATE TABLE `empresa`.`productos` (
 `id` INT NOT NULL AUTO_INCREMENT,
 `referencia` VARCHAR(45) NULL,
 `proveedor_id` INT NULL,
 `precio` DECIMAL(6,2) NULL,
 `activo` TINYINT NULL,
 PRIMARY KEY (`id`));

Queremos hacer mantenimiento en cakePHP.

Ningún campo puede tener un valor nulo.

Validaciones: crédito y precio, decimales. Referencia y nif, alfanuméricos. Referencia es, además, única.

La fecha tiene que validarse y tener un datepicker para escogerla.

El producto puede tener imágenes. Estas se añadirán en una vista aparte, guardándose dentro de la carpeta img de la raiz con una subcarpeta con la referencia del producto.

En la vista del producto (view) se deberán ver las imágenes si existen.

El campo 'activo' nunca será visible desde el mantenimiento en cakephp. Con este parámetro haremos otra cosa, pero más adelante.

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)
 );
 }

Parámetros en cakePHP

Vimos que el formato por defecto de enrutamiento es:

http://example.com/controller/action/param1/param2/param3

Por ejemplo, si yo accedo a:

http://localhost/cakeblog/autors/index/ola/k/ase

Dentro de la función index del controlador de autores tengo la variable $this->passedArgs que vale lo siguiente:

Array
(
[0] => ola
[1] => k
[2] => ase
)

Si yo paso parámetros con nombre el array es asociativo con el nombre del parámetro como clave. Ejemplo

http://localhost/cakeblog/autors/index/ola:5/k:7/ase:patata

Me da lo siguiente:

Array
(
[ola] => 5
[k] => 7
[ase] => patata
)

 

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