<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>TecnoRetales &#187; Programación</title>
	<atom:link href="http://www.tecnoretales.com/categoria/programacion/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.tecnoretales.com</link>
	<description>La experiencia no se olvida</description>
	<lastBuildDate>Wed, 07 Jul 2010 21:23:33 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.5</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
		<!-- google ad injected by adsense-optimizer http://www.adsenseoptimizer.de -->
			<div  style="padding:7px; float: right; padding-right: 0; margin: 3px;"><!-- Ad number: 1 --><script type="text/javascript"><!--
    	 
    	google_ad_client = "pub-7180773421652966"; google_alternate_color = "FFFFFF";
		google_ad_width = 468; google_ad_height = 60;
		google_ad_format = "468x60_as"; google_ad_type = "text";
		google_ad_channel =""; google_color_border = "FE8B00";
		google_color_link = "FE8B00"; google_color_bg = "FFFFFF";
		google_color_text = "000000"; google_color_url = "D9D9D9";
		google_ui_features = "rc:6"; //--></script>
		<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script></div>	<item>
		<title>Error SVN Working Copy locked y cleanup</title>
		<link>http://www.tecnoretales.com/programacion/error-svn-working-copy-locked-y-cleanup/</link>
		<comments>http://www.tecnoretales.com/programacion/error-svn-working-copy-locked-y-cleanup/#comments</comments>
		<pubDate>Wed, 07 Jul 2010 21:23:30 +0000</pubDate>
		<dc:creator>Manel Pérez Mata</dc:creator>
				<category><![CDATA[Programación]]></category>
		<category><![CDATA[SVN]]></category>

		<guid isPermaLink="false">http://www.tecnoretales.com/?p=760</guid>
		<description><![CDATA[En alguna ocasión me he encontrado con que no puedo hacer update de un proyecto porque SVN indica el error:
Working copy xxxxxxxx locked Please execute &#8220;Cleanup&#8221; command
Pero cuando lanzao el comando cleanup también devuelve un error:
Cleanup failed to process the following paths: xxxxxx
Con lo que aparentemente, la única solución que queda es hacer un checkout [...]]]></description>
			<content:encoded><![CDATA[<!-- google_ad_section_start --><p>En alguna ocasión me he encontrado con que no puedo hacer update de un proyecto porque SVN indica el error:</p>
<blockquote><p>Working copy xxxxxxxx locked Please execute &#8220;Cleanup&#8221; command</p></blockquote>
<p>Pero cuando lanzao el comando cleanup también devuelve un error:</p>
<blockquote><p>Cleanup failed to process the following paths: xxxxxx</p></blockquote>
<p>Con lo que aparentemente, la única solución que queda es hacer un checkout nuevo e intentar no perder los cambios, sin embargo, existe otra solución:</p>
<ol>
<li>Copia los archivos editados en otra carpeta para evitar perder los cambios</li>
<li>Borra la carpeta que esté causando el problema</li>
<li>Ahora podrás hacer update</li>
<li>Copia los archivos editados en la carpeta (no copies las carpetas enteras porque contienen directorios .svn que volverán a darte problemas)</li>
<li>Por último, haz commit</li>
</ol>
<p>Espero os sea de utilidad.</p>
<!-- google_ad_section_end -->]]></content:encoded>
			<wfw:commentRss>http://www.tecnoretales.com/programacion/error-svn-working-copy-locked-y-cleanup/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Aprender a programar en 21 días</title>
		<link>http://www.tecnoretales.com/programacion/aprender-a-programar-en-21-dias/</link>
		<comments>http://www.tecnoretales.com/programacion/aprender-a-programar-en-21-dias/#comments</comments>
		<pubDate>Thu, 01 Jul 2010 21:43:38 +0000</pubDate>
		<dc:creator>Manel Pérez Mata</dc:creator>
				<category><![CDATA[Programación]]></category>
		<category><![CDATA[Humor]]></category>

		<guid isPermaLink="false">http://www.tecnoretales.com/?p=753</guid>
		<description><![CDATA[Via &#124; Abstruse Goose
]]></description>
			<content:encoded><![CDATA[<!-- google_ad_section_start --><p style="text-align: left"><a href="http://www.tecnoretales.com/wp-content/uploads/2010/06/aprende-a-programar-en-21-dias.png"><img class="aligncenter size-full wp-image-754" src="http://www.tecnoretales.com/wp-content/uploads/2010/06/aprende-a-programar-en-21-dias.png" alt="Aprende a programar en 21 dias" width="595" height="510" /></a>Via | <a rel="nofollow" href="http://abstrusegoose.com/249" target="_blank">Abstruse Goose</a></p>
<!-- google_ad_section_end -->]]></content:encoded>
			<wfw:commentRss>http://www.tecnoretales.com/programacion/aprender-a-programar-en-21-dias/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Smarty3 y autoload</title>
		<link>http://www.tecnoretales.com/programacion/smarty3-y-autoload/</link>
		<comments>http://www.tecnoretales.com/programacion/smarty3-y-autoload/#comments</comments>
		<pubDate>Tue, 29 Jun 2010 07:41:32 +0000</pubDate>
		<dc:creator>Manel Pérez Mata</dc:creator>
				<category><![CDATA[Frameworks]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Smarty]]></category>

		<guid isPermaLink="false">http://www.tecnoretales.com/?p=741</guid>
		<description><![CDATA[
Uno de los errores comunes al implementar Smarty3 es:
Fatal error: Class &#8216;Smarty_Internal_Wrapper&#8217; not found
Fatal error: Class &#8216;Smarty_Internal_Register&#8217; not found
Fatal error: Class &#8216;Smarty_Internal_Template&#8217; not found
Estos se deban, probablemente, a que en tu aplicación estás utilizando la función __autoload también necesaria por Smarty3. La solución a este problema pasa por utilizar la función que PHP nos brinda [...]]]></description>
			<content:encoded><![CDATA[<!-- google_ad_section_start --><p><img class="size-full wp-image-74 alignright" src="http://www.tecnoretales.com/wp-content/uploads/2009/05/logo_smarty.gif" alt="Smarty Logo" width="250" height="64" /></p>
<p>Uno de los errores comunes al <strong>implementar Smarty3</strong> es:</p>
<blockquote><p>Fatal error: Class &#8216;Smarty_Internal_Wrapper&#8217; not found</p>
<p>Fatal error: Class &#8216;Smarty_Internal_Register&#8217; not found</p>
<p>Fatal error: Class &#8216;Smarty_Internal_Template&#8217; not found</p></blockquote>
<p>Estos se deban, probablemente, a que en tu aplicación estás utilizando la función <strong>__autoload</strong> también necesaria por Smarty3. La solución a este problema pasa por utilizar la función que PHP nos brinda <strong>spl_autoload_register</strong>.</p>
<p>En una aplicación, sólo puede existir una llamada a la función __autload, sin embargo, con spl_autoload_register podemos añadir tantos manejadores como queramos y estos se irán ejecutando en el orden en el que los hayamos registrado.</p>
<p>Un ejemplo sencillo de su uso sería:</p>
<pre class="brush: php;">

class AutoloadHandler
{
	static public function launch( $classname )
	{
		print '[['. $name .']]';
	}
}

spl_autoload_register( 'AutoloadHandler::launch' );

new ThisClassNotExists();
</pre>
<p>El resultado de ejecutar este script sería algo así:</p>
<blockquote><p>[[ThisClassNotExists]]</p>
<p>Fatal error: Class &#8216;ThisClassNotExists&#8217; not found in &#8230;</p></blockquote>
<p>El cual nos indica que está llamando de manera correcta al autoload, pero al no estar implementado de manera correcta y no existir la clase &#8216;ThisClassNotExists&#8217; nos devuelve un error.</p>
<p>En definitiva, <strong>para solventar el problema</strong>, no será necesario que modifiques el código Smarty, pues este ya está utilizando de manera correcta spl_autoload_register, lo que debes hacer es <strong>sustituir tu __autoload</strong> por una clase con una función &#8216;launch&#8217; (llámala como quieras) y registrarla mediante:</p>
<pre class="brush: php;">
&amp;amp;lt;pre&amp;amp;gt;spl_autoload_register( 'MyAutoloadHandler::launch' );&amp;amp;lt;/pre&amp;amp;gt;
</pre>
<!-- google_ad_section_end -->]]></content:encoded>
			<wfw:commentRss>http://www.tecnoretales.com/programacion/smarty3-y-autoload/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	<!-- google ad injected by adsense-optimizer http://www.adsenseoptimizer.de -->
			<div  style="padding:7px; float: left; padding-left: 0px; margin: 3px;"><!-- Ad number: 2 --><script type="text/javascript"><!--
    	 
    	google_ad_client = "pub-7180773421652966"; google_alternate_color = "FFFFFF";
		google_ad_width = 468; google_ad_height = 60;
		google_ad_format = "468x60_as"; google_ad_type = "text";
		google_ad_channel =""; google_color_border = "FE8B00";
		google_color_link = "FE8B00"; google_color_bg = "FFFFFF";
		google_color_text = "000000"; google_color_url = "D9D9D9";
		google_ui_features = "rc:6"; //--></script>
		<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script></div>	<item>
		<title>Smarty3 y gettext</title>
		<link>http://www.tecnoretales.com/programacion/smarty3-y-gettext/</link>
		<comments>http://www.tecnoretales.com/programacion/smarty3-y-gettext/#comments</comments>
		<pubDate>Sat, 26 Jun 2010 07:39:32 +0000</pubDate>
		<dc:creator>Manel Pérez Mata</dc:creator>
				<category><![CDATA[Frameworks]]></category>
		<category><![CDATA[Programación]]></category>

		<guid isPermaLink="false">http://www.tecnoretales.com/?p=732</guid>
		<description><![CDATA[Si estás utilizando Smarty2 y te has decidido a dar el salto a Smarty3 para aprovecharte de sus nuevas funcionalidades (como por ejemplo la nada despreciable opción de herencia en templates), verás que existen algunas incompatibilidades, por ejemplo, se han decidido por seguir el estandar camelCase en el nombre de las funciones, utilizan getters y [...]]]></description>
			<content:encoded><![CDATA[<!-- google_ad_section_start --><p>Si estás utilizando Smarty2 y te has decidido a dar el salto a Smarty3 para aprovecharte de sus nuevas funcionalidades (como por ejemplo la nada despreciable opción de herencia en templates), verás que existen algunas incompatibilidades, por ejemplo, se han decidido por seguir el estandar camelCase en el nombre de las funciones, utilizan getters y setters para los atributos o han cambiado la manera de registrar bloques.</p>
<p>En el caso del popular plugin <strong>smarty-gettext</strong>, si tenemos personalizada la llamada al traductor con, por ejemplo &#8216;{t}&#8217; como es mi caso, nos encontraremos con un bonito error:</p>
<blockquote><p>function call &#8216;register_block&#8217; is unknown or deprecated</p></blockquote>
<p>Esto es debido a que la forma correcta de registrar bloques en Smarty3 es:</p>
<pre class="brush: php;">

$this-&gt;register-&gt;block('t', 'translate');
</pre>
<p>en lugar de:</p>
<pre class="brush: php;">

$this-&gt;register_block( 't', 'translate' );
</pre>
<p>Una vez hecho esto, el siguiente error que nos deja Smarty es:</p>
<blockquote><p>Plugin &#8220;t&#8221; not callable</p></blockquote>
<p>En lugar del antiguo &#8216;translate&#8217;, el segundo parámetro deberá ser el nombre correcto de la función, es decir &#8217;smarty_translate&#8217;:</p>
<pre class="brush: php;">

$this-&gt;register-&gt;block('t', 'smarty_translate');
</pre>
<p>de este modo solventaremos el problema y podremos seguir disfrutando de nuestro plugin de traducción.</p>
<!-- google_ad_section_end -->]]></content:encoded>
			<wfw:commentRss>http://www.tecnoretales.com/programacion/smarty3-y-gettext/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Symfony: Upgrade de 1.2.x a 1.4 con PEAR</title>
		<link>http://www.tecnoretales.com/programacion/symfony-upgrade-de-1-2-x-a-1-4-con-pear/</link>
		<comments>http://www.tecnoretales.com/programacion/symfony-upgrade-de-1-2-x-a-1-4-con-pear/#comments</comments>
		<pubDate>Thu, 10 Dec 2009 17:55:15 +0000</pubDate>
		<dc:creator>Manel Pérez Mata</dc:creator>
				<category><![CDATA[Frameworks]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Symfony]]></category>

		<guid isPermaLink="false">http://www.tecnoretales.com/?p=722</guid>
		<description><![CDATA[Antes de empezar a hacer el upgrade de symfony debemos asegurarnos que los plugins utilizados actualmente en el proyecto son compatibles con la versión 1.4, en caso de no ser compatibles, tenemos tres opciones:

Buscar un plugin similar que sí sea compatible.
Modificar nuestra aplicación para que no utilice dicho plugin.
Si no podemos prescindir de él, habrá [...]]]></description>
			<content:encoded><![CDATA[<!-- google_ad_section_start --><p>Antes de empezar a hacer el <strong>upgrade de symfony</strong> debemos asegurarnos que los plugins utilizados actualmente en el proyecto son compatibles con la <strong>versión 1.4</strong>, en caso de no ser compatibles, tenemos tres opciones:</p>
<ol>
<li>Buscar un plugin similar que sí sea compatible.</li>
<li>Modificar nuestra aplicación para que no utilice dicho plugin.</li>
<li>Si no podemos prescindir de él, habrá que esperar a que saquen la compatibilidad o hackearlo nosotros mismos (lo qual podría ser muy fácil o muy difícil en función del tipo de problema).</li>
</ol>
<p>Pasos a seguir para subir de versión:</p>
<p>1) Update de los canales de pear</p>
<p style="padding-left: 30px;"><em>sudo pear update-channels</em></p>
<p>2) Upgrade de symfony a la versión 1.3</p>
<p style="padding-left: 30px;"><em>sudo pear upgrade -f symfony/symfony-1.3.0</em></p>
<p>3) Validamos que no estamos usando métodos deprecated (estós están eliminados en la <strong>versión 1.4</strong>)</p>
<p style="padding-left: 30px;"><em>symfony project:validate</em></p>
<p>En caso de obtener errores del validador, los solventaremos antes de hacer el upgrade siguiendo instrucciónes en la página <a title="Symfony deprecations and removals in 1.3" href="http://www.symfony-project.org/tutorial/1_4/en/deprecated" target="_blank">Deprecations and removals in 1.3</a></p>
<p>4) Upgrade del projecto a la versión 1.3</p>
<p style="padding-left: 30px;"><em>symfony project:upgrade1.3</em></p>
<p>5) Upgrade de los plugins a la última versión</p>
<p style="padding-left: 30px;"><em>symfony plugin:upgrade [plugin]</em></p>
<p>6) Upgrade de symfony a la última versión</p>
<p style="padding-left: 30px;"><em>sudo pear upgrade symfony/symfony</em></p>
<p>7) Limpiamos la caché antes de probar</p>
<p style="padding-left: 30px;"><em>symfony cc</em></p>
<p>Ahora deberíamos tener nuestro proyecto updateado a la última versión estable de symfony <img src='http://www.tecnoretales.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> </p>
<!-- google_ad_section_end -->]]></content:encoded>
			<wfw:commentRss>http://www.tecnoretales.com/programacion/symfony-upgrade-de-1-2-x-a-1-4-con-pear/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Symfony i18n con gettext</title>
		<link>http://www.tecnoretales.com/programacion/symfony-i18n-con-gettext/</link>
		<comments>http://www.tecnoretales.com/programacion/symfony-i18n-con-gettext/#comments</comments>
		<pubDate>Sat, 05 Dec 2009 14:26:01 +0000</pubDate>
		<dc:creator>Manel Pérez Mata</dc:creator>
				<category><![CDATA[Frameworks]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Symfony]]></category>

		<guid isPermaLink="false">http://www.tecnoretales.com/?p=716</guid>
		<description><![CDATA[Symfony permite varios métodos para internazionalizar nuestra aplicación. Por defecto, utilizan el formato XLIFF sin embargo, personalmente me gusta más gettext.
¿Cómo configurar symfony para usar gettext?
Para configurar symfony para que utilice gettext seguiremos los siguientes pasos:
1) Activamos el módulo I18N modificando el archivo settings.yml:
#apps/&#60;appName&#62;/config/settings.yml
all:
  .settings:
    charset:      [...]]]></description>
			<content:encoded><![CDATA[<!-- google_ad_section_start --><p>Symfony permite varios métodos para <strong>internazionalizar</strong> nuestra aplicación. Por defecto, utilizan el <a title="Formato XLIFF" href="http://es.wikipedia.org/wiki/XLIFF" target="_blank">formato XLIFF</a> sin embargo, personalmente me gusta más <a title="Gettext" href="http://es.wikipedia.org/wiki/Gettext" target="_blank">gettext</a>.</p>
<p><strong>¿Cómo configurar symfony para usar gettext?</strong></p>
<p>Para configurar symfony para que utilice <strong>gettext</strong> seguiremos los siguientes pasos:</p>
<p>1) Activamos el módulo I18N modificando el archivo <strong>settings.yml</strong>:</p>
<pre class="brush: php;">#apps/&lt;appName&gt;/config/settings.yml
all:
  .settings:
    charset:                utf-8
    i18n:                   on
    standard_helpers:       [ [TUS_HELPERS_ACTIVADOS]..., I18N]</pre>
<p>2) Abrimos el archivo <strong>factories.yml</strong> y añadimos la entrada i18n:</p>
<pre class="brush: php;">#apps/&lt;appName&gt;/config/factories.yml
all:
  i18n:
    class: sfI18N
    param:
      default_culture:  en_US
      source:           gettext&lt;/pre&gt;
</pre>
<p>3) Crearemos una carpeta i18n dentro de <em>apps/<appName>/</em>:</p>
<pre class="brush: php;">apps/&lt;appName&gt;/i18n/&lt;lang&gt;</pre>
<p>Donde &lt;lang&gt; será el idioma en dos letras (en, es, fr&#8230;) y dentro tendremos los ficheros messages.po y messages.mo.</p>
<p>Ahora podemos utilizar la función __( &#8216;texto_a_traducir&#8217; ) con doble <em>underscore</em> [ _ ] en lugar del simple utilizado normalmente.</p>
<p><strong>¿Cómo generar automáticamente nuestros ficheros po y mo?</strong></p>
<p>Symfony trae una serie de herramientas que nos permiten generar los archivos po y mo de manera automática. Invocando el comando:</p>
<p><code>symfony i18n:extract frontend en --auto-save</code></p>
<p>Se recorrerá todos los archivos php de nuestra aplicación (código y templates) y sacará los textos que encuentre en las funciones __().</p>
<p>También se puede utilizar el mismo comando de la siguiente manera:</p>
<p><code>symfony i18n:extract frontend en --auto-delete</code></p>
<p>para eliminar las cadenas de texto que ya no existen.</p>
<!-- google_ad_section_end -->]]></content:encoded>
			<wfw:commentRss>http://www.tecnoretales.com/programacion/symfony-i18n-con-gettext/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Pasar segundos a horas:minutos:segundos</title>
		<link>http://www.tecnoretales.com/programacion/pasar-segundos-a-horas-minutos-segundos/</link>
		<comments>http://www.tecnoretales.com/programacion/pasar-segundos-a-horas-minutos-segundos/#comments</comments>
		<pubDate>Thu, 05 Nov 2009 21:34:31 +0000</pubDate>
		<dc:creator>Manel Pérez Mata</dc:creator>
				<category><![CDATA[Programación]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Script]]></category>

		<guid isPermaLink="false">http://www.tecnoretales.com/?p=711</guid>
		<description><![CDATA[Una sencilla función que dado un número de segundos, nos devuelve el tiempo en formato hh:mm:ss


protected function makeTimeFromSeconds( $total_seconds )
{
    $horas              = floor ( $total_seconds / 3600 );
    $minutes            = ( ( $total_seconds / 60 ) % 60 );
    $seconds        [...]]]></description>
			<content:encoded><![CDATA[<!-- google_ad_section_start --><p>Una sencilla función que dado un número de segundos, nos devuelve el tiempo en formato hh:mm:ss</p>
<pre class="brush: php;">

protected function makeTimeFromSeconds( $total_seconds )
{
    $horas              = floor ( $total_seconds / 3600 );
    $minutes            = ( ( $total_seconds / 60 ) % 60 );
    $seconds            = ( $total_seconds % 60 );

    $time['horas']      = str_pad( $horas, 2, &quot;0&quot;, STR_PAD_LEFT );
    $time['minutes']    = str_pad( $minutes, 2, &quot;0&quot;, STR_PAD_LEFT );
    $time['seconds']    = str_pad( $seconds, 2, &quot;0&quot;, STR_PAD_LEFT );

    $time               = implode( ':', $time );

    return $time;
}
</pre>
<p>Espero os sea de utilidad.</p>
<!-- google_ad_section_end -->]]></content:encoded>
			<wfw:commentRss>http://www.tecnoretales.com/programacion/pasar-segundos-a-horas-minutos-segundos/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	<!-- google ad injected by adsense-optimizer http://www.adsenseoptimizer.de -->
			<div  style="padding:7px; display: block; margin-left: auto; margin-right: auto; text-align: center;"><!-- Ad number: 3 --><script type="text/javascript"><!--
    	 
    	google_ad_client = "pub-7180773421652966"; google_alternate_color = "FFFFFF";
		google_ad_width = 468; google_ad_height = 60;
		google_ad_format = "468x60_as"; google_ad_type = "text";
		google_ad_channel =""; google_color_border = "FE8B00";
		google_color_link = "FE8B00"; google_color_bg = "FFFFFF";
		google_color_text = "000000"; google_color_url = "D9D9D9";
		google_ui_features = "rc:6"; //--></script>
		<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script></div>	<item>
		<title>La clase sfConfig de Symfony</title>
		<link>http://www.tecnoretales.com/programacion/la-clase-sfconfig-de-symfony/</link>
		<comments>http://www.tecnoretales.com/programacion/la-clase-sfconfig-de-symfony/#comments</comments>
		<pubDate>Sat, 10 Oct 2009 21:05:27 +0000</pubDate>
		<dc:creator>Manel Pérez Mata</dc:creator>
				<category><![CDATA[Frameworks]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Symfony]]></category>

		<guid isPermaLink="false">http://www.tecnoretales.com/?p=701</guid>
		<description><![CDATA[Aquí os dejo algo de información sobre como solicitar variables de configuración en symfony además de un listado muy útil con todas las variables que Symfony trae predefinidas.
Cómo pedir variables definidas
Se puede llamar a la función estática get del objeto sfConfig para solicitar cualquier variable definida pasándo dos valores. El primero indica el nombre de [...]]]></description>
			<content:encoded><![CDATA[<!-- google_ad_section_start --><p>Aquí os dejo algo de información sobre como solicitar variables de configuración en symfony además de un listado muy útil con todas las variables que Symfony trae predefinidas.</p>
<h3>Cómo pedir variables definidas</h3>
<p>Se puede llamar a la función estática get del objeto sfConfig para solicitar cualquier variable definida pasándo dos valores. El primero indica el nombre de la variable solicitada y el segundo, el valor que retornará en caso de no existir dicha variable.</p>
<pre><strong>sfConfig::get('sf_config_variable', 'The default value'); </strong>// The default is optional</pre>
<p><span id="more-701"></span>Además de las variables que symfony trea configuradas por defecto, podemos añadir nuestras propias variables. Esto se hace en los archivos app.yml. Tenemos un app.yml global para todas las aplicaciones y módulos de nuestro proyecto localizado en:</p>
<pre>/path/to/project/[PROJECT_NAME]/config/app.yml</pre>
<p>y otro para cada una de las aplicaciones:</p>
<pre>/path/to/project/[PROJECT_NAME]/apps/[APP_NAME]/config/app.yml</pre>
<p>NOTA! Si existen dos variables con el mismo nombre en el app.yml global y en el de aplicación, este último valor sobreescribirá el valor global.</p>
<p>Para solicitar una variable definida en uno de estos archivos app.yml devemos añadir app_ al nombre de la variable como se muestra en el siguiente ejemplo:</p>
<pre>sfConfig::get('<strong>app_</strong>sf_config_variable');</pre>
<p>Si en el archivo app.yml definimos la variable en cascada, como por ejemplo:</p>
<pre>all:
  admin:
    email: admin@mail.bla
</pre>
<p>Deberemos acceder a ella añadiendo los diferentes niveles en la llamada:</p>
<pre>sfConfig::get('<strong>app_</strong>admin_email');
También podemos acceder a los valores configurados en settings.yml añadiendo el prefijo “sf_” al valor que queremos recuperar.
</pre>
<h3>Variables definidas por Symfony Framework</h3>
<pre><strong>sf_symfony_lib_dir</strong></pre>
<p>Path real a la carpeta lib del framework:</p>
<pre>/usr/share/php/symfony/symfony12/lib</pre>
<h3>Project Structure and Layout</h3>
<pre><strong>sf_root_dir</strong></pre>
<p>Path a la raiz del projecto:</p>
<pre>/path/to/project/[PROJECT_NAME]</pre>
<pre><strong>sf_apps_dir</strong></pre>
<p>Path a la carpeta &#8220;apps&#8221; del proyecto:</p>
<pre>/path/to/project/[PROJECT_NAME]/apps</pre>
<pre><strong>sf_lib_dir</strong></pre>
<p>Path a la carpeta &#8220;lib&#8221; del proyecto:</p>
<pre>/path/to/project/[PROJECT_NAME]/lib</pre>
<pre><strong>sf_log_dir</strong></pre>
<p>Path a la carpeta &#8220;log&#8221; del proyecto:</p>
<pre>/path/to/project/[PROJECT_NAME]/log</pre>
<pre><strong>sf_data_dir</strong></pre>
<p>Path a la carpeta &#8220;data&#8221; del proyecto:</p>
<pre>/path/to/project/[PROJECT_NAME]/data</pre>
<pre><strong>sf_config_dir</strong></pre>
<p>Path a la carpeta &#8220;config&#8221; del proyecto:</p>
<pre>/path/to/project/[PROJECT_NAME]/config</pre>
<pre><strong>sf_test_dir</strong></pre>
<p>Path a la carpeta &#8220;test&#8221; del proyecto:</p>
<pre>/path/to/project/[PROJECT_NAME]/test/</pre>
<pre><strong>sf_doc_dir</strong></pre>
<p>Path a la carpeta &#8220;doc&#8221; del proyecto:</p>
<pre>/path/to/project/[PROJECT_NAME]/doc</pre>
<pre><strong>sf_plugins_dir</strong></pre>
<p>Path a la carpeta de &#8220;plugins&#8221; del proyecto:</p>
<pre>/path/to/project/[PROJECT_NAME]/plugins</pre>
<pre><strong>sf_cache_dir</strong></pre>
<p>Path a la carpeta &#8220;cache&#8221; del proyecto:</p>
<pre>/path/to/project/[PROJECT_NAME]/cache</pre>
<pre><strong>sf_web_dir</strong></pre>
<p>Path a la carpeta pública &#8220;web&#8221;:</p>
<pre>/path/to/project/[PROJECT_NAME]/web</pre>
<pre><strong>sf_upload_dir</strong></pre>
<p>Path a la carpeta pública de &#8220;uploads&#8221;:</p>
<pre>/path/to/project/[PROJECT_NAME]/web/uploads</pre>
<h3>Application Information</h3>
<pre><strong>sf_app</strong></pre>
<p>El nombre de la aplicación en la que está el archivo, como por ejemplo &#8220;frontend&#8221; o &#8220;backend&#8221;.</p>
<pre><strong>sf_environment</strong></pre>
<p>Entorno de desarrollo actual como por ejemplo &#8220;dev&#8221;.</p>
<pre><strong>sf_debug</strong></pre>
<p>Devuelve el estado actual del modo debug. Puede estar activado &#8220;1&#8243; o desactivado &#8220;0&#8243;.</p>
<h3>Application Structure and Layout</h3>
<pre><strong>sf_app_dir</strong></pre>
<p>Path a la carpeta de la aplicación actual:</p>
<pre>/path/to/project/[PROJECT_NAME]/apps/[APP_NAME]</pre>
<pre><strong>sf_app_config_dir</strong></pre>
<p>Path a la carpeta &#8220;config&#8221; de la aplicación actual:</p>
<pre>/path/to/project/[PROJECT_NAME]/apps/[APP_NAME]/config</pre>
<pre><strong>sf_app_lib_dir</strong></pre>
<p>Path a la carpeta &#8220;lib&#8221; de la aplicación actual:</p>
<pre>/path/to/project/[PROJECT_NAME]/apps/[APP_NAME]/lib</pre>
<pre><strong>sf_app_module_dir</strong></pre>
<p>Path a la carpeta &#8220;modules&#8221; de la aplicación actual:</p>
<pre>/path/to/project/[PROJECT_NAME]/apps/[APP_NAME]/modules</pre>
<pre><strong>sf_app_template_dir</strong></pre>
<p>Path a la carpeta &#8220;templates&#8221; de la aplicación actual:</p>
<pre>/path/to/project/[PROJECT_NAME]/apps/[APP_NAME]/templates</pre>
<pre><strong>sf_app_i18n_dir</strong></pre>
<p>Path a la carpeta &#8220;i18n&#8221; de la aplicación actual:</p>
<pre>/path/to/project/[PROJECT_NAME]/apps/[APP_NAME]/i18n</pre>
<h3>Cache Structure and Layout</h3>
<pre><strong>sf_app_base_cache_dir</strong></pre>
<p>Path a la carpeta de la aplicación actual dentro de la caché.</p>
<pre>/path/to/project/[PROJECT_NAME]/cache/[APP_NAME]</pre>
<pre><strong>sf_app_cache_dir</strong></pre>
<p>Path a la carpeta de la aplicación actual en el entorno de desarrollo actual dentro de la caché.</p>
<pre>/path/to/project/[PROJECT_NAME]/cache/[APP_NAME]/dev</pre>
<pre><strong>sf_template_cache_dir</strong></pre>
<p>Path a la carpeta &#8220;template&#8221; de la aplicación actual en el entorno de desarrollo actual dentro de la caché.</p>
<pre>/path/to/project/[PROJECT_NAME]/cache/[APP_NAME]/dev/template</pre>
<pre><strong>sf_i18n_cache_dir</strong></pre>
<p>Path a la carpeta &#8220;i18n&#8221; de la aplicación actual en el entorno de desarrollo actual dentro de la caché.</p>
<pre>/path/to/project/[PROJECT_NAME]/cache/[APP_NAME]/dev/i18n</pre>
<pre><strong>sf_config_cache_dir</strong></pre>
<p>Path a la carpeta &#8220;config&#8221; de la aplicación actual en el entorno de desarrollo actual dentro de la caché.</p>
<pre>/path/to/project/[PROJECT_NAME]/cache/[APP_NAME]/dev/config</pre>
<pre><strong>sf_test_cache_dir</strong></pre>
<p>Path a la carpeta &#8220;test&#8221; de la aplicación actual en el entorno de desarrollo actual dentro de la caché.</p>
<pre>/path/to/project/[PROJECT_NAME]/cache/[APP_NAME]/dev/test</pre>
<pre><strong>sf_module_cache_dir</strong></pre>
<p>Path a la carpeta &#8220;modules&#8221; de la aplicación actual en el entorno de desarrollo actual dentro de la caché.</p>
<pre>/path/to/project/[PROJECT_NAME]/cache/[APP_NAME]/dev/modules</pre>
<h3>Application Settings</h3>
<pre><strong>sf_error_404_module</strong></pre>
<p style="padding-left: 30px;">Módulo que ha hecho saltar el error 404.</p>
<pre><strong>sf_error_404_action</strong></pre>
<p style="padding-left: 30px;">Acción que ha hecho saltar el error 404.</p>
<pre><strong>sf_logging_enabled</strong></pre>
<p style="padding-left: 30px;">Valor boleano que nos indica si el loggin de la web está activo &#8220;1&#8243; o no &#8220;0&#8243;.</p>
<pre><strong>sf_escaping_strategy</strong></pre>
<p style="padding-left: 30px;">Valor boleano que indica si la clase sfView está usando Escaping Strategy &#8220;1&#8243; o no &#8220;0&#8243;.</p>
<pre><strong>sf_no_script_name</strong></pre>
<p style="padding-left: 30px;">Valor boleano que indica si la aplicación requiere nombre de script.</p>
<pre><strong>sf_csrf_secret</strong></pre>
<p style="padding-left: 30px;">La clave CSRF secreta configurada en la aplicación.</p>
<h3>También:</h3>
<p>Se puede acceder a la información del actual contexto con las siguientes funciones:</p>
<pre><strong>sfContext::getInstance()-&gt;getActionName();</strong></pre>
<p>Devuelve el nombre de la acción actual. También puede llamarse desde los templates con  $this-&gt;getActionName().</p>
<pre><strong>sfContext::getInstance()-&gt;getModuleName();</strong></pre>
<p>Nombre del módulo actual. También puede llamarse desde los templates con $this-&gt;getModuleName().</p>
<pre><strong>sfContext::getInstance()-&gt;getModuleDirectory();</strong></pre>
<p>Path al directorio del módulo actual:</p>
<pre>/path/to/project/[PROJECT_NAME]/apps/[APP_NAME]/modules/[MODULE_NAME]</pre>
<!-- google_ad_section_end -->]]></content:encoded>
			<wfw:commentRss>http://www.tecnoretales.com/programacion/la-clase-sfconfig-de-symfony/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Cómo optimizar tus aplicaciones Web</title>
		<link>http://www.tecnoretales.com/programacion/como-optimizar-tus-aplicaciones-php/</link>
		<comments>http://www.tecnoretales.com/programacion/como-optimizar-tus-aplicaciones-php/#comments</comments>
		<pubDate>Fri, 02 Oct 2009 16:57:21 +0000</pubDate>
		<dc:creator>Manel Pérez Mata</dc:creator>
				<category><![CDATA[Navegadores]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Optimización]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[PHPBarcelona]]></category>

		<guid isPermaLink="false">http://www.tecnoretales.com/?p=685</guid>
		<description><![CDATA[Manuel Aguilar publicó una magnífica presentación sobre cómo optimizar aplicaciones Web dada en la PHP Barcelona Conference 2008 y he considerado interesante recopilar a modo de resumen las ideas más importantes de ese artículo, en cualquier caso, recomiendo la lectura del mismo para recoger toda su esencia y ampliar información.
Partiendo de un estudio de Yahoo! [...]]]></description>
			<content:encoded><![CDATA[<!-- google_ad_section_start --><p><a href="http://www.tecnoretales.com/wp-content/uploads/2009/10/internet-speed.jpg"><img class="alignleft size-full wp-image-693" title="Optimizar aplicaciones PHP" src="http://www.tecnoretales.com/wp-content/uploads/2009/10/internet-speed.jpg" alt="Optimizar aplicaciones PHP" width="200" height="200" /></a>Manuel Aguilar publicó una magnífica presentación sobre cómo <strong>optimizar aplicaciones Web</strong> dada en la PHP Barcelona Conference 2008 y he considerado interesante recopilar a modo de resumen las ideas más importantes de ese artículo, en cualquier caso, recomiendo la lectura del mismo para recoger toda su esencia y ampliar información.</p>
<p>Partiendo de un estudio de Yahoo! que dice que el 80% del tiempo de carga de una web corresponde al lado del cliente, podemos seguir una serie de reglas que aumentarán significativamente la percepción de velocidad del usuario.<span id="more-685"></span></p>
<p><strong>1. Aumentar el tiempo de expiración</strong> de los elementos cacheados que no varían como CSS o JavaScript: Para forzar la carga de los mismos cuando haya cambios, podemos añadir el md5 del contenido del fichero como parámetro, así el navegador lo recargará cuando cambie el hash. Ej: style.css?hash=f9d35dcf65d8f67e288ae2f12fc069f7</p>
<p><strong>2. No colocar código JavaScript o estilos inline</strong>: es mejor colocarlos como ficheros externos fácilmente cacheables, de este modo evitaremos descargar todo el html por un cambio de estilo.</p>
<p><strong>3. Reducir el número de ficheros externos</strong>: Los navegadores sólo pueden aceptar dos descargas simultaneas de un mismo dominio, si unimos nuestras librerías JavaScript y nuestros CSS en un único archivo evitaremos dilatar innecesariamente el tiempo de descarga.</p>
<p><a href="http://www.tecnoretales.com/wp-content/uploads/2009/10/firebug.jpg"><img class="aligncenter size-full wp-image-686" title="Firebug Net" src="http://www.tecnoretales.com/wp-content/uploads/2009/10/firebug.jpg" alt="Firebug Net" width="582" height="149" /></a></p>
<p><strong>4. Usar subdominios</strong> diferentes para las imágenes y para los elementos estáticos: Conseguiremos así descargar 8 elementos de manera simultánea y reducir la carga de la web. Si además podemos optimizar un apache aparte para servir las imágenes, conseguiremos un mejor rendimiento al servirlas.</p>
<p><strong>5. Compactar los ficheros JavaScript</strong>: Existen programas gratuitos como <a title="Yui Compressor" href="http://yuilibrary.com/downloads/#yuicompressor" target="_blank">YUI Compressor</a> que comprimen los archivos JavaScript consiguiendo resultados de hasta el 50%.</p>
<p><strong>6. Utilizar compresión en el servidor</strong>: Los servidores modernos como Apache son capaces de comprimir la información antes de servirla, posteriormente los navegadores actuales como Explorer o Firefox la descomprimen de manera transparente al usuario.</p>
<p><strong>7. Fomentar el uso de imágenes con muchos sprites</strong>: Estas son imágenes grandes que contienen muchas imágenes pequeñas. Según lo comentado en el punto 3 tardaremos mucho menos en descargar una imágen con 50 sprites que 50 sprites de manera individual. Posteriormente utilizaremos CSS para definir la sección de imágen que se mostrará.</p>
<p><a href="http://www.tecnoretales.com/wp-content/uploads/2009/10/sprites.jpg"><img class="aligncenter size-full wp-image-687" title="Sprites" src="http://www.tecnoretales.com/wp-content/uploads/2009/10/sprites.jpg" alt="Sprites" width="336" height="153" /></a></p>
<p><strong>8. Mover los CSS al &lt;head&gt;</strong>: Navegadores como Explorer no renderizan la web hasta que no tienen todos los CSS, si los colocas en la cabecera podrá empezar antes a mostrar la web.</p>
<p><strong>9. Mover los JavaScript al final de la página</strong>: Hasta que un fichero JavaScript no se ha leido completamente el navegador no continua con la carga. Si los movemos al final de la página este se estará cargando cuando el usuario ya está navegando por la web.</p>
<p><strong>10. Evitar llamadas duplicadas a JavaScript y CSS</strong>: Si el navegador encuentra un fichero JavaScript para la carga hasta que este se ha leido completamente, si posteriormente vuelve a encontrar una llamada al mismo JS, volverá a parar la carga hasta que se haya leido.</p>
<p style="text-align: right;">Vía | <a title="Optimización aplicaciones PHP" href="http://www.slideshare.net/maguilar/phpbarcelona-conference-optimizacin-aplicaciones-php-client-side" target="_blank">Optimización aplicaciones PHP</a></p>
<!-- google_ad_section_end -->]]></content:encoded>
			<wfw:commentRss>http://www.tecnoretales.com/programacion/como-optimizar-tus-aplicaciones-php/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Implementando un sistema de caché en PHP</title>
		<link>http://www.tecnoretales.com/programacion/implementando-un-sistema-de-cache-en-php/</link>
		<comments>http://www.tecnoretales.com/programacion/implementando-un-sistema-de-cache-en-php/#comments</comments>
		<pubDate>Mon, 21 Sep 2009 09:40:24 +0000</pubDate>
		<dc:creator>Manel Pérez Mata</dc:creator>
				<category><![CDATA[Programación]]></category>
		<category><![CDATA[Caché]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.tecnoretales.com/?p=658</guid>
		<description><![CDATA[Hace unos días, os comentaba que es una caché y como entenderla en el marco de la programación web. Para seguir con el aprendizaje de este sistema, he desarrollado una pequeña clase que permite cachear información (strings, arrays, resultados de base de datos, objetos&#8230;) en nuestra máquina y descongestionar así el motor de base de [...]]]></description>
			<content:encoded><![CDATA[<!-- google_ad_section_start --><p>Hace unos días, os comentaba <a title="Qué es una caché?" href="http://www.tecnoretales.com/programacion/que-es-una-cache-y-como-aplicarla-a-la-programacion-web/" target="_blank">que es una caché</a> y como entenderla en el marco de la programación web. Para seguir con el aprendizaje de este sistema, he desarrollado una pequeña <strong>clase que permite cachear información</strong> (strings, arrays, resultados de base de datos, objetos&#8230;) en nuestra máquina y descongestionar así el motor de base de datos, por poner un ejemplo.</p>
<p>Lo primero que debemos hacer es <strong>pensar en que necesitamos</strong> para su correcto funcionamiento, así que, manos a la obra.</p>
<p>Como sabemos, una caché es un sistema al que le pasamos un objeto X y él lo almacenará en su sistema de una manera determinada, por lo tanto, necesitaremos una función que dado un identificador único y unos datos, guardará la información. Además de esto, necesitamos indicarle un <strong>tiempo de vida</strong> (ttl) a esa información cacheada, sino estaremos devolviendo eternamente el valor almacenado.<span id="more-658"></span></p>
<p>Un concepto que nos puede resultar interesante es el de <strong>caché de grupo</strong>. Imaginemos que tenemos un sistema que va cacheando información de nuestra base de datos; tenemos una tabla user y una tabla user_profile y cacheamos los resultados de ambas tablas por separado. Imaginemos también que por temas de LOPD el usuario solicita que eliminemos todos sus datos de nuestras máquinas, así que eliminaremos el registro de la tabla user y user_profile y procederemos a eliminar el cacheo de los datos de cada tabla por separado. Si tuviesemos agrupada la información de usuario, con una única llamada a la función remove y pasándole el identificador de grupo, eliminará la caché de ambas tablas.</p>
<p>A medida que vaya explicando cada función, os pondré el resultado final para que os hagais una idea de como va quedando el código:</p>
<pre class="brush: php;">
    public function save ( $id, $group_id = 'default', $data, $ttl = self::CACHE_TTL )
    {
        if ( $this-&gt;caching )
        {
            $this-&gt;set_file_routes( $id, $group_id );

            // If the directory don't exists, I create.
            if ( !is_dir ( $this-&gt;file_path ) )
            {
                if ( !mkdir ( $this-&gt;file_path, 0777, true ) )
                {
                    return false;
                }
            }

            if ( !is_array ( $data ) &amp;amp;&amp;amp; !is_object( $data ) )
            {
                $data = array ( $data );
            }

            // Serialize data for caching.
            $data = serialize ( $data );

            // I get a hash to check integrity in the future.
            $hash = md5 ( $data );

            $meta['expiration_time']    = time () + $ttl;
            $meta['integrity']          = $hash;
            $meta['data']               = $data;

            // Serialize meta info to put in a file.
            $data    = serialize ( $meta );

            return file_put_contents ( $this-&gt;file, $data, LOCK_EX );
        }

        return false;
    }</pre>
<p>A su vez, debemos poder recuperar los objetos almacenados en un futuro, así que también programaremos una función que dado un identificador y un identificador de grupo, devolverá unos datos <strong>get($id, $group_id)</strong>. El tener que pasar el identificador de grupo en esta función es debido a que las rutas de almacenamiento se generan a partir de ambos identificadores.</p>
<pre class="brush: php;">
    public function get ( $id, $group_id = 'default' )
    {
        if ( $this-&gt;caching )
        {
            $this-&gt;set_file_routes ( $id, $group_id );

            if ( !file_exists ( $this-&gt;file ) )
            {
                return false;
            }

            $meta    = file_get_contents ( $this-&gt;file_path . $this-&gt;file_name );
            $meta    = unserialize ( $meta );

            $check_expiration   = $this-&gt;check_expiration ( $meta['expiration_time'] );
            $check_integrity    = $this-&gt;check_integrity ( $meta['integrity'], $meta['data'] );

            // Expiration and integrity control.
            if ( $check_expiration &amp;amp;&amp;amp; $check_integrity )
            {
                $data = unserialize ( $meta['data'] );

                return $data;
            }
            else
            // Clean the expired or not correct caché.
            {
                $this-&gt;remove ( $id, $group_id );

                return false;
            }
        }

        return false;
    }
</pre>
<p>Como último elemento fundamental, necesitaremos poder borrar unos datos de la caché en caso de que ya no sean válidos porque se han modificado o borrado, así que crearemos una función que dado un identificador y un identificador de grupo, elimine el objeto cacheado. A esta función la llamaremos <strong>remove($id, $group_id)</strong>.</p>
<pre class="brush: php;">
    public function remove( $id, $group_id = 'default', $group_level = false )
    {
        $this-&gt;set_file_routes( $id, $group_id );

        // Don't remove the 'default' group
        if ( $group_level &amp;amp;&amp;amp; $group_id != 'default' )
        {
            if ( !$this-&gt;group_path || empty ( $this-&gt;group_path ) )
            {
                return false;
            }

            return $this-&gt;del_tree ( $this-&gt;group_path );
        }
        // Check that the file exists and delete the file cached folder
        elseif ( $this-&gt;file_path &amp;amp;&amp;amp; !empty ( $this-&gt;file_path ) )
        {
            return $this-&gt;del_tree ( $this-&gt;file_path );
        }
        else
        {
            return false;
        }
    }
</pre>
<p>Como sabemos, la caché guarda los objetos durante un tiempo determinado y una vez ha pasado ese tiempo, el objeto se considera inservible, por lo tanto añadiremos una función <strong>check_expiration()</strong> que nos dirá si el objeto está caducado.</p>
<pre class="brush: php;">
private function check_expiration ( $expiration_time )
{
return ( time() &lt; $expiration_time );
}
</pre>
<p>¿Qué pasa si cuando estoy almacenando los datos hay un problema de escritura y los datos se almacenan mal? Podría suceder que los <strong>datos almacenados esten corruptos</strong>, y todas las devoluciones de dicho objeto fueran defectuosas. Para comprobar que los datos guardados no están corruptos, crearemos una función <strong>check_integrity()</strong>.</p>
<pre class="brush: php;">
    private function check_integrity ( $read_hash, $serialized_data )
    {
        $hash = md5 ( $serialized_data );

        return ( $read_hash == $hash );
    }
</pre>
<p>Además de estas funciones, crearemos varias constantes que definirán los valores de configuración del sistema como pueden ser el tiempo de vida (ttl) de un objeto cacheado por defecto o el directorio en el que se guardará la caché.</p>
<pre class="brush: php;">
    // Path to cache dir.
    const CACHE_DIR = 'cache/';

    // Max. time to life of this cache.
    const CACHE_TTL = '3600';

    // Extension to use in cache files.
    const CACHE_EXT = '.cache';
</pre>
<p>En el código se llama a las funciones <strong>get_status()</strong> y <strong>set_status()</strong> que sirven comprobar si está activo el sistema de cacheo y habilitar/deshabilitar respectivamente. <strong>set_file_routes()</strong> crea las rutas en las que se almacenará los datos cacheados y <strong>get_key()</strong> crea hashes a partir de un identificador. Por último, <strong>del_tree()</strong> nos ayudará a eliminar un directorio de manera recursiva.</p>
<pre class="brush: php;">
    public function get_status ()
    {
        return $this-&gt;caching;
    }

    public function set_status ( $status )
    {
        $this-&gt;caching = $status;
    }

    private function set_file_routes ( $id, $group_id )
    {
        $key_name    = $this-&gt;get_key ( $id );
        $key_group   = $this-&gt;get_key ( $group_id );

        $level_one = $key_group;
        $level_two = substr ( $key_name, 0, 4 );

        $this-&gt;group_path   = self::CACHE_DIR . $level_one . '/';
        $this-&gt;file_path    = self::CACHE_DIR . $level_one . '/' . $level_two . '/';
        $this-&gt;file_name    = $key_name . self::CACHE_EXT;
        $this-&gt;file         = $this-&gt;file_path . $this-&gt;file_name;
    }

    private function get_key ( $id )
    {
        return md5 ( $id );
    }

    private function del_tree ($dir)
    {
        if ( empty ( $dir ) )
        {
            return false;
        }

        if ( !file_exists ( $dir ) )
        {
            return true;
        }

        if ( !is_dir ( $dir ) || is_link ( $dir ) )
        {
            return unlink ( $dir );
        }

        foreach ( scandir ( $dir ) as $item )
        {
            if ( $item == '.' || $item == '..' )
            {
                continue;
            }

            if( is_dir ( $dir . $item ) )
            {
                $this-&gt;del_tree ( $dir . $item . '/' );
            }
            else
            {
                unlink ( $dir . $item );
            }
        }

        return rmdir ( $dir );
    }
</pre>
<p>Puedes descargarte el archivo final desde aquí <a href="http://www.tecnoretales.com/wp-content/uploads/2009/09/cache.class.php.txt" target="_blank">cache.class.php</a>.</p>
<p>Aunque esta caché es perfectamente funcional, este ejercicio nos sirve para <strong>entender un poco más el funcionamiento de un sistema de caché</strong>. Si queremos implementar uno en nuestra aplicación, os recomiendo mirar <a title="CacheLite" href="http://pear.php.net/package/Cache_Lite" target="_blank">CacheLite</a> (si nuestra aplicación es pequeña), <a title="APC" href="http://es2.php.net/apc" target="_blank">APC</a> o <a title="Memcached" href="http://www.danga.com/memcached/" target="_blank">Memcached</a> (si nuestra aplicación es grande y/o con servidores balanceados).</p>
<!-- google_ad_section_end -->]]></content:encoded>
			<wfw:commentRss>http://www.tecnoretales.com/programacion/implementando-un-sistema-de-cache-en-php/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
