<?xml version="1.0" encoding="UTF-8"?><!-- generator="bbPress" -->

<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
>

<channel>
<title>Dudas de cakephp &#187; Tag: cakephp-1.2 - Recent Topics</title>
<link>http://cakephp.hospedaxes.com/dudas/</link>
<description>Just another bbPress community</description>
<language>en</language>
<pubDate>Thu, 09 Sep 2010 02:50:10 +0000</pubDate>

<item>
<title>nuria en "Calendario en CakePHP"</title>
<link>http://cakephp.hospedaxes.com/dudas/topic/calendario-en-cakephp-1#post-111</link>
<pubDate>Lun, 01 Feb 2010 08:34:14 +0000</pubDate>
<dc:creator>nuria</dc:creator>
<guid isPermaLink="false">111@http://cakephp.hospedaxes.com/dudas/</guid>
<description>&#60;blockquote&#62;&#60;p&#62;Cuando estamos &#60;a href=&#34;http://www.hospedaxes.com&#34;&#62;desarrollando una página web&#60;/a&#62;, a menudo necesitamos introducir un calendario que nos permita seleccionar las fechas sin tener que escribirlas a mano.&#60;/p&#62;
&#60;p&#62;En este post vamos a explicar cómo hacer esto, utilizando para ello el calendario &#60;a href=&#34;http://www.dynarch.com/projects/calendar/&#34;&#62;DHTML Calendar&#60;/a&#62; desarrollado por &#60;a href=&#34;http://www.dynarch.com/&#34;&#62;Dynarch&#60;/a&#62;. Es un calendario con licencia &#60;a href=&#34;http://es.wikipedia.org/wiki/Licencia_p%C3%BAblica_general_de_GNU&#34;&#62;GNU&#60;/a&#62; y que cubre perfectamente todas las funcionalidades que necesitamos.&#60;/p&#62;
&#60;p&#62;Todos los ficheros necesarios para introducir el calendario en nuestra página web, junto con la estructura como se organizan en CakePHP 1.2, pueden descargarse &#60;a href=&#34;http://cakephp.hospedaxes.com/wp-content/uploads/2008/07/calendariotar.gz&#34;&#62;calendario&#60;/a&#62;. Lo explicaremos paso a paso.&#60;/p&#62;
&#60;p&#62;Lo primero que tenemos que hacer es descargarnos el calendario (podemos hacerlo directamente de la página web de Dynarch, o bien mediante el enlace del párrafo anterior) y descomprimirlo en la carpeta &#60;em&#62;app/webroot/js&#60;/em&#62;. Necesitamos también otro fichero javascript, &#60;em&#62;common.js&#60;/em&#62;, que también meteremos en esa carpeta. En el &#60;em&#62;body&#60;/em&#62;, incluiremos estos ficheros escribiendo:&#60;/p&#62;
&#60;pre class=&#34;prettyprint&#34;&#62;// Calendar includes
echo $javascript-&#62;link('jscalendar-1.0/calendar.js');
echo $javascript-&#62;link('jscalendar-1.0/lang/calendar-es.js');
echo $javascript-&#62;link('common.js');
// CSS Theme
echo $html-&#62;css('../js/jscalendar-1.0/skins/aqua/theme');&#60;/pre&#62;
&#60;p&#62;Necesitamos ahora implementar un helper para que nos sea mucho más fácil la utilización de este calendario. Lo descargamos del enlace anterior y lo metemos en la carpeta &#60;em&#62;app/views/helpers&#60;/em&#62;. Si miramos el código de este helper vemos que tenemos dos funciones, &#60;strong&#62;picker&#60;/strong&#62; y &#60;strong&#62;flat&#60;/strong&#62;, que nos permiten hacer que este calendario aparezca al pulsar un botón o que esté siempre visible en nuestra página.&#60;/p&#62;
&#60;p&#62;Ya sólo nos falta introducir este calendario en nuestras páginas.&#60;/p&#62;
&#60;p&#62;En el controlador, importamos el helper:&#60;/p&#62;
&#60;pre class=&#34;prettyprint&#34;&#62;var $helpers = array('DatePicker');&#60;/pre&#62;
&#60;p&#62;Y en la vista mostramos el calendario:&#60;/p&#62;
&#60;pre class=&#34;prettyprint&#34;&#62;echo $datePicker-&#62;flat('fechaCalendarioFlat', array('id'=&#62;'fechaCalendarioFlat'));
echo $datePicker-&#62;picker('fechaCalendarioPicker', array('id'=&#62;'fechaCalendarioPicker'));&#60;/pre&#62;
&#60;p&#62;Podemos ver una demostración del funcionamiento del calendario en este &#60;a title=&#34;Calendario en CakePHP 1.2&#34; href=&#34;http://cakephp.hospedaxes.com/pruebas/calendario&#34;&#62;enlace&#60;/a&#62;.&#60;/p&#62;
&#60;p&#62;A partir del código proporcionado, podríamos añadir muchas funcionalidades. Por ejemplo, podremos editar el código del helper, para añadirle un observador de javascript al calendario tipo flat y que al pulsar en una fecha nos lleve a otra url, o podríamos hacer que ciertas fechas especiales se coloreen de manera distinta al resto.&#60;/p&#62;
&#60;p&#62;&#60;em&#62;NOTA:&#60;/em&#62; Tras el comentario de Hijal, hemos comprobado que la versión del helper enlazada en este post es para la versión 1.1 de CakePHP, para la versión 1.2 únicamente habría que modificar las funciones &#60;strong&#62;flat&#60;/strong&#62; y &#60;strong&#62;picker&#60;/strong&#62;, de la manera que se muestra a continuación:&#60;/p&#62;
&#60;p&#62;function picker($fieldName, $options = array()) {&#60;br /&#62;
$this-&#38;gt;_setup();&#60;br /&#62;
$htmlAttributes = $this-&#38;gt;domId($options);&#60;br /&#62;
$divOptions['class'] = &#38;#8216;date&#38;#8217;;&#60;br /&#62;
$options['type'] = &#38;#8216;text&#38;#8217;;&#60;br /&#62;
$options['div']['class'] = &#38;#8216;date&#38;#8217;;&#60;br /&#62;
$options['after'] = $this-&#38;gt;Html-&#38;gt;link($this-&#38;gt;Html-&#38;gt;image(&#38;#8217;../js/jscalendar-1.0/img.gif&#38;#8217;), &#38;#8216;#&#38;#8217;, array(&#38;#8217;onClick&#38;#8217;=&#38;gt;&#38;#8221;return showCalendar(&#38;#8217;&#38;#8221;.$htmlAttributes['id'].&#38;#8221;&#38;#8216;, &#38;#8216;&#38;#8221;.$this-&#38;gt;format.&#38;#8221;&#38;#8216;); return false;&#38;#8221;), null, false);&#60;br /&#62;
$output = $this-&#38;gt;input($fieldName, $options);&#60;br /&#62;
return $output;&#60;br /&#62;
}&#60;/p&#62;
&#60;p&#62;function flat($fieldName, $options = array()){&#60;br /&#62;
$this-&#38;gt;_setup();&#60;br /&#62;
$htmlAttributes = $this-&#38;gt;domId($options);&#60;br /&#62;
$divOptions['class'] = &#38;#8216;date&#38;#8217;;&#60;br /&#62;
$options['type'] = &#38;#8216;hidden&#38;#8217;;&#60;br /&#62;
$options['div']['class'] = &#38;#8216;date&#38;#8217;;&#60;br /&#62;
$hoder = &#38;#8216;&#38;lt;div id=&#38;#8221;&#38;#8216;.$htmlAttributes['id'].&#38;#8217;_cal&#38;#8217;.'&#38;#8221;&#38;gt;&#38;lt;/div&#38;gt;&#38;lt;script type=&#38;#8221;text/javascript&#38;#8221;&#38;gt;showFlatCalendar(&#38;#8221;&#38;#8216;.$htmlAttributes['id'].&#38;#8217;&#38;#8221;, &#38;#8220;&#38;#8216;.$htmlAttributes['id'].&#38;#8217;_cal&#38;#8217;.'&#38;#8221;, &#38;#8220;&#38;#8216;.$this-&#38;gt;format.&#38;#8217;&#38;#8221;, function(cal, date){document.getElementById(&#38;#8221;.$htmlAttributes['id'].&#38;#8221;.&#38;#8217;').value = date});&#38;lt;/script&#38;gt;&#38;#8217;;&#60;br /&#62;
$output = $this-&#38;gt;input($fieldName, $options).$hoder;&#60;br /&#62;
return $output;&#60;br /&#62;
}&#60;/p&#62;
&#60;p&#62;Estas dos funciones se encuentran ya modificadas en el fichero tar.gz que se adjunta en el post. Junto con otra modificación surgida tras el siguiente comentario en el foro &#60;a href=&#34;http://cakephp.hospedaxes.com/dudas/topic/calendario-en-cakephp&#34; target=&#34;_blank&#34;&#62;http://cakephp.hospedaxes.com/dudas/topic/calendario-en-cakephp&#60;/a&#62;&#60;/p&#62;&#60;/blockquote&#62;
&#60;p&#62;&#60;br/&#62;&#60;a href=&#34;http://cakephp.hospedaxes.com/calendario-en-cakephp&#34;&#62;Calendario en CakePHP&#60;/a&#62;&#60;/p&#62;</description>
</item>
<item>
<title>bernal en "Crear pdfs en cakephp utilizando TCPDF"</title>
<link>http://cakephp.hospedaxes.com/dudas/topic/crear-pdfs-en-cakephp-utilizando-tcpdf#post-13</link>
<pubDate>Mie, 08 Jul 2009 06:59:21 +0000</pubDate>
<dc:creator>bernal</dc:creator>
<guid isPermaLink="false">13@http://cakephp.hospedaxes.com/dudas/</guid>
<description>&#60;blockquote&#62;&#60;p&#62;En nuestra experiencia en &#60;a href=&#34;http://www.hospedaxes.com&#34;&#62;desarrollo web&#60;/a&#62;, se nos ha planteado proyectos que tenían como uno de sus requisitos la creación de un archivo pdf generado automáticamente, por ejemplo una factura de compra o un informe de ventas.&#60;/p&#62;
&#60;p&#62;En un principio, comenzamos utilizando &#60;a href=&#34;http://www.fpdf.org&#34;&#62;fpdf&#60;/a&#62;, una clase en php, totalmente gratuíta, que permite crear automáticamente archivos pdf y que además tenía un helper para cakephp 1.1.&#60;/p&#62;
&#60;p&#62;Esta clase funcionaba increíblemente bien, pero como todos los proyectos que no se actualizan regularmente (hasta hace poco llevaban más de 4 años sin realizar cambios), se quedan desfasados.&#60;/p&#62;
&#60;p&#62;Tenía un gran número de desventajas como que no aceptaba codificación UTF-8, o lo complejo que resultaba su uso.&#60;/p&#62;
&#60;p&#62;De este proyecto surgió en 2002 una rama, &#60;a href=&#34;http://tcpdf.sf.net&#34;&#62;TCPDF&#60;/a&#62;. Este proyecto ,también libre y gratuíto, en un principio solucionaba carencias del &#60;a href=&#34;http://www.fpdf.org&#34;&#62;fpdf&#60;/a&#62;, pero finalmente se ha convertido en una versión mucho más potente, con gran cantidad de posibilidades como por ejemplo el soporte de UTF-8 o idiomas de derecha-izquierda, permite la utilización de códigos html e incluye una lista bastante amplia de fuentes libres, que podremos utilizar en nuestro pdf.&#60;/p&#62;
&#60;p&#62;Para incluirlo en uno de nuestros proyectos y empezar a utilizarlo hay que llevar a cabo una serie de pasos bastante sencillos (añadir nuevas funcionalidades a un proyecto cakePHP se ha facilitado en la versión 1.2), en primer lugar bajar la última versión de TCPDF, descomprimirla en el directorio /app/vendors de nuestra aplicación.&#60;/p&#62;
&#60;p&#62;El resultado debería ser /app/vendors/tcpdf/ conteniendo al menos, tcpdf.php y los directorios tcpdf/config y tcpdf/fonts&#60;/p&#62;
&#60;p&#62;En segundo lugar tendremos que crear un layout para los pdf&#38;#8217;s en /app/views/layouts/pdf.ctp, con este contenido&#60;/p&#62;
&#60;pre class=&#34;prettyprint&#34;&#62;header(&#34;Content-type: application/pdf&#34;);
echo $content_for_layout;&#60;/pre&#62;
&#60;p&#62;En el controlador que queramos crear los pdf&#38;#8217;s, crearemos una función para ello&#60;/p&#62;
&#60;pre class=&#34;prettyprint&#34;&#62;function pdf()
{
      Configure::write('debug',0);
      $this-&#62;layout = 'pdf'; //this will use the pdf.ctp layout
      // Operaciones que deseamos realizar y variables que pasaremos a la vista.
      $this-&#62;render();
}&#60;/pre&#62;
&#60;p&#62;Por último una vista para esta función, con el siguiente contenido:&#60;/p&#62;
&#60;pre class=&#34;prettyprint&#34;&#62;App::import('Vendor','tcpdf');
$tcpdf = new TCPDF();
$textfont = 'freesans';
$tcpdf-&#62;SetCreator(PDF_CREATOR);
$tcpdf-&#62;SetAuthor(&#34;autor&#34;);
$tcpdf-&#62;SetTitle(&#34;Título&#34;);
$tcpdf-&#62;SetSubject(&#34;Tutorial TCPDF en cakePHP&#34;);
$tcpdf-&#62;SetKeywords(&#34;TCPDF, PDF, cakePHP, ejemplo&#34;);
$tcpdf-&#62;setPrintHeader(false);
$tcpdf-&#62;setPrintFooter(false);
$tcpdf-&#62;SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT);
$tcpdf-&#62;SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);
$tcpdf-&#62;setImageScale(PDF_IMAGE_SCALE_RATIO);
$tcpdf-&#62;setLanguageArray($l);
$tcpdf-&#62;AliasNbPages();
$tcpdf-&#62;AddPage();
$tcpdf-&#62;SetFont(&#34;freesans&#34;, &#34;BI&#34;, 20);
$tcpdf-&#62;Cell(0,10,&#34;Hola mundo&#34;,1,1,'C');
$tcpdf-&#62;Output(&#34;ejemplo.pdf&#34;, &#34;I&#34;);&#60;/pre&#62;
&#60;p&#62;En este ejemplo se creará un pdf muy sencillo con un cuadrado con el texto hola mundo dentro.&#60;br /&#62;
Las posibilidades de TCPDF son muchas, para comprobar lo que es capaz de hacer, es recomendable ojear los ejemplos contenidos en la &#60;a href=&#34;http://www.tecnick.com/public/code/cp_dpage.php?aiocp_dp=tcpdf_examples&#34;&#62;página&#60;/a&#62; y la documentación de la &#60;a href=&#34;http://www.tecnick.com/pagefiles/tcpdf/doc/com-tecnick-tcpdf/TCPDF.html&#34;&#62;clase&#60;/a&#62;, que explica el funcionamiento de todos sus métodos.&#60;/p&#62;
&#60;p&#62;En nuestra página de &#60;a href=&#34;http://cakephp.hospedaxes.com/pruebas&#34;&#62;pruebas de cakephp&#60;/a&#62; hay un &#60;a href=&#34;http://cakephp.hospedaxes.com/pruebas/ejemplo_pdf&#34;&#62;ejemplo sencillo&#60;/a&#62; de funcionamiento.&#60;/p&#62;
&#60;p&#62;&#60;strong&#62;Actualización (9/2/2009) :&#60;/strong&#62;&#60;/p&#62;
&#60;p&#62;&#60;strong&#62;Errores frecuentes:&#60;/strong&#62;&#60;/p&#62;
&#60;p&#62;“TCPDF error: Some data has already been output to browser, can’t send PDF file”: Este error se produce cuando cakePHP envía algún dato antes de crear el pdf y enviarlo, esto puede ocurrir por una serie de razones que habrá que comprobar:&#60;/p&#62;
&#60;ul&#62;
&#60;li&#62;Realizar un debug o un echo, en la vista o controlador.Esto crea salida de datos por lo que se genera el error, para eso añadimos en la primera línea de la función del controlador Configure::write(&#38;#8217;debug&#38;#8217;,0); , función que lo que hace es cambiar el nivel de debug a modo producción, donde no se muestra ningún mensaje, ni de error ni warnings.&#60;/li&#62;
&#60;li&#62;Existencia de caracteres de salto de línea o espacios después del símbolo de fín de archivo php, ?&#38;gt;. Para esto hay que comprobar todos los ficheros de nuestro proyecto y borrar todos los caracteres o saltos de línea que haya al final del fichero. Esta suele ser la razón más habitual para este error por lo que debemos comprobar todos los ficheros antes de tirar la toalla con tcpdf.&#60;/li&#62;
&#60;/ul&#62;
&#60;/blockquote&#62;
&#60;p&#62;&#60;br/&#62;&#60;a href=&#34;http://cakephp.hospedaxes.com/crear-pdf&#34;&#62;Crear pdfs en cakephp utilizando TCPDF&#60;/a&#62;&#60;/p&#62;</description>
</item>
<item>
<title>bernal en "Actualizar el contenido de un select con ajax."</title>
<link>http://cakephp.hospedaxes.com/dudas/topic/actualizar-el-contenido-de-un-select-con-ajax#post-11</link>
<pubDate>Lun, 06 Jul 2009 09:34:42 +0000</pubDate>
<dc:creator>bernal</dc:creator>
<guid isPermaLink="false">11@http://cakephp.hospedaxes.com/dudas/</guid>
<description>&#60;blockquote&#62;&#60;p&#62;En esta entrada vamos a explicar como asociar dos selects mediante ajax y al modificar el elemento seleccionado en uno de ellos  cambie el contenido del otro.&#60;/p&#62;
&#60;p&#62;Podemos ver el ejemplo de funcionamiento &#60;a href=&#34;http://www.hospedaxes.com/blog-cakephp/pruebas&#34; target=&#34;_blank&#34;&#62;aquí.&#60;/a&#62;&#60;/p&#62;
&#60;p&#62;Un ejemplo muy claro para esta situación sería dos selects, uno con provincias y el otro con localidades, lo que queremos es que al cambiar de provincia varíe la lista de localidades y muestre las que están en la provincia seleccionada.&#60;/p&#62;
&#60;p&#62;Lo haremos utilizando el ajaxHelper, para que no sea necesario la recarga de la página y quede más atractivo.&#60;/p&#62;
&#60;p&#62;Lo primero que haremos será definir los modelos de provincias ,localidades y un tercer modelo en el que usaremos los selects, por ejemplo podría ser un modelo de cliente, en el que al insertar un nuevo cliente tendríamos que elegir la provincia y localidad a la que pertenece.&#60;/p&#62;
&#60;h1&#62;&#60;span style=&#34;text-decoration: underline;&#34;&#62;Modelos&#60;/span&#62;&#60;/h1&#62;
&#60;p&#62;&#60;strong&#62;Modelo de provincia.&#60;/strong&#62;&#60;/p&#62;
&#60;pre class=&#34;prettyprint&#34;&#62;/app/models/provincia.php

class Provincia extends AppModel
{
    var $name = 'Provincia';
}&#60;/pre&#62;
&#60;p&#62;&#60;strong&#62;Modelo de localidad.&#60;/strong&#62;&#60;/p&#62;
&#60;pre class=&#34;prettyprint&#34;&#62;/app/models/localidade.php

class Localidade extends AppModel
{
    var $name = 'localidade';
}&#60;/pre&#62;
&#60;p&#62;&#60;strong&#62;Modelo de cliente.&#60;/strong&#62;&#60;/p&#62;
&#60;pre class=&#34;prettyprint&#34;&#62;/app/models/cliente.php

class Cliente extends AppModel
{
    var $name = 'Cliente';
}&#60;/pre&#62;
&#60;h1&#62;&#60;span style=&#34;text-decoration: underline;&#34;&#62;Controladores&#60;/span&#62;&#60;/h1&#62;
&#60;p&#62;Después de esto tendremos que definir los controladores.&#60;/p&#62;
&#60;p&#62;&#60;strong&#62;Controlador de localidad.&#60;/strong&#62;&#60;/p&#62;
&#60;pre class=&#34;prettyprint&#34;&#62;/app/controllers/localidades_controller.php

class LocalidadesController extends AppController
{
	var $name = 'Localidades';
}&#60;/pre&#62;
&#60;p&#62;&#60;strong&#62;Controlador de provincia.&#60;/strong&#62;&#60;/p&#62;
&#60;pre class=&#34;prettyprint&#34;&#62;/app/controllers/provincias_controller.php

class ProvinciasController extends AppController
{
	var $name = 'Provincias';
}&#60;/pre&#62;
&#60;p&#62;Y por últino el controlador de clientes que será el que implementará la funcionalidad.&#60;/p&#62;
&#60;p&#62;&#60;strong&#62;Controlador de cliente.&#60;/strong&#62;&#60;/p&#62;
&#60;pre class=&#34;prettyprint&#34;&#62;/app/controllers/clientes_controller.php

class ClientesController extends AppController
{
	var $name = 'Clientes';
	var $helpers = array('Ajax');
	var $uses = array('Cliente','Provincia','Localidade');

	function insertar()
	{
		$listadoProvincias = $this-&#62;Provincia-&#62;find('all', array('fields'=&#62;array('id','nombre'),'order'=&#62;'nombre ASC'));
		$this-&#62;set('provincias', Set::combine($listadoProvincias, &#34;{n}.Provincia.id&#34;,&#34;{n}.Provincia.nombre&#34;));
		$primera_provincia = $this-&#62;Provincia-&#62;find(null,null,'nombre ASC');
		$listadoLocalidades = $this-&#62;Localidade-&#62;find('all', array('fields'=&#62;array('id','nombre'),'order'=&#62;'nombre ASC','conditions'=&#62;'Localidade.provincia_id='.$primera_provincia['Provincia']['id']));
		$this-&#62;set('localidades', Set::combine($listadoLocalidades, &#34;{n}.Localidade.id&#34;,&#34;{n}.Localidade.nombre&#34;));

		// RESTO DE LA FUNCIONALIDAD DE INSERCIÓN DE CLIENTES
	}

	function update_select()
	{
		if (!empty($this-&#62;data['Localidade']['provincia_id']))
		{
			$provincia_id = $this-&#62;data['Localidade']['provincia_id'];
			$localidades = $this-&#62;Localidade-&#62;find('all', array('fields'=&#62;array('id','nombre'),'order'=&#62;'nombre ASC','conditions'=&#62;array('provincia_id'=&#62;$provincia_id)));
		}
		else
		{
			$localidades = $this-&#62;Localidade-&#62;find('all', array('fields'=&#62;array('id','nombre'),'order'=&#62;'nombre ASC'));
		}
		$this-&#62;set('options', Set::combine($localidades, &#34;{n}.Localidade.id&#34;,&#34;{n}.Localidade.nombre&#34;));
		$this-&#62;render('/elements/update_select', 'ajax');
	}
}&#60;/pre&#62;
&#60;p&#62;Por un lado tenemos la &#60;strong&#62;función insertar&#60;/strong&#62;, que será una función genérica de inserción de clientes. La parte que a nosotros nos interesa es en la que se inicializan las variables que después utilizaremos en los selects, estas deberán ser arrays en los que cada elemento tenda un identificador y su valor, para que el select pueda utilizarlos en la vista.&#60;/p&#62;
&#60;p&#62;En la versión 1.1 de cakephp, esto se podía hacer mediante la función generateList del modelo, función que se ha eliminado en la 1.2.&#60;br /&#62;
Por ello ahora es necesario hacerlo en dos pasos, por un lado realizar la búsqueda con un findAll y después utilizar la función combine de la clase Set que genera un array con la estructura deseada, que será el que le pasemos a la vista.&#60;/p&#62;
&#60;pre class=&#34;prettyprint&#34;&#62;$listadoProvincias = $this-&#62;Provincia-&#62;find('all', array('fields'=&#62;array('id','nombre'),'order'=&#62;'nombre ASC'));
$this-&#62;set('provincias', Set::combine($listadoProvincias, &#34;{n}.Provincia.id&#34;,&#34;{n}.Provincia.nombre&#34;));&#60;/pre&#62;
&#60;p&#62;La segunda función &#60;strong&#62;update_select&#60;/strong&#62;, es a la que llamará el ajax para actualizar el listado de localidades a partir de un identificador de provincia.&#60;/p&#62;
&#60;p&#62;Como se puede ver en el código, la función coge el identificador de provincia del select y envía a la vista los arrays actualizados de provincias y localidades.&#60;/p&#62;
&#60;h1&#62;&#60;span style=&#34;text-decoration: underline;&#34;&#62;Vistas&#60;/span&#62;&#60;/h1&#62;
&#60;p&#62;Localidades y provincias no tendrán vistas asociadas, ya que no hay ninguna operación en el controlador.&#60;/p&#62;
&#60;p&#62;En clientes tendremos que crear la vista para la operación insertar del controlador, esta podría ser algo como esto:&#60;/p&#62;
&#60;pre class=&#34;prettyprint&#34;&#62;/app/views/clientes/insertar.ctp

echo $form-&#62;create('Inscripcione',array('action'=&#62;'insertar'));
echo $form-&#62;inputs(array('legend'=&#62;'Actualizar Provincias',
		'Localidade.provincia_id' =&#62; array('label'=&#62; 'Provincia','showEmpty'=&#62;'false','id'=&#62;'provincias'),
		'Alumno.localidade_id' =&#62; array('label'=&#62; 'Localidad','showEmpty'=&#62;'false','id'=&#62;'localidades'),
			));
echo $form-&#62;end();

$options = array('url' =&#62; 'update_select','update' =&#62; 'localidades');
echo $ajax-&#62;observeField('provincias',$options);&#60;/pre&#62;
&#60;p&#62;La vista será muy sencilla, un formulario con dos selects, uno de localidades y otro de provincias y una llamada al ajaxHelper en la que se indica que cada vez que se modifique el valor del select provincias, se llame a la función update_select y actualice el select de localidades.&#60;/p&#62;
&#60;p&#62;Este select se actualizará con los valores devueltos por la vista de update_select, que lo único que hace es imprimir todos los nombres de localidades devueltos por la función del controlador.&#60;/p&#62;
&#60;pre class=&#34;prettyprint&#34;&#62;/app/views/elements/update_select.ctp
if(!empty($options)) {
  foreach($options as $k =&#62; $v) {
    echo &#60;code &#62;&#34;&#38;lt;option value='$k'&#38;gt;$v&#38;lt;/option&#38;gt;&#34;;&#60;/code&#62;
  }
 }&#60;/pre&#62;
&#60;p&#62;En este enlace se puede ver un ejemplo de &#60;a href=&#34;http://www.hospedaxes.com/blog-cakephp/pruebas&#34; target=&#34;_blank&#34;&#62;funcionamiento&#60;/a&#62;.&#60;/p&#62;&#60;/blockquote&#62;
&#60;p&#62;&#60;br/&#62;&#60;a href=&#34;http://cakephp.hospedaxes.com/actualizar-el-contenido-de-un-select-con-ajax&#34;&#62;Actualizar el contenido de un select con ajax.&#60;/a&#62;&#60;/p&#62;</description>
</item>
<item>
<title>nuria en "Tree Behaviour o cómo crear una estructura jerárquica"</title>
<link>http://cakephp.hospedaxes.com/dudas/topic/tree-behaviour-o-como-crear-una-estructura-jerarquica#post-22</link>
<pubDate>Mie, 14 Oct 2009 08:42:35 +0000</pubDate>
<dc:creator>nuria</dc:creator>
<guid isPermaLink="false">22@http://cakephp.hospedaxes.com/dudas/</guid>
<description>&#60;blockquote&#62;&#60;p&#62;En esta ocasión hablaremos de cómo crear una estructura jerárquica utilizando el Tree Behavior de CakePHP. Este comportamiento facilita muchísimo las cosas a la hora de manipular árboles jerárquicos de datos.&#60;/p&#62;
&#60;p&#62;Utilizaremos también la librería de Javascript Ext JS para poder manipular el árbol gráficamente de manera sencilla, utilizando &#60;em&#62;drag and drop&#60;/em&#62;.&#60;/p&#62;
&#60;p&#62;Lo primero que tendremos que hacer será añadir en la tabla de la base de datos de la entidad. Utilizando los nombres por defecto de Cake, serían los siguientes campos:&#60;/p&#62;
&#60;ul&#62;
&#60;li&#62;parent_id: hace referencia al padre del elemento.&#60;/li&#62;
&#60;li&#62;lft: almacena el identificador del elemento de la izquierda en el mismo nivel.&#60;/li&#62;
&#60;li&#62;rght: almacena el identificador del elemento de la derecha en el mismo nivel.&#60;/li&#62;
&#60;/ul&#62;
&#60;p&#62;Incluiremos también los campos &#60;em&#62;id&#60;/em&#62; y &#60;em&#62;nombre&#60;/em&#62;, en una entidad denominada, por ejemplo, Categoria.&#60;/p&#62;
&#60;p&#62;El modelo lo haríamos de la siguiente manera:&#60;/p&#62;
&#60;p&#62;Este comportamiento tiene funciones muy útiles para la manipulación del árbol. Las más utilizadas quizás sean las siguientes:&#60;/p&#62;
&#60;ul&#62;
&#60;li&#62;children: devuelve los hijos de un nodo concreto, pudiendo seleccionar si deseamos obtener sólo los hijos directos o todos los hijos en el árbol.&#60;/li&#62;
&#60;li&#62;generatetreelist: función muy útil para obtener los elementos a introducir en un select de HTML.&#60;/li&#62;
&#60;li&#62;getpath: devuelve todo el path hasta el nodo especificado en un array.&#60;/li&#62;
&#60;li&#62;movedown y moveup: sirven para bajar o subir un nivel de un nodo del árbol.&#60;/li&#62;
&#60;li&#62;removefromtree: elimina un nodo del árbol sin perder la estructura, es decir, modificando el padre de sus hijos.&#60;/li&#62;
&#60;li&#62;reorder: reordena un nodo (arrastrando también a sus hijos) en función de los parámetros especificados.&#60;/li&#62;
&#60;/ul&#62;
&#60;p&#62;Para realizar la manipulación visual del árbol de categorías crearemos las siguientes funciones en el controlador &#60;em&#62;app/controllers/categorias_controller.php&#60;/em&#62; sería:&#60;/p&#62;
&#60;pre class=&#34;http://cakephp.hospedaxes.co/wp-admin/prettyprint&#34;&#62;&#60;code&#62;&#38;lt;?php

class CategoriasController extends AppController{

var $helpers = array( 'Javascript');

// Función para organizar las categorías
function organizar() {}

function getnodes() {
   Configure::write('debug', 0);
   // obtener el identificador del padre que se envío por POST vía Ajax
   $parent = intval($this-&#38;gt;params['form']['node']);
   // encontrar los hijos directos del nodo anterior
   $nodes = $this-&#38;gt;Categoria-&#38;gt;children($parent, true, null, 'Categoria.lft ASC');

   $this-&#38;gt;set(compact('nodes'));

   $this-&#38;gt;render('getnodes', 'ajax');
}

function reorder()
{
   Configure::write('debug', 0);

   // delta es la diferencia en la posición (1 = nodo siguiente, -1 = nod anterior)
   $node = intval($this-&#38;gt;params['form']['node']);
   $delta = intval($this-&#38;gt;params['form']['delta']);

   if ($delta &#38;gt; 0) {
      $this-&#38;gt;Categoria-&#38;gt;movedown($node, abs($delta));
   } elseif ($delta &#38;lt; 0) {
      $this-&#38;gt;Categoria-&#38;gt;moveup($node, abs($delta));
   }

   exit('1');
}

function reparent()
{
   Configure::write('debug', 0);

   $node = intval($this-&#38;gt;params['form']['node']);
   $parent = intval($this-&#38;gt;params['form']['parent']);
   $position = intval($this-&#38;gt;params['form']['position']);

   // guardamos el nuevo padre de la categoría
   $this-&#38;gt;Categoria-&#38;gt;id = $node;
   $this-&#38;gt;Categoria-&#38;gt;saveField('parent_id', $parent);

   // Si position == 0, nos movemos al inicio.
   // En otro caso, calculamos la distancia que nos moveremos ($delta).
   if ($position == 0) {
      $this-&#38;gt;Categoria-&#38;gt;moveup($node, true);
   } else {
      $count = $this-&#38;gt;Categoria-&#38;gt;childcount($parent, true);
      $delta = $count - $position - 1;
      if ($delta &#38;gt; 0) {
         $this-&#38;gt;Categoria-&#38;gt;moveup($node, $delta);
      }
   }

   exit('1');
}
}
?&#38;gt;&#60;/code&#62;&#60;/pre&#62;
&#60;p&#62;Sólo nos quedaría hacer las vistas. En este caso, necesitamos crear 2 vistas: organizar.ctp y getnodes.ctp.&#60;/p&#62;
&#60;pre class=&#34;http://cakephp.hospedaxes.co/wp-admin/prettyprint&#34;&#62;// app/views/categorias/organizar.ctp

&#60;?php echo $html-&#62;css('/js/ext-2.0.1/resources/css/ext-custom.css'); ?&#62;
&#60;?php echo $javascript-&#62;link('/js/ext-2.0.1/ext-custom.js'); ?&#62;

&#60;script type=&#34;http://cakephp.hospedaxes.co/wp-admin/text/javascript&#34;&#62;
Ext.BLANK_IMAGE_URL = '&#60;?php echo $html-&#62;url('/js/ext-2.0.1/resources/images/default/s.gif') ?&#62;';

Ext.onReady(function(){

   var getnodesUrl = '&#60;?php echo $html-&#62;url('/categorias/getnodes') ?&#62;';
   var reorderUrl = '&#60;?php echo $html-&#62;url('/categorias/reorder') ?&#62;';
   var reparentUrl = '&#60;?php echo $html-&#62;url('/categorias/reparent') ?&#62;';

   var Tree = Ext.tree;

   var tree = new Tree.TreePanel({
      el:'tree-div',
      autoScroll:true,
      animate:true,
      enableDD:true,
      containerScroll: true,
      rootVisible: true,
      loader: new Ext.tree.TreeLoader({
         dataUrl:getnodesUrl
      })
    });

   var root = new Tree.AsyncTreeNode({
      text:'Categorías',
      draggable:false,
      id:'root'
   });

   tree.setRootNode(root);
   tree.setHeight('auto');

   var oldPosition = null;
   var oldNextSibling = null;

   tree.on('startdrag', function(tree, node, event){
      oldPosition = node.parentNode.indexOf(node);
      oldNextSibling = node.nextSibling;
   });

   tree.on('movenode', function(tree, node, oldParent, newParent, position){

   if (oldParent == newParent){
      var url = reorderUrl;
      var params = {'node':node.id, 'delta':(position-oldPosition)};
   } else {
      var url = reparentUrl;
      var params = {'node':node.id, 'parent':newParent.id, 'position':position};
   }

tree.disable();

Ext.Ajax.request({
   url:url,
   params:params,
   success:function(response, request) {
      // if the first char of our response is zero, then we fail the operation,
      // otherwise we re-enable the tree
      if (response.responseText.charAt(0) != 1){
         request.failure();
      } else {
         tree.enable();
      }
   },
   failure:function() {
      // we move the node back to where it was beforehand and
      // we suspendEvents() so that we don't get stuck in a possible infinite loop
      tree.suspendEvents();
      oldParent.appendChild(node);
      if (oldNextSibling){
         oldParent.insertBefore(node, oldNextSibling);
      }
      tree.resumeEvents();
      tree.enable();
      alert(&#34;Oh no! Your changes could not be saved!&#34;);
   }
});
});

tree.render();
root.expand();
});
&#60;/script&#62;
&#60;div id=&#34;tree-div&#34;&#62;&#60;/div&#62;
&#60;/pre&#62;
&#60;p&#62;Y la última vista:&#60;/p&#62;
&#60;pre class=&#34;http://cakephp.hospedaxes.co/wp-admin/prettyprint&#34;&#62;&#60;code&#62;&#38;lt;?php
// app/views/categorias/getnodes.ctp
$data = array();
foreach ($nodes as $node)
{&#60;/code&#62;   &#60;code&#62;$data[] = array(&#60;/code&#62;      &#60;code&#62;&#34;text&#34; =&#38;gt; $node['Categoria']['nombre'],&#60;/code&#62;      &#60;code&#62;&#34;id&#34; =&#38;gt; $node['Categoria']['id']&#60;/code&#62;   &#60;code&#62;);
}
echo $javascript-&#38;gt;object($data);
?&#38;gt;&#60;/code&#62;&#60;/pre&#62;
&#60;p&#62;Ya sólo nos quedaría descargarnos la librería &#60;a title=&#34;http://cakephp.hospedaxes.co/wp-admin/Ext JS&#34; href=&#34;http://www.extjs.com/&#34; target=&#34;_blank&#34;&#62;ExtJS&#60;/a&#62; y copiarla en la carpeta /app/webroot/js. En el ejemplo, se ha utilizado la versión 2.0.1.&#60;/p&#62;
&#60;p&#62;Podemos ver una &#60;a title=&#34;http://cakephp.hospedaxes.co/wp-admin/Ejemplo de funcionamiento de Tree Behaviour&#34; href=&#34;http://cakephp.hospedaxes.com/pruebas/tree_behaviour&#34; target=&#34;_blank&#34;&#62;demostración de su funcionamiento&#60;/a&#62;.&#60;/p&#62;
&#60;div id=&#34;_mcePaste&#34; style=&#34;overflow: hidden; position: absolute; left: -10000px; top: 289px; width: 1px; height: 1px;&#34;&#62;
&#60;pre style=&#34;display: block;&#34;&#62;Categoria&#60;/pre&#62;
&#60;/div&#62;
&#60;/blockquote&#62;
&#60;p&#62;&#60;br/&#62;&#60;a href=&#34;http://cakephp.hospedaxes.com/tree-behaviour-o-como-crear-una-estructura-jerarquica&#34;&#62;Tree Behaviour o cómo crear una estructura jerárquica&#60;/a&#62;&#60;/p&#62;</description>
</item>

</channel>
</rss>
